From fffdbf31d8ef445ae506af0164ba3df4232e2074 Mon Sep 17 00:00:00 2001 From: olszomal Date: Fri, 7 Aug 2026 11:24:45 +0200 Subject: [PATCH] Add signature AlgorithmIdentifier support Add DER-encoded AlgorithmIdentifier support, including RSA-PSS parameters and correct default salt length handling. Also fix PSS salt length parsing and separate gettable/settable signature parameters. --- src/provider.c | 30 ++++-- src/provider_helpers.c | 240 ++++++++++++++++++++++++++++++++++++++++- src/provider_helpers.h | 1 + 3 files changed, 264 insertions(+), 7 deletions(-) diff --git a/src/provider.c b/src/provider.c index 8ecb96da..872b8769 100644 --- a/src/provider.c +++ b/src/provider.c @@ -1518,7 +1518,7 @@ static int signature_digest_verify(void *ctx, return 0; } -/* Get signature context parameters. */ +/* Get signature context parameters, EVP_PKEY_CTX_get_params(). */ static int signature_get_ctx_params(void *vctx, OSSL_PARAM params[]) { P11_SIGNATURE_CTX *sig_ctx = (P11_SIGNATURE_CTX *)vctx; @@ -1546,6 +1546,11 @@ static int signature_get_ctx_params(void *vctx, OSSL_PARAM params[]) return 0; } + /* algorithm-id */ + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + if (p != NULL && !p11_signature_set_algorithm_id(p, sig_ctx)) + return 0; + /* pad-mode (RSA), EVP_PKEY_CTX_get_rsa_padding() */ p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PAD_MODE); if (p != NULL) { @@ -1592,8 +1597,9 @@ static int signature_get_ctx_params(void *vctx, OSSL_PARAM params[]) /* Return signature context parameters that can be retrieved. */ static const OSSL_PARAM *signature_gettable_ctx_params(void *ctx, void *provctx) { - static const OSSL_PARAM settable[] = { + static const OSSL_PARAM gettable[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0), OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), @@ -1604,7 +1610,7 @@ static const OSSL_PARAM *signature_gettable_ctx_params(void *ctx, void *provctx) (void)ctx; (void)provctx; - return settable; + return gettable; } /* Set signature context parameters (digest, padding, PSS options) */ @@ -1667,7 +1673,7 @@ static int signature_set_ctx_params(void *ctx, const OSSL_PARAM params[]) } else if (p->data_type == OSSL_PARAM_UTF8_STRING) { const char *s = NULL; - if (OSSL_PARAM_get_utf8_string_ptr(p, &s) || s == NULL) + if (!OSSL_PARAM_get_utf8_string_ptr(p, &s) || s == NULL) return 0; if (OPENSSL_strcasecmp(s, "digest") == 0) @@ -1693,10 +1699,22 @@ static int signature_set_ctx_params(void *ctx, const OSSL_PARAM params[]) return 1; } -/* Return signature context parameters that can be retrieved (same as gettable) */ +/* Return signature context parameters that can be retrieved */ static const OSSL_PARAM *signature_settable_ctx_params(void *ctx, void *provctx) { - return signature_gettable_ctx_params(ctx, provctx); + static const OSSL_PARAM settable[] = { + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0), + OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), + OSSL_PARAM_int(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL), + OSSL_PARAM_END + }; + + (void)ctx; + (void)provctx; + return settable; } diff --git a/src/provider_helpers.c b/src/provider_helpers.c index a469912a..888043b7 100644 --- a/src/provider_helpers.c +++ b/src/provider_helpers.c @@ -274,6 +274,8 @@ static int keydata_has_rsa_pub(const P11_KEYDATA *keydata); static int keydata_has_ec_pub(const P11_KEYDATA *keydata); #endif /* OPENSSL_NO_EC */ static int keydata_has_raw_pub(const P11_KEYDATA *keydata); +static int p11_signature_set_pss_algorithm_id(OSSL_PARAM *p, + const P11_SIGNATURE_CTX *sig_ctx, const char *mdname); /******************************************************************************/ /* Provider helper API */ @@ -1090,7 +1092,12 @@ int p11_signature_ctx_init(P11_SIGNATURE_CTX *sig_ctx, P11_KEYDATA *keydata, /* (re)set defaults (important when params don't include them) */ sig_ctx->pad_mode = RSA_PKCS1_PADDING; +#ifdef RSA_PSS_SALTLEN_AUTO_DIGEST_MAX + /* Maximize up to digest length for sign */ + sig_ctx->pss_saltlen = RSA_PSS_SALTLEN_AUTO_DIGEST_MAX; /* -4 */ +#else sig_ctx->pss_saltlen = RSA_PSS_SALTLEN_AUTO; /* -2 */ +#endif OPENSSL_free(sig_ctx->mdname); sig_ctx->mdname = NULL; @@ -1410,6 +1417,83 @@ const char *p11_signature_pss_saltlen_to_string(int saltlen) } } +/* + * Build and return a DER-encoded signature AlgorithmIdentifier + * for the current key type, digest and signature parameters. + */ +int p11_signature_set_algorithm_id(OSSL_PARAM *p, const P11_SIGNATURE_CTX *sig_ctx) +{ + X509_ALGOR *alg = NULL; + ASN1_OBJECT *obj = NULL; + unsigned char *der = NULL; + const char *mdname; + int key_type; + int md_nid; + int sig_nid; + int param_type; + int der_len; + int ret = 0; + + if (p == NULL || sig_ctx == NULL) + return 0; + + key_type = p11_signature_ctx_get_type(sig_ctx); + mdname = p11_signature_ctx_get_mdname(sig_ctx); + + /* RSA-PSS requires RSASSA-PSS-params and must be handled separately. */ + if ((key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_RSA_PSS) && + p11_signature_ctx_get_pad_mode(sig_ctx) == RSA_PKCS1_PSS_PADDING) + return p11_signature_set_pss_algorithm_id(p, sig_ctx, mdname); + + if (mdname != NULL && *mdname != '\0') { + /* RSA PKCS#1, ECDSA, DSA, SM2 and other algorithms + * combining a digest with a key algorithm */ + md_nid = OBJ_txt2nid(mdname); + if (md_nid == NID_undef || !OBJ_find_sigid_by_algs(&sig_nid, md_nid, key_type)) + goto end; + + obj = OBJ_dup(OBJ_nid2obj(sig_nid)); + if (obj == NULL) + goto end; + + /* RSA PKCS#1 uses NULL; ECDSA/DSA parameters are absent. */ + param_type = key_type == EVP_PKEY_RSA ? V_ASN1_NULL : V_ASN1_UNDEF; + } else { + /* Ed25519, Ed448, ML-DSA, SLH-DSA, Falcon: parameters are absent */ + const char *algname = p11_keydata_get_name(sig_ctx->keydata); + + if (algname == NULL) + goto end; + + obj = OBJ_txt2obj(algname, 0); + if (obj == NULL) + goto end; + + param_type = V_ASN1_UNDEF; + } + + alg = X509_ALGOR_new(); + if (alg == NULL) + goto end; + + if (!X509_ALGOR_set0(alg, obj, param_type, NULL)) + goto end; + + obj = NULL; /* owned by alg */ + + der_len = i2d_X509_ALGOR(alg, &der); + if (der_len <= 0) + goto end; + + ret = OSSL_PARAM_set_octet_string(p, der, (size_t)der_len); + +end: + ASN1_OBJECT_free(obj); + X509_ALGOR_free(alg); + OPENSSL_free(der); + return ret; +} + /* Convert RSA padding mode to its string representation. */ const char *p11_pad_mode_to_string(int pad_mode) { @@ -2065,7 +2149,7 @@ size_t p11_keyexch_ctx_get_outsize(const P11_KEYEXCH_CTX *keyexch_ctx) if (pkey == NULL) return 0; - bits = EVP_PKEY_bits(pkey); + bits = EVP_PKEY_get_bits(pkey); if (bits <= 0) return 0; @@ -3479,4 +3563,158 @@ static int keydata_has_raw_pub(const P11_KEYDATA *keydata) return keydata->pubdata.raw.pub != NULL && keydata->pubdata.raw.pub_len != 0; } +/* + * Build and return a DER-encoded RSASSA-PSS AlgorithmIdentifier + * using the digest, MGF1 digest and salt length from the signature context. + */ +static int p11_signature_set_pss_algorithm_id(OSSL_PARAM *p, + const P11_SIGNATURE_CTX *sig_ctx, const char *mdname) +{ + RSA_PSS_PARAMS *pss = NULL; + X509_ALGOR *alg = NULL; + X509_ALGOR *mgf1_hash = NULL; + ASN1_STRING *mgf1_params = NULL; + ASN1_STRING *pss_params = NULL; + ASN1_OBJECT *obj = NULL; + EVP_PKEY *pkey; + const EVP_MD *md, *mgf1_md; + const char *mgf1_mdname; + unsigned char *der = NULL; + int saltlen, digest_salt, max_salt, der_len, key_size, key_bits; + int ret = 0; + + if (p == NULL || sig_ctx == NULL || mdname == NULL) + return 0; + + pkey = p11_signature_ctx_get_evp_pkey(sig_ctx); + if (pkey == NULL) + return 0; + + mgf1_mdname = p11_signature_ctx_get_mgf1_mdname(sig_ctx); + if (mgf1_mdname == NULL) + mgf1_mdname = mdname; + + md = EVP_get_digestbyname(mdname); + mgf1_md = EVP_get_digestbyname(mgf1_mdname); + if (md == NULL || mgf1_md == NULL) + goto end; + + digest_salt = EVP_MD_get_size(md); + key_size = EVP_PKEY_get_size(pkey); + key_bits = EVP_PKEY_get_bits(pkey); + if (digest_salt <= 0 || key_size <= 0 || key_bits <= 0) + goto end; + + max_salt = key_size - digest_salt - 2; + + if (((key_bits - 1) & 0x7) == 0) + max_salt--; + + if (max_salt < 0) + goto end; + + saltlen = p11_signature_ctx_get_pss_saltlen(sig_ctx); + + switch (saltlen) { + case RSA_PSS_SALTLEN_DIGEST: /* -1 */ + /* sets the salt length to the digest length */ + saltlen = digest_salt; + break; + case RSA_PSS_SALTLEN_AUTO: /* -2 */ + /* for signing: it has the same meaning as RSA_PSS_SALTLEN_MAX */ + case RSA_PSS_SALTLEN_MAX: /* -3 */ + /* sets the salt length to the maximum permissible value */ + saltlen = max_salt; + break; +#ifdef RSA_PSS_SALTLEN_AUTO_DIGEST_MAX + case RSA_PSS_SALTLEN_AUTO_DIGEST_MAX: /* -4 */ + /* for signing: use min(max_salt, digest_len) per FIPS 186-4 */ + saltlen = max_salt < digest_salt ? max_salt : digest_salt; + break; +#endif /* RSA_PSS_SALTLEN_AUTO_DIGEST_MAX */ + default: + if (saltlen < 0 || saltlen > max_salt) + goto end; + break; + } + + pss = RSA_PSS_PARAMS_new(); + alg = X509_ALGOR_new(); + mgf1_hash = X509_ALGOR_new(); + if (pss == NULL || alg == NULL || mgf1_hash == NULL) + goto end; + + /* hashAlgorithm */ + pss->hashAlgorithm = X509_ALGOR_new(); + if (pss->hashAlgorithm == NULL) + goto end; + + /* RFC 4055 Section 2.1 defines SHA AlgorithmIdentifiers used in + * RSASSA-PSS parameters with an explicit ASN.1 NULL parameter. */ + obj = OBJ_dup(OBJ_nid2obj(EVP_MD_get_type(md))); + if (obj == NULL || !X509_ALGOR_set0(pss->hashAlgorithm, obj, V_ASN1_NULL, NULL)) + goto end; + obj = NULL; + + /* maskGenAlgorithm: MGF1 with selected digest */ + obj = OBJ_dup(OBJ_nid2obj(EVP_MD_get_type(mgf1_md))); + if (obj == NULL || !X509_ALGOR_set0(mgf1_hash, obj, V_ASN1_NULL, NULL)) + goto end; + obj = NULL; + + mgf1_params = ASN1_item_pack(mgf1_hash, ASN1_ITEM_rptr(X509_ALGOR), NULL); + if (mgf1_params == NULL) + goto end; + + pss->maskGenAlgorithm = X509_ALGOR_new(); + if (pss->maskGenAlgorithm == NULL) + goto end; + + obj = OBJ_dup(OBJ_nid2obj(NID_mgf1)); + if (obj == NULL) + goto end; + + if (!X509_ALGOR_set0(pss->maskGenAlgorithm, obj, V_ASN1_SEQUENCE, mgf1_params)) + goto end; + + obj = NULL; + mgf1_params = NULL; + + /* saltLength */ + pss->saltLength = ASN1_INTEGER_new(); + if (pss->saltLength == NULL || !ASN1_INTEGER_set(pss->saltLength, saltlen)) + goto end; + + /* trailerField is omitted because its default value is 1. */ + pss_params = ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), NULL); + if (pss_params == NULL) + goto end; + + obj = OBJ_dup(OBJ_nid2obj(NID_rsassaPss)); + if (obj == NULL) + goto end; + + if (!X509_ALGOR_set0(alg, obj, V_ASN1_SEQUENCE, pss_params)) + goto end; + + obj = NULL; /* owned by alg */ + pss_params = NULL; + + der_len = i2d_X509_ALGOR(alg, &der); + if (der_len <= 0) + goto end; + + ret = OSSL_PARAM_set_octet_string(p, der, (size_t)der_len); + +end: + ASN1_OBJECT_free(obj); + ASN1_STRING_free(mgf1_params); + ASN1_STRING_free(pss_params); + X509_ALGOR_free(mgf1_hash); + RSA_PSS_PARAMS_free(pss); + X509_ALGOR_free(alg); + OPENSSL_free(der); + return ret; +} + /* vim: set noexpandtab: */ diff --git a/src/provider_helpers.h b/src/provider_helpers.h index a960d11c..93381451 100644 --- a/src/provider_helpers.h +++ b/src/provider_helpers.h @@ -134,6 +134,7 @@ const char *p11_signature_ctx_get_mgf1_mdname(const P11_SIGNATURE_CTX *sig_ctx); EVP_MD_CTX *p11_signature_ctx_get_mdctx(P11_SIGNATURE_CTX *sig_ctx); const char *p11_signature_pss_saltlen_to_string(int saltlen); +int p11_signature_set_algorithm_id(OSSL_PARAM *p, const P11_SIGNATURE_CTX *sig_ctx); const char *p11_pad_mode_to_string(int pad_mode); int is_oneshot_sig_type(int type); int has_raw_public_key(int type);