diff options
author | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-10-24 16:14:41 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-10-24 22:43:06 +0200 |
commit | c6f4af2c515f81e5baa0423442c4b1a0355f1b70 (patch) | |
tree | 3b9983dfd257f83941652c104c8ec4b7e3034d82 | |
parent | fbb55365326ca10b0f01241ea1e09d50c7cd7e42 (diff) | |
download | uxp-c6f4af2c515f81e5baa0423442c4b1a0355f1b70.tar.gz |
Support longer (up to RFC maximum) HKDF outputs
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.
-rw-r--r-- | security/nss/lib/softoken/pkcs11c.c | 33 |
1 files changed, 25 insertions, 8 deletions
diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c index 884702cc16..327a67d5c0 100644 --- a/security/nss/lib/softoken/pkcs11c.c +++ b/security/nss/lib/softoken/pkcs11c.c @@ -7668,9 +7668,11 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession, const SECHashObject *rawHash; unsigned hashLen; CK_BYTE hashbuf[HASH_LENGTH_MAX]; - CK_BYTE *prk; /* psuedo-random key */ + 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)) { @@ -7686,7 +7688,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; @@ -7736,34 +7738,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_* */ |