summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorChristina Fu <cfu@redhat.com>2014-12-02 14:38:08 -0800
committerChristina Fu <cfu@redhat.com>2014-12-19 11:17:34 -0800
commit4c910296a6c6c8bf74fbdace740680db2f1fecab (patch)
tree1d0d53e8f72c7f219830d387f228003074faf98a /base
parent00b1c33272900613687448ccab7809ba794679f6 (diff)
downloadpki-4c910296a6c6c8bf74fbdace740680db2f1fecab.tar.gz
pki-4c910296a6c6c8bf74fbdace740680db2f1fecab.tar.xz
pki-4c910296a6c6c8bf74fbdace740680db2f1fecab.zip
Ticket #864 866 (part 1 symkey, common) NIST SP800-108 KDF
- this patch does not include TPS side of changes: (#865 needs to be rewritten in Java)
Diffstat (limited to 'base')
-rw-r--r--base/server/cms/src/com/netscape/cms/selftests/tks/TKSKnownSessionKey.java59
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java3
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/tks/TokenServlet.java665
-rw-r--r--base/server/cmsbundle/src/LogMessages.properties80
-rw-r--r--base/symkey/src/com/netscape/symkey/CMakeLists.txt2
-rw-r--r--base/symkey/src/com/netscape/symkey/EncryptData.cpp140
-rw-r--r--base/symkey/src/com/netscape/symkey/NistSP800_108KDF.cpp470
-rw-r--r--base/symkey/src/com/netscape/symkey/NistSP800_108KDF.h115
-rw-r--r--base/symkey/src/com/netscape/symkey/SessionKey.cpp580
-rw-r--r--base/symkey/src/com/netscape/symkey/SessionKey.java25
-rw-r--r--base/symkey/src/com/netscape/symkey/SymKey.cpp424
-rw-r--r--base/tks/shared/conf/CS.cfg.in6
12 files changed, 2343 insertions, 226 deletions
diff --git a/base/server/cms/src/com/netscape/cms/selftests/tks/TKSKnownSessionKey.java b/base/server/cms/src/com/netscape/cms/selftests/tks/TKSKnownSessionKey.java
index 06a6398c5..d5e7c11ad 100644
--- a/base/server/cms/src/com/netscape/cms/selftests/tks/TKSKnownSessionKey.java
+++ b/base/server/cms/src/com/netscape/cms/selftests/tks/TKSKnownSessionKey.java
@@ -67,6 +67,9 @@ public class TKSKnownSessionKey
private byte[] mCUID = null;
private byte[] mMacKey = null;
private byte[] mSessionKey = null;
+ private byte mNistSP800_108KdfOnKeyVersion = 0; // AC: KDF SPEC CHANGE
+ private boolean mNistSP800_108KdfUseCuidAsKdd = false; // AC: KDF SPEC CHANGE
+ private byte[] mKDD = null; // AC: KDF SPEC CHANGE
/**
* Initializes this subsystem with the configuration store
@@ -101,6 +104,46 @@ public class TKSKnownSessionKey
mMacKey = getConfigByteArray("macKey", 16);
mUseSoftToken = getConfigString("useSoftToken");
+ // AC: KDF SPEC CHANGE
+ // read CUID for the KDD field
+ mKDD = getConfigByteArray("CUID", 10);
+ //
+ //
+ // read self-test configuration item for nistSP800-108KdfOnKeyVersion
+ //
+ // read setting as string
+ String nistSP800_108KdfOnKeyVersion_str = getConfigString("nistSP800-108KdfOnKeyVersion");
+ short nistSP800_108KdfOnKeyVersion_short;
+ // convert setting value (in ASCII-hex) to short
+ try{
+ nistSP800_108KdfOnKeyVersion_short = Short.parseShort(nistSP800_108KdfOnKeyVersion_str,16);
+ if ((nistSP800_108KdfOnKeyVersion_short < 0) || (nistSP800_108KdfOnKeyVersion_short > (short)0x00FF)){
+ throw new Exception("Out of range.");
+ }
+ }catch(Throwable t){
+ mSelfTestSubsystem.log (mSelfTestSubsystem.getSelfTestLogger(),
+ CMS.getLogMessage("SELFTESTS_MISSING_VALUES",
+ getSelfTestName(), mPrefix + ".nistSP800-108KdfOnKeyVersion"));
+ throw new EMissingSelfTestException("nistSP800-108KdfOnKeyVersion");
+ }
+ // convert to byte (anything higher than 0x7F is represented as negative)
+ mNistSP800_108KdfOnKeyVersion = (byte)nistSP800_108KdfOnKeyVersion_short;
+ //
+ //
+ // read self-test configuration item for nistSP800-108KdfUseCuidAsKdd
+ //
+ // read setting as string
+ String nistSP800_108KdfUseCuidAsKdd_str = getConfigString("nistSP800-108KdfUseCuidAsKdd");
+ // convert setting value to boolean
+ try{
+ mNistSP800_108KdfUseCuidAsKdd = Boolean.parseBoolean(nistSP800_108KdfUseCuidAsKdd_str);
+ }catch(Throwable t){
+ mSelfTestSubsystem.log (mSelfTestSubsystem.getSelfTestLogger(),
+ CMS.getLogMessage("SELFTESTS_MISSING_VALUES",
+ getSelfTestName(), mPrefix + ".nistSP800-108KdfUseCuidAsKdd"));
+ throw new EMissingSelfTestException("nistSP800-108KdfUseCuidAsKdd");
+ }
+
String defKeySetMacKey = null;
tks = CMS.getSubsystem(mTksSubId);
if (tks != null) {
@@ -132,7 +175,12 @@ public class TKSKnownSessionKey
if (mSessionKey == null) {
mSessionKey = SessionKey.ComputeSessionKey(mToken, mKeyName,
mCardChallenge, mHostChallenge,
- mKeyInfo, mCUID, mMacKey, mUseSoftToken, null, null);
+ mKeyInfo,
+ mNistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE - pass in configuration self-test value
+ mNistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE - pass in configuration self-test value
+ mCUID,
+ mKDD, // AC: KDF SPEC CHANGE - pass in KDD
+ mMacKey, mUseSoftToken, null, null);
if (mSessionKey == null || mSessionKey.length != 16) {
mSelfTestSubsystem.log(mSelfTestSubsystem.getSelfTestLogger(),
CMS.getLogMessage("SELFTESTS_MISSING_VALUES",
@@ -314,8 +362,13 @@ public class TKSKnownSessionKey
String keySet = "defKeySet";
byte[] sessionKey = SessionKey.ComputeSessionKey(
- mToken, mKeyName, mCardChallenge, mHostChallenge, mKeyInfo,
- mCUID, mMacKey, mUseSoftToken, keySet, sharedSecretName);
+ mToken, mKeyName, mCardChallenge, mHostChallenge,
+ mKeyInfo,
+ mNistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE - pass in configuration self-test value
+ mNistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE - pass in configuration self-test value
+ mCUID,
+ mKDD, // AC: KDF SPEC CHANGE - pass in KDD
+ mMacKey, mUseSoftToken, keySet, sharedSecretName);
// Now we just see if we can successfully generate a session key.
// For FIPS compliance, the routine now returns a wrapped key, which can't be extracted and compared.
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 4a6503897..0b1c6f6e2 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
@@ -275,6 +275,8 @@ public class ConfigurationUtils {
HttpResponse httpresponse = httpclient.send(httprequest);
c = httpresponse.getContent();
+ //cfu
+
} catch (ConnectException e) {
CMS.debug("getHttpResponse: " + e.toString());
throw new IOException("The server you tried to contact is not running.");
@@ -4104,6 +4106,7 @@ public class ConfigurationUtils {
CMS.debug("registerUser: response is empty or null.");
throw new IOException("The server " + targetURI + "is not available");
} else {
+ CMS.debug("registerUser: response: " + response);
ByteArrayInputStream bis = new ByteArrayInputStream(response.getBytes());
XMLObject parser = new XMLObject(bis);
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 9b0c2bcf2..2cca81bcf 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
@@ -72,25 +72,25 @@ public class TokenServlet extends CMSServlet {
IPrettyPrintFormat pp = CMS.getPrettyPrintFormat(":");
private final static String LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST =
- "LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_3";
+ "LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_4"; // AC: KDF SPEC CHANGE: Need to log both KDD and CUID.
private final static String LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS =
- "LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS_8";
+ "LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS_13"; // AC: KDF SPEC CHANGE: Need to log both KDD and CUID. Also added TKSKeyset, KeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd.
private final static String LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE =
- "LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE_9";
+ "LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE_14"; // AC: KDF SPEC CHANGE: Need to log both KDD and CUID. Also added TKSKeyset, KeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd.
private final static String LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST =
- "LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_5";
+ "LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_6"; // AC: KDF SPEC CHANGE: Need to log both KDD and CUID.
private final static String LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS =
- "LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS_6";
+ "LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS_12"; // AC: KDF SPEC CHANGE: Need to log both KDD and CUID. Also added TKSKeyset, OldKeyInfo_KeyVersion, NewKeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd.
private final static String LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE =
- "LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE_7";
+ "LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE_13"; // AC: KDF SPEC CHANGE: Need to log both KDD and CUID. Also added TKSKeyset, OldKeyInfo_KeyVersion, NewKeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd.
private final static String LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST =
- "LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_4";
+ "LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_5"; // AC: KDF SPEC CHANGE: Need to log both KDD and CUID.
private final static String LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS =
"LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS_7";
@@ -216,9 +216,110 @@ public class TokenServlet extends CMSServlet {
}
+ // AC: KDF SPEC CHANGE - read new setting value from config file
+ // (This value allows configuration of which master keys use the NIST SP800-108 KDF and which use the original KDF for backwards compatibility)
+ // CAREFUL: Result returned may be negative due to java's lack of unsigned types.
+ // Negative values need to be treated as higher key numbers than positive key numbers.
+ private static byte read_setting_nistSP800_108KdfOnKeyVersion(String keySet) throws Exception{
+ String nistSP800_108KdfOnKeyVersion_map = "tks." + keySet + ".nistSP800-108KdfOnKeyVersion";
+ // KDF phase1: default to 00
+ String nistSP800_108KdfOnKeyVersion_value =
+ CMS.getConfigStore().getString(nistSP800_108KdfOnKeyVersion_map, "00" /*null*/);
+ short nistSP800_108KdfOnKeyVersion_short = 0;
+ // if value does not exist in file
+ if (nistSP800_108KdfOnKeyVersion_value == null){
+ // throw
+ // (we want admins to pay attention to this configuration item rather than guessing for them)
+ throw new Exception("Required configuration value \"" + nistSP800_108KdfOnKeyVersion_map + "\" missing from configuration file.");
+ }
+ // convert setting value (in ASCII-hex) to short
+ try{
+ nistSP800_108KdfOnKeyVersion_short = Short.parseShort(nistSP800_108KdfOnKeyVersion_value, 16);
+ if ((nistSP800_108KdfOnKeyVersion_short < 0) || (nistSP800_108KdfOnKeyVersion_short > (short)0x00FF)){
+ throw new Exception("Out of range.");
+ }
+ } catch(Throwable t){
+ throw new Exception("Configuration value \"" + nistSP800_108KdfOnKeyVersion_map + "\" is in incorrect format. " +
+ "Correct format is \"" + nistSP800_108KdfOnKeyVersion_map + "=xx\" where xx is key version specified in ASCII-HEX format.", t);
+ }
+ // convert to byte (anything higher than 0x7F is represented as a negative)
+ byte nistSP800_108KdfOnKeyVersion_byte = (byte)nistSP800_108KdfOnKeyVersion_short;
+ return nistSP800_108KdfOnKeyVersion_byte;
+ }
+
+ // AC: KDF SPEC CHANGE - read new setting value from config file
+ // (This value allows configuration of the NIST SP800-108 KDF:
+ // If "true" we use the CUID parameter within the NIST SP800-108 KDF.
+ // If "false" we use the KDD parameter within the NIST SP800-108 KDF.
+ private static boolean read_setting_nistSP800_108KdfUseCuidAsKdd(String keySet) throws Exception{
+ String setting_map = "tks." + keySet + ".nistSP800-108KdfUseCuidAsKdd";
+ // KDF phase1: default to "false"
+ String setting_str =
+ CMS.getConfigStore().getString(setting_map, "false" /*null*/);
+ boolean setting_boolean = false;
+ // if value does not exist in file
+ if (setting_str == null){
+ // throw
+ // (we want admins to pay attention to this configuration item rather than guessing for them)
+ throw new Exception("Required configuration value \"" + setting_map + "\" missing from configuration file.");
+ }
+ // convert setting value to boolean
+ try{
+ setting_boolean = Boolean.parseBoolean(setting_str);
+ }catch(Throwable t){
+ throw new Exception("Configuration value \"" + setting_map + "\" is in incorrect format. Should be either \"true\" or \"false\".", t);
+ }
+ return setting_boolean;
+ }
+
+ // AC: KDF SPEC CHANGE - Audit logging helper functions.
+ // Converts a byte array to an ASCII-hex string.
+ // We implemented this ourselves rather than using this.pp.toHexArray() because
+ // the team preferred CUID and KDD strings to be without ":" separators every byte.
+ final char[] bytesToHex_hexArray = "0123456789ABCDEF".toCharArray();
+ private String bytesToHex(byte[] bytes){
+ char[] hexChars = new char[bytes.length * 2];
+ for (int i = 0; i < bytes.length; i++){
+ int thisChar = bytes[i] & 0x000000FF;
+ hexChars[i * 2] = bytesToHex_hexArray[thisChar >>> 4]; // div 16
+ hexChars[i*2 + 1] = bytesToHex_hexArray[thisChar & 0x0F];
+ }
+ return new String(hexChars);
+ }
+
+ // AC: KDF SPEC CHANGE - Audit logging helper functions.
+ // Safely converts a keyInfo byte array to a Key version hex string in the format: 0xa
+ // Since key version is always the first byte, this function returns the unsigned hex string representation of parameter[0].
+ // Returns "null" if parameter is null.
+ // Returns "invalid" if parameter.length < 1
+ private String log_string_from_keyInfo(byte[] xkeyInfo){
+ return (xkeyInfo == null) ? "null" : (xkeyInfo.length < 1 ? "invalid" : "0x" + Integer.toHexString((int)(xkeyInfo[0]) & 0x000000FF) );
+ }
+
+ // AC: KDF SPEC CHANGE - Audit logging helper functions.
+ // Safely converts a byte array containing specialDecoded information to an ASCII-hex string.
+ // Parameters:
+ // specialDecoded - byte array containing data. May be null.
+ // Returns:
+ // if specialDecoded is blank, returns "null"
+ // if specialDecoded != null, returns <ASCII-HEX string representation of specialDecoded>
+ private String log_string_from_specialDecoded_byte_array(byte[] specialDecoded){
+ if (specialDecoded == null){
+ return "null";
+ }else{
+ return bytesToHex(specialDecoded);
+ }
+ }
+
+
private void processComputeSessionKey(HttpServletRequest req,
HttpServletResponse resp) throws EBaseException {
- byte[] card_challenge, host_challenge, keyInfo, xCUID, CUID, session_key;
+ byte[] card_challenge ,host_challenge,keyInfo, xCUID, session_key, xKDD; // AC: KDF SPEC CHANGE: removed duplicative 'CUID' variable and added xKDD
+
+ // AC: KDF SPEC CHANGE - new config file values (needed for symkey)
+ byte nistSP800_108KdfOnKeyVersion = (byte)0xff;
+ boolean nistSP800_108KdfUseCuidAsKdd = false;
+
byte[] card_crypto, host_cryptogram, input_card_crypto;
byte[] xcard_challenge, xhost_challenge;
byte[] enc_session_key, xkeyInfo;
@@ -228,6 +329,15 @@ public class TokenServlet extends CMSServlet {
String transportKeyName = "";
String rCUID = req.getParameter(IRemoteRequest.TOKEN_CUID);
+
+ // AC: KDF SPEC CHANGE - read new KDD parameter from TPS
+ 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";
@@ -243,6 +353,10 @@ public class TokenServlet extends CMSServlet {
IConfigStore sconfig = CMS.getConfigStore();
boolean isCryptoValidate = true;
boolean missingParam = false;
+
+ // AC: KDF SPEC CHANGE - flag for if there is an error reading our new setting
+ Exception missingSetting_exception = null;
+
session_key = null;
card_crypto = null;
host_cryptogram = null;
@@ -257,9 +371,11 @@ public class TokenServlet extends CMSServlet {
(String) sContext.get(SessionContext.USER_ID);
}
+ // AC: KDF SPEC CHANGE: Need to log both KDD and CUID
auditMessage = CMS.getLogMessage(
LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST,
rCUID,
+ rKDD, // AC: KDF SPEC CHANGE - Log both CUID and KDD.
ILogger.SUCCESS,
agentId);
@@ -299,6 +415,13 @@ public class TokenServlet extends CMSServlet {
badParams += " CUID,";
missingParam = true;
}
+
+ // AC: KDF SPEC CHANGE - read new KDD parameter from TPS
+ if ((rKDD == null) || (rKDD.length() == 0)) {
+ CMS.debug("TokenServlet: ComputeSessionKey(): missing request parameter: KDD");
+ badParams += " KDD,";
+ missingParam = true;
+ }
if ((rcard_challenge == null) || (rcard_challenge.equals(""))) {
badParams += " card_challenge,";
@@ -322,6 +445,11 @@ public class TokenServlet extends CMSServlet {
String keyNickName = null;
boolean sameCardCrypto = true;
+ // AC: KDF SPEC CHANGE
+ xCUID = null; // avoid errors about non-initialization
+ xKDD = null; // avoid errors about non-initialization
+ xkeyInfo = null; // avoid errors about non-initialization
+
if (!missingParam) {
xCUID = com.netscape.cmsutil.util.Utils.SpecialDecode(rCUID);
@@ -330,6 +458,15 @@ public class TokenServlet extends CMSServlet {
CMS.debug("TokenServlet: Invalid CUID length");
missingParam = true;
}
+
+ // AC: KDF SPEC CHANGE - read new KDD parameter from TPS
+ 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 != 2) {
badParams += " KeyInfo length,";
@@ -353,7 +490,9 @@ public class TokenServlet extends CMSServlet {
}
- CUID = null;
+ // AC: KDF SPEC CHANGE - Remove duplicative variable.
+ // CUID = null;
+
if (!missingParam) {
card_challenge =
com.netscape.cmsutil.util.Utils.SpecialDecode(rcard_challenge);
@@ -361,7 +500,33 @@ public class TokenServlet extends CMSServlet {
host_challenge = com.netscape.cmsutil.util.Utils.SpecialDecode(rhost_challenge);
keyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(rKeyInfo);
- CUID = com.netscape.cmsutil.util.Utils.SpecialDecode(rCUID);
+ // CUID = com.netscape.cmsutil.util.Utils.SpecialDecode(rCUID);
+ // AC: KDF SPEC CHANGE: Removed duplicative variable/processing.
+
+ // AC: KDF SPEC CHANGE - read new config file values (needed for symkey)
+ try{
+ nistSP800_108KdfOnKeyVersion = TokenServlet.read_setting_nistSP800_108KdfOnKeyVersion(keySet);
+ nistSP800_108KdfUseCuidAsKdd = TokenServlet.read_setting_nistSP800_108KdfUseCuidAsKdd(keySet);
+
+ // log settings read in to debug log along with xkeyInfo
+ CMS.debug("TokenServlet: ComputeSessionKey(): xkeyInfo[0] = 0x"
+ + Integer.toHexString((int)(xkeyInfo[0]) & 0x0000000FF)
+ + ", xkeyInfo[1] = 0x"
+ + Integer.toHexString((int)(xkeyInfo[1]) & 0x0000000FF)
+ );
+ CMS.debug("TokenServlet: ComputeSessionKey(): Nist SP800-108 KDF will be used for key versions >= 0x"
+ + Integer.toHexString((int)(nistSP800_108KdfOnKeyVersion) & 0x0000000FF)
+ );
+ if (nistSP800_108KdfUseCuidAsKdd == true){
+ CMS.debug("TokenServlet: ComputeSessionKey(): Nist SP800-108 KDF (if used) will use CUID instead of KDD.");
+ }else{
+ CMS.debug("TokenServlet: ComputeSessionKey(): Nist SP800-108 KDF (if used) will use KDD.");
+ }
+ // conform to the set-an-error-flag mentality
+ }catch(Exception e){
+ missingSetting_exception = e;
+ CMS.debug("TokenServlet: ComputeSessionKey(): Exception reading Nist SP800-108 KDF config values: " + e.toString());
+ }
String keyInfoMap = "tks." + keySet + ".mk_mappings." + rKeyInfo; //#xx#xx
String mappingValue = CMS.getConfigStore().getString(keyInfoMap, null);
@@ -377,7 +542,9 @@ public class TokenServlet extends CMSServlet {
keyNickName = st.nextToken();
}
- if (selectedToken != null && keyNickName != null) {
+ if (selectedToken != null && keyNickName != null
+ // AC: KDF SPEC CHANGE - check for error flag
+ && missingSetting_exception == null) {
try {
@@ -388,7 +555,12 @@ public class TokenServlet extends CMSServlet {
+ selectedToken + " keyNickName=" + keyNickName);
session_key = SessionKey.ComputeSessionKey(
selectedToken, keyNickName, card_challenge,
- host_challenge, keyInfo, CUID, macKeyArray, useSoftToken_s, keySet, transportKeyName);
+ host_challenge,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
+ macKeyArray, useSoftToken_s, keySet, transportKeyName );
if (session_key == null) {
CMS.debug("TokenServlet:Tried ComputeSessionKey, got NULL ");
@@ -401,7 +573,12 @@ public class TokenServlet extends CMSServlet {
+ keySet + ".auth_key"));
enc_session_key = SessionKey.ComputeEncSessionKey(
selectedToken, keyNickName, card_challenge,
- host_challenge, keyInfo, CUID, encKeyArray, useSoftToken_s, keySet);
+ host_challenge,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
+ encKeyArray, useSoftToken_s, keySet);
if (enc_session_key == null) {
CMS.debug("TokenServlet:Tried ComputeEncSessionKey, got NULL ");
@@ -426,7 +603,12 @@ public class TokenServlet extends CMSServlet {
kek_key = SessionKey.ComputeKekKey(
selectedToken, keyNickName, card_challenge,
- host_challenge, keyInfo, CUID, kekKeyArray, useSoftToken_s, keySet);
+ host_challenge,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);
CMS.debug("TokenServlet: called ComputeKekKey");
@@ -462,10 +644,19 @@ public class TokenServlet extends CMSServlet {
CMS.debug("TokenServlet: key encryption key generated on " + selectedToken);
desKey = SessionKey.GenerateSymkey(selectedToken);
}
- if (desKey != null)
- CMS.debug("TokenServlet: key encryption key generated for " + rCUID);
- else {
- CMS.debug("TokenServlet: key encryption key generation failed for " + rCUID);
+ if (desKey != null) {
+ // AC: KDF SPEC CHANGE - Output using CUID and KDD
+ CMS.debug("TokenServlet: key encryption key generated for CUID=" +
+ trim(pp.toHexString(xCUID)) +
+ ", KDD=" +
+ trim(pp.toHexString(xKDD)));
+ } else {
+ // AC: KDF SPEC CHANGE - Output using CUID and KDD
+ CMS.debug("TokenServlet: key encryption key generation failed for CUID=" +
+ trim(pp.toHexString(xCUID)) +
+ ", KDD=" +
+ trim(pp.toHexString(xKDD)));
+
throw new Exception("can't generate key encryption key");
}
@@ -538,7 +729,12 @@ public class TokenServlet extends CMSServlet {
+ keySet + ".auth_key"));
host_cryptogram = SessionKey.ComputeCryptogram(
selectedToken, keyNickName, card_challenge,
- host_challenge, keyInfo, CUID, 0, authKeyArray, useSoftToken_s, keySet);
+ host_challenge,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
+ 0, authKeyArray, useSoftToken_s, keySet);
if (host_cryptogram == null) {
CMS.debug("TokenServlet:Tried ComputeCryptogram, got NULL ");
@@ -547,7 +743,13 @@ public class TokenServlet extends CMSServlet {
}
card_crypto = SessionKey.ComputeCryptogram(
selectedToken, keyNickName, card_challenge,
- host_challenge, keyInfo, CUID, 1, authKeyArray, useSoftToken_s, keySet);
+ host_challenge,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
+ 1, authKeyArray, useSoftToken_s, keySet);
+
if (card_crypto == null) {
CMS.debug("TokenServlet:Tried ComputeCryptogram, got NULL ");
@@ -575,10 +777,13 @@ public class TokenServlet extends CMSServlet {
}
}
+ // AC: KDF SPEC CHANGE - print both KDD and CUID
CMS.getLogger().log(ILogger.EV_AUDIT,
ILogger.S_TKS,
ILogger.LL_INFO, "processComputeSessionKey for CUID=" +
- trim(pp.toHexString(CUID)));
+ trim(pp.toHexString(xCUID)) +
+ ", KDD=" +
+ trim(pp.toHexString(xKDD)));
} catch (Exception e) {
CMS.debug(e);
CMS.debug("TokenServlet Computing Session Key: " + e.toString());
@@ -625,18 +830,35 @@ public class TokenServlet extends CMSServlet {
cryptogram =
com.netscape.cmsutil.util.Utils.SpecialEncode(host_cryptogram);
} else {
- status = "2";
+ // AC: Bugfix: Don't override status's value if an error was already flagged
+ if (status.equals("0") == true){
+ status = "2";
+ }
}
if (selectedToken == null || keyNickName == null) {
- status = "4";
+ // AC: Bugfix: Don't override status's value if an error was already flagged
+ if (status.equals("0") == true){
+ status = "4";
+ }
}
if (!sameCardCrypto) {
- status = "3";
+ // AC: Bugfix: Don't override status's value if an error was already flagged
+ if (status.equals("0") == true){
+ // AC: Bugfix: Don't mis-represent host cryptogram mismatch errors as TPS parameter issues
+ status = "5";
+ }
}
+ // AC: KDF SPEC CHANGE - check for settings file issue (flag)
+ if (missingSetting_exception != null){
+ // AC: Intentionally override previous errors if config file settings were missing.
+ status = "6";
+ }
+
if (missingParam) {
+ // AC: Intentionally override previous errors if parameters were missing.
status = "3";
}
@@ -650,10 +872,20 @@ public class TokenServlet extends CMSServlet {
errorMsg = "Problem creating host_cryptogram.";
}
+ // AC: Bugfix: Don't mis-represent card cryptogram mismatch errors as TPS parameter issues
+ if (status.equals("5")) {
+ errorMsg = "Card cryptogram mismatch. Token likely has incorrect keys.";
+ }
+
if (status.equals("4")) {
errorMsg = "Problem obtaining token information.";
}
+ // AC: KDF SPEC CHANGE - handle missing configuration item
+ if (status.equals("6")) {
+ errorMsg = "Problem reading required configuration value.";
+ }
+
if (status.equals("3")) {
if (badParams.endsWith(",")) {
badParams = badParams.substring(0, badParams.length() - 1);
@@ -706,31 +938,45 @@ public class TokenServlet extends CMSServlet {
}
if (status.equals("0")) {
-
- auditMessage = CMS.getLogMessage(
- LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS,
- rCUID,
- ILogger.SUCCESS,
- status,
- agentId,
- isCryptoValidate ? "true" : "false",
- serversideKeygen ? "true" : "false",
- selectedToken,
- keyNickName);
-
+ // AC: KDF SPEC CHANGE - Log both CUID and KDD.
+ // Also added TKSKeyset, KeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+ // Finally, log CUID and KDD in ASCII-HEX format, as long as special-decoded version is available.
+ 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
+ "0x" + Integer.toHexString((int)nistSP800_108KdfOnKeyVersion & 0x000000FF), // NistSP800_108KdfOnKeyVersion
+ Boolean.toString(nistSP800_108KdfUseCuidAsKdd) // NistSP800_108KdfUseCuidAsKdd
+ };
+ auditMessage = CMS.getLogMessage(LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS, logParams);
} else {
+ // AC: KDF SPEC CHANGE - Log both CUID and KDD
+ // Also added TKSKeyset, KeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+ // Finally, log CUID and KDD in ASCII-HEX format, as long as special-decoded version is available.
+ 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
+ "0x" + Integer.toHexString((int)nistSP800_108KdfOnKeyVersion & 0x000000FF), // NistSP800_108KdfOnKeyVersion
+ Boolean.toString(nistSP800_108KdfUseCuidAsKdd), // NistSP800_108KdfUseCuidAsKdd
+ errorMsg // Error
+ };
+ auditMessage = CMS.getLogMessage(LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE, logParams);
- auditMessage = CMS.getLogMessage(
- LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE,
- rCUID,
- ILogger.FAILURE,
- status,
- agentId,
- isCryptoValidate ? "true" : "false",
- serversideKeygen ? "true" : "false",
- selectedToken,
- keyNickName,
- errorMsg);
}
audit(auditMessage);
@@ -768,8 +1014,22 @@ public class TokenServlet extends CMSServlet {
private void processDiversifyKey(HttpServletRequest req,
HttpServletResponse resp) throws EBaseException {
- byte[] KeySetData, CUID, xCUID;
- byte[] xkeyInfo, xnewkeyInfo;
+ byte[] KeySetData,KeysValues,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.
+ String oldKeyNickName = null;
+ String newKeyNickName = null;
+
+ // AC: KDF SPEC CHANGE - new config file values (needed for symkey)
+ byte nistSP800_108KdfOnKeyVersion = (byte)0xff;
+ boolean nistSP800_108KdfUseCuidAsKdd = false;
+
+ // AC: BUGFIX for key versions higher than 09: We need to initialize these variables in order for the compiler not to complain when we pass them to DiversifyKey.
+ byte[] xkeyInfo = null,xnewkeyInfo = null;
+
+ // AC: KDF SPEC CHANGE - flag for if there is an error reading our new setting
+ Exception missingSetting_exception = null;
+
boolean missingParam = false;
String errorMsg = "";
String badParams = "";
@@ -779,6 +1039,15 @@ public class TokenServlet extends CMSServlet {
String newMasterKeyName = req.getParameter(IRemoteRequest.TOKEN_NEW_KEYINFO);
String oldMasterKeyName = req.getParameter(IRemoteRequest.TOKEN_KEYINFO);
String rCUID = req.getParameter(IRemoteRequest.TOKEN_CUID);
+
+ // AC: KDF SPEC CHANGE - read new KDD parameter from TPS
+ String rKDD = req.getParameter("KDD");
+ if ((rKDD == null) || (rKDD.length() == 0)) {
+ // temporarily make it friendly before TPS change
+ CMS.debug("TokenServlet: KDD not supplied, set to CUID before TPS change");
+ rKDD = rCUID;
+ }
+
String auditMessage = "";
String keySet = req.getParameter(IRemoteRequest.TOKEN_KEYSET);
@@ -795,9 +1064,11 @@ public class TokenServlet extends CMSServlet {
(String) sContext.get(SessionContext.USER_ID);
}
+ // AC: KDF SPEC CHANGE: Need to log both KDD and CUID
auditMessage = CMS.getLogMessage(
LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST,
rCUID,
+ rKDD, // AC: KDF SPEC CHANGE - Log both CUID and KDD.
ILogger.SUCCESS,
agentId,
oldMasterKeyName,
@@ -810,6 +1081,14 @@ public class TokenServlet extends CMSServlet {
CMS.debug("TokenServlet: processDiversifyKey(): missing request parameter: CUID");
missingParam = true;
}
+
+ // AC: KDF SPEC CHANGE - read new KDD parameter from TPS
+ if ((rKDD == null) || (rKDD.length() == 0)) {
+ CMS.debug("TokenServlet: processDiversifyKey(): missing request parameter: KDD");
+ badParams += " KDD,";
+ missingParam = true;
+ }
+
if ((rnewKeyInfo == null) || (rnewKeyInfo.equals(""))) {
badParams += " newKeyInfo,";
CMS.debug("TokenServlet: processDiversifyKey(): missing request parameter: newKeyInfo");
@@ -821,6 +1100,12 @@ public class TokenServlet extends CMSServlet {
missingParam = true;
}
+ // AC: KDF SPEC CHANGE
+ xCUID = null; // avoid errors about non-initialization
+ xKDD = null; // avoid errors about non-initialization
+ xkeyInfo = null; // avoid errors about non-initialization
+ xnewkeyInfo = null; // avoid errors about non-initialization
+
if (!missingParam) {
xkeyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(oldMasterKeyName);
if (xkeyInfo == null || xkeyInfo.length != 2) {
@@ -847,9 +1132,46 @@ public class TokenServlet extends CMSServlet {
CMS.debug("TokenServlet: Invalid CUID length");
missingParam = true;
}
+
+ // AC: KDF SPEC CHANGE - read new KDD parameter from TPS
+ 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;
+ }
}
if (!missingParam) {
- CUID = com.netscape.cmsutil.util.Utils.SpecialDecode(rCUID);
+ // CUID = com.netscape.cmsutil.util.Utils.SpecialDecode(rCUID); // AC: KDF SPEC CHANGE: Removed duplicative variable/processing.
+
+ // AC: KDF SPEC CHANGE - read new config file values (needed for symkey)
+ try{
+ nistSP800_108KdfOnKeyVersion = TokenServlet.read_setting_nistSP800_108KdfOnKeyVersion(keySet);
+ nistSP800_108KdfUseCuidAsKdd = TokenServlet.read_setting_nistSP800_108KdfUseCuidAsKdd(keySet);
+
+ // log settings read in to debug log along with xkeyInfo and xnewkeyInfo
+ CMS.debug("TokenServlet: processDiversifyKey(): xkeyInfo[0] (old) = 0x"
+ + Integer.toHexString((int)(xkeyInfo[0]) & 0x0000000FF)
+ + ", xkeyInfo[1] (old) = 0x"
+ + Integer.toHexString((int)(xkeyInfo[1]) & 0x0000000FF)
+ + ", xnewkeyInfo[0] = 0x"
+ + Integer.toHexString((int)(xnewkeyInfo[0]) & 0x000000FF)
+ + ", xnewkeyInfo[1] = 0x"
+ + Integer.toHexString((int)(xnewkeyInfo[1]) & 0x000000FF)
+ );
+ CMS.debug("TokenServlet: processDiversifyKey(): Nist SP800-108 KDF will be used for key versions >= 0x"
+ + Integer.toHexString((int)(nistSP800_108KdfOnKeyVersion) & 0x0000000FF)
+ );
+ if (nistSP800_108KdfUseCuidAsKdd == true){
+ CMS.debug("TokenServlet: processDiversifyKey(): Nist SP800-108 KDF (if used) will use CUID instead of KDD.");
+ }else{
+ CMS.debug("TokenServlet: processDiversifyKey(): Nist SP800-108 KDF (if used) will use KDD.");
+ }
+ // conform to the set-an-error-flag mentality
+ }catch(Exception e){
+ missingSetting_exception = e;
+ CMS.debug("TokenServlet: processDiversifyKey(): Exception reading Nist SP800-108 KDF config values: " + e.toString());
+ }
if (mKeyNickName != null)
oldMasterKeyName = mKeyNickName;
@@ -859,7 +1181,6 @@ public class TokenServlet extends CMSServlet {
String oldKeyInfoMap = "tks." + keySet + ".mk_mappings." + req.getParameter(IRemoteRequest.TOKEN_KEYINFO); //#xx#xx
String oldMappingValue = CMS.getConfigStore().getString(oldKeyInfoMap, null);
String oldSelectedToken = null;
- String oldKeyNickName = null;
if (oldMappingValue == null) {
oldSelectedToken = CMS.getConfigStore().getString("tks.defaultSlot", "internal");
oldKeyNickName = req.getParameter(IRemoteRequest.TOKEN_KEYINFO);
@@ -872,7 +1193,6 @@ public class TokenServlet extends CMSServlet {
String newKeyInfoMap = "tks.mk_mappings." + rnewKeyInfo; //#xx#xx
String newMappingValue = CMS.getConfigStore().getString(newKeyInfoMap, null);
String newSelectedToken = null;
- String newKeyNickName = null;
if (newMappingValue == null) {
newSelectedToken = CMS.getConfigStore().getString("tks.defaultSlot", "internal");
newKeyNickName = rnewKeyInfo;
@@ -888,10 +1208,20 @@ public class TokenServlet extends CMSServlet {
newKeyNickName);
byte kekKeyArray[] =
- com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + keySet + ".kek_key"));
+ 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){
KeySetData = SessionKey.DiversifyKey(oldSelectedToken,
newSelectedToken, oldKeyNickName,
- newKeyNickName, rnewKeyInfo, CUID, kekKeyArray, useSoftToken_s, keySet);
+ newKeyNickName,
+ xkeyInfo, // AC: KDF SPEC CHANGE - pass in old key info so symkey can make decision about which KDF version to use
+ xnewkeyInfo, // AC: BUGFIX for key versions higher than 09: We need to specialDecode keyInfo parameters before sending them into symkey! This means the parameters must be byte[]
+ 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);
if (KeySetData == null || KeySetData.length <= 1) {
CMS.getLogger().log(ILogger.EV_AUDIT,
@@ -901,11 +1231,18 @@ public class TokenServlet extends CMSServlet {
CMS.getLogger().log(ILogger.EV_AUDIT,
ILogger.S_TKS,
- ILogger.LL_INFO, "process DiversifyKey for CUID =" + trim(pp.toHexString(CUID))
+ ILogger.LL_INFO,
+ "process DiversifyKey for CUID=" +
+ trim(pp.toHexString(xCUID)) + // AC: KDF SPEC CHANGE: Log both CUID and KDD
+ ", KDD=" +
+ trim(pp.toHexString(xKDD))
+ ";from oldMasterKeyName=" + oldSelectedToken + ":" + oldKeyNickName
+ ";to newMasterKeyName=" + newSelectedToken + ":" + newKeyNickName);
resp.setContentType("text/html");
+
+ } // AC: KDF SPEC CHANGE - endif no error reading settings from settings file
+
} // ! missingParam
//CMS.debug("TokenServlet:processDiversifyKey " +outputString);
@@ -918,6 +1255,11 @@ public class TokenServlet extends CMSServlet {
value = IRemoteRequest.RESPONSE_STATUS+"=0&" + IRemoteRequest.TKS_RESPONSE_KeySetData+"=" +
com.netscape.cmsutil.util.Utils.SpecialEncode(KeySetData);
CMS.debug("TokenServlet:process DiversifyKey.encode " + value);
+ // AC: KDF SPEC CHANGE - check for settings file issue (flag)
+ } else if (missingSetting_exception != null){
+ status = "6";
+ errorMsg = "Problem reading required configuration value.";
+ value = "status=" + status;
} else if (missingParam) {
status = "3";
if (badParams.endsWith(",")) {
@@ -945,26 +1287,48 @@ public class TokenServlet extends CMSServlet {
if (status.equals("0")) {
- auditMessage = CMS.getLogMessage(
- LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS,
- rCUID,
- ILogger.SUCCESS,
- status,
- agentId,
- oldMasterKeyName,
- newMasterKeyName);
-
+ // AC: KDF SPEC CHANGE - Log both CUID and KDD
+ // Also added TKSKeyset, OldKeyInfo_KeyVersion, NewKeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+ // Finally, log CUID and KDD in ASCII-HEX format, as long as special-decoded version is available.
+ 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
+
+ // AC: BUGFIX: Record the actual parameters to DiversifyKey in the audit log.
+ oldKeyNickName, // oldMasterKeyName
+ newKeyNickName, // newMasterKeyName
+
+ keySet, // TKSKeyset
+ log_string_from_keyInfo(xkeyInfo), // OldKeyInfo_KeyVersion
+ log_string_from_keyInfo(xnewkeyInfo), // NewKeyInfo_KeyVersion
+ "0x" + Integer.toHexString((int)nistSP800_108KdfOnKeyVersion & 0x000000FF), // NistSP800_108KdfOnKeyVersion
+ Boolean.toString(nistSP800_108KdfUseCuidAsKdd) // NistSP800_108KdfUseCuidAsKdd
+ };
+ auditMessage = CMS.getLogMessage(LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS, logParams);
} else {
-
- auditMessage = CMS.getLogMessage(
- LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE,
- rCUID,
- ILogger.FAILURE,
- status,
- agentId,
- oldMasterKeyName,
- newMasterKeyName,
- errorMsg);
+ // AC: KDF SPEC CHANGE - Log both CUID and KDD
+ // Also added TKSKeyset, OldKeyInfo_KeyVersion, NewKeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+ // Finally, log CUID and KDD in ASCII-HEX format, as long as special-decoded version is available.
+ 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
+
+ // AC: BUGFIX: Record the actual parameters to DiversifyKey in the audit log.
+ oldKeyNickName, // oldMasterKeyName
+ newKeyNickName, // newMasterKeyName
+
+ keySet, // TKSKeyset
+ log_string_from_keyInfo(xkeyInfo), // OldKeyInfo_KeyVersion
+ log_string_from_keyInfo(xnewkeyInfo), // NewKeyInfo_KeyVersion
+ "0x" + Integer.toHexString((int)nistSP800_108KdfOnKeyVersion & 0x000000FF), // NistSP800_108KdfOnKeyVersion
+ Boolean.toString(nistSP800_108KdfUseCuidAsKdd), // NistSP800_108KdfUseCuidAsKdd
+ errorMsg // Error
+ };
+ auditMessage = CMS.getLogMessage(LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE, logParams);
}
audit(auditMessage);
@@ -972,7 +1336,15 @@ public class TokenServlet extends CMSServlet {
private void processEncryptData(HttpServletRequest req,
HttpServletResponse resp) throws EBaseException {
- byte[] keyInfo, CUID, xCUID, encryptedData, xkeyInfo;
+ byte[] keyInfo, xCUID, encryptedData, xkeyInfo, xKDD; // AC: KDF SPEC CHANGE: removed duplicative 'CUID' variable and added xKDD
+
+ // AC: KDF SPEC CHANGE - new config file values (needed for symkey)
+ byte nistSP800_108KdfOnKeyVersion = (byte)0xff;
+ boolean nistSP800_108KdfUseCuidAsKdd = false;
+
+ // AC: KDF SPEC CHANGE - flag for if there is an error reading our new setting
+ Exception missingSetting_exception = null;
+
boolean missingParam = false;
byte[] data = null;
boolean isRandom = true; // randomly generate the data to be encrypted
@@ -984,6 +1356,15 @@ public class TokenServlet extends CMSServlet {
String rdata = req.getParameter(IRemoteRequest.TOKEN_DATA);
String rKeyInfo = req.getParameter(IRemoteRequest.TOKEN_KEYINFO);
String rCUID = req.getParameter(IRemoteRequest.TOKEN_CUID);
+
+ // AC: KDF SPEC CHANGE - read new KDD parameter from TPS
+ String rKDD = req.getParameter("KDD");
+ if ((rKDD == null) || (rKDD.length() == 0)) {
+ // temporarily make it friendly before TPS change
+ 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";
@@ -1008,9 +1389,11 @@ public class TokenServlet extends CMSServlet {
isRandom = true;
}
+ // AC: KDF SPEC CHANGE: Need to log both KDD and CUID
String auditMessage = CMS.getLogMessage(
LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST,
rCUID,
+ rKDD, // AC: KDF SPEC CHANGE - Log both CUID and KDD.
ILogger.SUCCESS,
agentId,
s_isRandom);
@@ -1044,12 +1427,24 @@ public class TokenServlet extends CMSServlet {
missingParam = true;
}
+ // AC: KDF SPEC CHANGE - read new KDD parameter from TPS
+ if ((rKDD == null) || (rKDD.length() == 0)) {
+ CMS.debug("TokenServlet: processDiversifyKey(): missing request parameter: KDD");
+ badParams += " KDD,";
+ missingParam = true;
+ }
+
if ((rKeyInfo == null) || (rKeyInfo.equals(""))) {
badParams += " KeyInfo,";
CMS.debug("TokenServlet: processEncryptData(): missing request parameter: key info");
missingParam = true;
}
+ // AC: KDF SPEC CHANGE
+ xCUID = null; // avoid errors about non-initialization
+ xKDD = null; // avoid errors about non-initialization
+ xkeyInfo = null; // avoid errors about non-initialization
+
if (!missingParam) {
xCUID = com.netscape.cmsutil.util.Utils.SpecialDecode(rCUID);
if (xCUID == null || xCUID.length != 10) {
@@ -1057,6 +1452,15 @@ public class TokenServlet extends CMSServlet {
CMS.debug("TokenServlet: Invalid CUID length");
missingParam = true;
}
+
+ // AC: KDF SPEC CHANGE - read new KDD parameter from TPS
+ 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 != 2) {
badParams += " KeyInfo length,";
@@ -1072,10 +1476,35 @@ public class TokenServlet extends CMSServlet {
String selectedToken = null;
String keyNickName = null;
if (!missingParam) {
+
+ // AC: KDF SPEC CHANGE - read new config file values (needed for symkey
+ try{
+ nistSP800_108KdfOnKeyVersion = TokenServlet.read_setting_nistSP800_108KdfOnKeyVersion(keySet);
+ nistSP800_108KdfUseCuidAsKdd = TokenServlet.read_setting_nistSP800_108KdfUseCuidAsKdd(keySet);
+
+ // log settings read in to debug log along with xkeyInfo
+ CMS.debug("TokenServlet: processEncryptData(): xkeyInfo[0] = 0x"
+ + Integer.toHexString((int)(xkeyInfo[0]) & 0x0000000FF)
+ + ", xkeyInfo[1] = 0x"
+ + Integer.toHexString((int)(xkeyInfo[1]) & 0x0000000FF)
+ );
+ CMS.debug("TokenServlet: processEncryptData(): Nist SP800-108 KDF will be used for key versions >= 0x"
+ + Integer.toHexString((int)(nistSP800_108KdfOnKeyVersion) & 0x0000000FF)
+ );
+ if (nistSP800_108KdfUseCuidAsKdd == true){
+ CMS.debug("TokenServlet: processEncryptData(): Nist SP800-108 KDF (if used) will use CUID instead of KDD.");
+ }else{
+ CMS.debug("TokenServlet: processEncryptData(): Nist SP800-108 KDF (if used) will use KDD.");
+ }
+ // conform to the set-an-error-flag mentality
+ }catch(Exception e){
+ missingSetting_exception = e;
+ CMS.debug("TokenServlet: processEncryptData(): Exception reading Nist SP800-108 KDF config values: " + e.toString());
+ }
+
if (!isRandom)
data = com.netscape.cmsutil.util.Utils.SpecialDecode(rdata);
keyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(rKeyInfo);
- CUID = com.netscape.cmsutil.util.Utils.SpecialDecode(rCUID);
String keyInfoMap = "tks." + keySet + ".mk_mappings." + rKeyInfo;
String mappingValue = CMS.getConfigStore().getString(keyInfoMap, null);
@@ -1090,12 +1519,30 @@ public class TokenServlet extends CMSServlet {
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){
+
encryptedData = SessionKey.EncryptData(
- selectedToken, keyNickName, data, keyInfo, CUID, kekKeyArray, useSoftToken_s, keySet);
+ 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);
+
+ // AC: KDF SPEC CHANGE - Log both CUID and KDD
+
CMS.getLogger().log(ILogger.EV_AUDIT,
ILogger.S_TKS,
- ILogger.LL_INFO, "process EncryptData for CUID =" + trim(pp.toHexString(CUID)));
+ ILogger.LL_INFO,"process EncryptData for CUID="+
+ trim(pp.toHexString(xCUID)) +
+ ", KDD=" +
+ trim(pp.toHexString(xKDD)));
+
+ } // AC: KDF SPEC CHANGE - endif no error reading settings from settings file
+
+
} // !missingParam
resp.setContentType("text/html");
@@ -1109,6 +1556,11 @@ public class TokenServlet extends CMSServlet {
com.netscape.cmsutil.util.Utils.SpecialEncode(data) +
"&"+IRemoteRequest.TKS_RESPONSE_EncryptedData+"=" +
com.netscape.cmsutil.util.Utils.SpecialEncode(encryptedData);
+ // AC: KDF SPEC CHANGE - check for settings file issue (flag)
+ } else if (missingSetting_exception != null){
+ status = "6";
+ errorMsg = "Problem reading required configuration value.";
+ value = "status=" + status;
} else if (missingParam) {
if (badParams.endsWith(",")) {
badParams = badParams.substring(0, badParams.length() - 1);
@@ -1137,29 +1589,42 @@ public class TokenServlet extends CMSServlet {
}
if (status.equals("0")) {
-
- auditMessage = CMS.getLogMessage(
- LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS,
- rCUID,
- ILogger.SUCCESS,
- status,
- agentId,
- s_isRandom,
- selectedToken,
- keyNickName);
-
+ // AC: KDF SPEC CHANGE - Log both CUID and KDD
+ // Also added TKSKeyset, KeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+ // Finally, log CUID and KDD in ASCII-HEX format, as long as special-decoded version is available.
+ 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
+ s_isRandom, // isRandom
+ selectedToken, // SelectedToken
+ keyNickName, // KeyNickName
+ keySet, // TKSKeyset
+ log_string_from_keyInfo(xkeyInfo), // KeyInfo_KeyVersion
+ "0x" + Integer.toHexString((int)nistSP800_108KdfOnKeyVersion & 0x000000FF), // NistSP800_108KdfOnKeyVersion
+ Boolean.toString(nistSP800_108KdfUseCuidAsKdd) // NistSP800_108KdfUseCuidAsKdd
+ };
+ auditMessage = CMS.getLogMessage(LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS, logParams);
} else {
-
- auditMessage = CMS.getLogMessage(
- LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE,
- rCUID,
- ILogger.FAILURE,
- status,
- agentId,
- s_isRandom,
- selectedToken,
- keyNickName,
- errorMsg);
+ // AC: KDF SPEC CHANGE - Log both CUID and KDD
+ // Also added TKSKeyset, KeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+ // Finally, log CUID and KDD in ASCII-HEX format, as long as special-decoded version is available.
+ 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
+ s_isRandom, // isRandom
+ selectedToken, // SelectedToken
+ keyNickName, // KeyNickName
+ keySet, // TKSKeyset
+ log_string_from_keyInfo(xkeyInfo), // KeyInfo_KeyVersion
+ "0x" + Integer.toHexString((int)nistSP800_108KdfOnKeyVersion & 0x000000FF), // NistSP800_108KdfOnKeyVersion
+ Boolean.toString(nistSP800_108KdfUseCuidAsKdd), // NistSP800_108KdfUseCuidAsKdd
+ errorMsg // Error
+ };
+ auditMessage = CMS.getLogMessage(LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE, logParams);
}
audit(auditMessage);
diff --git a/base/server/cmsbundle/src/LogMessages.properties b/base/server/cmsbundle/src/LogMessages.properties
index dfa23c15b..ef3872c8d 100644
--- a/base/server/cmsbundle/src/LogMessages.properties
+++ b/base/server/cmsbundle/src/LogMessages.properties
@@ -2263,6 +2263,13 @@ LOGGING_SIGNED_AUDIT_COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_FAILURE_4=<type=COMPU
# SubjectID must be the CUID of the token establishing the secure channel
# AgentID must be the trusted agent id used to make the request
LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_3=<type=COMPUTE_SESSION_KEY_REQUEST>:[AuditEvent=COMPUTE_SESSION_KEY_REQUEST][SubjectID={0}][Outcome={1}][AgentID={2}] TKS Compute session key request
+## AC: KDF SPEC CHANGE - Need to log both the KDD and CUID, not just the
+## CUID. Renamed to "CUID_encoded" and "KDD_encoded" to reflect fact that
+## encoded parameters are being logged.
+# CUID_encoded must be the special-encoded CUID of the token establishing the secure channel
+# KDD_encoded must be the special-encoded KDD of the token establishing the secure channel
+LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_4=<type=COMPUTE_SESSION_KEY_REQUEST>:[AuditEvent=COMPUTE_SESSION_KEY_REQUEST][CUID_encoded={0}][KDD_encoded={1}][Outcome={2}][AgentID={3}] TKS Compute session key request
+
#
#
# LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS
@@ -2277,6 +2284,19 @@ LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_3=<type=COMPUTE_SESSION_KEY_REQ
# KeyNickName is the number keyset ex: #01#01
#
LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS_8=<type=COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS>:[AuditEvent=COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS][SubjectID={0}][Outcome={1}][status={2}][AgentID={3}][IsCryptoValidate={4}][IsServerSideKeygen={5}][SelectedToken={6}][KeyNickName={7}] TKS Compute session key request processed successfully
+## AC: KDF SPEC CHANGE - Need to log both the KDD and CUID, not just the
+## CUID. Renamed to "CUID_decoded" and "KDD_decoded" to reflect fact
+## that decoded parameters are now logged.
+## Also added TKSKeyset, KeyInfo_KeyVersion,
+## NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+# CUID_decoded must be the ASCII-HEX representation of the CUID of the token establishing the secure channel
+# KDD_decoded must be the ASCII-HEX representation of the KDD of the token establishing the secure channel
+# TKSKeyset is the name of the TKS keyset being used for this request.
+# KeyInfo_KeyVersion is the key version number requested in hex.
+# NistSP800_108KdfOnKeyVersion lists the value of the corresponding setting in hex.
+# NistSP800_108KdfUseCuidAsKdd lists the value of the corresponding setting in hex.
+LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS_13=<type=COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS>:[AuditEvent=COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS][CUID_decoded={0}][KDD_decoded={1}][Outcome={2}][status={3}][AgentID={4}][IsCryptoValidate={5}][IsServerSideKeygen={6}][SelectedToken={7}][KeyNickName={8}][TKSKeyset={9}][KeyInfo_KeyVersion={10}][NistSP800_108KdfOnKeyVersion={11}][NistSP800_108KdfUseCuidAsKdd={12}] TKS Compute session key request processed successfully
+
#
#
# LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE
@@ -2293,6 +2313,16 @@ LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS_8=<type=COMPU
# Error gives the error message
LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE_9=<type=COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE>:[AuditEvent=COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE][SubjectID={0}][Outcome={1}][status={2}][AgentID={3}][IsCryptoValidate={4}][IsServerSideKeygen={5}][SelectedToken={7}][KeyNickName={7}][Error={8}] TKS Compute session key request failed
#
+## AC: KDF SPEC CHANGE - Need to log both the KDD and CUID, not just the CUID. Renamed to "CUID_decoded" and "KDD_decoded" to reflect fact that decoded parameters are now logged.
+## Also added TKSKeyset, KeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+# CUID_decoded must be the ASCII-HEX representation of the CUID of the token establishing the secure channel
+# KDD_decoded must be the ASCII-HEX representation of the KDD of the token establishing the secure channel
+# TKSKeyset is the name of the TKS keyset being used for this request.
+# KeyInfo_KeyVersion is the key version number requested in hex.
+# NistSP800_108KdfOnKeyVersion lists the value of the corresponding setting in hex.
+# NistSP800_108KdfUseCuidAsKdd lists the value of the corresponding setting in hex
+LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE_14=<type=COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE>:[AuditEvent=COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE][CUID_decoded={0}][KDD_decoded={1}][Outcome={2}][status={3}][AgentID={4}][IsCryptoValidate={5}][IsServerSideKeygen={6}][SelectedToken={7}][KeyNickName={8}][TKSKeyset={9}][KeyInfo_KeyVersion={10}][NistSP800_108KdfOnKeyVersion={11}][NistSP800_108KdfUseCuidAsKdd={12}][Error={13}] TKS Compute session key request failed
+
# LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST
# - request for TPS to TKS to do key change over
@@ -2303,6 +2333,11 @@ LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE_9=<type=COMPU
# newMasterKeyName is the new master key name
LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_5=<type=DIVERSIFY_KEY_REQUEST>:[AuditEvent=DIVERSIFY_KEY_REQUEST][SubjectID={0}][Outcome={1}][AgentID={2}][oldMasterKeyName={3}][newMasterKeyName={4}] TKS Key Change Over request
#
+## AC: KDF SPEC CHANGE - Need to log both the KDD and CUID, not just the CUID. Renamed to "CUID_encoded" and "KDD_encoded" to reflect fact that encoded parameters are being logged.
+# CUID_encoded must be the special-encoded CUID of the token establishing the secure channel
+# KDD_encoded must be the special-encoded KDD of the token establishing the secure channel
+LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_6=<type=DIVERSIFY_KEY_REQUEST>:[AuditEvent=DIVERSIFY_KEY_REQUEST][CUID_encoded={0}][KDD_encoded={1}][Outcome={2}][AgentID={3}][oldMasterKeyName={4}][newMasterKeyName={5}] TKS Key Change Over request
+
###########################
# LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS
# - request for TPS to TKS to do key change over request processed
@@ -2314,6 +2349,17 @@ LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_5=<type=DIVERSIFY_KEY_REQUEST>:[Audit
# newMasterKeyName is the new master key name
LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS_6=<type=DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS>:[AuditEvent=DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS][SubjectID={0}][Outcome={1}][status={2}][AgentID={3}][oldMasterKeyName={4}][newMasterKeyName={5}] TKS Key Change Over request processed successfully
#
+## AC: KDF SPEC CHANGE - Need to log both the KDD and CUID, not just the CUID. Renamed to "CUID_decoded" and "KDD_decoded" to reflect fact that decoded parameters are now logged.
+## Also added TKSKeyset, OldKeyInfo_KeyVersion, NewKeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+# CUID_decoded must be the ASCII-HEX representation of the CUID of the token establishing the secure channel
+# KDD_decoded must be the ASCII-HEX representation of the KDD of the token establishing the secure channel
+# TKSKeyset is the name of the TKS keyset being used for this request.
+# OldKeyInfo_KeyVersion is the old key version number in hex.
+# NewKeyInfo_KeyVersion is the new key version number in hex.
+# NistSP800_108KdfOnKeyVersion lists the value of the corresponding setting in hex.
+# NistSP800_108KdfUseCuidAsKdd lists the value of the corresponding setting in hex.
+LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS_12=<type=DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS>:[AuditEvent=DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS][CUID_decoded={0}][KDD_decoded={1}][Outcome={2}][status={3}][AgentID={4}][oldMasterKeyName={5}][newMasterKeyName={6}][TKSKeyset={7}][OldKeyInfo_KeyVersion={8}][NewKeyInfo_KeyVersion={9}][NistSP800_108KdfOnKeyVersion={10}][NistSP800_108KdfUseCuidAsKdd={11}] TKS Key Change Over request processed successfully
+
#
###########################
# LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE
@@ -2327,6 +2373,16 @@ LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS_6=<type=DIVERSIFY_K
# Error gives the error message
LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE_7=<type=DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE>:[AuditEvent=DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE][SubjectID={0}][Outcome={1}][status={2}][AgentID={3}][oldMasterKeyName={4}][newMasterKeyName={5}][Error={6}] TKS Key Change Over request failed
#
+## AC: KDF SPEC CHANGE - Need to log both the KDD and CUID, not just the CUID. Renamed to "CUID_decoded" and "KDD_decoded" to reflect fact that decoded parameters are now logged.
+## Also added TKSKeyset, OldKeyInfo_KeyVersion, NewKeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+# CUID_decoded must be the ASCII-HEX representation of the CUID of the token establishing the secure channel
+# KDD_decoded must be the ASCII-HEX representation of the KDD of the token establishing the secure channel
+# TKSKeyset is the name of the TKS keyset being used for this request.
+# OldKeyInfo_KeyVersion is the old key version number in hex.
+# NewKeyInfo_KeyVersion is the new key version number in hex.
+# NistSP800_108KdfOnKeyVersion lists the value of the corresponding setting in hex.
+# NistSP800_108KdfUseCuidAsKdd lists the value of the corresponding setting in hex
+LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE_13=<type=DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE>:[AuditEvent=DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE][CUID_decoded={0}][KDD_decoded={1}][Outcome={2}][status={3}][AgentID={4}][oldMasterKeyName={5}][newMasterKeyName={6}][TKSKeyset={7}][OldKeyInfo_KeyVersion={8}][NewKeyInfo_KeyVersion={9}][NistSP800_108KdfOnKeyVersion={10}][NistSP800_108KdfUseCuidAsKdd={11}][Error={12}] TKS Key Change Over request failed
# LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST
# - request from TPS to TKS to encrypt data
@@ -2337,6 +2393,11 @@ LOGGING_SIGNED_AUDIT_DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE_7=<type=DIVERSIFY_K
# isRandom tells if the data is randomly generated on TKS
LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_4=<type=ENCRYPT_DATA_REQUEST>:[AuditEvent=ENCRYPT_DATA_REQUEST][SubjectID={0}][status={1}][AgentID={2}][isRandom={3}] TKS encrypt data request
#
+## AC: KDF SPEC CHANGE - Need to log both the KDD and CUID, not just the CUID. Renamed to "CUID_encoded" and "KDD_encoded" to reflect fact that encoded parameters are being logged.
+# CUID_encoded must be the special-encoded CUID of the token establishing the secure channel
+# KDD_encoded must be the special-encoded KDD of the token establishing the secure channel
+LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_5=<type=ENCRYPT_DATA_REQUEST>:[AuditEvent=ENCRYPT_DATA_REQUEST][CUID_encoded={0}][KDD_encoded={1}][status={2}][AgentID={3}][isRandom={4}] TKS encrypt data request
+
#
# LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS
# - request from TPS to TKS to encrypt data
@@ -2350,6 +2411,16 @@ LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_4=<type=ENCRYPT_DATA_REQUEST>:[AuditEv
# KeyNickName is the numeric keyset ex: #01#01
LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS_7=<type=ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS>:[AuditEvent=ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS][SubjectID={0}][Outcome={1}][status={2}][AgentID={3}][isRandom={4}][SelectedToken={5}][KeyNickName={6}] TKS encrypt data request processed successfully
#
+## AC: KDF SPEC CHANGE - Need to log both the KDD and CUID, not just the CUID. Renamed to "CUID_decoded" and "KDD_decoded" to reflect fact that decoded parameters are now logged.
+## Also added TKSKeyset, KeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+# CUID_decoded must be the ASCII-HEX representation of the CUID of the token establishing the secure channel
+# KDD_decoded must be the ASCII-HEX representation of the KDD of the token establishing the secure channel
+# TKSKeyset is the name of the TKS keyset being used for this request.
+# KeyInfo_KeyVersion is the key version number requested in hex.
+# NistSP800_108KdfOnKeyVersion lists the value of the corresponding setting in hex.
+# NistSP800_108KdfUseCuidAsKdd lists the value of the corresponding setting in hex.
+LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS_12=<type=ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS>:[AuditEvent=ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS][CUID_decoded={0}][KDD_decoded={1}][Outcome={2}][status={3}][AgentID={4}][isRandom={5}][SelectedToken={6}][KeyNickName={7}][TKSKeyset={8}][KeyInfo_KeyVersion={9}][NistSP800_108KdfOnKeyVersion={10}][NistSP800_108KdfUseCuidAsKdd={11}] TKS encrypt data request processed successfully
+
#
# LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE
# - request from TPS to TKS to encrypt data
@@ -2364,6 +2435,15 @@ LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS_7=<type=ENCRYPT_DATA
# Error gives the error message
LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE_8=<type=ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE>:[AuditEvent=ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE][SubjectID={0}][Outcome={1}][status={2}][AgentID={3}][isRandom={4}][SelectedToken={5}][KeyNickName={6}][Error={7}] TKS encrypt data request failed
#
+## AC: KDF SPEC CHANGE - Need to log both the KDD and CUID, not just the CUID. Renamed to "CUID_decoded" and "KDD_decoded" to reflect fact that decoded parameters are now logged.
+## Also added TKSKeyset, KeyInfo_KeyVersion, NistSP800_108KdfOnKeyVersion, NistSP800_108KdfUseCuidAsKdd
+# CUID_decoded must be the ASCII-HEX representation of the CUID of the token establishing the secure channel
+# KDD_decoded must be the ASCII-HEX representation of the KDD of the token establishing the secure channel
+# TKSKeyset is the name of the TKS keyset being used for this request.
+# KeyInfo_KeyVersion is the key version number requested in hex.
+# NistSP800_108KdfOnKeyVersion lists the value of the corresponding setting in hex.
+# NistSP800_108KdfUseCuidAsKdd lists the value of the corresponding setting in hex.
+LOGGING_SIGNED_AUDIT_ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE_13=<type=ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE>:[AuditEvent=ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE][CUID_decoded={0}][KDD_decoded={1}][Outcome={2}][status={3}][AgentID={4}][isRandom={5}][SelectedToken={6}][KeyNickName={7}][TKSKeyset={8}][KeyInfo_KeyVersion={9}][NistSP800_108KdfOnKeyVersion={10}][NistSP800_108KdfUseCuidAsKdd={11}][Error={12}] TKS encrypt data request failed
#
#
# LOGGING_SIGNED_AUDIT_SECURITY_DOMAIN_UPDATE
diff --git a/base/symkey/src/com/netscape/symkey/CMakeLists.txt b/base/symkey/src/com/netscape/symkey/CMakeLists.txt
index 84c8e086a..63c31903d 100644
--- a/base/symkey/src/com/netscape/symkey/CMakeLists.txt
+++ b/base/symkey/src/com/netscape/symkey/CMakeLists.txt
@@ -25,6 +25,7 @@ set(SYMKEY_LINK_LIBRARIES
set(symkey_library_HDRS
SessionKey.h
+ NistSP800_108KDF.h
)
set(symkey_library_SRCS
@@ -32,6 +33,7 @@ set(symkey_library_SRCS
EncryptData.cpp
SessionKey.cpp
SymKey.cpp
+ NistSP800_108KDF.cpp
)
include_directories(${SYMKEY_PRIVATE_INCLUDE_DIRS})
diff --git a/base/symkey/src/com/netscape/symkey/EncryptData.cpp b/base/symkey/src/com/netscape/symkey/EncryptData.cpp
index ccb817f7c..3963b5026 100644
--- a/base/symkey/src/com/netscape/symkey/EncryptData.cpp
+++ b/base/symkey/src/com/netscape/symkey/EncryptData.cpp
@@ -37,6 +37,10 @@ extern "C"
#include <stdlib.h>
#include "Buffer.h"
#include "SymKey.h"
+
+// AC: KDF SPEC CHANGE: Include headers for NIST SP800-108 KDF functions.
+#include "NistSP800_108KDF.h"
+
#define DES2_WORKAROUND
PRFileDesc *d = NULL;
@@ -66,17 +70,24 @@ void GetKeyName(jbyte *keyVersion, char *keyname)
sprintf(keyname+index+4,"%.2d", keyVersion[1]);
}
-
+// AC: KDF SPEC CHANGE: function signature change - added jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_EncryptData
-(JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jstring, jstring);
+(JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyte, jboolean, jbyteArray, jbyteArray, jbyteArray, jstring, jstring);
+// AC: KDF SPEC CHANGE: function signature change - added jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
extern "C" JNIEXPORT jbyteArray JNICALL
-Java_com_netscape_symkey_SessionKey_EncryptData(JNIEnv * env, jclass this2, jstring j_tokenName, jstring j_keyName, jbyteArray j_in, jbyteArray keyInfo, jbyteArray CUID, jbyteArray kekKeyArray, jstring useSoftToken_s,jstring keySet)
+Java_com_netscape_symkey_SessionKey_EncryptData(JNIEnv * env, jclass this2, jstring j_tokenName, jstring j_keyName, jbyteArray j_in, jbyteArray keyInfo, jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, jbyteArray CUID, jbyteArray KDD, jbyteArray kekKeyArray, jstring useSoftToken_s,jstring keySet)
{
jbyte * kek_key = NULL;
PK11SymKey *masterKey = NULL;
- PK11SymKey *kekKey = NULL;
+
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF, we build all 3 keys despite only using one of them (Kek) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ // KDF output keys
+ PK11SymKey* macKey = NULL;
+ PK11SymKey* encKey = NULL;
+ PK11SymKey* kekKey = NULL;
Buffer out = Buffer(KEYLENGTH, (BYTE)0);
BYTE kekData[KEYLENGTH];
@@ -86,7 +97,13 @@ Java_com_netscape_symkey_SessionKey_EncryptData(JNIEnv * env, jclass this2, jstr
jbyte *cc = NULL;
int cc_len = 0;
- jbyte * cuidValue = NULL;
+
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ jbyte* cuidValue = NULL;
+ jsize cuidValue_len = -1;
+ jbyte* kddValue = NULL;
+ jsize kddValue_len = -1;
if( kekKeyArray != NULL) {
kek_key = (jbyte*)(env)->GetByteArrayElements(kekKeyArray, NULL);
@@ -122,13 +139,30 @@ Java_com_netscape_symkey_SessionKey_EncryptData(JNIEnv * env, jclass this2, jstr
goto done;
}
- if( CUID != NULL) {
- cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL);
- }
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ if ( CUID != NULL ) {
+ cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL);
+ cuidValue_len = env->GetArrayLength(CUID);
+ }
if( cuidValue == NULL) {
goto done;
}
+ if ( cuidValue_len <= 0){ // check that CUID is at least 1 byte in length
+ goto done;
+ }
+ if ( KDD != NULL ){
+ kddValue = env->GetByteArrayElements(KDD, NULL);
+ kddValue_len = env->GetArrayLength(KDD);
+ }
+ if ( kddValue == NULL ){
+ goto done;
+ }
+ if ( kddValue_len != static_cast<jsize>(NistSP800_108KDF::KDD_SIZE_BYTES) ){ // check that KDD is expected size
+ goto done;
+ }
+
if( j_in != NULL) {
cc = (jbyte*)(env)->GetByteArrayElements( j_in, NULL);
@@ -139,7 +173,8 @@ Java_com_netscape_symkey_SessionKey_EncryptData(JNIEnv * env, jclass this2, jstr
goto done;
}
- GetDiversificationData(cuidValue,kekData,kek);
+ // AC: KDF SPEC CHANGE: Moved this call down. (We don't necessarily need it anymore depending on the KDF we're going to use.)
+ //GetDiversificationData(cuidValue,kekData,kek);
PR_fprintf(PR_STDOUT,"In SessionKey: EncryptData! \n");
@@ -181,12 +216,75 @@ Java_com_netscape_symkey_SessionKey_EncryptData(JNIEnv * env, jclass this2, jstr
{
masterKey = ReturnSymKey( slot,keyname);
- /* We need to use internal so that the key
- * can be exported by using PK11_GetKeyData()
- */
if (masterKey != NULL)
{
- kekKey = ComputeCardKeyOnToken(masterKey,kekData);
+
+
+ // ---------------------------------
+ // AC KDF SPEC CHANGE: Determine which KDF to use.
+ //
+ // Convert to unsigned types
+ BYTE nistSP800_108KdfOnKeyVersion_byte = static_cast<BYTE>(nistSP800_108KdfOnKeyVersion);
+ BYTE requestedKeyVersion_byte = static_cast<BYTE>(keyVersion[0]);
+ // if requested key version meets setting value, use NIST SP800-108 KDF
+ if (NistSP800_108KDF::useNistSP800_108KDF(nistSP800_108KdfOnKeyVersion_byte, requestedKeyVersion_byte) == true){
+
+ PR_fprintf(PR_STDOUT,"EncryptData NistSP800_108KDF code: Using NIST SP800-108 KDF.\n");
+
+ // react to "UseCUIDAsKDD" setting value
+ jbyte* context_jbyte = NULL;
+ jsize context_len_jsize = 0;
+ if (nistSP800_108KdfUseCuidAsKdd == JNI_TRUE){
+ context_jbyte = cuidValue;
+ context_len_jsize = cuidValue_len;
+ }else{
+ context_jbyte = kddValue;
+ context_len_jsize = kddValue_len;
+ }
+
+ // Converting this way is safe since jbyte is guaranteed to be 8 bits
+ // Of course, this assumes that "char" is 8 bits (not guaranteed, but typical),
+ // but it looks like this assumption is also made in GetDiversificationData
+ const BYTE* const context = reinterpret_cast<const BYTE*>(context_jbyte);
+
+ // Convert jsize to size_t
+ const size_t context_len = static_cast<size_t>(context_len_jsize);
+ if (context_len > 0x000000FF){ // sanity check (CUID should never be larger than 255 bytes)
+ PR_fprintf(PR_STDERR, "EncryptData NistSP800_108KDF code: Error; context_len larger than 255 bytes.\n");
+ goto done;
+ }
+
+ // call NIST SP800-108 KDF routine
+ try{
+ NistSP800_108KDF::ComputeCardKeys(masterKey, context, context_len, &encKey, &macKey, &kekKey);
+ }catch(std::runtime_error& ex){
+ PR_fprintf(PR_STDERR, "EncryptData NistSP800_108KDF code: Exception invoking NistSP800_108KDF::ComputeCardKeys: ");
+ PR_fprintf(PR_STDERR, "%s\n", ex.what() == NULL ? "null" : ex.what());
+ goto done;
+ }catch(...){
+ PR_fprintf(PR_STDERR, "EncryptData NistSP800_108KDF code: Unknown exception invoking NistSP800_108KDF::ComputeCardKeys.\n");
+ goto done;
+ }
+
+ // if not a key version where we use the NIST SP800-108 KDF, use the original KDF
+ }else{
+
+ PR_fprintf(PR_STDOUT,"EncryptData NistSP800_108KDF code: Using original KDF.\n");
+
+ // AC: KDF SPEC CHANGE: Moved this call down from the original location.
+ // (We don't always need to call it anymore; it depends on the KDF we're going to use.)
+ //
+ // Note the change from "cuidValue" to "kddValue".
+ // This change is necessary due to the semantics change in the parameters passed between TPS and TKS.
+ GetDiversificationData(kddValue,kekData,kek);
+
+ // AC: Derives the Kek key for the token.
+ kekKey = ComputeCardKeyOnToken(masterKey,kekData);
+
+ } // endif use original KDF
+ // ---------------------------------
+
+
if (kekKey != NULL)
{
Buffer input = Buffer((BYTE*)cc, cc_len);
@@ -213,6 +311,16 @@ done:
internal = NULL;
}
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF, we build all 3 keys despite only using one of them (Kek) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ if( macKey ) {
+ PK11_FreeSymKey(macKey);
+ macKey = NULL;
+ }
+ if ( encKey ) {
+ PK11_FreeSymKey(encKey);
+ encKey = NULL;
+ }
if ( kekKey != NULL) {
PK11_FreeSymKey( kekKey);
kekKey = NULL;
@@ -246,5 +354,11 @@ done:
env->ReleaseByteArrayElements(CUID, cuidValue, JNI_ABORT);
}
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ if ( kddValue != NULL){
+ env->ReleaseByteArrayElements(KDD, kddValue, JNI_ABORT);
+ kddValue = NULL;
+ }
+
return handleBA;
}
diff --git a/base/symkey/src/com/netscape/symkey/NistSP800_108KDF.cpp b/base/symkey/src/com/netscape/symkey/NistSP800_108KDF.cpp
new file mode 100644
index 000000000..9f89dd372
--- /dev/null
+++ b/base/symkey/src/com/netscape/symkey/NistSP800_108KDF.cpp
@@ -0,0 +1,470 @@
+/*
+ * NistSP800_108KDF.cpp - Implements the new Key Diversification Function (KDF) as required
+ * by the latest Department of Defense SIPRnet token interface
+ * specification. The functions in this file are internally called
+ * by other functions in the Symkey library. We have made patches
+ * to these other Symkey functions to trigger this new KDF routine
+ * at the appropriate times.
+ *
+ * Also provides a utility function for adding DES key parity.
+ */
+
+//*******************************************************************************
+
+#include "NistSP800_108KDF.h"
+
+//*******************************************************************************
+
+#include <cstring> // memset()
+#include <sstream> // std::ostringstream
+
+#ifdef NISTSP800_108_KDF_DEBUG
+#include <iostream>
+#endif
+
+#include "pk11pub.h"
+
+//*******************************************************************************
+
+namespace NistSP800_108KDF{
+
+//*******************************************************************************
+// Generates three PK11SymKey objects using the KDF_CM_SHA256HMAC_L384() function for key data.
+// After calling KDF_CM_SHA256HMAC_L384, the function splits up the output, sets DES parity,
+// and imports the keys into the token.
+//
+// Careful: This function currently generates the key data **IN RAM** using calls to NSS sha256.
+// The key data is then "unwrapped" (imported) to the NSS token and then erased from RAM.
+// (This means that a malicious actor on the box could steal the key data.)
+//
+// Note: Returned key material from the KDF is converted into keys according to the following:
+// * Bytes 0 - 15 : enc/auth key
+// * Bytes 16 - 31 : mac key
+// * Bytes 32 - 47 : kek key
+// We chose this order to conform with the key order used by the PUT KEY command.
+//
+//*******************************************************************************
+void ComputeCardKeys( PK11SymKey* masterKey, // Key Derivation Key
+ const BYTE* context, // unique data passed to the kdf (kdd)
+ const size_t context_length, // length of context
+ PK11SymKey** encKey, // output parameter: generated enc/auth key
+ PK11SymKey** macKey, // output parameter: generated mac key
+ PK11SymKey** kekKey) // output parameter: generated kek key
+{
+ // sanity check output parameters
+ if (*encKey != NULL){
+ throw std::runtime_error("Output parameter \"encKey\" wasn't initialized to NULL. Overwriting may result in a memory leak.");
+ }
+ if (*macKey != NULL){
+ throw std::runtime_error("Output parameter \"macKey\" wasn't initialized to NULL. Overwriting may result in a memory leak.");
+ }
+ if (*kekKey != NULL){
+ throw std::runtime_error("Output parameter \"kekKey\" wasn't initialized to NULL. Overwriting may result in a memory leak.");
+ }
+
+ // allocate space for KDF output
+ BYTE kdf_output[KDF_OUTPUT_SIZE_BYTES];
+
+ try{
+ // generate 384 bits of key data from the master key
+ KDF_CM_SHA256HMAC_L384(masterKey, context, context_length, KDF_LABEL, kdf_output, KDF_OUTPUT_SIZE_BYTES);
+ }catch(std::runtime_error& ex){
+ std::ostringstream msg;
+ msg << "Exception invoking NistSP800_108KDF::KDF_CM_SHA256HMAC_L384: ";
+ if (ex.what() == NULL){
+ msg << "NULL";
+ }else{
+ msg << ex.what();
+ }
+ throw std::runtime_error(msg.str());
+ }catch(...){
+ throw std::runtime_error("Unknown exception invoking NistSP800_108KDF::KDF_CM_SHA256HMAC_L384.");
+ }
+
+ try{
+ // get slot from master key
+ // (we need the slot to be able to generate our temp key and unwrap our generated bytes
+ PK11SlotInfo* slot = PK11_GetSlotFromKey(masterKey);
+ if (slot == NULL){
+ throw std::runtime_error("Failed to get slot from masterKey.");
+ }
+ try{
+ // generate a temp key to import the key data with
+ PK11SymKey* tmpKey = PK11_TokenKeyGenWithFlags(slot, // slot handle
+ CKM_DES3_KEY_GEN, // mechanism type
+ NULL, // pointer to params (SECItem structure)
+ 0, // keySize (per documentation in pk11skey.c, must be 0 for fixed key length algorithms)
+ 0, // pointer to keyid (SECItem structure)
+ CKF_WRAP | CKF_UNWRAP | CKF_ENCRYPT | CKF_DECRYPT, // opFlags
+ PK11_ATTR_PRIVATE | PK11_ATTR_UNEXTRACTABLE | PK11_ATTR_SENSITIVE, // attrFlags (AC: this is my "best guess" as to what flags should be set)
+ NULL); // pointer to wincx (AC: also my "best guess" - per pkix_sample_modules.h line 265, this should always be NULL on non-Windows)
+ if (tmpKey == NULL) {
+ throw std::runtime_error("Unable to create temp key (for use with importing the key data).");
+ }
+ try{
+
+ // set parity on each of the 3 generated **16 byte** keys
+ set_des_parity(kdf_output + (0 * KEY_DATA_SIZE_BYTES), KEY_DATA_SIZE_BYTES);
+ set_des_parity(kdf_output + (1 * KEY_DATA_SIZE_BYTES), KEY_DATA_SIZE_BYTES);
+ set_des_parity(kdf_output + (2 * KEY_DATA_SIZE_BYTES), KEY_DATA_SIZE_BYTES);
+
+ try{
+ // copy byte array information into 2-key 3DES PK11 keys on token
+ *encKey = Copy2Key3DESKeyDataToToken(slot, tmpKey, kdf_output + (0 * KEY_DATA_SIZE_BYTES), KEY_DATA_SIZE_BYTES);
+ *macKey = Copy2Key3DESKeyDataToToken(slot, tmpKey, kdf_output + (1 * KEY_DATA_SIZE_BYTES), KEY_DATA_SIZE_BYTES);
+ *kekKey = Copy2Key3DESKeyDataToToken(slot, tmpKey, kdf_output + (2 * KEY_DATA_SIZE_BYTES), KEY_DATA_SIZE_BYTES);
+ }catch(...){
+ // free any keys we created before rethrowing
+ if (*encKey != NULL){
+ PK11_FreeSymKey(*encKey);
+ *encKey = NULL;
+ }
+ if (*macKey != NULL){
+ PK11_FreeSymKey(*macKey);
+ *macKey = NULL;
+ }
+ if (*kekKey != NULL){
+ PK11_FreeSymKey(*kekKey);
+ *kekKey = NULL;
+ }
+
+ throw;
+ }
+
+ // clean up
+ PK11_FreeSymKey(tmpKey);
+ tmpKey = NULL;
+ }catch(...){
+ // clean up
+ PK11_FreeSymKey(tmpKey);
+ tmpKey = NULL;
+
+ throw;
+ }
+ // clean up
+ PK11_FreeSlot(slot);
+ slot = NULL;
+ }catch(...){
+ // clean up
+ PK11_FreeSlot(slot);
+ slot = NULL;
+
+ throw;
+ }
+
+ // erase key data from RAM
+ memset(kdf_output, 0, KDF_OUTPUT_SIZE_BYTES);
+ }catch(...){
+ // erase key data from RAM before rethrowing
+ memset(kdf_output, 0, KDF_OUTPUT_SIZE_BYTES);
+
+ throw;
+ }
+}
+
+// uses the specified temporary key to encrypt and then unwrap (decrypt) the specified binary data onto the specified token
+// this has the net effect of copying the raw key data to the token
+PK11SymKey* Copy2Key3DESKeyDataToToken( PK11SlotInfo* slot, // slot to unwrap key onto
+ PK11SymKey* tmpKey, // temporary key to use (must already be on the slot)
+ const BYTE* const data, // pointer to array containing the key data to encrypt and then unwrap (decrypt) on the token
+ const size_t data_len) // length of data in above array
+{
+
+ // ensure expected input data size
+ if (data_len != KEY_DATA_SIZE_BYTES){
+ throw std::runtime_error("Invalid data length value (should be 16) (Copy2Key3DESKeyDataToToken).");
+ }
+
+ // create encryption context
+ SECItem noParams = { siBuffer, NULL, 0 };
+ PK11Context* context = PK11_CreateContextBySymKey(CKM_DES3_ECB, // mechanism type
+ CKA_ENCRYPT, // operation type
+ tmpKey, // symKey to operate on
+ &noParams); // pointer to param (SECItem structure)
+ if (context == NULL) {
+ throw std::runtime_error("Unable to create context (Copy2Key3DESKeyDataToToken).");
+ }
+ try{
+ BYTE encryptedData[KEY_DATA_SIZE_BYTES + 8];
+ BYTE unencryptedData[KEY_DATA_SIZE_BYTES + 8];
+
+ // copy the key data to a new (larger) buffer
+ memcpy(unencryptedData, data, KEY_DATA_SIZE_BYTES);
+
+ // copy first DES key (of the two) into the end of the buffer
+ // (key1-key2-key1)
+ memcpy(unencryptedData + KEY_DATA_SIZE_BYTES, data, 8);
+
+ try{
+
+ // encrypt key data with the temp key
+ int encryptedData_result_len = -1;
+ SECStatus result = PK11_CipherOp( context, // [in] pointer to PK11Context object
+ encryptedData, // [out] pointer to output buffer for encrypted data
+ &encryptedData_result_len, // [out] pointer to output buffer length
+ KEY_DATA_SIZE_BYTES + 8, // [in] size of output buffer
+ unencryptedData, // [in] pointer to input buffer for unencrypted data
+ KEY_DATA_SIZE_BYTES + 8); // [in] size of input buffer
+ if (result != SECSuccess){
+ throw std::runtime_error("Unable to encrypt plaintext key data with temporary key (Copy2Key3DESKeyDataToToken).");
+ }
+ if (encryptedData_result_len != KEY_DATA_SIZE_BYTES + 8){
+ throw std::runtime_error("Invalid output encrypting plaintext key data with temporary key (Copy2Key3DESKeyDataToToken).");
+ }
+
+ // now "unwrap" the encrypted key data onto the token with the temporary key
+ SECItem wrappeditem;
+ wrappeditem.type = siBuffer;
+ wrappeditem.data = encryptedData;
+ wrappeditem.len = encryptedData_result_len;
+ noParams.type = siBuffer;
+ noParams.data = NULL;
+ noParams.len = 0;
+ PK11SymKey* const resultingKey = PK11_UnwrapSymKeyWithFlags(tmpKey, // pointer to wrappingKey (PK11SymKey)
+ CKM_DES3_ECB, // wrapType (CK_MECHANISM_TYPE)
+ &noParams, // pointer to param (SECItem struct)
+ &wrappeditem, // pointer to wrappedKey data (SECItem struct)
+ CKM_DES3_KEY_GEN, // target (CK_MECHANISM_TYPE)
+ CKA_DECRYPT, // operation (CK_ATTRIBUTE_TYPE)
+ KEY_DATA_SIZE_BYTES + 8, // keySize (int)
+ CKF_SIGN | CKF_WRAP | CKF_UNWRAP | CKF_ENCRYPT | CKF_DECRYPT); // flags (CK_FLAGS)
+ if (resultingKey == NULL){
+ throw std::runtime_error("Unable to unwrap key onto token (Copy2Key3DESKeyDataToToken).");
+ }
+
+ // zeroize unencrypted key data before returning
+ memset(unencryptedData, 0, KEY_DATA_SIZE_BYTES + 8);
+
+ // clean up
+ PK11_DestroyContext(context, PR_TRUE);
+
+ return resultingKey;
+ }catch(...){
+ // zeroize unencrypted key data before rethrowing
+ memset(unencryptedData, 0, KEY_DATA_SIZE_BYTES + 8);
+
+ throw;
+ }
+
+ }catch(...){
+ // clean up
+ PK11_DestroyContext(context, PR_TRUE);
+
+ throw;
+ }
+}
+
+//*******************************************************************************
+// 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)
+//*******************************************************************************
+void KDF_CM_SHA256HMAC_L384( PK11SymKey* K_I, // Key Derivation Key
+ const BYTE* context, // unique data passed to the kdf (kdd)
+ const size_t context_length, // length of context
+ const BYTE label, // one BYTE label parameter
+ BYTE* const output, // output is a L-bit array of BYTEs
+ const size_t output_length) // output length must be at least 48 bytes
+{
+ //unsigned int h_bits = SHA256_LENGTH * 8; // SHA256_HMAC output size = 256 bits
+ //unsigned int h_bytes = SHA256_LENGTH; // SHA256_HMAC output size = 32 bytes
+ //const unsigned int r_bits = 8; // The counter will be representable in 8 bits
+ //unsigned int n = L / h_bits; // Number of iterations of the PRF
+ //unsigned int L_BYTE_array_length = (int)ceil(L/256.0);
+
+ const BYTE n = 2; // ceil(384 / (SHA256LENGTH * 8)) == 2
+ const size_t L_BYTE_array_length = 2; // 384 = 0x0180 hex; 2 byte long representation
+
+ // sanity check that output buffer is large enough to contain 384 bits
+ if (output_length < KDF_OUTPUT_SIZE_BYTES){
+ throw std::runtime_error("Array \"output\" must be at least 48 bytes in size.");
+ }
+
+ // calculate size of temporary buffer
+ size_t HMAC_DATA_INPUT_SIZE = context_length + 3 + L_BYTE_array_length; // Don't change without reviewing code below.
+ // prevent integer overflow
+ if (HMAC_DATA_INPUT_SIZE < context_length){
+ throw std::runtime_error("Input parameter \"context_length\" too large.");
+ }
+ BYTE* hmac_data_input = new BYTE[HMAC_DATA_INPUT_SIZE]; // Hash Input = context + 5 BYTES
+
+ BYTE K[n * SHA256_LENGTH]; // BYTE K[n * h_bytes]; - Buffer to store PRF output
+ try{
+ const BYTE L_BYTE_array[L_BYTE_array_length] = {0x01, 0x80}; // Array to store L in BYTES
+
+ /* Establish HMAC Input */
+ memset(hmac_data_input, 0, HMAC_DATA_INPUT_SIZE);
+ hmac_data_input[1] = label;
+ hmac_data_input[2] = 0x00;
+ memcpy(&hmac_data_input[3], context, context_length);
+ memcpy(&hmac_data_input[context_length+3], L_BYTE_array, 2);
+
+ for(BYTE i = 1; i <= n; i++){
+ // hmac_data_input = i || label || 0x00 || context || L
+ hmac_data_input[0] = i;
+
+#ifdef NISTSP800_108_KDF_DEBUG
+ std::cout << "hmac_data_input:\n";
+ print_BYTE_array(hmac_data_input, HMAC_DATA_INPUT_SIZE); // 5 bytes added to context
+#endif
+
+ SHA256HMAC(K_I, hmac_data_input, HMAC_DATA_INPUT_SIZE, &K[(i - 1) * SHA256_LENGTH]);
+ }
+
+ // clean up
+ delete[] hmac_data_input;
+ hmac_data_input = NULL;
+
+ // upon exception, clean up before rethrowing
+ }catch(...){
+ // clean up
+ delete[] hmac_data_input;
+ hmac_data_input = NULL;
+
+ throw;
+ }
+
+#ifdef NISTSP800_108_KDF_DEBUG
+ std::cout << "KDF Output (untrimmed):\n";
+ print_BYTE_array(K, n * SHA256_LENGTH);
+#endif
+
+ // copy result to output buffer, trimming it to 384 bits
+ memcpy(output, K, KDF_OUTPUT_SIZE_BYTES);
+
+ // clear K before returning
+ memset(K, 0, n * SHA256_LENGTH);
+}
+
+//*******************************************************************************
+
+void SHA256HMAC( PK11SymKey* key, // HMAC Secret Key (K_I)
+ const BYTE* input, // HMAC Input (i||04||00||context||0180)
+ const size_t input_length, // Input Length
+ BYTE* const output) // Output Buffer (32 BYTES written)
+{
+ unsigned int len = 32;
+ PK11Context *context = 0;
+ SECStatus s;
+ SECItem noParams;
+ noParams.type = siBuffer;
+ noParams.data = 0;
+ noParams.len = 0;
+
+ context = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, key, &noParams);
+ if (!context) {
+ throw std::runtime_error("CreateContextBySymKey failed");
+ }
+ try{
+
+ s = PK11_DigestBegin(context);
+ if (s != SECSuccess) {
+ throw std::runtime_error("DigestBegin failed");
+ }
+
+ s = PK11_DigestOp(context, input, input_length);
+ if (s != SECSuccess) {
+ throw std::runtime_error("DigestOp failed");
+ }
+
+ s = PK11_DigestFinal(context, output, &len, 32);
+ if (s != SECSuccess) {
+ throw std::runtime_error("DigestFinal failed");
+ }
+
+/* Debug Output */
+#ifdef NISTSP800_108_KDF_DEBUG
+ std::cout << "********************SHA256HMAC_NSS********************\n";
+ std::cout << "\nInput Data:\n";
+ print_BYTE_array(input, input_length);
+ std::cout << "\nSHA256HMAC_NSS output:\n";
+ print_BYTE_array(output, SHA256_LENGTH);
+#endif
+
+ PK11_DestroyContext(context, PR_TRUE);
+ }catch(...){
+ PK11_DestroyContext(context, PR_TRUE);
+ throw;
+ }
+}
+
+//*******************************************************************************
+// DES Parity Functions
+//*******************************************************************************
+
+/* DES KEY Parity conversion table. Takes each byte >> 1 as an index, returns
+ * that byte with the proper parity bit set*/
+const unsigned char parityTable[256] =
+ {
+ /* Even...0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e */
+ /* E */0x01, 0x02, 0x04, 0x07, 0x08, 0x0b, 0x0d, 0x0e,
+ /* Odd....0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e */
+ /* O */0x10, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, 0x1f,
+ /* Odd....0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e */
+ /* O */0x20, 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x2f,
+ /* Even...0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e */
+ /* E */0x31, 0x32, 0x34, 0x37, 0x38, 0x3b, 0x3d, 0x3e,
+ /* Odd....0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e */
+ /* O */0x40, 0x43, 0x45, 0x46, 0x49, 0x4a, 0x4c, 0x4f,
+ /* Even...0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e */
+ /* E */0x51, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, 0x5e,
+ /* Even...0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e */
+ /* E */0x61, 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x6e,
+ /* Odd....0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e */
+ /* O */0x70, 0x73, 0x75, 0x76, 0x79, 0x7a, 0x7c, 0x7f,
+ /* Odd....0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e */
+ /* O */0x80, 0x83, 0x85, 0x86, 0x89, 0x8a, 0x8c, 0x8f,
+ /* Even...0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e */
+ /* E */0x91, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d, 0x9e,
+ /* Even...0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae */
+ /* E */0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xae,
+ /* Odd....0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe */
+ /* O */0xb0, 0xb3, 0xb5, 0xb6, 0xb9, 0xba, 0xbc, 0xbf,
+ /* Even...0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce */
+ /* E */0xc1, 0xc2, 0xc4, 0xc7, 0xc8, 0xcb, 0xcd, 0xce,
+ /* Odd....0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde */
+ /* O */0xd0, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc, 0xdf,
+ /* Odd....0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee */
+ /* O */0xe0, 0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xef,
+ /* Even...0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe */
+ /* E */0xf1, 0xf2, 0xf4, 0xf7, 0xf8, 0xfb, 0xfd, 0xfe, };
+
+void set_des_parity(BYTE* const key, const size_t length)
+{
+ if(length != 2*8){
+ throw std::runtime_error("set_des_parity failed: wrong key size");
+ }
+
+ for (size_t i=0; i < length; i++)
+ {
+ key[i] = parityTable[key[i]>>1];
+ }
+}
+
+//*******************************************************************************
+// BYTE Array Management Functions
+//*******************************************************************************
+#ifdef NISTSP800_108_KDF_DEBUG
+void print_BYTE_array(const BYTE *array2, const size_t length)
+{
+ for (size_t i = 0; i < length; i++){
+ printf("%02x ", array2[i]);
+ if((i+1)%16 == 0)
+ printf("\n");
+ }
+ std::cout << std::endl;
+}
+#endif
+
+//*******************************************************************************
+// NistSP800_108KDF Decision-Making Functions
+//*******************************************************************************
+// Returns true if the new KDF should be used, otherwise false.
+bool useNistSP800_108KDF(BYTE nistSP800_108KDFonKeyVersion, BYTE requestedKeyVersion){
+ return (requestedKeyVersion >= nistSP800_108KDFonKeyVersion);
+}
+
+//*******************************************************************************
+
+} // end namespace NistSP800_108KDF
+
+//*******************************************************************************
diff --git a/base/symkey/src/com/netscape/symkey/NistSP800_108KDF.h b/base/symkey/src/com/netscape/symkey/NistSP800_108KDF.h
new file mode 100644
index 000000000..f26edd5d2
--- /dev/null
+++ b/base/symkey/src/com/netscape/symkey/NistSP800_108KDF.h
@@ -0,0 +1,115 @@
+/*
+ * NistSP800_108KDF.H - Implements the new Key Diversification Function (KDF) as required
+ * by the latest Department of Defense SIPRnet token interface
+ * specification. The functions in this file are internally called
+ * by other functions in the Symkey library. We have made patches
+ * to these other Symkey functions to trigger this new KDF routine
+ * at the appropriate times.
+ *
+ * Also provides a utility function for adding DES key parity.
+ */
+
+#ifndef NISTSP800_108KDF_H_
+#define NISTSP800_108KDF_H_
+
+//*******************************************************************************
+// Defines
+//*******************************************************************************
+// Debug Flag - Enabling this includes <iostream> and results in the NIST SP800-108
+// KDF code printing out lots of stuff (including key material!) to stdout.
+//#define NISTSP800_108_KDF_DEBUG 1
+
+//*******************************************************************************
+// Includes
+//*******************************************************************************
+#include <cstddef> // typedef size_t
+#include <stdexcept> // std::runtime_error
+
+#include "pk11pub.h"
+
+#include "Base.h" // typedef BYTE
+
+//*******************************************************************************
+
+namespace NistSP800_108KDF{
+
+//*******************************************************************************
+// Constants
+//*******************************************************************************
+
+// might already be defined by NSS
+#ifndef SHA256_LENGTH
+#define SHA256_LENGTH 32
+#endif
+
+// AC: don't change any of these constants without validating the code that uses them
+const size_t KDF_OUTPUT_SIZE_BITS = 384;
+const size_t KDF_OUTPUT_SIZE_BYTES = KDF_OUTPUT_SIZE_BITS / 8;
+const size_t KEY_DATA_SIZE_BYTES = KDF_OUTPUT_SIZE_BYTES / 3;
+
+const size_t KDD_SIZE_BYTES = 10; // expected KDD field length in bytes
+
+const BYTE KDF_LABEL = 0x04; // arbitrary input to crypto routine (see documentation)
+
+//*******************************************************************************
+// Function Headers
+//*******************************************************************************
+
+// Generates three PK11SymKey objects using the KDF_CM_SHA256HMAC_L384() function for key data.
+// After calling KDF_CM_SHA256HMAC_L384, the function splits up the output, sets DES parity,
+// and imports the keys into the token.
+//
+// Careful: This function currently generates the key data **IN RAM** using calls to NSS sha256.
+// The key data is then "unwrapped" (imported) to the NSS token and then erased from RAM.
+// (This means that a malicious actor on the box could steal the key data.)
+//
+// Note: Returned key material from the KDF is converted into keys according to the following:
+// * Bytes 0 - 15 : enc/auth key
+// * Bytes 16 - 31 : mac key
+// * Bytes 32 - 47 : kek key
+// We chose this order to conform with the key order used by the PUT KEY command.
+void ComputeCardKeys( PK11SymKey* masterKey, // Key Derivation Key
+ const BYTE* context, // unique data passed to the kdf (kdd)
+ const size_t context_length, // length of context
+ PK11SymKey** encKey, // output parameter: generated enc/auth key
+ PK11SymKey** macKey, // output parameter: generated mac key
+ PK11SymKey** kekKey); // output parameter: generated kek key
+
+// uses the specified temporary key to encrypt and then unwrap (decrypt) the specified binary data onto the specified token
+// this has the net effect of copying the raw key data to the token
+PK11SymKey* Copy2Key3DESKeyDataToToken( PK11SlotInfo* slot, // slot to unwrap key onto
+ PK11SymKey* tmpKey, // temporary key to use (must already be on the slot)
+ const BYTE* const data, // pointer to array containing the key data to encrypt and then unwrap (decrypt) on the token
+ const size_t data_len); // length of data in above array
+
+// calculates 384 bits of diversified output from the provided master key (K_I)
+void KDF_CM_SHA256HMAC_L384( PK11SymKey* K_I, // Key Derivation Key
+ const BYTE* context, // unique data passed to the kdf (kdd)
+ const size_t context_length, // length of context
+ const BYTE label, // one BYTE label parameter
+ BYTE* const output, // output is a L-bit array of BYTEs
+ const size_t output_length); // output length must be at least 48 bytes
+
+void SHA256HMAC( PK11SymKey* key, // HMAC Secret Key (K_I)
+ const BYTE* input, // HMAC Input (i||04||00||context||0180)
+ const size_t input_length, // Input Length
+ BYTE* const output); // Output Buffer (32 BYTES written)
+
+/* DES KEY Parity conversion table. Takes each byte >> 1 as an index, returns
+ * that byte with the proper parity bit set*/
+void set_des_parity(BYTE* const key, const size_t length);
+
+#ifdef NISTSP800_108_KDF_DEBUG
+void print_BYTE_array(const BYTE *array2, const size_t len);
+#endif
+
+// Returns true if the new KDF should be used, otherwise false.
+bool useNistSP800_108KDF(BYTE nistSP800_108KDFonKeyVersion, BYTE requestedKeyVersion);
+
+//*******************************************************************************
+
+} // end namespace NistSP800_108KDF
+
+//*******************************************************************************
+
+#endif /* NISTSP800_108KDF_H_ */
diff --git a/base/symkey/src/com/netscape/symkey/SessionKey.cpp b/base/symkey/src/com/netscape/symkey/SessionKey.cpp
index 9f3a353a3..2c146730f 100644
--- a/base/symkey/src/com/netscape/symkey/SessionKey.cpp
+++ b/base/symkey/src/com/netscape/symkey/SessionKey.cpp
@@ -51,6 +51,10 @@ extern "C"
#include "Buffer.h"
#include "SymKey.h"
+// AC: KDF SPEC CHANGE: Include headers for NIST SP800-108 KDF functions.
+#include "NistSP800_108KDF.h"
+
+
#define STEAL_JSS
#ifdef STEAL_JSS
// stealing code from JSS to handle DRM support
@@ -573,13 +577,15 @@ extern "C"
* Method: ComputeSessionKey
* Signature: ([B[B[B[B)[B
*/
+// AC: KDF SPEC CHANGE: function signature change - added jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeSessionKey
- (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jstring, jstring, jstring);
+ (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyte, jboolean, jbyteArray, jbyteArray, jbyteArray, jstring, jstring, jstring);
#ifdef __cplusplus
}
#endif
#define KEYLENGTH 16
-extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeSessionKey(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyteArray CUID, jbyteArray macKeyArray, jstring useSoftToken_s, jstring keySet, jstring sharedSecretKeyName)
+// AC: KDF SPEC CHANGE: function signature change - added jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
+extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeSessionKey(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, jbyteArray CUID, jbyteArray KDD, jbyteArray macKeyArray, jstring useSoftToken_s, jstring keySet, jstring sharedSecretKeyName)
{
/* hardcore permanent mac key */
jbyte *mac_key = NULL;
@@ -608,8 +614,13 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
PK11SymKey *macSymKey = NULL;
PK11SymKey *symkey16 = NULL;
- PK11SymKey *macKey = NULL;
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF, we build all 3 keys despite only using one of them (Mac) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ // KDF output keys
+ PK11SymKey* macKey = NULL;
+ PK11SymKey* encKey = NULL;
+ PK11SymKey* kekKey = NULL;
BYTE macData[KEYLENGTH];
char keyname[KEYNAMELENGTH];
@@ -625,7 +636,12 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
jbyteArray handleBA=NULL;
jbyte *handleBytes=NULL;
- jbyte * cuidValue = NULL;
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ jbyte* cuidValue = NULL;
+ jsize cuidValue_len = -1;
+ jbyte* kddValue = NULL;
+ jsize kddValue_len = -1;
jbyte *cc = NULL;
int cc_len = 0;
@@ -693,13 +709,30 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
goto done;
}
+
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
if ( CUID != NULL ) {
cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL);
+ cuidValue_len = env->GetArrayLength(CUID);
}
-
if( cuidValue == NULL) {
goto done;
}
+ if ( cuidValue_len <= 0){ // check that CUID is at least 1 byte in length
+ goto done;
+ }
+ if ( KDD != NULL ){
+ kddValue = env->GetByteArrayElements(KDD, NULL);
+ kddValue_len = env->GetArrayLength(KDD);
+ }
+ if ( kddValue == NULL ){
+ goto done;
+ }
+ if ( kddValue_len != static_cast<jsize>(NistSP800_108KDF::KDD_SIZE_BYTES) ){ // check that KDD is expected size
+ goto done;
+ }
+
/* copy card and host challenge into input buffer */
for (i = 0; i < 8; i++)
@@ -711,7 +744,8 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
input[8+i] = hc[i];
}
- GetDiversificationData(cuidValue,macData,mac);//keytype is mac
+ // AC: KDF SPEC CHANGE: Moved this call down. (We don't necessarily need it anymore depending on the KDF we're going to use.)
+ //GetDiversificationData(cuidValue,macData,mac);//keytype is mac
if(tokenName)
{
@@ -753,21 +787,90 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
goto done;
}
- macKey =ComputeCardKeyOnToken(masterKey,macData);
+
+ // ---------------------------------
+ // AC KDF SPEC CHANGE: Determine which KDF to use.
+ //
+ // Convert to unsigned types
+ BYTE nistSP800_108KdfOnKeyVersion_byte = static_cast<BYTE>(nistSP800_108KdfOnKeyVersion);
+ BYTE requestedKeyVersion_byte = static_cast<BYTE>(keyVersion[0]);
+ // if requested key version meets setting value, use NIST SP800-108 KDF
+ if (NistSP800_108KDF::useNistSP800_108KDF(nistSP800_108KdfOnKeyVersion_byte, requestedKeyVersion_byte) == true){
+
+ PR_fprintf(PR_STDOUT,"ComputeSessionKey NistSP800_108KDF code: Using NIST SP800-108 KDF.\n");
+
+ // react to "UseCUIDAsKDD" setting value
+ jbyte* context_jbyte = NULL;
+ jsize context_len_jsize = 0;
+ if (nistSP800_108KdfUseCuidAsKdd == JNI_TRUE){
+ context_jbyte = cuidValue;
+ context_len_jsize = cuidValue_len;
+ }else{
+ context_jbyte = kddValue;
+ context_len_jsize = kddValue_len;
+ }
+
+ // Converting this way is safe since jbyte is guaranteed to be 8 bits
+ // Of course, this assumes that "char" is 8 bits (not guaranteed, but typical),
+ // but it looks like this assumption is also made in GetDiversificationData
+ const BYTE* const context = reinterpret_cast<const BYTE*>(context_jbyte);
+
+ // Convert jsize to size_t
+ const size_t context_len = static_cast<size_t>(context_len_jsize);
+ if (context_len > 0x000000FF){ // sanity check (CUID should never be larger than 255 bytes)
+ PR_fprintf(PR_STDERR, "ComputeSessionKey NistSP800_108KDF code: Error; context_len larger than 255 bytes.\n");
+ goto done;
+ }
+
+ // call NIST SP800-108 KDF routine
+ try{
+ NistSP800_108KDF::ComputeCardKeys(masterKey, context, context_len, &encKey, &macKey, &kekKey);
+ }catch(std::runtime_error& ex){
+ PR_fprintf(PR_STDERR, "ComputeSessionKey NistSP800_108KDF code: Exception invoking NistSP800_108KDF::ComputeCardKeys: ");
+ PR_fprintf(PR_STDERR, "%s\n", ex.what() == NULL ? "null" : ex.what());
+ goto done;
+ }catch(...){
+ PR_fprintf(PR_STDERR, "ComputeSessionKey NistSP800_108KDF code: Unknown exception invoking NistSP800_108KDF::ComputeCardKeys.\n");
+ goto done;
+ }
+
+ // if not a key version where we use the NIST SP800-108 KDF, use the original KDF
+ }else{
+
+ PR_fprintf(PR_STDOUT,"ComputeSessionKey NistSP800_108KDF code: Using original KDF.\n");
+
+ // AC: KDF SPEC CHANGE: Moved this call down from the original location.
+ // (We don't always need to call it anymore; it depends on the KDF we're going to use.)
+ //
+ // Note the change from "cuidValue" to "kddValue".
+ // This change is necessary due to the semantics change in the parameters passed between TPS and TKS.
+ GetDiversificationData(kddValue,macData,mac);//keytype is mac
+
+ // AC: Derives the mac key for the token.
+ macKey =ComputeCardKeyOnToken(masterKey,macData);
+
+ } // endif use original KDF
+ // ---------------------------------
+
+
if(macKey == NULL)
{
goto done;
}
-
+
+ // AC: This computes the GP session key using the card-specific MAC key we previously derived.
symkey = DeriveKey(macKey, Buffer((BYTE*)hc, hc_len), Buffer((BYTE*)cc, cc_len));
- if(symkey == NULL)
- {
- goto done;
- }
}
- //Now wrap the key for the trip back to TPS with shared secret transport key
+ // AC: Moved this check out of the else block so we catch NULL keys in the developer key case
+ // (The call already exists outside the "else" block for ComputeEncSessionKey and ComputeKekKey.)
+ if(symkey == NULL)
+ {
+ goto done;
+ }
+
+ //Now wrap the key for the trip back to TPS with shared secret transport key
symkey16 = NULL;
transportKey = ReturnSymKey( internal, GetSharedSecretKeyName(NULL));
if ( transportKey == NULL ) {
@@ -829,10 +932,20 @@ done:
masterKey = NULL;
}
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF, we build all 3 keys despite only using one of them (Mac) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
if( macKey ) {
PK11_FreeSymKey( macKey);
macKey = NULL;
}
+ if ( encKey ) {
+ PK11_FreeSymKey(encKey);
+ encKey = NULL;
+ }
+ if ( kekKey ) {
+ PK11_FreeSymKey(kekKey);
+ kekKey = NULL;
+ }
if( macSymKey ) {
PK11_FreeSymKey( macSymKey );
@@ -849,7 +962,9 @@ done:
sharedSecretKeyNameChars = NULL;
}
- if ( handleBA != NULL) {
+ // AC BUGFIX: Check the value of handleBytes (not handleBA) before freeing handleBytes!
+ //if ( handleBA != NULL) {
+ if ( handleBytes != NULL) {
(env)->ReleaseByteArrayElements( handleBA, handleBytes, 0);
}
@@ -869,11 +984,22 @@ done:
(env)->ReleaseByteArrayElements(CUID, cuidValue, JNI_ABORT);
}
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ if ( kddValue != NULL){
+ env->ReleaseByteArrayElements(KDD, kddValue, JNI_ABORT);
+ kddValue = NULL;
+ }
+
if( mac_key != NULL) {
(env)->ReleaseByteArrayElements(macKeyArray, mac_key, JNI_ABORT);
}
- return handleBA;
+ // AC: BUGFIX: Don't return a java array with uninitialized or zero'd data.
+ if (wrapStatus != SECFailure ){
+ return handleBA;
+ }else{
+ return NULL;
+ }
}
@@ -886,13 +1012,15 @@ extern "C"
* Method: ComputeEncSessionKey
* Signature: ([B[B[B[B)[B
*/
+// AC: KDF SPEC CHANGE: function signature change - added jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeEncSessionKey
- (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jstring, jstring);
+ (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyte, jboolean, jbyteArray, jbyteArray, jbyteArray, jstring, jstring);
#ifdef __cplusplus
}
#endif
#define KEYLENGTH 16
-extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeEncSessionKey(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyteArray CUID, jbyteArray encKeyArray, jstring useSoftToken_s, jstring keySet)
+// AC: KDF SPEC CHANGE: function signature change - added jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
+extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeEncSessionKey(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, jbyteArray CUID, jbyteArray KDD, jbyteArray encKeyArray, jstring useSoftToken_s, jstring keySet)
{
/* hardcoded permanent enc key */
jbyte *enc_key = NULL;
@@ -919,9 +1047,15 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
PK11SymKey *masterKey = NULL;
PK11SymKey *encSymKey = NULL;
- PK11SymKey *encKey = NULL;
PK11SymKey *symkey16 = NULL;
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF, we build all 3 keys despite only using one of them (Enc) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ // KDF output keys
+ PK11SymKey* macKey = NULL;
+ PK11SymKey* encKey = NULL;
+ PK11SymKey* kekKey = NULL;
+
BYTE encData[KEYLENGTH];
char keyname[KEYNAMELENGTH];
@@ -934,7 +1068,12 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
jbyteArray handleBA=NULL;
jbyte *handleBytes=NULL;
- jbyte * cuidValue = NULL;
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ jbyte* cuidValue = NULL;
+ jsize cuidValue_len = -1;
+ jbyte* kddValue = NULL;
+ jsize kddValue_len = -1;
jbyte *cc = NULL;
int cc_len = 0;
@@ -989,13 +1128,30 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
goto done;
}
- if( CUID != NULL) {
- cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL);
- }
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ if ( CUID != NULL ) {
+ cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL);
+ cuidValue_len = env->GetArrayLength(CUID);
+ }
if( cuidValue == NULL) {
goto done;
}
+ if ( cuidValue_len <= 0){ // check that CUID is at least 1 byte in length
+ goto done;
+ }
+ if ( KDD != NULL ){
+ kddValue = env->GetByteArrayElements(KDD, NULL);
+ kddValue_len = env->GetArrayLength(KDD);
+ }
+ if ( kddValue == NULL ){
+ goto done;
+ }
+ if ( kddValue_len != static_cast<jsize>(NistSP800_108KDF::KDD_SIZE_BYTES) ){ // check that KDD is expected size
+ goto done;
+ }
+
/* copy card and host challenge into input buffer */
for (i = 0; i < 8; i++)
@@ -1007,7 +1163,8 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
input[8+i] = hc[i];
}
- GetDiversificationData(cuidValue,encData,enc);
+ // AC: KDF SPEC CHANGE: Moved this call down. (We don't necessarily need it anymore depending on the KDF we're going to use.)
+ //GetDiversificationData(cuidValue,encData,enc);
if(tokenName)
{
@@ -1044,17 +1201,81 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
{
masterKey = ReturnSymKey( slot,keyname);
- /* We need to use internal so that the key
- * can be exported by using PK11_GetKeyData()
- */
if(masterKey == NULL) {
goto done;
}
- encKey =ComputeCardKeyOnToken(masterKey,encData);
+
+ // ---------------------------------
+ // AC KDF SPEC CHANGE: Determine which KDF to use.
+ //
+ // Convert to unsigned types
+ BYTE nistSP800_108KdfOnKeyVersion_byte = static_cast<BYTE>(nistSP800_108KdfOnKeyVersion);
+ BYTE requestedKeyVersion_byte = static_cast<BYTE>(keyVersion[0]);
+ // if requested key version meets setting value, use NIST SP800-108 KDF
+ if (NistSP800_108KDF::useNistSP800_108KDF(nistSP800_108KdfOnKeyVersion_byte, requestedKeyVersion_byte) == true){
+
+ PR_fprintf(PR_STDOUT,"ComputeEncSessionKey NistSP800_108KDF code: Using NIST SP800-108 KDF.\n");
+
+ // react to "UseCUIDAsKDD" setting value
+ jbyte* context_jbyte = NULL;
+ jsize context_len_jsize = 0;
+ if (nistSP800_108KdfUseCuidAsKdd == JNI_TRUE){
+ context_jbyte = cuidValue;
+ context_len_jsize = cuidValue_len;
+ }else{
+ context_jbyte = kddValue;
+ context_len_jsize = kddValue_len;
+ }
+
+ // Converting this way is safe since jbyte is guaranteed to be 8 bits
+ // Of course, this assumes that "char" is 8 bits (not guaranteed, but typical),
+ // but it looks like this assumption is also made in GetDiversificationData
+ const BYTE* const context = reinterpret_cast<const BYTE*>(context_jbyte);
+
+ // Convert jsize to size_t
+ const size_t context_len = static_cast<size_t>(context_len_jsize);
+ if (context_len > 0x000000FF){ // sanity check (CUID should never be larger than 255 bytes)
+ PR_fprintf(PR_STDERR, "ComputeEncSessionKey NistSP800_108KDF code: Error; context_len larger than 255 bytes.\n");
+ goto done;
+ }
+
+ // call NIST SP800-108 KDF routine
+ try{
+ NistSP800_108KDF::ComputeCardKeys(masterKey, context, context_len, &encKey, &macKey, &kekKey);
+ }catch(std::runtime_error& ex){
+ PR_fprintf(PR_STDERR, "ComputeEncSessionKey NistSP800_108KDF code: Exception invoking NistSP800_108KDF::ComputeCardKeys: ");
+ PR_fprintf(PR_STDERR, "%s\n", ex.what() == NULL ? "null" : ex.what());
+ goto done;
+ }catch(...){
+ PR_fprintf(PR_STDERR, "ComputeEncSessionKey NistSP800_108KDF code: Unknown exception invoking NistSP800_108KDF::ComputeCardKeys.\n");
+ goto done;
+ }
+
+ // if not a key version where we use the NIST SP800-108 KDF, use the original KDF
+ }else{
+
+ PR_fprintf(PR_STDOUT,"ComputeEncSessionKey NistSP800_108KDF code: Using original KDF.\n");
+
+ // AC: KDF SPEC CHANGE: Moved this call down from the original location.
+ // (We don't always need to call it anymore; it depends on the KDF we're going to use.)
+ //
+ // Note the change from "cuidValue" to "kddValue".
+ // This change is necessary due to the semantics change in the parameters passed between TPS and TKS.
+ GetDiversificationData(kddValue,encData,enc);
+
+ // AC: Derives the enc key for the token.
+ encKey =ComputeCardKeyOnToken(masterKey,encData);
+
+ } // endif use original KDF
+ // ---------------------------------
+
+
if(encKey == NULL) {
goto done;
}
+
+ // AC: This computes the GP session key using the card-specific ENC key we previously derived.
symkey = DeriveKey(encKey, Buffer((BYTE*)hc, hc_len), Buffer((BYTE*)cc, cc_len));
}
@@ -1127,9 +1348,19 @@ done:
encSymKey = NULL;
}
- if( encKey) {
- PK11_FreeSymKey( encKey);
- encKey = NULL;
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF, we build all 3 keys despite only using one of them (Enc) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ if( macKey ) {
+ PK11_FreeSymKey(macKey);
+ macKey = NULL;
+ }
+ if ( encKey) {
+ PK11_FreeSymKey( encKey);
+ encKey = NULL;
+ }
+ if ( kekKey ) {
+ PK11_FreeSymKey(kekKey);
+ kekKey = NULL;
}
if( keySetStringChars ) {
@@ -1156,11 +1387,22 @@ done:
(env)->ReleaseByteArrayElements(CUID, cuidValue, JNI_ABORT);
}
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ if ( kddValue != NULL){
+ env->ReleaseByteArrayElements(KDD, kddValue, JNI_ABORT);
+ kddValue = NULL;
+ }
+
if( enc_key != NULL) {
(env)->ReleaseByteArrayElements(encKeyArray, enc_key, JNI_ABORT);
}
- return handleBA;
+ // AC: BUGFIX: Don't return a java array with uninitialized or zero'd data.
+ if (wrapStatus != SECFailure ){
+ return handleBA;
+ }else{
+ return NULL;
+ }
}
#ifdef __cplusplus
@@ -1172,14 +1414,16 @@ extern "C"
* Method: ComputeKekKey
* Signature: ([B[B[B[B)[B
*/
+// AC: KDF SPEC CHANGE: function signature change - added jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_ComputeKekKey
- (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jstring, jstring);
+ (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyte, jboolean, jbyteArray, jbyteArray, jbyteArray, jstring, jstring);
#ifdef __cplusplus
}
#endif
#define KEYLENGTH 16
-extern "C" JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_ComputeKekKey(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyteArray CUID, jbyteArray kekKeyArray, jstring useSoftToken_s, jstring keySet)
+// AC: KDF SPEC CHANGE: function signature change - added jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
+extern "C" JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_ComputeKekKey(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, jbyteArray CUID, jbyteArray KDD, jbyteArray kekKeyArray, jstring useSoftToken_s, jstring keySet)
{
/* hardcoded permanent kek key */
jbyte *kek_key = NULL;
@@ -1210,13 +1454,25 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_Compute
jbyte *hc = NULL;
jbyte * keyVersion = NULL;
int keyVersion_len = 0;
- jbyte * cuidValue = NULL;
+
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ jbyte* cuidValue = NULL;
+ jsize cuidValue_len = -1;
+ jbyte* kddValue = NULL;
+ jsize kddValue_len = -1;
char *keyNameChars=NULL;
char *tokenNameChars = NULL;
PK11SlotInfo *slot = NULL;
- PK11SymKey *kekKey = NULL;
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF, we build all 3 keys despite only using one of them (KEK) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ // KDF output keys
+ PK11SymKey* macKey = NULL;
+ PK11SymKey* encKey = NULL;
+ PK11SymKey* kekKey = NULL;
+
PK11SymKey *masterKey = NULL;
BYTE kekData[KEYLENGTH];
@@ -1249,13 +1505,30 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_Compute
goto done;
}
- if( CUID != NULL) {
- cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL);
- }
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ if ( CUID != NULL ) {
+ cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL);
+ cuidValue_len = env->GetArrayLength(CUID);
+ }
if( cuidValue == NULL) {
goto done;
}
+ if ( cuidValue_len <= 0){ // check that CUID is at least 1 byte in length
+ goto done;
+ }
+ if ( KDD != NULL ){
+ kddValue = env->GetByteArrayElements(KDD, NULL);
+ kddValue_len = env->GetArrayLength(KDD);
+ }
+ if ( kddValue == NULL ){
+ goto done;
+ }
+ if ( kddValue_len != static_cast<jsize>(NistSP800_108KDF::KDD_SIZE_BYTES) ){ // check that KDD is expected size
+ goto done;
+ }
+
/* copy card and host challenge into input buffer */
for (i = 0; i < 8; i++)
@@ -1267,7 +1540,8 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_Compute
input[8+i] = hc[i];
}
- GetDiversificationData(cuidValue,kekData,kek);//keytype is kek
+ // AC: KDF SPEC CHANGE: Moved this call down. (We don't necessarily need it anymore depending on the KDF we're going to use.)
+ //GetDiversificationData(cuidValue,kekData,kek);//keytype is kek
if (tokenName)
{
@@ -1301,7 +1575,71 @@ extern "C" JNIEXPORT jobject JNICALL Java_com_netscape_symkey_SessionKey_Compute
goto done;
}
- kekKey =ComputeCardKeyOnToken(masterKey,kekData);
+
+ // ---------------------------------
+ // AC KDF SPEC CHANGE: Determine which KDF to use.
+ //
+ // Convert to unsigned types
+ BYTE nistSP800_108KdfOnKeyVersion_byte = static_cast<BYTE>(nistSP800_108KdfOnKeyVersion);
+ BYTE requestedKeyVersion_byte = static_cast<BYTE>(keyVersion[0]);
+ // if requested key version meets setting value, use NIST SP800-108 KDF
+ if (NistSP800_108KDF::useNistSP800_108KDF(nistSP800_108KdfOnKeyVersion_byte, requestedKeyVersion_byte) == true){
+
+ PR_fprintf(PR_STDOUT,"ComputeKekKey NistSP800_108KDF code: Using NIST SP800-108 KDF.\n");
+
+ // react to "UseCUIDAsKDD" setting value
+ jbyte* context_jbyte = NULL;
+ jsize context_len_jsize = 0;
+ if (nistSP800_108KdfUseCuidAsKdd == JNI_TRUE){
+ context_jbyte = cuidValue;
+ context_len_jsize = cuidValue_len;
+ }else{
+ context_jbyte = kddValue;
+ context_len_jsize = kddValue_len;
+ }
+
+ // Converting this way is safe since jbyte is guaranteed to be 8 bits
+ // Of course, this assumes that "char" is 8 bits (not guaranteed, but typical),
+ // but it looks like this assumption is also made in GetDiversificationData
+ const BYTE* const context = reinterpret_cast<const BYTE*>(context_jbyte);
+
+ // Convert jsize to size_t
+ const size_t context_len = static_cast<size_t>(context_len_jsize);
+ if (context_len > 0x000000FF){ // sanity check (CUID should never be larger than 255 bytes)
+ PR_fprintf(PR_STDERR, "ComputeKekKey NistSP800_108KDF code: Error; context_len larger than 255 bytes.\n");
+ goto done;
+ }
+
+ // call NIST SP800-108 KDF routine
+ try{
+ NistSP800_108KDF::ComputeCardKeys(masterKey, context, context_len, &encKey, &macKey, &kekKey);
+ }catch(std::runtime_error& ex){
+ PR_fprintf(PR_STDERR, "ComputeKekKey NistSP800_108KDF code: Exception invoking NistSP800_108KDF::ComputeCardKeys: ");
+ PR_fprintf(PR_STDERR, "%s\n", ex.what() == NULL ? "null" : ex.what());
+ goto done;
+ }catch(...){
+ PR_fprintf(PR_STDERR, "ComputeKekKey NistSP800_108KDF code: Unknown exception invoking NistSP800_108KDF::ComputeCardKeys.\n");
+ goto done;
+ }
+
+ // if not a key version where we use the NIST SP800-108 KDF, use the original KDF
+ }else{
+
+ PR_fprintf(PR_STDOUT,"ComputeKekKey NistSP800_108KDF code: Using original KDF.\n");
+
+ // AC: KDF SPEC CHANGE: Moved this call down from the original location.
+ // (We don't always need to call it anymore; it depends on the KDF we're going to use.)
+ //
+ // Note the change from "cuidValue" to "kddValue".
+ // This change is necessary due to the semantics change in the parameters passed between TPS and TKS.
+ GetDiversificationData(kddValue,kekData,kek);//keytype is kek
+
+ // AC: Derives the mac key for the token.
+ kekKey =ComputeCardKeyOnToken(masterKey,kekData);
+
+ } // endif use original KDF
+ // ---------------------------------
+
}
@@ -1323,6 +1661,16 @@ done:
masterKey = NULL;
}
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF, we build all 3 keys despite only using one of them (Kek) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ if( macKey ) {
+ PK11_FreeSymKey(macKey);
+ macKey = NULL;
+ }
+ if ( encKey ) {
+ PK11_FreeSymKey(encKey);
+ encKey = NULL;
+ }
if(kekKey) {
PK11_FreeSymKey( kekKey);
kekKey = NULL;
@@ -1349,6 +1697,12 @@ done:
(env)->ReleaseByteArrayElements(CUID, cuidValue, JNI_ABORT);
}
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ if ( kddValue != NULL){
+ env->ReleaseByteArrayElements(KDD, kddValue, JNI_ABORT);
+ kddValue = NULL;
+ }
+
return keyObj;
}
@@ -1498,13 +1852,15 @@ extern "C"
* Method: ComputeCryptogram
* Signature: ([B[B[B[B)[B
*/
+// AC: KDF SPEC CHANGE: function signature change - added jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeCryptogram
- (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyteArray, int, jbyteArray, jstring, jstring);
+ (JNIEnv *, jclass, jstring, jstring, jbyteArray, jbyteArray, jbyteArray, jbyte, jboolean, jbyteArray, jbyteArray, int, jbyteArray, jstring, jstring);
#ifdef __cplusplus
}
#endif
#define KEYLENGTH 16
-extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeCryptogram(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyteArray CUID, int type, jbyteArray authKeyArray, jstring useSoftToken_s, jstring keySet)
+// AC: KDF SPEC CHANGE: function signature change - added jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
+extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_ComputeCryptogram(JNIEnv * env, jclass this2, jstring tokenName, jstring keyName, jbyteArray card_challenge, jbyteArray host_challenge, jbyteArray keyInfo, jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, jbyteArray CUID, jbyteArray KDD, int type, jbyteArray authKeyArray, jstring useSoftToken_s, jstring keySet)
{
/* hardcore permanent mac key */
jbyte *auth_key = NULL;
@@ -1542,7 +1898,13 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
int hc_len = 0;
jbyte * keyVersion = NULL;
int keyVersion_len = 0;
- jbyte * cuidValue = NULL;
+
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ jbyte* cuidValue = NULL;
+ jsize cuidValue_len = -1;
+ jbyte* kddValue = NULL;
+ jsize kddValue_len = -1;
char *tokenNameChars = NULL;
char *keyNameChars=NULL;
@@ -1551,13 +1913,22 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
jbyte * session_key = NULL;
PK11SymKey *symkey = NULL;
PK11SymKey *masterKey = NULL;
- PK11SymKey *authKey = NULL;
PK11SymKey *authSymKey = NULL;
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF, we build all 3 keys despite only using one of them (Enc/Auth) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ // KDF output keys
+ PK11SymKey* macKey = NULL;
+ PK11SymKey* authKey = NULL;
+ PK11SymKey* kekKey = NULL;
+
BYTE authData[KEYLENGTH];
char keyname[KEYNAMELENGTH];
Buffer input_x = Buffer(KEYLENGTH);
+ // AC: BUGFIX: Don't return a java array with uninitialized or zero'd data.
+ bool error_computing_result = true;
+
if( card_challenge != NULL ) {
cc = (jbyte*)(env)->GetByteArrayElements( card_challenge, NULL);
cc_len = (env)->GetArrayLength(card_challenge);
@@ -1587,13 +1958,30 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
goto done;
}
- if( CUID != NULL) {
- cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL);
- }
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ if ( CUID != NULL ) {
+ cuidValue = (jbyte*)(env)->GetByteArrayElements( CUID, NULL);
+ cuidValue_len = env->GetArrayLength(CUID);
+ }
if( cuidValue == NULL) {
goto done;
}
+ if ( cuidValue_len <= 0){ // check that CUID is at least 1 byte in length
+ goto done;
+ }
+ if ( KDD != NULL ){
+ kddValue = env->GetByteArrayElements(KDD, NULL);
+ kddValue_len = env->GetArrayLength(KDD);
+ }
+ if ( kddValue == NULL ){
+ goto done;
+ }
+ if ( kddValue_len != static_cast<jsize>(NistSP800_108KDF::KDD_SIZE_BYTES) ){ // check that KDD is expected size
+ goto done;
+ }
+
if (type == 0) // compute host cryptogram
{
@@ -1621,7 +2009,8 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
input_x.replace(0, (BYTE*) input, KEYLENGTH);
- GetDiversificationData(cuidValue,authData,enc);
+ // AC: KDF SPEC CHANGE: Moved this call down. (We don't necessarily need it anymore depending on the KDF we're going to use.)
+ //GetDiversificationData(cuidValue,authData,enc);
if (tokenName)
{
@@ -1660,12 +2049,78 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
goto done;
}
- authKey = ComputeCardKeyOnToken(masterKey,authData);
+
+ // ---------------------------------
+ // AC KDF SPEC CHANGE: Determine which KDF to use.
+ //
+ // Convert to unsigned types
+ BYTE nistSP800_108KdfOnKeyVersion_byte = static_cast<BYTE>(nistSP800_108KdfOnKeyVersion);
+ BYTE requestedKeyVersion_byte = static_cast<BYTE>(keyVersion[0]);
+ // if requested key version meets setting value, use NIST SP800-108 KDF
+ if (NistSP800_108KDF::useNistSP800_108KDF(nistSP800_108KdfOnKeyVersion_byte, requestedKeyVersion_byte) == true){
+
+ PR_fprintf(PR_STDOUT,"ComputeCryptogram NistSP800_108KDF code: Using NIST SP800-108 KDF.\n");
+
+ // react to "UseCUIDAsKDD" setting value
+ jbyte* context_jbyte = NULL;
+ jsize context_len_jsize = 0;
+ if (nistSP800_108KdfUseCuidAsKdd == JNI_TRUE){
+ context_jbyte = cuidValue;
+ context_len_jsize = cuidValue_len;
+ }else{
+ context_jbyte = kddValue;
+ context_len_jsize = kddValue_len;
+ }
+
+ // Converting this way is safe since jbyte is guaranteed to be 8 bits
+ // Of course, this assumes that "char" is 8 bits (not guaranteed, but typical),
+ // but it looks like this assumption is also made in GetDiversificationData
+ const BYTE* const context = reinterpret_cast<const BYTE*>(context_jbyte);
+
+ // Convert jsize to size_t
+ const size_t context_len = static_cast<size_t>(context_len_jsize);
+ if (context_len > 0x000000FF){ // sanity check (CUID should never be larger than 255 bytes)
+ PR_fprintf(PR_STDERR, "ComputeCryptogram NistSP800_108KDF code: Error; context_len larger than 255 bytes.\n");
+ goto done;
+ }
+
+ // call NIST SP800-108 KDF routine
+ try{
+ NistSP800_108KDF::ComputeCardKeys(masterKey, context, context_len, &authKey, &macKey, &kekKey);
+ }catch(std::runtime_error& ex){
+ PR_fprintf(PR_STDERR, "ComputeCryptogram NistSP800_108KDF code: Exception invoking NistSP800_108KDF::ComputeCardKeys: ");
+ PR_fprintf(PR_STDERR, "%s\n", ex.what() == NULL ? "null" : ex.what());
+ goto done;
+ }catch(...){
+ PR_fprintf(PR_STDERR, "ComputeCryptogram NistSP800_108KDF code: Unknown exception invoking NistSP800_108KDF::ComputeCardKeys.\n");
+ goto done;
+ }
+
+ // if not a key version where we use the NIST SP800-108 KDF, use the original KDF
+ }else{
+
+ PR_fprintf(PR_STDOUT,"ComputeCryptogram NistSP800_108KDF code: Using original KDF.\n");
+
+ // AC: KDF SPEC CHANGE: Moved this call down from the original location.
+ // (We don't always need to call it anymore; it depends on the KDF we're going to use.)
+ //
+ // Note the change from "cuidValue" to "kddValue".
+ // This change is necessary due to the semantics change in the parameters passed between TPS and TKS.
+ GetDiversificationData(kddValue,authData,enc);
+
+ // AC: Derives the mac key for the token.
+ authKey = ComputeCardKeyOnToken(masterKey,authData);
+
+ } // endif use original KDF
+ // ---------------------------------
+
+
if (authKey == NULL)
{
goto done;
}
+ // AC: This computes the GP session key using the card-specific ENC key we previously derived.
symkey = DeriveKey(authKey,
Buffer((BYTE*)hc, hc_len), Buffer((BYTE*)cc, cc_len));
@@ -1678,6 +2133,10 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Comp
handleBytes = (env)->GetByteArrayElements(handleBA, NULL);
if( handleBytes ) {
memcpy(handleBytes, session_key, EIGHT_BYTES);
+
+ // AC: BUGFIX: Don't return a java array with uninitialized or zero'd data.
+ // Set flag that we've successfully copied.
+ error_computing_result = false;
}
done:
@@ -1697,10 +2156,20 @@ done:
authSymKey = NULL;
}
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF, we build all 3 keys despite only using one of them (Enc/Auth) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ if( macKey ) {
+ PK11_FreeSymKey(macKey);
+ macKey = NULL;
+ }
if( authKey) {
PK11_FreeSymKey( authKey);
authKey = NULL;
}
+ if ( kekKey ) {
+ PK11_FreeSymKey(kekKey);
+ kekKey = NULL;
+ }
if( masterKey) {
PK11_FreeSymKey( masterKey);
@@ -1732,7 +2201,18 @@ done:
(env)->ReleaseByteArrayElements(CUID, cuidValue, JNI_ABORT);
}
- return handleBA;
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ if ( kddValue != NULL){
+ env->ReleaseByteArrayElements(KDD, kddValue, JNI_ABORT);
+ kddValue = NULL;
+ }
+
+ // AC: BUGFIX: Don't return a java array with uninitialized or zero'd data.
+ if (error_computing_result == false){
+ return handleBA;
+ }else{
+ return NULL;
+ }
}
diff --git a/base/symkey/src/com/netscape/symkey/SessionKey.java b/base/symkey/src/com/netscape/symkey/SessionKey.java
index 56782aad9..d44cc5479 100644
--- a/base/symkey/src/com/netscape/symkey/SessionKey.java
+++ b/base/symkey/src/com/netscape/symkey/SessionKey.java
@@ -79,7 +79,10 @@ public class SessionKey {
byte[] card_challenge,
byte[] host_challenge,
byte[] keyInfo,
+ byte nistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE
+ boolean nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE
byte[] CUID,
+ byte[] KDD, // AC: KDF SPEC CHANGE
byte[] macKeyArray,
String useSoftToken,
String keySet,
@@ -90,11 +93,15 @@ public class SessionKey {
byte[] card_challenge,
byte[] host_challenge,
byte[] keyInfo,
+ byte nistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE
+ boolean nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE
byte[] CUID,
+ byte[] KDD, // AC: KDF SPEC CHANGE
byte[] encKeyArray,
String useSoftToken,
String keySet);
+ /* AC: KDF SPEC CHANGE; unused method with no JNI implementation
public static native PK11SymKey ComputeKekSessionKey(String tokenName,
String keyName,
byte[] card_challenge,
@@ -104,13 +111,17 @@ public class SessionKey {
byte[] kekKeyArray,
String useSoftToken,
String keySet);
+ */
public static native PK11SymKey ComputeKekKey(String tokenName,
String keyName,
byte[] card_challenge,
byte[] host_challenge,
byte[] keyInfo,
+ byte nistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE
+ boolean nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE
byte[] CUID,
+ byte[] KDD, // AC: KDF SPEC CHANGE
byte[] kekKeyArray,
String useSoftToken, String keySet);
@@ -130,7 +141,10 @@ public class SessionKey {
byte[] card_challenge,
byte[] host_challenge,
byte[] keyInfo,
+ byte nistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE
+ boolean nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE
byte[] CUID,
+ byte[] KDD, // AC: KDF SPEC CHANGE
int type,
byte[] authKeyArray,
String useSoftToken, String keySet);
@@ -139,7 +153,10 @@ public class SessionKey {
String keyName,
byte[] in,
byte[] keyInfo,
+ byte nistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE
+ boolean nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE
byte[] CUID,
+ byte[] KDD, // AC: KDF SPEC CHANGE
byte[] kekKeyArray,
String useSoftToken, String keySet);
@@ -147,8 +164,14 @@ public class SessionKey {
String newTokenName,
String oldMasterKeyName,
String newMasterKeyName,
- String keyInfo,
+ byte[] oldKeyInfo, // AC: KDF SPEC CHANGE
+ // AC: BUGFIX for key versions higher than 09: We need to specialDecode keyInfo parameters before sending them into symkey! This means the parameters must be jbyteArray's
+ // -- Changed parameter "jstring keyInfo" to "jbyteArray newKeyInfo"
+ byte[] newKeyInfo,
+ byte nistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE
+ boolean nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE
byte[] CUIDValue,
+ byte[] KDD, // AC: KDF SPEC CHANGE
byte[] kekKeyArray,
String useSoftToken, String keySet);
diff --git a/base/symkey/src/com/netscape/symkey/SymKey.cpp b/base/symkey/src/com/netscape/symkey/SymKey.cpp
index 758156677..6e206db54 100644
--- a/base/symkey/src/com/netscape/symkey/SymKey.cpp
+++ b/base/symkey/src/com/netscape/symkey/SymKey.cpp
@@ -69,6 +69,9 @@ extern "C"
#include "Buffer.h"
#include "SymKey.h"
+// AC: KDF SPEC CHANGE: Include headers for NIST SP800-108 KDF functions.
+#include "NistSP800_108KDF.h"
+
typedef unsigned char BYTE;
typedef struct
@@ -152,15 +155,17 @@ PK11SymKey * ReturnSymKey( PK11SlotInfo *slot, char *keyname)
firstSymKey = PK11_ListFixedKeysInSlot( slot , NULL, ( void *) &pwdata );
/* scan through the symmetric key list for a key matching our nickname */
sk = firstSymKey;
- while( sk != NULL )
+ // AC: Stop iteration if we've found the key
+ while(( sk != NULL ) && (foundSymKey == NULL))
{
/* get the nickname of this symkey */
name = PK11_GetSymKeyNickname( sk );
/* if the name matches, make a 'copy' of it */
- if ( name != NULL && !strcmp( keyname, name ))
+ // AC BUGFIX: Don't leak key name string memory if name isn't equal to keyname
+ if ( name != NULL )
{
- if (foundSymKey == NULL)
+ if ((foundSymKey == NULL) && (strcmp( keyname, name ) == 0))
{
foundSymKey = PK11_ReferenceSymKey(sk);
}
@@ -659,6 +664,8 @@ PRStatus EncryptData(const Buffer &kek_key,PK11SymKey *cardKey, Buffer &input, B
#ifdef DES2_WORKAROUND
unsigned char masterKeyData[DES3_LENGTH];
#else
+// AC: Prevent broken code from compiling.
+#error "This code will not work unless DES2_WORKAROUND is defined!!! (memcpy below writes beyond array bounds)"
unsigned char masterKeyData[KEYLENGTH];
#endif
unsigned char result[EIGHT_BYTES];
@@ -987,20 +994,22 @@ void GetDiversificationData(jbyte *cuidValue,BYTE *KDC,keyType keytype)
}
-static int getMasterKeyVersion(char *newMasterKeyNameChars)
-{
- if( newMasterKeyNameChars == NULL ||
- strlen( newMasterKeyNameChars) < 3) {
- return 0;
- }
-
- char masterKeyVersionNumber[3];
- masterKeyVersionNumber[0]=newMasterKeyNameChars[1];
- masterKeyVersionNumber[1]=newMasterKeyNameChars[2];
- masterKeyVersionNumber[2]=0;
- int newMasterKeyVesion = atoi(masterKeyVersionNumber);
- return newMasterKeyVesion;
-}
+// AC: BUGFIX for key versions higher than 09: We need to specialDecode keyInfo parameters before sending them into symkey!
+// (atoi doesn't do the same thing as specialDecode does; since we're decoding on the Java side, this function is unnecessary)
+//static int getMasterKeyVersion(char *newMasterKeyNameChars)
+//{
+// if( newMasterKeyNameChars == NULL ||
+// strlen( newMasterKeyNameChars) < 3) {
+// return 0;
+// }
+//
+// char masterKeyVersionNumber[3];
+// masterKeyVersionNumber[0]=newMasterKeyNameChars[1];
+// masterKeyVersionNumber[1]=newMasterKeyNameChars[2];
+// masterKeyVersionNumber[2]=0;
+// int newMasterKeyVesion = atoi(masterKeyVersionNumber);
+// return newMasterKeyVesion;
+//}
char *GetSharedSecretKeyName(char *newKeyName) {
if ( newKeyName && strlen( newKeyName ) > 0 ) {
@@ -1030,10 +1039,16 @@ void getFullName(char * fullMasterKeyName, char * masterKeyNameChars )
* Method: DiversifyKey
* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[B)[B
*/
+// AC: KDF SPEC CHANGE: function signature change - added jstring oldKeyInfo, jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
+// AC: BUGFIX for key versions higher than 09: We need to specialDecode keyInfo parameters before sending them into symkey! This means the parameters must be jbyteArray's
+// -- Changed parameter "jstring keyInfo" to "jbyteArray newKeyInfo"
extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_DiversifyKey
-(JNIEnv *, jclass, jstring, jstring, jstring, jstring, jstring, jbyteArray, jbyteArray, jstring, jstring);
+(JNIEnv *, jclass, jstring, jstring, jstring, jstring, jbyteArray, jbyteArray, jbyte, jboolean, jbyteArray, jbyteArray, jbyteArray, jstring, jstring);
-extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_DiversifyKey( JNIEnv * env, jclass this2, jstring tokenName,jstring newTokenName, jstring oldMasterKeyName, jstring newMasterKeyName, jstring keyInfo, jbyteArray CUIDValue, jbyteArray kekKeyArray, jstring useSoftToken_s, jstring keySet)
+// AC: KDF SPEC CHANGE: function signature change - added jstring oldKeyInfo, jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, and jbyteArray KDD
+// AC: BUGFIX for key versions higher than 09: We need to specialDecode keyInfo parameters before sending them into symkey! This means the parameters must be jbyteArray's
+// -- Changed parameter "jstring keyInfo" to "jbyteArray newKeyInfo"
+extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_DiversifyKey( JNIEnv * env, jclass this2, jstring tokenName,jstring newTokenName, jstring oldMasterKeyName, jstring newMasterKeyName, jbyteArray oldKeyInfo, jbyteArray newKeyInfo, jbyte nistSP800_108KdfOnKeyVersion, jboolean nistSP800_108KdfUseCuidAsKdd, jbyteArray CUIDValue, jbyteArray KDD, jbyteArray kekKeyArray, jstring useSoftToken_s, jstring keySet)
{
PK11SymKey *encKey = NULL;
PK11SymKey *macKey = NULL;
@@ -1047,7 +1062,13 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Dive
char fullMasterKeyName[KEYNAMELENGTH];
char fullNewMasterKeyName[KEYNAMELENGTH];
PRBool specified_key_is_present = PR_TRUE;
- PK11SymKey *old_kek_sym_key = NULL;
+
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF being used for old key version, we build all 3 old keys despite only using one of them (Kek) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ // KDF output keys
+ PK11SymKey* old_mac_sym_key = NULL;
+ PK11SymKey* old_enc_sym_key = NULL;
+ PK11SymKey* old_kek_sym_key = NULL;
char *keySetStringChars = NULL;
if ( keySet != NULL ) {
@@ -1062,7 +1083,19 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Dive
jbyteArray handleBA=NULL;
jbyte *handleBytes=NULL;
- int newMasterKeyVesion = 1;
+
+
+ // AC: BUGFIX for key versions higher than 09
+ // No longer need this variable (it's misspelled anyway) and it's the wrong type.
+ // int newMasterKeyVesion = 1;
+
+ // AC: BUGFIX for key versions higher than 09
+ // New variables used for JNI retrieval.
+ jbyte* oldKeyInfo_jbyteptr = NULL;
+ jbyte* newKeyInfo_jbyteptr = NULL;
+ jsize oldKeyInfo_jbyteptr_len = -1;
+ jsize newKeyInfo_jbyteptr_len = -1;
+
/* find slot */
char *tokenNameChars = NULL;
@@ -1075,7 +1108,19 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Dive
char * newTokenNameChars = NULL;
char *keyInfoChars = NULL;
- jbyte * cuidValue = NULL;
+ // AC: KDF SPEC CHANGE: Need to retrieve old key info from JNI.
+ char* oldKeyInfoChars = NULL;
+
+ // AC: KDF SPEC CHANGE: Convert new setting value to BYTE (unsigned).
+ BYTE nistSP800_108KdfOnKeyVersion_byte = static_cast<BYTE>(nistSP800_108KdfOnKeyVersion);
+
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ jbyte* cuidValue = NULL;
+ jsize cuidValue_len = -1;
+ jbyte* kddValue = NULL;
+ jsize kddValue_len = -1;
+
jbyte * old_kek_key = NULL;
PK11SymKey * masterKey = NULL;
@@ -1085,13 +1130,37 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Dive
BYTE KDCmac[KEYLENGTH];
BYTE KDCkek[KEYLENGTH];
- if( CUIDValue != NULL) {
- cuidValue = (jbyte*)(env)->GetByteArrayElements( CUIDValue, NULL);
- }
+ // AC: BUGFIX for key versions higher than 09: New code to retrieve oldKeyInfo and newKeyInfo byte arrays from JNI.
+ BYTE oldKeyVersion;
+ BYTE newKeyVersion;
+
+ // AC: BUGFIX: Don't return a java array with uninitialized or zero'd data.
+ bool error_computing_result = true;
+
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ // Also added "len" variable for CUID (for sanity check).
+ if ( CUIDValue != NULL ) {
+ cuidValue = (jbyte*)(env)->GetByteArrayElements( CUIDValue, NULL);
+ cuidValue_len = env->GetArrayLength(CUIDValue);
+ }
if( cuidValue == NULL) {
goto done;
}
+ if ( cuidValue_len <= 0){ // check that CUID is at least 1 byte in length
+ goto done;
+ }
+ if ( KDD != NULL ){
+ kddValue = env->GetByteArrayElements(KDD, NULL);
+ kddValue_len = env->GetArrayLength(KDD);
+ }
+ if ( kddValue == NULL ){
+ goto done;
+ }
+ if ( kddValue_len != static_cast<jsize>(NistSP800_108KDF::KDD_SIZE_BYTES) ){ // check that KDD is expected size
+ goto done;
+ }
+
if( kekKeyArray != NULL) {
old_kek_key = (jbyte*)(env)->GetByteArrayElements(kekKeyArray, NULL);
@@ -1103,9 +1172,12 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Dive
PR_fprintf(PR_STDOUT,"In SessionKey.DiversifyKey! \n");
- GetDiversificationData(cuidValue,KDCenc,enc);
- GetDiversificationData(cuidValue,KDCmac,mac);
- GetDiversificationData(cuidValue,KDCkek,kek);
+ // AC: KDF SPEC CHANGE:
+ // Changed from "cuidValue" to "kddValue".
+ // This change is necessary due to the semantics change in the parameters passed between TPS and TKS.
+ GetDiversificationData(kddValue,KDCenc,enc);
+ GetDiversificationData(kddValue,KDCmac,mac);
+ GetDiversificationData(kddValue,KDCkek,kek);
if(tokenName)
{
@@ -1142,20 +1214,56 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Dive
(env)->ReleaseStringUTFChars(newMasterKeyName, (const char *)newMasterKeyNameChars);
}
- /* packing return */
- if( keyInfo != NULL) {
- keyInfoChars = (char *)(env)->GetStringUTFChars(keyInfo, NULL);
- }
- newMasterKeyVesion = getMasterKeyVersion(keyInfoChars);
- if(keyInfoChars)
- {
- (env)->ReleaseStringUTFChars(keyInfo, (const char *)keyInfoChars);
+ // AC: BUGFIX for key versions higher than 09: Since "jstring keyInfo" is now passed in as "jbyteArray newKeyInfo", we no longer need this code.
+ //
+ ///* packing return */
+ //if( keyInfo != NULL) {
+ // keyInfoChars = (char *)(env)->GetStringUTFChars(keyInfo, NULL);
+ //}
+ //
+ //newMasterKeyVesion = getMasterKeyVersion(keyInfoChars);
+ //
+ //if(keyInfoChars)
+ //{
+ // (env)->ReleaseStringUTFChars(keyInfo, (const char *)keyInfoChars);
+ //}
+ //
+ ///* NEW MASTER KEY VERSION */
+ //newMasterKeyBuffer = Buffer((unsigned int) 1, (BYTE)newMasterKeyVesion);
+
+
+
+ // AC: BUGFIX for key versions higher than 09: New code to retrieve oldKeyInfo and newKeyInfo byte arrays from JNI.
+ if (oldKeyInfo != NULL){
+ oldKeyInfo_jbyteptr = env->GetByteArrayElements(oldKeyInfo, NULL);
+ oldKeyInfo_jbyteptr_len = env->GetArrayLength(oldKeyInfo);
+ }
+ if(oldKeyInfo_jbyteptr == NULL){
+ goto done;
+ }
+ if (oldKeyInfo_jbyteptr_len != 2){
+ goto done;
}
+ if (newKeyInfo != NULL){
+ newKeyInfo_jbyteptr = env->GetByteArrayElements(newKeyInfo, NULL);
+ newKeyInfo_jbyteptr_len = env->GetArrayLength(newKeyInfo);
+ }
+ if(newKeyInfo_jbyteptr == NULL){
+ goto done;
+ }
+ if (newKeyInfo_jbyteptr_len != 2){
+ goto done;
+ }
+ // now get the key versions from the byte arrays we got from JNI
+ oldKeyVersion = oldKeyInfo_jbyteptr[0];
+ newKeyVersion = newKeyInfo_jbyteptr[0];
+ // for compatibility with old code: wrap newKeyVersion inside Buffer object
+ newMasterKeyBuffer = Buffer((unsigned int) 1, newKeyVersion);
+
+
- /* NEW MASTER KEY VERSION */
- newMasterKeyBuffer = Buffer((unsigned int) 1, (BYTE)newMasterKeyVesion);
if(oldMasterKeyName)
{
oldMasterKeyNameChars = (char *)(env)->GetStringUTFChars(oldMasterKeyName, NULL);
@@ -1169,24 +1277,108 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Dive
if(strcmp( oldMasterKeyNameChars, "#01#01") == 0 || strcmp( oldMasterKeyNameChars, "#FF#01") == 0)
{
old_kek_key_buff = Buffer((BYTE*)old_kek_key, KEYLENGTH);
- }else if(strcmp( oldMasterKeyNameChars, "#00#00") == 0)
- {
- /* print Debug message - do not create real keysetdata */
- old_kek_key_buff = Buffer((BYTE*)"#00#00", 6);
- output = Buffer((BYTE*)old_kek_key, KEYLENGTH);
+
+
+ // AC: BUGFIX: Remove garbage code.
+ // I believe that this code is a no-op as long as the system is working correctly
+ // (with the developer keyset data populated in the config file & copied to HSM).
+ //
+ // Notes:
+ // "old_kek_key_buff" appears to only be used if unable to read/load the developer keys into HSM.
+ // "old_kek_key_buff" is populated with incorrect data (not appropriate key-length)
+ // "output" is overwritten when "CreateKeySetDataWithSymKeys" is called
+ //
+ // As a result, only when there is some failure (i.e. we execute a "goto" and skip assignment
+ // to "output") do we return a keyset data that is 16 bytes in length (the default KEK).
+ // This is unlikely to work and even if it does, is a horrible idea as the caller has no way
+ // of knowing that we've now essentially inserted a "backdoor" on the token. So, instead of
+ // this, we treat #00#00 just like any other "normal" case.
+ //
+ //}else if(strcmp( oldMasterKeyNameChars, "#00#00") == 0)
+ //{
+ // /* print Debug message - do not create real keysetdata */
+ // old_kek_key_buff = Buffer((BYTE*)"#00#00", 6);
+ // output = Buffer((BYTE*)old_kek_key, KEYLENGTH);
+
+
}
else
{
oldMasterKey = ReturnSymKey(slot,fullMasterKeyName);
- old_kek_sym_key = ComputeCardKeyOnToken(oldMasterKey,KDCkek);
- if (oldMasterKey) {
- PK11_FreeSymKey( oldMasterKey );
- oldMasterKey = NULL;
+
+
+ // AC: BUGFIX: Check for nonexistent master key instead of (potentially) crashing.
+ if (oldMasterKey == NULL){
+ goto done;
}
+
+
+ // ---------------------------------
+ // AC KDF SPEC CHANGE: Determine which KDF to use.
+ //
+ // if old key version meets setting value, use NIST SP800-108 KDF for deriving old keys
+ if (NistSP800_108KDF::useNistSP800_108KDF(nistSP800_108KdfOnKeyVersion_byte, oldKeyVersion) == true){
+
+ PR_fprintf(PR_STDOUT,"DiversifyKey old key NistSP800_108KDF code: Using NIST SP800-108 KDF for old keyset.\n");
+
+ // react to "UseCUIDAsKDD" setting value
+ jbyte* context_jbyte = NULL;
+ jsize context_len_jsize = 0;
+ if (nistSP800_108KdfUseCuidAsKdd == JNI_TRUE){
+ context_jbyte = cuidValue;
+ context_len_jsize = cuidValue_len;
+ }else{
+ context_jbyte = kddValue;
+ context_len_jsize = kddValue_len;
+ }
+
+ // Converting this way is safe since jbyte is guaranteed to be 8 bits
+ // Of course, this assumes that "char" is 8 bits (not guaranteed, but typical),
+ // but it looks like this assumption is also made in GetDiversificationData
+ const BYTE* const context = reinterpret_cast<const BYTE*>(context_jbyte);
+
+ // Convert jsize to size_t
+ const size_t context_len = static_cast<size_t>(context_len_jsize);
+ if (context_len > 0x000000FF){ // sanity check (CUID should never be larger than 255 bytes)
+ PR_fprintf(PR_STDERR, "DiversifyKey old key NistSP800_108KDF code: Error; context_len larger than 255 bytes.\n");
+ goto done;
+ }
+
+ // call NIST SP800-108 KDF routine
+ try{
+ NistSP800_108KDF::ComputeCardKeys(oldMasterKey, context, context_len, &old_enc_sym_key, &old_mac_sym_key, &old_kek_sym_key);
+ }catch(std::runtime_error& ex){
+ PR_fprintf(PR_STDERR, "DiversifyKey old key NistSP800_108KDF code: Exception invoking NistSP800_108KDF::ComputeCardKeys: ");
+ PR_fprintf(PR_STDERR, "%s\n", ex.what() == NULL ? "null" : ex.what());
+ goto done;
+ }catch(...){
+ PR_fprintf(PR_STDERR, "DiversifyKey old key NistSP800_108KDF code: Unknown exception invoking NistSP800_108KDF::ComputeCardKeys.\n");
+ goto done;
+ }
+
+ // if not a key version where we use the NIST SP800-108 KDF, use the original KDF
+ }else{
+
+ PR_fprintf(PR_STDOUT,"DiversifyKey old key NistSP800_108KDF code: Using original KDF for old keyset.\n");
+
+ // AC: Derives the kek key for the token.
+ old_kek_sym_key = ComputeCardKeyOnToken(oldMasterKey,KDCkek);
+
+ } // endif use original KDF
+ // ---------------------------------
+
+
+ // AC KDF SPEC CHANGE: Moved this code down so we don't skip it during "goto done".
+ //if (oldMasterKey) {
+ // PK11_FreeSymKey( oldMasterKey );
+ // oldMasterKey = NULL;
+ //}
}
- if(oldMasterKeyNameChars) {
- (env)->ReleaseStringUTFChars(oldMasterKeyName, (const char *)oldMasterKeyNameChars);
- }
+
+ // AC KDF SPEC CHANGE: Moved this code down so we don't skip it during "goto done".
+ //if(oldMasterKeyNameChars) {
+ // (env)->ReleaseStringUTFChars(oldMasterKeyName, (const char *)oldMasterKeyNameChars);
+ //}
/* special case #01#01 */
if (fullNewMasterKeyName != NULL && strcmp(fullNewMasterKeyName, "#01#01") == 0)
@@ -1213,10 +1405,65 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Dive
} else {
PR_fprintf(PR_STDOUT,"DiversifyKey: Compute card key on token case ! \n");
- /* compute card key */
- encKey = ComputeCardKeyOnSoftToken(masterKey, KDCenc);
- macKey = ComputeCardKeyOnSoftToken(masterKey, KDCmac);
- kekKey = ComputeCardKeyOnSoftToken(masterKey, KDCkek);
+
+
+ // ---------------------------------
+ // AC KDF SPEC CHANGE: Determine which KDF to use.
+ //
+ // if old key version meets setting value, use NIST SP800-108 KDF for deriving new keys
+ if (NistSP800_108KDF::useNistSP800_108KDF(nistSP800_108KdfOnKeyVersion_byte, newKeyVersion) == true){
+
+ PR_fprintf(PR_STDOUT,"DiversifyKey new key NistSP800_108KDF code: Using NIST SP800-108 KDF for new keyset.\n");
+
+ // react to "UseCUIDAsKDD" setting value
+ jbyte* context_jbyte = NULL;
+ jsize context_len_jsize = 0;
+ if (nistSP800_108KdfUseCuidAsKdd == JNI_TRUE){
+ context_jbyte = cuidValue;
+ context_len_jsize = cuidValue_len;
+ }else{
+ context_jbyte = kddValue;
+ context_len_jsize = kddValue_len;
+ }
+
+ // Converting this way is safe since jbyte is guaranteed to be 8 bits
+ // Of course, this assumes that "char" is 8 bits (not guaranteed, but typical),
+ // but it looks like this assumption is also made in GetDiversificationData
+ const BYTE* const context = reinterpret_cast<const BYTE*>(context_jbyte);
+
+ // Convert jsize to size_t
+ const size_t context_len = static_cast<size_t>(context_len_jsize);
+ if (context_len > 0x000000FF){ // sanity check (CUID should never be larger than 255 bytes)
+ PR_fprintf(PR_STDERR, "DiversifyKey new key NistSP800_108KDF code: Error; context_len larger than 255 bytes.\n");
+ goto done;
+ }
+
+ // call NIST SP800-108 KDF routine
+ try{
+ NistSP800_108KDF::ComputeCardKeys(masterKey, context, context_len, &encKey, &macKey, &kekKey);
+ }catch(std::runtime_error& ex){
+ PR_fprintf(PR_STDERR, "DiversifyKey new key NistSP800_108KDF code: Exception invoking NistSP800_108KDF::ComputeCardKeys: ");
+ PR_fprintf(PR_STDERR, "%s\n", ex.what() == NULL ? "null" : ex.what());
+ goto done;
+ }catch(...){
+ PR_fprintf(PR_STDERR, "DiversifyKey new key NistSP800_108KDF code: Unknown exception invoking NistSP800_108KDF::ComputeCardKeys.\n");
+ goto done;
+ }
+
+ // if not a key version where we use the NIST SP800-108 KDF, use the original KDF
+ }else{
+
+ PR_fprintf(PR_STDOUT,"DiversifyKey new key NistSP800_108KDF code: Using original KDF for new keyset.\n");
+
+ // AC: Derives the kek key for the token.
+ /* compute card key */
+ encKey = ComputeCardKeyOnSoftToken(masterKey, KDCenc);
+ macKey = ComputeCardKeyOnSoftToken(masterKey, KDCmac);
+ kekKey = ComputeCardKeyOnSoftToken(masterKey, KDCkek);
+
+ } // endif use original KDF
+ // ---------------------------------
+
/* Fixes Bugscape Bug #55855: TKS crashes if specified key
* is not present -- for each portion of the key, check if
@@ -1257,6 +1504,17 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_netscape_symkey_SessionKey_Dive
}
done:
+
+ // AC: BUGFIX for key versions higher than 09: Release oldKeyInfo and newKeyInfo JNI byte arrays.
+ if ( oldKeyInfo_jbyteptr != NULL){
+ env->ReleaseByteArrayElements(oldKeyInfo, oldKeyInfo_jbyteptr, JNI_ABORT);
+ oldKeyInfo_jbyteptr = NULL;
+ }
+ if ( newKeyInfo_jbyteptr != NULL){
+ env->ReleaseByteArrayElements(newKeyInfo, newKeyInfo_jbyteptr, JNI_ABORT);
+ newKeyInfo_jbyteptr = NULL;
+ }
+
if (masterKey != NULL) {
PK11_FreeSymKey( masterKey);
masterKey = NULL;
@@ -1277,6 +1535,32 @@ done:
kekKey = NULL;
}
+ // AC: KDF SPEC CHANGE: For the NIST SP800-108 KDF being used for old key version, we build all 3 old keys despite only using one of them (Kek) in this function.
+ // We do this because our NIST SP800-108 KDF outputs the data for all three keys simultaneously.
+ // AC: BUGFIX: Note that there was previously no PK11_FreeSymKey(old_kek_sym_key) call. This most likely resulted in a memory / keyhandle leak.
+ if( old_mac_sym_key ) {
+ PK11_FreeSymKey(old_mac_sym_key);
+ old_mac_sym_key = NULL;
+ }
+ if ( old_enc_sym_key ) {
+ PK11_FreeSymKey(old_enc_sym_key);
+ old_enc_sym_key = NULL;
+ }
+ if ( old_kek_sym_key ) {
+ PK11_FreeSymKey(old_kek_sym_key);
+ old_kek_sym_key = NULL;
+ }
+
+ // AC KDF SPEC CHANGE: Moved this code down so we don't skip it during "goto done".
+ if (oldMasterKey) {
+ PK11_FreeSymKey( oldMasterKey );
+ oldMasterKey = NULL;
+ }
+ if(oldMasterKeyNameChars) {
+ (env)->ReleaseStringUTFChars(oldMasterKeyName, (const char *)oldMasterKeyNameChars);
+ oldMasterKeyNameChars = NULL;
+ }
+
if( keySetStringChars ) {
(env)->ReleaseStringUTFChars(keySet, (const char *)keySetStringChars);
keySetStringChars = NULL;
@@ -1286,10 +1570,21 @@ done:
{
if(output.size()>0)
handleBA = (env)->NewByteArray( output.size());
- else
- handleBA = (env)->NewByteArray(1);
- handleBytes = (env)->GetByteArrayElements(handleBA, NULL);
- memcpy(handleBytes, (BYTE*)output,output.size());
+
+ // AC: Bugfix: Return NULL if no output is present.
+ //else
+ // handleBA = (env)->NewByteArray(1);
+
+ // AC: Bugfix: Don't crash if we couldn't allocate array.
+ if (handleBA != NULL){
+ handleBytes = (env)->GetByteArrayElements(handleBA, NULL);
+
+ // AC: BUGFIX: Don't return a java array with uninitialized or zero'd data.
+ if (handleBytes != NULL){
+ memcpy(handleBytes, (BYTE*)output,output.size());
+ error_computing_result = false;
+ }
+ }
if( handleBytes != NULL) {
(env)->ReleaseByteArrayElements( handleBA, handleBytes, 0);
@@ -1300,6 +1595,12 @@ done:
(env)->ReleaseByteArrayElements(CUIDValue, cuidValue, JNI_ABORT);
}
+ // AC: KDF SPEC CHANGE: Need to retrieve KDD as well as CUID from JNI.
+ if ( kddValue != NULL){
+ env->ReleaseByteArrayElements(KDD, kddValue, JNI_ABORT);
+ kddValue = NULL;
+ }
+
if( kekKeyArray != NULL) {
(env)->ReleaseByteArrayElements(kekKeyArray, old_kek_key, JNI_ABORT);
}
@@ -1319,7 +1620,12 @@ done:
internal = NULL;
}
- return handleBA;
+ // AC: BUGFIX: Don't return a java array with uninitialized or zero'd data.
+ if (error_computing_result == false){
+ return handleBA;
+ }else{
+ return NULL;
+ }
}
PK11SymKey *CreateUnWrappedSymKeyOnToken( PK11SlotInfo *slot, PK11SymKey * unWrappingKey, BYTE *keyToBeUnWrapped, int sizeOfKeyToBeUnWrapped, PRBool isPerm)
diff --git a/base/tks/shared/conf/CS.cfg.in b/base/tks/shared/conf/CS.cfg.in
index be8213788..2f7606f44 100644
--- a/base/tks/shared/conf/CS.cfg.in
+++ b/base/tks/shared/conf/CS.cfg.in
@@ -302,6 +302,8 @@ selftests.plugin.TKSKnownSessionKey.TksSubId=tks
selftests.plugin.TKSKnownSessionKey.cardChallenge=#bd#6d#19#85#6e#54#0f#cd
selftests.plugin.TKSKnownSessionKey.hostChallenge=#77#57#62#e4#5e#23#66#7d
selftests.plugin.TKSKnownSessionKey.keyName=#01#01
+selftests.plugin.TKSKnownSessionKey.nistSP800-108KdfOnKeyVersion=FF
+selftests.plugin.TKSKnownSessionKey.nistSP800-108KdfUseCuidAsKdd=false
selftests.plugin.TKSKnownSessionKey.macKey=#40#41#42#43#44#45#46#47#48#49#4a#4b#4c#4d#4e#4f
selftests.plugin.TKSKnownSessionKey.sessionKey=#d1#be#b8#26#dc#56#20#25#8c#93#e7#de#f0#ab#4f#5b
selftests.plugin.TKSKnownSessionKey.token=Internal Key Storage Token
@@ -339,6 +341,8 @@ tks.defKeySet._004=##
tks.defKeySet.auth_key=#40#41#42#43#44#45#46#47#48#49#4a#4b#4c#4d#4e#4f
tks.defKeySet.mac_key=#40#41#42#43#44#45#46#47#48#49#4a#4b#4c#4d#4e#4f
tks.defKeySet.kek_key=#40#41#42#43#44#45#46#47#48#49#4a#4b#4c#4d#4e#4f
+tks.defKeySet.nistSP800-108KdfOnKeyVersion=00
+tks.defKeySet.nistSP800-108KdfUseCuidAsKdd=false
tks.jForte._000=##
tks.jForte._001=## SAFLink's jForte default key set:
tks.jForte._002=##
@@ -347,6 +351,8 @@ tks.jForte._004=##
tks.jForte.auth_key=#30#31#32#33#34#35#36#37#38#39#3a#3b#3c#3d#3e#3f
tks.jForte.mac_key=#40#41#42#43#44#45#46#47#48#49#4a#4b#4c#4d#4e#4f
tks.jForte.kek_key=#50#51#52#53#54#55#56#57#58#59#5a#5b#5c#5d#5e#5f
+tks.jForte.nistSP800-108KdfOnKeyVersion=00
+tks.jForte.nistSP800-108KdfUseCuidAsKdd=false
multiroles._000=##
multiroles._001=## multiroles
multiroles._002=##