crypto: Add ML-DSA crypto_sig support

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
This commit is contained in:
David Howells
2025-11-20 09:15:19 +00:00
parent 959a634ebc
commit d3b6dd90e2
3 changed files with 212 additions and 0 deletions

View File

@@ -344,6 +344,15 @@ config CRYPTO_ECRDSA
One of the Russian cryptographic standard algorithms (called GOST One of the Russian cryptographic standard algorithms (called GOST
algorithms). Only signature verification is implemented. 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 endmenu
menu "Block ciphers" menu "Block ciphers"

View File

@@ -60,6 +60,8 @@ ecdsa_generic-y += ecdsa-p1363.o
ecdsa_generic-y += ecdsasignature.asn1.o ecdsa_generic-y += ecdsasignature.asn1.o
obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o
obj-$(CONFIG_CRYPTO_MLDSA) += mldsa.o
crypto_acompress-y := acompress.o crypto_acompress-y := acompress.o
crypto_acompress-y += scompress.o crypto_acompress-y += scompress.o
obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o

201
crypto/mldsa.c Normal file
View File

@@ -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");