diff options
Diffstat (limited to 'base/symkey/src/com/netscape/symkey/EncryptData.cpp')
-rw-r--r-- | base/symkey/src/com/netscape/symkey/EncryptData.cpp | 140 |
1 files changed, 127 insertions, 13 deletions
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; } |