]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add a flag so finalised contexts are not reused
authorSimo Sorce <simo@redhat.com>
Thu, 9 Mar 2023 16:45:02 +0000 (11:45 -0500)
committerPauli <pauli@openssl.org>
Tue, 14 Mar 2023 21:42:59 +0000 (08:42 +1100)
The EVP layer should not rely on the underlying low level code to
handle catching incorrect reuse of contexts.
Add a flag to mark a context as finalised as needed and then catch and
immediately error on Update/Final operations if called improperly.

Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/20375)

crypto/evp/digest.c
crypto/evp/m_sigver.c
include/crypto/evp.h
include/openssl/evp.h

index 6ce80a1b031b9363439b80238ed1eb28f89f36b6..e7590cda55471d3196ea66f710bfd71da7816ede 100644 (file)
@@ -181,7 +181,8 @@ static int evp_md_init_internal(EVP_MD_CTX *ctx, const EVP_MD *type,
     }
 #endif
 
-    EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
+    EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED
+                                | EVP_MD_CTX_FLAG_FINALISED);
 
     if (type != NULL) {
         ctx->reqdigest = type;
@@ -387,6 +388,11 @@ int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count)
     if (count == 0)
         return 1;
 
+    if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
+        return 0;
+    }
+
     if (ctx->pctx != NULL
             && EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx->pctx)
             && ctx->pctx->op.sig.algctx != NULL) {
@@ -453,8 +459,15 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize)
         return 0;
     }
 
+    if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
+        return 0;
+    }
+
     ret = ctx->digest->dfinal(ctx->algctx, md, &size, mdsize);
 
+    ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
+
     if (isize != NULL) {
         if (size <= UINT_MAX) {
             *isize = (unsigned int)size;
@@ -499,12 +512,19 @@ int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, size_t size)
         return 0;
     }
 
+    if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
+        return 0;
+    }
+
     params[i++] = OSSL_PARAM_construct_size_t(OSSL_DIGEST_PARAM_XOFLEN, &size);
     params[i++] = OSSL_PARAM_construct_end();
 
     if (EVP_MD_CTX_set_params(ctx, params) > 0)
         ret = ctx->digest->dfinal(ctx->algctx, md, &size, size);
 
+    ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
+
     return ret;
 
 legacy:
index 68ae95705812c209a931c3b3e6957ec8480e0b7f..e7888d2acd6e963559dbdce5c51ffb3e16bcf09b 100644 (file)
@@ -64,6 +64,8 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
     if (ctx->pctx == NULL)
         return 0;
 
+    EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_FINALISED);
+
     locpctx = ctx->pctx;
     ERR_set_mark();
 
