summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Jacobs <kjacobs@mozilla.com>2019-10-01 18:13:17 +0000
committerKevin Jacobs <kjacobs@mozilla.com>2019-10-01 18:13:17 +0000
commitb5eecf2f86646f45923664c494b1a430619d3742 (patch)
treefe6ac73173018268022cbab9347576109b18636c
parentd299d9ea9484af472d1f254a0765da69bfda1750 (diff)
downloadnss-hg-b5eecf2f86646f45923664c494b1a430619d3742.tar.gz
Bug 1577953 - Support longer (up to RFC maximum) HKDF outputs r=jcj
HKDF-Expand enforces a maximum output length much shorter than stated in the RFC. This patch aligns the implementation with the RFC by allocating more output space when necessary. Differential Revision: https://phabricator.services.mozilla.com/D45249
-rw-r--r--lib/softoken/pkcs11c.c31
1 files changed, 24 insertions, 7 deletions
diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
index 4f53cca61..0a1c69892 100644
--- a/lib/softoken/pkcs11c.c
+++ b/lib/softoken/pkcs11c.c
@@ -7952,7 +7952,9 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
CK_BYTE hashbuf[HASH_LENGTH_MAX];
CK_BYTE *prk; /* psuedo-random key */
CK_ULONG prkLen;
- CK_BYTE *okm; /* output keying material */
+ CK_BYTE *okm; /* output keying material */
+ unsigned allocated_space = 0; /* If we need more work space, track it */
+ unsigned char *key_buf = &key_block[0];
rawHash = HASH_GetRawHashObject(hashType);
if (rawHash == NULL || rawHash->length > sizeof(hashbuf)) {
@@ -7968,7 +7970,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
- if (keySize == 0 || keySize > sizeof key_block ||
+ if (keySize == 0 ||
(!params->bExpand && keySize > hashLen) ||
(params->bExpand && keySize > 255 * hashLen)) {
crv = CKR_TEMPLATE_INCONSISTENT;
@@ -8018,34 +8020,49 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
/* T(1) = HMAC-Hash(prk, "" | info | 0x01)
* T(n) = HMAC-Hash(prk, T(n-1) | info | n
* key material = T(1) | ... | T(n)
+ *
+ * If the requested output length does not fit
+ * within |key_block|, allocate space for expansion.
*/
HMACContext *hmac;
CK_BYTE bi;
- unsigned iterations = PR_ROUNDUP(keySize, hashLen) / hashLen;
+ unsigned n_bytes = PR_ROUNDUP(keySize, hashLen);
+ unsigned iterations = n_bytes / hashLen;
hmac = HMAC_Create(rawHash, prk, prkLen, isFIPS);
if (hmac == NULL) {
crv = CKR_HOST_MEMORY;
break;
}
- for (bi = 1; bi <= iterations; ++bi) {
+ if (n_bytes > sizeof(key_block)) {
+ key_buf = PORT_Alloc(n_bytes);
+ if (key_buf == NULL) {
+ crv = CKR_HOST_MEMORY;
+ break;
+ }
+ allocated_space = n_bytes;
+ }
+ for (bi = 1; bi <= iterations && bi > 0; ++bi) {
unsigned len;
HMAC_Begin(hmac);
if (bi > 1) {
- HMAC_Update(hmac, key_block + ((bi - 2) * hashLen), hashLen);
+ HMAC_Update(hmac, key_buf + ((bi - 2) * hashLen), hashLen);
}
if (params->ulInfoLen != 0) {
HMAC_Update(hmac, params->pInfo, params->ulInfoLen);
}
HMAC_Update(hmac, &bi, 1);
- HMAC_Finish(hmac, key_block + ((bi - 1) * hashLen), &len,
+ HMAC_Finish(hmac, key_buf + ((bi - 1) * hashLen), &len,
hashLen);
PORT_Assert(len == hashLen);
}
HMAC_Destroy(hmac, PR_TRUE);
- okm = key_block;
+ okm = key_buf;
}
/* key material = prk */
crv = sftk_forceAttribute(key, CKA_VALUE, okm, keySize);
+ if (allocated_space) {
+ PORT_ZFree(key_buf, allocated_space);
+ }
break;
} /* end of CKM_NSS_HKDF_* */