diff --git a/mozilla/security/nss/lib/softoken/pkcs11.c b/mozilla/security/nss/lib/softoken/pkcs11.c index 3ed0d32e295..1266f322c37 100644 --- a/mozilla/security/nss/lib/softoken/pkcs11.c +++ b/mozilla/security/nss/lib/softoken/pkcs11.c @@ -407,6 +407,11 @@ static const struct mechanismList mechanisms[] = { {CKM_SHA512_HMAC, {1, 128, CKF_SN_VR}, PR_TRUE}, {CKM_SHA512_HMAC_GENERAL, {1, 128, CKF_SN_VR}, PR_TRUE}, {CKM_TLS_PRF_GENERAL, {0, 512, CKF_SN_VR}, PR_FALSE}, + /* ------------------------- HKDF Operations -------------------------- */ + {CKM_NSS_HKDF_SHA1, {1, 128, CKF_DERIVE}, PR_TRUE}, + {CKM_NSS_HKDF_SHA256, {1, 128, CKF_DERIVE}, PR_TRUE}, + {CKM_NSS_HKDF_SHA384, {1, 128, CKF_DERIVE}, PR_TRUE}, + {CKM_NSS_HKDF_SHA512, {1, 128, CKF_DERIVE}, PR_TRUE}, /* ------------------------- CAST Operations --------------------------- */ #ifdef NSS_SOFTOKEN_DOES_CAST /* Cast operations are not supported ( yet? ) */ diff --git a/mozilla/security/nss/lib/softoken/pkcs11c.c b/mozilla/security/nss/lib/softoken/pkcs11c.c index d45c6ff5f2d..e7551d9cbc0 100644 --- a/mozilla/security/nss/lib/softoken/pkcs11c.c +++ b/mozilla/security/nss/lib/softoken/pkcs11c.c @@ -5024,6 +5024,7 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, unsigned char key_block[NUM_MIXERS * MD5_LENGTH]; unsigned char key_block2[MD5_LENGTH]; PRBool isFIPS; + HASH_HashType hashType; CHECK_FORK(); @@ -6008,6 +6009,112 @@ ec_loser: } #endif /* NSS_ENABLE_ECC */ + /* See RFC 5869 and CK_NSS_HKDFParams for documentation. */ + case CKM_NSS_HKDF_SHA1: hashType = HASH_AlgSHA1; goto hkdf; + case CKM_NSS_HKDF_SHA256: hashType = HASH_AlgSHA256; goto hkdf; + case CKM_NSS_HKDF_SHA384: hashType = HASH_AlgSHA384; goto hkdf; + case CKM_NSS_HKDF_SHA512: hashType = HASH_AlgSHA512; goto hkdf; +hkdf: { + const CK_NSS_HKDFParams * params = + (const CK_NSS_HKDFParams *) pMechanism->pParameter; + const SECHashObject * rawHash; + unsigned hashLen; + CK_BYTE buf[HASH_LENGTH_MAX]; + /* const */ CK_BYTE * prk; /* psuedo-random key */ + CK_ULONG prkLen; + const CK_BYTE * okm; /* output keying material */ + + rawHash = HASH_GetRawHashObject(hashType); + if (rawHash == NULL || rawHash->length > sizeof buf) { + crv = CKR_FUNCTION_FAILED; + break; + } + + if (pMechanism->ulParameterLen != sizeof(CK_NSS_HKDFParams) || + !params || (!params->bExpand && !params->bExtract) || + (params->bExtract && params->ulSaltLen > 0 && !params->pSalt) || + (params->bExpand && params->ulInfoLen > 0 && !params->pInfo)) { + crv = CKR_MECHANISM_PARAM_INVALID; + break; + } + if (keySize == 0 || keySize > sizeof key_block || + (!params->bExpand && keySize > hashLen) || + (params->bExpand && keySize > 255 * hashLen)) { + crv = CKR_TEMPLATE_INCONSISTENT; + break; + } + + /* HKDF-Extract(salt, base key value) */ + if (params->bExtract) { + CK_BYTE * salt; + CK_ULONG saltLen; + HMACContext * hmac; + unsigned int bufLen; + + salt = params->pSalt; + saltLen = params->ulSaltLen; + if (salt == NULL) { + saltLen = hashLen; + salt = buf; + memset(salt, 0, saltLen); + } + hmac = HMAC_Create(rawHash, salt, saltLen, isFIPS); + if (!hmac) { + crv = CKR_HOST_MEMORY; + break; + } + HMAC_Begin(hmac); + HMAC_Update(hmac, (const unsigned char*) att->attrib.pValue, + att->attrib.ulValueLen); + HMAC_Finish(hmac, buf, &bufLen, sizeof(buf)); + HMAC_Destroy(hmac, PR_TRUE); + PORT_Assert(bufLen == rawHash->length); + prk = buf; + prkLen = bufLen; + } else { + /* PRK = base key value */ + prk = (CK_BYTE*) att->attrib.pValue; + prkLen = att->attrib.ulValueLen; + } + + /* HKDF-Expand */ + if (!params->bExpand) { + okm = prk; + } else { + /* T(1) = HMAC-Hash(prk, "" | info | 0x01) + * T(n) = HMAC-Hash(prk, T(n-1) | info | n + * key material = T(1) | ... | T(n) + */ + HMACContext * hmac; + CK_BYTE i; + unsigned iterations = PR_ROUNDUP(keySize, hashLen) / hashLen; + hmac = HMAC_Create(rawHash, prk, prkLen, isFIPS); + if (hmac == NULL) { + crv = CKR_HOST_MEMORY; + break; + } + for (i = 1; i <= iterations; ++i) { + unsigned len; + HMAC_Begin(hmac); + if (i > 1) { + HMAC_Update(hmac, key_block + ((i-2) * hashLen), hashLen); + } + if (params->ulInfoLen != 0) { + HMAC_Update(hmac, params->pInfo, params->ulInfoLen); + } + HMAC_Update(hmac, &i, 1); + HMAC_Finish(hmac, key_block + ((i-1) * hashLen), &len, + hashLen); + PORT_Assert(len == hashLen); + } + HMAC_Destroy(hmac, PR_TRUE); + okm = key_block; + } + /* key material = prk */ + crv = sftk_forceAttribute(key, CKA_VALUE, okm, keySize); + break; + } /* end of CKM_NSS_HKDF_* */ + default: crv = CKR_MECHANISM_INVALID; } diff --git a/mozilla/security/nss/lib/util/pkcs11n.h b/mozilla/security/nss/lib/util/pkcs11n.h index 1adc6324429..5e0e4376280 100644 --- a/mozilla/security/nss/lib/util/pkcs11n.h +++ b/mozilla/security/nss/lib/util/pkcs11n.h @@ -39,7 +39,7 @@ #define _PKCS11N_H_ #ifdef DEBUG -static const char CKT_CVS_ID[] = "@(#) $RCSfile: pkcs11n.h,v $ $Revision: 1.19 $ $Date: 2009-03-25 05:21:03 $"; +static const char CKT_CVS_ID[] = "@(#) $RCSfile: pkcs11n.h,v $ $Revision: 1.19.22.1 $ $Date: 2010-12-03 01:19:51 $"; #endif /* DEBUG */ /* @@ -168,6 +168,12 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile: pkcs11n.h,v $ $Revision: 1.19 $ #define CKM_NSS_AES_KEY_WRAP (CKM_NSS + 1) #define CKM_NSS_AES_KEY_WRAP_PAD (CKM_NSS + 2) +/* HKDF key derivation mechanisms. See CK_NSS_HKDFParams for documentation. */ +#define CKM_NSS_HKDF_SHA1 (CKM_NSS + 3) +#define CKM_NSS_HKDF_SHA256 (CKM_NSS + 4) +#define CKM_NSS_HKDF_SHA384 (CKM_NSS + 5) +#define CKM_NSS_HKDF_SHA512 (CKM_NSS + 6) + /* * HISTORICAL: * Do not attempt to use these. They are only used by NETSCAPE's internal @@ -196,6 +202,33 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile: pkcs11n.h,v $ $Revision: 1.19 $ #define CKR_NSS_CERTDB_FAILED (CKR_NSS + 1) #define CKR_NSS_KEYDB_FAILED (CKR_NSS + 2) +/* Mandatory parameter for the CKM_NSS_HKDF_* key deriviation mechanisms. + See RFC 5869. + + bExtract: If set, HKDF-Extract will be applied to the input key. If + the optional salt is given, it is used; otherwise, the salt is + set to a sequence of zeros equal in length to the HMAC output. + If bExpand is not set, then the key template given to + C_DeriveKey must indicate an output key size less than or equal + to the output size of the HMAC. + + bExpand: If set, HKDF-Expand will be applied to the input key (if + bExtract is not set) or to the result of HKDF-Extract (if + bExtract is set). Any info given in the optional pInfo field will + be included in the calculation. + + The size of the output key must be specified in the template passed to + C_DeriveKey. +*/ +typedef struct CK_NSS_HKDFParams { + CK_BBOOL bExtract; + CK_BYTE_PTR pSalt; + CK_ULONG ulSaltLen; + CK_BBOOL bExpand; + CK_BYTE_PTR pInfo; + CK_ULONG ulInfoLen; +} CK_NSS_HKDFParams; + /* * Trust info *