| 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);
|
| }
|
| +
|
|
|
| +
|
| 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:
|
|
|