Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Unified Diff: mozilla/security/nss/lib/pk11wrap/pk11skey.c

Issue 10961060: Update NSS to NSS 3.14 Beta 1. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Add the NSS snapshot timestamp to README.chromium and nss-checkout.sh Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mozilla/security/nss/lib/pk11wrap/pk11pub.h ('k') | mozilla/security/nss/lib/pk11wrap/pk11slot.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mozilla/security/nss/lib/pk11wrap/pk11skey.c
===================================================================
--- mozilla/security/nss/lib/pk11wrap/pk11skey.c (revision 158129)
+++ mozilla/security/nss/lib/pk11wrap/pk11skey.c (working copy)
@@ -813,28 +813,53 @@
}
/*
- * Make sure the slot we are in the correct slot for the operation
+ * Make sure the slot we are in is the correct slot for the operation
+ * by verifying that it supports all of the specified mechanism types.
*/
PK11SymKey *
-pk11_ForceSlot(PK11SymKey *symKey,CK_MECHANISM_TYPE type,
- CK_ATTRIBUTE_TYPE operation)
+pk11_ForceSlotMultiple(PK11SymKey *symKey, CK_MECHANISM_TYPE *type,
+ int mechCount, CK_ATTRIBUTE_TYPE operation)
{
PK11SlotInfo *slot = symKey->slot;
PK11SymKey *newKey = NULL;
+ PRBool needToCopy = PR_FALSE;
+ int i;
- if ((slot== NULL) || !PK11_DoesMechanism(slot,type)) {
- slot = PK11_GetBestSlot(type,symKey->cx);
+ if (slot == NULL) {
+ needToCopy = PR_TRUE;
+ } else {
+ i = 0;
+ while ((i < mechCount) && (needToCopy == PR_FALSE)) {
+ if (!PK11_DoesMechanism(slot,type[i])) {
+ needToCopy = PR_TRUE;
+ }
+ i++;
+ }
+ }
+
+ if (needToCopy == PR_TRUE) {
+ slot = PK11_GetBestSlotMultiple(type,mechCount,symKey->cx);
if (slot == NULL) {
PORT_SetError( SEC_ERROR_NO_MODULE );
return NULL;
}
- newKey = pk11_CopyToSlot(slot, type, operation, symKey);
+ newKey = pk11_CopyToSlot(slot, type[0], operation, symKey);
PK11_FreeSlot(slot);
}
return newKey;
}
+/*
+ * Make sure the slot we are in is the correct slot for the operation
+ */
PK11SymKey *
+pk11_ForceSlot(PK11SymKey *symKey,CK_MECHANISM_TYPE type,
+ CK_ATTRIBUTE_TYPE operation)
+{
+ return pk11_ForceSlotMultiple(symKey, &type, 1, operation);
+}
+
+PK11SymKey *
PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation,
CK_FLAGS flags, PRBool perm, PK11SymKey *symKey)
{
@@ -1529,6 +1554,239 @@
return symKey;
}
+/* Create a new key by concatenating base and data
+ */
+static PK11SymKey *pk11_ConcatenateBaseAndData(PK11SymKey *base,
+ CK_BYTE *data, CK_ULONG dataLen, CK_MECHANISM_TYPE target,
+ CK_ATTRIBUTE_TYPE operation)
+{
+ CK_KEY_DERIVATION_STRING_DATA mechParams;
+ SECItem param;
+
+ if (base == NULL) {
+ PORT_SetError( SEC_ERROR_INVALID_ARGS );
+ return NULL;
+ }
+
+ mechParams.pData = data;
+ mechParams.ulLen = dataLen;
+ param.data = (unsigned char *)&mechParams;
+ param.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
+
+ return PK11_Derive(base, CKM_CONCATENATE_BASE_AND_DATA,
+ &param, target, operation, 0);
+}
+
+/* Create a new key by concatenating base and key
+ */
+static PK11SymKey *pk11_ConcatenateBaseAndKey(PK11SymKey *base,
+ PK11SymKey *key, CK_MECHANISM_TYPE target,
+ CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
+{
+ SECItem param;
+
+ if ((base == NULL) || (key == NULL)) {
+ PORT_SetError( SEC_ERROR_INVALID_ARGS );
+ return NULL;
+ }
+
+ param.data = (unsigned char *)&(key->objectID);
+ param.len = sizeof(CK_OBJECT_HANDLE);
+
+ return PK11_Derive(base, CKM_CONCATENATE_BASE_AND_KEY,
+ &param, target, operation, keySize);
+}
+
+/* Create a new key whose value is the hash of tobehashed.
+ * type is the mechanism for the derived key.
+ */
+static PK11SymKey *pk11_HashKeyDerivation(PK11SymKey *toBeHashed,
+ CK_MECHANISM_TYPE hashMechanism, CK_MECHANISM_TYPE target,
+ CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
+{
+ return PK11_Derive(toBeHashed, hashMechanism, NULL, target, operation, keySize);
+}
+
+/* This function implements the ANSI X9.63 key derivation function
+ */
+static PK11SymKey *pk11_ANSIX963Derive(PK11SymKey *sharedSecret,
+ CK_EC_KDF_TYPE kdf, SECItem *sharedData,
+ CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
+ CK_ULONG keySize)
+{
+ CK_KEY_TYPE keyType;
+ CK_MECHANISM_TYPE hashMechanism, mechanismArray[4];
+ CK_ULONG derivedKeySize, HashLen, counter, maxCounter, bufferLen;
+ CK_ULONG SharedInfoLen;
+ CK_BYTE *buffer = NULL;
+ PK11SymKey *toBeHashed, *hashOutput;
+ PK11SymKey *newSharedSecret = NULL;
+ PK11SymKey *oldIntermediateResult, *intermediateResult = NULL;
+
+ if (sharedSecret == NULL) {
+ PORT_SetError( SEC_ERROR_INVALID_ARGS );
+ return NULL;
+ }
+
+ switch (kdf) {
+ case CKD_SHA1_KDF:
+ HashLen = SHA1_LENGTH;
+ hashMechanism = CKM_SHA1_KEY_DERIVATION;
+ break;
+ case CKD_SHA224_KDF:
+ HashLen = SHA224_LENGTH;
+ hashMechanism = CKM_SHA224_KEY_DERIVATION;
+ break;
+ case CKD_SHA256_KDF:
+ HashLen = SHA256_LENGTH;
+ hashMechanism = CKM_SHA256_KEY_DERIVATION;
+ break;
+ case CKD_SHA384_KDF:
+ HashLen = SHA384_LENGTH;
+ hashMechanism = CKM_SHA384_KEY_DERIVATION;
+ break;
+ case CKD_SHA512_KDF:
+ HashLen = SHA512_LENGTH;
+ hashMechanism = CKM_SHA512_KEY_DERIVATION;
+ break;
+ default:
+ PORT_SetError( SEC_ERROR_INVALID_ARGS );
+ return NULL;
+ }
+
+ derivedKeySize = keySize;
+ if (derivedKeySize == 0) {
+ keyType = PK11_GetKeyType(target,keySize);
+ derivedKeySize = pk11_GetPredefinedKeyLength(keyType);
+ if (derivedKeySize == 0) {
+ derivedKeySize = HashLen;
+ }
+ }
+
+ /* Check that key_len isn't too long. The maximum key length could be
+ * greatly increased if the code below did not limit the 4-byte counter
+ * to a maximum value of 255. */
+ if (derivedKeySize > 254 * HashLen) {
+ PORT_SetError( SEC_ERROR_INVALID_ARGS );
+ return NULL;
+ }
+
+ maxCounter = derivedKeySize / HashLen;
+ if (derivedKeySize > maxCounter * HashLen)
+ maxCounter++;
+
+ if ((sharedData == NULL) || (sharedData->data == NULL))
+ SharedInfoLen = 0;
+ else
+ SharedInfoLen = sharedData->len;
+
+ bufferLen = SharedInfoLen + 4;
+
+ /* Populate buffer with Counter || sharedData
+ * where Counter is 0x00000001. */
+ buffer = (unsigned char *)PORT_Alloc(bufferLen);
+ if (buffer == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return NULL;
+ }
+
+ buffer[0] = 0;
+ buffer[1] = 0;
+ buffer[2] = 0;
+ buffer[3] = 1;
+ if (SharedInfoLen > 0) {
+ PORT_Memcpy(&buffer[4], sharedData->data, SharedInfoLen);
+ }
+
+ /* Look for a slot that supports the mechanisms needed
+ * to implement the ANSI X9.63 KDF as well as the
+ * target mechanism.
+ */
+ mechanismArray[0] = CKM_CONCATENATE_BASE_AND_DATA;
+ mechanismArray[1] = hashMechanism;
+ mechanismArray[2] = CKM_CONCATENATE_BASE_AND_KEY;
+ mechanismArray[3] = target;
+
+ newSharedSecret = pk11_ForceSlotMultiple(sharedSecret,
+ mechanismArray, 4, operation);
+ if (newSharedSecret != NULL) {
+ sharedSecret = newSharedSecret;
+ }
+
+ for(counter=1; counter <= maxCounter; counter++) {
+ /* Concatenate shared_secret and buffer */
+ toBeHashed = pk11_ConcatenateBaseAndData(sharedSecret, buffer,
+ bufferLen, hashMechanism, operation);
+ if (toBeHashed == NULL) {
+ goto loser;
+ }
+
+ /* Hash value */
+ if (maxCounter == 1) {
+ /* In this case the length of the key to be derived is
+ * less than or equal to the length of the hash output.
+ * So, the output of the hash operation will be the
+ * dervied key. */
+ hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
+ target, operation, keySize);
+ } else {
+ /* In this case, the output of the hash operation will be
+ * concatenated with other data to create the derived key. */
+ hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
+ CKM_CONCATENATE_BASE_AND_KEY, operation, 0);
+ }
+ PK11_FreeSymKey(toBeHashed);
+ if (hashOutput == NULL) {
+ goto loser;
+ }
+
+ /* Append result to intermediate result, if necessary */
+ oldIntermediateResult = intermediateResult;
+
+ if (oldIntermediateResult == NULL) {
+ intermediateResult = hashOutput;
+ } else {
+ if (counter == maxCounter) {
+ /* This is the final concatenation, and so the output
+ * will be the derived key. */
+ intermediateResult =
+ pk11_ConcatenateBaseAndKey(oldIntermediateResult,
+ hashOutput, target, operation, keySize);
+ } else {
+ /* The output of this concatenation will be concatenated
+ * with other data to create the derived key. */
+ intermediateResult =
+ pk11_ConcatenateBaseAndKey(oldIntermediateResult,
+ hashOutput, CKM_CONCATENATE_BASE_AND_KEY,
+ operation, 0);
+ }
+
+ PK11_FreeSymKey(hashOutput);
+ PK11_FreeSymKey(oldIntermediateResult);
+ if (intermediateResult == NULL) {
+ goto loser;
+ }
+ }
+
+ /* Increment counter (assumes maxCounter < 255) */
+ buffer[3]++;
+ }
+
+ PORT_ZFree(buffer, bufferLen);
+ if (newSharedSecret != NULL)
+ PK11_FreeSymKey(newSharedSecret);
+ return intermediateResult;
+
+loser:
+ if (buffer != NULL)
+ PORT_ZFree(buffer, bufferLen);
+ if (newSharedSecret != NULL)
+ PK11_FreeSymKey(newSharedSecret);
+ if (intermediateResult != NULL)
+ PK11_FreeSymKey(intermediateResult);
+ return NULL;
+}
+
/*
* This Generates a wrapping key based on a privateKey, publicKey, and two
* random numbers. For Mail usage RandomB should be NULL. In the Sender's
@@ -1677,7 +1935,7 @@
keyType = PK11_GetKeyType(target,keySize);
key_size = keySize;
if (key_size == 0) {
- if (pk11_GetPredefinedKeyLength(keyType)) {
+ if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
templateCount --;
} else {
/* sigh, some tokens can't figure this out and require
@@ -1737,6 +1995,23 @@
return NULL;
}
+/* Returns the size of the public key, or 0 if there
+ * is an error. */
+static CK_ULONG
+pk11_ECPubKeySize(SECItem *publicValue)
+{
+ if (publicValue->data[0] == 0x04) {
+ /* key encoded in uncompressed form */
+ return((publicValue->len - 1)/2);
+ } else if ( (publicValue->data[0] == 0x02) ||
+ (publicValue->data[0] == 0x03)) {
+ /* key encoded in compressed form */
+ return(publicValue->len - 1);
+ }
+ /* key encoding not recognized */
+ return(0);
+}
+
static PK11SymKey *
pk11_PubDeriveECKeyWithKDF(
SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
@@ -1747,6 +2022,7 @@
{
PK11SlotInfo *slot = privKey->pkcs11Slot;
PK11SymKey *symKey;
+ PK11SymKey *SharedSecret;
CK_MECHANISM mechanism;
CK_RV crv;
CK_BBOOL cktrue = CK_TRUE;
@@ -1762,7 +2038,9 @@
PORT_SetError(SEC_ERROR_BAD_KEY);
return NULL;
}
- if ((kdf < CKD_NULL) || (kdf > CKD_SHA1_KDF)) {
+ if ((kdf != CKD_NULL) && (kdf != CKD_SHA1_KDF) &&
+ (kdf != CKD_SHA224_KDF) && (kdf != CKD_SHA256_KDF) &&
+ (kdf != CKD_SHA384_KDF) && (kdf != CKD_SHA512_KDF)) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return NULL;
}
@@ -1785,18 +2063,34 @@
keyType = PK11_GetKeyType(target,keySize);
key_size = keySize;
if (key_size == 0) {
- if (pk11_GetPredefinedKeyLength(keyType)) {
+ if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
templateCount --;
} else {
/* sigh, some tokens can't figure this out and require
* CKA_VALUE_LEN to be set */
switch (kdf) {
case CKD_NULL:
- key_size = (pubKey->u.ec.publicValue.len-1)/2;
+ key_size = pk11_ECPubKeySize(&pubKey->u.ec.publicValue);
+ if (key_size == 0) {
+ PK11_FreeSymKey(symKey);
+ return NULL;
+ }
break;
case CKD_SHA1_KDF:
key_size = SHA1_LENGTH;
break;
+ case CKD_SHA224_KDF:
+ key_size = SHA224_LENGTH;
+ break;
+ case CKD_SHA256_KDF:
+ key_size = SHA256_LENGTH;
+ break;
+ case CKD_SHA384_KDF:
+ key_size = SHA384_LENGTH;
+ break;
+ case CKD_SHA512_KDF:
+ key_size = SHA512_LENGTH;
+ break;
default:
PORT_Assert(!"Invalid CKD");
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
@@ -1832,7 +2126,7 @@
pk11_ExitKeyMonitor(symKey);
/* old PKCS #11 spec was ambiguous on what needed to be passed,
- * try this again with and encoded public key */
+ * try this again with an encoded public key */
if (crv != CKR_OK) {
SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
&pubKey->u.ec.publicValue,
@@ -1849,6 +2143,60 @@
templateCount, &symKey->objectID);
pk11_ExitKeyMonitor(symKey);
+ if ((crv != CKR_OK) && (kdf != CKD_NULL)) {
+ /* Some PKCS #11 libraries cannot perform the key derivation
+ * function. So, try calling C_DeriveKey with CKD_NULL and then
+ * performing the KDF separately.
+ */
+ CK_ULONG derivedKeySize = key_size;
+
+ keyType = CKK_GENERIC_SECRET;
+ key_size = pk11_ECPubKeySize(&pubKey->u.ec.publicValue);
+ if (key_size == 0) {
+ SECITEM_FreeItem(pubValue,PR_TRUE);
+ goto loser;
+ }
+ SharedSecret = symKey;
+ SharedSecret->size = key_size;
+
+ mechParams->kdf = CKD_NULL;
+ mechParams->ulSharedDataLen = 0;
+ mechParams->pSharedData = NULL;
+ mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
+ mechParams->pPublicData = pubKey->u.ec.publicValue.data;
+
+ pk11_EnterKeyMonitor(SharedSecret);
+ crv = PK11_GETTAB(slot)->C_DeriveKey(SharedSecret->session,
+ &mechanism, privKey->pkcs11ID, keyTemplate,
+ templateCount, &SharedSecret->objectID);
+ pk11_ExitKeyMonitor(SharedSecret);
+
+ if (crv != CKR_OK) {
+ /* old PKCS #11 spec was ambiguous on what needed to be passed,
+ * try this one final time with an encoded public key */
+ mechParams->ulPublicDataLen = pubValue->len;
+ mechParams->pPublicData = pubValue->data;
+
+ pk11_EnterKeyMonitor(SharedSecret);
+ crv = PK11_GETTAB(slot)->C_DeriveKey(SharedSecret->session,
+ &mechanism, privKey->pkcs11ID, keyTemplate,
+ templateCount, &SharedSecret->objectID);
+ pk11_ExitKeyMonitor(SharedSecret);
+ }
+
+ /* Perform KDF. */
+ if (crv == CKR_OK) {
+ symKey = pk11_ANSIX963Derive(SharedSecret, kdf,
+ sharedData, target, operation,
+ derivedKeySize);
+ PK11_FreeSymKey(SharedSecret);
+ if (symKey == NULL) {
+ SECITEM_FreeItem(pubValue,PR_TRUE);
+ PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
+ return NULL;
+ }
+ }
+ }
SECITEM_FreeItem(pubValue,PR_TRUE);
}
« no previous file with comments | « mozilla/security/nss/lib/pk11wrap/pk11pub.h ('k') | mozilla/security/nss/lib/pk11wrap/pk11slot.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698