]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
crypto: Add ML-DSA crypto_sig support
authorDavid Howells <dhowells@redhat.com>
Thu, 20 Nov 2025 09:15:19 +0000 (09:15 +0000)
committerDavid Howells <dhowells@redhat.com>
Wed, 21 Jan 2026 22:32:50 +0000 (22:32 +0000)
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
crypto/Makefile
crypto/mldsa.c [new file with mode: 0644]

index 12a87f7cf1502fc89955f1dc2a2805604b56348e..a210575fa5e0ef8bd37788a62c834b6b3eaaaf84 100644 (file)
@@ -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"
index 23d3db7be4257c94f67ed605a996606b8eee8839..267d5403045bd8e239681d60a7e7db56580f2176 100644 (file)
@@ -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 (file)
index 0000000..d8de082
--- /dev/null
@@ -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");