aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssl/providers/implementations/signature
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssl/providers/implementations/signature')
-rw-r--r--crypto/openssl/providers/implementations/signature/build.info45
-rw-r--r--crypto/openssl/providers/implementations/signature/dsa_sig.c1085
-rw-r--r--crypto/openssl/providers/implementations/signature/ecdsa_sig.c1108
-rw-r--r--crypto/openssl/providers/implementations/signature/eddsa_sig.c1146
-rw-r--r--crypto/openssl/providers/implementations/signature/mac_legacy_sig.c265
-rw-r--r--crypto/openssl/providers/implementations/signature/ml_dsa_sig.c368
-rw-r--r--crypto/openssl/providers/implementations/signature/rsa_sig.c2144
-rw-r--r--crypto/openssl/providers/implementations/signature/slh_dsa_sig.c388
-rw-r--r--crypto/openssl/providers/implementations/signature/sm2_sig.c585
9 files changed, 7134 insertions, 0 deletions
diff --git a/crypto/openssl/providers/implementations/signature/build.info b/crypto/openssl/providers/implementations/signature/build.info
new file mode 100644
index 000000000000..0fd39841f340
--- /dev/null
+++ b/crypto/openssl/providers/implementations/signature/build.info
@@ -0,0 +1,45 @@
+# We make separate GOAL variables for each algorithm, to make it easy to
+# switch each to the Legacy provider when needed.
+
+$DSA_GOAL=../../libdefault.a ../../libfips.a
+$EC_GOAL=../../libdefault.a ../../libfips.a
+$MAC_GOAL=../../libdefault.a ../../libfips.a
+$RSA_GOAL=../../libdefault.a ../../libfips.a
+$SM2_GOAL=../../libdefault.a
+$ML_DSA_GOAL=../../libdefault.a ../../libfips.a
+$SLH_DSA_GOAL=../../libdefault.a ../../libfips.a
+
+IF[{- !$disabled{dsa} -}]
+ SOURCE[$DSA_GOAL]=dsa_sig.c
+ENDIF
+
+IF[{- !$disabled{ec} -}]
+ SOURCE[$EC_GOAL]=ecdsa_sig.c
+ IF[{- !$disabled{ecx} -}]
+ SOURCE[$EC_GOAL]=eddsa_sig.c
+ ENDIF
+ENDIF
+
+IF[{- !$disabled{sm2} -}]
+ SOURCE[$SM2_GOAL]=sm2_sig.c
+ENDIF
+
+SOURCE[$RSA_GOAL]=rsa_sig.c
+
+DEPEND[ml_dsa_sig.o]=../../common/include/prov/der_ml_dsa.h
+DEPEND[slh_dsa_sig.o]=../../common/include/prov/der_slh_dsa.h
+DEPEND[rsa_sig.o]=../../common/include/prov/der_rsa.h
+DEPEND[dsa_sig.o]=../../common/include/prov/der_dsa.h
+DEPEND[ecdsa_sig.o]=../../common/include/prov/der_ec.h
+DEPEND[eddsa_sig.o]=../../common/include/prov/der_ecx.h
+DEPEND[sm2_sig.o]=../../common/include/prov/der_sm2.h
+
+SOURCE[$MAC_GOAL]=mac_legacy_sig.c
+
+IF[{- !$disabled{'ml-dsa'} -}]
+ SOURCE[$ML_DSA_GOAL]=ml_dsa_sig.c
+ENDIF
+
+IF[{- !$disabled{'slh-dsa'} -}]
+ SOURCE[$DSA_GOAL]=slh_dsa_sig.c
+ENDIF
diff --git a/crypto/openssl/providers/implementations/signature/dsa_sig.c b/crypto/openssl/providers/implementations/signature/dsa_sig.c
new file mode 100644
index 000000000000..887f6cbb9018
--- /dev/null
+++ b/crypto/openssl/providers/implementations/signature/dsa_sig.c
@@ -0,0 +1,1085 @@
+/*
+ * Copyright 2019-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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * DSA low level APIs are deprecated for public use, but still ok for
+ * internal use.
+ */
+#include "internal/deprecated.h"
+
+#include <string.h>
+
+#include <openssl/crypto.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/err.h>
+#include <openssl/dsa.h>
+#include <openssl/params.h>
+#include <openssl/evp.h>
+#include <openssl/proverr.h>
+#include "internal/nelem.h"
+#include "internal/sizes.h"
+#include "internal/cryptlib.h"
+#include "prov/providercommon.h"
+#include "prov/implementations.h"
+#include "prov/provider_ctx.h"
+#include "prov/securitycheck.h"
+#include "prov/der_dsa.h"
+#include "crypto/dsa.h"
+
+static OSSL_FUNC_signature_newctx_fn dsa_newctx;
+static OSSL_FUNC_signature_sign_init_fn dsa_sign_init;
+static OSSL_FUNC_signature_verify_init_fn dsa_verify_init;
+static OSSL_FUNC_signature_sign_fn dsa_sign;
+static OSSL_FUNC_signature_sign_message_update_fn dsa_signverify_message_update;
+static OSSL_FUNC_signature_sign_message_final_fn dsa_sign_message_final;
+static OSSL_FUNC_signature_verify_fn dsa_verify;
+static OSSL_FUNC_signature_verify_message_update_fn dsa_signverify_message_update;
+static OSSL_FUNC_signature_verify_message_final_fn dsa_verify_message_final;
+static OSSL_FUNC_signature_digest_sign_init_fn dsa_digest_sign_init;
+static OSSL_FUNC_signature_digest_sign_update_fn dsa_digest_signverify_update;
+static OSSL_FUNC_signature_digest_sign_final_fn dsa_digest_sign_final;
+static OSSL_FUNC_signature_digest_verify_init_fn dsa_digest_verify_init;
+static OSSL_FUNC_signature_digest_verify_update_fn dsa_digest_signverify_update;
+static OSSL_FUNC_signature_digest_verify_final_fn dsa_digest_verify_final;
+static OSSL_FUNC_signature_freectx_fn dsa_freectx;
+static OSSL_FUNC_signature_dupctx_fn dsa_dupctx;
+static OSSL_FUNC_signature_query_key_types_fn dsa_sigalg_query_key_types;
+static OSSL_FUNC_signature_get_ctx_params_fn dsa_get_ctx_params;
+static OSSL_FUNC_signature_gettable_ctx_params_fn dsa_gettable_ctx_params;
+static OSSL_FUNC_signature_set_ctx_params_fn dsa_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn dsa_settable_ctx_params;
+static OSSL_FUNC_signature_get_ctx_md_params_fn dsa_get_ctx_md_params;
+static OSSL_FUNC_signature_gettable_ctx_md_params_fn dsa_gettable_ctx_md_params;
+static OSSL_FUNC_signature_set_ctx_md_params_fn dsa_set_ctx_md_params;
+static OSSL_FUNC_signature_settable_ctx_md_params_fn dsa_settable_ctx_md_params;
+static OSSL_FUNC_signature_set_ctx_params_fn dsa_sigalg_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn dsa_sigalg_settable_ctx_params;
+
+/*
+ * What's passed as an actual key is defined by the KEYMGMT interface.
+ * We happen to know that our KEYMGMT simply passes DSA structures, so
+ * we use that here too.
+ */
+
+typedef struct {
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+ DSA *dsa;
+ /* |operation| reuses EVP's operation bitfield */
+ int operation;
+
+ /*
+ * Flag to determine if a full sigalg is run (1) or if a composable
+ * signature algorithm is run (0).
+ *
+ * When a full sigalg is run (1), this currently affects the following
+ * other flags, which are to remain untouched after their initialization:
+ *
+ * - flag_allow_md (initialized to 0)
+ */
+ unsigned int flag_sigalg : 1;
+ /*
+ * Flag to determine if the hash function can be changed (1) or not (0)
+ * Because it's dangerous to change during a DigestSign or DigestVerify
+ * operation, this flag is cleared by their Init function, and set again
+ * by their Final function.
+ */
+ unsigned int flag_allow_md : 1;
+
+ /* If this is set to 1 then the generated k is not random */
+ unsigned int nonce_type;
+
+ /* The Algorithm Identifier of the combined signature algorithm */
+ unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE];
+ size_t aid_len;
+
+ /* main digest */
+ char mdname[OSSL_MAX_NAME_SIZE];
+ EVP_MD *md;
+ EVP_MD_CTX *mdctx;
+
+ /* Signature, for verification */
+ unsigned char *sig;
+ size_t siglen;
+
+ OSSL_FIPS_IND_DECLARE
+} PROV_DSA_CTX;
+
+static size_t dsa_get_md_size(const PROV_DSA_CTX *pdsactx)
+{
+ int md_size;
+
+ if (pdsactx->md != NULL) {
+ md_size = EVP_MD_get_size(pdsactx->md);
+ if (md_size <= 0)
+ return 0;
+ return (size_t)md_size;
+ }
+ return 0;
+}
+
+static void *dsa_newctx(void *provctx, const char *propq)
+{
+ PROV_DSA_CTX *pdsactx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ pdsactx = OPENSSL_zalloc(sizeof(PROV_DSA_CTX));
+ if (pdsactx == NULL)
+ return NULL;
+
+ pdsactx->libctx = PROV_LIBCTX_OF(provctx);
+ pdsactx->flag_allow_md = 1;
+ OSSL_FIPS_IND_INIT(pdsactx)
+ if (propq != NULL && (pdsactx->propq = OPENSSL_strdup(propq)) == NULL) {
+ OPENSSL_free(pdsactx);
+ pdsactx = NULL;
+ }
+ return pdsactx;
+}
+
+static int dsa_setup_md(PROV_DSA_CTX *ctx,
+ const char *mdname, const char *mdprops,
+ const char *desc)
+{
+ EVP_MD *md = NULL;
+
+ if (mdprops == NULL)
+ mdprops = ctx->propq;
+
+ if (mdname != NULL) {
+ WPACKET pkt;
+ int md_nid;
+ size_t mdname_len = strlen(mdname);
+ unsigned char *aid = NULL;
+
+ md = EVP_MD_fetch(ctx->libctx, mdname, mdprops);
+ md_nid = ossl_digest_get_approved_nid(md);
+
+ if (md == NULL) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "%s could not be fetched", mdname);
+ goto err;
+ }
+ if (md_nid == NID_undef) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED,
+ "digest=%s", mdname);
+ goto err;
+ }
+ if (mdname_len >= sizeof(ctx->mdname)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "%s exceeds name buffer length", mdname);
+ goto err;
+ }
+ /* XOF digests don't work */
+ if (EVP_MD_xof(md)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
+ goto err;
+ }
+#ifdef FIPS_MODULE
+ {
+ int sha1_allowed
+ = ((ctx->operation
+ & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_SIGNMSG)) == 0);
+
+ if (!ossl_fips_ind_digest_sign_check(OSSL_FIPS_IND_GET(ctx),
+ OSSL_FIPS_IND_SETTABLE1,
+ ctx->libctx,
+ md_nid, sha1_allowed, 0, desc,
+ ossl_fips_config_signature_digest_check))
+ goto err;
+ }
+#endif
+
+ if (!ctx->flag_allow_md) {
+ if (ctx->mdname[0] != '\0'
+ && !EVP_MD_is_a(md, ctx->mdname)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED,
+ "digest %s != %s", mdname, ctx->mdname);
+ goto err;
+ }
+ EVP_MD_free(md);
+ return 1;
+ }
+
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+
+ /*
+ * We do not care about DER writing errors.
+ * All it really means is that for some reason, there's no
+ * AlgorithmIdentifier to be had, but the operation itself is
+ * still valid, just as long as it's not used to construct
+ * anything that needs an AlgorithmIdentifier.
+ */
+ ctx->aid_len = 0;
+ if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf))
+ && ossl_DER_w_algorithmIdentifier_DSA_with_MD(&pkt, -1, ctx->dsa,
+ md_nid)
+ && WPACKET_finish(&pkt)) {
+ WPACKET_get_total_written(&pkt, &ctx->aid_len);
+ aid = WPACKET_get_curr(&pkt);
+ }
+ WPACKET_cleanup(&pkt);
+ if (aid != NULL && ctx->aid_len != 0)
+ memmove(ctx->aid_buf, aid, ctx->aid_len);
+
+ ctx->mdctx = NULL;
+ ctx->md = md;
+ OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname));
+ }
+
+ return 1;
+ err:
+ EVP_MD_free(md);
+ return 0;
+}
+
+#ifdef FIPS_MODULE
+
+static int dsa_sign_check_approved(PROV_DSA_CTX *ctx, int signing,
+ const char *desc)
+{
+ /* DSA Signing is not approved in FIPS 140-3 */
+ if (signing
+ && !OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE2,
+ ctx->libctx, desc, "DSA",
+ ossl_fips_config_dsa_sign_disallowed))
+ return 0;
+ return 1;
+}
+
+static int dsa_check_key(PROV_DSA_CTX *ctx, int sign, const char *desc)
+{
+ int approved = ossl_dsa_check_key(ctx->dsa, sign);
+
+ if (!approved) {
+ if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0,
+ ctx->libctx, desc, "DSA Key",
+ ossl_fips_config_signature_digest_check)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ }
+ return 1;
+}
+#endif
+
+static int
+dsa_signverify_init(void *vpdsactx, void *vdsa,
+ OSSL_FUNC_signature_set_ctx_params_fn *set_ctx_params,
+ const OSSL_PARAM params[], int operation,
+ const char *desc)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (!ossl_prov_is_running()
+ || pdsactx == NULL)
+ return 0;
+
+ if (vdsa == NULL && pdsactx->dsa == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
+ return 0;
+ }
+
+ if (vdsa != NULL) {
+ if (!DSA_up_ref(vdsa))
+ return 0;
+ DSA_free(pdsactx->dsa);
+ pdsactx->dsa = vdsa;
+ }
+
+ pdsactx->operation = operation;
+
+ OSSL_FIPS_IND_SET_APPROVED(pdsactx)
+ if (!set_ctx_params(pdsactx, params))
+ return 0;
+#ifdef FIPS_MODULE
+ {
+ int operation_is_sign
+ = (operation & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_SIGNMSG)) != 0;
+
+ if (!dsa_sign_check_approved(pdsactx, operation_is_sign, desc))
+ return 0;
+ if (!dsa_check_key(pdsactx, operation_is_sign, desc))
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+static int dsa_sign_init(void *vpdsactx, void *vdsa, const OSSL_PARAM params[])
+{
+ return dsa_signverify_init(vpdsactx, vdsa, dsa_set_ctx_params, params,
+ EVP_PKEY_OP_SIGN, "DSA Sign Init");
+}
+
+/*
+ * Sign tbs without digesting it first. This is suitable for "primitive"
+ * signing and signing the digest of a message, i.e. should be used with
+ * implementations of the keytype related algorithms.
+ */
+static int dsa_sign_directly(void *vpdsactx,
+ unsigned char *sig, size_t *siglen, size_t sigsize,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ int ret;
+ unsigned int sltmp;
+ size_t dsasize = DSA_size(pdsactx->dsa);
+ size_t mdsize = dsa_get_md_size(pdsactx);
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+#ifdef FIPS_MODULE
+ if (!dsa_sign_check_approved(pdsactx, 1, "Sign"))
+ return 0;
+#endif
+
+ if (sig == NULL) {
+ *siglen = dsasize;
+ return 1;
+ }
+
+ if (sigsize < dsasize)
+ return 0;
+
+ if (mdsize != 0 && tbslen != mdsize)
+ return 0;
+
+ ret = ossl_dsa_sign_int(0, tbs, tbslen, sig, &sltmp, pdsactx->dsa,
+ pdsactx->nonce_type, pdsactx->mdname,
+ pdsactx->libctx, pdsactx->propq);
+ if (ret <= 0)
+ return 0;
+
+ *siglen = sltmp;
+ return 1;
+}
+
+static int dsa_signverify_message_update(void *vpdsactx,
+ const unsigned char *data,
+ size_t datalen)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx == NULL)
+ return 0;
+
+ return EVP_DigestUpdate(pdsactx->mdctx, data, datalen);
+}
+
+static int dsa_sign_message_final(void *vpdsactx, unsigned char *sig,
+ size_t *siglen, size_t sigsize)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (!ossl_prov_is_running() || pdsactx == NULL || pdsactx->mdctx == NULL)
+ return 0;
+ /*
+ * If sig is NULL then we're just finding out the sig size. Other fields
+ * are ignored. Defer to dsa_sign.
+ */
+ if (sig != NULL) {
+ /*
+ * When this function is used through dsa_digest_sign_final(),
+ * there is the possibility that some externally provided digests
+ * exceed EVP_MAX_MD_SIZE. We should probably handle that
+ * somehow but that problem is much larger than just in DSA.
+ */
+ if (!EVP_DigestFinal_ex(pdsactx->mdctx, digest, &dlen))
+ return 0;
+ }
+
+ return dsa_sign_directly(vpdsactx, sig, siglen, sigsize, digest, dlen);
+}
+
+/*
+ * If signing a message, digest tbs and sign the result.
+ * Otherwise, sign tbs directly.
+ */
+static int dsa_sign(void *vpdsactx, unsigned char *sig, size_t *siglen,
+ size_t sigsize, const unsigned char *tbs, size_t tbslen)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx->operation == EVP_PKEY_OP_SIGNMSG) {
+ /*
+ * If |sig| is NULL, the caller is only looking for the sig length.
+ * DO NOT update the input in this case.
+ */
+ if (sig == NULL)
+ return dsa_sign_message_final(pdsactx, sig, siglen, sigsize);
+
+ if (dsa_signverify_message_update(pdsactx, tbs, tbslen) <= 0)
+ return 0;
+ return dsa_sign_message_final(pdsactx, sig, siglen, sigsize);
+ }
+ return dsa_sign_directly(pdsactx, sig, siglen, sigsize, tbs, tbslen);
+}
+
+static int dsa_verify_init(void *vpdsactx, void *vdsa,
+ const OSSL_PARAM params[])
+{
+ return dsa_signverify_init(vpdsactx, vdsa, dsa_set_ctx_params, params,
+ EVP_PKEY_OP_VERIFY, "DSA Verify Init");
+}
+
+static int dsa_verify_directly(void *vpdsactx,
+ const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ size_t mdsize = dsa_get_md_size(pdsactx);
+
+ if (!ossl_prov_is_running() || (mdsize != 0 && tbslen != mdsize))
+ return 0;
+
+ return DSA_verify(0, tbs, tbslen, sig, siglen, pdsactx->dsa);
+}
+
+static int dsa_verify_set_sig(void *vpdsactx,
+ const unsigned char *sig, size_t siglen)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ OSSL_PARAM params[2];
+
+ params[0] =
+ OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_SIGNATURE,
+ (unsigned char *)sig, siglen);
+ params[1] = OSSL_PARAM_construct_end();
+ return dsa_sigalg_set_ctx_params(pdsactx, params);
+}
+
+static int dsa_verify_message_final(void *vpdsactx)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (pdsactx == NULL || pdsactx->mdctx == NULL)
+ return 0;
+
+ /*
+ * The digests used here are all known (see dsa_get_md_nid()), so they
+ * should not exceed the internal buffer size of EVP_MAX_MD_SIZE.
+ */
+ if (!EVP_DigestFinal_ex(pdsactx->mdctx, digest, &dlen))
+ return 0;
+
+ return dsa_verify_directly(vpdsactx, pdsactx->sig, pdsactx->siglen,
+ digest, dlen);
+}
+
+/*
+ * If verifying a message, digest tbs and verify the result.
+ * Otherwise, verify tbs directly.
+ */
+static int dsa_verify(void *vpdsactx,
+ const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx->operation == EVP_PKEY_OP_VERIFYMSG) {
+ if (dsa_verify_set_sig(pdsactx, sig, siglen) <= 0)
+ return 0;
+ if (dsa_signverify_message_update(pdsactx, tbs, tbslen) <= 0)
+ return 0;
+ return dsa_verify_message_final(pdsactx);
+ }
+ return dsa_verify_directly(pdsactx, sig, siglen, tbs, tbslen);
+}
+
+/* DigestSign/DigestVerify wrappers */
+
+static int dsa_digest_signverify_init(void *vpdsactx, const char *mdname,
+ void *vdsa, const OSSL_PARAM params[],
+ int operation, const char *desc)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (!dsa_signverify_init(vpdsactx, vdsa, dsa_set_ctx_params, params,
+ operation, desc))
+ return 0;
+
+ if (mdname != NULL
+ /* was dsa_setup_md already called in dsa_signverify_init()? */
+ && (mdname[0] == '\0' || OPENSSL_strcasecmp(pdsactx->mdname, mdname) != 0)
+ && !dsa_setup_md(pdsactx, mdname, NULL, desc))
+ return 0;
+
+ pdsactx->flag_allow_md = 0;
+
+ if (pdsactx->mdctx == NULL) {
+ pdsactx->mdctx = EVP_MD_CTX_new();
+ if (pdsactx->mdctx == NULL)
+ goto error;
+ }
+
+ if (!EVP_DigestInit_ex2(pdsactx->mdctx, pdsactx->md, params))
+ goto error;
+
+ return 1;
+
+ error:
+ EVP_MD_CTX_free(pdsactx->mdctx);
+ pdsactx->mdctx = NULL;
+ return 0;
+}
+
+static int dsa_digest_sign_init(void *vpdsactx, const char *mdname,
+ void *vdsa, const OSSL_PARAM params[])
+{
+ return dsa_digest_signverify_init(vpdsactx, mdname, vdsa, params,
+ EVP_PKEY_OP_SIGNMSG,
+ "DSA Digest Sign Init");
+}
+
+static int dsa_digest_signverify_update(void *vpdsactx, const unsigned char *data,
+ size_t datalen)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx == NULL)
+ return 0;
+ /* Sigalg implementations shouldn't do digest_sign */
+ if (pdsactx->flag_sigalg)
+ return 0;
+
+ return dsa_signverify_message_update(vpdsactx, data, datalen);
+}
+
+static int dsa_digest_sign_final(void *vpdsactx, unsigned char *sig,
+ size_t *siglen, size_t sigsize)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ int ok = 0;
+
+ if (pdsactx == NULL)
+ return 0;
+ /* Sigalg implementations shouldn't do digest_sign */
+ if (pdsactx->flag_sigalg)
+ return 0;
+
+ ok = dsa_sign_message_final(pdsactx, sig, siglen, sigsize);
+
+ pdsactx->flag_allow_md = 1;
+
+ return ok;
+}
+
+static int dsa_digest_verify_init(void *vpdsactx, const char *mdname,
+ void *vdsa, const OSSL_PARAM params[])
+{
+ return dsa_digest_signverify_init(vpdsactx, mdname, vdsa, params,
+ EVP_PKEY_OP_VERIFYMSG,
+ "DSA Digest Verify Init");
+}
+
+int dsa_digest_verify_final(void *vpdsactx, const unsigned char *sig,
+ size_t siglen)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ int ok = 0;
+
+ if (pdsactx == NULL)
+ return 0;
+ /* Sigalg implementations shouldn't do digest_verify */
+ if (pdsactx->flag_sigalg)
+ return 0;
+
+ if (dsa_verify_set_sig(pdsactx, sig, siglen))
+ ok = dsa_verify_message_final(vpdsactx);
+
+ pdsactx->flag_allow_md = 1;
+
+ return ok;
+}
+
+static void dsa_freectx(void *vpdsactx)
+{
+ PROV_DSA_CTX *ctx = (PROV_DSA_CTX *)vpdsactx;
+
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+ OPENSSL_free(ctx->sig);
+ OPENSSL_free(ctx->propq);
+ DSA_free(ctx->dsa);
+ OPENSSL_free(ctx);
+}
+
+static void *dsa_dupctx(void *vpdsactx)
+{
+ PROV_DSA_CTX *srcctx = (PROV_DSA_CTX *)vpdsactx;
+ PROV_DSA_CTX *dstctx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+ if (dstctx == NULL)
+ return NULL;
+
+ *dstctx = *srcctx;
+ dstctx->dsa = NULL;
+ dstctx->propq = NULL;
+
+ if (srcctx->dsa != NULL && !DSA_up_ref(srcctx->dsa))
+ goto err;
+ dstctx->dsa = srcctx->dsa;
+
+ if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md))
+ goto err;
+ dstctx->md = srcctx->md;
+
+ if (srcctx->mdctx != NULL) {
+ dstctx->mdctx = EVP_MD_CTX_new();
+ if (dstctx->mdctx == NULL
+ || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx))
+ goto err;
+ }
+
+ if (srcctx->propq != NULL) {
+ dstctx->propq = OPENSSL_strdup(srcctx->propq);
+ if (dstctx->propq == NULL)
+ goto err;
+ }
+
+ return dstctx;
+ err:
+ dsa_freectx(dstctx);
+ return NULL;
+}
+
+static int dsa_get_ctx_params(void *vpdsactx, OSSL_PARAM *params)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ OSSL_PARAM *p;
+
+ if (pdsactx == NULL)
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
+ if (p != NULL
+ && !OSSL_PARAM_set_octet_string(p,
+ pdsactx->aid_len == 0 ? NULL : pdsactx->aid_buf,
+ pdsactx->aid_len))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ if (p != NULL && !OSSL_PARAM_set_utf8_string(p, pdsactx->mdname))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE);
+ if (p != NULL && !OSSL_PARAM_set_uint(p, pdsactx->nonce_type))
+ return 0;
+ if (!OSSL_FIPS_IND_GET_CTX_PARAM(pdsactx, params))
+ return 0;
+
+ return 1;
+}
+
+static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_NONCE_TYPE, NULL),
+ OSSL_FIPS_IND_GETTABLE_CTX_PARAM()
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *dsa_gettable_ctx_params(ossl_unused void *ctx,
+ ossl_unused void *provctx)
+{
+ return known_gettable_ctx_params;
+}
+
+/**
+ * @brief Setup common params for dsa_set_ctx_params and dsa_sigalg_set_ctx_params
+ * The caller is responsible for checking |vpdsactx| is not NULL and |params|
+ * is not empty.
+ */
+static int dsa_common_set_ctx_params(void *vpdsactx, const OSSL_PARAM params[])
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ const OSSL_PARAM *p;
+
+ if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdsactx, OSSL_FIPS_IND_SETTABLE0, params,
+ OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK))
+ return 0;
+ if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdsactx, OSSL_FIPS_IND_SETTABLE1, params,
+ OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK))
+ return 0;
+ if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdsactx, OSSL_FIPS_IND_SETTABLE2, params,
+ OSSL_SIGNATURE_PARAM_FIPS_SIGN_CHECK))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE);
+ if (p != NULL
+ && !OSSL_PARAM_get_uint(p, &pdsactx->nonce_type))
+ return 0;
+ return 1;
+}
+
+#define DSA_COMMON_SETTABLE_CTX_PARAMS \
+ OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_NONCE_TYPE, NULL), \
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK) \
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK) \
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_SIGN_CHECK) \
+ OSSL_PARAM_END
+
+static int dsa_set_ctx_params(void *vpdsactx, const OSSL_PARAM params[])
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ const OSSL_PARAM *p;
+ int ret;
+
+ if (pdsactx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ if ((ret = dsa_common_set_ctx_params(pdsactx, params)) <= 0)
+ return ret;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ if (p != NULL) {
+ char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = mdname;
+ char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = mdprops;
+ const OSSL_PARAM *propsp =
+ OSSL_PARAM_locate_const(params,
+ OSSL_SIGNATURE_PARAM_PROPERTIES);
+
+ if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname)))
+ return 0;
+ if (propsp != NULL
+ && !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops)))
+ return 0;
+ if (!dsa_setup_md(pdsactx, mdname, mdprops, "DSA Set Ctx"))
+ return 0;
+ }
+ return 1;
+}
+
+static const OSSL_PARAM settable_ctx_params[] = {
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0),
+ DSA_COMMON_SETTABLE_CTX_PARAMS
+};
+
+static const OSSL_PARAM settable_ctx_params_no_digest[] = {
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *dsa_settable_ctx_params(void *vpdsactx,
+ ossl_unused void *provctx)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx != NULL && !pdsactx->flag_allow_md)
+ return settable_ctx_params_no_digest;
+ return settable_ctx_params;
+}
+
+static int dsa_get_ctx_md_params(void *vpdsactx, OSSL_PARAM *params)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx->mdctx == NULL)
+ return 0;
+
+ return EVP_MD_CTX_get_params(pdsactx->mdctx, params);
+}
+
+static const OSSL_PARAM *dsa_gettable_ctx_md_params(void *vpdsactx)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx->md == NULL)
+ return 0;
+
+ return EVP_MD_gettable_ctx_params(pdsactx->md);
+}
+
+static int dsa_set_ctx_md_params(void *vpdsactx, const OSSL_PARAM params[])
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx->mdctx == NULL)
+ return 0;
+
+ return EVP_MD_CTX_set_params(pdsactx->mdctx, params);
+}
+
+static const OSSL_PARAM *dsa_settable_ctx_md_params(void *vpdsactx)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx->md == NULL)
+ return 0;
+
+ return EVP_MD_settable_ctx_params(pdsactx->md);
+}
+
+const OSSL_DISPATCH ossl_dsa_signature_functions[] = {
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))dsa_newctx },
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))dsa_sign_init },
+ { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))dsa_sign },
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))dsa_verify_init },
+ { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))dsa_verify },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,
+ (void (*)(void))dsa_digest_sign_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE,
+ (void (*)(void))dsa_digest_signverify_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL,
+ (void (*)(void))dsa_digest_sign_final },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT,
+ (void (*)(void))dsa_digest_verify_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE,
+ (void (*)(void))dsa_digest_signverify_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL,
+ (void (*)(void))dsa_digest_verify_final },
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))dsa_freectx },
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))dsa_dupctx },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))dsa_get_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,
+ (void (*)(void))dsa_gettable_ctx_params },
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))dsa_set_ctx_params },
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
+ (void (*)(void))dsa_settable_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS,
+ (void (*)(void))dsa_get_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS,
+ (void (*)(void))dsa_gettable_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS,
+ (void (*)(void))dsa_set_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS,
+ (void (*)(void))dsa_settable_ctx_md_params },
+ OSSL_DISPATCH_END
+};
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * So called sigalgs (composite DSA+hash) implemented below. They
+ * are pretty much hard coded.
+ */
+
+static OSSL_FUNC_signature_query_key_types_fn dsa_sigalg_query_key_types;
+static OSSL_FUNC_signature_settable_ctx_params_fn dsa_sigalg_settable_ctx_params;
+static OSSL_FUNC_signature_set_ctx_params_fn dsa_sigalg_set_ctx_params;
+
+/*
+ * dsa_sigalg_signverify_init() is almost like dsa_digest_signverify_init(),
+ * just doesn't allow fetching an MD from whatever the user chooses.
+ */
+static int dsa_sigalg_signverify_init(void *vpdsactx, void *vdsa,
+ OSSL_FUNC_signature_set_ctx_params_fn *set_ctx_params,
+ const OSSL_PARAM params[],
+ const char *mdname,
+ int operation, const char *desc)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (!dsa_signverify_init(vpdsactx, vdsa, set_ctx_params, params, operation,
+ desc))
+ return 0;
+
+ if (!dsa_setup_md(pdsactx, mdname, NULL, desc))
+ return 0;
+
+ pdsactx->flag_sigalg = 1;
+ pdsactx->flag_allow_md = 0;
+
+ if (pdsactx->mdctx == NULL) {
+ pdsactx->mdctx = EVP_MD_CTX_new();
+ if (pdsactx->mdctx == NULL)
+ goto error;
+ }
+
+ if (!EVP_DigestInit_ex2(pdsactx->mdctx, pdsactx->md, params))
+ goto error;
+
+ return 1;
+
+ error:
+ EVP_MD_CTX_free(pdsactx->mdctx);
+ pdsactx->mdctx = NULL;
+ return 0;
+}
+
+static const char **dsa_sigalg_query_key_types(void)
+{
+ static const char *keytypes[] = { "DSA", NULL };
+
+ return keytypes;
+}
+
+static const OSSL_PARAM settable_sigalg_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_SIGNATURE, NULL, 0),
+ DSA_COMMON_SETTABLE_CTX_PARAMS
+};
+
+static const OSSL_PARAM *dsa_sigalg_settable_ctx_params(void *vpdsactx,
+ ossl_unused void *provctx)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx != NULL && pdsactx->operation == EVP_PKEY_OP_VERIFYMSG)
+ return settable_sigalg_ctx_params;
+ return NULL;
+}
+
+static int dsa_sigalg_set_ctx_params(void *vpdsactx, const OSSL_PARAM params[])
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ const OSSL_PARAM *p;
+ int ret;
+
+ if (pdsactx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ if ((ret = dsa_common_set_ctx_params(pdsactx, params)) <= 0)
+ return ret;
+
+ if (pdsactx->operation == EVP_PKEY_OP_VERIFYMSG) {
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_SIGNATURE);
+ if (p != NULL) {
+ OPENSSL_free(pdsactx->sig);
+ pdsactx->sig = NULL;
+ pdsactx->siglen = 0;
+ if (!OSSL_PARAM_get_octet_string(p, (void **)&pdsactx->sig,
+ 0, &pdsactx->siglen))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#define IMPL_DSA_SIGALG(md, MD) \
+ static OSSL_FUNC_signature_sign_init_fn dsa_##md##_sign_init; \
+ static OSSL_FUNC_signature_sign_message_init_fn \
+ dsa_##md##_sign_message_init; \
+ static OSSL_FUNC_signature_verify_init_fn dsa_##md##_verify_init; \
+ static OSSL_FUNC_signature_verify_message_init_fn \
+ dsa_##md##_verify_message_init; \
+ \
+ static int \
+ dsa_##md##_sign_init(void *vpdsactx, void *vdsa, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "DSA-" #MD " Sign Init"; \
+ \
+ return dsa_sigalg_signverify_init(vpdsactx, vdsa, \
+ dsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_SIGN, \
+ desc); \
+ } \
+ \
+ static int \
+ dsa_##md##_sign_message_init(void *vpdsactx, void *vdsa, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "DSA-" #MD " Sign Message Init"; \
+ \
+ return dsa_sigalg_signverify_init(vpdsactx, vdsa, \
+ dsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_SIGNMSG, \
+ desc); \
+ } \
+ \
+ static int \
+ dsa_##md##_verify_init(void *vpdsactx, void *vdsa, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "DSA-" #MD " Verify Init"; \
+ \
+ return dsa_sigalg_signverify_init(vpdsactx, vdsa, \
+ dsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_VERIFY, \
+ desc); \
+ } \
+ \
+ static int \
+ dsa_##md##_verify_message_init(void *vpdsactx, void *vdsa, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "DSA-" #MD " Verify Message Init"; \
+ \
+ return dsa_sigalg_signverify_init(vpdsactx, vdsa, \
+ dsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_VERIFYMSG, \
+ desc); \
+ } \
+ \
+ const OSSL_DISPATCH ossl_dsa_##md##_signature_functions[] = { \
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))dsa_newctx }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, \
+ (void (*)(void))dsa_##md##_sign_init }, \
+ { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))dsa_sign }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT, \
+ (void (*)(void))dsa_##md##_sign_message_init }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_UPDATE, \
+ (void (*)(void))dsa_signverify_message_update }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_FINAL, \
+ (void (*)(void))dsa_sign_message_final }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, \
+ (void (*)(void))dsa_##md##_verify_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY, \
+ (void (*)(void))dsa_verify }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT, \
+ (void (*)(void))dsa_##md##_verify_message_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_UPDATE, \
+ (void (*)(void))dsa_signverify_message_update }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_FINAL, \
+ (void (*)(void))dsa_verify_message_final }, \
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))dsa_freectx }, \
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))dsa_dupctx }, \
+ { OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPES, \
+ (void (*)(void))dsa_sigalg_query_key_types }, \
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \
+ (void (*)(void))dsa_get_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))dsa_gettable_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \
+ (void (*)(void))dsa_sigalg_set_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))dsa_sigalg_settable_ctx_params }, \
+ OSSL_DISPATCH_END \
+ }
+
+IMPL_DSA_SIGALG(sha1, SHA1);
+IMPL_DSA_SIGALG(sha224, SHA2-224);
+IMPL_DSA_SIGALG(sha256, SHA2-256);
+IMPL_DSA_SIGALG(sha384, SHA2-384);
+IMPL_DSA_SIGALG(sha512, SHA2-512);
+IMPL_DSA_SIGALG(sha3_224, SHA3-224);
+IMPL_DSA_SIGALG(sha3_256, SHA3-256);
+IMPL_DSA_SIGALG(sha3_384, SHA3-384);
+IMPL_DSA_SIGALG(sha3_512, SHA3-512);
diff --git a/crypto/openssl/providers/implementations/signature/ecdsa_sig.c b/crypto/openssl/providers/implementations/signature/ecdsa_sig.c
new file mode 100644
index 000000000000..73bfbf4aa9c1
--- /dev/null
+++ b/crypto/openssl/providers/implementations/signature/ecdsa_sig.c
@@ -0,0 +1,1108 @@
+/*
+ * 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * ECDSA low level APIs are deprecated for public use, but still ok for
+ * internal use.
+ */
+#include "internal/deprecated.h"
+
+#include <string.h> /* memcpy */
+#include <openssl/crypto.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/dsa.h>
+#include <openssl/params.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/proverr.h>
+#include "internal/nelem.h"
+#include "internal/sizes.h"
+#include "internal/cryptlib.h"
+#include "internal/deterministic_nonce.h"
+#include "prov/providercommon.h"
+#include "prov/implementations.h"
+#include "prov/provider_ctx.h"
+#include "prov/securitycheck.h"
+#include "prov/der_ec.h"
+#include "crypto/ec.h"
+
+static OSSL_FUNC_signature_newctx_fn ecdsa_newctx;
+static OSSL_FUNC_signature_sign_init_fn ecdsa_sign_init;
+static OSSL_FUNC_signature_verify_init_fn ecdsa_verify_init;
+static OSSL_FUNC_signature_sign_fn ecdsa_sign;
+static OSSL_FUNC_signature_sign_message_update_fn ecdsa_signverify_message_update;
+static OSSL_FUNC_signature_sign_message_final_fn ecdsa_sign_message_final;
+static OSSL_FUNC_signature_verify_fn ecdsa_verify;
+static OSSL_FUNC_signature_verify_message_update_fn ecdsa_signverify_message_update;
+static OSSL_FUNC_signature_verify_message_final_fn ecdsa_verify_message_final;
+static OSSL_FUNC_signature_digest_sign_init_fn ecdsa_digest_sign_init;
+static OSSL_FUNC_signature_digest_sign_update_fn ecdsa_digest_signverify_update;
+static OSSL_FUNC_signature_digest_sign_final_fn ecdsa_digest_sign_final;
+static OSSL_FUNC_signature_digest_verify_init_fn ecdsa_digest_verify_init;
+static OSSL_FUNC_signature_digest_verify_update_fn ecdsa_digest_signverify_update;
+static OSSL_FUNC_signature_digest_verify_final_fn ecdsa_digest_verify_final;
+static OSSL_FUNC_signature_freectx_fn ecdsa_freectx;
+static OSSL_FUNC_signature_dupctx_fn ecdsa_dupctx;
+static OSSL_FUNC_signature_query_key_types_fn ecdsa_sigalg_query_key_types;
+static OSSL_FUNC_signature_get_ctx_params_fn ecdsa_get_ctx_params;
+static OSSL_FUNC_signature_gettable_ctx_params_fn ecdsa_gettable_ctx_params;
+static OSSL_FUNC_signature_set_ctx_params_fn ecdsa_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn ecdsa_settable_ctx_params;
+static OSSL_FUNC_signature_get_ctx_md_params_fn ecdsa_get_ctx_md_params;
+static OSSL_FUNC_signature_gettable_ctx_md_params_fn ecdsa_gettable_ctx_md_params;
+static OSSL_FUNC_signature_set_ctx_md_params_fn ecdsa_set_ctx_md_params;
+static OSSL_FUNC_signature_settable_ctx_md_params_fn ecdsa_settable_ctx_md_params;
+static OSSL_FUNC_signature_set_ctx_params_fn ecdsa_sigalg_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn ecdsa_sigalg_settable_ctx_params;
+
+/*
+ * What's passed as an actual key is defined by the KEYMGMT interface.
+ * We happen to know that our KEYMGMT simply passes DSA structures, so
+ * we use that here too.
+ */
+
+typedef struct {
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+ EC_KEY *ec;
+ /* |operation| reuses EVP's operation bitfield */
+ int operation;
+
+ /*
+ * Flag to determine if a full sigalg is run (1) or if a composable
+ * signature algorithm is run (0).
+ *
+ * When a full sigalg is run (1), this currently affects the following
+ * other flags, which are to remain untouched after their initialization:
+ *
+ * - flag_allow_md (initialized to 0)
+ */
+ unsigned int flag_sigalg : 1;
+ /*
+ * Flag to determine if the hash function can be changed (1) or not (0)
+ * Because it's dangerous to change during a DigestSign or DigestVerify
+ * operation, this flag is cleared by their Init function, and set again
+ * by their Final function.
+ */
+ unsigned int flag_allow_md : 1;
+
+ /* The Algorithm Identifier of the combined signature algorithm */
+ unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE];
+ size_t aid_len;
+
+ /* main digest */
+ char mdname[OSSL_MAX_NAME_SIZE];
+ EVP_MD *md;
+ EVP_MD_CTX *mdctx;
+ size_t mdsize;
+
+ /* Signature, for verification */
+ unsigned char *sig;
+ size_t siglen;
+
+ /*
+ * Internally used to cache the results of calling the EC group
+ * sign_setup() methods which are then passed to the sign operation.
+ * This is used by CAVS failure tests to terminate a loop if the signature
+ * is not valid.
+ * This could of also been done with a simple flag.
+ */
+ BIGNUM *kinv;
+ BIGNUM *r;
+#if !defined(OPENSSL_NO_ACVP_TESTS)
+ /*
+ * This indicates that KAT (CAVS) test is running. Externally an app will
+ * override the random callback such that the generated private key and k
+ * are known.
+ * Normal operation will loop to choose a new k if the signature is not
+ * valid - but for this mode of operation it forces a failure instead.
+ */
+ unsigned int kattest;
+#endif
+#ifdef FIPS_MODULE
+ /*
+ * FIPS 140-3 IG 2.4.B mandates that verification based on a digest of a
+ * message is not permitted. However, signing based on a digest is still
+ * permitted.
+ */
+ int verify_message;
+#endif
+ /* If this is set then the generated k is not random */
+ unsigned int nonce_type;
+ OSSL_FIPS_IND_DECLARE
+} PROV_ECDSA_CTX;
+
+static void *ecdsa_newctx(void *provctx, const char *propq)
+{
+ PROV_ECDSA_CTX *ctx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ ctx = OPENSSL_zalloc(sizeof(PROV_ECDSA_CTX));
+ if (ctx == NULL)
+ return NULL;
+
+ OSSL_FIPS_IND_INIT(ctx)
+ ctx->flag_allow_md = 1;
+#ifdef FIPS_MODULE
+ ctx->verify_message = 1;
+#endif
+ ctx->libctx = PROV_LIBCTX_OF(provctx);
+ if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL) {
+ OPENSSL_free(ctx);
+ ctx = NULL;
+ }
+ return ctx;
+}
+
+static int ecdsa_setup_md(PROV_ECDSA_CTX *ctx,
+ const char *mdname, const char *mdprops,
+ const char *desc)
+{
+ EVP_MD *md = NULL;
+ size_t mdname_len;
+ int md_nid, md_size;
+ WPACKET pkt;
+ unsigned char *aid = NULL;
+
+ if (mdname == NULL)
+ return 1;
+
+ mdname_len = strlen(mdname);
+ if (mdname_len >= sizeof(ctx->mdname)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "%s exceeds name buffer length", mdname);
+ return 0;
+ }
+ if (mdprops == NULL)
+ mdprops = ctx->propq;
+ md = EVP_MD_fetch(ctx->libctx, mdname, mdprops);
+ if (md == NULL) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "%s could not be fetched", mdname);
+ return 0;
+ }
+ md_size = EVP_MD_get_size(md);
+ if (md_size <= 0) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "%s has invalid md size %d", mdname, md_size);
+ goto err;
+ }
+ md_nid = ossl_digest_get_approved_nid(md);
+#ifdef FIPS_MODULE
+ if (md_nid == NID_undef) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED,
+ "digest=%s", mdname);
+ goto err;
+ }
+#endif
+ /* XOF digests don't work */
+ if (EVP_MD_xof(md)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
+ goto err;
+ }
+
+#ifdef FIPS_MODULE
+ {
+ int sha1_allowed
+ = ((ctx->operation
+ & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_SIGNMSG)) == 0);
+
+ if (!ossl_fips_ind_digest_sign_check(OSSL_FIPS_IND_GET(ctx),
+ OSSL_FIPS_IND_SETTABLE1,
+ ctx->libctx,
+ md_nid, sha1_allowed, 0, desc,
+ ossl_fips_config_signature_digest_check))
+ goto err;
+ }
+#endif
+
+ if (!ctx->flag_allow_md) {
+ if (ctx->mdname[0] != '\0' && !EVP_MD_is_a(md, ctx->mdname)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED,
+ "digest %s != %s", mdname, ctx->mdname);
+ goto err;
+ }
+ EVP_MD_free(md);
+ return 1;
+ }
+
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+
+ ctx->aid_len = 0;
+#ifndef FIPS_MODULE
+ if (md_nid != NID_undef) {
+#else
+ {
+#endif
+ if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf))
+ && ossl_DER_w_algorithmIdentifier_ECDSA_with_MD(&pkt, -1, ctx->ec,
+ md_nid)
+ && WPACKET_finish(&pkt)) {
+ WPACKET_get_total_written(&pkt, &ctx->aid_len);
+ aid = WPACKET_get_curr(&pkt);
+ }
+ WPACKET_cleanup(&pkt);
+ if (aid != NULL && ctx->aid_len != 0)
+ memmove(ctx->aid_buf, aid, ctx->aid_len);
+ }
+
+ ctx->mdctx = NULL;
+ ctx->md = md;
+ ctx->mdsize = (size_t)md_size;
+ OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname));
+
+ return 1;
+ err:
+ EVP_MD_free(md);
+ return 0;
+}
+
+static int
+ecdsa_signverify_init(PROV_ECDSA_CTX *ctx, void *ec,
+ OSSL_FUNC_signature_set_ctx_params_fn *set_ctx_params,
+ const OSSL_PARAM params[], int operation,
+ const char *desc)
+{
+ if (!ossl_prov_is_running()
+ || ctx == NULL)
+ return 0;
+
+ if (ec == NULL && ctx->ec == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
+ return 0;
+ }
+
+ if (ec != NULL) {
+ if (!EC_KEY_up_ref(ec))
+ return 0;
+ EC_KEY_free(ctx->ec);
+ ctx->ec = ec;
+ }
+
+ ctx->operation = operation;
+
+ OSSL_FIPS_IND_SET_APPROVED(ctx)
+ if (!set_ctx_params(ctx, params))
+ return 0;
+#ifdef FIPS_MODULE
+ if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(ctx),
+ OSSL_FIPS_IND_SETTABLE0, ctx->libctx,
+ EC_KEY_get0_group(ctx->ec), desc,
+ (operation & (EVP_PKEY_OP_SIGN
+ | EVP_PKEY_OP_SIGNMSG)) != 0))
+ return 0;
+#endif
+ return 1;
+}
+
+static int ecdsa_sign_init(void *vctx, void *ec, const OSSL_PARAM params[])
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+#ifdef FIPS_MODULE
+ ctx->verify_message = 1;
+#endif
+ return ecdsa_signverify_init(ctx, ec, ecdsa_set_ctx_params, params,
+ EVP_PKEY_OP_SIGN, "ECDSA Sign Init");
+}
+
+/*
+ * Sign tbs without digesting it first. This is suitable for "primitive"
+ * signing and signing the digest of a message.
+ */
+static int ecdsa_sign_directly(void *vctx,
+ unsigned char *sig, size_t *siglen, size_t sigsize,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+ int ret;
+ unsigned int sltmp;
+ size_t ecsize = ECDSA_size(ctx->ec);
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (sig == NULL) {
+ *siglen = ecsize;
+ return 1;
+ }
+
+#if !defined(OPENSSL_NO_ACVP_TESTS)
+ if (ctx->kattest && !ECDSA_sign_setup(ctx->ec, NULL, &ctx->kinv, &ctx->r))
+ return 0;
+#endif
+
+ if (sigsize < (size_t)ecsize)
+ return 0;
+
+ if (ctx->mdsize != 0 && tbslen != ctx->mdsize)
+ return 0;
+
+ if (ctx->nonce_type != 0) {
+ const char *mdname = NULL;
+
+ if (ctx->mdname[0] != '\0')
+ mdname = ctx->mdname;
+ ret = ossl_ecdsa_deterministic_sign(tbs, tbslen, sig, &sltmp,
+ ctx->ec, ctx->nonce_type,
+ mdname,
+ ctx->libctx, ctx->propq);
+ } else {
+ ret = ECDSA_sign_ex(0, tbs, tbslen, sig, &sltmp, ctx->kinv, ctx->r,
+ ctx->ec);
+ }
+ if (ret <= 0)
+ return 0;
+
+ *siglen = sltmp;
+ return 1;
+}
+
+static int ecdsa_signverify_message_update(void *vctx,
+ const unsigned char *data,
+ size_t datalen)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (ctx == NULL)
+ return 0;
+
+ return EVP_DigestUpdate(ctx->mdctx, data, datalen);
+}
+
+static int ecdsa_sign_message_final(void *vctx, unsigned char *sig,
+ size_t *siglen, size_t sigsize)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (!ossl_prov_is_running() || ctx == NULL)
+ return 0;
+ if (ctx->mdctx == NULL)
+ return 0;
+ /*
+ * If sig is NULL then we're just finding out the sig size. Other fields
+ * are ignored. Defer to ecdsa_sign.
+ */
+ if (sig != NULL
+ && !EVP_DigestFinal_ex(ctx->mdctx, digest, &dlen))
+ return 0;
+ return ecdsa_sign_directly(vctx, sig, siglen, sigsize, digest, dlen);
+}
+
+/*
+ * If signing a message, digest tbs and sign the result.
+ * Otherwise, sign tbs directly.
+ */
+static int ecdsa_sign(void *vctx, unsigned char *sig, size_t *siglen,
+ size_t sigsize, const unsigned char *tbs, size_t tbslen)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (ctx->operation == EVP_PKEY_OP_SIGNMSG) {
+ /*
+ * If |sig| is NULL, the caller is only looking for the sig length.
+ * DO NOT update the input in this case.
+ */
+ if (sig == NULL)
+ return ecdsa_sign_message_final(ctx, sig, siglen, sigsize);
+
+ if (ecdsa_signverify_message_update(ctx, tbs, tbslen) <= 0)
+ return 0;
+ return ecdsa_sign_message_final(ctx, sig, siglen, sigsize);
+ }
+ return ecdsa_sign_directly(ctx, sig, siglen, sigsize, tbs, tbslen);
+}
+
+static int ecdsa_verify_init(void *vctx, void *ec, const OSSL_PARAM params[])
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+#ifdef FIPS_MODULE
+ ctx->verify_message = 0;
+#endif
+ return ecdsa_signverify_init(ctx, ec, ecdsa_set_ctx_params, params,
+ EVP_PKEY_OP_VERIFY, "ECDSA Verify Init");
+}
+
+static int ecdsa_verify_directly(void *vctx,
+ const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (!ossl_prov_is_running() || (ctx->mdsize != 0 && tbslen != ctx->mdsize))
+ return 0;
+
+ return ECDSA_verify(0, tbs, tbslen, sig, siglen, ctx->ec);
+}
+
+static int ecdsa_verify_set_sig(void *vctx,
+ const unsigned char *sig, size_t siglen)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+ OSSL_PARAM params[2];
+
+ params[0] =
+ OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_SIGNATURE,
+ (unsigned char *)sig, siglen);
+ params[1] = OSSL_PARAM_construct_end();
+ return ecdsa_sigalg_set_ctx_params(ctx, params);
+}
+
+static int ecdsa_verify_message_final(void *vctx)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (!ossl_prov_is_running() || ctx == NULL || ctx->mdctx == NULL)
+ return 0;
+
+ /*
+ * The digests used here are all known (see ecdsa_get_md_nid()), so they
+ * should not exceed the internal buffer size of EVP_MAX_MD_SIZE.
+ */
+ if (!EVP_DigestFinal_ex(ctx->mdctx, digest, &dlen))
+ return 0;
+
+ return ecdsa_verify_directly(vctx, ctx->sig, ctx->siglen,
+ digest, dlen);
+}
+
+/*
+ * If verifying a message, digest tbs and verify the result.
+ * Otherwise, verify tbs directly.
+ */
+static int ecdsa_verify(void *vctx,
+ const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (ctx->operation == EVP_PKEY_OP_VERIFYMSG) {
+ if (ecdsa_verify_set_sig(ctx, sig, siglen) <= 0)
+ return 0;
+ if (ecdsa_signverify_message_update(ctx, tbs, tbslen) <= 0)
+ return 0;
+ return ecdsa_verify_message_final(ctx);
+ }
+ return ecdsa_verify_directly(ctx, sig, siglen, tbs, tbslen);
+}
+
+/* DigestSign/DigestVerify wrappers */
+
+static int ecdsa_digest_signverify_init(void *vctx, const char *mdname,
+ void *ec, const OSSL_PARAM params[],
+ int operation, const char *desc)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+#ifdef FIPS_MODULE
+ ctx->verify_message = 1;
+#endif
+ if (!ecdsa_signverify_init(vctx, ec, ecdsa_set_ctx_params, params,
+ operation, desc))
+ return 0;
+
+ if (mdname != NULL
+ /* was ecdsa_setup_md already called in ecdsa_signverify_init()? */
+ && (mdname[0] == '\0' || OPENSSL_strcasecmp(ctx->mdname, mdname) != 0)
+ && !ecdsa_setup_md(ctx, mdname, NULL, desc))
+ return 0;
+
+ ctx->flag_allow_md = 0;
+
+ if (ctx->mdctx == NULL) {
+ ctx->mdctx = EVP_MD_CTX_new();
+ if (ctx->mdctx == NULL)
+ goto error;
+ }
+
+ if (!EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params))
+ goto error;
+ return 1;
+error:
+ EVP_MD_CTX_free(ctx->mdctx);
+ ctx->mdctx = NULL;
+ return 0;
+}
+
+static int ecdsa_digest_sign_init(void *vctx, const char *mdname, void *ec,
+ const OSSL_PARAM params[])
+{
+ return ecdsa_digest_signverify_init(vctx, mdname, ec, params,
+ EVP_PKEY_OP_SIGNMSG,
+ "ECDSA Digest Sign Init");
+}
+
+static int ecdsa_digest_signverify_update(void *vctx, const unsigned char *data,
+ size_t datalen)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (ctx == NULL || ctx->mdctx == NULL)
+ return 0;
+ /* Sigalg implementations shouldn't do digest_sign */
+ if (ctx->flag_sigalg)
+ return 0;
+
+ return ecdsa_signverify_message_update(vctx, data, datalen);
+}
+
+int ecdsa_digest_sign_final(void *vctx, unsigned char *sig, size_t *siglen,
+ size_t sigsize)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+ int ok = 0;
+
+ if (ctx == NULL)
+ return 0;
+ /* Sigalg implementations shouldn't do digest_sign */
+ if (ctx->flag_sigalg)
+ return 0;
+
+ ok = ecdsa_sign_message_final(ctx, sig, siglen, sigsize);
+
+ ctx->flag_allow_md = 1;
+
+ return ok;
+}
+
+static int ecdsa_digest_verify_init(void *vctx, const char *mdname, void *ec,
+ const OSSL_PARAM params[])
+{
+ return ecdsa_digest_signverify_init(vctx, mdname, ec, params,
+ EVP_PKEY_OP_VERIFYMSG,
+ "ECDSA Digest Verify Init");
+}
+
+int ecdsa_digest_verify_final(void *vctx, const unsigned char *sig,
+ size_t siglen)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+ int ok = 0;
+
+ if (!ossl_prov_is_running() || ctx == NULL || ctx->mdctx == NULL)
+ return 0;
+
+ /* Sigalg implementations shouldn't do digest_verify */
+ if (ctx->flag_sigalg)
+ return 0;
+
+ if (ecdsa_verify_set_sig(ctx, sig, siglen))
+ ok = ecdsa_verify_message_final(ctx);
+
+ ctx->flag_allow_md = 1;
+
+ return ok;
+}
+
+static void ecdsa_freectx(void *vctx)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+ OPENSSL_free(ctx->propq);
+ OPENSSL_free(ctx->sig);
+ EC_KEY_free(ctx->ec);
+ BN_clear_free(ctx->kinv);
+ BN_clear_free(ctx->r);
+ OPENSSL_free(ctx);
+}
+
+static void *ecdsa_dupctx(void *vctx)
+{
+ PROV_ECDSA_CTX *srcctx = (PROV_ECDSA_CTX *)vctx;
+ PROV_ECDSA_CTX *dstctx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+ if (dstctx == NULL)
+ return NULL;
+
+ *dstctx = *srcctx;
+ dstctx->ec = NULL;
+ dstctx->propq = NULL;
+
+ if (srcctx->ec != NULL && !EC_KEY_up_ref(srcctx->ec))
+ goto err;
+ /* Test KATS should not need to be supported */
+ if (srcctx->kinv != NULL || srcctx->r != NULL)
+ goto err;
+ dstctx->ec = srcctx->ec;
+
+ if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md))
+ goto err;
+ dstctx->md = srcctx->md;
+
+ if (srcctx->mdctx != NULL) {
+ dstctx->mdctx = EVP_MD_CTX_new();
+ if (dstctx->mdctx == NULL
+ || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx))
+ goto err;
+ }
+
+ if (srcctx->propq != NULL) {
+ dstctx->propq = OPENSSL_strdup(srcctx->propq);
+ if (dstctx->propq == NULL)
+ goto err;
+ }
+
+ return dstctx;
+ err:
+ ecdsa_freectx(dstctx);
+ return NULL;
+}
+
+static int ecdsa_get_ctx_params(void *vctx, OSSL_PARAM *params)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+ OSSL_PARAM *p;
+
+ if (ctx == NULL)
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
+ if (p != NULL && !OSSL_PARAM_set_octet_string(p,
+ ctx->aid_len == 0 ? NULL : ctx->aid_buf,
+ ctx->aid_len))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->mdsize))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ if (p != NULL && !OSSL_PARAM_set_utf8_string(p, ctx->md == NULL
+ ? ctx->mdname
+ : EVP_MD_get0_name(ctx->md)))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE);
+ if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->nonce_type))
+ return 0;
+
+#ifdef FIPS_MODULE
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_FIPS_VERIFY_MESSAGE);
+ if (p != NULL && !OSSL_PARAM_set_uint(p, ctx->verify_message))
+ return 0;
+#endif
+
+ if (!OSSL_FIPS_IND_GET_CTX_PARAM(ctx, params))
+ return 0;
+ return 1;
+}
+
+static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
+ OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_NONCE_TYPE, NULL),
+#ifdef FIPS_MODULE
+ OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_FIPS_VERIFY_MESSAGE, NULL),
+#endif
+ OSSL_FIPS_IND_GETTABLE_CTX_PARAM()
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *ecdsa_gettable_ctx_params(ossl_unused void *vctx,
+ ossl_unused void *provctx)
+{
+ return known_gettable_ctx_params;
+}
+
+/**
+ * @brief Set up common params for ecdsa_set_ctx_params and
+ * ecdsa_sigalg_set_ctx_params. The caller is responsible for checking |vctx| is
+ * not NULL and |params| is not empty.
+ */
+static int ecdsa_common_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+ const OSSL_PARAM *p;
+
+ if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params,
+ OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK))
+ return 0;
+ if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE1, params,
+ OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK))
+ return 0;
+
+#if !defined(OPENSSL_NO_ACVP_TESTS)
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_KAT);
+ if (p != NULL && !OSSL_PARAM_get_uint(p, &ctx->kattest))
+ return 0;
+#endif
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE);
+ if (p != NULL
+ && !OSSL_PARAM_get_uint(p, &ctx->nonce_type))
+ return 0;
+ return 1;
+}
+
+#define ECDSA_COMMON_SETTABLE_CTX_PARAMS \
+ OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_KAT, NULL), \
+ OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_NONCE_TYPE, NULL), \
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK) \
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK) \
+ OSSL_PARAM_END
+
+static int ecdsa_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+ const OSSL_PARAM *p;
+ size_t mdsize = 0;
+ int ret;
+
+ if (ctx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ if ((ret = ecdsa_common_set_ctx_params(ctx, params)) <= 0)
+ return ret;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ if (p != NULL) {
+ char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = mdname;
+ char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = mdprops;
+ const OSSL_PARAM *propsp =
+ OSSL_PARAM_locate_const(params,
+ OSSL_SIGNATURE_PARAM_PROPERTIES);
+
+ if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname)))
+ return 0;
+ if (propsp != NULL
+ && !OSSL_PARAM_get_utf8_string(propsp, &pmdprops, sizeof(mdprops)))
+ return 0;
+ if (!ecdsa_setup_md(ctx, mdname, mdprops, "ECDSA Set Ctx"))
+ return 0;
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE);
+ if (p != NULL) {
+ if (!OSSL_PARAM_get_size_t(p, &mdsize)
+ || (!ctx->flag_allow_md && mdsize != ctx->mdsize))
+ return 0;
+ ctx->mdsize = mdsize;
+ }
+ return 1;
+}
+
+static const OSSL_PARAM settable_ctx_params[] = {
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0),
+ ECDSA_COMMON_SETTABLE_CTX_PARAMS
+};
+
+static const OSSL_PARAM *ecdsa_settable_ctx_params(void *vctx,
+ ossl_unused void *provctx)
+{
+ return settable_ctx_params;
+}
+
+static int ecdsa_get_ctx_md_params(void *vctx, OSSL_PARAM *params)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (ctx->mdctx == NULL)
+ return 0;
+
+ return EVP_MD_CTX_get_params(ctx->mdctx, params);
+}
+
+static const OSSL_PARAM *ecdsa_gettable_ctx_md_params(void *vctx)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (ctx->md == NULL)
+ return 0;
+
+ return EVP_MD_gettable_ctx_params(ctx->md);
+}
+
+static int ecdsa_set_ctx_md_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (ctx->mdctx == NULL)
+ return 0;
+
+ return EVP_MD_CTX_set_params(ctx->mdctx, params);
+}
+
+static const OSSL_PARAM *ecdsa_settable_ctx_md_params(void *vctx)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (ctx->md == NULL)
+ return 0;
+
+ return EVP_MD_settable_ctx_params(ctx->md);
+}
+
+const OSSL_DISPATCH ossl_ecdsa_signature_functions[] = {
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))ecdsa_newctx },
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))ecdsa_sign_init },
+ { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))ecdsa_sign },
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))ecdsa_verify_init },
+ { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))ecdsa_verify },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,
+ (void (*)(void))ecdsa_digest_sign_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE,
+ (void (*)(void))ecdsa_digest_signverify_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL,
+ (void (*)(void))ecdsa_digest_sign_final },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT,
+ (void (*)(void))ecdsa_digest_verify_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE,
+ (void (*)(void))ecdsa_digest_signverify_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL,
+ (void (*)(void))ecdsa_digest_verify_final },
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))ecdsa_freectx },
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))ecdsa_dupctx },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))ecdsa_get_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,
+ (void (*)(void))ecdsa_gettable_ctx_params },
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))ecdsa_set_ctx_params },
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
+ (void (*)(void))ecdsa_settable_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS,
+ (void (*)(void))ecdsa_get_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS,
+ (void (*)(void))ecdsa_gettable_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS,
+ (void (*)(void))ecdsa_set_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS,
+ (void (*)(void))ecdsa_settable_ctx_md_params },
+ OSSL_DISPATCH_END
+};
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * So called sigalgs (composite ECDSA+hash) implemented below. They
+ * are pretty much hard coded.
+ */
+
+static OSSL_FUNC_signature_query_key_types_fn ecdsa_sigalg_query_key_types;
+static OSSL_FUNC_signature_settable_ctx_params_fn ecdsa_sigalg_settable_ctx_params;
+static OSSL_FUNC_signature_set_ctx_params_fn ecdsa_sigalg_set_ctx_params;
+
+/*
+ * ecdsa_sigalg_signverify_init() is almost like ecdsa_digest_signverify_init(),
+ * just doesn't allow fetching an MD from whatever the user chooses.
+ */
+static int ecdsa_sigalg_signverify_init(void *vctx, void *vec,
+ OSSL_FUNC_signature_set_ctx_params_fn *set_ctx_params,
+ const OSSL_PARAM params[],
+ const char *mdname,
+ int operation, const char *desc)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (!ecdsa_signverify_init(vctx, vec, set_ctx_params, params, operation,
+ desc))
+ return 0;
+
+ if (!ecdsa_setup_md(ctx, mdname, NULL, desc))
+ return 0;
+
+ ctx->flag_sigalg = 1;
+ ctx->flag_allow_md = 0;
+
+ if (ctx->mdctx == NULL) {
+ ctx->mdctx = EVP_MD_CTX_new();
+ if (ctx->mdctx == NULL)
+ goto error;
+ }
+
+ if (!EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params))
+ goto error;
+
+ return 1;
+
+ error:
+ EVP_MD_CTX_free(ctx->mdctx);
+ ctx->mdctx = NULL;
+ return 0;
+}
+
+static const char **ecdsa_sigalg_query_key_types(void)
+{
+ static const char *keytypes[] = { "EC", NULL };
+
+ return keytypes;
+}
+
+static const OSSL_PARAM settable_sigalg_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_SIGNATURE, NULL, 0),
+ ECDSA_COMMON_SETTABLE_CTX_PARAMS
+};
+
+static const OSSL_PARAM *ecdsa_sigalg_settable_ctx_params(void *vctx,
+ ossl_unused void *provctx)
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+
+ if (ctx != NULL && ctx->operation == EVP_PKEY_OP_VERIFYMSG)
+ return settable_sigalg_ctx_params;
+ return NULL;
+}
+
+static int ecdsa_sigalg_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_ECDSA_CTX *ctx = (PROV_ECDSA_CTX *)vctx;
+ const OSSL_PARAM *p;
+ int ret;
+
+ if (ctx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ if ((ret = ecdsa_common_set_ctx_params(ctx, params)) <= 0)
+ return ret;
+
+ if (ctx->operation == EVP_PKEY_OP_VERIFYMSG) {
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_SIGNATURE);
+ if (p != NULL) {
+ OPENSSL_free(ctx->sig);
+ ctx->sig = NULL;
+ ctx->siglen = 0;
+ if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->sig,
+ 0, &ctx->siglen))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#define IMPL_ECDSA_SIGALG(md, MD) \
+ static OSSL_FUNC_signature_sign_init_fn ecdsa_##md##_sign_init; \
+ static OSSL_FUNC_signature_sign_message_init_fn \
+ ecdsa_##md##_sign_message_init; \
+ static OSSL_FUNC_signature_verify_init_fn ecdsa_##md##_verify_init; \
+ static OSSL_FUNC_signature_verify_message_init_fn \
+ ecdsa_##md##_verify_message_init; \
+ \
+ static int \
+ ecdsa_##md##_sign_init(void *vctx, void *vec, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "ECDSA-" #MD " Sign Init"; \
+ \
+ return ecdsa_sigalg_signverify_init(vctx, vec, \
+ ecdsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_SIGN, \
+ desc); \
+ } \
+ \
+ static int \
+ ecdsa_##md##_sign_message_init(void *vctx, void *vec, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "ECDSA-" #MD " Sign Message Init"; \
+ \
+ return ecdsa_sigalg_signverify_init(vctx, vec, \
+ ecdsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_SIGNMSG, \
+ desc); \
+ } \
+ \
+ static int \
+ ecdsa_##md##_verify_init(void *vctx, void *vec, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "ECDSA-" #MD " Verify Init"; \
+ \
+ return ecdsa_sigalg_signverify_init(vctx, vec, \
+ ecdsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_VERIFY, \
+ desc); \
+ } \
+ \
+ static int \
+ ecdsa_##md##_verify_message_init(void *vctx, void *vec, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "ECDSA-" #MD " Verify Message Init"; \
+ \
+ return ecdsa_sigalg_signverify_init(vctx, vec, \
+ ecdsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_VERIFYMSG, \
+ desc); \
+ } \
+ \
+ const OSSL_DISPATCH ossl_ecdsa_##md##_signature_functions[] = { \
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))ecdsa_newctx }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, \
+ (void (*)(void))ecdsa_##md##_sign_init }, \
+ { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))ecdsa_sign }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT, \
+ (void (*)(void))ecdsa_##md##_sign_message_init }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_UPDATE, \
+ (void (*)(void))ecdsa_signverify_message_update }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_FINAL, \
+ (void (*)(void))ecdsa_sign_message_final }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, \
+ (void (*)(void))ecdsa_##md##_verify_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY, \
+ (void (*)(void))ecdsa_verify }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT, \
+ (void (*)(void))ecdsa_##md##_verify_message_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_UPDATE, \
+ (void (*)(void))ecdsa_signverify_message_update }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_FINAL, \
+ (void (*)(void))ecdsa_verify_message_final }, \
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))ecdsa_freectx }, \
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))ecdsa_dupctx }, \
+ { OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPES, \
+ (void (*)(void))ecdsa_sigalg_query_key_types }, \
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \
+ (void (*)(void))ecdsa_get_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))ecdsa_gettable_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \
+ (void (*)(void))ecdsa_sigalg_set_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))ecdsa_sigalg_settable_ctx_params }, \
+ OSSL_DISPATCH_END \
+ }
+
+IMPL_ECDSA_SIGALG(sha1, SHA1);
+IMPL_ECDSA_SIGALG(sha224, SHA2-224);
+IMPL_ECDSA_SIGALG(sha256, SHA2-256);
+IMPL_ECDSA_SIGALG(sha384, SHA2-384);
+IMPL_ECDSA_SIGALG(sha512, SHA2-512);
+IMPL_ECDSA_SIGALG(sha3_224, SHA3-224);
+IMPL_ECDSA_SIGALG(sha3_256, SHA3-256);
+IMPL_ECDSA_SIGALG(sha3_384, SHA3-384);
+IMPL_ECDSA_SIGALG(sha3_512, SHA3-512);
diff --git a/crypto/openssl/providers/implementations/signature/eddsa_sig.c b/crypto/openssl/providers/implementations/signature/eddsa_sig.c
new file mode 100644
index 000000000000..28b17eab93f3
--- /dev/null
+++ b/crypto/openssl/providers/implementations/signature/eddsa_sig.c
@@ -0,0 +1,1146 @@
+/*
+ * 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/crypto.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/err.h>
+#include <openssl/params.h>
+#include <openssl/evp.h>
+#include <openssl/proverr.h>
+#include "internal/nelem.h"
+#include "internal/sizes.h"
+#include "prov/providercommon.h"
+#include "prov/implementations.h"
+#include "prov/securitycheck.h"
+#include "prov/provider_ctx.h"
+#include "prov/der_ecx.h"
+#include "crypto/ecx.h"
+
+#ifdef S390X_EC_ASM
+# include "s390x_arch.h"
+
+# define S390X_CAN_SIGN(edtype) \
+((OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_##edtype)) \
+&& (OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_##edtype)) \
+&& (OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_VERIFY_##edtype)))
+
+static int s390x_ed25519_digestsign(const ECX_KEY *edkey, unsigned char *sig,
+ const unsigned char *tbs, size_t tbslen);
+static int s390x_ed448_digestsign(const ECX_KEY *edkey, unsigned char *sig,
+ const unsigned char *tbs, size_t tbslen);
+static int s390x_ed25519_digestverify(const ECX_KEY *edkey,
+ const unsigned char *sig,
+ const unsigned char *tbs, size_t tbslen);
+static int s390x_ed448_digestverify(const ECX_KEY *edkey,
+ const unsigned char *sig,
+ const unsigned char *tbs, size_t tbslen);
+
+#endif /* S390X_EC_ASM */
+
+enum ID_EdDSA_INSTANCE {
+ ID_NOT_SET = 0,
+ ID_Ed25519,
+ ID_Ed25519ctx,
+ ID_Ed25519ph,
+ ID_Ed448,
+ ID_Ed448ph
+};
+
+#define SN_Ed25519 "Ed25519"
+#define SN_Ed25519ph "Ed25519ph"
+#define SN_Ed25519ctx "Ed25519ctx"
+#define SN_Ed448 "Ed448"
+#define SN_Ed448ph "Ed448ph"
+
+#define EDDSA_MAX_CONTEXT_STRING_LEN 255
+#define EDDSA_PREHASH_OUTPUT_LEN 64
+
+static OSSL_FUNC_signature_newctx_fn eddsa_newctx;
+static OSSL_FUNC_signature_sign_message_init_fn ed25519_signverify_message_init;
+static OSSL_FUNC_signature_sign_message_init_fn ed25519ph_signverify_message_init;
+static OSSL_FUNC_signature_sign_message_init_fn ed25519ctx_signverify_message_init;
+static OSSL_FUNC_signature_sign_message_init_fn ed448_signverify_message_init;
+static OSSL_FUNC_signature_sign_message_init_fn ed448ph_signverify_message_init;
+static OSSL_FUNC_signature_sign_fn ed25519_sign;
+static OSSL_FUNC_signature_sign_fn ed448_sign;
+static OSSL_FUNC_signature_verify_fn ed25519_verify;
+static OSSL_FUNC_signature_verify_fn ed448_verify;
+static OSSL_FUNC_signature_digest_sign_init_fn ed25519_digest_signverify_init;
+static OSSL_FUNC_signature_digest_sign_init_fn ed448_digest_signverify_init;
+static OSSL_FUNC_signature_digest_sign_fn ed25519_digest_sign;
+static OSSL_FUNC_signature_digest_sign_fn ed448_digest_sign;
+static OSSL_FUNC_signature_digest_verify_fn ed25519_digest_verify;
+static OSSL_FUNC_signature_digest_verify_fn ed448_digest_verify;
+static OSSL_FUNC_signature_freectx_fn eddsa_freectx;
+static OSSL_FUNC_signature_dupctx_fn eddsa_dupctx;
+static OSSL_FUNC_signature_query_key_types_fn ed25519_sigalg_query_key_types;
+static OSSL_FUNC_signature_query_key_types_fn ed448_sigalg_query_key_types;
+static OSSL_FUNC_signature_get_ctx_params_fn eddsa_get_ctx_params;
+static OSSL_FUNC_signature_gettable_ctx_params_fn eddsa_gettable_ctx_params;
+static OSSL_FUNC_signature_set_ctx_params_fn eddsa_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn eddsa_settable_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn eddsa_settable_variant_ctx_params;
+
+/* there are five EdDSA instances:
+
+ Ed25519
+ Ed25519ph
+ Ed25519ctx
+ Ed448
+ Ed448ph
+
+ Quoting from RFC 8032, Section 5.1:
+
+ For Ed25519, dom2(f,c) is the empty string. The phflag value is
+ irrelevant. The context (if present at all) MUST be empty. This
+ causes the scheme to be one and the same with the Ed25519 scheme
+ published earlier.
+
+ For Ed25519ctx, phflag=0. The context input SHOULD NOT be empty.
+
+ For Ed25519ph, phflag=1 and PH is SHA512 instead. That is, the input
+ is hashed using SHA-512 before signing with Ed25519.
+
+ Quoting from RFC 8032, Section 5.2:
+
+ Ed448ph is the same but with PH being SHAKE256(x, 64) and phflag
+ being 1, i.e., the input is hashed before signing with Ed448 with a
+ hash constant modified.
+
+ Value of context is set by signer and verifier (maximum of 255
+ octets; the default is empty string) and has to match octet by octet
+ for verification to be successful.
+
+ Quoting from RFC 8032, Section 2:
+
+ dom2(x, y) The blank octet string when signing or verifying
+ Ed25519. Otherwise, the octet string: "SigEd25519 no
+ Ed25519 collisions" || octet(x) || octet(OLEN(y)) ||
+ y, where x is in range 0-255 and y is an octet string
+ of at most 255 octets. "SigEd25519 no Ed25519
+ collisions" is in ASCII (32 octets).
+
+ dom4(x, y) The octet string "SigEd448" || octet(x) ||
+ octet(OLEN(y)) || y, where x is in range 0-255 and y
+ is an octet string of at most 255 octets. "SigEd448"
+ is in ASCII (8 octets).
+
+ Note above that x is the pre-hash flag, and y is the context string.
+*/
+
+typedef struct {
+ OSSL_LIB_CTX *libctx;
+ ECX_KEY *key;
+
+ /* The Algorithm Identifier of the signature algorithm */
+ unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE];
+ size_t aid_len;
+
+ /* id indicating the EdDSA instance */
+ int instance_id;
+ /* indicates that instance_id and associated flags are preset / hardcoded */
+ unsigned int instance_id_preset_flag : 1;
+ /* for ph instances, this indicates whether the caller is expected to prehash */
+ unsigned int prehash_by_caller_flag : 1;
+
+ unsigned int dom2_flag : 1;
+ unsigned int prehash_flag : 1;
+
+ /* indicates that a non-empty context string is required, as in Ed25519ctx */
+ unsigned int context_string_flag : 1;
+
+ unsigned char context_string[EDDSA_MAX_CONTEXT_STRING_LEN];
+ size_t context_string_len;
+
+} PROV_EDDSA_CTX;
+
+static void *eddsa_newctx(void *provctx, const char *propq_unused)
+{
+ PROV_EDDSA_CTX *peddsactx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ peddsactx = OPENSSL_zalloc(sizeof(PROV_EDDSA_CTX));
+ if (peddsactx == NULL)
+ return NULL;
+
+ peddsactx->libctx = PROV_LIBCTX_OF(provctx);
+
+ return peddsactx;
+}
+
+static int eddsa_setup_instance(void *vpeddsactx, int instance_id,
+ unsigned int instance_id_preset,
+ unsigned int prehash_by_caller)
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+
+ switch (instance_id) {
+ case ID_Ed25519:
+ if (peddsactx->key->type != ECX_KEY_TYPE_ED25519)
+ return 0;
+ peddsactx->dom2_flag = 0;
+ peddsactx->prehash_flag = 0;
+ peddsactx->context_string_flag = 0;
+ break;
+ case ID_Ed25519ctx:
+ if (peddsactx->key->type != ECX_KEY_TYPE_ED25519)
+ return 0;
+ peddsactx->dom2_flag = 1;
+ peddsactx->prehash_flag = 0;
+ peddsactx->context_string_flag = 1;
+ break;
+ case ID_Ed25519ph:
+ if (peddsactx->key->type != ECX_KEY_TYPE_ED25519)
+ return 0;
+ peddsactx->dom2_flag = 1;
+ peddsactx->prehash_flag = 1;
+ peddsactx->context_string_flag = 0;
+ break;
+ case ID_Ed448:
+ if (peddsactx->key->type != ECX_KEY_TYPE_ED448)
+ return 0;
+ peddsactx->prehash_flag = 0;
+ peddsactx->context_string_flag = 0;
+ break;
+ case ID_Ed448ph:
+ if (peddsactx->key->type != ECX_KEY_TYPE_ED448)
+ return 0;
+ peddsactx->prehash_flag = 1;
+ peddsactx->context_string_flag = 0;
+ break;
+ default:
+ /* we did not recognize the instance */
+ return 0;
+ }
+ peddsactx->instance_id = instance_id;
+ peddsactx->instance_id_preset_flag = instance_id_preset;
+ peddsactx->prehash_by_caller_flag = prehash_by_caller;
+ return 1;
+}
+
+static int eddsa_signverify_init(void *vpeddsactx, void *vedkey)
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+ ECX_KEY *edkey = (ECX_KEY *)vedkey;
+ WPACKET pkt;
+ int ret;
+ unsigned char *aid = NULL;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (edkey == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
+ return 0;
+ }
+
+ if (!ossl_ecx_key_up_ref(edkey)) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ peddsactx->instance_id_preset_flag = 0;
+ peddsactx->dom2_flag = 0;
+ peddsactx->prehash_flag = 0;
+ peddsactx->context_string_flag = 0;
+ peddsactx->context_string_len = 0;
+
+ peddsactx->key = edkey;
+
+ /*
+ * We do not care about DER writing errors.
+ * All it really means is that for some reason, there's no
+ * AlgorithmIdentifier to be had, but the operation itself is
+ * still valid, just as long as it's not used to construct
+ * anything that needs an AlgorithmIdentifier.
+ */
+ peddsactx->aid_len = 0;
+ ret = WPACKET_init_der(&pkt, peddsactx->aid_buf, sizeof(peddsactx->aid_buf));
+ switch (edkey->type) {
+ case ECX_KEY_TYPE_ED25519:
+ ret = ret && ossl_DER_w_algorithmIdentifier_ED25519(&pkt, -1, edkey);
+ break;
+ case ECX_KEY_TYPE_ED448:
+ ret = ret && ossl_DER_w_algorithmIdentifier_ED448(&pkt, -1, edkey);
+ break;
+ default:
+ /* Should never happen */
+ ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+ ossl_ecx_key_free(edkey);
+ peddsactx->key = NULL;
+ WPACKET_cleanup(&pkt);
+ return 0;
+ }
+ if (ret && WPACKET_finish(&pkt)) {
+ WPACKET_get_total_written(&pkt, &peddsactx->aid_len);
+ aid = WPACKET_get_curr(&pkt);
+ }
+ WPACKET_cleanup(&pkt);
+ if (aid != NULL && peddsactx->aid_len != 0)
+ memmove(peddsactx->aid_buf, aid, peddsactx->aid_len);
+
+ return 1;
+}
+
+static int ed25519_signverify_message_init(void *vpeddsactx, void *vedkey,
+ const OSSL_PARAM params[])
+{
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed25519, 1, 0)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+static int ed25519ph_signverify_message_init(void *vpeddsactx, void *vedkey,
+ const OSSL_PARAM params[])
+{
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed25519ph, 1, 0)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+static int ed25519ph_signverify_init(void *vpeddsactx, void *vedkey,
+ const OSSL_PARAM params[])
+{
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed25519ph, 1, 1)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+/*
+ * This supports using ED25519 with EVP_PKEY_{sign,verify}_init_ex() and
+ * EVP_PKEY_{sign,verify}_init_ex2(), under the condition that the caller
+ * explicitly sets the Ed25519ph instance (this is verified by ed25519_sign()
+ * and ed25519_verify())
+ */
+static int ed25519_signverify_init(void *vpeddsactx, void *vedkey,
+ const OSSL_PARAM params[])
+{
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed25519, 0, 1)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+static int ed25519ctx_signverify_message_init(void *vpeddsactx, void *vedkey,
+ const OSSL_PARAM params[])
+{
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed25519ctx, 1, 0)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+static int ed448_signverify_message_init(void *vpeddsactx, void *vedkey,
+ const OSSL_PARAM params[])
+{
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed448, 1, 0)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+static int ed448ph_signverify_message_init(void *vpeddsactx, void *vedkey,
+ const OSSL_PARAM params[])
+{
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed448ph, 1, 0)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+static int ed448ph_signverify_init(void *vpeddsactx, void *vedkey,
+ const OSSL_PARAM params[])
+{
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed448ph, 1, 1)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+/*
+ * This supports using ED448 with EVP_PKEY_{sign,verify}_init_ex() and
+ * EVP_PKEY_{sign,verify}_init_ex2(), under the condition that the caller
+ * explicitly sets the Ed448ph instance (this is verified by ed448_sign()
+ * and ed448_verify())
+ */
+static int ed448_signverify_init(void *vpeddsactx, void *vedkey,
+ const OSSL_PARAM params[])
+{
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed448, 0, 1)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+/*
+ * This is used directly for OSSL_FUNC_SIGNATURE_SIGN and indirectly
+ * for OSSL_FUNC_SIGNATURE_DIGEST_SIGN
+ */
+static int ed25519_sign(void *vpeddsactx,
+ unsigned char *sigret, size_t *siglen, size_t sigsize,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+ const ECX_KEY *edkey = peddsactx->key;
+ uint8_t md[EVP_MAX_MD_SIZE];
+ size_t mdlen;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (sigret == NULL) {
+ *siglen = ED25519_SIGSIZE;
+ return 1;
+ }
+ if (sigsize < ED25519_SIGSIZE) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ if (edkey->privkey == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY);
+ return 0;
+ }
+#ifdef S390X_EC_ASM
+ /*
+ * s390x_ed25519_digestsign() does not yet support dom2 or context-strings.
+ * fall back to non-accelerated sign if those options are set, or pre-hasing
+ * is provided.
+ */
+ if (S390X_CAN_SIGN(ED25519)
+ && !peddsactx->dom2_flag
+ && !peddsactx->context_string_flag
+ && peddsactx->context_string_len == 0
+ && !peddsactx->prehash_flag
+ && !peddsactx->prehash_by_caller_flag) {
+ if (s390x_ed25519_digestsign(edkey, sigret, tbs, tbslen) == 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN);
+ return 0;
+ }
+ *siglen = ED25519_SIGSIZE;
+ return 1;
+ }
+#endif /* S390X_EC_ASM */
+
+ if (peddsactx->prehash_flag) {
+ if (!peddsactx->prehash_by_caller_flag) {
+ if (!EVP_Q_digest(peddsactx->libctx, SN_sha512, NULL,
+ tbs, tbslen, md, &mdlen)
+ || mdlen != EDDSA_PREHASH_OUTPUT_LEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PREHASHED_DIGEST_LENGTH);
+ return 0;
+ }
+ tbs = md;
+ tbslen = mdlen;
+ } else if (tbslen != EDDSA_PREHASH_OUTPUT_LEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH);
+ return 0;
+ }
+ } else if (peddsactx->prehash_by_caller_flag) {
+ /* The caller is supposed to set up a ph instance! */
+ ERR_raise(ERR_LIB_PROV,
+ PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION);
+ return 0;
+ }
+
+ if (ossl_ed25519_sign(sigret, tbs, tbslen, edkey->pubkey, edkey->privkey,
+ peddsactx->dom2_flag, peddsactx->prehash_flag, peddsactx->context_string_flag,
+ peddsactx->context_string, peddsactx->context_string_len,
+ peddsactx->libctx, NULL) == 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN);
+ return 0;
+ }
+ *siglen = ED25519_SIGSIZE;
+ return 1;
+}
+
+/* EVP_Q_digest() does not allow variable output length for XOFs,
+ so we use this function */
+static int ed448_shake256(OSSL_LIB_CTX *libctx,
+ const char *propq,
+ const uint8_t *in, size_t inlen,
+ uint8_t *out, size_t outlen)
+{
+ int ret = 0;
+ EVP_MD_CTX *hash_ctx = EVP_MD_CTX_new();
+ EVP_MD *shake256 = EVP_MD_fetch(libctx, SN_shake256, propq);
+
+ if (hash_ctx == NULL || shake256 == NULL)
+ goto err;
+
+ if (!EVP_DigestInit_ex(hash_ctx, shake256, NULL)
+ || !EVP_DigestUpdate(hash_ctx, in, inlen)
+ || !EVP_DigestFinalXOF(hash_ctx, out, outlen))
+ goto err;
+
+ ret = 1;
+
+ err:
+ EVP_MD_CTX_free(hash_ctx);
+ EVP_MD_free(shake256);
+ return ret;
+}
+
+/*
+ * This is used directly for OSSL_FUNC_SIGNATURE_SIGN and indirectly
+ * for OSSL_FUNC_SIGNATURE_DIGEST_SIGN
+ */
+static int ed448_sign(void *vpeddsactx,
+ unsigned char *sigret, size_t *siglen, size_t sigsize,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+ const ECX_KEY *edkey = peddsactx->key;
+ uint8_t md[EDDSA_PREHASH_OUTPUT_LEN];
+ size_t mdlen = sizeof(md);
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (sigret == NULL) {
+ *siglen = ED448_SIGSIZE;
+ return 1;
+ }
+ if (sigsize < ED448_SIGSIZE) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ if (edkey->privkey == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY);
+ return 0;
+ }
+#ifdef S390X_EC_ASM
+ /*
+ * s390x_ed448_digestsign() does not yet support context-strings or
+ * pre-hashing. Fall back to non-accelerated sign if a context-string or
+ * pre-hasing is provided.
+ */
+ if (S390X_CAN_SIGN(ED448)
+ && peddsactx->context_string_len == 0
+ && !peddsactx->prehash_flag
+ && !peddsactx->prehash_by_caller_flag) {
+ if (s390x_ed448_digestsign(edkey, sigret, tbs, tbslen) == 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN);
+ return 0;
+ }
+ *siglen = ED448_SIGSIZE;
+ return 1;
+ }
+#endif /* S390X_EC_ASM */
+
+ if (peddsactx->prehash_flag) {
+ if (!peddsactx->prehash_by_caller_flag) {
+ if (!ed448_shake256(peddsactx->libctx, NULL, tbs, tbslen, md, mdlen))
+ return 0;
+ tbs = md;
+ tbslen = mdlen;
+ } else if (tbslen != EDDSA_PREHASH_OUTPUT_LEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH);
+ return 0;
+ }
+ } else if (peddsactx->prehash_by_caller_flag) {
+ /* The caller is supposed to set up a ph instance! */
+ ERR_raise(ERR_LIB_PROV,
+ PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION);
+ return 0;
+ }
+
+ if (ossl_ed448_sign(peddsactx->libctx, sigret, tbs, tbslen,
+ edkey->pubkey, edkey->privkey,
+ peddsactx->context_string, peddsactx->context_string_len,
+ peddsactx->prehash_flag, edkey->propq) == 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SIGN);
+ return 0;
+ }
+ *siglen = ED448_SIGSIZE;
+ return 1;
+}
+
+/*
+ * This is used directly for OSSL_FUNC_SIGNATURE_VERIFY and indirectly
+ * for OSSL_FUNC_SIGNATURE_DIGEST_VERIFY
+ */
+static int ed25519_verify(void *vpeddsactx,
+ const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+ const ECX_KEY *edkey = peddsactx->key;
+ uint8_t md[EVP_MAX_MD_SIZE];
+ size_t mdlen;
+
+ if (!ossl_prov_is_running() || siglen != ED25519_SIGSIZE)
+ return 0;
+
+#ifdef S390X_EC_ASM
+ /*
+ * s390x_ed25519_digestverify() does not yet support dom2 or context-strings.
+ * fall back to non-accelerated verify if those options are set, or
+ * pre-hasing is provided.
+ */
+ if (S390X_CAN_SIGN(ED25519)
+ && !peddsactx->dom2_flag
+ && !peddsactx->context_string_flag
+ && peddsactx->context_string_len == 0
+ && !peddsactx->prehash_flag
+ && !peddsactx->prehash_by_caller_flag)
+ return s390x_ed25519_digestverify(edkey, sig, tbs, tbslen);
+#endif /* S390X_EC_ASM */
+
+ if (peddsactx->prehash_flag) {
+ if (!peddsactx->prehash_by_caller_flag) {
+ if (!EVP_Q_digest(peddsactx->libctx, SN_sha512, NULL,
+ tbs, tbslen, md, &mdlen)
+ || mdlen != EDDSA_PREHASH_OUTPUT_LEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PREHASHED_DIGEST_LENGTH);
+ return 0;
+ }
+ tbs = md;
+ tbslen = mdlen;
+ } else if (tbslen != EDDSA_PREHASH_OUTPUT_LEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH);
+ return 0;
+ }
+ } else if (peddsactx->prehash_by_caller_flag) {
+ /* The caller is supposed to set up a ph instance! */
+ ERR_raise(ERR_LIB_PROV,
+ PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION);
+ return 0;
+ }
+
+ return ossl_ed25519_verify(tbs, tbslen, sig, edkey->pubkey,
+ peddsactx->dom2_flag, peddsactx->prehash_flag, peddsactx->context_string_flag,
+ peddsactx->context_string, peddsactx->context_string_len,
+ peddsactx->libctx, edkey->propq);
+}
+
+/*
+ * This is used directly for OSSL_FUNC_SIGNATURE_VERIFY and indirectly
+ * for OSSL_FUNC_SIGNATURE_DIGEST_VERIFY
+ */
+static int ed448_verify(void *vpeddsactx,
+ const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+ const ECX_KEY *edkey = peddsactx->key;
+ uint8_t md[EDDSA_PREHASH_OUTPUT_LEN];
+ size_t mdlen = sizeof(md);
+
+ if (!ossl_prov_is_running() || siglen != ED448_SIGSIZE)
+ return 0;
+
+#ifdef S390X_EC_ASM
+ /*
+ * s390x_ed448_digestverify() does not yet support context-strings or
+ * pre-hashing. Fall back to non-accelerated verify if a context-string or
+ * pre-hasing is provided.
+ */
+ if (S390X_CAN_SIGN(ED448)
+ && peddsactx->context_string_len == 0
+ && !peddsactx->prehash_flag
+ && !peddsactx->prehash_by_caller_flag)
+ return s390x_ed448_digestverify(edkey, sig, tbs, tbslen);
+#endif /* S390X_EC_ASM */
+
+ if (peddsactx->prehash_flag) {
+ if (!peddsactx->prehash_by_caller_flag) {
+ if (!ed448_shake256(peddsactx->libctx, NULL, tbs, tbslen, md, mdlen))
+ return 0;
+ tbs = md;
+ tbslen = mdlen;
+ } else if (tbslen != EDDSA_PREHASH_OUTPUT_LEN) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH);
+ return 0;
+ }
+ } else if (peddsactx->prehash_by_caller_flag) {
+ /* The caller is supposed to set up a ph instance! */
+ ERR_raise(ERR_LIB_PROV,
+ PROV_R_INVALID_EDDSA_INSTANCE_FOR_ATTEMPTED_OPERATION);
+ return 0;
+ }
+
+ return ossl_ed448_verify(peddsactx->libctx, tbs, tbslen, sig, edkey->pubkey,
+ peddsactx->context_string, peddsactx->context_string_len,
+ peddsactx->prehash_flag, edkey->propq);
+}
+
+/* All digest_{sign,verify} are simple wrappers around the functions above */
+
+static int ed25519_digest_signverify_init(void *vpeddsactx, const char *mdname,
+ void *vedkey,
+ const OSSL_PARAM params[])
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+
+ if (mdname != NULL && mdname[0] != '\0') {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "Explicit digest not allowed with EdDSA operations");
+ return 0;
+ }
+
+ if (vedkey == NULL && peddsactx->key != NULL)
+ return eddsa_set_ctx_params(peddsactx, params);
+
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed25519, 0, 0)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+static int ed25519_digest_sign(void *vpeddsactx,
+ unsigned char *sigret, size_t *siglen, size_t sigsize,
+ const unsigned char *tbs, size_t tbslen)
+{
+ return ed25519_sign(vpeddsactx, sigret, siglen, sigsize, tbs, tbslen);
+}
+
+static int ed25519_digest_verify(void *vpeddsactx,
+ const unsigned char *sigret, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ return ed25519_verify(vpeddsactx, sigret, siglen, tbs, tbslen);
+}
+
+static int ed448_digest_signverify_init(void *vpeddsactx, const char *mdname,
+ void *vedkey,
+ const OSSL_PARAM params[])
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+
+ if (mdname != NULL && mdname[0] != '\0') {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "Explicit digest not allowed with EdDSA operations");
+ return 0;
+ }
+
+ if (vedkey == NULL && peddsactx->key != NULL)
+ return eddsa_set_ctx_params(peddsactx, params);
+
+ return eddsa_signverify_init(vpeddsactx, vedkey)
+ && eddsa_setup_instance(vpeddsactx, ID_Ed448, 0, 0)
+ && eddsa_set_ctx_params(vpeddsactx, params);
+}
+
+static int ed448_digest_sign(void *vpeddsactx,
+ unsigned char *sigret, size_t *siglen, size_t sigsize,
+ const unsigned char *tbs, size_t tbslen)
+{
+ return ed448_sign(vpeddsactx, sigret, siglen, sigsize, tbs, tbslen);
+}
+
+static int ed448_digest_verify(void *vpeddsactx,
+ const unsigned char *sigret, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ return ed448_verify(vpeddsactx, sigret, siglen, tbs, tbslen);
+}
+
+static void eddsa_freectx(void *vpeddsactx)
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+
+ ossl_ecx_key_free(peddsactx->key);
+
+ OPENSSL_free(peddsactx);
+}
+
+static void *eddsa_dupctx(void *vpeddsactx)
+{
+ PROV_EDDSA_CTX *srcctx = (PROV_EDDSA_CTX *)vpeddsactx;
+ PROV_EDDSA_CTX *dstctx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+ if (dstctx == NULL)
+ return NULL;
+
+ *dstctx = *srcctx;
+ dstctx->key = NULL;
+
+ if (srcctx->key != NULL && !ossl_ecx_key_up_ref(srcctx->key)) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ dstctx->key = srcctx->key;
+
+ return dstctx;
+ err:
+ eddsa_freectx(dstctx);
+ return NULL;
+}
+
+static const char **ed25519_sigalg_query_key_types(void)
+{
+ static const char *keytypes[] = { "ED25519", NULL };
+
+ return keytypes;
+}
+
+static const char **ed448_sigalg_query_key_types(void)
+{
+ static const char *keytypes[] = { "ED448", NULL };
+
+ return keytypes;
+}
+
+
+
+static int eddsa_get_ctx_params(void *vpeddsactx, OSSL_PARAM *params)
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+ OSSL_PARAM *p;
+
+ if (peddsactx == NULL)
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
+ if (p != NULL
+ && !OSSL_PARAM_set_octet_string(p,
+ peddsactx->aid_len == 0 ? NULL : peddsactx->aid_buf,
+ peddsactx->aid_len))
+ return 0;
+
+ return 1;
+}
+
+static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_INSTANCE, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *eddsa_gettable_ctx_params(ossl_unused void *vpeddsactx,
+ ossl_unused void *provctx)
+{
+ return known_gettable_ctx_params;
+}
+
+static int eddsa_set_ctx_params(void *vpeddsactx, const OSSL_PARAM params[])
+{
+ PROV_EDDSA_CTX *peddsactx = (PROV_EDDSA_CTX *)vpeddsactx;
+ const OSSL_PARAM *p;
+
+ if (peddsactx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_INSTANCE);
+ if (p != NULL) {
+ char instance_name[OSSL_MAX_NAME_SIZE] = "";
+ char *pinstance_name = instance_name;
+
+ if (peddsactx->instance_id_preset_flag) {
+ /* When the instance is preset, the caller must no try to set it */
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_NO_INSTANCE_ALLOWED,
+ "the EdDSA instance is preset, you may not try to specify it",
+ NULL);
+ return 0;
+ }
+
+ if (!OSSL_PARAM_get_utf8_string(p, &pinstance_name, sizeof(instance_name)))
+ return 0;
+
+ /*
+ * When setting the new instance, we're careful not to change the
+ * prehash_by_caller flag, as that's always preset by the init
+ * functions. The sign functions will determine if the instance
+ * matches this flag.
+ */
+ if (OPENSSL_strcasecmp(pinstance_name, SN_Ed25519) == 0) {
+ eddsa_setup_instance(peddsactx, ID_Ed25519, 0,
+ peddsactx->prehash_by_caller_flag);
+ } else if (OPENSSL_strcasecmp(pinstance_name, SN_Ed25519ctx) == 0) {
+ eddsa_setup_instance(peddsactx, ID_Ed25519ctx, 0,
+ peddsactx->prehash_by_caller_flag);
+ } else if (OPENSSL_strcasecmp(pinstance_name, SN_Ed25519ph) == 0) {
+ eddsa_setup_instance(peddsactx, ID_Ed25519ph, 0,
+ peddsactx->prehash_by_caller_flag);
+ } else if (OPENSSL_strcasecmp(pinstance_name, SN_Ed448) == 0) {
+ eddsa_setup_instance(peddsactx, ID_Ed448, 0,
+ peddsactx->prehash_by_caller_flag);
+ } else if (OPENSSL_strcasecmp(pinstance_name, SN_Ed448ph) == 0) {
+ eddsa_setup_instance(peddsactx, ID_Ed448ph, 0,
+ peddsactx->prehash_by_caller_flag);
+ } else {
+ /* we did not recognize the instance */
+ return 0;
+ }
+
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_CONTEXT_STRING);
+ if (p != NULL) {
+ void *vp_context_string = peddsactx->context_string;
+
+ if (!OSSL_PARAM_get_octet_string(p, &vp_context_string, sizeof(peddsactx->context_string), &(peddsactx->context_string_len))) {
+ peddsactx->context_string_len = 0;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static const OSSL_PARAM settable_ctx_params[] = {
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_INSTANCE, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *eddsa_settable_ctx_params(ossl_unused void *vpeddsactx,
+ ossl_unused void *provctx)
+{
+ return settable_ctx_params;
+}
+
+static const OSSL_PARAM settable_variant_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *
+eddsa_settable_variant_ctx_params(ossl_unused void *vpeddsactx,
+ ossl_unused void *provctx)
+{
+ return settable_variant_ctx_params;
+}
+
+/*
+ * Ed25519 can be used with:
+ * - EVP_PKEY_sign_init_ex2() [ instance and prehash assumed done by caller ]
+ * - EVP_PKEY_verify_init_ex2() [ instance and prehash assumed done by caller ]
+ * - EVP_PKEY_sign_message_init()
+ * - EVP_PKEY_verify_message_init()
+ * - EVP_DigestSignInit_ex()
+ * - EVP_DigestVerifyInit_ex()
+ * Ed25519ph can be used with:
+ * - EVP_PKEY_sign_init_ex2() [ prehash assumed done by caller ]
+ * - EVP_PKEY_verify_init_ex2() [ prehash assumed done by caller ]
+ * - EVP_PKEY_sign_message_init()
+ * - EVP_PKEY_verify_message_init()
+ * Ed25519ctx can be used with:
+ * - EVP_PKEY_sign_message_init()
+ * - EVP_PKEY_verify_message_init()
+ * Ed448 can be used with:
+ * - EVP_PKEY_sign_init_ex2() [ instance and prehash assumed done by caller ]
+ * - EVP_PKEY_verify_init_ex2() [ instance and prehash assumed done by caller ]
+ * - EVP_PKEY_sign_message_init()
+ * - EVP_PKEY_verify_message_init()
+ * - EVP_DigestSignInit_ex()
+ * - EVP_DigestVerifyInit_ex()
+ * Ed448ph can be used with:
+ * - EVP_PKEY_sign_init_ex2() [ prehash assumed done by caller ]
+ * - EVP_PKEY_verify_init_ex2() [ prehash assumed done by caller ]
+ * - EVP_PKEY_sign_message_init()
+ * - EVP_PKEY_verify_message_init()
+ */
+
+#define ed25519_DISPATCH_END \
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, \
+ (void (*)(void))ed25519_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, \
+ (void (*)(void))ed25519_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \
+ (void (*)(void))ed25519_digest_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, \
+ (void (*)(void))ed25519_digest_sign }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, \
+ (void (*)(void))ed25519_digest_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, \
+ (void (*)(void))ed25519_digest_verify }, \
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \
+ (void (*)(void))eddsa_get_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))eddsa_gettable_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \
+ (void (*)(void))eddsa_set_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))eddsa_settable_ctx_params }, \
+ OSSL_DISPATCH_END
+
+#define eddsa_variant_DISPATCH_END(v) \
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, \
+ (void (*)(void))v##_signverify_message_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, \
+ (void (*)(void))v##_signverify_message_init }, \
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \
+ (void (*)(void))eddsa_get_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))eddsa_gettable_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \
+ (void (*)(void))eddsa_set_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))eddsa_settable_variant_ctx_params }, \
+ OSSL_DISPATCH_END
+
+#define ed25519ph_DISPATCH_END \
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, \
+ (void (*)(void))ed25519ph_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, \
+ (void (*)(void))ed25519ph_signverify_init }, \
+ eddsa_variant_DISPATCH_END(ed25519ph)
+
+#define ed25519ctx_DISPATCH_END eddsa_variant_DISPATCH_END(ed25519ctx)
+
+#define ed448_DISPATCH_END \
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, \
+ (void (*)(void))ed448_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, \
+ (void (*)(void))ed448_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \
+ (void (*)(void))ed448_digest_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, \
+ (void (*)(void))ed448_digest_sign }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, \
+ (void (*)(void))ed448_digest_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, \
+ (void (*)(void))ed448_digest_verify }, \
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \
+ (void (*)(void))eddsa_get_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))eddsa_gettable_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \
+ (void (*)(void))eddsa_set_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))eddsa_settable_ctx_params }, \
+ OSSL_DISPATCH_END
+
+#define ed448ph_DISPATCH_END \
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, \
+ (void (*)(void))ed448ph_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, \
+ (void (*)(void))ed448ph_signverify_init }, \
+ eddsa_variant_DISPATCH_END(ed448ph)
+
+/* vn = variant name, bn = base name */
+#define IMPL_EDDSA_DISPATCH(vn,bn) \
+ const OSSL_DISPATCH ossl_##vn##_signature_functions[] = { \
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))eddsa_newctx }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT, \
+ (void (*)(void))vn##_signverify_message_init }, \
+ { OSSL_FUNC_SIGNATURE_SIGN, \
+ (void (*)(void))bn##_sign }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT, \
+ (void (*)(void))vn##_signverify_message_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY, \
+ (void (*)(void))bn##_verify }, \
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))eddsa_freectx }, \
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))eddsa_dupctx }, \
+ { OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPES, \
+ (void (*)(void))bn##_sigalg_query_key_types }, \
+ vn##_DISPATCH_END \
+ }
+
+IMPL_EDDSA_DISPATCH(ed25519,ed25519);
+IMPL_EDDSA_DISPATCH(ed25519ph,ed25519);
+IMPL_EDDSA_DISPATCH(ed25519ctx,ed25519);
+IMPL_EDDSA_DISPATCH(ed448,ed448);
+IMPL_EDDSA_DISPATCH(ed448ph,ed448);
+
+#ifdef S390X_EC_ASM
+
+static int s390x_ed25519_digestsign(const ECX_KEY *edkey, unsigned char *sig,
+ const unsigned char *tbs, size_t tbslen)
+{
+ int rc;
+ union {
+ struct {
+ unsigned char sig[64];
+ unsigned char priv[32];
+ } ed25519;
+ unsigned long long buff[512];
+ } param;
+
+ memset(&param, 0, sizeof(param));
+ memcpy(param.ed25519.priv, edkey->privkey, sizeof(param.ed25519.priv));
+
+ rc = s390x_kdsa(S390X_EDDSA_SIGN_ED25519, &param.ed25519, tbs, tbslen);
+ OPENSSL_cleanse(param.ed25519.priv, sizeof(param.ed25519.priv));
+ if (rc != 0)
+ return 0;
+
+ s390x_flip_endian32(sig, param.ed25519.sig);
+ s390x_flip_endian32(sig + 32, param.ed25519.sig + 32);
+ return 1;
+}
+
+static int s390x_ed448_digestsign(const ECX_KEY *edkey, unsigned char *sig,
+ const unsigned char *tbs, size_t tbslen)
+{
+ int rc;
+ union {
+ struct {
+ unsigned char sig[128];
+ unsigned char priv[64];
+ } ed448;
+ unsigned long long buff[512];
+ } param;
+
+ memset(&param, 0, sizeof(param));
+ memcpy(param.ed448.priv + 64 - 57, edkey->privkey, 57);
+
+ rc = s390x_kdsa(S390X_EDDSA_SIGN_ED448, &param.ed448, tbs, tbslen);
+ OPENSSL_cleanse(param.ed448.priv, sizeof(param.ed448.priv));
+ if (rc != 0)
+ return 0;
+
+ s390x_flip_endian64(param.ed448.sig, param.ed448.sig);
+ s390x_flip_endian64(param.ed448.sig + 64, param.ed448.sig + 64);
+ memcpy(sig, param.ed448.sig, 57);
+ memcpy(sig + 57, param.ed448.sig + 64, 57);
+ return 1;
+}
+
+static int s390x_ed25519_digestverify(const ECX_KEY *edkey,
+ const unsigned char *sig,
+ const unsigned char *tbs, size_t tbslen)
+{
+ union {
+ struct {
+ unsigned char sig[64];
+ unsigned char pub[32];
+ } ed25519;
+ unsigned long long buff[512];
+ } param;
+
+ memset(&param, 0, sizeof(param));
+ s390x_flip_endian32(param.ed25519.sig, sig);
+ s390x_flip_endian32(param.ed25519.sig + 32, sig + 32);
+ s390x_flip_endian32(param.ed25519.pub, edkey->pubkey);
+
+ return s390x_kdsa(S390X_EDDSA_VERIFY_ED25519,
+ &param.ed25519, tbs, tbslen) == 0 ? 1 : 0;
+}
+
+static int s390x_ed448_digestverify(const ECX_KEY *edkey,
+ const unsigned char *sig,
+ const unsigned char *tbs,
+ size_t tbslen)
+{
+ union {
+ struct {
+ unsigned char sig[128];
+ unsigned char pub[64];
+ } ed448;
+ unsigned long long buff[512];
+ } param;
+
+ memset(&param, 0, sizeof(param));
+ memcpy(param.ed448.sig, sig, 57);
+ s390x_flip_endian64(param.ed448.sig, param.ed448.sig);
+ memcpy(param.ed448.sig + 64, sig + 57, 57);
+ s390x_flip_endian64(param.ed448.sig + 64, param.ed448.sig + 64);
+ memcpy(param.ed448.pub, edkey->pubkey, 57);
+ s390x_flip_endian64(param.ed448.pub, param.ed448.pub);
+
+ return s390x_kdsa(S390X_EDDSA_VERIFY_ED448,
+ &param.ed448, tbs, tbslen) == 0 ? 1 : 0;
+}
+
+#endif /* S390X_EC_ASM */
diff --git a/crypto/openssl/providers/implementations/signature/mac_legacy_sig.c b/crypto/openssl/providers/implementations/signature/mac_legacy_sig.c
new file mode 100644
index 000000000000..b25a74506ab0
--- /dev/null
+++ b/crypto/openssl/providers/implementations/signature/mac_legacy_sig.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2019-2023 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* We need to use some engine deprecated APIs */
+#define OPENSSL_SUPPRESS_DEPRECATED
+
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/params.h>
+#include <openssl/err.h>
+#include <openssl/proverr.h>
+#ifndef FIPS_MODULE
+# include <openssl/engine.h>
+#endif
+#include "prov/implementations.h"
+#include "prov/provider_ctx.h"
+#include "prov/macsignature.h"
+#include "prov/providercommon.h"
+
+static OSSL_FUNC_signature_newctx_fn mac_hmac_newctx;
+static OSSL_FUNC_signature_newctx_fn mac_siphash_newctx;
+static OSSL_FUNC_signature_newctx_fn mac_poly1305_newctx;
+static OSSL_FUNC_signature_newctx_fn mac_cmac_newctx;
+static OSSL_FUNC_signature_digest_sign_init_fn mac_digest_sign_init;
+static OSSL_FUNC_signature_digest_sign_update_fn mac_digest_sign_update;
+static OSSL_FUNC_signature_digest_sign_final_fn mac_digest_sign_final;
+static OSSL_FUNC_signature_freectx_fn mac_freectx;
+static OSSL_FUNC_signature_dupctx_fn mac_dupctx;
+static OSSL_FUNC_signature_set_ctx_params_fn mac_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn mac_hmac_settable_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn mac_siphash_settable_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn mac_poly1305_settable_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn mac_cmac_settable_ctx_params;
+
+typedef struct {
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+ MAC_KEY *key;
+ EVP_MAC_CTX *macctx;
+} PROV_MAC_CTX;
+
+static void *mac_newctx(void *provctx, const char *propq, const char *macname)
+{
+ PROV_MAC_CTX *pmacctx;
+ EVP_MAC *mac = NULL;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ pmacctx = OPENSSL_zalloc(sizeof(PROV_MAC_CTX));
+ if (pmacctx == NULL)
+ return NULL;
+
+ pmacctx->libctx = PROV_LIBCTX_OF(provctx);
+ if (propq != NULL && (pmacctx->propq = OPENSSL_strdup(propq)) == NULL)
+ goto err;
+
+ mac = EVP_MAC_fetch(pmacctx->libctx, macname, propq);
+ if (mac == NULL)
+ goto err;
+
+ pmacctx->macctx = EVP_MAC_CTX_new(mac);
+ if (pmacctx->macctx == NULL)
+ goto err;
+
+ EVP_MAC_free(mac);
+
+ return pmacctx;
+
+ err:
+ OPENSSL_free(pmacctx->propq);
+ OPENSSL_free(pmacctx);
+ EVP_MAC_free(mac);
+ return NULL;
+}
+
+#define MAC_NEWCTX(funcname, macname) \
+ static void *mac_##funcname##_newctx(void *provctx, const char *propq) \
+ { \
+ return mac_newctx(provctx, propq, macname); \
+ }
+
+MAC_NEWCTX(hmac, "HMAC")
+MAC_NEWCTX(siphash, "SIPHASH")
+MAC_NEWCTX(poly1305, "POLY1305")
+MAC_NEWCTX(cmac, "CMAC")
+
+static int mac_digest_sign_init(void *vpmacctx, const char *mdname, void *vkey,
+ const OSSL_PARAM params[])
+{
+ PROV_MAC_CTX *pmacctx = (PROV_MAC_CTX *)vpmacctx;
+ const char *ciphername = NULL, *engine = NULL;
+
+ if (!ossl_prov_is_running()
+ || pmacctx == NULL)
+ return 0;
+
+ if (pmacctx->key == NULL && vkey == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
+ return 0;
+ }
+
+ if (vkey != NULL) {
+ if (!ossl_mac_key_up_ref(vkey))
+ return 0;
+ ossl_mac_key_free(pmacctx->key);
+ pmacctx->key = vkey;
+ }
+
+ if (pmacctx->key->cipher.cipher != NULL)
+ ciphername = (char *)EVP_CIPHER_get0_name(pmacctx->key->cipher.cipher);
+#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE)
+ if (pmacctx->key->cipher.engine != NULL)
+ engine = (char *)ENGINE_get_id(pmacctx->key->cipher.engine);
+#endif
+
+ if (!ossl_prov_set_macctx(pmacctx->macctx, NULL,
+ (char *)ciphername,
+ (char *)mdname,
+ (char *)engine,
+ pmacctx->key->properties,
+ NULL, 0))
+ return 0;
+
+ if (!EVP_MAC_init(pmacctx->macctx, pmacctx->key->priv_key,
+ pmacctx->key->priv_key_len, params))
+ return 0;
+
+ return 1;
+}
+
+int mac_digest_sign_update(void *vpmacctx, const unsigned char *data,
+ size_t datalen)
+{
+ PROV_MAC_CTX *pmacctx = (PROV_MAC_CTX *)vpmacctx;
+
+ if (pmacctx == NULL || pmacctx->macctx == NULL)
+ return 0;
+
+ return EVP_MAC_update(pmacctx->macctx, data, datalen);
+}
+
+int mac_digest_sign_final(void *vpmacctx, unsigned char *mac, size_t *maclen,
+ size_t macsize)
+{
+ PROV_MAC_CTX *pmacctx = (PROV_MAC_CTX *)vpmacctx;
+
+ if (!ossl_prov_is_running() || pmacctx == NULL || pmacctx->macctx == NULL)
+ return 0;
+
+ return EVP_MAC_final(pmacctx->macctx, mac, maclen, macsize);
+}
+
+static void mac_freectx(void *vpmacctx)
+{
+ PROV_MAC_CTX *ctx = (PROV_MAC_CTX *)vpmacctx;
+
+ OPENSSL_free(ctx->propq);
+ EVP_MAC_CTX_free(ctx->macctx);
+ ossl_mac_key_free(ctx->key);
+ OPENSSL_free(ctx);
+}
+
+static void *mac_dupctx(void *vpmacctx)
+{
+ PROV_MAC_CTX *srcctx = (PROV_MAC_CTX *)vpmacctx;
+ PROV_MAC_CTX *dstctx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+ if (dstctx == NULL)
+ return NULL;
+
+ *dstctx = *srcctx;
+ dstctx->propq = NULL;
+ dstctx->key = NULL;
+ dstctx->macctx = NULL;
+
+ if (srcctx->propq != NULL && (dstctx->propq = OPENSSL_strdup(srcctx->propq)) == NULL)
+ goto err;
+
+ if (srcctx->key != NULL && !ossl_mac_key_up_ref(srcctx->key))
+ goto err;
+ dstctx->key = srcctx->key;
+
+ if (srcctx->macctx != NULL) {
+ dstctx->macctx = EVP_MAC_CTX_dup(srcctx->macctx);
+ if (dstctx->macctx == NULL)
+ goto err;
+ }
+
+ return dstctx;
+ err:
+ mac_freectx(dstctx);
+ return NULL;
+}
+
+static int mac_set_ctx_params(void *vpmacctx, const OSSL_PARAM params[])
+{
+ PROV_MAC_CTX *ctx = (PROV_MAC_CTX *)vpmacctx;
+
+ return EVP_MAC_CTX_set_params(ctx->macctx, params);
+}
+
+static const OSSL_PARAM *mac_settable_ctx_params(ossl_unused void *ctx,
+ void *provctx,
+ const char *macname)
+{
+ EVP_MAC *mac = EVP_MAC_fetch(PROV_LIBCTX_OF(provctx), macname,
+ NULL);
+ const OSSL_PARAM *params;
+
+ if (mac == NULL)
+ return NULL;
+
+ params = EVP_MAC_settable_ctx_params(mac);
+ EVP_MAC_free(mac);
+
+ return params;
+}
+
+#define MAC_SETTABLE_CTX_PARAMS(funcname, macname) \
+ static const OSSL_PARAM *mac_##funcname##_settable_ctx_params(void *ctx, \
+ void *provctx) \
+ { \
+ return mac_settable_ctx_params(ctx, provctx, macname); \
+ }
+
+MAC_SETTABLE_CTX_PARAMS(hmac, "HMAC")
+MAC_SETTABLE_CTX_PARAMS(siphash, "SIPHASH")
+MAC_SETTABLE_CTX_PARAMS(poly1305, "POLY1305")
+MAC_SETTABLE_CTX_PARAMS(cmac, "CMAC")
+
+#define MAC_SIGNATURE_FUNCTIONS(funcname) \
+ const OSSL_DISPATCH ossl_mac_legacy_##funcname##_signature_functions[] = { \
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))mac_##funcname##_newctx }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \
+ (void (*)(void))mac_digest_sign_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, \
+ (void (*)(void))mac_digest_sign_update }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, \
+ (void (*)(void))mac_digest_sign_final }, \
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))mac_freectx }, \
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))mac_dupctx }, \
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \
+ (void (*)(void))mac_set_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))mac_##funcname##_settable_ctx_params }, \
+ OSSL_DISPATCH_END \
+ };
+
+MAC_SIGNATURE_FUNCTIONS(hmac)
+MAC_SIGNATURE_FUNCTIONS(siphash)
+MAC_SIGNATURE_FUNCTIONS(poly1305)
+MAC_SIGNATURE_FUNCTIONS(cmac)
diff --git a/crypto/openssl/providers/implementations/signature/ml_dsa_sig.c b/crypto/openssl/providers/implementations/signature/ml_dsa_sig.c
new file mode 100644
index 000000000000..e235e31752eb
--- /dev/null
+++ b/crypto/openssl/providers/implementations/signature/ml_dsa_sig.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2024-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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "internal/deprecated.h"
+
+#include <assert.h>
+#include <string.h> /* memset */
+#include <openssl/core_names.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/proverr.h>
+#include "prov/implementations.h"
+#include "prov/providercommon.h"
+#include "prov/provider_ctx.h"
+#include "prov/der_ml_dsa.h"
+#include "crypto/ml_dsa.h"
+#include "internal/packet.h"
+#include "internal/sizes.h"
+
+#define ML_DSA_MESSAGE_ENCODE_RAW 0
+#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_fn ml_dsa_sign;
+static OSSL_FUNC_signature_verify_message_init_fn ml_dsa_verify_msg_init;
+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;
+static OSSL_FUNC_signature_digest_verify_fn ml_dsa_digest_verify;
+static OSSL_FUNC_signature_freectx_fn ml_dsa_freectx;
+static OSSL_FUNC_signature_set_ctx_params_fn ml_dsa_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn ml_dsa_settable_ctx_params;
+static OSSL_FUNC_signature_get_ctx_params_fn ml_dsa_get_ctx_params;
+static OSSL_FUNC_signature_gettable_ctx_params_fn ml_dsa_gettable_ctx_params;
+static OSSL_FUNC_signature_dupctx_fn ml_dsa_dupctx;
+
+typedef struct {
+ ML_DSA_KEY *key;
+ OSSL_LIB_CTX *libctx;
+ uint8_t context_string[ML_DSA_MAX_CONTEXT_STRING_LEN];
+ size_t context_string_len;
+ uint8_t test_entropy[ML_DSA_ENTROPY_LEN];
+ size_t test_entropy_len;
+ int msg_encode;
+ int deterministic;
+ int evp_type;
+ /* The Algorithm Identifier of the signature algorithm */
+ 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 */
+} PROV_ML_DSA_CTX;
+
+static void ml_dsa_freectx(void *vctx)
+{
+ PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx;
+
+ OPENSSL_cleanse(ctx->test_entropy, ctx->test_entropy_len);
+ OPENSSL_free(ctx);
+}
+
+static void *ml_dsa_newctx(void *provctx, int evp_type, const char *propq)
+{
+ PROV_ML_DSA_CTX *ctx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ ctx = OPENSSL_zalloc(sizeof(PROV_ML_DSA_CTX));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->libctx = PROV_LIBCTX_OF(provctx);
+ ctx->msg_encode = ML_DSA_MESSAGE_ENCODE_PURE;
+ ctx->evp_type = evp_type;
+ return ctx;
+}
+
+static void *ml_dsa_dupctx(void *vctx)
+{
+ PROV_ML_DSA_CTX *srcctx = (PROV_ML_DSA_CTX *)vctx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ /*
+ * 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));
+}
+
+static int set_alg_id_buffer(PROV_ML_DSA_CTX *ctx)
+{
+ int ret;
+ WPACKET pkt;
+ uint8_t *aid = NULL;
+
+ /*
+ * We do not care about DER writing errors.
+ * All it really means is that for some reason, there's no
+ * AlgorithmIdentifier to be had, but the operation itself is
+ * still valid, just as long as it's not used to construct
+ * anything that needs an AlgorithmIdentifier.
+ */
+ ctx->aid_len = 0;
+ ret = WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf));
+ ret = ret && ossl_DER_w_algorithmIdentifier_ML_DSA(&pkt, -1, ctx->key);
+ if (ret && WPACKET_finish(&pkt)) {
+ WPACKET_get_total_written(&pkt, &ctx->aid_len);
+ aid = WPACKET_get_curr(&pkt);
+ }
+ WPACKET_cleanup(&pkt);
+ if (aid != NULL && ctx->aid_len != 0)
+ memmove(ctx->aid_buf, aid, ctx->aid_len);
+ return 1;
+}
+
+static int ml_dsa_signverify_msg_init(void *vctx, void *vkey,
+ const OSSL_PARAM params[], int operation,
+ const char *desc)
+{
+ PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx;
+ ML_DSA_KEY *key = vkey;
+
+ if (!ossl_prov_is_running()
+ || ctx == NULL)
+ return 0;
+
+ if (vkey == NULL && ctx->key == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
+ return 0;
+ }
+
+ if (key != NULL)
+ ctx->key = vkey;
+ if (!ossl_ml_dsa_key_matches(ctx->key, ctx->evp_type))
+ return 0;
+
+ set_alg_id_buffer(ctx);
+ ctx->mu = 0;
+
+ return ml_dsa_set_ctx_params(ctx, params);
+}
+
+static int ml_dsa_sign_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[])
+{
+ return ml_dsa_signverify_msg_init(vctx, vkey, params,
+ EVP_PKEY_OP_SIGN, "ML_DSA Sign Init");
+}
+
+static int ml_dsa_digest_signverify_init(void *vctx, const char *mdname,
+ void *vkey, const OSSL_PARAM params[])
+{
+ PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx;
+
+ if (mdname != NULL && mdname[0] != '\0') {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "Explicit digest not supported for ML-DSA operations");
+ return 0;
+ }
+
+ ctx->mu = 0;
+
+ if (vkey == NULL && ctx->key != NULL)
+ return ml_dsa_set_ctx_params(ctx, params);
+
+ return ml_dsa_signverify_msg_init(vctx, vkey, params,
+ EVP_PKEY_OP_SIGN, "ML_DSA Sign Init");
+}
+
+static int ml_dsa_sign(void *vctx, uint8_t *sig, size_t *siglen, size_t sigsize,
+ const uint8_t *msg, size_t msg_len)
+{
+ int ret = 0;
+ PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx;
+ uint8_t rand_tmp[ML_DSA_ENTROPY_LEN], *rnd = NULL;
+
+ if (!ossl_prov_is_running())
+ 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;
+ }
+ }
+ ret = ossl_ml_dsa_sign(ctx->key, ctx->mu, msg, msg_len,
+ ctx->context_string, ctx->context_string_len,
+ rnd, sizeof(rand_tmp), ctx->msg_encode,
+ sig, siglen, sigsize);
+ if (rnd != ctx->test_entropy)
+ OPENSSL_cleanse(rand_tmp, sizeof(rand_tmp));
+ return ret;
+}
+
+static int ml_dsa_digest_sign(void *vctx, uint8_t *sig, size_t *siglen, size_t sigsize,
+ const uint8_t *tbs, size_t tbslen)
+{
+ return ml_dsa_sign(vctx, sig, siglen, sigsize, tbs, tbslen);
+}
+
+static int ml_dsa_verify_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[])
+{
+ return ml_dsa_signverify_msg_init(vctx, vkey, params, EVP_PKEY_OP_VERIFY,
+ "ML_DSA Verify Init");
+}
+
+static int ml_dsa_verify(void *vctx, const uint8_t *sig, size_t siglen,
+ const uint8_t *msg, size_t msg_len)
+{
+ PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx;
+
+ if (!ossl_prov_is_running())
+ return 0;
+ return ossl_ml_dsa_verify(ctx->key, ctx->mu, msg, msg_len,
+ ctx->context_string, ctx->context_string_len,
+ ctx->msg_encode, sig, siglen);
+}
+static int ml_dsa_digest_verify(void *vctx,
+ const uint8_t *sig, size_t siglen,
+ const uint8_t *tbs, size_t tbslen)
+{
+ return ml_dsa_verify(vctx, sig, siglen, tbs, tbslen);
+}
+
+static int ml_dsa_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_ML_DSA_CTX *pctx = (PROV_ML_DSA_CTX *)vctx;
+ const OSSL_PARAM *p;
+
+ if (pctx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_CONTEXT_STRING);
+ if (p != NULL) {
+ void *vp = pctx->context_string;
+
+ if (!OSSL_PARAM_get_octet_string(p, &vp, sizeof(pctx->context_string),
+ &(pctx->context_string_len))) {
+ pctx->context_string_len = 0;
+ return 0;
+ }
+ }
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_TEST_ENTROPY);
+ if (p != NULL) {
+ void *vp = pctx->test_entropy;
+
+ pctx->test_entropy_len = 0;
+ if (!OSSL_PARAM_get_octet_string(p, &vp, sizeof(pctx->test_entropy),
+ &(pctx->test_entropy_len)))
+ return 0;
+ if (pctx->test_entropy_len != sizeof(pctx->test_entropy)) {
+ pctx->test_entropy_len = 0;
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH);
+ return 0;
+ }
+ }
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DETERMINISTIC);
+ if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->deterministic))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING);
+ if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->msg_encode))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MU);
+ if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->mu))
+ return 0;
+
+ return 1;
+}
+
+static const OSSL_PARAM *ml_dsa_settable_ctx_params(void *vctx,
+ ossl_unused void *provctx)
+{
+ static const OSSL_PARAM settable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_TEST_ENTROPY, NULL, 0),
+ OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, 0),
+ OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_MU, 0),
+ OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, 0),
+ OSSL_PARAM_END
+ };
+
+ return settable_ctx_params;
+}
+
+static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *ml_dsa_gettable_ctx_params(ossl_unused void *vctx,
+ ossl_unused void *provctx)
+{
+ return known_gettable_ctx_params;
+}
+
+static int ml_dsa_get_ctx_params(void *vctx, OSSL_PARAM *params)
+{
+ PROV_ML_DSA_CTX *ctx = (PROV_ML_DSA_CTX *)vctx;
+ OSSL_PARAM *p;
+
+ if (ctx == NULL)
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
+ if (p != NULL
+ && !OSSL_PARAM_set_octet_string(p,
+ ctx->aid_len == 0 ? NULL : ctx->aid_buf,
+ ctx->aid_len))
+ return 0;
+
+ return 1;
+}
+
+#define MAKE_SIGNATURE_FUNCTIONS(alg) \
+ static OSSL_FUNC_signature_newctx_fn ml_dsa_##alg##_newctx; \
+ static void *ml_dsa_##alg##_newctx(void *provctx, const char *propq) \
+ { \
+ return ml_dsa_newctx(provctx, EVP_PKEY_ML_DSA_##alg, propq); \
+ } \
+ const OSSL_DISPATCH ossl_ml_dsa_##alg##_signature_functions[] = { \
+ { 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, (void (*)(void))ml_dsa_sign }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT, \
+ (void (*)(void))ml_dsa_verify_msg_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))ml_dsa_verify }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \
+ (void (*)(void))ml_dsa_digest_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, \
+ (void (*)(void))ml_dsa_digest_sign }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, \
+ (void (*)(void))ml_dsa_digest_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, \
+ (void (*)(void))ml_dsa_digest_verify }, \
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))ml_dsa_freectx }, \
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \
+ (void (*)(void))ml_dsa_set_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))ml_dsa_settable_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \
+ (void (*)(void))ml_dsa_get_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))ml_dsa_gettable_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))ml_dsa_dupctx }, \
+ OSSL_DISPATCH_END \
+ }
+
+MAKE_SIGNATURE_FUNCTIONS(44);
+MAKE_SIGNATURE_FUNCTIONS(65);
+MAKE_SIGNATURE_FUNCTIONS(87);
diff --git a/crypto/openssl/providers/implementations/signature/rsa_sig.c b/crypto/openssl/providers/implementations/signature/rsa_sig.c
new file mode 100644
index 000000000000..d8357cfe1578
--- /dev/null
+++ b/crypto/openssl/providers/implementations/signature/rsa_sig.c
@@ -0,0 +1,2144 @@
+/*
+ * Copyright 2019-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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * RSA low level APIs are deprecated for public use, but still ok for
+ * internal use.
+ */
+#include "internal/deprecated.h"
+
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/err.h>
+#include <openssl/obj_mac.h>
+#include <openssl/rsa.h>
+#include <openssl/params.h>
+#include <openssl/evp.h>
+#include <openssl/proverr.h>
+#include "internal/cryptlib.h"
+#include "internal/nelem.h"
+#include "internal/sizes.h"
+#include "crypto/rsa.h"
+#include "prov/providercommon.h"
+#include "prov/implementations.h"
+#include "prov/provider_ctx.h"
+#include "prov/der_rsa.h"
+#include "prov/securitycheck.h"
+
+#define RSA_DEFAULT_DIGEST_NAME OSSL_DIGEST_NAME_SHA1
+
+static OSSL_FUNC_signature_newctx_fn rsa_newctx;
+static OSSL_FUNC_signature_sign_init_fn rsa_sign_init;
+static OSSL_FUNC_signature_verify_init_fn rsa_verify_init;
+static OSSL_FUNC_signature_verify_recover_init_fn rsa_verify_recover_init;
+static OSSL_FUNC_signature_sign_fn rsa_sign;
+static OSSL_FUNC_signature_sign_message_update_fn rsa_signverify_message_update;
+static OSSL_FUNC_signature_sign_message_final_fn rsa_sign_message_final;
+static OSSL_FUNC_signature_verify_fn rsa_verify;
+static OSSL_FUNC_signature_verify_recover_fn rsa_verify_recover;
+static OSSL_FUNC_signature_verify_message_update_fn rsa_signverify_message_update;
+static OSSL_FUNC_signature_verify_message_final_fn rsa_verify_message_final;
+static OSSL_FUNC_signature_digest_sign_init_fn rsa_digest_sign_init;
+static OSSL_FUNC_signature_digest_sign_update_fn rsa_digest_sign_update;
+static OSSL_FUNC_signature_digest_sign_final_fn rsa_digest_sign_final;
+static OSSL_FUNC_signature_digest_verify_init_fn rsa_digest_verify_init;
+static OSSL_FUNC_signature_digest_verify_update_fn rsa_digest_verify_update;
+static OSSL_FUNC_signature_digest_verify_final_fn rsa_digest_verify_final;
+static OSSL_FUNC_signature_freectx_fn rsa_freectx;
+static OSSL_FUNC_signature_dupctx_fn rsa_dupctx;
+static OSSL_FUNC_signature_query_key_types_fn rsa_sigalg_query_key_types;
+static OSSL_FUNC_signature_get_ctx_params_fn rsa_get_ctx_params;
+static OSSL_FUNC_signature_gettable_ctx_params_fn rsa_gettable_ctx_params;
+static OSSL_FUNC_signature_set_ctx_params_fn rsa_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn rsa_settable_ctx_params;
+static OSSL_FUNC_signature_get_ctx_md_params_fn rsa_get_ctx_md_params;
+static OSSL_FUNC_signature_gettable_ctx_md_params_fn rsa_gettable_ctx_md_params;
+static OSSL_FUNC_signature_set_ctx_md_params_fn rsa_set_ctx_md_params;
+static OSSL_FUNC_signature_settable_ctx_md_params_fn rsa_settable_ctx_md_params;
+static OSSL_FUNC_signature_set_ctx_params_fn rsa_sigalg_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn rsa_sigalg_settable_ctx_params;
+
+static OSSL_ITEM padding_item[] = {
+ { RSA_PKCS1_PADDING, OSSL_PKEY_RSA_PAD_MODE_PKCSV15 },
+ { RSA_NO_PADDING, OSSL_PKEY_RSA_PAD_MODE_NONE },
+ { RSA_X931_PADDING, OSSL_PKEY_RSA_PAD_MODE_X931 },
+ { RSA_PKCS1_PSS_PADDING, OSSL_PKEY_RSA_PAD_MODE_PSS },
+ { 0, NULL }
+};
+
+/*
+ * What's passed as an actual key is defined by the KEYMGMT interface.
+ * We happen to know that our KEYMGMT simply passes RSA structures, so
+ * we use that here too.
+ */
+
+typedef struct {
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+ RSA *rsa;
+ int operation;
+
+ /*
+ * Flag to determine if a full sigalg is run (1) or if a composable
+ * signature algorithm is run (0).
+ *
+ * When a full sigalg is run (1), this currently affects the following
+ * other flags, which are to remain untouched after their initialization:
+ *
+ * - flag_allow_md (initialized to 0)
+ */
+ unsigned int flag_sigalg : 1;
+ /*
+ * Flag to determine if the hash function can be changed (1) or not (0)
+ * Because it's dangerous to change during a DigestSign or DigestVerify
+ * operation, this flag is cleared by their Init function, and set again
+ * by their Final function.
+ * Implementations of full sigalgs (such as RSA-SHA256) hard-code this
+ * flag to not allow changes (0).
+ */
+ unsigned int flag_allow_md : 1;
+ unsigned int mgf1_md_set : 1;
+ /*
+ * Flags to say what are the possible next external calls in what
+ * consitutes the life cycle of an algorithm. The relevant calls are:
+ * - init
+ * - update
+ * - final
+ * - oneshot
+ * All other external calls are regarded as utilitarian and are allowed
+ * at any time (they may be affected by other flags, like flag_allow_md,
+ * though).
+ */
+ unsigned int flag_allow_update : 1;
+ unsigned int flag_allow_final : 1;
+ unsigned int flag_allow_oneshot : 1;
+
+ /* main digest */
+ EVP_MD *md;
+ EVP_MD_CTX *mdctx;
+ int mdnid;
+ char mdname[OSSL_MAX_NAME_SIZE]; /* Purely informational */
+
+ /* RSA padding mode */
+ int pad_mode;
+ /* message digest for MGF1 */
+ EVP_MD *mgf1_md;
+ int mgf1_mdnid;
+ char mgf1_mdname[OSSL_MAX_NAME_SIZE]; /* Purely informational */
+ /* PSS salt length */
+ int saltlen;
+ /* Minimum salt length or -1 if no PSS parameter restriction */
+ int min_saltlen;
+
+ /* Signature, for verification */
+ unsigned char *sig;
+ size_t siglen;
+
+#ifdef FIPS_MODULE
+ /*
+ * FIPS 140-3 IG 2.4.B mandates that verification based on a digest of a
+ * message is not permitted. However, signing based on a digest is still
+ * permitted.
+ */
+ int verify_message;
+#endif
+
+ /* Temp buffer */
+ unsigned char *tbuf;
+
+ OSSL_FIPS_IND_DECLARE
+} PROV_RSA_CTX;
+
+/* True if PSS parameters are restricted */
+#define rsa_pss_restricted(prsactx) (prsactx->min_saltlen != -1)
+
+static size_t rsa_get_md_size(const PROV_RSA_CTX *prsactx)
+{
+ int md_size;
+
+ if (prsactx->md != NULL) {
+ md_size = EVP_MD_get_size(prsactx->md);
+ if (md_size <= 0)
+ return 0;
+ return md_size;
+ }
+ return 0;
+}
+
+static int rsa_check_padding(const PROV_RSA_CTX *prsactx,
+ const char *mdname, const char *mgf1_mdname,
+ int mdnid)
+{
+ switch (prsactx->pad_mode) {
+ case RSA_NO_PADDING:
+ if (mdname != NULL || mdnid != NID_undef) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE);
+ return 0;
+ }
+ break;
+ case RSA_X931_PADDING:
+ if (RSA_X931_hash_id(mdnid) == -1) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_X931_DIGEST);
+ return 0;
+ }
+ break;
+ case RSA_PKCS1_PSS_PADDING:
+ if (rsa_pss_restricted(prsactx))
+ if ((mdname != NULL && !EVP_MD_is_a(prsactx->md, mdname))
+ || (mgf1_mdname != NULL
+ && !EVP_MD_is_a(prsactx->mgf1_md, mgf1_mdname))) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED);
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+static int rsa_check_parameters(PROV_RSA_CTX *prsactx, int min_saltlen)
+{
+ if (prsactx->pad_mode == RSA_PKCS1_PSS_PADDING) {
+ int max_saltlen;
+
+ /* See if minimum salt length exceeds maximum possible */
+ max_saltlen = RSA_size(prsactx->rsa) - EVP_MD_get_size(prsactx->md);
+ if ((RSA_bits(prsactx->rsa) & 0x7) == 1)
+ max_saltlen--;
+ if (min_saltlen < 0 || min_saltlen > max_saltlen) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH);
+ return 0;
+ }
+ prsactx->min_saltlen = min_saltlen;
+ }
+ return 1;
+}
+
+static void *rsa_newctx(void *provctx, const char *propq)
+{
+ PROV_RSA_CTX *prsactx = NULL;
+ char *propq_copy = NULL;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ if ((prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX))) == NULL
+ || (propq != NULL
+ && (propq_copy = OPENSSL_strdup(propq)) == NULL)) {
+ OPENSSL_free(prsactx);
+ return NULL;
+ }
+
+ OSSL_FIPS_IND_INIT(prsactx)
+ prsactx->libctx = PROV_LIBCTX_OF(provctx);
+ prsactx->flag_allow_md = 1;
+#ifdef FIPS_MODULE
+ prsactx->verify_message = 1;
+#endif
+ prsactx->propq = propq_copy;
+ /* Maximum up to digest length for sign, auto for verify */
+ prsactx->saltlen = RSA_PSS_SALTLEN_AUTO_DIGEST_MAX;
+ prsactx->min_saltlen = -1;
+ return prsactx;
+}
+
+static int rsa_pss_compute_saltlen(PROV_RSA_CTX *ctx)
+{
+ int saltlen = ctx->saltlen;
+ int saltlenMax = -1;
+
+ /* FIPS 186-4 section 5 "The RSA Digital Signature Algorithm", subsection
+ * 5.5 "PKCS #1" says: "For RSASSA-PSS […] the length (in bytes) of the
+ * salt (sLen) shall satisfy 0 <= sLen <= hLen, where hLen is the length of
+ * the hash function output block (in bytes)."
+ *
+ * Provide a way to use at most the digest length, so that the default does
+ * not violate FIPS 186-4. */
+ if (saltlen == RSA_PSS_SALTLEN_DIGEST) {
+ if ((saltlen = EVP_MD_get_size(ctx->md)) <= 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST);
+ return -1;
+ }
+ } else if (saltlen == RSA_PSS_SALTLEN_AUTO_DIGEST_MAX) {
+ saltlen = RSA_PSS_SALTLEN_MAX;
+ if ((saltlenMax = EVP_MD_get_size(ctx->md)) <= 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST);
+ return -1;
+ }
+ }
+ if (saltlen == RSA_PSS_SALTLEN_MAX || saltlen == RSA_PSS_SALTLEN_AUTO) {
+ int mdsize, rsasize;
+
+ if ((mdsize = EVP_MD_get_size(ctx->md)) <= 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST);
+ return -1;
+ }
+ if ((rsasize = RSA_size(ctx->rsa)) <= 2 || rsasize - 2 < mdsize) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY);
+ return -1;
+ }
+ saltlen = rsasize - mdsize - 2;
+ if ((RSA_bits(ctx->rsa) & 0x7) == 1)
+ saltlen--;
+ if (saltlenMax >= 0 && saltlen > saltlenMax)
+ saltlen = saltlenMax;
+ }
+ if (saltlen < 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+ return -1;
+ } else if (saltlen < ctx->min_saltlen) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_PSS_SALTLEN_TOO_SMALL,
+ "minimum salt length: %d, actual salt length: %d",
+ ctx->min_saltlen, saltlen);
+ return -1;
+ }
+ return saltlen;
+}
+
+static unsigned char *rsa_generate_signature_aid(PROV_RSA_CTX *ctx,
+ unsigned char *aid_buf,
+ size_t buf_len,
+ size_t *aid_len)
+{
+ WPACKET pkt;
+ unsigned char *aid = NULL;
+ int saltlen;
+ RSA_PSS_PARAMS_30 pss_params;
+ int ret;
+
+ if (!WPACKET_init_der(&pkt, aid_buf, buf_len)) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_CRYPTO_LIB);
+ return NULL;
+ }
+
+ switch (ctx->pad_mode) {
+ case RSA_PKCS1_PADDING:
+ ret = ossl_DER_w_algorithmIdentifier_MDWithRSAEncryption(&pkt, -1,
+ ctx->mdnid);
+
+ if (ret > 0) {
+ break;
+ } else if (ret == 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+ goto cleanup;
+ }
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_UNSUPPORTED,
+ "Algorithm ID generation - md NID: %d",
+ ctx->mdnid);
+ goto cleanup;
+ case RSA_PKCS1_PSS_PADDING:
+ saltlen = rsa_pss_compute_saltlen(ctx);
+ if (saltlen < 0)
+ goto cleanup;
+ if (!ossl_rsa_pss_params_30_set_defaults(&pss_params)
+ || !ossl_rsa_pss_params_30_set_hashalg(&pss_params, ctx->mdnid)
+ || !ossl_rsa_pss_params_30_set_maskgenhashalg(&pss_params,
+ ctx->mgf1_mdnid)
+ || !ossl_rsa_pss_params_30_set_saltlen(&pss_params, saltlen)
+ || !ossl_DER_w_algorithmIdentifier_RSA_PSS(&pkt, -1,
+ RSA_FLAG_TYPE_RSASSAPSS,
+ &pss_params)) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+ goto cleanup;
+ }
+ break;
+ default:
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_UNSUPPORTED,
+ "Algorithm ID generation - pad mode: %d",
+ ctx->pad_mode);
+ goto cleanup;
+ }
+ if (WPACKET_finish(&pkt)) {
+ WPACKET_get_total_written(&pkt, aid_len);
+ aid = WPACKET_get_curr(&pkt);
+ }
+ cleanup:
+ WPACKET_cleanup(&pkt);
+ return aid;
+}
+
+static int rsa_setup_md(PROV_RSA_CTX *ctx, const char *mdname,
+ const char *mdprops, const char *desc)
+{
+ EVP_MD *md = NULL;
+
+ if (mdprops == NULL)
+ mdprops = ctx->propq;
+
+ if (mdname != NULL) {
+ int md_nid;
+ size_t mdname_len = strlen(mdname);
+
+ md = EVP_MD_fetch(ctx->libctx, mdname, mdprops);
+
+ if (md == NULL) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "%s could not be fetched", mdname);
+ goto err;
+ }
+ md_nid = ossl_digest_rsa_sign_get_md_nid(md);
+ if (md_nid == NID_undef) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED,
+ "digest=%s", mdname);
+ goto err;
+ }
+ /*
+ * XOF digests are not allowed except for RSA PSS.
+ * We don't support XOF digests with RSA PSS (yet), so just fail.
+ * When we do support them, uncomment the second clause.
+ */
+ if (EVP_MD_xof(md)
+ /* && ctx->pad_mode != RSA_PKCS1_PSS_PADDING */) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
+ goto err;
+ }
+#ifdef FIPS_MODULE
+ {
+ int sha1_allowed
+ = ((ctx->operation
+ & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_SIGNMSG)) == 0);
+
+ if (!ossl_fips_ind_digest_sign_check(OSSL_FIPS_IND_GET(ctx),
+ OSSL_FIPS_IND_SETTABLE1,
+ ctx->libctx,
+ md_nid, sha1_allowed, 1, desc,
+ ossl_fips_config_signature_digest_check))
+ goto err;
+ }
+#endif
+
+ if (!rsa_check_padding(ctx, mdname, NULL, md_nid))
+ goto err;
+ if (mdname_len >= sizeof(ctx->mdname)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "%s exceeds name buffer length", mdname);
+ goto err;
+ }
+
+ if (!ctx->flag_allow_md) {
+ if (ctx->mdname[0] != '\0' && !EVP_MD_is_a(md, ctx->mdname)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED,
+ "digest %s != %s", mdname, ctx->mdname);
+ goto err;
+ }
+ EVP_MD_free(md);
+ return 1;
+ }
+
+ if (!ctx->mgf1_md_set) {
+ if (!EVP_MD_up_ref(md)) {
+ goto err;
+ }
+ EVP_MD_free(ctx->mgf1_md);
+ ctx->mgf1_md = md;
+ ctx->mgf1_mdnid = md_nid;
+ OPENSSL_strlcpy(ctx->mgf1_mdname, mdname, sizeof(ctx->mgf1_mdname));
+ }
+
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+
+ ctx->mdctx = NULL;
+ ctx->md = md;
+ ctx->mdnid = md_nid;
+ OPENSSL_strlcpy(ctx->mdname, mdname, sizeof(ctx->mdname));
+ }
+
+ return 1;
+err:
+ EVP_MD_free(md);
+ return 0;
+}
+
+static int rsa_setup_mgf1_md(PROV_RSA_CTX *ctx, const char *mdname,
+ const char *mdprops)
+{
+ size_t len;
+ EVP_MD *md = NULL;
+ int mdnid;
+
+ if (mdprops == NULL)
+ mdprops = ctx->propq;
+
+ if ((md = EVP_MD_fetch(ctx->libctx, mdname, mdprops)) == NULL) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "%s could not be fetched", mdname);
+ return 0;
+ }
+ /* The default for mgf1 is SHA1 - so allow SHA1 */
+ if ((mdnid = ossl_digest_rsa_sign_get_md_nid(md)) <= 0
+ || !rsa_check_padding(ctx, NULL, mdname, mdnid)) {
+ if (mdnid <= 0)
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED,
+ "digest=%s", mdname);
+ EVP_MD_free(md);
+ return 0;
+ }
+ len = OPENSSL_strlcpy(ctx->mgf1_mdname, mdname, sizeof(ctx->mgf1_mdname));
+ if (len >= sizeof(ctx->mgf1_mdname)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "%s exceeds name buffer length", mdname);
+ EVP_MD_free(md);
+ return 0;
+ }
+
+ EVP_MD_free(ctx->mgf1_md);
+ ctx->mgf1_md = md;
+ ctx->mgf1_mdnid = mdnid;
+ ctx->mgf1_md_set = 1;
+ return 1;
+}
+
+static int
+rsa_signverify_init(PROV_RSA_CTX *prsactx, void *vrsa,
+ OSSL_FUNC_signature_set_ctx_params_fn *set_ctx_params,
+ const OSSL_PARAM params[], int operation,
+ const char *desc)
+{
+ int protect;
+
+ if (!ossl_prov_is_running() || prsactx == NULL)
+ return 0;
+
+ if (vrsa == NULL && prsactx->rsa == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
+ return 0;
+ }
+
+ if (vrsa != NULL) {
+ if (!RSA_up_ref(vrsa))
+ return 0;
+ RSA_free(prsactx->rsa);
+ prsactx->rsa = vrsa;
+ }
+ if (!ossl_rsa_key_op_get_protect(prsactx->rsa, operation, &protect))
+ return 0;
+
+ prsactx->operation = operation;
+ prsactx->flag_allow_update = 1;
+ prsactx->flag_allow_final = 1;
+ prsactx->flag_allow_oneshot = 1;
+
+ /* Maximize up to digest length for sign, auto for verify */
+ prsactx->saltlen = RSA_PSS_SALTLEN_AUTO_DIGEST_MAX;
+ prsactx->min_saltlen = -1;
+
+ switch (RSA_test_flags(prsactx->rsa, RSA_FLAG_TYPE_MASK)) {
+ case RSA_FLAG_TYPE_RSA:
+ prsactx->pad_mode = RSA_PKCS1_PADDING;
+ break;
+ case RSA_FLAG_TYPE_RSASSAPSS:
+ prsactx->pad_mode = RSA_PKCS1_PSS_PADDING;
+
+ {
+ const RSA_PSS_PARAMS_30 *pss =
+ ossl_rsa_get0_pss_params_30(prsactx->rsa);
+
+ if (!ossl_rsa_pss_params_30_is_unrestricted(pss)) {
+ int md_nid = ossl_rsa_pss_params_30_hashalg(pss);
+ int mgf1md_nid = ossl_rsa_pss_params_30_maskgenhashalg(pss);
+ int min_saltlen = ossl_rsa_pss_params_30_saltlen(pss);
+ const char *mdname, *mgf1mdname;
+ size_t len;
+
+ mdname = ossl_rsa_oaeppss_nid2name(md_nid);
+ mgf1mdname = ossl_rsa_oaeppss_nid2name(mgf1md_nid);
+
+ if (mdname == NULL) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "PSS restrictions lack hash algorithm");
+ return 0;
+ }
+ if (mgf1mdname == NULL) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "PSS restrictions lack MGF1 hash algorithm");
+ return 0;
+ }
+
+ len = OPENSSL_strlcpy(prsactx->mdname, mdname,
+ sizeof(prsactx->mdname));
+ if (len >= sizeof(prsactx->mdname)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "hash algorithm name too long");
+ return 0;
+ }
+ len = OPENSSL_strlcpy(prsactx->mgf1_mdname, mgf1mdname,
+ sizeof(prsactx->mgf1_mdname));
+ if (len >= sizeof(prsactx->mgf1_mdname)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "MGF1 hash algorithm name too long");
+ return 0;
+ }
+ prsactx->saltlen = min_saltlen;
+
+ /* call rsa_setup_mgf1_md before rsa_setup_md to avoid duplication */
+ if (!rsa_setup_mgf1_md(prsactx, mgf1mdname, prsactx->propq)
+ || !rsa_setup_md(prsactx, mdname, prsactx->propq, desc)
+ || !rsa_check_parameters(prsactx, min_saltlen))
+ return 0;
+ }
+ }
+
+ break;
+ default:
+ ERR_raise(ERR_LIB_RSA, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return 0;
+ }
+
+ OSSL_FIPS_IND_SET_APPROVED(prsactx)
+ if (!set_ctx_params(prsactx, params))
+ return 0;
+#ifdef FIPS_MODULE
+ if (!ossl_fips_ind_rsa_key_check(OSSL_FIPS_IND_GET(prsactx),
+ OSSL_FIPS_IND_SETTABLE0, prsactx->libctx,
+ prsactx->rsa, desc, protect))
+ return 0;
+#endif
+ return 1;
+}
+
+static int setup_tbuf(PROV_RSA_CTX *ctx)
+{
+ if (ctx->tbuf != NULL)
+ return 1;
+ if ((ctx->tbuf = OPENSSL_malloc(RSA_size(ctx->rsa))) == NULL)
+ return 0;
+ return 1;
+}
+
+static void clean_tbuf(PROV_RSA_CTX *ctx)
+{
+ if (ctx->tbuf != NULL)
+ OPENSSL_cleanse(ctx->tbuf, RSA_size(ctx->rsa));
+}
+
+static void free_tbuf(PROV_RSA_CTX *ctx)
+{
+ clean_tbuf(ctx);
+ OPENSSL_free(ctx->tbuf);
+ ctx->tbuf = NULL;
+}
+
+#ifdef FIPS_MODULE
+static int rsa_pss_saltlen_check_passed(PROV_RSA_CTX *ctx, const char *algoname, int saltlen)
+{
+ int mdsize = rsa_get_md_size(ctx);
+ /*
+ * Perform the check if the salt length is compliant to FIPS 186-5.
+ *
+ * According to FIPS 186-5 5.4 (g), the salt length shall be between zero
+ * and the output block length of the digest function (inclusive).
+ */
+ int approved = (saltlen >= 0 && saltlen <= mdsize);
+
+ if (!approved) {
+ if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE3,
+ ctx->libctx,
+ algoname, "PSS Salt Length",
+ ossl_fips_config_rsa_pss_saltlen_check)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+#endif
+
+static int rsa_sign_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[])
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+#ifdef FIPS_MODULE
+ if (prsactx != NULL)
+ prsactx->verify_message = 1;
+#endif
+
+ return rsa_signverify_init(prsactx, vrsa, rsa_set_ctx_params, params,
+ EVP_PKEY_OP_SIGN, "RSA Sign Init");
+}
+
+/*
+ * Sign tbs without digesting it first. This is suitable for "primitive"
+ * signing and signing the digest of a message, i.e. should be used with
+ * implementations of the keytype related algorithms.
+ */
+static int rsa_sign_directly(PROV_RSA_CTX *prsactx,
+ unsigned char *sig, size_t *siglen, size_t sigsize,
+ const unsigned char *tbs, size_t tbslen)
+{
+ int ret;
+ size_t rsasize = RSA_size(prsactx->rsa);
+ size_t mdsize = rsa_get_md_size(prsactx);
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (sig == NULL) {
+ *siglen = rsasize;
+ return 1;
+ }
+
+ if (sigsize < rsasize) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_SIGNATURE_SIZE,
+ "is %zu, should be at least %zu", sigsize, rsasize);
+ return 0;
+ }
+
+ if (mdsize != 0) {
+ if (tbslen != mdsize) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH);
+ return 0;
+ }
+
+#ifndef FIPS_MODULE
+ if (EVP_MD_is_a(prsactx->md, OSSL_DIGEST_NAME_MDC2)) {
+ unsigned int sltmp;
+
+ if (prsactx->pad_mode != RSA_PKCS1_PADDING) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
+ "only PKCS#1 padding supported with MDC2");
+ return 0;
+ }
+ ret = RSA_sign_ASN1_OCTET_STRING(0, tbs, tbslen, sig, &sltmp,
+ prsactx->rsa);
+
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+ ret = sltmp;
+ goto end;
+ }
+#endif
+ switch (prsactx->pad_mode) {
+ case RSA_X931_PADDING:
+ if ((size_t)RSA_size(prsactx->rsa) < tbslen + 1) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL,
+ "RSA key size = %d, expected minimum = %d",
+ RSA_size(prsactx->rsa), tbslen + 1);
+ return 0;
+ }
+ if (!setup_tbuf(prsactx)) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_PROV_LIB);
+ return 0;
+ }
+ memcpy(prsactx->tbuf, tbs, tbslen);
+ prsactx->tbuf[tbslen] = RSA_X931_hash_id(prsactx->mdnid);
+ ret = RSA_private_encrypt(tbslen + 1, prsactx->tbuf,
+ sig, prsactx->rsa, RSA_X931_PADDING);
+ clean_tbuf(prsactx);
+ break;
+ case RSA_PKCS1_PADDING:
+ {
+ unsigned int sltmp;
+
+ ret = RSA_sign(prsactx->mdnid, tbs, tbslen, sig, &sltmp,
+ prsactx->rsa);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+ ret = sltmp;
+ }
+ break;
+
+ case RSA_PKCS1_PSS_PADDING:
+ {
+ int saltlen;
+
+ /* Check PSS restrictions */
+ if (rsa_pss_restricted(prsactx)) {
+ switch (prsactx->saltlen) {
+ case RSA_PSS_SALTLEN_DIGEST:
+ if (prsactx->min_saltlen > EVP_MD_get_size(prsactx->md)) {
+ ERR_raise_data(ERR_LIB_PROV,
+ PROV_R_PSS_SALTLEN_TOO_SMALL,
+ "minimum salt length set to %d, "
+ "but the digest only gives %d",
+ prsactx->min_saltlen,
+ EVP_MD_get_size(prsactx->md));
+ return 0;
+ }
+ /* FALLTHRU */
+ default:
+ if (prsactx->saltlen >= 0
+ && prsactx->saltlen < prsactx->min_saltlen) {
+ ERR_raise_data(ERR_LIB_PROV,
+ PROV_R_PSS_SALTLEN_TOO_SMALL,
+ "minimum salt length set to %d, but the"
+ "actual salt length is only set to %d",
+ prsactx->min_saltlen,
+ prsactx->saltlen);
+ return 0;
+ }
+ break;
+ }
+ }
+ if (!setup_tbuf(prsactx))
+ return 0;
+ saltlen = prsactx->saltlen;
+ if (!ossl_rsa_padding_add_PKCS1_PSS_mgf1(prsactx->rsa,
+ prsactx->tbuf, tbs,
+ prsactx->md, prsactx->mgf1_md,
+ &saltlen)) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+#ifdef FIPS_MODULE
+ if (!rsa_pss_saltlen_check_passed(prsactx, "RSA Sign", saltlen))
+ return 0;
+#endif
+ ret = RSA_private_encrypt(RSA_size(prsactx->rsa), prsactx->tbuf,
+ sig, prsactx->rsa, RSA_NO_PADDING);
+ clean_tbuf(prsactx);
+ }
+ break;
+
+ default:
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
+ "Only X.931, PKCS#1 v1.5 or PSS padding allowed");
+ return 0;
+ }
+ } else {
+ ret = RSA_private_encrypt(tbslen, tbs, sig, prsactx->rsa,
+ prsactx->pad_mode);
+ }
+
+#ifndef FIPS_MODULE
+ end:
+#endif
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+
+ *siglen = ret;
+ return 1;
+}
+
+static int rsa_signverify_message_update(void *vprsactx,
+ const unsigned char *data,
+ size_t datalen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx == NULL || prsactx->mdctx == NULL)
+ return 0;
+
+ if (!prsactx->flag_allow_update) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_UPDATE_CALL_OUT_OF_ORDER);
+ return 0;
+ }
+ prsactx->flag_allow_oneshot = 0;
+
+ return EVP_DigestUpdate(prsactx->mdctx, data, datalen);
+}
+
+static int rsa_sign_message_final(void *vprsactx, unsigned char *sig,
+ size_t *siglen, size_t sigsize)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (!ossl_prov_is_running() || prsactx == NULL)
+ return 0;
+ if (prsactx->mdctx == NULL)
+ return 0;
+ if (!prsactx->flag_allow_final) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FINAL_CALL_OUT_OF_ORDER);
+ return 0;
+ }
+
+ /*
+ * If sig is NULL then we're just finding out the sig size. Other fields
+ * are ignored. Defer to rsa_sign.
+ */
+ if (sig != NULL) {
+ /*
+ * The digests used here are all known (see rsa_get_md_nid()), so they
+ * should not exceed the internal buffer size of EVP_MAX_MD_SIZE.
+ */
+ if (!EVP_DigestFinal_ex(prsactx->mdctx, digest, &dlen))
+ return 0;
+
+ prsactx->flag_allow_update = 0;
+ prsactx->flag_allow_oneshot = 0;
+ prsactx->flag_allow_final = 0;
+ }
+
+ return rsa_sign_directly(prsactx, sig, siglen, sigsize, digest, dlen);
+}
+
+/*
+ * If signing a message, digest tbs and sign the result.
+ * Otherwise, sign tbs directly.
+ */
+static int rsa_sign(void *vprsactx, unsigned char *sig, size_t *siglen,
+ size_t sigsize, const unsigned char *tbs, size_t tbslen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (!ossl_prov_is_running() || prsactx == NULL)
+ return 0;
+ if (!prsactx->flag_allow_oneshot) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_ONESHOT_CALL_OUT_OF_ORDER);
+ return 0;
+ }
+
+ if (prsactx->operation == EVP_PKEY_OP_SIGNMSG) {
+ /*
+ * If |sig| is NULL, the caller is only looking for the sig length.
+ * DO NOT update the input in this case.
+ */
+ if (sig == NULL)
+ return rsa_sign_message_final(prsactx, sig, siglen, sigsize);
+
+ return rsa_signverify_message_update(prsactx, tbs, tbslen)
+ && rsa_sign_message_final(prsactx, sig, siglen, sigsize);
+ }
+ return rsa_sign_directly(prsactx, sig, siglen, sigsize, tbs, tbslen);
+}
+
+static int rsa_verify_recover_init(void *vprsactx, void *vrsa,
+ const OSSL_PARAM params[])
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+#ifdef FIPS_MODULE
+ if (prsactx != NULL)
+ prsactx->verify_message = 0;
+#endif
+
+ return rsa_signverify_init(prsactx, vrsa, rsa_set_ctx_params, params,
+ EVP_PKEY_OP_VERIFYRECOVER, "RSA VerifyRecover Init");
+}
+
+/*
+ * There is no message variant of verify recover, so no need for
+ * 'rsa_verify_recover_directly', just use this function, er, directly.
+ */
+static int rsa_verify_recover(void *vprsactx,
+ unsigned char *rout, size_t *routlen,
+ size_t routsize,
+ const unsigned char *sig, size_t siglen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ int ret;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (rout == NULL) {
+ *routlen = RSA_size(prsactx->rsa);
+ return 1;
+ }
+
+ if (prsactx->md != NULL) {
+ switch (prsactx->pad_mode) {
+ case RSA_X931_PADDING:
+ if (!setup_tbuf(prsactx))
+ return 0;
+ ret = RSA_public_decrypt(siglen, sig, prsactx->tbuf, prsactx->rsa,
+ RSA_X931_PADDING);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+ ret--;
+ if (prsactx->tbuf[ret] != RSA_X931_hash_id(prsactx->mdnid)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_ALGORITHM_MISMATCH);
+ return 0;
+ }
+ if (ret != EVP_MD_get_size(prsactx->md)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH,
+ "Should be %d, but got %d",
+ EVP_MD_get_size(prsactx->md), ret);
+ return 0;
+ }
+
+ *routlen = ret;
+ if (rout != prsactx->tbuf) {
+ if (routsize < (size_t)ret) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
+ "buffer size is %d, should be %d",
+ routsize, ret);
+ return 0;
+ }
+ memcpy(rout, prsactx->tbuf, ret);
+ }
+ break;
+
+ case RSA_PKCS1_PADDING:
+ {
+ size_t sltmp;
+
+ ret = ossl_rsa_verify(prsactx->mdnid, NULL, 0, rout, &sltmp,
+ sig, siglen, prsactx->rsa);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+ ret = sltmp;
+ }
+ break;
+
+ default:
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
+ "Only X.931 or PKCS#1 v1.5 padding allowed");
+ return 0;
+ }
+ } else {
+ ret = RSA_public_decrypt(siglen, sig, rout, prsactx->rsa,
+ prsactx->pad_mode);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+ }
+ *routlen = ret;
+ return 1;
+}
+
+static int rsa_verify_init(void *vprsactx, void *vrsa,
+ const OSSL_PARAM params[])
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+#ifdef FIPS_MODULE
+ if (prsactx != NULL)
+ prsactx->verify_message = 0;
+#endif
+
+ return rsa_signverify_init(prsactx, vrsa, rsa_set_ctx_params, params,
+ EVP_PKEY_OP_VERIFY, "RSA Verify Init");
+}
+
+static int rsa_verify_directly(PROV_RSA_CTX *prsactx,
+ const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ size_t rslen;
+
+ if (!ossl_prov_is_running())
+ return 0;
+ if (prsactx->md != NULL) {
+ switch (prsactx->pad_mode) {
+ case RSA_PKCS1_PADDING:
+ if (!RSA_verify(prsactx->mdnid, tbs, tbslen, sig, siglen,
+ prsactx->rsa)) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+ return 1;
+ case RSA_X931_PADDING:
+ if (!setup_tbuf(prsactx))
+ return 0;
+ if (rsa_verify_recover(prsactx, prsactx->tbuf, &rslen, 0,
+ sig, siglen) <= 0)
+ return 0;
+ break;
+ case RSA_PKCS1_PSS_PADDING:
+ {
+ int ret;
+ int saltlen;
+ size_t mdsize;
+
+ /*
+ * We need to check this for the RSA_verify_PKCS1_PSS_mgf1()
+ * call
+ */
+ mdsize = rsa_get_md_size(prsactx);
+ if (tbslen != mdsize) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST_LENGTH,
+ "Should be %d, but got %d",
+ mdsize, tbslen);
+ return 0;
+ }
+
+ if (!setup_tbuf(prsactx))
+ return 0;
+ ret = RSA_public_decrypt(siglen, sig, prsactx->tbuf,
+ prsactx->rsa, RSA_NO_PADDING);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+ saltlen = prsactx->saltlen;
+ ret = ossl_rsa_verify_PKCS1_PSS_mgf1(prsactx->rsa, tbs,
+ prsactx->md, prsactx->mgf1_md,
+ prsactx->tbuf,
+ &saltlen);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+#ifdef FIPS_MODULE
+ if (!rsa_pss_saltlen_check_passed(prsactx, "RSA Verify", saltlen))
+ return 0;
+#endif
+ return 1;
+ }
+ default:
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_PADDING_MODE,
+ "Only X.931, PKCS#1 v1.5 or PSS padding allowed");
+ return 0;
+ }
+ } else {
+ int ret;
+
+ if (!setup_tbuf(prsactx))
+ return 0;
+ ret = RSA_public_decrypt(siglen, sig, prsactx->tbuf, prsactx->rsa,
+ prsactx->pad_mode);
+ if (ret <= 0) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_RSA_LIB);
+ return 0;
+ }
+ rslen = (size_t)ret;
+ }
+
+ if ((rslen != tbslen) || memcmp(tbs, prsactx->tbuf, rslen))
+ return 0;
+
+ return 1;
+}
+
+static int rsa_verify_set_sig(void *vprsactx,
+ const unsigned char *sig, size_t siglen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ OSSL_PARAM params[2];
+
+ params[0] =
+ OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_SIGNATURE,
+ (unsigned char *)sig, siglen);
+ params[1] = OSSL_PARAM_construct_end();
+ return rsa_sigalg_set_ctx_params(prsactx, params);
+}
+
+static int rsa_verify_message_final(void *vprsactx)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (!ossl_prov_is_running() || prsactx == NULL)
+ return 0;
+ if (prsactx->mdctx == NULL)
+ return 0;
+ if (!prsactx->flag_allow_final) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FINAL_CALL_OUT_OF_ORDER);
+ return 0;
+ }
+
+ /*
+ * The digests used here are all known (see rsa_get_md_nid()), so they
+ * should not exceed the internal buffer size of EVP_MAX_MD_SIZE.
+ */
+ if (!EVP_DigestFinal_ex(prsactx->mdctx, digest, &dlen))
+ return 0;
+
+ prsactx->flag_allow_update = 0;
+ prsactx->flag_allow_final = 0;
+ prsactx->flag_allow_oneshot = 0;
+
+ return rsa_verify_directly(prsactx, prsactx->sig, prsactx->siglen,
+ digest, dlen);
+}
+
+/*
+ * If verifying a message, digest tbs and verify the result.
+ * Otherwise, verify tbs directly.
+ */
+static int rsa_verify(void *vprsactx,
+ const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (!ossl_prov_is_running() || prsactx == NULL)
+ return 0;
+ if (!prsactx->flag_allow_oneshot) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_ONESHOT_CALL_OUT_OF_ORDER);
+ return 0;
+ }
+
+ if (prsactx->operation == EVP_PKEY_OP_VERIFYMSG)
+ return rsa_verify_set_sig(prsactx, sig, siglen)
+ && rsa_signverify_message_update(prsactx, tbs, tbslen)
+ && rsa_verify_message_final(prsactx);
+ return rsa_verify_directly(prsactx, sig, siglen, tbs, tbslen);
+}
+
+/* DigestSign/DigestVerify wrappers */
+
+static int rsa_digest_signverify_init(void *vprsactx, const char *mdname,
+ void *vrsa, const OSSL_PARAM params[],
+ int operation, const char *desc)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+#ifdef FIPS_MODULE
+ if (prsactx != NULL)
+ prsactx->verify_message = 1;
+#endif
+
+ if (!rsa_signverify_init(prsactx, vrsa, rsa_set_ctx_params, params,
+ operation, desc))
+ return 0;
+
+ if (mdname != NULL
+ /* was rsa_setup_md already called in rsa_signverify_init()? */
+ && (mdname[0] == '\0' || OPENSSL_strcasecmp(prsactx->mdname, mdname) != 0)
+ && !rsa_setup_md(prsactx, mdname, prsactx->propq, desc))
+ return 0;
+
+ prsactx->flag_allow_md = 0;
+
+ if (prsactx->mdctx == NULL) {
+ prsactx->mdctx = EVP_MD_CTX_new();
+ if (prsactx->mdctx == NULL)
+ goto error;
+ }
+
+ if (!EVP_DigestInit_ex2(prsactx->mdctx, prsactx->md, params))
+ goto error;
+
+ return 1;
+
+ error:
+ EVP_MD_CTX_free(prsactx->mdctx);
+ prsactx->mdctx = NULL;
+ return 0;
+}
+
+static int rsa_digest_sign_init(void *vprsactx, const char *mdname,
+ void *vrsa, const OSSL_PARAM params[])
+{
+ if (!ossl_prov_is_running())
+ return 0;
+ return rsa_digest_signverify_init(vprsactx, mdname, vrsa,
+ params, EVP_PKEY_OP_SIGNMSG,
+ "RSA Digest Sign Init");
+}
+
+static int rsa_digest_sign_update(void *vprsactx, const unsigned char *data,
+ size_t datalen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx == NULL)
+ return 0;
+ /* Sigalg implementations shouldn't do digest_sign */
+ if (prsactx->flag_sigalg)
+ return 0;
+
+ return rsa_signverify_message_update(prsactx, data, datalen);
+}
+
+static int rsa_digest_sign_final(void *vprsactx, unsigned char *sig,
+ size_t *siglen, size_t sigsize)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ int ok = 0;
+
+ if (prsactx == NULL)
+ return 0;
+ /* Sigalg implementations shouldn't do digest_sign */
+ if (prsactx->flag_sigalg)
+ return 0;
+
+ if (rsa_sign_message_final(prsactx, sig, siglen, sigsize))
+ ok = 1;
+
+ prsactx->flag_allow_md = 1;
+
+ return ok;
+}
+
+static int rsa_digest_verify_init(void *vprsactx, const char *mdname,
+ void *vrsa, const OSSL_PARAM params[])
+{
+ if (!ossl_prov_is_running())
+ return 0;
+ return rsa_digest_signverify_init(vprsactx, mdname, vrsa,
+ params, EVP_PKEY_OP_VERIFYMSG,
+ "RSA Digest Verify Init");
+}
+
+static int rsa_digest_verify_update(void *vprsactx, const unsigned char *data,
+ size_t datalen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx == NULL)
+ return 0;
+ /* Sigalg implementations shouldn't do digest_sign */
+ if (prsactx->flag_sigalg)
+ return 0;
+
+ return rsa_signverify_message_update(prsactx, data, datalen);
+}
+
+int rsa_digest_verify_final(void *vprsactx, const unsigned char *sig,
+ size_t siglen)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ int ok = 0;
+
+ if (prsactx == NULL)
+ return 0;
+ /* Sigalg implementations shouldn't do digest_verify */
+ if (prsactx->flag_sigalg)
+ return 0;
+
+ if (rsa_verify_set_sig(prsactx, sig, siglen)
+ && rsa_verify_message_final(vprsactx))
+ ok = 1;
+
+ prsactx->flag_allow_md = 1;
+
+ return ok;
+}
+
+static void rsa_freectx(void *vprsactx)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx == NULL)
+ return;
+
+ EVP_MD_CTX_free(prsactx->mdctx);
+ EVP_MD_free(prsactx->md);
+ EVP_MD_free(prsactx->mgf1_md);
+ OPENSSL_free(prsactx->sig);
+ OPENSSL_free(prsactx->propq);
+ free_tbuf(prsactx);
+ RSA_free(prsactx->rsa);
+
+ OPENSSL_clear_free(prsactx, sizeof(*prsactx));
+}
+
+static void *rsa_dupctx(void *vprsactx)
+{
+ PROV_RSA_CTX *srcctx = (PROV_RSA_CTX *)vprsactx;
+ PROV_RSA_CTX *dstctx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+ if (dstctx == NULL)
+ return NULL;
+
+ *dstctx = *srcctx;
+ dstctx->rsa = NULL;
+ dstctx->md = NULL;
+ dstctx->mgf1_md = NULL;
+ dstctx->mdctx = NULL;
+ dstctx->tbuf = NULL;
+ dstctx->propq = NULL;
+
+ if (srcctx->rsa != NULL && !RSA_up_ref(srcctx->rsa))
+ goto err;
+ dstctx->rsa = srcctx->rsa;
+
+ if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md))
+ goto err;
+ dstctx->md = srcctx->md;
+
+ if (srcctx->mgf1_md != NULL && !EVP_MD_up_ref(srcctx->mgf1_md))
+ goto err;
+ dstctx->mgf1_md = srcctx->mgf1_md;
+
+ if (srcctx->mdctx != NULL) {
+ dstctx->mdctx = EVP_MD_CTX_new();
+ if (dstctx->mdctx == NULL
+ || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx))
+ goto err;
+ }
+
+ if (srcctx->propq != NULL) {
+ dstctx->propq = OPENSSL_strdup(srcctx->propq);
+ if (dstctx->propq == NULL)
+ goto err;
+ }
+
+ return dstctx;
+ err:
+ rsa_freectx(dstctx);
+ return NULL;
+}
+
+static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ OSSL_PARAM *p;
+
+ if (prsactx == NULL)
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
+ if (p != NULL) {
+ /* The Algorithm Identifier of the combined signature algorithm */
+ unsigned char aid_buf[128];
+ unsigned char *aid;
+ size_t aid_len;
+
+ aid = rsa_generate_signature_aid(prsactx, aid_buf,
+ sizeof(aid_buf), &aid_len);
+ if (aid == NULL || !OSSL_PARAM_set_octet_string(p, aid, aid_len))
+ return 0;
+ }
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PAD_MODE);
+ if (p != NULL)
+ switch (p->data_type) {
+ case OSSL_PARAM_INTEGER:
+ if (!OSSL_PARAM_set_int(p, prsactx->pad_mode))
+ return 0;
+ break;
+ case OSSL_PARAM_UTF8_STRING:
+ {
+ int i;
+ const char *word = NULL;
+
+ for (i = 0; padding_item[i].id != 0; i++) {
+ if (prsactx->pad_mode == (int)padding_item[i].id) {
+ word = padding_item[i].ptr;
+ break;
+ }
+ }
+
+ if (word != NULL) {
+ if (!OSSL_PARAM_set_utf8_string(p, word))
+ return 0;
+ } else {
+ ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+ }
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->mdname))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_MGF1_DIGEST);
+ if (p != NULL && !OSSL_PARAM_set_utf8_string(p, prsactx->mgf1_mdname))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN);
+ if (p != NULL) {
+ if (p->data_type == OSSL_PARAM_INTEGER) {
+ if (!OSSL_PARAM_set_int(p, prsactx->saltlen))
+ return 0;
+ } else if (p->data_type == OSSL_PARAM_UTF8_STRING) {
+ const char *value = NULL;
+
+ switch (prsactx->saltlen) {
+ case RSA_PSS_SALTLEN_DIGEST:
+ value = OSSL_PKEY_RSA_PSS_SALT_LEN_DIGEST;
+ break;
+ case RSA_PSS_SALTLEN_MAX:
+ value = OSSL_PKEY_RSA_PSS_SALT_LEN_MAX;
+ break;
+ case RSA_PSS_SALTLEN_AUTO:
+ value = OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO;
+ break;
+ case RSA_PSS_SALTLEN_AUTO_DIGEST_MAX:
+ value = OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX;
+ break;
+ default:
+ {
+ int len = BIO_snprintf(p->data, p->data_size, "%d",
+ prsactx->saltlen);
+
+ if (len <= 0)
+ return 0;
+ p->return_size = len;
+ break;
+ }
+ }
+ if (value != NULL
+ && !OSSL_PARAM_set_utf8_string(p, value))
+ return 0;
+ }
+ }
+
+#ifdef FIPS_MODULE
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_FIPS_VERIFY_MESSAGE);
+ if (p != NULL && !OSSL_PARAM_set_uint(p, prsactx->verify_message))
+ return 0;
+#endif
+
+ if (!OSSL_FIPS_IND_GET_CTX_PARAM(prsactx, params))
+ return 0;
+ return 1;
+}
+
+static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0),
+#ifdef FIPS_MODULE
+ OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_FIPS_VERIFY_MESSAGE, NULL),
+#endif
+ OSSL_FIPS_IND_GETTABLE_CTX_PARAM()
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *rsa_gettable_ctx_params(ossl_unused void *vprsactx,
+ ossl_unused void *provctx)
+{
+ return known_gettable_ctx_params;
+}
+
+#ifdef FIPS_MODULE
+static int rsa_x931_padding_allowed(PROV_RSA_CTX *ctx)
+{
+ int approved = ((ctx->operation & EVP_PKEY_OP_SIGN) == 0);
+
+ if (!approved) {
+ if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE2,
+ ctx->libctx,
+ "RSA Sign set ctx", "X931 Padding",
+ ossl_fips_config_rsa_sign_x931_disallowed)) {
+ ERR_raise(ERR_LIB_PROV,
+ PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE);
+ return 0;
+ }
+ }
+ return 1;
+}
+#endif
+
+static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ const OSSL_PARAM *p;
+ int pad_mode;
+ int saltlen;
+ char mdname[OSSL_MAX_NAME_SIZE] = "", *pmdname = NULL;
+ char mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmdprops = NULL;
+ char mgf1mdname[OSSL_MAX_NAME_SIZE] = "", *pmgf1mdname = NULL;
+ char mgf1mdprops[OSSL_MAX_PROPQUERY_SIZE] = "", *pmgf1mdprops = NULL;
+
+ if (prsactx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ if (!OSSL_FIPS_IND_SET_CTX_PARAM(prsactx, OSSL_FIPS_IND_SETTABLE0, params,
+ OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK))
+ return 0;
+
+ if (!OSSL_FIPS_IND_SET_CTX_PARAM(prsactx, OSSL_FIPS_IND_SETTABLE1, params,
+ OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK))
+ return 0;
+
+ if (!OSSL_FIPS_IND_SET_CTX_PARAM(prsactx, OSSL_FIPS_IND_SETTABLE2, params,
+ OSSL_SIGNATURE_PARAM_FIPS_SIGN_X931_PAD_CHECK))
+ return 0;
+
+ if (!OSSL_FIPS_IND_SET_CTX_PARAM(prsactx, OSSL_FIPS_IND_SETTABLE3, params,
+ OSSL_SIGNATURE_PARAM_FIPS_RSA_PSS_SALTLEN_CHECK))
+ return 0;
+
+ pad_mode = prsactx->pad_mode;
+ saltlen = prsactx->saltlen;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ if (p != NULL) {
+ const OSSL_PARAM *propsp =
+ OSSL_PARAM_locate_const(params,
+ OSSL_SIGNATURE_PARAM_PROPERTIES);
+
+ pmdname = mdname;
+ if (!OSSL_PARAM_get_utf8_string(p, &pmdname, sizeof(mdname)))
+ return 0;
+
+ if (propsp != NULL) {
+ pmdprops = mdprops;
+ if (!OSSL_PARAM_get_utf8_string(propsp,
+ &pmdprops, sizeof(mdprops)))
+ return 0;
+ }
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PAD_MODE);
+ if (p != NULL) {
+ const char *err_extra_text = NULL;
+
+ switch (p->data_type) {
+ case OSSL_PARAM_INTEGER: /* Support for legacy pad mode number */
+ if (!OSSL_PARAM_get_int(p, &pad_mode))
+ return 0;
+ break;
+ case OSSL_PARAM_UTF8_STRING:
+ {
+ int i;
+
+ if (p->data == NULL)
+ return 0;
+
+ for (i = 0; padding_item[i].id != 0; i++) {
+ if (strcmp(p->data, padding_item[i].ptr) == 0) {
+ pad_mode = padding_item[i].id;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ switch (pad_mode) {
+ case RSA_PKCS1_OAEP_PADDING:
+ /*
+ * OAEP padding is for asymmetric cipher only so is not compatible
+ * with signature use.
+ */
+ err_extra_text = "OAEP padding not allowed for signing / verifying";
+ goto bad_pad;
+ case RSA_PKCS1_PSS_PADDING:
+ if ((prsactx->operation
+ & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_SIGNMSG
+ | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYMSG)) == 0) {
+ err_extra_text =
+ "PSS padding only allowed for sign and verify operations";
+ goto bad_pad;
+ }
+ break;
+ case RSA_PKCS1_PADDING:
+ err_extra_text = "PKCS#1 padding not allowed with RSA-PSS";
+ goto cont;
+ case RSA_NO_PADDING:
+ err_extra_text = "No padding not allowed with RSA-PSS";
+ goto cont;
+ case RSA_X931_PADDING:
+#ifdef FIPS_MODULE
+ /* X9.31 only allows sizes of 1024 + 256 * s (bits) */
+ if ((RSA_bits(prsactx->rsa) & 0xFF) != 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ /* RSA Signing with X9.31 padding is not allowed in FIPS 140-3 */
+ if (!rsa_x931_padding_allowed(prsactx))
+ return 0;
+#endif
+ err_extra_text = "X.931 padding not allowed with RSA-PSS";
+ cont:
+ if (RSA_test_flags(prsactx->rsa,
+ RSA_FLAG_TYPE_MASK) == RSA_FLAG_TYPE_RSA)
+ break;
+ /* FALLTHRU */
+ default:
+ bad_pad:
+ if (err_extra_text == NULL)
+ ERR_raise(ERR_LIB_PROV,
+ PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE);
+ else
+ ERR_raise_data(ERR_LIB_PROV,
+ PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE,
+ err_extra_text);
+ return 0;
+ }
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN);
+ if (p != NULL) {
+ if (pad_mode != RSA_PKCS1_PSS_PADDING) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED,
+ "PSS saltlen can only be specified if "
+ "PSS padding has been specified first");
+ return 0;
+ }
+
+ switch (p->data_type) {
+ case OSSL_PARAM_INTEGER: /* Support for legacy pad mode number */
+ if (!OSSL_PARAM_get_int(p, &saltlen))
+ return 0;
+ break;
+ case OSSL_PARAM_UTF8_STRING:
+ if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_DIGEST) == 0)
+ saltlen = RSA_PSS_SALTLEN_DIGEST;
+ else if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_MAX) == 0)
+ saltlen = RSA_PSS_SALTLEN_MAX;
+ else if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO) == 0)
+ saltlen = RSA_PSS_SALTLEN_AUTO;
+ else if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX) == 0)
+ saltlen = RSA_PSS_SALTLEN_AUTO_DIGEST_MAX;
+ else
+ saltlen = atoi(p->data);
+ break;
+ default:
+ return 0;
+ }
+
+ /*
+ * RSA_PSS_SALTLEN_AUTO_DIGEST_MAX seems curiously named in this check.
+ * Contrary to what it's name suggests, it's the currently lowest
+ * saltlen number possible.
+ */
+ if (saltlen < RSA_PSS_SALTLEN_AUTO_DIGEST_MAX) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH);
+ return 0;
+ }
+
+ if (rsa_pss_restricted(prsactx)) {
+ switch (saltlen) {
+ case RSA_PSS_SALTLEN_AUTO:
+ case RSA_PSS_SALTLEN_AUTO_DIGEST_MAX:
+ if ((prsactx->operation
+ & (EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYMSG)) == 0) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH,
+ "Cannot use autodetected salt length");
+ return 0;
+ }
+ break;
+ case RSA_PSS_SALTLEN_DIGEST:
+ if (prsactx->min_saltlen > EVP_MD_get_size(prsactx->md)) {
+ ERR_raise_data(ERR_LIB_PROV,
+ PROV_R_PSS_SALTLEN_TOO_SMALL,
+ "Should be more than %d, but would be "
+ "set to match digest size (%d)",
+ prsactx->min_saltlen,
+ EVP_MD_get_size(prsactx->md));
+ return 0;
+ }
+ break;
+ default:
+ if (saltlen >= 0 && saltlen < prsactx->min_saltlen) {
+ ERR_raise_data(ERR_LIB_PROV,
+ PROV_R_PSS_SALTLEN_TOO_SMALL,
+ "Should be more than %d, "
+ "but would be set to %d",
+ prsactx->min_saltlen, saltlen);
+ return 0;
+ }
+ }
+ }
+ }
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MGF1_DIGEST);
+ if (p != NULL) {
+ const OSSL_PARAM *propsp =
+ OSSL_PARAM_locate_const(params,
+ OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES);
+
+ pmgf1mdname = mgf1mdname;
+ if (!OSSL_PARAM_get_utf8_string(p, &pmgf1mdname, sizeof(mgf1mdname)))
+ return 0;
+
+ if (propsp != NULL) {
+ pmgf1mdprops = mgf1mdprops;
+ if (!OSSL_PARAM_get_utf8_string(propsp,
+ &pmgf1mdprops, sizeof(mgf1mdprops)))
+ return 0;
+ }
+
+ if (pad_mode != RSA_PKCS1_PSS_PADDING) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MGF1_MD);
+ return 0;
+ }
+ }
+
+ prsactx->saltlen = saltlen;
+ prsactx->pad_mode = pad_mode;
+
+ if (prsactx->md == NULL && pmdname == NULL
+ && pad_mode == RSA_PKCS1_PSS_PADDING)
+ pmdname = RSA_DEFAULT_DIGEST_NAME;
+
+ if (pmgf1mdname != NULL
+ && !rsa_setup_mgf1_md(prsactx, pmgf1mdname, pmgf1mdprops))
+ return 0;
+
+ if (pmdname != NULL) {
+ if (!rsa_setup_md(prsactx, pmdname, pmdprops, "RSA Sign Set Ctx"))
+ return 0;
+ } else {
+ if (!rsa_check_padding(prsactx, NULL, NULL, prsactx->mdnid))
+ return 0;
+ }
+ return 1;
+}
+
+static const OSSL_PARAM settable_ctx_params[] = {
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0),
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK)
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK)
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_RSA_PSS_SALTLEN_CHECK)
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_SIGN_X931_PAD_CHECK)
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM settable_ctx_params_no_digest[] = {
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_PROPERTIES, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0),
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_KEY_CHECK)
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_DIGEST_CHECK)
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_RSA_PSS_SALTLEN_CHECK)
+ OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_SIGNATURE_PARAM_FIPS_SIGN_X931_PAD_CHECK)
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *rsa_settable_ctx_params(void *vprsactx,
+ ossl_unused void *provctx)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx != NULL && !prsactx->flag_allow_md)
+ return settable_ctx_params_no_digest;
+ return settable_ctx_params;
+}
+
+static int rsa_get_ctx_md_params(void *vprsactx, OSSL_PARAM *params)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx->mdctx == NULL)
+ return 0;
+
+ return EVP_MD_CTX_get_params(prsactx->mdctx, params);
+}
+
+static const OSSL_PARAM *rsa_gettable_ctx_md_params(void *vprsactx)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx->md == NULL)
+ return 0;
+
+ return EVP_MD_gettable_ctx_params(prsactx->md);
+}
+
+static int rsa_set_ctx_md_params(void *vprsactx, const OSSL_PARAM params[])
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx->mdctx == NULL)
+ return 0;
+
+ return EVP_MD_CTX_set_params(prsactx->mdctx, params);
+}
+
+static const OSSL_PARAM *rsa_settable_ctx_md_params(void *vprsactx)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx->md == NULL)
+ return 0;
+
+ return EVP_MD_settable_ctx_params(prsactx->md);
+}
+
+const OSSL_DISPATCH ossl_rsa_signature_functions[] = {
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))rsa_newctx },
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))rsa_sign_init },
+ { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))rsa_sign },
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))rsa_verify_init },
+ { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))rsa_verify },
+ { OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT,
+ (void (*)(void))rsa_verify_recover_init },
+ { OSSL_FUNC_SIGNATURE_VERIFY_RECOVER,
+ (void (*)(void))rsa_verify_recover },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,
+ (void (*)(void))rsa_digest_sign_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE,
+ (void (*)(void))rsa_digest_sign_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL,
+ (void (*)(void))rsa_digest_sign_final },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT,
+ (void (*)(void))rsa_digest_verify_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE,
+ (void (*)(void))rsa_digest_verify_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL,
+ (void (*)(void))rsa_digest_verify_final },
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))rsa_freectx },
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))rsa_dupctx },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))rsa_get_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,
+ (void (*)(void))rsa_gettable_ctx_params },
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))rsa_set_ctx_params },
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
+ (void (*)(void))rsa_settable_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS,
+ (void (*)(void))rsa_get_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS,
+ (void (*)(void))rsa_gettable_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS,
+ (void (*)(void))rsa_set_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS,
+ (void (*)(void))rsa_settable_ctx_md_params },
+ OSSL_DISPATCH_END
+};
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * So called sigalgs (composite RSA+hash) implemented below. They
+ * are pretty much hard coded, and rely on the hash implementation
+ * being available as per what OPENSSL_NO_ macros allow.
+ */
+
+static OSSL_FUNC_signature_query_key_types_fn rsa_sigalg_query_key_types;
+static OSSL_FUNC_signature_settable_ctx_params_fn rsa_sigalg_settable_ctx_params;
+static OSSL_FUNC_signature_set_ctx_params_fn rsa_sigalg_set_ctx_params;
+
+/*
+ * rsa_sigalg_signverify_init() is almost like rsa_digest_signverify_init(),
+ * just doesn't allow fetching an MD from whatever the user chooses.
+ */
+static int rsa_sigalg_signverify_init(void *vprsactx, void *vrsa,
+ OSSL_FUNC_signature_set_ctx_params_fn *set_ctx_params,
+ const OSSL_PARAM params[],
+ const char *mdname,
+ int operation, int pad_mode,
+ const char *desc)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (!rsa_signverify_init(prsactx, vrsa, set_ctx_params, params, operation,
+ desc))
+ return 0;
+
+ /* PSS is currently not supported as a sigalg */
+ if (prsactx->pad_mode == RSA_PKCS1_PSS_PADDING) {
+ ERR_raise(ERR_LIB_RSA, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return 0;
+ }
+
+ if (!rsa_setup_md(prsactx, mdname, NULL, desc))
+ return 0;
+
+ prsactx->pad_mode = pad_mode;
+ prsactx->flag_sigalg = 1;
+ prsactx->flag_allow_md = 0;
+
+ if (prsactx->mdctx == NULL) {
+ prsactx->mdctx = EVP_MD_CTX_new();
+ if (prsactx->mdctx == NULL)
+ goto error;
+ }
+
+ if (!EVP_DigestInit_ex2(prsactx->mdctx, prsactx->md, params))
+ goto error;
+
+ return 1;
+
+ error:
+ EVP_MD_CTX_free(prsactx->mdctx);
+ prsactx->mdctx = NULL;
+ return 0;
+}
+
+static const char **rsa_sigalg_query_key_types(void)
+{
+ static const char *keytypes[] = { "RSA", NULL };
+
+ return keytypes;
+}
+
+static const OSSL_PARAM settable_sigalg_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_SIGNATURE, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *rsa_sigalg_settable_ctx_params(void *vprsactx,
+ ossl_unused void *provctx)
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+
+ if (prsactx != NULL && prsactx->operation == EVP_PKEY_OP_VERIFYMSG)
+ return settable_sigalg_ctx_params;
+ return NULL;
+}
+
+static int rsa_sigalg_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])
+{
+ PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
+ const OSSL_PARAM *p;
+
+ if (prsactx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ if (prsactx->operation == EVP_PKEY_OP_VERIFYMSG) {
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_SIGNATURE);
+ if (p != NULL) {
+ OPENSSL_free(prsactx->sig);
+ prsactx->sig = NULL;
+ prsactx->siglen = 0;
+ if (!OSSL_PARAM_get_octet_string(p, (void **)&prsactx->sig,
+ 0, &prsactx->siglen))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#define IMPL_RSA_SIGALG(md, MD) \
+ static OSSL_FUNC_signature_sign_init_fn rsa_##md##_sign_init; \
+ static OSSL_FUNC_signature_sign_message_init_fn \
+ rsa_##md##_sign_message_init; \
+ static OSSL_FUNC_signature_verify_init_fn rsa_##md##_verify_init; \
+ static OSSL_FUNC_signature_verify_message_init_fn \
+ rsa_##md##_verify_message_init; \
+ \
+ static int \
+ rsa_##md##_sign_init(void *vprsactx, void *vrsa, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "RSA Sigalg Sign Init"; \
+ \
+ return rsa_sigalg_signverify_init(vprsactx, vrsa, \
+ rsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_SIGN, \
+ RSA_PKCS1_PADDING, \
+ desc); \
+ } \
+ \
+ static int \
+ rsa_##md##_sign_message_init(void *vprsactx, void *vrsa, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "RSA Sigalg Sign Message Init"; \
+ \
+ return rsa_sigalg_signverify_init(vprsactx, vrsa, \
+ rsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_SIGNMSG, \
+ RSA_PKCS1_PADDING, \
+ desc); \
+ } \
+ \
+ static int \
+ rsa_##md##_verify_init(void *vprsactx, void *vrsa, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "RSA Sigalg Verify Init"; \
+ \
+ return rsa_sigalg_signverify_init(vprsactx, vrsa, \
+ rsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_VERIFY, \
+ RSA_PKCS1_PADDING, \
+ desc); \
+ } \
+ \
+ static int \
+ rsa_##md##_verify_recover_init(void *vprsactx, void *vrsa, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "RSA Sigalg Verify Recover Init"; \
+ \
+ return rsa_sigalg_signverify_init(vprsactx, vrsa, \
+ rsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_VERIFYRECOVER, \
+ RSA_PKCS1_PADDING, \
+ desc); \
+ } \
+ \
+ static int \
+ rsa_##md##_verify_message_init(void *vprsactx, void *vrsa, \
+ const OSSL_PARAM params[]) \
+ { \
+ static const char desc[] = "RSA Sigalg Verify Message Init"; \
+ \
+ return rsa_sigalg_signverify_init(vprsactx, vrsa, \
+ rsa_sigalg_set_ctx_params, \
+ params, #MD, \
+ EVP_PKEY_OP_VERIFYMSG, \
+ RSA_PKCS1_PADDING, \
+ desc); \
+ } \
+ \
+ const OSSL_DISPATCH ossl_rsa_##md##_signature_functions[] = { \
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))rsa_newctx }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, \
+ (void (*)(void))rsa_##md##_sign_init }, \
+ { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))rsa_sign }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT, \
+ (void (*)(void))rsa_##md##_sign_message_init }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_UPDATE, \
+ (void (*)(void))rsa_signverify_message_update }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_FINAL, \
+ (void (*)(void))rsa_sign_message_final }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, \
+ (void (*)(void))rsa_##md##_verify_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY, \
+ (void (*)(void))rsa_verify }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT, \
+ (void (*)(void))rsa_##md##_verify_message_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_UPDATE, \
+ (void (*)(void))rsa_signverify_message_update }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_FINAL, \
+ (void (*)(void))rsa_verify_message_final }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT, \
+ (void (*)(void))rsa_##md##_verify_recover_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_RECOVER, \
+ (void (*)(void))rsa_verify_recover }, \
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))rsa_freectx }, \
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))rsa_dupctx }, \
+ { OSSL_FUNC_SIGNATURE_QUERY_KEY_TYPES, \
+ (void (*)(void))rsa_sigalg_query_key_types }, \
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \
+ (void (*)(void))rsa_get_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))rsa_gettable_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \
+ (void (*)(void))rsa_sigalg_set_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))rsa_sigalg_settable_ctx_params }, \
+ OSSL_DISPATCH_END \
+ }
+
+#if !defined(OPENSSL_NO_RMD160) && !defined(FIPS_MODULE)
+IMPL_RSA_SIGALG(ripemd160, RIPEMD160);
+#endif
+IMPL_RSA_SIGALG(sha1, SHA1);
+IMPL_RSA_SIGALG(sha224, SHA2-224);
+IMPL_RSA_SIGALG(sha256, SHA2-256);
+IMPL_RSA_SIGALG(sha384, SHA2-384);
+IMPL_RSA_SIGALG(sha512, SHA2-512);
+IMPL_RSA_SIGALG(sha512_224, SHA2-512/224);
+IMPL_RSA_SIGALG(sha512_256, SHA2-512/256);
+IMPL_RSA_SIGALG(sha3_224, SHA3-224);
+IMPL_RSA_SIGALG(sha3_256, SHA3-256);
+IMPL_RSA_SIGALG(sha3_384, SHA3-384);
+IMPL_RSA_SIGALG(sha3_512, SHA3-512);
+#if !defined(OPENSSL_NO_SM3) && !defined(FIPS_MODULE)
+IMPL_RSA_SIGALG(sm3, SM3);
+#endif
diff --git a/crypto/openssl/providers/implementations/signature/slh_dsa_sig.c b/crypto/openssl/providers/implementations/signature/slh_dsa_sig.c
new file mode 100644
index 000000000000..40fc6846e2ad
--- /dev/null
+++ b/crypto/openssl/providers/implementations/signature/slh_dsa_sig.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2024-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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_names.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/proverr.h>
+#include "prov/implementations.h"
+#include "prov/providercommon.h"
+#include "prov/provider_ctx.h"
+#include "prov/der_slh_dsa.h"
+#include "crypto/slh_dsa.h"
+#include "internal/sizes.h"
+
+#define SLH_DSA_MAX_ADD_RANDOM_LEN 32
+
+#define SLH_DSA_MESSAGE_ENCODE_RAW 0
+#define SLH_DSA_MESSAGE_ENCODE_PURE 1
+
+static OSSL_FUNC_signature_sign_message_init_fn slh_dsa_sign_msg_init;
+static OSSL_FUNC_signature_sign_fn slh_dsa_sign;
+static OSSL_FUNC_signature_verify_message_init_fn slh_dsa_verify_msg_init;
+static OSSL_FUNC_signature_verify_fn slh_dsa_verify;
+static OSSL_FUNC_signature_digest_sign_init_fn slh_dsa_digest_signverify_init;
+static OSSL_FUNC_signature_digest_sign_fn slh_dsa_digest_sign;
+static OSSL_FUNC_signature_digest_verify_fn slh_dsa_digest_verify;
+static OSSL_FUNC_signature_freectx_fn slh_dsa_freectx;
+static OSSL_FUNC_signature_dupctx_fn slh_dsa_dupctx;
+static OSSL_FUNC_signature_set_ctx_params_fn slh_dsa_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn slh_dsa_settable_ctx_params;
+
+/*
+ * NOTE: Any changes to this structure may require updating slh_dsa_dupctx().
+ */
+typedef struct {
+ SLH_DSA_KEY *key; /* Note that the key is not owned by this object */
+ SLH_DSA_HASH_CTX *hash_ctx;
+ uint8_t context_string[SLH_DSA_MAX_CONTEXT_STRING_LEN];
+ size_t context_string_len;
+ uint8_t add_random[SLH_DSA_MAX_ADD_RANDOM_LEN];
+ size_t add_random_len;
+ int msg_encode;
+ int deterministic;
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+ const char *alg;
+ /* The Algorithm Identifier of the signature algorithm */
+ uint8_t aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE];
+ size_t aid_len;
+} PROV_SLH_DSA_CTX;
+
+static void slh_dsa_freectx(void *vctx)
+{
+ PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
+
+ ossl_slh_dsa_hash_ctx_free(ctx->hash_ctx);
+ OPENSSL_free(ctx->propq);
+ OPENSSL_cleanse(ctx->add_random, ctx->add_random_len);
+ OPENSSL_free(ctx);
+}
+
+static void *slh_dsa_newctx(void *provctx, const char *alg, const char *propq)
+{
+ PROV_SLH_DSA_CTX *ctx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ ctx = OPENSSL_zalloc(sizeof(PROV_SLH_DSA_CTX));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->libctx = PROV_LIBCTX_OF(provctx);
+ if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL)
+ goto err;
+ ctx->alg = alg;
+ ctx->msg_encode = SLH_DSA_MESSAGE_ENCODE_PURE;
+ return ctx;
+ err:
+ slh_dsa_freectx(ctx);
+ return NULL;
+}
+
+static void *slh_dsa_dupctx(void *vctx)
+{
+ PROV_SLH_DSA_CTX *src = (PROV_SLH_DSA_CTX *)vctx;
+ PROV_SLH_DSA_CTX *ret;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ /*
+ * Note that the SLH_DSA_KEY is ref counted via EVP_PKEY so we can just copy
+ * the key here.
+ */
+ ret = OPENSSL_memdup(src, sizeof(*src));
+ if (ret == NULL)
+ return NULL;
+ ret->propq = NULL;
+ ret->hash_ctx = NULL;
+ if (src->propq != NULL && (ret->propq = OPENSSL_strdup(src->propq)) == NULL)
+ goto err;
+ ret->hash_ctx = ossl_slh_dsa_hash_ctx_dup(src->hash_ctx);
+ if (ret->hash_ctx == NULL)
+ goto err;
+
+ return ret;
+ err:
+ slh_dsa_freectx(ret);
+ return NULL;
+}
+
+static int slh_dsa_set_alg_id_buffer(PROV_SLH_DSA_CTX *ctx)
+{
+ int ret;
+ WPACKET pkt;
+ uint8_t *aid = NULL;
+
+ /*
+ * We do not care about DER writing errors.
+ * All it really means is that for some reason, there's no
+ * AlgorithmIdentifier to be had, but the operation itself is
+ * still valid, just as long as it's not used to construct
+ * anything that needs an AlgorithmIdentifier.
+ */
+ ctx->aid_len = 0;
+ ret = WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf));
+ ret = ret && ossl_DER_w_algorithmIdentifier_SLH_DSA(&pkt, -1, ctx->key);
+ if (ret && WPACKET_finish(&pkt)) {
+ WPACKET_get_total_written(&pkt, &ctx->aid_len);
+ aid = WPACKET_get_curr(&pkt);
+ }
+ WPACKET_cleanup(&pkt);
+ if (aid != NULL && ctx->aid_len != 0)
+ memmove(ctx->aid_buf, aid, ctx->aid_len);
+ return 1;
+}
+
+static int slh_dsa_signverify_msg_init(void *vctx, void *vkey,
+ const OSSL_PARAM params[], int operation,
+ const char *desc)
+{
+ PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
+ SLH_DSA_KEY *key = vkey;
+
+ if (!ossl_prov_is_running()
+ || ctx == NULL)
+ return 0;
+
+ if (vkey == NULL && ctx->key == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
+ return 0;
+ }
+
+ if (key != NULL) {
+ if (!ossl_slh_dsa_key_type_matches(key, ctx->alg))
+ return 0;
+ ctx->hash_ctx = ossl_slh_dsa_hash_ctx_new(key);
+ if (ctx->hash_ctx == NULL)
+ return 0;
+ ctx->key = vkey;
+ }
+
+ slh_dsa_set_alg_id_buffer(ctx);
+ if (!slh_dsa_set_ctx_params(ctx, params))
+ return 0;
+ return 1;
+}
+
+static int slh_dsa_sign_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[])
+{
+ return slh_dsa_signverify_msg_init(vctx, vkey, params,
+ EVP_PKEY_OP_SIGN, "SLH_DSA Sign Init");
+}
+
+static int slh_dsa_digest_signverify_init(void *vctx, const char *mdname,
+ void *vkey, const OSSL_PARAM params[])
+{
+ PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
+
+ if (mdname != NULL && mdname[0] != '\0') {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST,
+ "Explicit digest not supported for SLH-DSA operations");
+ return 0;
+ }
+
+ if (vkey == NULL && ctx->key != NULL)
+ return slh_dsa_set_ctx_params(ctx, params);
+
+ return slh_dsa_signverify_msg_init(vctx, vkey, params,
+ EVP_PKEY_OP_SIGN, "SLH_DSA Sign Init");
+}
+
+static int slh_dsa_sign(void *vctx, unsigned char *sig, size_t *siglen,
+ size_t sigsize, const unsigned char *msg, size_t msg_len)
+{
+ int ret = 0;
+ PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
+ uint8_t add_rand[SLH_DSA_MAX_ADD_RANDOM_LEN], *opt_rand = NULL;
+ size_t n = 0;
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ if (sig != NULL) {
+ if (ctx->add_random_len != 0) {
+ opt_rand = ctx->add_random;
+ } else if (ctx->deterministic == 0) {
+ n = ossl_slh_dsa_key_get_n(ctx->key);
+ if (RAND_priv_bytes_ex(ctx->libctx, add_rand, n, 0) <= 0)
+ return 0;
+ opt_rand = add_rand;
+ }
+ }
+ ret = ossl_slh_dsa_sign(ctx->hash_ctx, msg, msg_len,
+ ctx->context_string, ctx->context_string_len,
+ opt_rand, ctx->msg_encode,
+ sig, siglen, sigsize);
+ if (opt_rand != add_rand)
+ OPENSSL_cleanse(opt_rand, n);
+ return ret;
+}
+
+static int slh_dsa_digest_sign(void *vctx, uint8_t *sig, size_t *siglen, size_t sigsize,
+ const uint8_t *tbs, size_t tbslen)
+{
+ return slh_dsa_sign(vctx, sig, siglen, sigsize, tbs, tbslen);
+}
+
+static int slh_dsa_verify_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[])
+{
+ return slh_dsa_signverify_msg_init(vctx, vkey, params, EVP_PKEY_OP_VERIFY,
+ "SLH_DSA Verify Init");
+}
+
+static int slh_dsa_verify(void *vctx, const uint8_t *sig, size_t siglen,
+ const uint8_t *msg, size_t msg_len)
+{
+ PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
+
+ if (!ossl_prov_is_running())
+ return 0;
+ return ossl_slh_dsa_verify(ctx->hash_ctx, msg, msg_len,
+ ctx->context_string, ctx->context_string_len,
+ ctx->msg_encode, sig, siglen);
+}
+static int slh_dsa_digest_verify(void *vctx, const uint8_t *sig, size_t siglen,
+ const uint8_t *tbs, size_t tbslen)
+{
+ return slh_dsa_verify(vctx, sig, siglen, tbs, tbslen);
+}
+
+static int slh_dsa_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_SLH_DSA_CTX *pctx = (PROV_SLH_DSA_CTX *)vctx;
+ const OSSL_PARAM *p;
+
+ if (pctx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_CONTEXT_STRING);
+ if (p != NULL) {
+ void *vp = pctx->context_string;
+
+ if (!OSSL_PARAM_get_octet_string(p, &vp, sizeof(pctx->context_string),
+ &(pctx->context_string_len))) {
+ pctx->context_string_len = 0;
+ return 0;
+ }
+ }
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_TEST_ENTROPY);
+ if (p != NULL) {
+ void *vp = pctx->add_random;
+ size_t n = ossl_slh_dsa_key_get_n(pctx->key);
+
+ if (!OSSL_PARAM_get_octet_string(p, &vp, n, &(pctx->add_random_len))
+ || pctx->add_random_len != n) {
+ pctx->add_random_len = 0;
+ return 0;
+ }
+ }
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DETERMINISTIC);
+ if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->deterministic))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING);
+ if (p != NULL && !OSSL_PARAM_get_int(p, &pctx->msg_encode))
+ return 0;
+ return 1;
+}
+
+static const OSSL_PARAM *slh_dsa_settable_ctx_params(void *vctx,
+ ossl_unused void *provctx)
+{
+ static const OSSL_PARAM settable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_TEST_ENTROPY, NULL, 0),
+ OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_DETERMINISTIC, 0),
+ OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_MESSAGE_ENCODING, 0),
+ OSSL_PARAM_END
+ };
+
+ return settable_ctx_params;
+}
+
+static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *slh_dsa_gettable_ctx_params(ossl_unused void *vctx,
+ ossl_unused void *provctx)
+{
+ return known_gettable_ctx_params;
+}
+
+static int slh_dsa_get_ctx_params(void *vctx, OSSL_PARAM *params)
+{
+ PROV_SLH_DSA_CTX *ctx = (PROV_SLH_DSA_CTX *)vctx;
+ OSSL_PARAM *p;
+
+ if (ctx == NULL)
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
+ if (p != NULL
+ && !OSSL_PARAM_set_octet_string(p,
+ ctx->aid_len == 0 ? NULL : ctx->aid_buf,
+ ctx->aid_len))
+ return 0;
+
+ return 1;
+}
+
+#define MAKE_SIGNATURE_FUNCTIONS(alg, fn) \
+ static OSSL_FUNC_signature_newctx_fn slh_dsa_##fn##_newctx; \
+ static void *slh_dsa_##fn##_newctx(void *provctx, const char *propq) \
+ { \
+ return slh_dsa_newctx(provctx, alg, propq); \
+ } \
+ const OSSL_DISPATCH ossl_slh_dsa_##fn##_signature_functions[] = { \
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))slh_dsa_##fn##_newctx }, \
+ { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT, \
+ (void (*)(void))slh_dsa_sign_msg_init }, \
+ { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))slh_dsa_sign }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT, \
+ (void (*)(void))slh_dsa_verify_msg_init }, \
+ { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))slh_dsa_verify }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \
+ (void (*)(void))slh_dsa_digest_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, \
+ (void (*)(void))slh_dsa_digest_sign }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, \
+ (void (*)(void))slh_dsa_digest_signverify_init }, \
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, \
+ (void (*)(void))slh_dsa_digest_verify }, \
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))slh_dsa_freectx }, \
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))slh_dsa_dupctx }, \
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))slh_dsa_set_ctx_params },\
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))slh_dsa_settable_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \
+ (void (*)(void))slh_dsa_get_ctx_params }, \
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))slh_dsa_gettable_ctx_params }, \
+ OSSL_DISPATCH_END \
+ }
+
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-128s", sha2_128s);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-128f", sha2_128f);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-192s", sha2_192s);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-192f", sha2_192f);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-256s", sha2_256s);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHA2-256f", sha2_256f);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-128s", shake_128s);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-128f", shake_128f);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-192s", shake_192s);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-192f", shake_192f);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-256s", shake_256s);
+MAKE_SIGNATURE_FUNCTIONS("SLH-DSA-SHAKE-256f", shake_256f);
diff --git a/crypto/openssl/providers/implementations/signature/sm2_sig.c b/crypto/openssl/providers/implementations/signature/sm2_sig.c
new file mode 100644
index 000000000000..bcbbd1e24503
--- /dev/null
+++ b/crypto/openssl/providers/implementations/signature/sm2_sig.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright 2020-2024 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * ECDSA low level APIs are deprecated for public use, but still ok for
+ * internal use - SM2 implementation uses ECDSA_size() function.
+ */
+#include "internal/deprecated.h"
+
+#include <string.h> /* memcpy */
+#include <openssl/crypto.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/dsa.h>
+#include <openssl/params.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/proverr.h>
+#include "internal/nelem.h"
+#include "internal/sizes.h"
+#include "internal/cryptlib.h"
+#include "internal/sm3.h"
+#include "prov/implementations.h"
+#include "prov/providercommon.h"
+#include "prov/provider_ctx.h"
+#include "crypto/ec.h"
+#include "crypto/sm2.h"
+#include "prov/der_sm2.h"
+
+static OSSL_FUNC_signature_newctx_fn sm2sig_newctx;
+static OSSL_FUNC_signature_sign_init_fn sm2sig_signature_init;
+static OSSL_FUNC_signature_verify_init_fn sm2sig_signature_init;
+static OSSL_FUNC_signature_sign_fn sm2sig_sign;
+static OSSL_FUNC_signature_verify_fn sm2sig_verify;
+static OSSL_FUNC_signature_digest_sign_init_fn sm2sig_digest_signverify_init;
+static OSSL_FUNC_signature_digest_sign_update_fn sm2sig_digest_signverify_update;
+static OSSL_FUNC_signature_digest_sign_final_fn sm2sig_digest_sign_final;
+static OSSL_FUNC_signature_digest_verify_init_fn sm2sig_digest_signverify_init;
+static OSSL_FUNC_signature_digest_verify_update_fn sm2sig_digest_signverify_update;
+static OSSL_FUNC_signature_digest_verify_final_fn sm2sig_digest_verify_final;
+static OSSL_FUNC_signature_freectx_fn sm2sig_freectx;
+static OSSL_FUNC_signature_dupctx_fn sm2sig_dupctx;
+static OSSL_FUNC_signature_get_ctx_params_fn sm2sig_get_ctx_params;
+static OSSL_FUNC_signature_gettable_ctx_params_fn sm2sig_gettable_ctx_params;
+static OSSL_FUNC_signature_set_ctx_params_fn sm2sig_set_ctx_params;
+static OSSL_FUNC_signature_settable_ctx_params_fn sm2sig_settable_ctx_params;
+static OSSL_FUNC_signature_get_ctx_md_params_fn sm2sig_get_ctx_md_params;
+static OSSL_FUNC_signature_gettable_ctx_md_params_fn sm2sig_gettable_ctx_md_params;
+static OSSL_FUNC_signature_set_ctx_md_params_fn sm2sig_set_ctx_md_params;
+static OSSL_FUNC_signature_settable_ctx_md_params_fn sm2sig_settable_ctx_md_params;
+
+/*
+ * What's passed as an actual key is defined by the KEYMGMT interface.
+ * We happen to know that our KEYMGMT simply passes EC structures, so
+ * we use that here too.
+ */
+typedef struct {
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+ EC_KEY *ec;
+
+ /*
+ * Flag to determine if the 'z' digest needs to be computed and fed to the
+ * hash function.
+ * This flag should be set on initialization and the computation should
+ * be performed only once, on first update.
+ */
+ unsigned int flag_compute_z_digest : 1;
+
+ char mdname[OSSL_MAX_NAME_SIZE];
+
+ /* The Algorithm Identifier of the combined signature algorithm */
+ unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE];
+ size_t aid_len;
+
+ /* main digest */
+ EVP_MD *md;
+ EVP_MD_CTX *mdctx;
+ size_t mdsize;
+
+ /* SM2 ID used for calculating the Z value */
+ unsigned char *id;
+ size_t id_len;
+} PROV_SM2_CTX;
+
+static int sm2sig_set_mdname(PROV_SM2_CTX *psm2ctx, const char *mdname)
+{
+ if (psm2ctx->md == NULL) /* We need an SM3 md to compare with */
+ psm2ctx->md = EVP_MD_fetch(psm2ctx->libctx, psm2ctx->mdname,
+ psm2ctx->propq);
+ if (psm2ctx->md == NULL)
+ return 0;
+
+ /* XOF digests don't work */
+ if (EVP_MD_xof(psm2ctx->md)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
+ return 0;
+ }
+
+ if (mdname == NULL)
+ return 1;
+
+ if (strlen(mdname) >= sizeof(psm2ctx->mdname)
+ || !EVP_MD_is_a(psm2ctx->md, mdname)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, "digest=%s",
+ mdname);
+ return 0;
+ }
+
+ OPENSSL_strlcpy(psm2ctx->mdname, mdname, sizeof(psm2ctx->mdname));
+ return 1;
+}
+
+static void *sm2sig_newctx(void *provctx, const char *propq)
+{
+ PROV_SM2_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_SM2_CTX));
+
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->libctx = PROV_LIBCTX_OF(provctx);
+ if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL) {
+ OPENSSL_free(ctx);
+ return NULL;
+ }
+ ctx->mdsize = SM3_DIGEST_LENGTH;
+ strcpy(ctx->mdname, OSSL_DIGEST_NAME_SM3);
+ return ctx;
+}
+
+static int sm2sig_signature_init(void *vpsm2ctx, void *ec,
+ const OSSL_PARAM params[])
+{
+ PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx;
+
+ if (!ossl_prov_is_running()
+ || psm2ctx == NULL)
+ return 0;
+
+ if (ec == NULL && psm2ctx->ec == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
+ return 0;
+ }
+
+ if (ec != NULL) {
+ if (!EC_KEY_up_ref(ec))
+ return 0;
+ EC_KEY_free(psm2ctx->ec);
+ psm2ctx->ec = ec;
+ }
+
+ return sm2sig_set_ctx_params(psm2ctx, params);
+}
+
+static int sm2sig_sign(void *vpsm2ctx, unsigned char *sig, size_t *siglen,
+ size_t sigsize, const unsigned char *tbs, size_t tbslen)
+{
+ PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx;
+ int ret;
+ unsigned int sltmp;
+ /* SM2 uses ECDSA_size as well */
+ size_t ecsize = ECDSA_size(ctx->ec);
+
+ if (sig == NULL) {
+ *siglen = ecsize;
+ return 1;
+ }
+
+ if (sigsize < (size_t)ecsize)
+ return 0;
+
+ if (ctx->mdsize != 0 && tbslen != ctx->mdsize)
+ return 0;
+
+ ret = ossl_sm2_internal_sign(tbs, tbslen, sig, &sltmp, ctx->ec);
+ if (ret <= 0)
+ return 0;
+
+ *siglen = sltmp;
+ return 1;
+}
+
+static int sm2sig_verify(void *vpsm2ctx, const unsigned char *sig, size_t siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx;
+
+ if (ctx->mdsize != 0 && tbslen != ctx->mdsize)
+ return 0;
+
+ return ossl_sm2_internal_verify(tbs, tbslen, sig, siglen, ctx->ec);
+}
+
+static void free_md(PROV_SM2_CTX *ctx)
+{
+ EVP_MD_CTX_free(ctx->mdctx);
+ EVP_MD_free(ctx->md);
+ ctx->mdctx = NULL;
+ ctx->md = NULL;
+}
+
+static int sm2sig_digest_signverify_init(void *vpsm2ctx, const char *mdname,
+ void *ec, const OSSL_PARAM params[])
+{
+ PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx;
+ int md_nid;
+ WPACKET pkt;
+ int ret = 0;
+ unsigned char *aid = NULL;
+
+ if (!sm2sig_signature_init(vpsm2ctx, ec, params)
+ || !sm2sig_set_mdname(ctx, mdname))
+ return ret;
+
+ if (ctx->mdctx == NULL) {
+ ctx->mdctx = EVP_MD_CTX_new();
+ if (ctx->mdctx == NULL)
+ goto error;
+ }
+
+ md_nid = EVP_MD_get_type(ctx->md);
+
+ /*
+ * We do not care about DER writing errors.
+ * All it really means is that for some reason, there's no
+ * AlgorithmIdentifier to be had, but the operation itself is
+ * still valid, just as long as it's not used to construct
+ * anything that needs an AlgorithmIdentifier.
+ */
+ ctx->aid_len = 0;
+ if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf))
+ && ossl_DER_w_algorithmIdentifier_SM2_with_MD(&pkt, -1, ctx->ec, md_nid)
+ && WPACKET_finish(&pkt)) {
+ WPACKET_get_total_written(&pkt, &ctx->aid_len);
+ aid = WPACKET_get_curr(&pkt);
+ }
+ WPACKET_cleanup(&pkt);
+ if (aid != NULL && ctx->aid_len != 0)
+ memmove(ctx->aid_buf, aid, ctx->aid_len);
+
+ if (!EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params))
+ goto error;
+
+ ctx->flag_compute_z_digest = 1;
+
+ ret = 1;
+
+ error:
+ return ret;
+}
+
+static int sm2sig_compute_z_digest(PROV_SM2_CTX *ctx)
+{
+ uint8_t *z = NULL;
+ int ret = 1;
+
+ if (ctx->flag_compute_z_digest) {
+ /* Only do this once */
+ ctx->flag_compute_z_digest = 0;
+
+ if ((z = OPENSSL_zalloc(ctx->mdsize)) == NULL
+ /* get hashed prefix 'z' of tbs message */
+ || !ossl_sm2_compute_z_digest(z, ctx->md, ctx->id, ctx->id_len,
+ ctx->ec)
+ || !EVP_DigestUpdate(ctx->mdctx, z, ctx->mdsize))
+ ret = 0;
+ OPENSSL_free(z);
+ }
+
+ return ret;
+}
+
+int sm2sig_digest_signverify_update(void *vpsm2ctx, const unsigned char *data,
+ size_t datalen)
+{
+ PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx;
+
+ if (psm2ctx == NULL || psm2ctx->mdctx == NULL)
+ return 0;
+
+ return sm2sig_compute_z_digest(psm2ctx)
+ && EVP_DigestUpdate(psm2ctx->mdctx, data, datalen);
+}
+
+int sm2sig_digest_sign_final(void *vpsm2ctx, unsigned char *sig, size_t *siglen,
+ size_t sigsize)
+{
+ PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (psm2ctx == NULL || psm2ctx->mdctx == NULL)
+ return 0;
+
+ /*
+ * If sig is NULL then we're just finding out the sig size. Other fields
+ * are ignored. Defer to sm2sig_sign.
+ */
+ if (sig != NULL) {
+ if (!(sm2sig_compute_z_digest(psm2ctx)
+ && EVP_DigestFinal_ex(psm2ctx->mdctx, digest, &dlen)))
+ return 0;
+ }
+
+ return sm2sig_sign(vpsm2ctx, sig, siglen, sigsize, digest, (size_t)dlen);
+}
+
+
+int sm2sig_digest_verify_final(void *vpsm2ctx, const unsigned char *sig,
+ size_t siglen)
+{
+ PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+ int md_size;
+
+ if (psm2ctx == NULL || psm2ctx->mdctx == NULL)
+ return 0;
+
+ md_size = EVP_MD_get_size(psm2ctx->md);
+ if (md_size <= 0 || md_size > (int)sizeof(digest))
+ return 0;
+
+ if (!(sm2sig_compute_z_digest(psm2ctx)
+ && EVP_DigestFinal_ex(psm2ctx->mdctx, digest, &dlen)))
+ return 0;
+
+ return sm2sig_verify(vpsm2ctx, sig, siglen, digest, (size_t)dlen);
+}
+
+static void sm2sig_freectx(void *vpsm2ctx)
+{
+ PROV_SM2_CTX *ctx = (PROV_SM2_CTX *)vpsm2ctx;
+
+ free_md(ctx);
+ EC_KEY_free(ctx->ec);
+ OPENSSL_free(ctx->propq);
+ OPENSSL_free(ctx->id);
+ OPENSSL_free(ctx);
+}
+
+static void *sm2sig_dupctx(void *vpsm2ctx)
+{
+ PROV_SM2_CTX *srcctx = (PROV_SM2_CTX *)vpsm2ctx;
+ PROV_SM2_CTX *dstctx;
+
+ dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+ if (dstctx == NULL)
+ return NULL;
+
+ *dstctx = *srcctx;
+ dstctx->ec = NULL;
+ dstctx->propq = NULL;
+ dstctx->md = NULL;
+ dstctx->mdctx = NULL;
+ dstctx->id = NULL;
+
+ if (srcctx->ec != NULL && !EC_KEY_up_ref(srcctx->ec))
+ goto err;
+ dstctx->ec = srcctx->ec;
+
+ if (srcctx->propq != NULL) {
+ dstctx->propq = OPENSSL_strdup(srcctx->propq);
+ if (dstctx->propq == NULL)
+ goto err;
+ }
+
+ if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md))
+ goto err;
+ dstctx->md = srcctx->md;
+
+ if (srcctx->mdctx != NULL) {
+ dstctx->mdctx = EVP_MD_CTX_new();
+ if (dstctx->mdctx == NULL
+ || !EVP_MD_CTX_copy_ex(dstctx->mdctx, srcctx->mdctx))
+ goto err;
+ }
+
+ if (srcctx->id != NULL) {
+ dstctx->id = OPENSSL_malloc(srcctx->id_len);
+ if (dstctx->id == NULL)
+ goto err;
+ dstctx->id_len = srcctx->id_len;
+ memcpy(dstctx->id, srcctx->id, srcctx->id_len);
+ }
+
+ return dstctx;
+ err:
+ sm2sig_freectx(dstctx);
+ return NULL;
+}
+
+static int sm2sig_get_ctx_params(void *vpsm2ctx, OSSL_PARAM *params)
+{
+ PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx;
+ OSSL_PARAM *p;
+
+ if (psm2ctx == NULL)
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID);
+ if (p != NULL
+ && !OSSL_PARAM_set_octet_string(p,
+ psm2ctx->aid_len == 0 ? NULL : psm2ctx->aid_buf,
+ psm2ctx->aid_len))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, psm2ctx->mdsize))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ if (p != NULL && !OSSL_PARAM_set_utf8_string(p, psm2ctx->md == NULL
+ ? psm2ctx->mdname
+ : EVP_MD_get0_name(psm2ctx->md)))
+ return 0;
+
+ return 1;
+}
+
+static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0),
+ OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *sm2sig_gettable_ctx_params(ossl_unused void *vpsm2ctx,
+ ossl_unused void *provctx)
+{
+ return known_gettable_ctx_params;
+}
+
+static int sm2sig_set_ctx_params(void *vpsm2ctx, const OSSL_PARAM params[])
+{
+ PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx;
+ const OSSL_PARAM *p;
+ size_t mdsize;
+
+ if (psm2ctx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DIST_ID);
+ if (p != NULL) {
+ void *tmp_id = NULL;
+ size_t tmp_idlen = 0;
+
+ /*
+ * If the 'z' digest has already been computed, the ID is set too late
+ */
+ if (!psm2ctx->flag_compute_z_digest)
+ return 0;
+
+ if (p->data_size != 0
+ && !OSSL_PARAM_get_octet_string(p, &tmp_id, 0, &tmp_idlen))
+ return 0;
+ OPENSSL_free(psm2ctx->id);
+ psm2ctx->id = tmp_id;
+ psm2ctx->id_len = tmp_idlen;
+ }
+
+ /*
+ * The following code checks that the size is the same as the SM3 digest
+ * size returning an error otherwise.
+ * If there is ever any different digest algorithm allowed with SM2
+ * this needs to be adjusted accordingly.
+ */
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE);
+ if (p != NULL && (!OSSL_PARAM_get_size_t(p, &mdsize)
+ || mdsize != psm2ctx->mdsize))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST);
+ if (p != NULL) {
+ char *mdname = NULL;
+
+ if (!OSSL_PARAM_get_utf8_string(p, &mdname, 0))
+ return 0;
+ if (!sm2sig_set_mdname(psm2ctx, mdname)) {
+ OPENSSL_free(mdname);
+ return 0;
+ }
+ OPENSSL_free(mdname);
+ }
+
+ return 1;
+}
+
+static const OSSL_PARAM known_settable_ctx_params[] = {
+ OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL),
+ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_DIST_ID, NULL, 0),
+ OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *sm2sig_settable_ctx_params(ossl_unused void *vpsm2ctx,
+ ossl_unused void *provctx)
+{
+ return known_settable_ctx_params;
+}
+
+static int sm2sig_get_ctx_md_params(void *vpsm2ctx, OSSL_PARAM *params)
+{
+ PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx;
+
+ if (psm2ctx->mdctx == NULL)
+ return 0;
+
+ return EVP_MD_CTX_get_params(psm2ctx->mdctx, params);
+}
+
+static const OSSL_PARAM *sm2sig_gettable_ctx_md_params(void *vpsm2ctx)
+{
+ PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx;
+
+ if (psm2ctx->md == NULL)
+ return 0;
+
+ return EVP_MD_gettable_ctx_params(psm2ctx->md);
+}
+
+static int sm2sig_set_ctx_md_params(void *vpsm2ctx, const OSSL_PARAM params[])
+{
+ PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx;
+
+ if (psm2ctx->mdctx == NULL)
+ return 0;
+
+ return EVP_MD_CTX_set_params(psm2ctx->mdctx, params);
+}
+
+static const OSSL_PARAM *sm2sig_settable_ctx_md_params(void *vpsm2ctx)
+{
+ PROV_SM2_CTX *psm2ctx = (PROV_SM2_CTX *)vpsm2ctx;
+
+ if (psm2ctx->md == NULL)
+ return 0;
+
+ return EVP_MD_settable_ctx_params(psm2ctx->md);
+}
+
+const OSSL_DISPATCH ossl_sm2_signature_functions[] = {
+ { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))sm2sig_newctx },
+ { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))sm2sig_signature_init },
+ { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))sm2sig_sign },
+ { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))sm2sig_signature_init },
+ { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))sm2sig_verify },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT,
+ (void (*)(void))sm2sig_digest_signverify_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE,
+ (void (*)(void))sm2sig_digest_signverify_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL,
+ (void (*)(void))sm2sig_digest_sign_final },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT,
+ (void (*)(void))sm2sig_digest_signverify_init },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE,
+ (void (*)(void))sm2sig_digest_signverify_update },
+ { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL,
+ (void (*)(void))sm2sig_digest_verify_final },
+ { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))sm2sig_freectx },
+ { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))sm2sig_dupctx },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))sm2sig_get_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,
+ (void (*)(void))sm2sig_gettable_ctx_params },
+ { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))sm2sig_set_ctx_params },
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,
+ (void (*)(void))sm2sig_settable_ctx_params },
+ { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS,
+ (void (*)(void))sm2sig_get_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS,
+ (void (*)(void))sm2sig_gettable_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS,
+ (void (*)(void))sm2sig_set_ctx_md_params },
+ { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS,
+ (void (*)(void))sm2sig_settable_ctx_md_params },
+ OSSL_DISPATCH_END
+};