@@ -401,6 +403,11 @@ int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize)
 {
     EVP_PKEY_CTX *pctx = ctx->pctx;
 
+    if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
+        return 0;
+    }
+
     if (pctx == NULL
             || pctx->operation != EVP_PKEY_OP_SIGNCTX
             || pctx->op.sig.algctx == NULL
@@ -431,6 +438,11 @@ int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t dsize)
 {
     EVP_PKEY_CTX *pctx = ctx->pctx;
 
+    if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
+        return 0;
+    }
+
     if (pctx == NULL
             || pctx->operation != EVP_PKEY_OP_VERIFYCTX
             || pctx->op.sig.algctx == NULL
@@ -464,6 +476,11 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
     int sctx = 0, r = 0;
     EVP_PKEY_CTX *dctx = NULL, *pctx = ctx->pctx;
 
+    if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
+        return 0;
+    }
+
     if (pctx == NULL
             || pctx->operation != EVP_PKEY_OP_SIGNCTX
             || pctx->op.sig.algctx == NULL
@@ -479,7 +496,10 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
     r = pctx->op.sig.signature->digest_sign_final(pctx->op.sig.algctx,
                                                   sigret, siglen,
                                                   sigret == NULL ? 0 : *siglen);
-    EVP_PKEY_CTX_free(dctx);
+    if (dctx == NULL && sigret != NULL)
+        ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
+    else
+        EVP_PKEY_CTX_free(dctx);
     return r;
 
  legacy:
@@ -497,9 +517,10 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
     if (pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) {
         if (sigret == NULL)
             return pctx->pmeth->signctx(pctx, sigret, siglen, ctx);
-        if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE)
+        if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISE) != 0) {
             r = pctx->pmeth->signctx(pctx, sigret, siglen, ctx);
-        else {
+            ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
+        } else {
             dctx = EVP_PKEY_CTX_dup(pctx);
             if (dctx == NULL)
                 return 0;
@@ -560,15 +581,23 @@ int EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen,
 {
     EVP_PKEY_CTX *pctx = ctx->pctx;
 
+    if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
+        return 0;
+    }
+
     if (pctx != NULL
             && pctx->operation == EVP_PKEY_OP_SIGNCTX
             && pctx->op.sig.algctx != NULL
             && pctx->op.sig.signature != NULL) {
-        if (pctx->op.sig.signature->digest_sign != NULL)
+        if (pctx->op.sig.signature->digest_sign != NULL) {
+            if (sigret != NULL)
+                ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
             return pctx->op.sig.signature->digest_sign(pctx->op.sig.algctx,
                                                        sigret, siglen,
                                                        sigret == NULL ? 0 : *siglen,
                                                        tbs, tbslen);
+        }
     } else {
         /* legacy */
         if (ctx->pctx->pmeth != NULL && ctx->pctx->pmeth->digestsign != NULL)
@@ -589,6 +618,11 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig,
     int vctx = 0;
     EVP_PKEY_CTX *dctx = NULL, *pctx = ctx->pctx;
 
+    if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
+        return 0;
+    }
+
     if (pctx == NULL
             || pctx->operation != EVP_PKEY_OP_VERIFYCTX
             || pctx->op.sig.algctx == NULL
@@ -603,7 +637,10 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig,
     }
     r = pctx->op.sig.signature->digest_verify_final(pctx->op.sig.algctx,
                                                     sig, siglen);
-    EVP_PKEY_CTX_free(dctx);
+    if (dctx == NULL)
+        ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
+    else
+        EVP_PKEY_CTX_free(dctx);
     return r;
 
  legacy:
@@ -623,9 +660,10 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig,
     else
         vctx = 0;
     if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) {
-        if (vctx)
+        if (vctx) {
             r = pctx->pmeth->verifyctx(pctx, sig, siglen, ctx);
-        else
+            ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
+        } else
             r = EVP_DigestFinal_ex(ctx, md, &mdlen);
     } else {
         EVP_MD_CTX *tmp_ctx = EVP_MD_CTX_new();
@@ -652,14 +690,21 @@ int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret,
 {
     EVP_PKEY_CTX *pctx = ctx->pctx;
 
+    if ((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
+        return 0;
+    }
+
     if (pctx != NULL
             && pctx->operation == EVP_PKEY_OP_VERIFYCTX
             && pctx->op.sig.algctx != NULL
             && pctx->op.sig.signature != NULL) {
-        if (pctx->op.sig.signature->digest_verify != NULL)
+        if (pctx->op.sig.signature->digest_verify != NULL) {
+            ctx->flags |= EVP_MD_CTX_FLAG_FINALISED;
             return pctx->op.sig.signature->digest_verify(pctx->op.sig.algctx,
                                                          sigret, siglen,
                                                          tbs, tbslen);
+        }
     } else {
         /* legacy */
         if (ctx->pctx->pmeth != NULL && ctx->pctx->pmeth->digestverify != NULL)
index dbbdcccbda90ce0b63c3a1ac9847a9d2300be4f4..55b44cd8353c92cfaddd725b327472be903cc554 100644 (file)
@@ -21,6 +21,7 @@
  * values in evp.h
  */
 #define EVP_MD_CTX_FLAG_KEEP_PKEY_CTX   0x0400
+#define EVP_MD_CTX_FLAG_FINALISED       0x0800
 
 #define evp_pkey_ctx_is_legacy(ctx)                             \
     ((ctx)->keymgmt == NULL)
index b8bafe4e1258e6e3654dadbbe12923030166c58b..e10c0617a486031844973b3e42d25ad5857d4368 100644 (file)
@@ -226,7 +226,8 @@ int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd,
  * if the following flag is set.
  */
 # define EVP_MD_CTX_FLAG_FINALISE        0x0200
-/* NOTE: 0x0400 is reserved for internal usage */
+/* NOTE: 0x0400 and 0x0800 are reserved for internal usage */
+
 # ifndef OPENSSL_NO_DEPRECATED_3_0
 OSSL_DEPRECATEDIN_3_0
 EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len);