From: Matt Caswell Date: Fri, 3 Jan 2020 09:37:19 +0000 (+0000) Subject: Don't store an HMAC key for longer than we need X-Git-Tag: OpenSSL_1_1_1e~72 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=16d92fa873975b2a32d3ea01b7d63c64f7fd9ee7;p=oweals%2Fopenssl.git Don't store an HMAC key for longer than we need The HMAC_CTX structure stores the original key in case the ctx is reused without changing the key. However, HMAC_Init_ex() checks its parameters such that the only code path where the stored key is ever used is in the case where HMAC_Init_ex is called with a NULL key and an explicit md is provided which is the same as the md that was provided previously. But in that case we can actually reuse the pre-digested key that we calculated last time, so we can refactor the code not to use the stored key at all. With that refactor done it is no longer necessary to store the key in the ctx at all. This means that long running ctx's will not keep the key in memory for any longer than required. Note though that the digested key *is* still kept in memory for the duration of the life of the ctx. Fixes #10743 Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/10763) --- diff --git a/crypto/hmac/hmac.c b/crypto/hmac/hmac.c index 51dd91237c..bc49b26ab1 100644 --- a/crypto/hmac/hmac.c +++ b/crypto/hmac/hmac.c @@ -18,16 +18,17 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, const EVP_MD *md, ENGINE *impl) { - int rv = 0; - int i, j, reset = 0; + int rv = 0, reset = 0; + int i, j; unsigned char pad[HMAC_MAX_MD_CBLOCK_SIZE]; + unsigned int keytmp_length; + unsigned char keytmp[HMAC_MAX_MD_CBLOCK_SIZE]; /* If we are changing MD then we must have a key */ if (md != NULL && md != ctx->md && (key == NULL || len < 0)) return 0; if (md != NULL) { - reset = 1; ctx->md = md; } else if (ctx->md) { md = ctx->md; @@ -44,35 +45,34 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, if (key != NULL) { reset = 1; + j = EVP_MD_block_size(md); - if (!ossl_assert(j <= (int)sizeof(ctx->key))) + if (!ossl_assert(j <= (int)sizeof(keytmp))) return 0; if (j < len) { if (!EVP_DigestInit_ex(ctx->md_ctx, md, impl) || !EVP_DigestUpdate(ctx->md_ctx, key, len) - || !EVP_DigestFinal_ex(ctx->md_ctx, ctx->key, - &ctx->key_length)) + || !EVP_DigestFinal_ex(ctx->md_ctx, keytmp, + &keytmp_length)) return 0; } else { - if (len < 0 || len > (int)sizeof(ctx->key)) + if (len < 0 || len > (int)sizeof(keytmp)) return 0; - memcpy(ctx->key, key, len); - ctx->key_length = len; + memcpy(keytmp, key, len); + keytmp_length = len; } - if (ctx->key_length != HMAC_MAX_MD_CBLOCK_SIZE) - memset(&ctx->key[ctx->key_length], 0, - HMAC_MAX_MD_CBLOCK_SIZE - ctx->key_length); - } + if (keytmp_length != HMAC_MAX_MD_CBLOCK_SIZE) + memset(&keytmp[keytmp_length], 0, + HMAC_MAX_MD_CBLOCK_SIZE - keytmp_length); - if (reset) { for (i = 0; i < HMAC_MAX_MD_CBLOCK_SIZE; i++) - pad[i] = 0x36 ^ ctx->key[i]; + pad[i] = 0x36 ^ keytmp[i]; if (!EVP_DigestInit_ex(ctx->i_ctx, md, impl) || !EVP_DigestUpdate(ctx->i_ctx, pad, EVP_MD_block_size(md))) goto err; for (i = 0; i < HMAC_MAX_MD_CBLOCK_SIZE; i++) - pad[i] = 0x5c ^ ctx->key[i]; + pad[i] = 0x5c ^ keytmp[i]; if (!EVP_DigestInit_ex(ctx->o_ctx, md, impl) || !EVP_DigestUpdate(ctx->o_ctx, pad, EVP_MD_block_size(md))) goto err; @@ -81,8 +81,10 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, goto err; rv = 1; err: - if (reset) + if (reset) { + OPENSSL_cleanse(keytmp, sizeof(keytmp)); OPENSSL_cleanse(pad, sizeof(pad)); + } return rv; } @@ -149,8 +151,6 @@ static void hmac_ctx_cleanup(HMAC_CTX *ctx) EVP_MD_CTX_reset(ctx->o_ctx); EVP_MD_CTX_reset(ctx->md_ctx); ctx->md = NULL; - ctx->key_length = 0; - OPENSSL_cleanse(ctx->key, sizeof(ctx->key)); } void HMAC_CTX_free(HMAC_CTX *ctx) @@ -201,8 +201,6 @@ int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx) goto err; if (!EVP_MD_CTX_copy_ex(dctx->md_ctx, sctx->md_ctx)) goto err; - memcpy(dctx->key, sctx->key, HMAC_MAX_MD_CBLOCK_SIZE); - dctx->key_length = sctx->key_length; dctx->md = sctx->md; return 1; err: diff --git a/crypto/hmac/hmac_local.h b/crypto/hmac/hmac_local.h index ed855e89a4..1f40e01a59 100644 --- a/crypto/hmac/hmac_local.h +++ b/crypto/hmac/hmac_local.h @@ -18,8 +18,6 @@ struct hmac_ctx_st { EVP_MD_CTX *md_ctx; EVP_MD_CTX *i_ctx; EVP_MD_CTX *o_ctx; - unsigned int key_length; - unsigned char key[HMAC_MAX_MD_CBLOCK_SIZE]; }; #endif diff --git a/test/hmactest.c b/test/hmactest.c index ca775773a6..e12c48fd8d 100644 --- a/test/hmactest.c +++ b/test/hmactest.c @@ -173,6 +173,27 @@ static int test_hmac_run(void) if (!TEST_str_eq(p, (char *)test[6].digest)) goto err; + /* Test reusing a key */ + if (!TEST_true(HMAC_Init_ex(ctx, NULL, 0, NULL, NULL)) + || !TEST_true(HMAC_Update(ctx, test[6].data, test[6].data_len)) + || !TEST_true(HMAC_Final(ctx, buf, &len))) + goto err; + p = pt(buf, len); + if (!TEST_str_eq(p, (char *)test[6].digest)) + goto err; + + /* + * Test reusing a key where the digest is provided again but is the same as + * last time + */ + if (!TEST_true(HMAC_Init_ex(ctx, NULL, 0, EVP_sha256(), NULL)) + || !TEST_true(HMAC_Update(ctx, test[6].data, test[6].data_len)) + || !TEST_true(HMAC_Final(ctx, buf, &len))) + goto err; + p = pt(buf, len); + if (!TEST_str_eq(p, (char *)test[6].digest)) + goto err; + ret = 1; err: HMAC_CTX_free(ctx);