diff options
| author | Ade Lee <alee@redhat.com> | 2017-03-15 23:05:07 -0400 |
|---|---|---|
| committer | Ade Lee <alee@redhat.com> | 2017-03-15 23:05:07 -0400 |
| commit | 080f3d2a8bf36be407c79ddd71381450c8667b2e (patch) | |
| tree | 58594f9c45e88c882579d9f6638ff6639e506729 /base/server | |
| parent | 764a17314e81cade8bf1192739b5a2fad11d18bd (diff) | |
| parent | 07135b5906f97a8c68148a07484e63d6896f410b (diff) | |
| download | pki-080f3d2a8bf36be407c79ddd71381450c8667b2e.tar.gz pki-080f3d2a8bf36be407c79ddd71381450c8667b2e.tar.xz pki-080f3d2a8bf36be407c79ddd71381450c8667b2e.zip | |
Merge branch 'master' of github.com:dogtagpki/pki
Diffstat (limited to 'base/server')
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) |
