* [PATCH v15 1/7] crypto: Add ML-DSA crypto_sig support
2026-01-26 14:29 [PATCH v15 0/7] x509, pkcs7, crypto: Add ML-DSA signing David Howells
@ 2026-01-26 14:29 ` David Howells
2026-01-26 14:29 ` [PATCH v15 2/7] x509: Separately calculate sha256 for blacklist David Howells
` (5 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
Add verify-only public key crypto support for ML-DSA so that the
X.509/PKCS#7 signature verification code, as used by module signing,
amongst other things, can make use of it through the common crypto_sig API.
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/Kconfig | 9 +++
crypto/Makefile | 2 +
crypto/mldsa.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 212 insertions(+)
create mode 100644 crypto/mldsa.c
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 12a87f7cf150..a210575fa5e0 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -344,6 +344,15 @@ config CRYPTO_ECRDSA
One of the Russian cryptographic standard algorithms (called GOST
algorithms). Only signature verification is implemented.
+config CRYPTO_MLDSA
+ tristate "ML-DSA (Module-Lattice-Based Digital Signature Algorithm)"
+ select CRYPTO_SIG
+ select CRYPTO_LIB_MLDSA
+ help
+ ML-DSA (Module-Lattice-Based Digital Signature Algorithm) (FIPS-204).
+
+ Only signature verification is implemented.
+
endmenu
menu "Block ciphers"
diff --git a/crypto/Makefile b/crypto/Makefile
index 23d3db7be425..267d5403045b 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -60,6 +60,8 @@ ecdsa_generic-y += ecdsa-p1363.o
ecdsa_generic-y += ecdsasignature.asn1.o
obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o
+obj-$(CONFIG_CRYPTO_MLDSA) += mldsa.o
+
crypto_acompress-y := acompress.o
crypto_acompress-y += scompress.o
obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o
diff --git a/crypto/mldsa.c b/crypto/mldsa.c
new file mode 100644
index 000000000000..d8de082cc67a
--- /dev/null
+++ b/crypto/mldsa.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * crypto_sig wrapper around ML-DSA library.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <crypto/internal/sig.h>
+#include <crypto/mldsa.h>
+
+struct crypto_mldsa_ctx {
+ u8 pk[MAX(MAX(MLDSA44_PUBLIC_KEY_SIZE,
+ MLDSA65_PUBLIC_KEY_SIZE),
+ MLDSA87_PUBLIC_KEY_SIZE)];
+ unsigned int pk_len;
+ enum mldsa_alg strength;
+ bool key_set;
+};
+
+static int crypto_mldsa_sign(struct crypto_sig *tfm,
+ const void *msg, unsigned int msg_len,
+ void *sig, unsigned int sig_len)
+{
+ return -EOPNOTSUPP;
+}
+
+static int crypto_mldsa_verify(struct crypto_sig *tfm,
+ const void *sig, unsigned int sig_len,
+ const void *msg, unsigned int msg_len)
+{
+ const struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ if (unlikely(!ctx->key_set))
+ return -EINVAL;
+
+ return mldsa_verify(ctx->strength, sig, sig_len, msg, msg_len,
+ ctx->pk, ctx->pk_len);
+}
+
+static unsigned int crypto_mldsa_key_size(struct crypto_sig *tfm)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ switch (ctx->strength) {
+ case MLDSA44:
+ return MLDSA44_PUBLIC_KEY_SIZE;
+ case MLDSA65:
+ return MLDSA65_PUBLIC_KEY_SIZE;
+ case MLDSA87:
+ return MLDSA87_PUBLIC_KEY_SIZE;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+}
+
+static int crypto_mldsa_set_pub_key(struct crypto_sig *tfm,
+ const void *key, unsigned int keylen)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+ unsigned int expected_len = crypto_mldsa_key_size(tfm);
+
+ if (keylen != expected_len)
+ return -EINVAL;
+
+ ctx->pk_len = keylen;
+ memcpy(ctx->pk, key, keylen);
+ ctx->key_set = true;
+ return 0;
+}
+
+static int crypto_mldsa_set_priv_key(struct crypto_sig *tfm,
+ const void *key, unsigned int keylen)
+{
+ return -EOPNOTSUPP;
+}
+
+static unsigned int crypto_mldsa_max_size(struct crypto_sig *tfm)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ switch (ctx->strength) {
+ case MLDSA44:
+ return MLDSA44_SIGNATURE_SIZE;
+ case MLDSA65:
+ return MLDSA65_SIGNATURE_SIZE;
+ case MLDSA87:
+ return MLDSA87_SIGNATURE_SIZE;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+}
+
+static int crypto_mldsa44_alg_init(struct crypto_sig *tfm)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ ctx->strength = MLDSA44;
+ ctx->key_set = false;
+ return 0;
+}
+
+static int crypto_mldsa65_alg_init(struct crypto_sig *tfm)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ ctx->strength = MLDSA65;
+ ctx->key_set = false;
+ return 0;
+}
+
+static int crypto_mldsa87_alg_init(struct crypto_sig *tfm)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ ctx->strength = MLDSA87;
+ ctx->key_set = false;
+ return 0;
+}
+
+static void crypto_mldsa_alg_exit(struct crypto_sig *tfm)
+{
+}
+
+static struct sig_alg crypto_mldsa_algs[] = {
+ {
+ .sign = crypto_mldsa_sign,
+ .verify = crypto_mldsa_verify,
+ .set_pub_key = crypto_mldsa_set_pub_key,
+ .set_priv_key = crypto_mldsa_set_priv_key,
+ .key_size = crypto_mldsa_key_size,
+ .max_size = crypto_mldsa_max_size,
+ .init = crypto_mldsa44_alg_init,
+ .exit = crypto_mldsa_alg_exit,
+ .base.cra_name = "mldsa44",
+ .base.cra_driver_name = "mldsa44-lib",
+ .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx),
+ .base.cra_module = THIS_MODULE,
+ .base.cra_priority = 5000,
+ }, {
+ .sign = crypto_mldsa_sign,
+ .verify = crypto_mldsa_verify,
+ .set_pub_key = crypto_mldsa_set_pub_key,
+ .set_priv_key = crypto_mldsa_set_priv_key,
+ .key_size = crypto_mldsa_key_size,
+ .max_size = crypto_mldsa_max_size,
+ .init = crypto_mldsa65_alg_init,
+ .exit = crypto_mldsa_alg_exit,
+ .base.cra_name = "mldsa65",
+ .base.cra_driver_name = "mldsa65-lib",
+ .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx),
+ .base.cra_module = THIS_MODULE,
+ .base.cra_priority = 5000,
+ }, {
+ .sign = crypto_mldsa_sign,
+ .verify = crypto_mldsa_verify,
+ .set_pub_key = crypto_mldsa_set_pub_key,
+ .set_priv_key = crypto_mldsa_set_priv_key,
+ .key_size = crypto_mldsa_key_size,
+ .max_size = crypto_mldsa_max_size,
+ .init = crypto_mldsa87_alg_init,
+ .exit = crypto_mldsa_alg_exit,
+ .base.cra_name = "mldsa87",
+ .base.cra_driver_name = "mldsa87-lib",
+ .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx),
+ .base.cra_module = THIS_MODULE,
+ .base.cra_priority = 5000,
+ },
+};
+
+static int __init mldsa_init(void)
+{
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(crypto_mldsa_algs); i++) {
+ ret = crypto_register_sig(&crypto_mldsa_algs[i]);
+ if (ret < 0)
+ goto error;
+ }
+ return 0;
+
+error:
+ pr_err("Failed to register (%d)\n", ret);
+ for (i--; i >= 0; i--)
+ crypto_unregister_sig(&crypto_mldsa_algs[i]);
+ return ret;
+}
+module_init(mldsa_init);
+
+static void mldsa_exit(void)
+{
+ for (int i = 0; i < ARRAY_SIZE(crypto_mldsa_algs); i++)
+ crypto_unregister_sig(&crypto_mldsa_algs[i]);
+}
+module_exit(mldsa_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Crypto API support for ML-DSA signature verification");
+MODULE_ALIAS_CRYPTO("mldsa44");
+MODULE_ALIAS_CRYPTO("mldsa65");
+MODULE_ALIAS_CRYPTO("mldsa87");
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v15 2/7] x509: Separately calculate sha256 for blacklist
2026-01-26 14:29 [PATCH v15 0/7] x509, pkcs7, crypto: Add ML-DSA signing David Howells
2026-01-26 14:29 ` [PATCH v15 1/7] crypto: Add ML-DSA crypto_sig support David Howells
@ 2026-01-26 14:29 ` David Howells
2026-01-28 23:14 ` Jarkko Sakkinen
2026-01-26 14:29 ` [PATCH v15 3/7] pkcs7, x509: Rename ->digest to ->m David Howells
` (4 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
Calculate the SHA256 hash for blacklisting purposes independently of the
signature hash (which may be something other than SHA256).
This is necessary because when ML-DSA is used, no digest is calculated.
Note that this represents a change of behaviour in that the hash used for
the blacklist check would previously have been whatever digest was used
for, say, RSA-based signatures. It may be that this is inadvisable.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/asymmetric_keys/x509_parser.h | 2 ++
crypto/asymmetric_keys/x509_public_key.c | 22 +++++++++++++---------
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 0688c222806b..b7aeebdddb36 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -9,12 +9,14 @@
#include <linux/time.h>
#include <crypto/public_key.h>
#include <keys/asymmetric-type.h>
+#include <crypto/sha2.h>
struct x509_certificate {
struct x509_certificate *next;
struct x509_certificate *signer; /* Certificate that signed this one */
struct public_key *pub; /* Public key details */
struct public_key_signature *sig; /* Signature parameters */
+ u8 sha256[SHA256_DIGEST_SIZE]; /* Hash for blacklist purposes */
char *issuer; /* Name of certificate issuer */
char *subject; /* Name of certificate subject */
struct asymmetric_key_id *id; /* Issuer + Serial number */
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 12e3341e806b..79cc7b7a0630 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -31,6 +31,19 @@ int x509_get_sig_params(struct x509_certificate *cert)
pr_devel("==>%s()\n", __func__);
+ /* Calculate a SHA256 hash of the TBS and check it against the
+ * blacklist.
+ */
+ sha256(cert->tbs, cert->tbs_size, cert->sha256);
+ ret = is_hash_blacklisted(cert->sha256, sizeof(cert->sha256),
+ BLACKLIST_HASH_X509_TBS);
+ if (ret == -EKEYREJECTED) {
+ pr_err("Cert %*phN is blacklisted\n",
+ (int)sizeof(cert->sha256), cert->sha256);
+ cert->blacklisted = true;
+ ret = 0;
+ }
+
sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
if (!sig->s)
return -ENOMEM;
@@ -69,15 +82,6 @@ int x509_get_sig_params(struct x509_certificate *cert)
if (ret < 0)
goto error_2;
- ret = is_hash_blacklisted(sig->digest, sig->digest_size,
- BLACKLIST_HASH_X509_TBS);
- if (ret == -EKEYREJECTED) {
- pr_err("Cert %*phN is blacklisted\n",
- sig->digest_size, sig->digest);
- cert->blacklisted = true;
- ret = 0;
- }
-
error_2:
kfree(desc);
error:
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v15 2/7] x509: Separately calculate sha256 for blacklist
2026-01-26 14:29 ` [PATCH v15 2/7] x509: Separately calculate sha256 for blacklist David Howells
@ 2026-01-28 23:14 ` Jarkko Sakkinen
0 siblings, 0 replies; 16+ messages in thread
From: Jarkko Sakkinen @ 2026-01-28 23:14 UTC (permalink / raw)
To: David Howells
Cc: Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
On Mon, Jan 26, 2026 at 02:29:23PM +0000, David Howells wrote:
> Calculate the SHA256 hash for blacklisting purposes independently of the
> signature hash (which may be something other than SHA256).
>
> This is necessary because when ML-DSA is used, no digest is calculated.
>
> Note that this represents a change of behaviour in that the hash used for
> the blacklist check would previously have been whatever digest was used
> for, say, RSA-based signatures. It may be that this is inadvisable.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Stephan Mueller <smueller@chronox.de>
> cc: Eric Biggers <ebiggers@kernel.org>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> ---
> crypto/asymmetric_keys/x509_parser.h | 2 ++
> crypto/asymmetric_keys/x509_public_key.c | 22 +++++++++++++---------
> 2 files changed, 15 insertions(+), 9 deletions(-)
>
> diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
> index 0688c222806b..b7aeebdddb36 100644
> --- a/crypto/asymmetric_keys/x509_parser.h
> +++ b/crypto/asymmetric_keys/x509_parser.h
> @@ -9,12 +9,14 @@
> #include <linux/time.h>
> #include <crypto/public_key.h>
> #include <keys/asymmetric-type.h>
> +#include <crypto/sha2.h>
>
> struct x509_certificate {
> struct x509_certificate *next;
> struct x509_certificate *signer; /* Certificate that signed this one */
> struct public_key *pub; /* Public key details */
> struct public_key_signature *sig; /* Signature parameters */
> + u8 sha256[SHA256_DIGEST_SIZE]; /* Hash for blacklist purposes */
> char *issuer; /* Name of certificate issuer */
> char *subject; /* Name of certificate subject */
> struct asymmetric_key_id *id; /* Issuer + Serial number */
> diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
> index 12e3341e806b..79cc7b7a0630 100644
> --- a/crypto/asymmetric_keys/x509_public_key.c
> +++ b/crypto/asymmetric_keys/x509_public_key.c
> @@ -31,6 +31,19 @@ int x509_get_sig_params(struct x509_certificate *cert)
>
> pr_devel("==>%s()\n", __func__);
>
> + /* Calculate a SHA256 hash of the TBS and check it against the
> + * blacklist.
> + */
> + sha256(cert->tbs, cert->tbs_size, cert->sha256);
> + ret = is_hash_blacklisted(cert->sha256, sizeof(cert->sha256),
> + BLACKLIST_HASH_X509_TBS);
> + if (ret == -EKEYREJECTED) {
> + pr_err("Cert %*phN is blacklisted\n",
> + (int)sizeof(cert->sha256), cert->sha256);
> + cert->blacklisted = true;
> + ret = 0;
> + }
> +
> sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
> if (!sig->s)
> return -ENOMEM;
> @@ -69,15 +82,6 @@ int x509_get_sig_params(struct x509_certificate *cert)
> if (ret < 0)
> goto error_2;
>
> - ret = is_hash_blacklisted(sig->digest, sig->digest_size,
> - BLACKLIST_HASH_X509_TBS);
> - if (ret == -EKEYREJECTED) {
> - pr_err("Cert %*phN is blacklisted\n",
> - sig->digest_size, sig->digest);
> - cert->blacklisted = true;
> - ret = 0;
> - }
> -
> error_2:
> kfree(desc);
> error:
>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
BR, Jarkko
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v15 3/7] pkcs7, x509: Rename ->digest to ->m
2026-01-26 14:29 [PATCH v15 0/7] x509, pkcs7, crypto: Add ML-DSA signing David Howells
2026-01-26 14:29 ` [PATCH v15 1/7] crypto: Add ML-DSA crypto_sig support David Howells
2026-01-26 14:29 ` [PATCH v15 2/7] x509: Separately calculate sha256 for blacklist David Howells
@ 2026-01-26 14:29 ` David Howells
2026-01-28 23:15 ` Jarkko Sakkinen
2026-01-26 14:29 ` [PATCH v15 4/7] pkcs7: Allow the signing algo to do whatever digestion it wants itself David Howells
` (3 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
Rename ->digest and ->digest_len to ->m and ->m_size to represent the input
to the signature verification algorithm, reflecting that ->digest may no
longer actually *be* a digest.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Jarkko Sakkinen <jarkko@kernel.org>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/asymmetric_keys/asymmetric_type.c | 4 ++--
crypto/asymmetric_keys/pkcs7_verify.c | 28 ++++++++++++------------
crypto/asymmetric_keys/public_key.c | 3 +--
crypto/asymmetric_keys/signature.c | 2 +-
crypto/asymmetric_keys/x509_public_key.c | 10 ++++-----
include/crypto/public_key.h | 4 ++--
security/integrity/digsig_asymmetric.c | 4 ++--
7 files changed, 26 insertions(+), 29 deletions(-)
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index 348966ea2175..2326743310b1 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -593,10 +593,10 @@ static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
{
struct public_key_signature sig = {
.s_size = params->in2_len,
- .digest_size = params->in_len,
+ .m_size = params->in_len,
.encoding = params->encoding,
.hash_algo = params->hash_algo,
- .digest = (void *)in,
+ .m = (void *)in,
.s = (void *)in2,
};
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 6d6475e3a9bf..aa085ec6fb1c 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -31,7 +31,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
/* The digest was calculated already. */
- if (sig->digest)
+ if (sig->m)
return 0;
if (!sinfo->sig->hash_algo)
@@ -45,11 +45,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
- sig->digest_size = crypto_shash_digestsize(tfm);
+ sig->m_size = crypto_shash_digestsize(tfm);
ret = -ENOMEM;
- sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
- if (!sig->digest)
+ sig->m = kmalloc(sig->m_size, GFP_KERNEL);
+ if (!sig->m)
goto error_no_desc;
desc = kzalloc(desc_size, GFP_KERNEL);
@@ -59,11 +59,10 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
desc->tfm = tfm;
/* Digest the message [RFC2315 9.3] */
- ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len,
- sig->digest);
+ ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len, sig->m);
if (ret < 0)
goto error;
- pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
+ pr_devel("MsgDigest = [%*ph]\n", 8, sig->m);
/* However, if there are authenticated attributes, there must be a
* message digest attribute amongst them which corresponds to the
@@ -78,14 +77,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
goto error;
}
- if (sinfo->msgdigest_len != sig->digest_size) {
+ if (sinfo->msgdigest_len != sig->m_size) {
pr_warn("Sig %u: Invalid digest size (%u)\n",
sinfo->index, sinfo->msgdigest_len);
ret = -EBADMSG;
goto error;
}
- if (memcmp(sig->digest, sinfo->msgdigest,
+ if (memcmp(sig->m, sinfo->msgdigest,
sinfo->msgdigest_len) != 0) {
pr_warn("Sig %u: Message digest doesn't match\n",
sinfo->index);
@@ -98,7 +97,8 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
* convert the attributes from a CONT.0 into a SET before we
* hash it.
*/
- memset(sig->digest, 0, sig->digest_size);
+ memset(sig->m, 0, sig->m_size);
+
ret = crypto_shash_init(desc);
if (ret < 0)
@@ -108,10 +108,10 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
if (ret < 0)
goto error;
ret = crypto_shash_finup(desc, sinfo->authattrs,
- sinfo->authattrs_len, sig->digest);
+ sinfo->authattrs_len, sig->m);
if (ret < 0)
goto error;
- pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
+ pr_devel("AADigest = [%*ph]\n", 8, sig->m);
}
error:
@@ -138,8 +138,8 @@ int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len,
if (ret)
return ret;
- *buf = sinfo->sig->digest;
- *len = sinfo->sig->digest_size;
+ *buf = sinfo->sig->m;
+ *len = sinfo->sig->m_size;
i = match_string(hash_algo_name, HASH_ALGO__LAST,
sinfo->sig->hash_algo);
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index e5b177c8e842..a46356e0c08b 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -425,8 +425,7 @@ int public_key_verify_signature(const struct public_key *pkey,
if (ret)
goto error_free_key;
- ret = crypto_sig_verify(tfm, sig->s, sig->s_size,
- sig->digest, sig->digest_size);
+ ret = crypto_sig_verify(tfm, sig->s, sig->s_size, sig->m, sig->m_size);
error_free_key:
kfree_sensitive(key);
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
index 041d04b5c953..f4ec126121b3 100644
--- a/crypto/asymmetric_keys/signature.c
+++ b/crypto/asymmetric_keys/signature.c
@@ -28,7 +28,7 @@ void public_key_signature_free(struct public_key_signature *sig)
for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
kfree(sig->auth_ids[i]);
kfree(sig->s);
- kfree(sig->digest);
+ kfree(sig->m);
kfree(sig);
}
}
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 79cc7b7a0630..3854f7ae4ed0 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -63,11 +63,11 @@ int x509_get_sig_params(struct x509_certificate *cert)
}
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
- sig->digest_size = crypto_shash_digestsize(tfm);
+ sig->m_size = crypto_shash_digestsize(tfm);
ret = -ENOMEM;
- sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
- if (!sig->digest)
+ sig->m = kmalloc(sig->m_size, GFP_KERNEL);
+ if (!sig->m)
goto error;
desc = kzalloc(desc_size, GFP_KERNEL);
@@ -76,9 +76,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
desc->tfm = tfm;
- ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size,
- sig->digest);
-
+ ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, sig->m);
if (ret < 0)
goto error_2;
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 81098e00c08f..bd38ba4d217d 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -43,9 +43,9 @@ extern void public_key_free(struct public_key *key);
struct public_key_signature {
struct asymmetric_key_id *auth_ids[3];
u8 *s; /* Signature */
- u8 *digest;
+ u8 *m; /* Message data to pass to verifier */
u32 s_size; /* Number of bytes in signature */
- u32 digest_size; /* Number of bytes in digest */
+ u32 m_size; /* Number of bytes in ->m */
const char *pkey_algo;
const char *hash_algo;
const char *encoding;
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 457c0a396caf..87be85f477d1 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -121,8 +121,8 @@ int asymmetric_verify(struct key *keyring, const char *sig,
goto out;
}
- pks.digest = (u8 *)data;
- pks.digest_size = datalen;
+ pks.m = (u8 *)data;
+ pks.m_size = datalen;
pks.s = hdr->sig;
pks.s_size = siglen;
ret = verify_signature(key, &pks);
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v15 3/7] pkcs7, x509: Rename ->digest to ->m
2026-01-26 14:29 ` [PATCH v15 3/7] pkcs7, x509: Rename ->digest to ->m David Howells
@ 2026-01-28 23:15 ` Jarkko Sakkinen
0 siblings, 0 replies; 16+ messages in thread
From: Jarkko Sakkinen @ 2026-01-28 23:15 UTC (permalink / raw)
To: David Howells
Cc: Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
On Mon, Jan 26, 2026 at 02:29:24PM +0000, David Howells wrote:
> Rename ->digest and ->digest_len to ->m and ->m_size to represent the input
> to the signature verification algorithm, reflecting that ->digest may no
> longer actually *be* a digest.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Jarkko Sakkinen <jarkko@kernel.org>
> cc: Stephan Mueller <smueller@chronox.de>
> cc: Eric Biggers <ebiggers@kernel.org>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> ---
> crypto/asymmetric_keys/asymmetric_type.c | 4 ++--
> crypto/asymmetric_keys/pkcs7_verify.c | 28 ++++++++++++------------
> crypto/asymmetric_keys/public_key.c | 3 +--
> crypto/asymmetric_keys/signature.c | 2 +-
> crypto/asymmetric_keys/x509_public_key.c | 10 ++++-----
> include/crypto/public_key.h | 4 ++--
> security/integrity/digsig_asymmetric.c | 4 ++--
> 7 files changed, 26 insertions(+), 29 deletions(-)
>
> diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
> index 348966ea2175..2326743310b1 100644
> --- a/crypto/asymmetric_keys/asymmetric_type.c
> +++ b/crypto/asymmetric_keys/asymmetric_type.c
> @@ -593,10 +593,10 @@ static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
> {
> struct public_key_signature sig = {
> .s_size = params->in2_len,
> - .digest_size = params->in_len,
> + .m_size = params->in_len,
> .encoding = params->encoding,
> .hash_algo = params->hash_algo,
> - .digest = (void *)in,
> + .m = (void *)in,
> .s = (void *)in2,
> };
>
> diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
> index 6d6475e3a9bf..aa085ec6fb1c 100644
> --- a/crypto/asymmetric_keys/pkcs7_verify.c
> +++ b/crypto/asymmetric_keys/pkcs7_verify.c
> @@ -31,7 +31,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
> kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
>
> /* The digest was calculated already. */
> - if (sig->digest)
> + if (sig->m)
> return 0;
>
> if (!sinfo->sig->hash_algo)
> @@ -45,11 +45,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
> return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
>
> desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
> - sig->digest_size = crypto_shash_digestsize(tfm);
> + sig->m_size = crypto_shash_digestsize(tfm);
>
> ret = -ENOMEM;
> - sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
> - if (!sig->digest)
> + sig->m = kmalloc(sig->m_size, GFP_KERNEL);
> + if (!sig->m)
> goto error_no_desc;
>
> desc = kzalloc(desc_size, GFP_KERNEL);
> @@ -59,11 +59,10 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
> desc->tfm = tfm;
>
> /* Digest the message [RFC2315 9.3] */
> - ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len,
> - sig->digest);
> + ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len, sig->m);
> if (ret < 0)
> goto error;
> - pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
> + pr_devel("MsgDigest = [%*ph]\n", 8, sig->m);
>
> /* However, if there are authenticated attributes, there must be a
> * message digest attribute amongst them which corresponds to the
> @@ -78,14 +77,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
> goto error;
> }
>
> - if (sinfo->msgdigest_len != sig->digest_size) {
> + if (sinfo->msgdigest_len != sig->m_size) {
> pr_warn("Sig %u: Invalid digest size (%u)\n",
> sinfo->index, sinfo->msgdigest_len);
> ret = -EBADMSG;
> goto error;
> }
>
> - if (memcmp(sig->digest, sinfo->msgdigest,
> + if (memcmp(sig->m, sinfo->msgdigest,
> sinfo->msgdigest_len) != 0) {
> pr_warn("Sig %u: Message digest doesn't match\n",
> sinfo->index);
> @@ -98,7 +97,8 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
> * convert the attributes from a CONT.0 into a SET before we
> * hash it.
> */
> - memset(sig->digest, 0, sig->digest_size);
> + memset(sig->m, 0, sig->m_size);
> +
>
> ret = crypto_shash_init(desc);
> if (ret < 0)
> @@ -108,10 +108,10 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
> if (ret < 0)
> goto error;
> ret = crypto_shash_finup(desc, sinfo->authattrs,
> - sinfo->authattrs_len, sig->digest);
> + sinfo->authattrs_len, sig->m);
> if (ret < 0)
> goto error;
> - pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
> + pr_devel("AADigest = [%*ph]\n", 8, sig->m);
> }
>
> error:
> @@ -138,8 +138,8 @@ int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len,
> if (ret)
> return ret;
>
> - *buf = sinfo->sig->digest;
> - *len = sinfo->sig->digest_size;
> + *buf = sinfo->sig->m;
> + *len = sinfo->sig->m_size;
>
> i = match_string(hash_algo_name, HASH_ALGO__LAST,
> sinfo->sig->hash_algo);
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index e5b177c8e842..a46356e0c08b 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -425,8 +425,7 @@ int public_key_verify_signature(const struct public_key *pkey,
> if (ret)
> goto error_free_key;
>
> - ret = crypto_sig_verify(tfm, sig->s, sig->s_size,
> - sig->digest, sig->digest_size);
> + ret = crypto_sig_verify(tfm, sig->s, sig->s_size, sig->m, sig->m_size);
>
> error_free_key:
> kfree_sensitive(key);
> diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
> index 041d04b5c953..f4ec126121b3 100644
> --- a/crypto/asymmetric_keys/signature.c
> +++ b/crypto/asymmetric_keys/signature.c
> @@ -28,7 +28,7 @@ void public_key_signature_free(struct public_key_signature *sig)
> for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
> kfree(sig->auth_ids[i]);
> kfree(sig->s);
> - kfree(sig->digest);
> + kfree(sig->m);
> kfree(sig);
> }
> }
> diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
> index 79cc7b7a0630..3854f7ae4ed0 100644
> --- a/crypto/asymmetric_keys/x509_public_key.c
> +++ b/crypto/asymmetric_keys/x509_public_key.c
> @@ -63,11 +63,11 @@ int x509_get_sig_params(struct x509_certificate *cert)
> }
>
> desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
> - sig->digest_size = crypto_shash_digestsize(tfm);
> + sig->m_size = crypto_shash_digestsize(tfm);
>
> ret = -ENOMEM;
> - sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
> - if (!sig->digest)
> + sig->m = kmalloc(sig->m_size, GFP_KERNEL);
> + if (!sig->m)
> goto error;
>
> desc = kzalloc(desc_size, GFP_KERNEL);
> @@ -76,9 +76,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
>
> desc->tfm = tfm;
>
> - ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size,
> - sig->digest);
> -
> + ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, sig->m);
> if (ret < 0)
> goto error_2;
>
> diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
> index 81098e00c08f..bd38ba4d217d 100644
> --- a/include/crypto/public_key.h
> +++ b/include/crypto/public_key.h
> @@ -43,9 +43,9 @@ extern void public_key_free(struct public_key *key);
> struct public_key_signature {
> struct asymmetric_key_id *auth_ids[3];
> u8 *s; /* Signature */
> - u8 *digest;
> + u8 *m; /* Message data to pass to verifier */
> u32 s_size; /* Number of bytes in signature */
> - u32 digest_size; /* Number of bytes in digest */
> + u32 m_size; /* Number of bytes in ->m */
> const char *pkey_algo;
> const char *hash_algo;
> const char *encoding;
> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
> index 457c0a396caf..87be85f477d1 100644
> --- a/security/integrity/digsig_asymmetric.c
> +++ b/security/integrity/digsig_asymmetric.c
> @@ -121,8 +121,8 @@ int asymmetric_verify(struct key *keyring, const char *sig,
> goto out;
> }
>
> - pks.digest = (u8 *)data;
> - pks.digest_size = datalen;
> + pks.m = (u8 *)data;
> + pks.m_size = datalen;
> pks.s = hdr->sig;
> pks.s_size = siglen;
> ret = verify_signature(key, &pks);
>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
BR, Jarkko
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v15 4/7] pkcs7: Allow the signing algo to do whatever digestion it wants itself
2026-01-26 14:29 [PATCH v15 0/7] x509, pkcs7, crypto: Add ML-DSA signing David Howells
` (2 preceding siblings ...)
2026-01-26 14:29 ` [PATCH v15 3/7] pkcs7, x509: Rename ->digest to ->m David Howells
@ 2026-01-26 14:29 ` David Howells
2026-01-26 14:29 ` [PATCH v15 5/7] pkcs7, x509: Add ML-DSA support David Howells
` (2 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
Allow the data to be verified in a PKCS#7 or CMS message to be passed
directly to an asymmetric cipher algorithm (e.g. ML-DSA) if it wants to do
whatever passes for hashing/digestion itself. The normal digestion of the
data is then skipped as that would be ignored unless another signed info in
the message has some other algorithm that needs it.
The 'data to be verified' may be the content of the PKCS#7 message or it
will be the authenticatedAttributes (signedAttrs if CMS), modified, if
those are present.
This is done by:
(1) Make ->m and ->m_size point to the data to be verified rather than
making public_key_verify_signature() access the data directly. This
is so that keyctl(KEYCTL_PKEY_VERIFY) will still work.
(2) Add a flag, ->algo_takes_data, to indicate that the verification
algorithm wants to access the data to be verified directly rather than
having it digested first.
(3) If the PKCS#7 message has authenticatedAttributes (or CMS
signedAttrs), then the digest contained therein will be validated as
now, and the modified attrs blob will either be digested or assigned
to ->m as appropriate.
(4) If present, always copy and modify the authenticatedAttributes (or
signedAttrs) then digest that in one go rather than calling the shash
update twice (once for the tag and once for the rest).
(5) For ML-DSA, point ->m to the TBSCertificate instead of digesting it
and using the digest.
Note that whilst ML-DSA does allow for an "external mu", CMS doesn't yet
have that standardised.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/asymmetric_keys/pkcs7_parser.c | 4 +-
crypto/asymmetric_keys/pkcs7_verify.c | 52 ++++++++++++++++--------
crypto/asymmetric_keys/signature.c | 3 +-
crypto/asymmetric_keys/x509_public_key.c | 10 +++++
include/crypto/public_key.h | 2 +
5 files changed, 51 insertions(+), 20 deletions(-)
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 423d13c47545..3cdbab3b9f50 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -599,8 +599,8 @@ int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
}
/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
- sinfo->authattrs = value - (hdrlen - 1);
- sinfo->authattrs_len = vlen + (hdrlen - 1);
+ sinfo->authattrs = value - hdrlen;
+ sinfo->authattrs_len = vlen + hdrlen;
return 0;
}
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index aa085ec6fb1c..06abb9838f95 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -30,6 +30,16 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
+ if (!sinfo->authattrs && sig->algo_takes_data) {
+ /* There's no intermediate digest and the signature algo
+ * doesn't want the data prehashing.
+ */
+ sig->m = (void *)pkcs7->data;
+ sig->m_size = pkcs7->data_len;
+ sig->m_free = false;
+ return 0;
+ }
+
/* The digest was calculated already. */
if (sig->m)
return 0;
@@ -48,9 +58,10 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
sig->m_size = crypto_shash_digestsize(tfm);
ret = -ENOMEM;
- sig->m = kmalloc(sig->m_size, GFP_KERNEL);
+ sig->m = kmalloc(umax(sinfo->authattrs_len, sig->m_size), GFP_KERNEL);
if (!sig->m)
goto error_no_desc;
+ sig->m_free = true;
desc = kzalloc(desc_size, GFP_KERNEL);
if (!desc)
@@ -69,8 +80,6 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
* digest we just calculated.
*/
if (sinfo->authattrs) {
- u8 tag;
-
if (!sinfo->msgdigest) {
pr_warn("Sig %u: No messageDigest\n", sinfo->index);
ret = -EKEYREJECTED;
@@ -96,21 +105,25 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
* as the contents of the digest instead. Note that we need to
* convert the attributes from a CONT.0 into a SET before we
* hash it.
+ *
+ * However, for certain algorithms, such as ML-DSA, the digest
+ * is integrated into the signing algorithm. In such a case,
+ * we copy the authattrs, modifying the tag type, and set that
+ * as the digest.
*/
- memset(sig->m, 0, sig->m_size);
-
-
- ret = crypto_shash_init(desc);
- if (ret < 0)
- goto error;
- tag = ASN1_CONS_BIT | ASN1_SET;
- ret = crypto_shash_update(desc, &tag, 1);
- if (ret < 0)
- goto error;
- ret = crypto_shash_finup(desc, sinfo->authattrs,
- sinfo->authattrs_len, sig->m);
- if (ret < 0)
- goto error;
+ memcpy(sig->m, sinfo->authattrs, sinfo->authattrs_len);
+ sig->m[0] = ASN1_CONS_BIT | ASN1_SET;
+
+ if (sig->algo_takes_data) {
+ sig->m_size = sinfo->authattrs_len;
+ ret = 0;
+ } else {
+ ret = crypto_shash_digest(desc, sig->m,
+ sinfo->authattrs_len,
+ sig->m);
+ if (ret < 0)
+ goto error;
+ }
pr_devel("AADigest = [%*ph]\n", 8, sig->m);
}
@@ -137,6 +150,11 @@ int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len,
ret = pkcs7_digest(pkcs7, sinfo);
if (ret)
return ret;
+ if (!sinfo->sig->m_free) {
+ pr_notice_once("%s: No digest available\n", __func__);
+ return -EINVAL; /* TODO: MLDSA doesn't necessarily calculate an
+ * intermediate digest. */
+ }
*buf = sinfo->sig->m;
*len = sinfo->sig->m_size;
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
index f4ec126121b3..a5ac7a53b670 100644
--- a/crypto/asymmetric_keys/signature.c
+++ b/crypto/asymmetric_keys/signature.c
@@ -28,7 +28,8 @@ void public_key_signature_free(struct public_key_signature *sig)
for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
kfree(sig->auth_ids[i]);
kfree(sig->s);
- kfree(sig->m);
+ if (sig->m_free)
+ kfree(sig->m);
kfree(sig);
}
}
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 3854f7ae4ed0..27b4fea37845 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -50,6 +50,14 @@ int x509_get_sig_params(struct x509_certificate *cert)
sig->s_size = cert->raw_sig_size;
+ if (sig->algo_takes_data) {
+ /* The signature algorithm does whatever passes for hashing. */
+ sig->m = (u8 *)cert->tbs;
+ sig->m_size = cert->tbs_size;
+ sig->m_free = false;
+ goto out;
+ }
+
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
@@ -69,6 +77,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
sig->m = kmalloc(sig->m_size, GFP_KERNEL);
if (!sig->m)
goto error;
+ sig->m_free = true;
desc = kzalloc(desc_size, GFP_KERNEL);
if (!desc)
@@ -84,6 +93,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
kfree(desc);
error:
crypto_free_shash(tfm);
+out:
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index bd38ba4d217d..4c5199b20338 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -46,6 +46,8 @@ struct public_key_signature {
u8 *m; /* Message data to pass to verifier */
u32 s_size; /* Number of bytes in signature */
u32 m_size; /* Number of bytes in ->m */
+ bool m_free; /* T if ->m needs freeing */
+ bool algo_takes_data; /* T if public key algo operates on data, not a hash */
const char *pkey_algo;
const char *hash_algo;
const char *encoding;
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v15 5/7] pkcs7, x509: Add ML-DSA support
2026-01-26 14:29 [PATCH v15 0/7] x509, pkcs7, crypto: Add ML-DSA signing David Howells
` (3 preceding siblings ...)
2026-01-26 14:29 ` [PATCH v15 4/7] pkcs7: Allow the signing algo to do whatever digestion it wants itself David Howells
@ 2026-01-26 14:29 ` David Howells
2026-01-26 14:29 ` [PATCH v15 6/7] modsign: Enable ML-DSA module signing David Howells
2026-01-26 14:29 ` [PATCH v15 7/7] pkcs7: Allow authenticatedAttributes for ML-DSA David Howells
6 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
Add support for ML-DSA keys and signatures to the CMS/PKCS#7 and X.509
implementations. ML-DSA-44, -65 and -87 are all supported. For X.509
certificates, the TBSCertificate is required to be signed directly; for CMS,
direct signing of the data is preferred, though use of SHA512 (and only that)
as an intermediate hash of the content is permitted with signedAttrs.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/asymmetric_keys/pkcs7_parser.c | 24 +++++++++++++++++++-
crypto/asymmetric_keys/public_key.c | 10 +++++++++
crypto/asymmetric_keys/x509_cert_parser.c | 27 ++++++++++++++++++++++-
include/linux/oid_registry.h | 5 +++++
4 files changed, 64 insertions(+), 2 deletions(-)
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 3cdbab3b9f50..594a8f1d9dfb 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -95,11 +95,18 @@ static int pkcs7_check_authattrs(struct pkcs7_message *msg)
if (sinfo->authattrs) {
want = true;
msg->have_authattrs = true;
+ } else if (sinfo->sig->algo_takes_data) {
+ sinfo->sig->hash_algo = "none";
}
- for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
+ for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next) {
if (!!sinfo->authattrs != want)
goto inconsistent;
+
+ if (!sinfo->authattrs &&
+ sinfo->sig->algo_takes_data)
+ sinfo->sig->hash_algo = "none";
+ }
return 0;
inconsistent:
@@ -297,6 +304,21 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
ctx->sinfo->sig->pkey_algo = "ecrdsa";
ctx->sinfo->sig->encoding = "raw";
break;
+ case OID_id_ml_dsa_44:
+ ctx->sinfo->sig->pkey_algo = "mldsa44";
+ ctx->sinfo->sig->encoding = "raw";
+ ctx->sinfo->sig->algo_takes_data = true;
+ break;
+ case OID_id_ml_dsa_65:
+ ctx->sinfo->sig->pkey_algo = "mldsa65";
+ ctx->sinfo->sig->encoding = "raw";
+ ctx->sinfo->sig->algo_takes_data = true;
+ break;
+ case OID_id_ml_dsa_87:
+ ctx->sinfo->sig->pkey_algo = "mldsa87";
+ ctx->sinfo->sig->encoding = "raw";
+ ctx->sinfo->sig->algo_takes_data = true;
+ break;
default:
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
return -ENOPKG;
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index a46356e0c08b..09a0b83d5d77 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -142,6 +142,16 @@ software_key_determine_akcipher(const struct public_key *pkey,
if (strcmp(hash_algo, "streebog256") != 0 &&
strcmp(hash_algo, "streebog512") != 0)
return -EINVAL;
+ } else if (strcmp(pkey->pkey_algo, "mldsa44") == 0 ||
+ strcmp(pkey->pkey_algo, "mldsa65") == 0 ||
+ strcmp(pkey->pkey_algo, "mldsa87") == 0) {
+ if (strcmp(encoding, "raw") != 0)
+ return -EINVAL;
+ if (!hash_algo)
+ return -EINVAL;
+ if (strcmp(hash_algo, "none") != 0 &&
+ strcmp(hash_algo, "sha512") != 0)
+ return -EINVAL;
} else {
/* Unknown public key algorithm */
return -ENOPKG;
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index b37cae914987..2fe094f5caf3 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -257,6 +257,15 @@ int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
case OID_gost2012Signature512:
ctx->cert->sig->hash_algo = "streebog512";
goto ecrdsa;
+ case OID_id_ml_dsa_44:
+ ctx->cert->sig->pkey_algo = "mldsa44";
+ goto ml_dsa;
+ case OID_id_ml_dsa_65:
+ ctx->cert->sig->pkey_algo = "mldsa65";
+ goto ml_dsa;
+ case OID_id_ml_dsa_87:
+ ctx->cert->sig->pkey_algo = "mldsa87";
+ goto ml_dsa;
}
rsa_pkcs1:
@@ -274,6 +283,12 @@ int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
ctx->cert->sig->encoding = "x962";
ctx->sig_algo = ctx->last_oid;
return 0;
+ml_dsa:
+ ctx->cert->sig->algo_takes_data = true;
+ ctx->cert->sig->hash_algo = "none";
+ ctx->cert->sig->encoding = "raw";
+ ctx->sig_algo = ctx->last_oid;
+ return 0;
}
/*
@@ -300,7 +315,8 @@ int x509_note_signature(void *context, size_t hdrlen,
if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 ||
strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 ||
- strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0) {
+ strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0 ||
+ strncmp(ctx->cert->sig->pkey_algo, "mldsa", 5) == 0) {
/* Discard the BIT STRING metadata */
if (vlen < 1 || *(const u8 *)value != 0)
return -EBADMSG;
@@ -524,6 +540,15 @@ int x509_extract_key_data(void *context, size_t hdrlen,
return -ENOPKG;
}
break;
+ case OID_id_ml_dsa_44:
+ ctx->cert->pub->pkey_algo = "mldsa44";
+ break;
+ case OID_id_ml_dsa_65:
+ ctx->cert->pub->pkey_algo = "mldsa65";
+ break;
+ case OID_id_ml_dsa_87:
+ ctx->cert->pub->pkey_algo = "mldsa87";
+ break;
default:
return -ENOPKG;
}
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
index 6de479ebbe5d..ebce402854de 100644
--- a/include/linux/oid_registry.h
+++ b/include/linux/oid_registry.h
@@ -145,6 +145,11 @@ enum OID {
OID_id_rsassa_pkcs1_v1_5_with_sha3_384, /* 2.16.840.1.101.3.4.3.15 */
OID_id_rsassa_pkcs1_v1_5_with_sha3_512, /* 2.16.840.1.101.3.4.3.16 */
+ /* NIST FIPS-204 ML-DSA */
+ OID_id_ml_dsa_44, /* 2.16.840.1.101.3.4.3.17 */
+ OID_id_ml_dsa_65, /* 2.16.840.1.101.3.4.3.18 */
+ OID_id_ml_dsa_87, /* 2.16.840.1.101.3.4.3.19 */
+
OID__NR
};
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v15 6/7] modsign: Enable ML-DSA module signing
2026-01-26 14:29 [PATCH v15 0/7] x509, pkcs7, crypto: Add ML-DSA signing David Howells
` (4 preceding siblings ...)
2026-01-26 14:29 ` [PATCH v15 5/7] pkcs7, x509: Add ML-DSA support David Howells
@ 2026-01-26 14:29 ` David Howells
2026-01-31 16:00 ` Michael Kelley
2026-01-26 14:29 ` [PATCH v15 7/7] pkcs7: Allow authenticatedAttributes for ML-DSA David Howells
6 siblings, 1 reply; 16+ messages in thread
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
Allow ML-DSA module signing to be enabled.
Note that OpenSSL's CMS_*() function suite does not, as of OpenSSL-3.6,
support the use of CMS_NOATTR with ML-DSA, so the prohibition against using
signedAttrs with module signing has to be removed. The selected digest
then applies only to the algorithm used to calculate the digest stored in
the messageDigest attribute. The OpenSSL development branch has patches
applied that fix this[1], but it appears that that will only be available
in OpenSSL-4.
[1] https://github.com/openssl/openssl/pull/28923
sign-file won't set CMS_NOATTR if openssl is earlier than v4, resulting in
the use of signed attributes.
The ML-DSA algorithm takes the raw data to be signed without regard to what
digest algorithm is specified in the CMS message. The CMS specified digest
algorithm is ignored unless signedAttrs are used; in such a case, only
SHA512 is permitted.
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
Documentation/admin-guide/module-signing.rst | 16 +++++----
certs/Kconfig | 30 +++++++++++++++++
certs/Makefile | 3 ++
scripts/sign-file.c | 34 +++++++++++++++-----
4 files changed, 68 insertions(+), 15 deletions(-)
diff --git a/Documentation/admin-guide/module-signing.rst b/Documentation/admin-guide/module-signing.rst
index a8667a777490..7f2f127dc76f 100644
--- a/Documentation/admin-guide/module-signing.rst
+++ b/Documentation/admin-guide/module-signing.rst
@@ -28,10 +28,12 @@ trusted userspace bits.
This facility uses X.509 ITU-T standard certificates to encode the public keys
involved. The signatures are not themselves encoded in any industrial standard
-type. The built-in facility currently only supports the RSA & NIST P-384 ECDSA
-public key signing standard (though it is pluggable and permits others to be
-used). The possible hash algorithms that can be used are SHA-2 and SHA-3 of
-sizes 256, 384, and 512 (the algorithm is selected by data in the signature).
+type. The built-in facility currently only supports the RSA, NIST P-384 ECDSA
+and NIST FIPS-204 ML-DSA public key signing standards (though it is pluggable
+and permits others to be used). For RSA and ECDSA, the possible hash
+algorithms that can be used are SHA-2 and SHA-3 of sizes 256, 384, and 512 (the
+algorithm is selected by data in the signature); ML-DSA does its own hashing,
+but is allowed to be used with a SHA512 hash for signed attributes.
==========================
@@ -146,9 +148,9 @@ into vmlinux) using parameters in the::
file (which is also generated if it does not already exist).
-One can select between RSA (``MODULE_SIG_KEY_TYPE_RSA``) and ECDSA
-(``MODULE_SIG_KEY_TYPE_ECDSA``) to generate either RSA 4k or NIST
-P-384 keypair.
+One can select between RSA (``MODULE_SIG_KEY_TYPE_RSA``), ECDSA
+(``MODULE_SIG_KEY_TYPE_ECDSA``) and ML-DSA (``MODULE_SIG_KEY_TYPE_MLDSA_*``) to
+generate an RSA 4k, a NIST P-384 keypair or an ML-DSA 44, 65 or 87 keypair.
It is strongly recommended that you provide your own x509.genkey file.
diff --git a/certs/Kconfig b/certs/Kconfig
index 78307dc25559..2b088ef58373 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -39,6 +39,36 @@ config MODULE_SIG_KEY_TYPE_ECDSA
Note: Remove all ECDSA signing keys, e.g. certs/signing_key.pem,
when falling back to building Linux 5.14 and older kernels.
+config MODULE_SIG_KEY_TYPE_MLDSA_44
+ bool "ML-DSA-44"
+ select CRYPTO_MLDSA
+ help
+ Use an ML-DSA-44 key (NIST FIPS 204) for module signing. ML-DSA
+ support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With
+ the latter, the entire module body will be signed; with the former,
+ signedAttrs will be used as it lacks support for CMS_NOATTR with
+ ML-DSA.
+
+config MODULE_SIG_KEY_TYPE_MLDSA_65
+ bool "ML-DSA-65"
+ select CRYPTO_MLDSA
+ help
+ Use an ML-DSA-65 key (NIST FIPS 204) for module signing. ML-DSA
+ support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With
+ the latter, the entire module body will be signed; with the former,
+ signedAttrs will be used as it lacks support for CMS_NOATTR with
+ ML-DSA.
+
+config MODULE_SIG_KEY_TYPE_MLDSA_87
+ bool "ML-DSA-87"
+ select CRYPTO_MLDSA
+ help
+ Use an ML-DSA-87 key (NIST FIPS 204) for module signing. ML-DSA
+ support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With
+ the latter, the entire module body will be signed; with the former,
+ signedAttrs will be used as it lacks support for CMS_NOATTR with
+ ML-DSA.
+
endchoice
config SYSTEM_TRUSTED_KEYRING
diff --git a/certs/Makefile b/certs/Makefile
index f6fa4d8d75e0..3ee1960f9f4a 100644
--- a/certs/Makefile
+++ b/certs/Makefile
@@ -43,6 +43,9 @@ targets += x509_certificate_list
ifeq ($(CONFIG_MODULE_SIG_KEY),certs/signing_key.pem)
keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_ECDSA) := -newkey ec -pkeyopt ec_paramgen_curve:secp384r1
+keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_44) := -newkey ml-dsa-44
+keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_65) := -newkey ml-dsa-65
+keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_87) := -newkey ml-dsa-87
quiet_cmd_gen_key = GENKEY $@
cmd_gen_key = openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index 7070245edfc1..547b97097230 100644
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -315,18 +315,36 @@ int main(int argc, char **argv)
ERR(!digest_algo, "EVP_get_digestbyname");
#ifndef USE_PKCS7
+
+ unsigned int flags =
+ CMS_NOCERTS |
+ CMS_PARTIAL |
+ CMS_BINARY |
+ CMS_DETACHED |
+ CMS_STREAM |
+ CMS_NOSMIMECAP |
+ CMS_NO_SIGNING_TIME |
+ use_keyid;
+
+ if ((EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
+ EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
+ EVP_PKEY_is_a(private_key, "ML-DSA-87")) &&
+ OPENSSL_VERSION_MAJOR < 4) {
+ /* ML-DSA + CMS_NOATTR is not supported in openssl-3.5
+ * and before.
+ */
+ use_signed_attrs = 0;
+ }
+
+ flags |= use_signed_attrs;
+
/* Load the signature message from the digest buffer. */
- cms = CMS_sign(NULL, NULL, NULL, NULL,
- CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
- CMS_DETACHED | CMS_STREAM);
+ cms = CMS_sign(NULL, NULL, NULL, NULL, flags);
ERR(!cms, "CMS_sign");
- ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
- CMS_NOCERTS | CMS_BINARY |
- CMS_NOSMIMECAP | use_keyid |
- use_signed_attrs),
+ ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, flags),
"CMS_add1_signer");
- ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) != 1,
+ ERR(CMS_final(cms, bm, NULL, flags) != 1,
"CMS_final");
#else
^ permalink raw reply related [flat|nested] 16+ messages in thread* RE: [PATCH v15 6/7] modsign: Enable ML-DSA module signing
2026-01-26 14:29 ` [PATCH v15 6/7] modsign: Enable ML-DSA module signing David Howells
@ 2026-01-31 16:00 ` Michael Kelley
2026-02-01 16:44 ` David Howells
0 siblings, 1 reply; 16+ messages in thread
From: Michael Kelley @ 2026-01-31 16:00 UTC (permalink / raw)
To: David Howells, Lukas Wunner, Ignat Korchagin
Cc: Jarkko Sakkinen, Herbert Xu, Eric Biggers, Luis Chamberlain,
Petr Pavlu, Daniel Gomez, Sami Tolvanen, Jason A . Donenfeld,
Ard Biesheuvel, Stephan Mueller, linux-crypto@vger.kernel.org,
keyrings@vger.kernel.org, linux-modules@vger.kernel.org,
linux-kernel@vger.kernel.org
From: David Howells <dhowells@redhat.com> Sent: Monday, January 26, 2026 6:29 AM
>
> Allow ML-DSA module signing to be enabled.
>
> Note that OpenSSL's CMS_*() function suite does not, as of OpenSSL-3.6,
> support the use of CMS_NOATTR with ML-DSA, so the prohibition against using
> signedAttrs with module signing has to be removed. The selected digest
> then applies only to the algorithm used to calculate the digest stored in
> the messageDigest attribute. The OpenSSL development branch has patches
> applied that fix this[1], but it appears that that will only be available
> in OpenSSL-4.
>
> [1] https://github.com/openssl/openssl/pull/28923
>
> sign-file won't set CMS_NOATTR if openssl is earlier than v4, resulting in
> the use of signed attributes.
>
> The ML-DSA algorithm takes the raw data to be signed without regard to what
> digest algorithm is specified in the CMS message. The CMS specified digest
> algorithm is ignored unless signedAttrs are used; in such a case, only
> SHA512 is permitted.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
> cc: Eric Biggers <ebiggers@kernel.org>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Stephan Mueller <smueller@chronox.de>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
I'm building linux-next20260130, which has this patch, and get the following errors:
HOSTCC scripts/sign-file
scripts/sign-file.c: In function 'main':
scripts/sign-file.c:282:25: error: 'CMS_NO_SIGNING_TIME' undeclared (first use in this function)
282 | CMS_NO_SIGNING_TIME |
| ^~~~~~~~~~~~~~~~~~~
scripts/sign-file.c:282:25: note: each undeclared identifier is reported only once for each function it appears in
scripts/sign-file.c:285:22: warning: implicit declaration of function 'EVP_PKEY_is_a'; did you mean 'EVP_PKEY_sign'? [-Wimplicit-function-declaration]
285 | if ((EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
| ^~~~~~~~~~~~~
| EVP_PKEY_sign
scripts/sign-file.c:288:21: error: 'OPENSSL_VERSION_MAJOR' undeclared (first use in this function); did you mean 'OPENSSL_VERSION_NUMBER'?
288 | OPENSSL_VERSION_MAJOR < 4) {
| ^~~~~~~~~~~~~~~~~~~~~
| OPENSSL_VERSION_NUMBER
The problem is that I'm running on Ubuntu 20.04, with this openssl:
# openssl version
OpenSSL 1.1.1f 31 Mar 2020
The symbols CMS_NO_SIGNING_TIME, EVP_PKEY_is_a() and OPENSSL_VERSION_MAJOR
don't exist in the include/openssl/* files for that old version.
Yes, I'm running on an old distro version which has been out-of-support for 9 months
now. But I suspect this patch is not intending to raise the kernel build requirements
to be openssl 3.0 or later -- at least there's no mention of that larger impact in the
commit message.
Thoughts? Can this patch be enhanced to handle openssl 1.1.1 appropriately?
Michael
> ---
> Documentation/admin-guide/module-signing.rst | 16 +++++----
> certs/Kconfig | 30 +++++++++++++++++
> certs/Makefile | 3 ++
> scripts/sign-file.c | 34 +++++++++++++++-----
> 4 files changed, 68 insertions(+), 15 deletions(-)
>
> diff --git a/Documentation/admin-guide/module-signing.rst b/Documentation/admin-
> guide/module-signing.rst
> index a8667a777490..7f2f127dc76f 100644
> --- a/Documentation/admin-guide/module-signing.rst
> +++ b/Documentation/admin-guide/module-signing.rst
> @@ -28,10 +28,12 @@ trusted userspace bits.
>
> This facility uses X.509 ITU-T standard certificates to encode the public keys
> involved. The signatures are not themselves encoded in any industrial standard
> -type. The built-in facility currently only supports the RSA & NIST P-384 ECDSA
> -public key signing standard (though it is pluggable and permits others to be
> -used). The possible hash algorithms that can be used are SHA-2 and SHA-3 of
> -sizes 256, 384, and 512 (the algorithm is selected by data in the signature).
> +type. The built-in facility currently only supports the RSA, NIST P-384 ECDSA
> +and NIST FIPS-204 ML-DSA public key signing standards (though it is pluggable
> +and permits others to be used). For RSA and ECDSA, the possible hash
> +algorithms that can be used are SHA-2 and SHA-3 of sizes 256, 384, and 512 (the
> +algorithm is selected by data in the signature); ML-DSA does its own hashing,
> +but is allowed to be used with a SHA512 hash for signed attributes.
>
>
> ==========================
> @@ -146,9 +148,9 @@ into vmlinux) using parameters in the::
>
> file (which is also generated if it does not already exist).
>
> -One can select between RSA (``MODULE_SIG_KEY_TYPE_RSA``) and ECDSA
> -(``MODULE_SIG_KEY_TYPE_ECDSA``) to generate either RSA 4k or NIST
> -P-384 keypair.
> +One can select between RSA (``MODULE_SIG_KEY_TYPE_RSA``), ECDSA
> +(``MODULE_SIG_KEY_TYPE_ECDSA``) and ML-DSA
> (``MODULE_SIG_KEY_TYPE_MLDSA_*``) to
> +generate an RSA 4k, a NIST P-384 keypair or an ML-DSA 44, 65 or 87 keypair.
>
> It is strongly recommended that you provide your own x509.genkey file.
>
> diff --git a/certs/Kconfig b/certs/Kconfig
> index 78307dc25559..2b088ef58373 100644
> --- a/certs/Kconfig
> +++ b/certs/Kconfig
> @@ -39,6 +39,36 @@ config MODULE_SIG_KEY_TYPE_ECDSA
> Note: Remove all ECDSA signing keys, e.g. certs/signing_key.pem,
> when falling back to building Linux 5.14 and older kernels.
>
> +config MODULE_SIG_KEY_TYPE_MLDSA_44
> + bool "ML-DSA-44"
> + select CRYPTO_MLDSA
> + help
> + Use an ML-DSA-44 key (NIST FIPS 204) for module signing. ML-DSA
> + support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With
> + the latter, the entire module body will be signed; with the former,
> + signedAttrs will be used as it lacks support for CMS_NOATTR with
> + ML-DSA.
> +
> +config MODULE_SIG_KEY_TYPE_MLDSA_65
> + bool "ML-DSA-65"
> + select CRYPTO_MLDSA
> + help
> + Use an ML-DSA-65 key (NIST FIPS 204) for module signing. ML-DSA
> + support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With
> + the latter, the entire module body will be signed; with the former,
> + signedAttrs will be used as it lacks support for CMS_NOATTR with
> + ML-DSA.
> +
> +config MODULE_SIG_KEY_TYPE_MLDSA_87
> + bool "ML-DSA-87"
> + select CRYPTO_MLDSA
> + help
> + Use an ML-DSA-87 key (NIST FIPS 204) for module signing. ML-DSA
> + support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With
> + the latter, the entire module body will be signed; with the former,
> + signedAttrs will be used as it lacks support for CMS_NOATTR with
> + ML-DSA.
> +
> endchoice
>
> config SYSTEM_TRUSTED_KEYRING
> diff --git a/certs/Makefile b/certs/Makefile
> index f6fa4d8d75e0..3ee1960f9f4a 100644
> --- a/certs/Makefile
> +++ b/certs/Makefile
> @@ -43,6 +43,9 @@ targets += x509_certificate_list
> ifeq ($(CONFIG_MODULE_SIG_KEY),certs/signing_key.pem)
>
> keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_ECDSA) := -newkey ec -pkeyopt
> ec_paramgen_curve:secp384r1
> +keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_44) := -newkey ml-dsa-44
> +keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_65) := -newkey ml-dsa-65
> +keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_87) := -newkey ml-dsa-87
>
> quiet_cmd_gen_key = GENKEY $@
> cmd_gen_key = openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -
> days 36500 \
> diff --git a/scripts/sign-file.c b/scripts/sign-file.c
> index 7070245edfc1..547b97097230 100644
> --- a/scripts/sign-file.c
> +++ b/scripts/sign-file.c
> @@ -315,18 +315,36 @@ int main(int argc, char **argv)
> ERR(!digest_algo, "EVP_get_digestbyname");
>
> #ifndef USE_PKCS7
> +
> + unsigned int flags =
> + CMS_NOCERTS |
> + CMS_PARTIAL |
> + CMS_BINARY |
> + CMS_DETACHED |
> + CMS_STREAM |
> + CMS_NOSMIMECAP |
> + CMS_NO_SIGNING_TIME |
> + use_keyid;
> +
> + if ((EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
> + EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
> + EVP_PKEY_is_a(private_key, "ML-DSA-87")) &&
> + OPENSSL_VERSION_MAJOR < 4) {
> + /* ML-DSA + CMS_NOATTR is not supported in openssl-3.5
> + * and before.
> + */
> + use_signed_attrs = 0;
> + }
> +
> + flags |= use_signed_attrs;
> +
> /* Load the signature message from the digest buffer. */
> - cms = CMS_sign(NULL, NULL, NULL, NULL,
> - CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
> - CMS_DETACHED | CMS_STREAM);
> + cms = CMS_sign(NULL, NULL, NULL, NULL, flags);
> ERR(!cms, "CMS_sign");
>
> - ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
> - CMS_NOCERTS | CMS_BINARY |
> - CMS_NOSMIMECAP | use_keyid |
> - use_signed_attrs),
> + ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, flags),
> "CMS_add1_signer");
> - ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) != 1,
> + ERR(CMS_final(cms, bm, NULL, flags) != 1,
> "CMS_final");
>
> #else
>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v15 6/7] modsign: Enable ML-DSA module signing
2026-01-31 16:00 ` Michael Kelley
@ 2026-02-01 16:44 ` David Howells
2026-02-01 19:30 ` Michael Kelley
0 siblings, 1 reply; 16+ messages in thread
From: David Howells @ 2026-02-01 16:44 UTC (permalink / raw)
To: Michael Kelley, Sami Tolvanen
Cc: dhowells, Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen,
Herbert Xu, Eric Biggers, Luis Chamberlain, Petr Pavlu,
Daniel Gomez, Jason A . Donenfeld, Ard Biesheuvel,
Stephan Mueller, linux-crypto@vger.kernel.org,
keyrings@vger.kernel.org, linux-modules@vger.kernel.org,
linux-kernel@vger.kernel.org
Michael Kelley <mhklinux@outlook.com> wrote:
> I'm building linux-next20260130, which has this patch, and get the following errors:
>
> HOSTCC scripts/sign-file
> scripts/sign-file.c: In function 'main':
> scripts/sign-file.c:282:25: error: 'CMS_NO_SIGNING_TIME' undeclared (first use in this function)
> ...
> The problem is that I'm running on Ubuntu 20.04, with this openssl:
>
> # openssl version
> OpenSSL 1.1.1f 31 Mar 2020
The problem probably isn't this patch, it's almost certainly due to:
d7afd65b4acc7 ("sign-file: Use only the OpenSSL CMS API for signing")
in the modules tree. It removes support for PKCS#7 signature generation.
Were you using PKCS#7 with SHA1?
David
^ permalink raw reply [flat|nested] 16+ messages in thread* RE: [PATCH v15 6/7] modsign: Enable ML-DSA module signing
2026-02-01 16:44 ` David Howells
@ 2026-02-01 19:30 ` Michael Kelley
2026-02-02 11:48 ` David Howells
0 siblings, 1 reply; 16+ messages in thread
From: Michael Kelley @ 2026-02-01 19:30 UTC (permalink / raw)
To: David Howells, Sami Tolvanen
Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
Eric Biggers, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto@vger.kernel.org, keyrings@vger.kernel.org,
linux-modules@vger.kernel.org, linux-kernel@vger.kernel.org
From: David Howells <dhowells@redhat.com> Sent: Sunday, February 1, 2026 8:45 AM
>
> Michael Kelley <mhklinux@outlook.com> wrote:
>
> > I'm building linux-next20260130, which has this patch, and get the following errors:
> >
> > HOSTCC scripts/sign-file
> > scripts/sign-file.c: In function 'main':
> > scripts/sign-file.c:282:25: error: 'CMS_NO_SIGNING_TIME' undeclared (first use in this function)
> > ...
> > The problem is that I'm running on Ubuntu 20.04, with this openssl:
> >
> > # openssl version
> > OpenSSL 1.1.1f 31 Mar 2020
>
> The problem probably isn't this patch, it's almost certainly due to:
>
> d7afd65b4acc7 ("sign-file: Use only the OpenSSL CMS API for signing")
>
> in the modules tree. It removes support for PKCS#7 signature generation.
>
> Were you using PKCS#7 with SHA1?
>
If I comment out code from 7ca1c9dcb7b0 as follows, sign-file.c will build. The
kernel will then build and run. I'm doing dev/test builds with no need to sign
anything. MODULE_SIG_ALL is not set.
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index 5391b5b7e178..724944cf8a26 100644
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -279,18 +279,15 @@ int main(int argc, char **argv)
CMS_DETACHED |
CMS_STREAM |
CMS_NOSMIMECAP |
- CMS_NO_SIGNING_TIME |
+ /* CMS_NO_SIGNING_TIME | */
use_keyid;
- if ((EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
+/* if ((EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
EVP_PKEY_is_a(private_key, "ML-DSA-87")) &&
- OPENSSL_VERSION_MAJOR < 4) {
- /* ML-DSA + CMS_NOATTR is not supported in openssl-3.5
- * and before.
- */
+ OPENSSL_VERSION_MAJOR < 4) {
use_signed_attrs = 0;
- }
+ } */
Pardon my ignorance of the signing details, but I don't see an indication
of having selected PKCS#7 with SHA1 in my .config. What am I looking for?
Michael
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v15 6/7] modsign: Enable ML-DSA module signing
2026-02-01 19:30 ` Michael Kelley
@ 2026-02-02 11:48 ` David Howells
2026-02-02 15:45 ` Michael Kelley
2026-02-03 9:42 ` Venkat
0 siblings, 2 replies; 16+ messages in thread
From: David Howells @ 2026-02-02 11:48 UTC (permalink / raw)
To: Michael Kelley
Cc: dhowells, Sami Tolvanen, Lukas Wunner, Ignat Korchagin,
Jarkko Sakkinen, Herbert Xu, Eric Biggers, Luis Chamberlain,
Petr Pavlu, Daniel Gomez, Jason A . Donenfeld, Ard Biesheuvel,
Stephan Mueller, linux-crypto@vger.kernel.org,
keyrings@vger.kernel.org, linux-modules@vger.kernel.org,
linux-kernel@vger.kernel.org
Michael Kelley <mhklinux@outlook.com> wrote:
> Pardon my ignorance of the signing details, but I don't see an indication
> of having selected PKCS#7 with SHA1 in my .config. What am I looking for?
Actually, if you have openssl >= 1.0.0 then it sign-file will be built to use
CMS rather than PKCS#7, and will use the configured hash algo, so you can
ignore this.
> The symbols CMS_NO_SIGNING_TIME,
I can probably just not add that.
> EVP_PKEY_is_a()
I guess I can probably make this contingent on >= 3.0.0.
> and OPENSSL_VERSION_MAJOR don't exist in the include/openssl/* files for
> that old version.
I should probably use OPENSSL_VERSION_NUMBER instead - though we already use
it for selecting #includes (I guess #if doesn't complain).
Do the attached changes work for you?
David
---
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index 547b97097230..78276b15ab23 100644
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -27,7 +27,7 @@
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
-#if OPENSSL_VERSION_MAJOR >= 3
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
# define USE_PKCS11_PROVIDER
# include <openssl/provider.h>
# include <openssl/store.h>
@@ -323,18 +323,21 @@ int main(int argc, char **argv)
CMS_DETACHED |
CMS_STREAM |
CMS_NOSMIMECAP |
+#ifdef CMS_NO_SIGNING_TIME
CMS_NO_SIGNING_TIME |
+#endif
use_keyid;
- if ((EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
- EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
- EVP_PKEY_is_a(private_key, "ML-DSA-87")) &&
- OPENSSL_VERSION_MAJOR < 4) {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L
+ if (EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
+ EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
+ EVP_PKEY_is_a(private_key, "ML-DSA-87")) {
/* ML-DSA + CMS_NOATTR is not supported in openssl-3.5
* and before.
*/
use_signed_attrs = 0;
}
+#endif
flags |= use_signed_attrs;
^ permalink raw reply related [flat|nested] 16+ messages in thread* RE: [PATCH v15 6/7] modsign: Enable ML-DSA module signing
2026-02-02 11:48 ` David Howells
@ 2026-02-02 15:45 ` Michael Kelley
2026-02-03 9:42 ` Venkat
1 sibling, 0 replies; 16+ messages in thread
From: Michael Kelley @ 2026-02-02 15:45 UTC (permalink / raw)
To: David Howells
Cc: Sami Tolvanen, Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen,
Herbert Xu, Eric Biggers, Luis Chamberlain, Petr Pavlu,
Daniel Gomez, Jason A . Donenfeld, Ard Biesheuvel,
Stephan Mueller, linux-crypto@vger.kernel.org,
keyrings@vger.kernel.org, linux-modules@vger.kernel.org,
linux-kernel@vger.kernel.org
From: David Howells <dhowells@redhat.com> Sent: Monday, February 2, 2026 3:48 AM
>
> Michael Kelley <mhklinux@outlook.com> wrote:
>
> > Pardon my ignorance of the signing details, but I don't see an indication
> > of having selected PKCS#7 with SHA1 in my .config. What am I looking for?
>
> Actually, if you have openssl >= 1.0.0 then it sign-file will be built to use
> CMS rather than PKCS#7, and will use the configured hash algo, so you can
> ignore this.
>
> > The symbols CMS_NO_SIGNING_TIME,
>
> I can probably just not add that.
>
> > EVP_PKEY_is_a()
>
> I guess I can probably make this contingent on >= 3.0.0.
>
> > and OPENSSL_VERSION_MAJOR don't exist in the include/openssl/* files for
> > that old version.
>
> I should probably use OPENSSL_VERSION_NUMBER instead - though we already use
> it for selecting #includes (I guess #if doesn't complain).
>
> Do the attached changes work for you?
Yes, these changes work in my environment. A full kernel build succeeds with
no errors, and the resulting kernel runs as expected.
Thanks!
Michael
>
> David
> ---
> diff --git a/scripts/sign-file.c b/scripts/sign-file.c
> index 547b97097230..78276b15ab23 100644
> --- a/scripts/sign-file.c
> +++ b/scripts/sign-file.c
> @@ -27,7 +27,7 @@
> #include <openssl/evp.h>
> #include <openssl/pem.h>
> #include <openssl/err.h>
> -#if OPENSSL_VERSION_MAJOR >= 3
> +#if OPENSSL_VERSION_NUMBER >= 0x30000000L
> # define USE_PKCS11_PROVIDER
> # include <openssl/provider.h>
> # include <openssl/store.h>
> @@ -323,18 +323,21 @@ int main(int argc, char **argv)
> CMS_DETACHED |
> CMS_STREAM |
> CMS_NOSMIMECAP |
> +#ifdef CMS_NO_SIGNING_TIME
> CMS_NO_SIGNING_TIME |
> +#endif
> use_keyid;
>
> - if ((EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
> - EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
> - EVP_PKEY_is_a(private_key, "ML-DSA-87")) &&
> - OPENSSL_VERSION_MAJOR < 4) {
> +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L
> + if (EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
> + EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
> + EVP_PKEY_is_a(private_key, "ML-DSA-87")) {
> /* ML-DSA + CMS_NOATTR is not supported in openssl-3.5
> * and before.
> */
> use_signed_attrs = 0;
> }
> +#endif
>
> flags |= use_signed_attrs;
>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v15 6/7] modsign: Enable ML-DSA module signing
2026-02-02 11:48 ` David Howells
2026-02-02 15:45 ` Michael Kelley
@ 2026-02-03 9:42 ` Venkat
1 sibling, 0 replies; 16+ messages in thread
From: Venkat @ 2026-02-03 9:42 UTC (permalink / raw)
To: David Howells
Cc: Michael Kelley, Sami Tolvanen, Lukas Wunner, Ignat Korchagin,
Jarkko Sakkinen, Herbert Xu, Eric Biggers, Luis Chamberlain,
Petr Pavlu, Daniel Gomez, Jason A . Donenfeld, Ard Biesheuvel,
Stephan Mueller, linux-crypto@vger.kernel.org,
keyrings@vger.kernel.org, linux-modules@vger.kernel.org,
linux-kernel@vger.kernel.org
> On 2 Feb 2026, at 5:18 PM, David Howells <dhowells@redhat.com> wrote:
>
> Michael Kelley <mhklinux@outlook.com> wrote:
>
>> Pardon my ignorance of the signing details, but I don't see an indication
>> of having selected PKCS#7 with SHA1 in my .config. What am I looking for?
>
> Actually, if you have openssl >= 1.0.0 then it sign-file will be built to use
> CMS rather than PKCS#7, and will use the configured hash algo, so you can
> ignore this.
>
>> The symbols CMS_NO_SIGNING_TIME,
>
> I can probably just not add that.
>
>> EVP_PKEY_is_a()
>
> I guess I can probably make this contingent on >= 3.0.0.
>
>> and OPENSSL_VERSION_MAJOR don't exist in the include/openssl/* files for
>> that old version.
>
> I should probably use OPENSSL_VERSION_NUMBER instead - though we already use
> it for selecting #includes (I guess #if doesn't complain).
>
> Do the attached changes work for you?
>
> David
> ---
> diff --git a/scripts/sign-file.c b/scripts/sign-file.c
> index 547b97097230..78276b15ab23 100644
> --- a/scripts/sign-file.c
> +++ b/scripts/sign-file.c
> @@ -27,7 +27,7 @@
> #include <openssl/evp.h>
> #include <openssl/pem.h>
> #include <openssl/err.h>
> -#if OPENSSL_VERSION_MAJOR >= 3
> +#if OPENSSL_VERSION_NUMBER >= 0x30000000L
> # define USE_PKCS11_PROVIDER
> # include <openssl/provider.h>
> # include <openssl/store.h>
> @@ -323,18 +323,21 @@ int main(int argc, char **argv)
> CMS_DETACHED |
> CMS_STREAM |
> CMS_NOSMIMECAP |
> +#ifdef CMS_NO_SIGNING_TIME
> CMS_NO_SIGNING_TIME |
> +#endif
> use_keyid;
>
> - if ((EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
> - EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
> - EVP_PKEY_is_a(private_key, "ML-DSA-87")) &&
> - OPENSSL_VERSION_MAJOR < 4) {
> +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L
> + if (EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
> + EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
> + EVP_PKEY_is_a(private_key, "ML-DSA-87")) {
> /* ML-DSA + CMS_NOATTR is not supported in openssl-3.5
> * and before.
> */
> use_signed_attrs = 0;
> }
> +#endif
>
> flags |= use_signed_attrs;
>
Tested this, and build is successful. Please add below tag.
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Regards,
Venkat.
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v15 7/7] pkcs7: Allow authenticatedAttributes for ML-DSA
2026-01-26 14:29 [PATCH v15 0/7] x509, pkcs7, crypto: Add ML-DSA signing David Howells
` (5 preceding siblings ...)
2026-01-26 14:29 ` [PATCH v15 6/7] modsign: Enable ML-DSA module signing David Howells
@ 2026-01-26 14:29 ` David Howells
6 siblings, 0 replies; 16+ messages in thread
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
Allow the rejection of authenticatedAttributes in PKCS#7 (signedAttrs in
CMS) to be waived in the kernel config for ML-DSA when used for module
signing. This reflects the issue that openssl < 4.0 cannot do this and
openssl-4 has not yet been released.
This does not permit RSA, ECDSA or ECRDSA to be so waived (behaviour
unchanged).
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Jarkko Sakkinen <jarkko@kernel.org>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/asymmetric_keys/Kconfig | 11 +++++++++++
crypto/asymmetric_keys/pkcs7_parser.c | 8 ++++++++
crypto/asymmetric_keys/pkcs7_parser.h | 3 +++
crypto/asymmetric_keys/pkcs7_verify.c | 6 ++++++
4 files changed, 28 insertions(+)
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index e1345b8f39f1..1dae2232fe9a 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -53,6 +53,17 @@ config PKCS7_MESSAGE_PARSER
This option provides support for parsing PKCS#7 format messages for
signature data and provides the ability to verify the signature.
+config PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA
+ bool "Waive rejection of authenticatedAttributes for ML-DSA"
+ depends on PKCS7_MESSAGE_PARSER
+ depends on CRYPTO_MLDSA
+ help
+ Due to use of CMS_NOATTR with ML-DSA not being supported in
+ OpenSSL < 4.0 (and thus any released version), enabling this
+ allows authenticatedAttributes to be used with ML-DSA for
+ module signing. Use of authenticatedAttributes in this
+ context is normally rejected.
+
config PKCS7_TEST_KEY
tristate "PKCS#7 testing key type"
depends on SYSTEM_DATA_VERIFICATION
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 594a8f1d9dfb..db1c90ca6fc1 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -92,9 +92,17 @@ static int pkcs7_check_authattrs(struct pkcs7_message *msg)
if (!sinfo)
goto inconsistent;
+#ifdef CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA
+ msg->authattrs_rej_waivable = true;
+#endif
+
if (sinfo->authattrs) {
want = true;
msg->have_authattrs = true;
+#ifdef CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA
+ if (strncmp(sinfo->sig->pkey_algo, "mldsa", 5) != 0)
+ msg->authattrs_rej_waivable = false;
+#endif
} else if (sinfo->sig->algo_takes_data) {
sinfo->sig->hash_algo = "none";
}
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
index e17f7ce4fb43..6ef9f335bb17 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.h
+++ b/crypto/asymmetric_keys/pkcs7_parser.h
@@ -55,6 +55,9 @@ struct pkcs7_message {
struct pkcs7_signed_info *signed_infos;
u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */
bool have_authattrs; /* T if have authattrs */
+#ifdef CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA
+ bool authattrs_rej_waivable; /* T if authatts rejection can be waived */
+#endif
/* Content Data (or NULL) */
enum OID data_type; /* Type of Data */
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 06abb9838f95..519eecfe6778 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -425,6 +425,12 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
return -EKEYREJECTED;
}
if (pkcs7->have_authattrs) {
+#ifdef CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA
+ if (pkcs7->authattrs_rej_waivable) {
+ pr_warn("Waived invalid module sig (has authattrs)\n");
+ break;
+ }
+#endif
pr_warn("Invalid module sig (has authattrs)\n");
return -EKEYREJECTED;
}
^ permalink raw reply related [flat|nested] 16+ messages in thread