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 <[email protected]>
cc: Eric Biggers <[email protected]>
cc: Lukas Wunner <[email protected]>
cc: Ignat Korchagin <[email protected]>
cc: Stephan Mueller <[email protected]>
cc: Herbert Xu <[email protected]>
cc: [email protected]
cc: [email protected]
---
 crypto/Kconfig  |  10 +++
 crypto/Makefile |   2 +
 crypto/mldsa.c  | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 213 insertions(+)
 create mode 100644 crypto/mldsa.c

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 12a87f7cf150..8dd5c6660c5a 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -344,6 +344,16 @@ 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
+       select CRYPTO_LIB_SHA3
+       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..2146c774b5ca
--- /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;
+       u8 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");


Reply via email to