Commit 341f1b7f70 for openssl.org

commit 341f1b7f70567aab668452c824d978768ea765b4
Author: Simo Sorce <simo@redhat.com>
Date:   Fri Apr 11 17:24:09 2025 -0400

    Add ml_dsa msg_update functions to provider code

    Signed-off-by: Simo Sorce <simo@redhat.com>

    Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
    Reviewed-by: Tomas Mraz <tomas@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/27342)

diff --git a/crypto/ml_dsa/ml_dsa_local.h b/crypto/ml_dsa/ml_dsa_local.h
index 7dfc91bb03..3bbe7556e4 100644
--- a/crypto/ml_dsa/ml_dsa_local.h
+++ b/crypto/ml_dsa/ml_dsa_local.h
@@ -29,7 +29,6 @@
 # define ML_DSA_PRIV_SEED_BYTES 64 /* p' = Private random seed */
 # define ML_DSA_K_BYTES 32 /* K = Private random seed for signing */
 # define ML_DSA_TR_BYTES 64 /* Size of the Hash of the public key used for signing */
-# define ML_DSA_MU_BYTES 64 /* Size of the Hash for the message representative */
 # define ML_DSA_RHO_PRIME_BYTES 64 /* private random seed size */

 /*
diff --git a/include/crypto/ml_dsa.h b/include/crypto/ml_dsa.h
index e8054c6102..3508993542 100644
--- a/include/crypto/ml_dsa.h
+++ b/include/crypto/ml_dsa.h
@@ -22,6 +22,8 @@

 # define ML_DSA_ENTROPY_LEN 32

+# define ML_DSA_MU_BYTES 64 /* Size of the Hash for the message representative */
+
 /* See FIPS 204 Section 4 Table 1 & Table 2 */
 # define ML_DSA_44_PRIV_LEN 2560
 # define ML_DSA_44_PUB_LEN 1312
diff --git a/providers/implementations/signature/ml_dsa_sig.c b/providers/implementations/signature/ml_dsa_sig.c
index b799fda2cc..63c5b7fecb 100644
--- a/providers/implementations/signature/ml_dsa_sig.c
+++ b/providers/implementations/signature/ml_dsa_sig.c
@@ -27,8 +27,12 @@
 #define ML_DSA_MESSAGE_ENCODE_PURE 1

 static OSSL_FUNC_signature_sign_message_init_fn ml_dsa_sign_msg_init;
+static OSSL_FUNC_signature_sign_message_update_fn ml_dsa_signverify_msg_update;
+static OSSL_FUNC_signature_sign_message_final_fn ml_dsa_sign_msg_final;
 static OSSL_FUNC_signature_sign_fn ml_dsa_sign;
 static OSSL_FUNC_signature_verify_message_init_fn ml_dsa_verify_msg_init;
+static OSSL_FUNC_signature_verify_message_update_fn ml_dsa_signverify_msg_update;
+static OSSL_FUNC_signature_verify_message_final_fn ml_dsa_verify_msg_final;
 static OSSL_FUNC_signature_verify_fn ml_dsa_verify;
 static OSSL_FUNC_signature_digest_sign_init_fn ml_dsa_digest_signverify_init;
 static OSSL_FUNC_signature_digest_sign_fn ml_dsa_digest_sign;
@@ -54,13 +58,20 @@ typedef struct {
     uint8_t aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE];
     size_t  aid_len;
     int mu;     /* Flag indicating we should begin from \mu, not the message */
+
+    int operation;
+    EVP_MD_CTX *md_ctx; /* Ctx for msg_init/update/final interface */
+    unsigned char *sig; /* Signature, for verification */
+    size_t siglen;
 } PROV_ML_DSA_CTX;

 static void ml_dsa_freectx(void *vctx)
 {
     PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx;

+    EVP_MD_CTX_free(ctx->md_ctx);
     OPENSSL_cleanse(ctx->test_entropy, ctx->test_entropy_len);
+    OPENSSL_free(ctx->sig);
     OPENSSL_free(ctx);
 }

@@ -84,6 +95,7 @@ static void *ml_dsa_newctx(void *provctx, int evp_type, const char *propq)
 static void *ml_dsa_dupctx(void *vctx)
 {
     PROV_ML_DSA_CTX *srcctx = (PROV_ML_DSA_CTX *)vctx;
+    PROV_ML_DSA_CTX *dstctx;

     if (!ossl_prov_is_running())
         return NULL;
@@ -92,7 +104,32 @@ static void *ml_dsa_dupctx(void *vctx)
      * Note that the ML_DSA_KEY is ref counted via EVP_PKEY so we can just copy
      * the key here.
      */
-    return OPENSSL_memdup(srcctx, sizeof(*srcctx));
+    dstctx = OPENSSL_memdup(srcctx, sizeof(*srcctx));
+
+    if (dstctx == NULL)
+        return NULL;
+
+    if (srcctx->sig != NULL) {
+        dstctx->sig = OPENSSL_memdup(srcctx->sig, srcctx->siglen);
+        if (dstctx->sig == NULL) {
+            /*
+             * Can't call ml_dsa_freectx() here, as it would free
+             * md_ctx which has not been duplicated yet.
+             */
+            OPENSSL_free(dstctx);
+            return NULL;
+        }
+    }
+
+    if (srcctx->md_ctx != NULL) {
+        dstctx->md_ctx = EVP_MD_CTX_dup(srcctx->md_ctx);
+        if (dstctx->md_ctx == NULL) {
+            ml_dsa_freectx(dstctx);
+            return NULL;
+        }
+    }
+
+    return dstctx;
 }

 static int set_alg_id_buffer(PROV_ML_DSA_CTX *ctx)
