Chromium Code Reviews| Index: mozilla/security/nss/lib/softoken/pkcs11c.c |
| =================================================================== |
| --- mozilla/security/nss/lib/softoken/pkcs11c.c (revision 164196) |
| +++ mozilla/security/nss/lib/softoken/pkcs11c.c (working copy) |
| @@ -2057,7 +2057,7 @@ |
| context->update = (SFTKCipher) nsc_DSA_Sign_Stub; |
| context->destroy = (privKey == key->objectInfo) ? |
| (SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey; |
| - context->maxLen = DSA_SIGNATURE_LEN; |
| + context->maxLen = DSA_MAX_SIGNATURE_LEN; |
| break; |
| @@ -2905,14 +2905,36 @@ |
| return CKR_OK; |
| } |
| + |
| +/* |
| + * this is coded for "full" support. These selections will be limitted to |
| + * the official subset by freebl. |
| + */ |
| +static unsigned int |
| +sftk_GetSubPrimeFromPrime(unsigned int primeBits) |
| +{ |
| + if (primeBits <= 1024) { |
| + return 160; |
| + } else if (primeBits <= 2048) { |
| + return 224; |
| + } else if (primeBits <= 3072) { |
| + return 256; |
| + } else if (primeBits <= 7680) { |
| + return 384; |
| + } else { |
| + return 512; |
| + } |
| +} |
| + |
| static CK_RV |
| nsc_parameter_gen(CK_KEY_TYPE key_type, SFTKObject *key) |
| { |
| SFTKAttribute *attribute; |
| CK_ULONG counter; |
| unsigned int seedBits = 0; |
| + unsigned int subprimeBits = 0; |
| unsigned int primeBits; |
| - unsigned int j; |
| + unsigned int j = 8; /* default to 1024 bits */ |
| CK_RV crv = CKR_OK; |
| PQGParams *params = NULL; |
| PQGVerify *vfy = NULL; |
| @@ -2924,9 +2946,11 @@ |
| } |
| primeBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue; |
| sftk_FreeAttribute(attribute); |
| - j = PQG_PBITS_TO_INDEX(primeBits); |
| - if (j == (unsigned int)-1) { |
| - return CKR_ATTRIBUTE_VALUE_INVALID; |
| + if (primeBits < 1024) { |
| + j = PQG_PBITS_TO_INDEX(primeBits); |
| + if (j == (unsigned int)-1) { |
| + return CKR_ATTRIBUTE_VALUE_INVALID; |
| + } |
| } |
| attribute = sftk_FindAttribute(key, CKA_NETSCAPE_PQG_SEED_BITS); |
| @@ -2935,15 +2959,35 @@ |
| sftk_FreeAttribute(attribute); |
| } |
| + attribute = sftk_FindAttribute(key, CKA_SUBPRIME_BITS); |
| + if (attribute != NULL) { |
| + subprimeBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue; |
| + sftk_FreeAttribute(attribute); |
| + } |
| + |
| sftk_DeleteAttributeType(key,CKA_PRIME_BITS); |
| + sftk_DeleteAttributeType(key,CKA_SUBPRIME_BITS); |
| sftk_DeleteAttributeType(key,CKA_NETSCAPE_PQG_SEED_BITS); |
| - if (seedBits == 0) { |
| - rv = PQG_ParamGen(j, ¶ms, &vfy); |
| + /* use the old PQG interface if we have old input data */ |
| + if ((primeBits < 1024) || ((primeBits == 1024) && (subprimeBits == 0))) { |
| + if (seedBits == 0) { |
| + rv = PQG_ParamGen(j, ¶ms, &vfy); |
| + } else { |
| + rv = PQG_ParamGenSeedLen(j,seedBits/8, ¶ms, &vfy); |
| + } |
| } else { |
| - rv = PQG_ParamGenSeedLen(j,seedBits/8, ¶ms, &vfy); |
| + if (subprimeBits == 0) { |
| + subprimeBits = sftk_GetSubPrimeFromPrime(primeBits); |
| + } |
| + if (seedBits == 0) { |
| + seedBits = primeBits; |
| + } |
| + rv = PQG_ParamGenV2(primeBits, subprimeBits, seedBits/8, ¶ms, &vfy); |
| } |
| + |
|
wtc
2012/11/07 22:12:33
Should remove these blank lines.
|
| + |
| if (rv != SECSuccess) { |
| if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) { |
| sftk_fatalError = PR_TRUE; |
| @@ -3459,6 +3503,7 @@ |
| CK_MECHANISM mech = {0, NULL, 0}; |
| CK_ULONG modulusLen; |
| + CK_ULONG subPrimeLen; |
| PRBool isEncryptable = PR_FALSE; |
| PRBool canSignVerify = PR_FALSE; |
| PRBool isDerivable = PR_FALSE; |
| @@ -3472,10 +3517,12 @@ |
| unsigned char *text_compared; |
| CK_ULONG bytes_encrypted; |
| CK_ULONG bytes_compared; |
| + CK_ULONG pairwise_digest_length = PAIRWISE_DIGEST_LENGTH; |
| /* Variables used for Signature/Verification functions. */ |
| - /* always uses SHA-1 digest */ |
| - unsigned char *known_digest = (unsigned char *)"Mozilla Rules World!"; |
| + /* Must be at least 256 bits for DSA2 digest */ |
| + unsigned char *known_digest = (unsigned char *) |
| + "Mozilla Rules the World through NSS!"; |
| unsigned char *signature; |
| CK_ULONG signature_length; |
| @@ -3492,6 +3539,19 @@ |
| modulusLen--; |
| } |
| sftk_FreeAttribute(attribute); |
| + } else if (keyType == CKK_DSA) { |
| + SFTKAttribute *attribute; |
| + |
| + /* Get subprime length of private key. */ |
| + attribute = sftk_FindAttribute(privateKey, CKA_SUBPRIME); |
| + if (attribute == NULL) { |
| + return CKR_DEVICE_ERROR; |
| + } |
| + subPrimeLen = attribute->attrib.ulValueLen; |
| + if (subPrimeLen > 1 && *(unsigned char *)attribute->attrib.pValue == 0) { |
| + subPrimeLen--; |
| + } |
| + sftk_FreeAttribute(attribute); |
| } |
| /**************************************************/ |
| @@ -3617,7 +3677,8 @@ |
| mech.mechanism = CKM_RSA_PKCS; |
| break; |
| case CKK_DSA: |
| - signature_length = DSA_SIGNATURE_LEN; |
| + signature_length = DSA_MAX_SIGNATURE_LEN; |
| + pairwise_digest_length = subPrimeLen; |
| mech.mechanism = CKM_DSA; |
| break; |
| #ifdef NSS_ENABLE_ECC |
| @@ -3645,7 +3706,7 @@ |
| crv = NSC_Sign(hSession, |
| known_digest, |
| - PAIRWISE_DIGEST_LENGTH, |
| + pairwise_digest_length, |
| signature, |
| &signature_length); |
| if (crv != CKR_OK) { |
| @@ -3662,7 +3723,7 @@ |
| crv = NSC_Verify(hSession, |
| known_digest, |
| - PAIRWISE_DIGEST_LENGTH, |
| + pairwise_digest_length, |
| signature, |
| signature_length); |
| @@ -3945,9 +4006,12 @@ |
| break; |
| } |
| + /* |
| + * these are checked by DSA_NewKey |
| + */ |
| bitSize = sftk_GetLengthInBits(pqgParam.subPrime.data, |
| pqgParam.subPrime.len); |
| - if (bitSize != DSA_Q_BITS) { |
| + if ((bitSize < DSA_MIN_Q_BITS) || (bitSize > DSA_MAX_Q_BITS)) { |
| crv = CKR_TEMPLATE_INCOMPLETE; |
| PORT_Free(pqgParam.prime.data); |
| PORT_Free(pqgParam.subPrime.data); |
| @@ -3963,7 +4027,7 @@ |
| break; |
| } |
| bitSize = sftk_GetLengthInBits(pqgParam.base.data,pqgParam.base.len); |
| - if ((bitSize < 1) || (bitSize > DSA_MAX_P_BITS)) { |
| + if ((bitSize < 2) || (bitSize > DSA_MAX_P_BITS)) { |
| crv = CKR_TEMPLATE_INCOMPLETE; |
| PORT_Free(pqgParam.prime.data); |
| PORT_Free(pqgParam.subPrime.data); |
| @@ -5065,6 +5129,113 @@ |
| return 0; |
| } |
| +/* Inputs: |
| + * key_len: Length of derived key to be generated. |
| + * SharedSecret: a shared secret that is the output of a key agreement primitive. |
| + * SharedInfo: (Optional) some data shared by the entities computing the secret key. |
| + * SharedInfoLen: the length in octets of SharedInfo |
| + * Hash: The hash function to be used in the KDF |
| + * HashLen: the length in octets of the output of Hash |
| + * Output: |
| + * key: Pointer to a buffer containing derived key, if return value is SECSuccess. |
| + */ |
| +static CK_RV sftk_compute_ANSI_X9_63_kdf(CK_BYTE **key, CK_ULONG key_len, SECItem *SharedSecret, |
| + CK_BYTE_PTR SharedInfo, CK_ULONG SharedInfoLen, |
| + SECStatus Hash(unsigned char *, const unsigned char *, uint32), |
| + CK_ULONG HashLen) |
| +{ |
| + unsigned char *buffer = NULL, *output_buffer = NULL; |
| + uint32 buffer_len, max_counter, i; |
| + SECStatus rv; |
| + |
| + /* 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 (key_len > 254 * HashLen) |
| + return SEC_ERROR_INVALID_ARGS; |
| + |
| + if (SharedInfo == NULL) |
| + SharedInfoLen = 0; |
| + |
| + buffer_len = SharedSecret->len + 4 + SharedInfoLen; |
| + buffer = (CK_BYTE *)PORT_Alloc(buffer_len); |
| + if (buffer == NULL) { |
| + rv = SEC_ERROR_NO_MEMORY; |
| + goto loser; |
| + } |
| + |
| + max_counter = key_len/HashLen; |
| + if (key_len > max_counter * HashLen) |
| + max_counter++; |
| + |
| + output_buffer = (CK_BYTE *)PORT_Alloc(max_counter * HashLen); |
| + if (output_buffer == NULL) { |
| + rv = SEC_ERROR_NO_MEMORY; |
| + goto loser; |
| + } |
| + |
| + /* Populate buffer with SharedSecret || Counter || [SharedInfo] |
| + * where Counter is 0x00000001 */ |
| + PORT_Memcpy(buffer, SharedSecret->data, SharedSecret->len); |
| + buffer[SharedSecret->len] = 0; |
| + buffer[SharedSecret->len + 1] = 0; |
| + buffer[SharedSecret->len + 2] = 0; |
| + buffer[SharedSecret->len + 3] = 1; |
| + if (SharedInfo) { |
| + PORT_Memcpy(&buffer[SharedSecret->len + 4], SharedInfo, SharedInfoLen); |
| + } |
| + |
| + for(i=0; i < max_counter; i++) { |
| + rv = Hash(&output_buffer[i * HashLen], buffer, buffer_len); |
| + if (rv != SECSuccess) |
| + goto loser; |
| + |
| + /* Increment counter (assumes max_counter < 255) */ |
| + buffer[SharedSecret->len + 3]++; |
| + } |
| + |
| + PORT_ZFree(buffer, buffer_len); |
| + if (key_len < max_counter * HashLen) { |
| + PORT_Memset(output_buffer + key_len, 0, max_counter * HashLen - key_len); |
| + } |
| + *key = output_buffer; |
| + |
| + return SECSuccess; |
| + |
| + loser: |
| + if (buffer) { |
| + PORT_ZFree(buffer, buffer_len); |
| + } |
| + if (output_buffer) { |
| + PORT_ZFree(output_buffer, max_counter * HashLen); |
| + } |
| + return rv; |
| +} |
| + |
| +static CK_RV sftk_ANSI_X9_63_kdf(CK_BYTE **key, CK_ULONG key_len, |
| + SECItem *SharedSecret, |
| + CK_BYTE_PTR SharedInfo, CK_ULONG SharedInfoLen, |
| + CK_EC_KDF_TYPE kdf) |
| +{ |
| + if (kdf == CKD_SHA1_KDF) |
| + return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo, |
| + SharedInfoLen, SHA1_HashBuf, SHA1_LENGTH); |
| + else if (kdf == CKD_SHA224_KDF) |
| + return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo, |
| + SharedInfoLen, SHA224_HashBuf, SHA224_LENGTH); |
| + else if (kdf == CKD_SHA256_KDF) |
| + return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo, |
| + SharedInfoLen, SHA256_HashBuf, SHA256_LENGTH); |
| + else if (kdf == CKD_SHA384_KDF) |
| + return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo, |
| + SharedInfoLen, SHA384_HashBuf, SHA384_LENGTH); |
| + else if (kdf == CKD_SHA512_KDF) |
| + return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo, |
| + SharedInfoLen, SHA512_HashBuf, SHA512_LENGTH); |
| + else |
| + return SEC_ERROR_INVALID_ALGORITHM; |
| +} |
| + |
| /* |
| * SSL Key generation given pre master secret |
| */ |
| @@ -5967,7 +6138,6 @@ |
| SECItem ecScalar, ecPoint; |
| SECItem tmp; |
| PRBool withCofactor = PR_FALSE; |
| - unsigned char secret_hash[20]; |
| unsigned char *secret; |
| unsigned char *keyData = NULL; |
| int secretlen, curveLen, pubKeyLen; |
| @@ -6053,28 +6223,30 @@ |
| break; |
| } |
| - /* |
| - * tmp is the raw data created by ECDH_Derive, |
| - * secret and secretlen are the values we will eventually pass as our |
| - * generated key. |
| - */ |
| - secret = tmp.data; |
| - secretlen = tmp.len; |
| /* |
| * apply the kdf function. |
| */ |
| - if (mechParams->kdf == CKD_SHA1_KDF) { |
| - /* Compute SHA1 hash */ |
| - PORT_Memset(secret_hash, 0, 20); |
| - rv = SHA1_HashBuf(secret_hash, tmp.data, tmp.len); |
| + if (mechParams->kdf == CKD_NULL) { |
| + /* |
| + * tmp is the raw data created by ECDH_Derive, |
| + * secret and secretlen are the values we will |
| + * eventually pass as our generated key. |
| + */ |
| + secret = tmp.data; |
| + secretlen = tmp.len; |
| + } else { |
| + secretlen = keySize; |
| + rv = sftk_ANSI_X9_63_kdf(&secret, keySize, |
| + &tmp, mechParams->pSharedData, |
| + mechParams->ulSharedDataLen, mechParams->kdf); |
| + PORT_ZFree(tmp.data, tmp.len); |
| if (rv != SECSuccess) { |
| - PORT_ZFree(tmp.data, tmp.len); |
| crv = CKR_HOST_MEMORY; |
| break; |
| - } |
| - secret = secret_hash; |
| - secretlen = 20; |
| + } |
| + tmp.data = secret; |
| + tmp.len = secretlen; |
| } |
| /* |
| @@ -6105,8 +6277,6 @@ |
| if (keyData) { |
| PORT_ZFree(keyData, keySize); |
| } |
| - PORT_Memset(secret_hash, 0, 20); |
| - |
| break; |
| ec_loser: |