Bug 614076 - Implement HKDF in Softoken
patch by bsmith r=rrelyea git-svn-id: svn://10.0.0.236/branches/NSS_3_12_BRANCH@261617 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -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? ) */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user