@@ -144,6 +181,7 @@ static int ml_dsa_signverify_msg_init(void *vctx, void *vkey,

     set_alg_id_buffer(ctx);
     ctx->mu = 0;
+    ctx->operation = operation;

     return ml_dsa_set_ctx_params(ctx, params);
 }
@@ -174,6 +212,72 @@ static int ml_dsa_digest_signverify_init(void *vctx, const char *mdname,
                                       EVP_PKEY_OP_SIGN, "ML_DSA Sign Init");
 }

+static int ml_dsa_signverify_msg_update(void *vctx,
+                                        const unsigned char *data,
+                                        size_t datalen)
+{
+    PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx;
+
+    if (ctx == NULL)
+        return 0;
+
+    if (!ossl_prov_is_running())
+        return 0;
+
+    if (ctx->mu)
+        return 0;
+
+    if (ctx->md_ctx == NULL) {
+        ctx->md_ctx = ossl_ml_dsa_mu_init(ctx->key, ctx->msg_encode,
+                                          ctx->context_string,
+                                          ctx->context_string_len);
+        if (ctx->md_ctx == NULL)
+            return 0;
+    }
+
+    return ossl_ml_dsa_mu_update(ctx->md_ctx, data, datalen);
+}
+
+static int ml_dsa_sign_msg_final(void *vctx, unsigned char *sig,
+                                 size_t *siglen, size_t sigsize)
+{
+    PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx;
+    uint8_t rand_tmp[ML_DSA_ENTROPY_LEN], *rnd = NULL;
+    uint8_t mu[ML_DSA_MU_BYTES];
+    int ret = 0;
+
+    if (ctx == NULL)
+        return 0;
+
+    if (!ossl_prov_is_running())
+        return 0;
+
+    if (ctx->md_ctx == NULL)
+        return 0;
+
+    if (sig != NULL) {
+        if (ctx->test_entropy_len != 0) {
+            rnd = ctx->test_entropy;
+        } else {
+            rnd = rand_tmp;
+
+            if (ctx->deterministic == 1)
+                memset(rnd, 0, sizeof(rand_tmp));
+            else if (RAND_priv_bytes_ex(ctx->libctx, rnd, sizeof(rand_tmp), 0) <= 0)
+                return 0;
+        }
+
+        if (!ossl_ml_dsa_mu_finalize(ctx->md_ctx, mu, sizeof(mu)))
+            return 0;
+    }
+
+    ret = ossl_ml_dsa_sign(ctx->key, 1, mu, sizeof(mu), NULL, 0, rnd,
+                           sizeof(rand_tmp), 0, sig, siglen, sigsize);
+    if (rnd != ctx->test_entropy)
+        OPENSSL_cleanse(rand_tmp, sizeof(rand_tmp));
+    return ret;
+}
+
 static int ml_dsa_sign(void *vctx, uint8_t *sig, size_t *siglen, size_t sigsize,
                        const uint8_t *msg, size_t msg_len)
 {
@@ -217,6 +321,24 @@ static int ml_dsa_verify_msg_init(void *vctx, void *vkey, const OSSL_PARAM param
                                       "ML_DSA Verify Init");
 }

+static int ml_dsa_verify_msg_final(void *vctx)
+{
+    PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx;
+    uint8_t mu[ML_DSA_MU_BYTES];
+
+    if (!ossl_prov_is_running())
+        return 0;
+
+    if (ctx->md_ctx == NULL)
+        return 0;
+
+    if (!ossl_ml_dsa_mu_finalize(ctx->md_ctx, mu, sizeof(mu)))
+        return 0;
+
+    return ossl_ml_dsa_verify(ctx->key, 1, mu, sizeof(mu), NULL, 0, 0,
+                              ctx->sig, ctx->siglen);
+}
+
 static int ml_dsa_verify(void *vctx, const uint8_t *sig, size_t siglen,
                          const uint8_t *msg, size_t msg_len)
 {
@@ -281,6 +403,18 @@ static int ml_dsa_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->mu))
         return 0;

+    if (pctx->operation == EVP_PKEY_OP_VERIFYMSG) {
+        p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_SIGNATURE);
+        if (p != NULL) {
+            OPENSSL_free(pctx->sig);
+            pctx->sig = NULL;
+            pctx->siglen = 0;
+            if (!OSSL_PARAM_get_octet_string(p, (void **)&pctx->sig,
+                                             0, &pctx->siglen))
+                return 0;
+        }
+    }
+
     return 1;
 }

@@ -338,9 +472,17 @@ static int ml_dsa_get_ctx_params(void *vctx, OSSL_PARAM *params)
         { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))ml_dsa_##alg##_newctx }, \
         { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT,                               \
           (void (*)(void))ml_dsa_sign_msg_init },                              \
+        { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_UPDATE,                             \
+          (void (*)(void))ml_dsa_signverify_msg_update },                      \
+        { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_FINAL,                              \
+          (void (*)(void))ml_dsa_sign_msg_final },                             \
         { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))ml_dsa_sign },             \
         { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT,                             \
           (void (*)(void))ml_dsa_verify_msg_init },                            \
+        { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_UPDATE,                           \
+          (void (*)(void))ml_dsa_signverify_msg_update },                      \
+        { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_FINAL,                            \
+          (void (*)(void))ml_dsa_verify_msg_final },                           \
         { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))ml_dsa_verify },         \
         { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,                                \
           (void (*)(void))ml_dsa_digest_signverify_init },                     \