Selaa lähdekoodia

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: Tomas Mraz <tmraz@fedoraproject.org>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/10747)
Matt Caswell 4 vuotta sitten
vanhempi
commit
b1558c0bc8
3 muutettua tiedostoa jossa 40 lisäystä ja 23 poistoa
  1. 19 21
      crypto/hmac/hmac.c
  2. 0 2
      crypto/hmac/hmac_local.h
  3. 21 0
      test/hmactest.c

+ 19 - 21
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:

+ 0 - 2
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

+ 21 - 0
test/hmactest.c

@@ -169,6 +169,27 @@ static int test_hmac_run(void)
     if (!TEST_str_eq(p, 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, 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, test[6].digest))
+        goto err;
+
     ret = 1;
 err:
     HMAC_CTX_free(ctx);