From 3383911536e8b73bbe9001590b60f1791fc92a3d Mon Sep 17 00:00:00 2001 From: jsing Date: Mon, 25 Mar 2024 13:09:13 +0000 Subject: [PATCH] Rewrite HKDF_expand(). Simplify overflow checking and length tracking, use a CBB to handle output and use HMAC_CTX_new() rather than having a HMAC_CTX on the stack. ok tb@ --- lib/libcrypto/hkdf/hkdf.c | 88 ++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/lib/libcrypto/hkdf/hkdf.c b/lib/libcrypto/hkdf/hkdf.c index 4f9c9e566a0..6104ef0cc78 100644 --- a/lib/libcrypto/hkdf/hkdf.c +++ b/lib/libcrypto/hkdf/hkdf.c @@ -1,5 +1,6 @@ -/* $OpenBSD: hkdf.c,v 1.10 2023/07/07 13:54:46 beck Exp $ */ -/* Copyright (c) 2014, Google Inc. +/* $OpenBSD: hkdf.c,v 1.11 2024/03/25 13:09:13 jsing Exp $ */ +/* + * Copyright (c) 2014, Google Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,6 +22,7 @@ #include #include +#include "bytestring.h" #include "evp_local.h" #include "hmac_local.h" @@ -73,51 +75,61 @@ HKDF_expand(uint8_t *out_key, size_t out_len, const uint8_t *info, size_t info_len) { const size_t digest_len = EVP_MD_size(digest); - uint8_t previous[EVP_MAX_MD_SIZE]; - size_t n, done = 0; - unsigned int i; + uint8_t out_hmac[EVP_MAX_MD_SIZE]; + size_t n, remaining; + uint8_t ctr; + HMAC_CTX *hmac = NULL; + CBB cbb; int ret = 0; - HMAC_CTX hmac; - /* Expand key material to desired length. */ - n = (out_len + digest_len - 1) / digest_len; - if (out_len + digest_len < out_len || n > 255) { - CRYPTOerror(EVP_R_TOO_LARGE); - return 0; - } - - HMAC_CTX_init(&hmac); - if (!HMAC_Init_ex(&hmac, prk, prk_len, digest, NULL)) - goto out; - - for (i = 0; i < n; i++) { - uint8_t ctr = i + 1; - size_t todo; + if (!CBB_init_fixed(&cbb, out_key, out_len)) + goto err; - if (i != 0 && (!HMAC_Init_ex(&hmac, NULL, 0, NULL, NULL) || - !HMAC_Update(&hmac, previous, digest_len))) - goto out; + if ((hmac = HMAC_CTX_new()) == NULL) + goto err; + if (!HMAC_Init_ex(hmac, prk, prk_len, digest, NULL)) + goto err; - if (!HMAC_Update(&hmac, info, info_len) || - !HMAC_Update(&hmac, &ctr, 1) || - !HMAC_Final(&hmac, previous, NULL)) - goto out; + remaining = out_len; + ctr = 0; - todo = digest_len; - if (todo > out_len - done) - todo = out_len - done; - - memcpy(out_key + done, previous, todo); - done += todo; + /* Expand key material to desired length. */ + while (remaining > 0) { + if (++ctr == 0) { + CRYPTOerror(EVP_R_TOO_LARGE); + goto err; + } + + if (!HMAC_Update(hmac, info, info_len)) + goto err; + if (!HMAC_Update(hmac, &ctr, 1)) + goto err; + if (!HMAC_Final(hmac, out_hmac, NULL)) + goto err; + + if ((n = remaining) > digest_len) + n = digest_len; + + if (!CBB_add_bytes(&cbb, out_hmac, n)) + goto err; + + remaining -= n; + + if (remaining > 0) { + if (!HMAC_Init_ex(hmac, NULL, 0, NULL, NULL)) + goto err; + if (!HMAC_Update(hmac, out_hmac, digest_len)) + goto err; + } } ret = 1; - out: - HMAC_CTX_cleanup(&hmac); - explicit_bzero(previous, sizeof(previous)); - if (ret != 1) - CRYPTOerror(ERR_R_CRYPTO_LIB); + err: + CBB_cleanup(&cbb); + HMAC_CTX_free(hmac); + explicit_bzero(out_hmac, sizeof(out_hmac)); + return ret; } LCRYPTO_ALIAS(HKDF_expand); -- 2.20.1