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:
rrelyea%redhat.com
2010-12-03 01:19:51 +00:00
parent d3c8ad7df8
commit cce303b1ab
3 changed files with 146 additions and 1 deletions

View File

@@ -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? ) */

View File

@@ -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;
}

View File

@@ -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
*