From edfba06ce39f155f9394381d4f445a0c986bac77 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 24 Oct 2019 16:14:41 +0200 Subject: 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. --- security/nss/lib/softoken/pkcs11c.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'security/nss') diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c index 884702cc1..327a67d5c 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_* */ -- cgit v1.2.3