summaryrefslogtreecommitdiffstats
path: root/base/server
diff options
context:
space:
mode:
authorAde Lee <alee@redhat.com>2017-03-15 23:05:07 -0400
committerAde Lee <alee@redhat.com>2017-03-15 23:05:07 -0400
commit080f3d2a8bf36be407c79ddd71381450c8667b2e (patch)
tree58594f9c45e88c882579d9f6638ff6639e506729 /base/server
parent764a17314e81cade8bf1192739b5a2fad11d18bd (diff)
parent07135b5906f97a8c68148a07484e63d6896f410b (diff)
downloadpki-080f3d2a8bf36be407c79ddd71381450c8667b2e.tar.gz
pki-080f3d2a8bf36be407c79ddd71381450c8667b2e.tar.xz
pki-080f3d2a8bf36be407c79ddd71381450c8667b2e.zip
Merge branch 'master' of github.com:dogtagpki/pki
Diffstat (limited to 'base/server')
-rw-r--r--base/server/cms/src/com/netscape/cms/authentication/AgentCertAuthentication.java6
-rw-r--r--base/server/cms/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java10
-rw-r--r--base/server/cms/src/com/netscape/cms/authentication/SharedSecret.java4
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java19
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/key/KeyRecordParser.java13
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/tks/GPParams.java108
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/tks/KDF.java59
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/tks/NistSP800_108KDF.java426
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/tks/SecureChannelProtocol.java785
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/tks/StandardKDF.java41
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/tks/TokenServlet.java800
-rw-r--r--base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java2
-rw-r--r--base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRecord.java105
-rw-r--r--base/server/man/man5/pki_default.cfg.52
-rw-r--r--base/server/man/man8/pkispawn.82
-rw-r--r--base/server/python/pki/server/__init__.py14
16 files changed, 2264 insertions, 132 deletions
diff --git a/base/server/cms/src/com/netscape/cms/authentication/AgentCertAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/AgentCertAuthentication.java
index c65dd3971..e7f50fbc2 100644
--- a/base/server/cms/src/com/netscape/cms/authentication/AgentCertAuthentication.java
+++ b/base/server/cms/src/com/netscape/cms/authentication/AgentCertAuthentication.java
@@ -22,8 +22,6 @@ import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.Locale;
-import netscape.security.x509.X509CertImpl;
-
import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.authentication.AuthToken;
import com.netscape.certsrv.authentication.EInvalidCredentials;
@@ -46,6 +44,8 @@ import com.netscape.certsrv.usrgrp.ICertUserLocator;
import com.netscape.certsrv.usrgrp.IUGSubsystem;
import com.netscape.certsrv.usrgrp.IUser;
+import netscape.security.x509.X509CertImpl;
+
/**
* Certificate server agent authentication.
* Maps a SSL client authenticate certificate to a user (agent) entry in the
@@ -196,7 +196,7 @@ public class AgentCertAuthentication implements IAuthManager,
try {
user = mCULocator.locateUser(certs);
} catch (EUsrGrpException e) {
- throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"), e);
} catch (netscape.ldap.LDAPException e) {
throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR",
e.toString()));
diff --git a/base/server/cms/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java
index 2bec1b68d..a9b0ccc77 100644
--- a/base/server/cms/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java
+++ b/base/server/cms/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java
@@ -24,9 +24,6 @@ import java.util.Enumeration;
import java.util.Locale;
import java.util.StringTokenizer;
-import netscape.security.x509.BasicConstraintsExtension;
-import netscape.security.x509.X509CertImpl;
-
import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.authentication.AuthToken;
import com.netscape.certsrv.authentication.EInvalidCredentials;
@@ -45,6 +42,9 @@ import com.netscape.certsrv.property.IDescriptor;
import com.netscape.certsrv.request.IRequest;
import com.netscape.certsrv.usrgrp.Certificates;
+import netscape.security.x509.BasicConstraintsExtension;
+import netscape.security.x509.X509CertImpl;
+
/**
* Certificate server SSL client authentication.
*
@@ -189,7 +189,7 @@ public class SSLclientCertAuthentication implements IAuthManager,
} catch (Exception e) {
CMS.debug("SSLclientCertAuthentication: authenticate: exception:" +
e.toString());
- throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"), e);
}
}
}
@@ -199,7 +199,7 @@ public class SSLclientCertAuthentication implements IAuthManager,
}
} catch (CertificateException e) {
CMS.debug(e.toString());
- throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"), e);
}
// check if certificate(s) is revoked
diff --git a/base/server/cms/src/com/netscape/cms/authentication/SharedSecret.java b/base/server/cms/src/com/netscape/cms/authentication/SharedSecret.java
index 7a0784c53..48a23536a 100644
--- a/base/server/cms/src/com/netscape/cms/authentication/SharedSecret.java
+++ b/base/server/cms/src/com/netscape/cms/authentication/SharedSecret.java
@@ -35,4 +35,8 @@ public class SharedSecret implements ISharedToken {
public String getSharedToken(BigInteger serial) {
return "testing";
}
+
+ public String getSharedToken(String identification) {
+ return "testing";
+ }
}
diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index 0f3153d3d..ed2423ff1 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -845,11 +845,7 @@ public class ConfigurationUtils {
return false;
}
- public static void restoreCertsFromP12(String p12File, String p12Pass) throws EPropertyNotFound, EBaseException,
- InvalidKeyException, CertificateException, NoSuchAlgorithmException,
- InvalidAlgorithmParameterException, IllegalStateException, TokenException, IllegalBlockSizeException,
- BadPaddingException, NotInitializedException, NicknameConflictException, UserCertConflictException,
- NoSuchItemOnTokenException, InvalidBERException, IOException {
+ public static void restoreCertsFromP12(String p12File, String p12Pass) throws Exception {
// TODO: The PKCS #12 file is already imported in security_database.py.
// This method should be removed.
@@ -1018,11 +1014,7 @@ public class ConfigurationUtils {
public static void importKeyCert(
Vector<Vector<Object>> pkeyinfo_collection,
Vector<Vector<Object>> cert_collection
- ) throws IOException, CertificateException, TokenException,
- NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException,
- IllegalStateException,
- IllegalBlockSizeException, BadPaddingException, NotInitializedException, NicknameConflictException,
- UserCertConflictException, NoSuchItemOnTokenException, EPropertyNotFound, EBaseException {
+ ) throws Exception {
CMS.debug("ConfigurationUtils.importKeyCert()");
CryptoManager cm = CryptoManager.getInstance();
@@ -1072,13 +1064,10 @@ public class ConfigurationUtils {
}
// encrypt private key
- KeyGenerator kg = token.getKeyGenerator(KeyGenAlgorithm.DES3);
- SymmetricKey sk = kg.generate();
+ SymmetricKey sk = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0, null, true);
byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
IVParameterSpec param = new IVParameterSpec(iv);
- Cipher c = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
- c.initEncrypt(sk, param);
- byte[] encpkey = c.doFinal(pkey);
+ byte[] encpkey = CryptoUtil.encryptUsingSymmetricKey(token, sk, pkey, EncryptionAlgorithm.DES3_CBC_PAD, param);
// unwrap private key to load into database
KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
diff --git a/base/server/cms/src/com/netscape/cms/servlet/key/KeyRecordParser.java b/base/server/cms/src/com/netscape/cms/servlet/key/KeyRecordParser.java
index 256f72879..c471a2869 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/key/KeyRecordParser.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/key/KeyRecordParser.java
@@ -46,6 +46,19 @@ public class KeyRecordParser {
public final static String OUT_RECOVERED_BY = "recoveredBy";
public final static String OUT_RECOVERED_ON = "recoveredOn";
+ /* parameters to populate WrappingParams */
+ public final static String OUT_SK_TYPE = "sessionKeyType";
+ public final static String OUT_SK_KEYGEN_ALGORITHM = "sessionKeyKeyGenAlgorithm";
+ public final static String OUT_SK_LENGTH = "sessionKeyLength";
+ public final static String OUT_SK_WRAP_ALGORITHM = "sessionKeyWrapAlgorithm";
+ public final static String OUT_PL_WRAP_ALGORITHM = "payloadWrapAlgorithm";
+ public final static String OUT_PL_WRAP_IV = "payloadWrapIV";
+ public final static String OUT_PL_ENCRYPTION_ALGORITHM = "payloadEncryptionAlgorithm";
+ public final static String OUT_PL_ENCRYPTION_MODE = "payloadEncryptionMode";
+ public final static String OUT_PL_ENCRYPTION_PADDING = "payloadEncryptionPadding";
+ public final static String OUT_PL_ENCRYPTION_IV = "payloadEncryptionIV";
+ public final static String OUT_PL_ENCRYPTION_OID = "payloadEncryptionOID";
+
/**
* Fills key record into argument block.
*/
diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/GPParams.java b/base/server/cms/src/com/netscape/cms/servlet/tks/GPParams.java
new file mode 100644
index 000000000..f16481be5
--- /dev/null
+++ b/base/server/cms/src/com/netscape/cms/servlet/tks/GPParams.java
@@ -0,0 +1,108 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.servlet.tks;
+
+
+//Simple class used to hold scp03 related settings in TKS keyset config block
+// Ex: tks.defKeySet.prot3.divers=emv
+// tks.defKeySet.prot3.diversVer1Keys=emv
+
+// Will probably be extended to allow params for future tokens
+
+public class GPParams {
+
+ public static String DIVER_EMV = "emv";
+ public static String DIVER_NONE = "none";
+ public static String DIVER_VISA2 = "visa2";
+ public static String NIST_SP800 = "nistsp_800";
+
+ public GPParams() {
+ }
+
+ // Diversification scheme for all keysets after 1
+ private String diversificationScheme;
+ //Diversification scheme for just version one or developer keys
+ private String version1DiversificationScheme;
+
+ public boolean isDiversEmv() {
+ if (DIVER_EMV.equalsIgnoreCase(diversificationScheme))
+ return true;
+ else
+ return false;
+ }
+
+ public boolean isDiversVisa2() {
+ if (DIVER_VISA2.equalsIgnoreCase(diversificationScheme))
+ return true;
+ else
+ return false;
+ }
+
+ public boolean isDiversNone() {
+ if (DIVER_NONE.equalsIgnoreCase(diversificationScheme))
+ return true;
+ else
+ return false;
+ }
+
+ public boolean isVer1DiversEmv() {
+ if (DIVER_EMV.equalsIgnoreCase(version1DiversificationScheme))
+ return true;
+ else
+ return false;
+ }
+
+ public boolean isVer1DiversVisa2() {
+ if (DIVER_VISA2.equalsIgnoreCase(version1DiversificationScheme))
+ return true;
+ else
+ return false;
+
+ }
+
+ public boolean isVer1DiversNone() {
+ if (DIVER_NONE.equalsIgnoreCase(version1DiversificationScheme))
+ return true;
+ else
+ return false;
+ }
+
+ public void setDiversificationScheme(String scheme) {
+ diversificationScheme = scheme;
+ }
+
+ public String getDiversificationScheme() {
+ return diversificationScheme;
+ }
+
+ public String getVersion1DiversificationScheme() {
+ return version1DiversificationScheme;
+ }
+
+ public void setVersion1DiversificationScheme(String version1DiversificationScheme) {
+ this.version1DiversificationScheme = version1DiversificationScheme;
+ }
+
+ public String toString() {
+ String output = " Version1 Diversification Scheme: " + version1DiversificationScheme + " All other versions : "
+ + diversificationScheme;
+
+ return output;
+ }
+
+}
diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/KDF.java b/base/server/cms/src/com/netscape/cms/servlet/tks/KDF.java
index 0407e2934..e7b183b4e 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/tks/KDF.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/tks/KDF.java
@@ -41,9 +41,64 @@ public class KDF {
/* Even...0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe */
/* E */0xf1, 0xf2, 0xf4, 0xf7, 0xf8, 0xfb, 0xfd, 0xfe, };
- public static byte[] getDiversificationData(byte[] context, String type) throws EBaseException {
+ //Add the emv diversification method, used in SCP03 g&d card.
+ public static byte[] getDiversificationData_EMV(byte[] context, String type) throws EBaseException {
- String method = "KDF.getDiversificationData:";
+ String method = "KDF.getDiversificationData_EMV:";
+
+ CMS.debug(method + " entering ...");
+
+ if (context == null || type == null) {
+ throw new EBaseException(method + "Invalid input parameters!");
+ }
+
+ byte[] KDC = new byte[SecureChannelProtocol.DES2_LENGTH];
+
+ KDC[0] = context[4 + 0];
+ KDC[1] = context[4 + 1];
+ KDC[2] = context[4 + 2];
+ KDC[3] = context[4 + 3];
+ KDC[4] = context[4 + 4];
+ KDC[5] = context[4 + 5];
+ KDC[6] = (byte) 0xF0;
+
+ KDC[7] = 0x1;
+
+ KDC[8] = context[4 + 0];
+ KDC[9] = context[4 + 1];
+ KDC[10] = context[4 + 2];
+ KDC[11] = context[4 +3];
+ KDC[12] = context[4 + 4];
+ KDC[13] = context[4 + 5];
+ KDC[14] = (byte) 0x0f;
+
+ KDC[15] = 0x1;
+
+ if (type.equals(SecureChannelProtocol.encType))
+ return KDC;
+
+ KDC[7] = 0x02;
+ KDC[15] = 0x02;
+ if (type.equals(SecureChannelProtocol.macType))
+ return KDC;
+
+ KDC[7] = 0x03;
+ KDC[15] = 0x03;
+ if (type.equals(SecureChannelProtocol.kekType))
+ return KDC;
+
+ KDC[7] = 0x04;
+ KDC[15] = 0x04;
+ if (type.equals(SecureChannelProtocol.rmacType))
+ return KDC;
+ return KDC;
+
+ }
+
+ //Standard visa2 diversification method
+ public static byte[] getDiversificationData_VISA2(byte[] context, String type) throws EBaseException {
+
+ String method = "KDF.getDiversificationData_VISA2:";
CMS.debug(method + " entering ...");
diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/NistSP800_108KDF.java b/base/server/cms/src/com/netscape/cms/servlet/tks/NistSP800_108KDF.java
index e392ce1a3..ad4a370c2 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/tks/NistSP800_108KDF.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/tks/NistSP800_108KDF.java
@@ -1,13 +1,24 @@
package com.netscape.cms.servlet.tks;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import org.mozilla.jss.crypto.BadPaddingException;
+import org.mozilla.jss.crypto.Cipher;
import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
import org.mozilla.jss.crypto.HMACAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
import org.mozilla.jss.crypto.JSSMessageDigest;
import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenException;
import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.base.EBaseException;
@@ -22,7 +33,18 @@ public class NistSP800_108KDF extends KDF {
static final byte KDF_LABEL = 0x04; // arbitra
- static final int SHA256_LENGTH = 32;
+ //SCP03, AES related constants
+
+ public static final int SHA256_LENGTH = 32;
+ private static final int AES_CMAC_BLOCK_SIZE = 16;
+ private static final byte AES_CMAC_CONSTANT = (byte) 0x87;
+ public static final byte ENC_KDF_CONSTANT = (byte) 0x04;
+ public static final byte MAC_KDF_CONSTANT = (byte) 0x06;
+ public static final byte RMAC_KDF_CONSTANT = (byte) 0x07;
+ public static final byte CARD_CRYPTO_KDF_CONSTANT = 0x0;
+ public static final byte HOST_CRYPTO_KDF_CONSTANT = 0x1;
+
+
SecureChannelProtocol protocol = null;
@@ -57,7 +79,7 @@ public class NistSP800_108KDF extends KDF {
String method = "NistSP800_108KDF.computeCardKeys:";
if (masterKey == null || context == null || token == null) {
- throw new EBaseException(method + " Invlalid input parameters!");
+ throw new EBaseException(method + " Invalid input parameters!");
}
Map<String, SymmetricKey> keys = new HashMap<String, SymmetricKey>();
@@ -101,9 +123,9 @@ public class NistSP800_108KDF extends KDF {
Arrays.fill(kek, (byte) 0);
Arrays.fill(kdf_output, (byte) 0);
- SymmetricKey macKey = protocol.unwrapSymKeyOnToken(token, null, macFinal, false);
- SymmetricKey encKey = protocol.unwrapSymKeyOnToken(token, null, encFinal, false);
- SymmetricKey kekKey = protocol.unwrapSymKeyOnToken(token, null, kekFinal, false);
+ SymmetricKey macKey = protocol.unwrapSymKeyOnToken(token, null, macFinal, false,SymmetricKey.DES3);
+ SymmetricKey encKey = protocol.unwrapSymKeyOnToken(token, null, encFinal, false,SymmetricKey.DES3);
+ SymmetricKey kekKey = protocol.unwrapSymKeyOnToken(token, null, kekFinal, false,SymmetricKey.DES3);
Arrays.fill(encFinal, (byte) 0);
Arrays.fill(macFinal, (byte) 0);
@@ -117,6 +139,79 @@ public class NistSP800_108KDF extends KDF {
}
+ //Compute the AES based CMAC operation. Used to derive session keys and cryptograms
+ public byte[] kdf_AES_CMAC_SCP03(SymmetricKey masterKey, byte[] context, byte kdfConstant,
+ int kdfOutputSizeBytes) throws EBaseException {
+
+ String method = "NistSP800_108KDF.kdf_AES_CMAC_SCP03:";
+ // 11 bytes label
+ byte[] label = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ // sanity checking
+
+ if (masterKey == null || context == null || kdfOutputSizeBytes <= 0) {
+ throw new EBaseException(method + " Invalid input!");
+ }
+
+ ByteArrayOutputStream data = new ByteArrayOutputStream();
+
+ int outputBits = kdfOutputSizeBytes * 8;
+
+ //output size of cmac PRF
+ final int h = 128;
+
+ int remainder = outputBits % h;
+
+ //calculate counter size
+ int n = 0;
+ if (remainder == 0) {
+ n = outputBits / h;
+ } else {
+ n = outputBits / h + 1;
+ }
+
+ byte b1 = (byte) ((outputBits >> 8) & 0xFF);
+ byte b2 = (byte) (outputBits & 0xFF);
+
+ byte[] outputBitsBinary = new byte[2];
+ outputBitsBinary[0] = b1;
+ outputBitsBinary[1] = b2;
+
+ try {
+ data.write(label);
+ data.write(kdfConstant);
+ data.write(0x0);
+ data.write(outputBitsBinary);
+ } catch (IOException e) {
+ throw new EBaseException(method + "Unable to calculate kdf!");
+ }
+
+ byte[] headerBytes = data.toByteArray();
+
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ ByteArrayOutputStream input = new ByteArrayOutputStream();
+
+ byte[] kI = null;
+ for (int i = 1; i <= n; i++) {
+
+ try {
+ input.write(headerBytes);
+ input.write((byte) i);
+ input.write(context);
+
+ kI = computeAES_CMAC(masterKey, input.toByteArray());
+
+ output.write(kI);
+
+ } catch (IOException e) {
+ throw new EBaseException(method + "Unable to calculate kdf!");
+ }
+
+ }
+
+ return output.toByteArray();
+ }
+
/*******************************************************************************
Key Derivation Function in Counter Mode using PRF = SHA256HMAC (NIST SP 800-108)
Calculates 384 bits of diversified output from the provided master key (K_I)
@@ -132,7 +227,6 @@ public class NistSP800_108KDF extends KDF {
int L_BYTE_array_length = 2; // 384 = 0x0180 hex; 2 byte long representation
if (context == null) {
- throw new EBaseException(method + " Input value context must not be null.");
}
// sanity check that output buffer is large enough to contain 384 bits
if (kdfOutputSizeBytes < KDF_OUTPUT_SIZE_BYTES) {
@@ -215,4 +309,324 @@ public class NistSP800_108KDF extends KDF {
return digestBytes;
}
+ // Implements agorithm http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38b.pdf
+ // Input an aes key of 128, 192, or 256 bits
+ // For now calling code only using 128
+ // Will move later to common class used by both tks and tps
+
+ public static byte[] computeAES_CMAC(SymmetricKey aesKey, byte[] input) throws EBaseException {
+
+ String method = "NistSP800_108KDF.computeAES_CMAC:";
+ byte iv[] = null;
+
+ if (aesKey == null || input == null) {
+ throw new EBaseException(method + " invalid input data!");
+ }
+
+ byte[] data = new byte[input.length];
+ System.arraycopy(input, 0, data, 0, input.length);
+
+ String alg = aesKey.getAlgorithm();
+ System.out.println(" AES ALG: " + alg);
+
+ EncryptionAlgorithm eAlg = EncryptionAlgorithm.AES_128_CBC;
+ int ivLength = eAlg.getIVLength();
+
+ if (ivLength > 0) {
+ iv = new byte[ivLength];
+ }
+
+ if (!("AES".equals(alg))) {
+ throw new EBaseException(method + " invalid in put key type , must be AES!");
+ }
+
+ byte[] k0 = new byte[AES_CMAC_BLOCK_SIZE];
+
+ //Encrypt the zero array
+ CryptoToken token = aesKey.getOwningToken();
+ Cipher encryptor = null;
+
+ try {
+ encryptor = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC);
+ encryptor.initEncrypt(aesKey, new IVParameterSpec(iv));
+ k0 = encryptor.doFinal(k0);
+
+ } catch (NoSuchAlgorithmException | TokenException | IllegalStateException | IllegalBlockSizeException
+ | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
+ throw new EBaseException(e);
+ }
+
+ byte[] k1 = getAES_CMAC_SubKey(k0);
+ byte[] k2 = getAES_CMAC_SubKey(k1);
+
+ int numBlocks = 0;
+ int messageSize = data.length;;
+ boolean perfectBlocks = false;
+
+ if (((messageSize % AES_CMAC_BLOCK_SIZE) == 0) && (messageSize != 0)) {
+ numBlocks = messageSize / AES_CMAC_BLOCK_SIZE;
+ perfectBlocks = true;
+ }
+ else {
+ numBlocks = messageSize / AES_CMAC_BLOCK_SIZE + 1;
+ perfectBlocks = false;
+ }
+
+ int index = 0;
+ byte inb = 0;
+
+ byte[] finalData = null;
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
+
+ if (perfectBlocks == true)
+ {
+ // If the size of the message is an integer multiple of the block block size (namely, 128 bits) (16 bytes)
+ // the last block shall be exclusive-OR'ed with the first subKey k1
+
+ for (int j = 0; j < k1.length; j++) {
+ index = messageSize - AES_CMAC_BLOCK_SIZE + j;
+ inb = data[index];
+ data[index] = (byte) (inb ^ k1[j]);
+ }
+ try {
+ outputStream.write(data);
+ } catch (IOException e) {
+ throw new EBaseException(method + " internal buffer erro!");
+ }
+ finalData = outputStream.toByteArray();
+ }
+ else
+ {
+ // Otherwise, the last block shall be padded with 10^i
+ byte[] padding = new byte[AES_CMAC_BLOCK_SIZE - messageSize % AES_CMAC_BLOCK_SIZE];
+ padding[0] = (byte) 0x80;
+
+ try {
+ outputStream.write(data);
+ outputStream.write(padding);
+ } catch (IOException e) {
+ throw new EBaseException(method + " internal buffer error!");
+ }
+
+ finalData = outputStream.toByteArray();
+
+ //Get new data size , it's changed
+ messageSize = finalData.length;
+
+ // and exclusive-OR'ed with K2
+ for (int j = 0; j < k2.length; j++) {
+ index = messageSize - AES_CMAC_BLOCK_SIZE + j;
+ inb = finalData[index];
+ finalData[index] = (byte) (inb ^ k2[j]);
+ }
+ }
+
+ // Initialization vector starts as zeroes but changes inside the loop's
+ // subsequent iterations, it becomes the last encryption output
+ byte[] encData = new byte[AES_CMAC_BLOCK_SIZE];
+ byte[] currentBlock = new byte[AES_CMAC_BLOCK_SIZE];
+ for (int i = 0; i < numBlocks; i++) {
+ try {
+ encryptor.initEncrypt(aesKey, new IVParameterSpec(encData));
+ System.arraycopy(finalData, i * AES_CMAC_BLOCK_SIZE, currentBlock, 0, AES_CMAC_BLOCK_SIZE);
+ encData = encryptor.doFinal(currentBlock);
+ } catch (TokenException | IllegalStateException | IllegalBlockSizeException
+ | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
+ throw new EBaseException(e);
+ }
+ }
+
+ return encData;
+
+ }
+
+ // SCP03 AES-CMAC support function
+ private static byte[] getAES_CMAC_SubKey(byte[] input) {
+
+ byte[] output = new byte[input.length];
+
+ boolean msbSet = ((input[0]&0x80) != 0);
+ for (int i=0; i<input.length; i++) {
+ output[i] = (byte) (input[i] << 1);
+ if (i+1 < input.length && ((input[i+1]&0x80) != 0)) {
+ output[i] |= 0x01;
+ }
+ }
+ if (msbSet) {
+ output[output.length-1] ^= AES_CMAC_CONSTANT;
+ }
+ return output;
+ }
+
+ // Collection of informal invocations of api used to create various session keys
+ // Done with test data.
+ public static void main(String[] args) {
+/*
+ Options options = new Options();
+
+ options.addOption("d", true, "Directory for tokendb");
+
+ String db_dir = null;
+ CryptoManager cm = null;
+
+ byte devKey[] = { (byte) 0x40, (byte) 0x41, (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46,
+ (byte) 0x47, (byte) 0x48, (byte) 0x49, (byte) 0x4a, (byte) 0x4b, (byte) 0x4c, (byte) 0x4d, (byte) 0x4e,
+ (byte) 0x4f };
+
+ byte test_cuid[] = { (byte) 0x47,(byte) 0x90,(byte)0x50,(byte)0x37,(byte)0x72,(byte)0x71,(byte)0x97,(byte)0x00,(byte)0x74,(byte)0xA9 };
+ byte test_kdd[] = { (byte)0x00, (byte)0x00, (byte)0x50, (byte)0x24,(byte) 0x97,(byte) 0x00,(byte) 0x74, (byte) 0xA9, (byte)0x72,(byte)0x71 };
+
+
+ byte test_host_challenge[] = { 0x06 ,(byte)0xA4 ,0x46 ,0x57 ,(byte) 0x8B ,0x65 ,0x48 ,0x51 };
+ byte test_card_challenge[] = { (byte) 0xAD ,(byte) 0x2E ,(byte)0xD0 ,0x1E ,0x7C ,0x2D ,0x0C ,0x6F};
+
+ byte test_key_info[] = { (byte) 0x02,(byte) 03,(byte) 00 };
+ byte test_old_key_info[] = {0x01,0x03,0x00};
+
+ try {
+ CommandLineParser parser = new DefaultParser();
+ CommandLine cmd = parser.parse(options, args);
+
+ if (cmd.hasOption("d")) {
+ db_dir = cmd.getOptionValue("d");
+ }
+
+ } catch (ParseException e) {
+ System.err.println("Error in parsing command line options: " + e.getMessage());
+
+ }
+
+ SymmetricKey encKey = null;
+ SymmetricKey macKey = null;
+ SymmetricKey kekKey = null;
+
+ SymmetricKey putEncKey = null;
+ SymmetricKey putMacKey = null;
+ SymmetricKey putKekKey = null;
+
+ SymmetricKey tempKey = null;
+
+ try {
+ CryptoManager.initialize(db_dir);
+ cm = CryptoManager.getInstance();
+
+ CryptoToken token = cm.getInternalKeyStorageToken();
+
+ KeyGenerator kg = token.getKeyGenerator(KeyGenAlgorithm.AES);
+
+ SymmetricKey.Usage usages[] = new SymmetricKey.Usage[4];
+ usages[0] = SymmetricKey.Usage.WRAP;
+ usages[1] = SymmetricKey.Usage.UNWRAP;
+ usages[2] = SymmetricKey.Usage.ENCRYPT;
+ usages[3] = SymmetricKey.Usage.DECRYPT;
+
+ kg.setKeyUsages(usages);
+ kg.temporaryKeys(true);
+ kg.initialize(128);
+ tempKey = kg.generate();
+
+
+ Cipher encryptor = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC);
+
+ int ivLength = EncryptionAlgorithm.AES_128_CBC.getIVLength();
+ byte[] iv = null;
+
+ if (ivLength > 0) {
+ iv = new byte[ivLength]; // all zeroes
+ }
+
+ encryptor.initEncrypt(tempKey, new IVParameterSpec(iv));
+ byte[] wrappedKey = encryptor.doFinal(devKey);
+
+ KeyWrapper keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC);
+ keyWrap.initUnwrap(tempKey, new IVParameterSpec(iv));
+
+ encKey = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.DES3, 16);
+ macKey = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.DES3, 16);
+ kekKey = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.DES3, 16);
+
+ String transportName = "TPS-dhcp-16-206.sjc.redhat.com-8443 sharedSecret";
+ SecureChannelProtocol prot = new SecureChannelProtocol(SecureChannelProtocol.PROTOCOL_THREE);
+
+ SymmetricKey masterKey = SecureChannelProtocol.getSymKeyByName(token,"new_master");
+
+ GPParams params = new GPParams();
+ params.setVersion1DiversificationScheme("visa2");
+ params.setDiversificationScheme("visa2");
+
+ putEncKey = prot.computeSessionKey_SCP03("internal", "new_master",test_old_key_info,
+ SecureChannelProtocol.encType, devKey, "defKeySet", test_cuid, test_kdd, null, null,
+ transportName,params);
+
+ putMacKey = prot.computeSessionKey_SCP03("internal", "new_master",test_old_key_info,
+ SecureChannelProtocol.macType, devKey, "defKeySet", test_cuid, test_kdd, null, null,
+ transportName,params);
+
+ putKekKey = prot.computeSessionKey_SCP03("internal", "new_master",test_old_key_info,
+ SecureChannelProtocol.kekType, devKey, "defKeySet", test_cuid, test_kdd, null, null,
+ transportName,params);
+
+ //create test session keys
+ encKey = prot.computeSessionKey_SCP03("internal", "new_master",test_key_info,
+ SecureChannelProtocol.encType, devKey, "defKeySet", test_cuid, test_kdd, test_host_challenge, test_card_challenge,
+ transportName,params);
+
+ macKey = prot.computeSessionKey_SCP03("internal", "new_master",test_key_info,
+ SecureChannelProtocol.macType,devKey,"defKeySet", test_cuid, test_kdd, test_host_challenge, test_card_challenge,
+ transportName,params);
+
+ kekKey = prot.computeSessionKey_SCP03("internal", "new_master",test_key_info,
+ SecureChannelProtocol.kekType, devKey, "defKeySet", test_cuid, test_kdd, test_host_challenge, test_card_challenge,
+ transportName,params);
+
+ System.out.println("masterKey: " + masterKey);
+
+ System.out.println("\n");
+
+ SecureChannelProtocol.debugByteArray(putEncKey.getKeyData(), " derived putEnc session key data: ");
+ SecureChannelProtocol.debugByteArray(putMacKey.getKeyData(), " derived putMac session key data: ");
+ SecureChannelProtocol.debugByteArray(putKekKey.getKeyData(), " derived putKek session key data: ");
+
+ System.out.println("\n");
+
+ SecureChannelProtocol.debugByteArray(encKey.getKeyData(), " derived enc session key data: ");
+ SecureChannelProtocol.debugByteArray(macKey.getKeyData(), " derived mac session key data: ");
+ SecureChannelProtocol.debugByteArray(kekKey.getKeyData(), " derived kek session key data: ");
+
+ ByteArrayOutputStream contextStream = new ByteArrayOutputStream();
+ try {
+ contextStream.write(test_host_challenge);
+ contextStream.write(test_card_challenge);
+ } catch (IOException e) {
+ }
+
+ StandardKDF standard = new StandardKDF(prot);
+
+ ByteArrayOutputStream testContext = new ByteArrayOutputStream();
+
+ testContext.write(test_host_challenge);
+ testContext.write(test_card_challenge);
+
+ NistSP800_108KDF nistKdf = new NistSP800_108KDF(prot);
+
+ byte[] finalEncBytes = nistKdf.kdf_AES_CMAC_SCP03(encKey, testContext.toByteArray(), (byte) 0x04, 16);
+ byte[] finalMacBytes = nistKdf.kdf_AES_CMAC_SCP03(macKey, testContext.toByteArray(), (byte) 0x06, 16);
+
+ SymmetricKey sEnc = prot.unwrapAESSymKeyOnToken(token, finalEncBytes, false);
+ SymmetricKey sMac = macKey = prot.unwrapAESSymKeyOnToken(token, finalMacBytes, false);
+
+ byte[] cardCryptoVerify = nistKdf.kdf_AES_CMAC_SCP03(sMac, testContext.toByteArray(), CARD_CRYPTO_KDF_CONSTANT, 8);
+ SecureChannelProtocol.debugByteArray(cardCryptoVerify, " calculated card cryptogram");
+
+ byte[] hostCrypto = nistKdf.kdf_AES_CMAC_SCP03(sMac, testContext.toByteArray(), HOST_CRYPTO_KDF_CONSTANT, 8);
+ SecureChannelProtocol.debugByteArray(hostCrypto, " calculated host cryptogram");
+
+ } catch (AlreadyInitializedException e) {
+ // it is ok if it is already initialized
+ } catch (Exception e) {
+ System.err.println("JSS error!" + e);
+ System.exit(1);
+ }
+*/
+ }
}
diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/SecureChannelProtocol.java b/base/server/cms/src/com/netscape/cms/servlet/tks/SecureChannelProtocol.java
index 1766f0459..371e734df 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/tks/SecureChannelProtocol.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/tks/SecureChannelProtocol.java
@@ -15,6 +15,7 @@ import org.mozilla.jss.NoSuchTokenException;
import org.mozilla.jss.crypto.Cipher;
import org.mozilla.jss.crypto.CryptoToken;
import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
import org.mozilla.jss.crypto.KeyGenAlgorithm;
import org.mozilla.jss.crypto.KeyGenerator;
import org.mozilla.jss.crypto.KeyWrapAlgorithm;
@@ -24,12 +25,12 @@ import org.mozilla.jss.crypto.SymmetricKey.NotExtractableException;
import org.mozilla.jss.crypto.SymmetricKeyDeriver;
import org.mozilla.jss.crypto.TokenException;
+import sun.security.pkcs11.wrapper.PKCS11Constants;
+
import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.base.EBaseException;
import com.netscape.cmsutil.crypto.CryptoUtil;
-import sun.security.pkcs11.wrapper.PKCS11Constants;
-
public class SecureChannelProtocol {
static String sharedSecretKeyName = null;
@@ -43,12 +44,14 @@ public class SecureChannelProtocol {
static final int KEYNAMELENGTH = PREFIXLENGHT + 7;
static final String TRANSPORT_KEY_NAME = "sharedSecret";
static final String DEFKEYSET_NAME = "defKeySet";
+ static int protocol = 1;
static final String encType = "enc";
static final String macType = "mac";
static final String kekType = "kek";
static final String authType = "auth";
static final String dekType = "dek";
+ static final String rmacType = "rmac";
static final int PROTOCOL_ONE = 1;
static final int PROTOCOL_TWO = 2;
static final int PROTOCOL_THREE = 3;
@@ -57,12 +60,26 @@ public class SecureChannelProtocol {
//Size of long type in bytes, since java7 has no define for this
static final int LONG_SIZE = 8;
+ // constants
+
+ static final int AES_128_BYTES = 16;
+ static final int AES_192_BYTES = 24;
+ static final int AES_256_BYTES = 32;
+
+ static final int AES_128_BITS = 128;
+ static final int AES_192_BITS = 192;
+ static final int AES_256_BITS = 256;
+
private SymmetricKey transportKey = null;
CryptoManager cryptoManager = null;
public SecureChannelProtocol() {
}
+ public SecureChannelProtocol(int theProtocol) {
+ protocol = theProtocol;
+ }
+
public byte[] computeCryptogram_SCP01(
String selectedToken, String keyNickName, byte[] card_challenge,
byte[] host_challenge, byte[] keyInfo,
@@ -144,6 +161,222 @@ public class SecureChannelProtocol {
throw new EBaseException(method + " Not yet implemented!");
}
+ public int getProtocol() {
+ return protocol;
+ }
+
+ // Either calculate a full session key, with the KDF applied or
+ // Merely calculate the card key. Card key mode is when host_challenge and
+ // card_challenge are passed in as null. Card keys are calculated
+ // when creating a new keyset to send to the token
+ public SymmetricKey computeSessionKey_SCP03(String selectedToken,
+ String keyNickName, byte[] keyInfo, String keyType,
+ byte[] devKeyArray, String keySet, byte[] xCUID, byte[] xKDD,
+ byte[] host_challenge, byte[] card_challenge, String transportKeyName, GPParams params)
+ throws EBaseException {
+
+ final byte mac_constant = 0x06;
+ final byte enc_constant = 0x04;
+ final byte rmac_constant = 0x07;
+
+ boolean noDerive = false;
+
+ byte constant = 0;
+
+ String method = "SecureChannelProtocol.computeSessionKey_SCP03:";
+
+ if (keyType == null || devKeyArray == null
+ || transportKeyName == null) {
+ throw new EBaseException(method + " invalid input data");
+ }
+
+ if (xCUID == null || xCUID.length <= 0) {
+ throw new EBaseException(method + "CUID invalid size!");
+ }
+
+ if (xKDD == null || xKDD.length != NistSP800_108KDF.KDD_SIZE_BYTES) {
+ throw new EBaseException(method + "KDD invalid size!");
+ }
+
+
+ //Detect card key mode or full derivation mode
+ if (card_challenge == null && host_challenge == null) {
+ noDerive = true;
+ } else {
+ if (card_challenge == null || host_challenge == null) {
+ throw new EBaseException(method + " Invalid challenge data!");
+ }
+ }
+
+ CMS.debug(method + " entering. nickname: " + keyNickName + " selectedToken: " + selectedToken);
+
+ CryptoManager cm = null;
+ CryptoToken token = null;
+ CryptoToken internalToken = null;
+ try {
+ cm = CryptoManager.getInstance();
+ token = returnTokenByName(selectedToken, cm);
+ internalToken = returnTokenByName("internal", cm);
+ } catch (NotInitializedException e) {
+ CMS.debug(method + " " + e);
+ throw new EBaseException(e);
+
+ } catch (NoSuchTokenException e) {
+ CMS.debug(method + " " + e);
+ throw new EBaseException(e);
+ }
+
+ sharedSecretKeyName = SecureChannelProtocol.getSharedSecretKeyName(transportKeyName);
+ transportKey = getSharedSecretKey(internalToken);
+
+ //concat host and card challenge:
+
+ byte[] context = null;
+
+ ByteArrayOutputStream contextStream = new ByteArrayOutputStream();
+
+ // Full derivation mode create context used in derivation
+ // host_challenge + card_challenge concatenated
+ if (noDerive == false) {
+ try {
+ contextStream.write(host_challenge);
+ contextStream.write(card_challenge);
+ } catch (IOException e) {
+ throw new EBaseException(method + " Error calculating derivation data!");
+ }
+
+ context = contextStream.toByteArray();
+ }
+
+ //Calculate the constant based on what type of key we want.
+ // Note the kek key never goes through final derivation in scp03
+
+ if (keyType.equalsIgnoreCase(SecureChannelProtocol.encType)) {
+ constant = enc_constant;
+ }
+
+ if (keyType.equalsIgnoreCase(SecureChannelProtocol.macType)) {
+ constant = mac_constant;
+ }
+
+ if (keyType.equalsIgnoreCase(SecureChannelProtocol.rmacType)) {
+ constant = rmac_constant;
+ }
+
+ if (keyType.equalsIgnoreCase(SecureChannelProtocol.kekType)) {
+ constant = 0;
+ }
+
+ String keyNameStr = null;
+
+ SymmetricKey sessionKey = null;
+ SymmetricKey masterKey = null;
+
+ if (keyNickName == null) {
+ keyNameStr = this.getKeyName(keyInfo);
+ } else {
+ keyNameStr = keyNickName;
+ }
+
+ boolean noDivers = false;
+
+ CMS.debug(method + " keyNameStr: " + keyNameStr);
+
+ //Starting with version 1 or factory keyset.
+ if ((keyInfo[0] == 0x1 && keyNameStr.contains("#01#")) ||
+ (keyInfo[0] == -1 && keyNameStr.indexOf("#FF") != -1))
+
+ {
+ String finalKeyType = keyType;
+ SymmetricKey devSymKey = returnDeveloperSymKey(token, finalKeyType, keySet, devKeyArray);
+
+ StandardKDF standard = new StandardKDF(this);
+ SymmetricKey divKey = null;
+
+ byte[] keyDiversified = null;
+
+ //Consult the config to determine with diversification method to use.
+ if (params.isVer1DiversNone()) {
+ noDivers = true;
+ } else if (params.isVer1DiversEmv()) {
+ keyDiversified = KDF.getDiversificationData_EMV(xKDD, keyType);
+ } else if (params.isVer1DiversVisa2()) {
+ keyDiversified = KDF.getDiversificationData_VISA2(xKDD, keyType);
+ } else {
+ throw new EBaseException(method + " Invalid diversification method!");
+ }
+
+ //Obtain the card key,it may just be the raw developer key
+ if (noDivers == true) {
+ divKey = unwrapAESSymKeyOnToken(token, devKeyArray, false);
+ } else {
+
+ // The g&d calls for computing the aes card key with DES, it will then be treated as aes
+ divKey = standard.computeCardKey_SCP03_WithDES3(devSymKey, keyDiversified, token);
+ }
+
+ NistSP800_108KDF nistKdf = new NistSP800_108KDF(this);
+
+ //IN scp03, the kek key IS the card key
+ if (constant == 0 /* kek key */) {
+ sessionKey = divKey;
+ } else { // session keys will become AES
+ if (noDerive) {
+ sessionKey = divKey;
+ }
+ else {
+ byte[] finalKeyBytes = nistKdf.kdf_AES_CMAC_SCP03(divKey, context, constant, 16);
+ sessionKey = unwrapAESSymKeyOnToken(token, finalKeyBytes, false);
+
+ Arrays.fill(finalKeyBytes,(byte) 0);
+
+ //The final session key is AES.
+ }
+ }
+ } else { // Creating a session key for the case where we have already upgraded the keys on the token, using the master key
+ CMS.debug(method + "In master key mode.");
+
+ masterKey = getSymKeyByName(token, keyNameStr);
+
+ StandardKDF standard = new StandardKDF(this);
+
+ byte[] keyDiversified = null;
+
+ if (params.isDiversNone()) {
+ throw new EBaseException(method + " No diversification requested in master key mode. Aborting...");
+ } //Allow choice of emv or standard diversification
+ else if (params.isDiversEmv()) {
+ keyDiversified = KDF.getDiversificationData_EMV(xKDD, keyType);
+ } else if (params.isDiversVisa2()) {
+ keyDiversified = KDF.getDiversificationData_VISA2(xKDD, keyType);
+ }
+
+ SymmetricKey divKey = null;
+
+ divKey = standard.computeCardKey_SCP03_WithDES3(masterKey, keyDiversified, token);
+
+ NistSP800_108KDF nistKdf = new NistSP800_108KDF(this);
+ // The kek session key does not call for derivation
+ if (constant == 0 /* kek key */) {
+ sessionKey = divKey;
+ } else {
+ if (noDerive) {
+ sessionKey = divKey;
+ }
+ else {
+ byte[] finalKeyBytes = nistKdf.kdf_AES_CMAC_SCP03(divKey, context, constant, 16);
+ sessionKey = unwrapAESSymKeyOnToken(token, finalKeyBytes, false);
+
+ Arrays.fill(finalKeyBytes,(byte) 0);
+ }
+ }
+ }
+
+ //SecureChannelProtocol.debugByteArray(sessionKey.getEncoded(), keyType + " : session key");
+
+ return sessionKey;
+ }
+
public SymmetricKey computeKEKKey_SCP01(
String selectedToken, String keyNickName,
byte[] keyInfo,
@@ -153,7 +386,6 @@ public class SecureChannelProtocol {
byte[] xKDD, // AC: KDF SPEC CHANGE - pass in KDD so symkey can make decision about which value (KDD,CUID) to use
byte[] devKeyArray, String useSoftToken_s, String keySet, String transportKeyName) throws EBaseException {
-
String method = "SecureChannelProtocol.computeKEKKey_SCP01:";
CMS.debug(method + " entering... ");
@@ -294,7 +526,7 @@ public class SecureChannelProtocol {
} else {
StandardKDF standardKDF = new StandardKDF(this);
CMS.debug(method + " ComputeSessionKey NistSP800_108KDF code: Using original KDF.");
- byte[] data = KDF.getDiversificationData(context, keyType);
+ byte[] data = KDF.getDiversificationData_VISA2(context, keyType);
devKey = standardKDF.computeCardKey(masterKey, data, token, PROTOCOL_ONE);
}
@@ -349,7 +581,7 @@ public class SecureChannelProtocol {
byte[] parityEncrypted = KDF.getDesParity(encrypted);
CMS.debug(method + "encryption completed");
- derivedKey = this.unwrapSymKeyOnToken(token, null, parityEncrypted, false);
+ derivedKey = this.unwrapSymKeyOnToken(token, null, parityEncrypted, false, SymmetricKey.DES3);
}
} catch (TokenException | InvalidKeyException | EBaseException e) {
@@ -440,7 +672,7 @@ public class SecureChannelProtocol {
From that point it is a simple matter of retrieving the desired key from the token.
No security advantage is implied or desired here.
*/
- private SymmetricKey returnDeveloperSymKey(CryptoToken token, String keyType, String keySet, byte[] inputKeyArray)
+ public SymmetricKey returnDeveloperSymKey(CryptoToken token, String keyType, String keySet, byte[] inputKeyArray)
throws EBaseException {
SymmetricKey devKey = null;
@@ -497,10 +729,157 @@ public class SecureChannelProtocol {
return devKey;
}
- public SymmetricKey unwrapSymKeyOnToken(CryptoToken token, SymmetricKey unwrappingKey, byte[] inputKeyArray,
+ //Takes raw des key 16 bytes, such as developer key and returns an AES key of the same size
+ //Supports 128 bits for now
+ public SymmetricKey unwrapAESSymKeyOnToken(CryptoToken token, byte[] inputKeyArray,
+ boolean isPerm)
+ throws EBaseException {
+
+ String method = "SecureChannelProtocol.unwrapAESSymKeyOnToken:";
+ CMS.debug(method + "Entering...");
+
+ if(token == null || inputKeyArray == null) {
+ throw new EBaseException(method + " Invalid input data!");
+ }
+
+ if(inputKeyArray.length < 16) {
+ throw new EBaseException(method + " Invalid key size!");
+ }
+
+ byte[] finalInputKeyArray = inputKeyArray;
+ if(inputKeyArray.length > 16) {
+ finalInputKeyArray = new byte[16];
+ System.arraycopy(inputKeyArray, 0, finalInputKeyArray, 0, 16);;
+
+ }
+
+ KeyGenerator kg;
+ SymmetricKey finalAESKey;
+ try {
+ kg = token.getKeyGenerator(KeyGenAlgorithm.AES);
+
+ SymmetricKey.Usage usages[] = new SymmetricKey.Usage[4];
+ usages[0] = SymmetricKey.Usage.WRAP;
+ usages[1] = SymmetricKey.Usage.UNWRAP;
+ usages[2] = SymmetricKey.Usage.ENCRYPT;
+ usages[3] = SymmetricKey.Usage.DECRYPT;
+
+ kg.setKeyUsages(usages);
+ kg.temporaryKeys(true);
+ kg.initialize(128);
+ SymmetricKey tempKey = kg.generate();
+
+ //unwrap the test aes keys onto the token
+
+ Cipher encryptor = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC);
+
+ int ivLength = EncryptionAlgorithm.AES_128_CBC.getIVLength();
+ byte[] iv = null;
+
+ if (ivLength > 0) {
+ iv = new byte[ivLength]; // all zeroes
+ }
+
+ encryptor.initEncrypt(tempKey, new IVParameterSpec(iv));
+ byte[] wrappedKey = encryptor.doFinal(finalInputKeyArray);
+
+ KeyWrapper keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC);
+ keyWrap.initUnwrap(tempKey, new IVParameterSpec(iv));
+ finalAESKey = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.AES, 16);
+
+ } catch (Exception e) {
+ throw new EBaseException(method + " Can't unwrap key onto token!");
+ }
+
+ return finalAESKey;
+ }
+
+ //Supports 128 bits for now
+ //Used to convert a des key (on token) to aes
+ //Not used as of now, future if needed
+ public SymmetricKey unwrapAESSymKeyOnToken(CryptoToken token, SymmetricKey keyToUnwrap,
boolean isPerm)
throws EBaseException {
+ String method = "SecureChannelProtocol.unwrapAESSymKeyOnToken:";
+ CMS.debug(method + "Entering...");
+
+ if(token == null || keyToUnwrap == null) {
+ throw new EBaseException(method + " Invalid input data!");
+ }
+
+ if(keyToUnwrap.getLength()< 16) {
+ throw new EBaseException(method + " Invalid key size!");
+ }
+
+ KeyGenerator kg;
+ SymmetricKey finalAESKey;
+ try {
+ kg = token.getKeyGenerator(KeyGenAlgorithm.AES);
+
+ SymmetricKey.Usage usages[] = new SymmetricKey.Usage[4];
+ usages[0] = SymmetricKey.Usage.WRAP;
+ usages[1] = SymmetricKey.Usage.UNWRAP;
+ usages[2] = SymmetricKey.Usage.ENCRYPT;
+ usages[3] = SymmetricKey.Usage.DECRYPT;
+
+ kg.setKeyUsages(usages);
+ kg.temporaryKeys(true);
+ kg.initialize(128);
+ SymmetricKey tempKey = kg.generate();
+
+
+ int ivLength = EncryptionAlgorithm.AES_128_CBC.getIVLength();
+ byte[] iv = null;
+
+ if (ivLength > 0) {
+ iv = new byte[ivLength]; // all zeroes
+ }
+
+ //Wrap the arbitrary key first
+
+ int len = keyToUnwrap.getLength();
+
+ SymmetricKey finalKeyToWrap = null;
+ SymmetricKey key16 = null;
+ if(len > 16) {
+ key16 = extractDes2FromDes3(keyToUnwrap, token.getName());
+ if(key16 != null)
+ len = key16.getLength();
+ finalKeyToWrap = key16;
+ } else {
+ finalKeyToWrap = keyToUnwrap;
+ }
+
+ KeyWrapper keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC);
+ keyWrap.initWrap(tempKey, new IVParameterSpec(iv));
+ byte[] wrappedKey = keyWrap.wrap(finalKeyToWrap);
+
+ //Now unwrap to an AES key
+
+ KeyWrapper keyUnWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC);
+ keyUnWrap.initUnwrap(tempKey, new IVParameterSpec(iv));
+ finalAESKey = keyUnWrap.unwrapSymmetric(wrappedKey, SymmetricKey.AES, 16);
+
+
+ Arrays.fill(wrappedKey,(byte) 0);
+
+ //byte[] finalKeyBytes = finalAESKey.getKeyData();
+ //displayByteArray(finalKeyBytes, false);
+
+ } catch (Exception e) {
+ throw new EBaseException(method + " Can't unwrap key onto token!");
+ }
+
+ return finalAESKey;
+
+ }
+
+ //Final param allows us to request the final type, DES or AES
+ public SymmetricKey unwrapSymKeyOnToken(CryptoToken token, SymmetricKey unwrappingKey, byte[] inputKeyArray,
+ boolean isPerm, SymmetricKey.Type finalKeyType)
+ throws EBaseException {
+
String method = "SecureChannelProtocol.unwrapSymKeyOnToken:";
CMS.debug(method + "Entering...");
SymmetricKey unwrapped = null;
@@ -535,7 +914,7 @@ public class SecureChannelProtocol {
byte[] finalKeyArray = null;
- if (inputKeyArray.length == DES2_LENGTH) {
+ if (inputKeyArray.length == DES2_LENGTH && finalKeyType == SymmetricKey.DES3) {
finalKeyArray = SecureChannelProtocol.makeDes3FromDes2(inputKeyArray);
}
@@ -570,9 +949,9 @@ public class SecureChannelProtocol {
if (isPerm == true) {
unwrapped = keyWrap.unwrapSymmetricPerm(wrappedKey,
- SymmetricKey.DES3, 0);
+ finalKeyType, 0);
} else {
- unwrapped = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.DES3, 0);
+ unwrapped = keyWrap.unwrapSymmetric(wrappedKey, finalKeyType, 0);
}
} catch (Exception e) {
@@ -590,8 +969,9 @@ public class SecureChannelProtocol {
return unwrapped;
}
+ //Final param allows us to request the final type, DES or AES
public SymmetricKey unwrapWrappedSymKeyOnToken(CryptoToken token, SymmetricKey unwrappingKey, byte[] inputKeyArray,
- boolean isPerm)
+ boolean isPerm, SymmetricKey.Type keyType)
throws EBaseException {
String method = "SecureChannelProtocol.unwrapWrappedSymKeyOnToken:";
@@ -613,13 +993,15 @@ public class SecureChannelProtocol {
if (isPerm) {
unwrapped = keyWrap.unwrapSymmetricPerm(inputKeyArray,
- SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP, inputKeyArray.length);
+ keyType, SymmetricKey.Usage.UNWRAP, inputKeyArray.length);
} else {
- unwrapped = keyWrap.unwrapSymmetric(inputKeyArray, SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP,
+ unwrapped = keyWrap.unwrapSymmetric(inputKeyArray, keyType, SymmetricKey.Usage.UNWRAP,
inputKeyArray.length);
}
- finalUnwrapped = makeDes3KeyDerivedFromDes2(unwrapped, token.getName());
+ if (keyType == SymmetricKey.DES3) {
+ finalUnwrapped = makeDes3KeyDerivedFromDes2(unwrapped, token.getName());
+ }
} catch (Exception e) {
CMS.debug(method + " " + e);
@@ -629,7 +1011,10 @@ public class SecureChannelProtocol {
//CMS.debug(method + "Returning symkey: " + unwrapped);
CMS.debug(method + "Returning symkey...");
- return finalUnwrapped;
+ if (finalUnwrapped != null)
+ return finalUnwrapped;
+ else
+ return unwrapped;
}
public SymmetricKey unwrapSymKeyOnToken(CryptoToken token, byte[] inputKeyArray, boolean isPerm)
@@ -648,7 +1033,7 @@ public class SecureChannelProtocol {
}
SymmetricKey transport = getSharedSecretKey(token);
- unwrapped = this.unwrapSymKeyOnToken(token, transport, inputKeyArray, isPerm);
+ unwrapped = this.unwrapSymKeyOnToken(token, transport, inputKeyArray, isPerm, SymmetricKey.DES3);
CMS.debug(method + "Returning symkey: " + unwrapped);
@@ -710,16 +1095,36 @@ public class SecureChannelProtocol {
public static void debugByteArray(byte[] array, String message) {
CMS.debug("About to dump array: " + message);
+ System.out.println("About to dump array: " + message);
if (array == null) {
CMS.debug("Array to dump is empty!");
return;
}
+ System.out.println("################### ");
CMS.debug("################### ");
String result = getHexString(array);
CMS.debug(result);
+ System.out.println(result);
+ }
+
+ public static void
+ displayByteArray(byte[] ba, boolean has_check_sum) {
+ char mask = 0xff;
+
+ if (has_check_sum == true)
+ mask = 0xfe;
+
+ for (int i = 0; i < ba.length; i++) {
+
+ System.out.print(Integer.toHexString(ba[i] & mask) + " ");
+ if ((i % 26) == 25) {
+ System.out.println("");
+ }
+ }
+ System.out.println("");
}
final protected static char[] hex = "0123456789abcdef".toCharArray();
@@ -815,6 +1220,8 @@ public class SecureChannelProtocol {
}
SymmetricKey des2 = this.extractDes2FromDes3(symKey, devKeyToken);
+ //SecureChannelProtocol.debugByteArray(des2.getEncoded(), method + " raw des2 key, to be wrapped.");
+
result = this.wrapSessionKey(selectedToken, des2, devKey);
// SecureChannelProtocol.debugByteArray(result, " Wrapped des2 key");
@@ -929,25 +1336,93 @@ public class SecureChannelProtocol {
wrapper = wrappingKey;
}
- try {
- CryptoManager cm = this.getCryptoManger();
- CryptoToken token = returnTokenByName(tokenName, cm);
+ CMS.debug(method + " wrapper key type: " + wrapper.getType());
- keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.DES3_ECB);
- keyWrap.initWrap(wrapper, null);
- wrappedSessKeyData = keyWrap.wrap(sessionKey);
- } catch (Exception e) {
- CMS.debug(method + " " + e);
- throw new EBaseException(e);
+ if (wrapper.getType() != SymmetricKey.AES) {
+ CMS.debug(method + "Trying to wrap a key with an DES key!");
+
+ try {
+ CryptoManager cm = this.getCryptoManger();
+ CryptoToken token = returnTokenByName(tokenName, cm);
+
+ keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.DES3_ECB);
+ keyWrap.initWrap(wrapper, null);
+ wrappedSessKeyData = keyWrap.wrap(sessionKey);
+
+ } catch (
+ Exception e) {
+ CMS.debug(method + " " + e);
+ throw new EBaseException(e);
+ }
+
+ } else if (wrapper.getType() == SymmetricKey.AES) {
+ CMS.debug(method + "Trying to wrap a key with an AES key!");
+ try {
+ CryptoManager cm = this.getCryptoManger();
+ CryptoToken token = returnTokenByName(tokenName, cm);
+
+ int ivLength = EncryptionAlgorithm.AES_128_CBC.getIVLength();
+ byte[] iv = null;
+
+ if (ivLength > 0) {
+ iv = new byte[ivLength]; // all zeroes
+ }
+
+ keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC);
+ keyWrap.initWrap(wrapper, new IVParameterSpec(iv));
+ wrappedSessKeyData = keyWrap.wrap(sessionKey);
+
+
+ } catch (Exception e) {
+ CMS.debug(method + " " + e);
+ throw new EBaseException(e);
+ }
}
- //CMS.debug(method + " About to return session key: " + wrappedSessKeyData);
+
+ //SecureChannelProtocol.debugByteArray(wrappedSessKeyData, "wrappedSessKeyData");
CMS.debug(method + " returning session key");
return wrappedSessKeyData;
}
+ //128 for now.
+ public byte[] computeAES_CBCEncryption(SymmetricKey symKey, String selectedToken, byte[] input, byte[] iv)
+ throws EBaseException
+ {
+ String method = "SecureChannelProtocol.computeAES_CBCEncryption";
+ byte[] output = null;
+ byte[] finalIv = null;
+
+ if (symKey == null || selectedToken == null) {
+ throw new EBaseException(method + " Invalid input data.");
+ }
+
+ if (iv == null) {
+ finalIv = new byte[16];
+
+ } else {
+ finalIv = iv;
+ }
+
+ try {
+ CryptoManager cm = this.getCryptoManger();
+ CryptoToken token = returnTokenByName(selectedToken, cm);
+ Cipher encryptor = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC);
+ encryptor.initEncrypt(symKey, new IVParameterSpec(finalIv));
+ output = encryptor.doFinal(input);
+
+ SecureChannelProtocol.debugByteArray(output, "Encrypted data:");
+ } catch (Exception e) {
+
+ CMS.debug(method + e);
+ throw new EBaseException(method + e);
+ }
+
+ return output;
+ }
+
public byte[] computeDes3EcbEncryption(SymmetricKey desKey, String selectedToken, byte[] input)
throws EBaseException {
@@ -983,6 +1458,61 @@ public class SecureChannelProtocol {
return output;
}
+ //SCP03 uses aes
+ public byte[] computeKeyCheck_SCP03(SymmetricKey symKey, String selectedToken) throws EBaseException {
+
+ String method = "SecureChannelProtocol.computeKeyCheck_SCP03:";
+
+ if (symKey == null || selectedToken == null) {
+ throw new EBaseException(method + " invalid input data!");
+ }
+
+ byte[] key_check_message = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
+ //zero iv vector
+ byte[] key_check_iv = new byte[16];
+
+ byte[] output = null;
+ byte[] finalOutput = new byte[3];
+
+ try {
+ output = computeAES_CBCEncryption(symKey, selectedToken, key_check_message, key_check_iv);
+ } catch (EBaseException e) {
+ CMS.debug(method + e);
+ throw e;
+
+ }
+
+ //Get the 3 bytes needed
+ System.arraycopy(output, 0, finalOutput, 0, 3);
+
+ //SecureChannelProtocol.debugByteArray(finalOutput, method + " output: ");
+
+ return finalOutput;
+ }
+
+ //AES, uses AES_CMAC alg to do the work.
+ public byte[] computeCryptogram_SCP03(SymmetricKey symKey, String selectedToken, byte[] context, byte cryptoType)
+ throws EBaseException {
+ String method = "SecureChannelProtocol.computeCryptogram_";
+
+ CMS.debug(method + " entering ..");
+
+ if (symKey == null || selectedToken == null || (cryptoType != NistSP800_108KDF.CARD_CRYPTO_KDF_CONSTANT)
+ && cryptoType != NistSP800_108KDF.HOST_CRYPTO_KDF_CONSTANT) {
+ throw new EBaseException(method + " Invalid input data.");
+ }
+
+ NistSP800_108KDF nistKdf = new NistSP800_108KDF(this);
+ byte[] crypto = nistKdf.kdf_AES_CMAC_SCP03(symKey, context, cryptoType, 8);
+ //SecureChannelProtocol.debugByteArray(crypto, " calculated cryptogram");
+
+ byte[] finalCrypto = new byte[8];
+
+ System.arraycopy(crypto, 0, finalCrypto, 0, 8);
+
+ return finalCrypto;
+ }
+
public byte[] computeKeyCheck(SymmetricKey desKey, String selectedToken) throws EBaseException {
String method = "SecureChannelProtocol.computeKeyCheck:";
@@ -1115,6 +1645,9 @@ public class SecureChannelProtocol {
return output;
}
+ //Calculates the 3 new card keys to be written to the token for
+ //Symmetric key changeover. Supports SCP03 now.
+ //Provide all the static developer key arrays should we need them
public byte[] diversifyKey(String tokenName,
String newTokenName,
String oldMasterKeyName,
@@ -1125,12 +1658,18 @@ public class SecureChannelProtocol {
boolean nistSP800_108KdfUseCuidAsKdd,
byte[] CUIDValue,
byte[] KDD,
- byte[] kekKeyArray,
- String useSoftToken, String keySet, byte protocol) throws EBaseException {
+ byte[] kekKeyArray, byte[] encKeyArray, byte[] macKeyArray,
+ String useSoftToken, String keySet, byte protocol, GPParams params) throws EBaseException {
String method = "SecureChannelProtocol.diversifyKey:";
- CMS.debug(method + " Entering ... newTokenName: " + newTokenName);
+ CMS.debug(method + " Entering ... newTokenName: " + newTokenName + " protocol: " + protocol);
+ CMS.debug(method + " oldMasterKeyName: " + oldMasterKeyName);
+ CMS.debug(method + " newMasterKeyName: " + newMasterKeyName);
+
+ SecureChannelProtocol.debugByteArray(encKeyArray, " Developer enc key array: ");
+ SecureChannelProtocol.debugByteArray(macKeyArray, " Developer mac key array: ");
+ SecureChannelProtocol.debugByteArray(kekKeyArray, " Developer kek key array: ");
SymmetricKey masterKey = null;
SymmetricKey oldMasterKey = null;
@@ -1151,7 +1690,7 @@ public class SecureChannelProtocol {
byte[] output = null;
if (oldMasterKeyName == null || oldKeyInfo == null || newKeyInfo == null
- || keySet == null) {
+ || keySet == null || params == null) {
throw new EBaseException(method + "Invalid input!");
}
@@ -1162,6 +1701,9 @@ public class SecureChannelProtocol {
String fullNewMasterKeyName = getFullMasterKeyName(newMasterKeyName);
String fullOldMasterKeyName = getFullMasterKeyName(oldMasterKeyName);
+ CMS.debug(method + " fullOldMasterKeyName: " + fullOldMasterKeyName);
+ CMS.debug(method + " fullNewMasterKeyName: " + fullNewMasterKeyName);
+
CryptoManager cm = null;
CryptoToken token = null;
CryptoToken newToken = null;
@@ -1217,16 +1759,27 @@ public class SecureChannelProtocol {
StandardKDF standardKDF = new StandardKDF(this);
NistSP800_108KDF nistKDF = new NistSP800_108KDF(this);
- KDCenc = KDF.getDiversificationData(KDD, SecureChannelProtocol.encType);
- KDCmac = KDF.getDiversificationData(KDD, SecureChannelProtocol.macType);
- KDCkek = KDF.getDiversificationData(KDD, SecureChannelProtocol.kekType);
+ KDCenc = KDF.getDiversificationData_VISA2(KDD, SecureChannelProtocol.encType);
+ KDCmac = KDF.getDiversificationData_VISA2(KDD, SecureChannelProtocol.macType);
+ KDCkek = KDF.getDiversificationData_VISA2(KDD, SecureChannelProtocol.kekType);
- if (protocol == PROTOCOL_ONE) {
- if (checkForDeveloperKeySet(oldMasterKeyName) == true) {
- CMS.debug(method + " Developer key set case: ");
- } else {
- CMS.debug(method + " Not Developer key set case: ");
+ //This routine does not even support protocol 2, bail if asked to do so.
+ if (protocol == PROTOCOL_TWO) {
+ throw new EBaseException(method + " SCP 02 not yet supported here.");
+ }
+ String transportKeyName = SecureChannelProtocol.getSharedSecretKeyName(null);
+
+ if (checkForDeveloperKeySet(oldMasterKeyName) == true) {
+ //Starting with the deve key set, do nothing in this clause
+ CMS.debug(method + " Developer key set case: protocol: " + protocol);
+ } else {
+ //Case where down grading back to the deve key set, or to another master key set
+ // This clause does nothing but calculate the kek key of the
+ // Current keyset, which will be used to wrap the new keys, to be calculated
+ CMS.debug(method + " Not Developer key set case: ");
+
+ if (protocol == PROTOCOL_ONE ) {
if (NistSP800_108KDF.useThisKDF(nistSP800_108KdfOnKeyVersion, oldKeyVersion)) {
CMS.debug(method + " NistSP800_108KDF code: Using NIST SP800-108 KDF.");
@@ -1252,19 +1805,44 @@ public class SecureChannelProtocol {
old_kek_sym_key = standardKDF.computeCardKey(oldMasterKey, KDCkek, token, PROTOCOL_ONE);
}
- }
+ } else { // Protocol 3
- /* special case #01#01 */
- if (fullNewMasterKeyName != null && fullNewMasterKeyName.equals("#01#01"))
- {
- CMS.debug(method + " Special case dev key set for DiversifyKey!");
+ old_kek_sym_key = this.computeSessionKey_SCP03(tokenName, oldMasterKeyName,
+ oldKeyInfo, SecureChannelProtocol.kekType, kekKeyArray, keySet,
+ CUIDValue, KDD, null, null, transportKeyName, params);
+ CMS.debug(method + " Moving back to the developer key set case, protocol 3");
+ }
+ }
+
+ // Now compute the new keys to be written to the token.
+ /* special case #01#01 */
+ if (fullNewMasterKeyName != null
+ && (fullNewMasterKeyName.equals("#01#01") || fullNewMasterKeyName.contains("#01#03")))
+ {
+ //This is the case where we revert to the original developer key set or key set 1
+ if (protocol == PROTOCOL_ONE) {
+ CMS.debug(method + " Special case returning to the dev key set (1) for DiversifyKey, protocol 1!");
encKey = returnDeveloperSymKey(newToken, SecureChannelProtocol.encType, keySet, null);
macKey = returnDeveloperSymKey(newToken, SecureChannelProtocol.macType, keySet, null);
kekKey = returnDeveloperSymKey(newToken, SecureChannelProtocol.kekType, keySet, null);
- } else {
- CMS.debug(method + " Compute card key on token case ! For new key version");
+ } else if (protocol == PROTOCOL_THREE) {
+ CMS.debug(method + " Special case or returning to the dev key set (or ver 1) for DiversifyKey, protocol 3!");
+ encKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, newKeyInfo,
+ SecureChannelProtocol.encType, kekKeyArray,
+ keySet, CUIDValue, KDD, null, null, transportKeyName, params);
+ macKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, newKeyInfo,
+ SecureChannelProtocol.macType, kekKeyArray,
+ keySet, CUIDValue, KDD, null, null, transportKeyName, params);
+ kekKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, newKeyInfo,
+ SecureChannelProtocol.kekType, kekKeyArray,
+ keySet, CUIDValue, KDD, null, null, transportKeyName, params);
+ }
+ } else {
+ //Compute new card keys for upgraded key set
+ CMS.debug(method + " Compute card key on token case ! For new key version.");
+ if (protocol == PROTOCOL_ONE) {
if (NistSP800_108KDF.useThisKDF(nistSP800_108KdfOnKeyVersion, newKeyVersion)) {
CMS.debug(method + " NistSP800_108KDF code: Using NIST SP800-108 KDF. For new key version.");
@@ -1289,17 +1867,31 @@ public class SecureChannelProtocol {
kekKey = standardKDF.computeCardKeyOnToken(masterKey, KDCkek, protocol);
}
- if (encKey == null || macKey == null || kekKey == null) {
- throw new EBaseException(method
- + " Can't derive session keys with selected KDF. For new key version.");
- }
+ } else { // protocol 3
+ CMS.debug(method + " Generating new card keys to upgrade to, protocol 3.");
+ encKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, oldKeyInfo,
+ SecureChannelProtocol.encType, kekKeyArray,
+ keySet, CUIDValue, KDD, null, null, transportKeyName, params);
+ macKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, oldKeyInfo,
+ SecureChannelProtocol.macType, kekKeyArray,
+ keySet, CUIDValue, KDD, null, null, transportKeyName, params);
+ kekKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, oldKeyInfo,
+ SecureChannelProtocol.kekType, kekKeyArray,
+ keySet, CUIDValue, KDD, null, null, transportKeyName, params);
+
+ // Generate an old kek key to do the encrypting of the new static keys
+
+ old_kek_sym_key = this.computeSessionKey_SCP03(tokenName, oldMasterKeyName, oldKeyInfo,
+ SecureChannelProtocol.kekType, kekKeyArray,
+ keySet, CUIDValue, KDD, null, null, transportKeyName, params);
+ }
+
+ if (encKey == null || macKey == null || kekKey == null) {
+ throw new EBaseException(method
+ + " Can't derive session keys with selected KDF. For new key version.");
}
- } else if (protocol == PROTOCOL_TWO) {
- throw new EBaseException(method + " SCP 02 not yet supported here.");
- } else {
- throw new EBaseException(method + " Unsupported protocol verison.");
}
boolean showKeysForDebug = false;
@@ -1327,7 +1919,9 @@ public class SecureChannelProtocol {
} else {
CMS.debug(method + " old kek sym key is null");
+
old_kek_sym_key = returnDeveloperSymKey(token, SecureChannelProtocol.kekType, keySet, kekKeyArray);
+
output = createKeySetDataWithSymKeys(newKeyVersion, (byte[]) null,
old_kek_sym_key,
encKey,
@@ -1340,6 +1934,8 @@ public class SecureChannelProtocol {
return output;
}
+ //Create the actual blob of new keys to be written to the token
+ // Suports prot1 and prot3
private byte[] createKeySetDataWithSymKeys(byte newKeyVersion, byte[] old_kek_key_array,
SymmetricKey old_kek_sym_key,
SymmetricKey encKey, SymmetricKey macKey, SymmetricKey kekKey, byte protocol, String tokenName)
@@ -1392,6 +1988,8 @@ public class SecureChannelProtocol {
wrappingKey = old_kek_sym_key;
}
+ CMS.debug(method + "Wrapping key: length: " + wrappingKey.getLength());
+
alg = (byte) 0x81;
encKey16 = extractDes2FromDes3(encKey, tokenName);
macKey16 = extractDes2FromDes3(macKey, tokenName);
@@ -1404,23 +2002,48 @@ public class SecureChannelProtocol {
keycheck_enc_key = this.computeKeyCheck(encKey, tokenName);
keycheck_mac_key = this.computeKeyCheck(macKey, tokenName);
keycheck_kek_key = this.computeKeyCheck(kekKey, tokenName);
- /*
- debugByteArray(keycheck_enc_key, " Keycheck enc key: ");
- debugByteArray(keycheck_mac_key, " Keycheck mac key: ");
- debugByteArray(keycheck_kek_key, " KeyCheck kek key: ");
- */
} else if (protocol == PROTOCOL_TWO) {
- alg = (byte) 0x80;
throw new EBaseException(method + " SCP 02 not yet implemented!");
+ } else if (protocol == PROTOCOL_THREE) {
+ CMS.debug(method + " Attempting SCP03");
+
+ if (old_kek_sym_key == null) {
+ CMS.debug(method + " SCP03: Using old kek key array.");
+ wrappingKey = unwrapAESSymKeyOnToken(token, old_kek_key_array, false);
+ } else {
+ CMS.debug(method + "SCP03: Using input old key key sym key.");
+ wrappingKey = old_kek_sym_key;
+ }
+
+ alg = (byte) 0x88;
+
+ encrypted_enc_key = this.wrapSessionKey(tokenName, encKey, wrappingKey);
+ encrypted_mac_key = this.wrapSessionKey(tokenName, macKey, wrappingKey);
+ encrypted_kek_key = this.wrapSessionKey(tokenName, kekKey, wrappingKey);
+
+ keycheck_enc_key = this.computeKeyCheck_SCP03(encKey, tokenName);
+ keycheck_mac_key = this.computeKeyCheck_SCP03(macKey, tokenName);
+ keycheck_kek_key = this.computeKeyCheck_SCP03(kekKey, tokenName);
+
} else {
throw new EBaseException(method + " Invalid SCP version requested!");
}
// Compose the final key set data byte array
- byte[] b1 = new byte[] { alg, 0x10 };
- byte[] b2 = new byte[] { 0x3 };
+ byte[] b1 = null;
+ byte[] b2 = null;
+
+ if (protocol == PROTOCOL_THREE) {
+ //Will be different if the key is bigger than AES 128
+ // Support 128 for now
+ b1 = new byte[] { alg, 0x11, (byte) encrypted_enc_key.length };
+ } else {
+ b1 = new byte[] { alg, 0x10 };
+ }
+
+ b2 = new byte[] { 0x3 };
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
@@ -1484,6 +2107,10 @@ public class SecureChannelProtocol {
if (keyInfo.equals("#01#02") || keyInfo.equals("#FF#02"))
return true;
+ //SCP03
+ if (keyInfo.contains("#01#03") || keyInfo.contains("#FF#03"))
+ return true;
+
return false;
}
@@ -1493,6 +2120,42 @@ public class SecureChannelProtocol {
}
}
+
+ //SCP03 wrap a session key with AES kek key.
+ public byte[] encryptData_SCP03(String selectedToken, String keyNickName, byte[] data, byte[] keyInfo,
+ byte nistSP800_108KdfOnKeyVersion, boolean nistSP800_108KdfUseCuidAsKdd, byte[] xCUID, byte[] xKDD,
+ byte[] kekKeyArray, String useSoftToken_s, String keySet, GPParams params) throws EBaseException {
+
+ String method = "SecureChannelProtocol.encryptData_SCP03:";
+
+ CMS.debug(method + " Entering ....");
+
+ String transportKeyName = SecureChannelProtocol.getSharedSecretKeyName(null);
+
+ if (keyInfo == null || keySet == null || (keyInfo == null || keyInfo.length < 2) || params == null) {
+ throw new EBaseException(method + "Invalid input!");
+ }
+
+ if (xCUID == null || xCUID.length <= 0) {
+ throw new EBaseException(method + "CUID invalid size!");
+ }
+
+ if (xKDD == null || xKDD.length != NistSP800_108KDF.KDD_SIZE_BYTES) {
+ throw new EBaseException(method + "KDD invalid size!");
+ }
+
+ SymmetricKey kekKey = computeSessionKey_SCP03(selectedToken, keyNickName,
+ keyInfo, kekType, kekKeyArray, keySet, xCUID, xKDD,
+ null, null, transportKeyName, params);
+
+ byte[] output = null;
+ output = computeAES_CBCEncryption(kekKey, selectedToken, data, null);
+
+ debugByteArray(output, method + " encryptData: Output: ");
+
+ return output;
+ }
+
public byte[] encryptData(String selectedToken, String keyNickName, byte[] data, byte[] keyInfo,
byte nistSP800_108KdfOnKeyVersion, boolean nistSP800_108KdfUseCuidAsKdd, byte[] xCUID, byte[] xKDD,
byte[] kekKeyArray, String useSoftToken_s, String keySet) throws EBaseException {
diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/StandardKDF.java b/base/server/cms/src/com/netscape/cms/servlet/tks/StandardKDF.java
index 1d61a465d..8c228a15c 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/tks/StandardKDF.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/tks/StandardKDF.java
@@ -19,6 +19,39 @@ public class StandardKDF extends KDF {
this.protocol = protocol;
}
+ // For the scp03 g&d smart cafe, the dev keys must start out as DES3 keys
+ // but then this routine must return the AES version of the key
+
+ public SymmetricKey computeCardKey_SCP03_WithDES3(SymmetricKey masterKey, byte[] derivationData, CryptoToken token)
+ throws EBaseException {
+
+ String method = "StandardKDF.computeCardKey_SCP03_WithDES3:";
+
+ CMS.debug(method + " entering ...");
+
+ if (masterKey == null || token == null
+ || derivationData == null || ((derivationData.length != SecureChannelProtocol.AES_128_BYTES) &&
+ (derivationData.length != SecureChannelProtocol.AES_192_BYTES) &&
+ (derivationData.length != SecureChannelProtocol.AES_256_BYTES))) {
+
+ CMS.debug(method + " Invalid input parameters!");
+
+ throw new EBaseException(method + " Invalid input parameters!");
+ }
+
+ //Now the new key data is the derivation data encrypted with DESS3
+
+ byte[] encrypted;
+ try {
+ encrypted = this.protocol.computeDes3EcbEncryption(masterKey, token.getName(), derivationData);
+ } catch (TokenException e) {
+ throw new EBaseException(method + "Can't derive key data!");
+ }
+ //SecureChannelProtocol.debugByteArray(encrypted, "calculated key: ");
+
+ return this.protocol.unwrapAESSymKeyOnToken(token, encrypted, false);
+
+ }
public SymmetricKey computeCardKey(SymmetricKey masterKey, byte[] derivationData, CryptoToken token, int protocol)
throws EBaseException {
@@ -54,12 +87,14 @@ public class StandardKDF extends KDF {
CMS.debug(method + "Now try this the old fashioned way");
byte[] encrypted = this.protocol.computeDes3EcbEncryption(masterKey, token.getName(), derivationData);
- byte[] parityEncrypted = KDF.getDesParity(encrypted);
+ SecureChannelProtocol.debugByteArray(encrypted, "calculated key: ");
+ // byte[] parityEncrypted = KDF.getDesParity(encrypted);
CMS.debug(method + "done computeDes3EcbEncryptiong");
+
derivedKey = this.protocol.unwrapSymKeyOnToken(token, null,
- parityEncrypted, false);
+ encrypted, false,SymmetricKey.DES3);
- // The key this way is aleady des3, return
+ // The key this way is already final, return
return derivedKey;
}
diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/TokenServlet.java b/base/server/cms/src/com/netscape/cms/servlet/tks/TokenServlet.java
index a282cd26f..6a1746616 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/tks/TokenServlet.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/tks/TokenServlet.java
@@ -22,6 +22,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.security.PublicKey;
import java.security.SecureRandom;
+import java.util.ArrayList;
import java.util.StringTokenizer;
import javax.servlet.ServletConfig;
@@ -1570,8 +1571,11 @@ public class TokenServlet extends CMSServlet {
return cs.getString("tks.tksSharedSymKeyName", TRANSPORT_KEY_NAME);
}
+ //Accepts protocol param and supports scp03.
private void processDiversifyKey(HttpServletRequest req,
HttpServletResponse resp) throws EBaseException {
+
+ String method = "TokenServlet.processDiversifyKey: ";
byte[] KeySetData, xCUID, xKDD; // AC: KDF SPEC CHANGE: removed duplicative 'CUID' variable and added xKDD
// AC: BUGFIX: Record the actual parameters to DiversifyKey in the audit log.
@@ -1609,6 +1613,9 @@ public class TokenServlet extends CMSServlet {
String rProtocol = req.getParameter(IRemoteRequest.CHANNEL_PROTOCOL);
String rWrappedDekKey = req.getParameter(IRemoteRequest.WRAPPED_DEK_SESSION_KEY);
+
+ CMS.debug(method + "rWrappedDekKey: " + rWrappedDekKey);
+
int protocol = 1;
String auditMessage = "";
@@ -1670,13 +1677,13 @@ public class TokenServlet extends CMSServlet {
if (!missingParam) {
xkeyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(oldMasterKeyName);
- if (xkeyInfo == null || xkeyInfo.length != 2) {
+ if (xkeyInfo == null || (xkeyInfo.length != 2 && xkeyInfo.length != 3)) {
badParams += " KeyInfo length,";
CMS.debug("TokenServlet: Invalid key info length");
missingParam = true;
}
xnewkeyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(newMasterKeyName);
- if (xnewkeyInfo == null || xnewkeyInfo.length != 2) {
+ if (xnewkeyInfo == null || (xnewkeyInfo.length != 2 && xnewkeyInfo.length != 3)) {
badParams += " NewKeyInfo length,";
CMS.debug("TokenServlet: Invalid new key info length");
missingParam = true;
@@ -1692,7 +1699,6 @@ public class TokenServlet extends CMSServlet {
CMS.debug("process DiversifyKey: protocol value: " + protocol);
if (protocol == 2) {
-
if ((rWrappedDekKey == null) || (rWrappedDekKey.equals(""))) {
badParams += " WrappedDekKey,";
CMS.debug("TokenServlet: processDiversifyKey(): missing request parameter: WrappedDekKey, with SCP02.");
@@ -1766,7 +1772,12 @@ public class TokenServlet extends CMSServlet {
if (mNewKeyNickName != null)
newMasterKeyName = mNewKeyNickName;
- String oldKeyInfoMap = "tks." + keySet + ".mk_mappings." + req.getParameter(IRemoteRequest.TOKEN_KEYINFO); //#xx#xx
+ String tokKeyInfo = req.getParameter(IRemoteRequest.TOKEN_KEYINFO);
+
+ // Get the first 6 characters, since scp03 gives us extra characters.
+ tokKeyInfo = tokKeyInfo.substring(0,6);
+ String oldKeyInfoMap = "tks." + keySet + ".mk_mappings." + tokKeyInfo; //#xx#xx
+ CMS.debug(method + " oldKeyInfoMap: " + oldKeyInfoMap);
String oldMappingValue = CMS.getConfigStore().getString(oldKeyInfoMap, null);
String oldSelectedToken = null;
if (oldMappingValue == null) {
@@ -1778,7 +1789,9 @@ public class TokenServlet extends CMSServlet {
oldKeyNickName = st.nextToken();
}
- String newKeyInfoMap = "tks.mk_mappings." + rnewKeyInfo; //#xx#xx
+
+ String newKeyInfoMap = "tks.mk_mappings." + rnewKeyInfo.substring(0,6); //#xx#xx
+ CMS.debug(method + " newKeyInfoMap: " + newKeyInfoMap);
String newMappingValue = CMS.getConfigStore().getString(newKeyInfoMap, null);
String newSelectedToken = null;
if (newMappingValue == null) {
@@ -1795,14 +1808,22 @@ public class TokenServlet extends CMSServlet {
" oldKeyNickName=" + oldKeyNickName + " newKeyNickName=" +
newKeyNickName);
- byte kekKeyArray[] =
- com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + keySet + ".kek_key"));
+ byte kekKeyArray[] = getDeveKeyArray("kek_key", sconfig, keySet);
+ byte macKeyArray[] = getDeveKeyArray("auth_key", sconfig, keySet);
+ byte encKeyArray[] = getDeveKeyArray("mac_key", sconfig, keySet);
+
+ // com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + keySet + ".kek_key"));
+
+ //GPParams for scp03 right now, reads some scp03 specific values from the config of a given keyset
+ // passed down to the SecureChannelProtocol functions that deal with SCP03
+
+ GPParams gp3Params = readGPSettings(keySet);
- SecureChannelProtocol secProtocol = new SecureChannelProtocol();
+ SecureChannelProtocol secProtocol = new SecureChannelProtocol(protocol);
// AC: KDF SPEC CHANGE - check for error reading settings
if (missingSetting_exception == null) {
- if (protocol == 1) {
- KeySetData = secProtocol.diversifyKey(oldSelectedToken,
+ if (protocol == 1 || protocol == 3) {
+ KeySetData = secProtocol.diversifyKey(oldSelectedToken,
newSelectedToken, oldKeyNickName,
newKeyNickName,
xkeyInfo, // AC: KDF SPEC CHANGE - pass in old key info so symkey can make decision about which KDF version to use
@@ -1811,7 +1832,7 @@ public class TokenServlet extends CMSServlet {
nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE - pass in configuration file value
xCUID, // AC: KDF SPEC CHANGE - removed duplicative 'CUID' variable and replaced with 'xCUID'
xKDD, // AC: KDF SPEC CHANGE - pass in KDD so symkey can make decision about which value (KDD,CUID) to use
- (protocol == 2) ? xWrappedDekKey : kekKeyArray, useSoftToken_s, keySet, (byte) protocol);
+ kekKeyArray,encKeyArray,macKeyArray, useSoftToken_s, keySet, (byte) protocol,gp3Params);
} else if (protocol == 2) {
KeySetData = SessionKey.DiversifyKey(oldSelectedToken, newSelectedToken, oldKeyNickName,
@@ -1954,6 +1975,8 @@ public class TokenServlet extends CMSServlet {
String rKeyInfo = req.getParameter(IRemoteRequest.TOKEN_KEYINFO);
String rCUID = req.getParameter(IRemoteRequest.TOKEN_CUID);
+ String protocolValue = req.getParameter(IRemoteRequest.CHANNEL_PROTOCOL);
+
// AC: KDF SPEC CHANGE - read new KDD parameter from TPS
String rKDD = req.getParameter("KDD");
if ((rKDD == null) || (rKDD.length() == 0)) {
@@ -1996,6 +2019,8 @@ public class TokenServlet extends CMSServlet {
s_isRandom);
audit(auditMessage);
+ GPParams gp3Params = readGPSettings(keySet);
+
if (isRandom) {
if ((rdata == null) || (rdata.equals(""))) {
CMS.debug("TokenServlet: processEncryptData(): no data in request. Generating random number as data");
@@ -2058,7 +2083,7 @@ public class TokenServlet extends CMSServlet {
}
xkeyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(rKeyInfo);
- if (xkeyInfo == null || xkeyInfo.length != 2) {
+ if (xkeyInfo == null || (xkeyInfo.length != 2 && xkeyInfo.length != 3)) {
badParams += " KeyInfo length,";
CMS.debug("TokenServlet: Invalid key info length");
missingParam = true;
@@ -2103,7 +2128,7 @@ public class TokenServlet extends CMSServlet {
data = com.netscape.cmsutil.util.Utils.SpecialDecode(rdata);
keyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(rKeyInfo);
- String keyInfoMap = "tks." + keySet + ".mk_mappings." + rKeyInfo;
+ String keyInfoMap = "tks." + keySet + ".mk_mappings." + rKeyInfo.substring(0,6);
String mappingValue = CMS.getConfigStore().getString(keyInfoMap, null);
if (mappingValue == null) {
selectedToken = CMS.getConfigStore().getString("tks.defaultSlot", CryptoUtil.INTERNAL_TOKEN_NAME);
@@ -2114,20 +2139,53 @@ public class TokenServlet extends CMSServlet {
keyNickName = st.nextToken();
}
+
+ //calculate the protocol
+
+ int protocolInt = SecureChannelProtocol.PROTOCOL_ONE;
+ try
+ {
+ protocolInt = Integer.parseInt(protocolValue);
+ }
+ catch (NumberFormatException nfe)
+ {
+ protocolInt = SecureChannelProtocol.PROTOCOL_ONE;
+ }
+
+ CMS.debug( "TokenServerlet.encryptData: protocol input: " + protocolInt);
+
+ //Check for reasonable sanity, leave room for future versions
+ if(protocolInt <= 0 || protocolInt > 20) {
+ CMS.debug( "TokenServerlet.encryptData: unfamliar protocl, assume default of 1.");
+ protocolInt = 1;
+
+ }
+
byte kekKeyArray[] =
com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + keySet + ".kek_key"));
// AC: KDF SPEC CHANGE - check for error reading settings
if (missingSetting_exception == null) {
- SecureChannelProtocol protocol = new SecureChannelProtocol();
- encryptedData = protocol.encryptData(
- selectedToken, keyNickName, data, keyInfo,
- nistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE - pass in configuration file value
- nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE - pass in configuration file value
- xCUID, // AC: KDF SPEC CHANGE - removed duplicative 'CUID' variable and replaced with 'xCUID'
- xKDD, // AC: KDF SPEC CHANGE - pass in KDD so symkey can make decision about which value (KDD,CUID) to use
- kekKeyArray, useSoftToken_s, keySet);
+ SecureChannelProtocol protocol = new SecureChannelProtocol(protocolInt);
+
+ if (protocolInt != SecureChannelProtocol.PROTOCOL_THREE) {
+
+ encryptedData = protocol.encryptData(
+ selectedToken, keyNickName, data, keyInfo,
+ nistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE - pass in configuration file value
+ nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE - pass in configuration file value
+ xCUID, // AC: KDF SPEC CHANGE - removed duplicative 'CUID' variable and replaced with 'xCUID'
+ xKDD, // AC: KDF SPEC CHANGE - pass in KDD so symkey can make decision about which value (KDD,CUID) to use
+ kekKeyArray, useSoftToken_s, keySet);
+
+ } else {
+
+ encryptedData = protocol.encryptData_SCP03(selectedToken, keyNickName, data, xkeyInfo,
+ nistSP800_108KdfOnKeyVersion, nistSP800_108KdfUseCuidAsKdd, xCUID, xKDD, kekKeyArray,
+ useSoftToken_s, keySet,gp3Params);
+
+ }
SecureChannelProtocol.debugByteArray(encryptedData, "New Encrypt Data: ");
@@ -2402,7 +2460,7 @@ public class TokenServlet extends CMSServlet {
//CMS.debug("Protocol: " + protocol + " temp: " + temp);
setDefaultSlotAndKeyName(req);
- if (temp != null) {
+ if (temp != null && protocol == null) {
processComputeSessionKey(req, resp);
} else if (req.getParameter(IRemoteRequest.TOKEN_DATA) != null) {
processEncryptData(req, resp);
@@ -2413,10 +2471,515 @@ public class TokenServlet extends CMSServlet {
} else if (protocol != null && protocol.contains("2") && (derivationConstant != null)) {
//SCP02 compute one session key.
processComputeSessionKeySCP02(req, resp);
+
+ } else if (protocol != null && protocol.contains("3") ) {
+ processComputeSessionKeysSCP03(req,resp);
} else {
throw new EBaseException("Process: Can't decide upon function to call!");
+ }
+ }
+
+ //Create all the session keys for scp03 at once and return.
+ //ToDo: calcualte the optional rmac key
+ private void processComputeSessionKeysSCP03(HttpServletRequest req, HttpServletResponse resp) throws EBaseException {
+ String method = "processComputeSessionKeysSCP03:";
+ CMS.debug(method + " entering ...");
+
+ byte[] card_challenge, host_challenge, xCUID, xKDD;
+ byte[] card_crypto, host_cryptogram, input_card_crypto;
+ byte[] xcard_challenge, xhost_challenge;
+ byte[] enc_session_key, xkeyInfo,mac_session_key, kek_session_key;
+ String auditMessage = null;
+ String errorMsg = "";
+ String badParams = "";
+ String transportKeyName = "";
+ String rCUID = req.getParameter(IRemoteRequest.TOKEN_CUID);
+
+ String rKDD = req.getParameter("KDD");
+ if ((rKDD == null) || (rKDD.length() == 0)) {
+ // KDF phase1: default to rCUID if not present
+ CMS.debug("TokenServlet: KDD not supplied, set to CUID before TPS change");
+ rKDD = rCUID;
+ }
+
+ String keySet = req.getParameter(IRemoteRequest.TOKEN_KEYSET);
+ if (keySet == null || keySet.equals("")) {
+ keySet = "defKeySet";
+ }
+ CMS.debug("keySet selected: " + keySet);
+
+ GPParams gp3Params = readGPSettings(keySet);
+
+ boolean serversideKeygen = false;
+
+ IConfigStore sconfig = CMS.getConfigStore();
+ boolean isCryptoValidate = true;
+ boolean missingParam = false;
+
+ Exception missingSetting_exception = null;
+
+ mac_session_key = null;
+ kek_session_key = null;
+ card_crypto = null;
+ host_cryptogram = null;
+ enc_session_key = null;
+
+ SessionContext sContext = SessionContext.getContext();
+
+ String agentId = "";
+ if (sContext != null) {
+ agentId =
+ (String) sContext.get(SessionContext.USER_ID);
+ }
+
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST,
+ rCUID,
+ rKDD,
+ ILogger.SUCCESS,
+ agentId);
+
+ audit(auditMessage);
+
+ String kek_wrapped_desKeyString = null;
+ String keycheck_s = null;
+
+ String useSoftToken_s = CMS.getConfigStore().getString("tks.useSoftToken", "true");
+ if (!useSoftToken_s.equalsIgnoreCase("true"))
+ useSoftToken_s = "false";
+
+ CMS.debug(method + " useSoftToken: " + useSoftToken_s);
+
+ String rServersideKeygen = req.getParameter(IRemoteRequest.SERVER_SIDE_KEYGEN);
+ if (rServersideKeygen.equals("true")) {
+
+ serversideKeygen = true;
+ }
+
+ CMS.debug(method + " serversideKeygen: " + serversideKeygen);
+
+ try {
+ isCryptoValidate = sconfig.getBoolean("cardcryptogram.validate.enable", true);
+ } catch (EBaseException eee) {
+ }
+
+ CMS.debug(method + " Do crypto validation: " + isCryptoValidate);
+
+ transportKeyName = getSharedSecretName(sconfig);
+
+ String rcard_challenge = req.getParameter(IRemoteRequest.TOKEN_CARD_CHALLENGE);
+ String rhost_challenge = req.getParameter(IRemoteRequest.TOKEN_HOST_CHALLENGE);
+ String rKeyInfo = req.getParameter(IRemoteRequest.TOKEN_KEYINFO);
+ String rcard_cryptogram = req.getParameter(IRemoteRequest.TOKEN_CARD_CRYPTOGRAM);
+
+ if ((rCUID == null) || (rCUID.equals(""))) {
+ CMS.debug(method + " missing request parameter: CUID");
+ badParams += " CUID,";
+ missingParam = true;
+ }
+
+ if ((rKDD == null) || (rKDD.length() == 0)) {
+ CMS.debug(method + " missing request parameter: KDD");
+ badParams += " KDD,";
+ missingParam = true;
+ }
+
+ if ((rcard_challenge == null) || (rcard_challenge.equals(""))) {
+ badParams += " card_challenge,";
+ CMS.debug(method + " missing request parameter: card challenge");
+ missingParam = true;
+ }
+
+ if ((rhost_challenge == null) || (rhost_challenge.equals(""))) {
+ badParams += " host_challenge,";
+ CMS.debug(method + " missing request parameter: host challenge");
+ missingParam = true;
+ }
+
+ if ((rcard_cryptogram == null) || (rcard_cryptogram.equals(""))) {
+ badParams += " card_cryptogram,";
+ CMS.debug(method + " missing request parameter: card_cryptogram");
+ missingParam = true;
+ }
+
+ if ((rKeyInfo == null) || (rKeyInfo.equals(""))) {
+ badParams += " KeyInfo,";
+ CMS.debug(method + "missing request parameter: key info");
+ missingParam = true;
+ }
+
+ String selectedToken = null;
+ String keyNickName = null;
+ boolean sameCardCrypto = true;
+
+ xCUID = null;
+ xKDD = null;
+ xkeyInfo = null;
+ xcard_challenge = null;
+ xhost_challenge = null;
+
+ if (!missingParam) {
+ xCUID = com.netscape.cmsutil.util.Utils.SpecialDecode(rCUID);
+ if (xCUID == null || xCUID.length != 10) {
+ badParams += " CUID length,";
+ CMS.debug("TokenServlet: Invalid CUID length");
+ missingParam = true;
+ }
+
+ xKDD = com.netscape.cmsutil.util.Utils.SpecialDecode(rKDD);
+ if (xKDD == null || xKDD.length != 10) {
+ badParams += " KDD length,";
+ CMS.debug("TokenServlet: Invalid KDD length");
+ missingParam = true;
+ }
+
+ xkeyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(rKeyInfo);
+ if (xkeyInfo == null || xkeyInfo.length != 3) {
+ badParams += " KeyInfo length,";
+ CMS.debug("TokenServlet: Invalid key info length.");
+ missingParam = true;
+ }
+ xcard_challenge =
+ com.netscape.cmsutil.util.Utils.SpecialDecode(rcard_challenge);
+ if (xcard_challenge == null || xcard_challenge.length != 8) {
+ badParams += " card_challenge length,";
+ CMS.debug("TokenServlet: Invalid card challenge length.");
+ missingParam = true;
+ }
+
+ xhost_challenge = com.netscape.cmsutil.util.Utils.SpecialDecode(rhost_challenge);
+ if (xhost_challenge == null || xhost_challenge.length != 8) {
+ badParams += " host_challenge length,";
+ CMS.debug("TokenServlet: Invalid host challenge length");
+ missingParam = true;
+ }
+ }
+
+ ArrayList<String> serverSideValues = null;
+
+ if (!missingParam) {
+ card_challenge =
+ com.netscape.cmsutil.util.Utils.SpecialDecode(rcard_challenge);
+
+ host_challenge = com.netscape.cmsutil.util.Utils.SpecialDecode(rhost_challenge);
+
+ String keyInfoMap = "tks." + keySet + ".mk_mappings." + rKeyInfo.substring(0,6); //#xx#xx
+ String mappingValue = CMS.getConfigStore().getString(keyInfoMap, null);
+
+
+ if (mappingValue == null) {
+ selectedToken =
+ CMS.getConfigStore().getString("tks.defaultSlot", "internal");
+ keyNickName = rKeyInfo;
+ } else {
+ StringTokenizer st = new StringTokenizer(mappingValue, ":");
+ if (st.hasMoreTokens())
+ selectedToken = st.nextToken();
+ if (st.hasMoreTokens())
+ keyNickName = st.nextToken();
+ }
+
+ CMS.debug(method + " selectedToken: " + selectedToken + " keyNickName: " + keyNickName );
+
+ SymmetricKey macSessionKey = null;
+ SymmetricKey encSessionKey = null;
+ SymmetricKey kekSessionKey = null;
+
+ if (selectedToken != null && keyNickName != null
+ && missingSetting_exception == null) {
+
+ try {
+
+ byte macKeyArray[] =
+ com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks."
+ + keySet + ".mac_key"));
+ CMS.debug("TokenServlet about to try ComputeSessionKey selectedToken="
+ + selectedToken + " keyNickName=" + keyNickName);
+
+ SecureChannelProtocol protocol = new SecureChannelProtocol(SecureChannelProtocol.PROTOCOL_THREE);
+
+ macSessionKey = protocol.computeSessionKey_SCP03(selectedToken, keyNickName,xkeyInfo,
+ SecureChannelProtocol.macType, macKeyArray, keySet,xCUID, xKDD, xhost_challenge, xcard_challenge,
+ transportKeyName,gp3Params);
+
+ mac_session_key = protocol.wrapSessionKey(selectedToken, macSessionKey, null);
+
+ if (mac_session_key == null) {
+ CMS.debug(method + " Can't get mac session key bytes");
+ throw new Exception(method + " Can't get mac session key bytes");
+
+ }
+
+ byte encKeyArray[] =
+ com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks."
+ + keySet + ".auth_key"));
+
+ encSessionKey = protocol.computeSessionKey_SCP03(selectedToken, keyNickName,xkeyInfo,
+ SecureChannelProtocol.encType, encKeyArray, keySet, xCUID, xKDD, xhost_challenge, xcard_challenge,
+ transportKeyName,gp3Params);
+
+ enc_session_key = protocol.wrapSessionKey(selectedToken, encSessionKey, null);
+
+ if (enc_session_key == null) {
+ CMS.debug("TokenServlet:Tried ComputeEncSessionKey, got NULL ");
+ throw new Exception("Can't compute enc session key!");
+
+ }
+
+ byte kekKeyArray[] =
+ com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks."
+ + keySet + ".kek_key"));
+
+ kekSessionKey = protocol.computeSessionKey_SCP03(selectedToken, keyNickName, xkeyInfo,
+ SecureChannelProtocol.kekType, kekKeyArray, keySet, xCUID, xKDD, xhost_challenge,
+ xcard_challenge,
+ transportKeyName,gp3Params);
+
+ kek_session_key = protocol.wrapSessionKey(selectedToken, kekSessionKey, null);
+
+
+ //Offload some of the tedious params gathering to another method
+ //ToDo, create a method that reads all this stuff at once for all major methods
+ if (serversideKeygen) {
+ try {
+ serverSideValues = calculateServerSideKeygenValues(useSoftToken_s, selectedToken,
+ kekSessionKey, protocol);
+ } catch (EBaseException e) {
+
+ CMS.debug(method + " Can't calcualte server side keygen required values...");
+
+ }
+ }
+
+ try {
+ isCryptoValidate = sconfig.getBoolean("cardcryptogram.validate.enable", true);
+ } catch (EBaseException eee) {
+ }
+
+ ByteArrayOutputStream contextStream = new ByteArrayOutputStream();
+ try {
+ contextStream.write(host_challenge);
+ contextStream.write(card_challenge);
+ } catch (IOException e) {
+ throw new EBaseException(method + " Error calculating derivation data!");
+ }
+
+ host_cryptogram = protocol.computeCryptogram_SCP03(macSessionKey, selectedToken, contextStream.toByteArray(),NistSP800_108KDF.HOST_CRYPTO_KDF_CONSTANT);
+ SecureChannelProtocol.debugByteArray(host_cryptogram, method + " calculated host crypto: " + host_cryptogram.length);
+
+
+ if( isCryptoValidate) {
+ if (rcard_cryptogram == null) {
+ CMS.debug(method + " missing card cryptogram");
+ throw new Exception(method + "Missing card cryptogram");
+ }
+ input_card_crypto =
+ com.netscape.cmsutil.util.Utils.SpecialDecode(rcard_cryptogram);
+ card_crypto = protocol.computeCryptogram_SCP03(macSessionKey, selectedToken, contextStream.toByteArray(),NistSP800_108KDF.CARD_CRYPTO_KDF_CONSTANT);
+ SecureChannelProtocol.debugByteArray(card_crypto, method + " calculated card crypto: ");
+ SecureChannelProtocol.debugByteArray(input_card_crypto, method + " original card crypto: ");
+
+ if(!cryptoGramsAreEqual(input_card_crypto, card_crypto)) {
+ throw new Exception(method + "Card cryptogram mismatch!");
+ }
+
+ }
+ } catch (Exception e) {
+ CMS.debug(e);
+ CMS.debug("TokenServlet Computing Session Key: " + e.toString());
+ if (isCryptoValidate)
+ sameCardCrypto = false;
+ }
+ }
+ } // ! missingParam
+
+ String value = "";
+
+ resp.setContentType("text/html");
+
+ String encSessionKeyString = "";
+ String macSessionKeyString = "";
+ String kekSessionKeyString = "";
+
+ String drm_trans_wrapped_desKeyString = "";
+ String cryptogram = "";
+ String status = "0";
+
+ if (enc_session_key != null && enc_session_key.length > 0) {
+ encSessionKeyString =
+ com.netscape.cmsutil.util.Utils.SpecialEncode(enc_session_key);
+ } else {
+ status = "1";
+ }
+
+ if (mac_session_key != null && mac_session_key.length > 0) {
+ macSessionKeyString =
+ com.netscape.cmsutil.util.Utils.SpecialEncode(mac_session_key);
+ } else {
+ status = "1";
+ }
+
+ if (kek_session_key != null && kek_session_key.length > 0) {
+ kekSessionKeyString =
+ com.netscape.cmsutil.util.Utils.SpecialEncode(kek_session_key);
+ } else {
+ status = "1";
+ }
+
+ if (serversideKeygen == true) {
+ if (serverSideValues.size() == 3) {
+ drm_trans_wrapped_desKeyString = serverSideValues.get(2);
+ kek_wrapped_desKeyString = serverSideValues.get(0);
+ keycheck_s = serverSideValues.get(1);
+ }
+ else {
+ status = "1";
+ }
+ }
+ if (host_cryptogram != null && host_cryptogram.length > 0) {
+ cryptogram =
+ com.netscape.cmsutil.util.Utils.SpecialEncode(host_cryptogram);
+ } else {
+ if (status.equals("0") == true) {
+ status = "2";
+ }
+ }
+
+ if (selectedToken == null || keyNickName == null) {
+ // AC: Bugfix: Don't override status's value if an error was already flagged
+ if (status.equals("0") == true) {
+ status = "4";
+ }
}
+
+ if (!sameCardCrypto) {
+ if (status.equals("0") == true) {
+ status = "5";
+ }
+ }
+
+ if (missingSetting_exception != null) {
+ status = "6";
+ }
+
+ if (missingParam) {
+ status = "3";
+ }
+
+ if (!status.equals("0")) {
+
+ if (status.equals("1")) {
+ errorMsg = "Problem generating session key info.";
+ }
+
+ if (status.equals("2")) {
+ errorMsg = "Problem creating host_cryptogram.";
+ }
+
+ if (status.equals("5")) {
+ errorMsg = "Card cryptogram mismatch. Token likely has incorrect keys.";
+ }
+
+ if (status.equals("4")) {
+ errorMsg = "Problem obtaining token information.";
+ }
+
+ if (status.equals("6")) {
+ errorMsg = "Problem reading required configuration value.";
+ }
+
+ if (status.equals("3")) {
+ if (badParams.endsWith(",")) {
+ badParams = badParams.substring(0, badParams.length() - 1);
+ }
+ errorMsg = "Missing input parameters :" + badParams;
+ }
+
+ value = IRemoteRequest.RESPONSE_STATUS + "=" + status;
+ } else {
+ if (serversideKeygen == true) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(IRemoteRequest.RESPONSE_STATUS + "=0&");
+ sb.append(IRemoteRequest.TKS_RESPONSE_MacSessionKey + "=");
+ sb.append(macSessionKeyString);
+ sb.append("&" + IRemoteRequest.TKS_RESPONSE_HostCryptogram + "=");
+ sb.append(cryptogram);
+ sb.append("&" + IRemoteRequest.TKS_RESPONSE_EncSessionKey + "=");
+ sb.append(encSessionKeyString);
+ sb.append("&" + IRemoteRequest.TKS_RESPONSE_KekSessionKey + "=");
+ sb.append(kekSessionKeyString);
+ sb.append("&" + IRemoteRequest.TKS_RESPONSE_KEK_DesKey + "=");
+ sb.append(kek_wrapped_desKeyString);
+ sb.append("&" + IRemoteRequest.TKS_RESPONSE_KeyCheck + "=");
+ sb.append(keycheck_s);
+ sb.append("&" + IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey + "=");
+ sb.append(drm_trans_wrapped_desKeyString);
+ value = sb.toString();
+ } else {
+ StringBuffer sb = new StringBuffer();
+ sb.append(IRemoteRequest.RESPONSE_STATUS + "=0&");
+ sb.append(IRemoteRequest.TKS_RESPONSE_MacSessionKey + "=");
+ sb.append(macSessionKeyString);
+ sb.append("&" + IRemoteRequest.TKS_RESPONSE_HostCryptogram + "=");
+ sb.append(cryptogram);
+ sb.append("&" + IRemoteRequest.TKS_RESPONSE_EncSessionKey + "=");
+ sb.append(encSessionKeyString);
+ sb.append("&" + IRemoteRequest.TKS_RESPONSE_KekSessionKey + "=");
+ value = sb.toString();
+ }
+
+ }
+ //CMS.debug(method + "outputString.encode " + value);
+
+ try {
+ resp.setContentLength(value.length());
+ CMS.debug("TokenServlet:outputString.length " + value.length());
+ OutputStream ooss = resp.getOutputStream();
+ ooss.write(value.getBytes());
+ ooss.flush();
+ mRenderResult = false;
+ } catch (IOException e) {
+ CMS.debug("TokenServlet: " + e.toString());
+ }
+
+ if (status.equals("0")) {
+ String[] logParams = { log_string_from_specialDecoded_byte_array(xCUID), // CUID_decoded
+ log_string_from_specialDecoded_byte_array(xKDD), // KDD_decoded
+ ILogger.SUCCESS, // Outcome
+ status, // status
+ agentId, // AgentID
+ isCryptoValidate ? "true" : "false", // IsCryptoValidate
+ serversideKeygen ? "true" : "false", // IsServerSideKeygen
+ selectedToken, // SelectedToken
+ keyNickName, // KeyNickName
+ keySet, // TKSKeyset
+ log_string_from_keyInfo(xkeyInfo), // KeyInfo_KeyVersion
+ };
+ auditMessage = CMS.getLogMessage(LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS,
+ logParams);
+
+ } else {
+ String[] logParams = { log_string_from_specialDecoded_byte_array(xCUID), // CUID_decoded
+ log_string_from_specialDecoded_byte_array(xKDD), // KDD_decoded
+ ILogger.FAILURE, // Outcome
+ status, // status
+ agentId, // AgentID
+ isCryptoValidate ? "true" : "false", // IsCryptoValidate
+ serversideKeygen ? "true" : "false", // IsServerSideKeygen
+ selectedToken, // SelectedToken
+ keyNickName, // KeyNickName
+ keySet, // TKSKeyset
+ log_string_from_keyInfo(xkeyInfo), // KeyInfo_KeyVersion
+ errorMsg // Error
+ };
+ auditMessage = CMS.getLogMessage(LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE,
+ logParams);
+
+ }
+
+ audit(auditMessage);
+
}
/**
@@ -2479,4 +3042,197 @@ public class TokenServlet extends CMSServlet {
}
+ //returns ArrayList of following values
+ // 0 : Kek wrapped des key
+ // 1 : keycheck value
+ // 2 : trans wrapped des key
+ private ArrayList<String> calculateServerSideKeygenValues(String useSoftToken, String selectedToken,
+ SymmetricKey kekSessionKey, SecureChannelProtocol protocol) throws EBaseException {
+
+ SymmetricKey desKey = null;
+ String method = "TokenServlet.calculateSErverSideKeygenValues: ";
+ ArrayList<String> values = new ArrayList<String>();
+
+ /**
+ * 0. generate des key
+ * 1. encrypt des key with kek key
+ * 2. encrypt des key with DRM transport key
+ * These two wrapped items are to be sent back to
+ * TPS. 2nd item is to DRM
+ **/
+ CMS.debug(method + " entering...");
+
+ // (1) generate DES key
+ /* applet does not support DES3
+ org.mozilla.jss.crypto.KeyGenerator kg =
+ internalToken.getKeyGenerator(KeyGenAlgorithm.DES3);
+ desKey = kg.generate();*/
+
+ /*
+ * GenerateSymkey firt generates a 16 byte DES2 key.
+ * It then pads it into a 24 byte key with last
+ * 8 bytes copied from the 1st 8 bytes. Effectively
+ * making it a 24 byte DES2 key. We need this for
+ * wrapping private keys on DRM.
+ */
+ /*generate it on whichever token the master key is at*/
+
+ if (useSoftToken.equals("true")) {
+ CMS.debug(method + " key encryption key generated on internal");
+ desKey = protocol.generateSymKey("internal");
+ //cfu audit here? sym key gen done
+ } else {
+ CMS.debug("TokenServlet: key encryption key generated on " + selectedToken);
+ desKey = protocol.generateSymKey(selectedToken);
+ }
+ if (desKey == null) {
+ throw new EBaseException(method + "can't generate key encryption key");
+ }
+
+ /*
+ * ECBencrypt actually takes the 24 byte DES2 key
+ * and discard the last 8 bytes before it encrypts.
+ * This is done so that the applet can digest it
+ */
+
+
+ // protocol.wrapSessionKey(tokenName, sessionKey, wrappingKey)
+
+ byte[] encDesKey = protocol.ecbEncrypt(kekSessionKey, desKey, selectedToken);
+
+ String kek_wrapped_desKeyString =
+ com.netscape.cmsutil.util.Utils.SpecialEncode(encDesKey);
+
+ CMS.debug(method + "kek_wrapped_desKeyString: " + kek_wrapped_desKeyString);
+
+ values.add(kek_wrapped_desKeyString);
+
+ // get keycheck
+
+ byte[] keycheck = null;
+
+ keycheck = protocol.computeKeyCheck(desKey, selectedToken);
+
+ String keycheck_s =
+ com.netscape.cmsutil.util.Utils.SpecialEncode(keycheck);
+
+ CMS.debug(method + "keycheck_s " + keycheck_s);
+
+ values.add(keycheck_s);
+
+ //use DRM transport cert to wrap desKey
+ String drmTransNickname = CMS.getConfigStore().getString("tks.drm_transport_cert_nickname", "");
+
+ if ((drmTransNickname == null) || (drmTransNickname == "")) {
+ CMS.debug(method + " did not find DRM transport certificate nickname");
+ throw new EBaseException(method + "can't find DRM transport certificate nickname");
+ } else {
+ CMS.debug(method + " drmtransport_cert_nickname=" + drmTransNickname);
+ }
+
+ X509Certificate drmTransCert = null;
+ try {
+
+ drmTransCert = CryptoManager.getInstance().findCertByNickname(drmTransNickname);
+ // wrap kek session key with DRM transport public key
+ CryptoToken token = null;
+ if (useSoftToken.equals("true")) {
+ //token = CryptoManager.getInstance().getTokenByName(selectedToken);
+ token = CryptoManager.getInstance().getInternalCryptoToken();
+ } else {
+ token = CryptoManager.getInstance().getTokenByName(selectedToken);
+ }
+ PublicKey pubKey = drmTransCert.getPublicKey();
+ String pubKeyAlgo = pubKey.getAlgorithm();
+ CMS.debug("Transport Cert Key Algorithm: " + pubKeyAlgo);
+ KeyWrapper keyWrapper = null;
+ //For wrapping symmetric keys don't need IV, use ECB
+ if (pubKeyAlgo.equals("EC")) {
+ keyWrapper = token.getKeyWrapper(KeyWrapAlgorithm.AES_ECB);
+ keyWrapper.initWrap(pubKey, null);
+ } else {
+ keyWrapper = token.getKeyWrapper(KeyWrapAlgorithm.RSA);
+ keyWrapper.initWrap(pubKey, null);
+ }
+ CMS.debug("desKey token " + desKey.getOwningToken().getName() + " token: " + token.getName());
+ byte[] drm_trans_wrapped_desKey = keyWrapper.wrap(desKey);
+
+ String drmWrappedDesStr =
+ com.netscape.cmsutil.util.Utils.SpecialEncode(drm_trans_wrapped_desKey);
+
+ CMS.debug(method + " drmWrappedDesStr: " + drmWrappedDesStr);
+ values.add(drmWrappedDesStr);
+
+ } catch (Exception e) {
+ throw new EBaseException(e);
+ }
+
+ return values;
+ }
+
+ private boolean cryptoGramsAreEqual(byte[] original_cryptogram, byte[] calculated_cryptogram) {
+ boolean sameCardCrypto = true;
+
+ if (original_cryptogram == null || calculated_cryptogram == null) {
+ return false;
+ }
+ if (original_cryptogram.length == calculated_cryptogram.length) {
+ for (int i = 0; i < original_cryptogram.length; i++) {
+ if (original_cryptogram[i] != calculated_cryptogram[i]) {
+ sameCardCrypto = false;
+ break;
+ }
+ }
+ } else {
+ // different length; must be different
+ sameCardCrypto = false;
+ }
+
+ return sameCardCrypto;
+ }
+
+ //For now only used for scp03
+
+ static GPParams readGPSettings(String keySet) {
+ GPParams params = new GPParams();
+
+ String method = "TokenServlet.readGPSettings: ";
+ String gp3Settings = "tks." + keySet + ".prot3";
+
+ String divers = "emv";
+ try {
+ divers = CMS.getConfigStore().getString(gp3Settings + ".divers", "emv");
+ } catch (EBaseException e) {
+ }
+
+ params.setDiversificationScheme(divers);
+
+ CMS.debug(method + " Divers: " + divers);
+
+ String diversVer1Keys = "emv";
+
+ try {
+ diversVer1Keys = CMS.getConfigStore().getString(gp3Settings + ".diversVer1Keys","emv");
+ } catch (EBaseException e) {
+ }
+
+ params.setVersion1DiversificationScheme(diversVer1Keys);
+ CMS.debug(method + " Version 1 keys Divers: " + divers);
+
+ return params;
+ }
+
+ private byte[] getDeveKeyArray(String keyType,IConfigStore sconfig,String keySet) throws EBaseException {
+ byte devKeyArray[] = null;
+ try {
+ devKeyArray = com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks."
+ + keySet + "." + keyType));
+ } catch (Exception e) {
+ throw new EBaseException("Can't read static developer key array: " + keySet + ": " + keyType);
+ }
+
+ return devKeyArray;
+ }
+
+
}
diff --git a/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java b/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java
index 233124968..82482d09c 100644
--- a/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java
+++ b/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java
@@ -53,6 +53,8 @@ public interface IRemoteRequest {
/* computeSessionKey responses */
public static final String TKS_RESPONSE_SessionKey = "sessionKey";
public static final String TKS_RESPONSE_EncSessionKey = "encSessionKey";
+ public static final String TKS_RESPONSE_MacSessionKey = "macSessionKey";
+ public static final String TKS_RESPONSE_KekSessionKey = "kekSessionKey";
public static final String TKS_RESPONSE_KEK_DesKey = "kek_wrapped_desKey";
public static final String TKS_RESPONSE_DRM_Trans_DesKey = "drm_trans_desKey";
public static final String TKS_RESPONSE_KeyCheck = "keycheck";
diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRecord.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRecord.java
index 90050132b..6e594f849 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRecord.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRecord.java
@@ -18,15 +18,23 @@
package com.netscape.cmscore.dbs;
import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
+import org.apache.commons.codec.binary.Base64;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+
import com.netscape.certsrv.base.EBaseException;
import com.netscape.certsrv.base.MetaInfo;
import com.netscape.certsrv.dbs.IDBObj;
import com.netscape.certsrv.dbs.keydb.IKeyRecord;
import com.netscape.certsrv.dbs.keydb.KeyState;
+import com.netscape.certsrv.security.WrappingParams;
+import com.netscape.cms.servlet.key.KeyRecordParser;
/**
* A class represents a Key record. It maintains the key
@@ -397,4 +405,101 @@ public class KeyRecord implements IDBObj, IKeyRecord {
public String getRealm() throws EBaseException {
return realm;
}
+
+ public void setWrappingParams(WrappingParams params) throws Exception {
+ if (mMetaInfo == null) {
+ mMetaInfo = new MetaInfo();
+ }
+ // set session key parameters
+ mMetaInfo.set(KeyRecordParser.OUT_SK_LENGTH, String.valueOf(params.getSkLength()));
+ if (params.getSkType() != null) {
+ mMetaInfo.set(KeyRecordParser.OUT_SK_TYPE, params.getSkType().toString());
+ }
+ if (params.getSkKeyGenAlgorithm() != null) {
+ // JSS doesn't have a name map or a functional OID map
+ // for now, save the "name"
+ mMetaInfo.set(KeyRecordParser.OUT_SK_KEYGEN_ALGORITHM, params.getSkKeyGenAlgorithm().toString());
+ }
+ if (params.getSkWrapAlgorithm() != null) {
+ mMetaInfo.set(KeyRecordParser.OUT_SK_WRAP_ALGORITHM, params.getSkWrapAlgorithm().toString());
+ }
+
+ // set payload parameters
+ if (params.getPayloadEncryptionAlgorithm() != null) {
+ EncryptionAlgorithm encrypt = params.getPayloadEncryptionAlgorithm();
+ try {
+ OBJECT_IDENTIFIER oid = encrypt.toOID();
+ mMetaInfo.set(KeyRecordParser.OUT_PL_ENCRYPTION_OID, oid.toDottedString());
+ } catch (NoSuchAlgorithmException e) {
+ // oid not defined in JSS
+ mMetaInfo.set(KeyRecordParser.OUT_PL_ENCRYPTION_ALGORITHM, encrypt.getAlg().toString());
+ mMetaInfo.set(KeyRecordParser.OUT_PL_ENCRYPTION_MODE, encrypt.getMode().toString());
+ mMetaInfo.set(KeyRecordParser.OUT_PL_ENCRYPTION_PADDING, encrypt.getPadding().toString());
+ }
+ }
+ if (params.getPayloadWrapAlgorithm() != null) {
+ mMetaInfo.set(KeyRecordParser.OUT_PL_WRAP_ALGORITHM, params.getPayloadWrapAlgorithm().toString());
+ }
+ if (params.getPayloadWrappingIV() != null) {
+ // store as base64 encoded string
+ mMetaInfo.set(
+ KeyRecordParser.OUT_PL_WRAP_IV,
+ Base64.encodeBase64String(params.getPayloadWrappingIV().getIV())
+ );
+ }
+ if (params.getPayloadEncryptionIV() != null) {
+ // store as base 64 encoded string
+ mMetaInfo.set(
+ KeyRecordParser.OUT_PL_ENCRYPTION_IV,
+ Base64.encodeBase64String(params.getPayloadEncryptionIV().getIV())
+ );
+ }
+
+ }
+
+ public WrappingParams getWrappingParams(WrappingParams oldParams) throws Exception {
+ if ((mMetaInfo == null) || (mMetaInfo.get(KeyRecordParser.OUT_SK_TYPE) == null)) {
+ // This is likely a legacy record. Return the old DES3 parameters.
+ // TODO(alee) modify to pass this in - to keep bean-ness
+ return oldParams;
+ }
+
+ WrappingParams params = new WrappingParams();
+ params.setSkType(mMetaInfo.get(KeyRecordParser.OUT_SK_TYPE).toString());
+ params.setSkLength(Integer.parseInt(mMetaInfo.get(KeyRecordParser.OUT_SK_LENGTH).toString()));
+
+ Object data = mMetaInfo.get(KeyRecordParser.OUT_SK_WRAP_ALGORITHM);
+ if (data != null) params.setSkWrapAlgorithm(data.toString());
+
+ data = mMetaInfo.get(KeyRecordParser.OUT_SK_KEYGEN_ALGORITHM);
+ if (data != null) params.setSkKeyGenAlgorithm(data.toString());
+
+ data = mMetaInfo.get(KeyRecordParser.OUT_PL_WRAP_ALGORITHM);
+ if (data != null) params.setPayloadWrapAlgorithm(data.toString());
+
+ if (mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_OID) != null) {
+ String oidString = mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_OID).toString();
+ params.setPayloadEncryptionAlgorithm(EncryptionAlgorithm.fromOID(new OBJECT_IDENTIFIER(oidString)));
+ } else {
+ params.setPayloadEncryptionAlgorithm(
+ mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_ALGORITHM).toString(),
+ mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_MODE).toString(),
+ mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_PADDING).toString(),
+ Integer.parseInt(mMetaInfo.get(KeyRecordParser.OUT_SK_LENGTH).toString()));
+ }
+
+ data = mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_IV);
+ if (data != null) {
+ byte[] iv = Base64.decodeBase64(data.toString());
+ params.setPayloadEncryptionIV(new IVParameterSpec(iv));
+ }
+
+ data = mMetaInfo.get(KeyRecordParser.OUT_PL_WRAP_IV);
+ if (data != null) {
+ byte[] iv = Base64.decodeBase64(data.toString());
+ params.setPayloadWrappingIV(new IVParameterSpec(iv));
+ }
+
+ return params;
+ }
}
diff --git a/base/server/man/man5/pki_default.cfg.5 b/base/server/man/man5/pki_default.cfg.5
index 1eb4ab99b..856081dcf 100644
--- a/base/server/man/man5/pki_default.cfg.5
+++ b/base/server/man/man5/pki_default.cfg.5
@@ -107,7 +107,7 @@ If an optional hardware security module (HSM) is being utilized (rather than the
.SS SYSTEM CERTIFICATE PARAMETERS
\fBpkispawn\fP sets up a number of system certificates for each subsystem. The system certificates which are required differ between subsystems. Each system certificate is denoted by a tag, as noted below. The different system certificates are:
.IP
-* signing certificate ("signing"). Used to sign other certificates. Required for CA.
+* signing certificate ("ca_signing"). Used to sign other certificates. Required for CA.
.IP
* OCSP signing certificate ("ocsp_signing" in CA, "signing" in OCSP). Used to sign CRLs. Required for OCSP and CA.
.IP
diff --git a/base/server/man/man8/pkispawn.8 b/base/server/man/man8/pkispawn.8
index 40ec7f0ad..002520a0b 100644
--- a/base/server/man/man8/pkispawn.8
+++ b/base/server/man/man8/pkispawn.8
@@ -1387,7 +1387,7 @@ Directory Server and Admin Server instances can be created with the following
command:
.IP
-\fBsetup-ds-admin.pl\fP
+\fBsetup-ds.pl\fP
.PP
Enable LDAPS in the Directory Server with the following command:
diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py
index d556312a7..70734c3db 100644
--- a/base/server/python/pki/server/__init__.py
+++ b/base/server/python/pki/server/__init__.py
@@ -568,19 +568,7 @@ class PKIInstance(object):
# load passwords
self.passwords.clear()
if os.path.exists(self.password_conf):
-
- lines = open(self.password_conf).read().splitlines()
-
- for index, line in enumerate(lines):
- if not line or line.startswith('#'):
- continue
- parts = line.split('=', 1)
- if len(parts) < 2:
- raise Exception('Missing delimiter in %s line %d' %
- (self.password_conf, index + 1))
- name = parts[0]
- value = parts[1]
- self.passwords[name] = value
+ pki.util.load_properties(self.password_conf, self.passwords)
self.load_external_certs(self.external_certs_conf)