]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add EVP digest context serialization
authorSimo Sorce <simo@redhat.com>
Thu, 20 Nov 2025 15:25:47 +0000 (10:25 -0500)
committerDmitry Belyavskiy <beldmit@gmail.com>
Fri, 12 Dec 2025 08:08:33 +0000 (09:08 +0100)
This commit introduces two new functions, EVP_MD_CTX_serialize and
EVP_MD_CTX_deserialize, to the EVP digest API.

These functions allow an application to save the state of a digest
context (EVP_MD_CTX) and restore it later. This is useful for
checkpointing long-running computations, enabling them to be paused
and resumed without starting over.

The implementation adds the OSSL_FUNC_DIGEST_SERIALIZE and
OSSL_FUNC_DIGEST_DESERIALIZE dispatch functions for providers to
supply this functionality.

Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/28837)

crypto/err/openssl.txt
crypto/evp/digest.c
crypto/evp/evp_err.c
include/crypto/evp.h
include/crypto/evperr.h
include/openssl/core_dispatch.h
include/openssl/evp.h
include/openssl/evperr.h
util/libcrypto.num

index 70e06a6a38aed05a9eeb6864c2eb2dcc1bd4042f..28f8b4fd61952a5b072878b621ede0853821d3af 100644 (file)
@@ -700,6 +700,7 @@ EVP_R_CIPHER_NOT_GCM_MODE:184:cipher not gcm mode
 EVP_R_CIPHER_PARAMETER_ERROR:122:cipher parameter error
 EVP_R_COMMAND_NOT_SUPPORTED:147:command not supported
 EVP_R_CONFLICTING_ALGORITHM_NAME:201:conflicting algorithm name
+EVP_R_CONTEXT_FINALIZED:239:context finalized
 EVP_R_COPY_ERROR:173:copy error
 EVP_R_CTRL_NOT_IMPLEMENTED:132:ctrl not implemented
 EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED:133:ctrl operation not implemented
index 7184f9a051e8bf091a43362e52e4ee35eba47e40..61c9b49c5095ec9172a41976d8bad29300fb59ef 100644 (file)
@@ -494,6 +494,57 @@ int EVP_DigestSqueeze(EVP_MD_CTX *ctx, unsigned char *md, size_t size)
     return ctx->digest->dsqueeze(ctx->algctx, md, &size, size);
 }
 
+int EVP_MD_CTX_serialize(EVP_MD_CTX *ctx, unsigned char *out, size_t *outlen)
+{
+    if (ctx->digest == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_NULL_ALGORITHM);
+        return 0;
+    }
+
+    if (ctx->digest->prov == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION);
+        return 0;
+    }
+
+    if (ctx->digest->serialize == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_METHOD_NOT_SUPPORTED);
+        return 0;
+    }
+
+    if (ossl_unlikely((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_CONTEXT_FINALIZED);
+        return 0;
+    }
+
+    return ctx->digest->serialize(ctx->algctx, out, outlen);
+}
+
+int EVP_MD_CTX_deserialize(EVP_MD_CTX *ctx, const unsigned char *in,
+    size_t inlen)
+{
+    if (ctx->digest == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_NULL_ALGORITHM);
+        return 0;
+    }
+
+    if (ctx->digest->prov == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION);
+        return 0;
+    }
+
+    if (ctx->digest->deserialize == NULL) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_METHOD_NOT_SUPPORTED);
+        return 0;
+    }
+
+    if (ossl_unlikely((ctx->flags & EVP_MD_CTX_FLAG_FINALISED) != 0)) {
+        ERR_raise(ERR_LIB_EVP, EVP_R_CONTEXT_FINALIZED);
+        return 0;
+    }
+
+    return ctx->digest->deserialize(ctx->algctx, in, inlen);
+}
+
 EVP_MD_CTX *EVP_MD_CTX_dup(const EVP_MD_CTX *in)
 {
     EVP_MD_CTX *out = EVP_MD_CTX_new();
@@ -1035,6 +1086,14 @@ static void *evp_md_from_algorithm(int name_id,
             if (md->copyctx == NULL)
                 md->copyctx = OSSL_FUNC_digest_copyctx(fns);
             break;
+        case OSSL_FUNC_DIGEST_SERIALIZE:
+            if (md->serialize == NULL)
+                md->serialize = OSSL_FUNC_digest_serialize(fns);
+            break;
+        case OSSL_FUNC_DIGEST_DESERIALIZE:
+            if (md->deserialize == NULL)
+                md->deserialize = OSSL_FUNC_digest_deserialize(fns);
+            break;
         }
     }
     if ((fncnt != 0 && fncnt != 5 && fncnt != 6)
index 5672e7293f6520addffd0d2f407749f6d11dc6c5..55b26c7cd7ae4b3eb9c178ffd7dfd6729e2d93c4 100644 (file)
@@ -39,6 +39,7 @@ static const ERR_STRING_DATA EVP_str_reasons[] = {
         "command not supported" },
     { ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CONFLICTING_ALGORITHM_NAME),
         "conflicting algorithm name" },
