Commit d3b6dd90 authored by David Howells's avatar David Howells
Browse files

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: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarJarkko 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
parent 959a634e
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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"
+2 −0
Original line number Diff line number Diff line
@@ -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

crypto/mldsa.c

0 → 100644
+201 −0
Original line number Diff line number Diff line
// 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");