+    { ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CONTEXT_FINALIZED), "context finalized" },
     { ERR_PACK(ERR_LIB_EVP, 0, EVP_R_COPY_ERROR), "copy error" },
     { ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CTRL_NOT_IMPLEMENTED),
         "ctrl not implemented" },
index 43d4fdc5276bc70bf9da225c9974c59396cf516a..30de8b272f32c7d104c54742fb5b381e4a263ac0 100644 (file)
@@ -294,6 +294,8 @@ struct evp_md_st {
     OSSL_FUNC_digest_gettable_params_fn *gettable_params;
     OSSL_FUNC_digest_settable_ctx_params_fn *settable_ctx_params;
     OSSL_FUNC_digest_gettable_ctx_params_fn *gettable_ctx_params;
+    OSSL_FUNC_digest_serialize_fn *serialize;
+    OSSL_FUNC_digest_deserialize_fn *deserialize;
 
 } /* EVP_MD */;
 
index 1a91b62fce5681abbf1acf095165c73966d5ede2..afe136c816ae6df9e391921acf42d3d19849cdd7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
index 8f6278070e1d3dc1f8793c40041f3578b455b282..acdf15433201fda709ca82cd5996e86d756ef1a6 100644 (file)
@@ -315,6 +315,8 @@ OSSL_CORE_MAKE_FUNC(int, SSL_QUIC_TLS_alert,
 #define OSSL_FUNC_DIGEST_GETTABLE_CTX_PARAMS 13
 #define OSSL_FUNC_DIGEST_SQUEEZE 14
 #define OSSL_FUNC_DIGEST_COPYCTX 15
+#define OSSL_FUNC_DIGEST_SERIALIZE 16
+#define OSSL_FUNC_DIGEST_DESERIALIZE 17
 
 OSSL_CORE_MAKE_FUNC(void *, digest_newctx, (void *provctx))
 OSSL_CORE_MAKE_FUNC(int, digest_init, (void *dctx, const OSSL_PARAM params[]))
@@ -345,6 +347,10 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, digest_settable_ctx_params,
     (void *dctx, void *provctx))
 OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, digest_gettable_ctx_params,
     (void *dctx, void *provctx))
+OSSL_CORE_MAKE_FUNC(int, digest_serialize,
+    (void *dctx, unsigned char *out, size_t *outl))
+OSSL_CORE_MAKE_FUNC(int, digest_deserialize,
+    (void *dctx, const unsigned char *in, size_t inl))
 
 /* Symmetric Ciphers */
 
index 6c05d9a9136077545236a7111cd8450807bddd73..1cf61076cc9f3f923a1de11a83b79c15b50cebf3 100644 (file)
@@ -753,6 +753,10 @@ __owur int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *out,
     size_t outlen);
 __owur int EVP_DigestSqueeze(EVP_MD_CTX *ctx, unsigned char *out,
     size_t outlen);
+__owur int EVP_MD_CTX_serialize(EVP_MD_CTX *ctx, unsigned char *out,
+    size_t *outlen);
+__owur int EVP_MD_CTX_deserialize(EVP_MD_CTX *ctx, const unsigned char *in,
+    size_t inlen);
 
 __owur EVP_MD *EVP_MD_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
     const char *properties);
index 23e4a9796a0186de07be9f6e4242d89e8d060c2b..b3d2cb04efabe48031dc79c37e6729e0e07808ee 100644 (file)
@@ -33,6 +33,7 @@
 #define EVP_R_CIPHER_PARAMETER_ERROR 122
 #define EVP_R_COMMAND_NOT_SUPPORTED 147
 #define EVP_R_CONFLICTING_ALGORITHM_NAME 201
+#define EVP_R_CONTEXT_FINALIZED 239
 #define EVP_R_COPY_ERROR 173
 #define EVP_R_CTRL_NOT_IMPLEMENTED 132
 #define EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED 133
index 155ba0f93d18c816d00ee5071c0ea156649e9cc7..324cc46a72992225115ca870918bb23117b69b73 100644 (file)
@@ -5815,3 +5815,5 @@ OSSL_PARAM_clear_free                   ? 4_0_0   EXIST::FUNCTION:
 CMS_dataFinal_ex                        ?      4_0_0   EXIST::FUNCTION:CMS
 CMS_SignerInfo_verify_ex                ?      4_0_0   EXIST::FUNCTION:CMS
 EVP_SIGNATURE_has_message_update        ?      4_0_0   EXIST::FUNCTION:
+EVP_MD_CTX_serialize                    ?      4_0_0   EXIST::FUNCTION:
+EVP_MD_CTX_deserialize                  ?      4_0_0   EXIST::FUNCTION: