public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing
@ 2026-01-20 14:50 David Howells
  2026-01-20 14:50 ` [PATCH v13 01/12] crypto: Add ML-DSA crypto_sig support David Howells
                   ` (11 more replies)
  0 siblings, 12 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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

Hi Lukas, Ignat,

[Note this is based on Eric Bigger's libcrypto-next branch].

These patches add ML-DSA module signing and RSASSA-PSS module signing.  The
first half of the set adds ML-DSA signing:

 (1) Add a crypto_sig interface for ML-DSA, verification only.

 (2) Modify PKCS#7 support to allow kernel module signatures to carry
     authenticatedAttributes as OpenSSL refuses to let them be opted out of
     for ML-DSA (CMS_NOATTR).  This adds an extra digest calculation to the
     process.

     Modify PKCS#7 to pass the authenticatedAttributes directly to the
     ML-DSA algorithm rather than passing over a digest as is done with RSA
     as ML-DSA wants to do its own hashing and will add other stuff into
     the hash.  We could use hashML-DSA or an external mu instead, but they
     aren't standardised for CMS yet.

 (3) Add support to the PKCS#7 and X.509 parsers for ML-DSA.

 (4) Modify sign-file to handle OpenSSL not permitting CMS_NOATTR with
     ML-DSA and add ML-DSA to the choice of algorithm with which to sign
     modules.  Note that this might need some more 'select' lines in the
     Kconfig to select the lib stuff as well.

This is based on Eric's libcrypto-next branch which has the core
implementation of ML-DSA.

The second half of the set adds RSASSA-PSS signing:

 (5) Add an info string parameter to the internal signature verification
     routines where that does not already exist.  This is necessary to pass
     extra parameters and is already supported in the KEYCTL_PKEY_VERIFY
     keyctl.

     Both X.509 and PKCS#7 provide for these parameters to be supplied, but
     it is tricky to pass the parameters in a blob with the signature or
     key data as there are checks on these sizes that are then violated;
     further, the way the parameters are laid out in the ASN.1 doesn't lend
     itself easily to simply extracting out a larger blob.

 (6) Add RSASSA-PSS support to the RSA driver in crypto/.  This parses the
     info string to get the verification parameters.

 (7) Add support to the PKCS#7 and X.509 parsers for RSASSA-PSS.

 (8) Modify sign-file to pass the extra parameters necessary to be able
     generate RSASSA-PSS.  For the moment, only select MGF1 with the same
     hash algorithm as for the data for the mask function.  Add RSASSA-PSS
     to the choice of algorithm with which to sign modules.

Note that I do still need to add some FIPS tests for ML-DSA in the form of
X.509 certs, data and detached PKCS#7 signatures.  I'm not sure if I can
use FIPS-standard tests for that.

The patches can also be found here:

	https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-pqc

David

Changes
=======
ver #13)
 - Allow a zero-length salt in RSAPSS-PSS.
 - Don't reject ECDSA/ECRDSA with SHA256 and SHA384 otherwise the FIPS
   selftest panics when used.
 - Add a FIPS test for RSASSA-PSS (from NIST's SigVerPSS_186-3.rsp).
 - Add a FIPS test for ML-DSA (from NIST's FIPS204 JSON set).

ver #12)
 - Rebased on Eric's libcrypto-next branch.
 - Delete references to Dilithium (ML-DSA derived from this).
 - Made sign-file supply CMS_NOATTR for ML-DSA if openssl >= v4.
 - Made it possible to do ML-DSA over the data without signedAttrs.
 - Made RSASSA-PSS info parser use strsep() and match_token().
 - Cleaned the RSASSA-PSS param parsing.
 - Added limitation on what hashes can be used with what algos.
 - Moved __free()-marked variables to the point of setting.

ver #11)
 - Rebased on Eric's libcrypto-next branch.
 - Added RSASSA-PSS support patches.

ver #10)
 - Replaced the Leancrypto ML-DSA implementation with Eric's.
 - Fixed Eric's implementation to have MODULE_* info.
 - Added a patch to drive Eric's ML-DSA implementation from crypto_sig.
 - Removed SHAKE256 from the list of available module hash algorithms.
 - Changed a some more ML_DSA to MLDSA in config symbols.

ver #9)
 - ML-DSA changes:
   - Separate output into four modules (1 common, 3 strength-specific).
     - Solves Kconfig issue with needing to select at least one strength.
   - Separate the strength-specific crypto-lib APIs.
     - This is now generated by preprocessor-templating.
   - Remove the multiplexor code.
   - Multiplex the crypto-lib APIs by C type.
 - Fix the PKCS#7/X.509 code to have the correct algo names.

ver #8)
 - Moved the ML-DSA code to lib/crypto/mldsa/.
 - Renamed some bits from ml-dsa to mldsa.
 - Created a simplified API and placed that in include/crypto/mldsa.h.
 - Made the testing code use the simplified API.
 - Fixed a warning about implicitly casting between uint16_t and __le16.

ver #7)
 - Rebased on Eric's tree as that now contains all the necessary SHA-3
   infrastructure and drop the SHA-3 patches from here.
 - Added a minimal patch to provide shake256 support for crypto_sig.
 - Got rid of the memory allocation wrappers.
 - Removed the ML-DSA keypair generation code and the signing code, leaving
   only the signature verification code.
 - Removed the secret key handling code.
 - Removed the secret keys from the kunit tests and the signing testing.
 - Removed some unused bits from the ML-DSA code.
 - Downgraded the kdoc comments to ordinary comments, but keep the markup
   for easier comparison to Leancrypto.

ver #6)
 - Added a patch to make the jitterentropy RNG use lib/sha3.
 - Added back the crypto/sha3_generic changes.
 - Added ML-DSA implementation (still needs more cleanup).
 - Added kunit test for ML-DSA.
 - Modified PKCS#7 to accommodate ML-DSA.
 - Modified PKCS#7 and X.509 to allow ML-DSA to be specified and used.
 - Modified sign-file to not use CMS_NOATTR with ML-DSA.
 - Allowed SHA3 and SHAKE* algorithms for module signing default.
 - Allowed ML-DSA-{44,65,87} to be selected as the module signing default.

ver #5)
 - Fix gen-hash-testvecs.py to correctly handle algo names that contain a
   dash.
 - Fix gen-hash-testvecs.py to not generate HMAC for SHA3-* or SHAKE* as
   these don't currently have HMAC variants implemented.
 - Fix algo names to be correct.
 - Fix kunit module description as it now tests all SHA3 variants.

ver #4)
 - Fix a couple of arm64 build problems.
 - Doc fixes:
   - Fix the description of the algorithm to be closer to the NIST spec's
     terminology.
   - Don't talk of finialising the context for XOFs.
   - Don't say "Return: None".
   - Declare the "Context" to be "Any context" and make no mention of the
     fact that it might use the FPU.
   - Change "initialise" to "initialize".
   - Don't warn that the context is relatively large for stack use.
 - Use size_t for size parameters/variables.
 - Make the module_exit unconditional.
 - Dropped the crypto/ dir-affecting patches for the moment.

ver #3)
 - Renamed conflicting arm64 functions.
 - Made a separate wrapper API for each algorithm in the family.
 - Removed sha3_init(), sha3_reinit() and sha3_final().
 - Removed sha3_ctx::digest_size.
 - Renamed sha3_ctx::partial to sha3_ctx::absorb_offset.
 - Refer to the output of SHAKE* as "output" not "digest".
 - Moved the Iota transform into the one-round function.
 - Made sha3_update() warn if called after sha3_squeeze().
 - Simplified the module-load test to not do update after squeeze.
 - Added Return: and Context: kdoc statements and expanded the kdoc
   headers.
 - Added an API description document.
 - Overhauled the kunit tests.
   - Only have one kunit test.
   - Only call the general hash tester on one algo.
   - Add separate simple cursory checks for the other algos.
   - Add resqueezing tests.
   - Add some NIST example tests.
 - Changed crypto/sha3_generic to use this
 - Added SHAKE128/256 to crypto/sha3_generic and crypto/testmgr
 - Folded struct sha3_state into struct sha3_ctx.

ver #2)
  - Simplify the endianness handling.
  - Rename sha3_final() to sha3_squeeze() and don't clear the context at the
    end as it's permitted to continue calling sha3_final() to extract
    continuations of the digest (needed by ML-DSA).
  - Don't reapply the end marker to the hash state in continuation
    sha3_squeeze() unless sha3_update() gets called again (needed by
    ML-DSA).
  - Give sha3_squeeze() the amount of digest to produce as a parameter
    rather than using ctx->digest_size and don't return the amount digested.
  - Reimplement sha3_final() as a wrapper around sha3_squeeze() that
    extracts ctx->digest_size amount of digest and then zeroes out the
    context.  The latter is necessary to avoid upsetting
    hash-test-template.h.
  - Provide a sha3_reinit() function to clear the state, but to leave the
    parameters that indicate the hash properties unaffected, allowing for
    reuse.
  - Provide a sha3_set_digestsize() function to change the size of the
    digest to be extracted by sha3_final().  sha3_squeeze() takes a
    parameter for this instead.
  - Don't pass the digest size as a parameter to shake128/256_init() but
    rather default to 128/256 bits as per the function name.
  - Provide a sha3_clear() function to zero out the context.

David Howells (12):
  crypto: Add ML-DSA crypto_sig support
  pkcs7: Allow the signing algo to calculate the digest itself
  pkcs7: Allow direct signing of data with ML-DSA
  pkcs7, x509: Add ML-DSA support
  modsign: Enable ML-DSA module signing
  crypto: Add supplementary info param to asymmetric key signature
    verification
  crypto: Add RSASSA-PSS support
  pkcs7, x509: Add RSASSA-PSS support
  modsign: Enable RSASSA-PSS module signing
  pkcs7: Add FIPS selftest for RSASSA-PSS
  x509, pkcs7: Limit crypto combinations that may be used for module
    signing
  pkcs7: Add ML-DSA FIPS selftest

 Documentation/admin-guide/module-signing.rst |  17 +-
 certs/Kconfig                                |  27 +
 certs/Makefile                               |   4 +
 crypto/Kconfig                               |  10 +
 crypto/Makefile                              |   3 +
 crypto/asymmetric_keys/Kconfig               |   6 +
 crypto/asymmetric_keys/Makefile              |  13 +-
 crypto/asymmetric_keys/asymmetric_type.c     |   1 +
 crypto/asymmetric_keys/mgf1_params.asn1      |  12 +
 crypto/asymmetric_keys/mscode_parser.c       |   2 +-
 crypto/asymmetric_keys/pkcs7.asn1            |   2 +-
 crypto/asymmetric_keys/pkcs7_parser.c        | 115 ++--
 crypto/asymmetric_keys/pkcs7_verify.c        |  70 +-
 crypto/asymmetric_keys/public_key.c          |  74 +-
 crypto/asymmetric_keys/rsassa_params.asn1    |  25 +
 crypto/asymmetric_keys/rsassa_parser.c       | 240 +++++++
 crypto/asymmetric_keys/rsassa_parser.h       |  25 +
 crypto/asymmetric_keys/selftest.c            |   1 +
 crypto/asymmetric_keys/selftest.h            |   6 +
 crypto/asymmetric_keys/selftest_mldsa.c      | 688 +++++++++++++++++++
 crypto/asymmetric_keys/selftest_rsa.c        | 133 ++++
 crypto/asymmetric_keys/signature.c           |   4 +-
 crypto/asymmetric_keys/verify_pefile.c       |   3 +-
 crypto/asymmetric_keys/verify_pefile.h       |   1 +
 crypto/asymmetric_keys/x509.asn1             |   2 +-
 crypto/asymmetric_keys/x509_cert_parser.c    | 124 ++--
 crypto/asymmetric_keys/x509_parser.h         |  45 +-
 crypto/asymmetric_keys/x509_public_key.c     |  37 +-
 crypto/ecdsa-p1363.c                         |   5 +-
 crypto/ecdsa-x962.c                          |   5 +-
 crypto/ecdsa.c                               |   3 +-
 crypto/ecrdsa.c                              |   3 +-
 crypto/mldsa.c                               | 202 ++++++
 crypto/rsa.c                                 |   8 +
 crypto/rsassa-pkcs1.c                        |   3 +-
 crypto/rsassa-pss.c                          | 383 +++++++++++
 crypto/sig.c                                 |   3 +-
 crypto/testmgr.c                             |   2 +-
 crypto/testmgr.h                             |   1 +
 include/crypto/hash.h                        |   3 +
 include/crypto/internal/rsa.h                |   2 +
 include/crypto/public_key.h                  |   3 +
 include/crypto/sig.h                         |   9 +-
 include/linux/oid_registry.h                 |   7 +
 scripts/sign-file.c                          |  71 +-
 45 files changed, 2235 insertions(+), 168 deletions(-)
 create mode 100644 crypto/asymmetric_keys/mgf1_params.asn1
 create mode 100644 crypto/asymmetric_keys/rsassa_params.asn1
 create mode 100644 crypto/asymmetric_keys/rsassa_parser.c
 create mode 100644 crypto/asymmetric_keys/rsassa_parser.h
 create mode 100644 crypto/asymmetric_keys/selftest_mldsa.c
 create mode 100644 crypto/mldsa.c
 create mode 100644 crypto/rsassa-pss.c


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v13 01/12] crypto: Add ML-DSA crypto_sig support
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 17:37   ` Jarkko Sakkinen
  2026-01-20 20:52   ` Eric Biggers
  2026-01-20 14:50 ` [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself David Howells
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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>
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  |  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");


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
  2026-01-20 14:50 ` [PATCH v13 01/12] crypto: Add ML-DSA crypto_sig support David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 17:53   ` Jarkko Sakkinen
  2026-01-20 21:12   ` Eric Biggers
  2026-01-20 14:50 ` [PATCH v13 03/12] pkcs7: Allow direct signing of data with ML-DSA David Howells
                   ` (9 subsequent siblings)
  11 siblings, 2 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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

The ML-DSA public key algorithm really wants to calculate the message
digest itself, rather than having the digest precalculated and fed to it
separately as RSA does[*].  The kernel's PKCS#7 parser, however, is
designed around the latter approach.

  [*] ML-DSA does allow for an "external mu", but CMS doesn't yet have that
  standardised.

Fix this by noting in the public_key_signature struct when the signing
algorithm is going to want this and then, rather than doing the digest of
the authenticatedAttributes ourselves and overwriting the sig->digest with
that, replace sig->digest with a copy of the contents of the
authenticatedAttributes section and adjust the digest length to match.

This will then be fed to the public key algorithm as normal which can do
what it wants with the data.

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 | 48 ++++++++++++++++++---------
 include/crypto/public_key.h           |  1 +
 3 files changed, 36 insertions(+), 17 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 6d6475e3a9bf..0f9f515b784d 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -70,8 +70,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;
@@ -97,20 +95,40 @@ 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->digest, 0, sig->digest_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->digest);
-		if (ret < 0)
-			goto error;
+		if (sig->algo_does_hash) {
+			kfree(sig->digest);
+
+			ret = -ENOMEM;
+			sig->digest = kmalloc(umax(sinfo->authattrs_len, sig->digest_size),
+					      GFP_KERNEL);
+			if (!sig->digest)
+				goto error_no_desc;
+
+			sig->digest_size = sinfo->authattrs_len;
+			memcpy(sig->digest, sinfo->authattrs, sinfo->authattrs_len);
+			((u8 *)sig->digest)[0] = ASN1_CONS_BIT | ASN1_SET;
+			ret = 0;
+		} else {
+			u8 tag = ASN1_CONS_BIT | ASN1_SET;
+
+			ret = crypto_shash_init(desc);
+			if (ret < 0)
+				goto error;
+			ret = crypto_shash_update(desc, &tag, 1);
+			if (ret < 0)
+				goto error;
+			ret = crypto_shash_finup(desc, sinfo->authattrs + 1,
+						 sinfo->authattrs_len - 1,
+						 sig->digest);
+			if (ret < 0)
+				goto error;
+		}
 		pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
 	}
 
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 81098e00c08f..e4ec8003a3a4 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -46,6 +46,7 @@ struct public_key_signature {
 	u8 *digest;
 	u32 s_size;		/* Number of bytes in signature */
 	u32 digest_size;	/* Number of bytes in digest */
+	bool algo_does_hash;	/* Public key algo does its own hashing */
 	const char *pkey_algo;
 	const char *hash_algo;
 	const char *encoding;


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v13 03/12] pkcs7: Allow direct signing of data with ML-DSA
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
  2026-01-20 14:50 ` [PATCH v13 01/12] crypto: Add ML-DSA crypto_sig support David Howells
  2026-01-20 14:50 ` [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 14:50 ` [PATCH v13 04/12] pkcs7, x509: Add ML-DSA support David Howells
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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 part of a PKCS#7 or CMS messge to be passed directly to an
asymmetric cipher algorithm (e.g. ML-DSA) if it wants to do the 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.

This is done by setting the digest parameters to 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.

To test this with ML-DSA, sign-file must be built with openssl > v3.5 and
must include the following fix:

	https://github.com/openssl/openssl/pull/28923

which will allow CMS_NOATTR to be used with CMS_sign() for an ML-DSA key.

sign-file will remove CMS_NOATTR if openssl is earlier than v4 and signed
attributes will be used.

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/mscode_parser.c   |  2 +-
 crypto/asymmetric_keys/pkcs7_verify.c    | 18 ++++++++++++++++++
 crypto/asymmetric_keys/signature.c       |  3 ++-
 crypto/asymmetric_keys/verify_pefile.c   |  3 ++-
 crypto/asymmetric_keys/verify_pefile.h   |  1 +
 crypto/asymmetric_keys/x509_public_key.c |  1 +
 include/crypto/public_key.h              |  1 +
 7 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c
index 8aecbe4637f3..54dac17f19e2 100644
--- a/crypto/asymmetric_keys/mscode_parser.c
+++ b/crypto/asymmetric_keys/mscode_parser.c
@@ -124,6 +124,6 @@ int mscode_note_digest(void *context, size_t hdrlen,
 		return -ENOMEM;
 
 	ctx->digest_len = vlen;
-
+	ctx->digest_free = true;
 	return 0;
 }
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 0f9f515b784d..46eee9811023 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_does_hash) {
+		/* There's no intermediate digest and the signature algo
+		 * doesn't want the data prehashing.
+		 */
+		sig->digest = (void *)pkcs7->data;
+		sig->digest_size = pkcs7->data_len;
+		sig->digest_free = false;
+		return 0;
+	}
+
 	/* The digest was calculated already. */
 	if (sig->digest)
 		return 0;
@@ -51,6 +61,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
 	if (!sig->digest)
 		goto error_no_desc;
+	sig->digest_free = true;
 
 	desc = kzalloc(desc_size, GFP_KERNEL);
 	if (!desc)
@@ -103,6 +114,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 		 */
 		if (sig->algo_does_hash) {
 			kfree(sig->digest);
+			sig->digest_free = false;
 
 			ret = -ENOMEM;
 			sig->digest = kmalloc(umax(sinfo->authattrs_len, sig->digest_size),
@@ -110,6 +122,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 			if (!sig->digest)
 				goto error_no_desc;
 
+			sig->digest_free = true;
 			sig->digest_size = sinfo->authattrs_len;
 			memcpy(sig->digest, sinfo->authattrs, sinfo->authattrs_len);
 			((u8 *)sig->digest)[0] = ASN1_CONS_BIT | ASN1_SET;
@@ -155,6 +168,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->digest_free) {
+		pr_notice_once("%s: No digest available\n", __func__);
+		return -EINVAL; /* TODO: MLDSA doesn't necessarily calculate an
+				 * intermediate digest. */
+	}
 
 	*buf = sinfo->sig->digest;
 	*len = sinfo->sig->digest_size;
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
index 041d04b5c953..bea01cf27d0a 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->digest);
+		if (sig->digest_free)
+			kfree(sig->digest);
 		kfree(sig);
 	}
 }
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index 1f3b227ba7f2..30c23aea3b25 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -451,6 +451,7 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
 	ret = pefile_digest_pe(pebuf, pelen, &ctx);
 
 error:
-	kfree_sensitive(ctx.digest);
+	if (ctx.digest_free)
+		kfree_sensitive(ctx.digest);
 	return ret;
 }
diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h
index e1628e100cde..f641437264b4 100644
--- a/crypto/asymmetric_keys/verify_pefile.h
+++ b/crypto/asymmetric_keys/verify_pefile.h
@@ -22,6 +22,7 @@ struct pefile_context {
 	/* PKCS#7 MS Individual Code Signing content */
 	const void	*digest;		/* Digest */
 	unsigned	digest_len;		/* Digest length */
+	bool		digest_free;		/* T if digest should be freed */
 	const char	*digest_algo;		/* Digest algorithm */
 };
 
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 12e3341e806b..2243add11d48 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -56,6 +56,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
 	if (!sig->digest)
 		goto error;
+	sig->digest_free = true;
 
 	desc = kzalloc(desc_size, GFP_KERNEL);
 	if (!desc)
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index e4ec8003a3a4..68899a49cd0d 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -46,6 +46,7 @@ struct public_key_signature {
 	u8 *digest;
 	u32 s_size;		/* Number of bytes in signature */
 	u32 digest_size;	/* Number of bytes in digest */
+	bool digest_free;	/* T if digest needs freeing */
 	bool algo_does_hash;	/* Public key algo does its own hashing */
 	const char *pkey_algo;
 	const char *hash_algo;


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v13 04/12] pkcs7, x509: Add ML-DSA support
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
                   ` (2 preceding siblings ...)
  2026-01-20 14:50 ` [PATCH v13 03/12] pkcs7: Allow direct signing of data with ML-DSA David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 21:17   ` Eric Biggers
  2026-01-20 14:50 ` [PATCH v13 05/12] modsign: Enable ML-DSA module signing David Howells
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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 PKCS#7 and X.509
implementations.

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     | 15 ++++++++++++++
 crypto/asymmetric_keys/public_key.c       |  7 +++++++
 crypto/asymmetric_keys/x509_cert_parser.c | 24 +++++++++++++++++++++++
 include/linux/oid_registry.h              |  5 +++++
 4 files changed, 51 insertions(+)

diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 3cdbab3b9f50..90c36fe1b5ed 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -297,6 +297,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_does_hash = true;
+		break;
+	case OID_id_ml_dsa_65:
+		ctx->sinfo->sig->pkey_algo = "mldsa65";
+		ctx->sinfo->sig->encoding = "raw";
+		ctx->sinfo->sig->algo_does_hash = true;
+		break;
+	case OID_id_ml_dsa_87:
+		ctx->sinfo->sig->pkey_algo = "mldsa87";
+		ctx->sinfo->sig->encoding = "raw";
+		ctx->sinfo->sig->algo_does_hash = 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 e5b177c8e842..ed6b4b5ae4ef 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -142,6 +142,13 @@ 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;
 	} 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..5ab5b4e5f1b4 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_does_hash = true;
+	ctx->cert->sig->hash_algo = ctx->cert->sig->pkey_algo;
+	ctx->cert->sig->encoding = "raw";
+	ctx->sig_algo = ctx->last_oid;
+	return 0;
 }
 
 /*
@@ -524,6 +539,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] 37+ messages in thread

* [PATCH v13 05/12] modsign: Enable ML-DSA module signing
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
                   ` (3 preceding siblings ...)
  2026-01-20 14:50 ` [PATCH v13 04/12] pkcs7, x509: Add ML-DSA support David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 21:38   ` Eric Biggers
  2026-01-20 14:50 ` [PATCH v13 06/12] crypto: Add supplementary info param to asymmetric key signature verification David Howells
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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.5.1,
support the use of CMS_NOATTR with ML-DSA, so the prohibition against using
authenticatedAttributes 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 ML-DSA algorithm uses its own internal choice of digest (SHAKE256)
without regard to what's specified in the CMS message.  This is, in theory,
configurable, but there's currently no hook in the crypto_sig API to do
that, though possibly it could be done by parameterising the name of the
algorithm, e.g. ("mldsa87(sha512)").

Signed-off-by: David Howells <dhowells@redhat.com>
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                                | 21 ++++++++++++
 certs/Makefile                               |  3 ++
 crypto/asymmetric_keys/pkcs7_verify.c        |  4 ---
 scripts/sign-file.c                          | 34 +++++++++++++++-----
 5 files changed, 59 insertions(+), 19 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..67a5786423b5 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -39,6 +39,27 @@ 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
+	  with a SHAKE256 'hash' of the authenticatedAttributes.
+
+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
+	  with a SHAKE256 'hash' of the authenticatedAttributes.
+
+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
+	  with a SHAKE256 'hash' of the authenticatedAttributes.
+
 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/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 46eee9811023..3896e24423f9 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -442,10 +442,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
 			pr_warn("Invalid module sig (not pkcs7-data)\n");
 			return -EKEYREJECTED;
 		}
-		if (pkcs7->have_authattrs) {
-			pr_warn("Invalid module sig (has authattrs)\n");
-			return -EKEYREJECTED;
-		}
 		break;
 	case VERIFYING_FIRMWARE_SIGNATURE:
 		if (pkcs7->data_type != OID_data) {
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] 37+ messages in thread

* [PATCH v13 06/12] crypto: Add supplementary info param to asymmetric key signature verification
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
                   ` (4 preceding siblings ...)
  2026-01-20 14:50 ` [PATCH v13 05/12] modsign: Enable ML-DSA module signing David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 14:50 ` [PATCH v13 07/12] crypto: Add RSASSA-PSS support David Howells
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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,
	David S. Miller

Add a supplementary information parameter to the asymmetric key signature
verification API, in particular crypto_sig_verify() and sig_alg::verify.
This takes the form of a printable string containing of key=val elements.

This is needed as some algorithms require additional metadata
(e.g. RSASSA-PSS) and this extra metadata is included in the X.509
certificates and PKCS#7 messages.  Furthermore, keyctl(KEYCTL_PKEY_VERIFY)
already allows for this to be passed to the kernel, as do the _SIGN,
_ENCRYPT and _DECRYPT keyctls.

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Ignat Korchagin <ignat@cloudflare.com>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: "David S. Miller" <davem@davemloft.net>
cc: Lukas Wunner <lukas@wunner.de>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
 crypto/asymmetric_keys/asymmetric_type.c | 1 +
 crypto/asymmetric_keys/public_key.c      | 2 +-
 crypto/asymmetric_keys/signature.c       | 1 +
 crypto/ecdsa-p1363.c                     | 5 +++--
 crypto/ecdsa-x962.c                      | 5 +++--
 crypto/ecdsa.c                           | 3 ++-
 crypto/ecrdsa.c                          | 3 ++-
 crypto/mldsa.c                           | 3 ++-
 crypto/rsassa-pkcs1.c                    | 3 ++-
 crypto/sig.c                             | 3 ++-
 crypto/testmgr.c                         | 2 +-
 crypto/testmgr.h                         | 1 +
 include/crypto/public_key.h              | 1 +
 include/crypto/sig.h                     | 9 ++++++---
 14 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index 348966ea2175..dad4f0edfa25 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -596,6 +596,7 @@ static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
 		.digest_size	= params->in_len,
 		.encoding	= params->encoding,
 		.hash_algo	= params->hash_algo,
+		.info		= params->info,
 		.digest		= (void *)in,
 		.s		= (void *)in2,
 	};
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index ed6b4b5ae4ef..61dc4f626620 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -433,7 +433,7 @@ int public_key_verify_signature(const struct public_key *pkey,
 		goto error_free_key;
 
 	ret = crypto_sig_verify(tfm, sig->s, sig->s_size,
-				sig->digest, sig->digest_size);
+				sig->digest, sig->digest_size, sig->info);
 
 error_free_key:
 	kfree_sensitive(key);
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
index bea01cf27d0a..30ba50eb44af 100644
--- a/crypto/asymmetric_keys/signature.c
+++ b/crypto/asymmetric_keys/signature.c
@@ -30,6 +30,7 @@ void public_key_signature_free(struct public_key_signature *sig)
 		kfree(sig->s);
 		if (sig->digest_free)
 			kfree(sig->digest);
+		kfree(sig->info);
 		kfree(sig);
 	}
 }
diff --git a/crypto/ecdsa-p1363.c b/crypto/ecdsa-p1363.c
index e0c55c64711c..fa987dba1213 100644
--- a/crypto/ecdsa-p1363.c
+++ b/crypto/ecdsa-p1363.c
@@ -18,7 +18,8 @@ struct ecdsa_p1363_ctx {
 
 static int ecdsa_p1363_verify(struct crypto_sig *tfm,
 			      const void *src, unsigned int slen,
-			      const void *digest, unsigned int dlen)
+			      const void *digest, unsigned int dlen,
+			      const char *info)
 {
 	struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm);
 	unsigned int keylen = DIV_ROUND_UP_POW2(crypto_sig_keysize(ctx->child),
@@ -32,7 +33,7 @@ static int ecdsa_p1363_verify(struct crypto_sig *tfm,
 	ecc_digits_from_bytes(src, keylen, sig.r, ndigits);
 	ecc_digits_from_bytes(src + keylen, keylen, sig.s, ndigits);
 
-	return crypto_sig_verify(ctx->child, &sig, sizeof(sig), digest, dlen);
+	return crypto_sig_verify(ctx->child, &sig, sizeof(sig), digest, dlen, info);
 }
 
 static unsigned int ecdsa_p1363_key_size(struct crypto_sig *tfm)
diff --git a/crypto/ecdsa-x962.c b/crypto/ecdsa-x962.c
index ee71594d10a0..5d7f1078989c 100644
--- a/crypto/ecdsa-x962.c
+++ b/crypto/ecdsa-x962.c
@@ -75,7 +75,8 @@ int ecdsa_get_signature_s(void *context, size_t hdrlen, unsigned char tag,
 
 static int ecdsa_x962_verify(struct crypto_sig *tfm,
 			     const void *src, unsigned int slen,
-			     const void *digest, unsigned int dlen)
+			     const void *digest, unsigned int dlen,
+			     const char *info)
 {
 	struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm);
 	struct ecdsa_x962_signature_ctx sig_ctx;
@@ -89,7 +90,7 @@ static int ecdsa_x962_verify(struct crypto_sig *tfm,
 		return err;
 
 	return crypto_sig_verify(ctx->child, &sig_ctx.sig, sizeof(sig_ctx.sig),
-				 digest, dlen);
+				 digest, dlen, info);
 }
 
 static unsigned int ecdsa_x962_key_size(struct crypto_sig *tfm)
diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c
index ce8e4364842f..144fd6b9168b 100644
--- a/crypto/ecdsa.c
+++ b/crypto/ecdsa.c
@@ -65,7 +65,8 @@ static int _ecdsa_verify(struct ecc_ctx *ctx, const u64 *hash, const u64 *r, con
  */
 static int ecdsa_verify(struct crypto_sig *tfm,
 			const void *src, unsigned int slen,
-			const void *digest, unsigned int dlen)
+			const void *digest, unsigned int dlen,
+			const char *info)
 {
 	struct ecc_ctx *ctx = crypto_sig_ctx(tfm);
 	size_t bufsize = ctx->curve->g.ndigits * sizeof(u64);
diff --git a/crypto/ecrdsa.c b/crypto/ecrdsa.c
index 2c0602f0cd40..59f2d5bb3be4 100644
--- a/crypto/ecrdsa.c
+++ b/crypto/ecrdsa.c
@@ -69,7 +69,8 @@ static const struct ecc_curve *get_curve_by_oid(enum OID oid)
 
 static int ecrdsa_verify(struct crypto_sig *tfm,
 			 const void *src, unsigned int slen,
-			 const void *digest, unsigned int dlen)
+			 const void *digest, unsigned int dlen,
+			 const char *info)
 {
 	struct ecrdsa_ctx *ctx = crypto_sig_ctx(tfm);
 	unsigned int ndigits = dlen / sizeof(u64);
diff --git a/crypto/mldsa.c b/crypto/mldsa.c
index 2146c774b5ca..ba071d030ab0 100644
--- a/crypto/mldsa.c
+++ b/crypto/mldsa.c
@@ -25,7 +25,8 @@ static int crypto_mldsa_sign(struct crypto_sig *tfm,
 
 static int crypto_mldsa_verify(struct crypto_sig *tfm,
 			       const void *sig, unsigned int sig_len,
-			       const void *msg, unsigned int msg_len)
+			       const void *msg, unsigned int msg_len,
+			       const char *info)
 {
 	const struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
 
diff --git a/crypto/rsassa-pkcs1.c b/crypto/rsassa-pkcs1.c
index 94fa5e9600e7..6283050e609a 100644
--- a/crypto/rsassa-pkcs1.c
+++ b/crypto/rsassa-pkcs1.c
@@ -215,7 +215,8 @@ static int rsassa_pkcs1_sign(struct crypto_sig *tfm,
 
 static int rsassa_pkcs1_verify(struct crypto_sig *tfm,
 			       const void *src, unsigned int slen,
-			       const void *digest, unsigned int dlen)
+			       const void *digest, unsigned int dlen,
+			       const char *info)
 {
 	struct sig_instance *inst = sig_alg_instance(tfm);
 	struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
diff --git a/crypto/sig.c b/crypto/sig.c
index beba745b6405..c56fea3a53ae 100644
--- a/crypto/sig.c
+++ b/crypto/sig.c
@@ -92,7 +92,8 @@ static int sig_default_sign(struct crypto_sig *tfm,
 
 static int sig_default_verify(struct crypto_sig *tfm,
 			      const void *src, unsigned int slen,
-			      const void *dst, unsigned int dlen)
+			      const void *dst, unsigned int dlen,
+			      const char *info)
 {
 	return -ENOSYS;
 }
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 5df204d9c9dd..51f76b15f134 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -3969,7 +3969,7 @@ static int test_sig_one(struct crypto_sig *tfm, const struct sig_testvec *vecs)
 	 * (which does not require a private key)
 	 */
 	err = crypto_sig_verify(tfm, vecs->c, vecs->c_size,
-				vecs->m, vecs->m_size);
+				vecs->m, vecs->m_size, vecs->verify_info);
 	if (err) {
 		pr_err("alg: sig: verify test failed: err %d\n", err);
 		return err;
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 1a3329e1c325..305adad2f2d0 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -146,6 +146,7 @@ struct akcipher_testvec {
 
 struct sig_testvec {
 	const unsigned char *key;
+	const unsigned char *verify_info;
 	const unsigned char *params;
 	const unsigned char *m;
 	const unsigned char *c;
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 68899a49cd0d..b6f2f2218aae 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -48,6 +48,7 @@ struct public_key_signature {
 	u32 digest_size;	/* Number of bytes in digest */
 	bool digest_free;	/* T if digest needs freeing */
 	bool algo_does_hash;	/* Public key algo does its own hashing */
+	char *info;		/* Supplementary parameters */
 	const char *pkey_algo;
 	const char *hash_algo;
 	const char *encoding;
diff --git a/include/crypto/sig.h b/include/crypto/sig.h
index fa6dafafab3f..885fa6487780 100644
--- a/include/crypto/sig.h
+++ b/include/crypto/sig.h
@@ -56,7 +56,8 @@ struct sig_alg {
 		    void *dst, unsigned int dlen);
 	int (*verify)(struct crypto_sig *tfm,
 		      const void *src, unsigned int slen,
-		      const void *digest, unsigned int dlen);
+		      const void *digest, unsigned int dlen,
+		      const char *info);
 	int (*set_pub_key)(struct crypto_sig *tfm,
 			   const void *key, unsigned int keylen);
 	int (*set_priv_key)(struct crypto_sig *tfm,
@@ -209,16 +210,18 @@ static inline int crypto_sig_sign(struct crypto_sig *tfm,
  * @slen:	source length
  * @digest:	digest
  * @dlen:	digest length
+ * @info:	Additional parameters as a set of k=v
  *
  * Return: zero on verification success; error code in case of error.
  */
 static inline int crypto_sig_verify(struct crypto_sig *tfm,
 				    const void *src, unsigned int slen,
-				    const void *digest, unsigned int dlen)
+				    const void *digest, unsigned int dlen,
+				    const char *info)
 {
 	struct sig_alg *alg = crypto_sig_alg(tfm);
 
-	return alg->verify(tfm, src, slen, digest, dlen);
+	return alg->verify(tfm, src, slen, digest, dlen, info);
 }
 
 /**


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v13 07/12] crypto: Add RSASSA-PSS support
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
                   ` (5 preceding siblings ...)
  2026-01-20 14:50 ` [PATCH v13 06/12] crypto: Add supplementary info param to asymmetric key signature verification David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 22:41   ` Eric Biggers
  2026-01-20 14:50 ` [PATCH v13 08/12] pkcs7, x509: " David Howells
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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,
	Tadeusz Struk, David S. Miller

Add support for RSASSA-PSS [RFC8017 sec 8.1] signature verification support
to the RSA driver in crypto/.  Note that signing support is not provided.

The verification function requires an info string formatted as a
space-separated list of key=value pairs.  The following parameters need to
be provided:

 (1) sighash=<algo>

     The hash algorithm to be used to digest the data.

 (2) pss_mask=<type>,...

     The mask generation function (MGF) and its parameters.

 (3) pss_salt=<len>

     The length of the salt used.

The only MGF currently supported is "mgf1".  This takes an additional
parameter indicating the mask-generating hash (which need not be the same
as the data hash).  E.g.:

     "sighash=sha256 pss_mask=mgf1,sha256 pss_salt=32"

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Tadeusz Struk <tadeusz.struk@intel.com>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: David S. Miller <davem@davemloft.net>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
 crypto/Makefile               |   1 +
 crypto/rsa.c                  |   8 +
 crypto/rsassa-pss.c           | 383 ++++++++++++++++++++++++++++++++++
 include/crypto/hash.h         |   3 +
 include/crypto/internal/rsa.h |   2 +
 5 files changed, 397 insertions(+)
 create mode 100644 crypto/rsassa-pss.c

diff --git a/crypto/Makefile b/crypto/Makefile
index 267d5403045b..5c91440d1751 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -50,6 +50,7 @@ rsa_generic-y += rsa.o
 rsa_generic-y += rsa_helper.o
 rsa_generic-y += rsa-pkcs1pad.o
 rsa_generic-y += rsassa-pkcs1.o
+rsa_generic-y += rsassa-pss.o
 obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o
 
 $(obj)/ecdsasignature.asn1.o: $(obj)/ecdsasignature.asn1.c $(obj)/ecdsasignature.asn1.h
diff --git a/crypto/rsa.c b/crypto/rsa.c
index 6c7734083c98..189a09d54c16 100644
--- a/crypto/rsa.c
+++ b/crypto/rsa.c
@@ -10,6 +10,7 @@
 #include <linux/mpi.h>
 #include <crypto/internal/rsa.h>
 #include <crypto/internal/akcipher.h>
+#include <crypto/internal/sig.h>
 #include <crypto/akcipher.h>
 #include <crypto/algapi.h>
 
@@ -414,8 +415,14 @@ static int __init rsa_init(void)
 	if (err)
 		goto err_unregister_rsa_pkcs1pad;
 
+	err = crypto_register_sig(&rsassa_pss_alg);
+	if (err)
+		goto err_rsassa_pss;
+
 	return 0;
 
+err_rsassa_pss:
+	crypto_unregister_template(&rsassa_pkcs1_tmpl);
 err_unregister_rsa_pkcs1pad:
 	crypto_unregister_template(&rsa_pkcs1pad_tmpl);
 err_unregister_rsa:
@@ -425,6 +432,7 @@ static int __init rsa_init(void)
 
 static void __exit rsa_exit(void)
 {
+	crypto_unregister_sig(&rsassa_pss_alg);
 	crypto_unregister_template(&rsassa_pkcs1_tmpl);
 	crypto_unregister_template(&rsa_pkcs1pad_tmpl);
 	crypto_unregister_akcipher(&rsa);
diff --git a/crypto/rsassa-pss.c b/crypto/rsassa-pss.c
new file mode 100644
index 000000000000..4cc2b6fa9274
--- /dev/null
+++ b/crypto/rsassa-pss.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * RSA Signature Scheme combined with EMSA-PSS encoding (RFC 8017 sec 8.2)
+ *
+ * https://www.rfc-editor.org/rfc/rfc8017#section-8.1
+ *
+ * Copyright (c) 2025 Red Hat
+ */
+
+#define pr_fmt(fmt) "RSAPSS: "fmt
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/oid_registry.h>
+#include <linux/parser.h>
+#include <linux/scatterlist.h>
+#include <crypto/akcipher.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include <crypto/sig.h>
+#include <crypto/internal/akcipher.h>
+#include <crypto/internal/rsa.h>
+#include <crypto/internal/sig.h>
+
+struct rsassa_pss_ctx {
+	struct crypto_akcipher *rsa;
+	unsigned int	key_size;
+	unsigned int	salt_len;
+	char		*pss_hash;
+	char		*mgf1_hash;
+};
+
+enum {
+	rsassa_pss_verify_hash_algo,
+	rsassa_pss_verify_pss_mask,
+	rsassa_pss_verify_pss_salt,
+};
+
+static const match_table_t rsassa_pss_verify_params = {
+	{ rsassa_pss_verify_hash_algo,	"sighash=%s" },
+	{ rsassa_pss_verify_pss_mask,	"pss_mask=%s" },
+	{ rsassa_pss_verify_pss_salt,	"pss_salt=%u" },
+	{}
+};
+
+/*
+ * Parse the signature parameters out of the info string.
+ */
+static int rsassa_pss_vinfo_parse(struct rsassa_pss_ctx *ctx,
+				  char *info)
+{
+	substring_t args[MAX_OPT_ARGS];
+	char *p;
+
+	ctx->pss_hash = NULL;
+	ctx->mgf1_hash = NULL;
+	ctx->salt_len = 0;
+
+	while ((p = strsep(&info, " \t"))) {
+		if (*p == '\0' || *p == ' ' || *p == '\t')
+			continue;
+
+		switch (match_token(p, rsassa_pss_verify_params, args)) {
+		case rsassa_pss_verify_hash_algo:
+			*args[0].to = 0;
+			ctx->pss_hash = args[0].from;
+			break;
+		case rsassa_pss_verify_pss_mask:
+			if (memcmp(args[0].from, "mgf1", 4) != 0)
+				return -ENOPKG;
+			if (args[0].from[4] != ',')
+				return -EINVAL;
+			args[0].from += 5;
+			if (args[0].from >= args[0].to)
+				return -EINVAL;
+			*args[0].to = 0;
+			ctx->mgf1_hash = args[0].from;
+			break;
+		case rsassa_pss_verify_pss_salt:
+			if (match_uint(&args[0], &ctx->salt_len) < 0)
+				return -EINVAL;
+			break;
+		default:
+			pr_debug("Unknown info param\n");
+			return -EINVAL; /* Ignoring it might be better. */
+		}
+	}
+
+	if (!ctx->pss_hash ||
+	    !ctx->mgf1_hash)
+		return -EINVAL;
+	return 0;
+}
+
+/*
+ * Perform mask = MGF1(mgfSeed, masklen) - RFC8017 appendix B.2.1.
+ */
+static int MGF1(struct rsassa_pss_ctx *ctx,
+		const u8 *mgfSeed, unsigned int mgfSeed_len,
+		u8 *mask, unsigned int maskLen)
+{
+	unsigned int counter, count_to, hLen, T_len;
+	__be32 *C;
+	int err;
+	u8 *T, *t, *to_hash;
+
+	struct crypto_shash *hash_tfm __free(crypto_free_shash) =
+		crypto_alloc_shash(ctx->mgf1_hash, 0, 0);
+	if (IS_ERR(hash_tfm))
+		return PTR_ERR(hash_tfm);
+
+	hLen = crypto_shash_digestsize(hash_tfm);
+	count_to = DIV_ROUND_UP(maskLen, hLen);
+	T_len = hLen * count_to;
+
+	struct shash_desc *Hash __free(kfree) =
+		kmalloc(roundup(sizeof(struct shash_desc) +
+				crypto_shash_descsize(hash_tfm), 64) +
+			roundup(T_len, 64) + /* T */
+			roundup(mgfSeed_len + 4, 64), /* mgfSeed||C */
+			GFP_KERNEL);
+	if (!Hash)
+		return -ENOMEM;
+
+	Hash->tfm = hash_tfm;
+
+	/* 2: Let T be the empty octet string. */
+	T = (void *)Hash +
+		roundup(sizeof(struct shash_desc) +
+			crypto_shash_descsize(hash_tfm), 64);
+
+	/* 3: Generate the mask. */
+	to_hash = T + roundup(T_len, 64);
+	memcpy(to_hash, mgfSeed, mgfSeed_len);
+	C = (__be32 *)(to_hash + mgfSeed_len);
+
+	t = T;
+	for (counter = 0; counter < count_to; counter++) {
+		/* 3A: C = I2OSP(counter, 4). */
+		put_unaligned_be32(counter, C);
+
+		/* 3B: T = T || Hash(mgfSeed || C). */
+		err = crypto_shash_digest(Hash, to_hash, mgfSeed_len + 4, t);
+		if (err < 0)
+			return err;
+
+		t += hLen;
+	}
+
+	/* 4: Output T to mask */
+	memcpy(mask, T, maskLen);
+	return 0;
+}
+
+/*
+ * Perform EMSA-PSS-VERIFY(M, EM, emBits) - RFC8017 sec 9.1.2.
+ */
+static int emsa_pss_verify(struct rsassa_pss_ctx *ctx,
+			   const u8 *M, unsigned int M_len,
+			   const u8 *EM, unsigned int emLen)
+{
+	unsigned int emBits, hLen, sLen, DB_len;
+	const u8 *maskedDB, *H;
+	u8 *mHash, *dbMask, *DB, *salt, *Mprime, *Hprime;
+	int err, i;
+
+	emBits = 8 - fls(EM[0]);
+	emBits = emLen * 8 - emBits;
+
+	struct crypto_shash *hash_tfm __free(crypto_free_shash) =
+		crypto_alloc_shash(ctx->pss_hash, 0, 0);
+	if (IS_ERR(hash_tfm))
+		return PTR_ERR(hash_tfm);
+
+	hLen = crypto_shash_digestsize(hash_tfm);
+	sLen = ctx->salt_len;
+
+	if (sLen > 65536 ||
+	    emBits < 8 * (hLen + sLen) + 9)
+		return -EBADMSG;
+
+	DB_len = emLen - hLen - 1;
+
+	struct shash_desc *Hash __free(kfree) =
+		kmalloc(roundup(sizeof(struct shash_desc) +
+				crypto_shash_descsize(hash_tfm), 64) +
+			roundup(hLen, 64) + /* mHash */
+			roundup(DB_len, 64) + /* DB and dbMask */
+			roundup(8 + hLen + sLen, 64) + /* M' */
+			roundup(hLen, 64), /* H' */
+			GFP_KERNEL);
+	if (!Hash)
+		return -ENOMEM;
+
+	Hash->tfm = hash_tfm;
+
+	mHash = (void *)Hash +
+		roundup(sizeof(struct shash_desc) +
+			crypto_shash_descsize(hash_tfm), 64);
+	DB = dbMask = mHash + roundup(hLen, 64);
+	Mprime = dbMask + roundup(DB_len, 64);
+	Hprime = Mprime + roundup(8 + hLen + sLen, 64);
+
+	/* 1. Check len M against hash input limitation. */
+	/* The standard says ~2EiB for SHA1, so I think we can ignore this. */
+
+	/* 2. mHash = Hash(M).
+	 * In theory, we would do:
+	 *	err = crypto_shash_digest(Hash, M, M_len, mHash);
+	 * but the caller is assumed to already have done that for us.
+	 */
+	if (M_len != hLen)
+		return -EINVAL;
+	memcpy(mHash, M, hLen);
+
+	/* 3. Check emLen against hLen + sLen + 2. */
+	if (emLen < hLen + sLen + 2)
+		return -EBADMSG;
+
+	/* 4. Validate EM. */
+	if (EM[emLen - 1] != 0xbc)
+		return -EKEYREJECTED;
+
+	/* 5. Pick maskedDB and H. */
+	maskedDB = EM;
+	H = EM + DB_len;
+
+	/* 6. Check leftmost 8emLen-emBits bits of maskedDB are 0. */
+	/* Can only find emBits by counting the zeros on the Left. */
+
+	/* 7. Let dbMask = MGF(H, emLen - hLen - 1). */
+	err = MGF1(ctx, H, hLen, dbMask, DB_len);
+	if (err < 0)
+		return err;
+
+	/* 8. Let DB = maskedDB XOR dbMask. */
+	for (i = 0; i < DB_len; i++)
+		DB[i] = maskedDB[i] ^ dbMask[i];
+
+	/* 9. Set leftmost bits in DB to zero. */
+	int z = 8 * emLen - emBits;
+
+	if (z > 0) {
+		if (z >= 8) {
+			DB[0] = 0;
+		} else {
+			z = 8 - z;
+			DB[0] &= (1 << z) - 1;
+		}
+	}
+
+	/* 10. Check the left part of DB is {0,0,...,1}. */
+	for (i = 0; i < emLen - hLen - sLen - 2; i++)
+		if (DB[i] != 0)
+			return -EKEYREJECTED;
+	if (DB[i] != 0x01)
+		return -EKEYREJECTED;
+
+	/* 11. Let salt be the last sLen octets of DB. */
+	salt = DB + DB_len - sLen;
+
+	/* 12. Let M' be 00 00 00 00 00 00 00 00 || mHash || salt. */
+	memset(Mprime, 0, 8);
+	memcpy(Mprime + 8, mHash, hLen);
+	memcpy(Mprime + 8 + hLen, salt, sLen);
+
+	/* 13. Let H' = Hash(M'). */
+	err = crypto_shash_digest(Hash, Mprime, 8 + hLen + sLen, Hprime);
+	if (err < 0)
+		return err;
+
+	/* 14. Check H = H'. */
+	if (memcmp(H, Hprime, hLen) != 0)
+		return -EKEYREJECTED;
+	return 0;
+}
+
+/*
+ * Perform RSASSA-PSS-VERIFY((n,e),M,S) - RFC8017 sec 8.1.2.
+ */
+static int rsassa_pss_verify(struct crypto_sig *tfm,
+			     const void *src, unsigned int slen,
+			     const void *digest, unsigned int dlen,
+			     const char *info)
+{
+	struct rsassa_pss_ctx *ctx = crypto_sig_ctx(tfm);
+	struct crypto_wait cwait;
+	struct scatterlist sg;
+	unsigned int rsa_reqsize = crypto_akcipher_reqsize(ctx->rsa);
+	u8 *EM;
+	int err;
+
+	if (!info)
+		return -EINVAL;
+
+	char *str __free(kfree) = kstrdup(info, GFP_KERNEL);
+	if (!str)
+		return -ENOMEM;
+
+	err = rsassa_pss_vinfo_parse(ctx, str);
+	if (err < 0)
+		return err;
+
+	/* RFC8017 sec 8.1.2 step 1 - length checking */
+	if (!ctx->key_size || slen != ctx->key_size)
+		return -EINVAL;
+
+	/* RFC8017 sec 8.1.2 step 2 - RSA verification */
+	struct akcipher_request *rsa_req __free(kfree) =
+		kmalloc(sizeof(*rsa_req) + rsa_reqsize + ctx->key_size,
+			GFP_KERNEL);
+	if (!rsa_req)
+		return -ENOMEM;
+
+	EM = (u8 *)(rsa_req + 1) + rsa_reqsize;
+	memcpy(EM, src, slen);
+
+	crypto_init_wait(&cwait);
+	sg_init_one(&sg, EM, slen);
+	akcipher_request_set_tfm(rsa_req, ctx->rsa);
+	akcipher_request_set_crypt(rsa_req, &sg, &sg, slen, slen);
+	akcipher_request_set_callback(rsa_req, CRYPTO_TFM_REQ_MAY_SLEEP,
+				      crypto_req_done, &cwait);
+
+	err = crypto_akcipher_encrypt(rsa_req);
+	err = crypto_wait_req(err, &cwait);
+	if (err)
+		return err;
+
+	/* RFC 8017 sec 8.1.2 step 3 - EMSA-PSS(M, EM, modbits-1) */
+	return emsa_pss_verify(ctx, digest, dlen, EM, slen);
+}
+
+static unsigned int rsassa_pss_key_size(struct crypto_sig *tfm)
+{
+	struct rsassa_pss_ctx *ctx = crypto_sig_ctx(tfm);
+
+	return ctx->key_size * BITS_PER_BYTE;
+}
+
+static int rsassa_pss_set_pub_key(struct crypto_sig *tfm,
+				    const void *key, unsigned int keylen)
+{
+	struct rsassa_pss_ctx *ctx = crypto_sig_ctx(tfm);
+
+	return rsa_set_key(ctx->rsa, &ctx->key_size, RSA_PUB, key, keylen);
+}
+
+static int rsassa_pss_init_tfm(struct crypto_sig *tfm)
+{
+	struct crypto_akcipher *rsa;
+	struct rsassa_pss_ctx *ctx = crypto_sig_ctx(tfm);
+
+	rsa = crypto_alloc_akcipher("rsa", 0, 0);
+	if (IS_ERR(rsa))
+		return PTR_ERR(rsa);
+
+	ctx->rsa = rsa;
+	return 0;
+}
+
+static void rsassa_pss_exit_tfm(struct crypto_sig *tfm)
+{
+	struct rsassa_pss_ctx *ctx = crypto_sig_ctx(tfm);
+
+	crypto_free_akcipher(ctx->rsa);
+}
+
+struct sig_alg rsassa_pss_alg = {
+	.verify		= rsassa_pss_verify,
+	.set_pub_key	= rsassa_pss_set_pub_key,
+	.key_size	= rsassa_pss_key_size,
+	.init		= rsassa_pss_init_tfm,
+	.exit		= rsassa_pss_exit_tfm,
+	.base = {
+		.cra_name	 = "rsassa-pss",
+		.cra_driver_name = "rsassa-pss-generic",
+		.cra_priority	 = 100,
+		.cra_module	 = THIS_MODULE,
+		.cra_ctxsize	 = sizeof(struct rsassa_pss_ctx),
+	},
+};
+
+MODULE_ALIAS_CRYPTO("rsassa-pss");
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 586700332c73..49b1ea5cf78d 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -779,6 +779,9 @@ static inline void crypto_free_shash(struct crypto_shash *tfm)
 	crypto_destroy_tfm(tfm, crypto_shash_tfm(tfm));
 }
 
+DEFINE_FREE(crypto_free_shash, struct crypto_shash*,
+	    if (!IS_ERR_OR_NULL(_T)) { crypto_free_shash(_T); });
+
 static inline const char *crypto_shash_alg_name(struct crypto_shash *tfm)
 {
 	return crypto_tfm_alg_name(crypto_shash_tfm(tfm));
diff --git a/include/crypto/internal/rsa.h b/include/crypto/internal/rsa.h
index 071a1951b992..d7f38a273949 100644
--- a/include/crypto/internal/rsa.h
+++ b/include/crypto/internal/rsa.h
@@ -83,4 +83,6 @@ static inline int rsa_set_key(struct crypto_akcipher *child,
 
 extern struct crypto_template rsa_pkcs1pad_tmpl;
 extern struct crypto_template rsassa_pkcs1_tmpl;
+extern struct sig_alg rsassa_pss_alg;
+
 #endif


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v13 08/12] pkcs7, x509: Add RSASSA-PSS support
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
                   ` (6 preceding siblings ...)
  2026-01-20 14:50 ` [PATCH v13 07/12] crypto: Add RSASSA-PSS support David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 14:50 ` [PATCH v13 09/12] modsign: Enable RSASSA-PSS module signing David Howells
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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 RSASSA-PSS keys and signatures to the PKCS#7 and X.509
implementations.  This requires adding support for algorithm parameters for
keys and signatures as RSASSA-PSS needs metadata.  The ASN.1 encoded data
is converted into a printable key=value list string and passed to the
verification code.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
 crypto/asymmetric_keys/Makefile           |  12 +-
 crypto/asymmetric_keys/mgf1_params.asn1   |  12 ++
 crypto/asymmetric_keys/pkcs7.asn1         |   2 +-
 crypto/asymmetric_keys/pkcs7_parser.c     | 114 +++++-----
 crypto/asymmetric_keys/public_key.c       |  10 +
 crypto/asymmetric_keys/rsassa_params.asn1 |  25 +++
 crypto/asymmetric_keys/rsassa_parser.c    | 240 ++++++++++++++++++++++
 crypto/asymmetric_keys/rsassa_parser.h    |  25 +++
 crypto/asymmetric_keys/x509.asn1          |   2 +-
 crypto/asymmetric_keys/x509_cert_parser.c | 100 ++++-----
 crypto/asymmetric_keys/x509_parser.h      |  45 +++-
 crypto/asymmetric_keys/x509_public_key.c  |  36 +++-
 include/linux/oid_registry.h              |   2 +
 13 files changed, 503 insertions(+), 122 deletions(-)
 create mode 100644 crypto/asymmetric_keys/mgf1_params.asn1
 create mode 100644 crypto/asymmetric_keys/rsassa_params.asn1
 create mode 100644 crypto/asymmetric_keys/rsassa_parser.c
 create mode 100644 crypto/asymmetric_keys/rsassa_parser.h

diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index bc65d3b98dcb..c5aed382ee8a 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -21,7 +21,11 @@ x509_key_parser-y := \
 	x509_akid.asn1.o \
 	x509_cert_parser.o \
 	x509_loader.o \
-	x509_public_key.o
+	x509_public_key.o \
+	rsassa_params.asn1.o \
+	rsassa_parser.o \
+	mgf1_params.asn1.o
+
 obj-$(CONFIG_FIPS_SIGNATURE_SELFTEST) += x509_selftest.o
 x509_selftest-y += selftest.o
 x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_RSA) += selftest_rsa.o
@@ -31,8 +35,14 @@ $(obj)/x509_cert_parser.o: \
 	$(obj)/x509.asn1.h \
 	$(obj)/x509_akid.asn1.h
 
+$(obj)/rsassa_parser.o: \
+	$(obj)/rsassa_params.asn1.h \
+	$(obj)/mgf1_params.asn1.h
+
 $(obj)/x509.asn1.o: $(obj)/x509.asn1.c $(obj)/x509.asn1.h
 $(obj)/x509_akid.asn1.o: $(obj)/x509_akid.asn1.c $(obj)/x509_akid.asn1.h
+$(obj)/rsassa_params.asn1.o: $(obj)/rsassa_params.asn1.c $(obj)/rsassa_params.asn1.h
+$(obj)/mgf1_params.asn1.o: $(obj)/mgf1_params.asn1.c $(obj)/mgf1_params.asn1.h
 
 #
 # PKCS#8 private key handling
diff --git a/crypto/asymmetric_keys/mgf1_params.asn1 b/crypto/asymmetric_keys/mgf1_params.asn1
new file mode 100644
index 000000000000..c3bc4643e72c
--- /dev/null
+++ b/crypto/asymmetric_keys/mgf1_params.asn1
@@ -0,0 +1,12 @@
+-- SPDX-License-Identifier: BSD-3-Clause
+--
+-- Copyright (C) 2009 IETF Trust and the persons identified as authors
+-- of the code
+--
+--
+-- https://datatracker.ietf.org/doc/html/rfc4055 Section 6.
+
+AlgorithmIdentifier ::= SEQUENCE {
+	algorithm	OBJECT IDENTIFIER ({ mgf1_note_OID }),
+	parameters	ANY OPTIONAL
+}
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1
index 28e1f4a41c14..03c2248f23bc 100644
--- a/crypto/asymmetric_keys/pkcs7.asn1
+++ b/crypto/asymmetric_keys/pkcs7.asn1
@@ -124,7 +124,7 @@ UnauthenticatedAttribute ::= SEQUENCE {
 
 DigestEncryptionAlgorithmIdentifier ::= SEQUENCE {
 	algorithm		OBJECT IDENTIFIER ({ pkcs7_note_OID }),
-	parameters		ANY OPTIONAL
+	parameters		ANY OPTIONAL ({ pkcs7_sig_note_algo_params })
 }
 
 EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature })
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 90c36fe1b5ed..47d3c1920e8f 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -14,6 +14,7 @@
 #include <linux/oid_registry.h>
 #include <crypto/public_key.h>
 #include "pkcs7_parser.h"
+#include "rsassa_parser.h"
 #include "pkcs7.asn1.h"
 
 MODULE_DESCRIPTION("PKCS#7 parser");
@@ -28,14 +29,16 @@ struct pkcs7_parse_context {
 	struct x509_certificate **ppcerts;
 	unsigned long	data;			/* Start of data */
 	enum OID	last_oid;		/* Last OID encountered */
-	unsigned	x509_index;
-	unsigned	sinfo_index;
+	unsigned int	x509_index;
+	unsigned int	sinfo_index;
+	unsigned int	algo_params_size;
+	const void	*algo_params;
 	const void	*raw_serial;
-	unsigned	raw_serial_size;
-	unsigned	raw_issuer_size;
+	unsigned int	raw_serial_size;
+	unsigned int	raw_issuer_size;
 	const void	*raw_issuer;
 	const void	*raw_skid;
-	unsigned	raw_skid_size;
+	unsigned int	raw_skid_size;
 	bool		expect_skid;
 };
 
@@ -225,45 +228,29 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
 			       const void *value, size_t vlen)
 {
 	struct pkcs7_parse_context *ctx = context;
+	const char *algo;
 
-	switch (ctx->last_oid) {
-	case OID_sha1:
-		ctx->sinfo->sig->hash_algo = "sha1";
-		break;
-	case OID_sha256:
-		ctx->sinfo->sig->hash_algo = "sha256";
-		break;
-	case OID_sha384:
-		ctx->sinfo->sig->hash_algo = "sha384";
-		break;
-	case OID_sha512:
-		ctx->sinfo->sig->hash_algo = "sha512";
-		break;
-	case OID_sha224:
-		ctx->sinfo->sig->hash_algo = "sha224";
-		break;
-	case OID_sm3:
-		ctx->sinfo->sig->hash_algo = "sm3";
-		break;
-	case OID_gost2012Digest256:
-		ctx->sinfo->sig->hash_algo = "streebog256";
-		break;
-	case OID_gost2012Digest512:
-		ctx->sinfo->sig->hash_algo = "streebog512";
-		break;
-	case OID_sha3_256:
-		ctx->sinfo->sig->hash_algo = "sha3-256";
-		break;
-	case OID_sha3_384:
-		ctx->sinfo->sig->hash_algo = "sha3-384";
-		break;
-	case OID_sha3_512:
-		ctx->sinfo->sig->hash_algo = "sha3-512";
-		break;
-	default:
-		printk("Unsupported digest algo: %u\n", ctx->last_oid);
+	algo = oid_to_hash(ctx->last_oid);
+	if (!algo) {
+		pr_notice("Unsupported digest algo: %u\n", ctx->last_oid);
 		return -ENOPKG;
 	}
+
+	ctx->sinfo->sig->hash_algo = algo;
+	return 0;
+}
+
+/*
+ * Note the parameters for the signature.
+ */
+int pkcs7_sig_note_algo_params(void *context, size_t hdrlen,
+			       unsigned char tag,
+			       const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+
+	ctx->algo_params = value - hdrlen;
+	ctx->algo_params_size = vlen + hdrlen;
 	return 0;
 }
 
@@ -275,11 +262,21 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
 			     const void *value, size_t vlen)
 {
 	struct pkcs7_parse_context *ctx = context;
+	struct public_key_signature *sig = ctx->sinfo->sig;
+	int err;
 
 	switch (ctx->last_oid) {
 	case OID_rsaEncryption:
-		ctx->sinfo->sig->pkey_algo = "rsa";
-		ctx->sinfo->sig->encoding = "pkcs1";
+		sig->pkey_algo = "rsa";
+		sig->encoding = "pkcs1";
+		break;
+	case OID_id_rsassa_pss:
+		err = rsassa_parse_sig_params(sig, ctx->algo_params,
+					      ctx->algo_params_size);
+		if (err < 0)
+			return err;
+		sig->pkey_algo = "rsa";
+		sig->encoding = "emsa-pss";
 		break;
 	case OID_id_ecdsa_with_sha1:
 	case OID_id_ecdsa_with_sha224:
@@ -289,33 +286,36 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
 	case OID_id_ecdsa_with_sha3_256:
 	case OID_id_ecdsa_with_sha3_384:
 	case OID_id_ecdsa_with_sha3_512:
-		ctx->sinfo->sig->pkey_algo = "ecdsa";
-		ctx->sinfo->sig->encoding = "x962";
+		sig->pkey_algo = "ecdsa";
+		sig->encoding = "x962";
 		break;
 	case OID_gost2012PKey256:
 	case OID_gost2012PKey512:
-		ctx->sinfo->sig->pkey_algo = "ecrdsa";
-		ctx->sinfo->sig->encoding = "raw";
+		sig->pkey_algo = "ecrdsa";
+		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_does_hash = true;
+		sig->pkey_algo = "mldsa44";
+		sig->encoding = "raw";
+		sig->algo_does_hash = true;
 		break;
 	case OID_id_ml_dsa_65:
-		ctx->sinfo->sig->pkey_algo = "mldsa65";
-		ctx->sinfo->sig->encoding = "raw";
-		ctx->sinfo->sig->algo_does_hash = true;
+		sig->pkey_algo = "mldsa65";
+		sig->encoding = "raw";
+		sig->algo_does_hash = true;
 		break;
 	case OID_id_ml_dsa_87:
-		ctx->sinfo->sig->pkey_algo = "mldsa87";
-		ctx->sinfo->sig->encoding = "raw";
-		ctx->sinfo->sig->algo_does_hash = true;
+		sig->pkey_algo = "mldsa87";
+		sig->encoding = "raw";
+		sig->algo_does_hash = true;
 		break;
 	default:
-		printk("Unsupported pkey algo: %u\n", ctx->last_oid);
+		pr_notice("Unsupported pkey algo: %u\n", ctx->last_oid);
 		return -ENOPKG;
 	}
+
+	ctx->algo_params = NULL;
+	ctx->algo_params_size = 0;
 	return 0;
 }
 
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 61dc4f626620..13a5616becaa 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -100,6 +100,16 @@ software_key_determine_akcipher(const struct public_key *pkey,
 			}
 			return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
 		}
+		if (strcmp(encoding, "emsa-pss") == 0) {
+			if (op != kernel_pkey_sign &&
+			    op != kernel_pkey_verify)
+				return -EINVAL;
+			*sig = true;
+			if (!hash_algo)
+				hash_algo = "none";
+			n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, "rsassa-pss");
+			return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
+		}
 		if (strcmp(encoding, "raw") != 0)
 			return -EINVAL;
 		/*
diff --git a/crypto/asymmetric_keys/rsassa_params.asn1 b/crypto/asymmetric_keys/rsassa_params.asn1
new file mode 100644
index 000000000000..95a4e5f0dcd5
--- /dev/null
+++ b/crypto/asymmetric_keys/rsassa_params.asn1
@@ -0,0 +1,25 @@
+-- SPDX-License-Identifier: BSD-3-Clause
+--
+-- Copyright (C) 2009 IETF Trust and the persons identified as authors
+-- of the code
+--
+--
+-- https://datatracker.ietf.org/doc/html/rfc4055 Section 6.
+
+RSASSA-PSS-params ::= SEQUENCE {
+	hashAlgorithm      [0] HashAlgorithm,
+	maskGenAlgorithm   [1] MaskGenAlgorithm,
+	saltLength         [2] INTEGER ({ rsassa_note_salt_length }),
+	trailerField       [3] TrailerField OPTIONAL
+}
+
+TrailerField ::= INTEGER ({ rsassa_note_trailer })
+-- { trailerFieldBC(1) }
+
+HashAlgorithm ::= AlgorithmIdentifier ({ rsassa_note_hash_algo })
+MaskGenAlgorithm ::= AlgorithmIdentifier ({ rsassa_note_maskgen_algo })
+
+AlgorithmIdentifier ::= SEQUENCE {
+	algorithm	OBJECT IDENTIFIER ({ rsassa_note_OID }),
+	parameters	ANY OPTIONAL ({ rsassa_note_params })
+}
diff --git a/crypto/asymmetric_keys/rsassa_parser.c b/crypto/asymmetric_keys/rsassa_parser.c
new file mode 100644
index 000000000000..b80720fa94be
--- /dev/null
+++ b/crypto/asymmetric_keys/rsassa_parser.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* RSASSA-PSS ASN.1 parameter parser
+ *
+ * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#define pr_fmt(fmt) "RSASSA-PSS: "fmt
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/asn1.h>
+#include <crypto/hash.h>
+#include <crypto/hash_info.h>
+#include <crypto/public_key.h>
+#include "x509_parser.h"
+#include "rsassa_parser.h"
+#include "rsassa_params.asn1.h"
+#include "mgf1_params.asn1.h"
+
+struct rsassa_parse_context {
+	struct rsassa_parameters *rsassa;	/* The parsed parameters */
+	unsigned long	data;			/* Start of data */
+	const void	*params;		/* Algo parameters */
+	unsigned int	params_len;		/* Length of algo parameters */
+	enum OID	last_oid;		/* Last OID encountered */
+	enum OID	mgf1_last_oid;		/* Last OID encountered in MGF1 */
+};
+
+/*
+ * Parse an RSASSA parameter block.
+ */
+struct rsassa_parameters *rsassa_params_parse(const void *data, size_t datalen)
+{
+	struct rsassa_parse_context ctx = {};
+	long ret;
+
+	struct rsassa_parameters *rsassa __free(kfree) =
+		kzalloc(sizeof(*rsassa), GFP_KERNEL);
+	if (!rsassa)
+		return ERR_PTR(-ENOMEM);
+
+	ctx.rsassa = rsassa;
+	ctx.data = (unsigned long)data;
+
+	/* Attempt to decode the parameters */
+	ret = asn1_ber_decoder(&rsassa_params_decoder, &ctx, data, datalen);
+	if (ret < 0) {
+		pr_debug("RSASSA parse failed %ld\n", ret);
+		return ERR_PTR(ret);
+	}
+
+	return no_free_ptr(rsassa);
+}
+
+/*
+ * Note an OID when we find one for later processing when we know how
+ * to interpret it.
+ */
+int rsassa_note_OID(void *context, size_t hdrlen, unsigned char tag,
+		    const void *value, size_t vlen)
+{
+	struct rsassa_parse_context *ctx = context;
+
+	ctx->last_oid = look_up_OID(value, vlen);
+	if (ctx->last_oid == OID__NR) {
+		char buffer[56];
+
+		sprint_oid(value, vlen, buffer, sizeof(buffer));
+		pr_debug("Unknown OID: %s\n", buffer);
+	}
+	return 0;
+}
+
+/*
+ * Parse trailerField.  We only accept trailerFieldBC.
+ */
+int rsassa_note_trailer(void *context, size_t hdrlen, unsigned char tag,
+			const void *value, size_t vlen)
+{
+	if (vlen != 1 || *(u8 *)value != 0x01) {
+		pr_debug("Unknown trailerField\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int rsassa_note_hash_algo(void *context, size_t hdrlen, unsigned char tag,
+			  const void *value, size_t vlen)
+{
+	struct rsassa_parse_context *ctx = context;
+
+	ctx->rsassa->hash_algo = ctx->last_oid;
+	pr_debug("HASH-ALGO %u %u\n", ctx->rsassa->hash_algo, ctx->params_len);
+	ctx->params = NULL;
+	return 0;
+}
+
+int rsassa_note_maskgen_algo(void *context, size_t hdrlen, unsigned char tag,
+			     const void *value, size_t vlen)
+{
+	struct rsassa_parse_context *ctx = context;
+	int ret;
+
+	ctx->rsassa->maskgen_algo = ctx->last_oid;
+	pr_debug("MGF-ALGO %u %u\n", ctx->rsassa->maskgen_algo, ctx->params_len);
+
+	switch (ctx->rsassa->maskgen_algo) {
+	case OID_id_mgf1:
+		if (!vlen) {
+			pr_debug("MGF1 missing parameters\n");
+			return -EBADMSG;
+		}
+
+		ret = asn1_ber_decoder(&mgf1_params_decoder, ctx,
+				       ctx->params, ctx->params_len);
+		if (ret < 0) {
+			pr_debug("MGF1 parse failed %d\n", ret);
+			return ret;
+		}
+		ctx->rsassa->maskgen_hash = ctx->mgf1_last_oid;
+		break;
+
+	default:
+		pr_debug("Unsupported MaskGenAlgorithm %d\n", ret);
+		return -ENOPKG;
+	}
+
+	ctx->params = NULL;
+	return 0;
+}
+
+int rsassa_note_salt_length(void *context, size_t hdrlen, unsigned char tag,
+			    const void *value, size_t vlen)
+{
+	struct rsassa_parse_context *ctx = context;
+	u32 salt_len = 0;
+
+	if (!vlen) {
+		pr_debug("Salt len bad integer\n");
+		return -EBADMSG;
+	}
+	if (vlen > 4) {
+		pr_debug("Salt len too long %zu\n", vlen);
+		return -EBADMSG;
+	}
+	if (((u8 *)value)[0] & 0x80) {
+		pr_debug("Salt len negative\n");
+		return -EBADMSG;
+	}
+
+	for (size_t i = 0; i < vlen; i++) {
+		salt_len <<= 8;
+		salt_len |= ((u8 *)value)[i];
+	}
+
+	ctx->rsassa->salt_len = salt_len;
+	pr_debug("Salt-Len %u\n", salt_len);
+	return 0;
+}
+
+/*
+ * Extract arbitrary parameters.
+ */
+int rsassa_note_params(void *context, size_t hdrlen, unsigned char tag,
+		       const void *value, size_t vlen)
+{
+	struct rsassa_parse_context *ctx = context;
+
+	ctx->params	= value - hdrlen;
+	ctx->params_len	= vlen + hdrlen;
+	return 0;
+}
+
+/*
+ * Note an OID when we find one for later processing when we know how to
+ * interpret it.
+ */
+int mgf1_note_OID(void *context, size_t hdrlen, unsigned char tag,
+		  const void *value, size_t vlen)
+{
+	struct rsassa_parse_context *ctx = context;
+
+	ctx->mgf1_last_oid = look_up_OID(value, vlen);
+	if (ctx->mgf1_last_oid == OID__NR) {
+		char buffer[56];
+
+		sprint_oid(value, vlen, buffer, sizeof(buffer));
+		pr_debug("Unknown MGF1 OID: %s\n", buffer);
+	}
+	return 0;
+}
+
+/*
+ * Parse the signature parameter block and generate a suitable info string from
+ * it.
+ */
+int rsassa_parse_sig_params(struct public_key_signature *sig,
+			    const u8 *sig_params, unsigned int sig_params_size)
+{
+	const char *mf, *mh;
+
+	if (!sig_params || !sig_params_size) {
+		pr_debug("sig algo without parameters\n");
+		return -EBADMSG;
+	}
+
+	struct rsassa_parameters *rsassa __free(rsassa_params_free) =
+		rsassa_params_parse(sig_params, sig_params_size);
+	if (IS_ERR(rsassa))
+		return PTR_ERR(rsassa);
+
+	sig->hash_algo = oid_to_hash(rsassa->hash_algo);
+	if (!sig->hash_algo) {
+		pr_notice("Unsupported hash: %u\n", rsassa->hash_algo);
+		return -ENOPKG;
+	}
+
+	switch (rsassa->maskgen_algo) {
+	case OID_id_mgf1:
+		mf = "mgf1";
+		break;
+	default:
+		pr_notice("Unsupported maskgen algo: %u\n", rsassa->maskgen_algo);
+		return -ENOPKG;
+	}
+
+	mh = oid_to_hash(rsassa->maskgen_hash);
+	if (!mh) {
+		pr_notice("Unsupported MGF1 hash: %u\n", rsassa->maskgen_hash);
+		return -ENOPKG;
+	}
+
+	sig->info = kasprintf(GFP_KERNEL, "sighash=%s pss_mask=%s,%s pss_salt=%u",
+			      sig->hash_algo, mf, mh, rsassa->salt_len);
+	if (!sig->info)
+		return -ENOMEM;
+	pr_debug("Info string: %s\n", sig->info);
+	return 0;
+}
diff --git a/crypto/asymmetric_keys/rsassa_parser.h b/crypto/asymmetric_keys/rsassa_parser.h
new file mode 100644
index 000000000000..b80401a3de8f
--- /dev/null
+++ b/crypto/asymmetric_keys/rsassa_parser.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* RSASSA-PSS parameter parsing context
+ *
+ * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#include <linux/oid_registry.h>
+
+struct rsassa_parameters {
+	enum OID	hash_algo;		/* Hash algorithm identifier */
+	enum OID	maskgen_algo;		/* Mask gen algorithm identifier */
+	enum OID	maskgen_hash;		/* Mask gen hash algorithm identifier */
+	u32		salt_len;
+};
+
+struct rsassa_parameters *rsassa_params_parse(const void *data, size_t datalen);
+int rsassa_parse_sig_params(struct public_key_signature *sig,
+			    const u8 *sig_params, unsigned int sig_params_size);
+
+static inline void rsassa_params_free(struct rsassa_parameters *params)
+{
+	kfree(params);
+}
+DEFINE_FREE(rsassa_params_free,  struct rsassa_parameters*, rsassa_params_free(_T))
diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1
index feb9573cacce..453b72eba1fe 100644
--- a/crypto/asymmetric_keys/x509.asn1
+++ b/crypto/asymmetric_keys/x509.asn1
@@ -29,7 +29,7 @@ CertificateSerialNumber ::= INTEGER
 
 AlgorithmIdentifier ::= SEQUENCE {
 	algorithm		OBJECT IDENTIFIER ({ x509_note_OID }),
-	parameters		ANY OPTIONAL ({ x509_note_params })
+	parameters		ANY OPTIONAL ({ x509_note_algo_id_params })
 }
 
 Name ::= SEQUENCE OF RelativeDistinguishedName
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 5ab5b4e5f1b4..a4b848628e37 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -15,28 +15,7 @@
 #include "x509_parser.h"
 #include "x509.asn1.h"
 #include "x509_akid.asn1.h"
-
-struct x509_parse_context {
-	struct x509_certificate	*cert;		/* Certificate being constructed */
-	unsigned long	data;			/* Start of data */
-	const void	*key;			/* Key data */
-	size_t		key_size;		/* Size of key data */
-	const void	*params;		/* Key parameters */
-	size_t		params_size;		/* Size of key parameters */
-	enum OID	key_algo;		/* Algorithm used by the cert's key */
-	enum OID	last_oid;		/* Last OID encountered */
-	enum OID	sig_algo;		/* Algorithm used to sign the cert */
-	u8		o_size;			/* Size of organizationName (O) */
-	u8		cn_size;		/* Size of commonName (CN) */
-	u8		email_size;		/* Size of emailAddress */
-	u16		o_offset;		/* Offset of organizationName (O) */
-	u16		cn_offset;		/* Offset of commonName (CN) */
-	u16		email_offset;		/* Offset of emailAddress */
-	unsigned	raw_akid_size;
-	const void	*raw_akid;		/* Raw authorityKeyId in ASN.1 */
-	const void	*akid_raw_issuer;	/* Raw directoryName in authorityKeyId */
-	unsigned	akid_raw_issuer_size;
-};
+#include "rsassa_parser.h"
 
 /*
  * Free an X.509 certificate
@@ -60,12 +39,11 @@ EXPORT_SYMBOL_GPL(x509_free_certificate);
  */
 struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 {
-	struct x509_certificate *cert __free(x509_free_certificate) = NULL;
-	struct x509_parse_context *ctx __free(kfree) = NULL;
 	struct asymmetric_key_id *kid;
 	long ret;
 
-	cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
+	struct x509_certificate *cert __free(x509_free_certificate) =
+		kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
 	if (!cert)
 		return ERR_PTR(-ENOMEM);
 	cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
@@ -74,7 +52,9 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 	cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
 	if (!cert->sig)
 		return ERR_PTR(-ENOMEM);
-	ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
+
+	struct x509_parse_context *ctx __free(kfree) =
+		kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
 	if (!ctx)
 		return ERR_PTR(-ENOMEM);
 
@@ -104,15 +84,15 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 
 	cert->pub->keylen = ctx->key_size;
 
-	cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL);
+	cert->pub->params = kmemdup(ctx->key_params, ctx->key_params_size, GFP_KERNEL);
 	if (!cert->pub->params)
 		return ERR_PTR(-ENOMEM);
 
-	cert->pub->paramlen = ctx->params_size;
+	cert->pub->paramlen = ctx->key_params_size;
 	cert->pub->algo = ctx->key_algo;
 
 	/* Grab the signature bits */
-	ret = x509_get_sig_params(cert);
+	ret = x509_get_sig_params(cert, ctx);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
@@ -146,7 +126,7 @@ int x509_note_OID(void *context, size_t hdrlen,
 
 	ctx->last_oid = look_up_OID(value, vlen);
 	if (ctx->last_oid == OID__NR) {
-		char buffer[50];
+		char buffer[56];
 		sprint_oid(value, vlen, buffer, sizeof(buffer));
 		pr_debug("Unknown OID: [%lu] %s\n",
 			 (unsigned long)value - ctx->data, buffer);
@@ -179,6 +159,7 @@ int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
 		       const void *value, size_t vlen)
 {
 	struct x509_parse_context *ctx = context;
+	int err;
 
 	pr_debug("PubKey Algo: %u\n", ctx->last_oid);
 
@@ -210,6 +191,9 @@ int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
 		ctx->cert->sig->hash_algo = "sha1";
 		goto ecdsa;
 
+	case OID_id_rsassa_pss:
+		goto rsassa_pss;
+
 	case OID_id_rsassa_pkcs1_v1_5_with_sha3_256:
 		ctx->cert->sig->hash_algo = "sha3-256";
 		goto rsa_pkcs1;
@@ -268,6 +252,19 @@ int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
 		goto ml_dsa;
 	}
 
+rsassa_pss:
+	err = rsassa_parse_sig_params(ctx->cert->sig,
+				      ctx->algo_params, ctx->algo_params_size);
+	if (err < 0)
+		return err;
+
+	ctx->cert->sig->pkey_algo = "rsa";
+	ctx->cert->sig->encoding = "emsa-pss";
+	ctx->sig_algo = ctx->last_oid;
+	ctx->algo_params = NULL;
+	ctx->algo_params_size = 0;
+	return 0;
+
 rsa_pkcs1:
 	ctx->cert->sig->pkey_algo = "rsa";
 	ctx->cert->sig->encoding = "pkcs1";
@@ -324,8 +321,8 @@ int x509_note_signature(void *context, size_t hdrlen,
 		vlen--;
 	}
 
-	ctx->cert->raw_sig = value;
-	ctx->cert->raw_sig_size = vlen;
+	ctx->sig = value;
+	ctx->sig_size = vlen;
 	return 0;
 }
 
@@ -479,23 +476,16 @@ int x509_note_subject(void *context, size_t hdrlen,
 }
 
 /*
- * Extract the parameters for the public key
+ * Extract the parameters for an AlgorithmIdentifier.
  */
-int x509_note_params(void *context, size_t hdrlen,
-		     unsigned char tag,
-		     const void *value, size_t vlen)
+int x509_note_algo_id_params(void *context, size_t hdrlen,
+			     unsigned char tag,
+			     const void *value, size_t vlen)
 {
 	struct x509_parse_context *ctx = context;
 
-	/*
-	 * AlgorithmIdentifier is used three times in the x509, we should skip
-	 * first and ignore third, using second one which is after subject and
-	 * before subjectPublicKey.
-	 */
-	if (!ctx->cert->raw_subject || ctx->key)
-		return 0;
-	ctx->params = value - hdrlen;
-	ctx->params_size = vlen + hdrlen;
+	ctx->algo_params = value - hdrlen;
+	ctx->algo_params_size = vlen + hdrlen;
 	return 0;
 }
 
@@ -514,12 +504,28 @@ int x509_extract_key_data(void *context, size_t hdrlen,
 	case OID_rsaEncryption:
 		ctx->cert->pub->pkey_algo = "rsa";
 		break;
+	case OID_id_rsassa_pss:
+		/* Parameters are optional for the key itself. */
+		if (ctx->algo_params_size) {
+			ctx->key_params = ctx->algo_params;
+			ctx->key_params_size = ctx->algo_params_size;
+			ctx->algo_params = NULL;
+			ctx->algo_params_size = 0;
+
+			struct rsassa_parameters *params __free(rsassa_params_free) =
+				rsassa_params_parse(ctx->key_params, ctx->key_params_size);
+			if (IS_ERR(params))
+				return PTR_ERR(params);
+			break;
+		}
+		ctx->cert->pub->pkey_algo = "rsa";
+		break;
 	case OID_gost2012PKey256:
 	case OID_gost2012PKey512:
 		ctx->cert->pub->pkey_algo = "ecrdsa";
 		break;
 	case OID_id_ecPublicKey:
-		if (parse_OID(ctx->params, ctx->params_size, &oid) != 0)
+		if (parse_OID(ctx->algo_params, ctx->algo_params_size, &oid) != 0)
 			return -EBADMSG;
 
 		switch (oid) {
@@ -557,6 +563,8 @@ int x509_extract_key_data(void *context, size_t hdrlen,
 		return -EBADMSG;
 	ctx->key = value + 1;
 	ctx->key_size = vlen - 1;
+	ctx->algo_params = NULL;
+	ctx->algo_params_size = 0;
 	return 0;
 }
 
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 0688c222806b..578de49c37bc 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -22,18 +22,16 @@ struct x509_certificate {
 	time64_t	valid_from;
 	time64_t	valid_to;
 	const void	*tbs;			/* Signed data */
-	unsigned	tbs_size;		/* Size of signed data */
-	unsigned	raw_sig_size;		/* Size of signature */
-	const void	*raw_sig;		/* Signature data */
+	unsigned int	tbs_size;		/* Size of signed data */
 	const void	*raw_serial;		/* Raw serial number in ASN.1 */
-	unsigned	raw_serial_size;
-	unsigned	raw_issuer_size;
+	unsigned int	raw_serial_size;
+	unsigned int	raw_issuer_size;
 	const void	*raw_issuer;		/* Raw issuer name in ASN.1 */
 	const void	*raw_subject;		/* Raw subject name in ASN.1 */
-	unsigned	raw_subject_size;
-	unsigned	raw_skid_size;
+	unsigned int	raw_subject_size;
+	unsigned int	raw_skid_size;
 	const void	*raw_skid;		/* Raw subjectKeyId in ASN.1 */
-	unsigned	index;
+	unsigned int	index;
 	bool		seen;			/* Infinite recursion prevention */
 	bool		verified;
 	bool		self_signed;		/* T if self-signed (check unsupported_sig too) */
@@ -41,6 +39,34 @@ struct x509_certificate {
 	bool		blacklisted;
 };
 
+struct x509_parse_context {
+	struct x509_certificate	*cert;		/* Certificate being constructed */
+	unsigned long	data;			/* Start of data */
+	const void	*key;			/* Key data */
+	size_t		key_size;		/* Size of key data */
+	const void	*algo_params;		/* AlgorithmIdentifier: parameters */
+	size_t		algo_params_size;	/* AlgorithmIdentifier: parameters size */
+	const void	*key_params;		/* Key parameters */
+	size_t		key_params_size;	/* Size of key parameters */
+	const void	*sig_params;		/* Signature parameters */
+	unsigned int	sig_params_size;	/* Size of sig parameters */
+	unsigned int	sig_size;		/* Size of signature */
+	const void	*sig;			/* Signature data */
+	enum OID	key_algo;		/* Algorithm used by the cert's key */
+	enum OID	last_oid;		/* Last OID encountered */
+	enum OID	sig_algo;		/* Algorithm used to sign the cert */
+	u8		o_size;			/* Size of organizationName (O) */
+	u8		cn_size;		/* Size of commonName (CN) */
+	u8		email_size;		/* Size of emailAddress */
+	u16		o_offset;		/* Offset of organizationName (O) */
+	u16		cn_offset;		/* Offset of commonName (CN) */
+	u16		email_offset;		/* Offset of emailAddress */
+	unsigned int	raw_akid_size;
+	const void	*raw_akid;		/* Raw authorityKeyId in ASN.1 */
+	const void	*akid_raw_issuer;	/* Raw directoryName in authorityKeyId */
+	unsigned int	akid_raw_issuer_size;
+};
+
 /*
  * x509_cert_parser.c
  */
@@ -55,5 +81,6 @@ extern int x509_decode_time(time64_t *_t,  size_t hdrlen,
 /*
  * x509_public_key.c
  */
-extern int x509_get_sig_params(struct x509_certificate *cert);
+extern const char *oid_to_hash(enum OID oid);
+extern int x509_get_sig_params(struct x509_certificate *cert, struct x509_parse_context *parse);
 extern int x509_check_for_self_signed(struct x509_certificate *cert);
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 2243add11d48..4490cfa368a3 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -17,11 +17,32 @@
 #include "asymmetric_keys.h"
 #include "x509_parser.h"
 
+/*
+ * Translate OIDs to hash algorithm names.
+ */
+const char *oid_to_hash(enum OID oid)
+{
+	switch (oid) {
+	case OID_sha1:			return "sha1";
+	case OID_sha256:		return "sha256";
+	case OID_sha384:		return "sha384";
+	case OID_sha512:		return "sha512";
+	case OID_sha224:		return "sha224";
+	case OID_sm3:			return "sm3";
+	case OID_gost2012Digest256:	return "streebog256";
+	case OID_gost2012Digest512:	return "streebog512";
+	case OID_sha3_256:		return "sha3-256";
+	case OID_sha3_384:		return "sha3-384";
+	case OID_sha3_512:		return "sha3-512";
+	default:			return NULL;
+	}
+}
+
 /*
  * Set up the signature parameters in an X.509 certificate.  This involves
  * digesting the signed data and extracting the signature.
  */
-int x509_get_sig_params(struct x509_certificate *cert)
+int x509_get_sig_params(struct x509_certificate *cert, struct x509_parse_context *parse)
 {
 	struct public_key_signature *sig = cert->sig;
 	struct crypto_shash *tfm;
@@ -31,11 +52,11 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
 	pr_devel("==>%s()\n", __func__);
 
-	sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
+	sig->s = kmemdup(parse->sig, parse->sig_size, GFP_KERNEL);
 	if (!sig->s)
 		return -ENOMEM;
 
-	sig->s_size = cert->raw_sig_size;
+	sig->s_size = parse->sig_size;
 
 	/* Allocate the hashing algorithm we're going to need and find out how
 	 * big the hash operational data will be.
@@ -43,6 +64,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	tfm = crypto_alloc_shash(sig->hash_algo, 0, 0);
 	if (IS_ERR(tfm)) {
 		if (PTR_ERR(tfm) == -ENOENT) {
+			pr_debug("Unsupported hash %s\n", sig->hash_algo);
 			cert->unsupported_sig = true;
 			return 0;
 		}
@@ -149,13 +171,12 @@ int x509_check_for_self_signed(struct x509_certificate *cert)
  */
 static int x509_key_preparse(struct key_preparsed_payload *prep)
 {
-	struct x509_certificate *cert __free(x509_free_certificate) = NULL;
-	struct asymmetric_key_ids *kids __free(kfree) = NULL;
 	char *p, *desc __free(kfree) = NULL;
 	const char *q;
 	size_t srlen, sulen;
 
-	cert = x509_cert_parse(prep->data, prep->datalen);
+	struct x509_certificate *cert __free(x509_free_certificate) =
+		x509_cert_parse(prep->data, prep->datalen);
 	if (IS_ERR(cert))
 		return PTR_ERR(cert);
 
@@ -198,7 +219,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	p = bin2hex(p, q, srlen);
 	*p = 0;
 
-	kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL);
+	struct asymmetric_key_ids *kids __free(kfree) =
+		kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL);
 	if (!kids)
 		return -ENOMEM;
 	kids->id[0] = cert->id;
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
index ebce402854de..7fe168f54a6c 100644
--- a/include/linux/oid_registry.h
+++ b/include/linux/oid_registry.h
@@ -31,6 +31,8 @@ enum OID {
 	/* PKCS#1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)} */
 	OID_rsaEncryption,		/* 1.2.840.113549.1.1.1 */
 	OID_sha1WithRSAEncryption,	/* 1.2.840.113549.1.1.5 */
+	OID_id_mgf1,			/* 1.2.840.113549.1.1.8 */
+	OID_id_rsassa_pss,		/* 1.2.840.113549.1.1.10 */
 	OID_sha256WithRSAEncryption,	/* 1.2.840.113549.1.1.11 */
 	OID_sha384WithRSAEncryption,	/* 1.2.840.113549.1.1.12 */
 	OID_sha512WithRSAEncryption,	/* 1.2.840.113549.1.1.13 */


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v13 09/12] modsign: Enable RSASSA-PSS module signing
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
                   ` (7 preceding siblings ...)
  2026-01-20 14:50 ` [PATCH v13 08/12] pkcs7, x509: " David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 14:50 ` [PATCH v13 10/12] pkcs7: Add FIPS selftest for RSASSA-PSS David Howells
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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 RSASSA-PSS signatures (RFC8017) for use with module signing
and other public key cryptography done by the kernel.

Note that only signature verification is supported by the kernel.

Note further that this alters some of the same code as the MLDSA support,
so that needs to be applied first to avoid conflicts.

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Ignat Korchagin <ignat@cloudflare.com>
cc: Lukas Wunner <lukas@wunner.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 |  5 ++-
 certs/Kconfig                                |  6 +++
 certs/Makefile                               |  1 +
 scripts/sign-file.c                          | 39 +++++++++++++++++++-
 4 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/Documentation/admin-guide/module-signing.rst b/Documentation/admin-guide/module-signing.rst
index 7f2f127dc76f..aa24715cd2d8 100644
--- a/Documentation/admin-guide/module-signing.rst
+++ b/Documentation/admin-guide/module-signing.rst
@@ -32,8 +32,9 @@ 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.
+algorithm is selected by data in the signature); RSASSA-PSS is allowed to use
+SHA512 only; ML-DSA does its own hashing, but is allowed to be used with a
+SHA512 hash for signed attributes.
 
 
 ==========================
diff --git a/certs/Kconfig b/certs/Kconfig
index 67a5786423b5..524d1747c541 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -27,6 +27,12 @@ config MODULE_SIG_KEY_TYPE_RSA
 	help
 	 Use an RSA key for module signing.
 
+config MODULE_SIG_KEY_TYPE_RSASSA_PSS
+	bool "RSASSA-PSS"
+	select CRYPTO_RSA
+	help
+	 Use an RSASSA-PSS key for module signing.
+
 config MODULE_SIG_KEY_TYPE_ECDSA
 	bool "ECDSA"
 	select CRYPTO_ECDSA
diff --git a/certs/Makefile b/certs/Makefile
index 3ee1960f9f4a..3b5a3a303f4c 100644
--- a/certs/Makefile
+++ b/certs/Makefile
@@ -42,6 +42,7 @@ targets += x509_certificate_list
 # boolean option and we unfortunately can't make it depend on !RANDCONFIG.
 ifeq ($(CONFIG_MODULE_SIG_KEY),certs/signing_key.pem)
 
+keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_RSASSA_PSS) := -newkey rsassa-pss
 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
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index 547b97097230..800e2e2e36c3 100644
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -233,6 +233,7 @@ int main(int argc, char **argv)
 	EVP_PKEY *private_key;
 #ifndef USE_PKCS7
 	CMS_ContentInfo *cms = NULL;
+	CMS_SignerInfo *signer;
 	unsigned int use_keyid = 0;
 #else
 	PKCS7 *pkcs7 = NULL;
@@ -338,12 +339,46 @@ int main(int argc, char **argv)
 
 		flags |= use_signed_attrs;
 
+		if (EVP_PKEY_is_a(private_key, "RSASSA-PSS")) {
+			EVP_PKEY_CTX *pkctx;
+			char mdname[1024] = {};
+
+			pkctx = EVP_PKEY_CTX_new(private_key, NULL);
+
+			ERR(!EVP_PKEY_sign_init(pkctx), "EVP_PKEY_sign_init");
+			ERR(!EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING),
+			    "EVP_PKEY_CTX_set_rsa_padding");
+			ERR(!EVP_PKEY_CTX_set_rsa_mgf1_md_name(pkctx, hash_algo, NULL),
+			    "EVP_PKEY_CTX_set_rsa_mgf1_md_name");
+
+			ERR(!EVP_PKEY_CTX_get_rsa_mgf1_md_name(pkctx, mdname, sizeof(mdname)),
+			    "EVP_PKEY_CTX_get_rsa_mgf1_md_name");
+			printf("RSASSA-PSS %s\n", mdname);
+			flags |= CMS_KEY_PARAM;
+		}
+
 		/* Load the signature message from the digest buffer. */
 		cms = CMS_sign(NULL, NULL, NULL, NULL, flags);
 		ERR(!cms, "CMS_sign");
 
-		ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, flags),
-		    "CMS_add1_signer");
+		signer = CMS_add1_signer(cms, x509, private_key, digest_algo, flags);
+		ERR(!signer, "CMS_add1_signer");
+
+		if (EVP_PKEY_is_a(private_key, "RSASSA-PSS")) {
+			EVP_PKEY_CTX *pkctx;
+			char mdname[1024] = {};
+
+			pkctx = CMS_SignerInfo_get0_pkey_ctx(signer);
+			ERR(!EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING),
+			    "EVP_PKEY_CTX_set_rsa_padding");
+			ERR(!EVP_PKEY_CTX_set_rsa_mgf1_md_name(pkctx, hash_algo, NULL),
+			    "EVP_PKEY_CTX_set_rsa_mgf1_md_name");
+
+			ERR(!EVP_PKEY_CTX_get_rsa_mgf1_md_name(pkctx, mdname, sizeof(mdname)),
+			    "EVP_PKEY_CTX_get_rsa_mgf1_md_name");
+			printf("RSASSA-PSS %s\n", mdname);
+		}
+
 		ERR(CMS_final(cms, bm, NULL, flags) != 1,
 		    "CMS_final");
 


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v13 10/12] pkcs7: Add FIPS selftest for RSASSA-PSS
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
                   ` (8 preceding siblings ...)
  2026-01-20 14:50 ` [PATCH v13 09/12] modsign: Enable RSASSA-PSS module signing David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 14:50 ` [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing David Howells
  2026-01-20 14:50 ` [PATCH v13 12/12] pkcs7: Add ML-DSA FIPS selftest David Howells
  11 siblings, 0 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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 a FIPS selftest for RSASSA-PSS.

This is the 267th test vector taken from NIST's SigVerPSS_186-3.rsp in
186-3rsatestvectors.zip on line 2460, packaged into a rudimentary X.509
cert and PKCS#7 message.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
 crypto/asymmetric_keys/selftest_rsa.c | 133 ++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)

diff --git a/crypto/asymmetric_keys/selftest_rsa.c b/crypto/asymmetric_keys/selftest_rsa.c
index 09c9815e456a..c06e32da0f7e 100644
--- a/crypto/asymmetric_keys/selftest_rsa.c
+++ b/crypto/asymmetric_keys/selftest_rsa.c
@@ -159,6 +159,131 @@ static const u8 certs_selftest_rsa_sig[] __initconst = {
 	"\x77\x55\x3c\x6f\x0c\x32\xd3\x8c\x44\x39\x71\x25\xfe\x96\xd2"
 };
 
+/*
+ * RSASSA-PSS test vector from SigVerPSS_186-3.rsp published by NIST
+ * in 186-3rsatestvectors.zip.  This is the 267th test on line 2460.
+ */
+static const u8 certs_selftest_rsassa_keys[] __initconst = {
+	"\x30\x82\x04\x4c\x30\x82\x02\x84\xa0\x03\x02\x01\x02\x02\x04\x01"
+	"\x23\x41\x0b\x30\x3d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0a"
+	"\x30\x30\xa0\x0d\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02"
+	"\x03\xa1\x1a\x30\x18\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x08"
+	"\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\xa2\x03\x02"
+	"\x01\x00\x30\x0f\x31\x0d\x30\x0b\x06\x03\x55\x04\x03\x0c\x04\x46"
+	"\x72\x65\x64\x30\x20\x17\x0d\x32\x36\x30\x31\x30\x31\x30\x30\x30"
+	"\x30\x30\x30\x5a\x18\x0f\x32\x31\x39\x39\x30\x31\x30\x31\x30\x30"
+	"\x30\x30\x30\x30\x5a\x30\x1c\x31\x1a\x30\x18\x06\x03\x55\x04\x03"
+	"\x0c\x11\x6e\x69\x73\x74\x5f\x72\x73\x61\x70\x73\x73\x5f\x32\x36"
+	"\x37\x5f\x50\x30\x82\x01\xa1\x30\x0b\x06\x09\x2a\x86\x48\x86\xf7"
+	"\x0d\x01\x01\x0a\x03\x82\x01\x90\x00\x30\x82\x01\x8b\x02\x82\x01"
+	"\x81\x00\xa3\xf2\x23\x5a\xd2\x05\x3b\x4c\x83\xfa\x38\xf8\x28\x4e"
+	"\xd8\x05\x42\x16\x21\xfe\x98\x84\x5f\xb0\x1b\x68\x9f\x5b\x82\xb3"
+	"\x25\x11\xb6\xd1\x61\x73\xe7\xb4\x0a\x66\xa3\xa9\x99\xc1\x89\xbe"
+	"\xb9\xe0\x68\x22\x15\x0a\xc8\xbe\x67\x71\x86\x37\x0c\x82\x3b\x52"
+	"\x77\xd9\x09\xde\x07\x56\x4e\x28\x1c\xca\x2f\x13\x87\x3d\x9d\x07"
+	"\xb7\xbd\x85\xa2\xb9\xac\x66\xf4\xce\x4f\x5e\x38\xb8\xe9\xee\xbe"
+	"\xc0\x4c\x8c\xaf\x31\x1e\x37\x5d\x69\xe8\x08\x51\xd5\x59\xb8\xe9"
+	"\x0e\x85\xba\x6b\x96\x47\x67\x90\xf7\x27\xc2\x5a\xa8\x16\x30\x62"
+	"\xec\x85\x43\xfc\xc7\x75\x9b\xe6\x2c\x77\x68\xec\xc3\x7f\x34\x0b"
+	"\xb0\x61\x02\x76\x2b\xf0\x44\x1c\xa1\xaa\x2c\x7a\x81\xbf\x37\xdc"
+	"\x8b\x27\x43\x9d\x3a\xbb\xa9\x38\x12\xc9\xbb\x44\xfe\x4d\x6a\x94"
+	"\xba\xae\x70\x93\x79\xf5\xce\x5d\x0c\x8f\x81\xd0\x00\x86\xb9\xca"
+	"\xa3\x02\x68\x19\x58\x8f\x49\x1b\x52\x58\x07\x89\x9c\xda\xb3\x3d"
+	"\x8e\x99\x21\x50\xd2\xb1\x05\xd3\xaa\xb6\x15\x21\x7c\x6a\x3d\x74"
+	"\x08\x31\xc7\xdc\x76\xfa\xab\xd9\xc9\xb9\x81\x7e\xad\x0b\x49\x45"
+	"\x66\xde\x14\x33\xff\xf5\xba\x46\x04\xc6\xb8\x44\x6f\x6f\xc3\x5e"
+	"\x74\x6a\xff\x84\xff\x8b\xd7\x50\x04\x10\xd1\x0e\x82\xbf\x4c\x90"
+	"\x36\x48\x9d\xe4\x7d\xee\x9a\x32\x7a\x5c\x45\x10\xd8\x56\x13\x21"
+	"\xb9\x1d\x55\x55\x9a\x4c\xba\x85\xe0\xc3\x61\x76\x70\x84\xb2\x52"
+	"\x17\xe8\xa6\x3c\x4e\x15\x1a\x1e\x88\x68\x9f\xee\xcf\xfd\x16\xfa"
+	"\x0a\x65\xae\x41\xd2\xba\xbc\xa9\x9c\xf1\xb9\x59\xc3\xc0\x76\xc0"
+	"\xf7\x59\x74\x14\x6f\x2c\xc4\x94\x12\x6f\xbe\xca\xd4\x21\x7b\x9a"
+	"\xaa\x00\xf1\x69\xfa\x51\x25\x27\xff\x5a\x0b\x50\xda\x46\xd6\xbe"
+	"\x87\x0e\xce\xf2\xaf\x7a\x1e\x6c\x45\x56\xf6\xf7\xa0\xa0\x0b\x9f"
+	"\x47\xcb\x02\x04\x00\xb3\xf5\x7f\xa3\x42\x30\x40\x30\x0c\x06\x03"
+	"\x55\x1d\x13\x01\x01\xff\x04\x02\x30\x00\x30\x0e\x06\x03\x55\x1d"
+	"\x0f\x01\x01\x00\x04\x04\x03\x02\x07\x80\x30\x20\x06\x03\x55\x1d"
+	"\x0e\x01\x01\x00\x04\x16\x04\x14\x2b\x73\x93\x2c\xf0\x6c\x34\x1a"
+	"\xa7\x2c\xce\xa4\xe0\xac\x35\xa9\x6c\xcc\x01\x0b\x30\x3d\x06\x09"
+	"\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0a\x30\x30\xa0\x0d\x30\x0b\x06"
+	"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\xa1\x1a\x30\x18\x06\x09"
+	"\x2a\x86\x48\x86\xf7\x0d\x01\x01\x08\x30\x0b\x06\x09\x60\x86\x48"
+	"\x01\x65\x03\x04\x02\x03\xa2\x03\x02\x01\x00\x03\x82\x01\x81\x00"
+	"\x78\x7c\xdd\x6e\x1d\x4f\xdf\x9a\x0d\x9f\x96\x5e\xb8\x57\x25\x23"
+	"\x2a\x9e\xfc\xc1\x2a\xbf\xa1\xef\x25\xa8\x1e\x09\x83\x11\x1d\x90"
+	"\x00\xd4\x94\xfc\x7d\x32\x01\xeb\x3b\xba\x32\x73\x02\x72\x7f\x70"
+	"\x86\x14\x7a\x75\x5b\x48\x27\x03\x0c\x72\x76\x53\x6f\x42\x55\x93"
+	"\xab\x2e\x91\x27\xa1\x49\xe7\x54\xde\x7a\xd7\x7f\x8c\x20\x43\x26"
+	"\x7d\xb4\x9f\x8a\x35\x03\x1d\x83\xf1\x3d\x14\x0d\x5d\xf4\xd4\x24"
+	"\xb4\x74\x54\x04\x1a\x23\xb9\x2f\xf6\x81\x8e\x74\x9d\x65\xd0\x1f"
+	"\xc5\x0b\xeb\xf6\x91\x52\xf3\xf5\xfc\xb4\x87\x3b\x10\x36\x21\x9e"
+	"\x22\xb1\xe7\x4f\x83\x68\xc8\xc5\x01\xce\x65\xf2\xc9\x29\xd9\x0a"
+	"\x8e\xc8\x99\x63\x0e\x80\x25\x47\xa7\xca\x6e\xf1\x8a\xb3\xcb\x3e"
+	"\xb4\xa6\x91\xee\x68\xae\xbe\xaf\x1b\x9c\x05\x5a\xd1\x22\x18\x03"
+	"\x9c\xf4\x80\xcd\x8d\x29\x43\x32\xc5\xe1\x6e\xbb\xe6\xaf\x11\xf8"
+	"\xf4\xbf\x49\xf9\xb4\xed\x2f\x51\x11\x26\xae\x78\x0a\x3b\x78\x4b"
+	"\xe8\xf4\x42\x6a\xbd\x17\xf8\x60\x00\x74\x48\x3f\x2a\xf3\xb7\x1a"
+	"\x89\x64\xc6\xe0\xfa\x00\x04\x9a\x1d\x94\x0d\x34\xcc\x08\x83\x9e"
+	"\x0c\x59\x25\x3d\x99\xe9\x0d\x17\x87\x1d\x48\x96\x74\x69\x56\x63"
+	"\x62\x61\x66\xd3\x6f\xf9\x1d\x8c\x22\x99\xa2\xf0\x51\xea\xe2\xd6"
+	"\x0e\x8e\xd0\xbc\x3f\xac\x1e\x49\x0b\x47\x0c\x12\xf3\xd6\x97\xf6"
+	"\xfb\xfd\x88\x0d\xe2\xe9\x0e\x9f\xcb\xd4\x85\xfa\x33\x93\x19\x83"
+	"\x72\xfb\x01\xe4\xce\xc5\xc1\x59\x17\xec\xdd\x42\xe5\x7c\x43\xec"
+	"\xf5\x5a\x8c\x0e\xcb\xdc\xef\x1b\xce\x4e\x36\xd9\x6d\x46\xb1\x12"
+	"\x57\x0b\x53\xf8\x2f\x3d\x20\x64\xb0\x8a\xc7\x86\x13\x67\x0a\x28"
+	"\xea\x69\xd7\x9c\x71\x7e\xb1\xc2\x94\x09\x0d\xbd\x56\x1f\xa6\xe5"
+	"\x04\xd0\x9d\x26\x57\x24\xe3\x7a\x2d\xc6\xf4\x45\xf6\xf5\x28\xc9"
+};
+
+static const u8 certs_selftest_rsassa_data[] __initconst = {
+	"\xbe\x2f\x3e\x1d\xc8\xa3\x71\x15\x70\x40\x1b\xd5\x35\x18\x54\x26"
+	"\x94\x4d\x09\x4e\x84\x81\xa1\x2a\x43\x8d\xe0\x7d\x54\x76\x0c\x88"
+	"\xc9\x9d\x4f\xdb\xbe\x35\x5d\x6a\x26\xfa\x56\xe3\xca\x20\xee\x3f"
+	"\x8e\x8a\xcb\x98\xf6\x3d\x2f\x3a\xea\x14\xd6\xfc\xb6\xb5\x22\xd1"
+	"\x55\xc3\x75\x9a\xef\x56\xde\x3e\xa0\xa8\xf9\xfd\x7b\x11\x10\x01"
+	"\xcf\x35\x86\x36\xa8\x7c\x76\x5c\x99\xc2\x97\x5b\xb9\x50\x63\xd6"
+	"\xec\x0b\x78\x02\x64\xec\x3e\xb9\x67\xb0\xca\xca\x52\xd1\x02\x94"
+	"\xde\xb4\x02\xd3\xa2\x24\xbf\xb9\xd9\xff\xea\x41\x66\x2f\x18\xc0"
+};
+
+static const u8 certs_selftest_rsassa_sig[] __initconst = {
+	"\x30\x82\x02\x26\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x07\x02\xa0"
+	"\x82\x02\x17\x30\x82\x02\x13\x02\x01\x01\x31\x0d\x30\x0b\x06\x09"
+	"\x60\x86\x48\x01\x65\x03\x04\x02\x03\x30\x0b\x06\x09\x2a\x86\x48"
+	"\x86\xf7\x0d\x01\x07\x01\x31\x82\x01\xf0\x30\x82\x01\xec\x02\x01"
+	"\x01\x30\x17\x30\x0f\x31\x0d\x30\x0b\x06\x03\x55\x04\x03\x0c\x04"
+	"\x46\x72\x65\x64\x02\x04\x01\x23\x41\x0b\x30\x0b\x06\x09\x60\x86"
+	"\x48\x01\x65\x03\x04\x02\x03\x30\x3d\x06\x09\x2a\x86\x48\x86\xf7"
+	"\x0d\x01\x01\x0a\x30\x30\xa0\x0d\x30\x0b\x06\x09\x60\x86\x48\x01"
+	"\x65\x03\x04\x02\x03\xa1\x1a\x30\x18\x06\x09\x2a\x86\x48\x86\xf7"
+	"\x0d\x01\x01\x08\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02"
+	"\x03\xa2\x03\x02\x01\x00\x04\x82\x01\x80\x78\x7c\xdd\x6e\x1d\x4f"
+	"\xdf\x9a\x0d\x9f\x96\x5e\xb8\x57\x25\x23\x2a\x9e\xfc\xc1\x2a\xbf"
+	"\xa1\xef\x25\xa8\x1e\x09\x83\x11\x1d\x90\x00\xd4\x94\xfc\x7d\x32"
+	"\x01\xeb\x3b\xba\x32\x73\x02\x72\x7f\x70\x86\x14\x7a\x75\x5b\x48"
+	"\x27\x03\x0c\x72\x76\x53\x6f\x42\x55\x93\xab\x2e\x91\x27\xa1\x49"
+	"\xe7\x54\xde\x7a\xd7\x7f\x8c\x20\x43\x26\x7d\xb4\x9f\x8a\x35\x03"
+	"\x1d\x83\xf1\x3d\x14\x0d\x5d\xf4\xd4\x24\xb4\x74\x54\x04\x1a\x23"
+	"\xb9\x2f\xf6\x81\x8e\x74\x9d\x65\xd0\x1f\xc5\x0b\xeb\xf6\x91\x52"
+	"\xf3\xf5\xfc\xb4\x87\x3b\x10\x36\x21\x9e\x22\xb1\xe7\x4f\x83\x68"
+	"\xc8\xc5\x01\xce\x65\xf2\xc9\x29\xd9\x0a\x8e\xc8\x99\x63\x0e\x80"
+	"\x25\x47\xa7\xca\x6e\xf1\x8a\xb3\xcb\x3e\xb4\xa6\x91\xee\x68\xae"
+	"\xbe\xaf\x1b\x9c\x05\x5a\xd1\x22\x18\x03\x9c\xf4\x80\xcd\x8d\x29"
+	"\x43\x32\xc5\xe1\x6e\xbb\xe6\xaf\x11\xf8\xf4\xbf\x49\xf9\xb4\xed"
+	"\x2f\x51\x11\x26\xae\x78\x0a\x3b\x78\x4b\xe8\xf4\x42\x6a\xbd\x17"
+	"\xf8\x60\x00\x74\x48\x3f\x2a\xf3\xb7\x1a\x89\x64\xc6\xe0\xfa\x00"
+	"\x04\x9a\x1d\x94\x0d\x34\xcc\x08\x83\x9e\x0c\x59\x25\x3d\x99\xe9"
+	"\x0d\x17\x87\x1d\x48\x96\x74\x69\x56\x63\x62\x61\x66\xd3\x6f\xf9"
+	"\x1d\x8c\x22\x99\xa2\xf0\x51\xea\xe2\xd6\x0e\x8e\xd0\xbc\x3f\xac"
+	"\x1e\x49\x0b\x47\x0c\x12\xf3\xd6\x97\xf6\xfb\xfd\x88\x0d\xe2\xe9"
+	"\x0e\x9f\xcb\xd4\x85\xfa\x33\x93\x19\x83\x72\xfb\x01\xe4\xce\xc5"
+	"\xc1\x59\x17\xec\xdd\x42\xe5\x7c\x43\xec\xf5\x5a\x8c\x0e\xcb\xdc"
+	"\xef\x1b\xce\x4e\x36\xd9\x6d\x46\xb1\x12\x57\x0b\x53\xf8\x2f\x3d"
+	"\x20\x64\xb0\x8a\xc7\x86\x13\x67\x0a\x28\xea\x69\xd7\x9c\x71\x7e"
+	"\xb1\xc2\x94\x09\x0d\xbd\x56\x1f\xa6\xe5\x04\xd0\x9d\x26\x57\x24"
+	"\xe3\x7a\x2d\xc6\xf4\x45\xf6\xf5\x28\xc9"
+};
+
 void __init fips_signature_selftest_rsa(void)
 {
 	fips_signature_selftest("RSA",
@@ -168,4 +293,12 @@ void __init fips_signature_selftest_rsa(void)
 				sizeof(certs_selftest_rsa_data) - 1,
 				certs_selftest_rsa_sig,
 				sizeof(certs_selftest_rsa_sig) - 1);
+
+	fips_signature_selftest("RSASSA",
+				certs_selftest_rsassa_keys,
+				sizeof(certs_selftest_rsassa_keys) - 1,
+				certs_selftest_rsassa_data,
+				sizeof(certs_selftest_rsassa_data) - 1,
+				certs_selftest_rsassa_sig,
+				sizeof(certs_selftest_rsassa_sig) - 1);
 }


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
                   ` (9 preceding siblings ...)
  2026-01-20 14:50 ` [PATCH v13 10/12] pkcs7: Add FIPS selftest for RSASSA-PSS David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 18:31   ` Ignat Korchagin
                     ` (2 more replies)
  2026-01-20 14:50 ` [PATCH v13 12/12] pkcs7: Add ML-DSA FIPS selftest David Howells
  11 siblings, 3 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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

Limit the set of crypto combinations that may be used for module signing as
no indication of hash algorithm used for signing is added to the hash of
the data, so in theory a data blob hashed with a different algorithm can be
substituted provided it has the same hash output.

This also rejects the use of less secure algorithms.

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/public_key.c | 55 +++++++++++++++++++++++++++--
 1 file changed, 53 insertions(+), 2 deletions(-)

diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 13a5616becaa..90b98e1a952d 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -24,6 +24,52 @@ MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
 MODULE_AUTHOR("Red Hat, Inc.");
 MODULE_LICENSE("GPL");
 
+struct public_key_restriction {
+	const char	*pkey_algo;	/* Signing algorithm (e.g. "rsa") */
+	const char	*pkey_enc;	/* Signature encoding (e.g. "pkcs1") */
+	const char	*hash_algo;	/* Content hash algorithm (e.g. "sha256") */
+};
+
+static const struct public_key_restriction public_key_restrictions[] = {
+	/* algo			encoding	hash */
+	{ "rsa",		"pkcs1",	"sha256" },
+	{ "rsa",		"pkcs1",	"sha384" },
+	{ "rsa",		"pkcs1",	"sha512" },
+	{ "rsa",		"emsa-pss",	"sha512" },
+	{ "ecdsa",		"x962",		"sha256" },
+	{ "ecdsa",		"x962",		"sha384" },
+	{ "ecdsa",		"x962",		"sha512" },
+	{ "ecrdsa",		"raw",		"sha256" },
+	{ "ecrdsa",		"raw",		"sha384" },
+	{ "ecrdsa",		"raw",		"sha512" },
+	{ "mldsa44",		"raw",		"sha512" },
+	{ "mldsa65",		"raw",		"sha512" },
+	{ "mldsa87",		"raw",		"sha512" },
+	/* ML-DSA may also do its own hashing over the entire message. */
+	{ "mldsa44",		"raw",		"-" },
+	{ "mldsa65",		"raw",		"-" },
+	{ "mldsa87",		"raw",		"-" },
+};
+
+/*
+ * Determine if a particular key/hash combination is allowed.
+ */
+static int is_public_key_sig_allowed(const struct public_key_signature *sig)
+{
+	for (int i = 0; i < ARRAY_SIZE(public_key_restrictions); i++) {
+		if (strcmp(public_key_restrictions[i].pkey_algo, sig->pkey_algo) != 0)
+			continue;
+		if (strcmp(public_key_restrictions[i].pkey_enc, sig->encoding) != 0)
+			continue;
+		if (strcmp(public_key_restrictions[i].hash_algo, sig->hash_algo) != 0)
+			continue;
+		return 0;
+	}
+	pr_warn_once("Public key signature combo (%s,%s,%s) rejected\n",
+		     sig->pkey_algo, sig->encoding, sig->hash_algo);
+	return -EKEYREJECTED;
+}
+
 /*
  * Provide a part of a description of the key for /proc/keys.
  */
@@ -391,12 +437,17 @@ int public_key_verify_signature(const struct public_key *pkey,
 	bool issig;
 	int ret;
 
-	pr_devel("==>%s()\n", __func__);
-
 	BUG_ON(!pkey);
 	BUG_ON(!sig);
 	BUG_ON(!sig->s);
 
+	ret = is_public_key_sig_allowed(sig);
+	if (ret < 0)
+		return ret;
+
+	pr_devel("==>%s(%s,%s,%s)\n",
+		 __func__, sig->pkey_algo, sig->encoding, sig->hash_algo);
+
 	/*
 	 * If the signature specifies a public key algorithm, it *must* match
 	 * the key's actual public key algorithm.


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v13 12/12] pkcs7: Add ML-DSA FIPS selftest
  2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
                   ` (10 preceding siblings ...)
  2026-01-20 14:50 ` [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing David Howells
@ 2026-01-20 14:50 ` David Howells
  2026-01-20 17:54   ` Jarkko Sakkinen
  2026-01-20 21:43   ` Eric Biggers
  11 siblings, 2 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 14:50 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 a FIPS selftest for ML-DSA.

This is testcase (tcId) 35 from the ML-DSA-sigVer-FIPS204 JSON set[1],
packaged into a rudimentary X.509 cert and PKCS#7 message.

Note that only this particular testcase can be used because the current
ML-DSA implementation assumes an empty context string.

[1] https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-sigVer-FIPS204

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
 crypto/asymmetric_keys/Kconfig          |   6 +
 crypto/asymmetric_keys/Makefile         |   1 +
 crypto/asymmetric_keys/selftest.c       |   1 +
 crypto/asymmetric_keys/selftest.h       |   6 +
 crypto/asymmetric_keys/selftest_mldsa.c | 688 ++++++++++++++++++++++++
 5 files changed, 702 insertions(+)
 create mode 100644 crypto/asymmetric_keys/selftest_mldsa.c

diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index e1345b8f39f1..c698a7a39fe2 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -103,4 +103,10 @@ config FIPS_SIGNATURE_SELFTEST_ECDSA
 	depends on CRYPTO_SHA256=y || CRYPTO_SHA256=FIPS_SIGNATURE_SELFTEST
 	depends on CRYPTO_ECDSA=y || CRYPTO_ECDSA=FIPS_SIGNATURE_SELFTEST
 
+config FIPS_SIGNATURE_SELFTEST_MLDSA
+	bool
+	default y
+	depends on FIPS_SIGNATURE_SELFTEST
+	depends on CRYPTO_MLDSA=y || CRYPTO_MLDSA=FIPS_SIGNATURE_SELFTEST
+
 endif # ASYMMETRIC_KEY_TYPE
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index c5aed382ee8a..25623d100b74 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_FIPS_SIGNATURE_SELFTEST) += x509_selftest.o
 x509_selftest-y += selftest.o
 x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_RSA) += selftest_rsa.o
 x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_ECDSA) += selftest_ecdsa.o
+x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_MLDSA) += selftest_mldsa.o
 
 $(obj)/x509_cert_parser.o: \
 	$(obj)/x509.asn1.h \
diff --git a/crypto/asymmetric_keys/selftest.c b/crypto/asymmetric_keys/selftest.c
index 98dc5cdfdebe..d31cf5efefc7 100644
--- a/crypto/asymmetric_keys/selftest.c
+++ b/crypto/asymmetric_keys/selftest.c
@@ -62,6 +62,7 @@ static int __init fips_signature_selftest_init(void)
 {
 	fips_signature_selftest_rsa();
 	fips_signature_selftest_ecdsa();
+	fips_signature_selftest_mldsa();
 	return 0;
 }
 
diff --git a/crypto/asymmetric_keys/selftest.h b/crypto/asymmetric_keys/selftest.h
index 4139f05906cb..d515224fcfb3 100644
--- a/crypto/asymmetric_keys/selftest.h
+++ b/crypto/asymmetric_keys/selftest.h
@@ -20,3 +20,9 @@ void __init fips_signature_selftest_ecdsa(void);
 #else
 static inline void __init fips_signature_selftest_ecdsa(void) { }
 #endif
+
+#ifdef CONFIG_FIPS_SIGNATURE_SELFTEST_MLDSA
+void __init fips_signature_selftest_mldsa(void);
+#else
+static inline void __init fips_signature_selftest_mldsa(void) { }
+#endif
diff --git a/crypto/asymmetric_keys/selftest_mldsa.c b/crypto/asymmetric_keys/selftest_mldsa.c
new file mode 100644
index 000000000000..9927a4423067
--- /dev/null
+++ b/crypto/asymmetric_keys/selftest_mldsa.c
@@ -0,0 +1,688 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Self-tests for PKCS#7 RSA signature verification.
+ *
+ * Copyright (C) 2024 Joachim Vandersmissen <git@jvdsn.com>
+ */
+
+#include <linux/module.h>
+#include "selftest.h"
+
+/*
+ * Set of X.509 certificates to provide public keys for the tests. These will
+ * be loaded into a temporary keyring for the duration of the testing.
+ */
+static const u8 nist_mldsa_fips204_35_key[] __initconst = {
+	"\x30\x82\x15\x6a\x30\x82\x08\x67\xa0\x03\x02\x01\x02\x02\x04\x01"
+	"\x23\x40\x23\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x03\x12"
+	"\x30\x0f\x31\x0d\x30\x0b\x06\x03\x55\x04\x03\x0c\x04\x46\x72\x65"
+	"\x64\x30\x20\x17\x0d\x32\x36\x30\x31\x30\x31\x30\x30\x30\x30\x30"
+	"\x30\x5a\x18\x0f\x32\x31\x39\x39\x30\x31\x30\x31\x30\x30\x30\x30"
+	"\x30\x30\x5a\x30\x20\x31\x1e\x30\x1c\x06\x03\x55\x04\x03\x0c\x15"
+	"\x6e\x69\x73\x74\x5f\x6d\x6c\x64\x73\x61\x5f\x66\x69\x70\x73\x32"
+	"\x30\x34\x5f\x33\x35\x30\x82\x07\xb2\x30\x0b\x06\x09\x60\x86\x48"
+	"\x01\x65\x03\x04\x03\x12\x03\x82\x07\xa1\x00\x91\x52\xc0\xc6\x86"
+	"\x77\x60\x8f\x42\x6f\xb1\x6f\x8f\x75\xf7\x6c\x64\x70\x99\xd9\xd5"
+	"\x94\x31\xf4\x6f\x12\xa2\xf2\x93\x6e\x6e\x1f\x7e\x2d\xd2\x8f\x99"
+	"\xc8\x05\x81\x94\xc3\xfa\xe6\xdf\xf2\x87\xf5\x9b\xe5\x6b\x04\xb3"
+	"\xfd\x92\xda\xbd\x7b\xd3\xa3\xdf\x48\x3f\xec\xed\x84\xd3\x18\x80"
+	"\x90\x06\xda\x91\x46\x8d\x77\xd7\xc6\xeb\x9a\x51\x81\x75\x47\x7a"
+	"\x0e\x2b\x43\x56\x97\xc2\x69\xf1\x6f\xbb\x56\x99\x6b\x64\x55\xf0"
+	"\x4b\x3c\xc1\x1e\xb5\xd6\x65\x5d\x07\x3d\x96\xbf\x4b\x4c\xdb\x9e"
+	"\x31\xe9\x93\xf0\xf1\x0c\x65\x59\x83\x21\x20\x5e\x11\x15\xfa\x60"
+	"\xa1\xf3\xca\x5a\xd0\x49\x21\x8b\x16\xfd\xf7\xb5\xe2\xbf\x41\x79"
+	"\x8d\x58\x39\x52\x3b\xcf\x1d\xe3\x11\x05\x57\x79\xce\xb2\x07\x69"
+	"\xb8\x2e\x0a\xce\x7b\xb4\xed\x00\xcc\xed\x66\x5e\x42\x21\xf0\x48"
+	"\xea\xfa\x77\x4c\x7e\x9a\x49\x8d\xa2\x67\x5f\x9b\xe9\xf7\x2b\x58"
+	"\xa1\xe7\x30\xfa\xda\xad\x39\xe2\x31\xe4\x6d\x88\x4a\x22\xee\xe5"
+	"\xc3\x3a\xe2\xe6\x74\x04\xd5\x7e\xdb\xa0\xb9\x4a\x4f\x27\xd2\x08"
+	"\x1f\x46\x62\x66\xd6\x54\xc0\xb8\x37\xbe\x74\x65\x87\x34\x55\x5a"
+	"\x06\x82\x82\x7d\x65\xc3\x46\x4e\x96\x90\xdf\x6b\xb8\x1a\xdc\x11"
+	"\x79\x02\xc5\x48\x06\xb7\x3b\xcb\x6c\x44\xa9\x35\xbc\xe9\xea\x8f"
+	"\xc8\x9e\xaa\x27\xd0\x4a\x67\xe0\xf6\xe6\x0a\x94\x78\xdb\x70\xc9"
+	"\xf5\xd5\x87\xca\xd5\xb6\x2e\x55\xea\xff\xd4\xcf\xad\x4d\xd3\x67"
+	"\x2b\xb7\xaa\x80\x9b\x7f\x56\x0a\xd1\xea\xbd\xbd\x20\x88\x01\x00"
+	"\xaa\x2f\xcc\x7d\x0a\x31\x6b\xe5\x66\xee\x87\xaf\xbf\x08\xc7\xa7"
+	"\xd3\x50\xde\x31\xd2\x3d\xfd\xf5\x87\x74\x76\x30\x31\x9c\x3f\x14"
+	"\x00\x22\xf9\x70\xba\x6c\x4e\xdd\x84\x64\xdb\xaa\x5e\xb0\x22\xff"
+	"\x87\x25\x2f\x55\xab\xbd\xdf\xac\x6d\x31\xd8\x53\xb3\x50\x56\xea"
+	"\x48\xad\x33\x94\xa5\xe6\x85\x21\x06\x10\xbb\xa8\x96\xdd\xc9\x00"
+	"\x99\x93\xe2\x0e\xa1\xb0\x66\x41\xe4\xd5\x24\x2d\xd0\x8f\x6e\xff"
+	"\xdd\x6f\x0c\xcd\x8e\x5c\xb9\x8b\x6b\x66\xeb\x2b\x38\x52\x01\x4a"
+	"\xc2\x80\xc5\x44\x48\x87\xcd\x6b\xcd\xea\xb5\x94\x7f\x8f\x19\x86"
+	"\xb7\xf9\x65\xb5\x08\x51\x77\xe7\x73\x2f\xd4\xf9\x74\xd8\x7c\xc3"
+	"\x03\x24\xcf\x42\xaf\x25\xdc\x73\x68\xa1\x34\x9e\x26\x86\xa6\x05"
+	"\x5f\xe2\x6f\xcc\x5d\x1f\xa1\x1d\xed\x9f\x1c\x24\x65\x6d\x43\x6c"
+	"\xdd\x1a\xc4\x10\xf6\x00\x8b\x0f\xf2\x33\xb5\x53\x79\x17\x9f\x47"
+	"\x67\x4a\x52\xad\x56\xd1\x38\x85\xef\x03\xd7\x22\x3b\x39\xe6\xb8"
+	"\x63\x4d\x52\x89\xcf\xd9\x46\xd9\x7b\x7b\xfb\xf2\x28\xa6\xe9\x38"
+	"\x42\xbe\xb3\x75\xd7\x6e\x01\xbb\xff\xc2\xe6\x76\x58\xe3\x63\x65"
+	"\x76\x1a\xde\xc0\x72\xe3\x3a\x8e\x9d\x53\xf9\x2d\x74\x1a\xe7\x0c"
+	"\xe7\x8b\xd1\x90\xbd\x91\xc3\xa8\xe3\x09\x35\xcc\x25\x00\xa6\xdb"
+	"\x87\x5c\x45\x6c\x1d\x15\xf1\x1b\x16\xe8\x79\xb1\xb4\x63\x35\x22"
+	"\x66\x69\x5e\xad\xcb\x75\x77\xff\xfc\xfe\x6f\x5d\x72\x12\xcf\x07"
+	"\x39\x94\x04\x03\x9a\x0d\x15\xa6\x97\x85\x5b\x82\x77\xe9\x45\xc2"
+	"\xa2\x70\x14\x89\x61\x07\x0e\xe9\x5c\x13\x53\x38\x7f\xa6\x14\xea"
+	"\xec\x62\xb4\x41\xdf\x38\x5f\xff\x80\x7f\x29\xd9\x41\x63\x75\x12"
+	"\xb4\x87\x73\xfc\x48\x5a\x52\x1d\x55\x5f\xec\x22\x76\x57\x5f\x10"
+	"\x95\xc0\x23\x7e\x66\x34\x77\x73\xbf\xf4\x37\x1b\x3e\x9f\x10\x4b"
+	"\x09\x6b\x6e\xb8\x06\x8d\xff\xd2\xcf\xb3\xc0\x61\x31\xf0\xaf\xd3"
+	"\xae\xfc\x36\x03\x5f\x92\x21\xc2\xdc\x03\x63\x75\x08\xd3\x9d\xc0"
+	"\x0a\xc7\xac\x36\x2c\x15\xf2\xf5\x16\xc7\x71\x59\x34\xf5\xf8\x01"
+	"\x82\xd2\x8e\xeb\x1a\xe2\x63\xce\xf7\x24\xe5\xb1\x14\x10\x0c\x74"
+	"\xea\xd0\x0e\xc3\x6c\x7e\x1e\x7e\x04\xb6\x5f\x79\x20\x91\xe5\x22"
+	"\xb2\x5f\x8d\xe2\x25\xf5\x07\x0a\x57\xb3\x04\x53\x60\x54\x28\x29"
+	"\x64\xd6\x66\x5b\x38\x78\xcb\xd5\x93\xc8\xd8\x40\xed\x84\x9f\x14"
+	"\xc8\xf6\x16\xbc\xc1\x4d\xcb\xb4\xf2\xf0\x85\x97\x93\xb8\x0c\xbe"
+	"\x30\xb8\x3a\x31\x6a\x6e\x8b\x64\x64\x51\x2e\xaf\x53\xda\xf6\xdf"
+	"\x66\x1b\xc9\x24\xb1\xf7\x34\x64\x53\xd5\x27\xed\xc3\x7d\xc1\x42"
+	"\x15\x25\x71\x41\x14\xd6\x6c\xb0\xe3\x82\x07\x25\x88\x70\x6a\x03"
+	"\x6d\xff\xef\x9f\xf3\x0f\xe3\xc7\xe8\x1d\x00\x99\x53\x72\x33\x14"
+	"\x8e\x03\xa4\xdf\xb6\xfc\xde\xd3\x30\x2f\xe8\xa8\xe0\xb2\x21\x90"
+	"\x3c\x97\xbf\x3a\xf8\xd8\x86\x01\xea\x90\xf0\x9f\xae\x83\xe5\x6a"
+	"\x78\x2f\x3c\xb2\x4c\x48\x51\x3a\x50\xf4\xae\xf1\x2e\x39\x8b\xeb"
+	"\x5e\xd9\x44\x97\x94\xb5\x9b\x54\x34\x20\x0a\x8f\x09\x89\x2e\x0a"
+	"\x0b\xac\x13\x66\x91\x99\xe6\x75\xb3\x8e\x39\x21\x1d\xcc\xf4\x83"
+	"\x2e\x71\xcb\x11\x2a\xc2\x77\xb6\xe4\x3e\xd7\x83\x64\x7b\xd9\x44"
+	"\x52\xf7\x96\xbd\x77\x96\x83\xec\xf0\xa9\xaf\x0d\x8b\xd7\xbb\x3e"
+	"\xdd\x8d\xd3\xf7\x8b\x81\xbd\x3a\x87\x2c\x72\x11\xa9\x31\x86\xfd"
+	"\x9a\x54\x21\xb8\x0c\x57\xcc\x83\xf2\xff\xb8\x9e\x1e\x21\xdf\xbb"
+	"\x1f\x71\x0f\xbe\xdd\x52\xf0\x02\xe5\xed\x67\xba\x26\x1b\xdc\x6d"
+	"\x35\x86\x81\x9a\xfa\xbf\xbe\xc4\x52\x81\x99\xa3\xf5\x58\x95\x9a"
+	"\x9a\x03\x22\xe5\xdd\xe4\x56\x38\x2b\x7f\x26\x26\x1d\x45\xde\xe1"
+	"\x22\x94\x5d\xad\x8a\x64\xc6\x2a\xe2\xa8\x00\x7f\xba\x75\x97\x9b"
+	"\x77\xd4\x2c\xe9\xbf\x25\xf8\x54\xcb\xb0\xe3\xce\xc4\x62\x7a\x13"
+	"\x46\x69\xb9\xd4\x4b\x01\x08\x72\x9a\x85\xb8\xf9\x5f\x7d\x30\xa1"
+	"\x76\x18\x48\x0f\x3d\x01\xd0\xf1\xa5\x48\xaf\x79\x8b\x5e\x71\x28"
+	"\x37\x75\xc5\xa8\x3d\x79\x0d\x25\xb6\x3d\xf4\xba\xa5\x82\x8c\xfd"
+	"\x77\x1a\xf2\x0e\x06\xb3\x04\xea\x62\x34\x4a\x09\xd5\x7a\x29\xa6"
+	"\xa9\xfe\x25\x82\x23\xe1\x68\x6a\xd5\xd3\x11\x60\xfd\x64\x29\x0c"
+	"\x71\x2d\xcb\xc2\xf3\x20\x6e\x29\x4f\xf6\xf3\x6e\x56\x08\x4a\x20"
+	"\x31\xdb\x1d\xdd\xdc\x1a\x8d\xdc\x40\x19\x65\xf3\x8a\xea\x45\x76"
+	"\x4f\xf0\x9f\x1c\x6c\x07\x88\xdd\x0c\x7b\x1d\x4f\x8d\x9c\x60\xf0"
+	"\x27\x2e\x7f\x50\x8b\xd0\x34\x92\x9a\x19\x10\xbd\x46\x06\x33\x70"
+	"\x1c\x65\xaf\xf6\x85\xb6\xb8\xa3\x67\x55\xc0\xab\xd8\xc7\x47\x42"
+	"\xae\x80\x45\xc9\x88\x9e\xa5\x05\x72\x42\x6a\x5b\x09\xb8\x30\x05"
+	"\x43\x62\xe6\xb3\xdf\x3d\x84\x98\xc2\xfe\xd9\xea\x59\xba\x90\xf0"
+	"\xad\x8f\xeb\x87\x33\x53\xe3\x33\x60\xf6\x32\x3f\x39\xa4\x06\xfe"
+	"\x78\x27\xe8\xac\x2f\xfd\xde\x6b\xb6\xf7\x26\xca\x1c\x14\x64\x3c"
+	"\x4e\x85\x41\xd5\x7d\x6a\x18\xaf\xca\x73\xca\xdc\x53\xb7\x29\x1e"
+	"\x4b\x37\x71\xf2\xb2\x9d\xec\xbd\xf2\xf7\x21\x38\x6b\xd2\x2e\xf5"
+	"\xc1\xb9\x7c\x54\x86\xad\xf2\x60\x9a\xb3\x87\x2d\xb0\x69\xf1\xd0"
+	"\x3e\x94\x2b\xb7\x61\x93\x04\x3d\xba\x68\xd3\x1b\x20\xe0\x41\x2c"
+	"\x0a\x4a\xf5\x15\xa6\x20\xd2\x7b\x7e\x4b\xc1\x15\x3d\xde\xbb\xb3"
+	"\xe8\x79\x9c\xd1\x02\x54\x4f\xdf\xa3\x40\xaf\xa4\x66\x16\x04\xfa"
+	"\x68\x21\x2c\xfc\x0c\x15\x7e\x06\x0f\x1c\xc1\xbd\xd6\xa0\x29\x85"
+	"\x38\x0b\x61\xb6\x08\xd4\xc7\x45\x9b\x49\x4d\xd5\x3d\xc8\x00\x9b"
+	"\xab\xc7\x6f\x62\x39\x7e\x96\x2d\x18\xac\xab\xec\xd4\x98\x9b\x86"
+	"\x18\x59\x2f\x9d\xda\x47\x47\x0e\x19\x8c\xe2\xd9\x6f\x62\x3e\x9d"
+	"\x3f\x73\x13\xb4\x62\x39\x31\x9a\x54\x04\x76\x7c\x5f\xf9\xe7\x79"
+	"\x5b\x4a\xf6\x95\x82\x64\xaa\x7d\xf3\x83\x00\x72\xc5\xd9\xc3\xaa"
+	"\x75\x0c\x42\x2d\x9a\x1c\x3c\x6e\x44\xf2\x52\x9c\x91\xe0\xea\xf3"
+	"\x06\x18\xe8\x61\x63\x04\x7e\x29\x9d\xa6\x1e\x3e\xce\x10\x38\xac"
+	"\xde\xb8\x52\x67\x14\x8a\x32\xdb\x71\x40\x5f\x0c\xd6\x2d\x52\xa4"
+	"\xd2\x9d\x4d\xf3\x21\xa0\x45\x2a\x19\xda\x75\x70\xae\xbd\x4a\x7b"
+	"\x3a\x2f\x5f\xc5\xbd\x79\x28\x2d\xbc\xff\x43\x3c\x3f\xe4\x23\xa7"
+	"\x77\xa6\xf1\x2b\x62\x75\xb5\xab\x85\x0c\x76\xec\xdd\x42\xc9\xdf"
+	"\x67\xb4\x0b\x95\x61\xd1\xf8\x55\xdb\x54\xfa\xcd\x98\xb2\x0d\xc6"
+	"\x15\xfe\xb4\xea\x3f\xae\xe9\xcc\x90\xf1\x08\x15\x88\xca\xe8\x32"
+	"\x0f\xa1\xca\x4a\xd1\x21\xe4\xf3\x11\x76\xdf\xed\xec\x3e\x61\x09"
+	"\x56\x7f\xf1\x88\x39\x34\x41\x76\x5b\x9a\x88\xad\x04\x40\x67\x55"
+	"\x2e\x8d\xc1\xe1\x91\x2f\x6a\xc0\xd5\x54\x46\x24\x7a\x48\x14\x56"
+	"\x98\x74\xec\x7c\x3d\x6a\x28\x8b\xbc\xce\xe6\x47\x5f\x9a\x84\x0b"
+	"\xa4\x40\xdf\x6f\x6a\x9e\xd4\x7f\x0b\x12\x24\xbb\xbe\x4a\xce\x0b"
+	"\xd8\x7c\xf6\x0c\x69\xcd\x63\xfa\xd2\xfb\x8e\xc2\x80\x5c\xb8\x0b"
+	"\x2d\x5d\xd0\x31\x25\x41\xdb\xc1\x02\x04\xcc\x55\x74\xf9\xe4\xe7"
+	"\x56\xcb\xc8\x73\x70\xdd\x66\xeb\x9f\x6e\x09\x57\xa0\xab\xd7\x1a"
+	"\x15\xe0\xeb\x18\xf4\xe2\xe1\xc7\x3a\x38\xfd\x3d\x36\x44\xe4\xd9"
+	"\xa7\x4b\xf8\x5a\xa1\xd5\xb4\x2a\x68\xa3\x05\x74\x58\x11\x17\xdb"
+	"\x27\xe1\xd5\x5f\x7d\x01\x6d\xa0\x8d\x0e\x6b\x4f\x88\x1b\xcd\xde"
+	"\x48\xab\x47\x3e\xd0\x73\xd8\x55\xf1\x90\x91\xa8\xc6\x9b\xd9\xd3"
+	"\x2e\xf5\x7e\xde\xb3\xe8\xfb\x4f\x80\xec\x87\xa3\xa3\x02\x78\x54"
+	"\xe0\x33\x8d\x24\x88\xc9\x5d\xab\x6b\x67\x72\x01\xb0\xc0\x94\x26"
+	"\x9b\x1a\xf4\xc3\x21\x8d\x4b\xfd\xac\xea\x35\xe5\xb9\x93\x1c\xe6"
+	"\x36\x69\x80\x8f\x20\xb7\x3d\x42\x90\xbd\xea\x77\x38\xbf\xa8\xa8"
+	"\x29\x05\x32\x32\x1d\x20\xf1\x3f\x39\x9c\x92\x6e\x2e\x39\xd1\x27"
+	"\x55\x59\xe4\x79\x3a\xf4\x4e\x14\x38\x78\x80\xa3\x42\x30\x40\x30"
+	"\x0c\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x02\x30\x00\x30\x0e\x06"
+	"\x03\x55\x1d\x0f\x01\x01\x00\x04\x04\x03\x02\x07\x80\x30\x20\x06"
+	"\x03\x55\x1d\x0e\x01\x01\x00\x04\x16\x04\x14\x2b\x73\x93\x2c\xf0"
+	"\x6c\x34\x1a\xa7\x2c\xce\xa4\xe0\xac\x35\xa9\x6c\xcc\x00\x23\x30"
+	"\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x03\x12\x03\x82\x0c\xee"
+	"\x00\x6e\x8c\x4b\x20\x61\xc2\xcd\xf2\x71\x54\xbf\x70\x85\xf6\x3c"
+	"\xb1\x5d\xa3\xce\xc8\x2d\x52\xca\xd1\xa6\x50\x80\x68\x75\x05\x25"
+	"\x24\xda\xa1\xef\xdf\xf4\x6f\xde\x5e\xff\x63\xef\xf5\x70\x74\x7c"
+	"\x69\xfd\x23\x4b\xa3\xaa\x3b\xa9\xa8\x0f\x48\x8b\xc4\x8f\x95\x9f"
+	"\xf5\x6a\xb3\x17\x35\x5f\xfe\x91\x7b\xdd\xd3\xbb\xf7\x3b\xf0\xa8"
+	"\x22\x09\xbe\x25\x48\xcd\xca\x1a\x37\xc4\xde\x57\x18\x56\x30\x19"
+	"\xa9\x26\x99\x13\x9a\x6d\x6a\x69\xe9\x64\x83\x2d\xdd\x70\xf5\xe8"
+	"\x03\x75\xdc\x9f\xe0\xba\x8e\x22\xae\x3a\xd8\xaa\xd9\x45\x84\x71"
+	"\xcd\x37\x61\xb1\xb9\x04\xe8\xbb\xba\x72\xfa\x8a\x07\x1d\xf1\x82"
+	"\x55\x17\xff\xa2\x2e\x2b\xbf\xf9\x9a\x0f\x86\x94\x06\xd9\x07\xdb"
+	"\xc3\x16\x92\x90\xce\xd1\x4e\xb8\xee\x7a\x2b\x6c\xe7\xc2\x6a\x0a"
+	"\xe2\x8b\x32\x5e\xd4\x61\x38\x90\xaf\xce\xbb\x38\xe6\xe9\xd5\x43"
+	"\x74\xc9\xeb\x48\xd0\xe6\x00\x30\xa1\x1e\x75\x03\xb9\x06\xe9\x16"
+	"\x35\x7c\x6f\x81\xd5\x9f\x89\xcc\x36\x33\x75\xcb\xf0\x1e\xd0\xd8"
+	"\x51\x54\xd5\x5c\xb8\xfc\xe7\xb2\x17\xd5\xed\xeb\xe9\x36\x85\xe0"
+	"\xbe\x43\x4c\xb0\xc5\x67\xc8\x97\x62\xb3\x80\x89\xec\x2c\xf3\x4c"
+	"\x93\x87\x9c\x0b\x23\x5d\x44\x25\x6a\x10\x3f\x21\x08\x7d\x8d\xfc"
+	"\x99\x8d\xc5\xbe\xbe\x57\x5c\x5d\x4d\x27\x7b\xa2\x2e\x81\xcd\x0a"
+	"\xf1\x49\x2b\x43\xda\xc4\x36\x5c\xc6\x91\x75\xd8\x95\xa6\x9b\xbf"
+	"\xe9\x21\x45\x3c\x07\xae\x56\xcd\xf5\x1b\x91\x56\xe4\x49\x40\x12"
+	"\x58\x8a\xa4\xac\x32\x53\x93\xbe\xe9\x8a\x65\xef\x71\xe3\x07\xc8"
+	"\x4d\xb9\x35\x85\x4d\x06\x9b\xa4\x11\x6a\x67\x7a\x5b\x49\xee\xea"
+	"\xf2\x0d\x16\x49\x2b\x74\x46\x78\xcc\x59\x12\x0c\x80\x6f\xae\x7d"
+	"\x23\x30\x87\x7f\x16\x52\x04\x11\x41\x0b\xba\x48\xbf\x49\xaa\x08"
+	"\xf4\x44\x00\x75\x4a\x05\x79\x79\x66\x31\x94\x44\x9e\x66\xf5\xc0"
+	"\xd7\xa1\xeb\xb5\xda\xc4\xb6\x5c\xf9\x20\x0b\x21\x89\xf6\x0f\xa5"
+	"\x29\x48\xcb\x7a\x83\xd5\xfd\x54\x45\xaf\xa3\x0d\x99\xe9\x14\x30"
+	"\x06\x8a\x53\x51\x08\x0d\xa4\x24\xa6\xf4\xae\x5f\x8e\x1b\x7b\xa6"
+	"\x48\x1c\xfb\x39\xfc\x34\x2a\xcf\xa0\x84\xb3\x79\xb7\xc7\x4d\x64"
+	"\x0e\x0c\x04\x87\x31\x9f\xf6\x97\x02\x8b\xe8\xc2\x13\x21\x8e\xfc"
+	"\x85\x7c\xac\xfa\xc4\x44\x10\x3f\x2f\x93\x02\x74\x44\x1f\x18\xdc"
+	"\x2e\x17\xca\x18\x27\x86\x55\xfb\xc0\x79\x4b\x50\x08\x33\x62\x4c"
+	"\x58\x29\x20\x98\x95\x9f\x8c\x7a\xf7\x82\xe1\x41\x43\xf3\x5c\x55"
+	"\x54\xe3\x22\x60\xf2\xa4\x85\x17\x88\x93\x6b\x6d\xc7\x48\xf6\xc0"
+	"\x0b\x4b\xf0\x86\xc6\x64\xae\xd9\x22\x08\x75\x35\xce\xf4\x7b\xad"
+	"\xf2\xb6\x7d\x50\x6e\xba\xf6\x46\x30\x7b\xbc\x60\xc3\xf7\xf7\xeb"
+	"\x39\x44\x6a\x34\xde\xb4\x6f\x43\x3f\xfb\xcb\x23\x60\xfb\x55\x57"
+	"\xaa\x9a\x2e\x33\x29\x37\xd7\x9a\xb6\x85\xa2\xad\x9b\x25\x42\x38"
+	"\x83\x44\x85\x0e\xec\x19\x74\xa3\xdc\x73\x4b\x30\xb9\x6b\x05\x63"
+	"\xcd\xdb\xa3\x18\xed\xfd\xc2\x94\x1b\xdf\x1f\x64\x6c\xd6\x29\x05"
+	"\x58\xe0\x77\xb9\x1b\xd5\x40\xe6\xff\x3b\x7e\x13\x2b\xef\xed\x35"
+	"\x8e\x06\x69\x13\x8f\xe4\x93\x59\x34\x54\x50\x16\x3c\xbb\x5b\xe2"
+	"\xa4\x7a\xd5\x35\x60\x3a\x13\x8e\x7c\x37\xf6\xb8\xfd\x1f\xa1\x1d"
+	"\xd4\x25\x19\x54\xba\xe7\x8e\x7c\x59\x40\xc3\x7a\xf2\x2c\x94\x78"
+	"\xca\x02\x0a\x1d\x21\x4f\x97\x57\xbc\x06\x36\x23\xce\x8d\xce\xdd"
+	"\x39\x5d\x6b\x7b\xc1\xa8\x06\x90\x4e\xbf\xaf\x28\xf0\xf8\xc5\xa6"
+	"\x3a\x0c\x1c\xc6\x31\x4f\xe8\x05\x79\x1d\x76\x57\x05\xf5\xfa\x33"
+	"\x17\x1a\xb4\xc8\x51\xc2\x6e\x42\xc0\xf9\xdc\xcf\x9c\x28\x37\xc1"
+	"\x11\x42\x1d\x0f\x5f\xdc\xf9\xa9\xeb\xa0\x9c\x25\xdb\x0d\x79\x65"
+	"\xdc\x91\xdc\x4e\x63\x84\x1a\x76\xae\x9a\x68\x7a\xd8\xb6\xe4\x90"
+	"\x68\xcf\x74\xfa\xaf\xd8\xa6\x6c\x91\x39\xd3\xc3\xa6\xbe\x06\x56"
+	"\x3c\xb5\x7f\xe7\x73\x30\x14\x79\x57\x4c\x68\xeb\x32\x94\xe3\x35"
+	"\xf9\xf1\xbb\x7c\xfd\xf5\x0e\xa1\x13\x92\xf0\x4f\x5f\x3b\xe9\x9c"
+	"\xb2\x4b\x07\xa8\x91\x17\x34\x02\xef\x38\xf7\x44\xdd\xf9\x27\xf0"
+	"\x60\x1f\x70\xba\x50\xf8\xab\x84\x5f\xf2\xa0\x12\x40\x1a\x99\xcf"
+	"\x4f\x03\x36\x4c\x30\x82\xd4\x21\x81\x91\x9e\x87\xd4\xac\x3b\x3b"
+	"\xe1\xf9\x5a\xb6\x90\xfc\xda\x10\x6c\x87\xc6\x3c\x7b\xed\xf1\x29"
+	"\x08\xd6\xa0\xee\xc3\xb6\x72\x46\x1b\xb1\x38\xec\xfd\x48\x01\x9a"
+	"\x07\x7e\xf4\xe5\x90\x94\x8a\xbd\x08\x3e\x28\xef\x4d\x06\x2f\x8e"
+	"\x58\x3b\x69\xcb\x79\x80\x3b\x70\xde\x5d\xea\x1f\x60\x00\x51\xd9"
+	"\xed\xef\x2a\xed\x93\xa5\xd5\xbb\x5a\xb7\xb5\xb1\x96\x84\x62\x25"
+	"\xf6\xb0\x73\xdf\xbe\x40\x13\xb4\xc8\x14\xae\x15\x20\x7d\xbb\x76"
+	"\x0b\x97\xe6\xbc\xb7\x61\x7e\xb2\x6c\xd3\xb5\xa4\x1b\xa6\xb5\xdd"
+	"\x88\x45\x1b\x5b\xcc\xf5\x52\xdc\x49\x3f\x85\xa1\xcf\x3a\xfa\xae"
+	"\x80\x81\x89\xb2\xfe\xdf\x04\x47\x8e\xde\x57\x94\x82\xa7\x11\xb2"
+	"\x2b\x55\xd4\x8a\xb2\x18\x9e\x6c\x14\xf6\xf8\x69\x84\x5d\x88\xf7"
+	"\x8a\xf5\x40\x20\x24\x60\x5f\xa3\xe2\x47\x32\xf9\x93\x17\x09\xac"
+	"\x35\x9d\xfa\x74\x78\x17\xb1\x2c\x37\xb0\xdc\x0b\xe0\x8b\x5a\xcf"
+	"\x9d\x3f\x09\x6e\x44\xf4\xdb\xa0\x23\x34\x76\xb2\x66\xf4\x2b\x92"
+	"\x04\x0a\x9c\x88\x49\x6c\x80\xfb\x99\x6c\x70\xfb\xd5\xdc\xce\x10"
+	"\xd1\x1a\x72\x2b\x4e\x9e\x34\xe0\x60\xf0\x06\x04\xd2\x55\x78\xc4"
+	"\xea\xe8\x6b\x4a\x43\x7a\x14\xc7\x2c\x83\x34\x63\xf4\x4c\xa5\xee"
+	"\xb3\xf0\x02\x78\x57\x44\x69\x37\xed\xda\x22\xb6\x3f\x86\x15\x81"
+	"\xeb\x1f\xae\x69\x75\x29\x8c\x04\x83\xff\x80\xad\x45\x18\x88\x6a"
+	"\x78\x43\x1b\x93\xf8\xd4\x19\x89\x1d\xbb\x85\x6b\x2f\x08\xdf\xc2"
+	"\x27\x72\xbe\x36\xdb\x30\x7f\x3b\x36\xfe\x81\x60\xad\xb9\xc1\xf8"
+	"\x9b\x80\x31\xba\xb2\x42\xaa\x5b\x41\x68\x06\x40\x41\xe1\xaf\xf6"
+	"\x3f\x73\x67\xdd\x83\x92\x6d\xb6\x4b\x21\xe1\x97\x7c\x62\x46\x36"
+	"\xfd\x93\x8e\x26\x54\x20\x95\xb8\xdd\x35\xb8\x87\xe8\xd7\x01\x10"
+	"\x89\x20\xaa\x0f\x0c\x5e\x3d\xd1\xc1\xc6\x98\x15\x38\xc5\x73\xe3"
+	"\xbf\x08\x51\x83\x32\x56\x5d\x1a\xa9\x0c\x4f\x2f\x16\x51\x16\xc9"
+	"\x2e\x39\x8c\x5c\xe8\x95\x22\xc1\x19\xf9\x8b\x38\x53\xc6\x55\x8a"
+	"\x07\x13\xae\x00\xc3\xc2\xe0\x8b\x0c\xdd\xb8\xf3\xdd\xca\x21\x1f"
+	"\xfe\xdb\x9b\x28\x8f\x9e\xd8\x96\x02\x6a\x2b\x35\x89\x6e\xcb\x65"
+	"\xf3\xde\x3a\xa5\x3f\x38\xd9\x8f\xbf\xa2\xb9\xc3\x6b\xaa\x2a\x28"
+	"\x7a\xc6\xe6\xa0\xfc\xe3\x37\xfa\x60\xf7\xdd\x4e\xcd\x5d\x64\xa8"
+	"\x4b\xd2\x30\x40\x68\x92\x5f\xa3\x72\x9f\x4d\xd8\x71\xae\x2c\xd7"
+	"\x59\x60\xd9\x14\x88\x93\x9d\xd7\x56\x1e\x6b\xa0\x46\x23\x69\x82"
+	"\x95\xb2\xa0\x66\xe4\xc2\x7b\xee\x44\x51\x93\xb8\x4d\x8b\xa4\x24"
+	"\x57\x94\xaf\xb6\x26\x02\x7b\x00\xd9\x84\xda\x51\xcc\xce\x4c\x63"
+	"\x90\x98\xb3\x13\x2a\x85\xec\x77\x52\x69\x79\x9f\x37\xb8\xa3\xfb"
+	"\x2b\x76\x39\x1a\x6a\x99\xd7\x0f\xa5\xc7\xa3\x55\xc3\x99\x59\x47"
+	"\x2b\x36\x1e\xe9\xf0\x8d\x85\xb9\x0d\x26\x57\x50\xce\x0a\xf6\xdc"
+	"\xb2\x60\x21\xe8\x76\xfd\x15\x7a\x9a\xe4\x7c\xd8\x17\x0e\x58\x6b"
+	"\x86\xf6\x7f\xf0\x69\xf8\x1c\xc3\x6c\x5a\xf7\xe9\xd5\xf0\x5d\xfc"
+	"\x50\x5a\x89\x7a\xad\xaa\xa5\x39\xe4\x08\x42\xf6\xc2\x23\x90\xf0"
+	"\x66\x39\x8b\x27\xe3\x05\x21\x43\x21\xc9\xe6\xd6\x21\xa2\xda\x34"
+	"\x5b\x34\x58\xe6\xef\x93\x02\x96\xa4\xa4\x86\x12\x12\xdd\x67\x10"
+	"\xc4\x5e\xf3\xca\x79\xfd\x65\x29\xee\xe6\xb9\x1c\x0a\x20\x98\x74"
+	"\xd6\xc4\x3f\x10\xe0\xee\x31\x53\x05\xa8\xb4\x2d\xa1\xde\x26\x30"
+	"\x80\xc6\x13\x9d\xf0\x67\x51\xd1\xfb\x09\x22\x02\x2b\x51\x92\x3e"
+	"\x36\x36\x6c\x5b\xcf\x00\xf9\xa4\xa0\x20\x06\x46\x87\x3b\xc5\x19"
+	"\x8d\x43\x7b\x57\xd7\xe0\xa4\x2e\xe9\x6d\xe7\x64\x1a\x77\x1f\xf7"
+	"\x99\x5b\xc8\x43\x39\x62\xbc\x1f\xff\xb4\x4a\x2a\x5c\x06\x3f\x04"
+	"\xb0\xea\x22\x83\xa5\x50\xae\x4a\xf8\x90\xd0\x4a\x61\xe2\xba\x45"
+	"\x0d\x7a\xba\xeb\xfe\xd1\x22\x61\x8b\xa2\x46\x9c\x74\x10\xd0\x66"
+	"\x92\x7c\x01\x56\x3a\x30\xb9\xc3\x3e\x57\x1a\x0c\xdb\xa6\xc3\x64"
+	"\xd5\xff\x06\xa3\x46\x33\x8a\x1a\x6d\x5d\x07\x0d\xbf\x88\xf2\x38"
+	"\x41\xf9\x2d\xbc\xb2\x55\x6d\xa0\xf7\xc1\x9e\x64\x51\xf8\xb4\xea"
+	"\x35\x8b\x11\x80\xe3\x6c\xa2\xb6\x3b\xed\xaa\xdd\xf3\x69\xfa\xa2"
+	"\x53\x1f\x22\xa8\x28\x8f\x57\xe1\x41\xbf\xcc\xb3\x3d\x86\x47\x7a"
+	"\xa3\xc1\xd4\xfe\x0e\xfa\x6b\x95\x4e\x1a\xbf\x33\x50\x9d\x2a\x7d"
+	"\x28\x0a\x64\x4d\x26\xae\x17\x65\x65\xe8\x55\xd0\x63\xf4\x1d\x03"
+	"\x5c\x9f\xe9\x1b\x25\x12\x7c\x06\x41\xc0\x90\xb9\x9c\x17\x02\xf8"
+	"\x7a\xef\xe5\x63\x7d\x8b\x38\x7a\x3c\x85\xdc\xdf\xad\x47\x5e\xef"
+	"\x0d\x96\x7d\xed\xf2\xc5\x00\x1a\xd2\x09\xef\x1e\xff\xc3\x8b\xd0"
+	"\xbc\xb8\x36\x76\x13\x33\xbd\xda\xa0\x1e\x02\x6c\x44\x8a\xd8\x7c"
+	"\x3e\x7d\xc9\x66\x5e\xf3\xbe\xb1\x72\x8e\xfc\xbc\xe5\x99\x30\x89"
+	"\x88\x91\x34\x3f\x9d\x2f\xfe\xa5\x1e\xb1\xef\x82\x23\x62\x91\x25"
+	"\x22\x0a\x8a\xdb\x39\xe4\x5b\xf8\x2a\x75\xb7\x38\xff\xef\xca\x45"
+	"\x9a\x57\xfb\xb3\xfe\xfb\x6d\x8f\x2e\xb1\x62\x64\x6d\x39\x57\x8d"
+	"\x95\xe7\x79\xdd\x98\x3e\x68\xaa\x12\x50\x7b\x0e\xa2\x2b\x89\x52"
+	"\x9f\xca\xd5\xc1\x22\xc2\x6f\x54\x83\xbd\xd7\x2c\xbb\xba\x50\xda"
+	"\xad\x42\x93\xe7\x86\x9d\x60\xf5\x33\x1b\x7f\xaa\x75\x65\xbd\xa8"
+	"\x34\x15\x6d\x1c\xf7\x47\x1f\x94\xdc\xab\xa8\x14\x93\x69\xdd\x2c"
+	"\x3b\xf9\x21\x11\x36\x80\x63\xec\xc9\x8e\x78\x48\xb4\x31\xac\xa0"
+	"\x48\x00\x3e\xed\x6f\xb3\xb0\x15\xc9\x24\x72\x24\x5b\x51\x7c\x65"
+	"\xbb\x24\xb6\xb1\x53\xfd\x3f\x36\x7a\x6c\xbf\xec\x90\xcc\xd9\x01"
+	"\x03\x30\x9e\xe3\x4a\x97\xcc\x3a\x35\xc6\x4a\x2b\xd3\x18\xbc\xb1"
+	"\x1f\x64\x08\xa0\xf8\x84\x34\x36\x3a\x91\x1a\x28\x72\x98\xdd\x1a"
+	"\xbe\xb1\x32\x77\x95\x72\x7e\xc5\xc1\xd7\x3b\xf8\x1e\x55\xc2\xdd"
+	"\xed\x24\xdb\x1b\x9b\x0e\xd1\x07\x01\x85\x41\x90\x3c\x90\x6a\xf2"
+	"\x0a\x8b\x4b\x7e\x9e\x87\xed\xa8\xa8\x8c\x5a\x4c\x4d\xc3\xb5\xec"
+	"\x7a\x4d\xe1\x51\xf0\x00\x64\xb9\xc3\x6e\x61\x2a\x41\xd5\x2e\x0e"
+	"\xf1\x1e\x87\xe5\xd5\xe4\xcc\x1a\x36\x7e\x5d\x96\x02\x14\xce\xaf"
+	"\xa2\xbb\x61\x05\xf4\x2e\x64\xba\x17\xff\x18\xc8\xe1\x17\x8a\x02"
+	"\x6b\x22\xe5\xd4\xd0\x68\xf6\x9c\x10\xf0\x2d\x4f\x82\xb3\x21\xb4"
+	"\xaa\x7f\xff\x6b\x7e\x9a\xf2\x12\x44\x4a\xa5\xbb\x16\xb6\x56\x6e"
+	"\xb1\x20\xb4\xb0\x34\x8f\xe4\x94\xb2\xf6\x7f\x9f\x05\xd0\x42\x30"
+	"\x04\xdb\x11\xb8\xd7\x5a\x1b\xb6\x06\xed\x6e\x9c\x69\x6d\x2c\x0f"
+	"\x6f\x7f\xf3\x9c\x76\x2e\xad\xc2\xd6\xc6\xfd\x93\xc1\xee\x25\xbb"
+	"\xc8\xc6\xb5\xd1\x37\x65\xdd\xe5\x78\xb0\x89\x0a\x91\x4a\xe1\x17"
+	"\x61\x43\x18\x47\xf3\xc2\x2a\x22\xc2\x56\x4e\x01\x31\xa3\x0b\xc7"
+	"\xe6\x53\x27\xa8\xc8\x32\x25\x69\x7c\x8b\x8e\xb1\x2b\xc6\xc9\x85"
+	"\x05\x1d\x67\x1e\xc6\x10\xa3\x60\x46\xbf\x9d\x5b\x3f\xda\x1f\xd3"
+	"\x8b\x1a\x95\x88\xa2\x16\xb0\xdd\x7f\x46\x2f\x5f\xef\xa0\x17\x0e"
+	"\x5e\x19\x20\x8c\xeb\x97\x52\xc8\xe0\xdc\xc0\x40\x0a\xd1\x84\xc1"
+	"\xa6\xb2\xf4\x6c\xc7\x8d\xc9\xd4\xb8\xc3\xe3\xe5\xf9\x8a\xc5\xdb"
+	"\x04\x2a\x89\xa5\x92\x64\x3f\x91\xd0\x60\x97\x8a\x42\x2d\x4b\x2c"
+	"\xf8\xa7\xe2\x68\xf9\xd3\x94\x1c\x24\xe8\x80\xff\x05\xa7\x02\xab"
+	"\x66\xd7\xb9\xa3\xeb\xd5\x0f\xf7\x26\x4f\x8f\x6b\x5a\xb2\x7c\xda"
+	"\x1a\xb3\x83\x5f\xbc\xcc\xfc\x50\xc8\x24\x8c\x38\x9d\x80\x79\x50"
+	"\x9d\x84\xe8\xee\x85\x19\xf3\x73\x5a\xd2\x41\x92\xde\x87\x5f\x52"
+	"\x62\x91\xbe\x90\x1e\xce\x54\x13\x68\x35\x3e\x2b\xe5\xa2\x1e\xc0"
+	"\xc1\x2f\x9c\x52\xd9\xe1\x5c\xe4\xfd\x21\xa3\x5a\x51\xb3\x01\x9d"
+	"\x22\x2c\x6c\xa8\xb9\xda\xfb\x78\xa8\x24\x1f\xef\xe9\x1c\x38\x04"
+	"\xf5\x8b\x80\xca\xe6\xb9\x76\x27\x31\xe1\x24\xf0\x07\xf9\xa9\x11"
+	"\x77\x9a\x8a\xc1\x87\x21\x49\x1b\x6e\x94\x94\x4e\xe7\x3a\x10\x00"
+	"\xd1\xd7\x02\xbf\x53\xe7\x88\x4e\xab\x63\x35\x61\x39\x81\x45\x21"
+	"\x85\x35\x4b\x44\xca\xc0\xdb\x8f\xa3\x6a\xc7\x90\x12\x7a\xd5\x94"
+	"\xd7\xfe\x30\xb2\x0f\x51\x52\xd0\xe6\xa7\xbe\x52\x2d\x45\xba\xed"
+	"\xbc\x3c\x95\x35\x50\x3f\x83\x97\xa8\x8f\x7e\xfb\x2e\xa3\x5b\xe1"
+	"\x2c\xb9\x15\x79\x62\x28\x8f\x02\x47\x31\x63\x2f\x45\xa7\xa7\x21"
+	"\xa4\x26\x17\x2f\x46\x72\x22\x44\xed\x3a\xff\x0a\x80\x27\xb7\xaa"
+	"\xa3\x9e\xe3\xb7\x71\xd2\xd9\x98\xa2\x6a\x5b\x18\x70\x6b\xfa\xf3"
+	"\x9f\xcd\xa9\x4c\xca\x97\x76\x41\x98\xb2\x8b\x98\x23\x88\xe7\x1e"
+	"\xa3\xd3\x56\x9a\x48\xf1\xd8\xf5\xd5\xf5\xd2\xff\x60\x52\x82\xeb"
+	"\xe8\x92\x5c\x36\xfc\x32\xfe\x46\x2d\x9a\xbd\xb8\xc2\x37\x63\xee"
+	"\xbe\x69\x4c\x98\x3d\x3d\xa3\x76\xe7\xbe\x8b\xb9\xe2\x07\x4b\x9a"
+	"\x55\x44\x71\x6e\x7d\x7f\xb0\x31\x55\xb8\x74\x82\x9c\x47\xf9\xdc"
+	"\x9a\x21\xd3\xbb\x47\x22\x05\x3b\x4b\x00\x31\xe1\x7f\x9d\xcf\xd1"
+	"\xde\xeb\xd6\x2a\xd9\x0b\xa8\x34\x03\xc3\x66\x34\x1f\xcb\xe8\xd8"
+	"\xf2\xf9\x4a\x3f\x6e\x8e\x3f\x8b\xce\xef\x9d\xe9\xf9\x92\x33\x7d"
+	"\x8a\x61\x2f\x5c\xaf\x5d\x4c\x66\x30\x37\x09\x3f\xd0\x5e\xe6\x43"
+	"\xef\x03\x63\x63\xc5\x39\x2b\xa8\x09\x5a\x86\x78\x5c\xa0\xa0\x5c"
+	"\xa1\xba\xb7\xbc\xdb\xd7\x70\x60\x81\x20\x19\x72\x82\x85\xed\x96"
+	"\x58\xa9\xdb\xa2\xcc\x03\xfc\x00\x92\x46\x3c\x79\x30\xce\xe0\x8f"
+	"\xa0\x91\xd5\x16\xcc\x46\xce\xf2\x4a\x62\xaa\x1d\x80\x2f\xf5\x45"
+	"\x7b\x9e\x97\xd7\x94\x39\x73\x6d\x5a\x25\xe4\x46\xb9\x6c\x58\xcc"
+	"\xa7\xc9\x9b\x81\x9a\x98\x05\x0b\x82\xb4\xb1\xc5\x08\x71\x15\x1f"
+	"\x26\x86\x26\x7b\xa8\x47\xaf\x80\x42\x2d\xd1\x68\x07\xb6\xa3\x81"
+	"\xc5\x40\x6e\xf7\xf6\x66\x81\x2d\x1e\x65\x01\xae\x2c\xaa\x59\x7c"
+	"\x90\xa4\xfd\x34\x04\x73\x3a\x40\x1a\x2b\x9f\x35\x4b\x25\x17\x8f"
+	"\xe5\xe6\x99\x0f\x1e\x23\xed\x95\xfe\xf6\xa3\x90\xd3\xca\xd4\x22"
+	"\xb4\x8b\x66\xac\xe9\xf3\xaf\xc8\x1b\xaa\x9f\x92\xc0\x19\x3c\x01"
+	"\x66\xc6\x07\xed\x82\xbe\x60\x08\x6a\x94\xfc\x79\xfa\x3c\xb5\x24"
+	"\xb1\xc8\x7f\xf3\x53\x20\x90\x1f\x07\x06\xd4\xf6\x7f\xeb\xcb\x96"
+	"\x5f\xd8\x2b\xd2\x7e\x44\xaa\x62\x75\x43\xfa\xc9\xfa\x27\x78\xe7"
+	"\xe7\x61\xc2\xc2\xd2\x87\x24\x75\xab\x22\x4d\xc4\xbe\xa2\x9e\xe6"
+	"\x2e\xc3\xee\xd3\x37\x69\x02\x50\x13\xcb\xa3\x65\xf2\xdd\xed\xbc"
+	"\x15\x68\x20\x50\x6d\xe4\x8a\x8b\x9f\x45\x39\xc5\xe4\xf1\x74\x7a"
+	"\xf5\x0f\xa5\x94\x5a\x5a\x3c\x0c\xd0\xb1\x5e\x27\xd5\x8a\x98\x15"
+	"\x24\x65\x24\x15\xcb\x7e\xee\x62\x0b\xbd\xf4\xb0\x32\x31\xb3\xc3"
+	"\x21\x58\xe5\x7a\x69\x0e\x28\x9e\x00\x75\x71\x47\x81\x52\x9f\x6d"
+	"\xc8\x80\x19\x1d\xaf\x76\x9f\x3a\x11\xa0\x6d\xe8\x43\xba\x73\xef"
+	"\x85\x61\x09\x7a\xe2\x82\x44\xaa\xf2\x3a\x56\x08\x46\x04\x7e\x65"
+	"\x83\xcf\xbc\xaa\x8a\xa3\xb4\xf8\x44\xb0\x43\x0e\xcd\x25\x40\x0b"
+	"\xd7\x7c\x8c\xf9\xae\x42\xc9\xea\x2e\x3e\x83\x6a\xd8\xd4\x44\x23"
+	"\x14\x33\x27\x00\x49\xdb\x61\xb5\x51\x52\xe4\x54\xbe\x05\xc9\xd6"
+	"\xe3\xc2\x1a\x07\xf3\xbf\xd3\xb1\x1d\xb4\x88\xda\x62\x09\xb8\x94"
+	"\x2a\xcc\x24\x22\x46\xe9\x6f\x99\x6d\xbf\x24\xa3\x9a\xc3\x3f\x42"
+	"\x88\x5f\x36\x45\x68\xce\x95\xb3\xe5\x7f\x9c\xe3\xd6\xe5\xb9\xd5"
+	"\x40\x36\xb8\x36\xc8\x88\x9a\xf7\xcf\xe0\x76\x56\xb3\x9a\x0d\x68"
+	"\xc0\x60\x94\x9e\xdb\x14\x81\x95\xb3\xdd\xe5\xeb\xf2\x14\x18\x56"
+	"\x74\x7b\x81\x9d\xb1\xd2\xed\xef\xf1\xf8\xfc\x41\x4c\x66\x77\xbd"
+	"\xc9\x16\x32\x3f\x8f\x9a\xa7\xc2\xe1\x1c\x1f\x44\x48\x54\xd3\xe0"
+	"\x00\x00\x00\x00\x00\x00\x00\x00\x04\x0c\x1a\x20\x28\x2f"
+};
+
+static const u8 nist_mldsa_fips204_35_data[] __initconst = {
+	"\x88\x45\xad\x39\x4b\xce\x60\xb2\x84\x76\xb2\x13\x99\xb0\xd4\x72"
+	"\x6b\xb3\xfe\x5f\x4d\x43\xde\x87\x62\xa4\xce\x19\x1b\xba\x7c\x13"
+	"\xb5\x2e\x1e\xc9\x59\x02\x99\x0b\x89\x7b\xe9\xe9\x6a\x9a\x25\x8f"
+	"\xdb\xd4\x6b\xaa\xe2\x2a\x3d\xa7\x0e\x07\x3b\xe5\xda\xea\x2d\x6e"
+	"\x60\x1c\xad\xbe\x3f\xb0\x47\xd7\x5e\xe0\x8a\x8a\xeb\xec\x8e\x9e"
+	"\x89\xa8\x03\x49\x29\xdd\x30\x63\xed\x5d\x79\xa1\xd9\xf7\xec\x13"
+	"\x06\xd5\xd6\xf9\x38\xae\x37\xdf\x1d\x95\x87\x12\x8d\x2a\x05\x88"
+	"\xa8\x15\xdc\xc6\xfe\x33\x44\x36\x16\xe6\x6c\x76\x8f\x65\x6c\xe6"
+	"\xf3\x18\xb5\xf1\x74\x37\xb3\x66\x6f\x01\x7c\x6d\x14\x47\x4a\x59"
+	"\xd4\x09\x06\x46\xde\xe0\x2b\xbc\xc6\x4a\x31\xec\x14\xa6\xe0\x9a"
+	"\x03\x9c\x5a\xd8\x84\xda\x91\xaf\x5b\xba\xa7\x2a\xef\x0a\x81\x47"
+	"\xd3\x81\x1d\x70\xff\x70\x82\x4d\xf0\x3a\xcb\x06\xe7\x0e\x20\x16"
+	"\x2b\x6c\x78\x95\x8e\x1d\xdb\xf2\x79\x06\xb6\x60\x2e\x1c\xf6\x92"
+	"\x50\x18\xfb\x35\xbd\x0c\x07\x7b\x31\xe9\xf5\x5f\xcc\x0b\xb6\x12"
+	"\x1b\xd5\x46\xe6\x9d\xd2\x5f\xce\xb6\xdb\x7c\x07\xeb\xb4\x37\xe6"
+	"\x9a\x98\x11\x9d\x21\x3c\xec\x71\x53\x15\x68\xee\xec\x91\xcd\xf6"
+	"\x0d\xa2\x14\x65\x02\x90\x2b\x62\xb5\x1c\x71\xa9\x7e\x5a\x90\x99"
+	"\xd7\xe1\xf1\x9a\x01\xc3\xb4\x2f\x3b\x48\x77\xc8\x34\x15\xea\x28"
+	"\x85\xfb\x61\x7c\x4d\x0e\xc8\x8b\x32\x12\x60\xd5\x6b\x27\xba\xca"
+	"\xdd\x9c\x04\xd7\xba\x52\xf1\x6f\x1e\x62\x74\xca\x1c\x5d\x75\x16"
+	"\xf1\xdd\xd1\x38\x25\x6e\x36\xdb\xb8\xab\xec\xf3\x33\xd2\x91\xaf"
+	"\x13\x94\x26\xaa\x2b\xdc\x05\x57\x33\x87\xea\x84\xea\x81\x37\x1f"
+	"\x06\x94\xa8\xfd\xd7\xce\x5e\x03\x46\x2f\xb3\xbf\xa9\x25\xf6\x09"
+	"\xe6\x5f\x4c\x54\x7d\x7b\xaa\x99\xda\xa9\x07\x84\x72\x7d\x0b\x6c"
+	"\x6b\x96\x18\x2a\xdb\x78\x0f\x5f\xe8\xa3\x25\xd6\x76\xe0\x00\x3b"
+	"\x0b\x5c\x02\xf6\xee\xa3\xb5\x1e\xbe\x83\x76\xe7\x2e\x47\xa7\x6c"
+	"\x05\x2a\xa0\xaa\x60\x02\x65\xe9\x55\x3a\xf7\x33\x9a\x69\x1d\x50"
+	"\x91\x35\xcb\x19\xea\x11\x97\x0c\x40\x79\x2c\x41\x61\x64\x9a\xdf"
+	"\xd6\xbf\x40\x94\x31\x92\x71\xd6\x76\xec\x07\x85\xaf\xf5\x98\xeb"
+	"\xc5\xd7\x4c\xc8\x26\x7e\x2c\x45\xbf\xd2\x3c\xd1\xd9\xdc\xd5\x5d"
+	"\xc0\xa7\x29\x32\x55\xe3\x28\xdd\xfe\xf2\x97\x16\x57\x56\xde\x7c"
+	"\x4b\x06\x1d\x37\xc1\x5a\x87\xff\xf2\x95\x77\x5a\x6f\x6f\xc9\x0d"
+	"\x02\x5f\xdc\x8e\x72\xe3\xf1\xe2\x0e\x0d\x23\xae\x7d\x1e\xdb\x36"
+	"\x2c\xab\x41\xa2\xe9\xd8\xbc\x9c\x35\x9b\x16\x47\xc5\x37\xeb\x21"
+	"\xa0\x15\x34\x32\x8d\x0a\x28\x8c\xa8\x07\x0f\x7e\xf7\xbc\x9b\x08"
+	"\xdc\x3d\x91\x5a\x90\x69\x23\x37\x91\x6a\x98\x9b\x70\x9a\xea\x1d"
+	"\x8c\x1a\x6a\x19\x27\xb7\x74\xbd\x06\xd1\x0c\x0d\x0f\x4e\x06\xce"
+	"\x37\x86\xe1\xb0\x55\x77\x3b\x0b\x2f\x5c\xea\x01\xc8\x2f\x5e\xb5"
+	"\x14\x1e\xcc\xfe\x8a\xd3\x8f\xbe\xed\xe6\xd1\xcc\x74\x52\x93\x7c"
+	"\x6c\x60\xcb\xcf\x4f\xfe\x3c\x58\x18\xf5\xed\xb7\x75\x61\xa3\xd8"
+	"\x9e\x81\x5f\xa2\xca\x73\x2e\x02\x55\x31\xae\x91\xcf\x53\x00\x1c"
+	"\x13\x60\x63\x6b\x07\xfc\x36\x74\xc0\x96\x71\xb9\xd6\xe5\xef\x9c"
+	"\x77\xa1\x1f\x75\x6f\xa6\xdc\xd0\xcc\xd3\xcb\x86\x72\xfd\xee\x89"
+	"\xae\xc4\x9c\x65\xfd\x1b\x7a\xbd\xf6\xcf\x49\xa6\x43\xfb\xd6\x21"
+	"\xb8\x21\x8e\xbe\xdc\xaf\xe0\xb0\xc6\x61\x87\x82\xba\x2d\x43\x0a"
+	"\x3d\xb4\xb5\xac\x07\xa8\xbd\x06\x60\xfc\x24\x50\x56\xa2\x31\x54"
+	"\x55\x86\xb4\xb6\x07\x2c\x3d\x63\x70\xa4\x0e\xbb\x22\xda\xba\x1b"
+	"\x1f\x9f\x49\x75\x50\x2b\xa7\x6c\xd7\x95\xeb\x1a\x13\x51\x54\xd4"
+	"\x1d\xaa\x5d\x74\x49\x63\xaa\x86\x29\x05\xd8\xaf\x15\x94\x9c\x4b"
+	"\x17\x37\xa2\xab\x77\x4f\xfe\xb2\xfb\xfd\x19\xb1\xb2\x67\x68\x49"
+	"\x53\x23\x50\xbe\x26\xd1\x53\xc1\x4b\xc0\xc4\x4e\xde\xa2\x6a\xf0"
+	"\x47\x9e\x82\x7b\x9a\xa8\xf7\x6d\x68\x83\x46\x9c\x25\xf5\x47\xed"
+	"\x53\xb6\x52\x7f\x85\xe3\xe9\x99\xb3\x3d\x53\x6e\xbc\x67\x36\x41"
+	"\x9a\x3e\xa7\xfa\x55\xbc\xff\xa6\xa2\xd5\xa2\x10\x6b\x07\xff\x9f"
+	"\x2f\x80\xb5\x14\xe4\x04\x2e\xee\x98\xd7\x38\x9a\x4e\x9a\x43\x0b"
+	"\x93\xb2\xa3\x24\x94\x76\x6e\x09\xca\x37\x83\xb4\xd2\x81\x71\xec"
+	"\xd7\xa2\x09\xff\x72\xc9\xf4\x3e\x62\x3b\x70\xc3\xc5\xc9\xdd\x26"
+	"\x8a\x75\x91\xdc\xf3\xd6\x41\x38\x80\x28\xdd\xd9\x42\x91\x2a\x08"
+	"\x9a\xfe\x64\x2b\xc0\xcd\x80\x25\x8f\x97\xfa\xd6\xae\xee\x31\xa8"
+	"\x10\xc6\x45\xfc\x89\x0c\xea\x3b\xce\xc9\xcc\xf2\xef\x83\xd5\x5c"
+	"\x12\x1e\xb2\xf7\x72\xed\xec\xcf\x71\x1b\xe8\xdd\x12\x0f\x02\x4c"
+	"\x1b\xcd\x5c\x17\xee\x3c\x26\x4d\xf5\xd6\x19\xad\x9c\xf2\x41\x77"
+	"\x75\x0c\xe6\xb0\x3b\x4c\x75\x6d\xde\x34\x39\xb0\x59\xdf\x11\xe7"
+	"\x77\x69\xe5\x30\xfb\x4a\x69\xf8\xcf\xee\x44\xe7\x5a\xca\x04\xab"
+	"\xcc\x42\xbd\x23\xf7\x79\xb6\x00\xfd\x57\x62\x57\x34\xf6\x3b\x39"
+	"\xbd\x74\x77\xa1\x9d\x0d\xb9\x32\x30\xdd\x29\xf2\x4d\x72\xc5\x40"
+	"\x8c\x6d\xa6\x94\x19\xcf\x5b\xee\x0a\x82\x3e\xb5\x7d\x99\xd5\xf9"
+	"\xe0\x91\x5a\x1f\x0b\x90\x18\x73\xd6\xd7\xf2\x53\x68\xc1\x83\x3b"
+	"\x0c\xdf\xf1\x0a\xef\x1b\xcb\x17\x94\x83\x31\xb6\x81\x90\x0a\x23"
+	"\x30\x92\xb3\xd0\xae\xd2\x20\x7d\x78\x96\xb0\xe5\xe6\xef\x72\x3b"
+	"\x38\xbf\x45\x87\xbd\x06\x8b\x93\x62\x08\xf1\x2b\x0e\x91\x09\x87"
+	"\xbd\xd9\x42\xda\xfd\xbc\xfa\x52\x66\xae\x10\x7a\xaf\x2d\x1f\x85"
+	"\xae\x3f\x47\x8a\x17\xc7\xfc\x73\x6c\xb0\x8c\xa8\x24\x87\x2c\x88"
+	"\x11\x5f\x13\x06\x75\x20\x7b\x80\x4a\x5d\x4e\xba\x79\xf7\x44\xee"
+	"\xb1\x16\xb2\x3a\x19\x1a\xe6\xd0\xe0\xb8\xfb\x78\x3c\x44\xaf\xb5"
+	"\x69\x8a\x72\xf3\x1c\xd1\x9c\x61\x7a\x61\xa5\xfe\x98\xdd\x2c\x67"
+	"\x29\xc8\xed\xd4\x3c\x95\x13\x83\x53\x30\xd7\x12\x82\xf5\xe1\xef"
+	"\x5c\xe6\x97\xa6\x5f\x6d\xb7\x9e\xeb\xef\xd0\x2d\x9e\x3a\x00\xb8"
+	"\xcb\x7d\x6d\x1d\x34\x0c\x9c\x00\x30\xd1\x61\xd4\x70\x87\x50\x4b"
+	"\x8e\x43\x39\x98\x95\xf7\xe4\x96\xe6\x21\xe0\xd9\x96\x44\x54\xb5"
+	"\x04\x47\x9a\xd3\x40\x6f\x33\x95\x7f\x2c\x9e\x43\x04\x9d\xc0\xcc"
+	"\xc8\x67\x71\xf2\xf0\x05\x00\x65\x50\xad\x8d\x68\xa1\x1c\x2d\xcf"
+	"\x15\x65\x72\x30\x53\x19\xb2\xff\x36\x29\x9e\x95\x5d\x35\x44\x73"
+	"\x8a\x82\xf5\xc4\x13\x69\x1b\x76\x78\xee\xec\xf2\x6f\x6a\xbf\x1d"
+	"\xc2\xfb\x79\x48\x11\x4b\x4e\xbd\x2b\x84\x5c\x0b\x7b\x78\x54\x3d"
+	"\xa0\xfc\xd2\x61\x39\xf0\xca\x8e\xae\x83\x7b\xa2\xd7\xde\x84\x93"
+	"\x34\x19\x0e\xb1\x72\xe5\x70\x5c\xe3\x2f\xb4\xdd\xf8\xc9\xfa\xf4"
+	"\x90\xc3\xd1\xf3\xfd\xf4\x37\xd1\xad\xeb\x2e\x82\xa7\x31\xec\xdf"
+	"\x62\x54\xd4\x75\x6d\xe4\x00\x71\xef\xd0\x55\x71\xc1\x77\x79\xdc"
+	"\x06\x23\xd4\xc3\xbd\xe6\xe8\x09\x8f\x7c\x96\x73\x57\x60\x2d\x38"
+	"\xa0\x75\x55\x71\xa6\x00\x18\x65\x87\x8e\xd9\xe5\xfd\xc6\x4d\x43"
+	"\x5e\x85\xe2\xd5\x6a\x8c\x55\xb7\xc6\x7a\x75\x86\x4a\x88\x00\xc9"
+	"\xb6\x53\x37\x0e\xbb\xd8\x62\xe8\xf9\x3f\x50\x12\x9e\xae\x84\x04"
+	"\x02\xe0\xfb\x58\x29\xe4\x8b\xd7\x83\x10\x4a\x08\xe8\x12\xa4\xd8"
+	"\xa1\x77\x94\x82\xcb\x4f\x24\x5a\xdd\x0c\xb9\xf6\x64\xd8\xc7\x11"
+	"\x83\x5e\x98\xee\x60\xa2\x41\x4b\xd5\x02\x5e\xdf\x32\x40\xf4\xb3"
+	"\x35\xb5\xeb\x65\xbf\x08\x63\x9b\xcf\x5b\xfa\x6b\x2f\x61\xda\xe1"
+	"\xef\x7d"
+};
+
+static const u8 nist_mldsa_fips204_35_sig[] __initconst = {
+	"\x30\x82\x0d\x61\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x07\x02\xa0"
+	"\x82\x0d\x52\x30\x82\x0d\x4e\x02\x01\x01\x31\x0d\x30\x0b\x06\x09"
+	"\x60\x86\x48\x01\x65\x03\x04\x02\x03\x30\x0b\x06\x09\x2a\x86\x48"
+	"\x86\xf7\x0d\x01\x07\x01\x31\x82\x0d\x2b\x30\x82\x0d\x27\x02\x01"
+	"\x01\x30\x17\x30\x0f\x31\x0d\x30\x0b\x06\x03\x55\x04\x03\x0c\x04"
+	"\x46\x72\x65\x64\x02\x04\x01\x23\x40\x23\x30\x0b\x06\x09\x60\x86"
+	"\x48\x01\x65\x03\x04\x02\x03\x30\x0b\x06\x09\x60\x86\x48\x01\x65"
+	"\x03\x04\x03\x12\x04\x82\x0c\xed\x6e\x8c\x4b\x20\x61\xc2\xcd\xf2"
+	"\x71\x54\xbf\x70\x85\xf6\x3c\xb1\x5d\xa3\xce\xc8\x2d\x52\xca\xd1"
+	"\xa6\x50\x80\x68\x75\x05\x25\x24\xda\xa1\xef\xdf\xf4\x6f\xde\x5e"
+	"\xff\x63\xef\xf5\x70\x74\x7c\x69\xfd\x23\x4b\xa3\xaa\x3b\xa9\xa8"
+	"\x0f\x48\x8b\xc4\x8f\x95\x9f\xf5\x6a\xb3\x17\x35\x5f\xfe\x91\x7b"
+	"\xdd\xd3\xbb\xf7\x3b\xf0\xa8\x22\x09\xbe\x25\x48\xcd\xca\x1a\x37"
+	"\xc4\xde\x57\x18\x56\x30\x19\xa9\x26\x99\x13\x9a\x6d\x6a\x69\xe9"
+	"\x64\x83\x2d\xdd\x70\xf5\xe8\x03\x75\xdc\x9f\xe0\xba\x8e\x22\xae"
+	"\x3a\xd8\xaa\xd9\x45\x84\x71\xcd\x37\x61\xb1\xb9\x04\xe8\xbb\xba"
+	"\x72\xfa\x8a\x07\x1d\xf1\x82\x55\x17\xff\xa2\x2e\x2b\xbf\xf9\x9a"
+	"\x0f\x86\x94\x06\xd9\x07\xdb\xc3\x16\x92\x90\xce\xd1\x4e\xb8\xee"
+	"\x7a\x2b\x6c\xe7\xc2\x6a\x0a\xe2\x8b\x32\x5e\xd4\x61\x38\x90\xaf"
+	"\xce\xbb\x38\xe6\xe9\xd5\x43\x74\xc9\xeb\x48\xd0\xe6\x00\x30\xa1"
+	"\x1e\x75\x03\xb9\x06\xe9\x16\x35\x7c\x6f\x81\xd5\x9f\x89\xcc\x36"
+	"\x33\x75\xcb\xf0\x1e\xd0\xd8\x51\x54\xd5\x5c\xb8\xfc\xe7\xb2\x17"
+	"\xd5\xed\xeb\xe9\x36\x85\xe0\xbe\x43\x4c\xb0\xc5\x67\xc8\x97\x62"
+	"\xb3\x80\x89\xec\x2c\xf3\x4c\x93\x87\x9c\x0b\x23\x5d\x44\x25\x6a"
+	"\x10\x3f\x21\x08\x7d\x8d\xfc\x99\x8d\xc5\xbe\xbe\x57\x5c\x5d\x4d"
+	"\x27\x7b\xa2\x2e\x81\xcd\x0a\xf1\x49\x2b\x43\xda\xc4\x36\x5c\xc6"
+	"\x91\x75\xd8\x95\xa6\x9b\xbf\xe9\x21\x45\x3c\x07\xae\x56\xcd\xf5"
+	"\x1b\x91\x56\xe4\x49\x40\x12\x58\x8a\xa4\xac\x32\x53\x93\xbe\xe9"
+	"\x8a\x65\xef\x71\xe3\x07\xc8\x4d\xb9\x35\x85\x4d\x06\x9b\xa4\x11"
+	"\x6a\x67\x7a\x5b\x49\xee\xea\xf2\x0d\x16\x49\x2b\x74\x46\x78\xcc"
+	"\x59\x12\x0c\x80\x6f\xae\x7d\x23\x30\x87\x7f\x16\x52\x04\x11\x41"
+	"\x0b\xba\x48\xbf\x49\xaa\x08\xf4\x44\x00\x75\x4a\x05\x79\x79\x66"
+	"\x31\x94\x44\x9e\x66\xf5\xc0\xd7\xa1\xeb\xb5\xda\xc4\xb6\x5c\xf9"
+	"\x20\x0b\x21\x89\xf6\x0f\xa5\x29\x48\xcb\x7a\x83\xd5\xfd\x54\x45"
+	"\xaf\xa3\x0d\x99\xe9\x14\x30\x06\x8a\x53\x51\x08\x0d\xa4\x24\xa6"
+	"\xf4\xae\x5f\x8e\x1b\x7b\xa6\x48\x1c\xfb\x39\xfc\x34\x2a\xcf\xa0"
+	"\x84\xb3\x79\xb7\xc7\x4d\x64\x0e\x0c\x04\x87\x31\x9f\xf6\x97\x02"
+	"\x8b\xe8\xc2\x13\x21\x8e\xfc\x85\x7c\xac\xfa\xc4\x44\x10\x3f\x2f"
+	"\x93\x02\x74\x44\x1f\x18\xdc\x2e\x17\xca\x18\x27\x86\x55\xfb\xc0"
+	"\x79\x4b\x50\x08\x33\x62\x4c\x58\x29\x20\x98\x95\x9f\x8c\x7a\xf7"
+	"\x82\xe1\x41\x43\xf3\x5c\x55\x54\xe3\x22\x60\xf2\xa4\x85\x17\x88"
+	"\x93\x6b\x6d\xc7\x48\xf6\xc0\x0b\x4b\xf0\x86\xc6\x64\xae\xd9\x22"
+	"\x08\x75\x35\xce\xf4\x7b\xad\xf2\xb6\x7d\x50\x6e\xba\xf6\x46\x30"
+	"\x7b\xbc\x60\xc3\xf7\xf7\xeb\x39\x44\x6a\x34\xde\xb4\x6f\x43\x3f"
+	"\xfb\xcb\x23\x60\xfb\x55\x57\xaa\x9a\x2e\x33\x29\x37\xd7\x9a\xb6"
+	"\x85\xa2\xad\x9b\x25\x42\x38\x83\x44\x85\x0e\xec\x19\x74\xa3\xdc"
+	"\x73\x4b\x30\xb9\x6b\x05\x63\xcd\xdb\xa3\x18\xed\xfd\xc2\x94\x1b"
+	"\xdf\x1f\x64\x6c\xd6\x29\x05\x58\xe0\x77\xb9\x1b\xd5\x40\xe6\xff"
+	"\x3b\x7e\x13\x2b\xef\xed\x35\x8e\x06\x69\x13\x8f\xe4\x93\x59\x34"
+	"\x54\x50\x16\x3c\xbb\x5b\xe2\xa4\x7a\xd5\x35\x60\x3a\x13\x8e\x7c"
+	"\x37\xf6\xb8\xfd\x1f\xa1\x1d\xd4\x25\x19\x54\xba\xe7\x8e\x7c\x59"
+	"\x40\xc3\x7a\xf2\x2c\x94\x78\xca\x02\x0a\x1d\x21\x4f\x97\x57\xbc"
+	"\x06\x36\x23\xce\x8d\xce\xdd\x39\x5d\x6b\x7b\xc1\xa8\x06\x90\x4e"
+	"\xbf\xaf\x28\xf0\xf8\xc5\xa6\x3a\x0c\x1c\xc6\x31\x4f\xe8\x05\x79"
+	"\x1d\x76\x57\x05\xf5\xfa\x33\x17\x1a\xb4\xc8\x51\xc2\x6e\x42\xc0"
+	"\xf9\xdc\xcf\x9c\x28\x37\xc1\x11\x42\x1d\x0f\x5f\xdc\xf9\xa9\xeb"
+	"\xa0\x9c\x25\xdb\x0d\x79\x65\xdc\x91\xdc\x4e\x63\x84\x1a\x76\xae"
+	"\x9a\x68\x7a\xd8\xb6\xe4\x90\x68\xcf\x74\xfa\xaf\xd8\xa6\x6c\x91"
+	"\x39\xd3\xc3\xa6\xbe\x06\x56\x3c\xb5\x7f\xe7\x73\x30\x14\x79\x57"
+	"\x4c\x68\xeb\x32\x94\xe3\x35\xf9\xf1\xbb\x7c\xfd\xf5\x0e\xa1\x13"
+	"\x92\xf0\x4f\x5f\x3b\xe9\x9c\xb2\x4b\x07\xa8\x91\x17\x34\x02\xef"
+	"\x38\xf7\x44\xdd\xf9\x27\xf0\x60\x1f\x70\xba\x50\xf8\xab\x84\x5f"
+	"\xf2\xa0\x12\x40\x1a\x99\xcf\x4f\x03\x36\x4c\x30\x82\xd4\x21\x81"
+	"\x91\x9e\x87\xd4\xac\x3b\x3b\xe1\xf9\x5a\xb6\x90\xfc\xda\x10\x6c"
+	"\x87\xc6\x3c\x7b\xed\xf1\x29\x08\xd6\xa0\xee\xc3\xb6\x72\x46\x1b"
+	"\xb1\x38\xec\xfd\x48\x01\x9a\x07\x7e\xf4\xe5\x90\x94\x8a\xbd\x08"
+	"\x3e\x28\xef\x4d\x06\x2f\x8e\x58\x3b\x69\xcb\x79\x80\x3b\x70\xde"
+	"\x5d\xea\x1f\x60\x00\x51\xd9\xed\xef\x2a\xed\x93\xa5\xd5\xbb\x5a"
+	"\xb7\xb5\xb1\x96\x84\x62\x25\xf6\xb0\x73\xdf\xbe\x40\x13\xb4\xc8"
+	"\x14\xae\x15\x20\x7d\xbb\x76\x0b\x97\xe6\xbc\xb7\x61\x7e\xb2\x6c"
+	"\xd3\xb5\xa4\x1b\xa6\xb5\xdd\x88\x45\x1b\x5b\xcc\xf5\x52\xdc\x49"
+	"\x3f\x85\xa1\xcf\x3a\xfa\xae\x80\x81\x89\xb2\xfe\xdf\x04\x47\x8e"
+	"\xde\x57\x94\x82\xa7\x11\xb2\x2b\x55\xd4\x8a\xb2\x18\x9e\x6c\x14"
+	"\xf6\xf8\x69\x84\x5d\x88\xf7\x8a\xf5\x40\x20\x24\x60\x5f\xa3\xe2"
+	"\x47\x32\xf9\x93\x17\x09\xac\x35\x9d\xfa\x74\x78\x17\xb1\x2c\x37"
+	"\xb0\xdc\x0b\xe0\x8b\x5a\xcf\x9d\x3f\x09\x6e\x44\xf4\xdb\xa0\x23"
+	"\x34\x76\xb2\x66\xf4\x2b\x92\x04\x0a\x9c\x88\x49\x6c\x80\xfb\x99"
+	"\x6c\x70\xfb\xd5\xdc\xce\x10\xd1\x1a\x72\x2b\x4e\x9e\x34\xe0\x60"
+	"\xf0\x06\x04\xd2\x55\x78\xc4\xea\xe8\x6b\x4a\x43\x7a\x14\xc7\x2c"
+	"\x83\x34\x63\xf4\x4c\xa5\xee\xb3\xf0\x02\x78\x57\x44\x69\x37\xed"
+	"\xda\x22\xb6\x3f\x86\x15\x81\xeb\x1f\xae\x69\x75\x29\x8c\x04\x83"
+	"\xff\x80\xad\x45\x18\x88\x6a\x78\x43\x1b\x93\xf8\xd4\x19\x89\x1d"
+	"\xbb\x85\x6b\x2f\x08\xdf\xc2\x27\x72\xbe\x36\xdb\x30\x7f\x3b\x36"
+	"\xfe\x81\x60\xad\xb9\xc1\xf8\x9b\x80\x31\xba\xb2\x42\xaa\x5b\x41"
+	"\x68\x06\x40\x41\xe1\xaf\xf6\x3f\x73\x67\xdd\x83\x92\x6d\xb6\x4b"
+	"\x21\xe1\x97\x7c\x62\x46\x36\xfd\x93\x8e\x26\x54\x20\x95\xb8\xdd"
+	"\x35\xb8\x87\xe8\xd7\x01\x10\x89\x20\xaa\x0f\x0c\x5e\x3d\xd1\xc1"
+	"\xc6\x98\x15\x38\xc5\x73\xe3\xbf\x08\x51\x83\x32\x56\x5d\x1a\xa9"
+	"\x0c\x4f\x2f\x16\x51\x16\xc9\x2e\x39\x8c\x5c\xe8\x95\x22\xc1\x19"
+	"\xf9\x8b\x38\x53\xc6\x55\x8a\x07\x13\xae\x00\xc3\xc2\xe0\x8b\x0c"
+	"\xdd\xb8\xf3\xdd\xca\x21\x1f\xfe\xdb\x9b\x28\x8f\x9e\xd8\x96\x02"
+	"\x6a\x2b\x35\x89\x6e\xcb\x65\xf3\xde\x3a\xa5\x3f\x38\xd9\x8f\xbf"
+	"\xa2\xb9\xc3\x6b\xaa\x2a\x28\x7a\xc6\xe6\xa0\xfc\xe3\x37\xfa\x60"
+	"\xf7\xdd\x4e\xcd\x5d\x64\xa8\x4b\xd2\x30\x40\x68\x92\x5f\xa3\x72"
+	"\x9f\x4d\xd8\x71\xae\x2c\xd7\x59\x60\xd9\x14\x88\x93\x9d\xd7\x56"
+	"\x1e\x6b\xa0\x46\x23\x69\x82\x95\xb2\xa0\x66\xe4\xc2\x7b\xee\x44"
+	"\x51\x93\xb8\x4d\x8b\xa4\x24\x57\x94\xaf\xb6\x26\x02\x7b\x00\xd9"
+	"\x84\xda\x51\xcc\xce\x4c\x63\x90\x98\xb3\x13\x2a\x85\xec\x77\x52"
+	"\x69\x79\x9f\x37\xb8\xa3\xfb\x2b\x76\x39\x1a\x6a\x99\xd7\x0f\xa5"
+	"\xc7\xa3\x55\xc3\x99\x59\x47\x2b\x36\x1e\xe9\xf0\x8d\x85\xb9\x0d"
+	"\x26\x57\x50\xce\x0a\xf6\xdc\xb2\x60\x21\xe8\x76\xfd\x15\x7a\x9a"
+	"\xe4\x7c\xd8\x17\x0e\x58\x6b\x86\xf6\x7f\xf0\x69\xf8\x1c\xc3\x6c"
+	"\x5a\xf7\xe9\xd5\xf0\x5d\xfc\x50\x5a\x89\x7a\xad\xaa\xa5\x39\xe4"
+	"\x08\x42\xf6\xc2\x23\x90\xf0\x66\x39\x8b\x27\xe3\x05\x21\x43\x21"
+	"\xc9\xe6\xd6\x21\xa2\xda\x34\x5b\x34\x58\xe6\xef\x93\x02\x96\xa4"
+	"\xa4\x86\x12\x12\xdd\x67\x10\xc4\x5e\xf3\xca\x79\xfd\x65\x29\xee"
+	"\xe6\xb9\x1c\x0a\x20\x98\x74\xd6\xc4\x3f\x10\xe0\xee\x31\x53\x05"
+	"\xa8\xb4\x2d\xa1\xde\x26\x30\x80\xc6\x13\x9d\xf0\x67\x51\xd1\xfb"
+	"\x09\x22\x02\x2b\x51\x92\x3e\x36\x36\x6c\x5b\xcf\x00\xf9\xa4\xa0"
+	"\x20\x06\x46\x87\x3b\xc5\x19\x8d\x43\x7b\x57\xd7\xe0\xa4\x2e\xe9"
+	"\x6d\xe7\x64\x1a\x77\x1f\xf7\x99\x5b\xc8\x43\x39\x62\xbc\x1f\xff"
+	"\xb4\x4a\x2a\x5c\x06\x3f\x04\xb0\xea\x22\x83\xa5\x50\xae\x4a\xf8"
+	"\x90\xd0\x4a\x61\xe2\xba\x45\x0d\x7a\xba\xeb\xfe\xd1\x22\x61\x8b"
+	"\xa2\x46\x9c\x74\x10\xd0\x66\x92\x7c\x01\x56\x3a\x30\xb9\xc3\x3e"
+	"\x57\x1a\x0c\xdb\xa6\xc3\x64\xd5\xff\x06\xa3\x46\x33\x8a\x1a\x6d"
+	"\x5d\x07\x0d\xbf\x88\xf2\x38\x41\xf9\x2d\xbc\xb2\x55\x6d\xa0\xf7"
+	"\xc1\x9e\x64\x51\xf8\xb4\xea\x35\x8b\x11\x80\xe3\x6c\xa2\xb6\x3b"
+	"\xed\xaa\xdd\xf3\x69\xfa\xa2\x53\x1f\x22\xa8\x28\x8f\x57\xe1\x41"
+	"\xbf\xcc\xb3\x3d\x86\x47\x7a\xa3\xc1\xd4\xfe\x0e\xfa\x6b\x95\x4e"
+	"\x1a\xbf\x33\x50\x9d\x2a\x7d\x28\x0a\x64\x4d\x26\xae\x17\x65\x65"
+	"\xe8\x55\xd0\x63\xf4\x1d\x03\x5c\x9f\xe9\x1b\x25\x12\x7c\x06\x41"
+	"\xc0\x90\xb9\x9c\x17\x02\xf8\x7a\xef\xe5\x63\x7d\x8b\x38\x7a\x3c"
+	"\x85\xdc\xdf\xad\x47\x5e\xef\x0d\x96\x7d\xed\xf2\xc5\x00\x1a\xd2"
+	"\x09\xef\x1e\xff\xc3\x8b\xd0\xbc\xb8\x36\x76\x13\x33\xbd\xda\xa0"
+	"\x1e\x02\x6c\x44\x8a\xd8\x7c\x3e\x7d\xc9\x66\x5e\xf3\xbe\xb1\x72"
+	"\x8e\xfc\xbc\xe5\x99\x30\x89\x88\x91\x34\x3f\x9d\x2f\xfe\xa5\x1e"
+	"\xb1\xef\x82\x23\x62\x91\x25\x22\x0a\x8a\xdb\x39\xe4\x5b\xf8\x2a"
+	"\x75\xb7\x38\xff\xef\xca\x45\x9a\x57\xfb\xb3\xfe\xfb\x6d\x8f\x2e"
+	"\xb1\x62\x64\x6d\x39\x57\x8d\x95\xe7\x79\xdd\x98\x3e\x68\xaa\x12"
+	"\x50\x7b\x0e\xa2\x2b\x89\x52\x9f\xca\xd5\xc1\x22\xc2\x6f\x54\x83"
+	"\xbd\xd7\x2c\xbb\xba\x50\xda\xad\x42\x93\xe7\x86\x9d\x60\xf5\x33"
+	"\x1b\x7f\xaa\x75\x65\xbd\xa8\x34\x15\x6d\x1c\xf7\x47\x1f\x94\xdc"
+	"\xab\xa8\x14\x93\x69\xdd\x2c\x3b\xf9\x21\x11\x36\x80\x63\xec\xc9"
+	"\x8e\x78\x48\xb4\x31\xac\xa0\x48\x00\x3e\xed\x6f\xb3\xb0\x15\xc9"
+	"\x24\x72\x24\x5b\x51\x7c\x65\xbb\x24\xb6\xb1\x53\xfd\x3f\x36\x7a"
+	"\x6c\xbf\xec\x90\xcc\xd9\x01\x03\x30\x9e\xe3\x4a\x97\xcc\x3a\x35"
+	"\xc6\x4a\x2b\xd3\x18\xbc\xb1\x1f\x64\x08\xa0\xf8\x84\x34\x36\x3a"
+	"\x91\x1a\x28\x72\x98\xdd\x1a\xbe\xb1\x32\x77\x95\x72\x7e\xc5\xc1"
+	"\xd7\x3b\xf8\x1e\x55\xc2\xdd\xed\x24\xdb\x1b\x9b\x0e\xd1\x07\x01"
+	"\x85\x41\x90\x3c\x90\x6a\xf2\x0a\x8b\x4b\x7e\x9e\x87\xed\xa8\xa8"
+	"\x8c\x5a\x4c\x4d\xc3\xb5\xec\x7a\x4d\xe1\x51\xf0\x00\x64\xb9\xc3"
+	"\x6e\x61\x2a\x41\xd5\x2e\x0e\xf1\x1e\x87\xe5\xd5\xe4\xcc\x1a\x36"
+	"\x7e\x5d\x96\x02\x14\xce\xaf\xa2\xbb\x61\x05\xf4\x2e\x64\xba\x17"
+	"\xff\x18\xc8\xe1\x17\x8a\x02\x6b\x22\xe5\xd4\xd0\x68\xf6\x9c\x10"
+	"\xf0\x2d\x4f\x82\xb3\x21\xb4\xaa\x7f\xff\x6b\x7e\x9a\xf2\x12\x44"
+	"\x4a\xa5\xbb\x16\xb6\x56\x6e\xb1\x20\xb4\xb0\x34\x8f\xe4\x94\xb2"
+	"\xf6\x7f\x9f\x05\xd0\x42\x30\x04\xdb\x11\xb8\xd7\x5a\x1b\xb6\x06"
+	"\xed\x6e\x9c\x69\x6d\x2c\x0f\x6f\x7f\xf3\x9c\x76\x2e\xad\xc2\xd6"
+	"\xc6\xfd\x93\xc1\xee\x25\xbb\xc8\xc6\xb5\xd1\x37\x65\xdd\xe5\x78"
+	"\xb0\x89\x0a\x91\x4a\xe1\x17\x61\x43\x18\x47\xf3\xc2\x2a\x22\xc2"
+	"\x56\x4e\x01\x31\xa3\x0b\xc7\xe6\x53\x27\xa8\xc8\x32\x25\x69\x7c"
+	"\x8b\x8e\xb1\x2b\xc6\xc9\x85\x05\x1d\x67\x1e\xc6\x10\xa3\x60\x46"
+	"\xbf\x9d\x5b\x3f\xda\x1f\xd3\x8b\x1a\x95\x88\xa2\x16\xb0\xdd\x7f"
+	"\x46\x2f\x5f\xef\xa0\x17\x0e\x5e\x19\x20\x8c\xeb\x97\x52\xc8\xe0"
+	"\xdc\xc0\x40\x0a\xd1\x84\xc1\xa6\xb2\xf4\x6c\xc7\x8d\xc9\xd4\xb8"
+	"\xc3\xe3\xe5\xf9\x8a\xc5\xdb\x04\x2a\x89\xa5\x92\x64\x3f\x91\xd0"
+	"\x60\x97\x8a\x42\x2d\x4b\x2c\xf8\xa7\xe2\x68\xf9\xd3\x94\x1c\x24"
+	"\xe8\x80\xff\x05\xa7\x02\xab\x66\xd7\xb9\xa3\xeb\xd5\x0f\xf7\x26"
+	"\x4f\x8f\x6b\x5a\xb2\x7c\xda\x1a\xb3\x83\x5f\xbc\xcc\xfc\x50\xc8"
+	"\x24\x8c\x38\x9d\x80\x79\x50\x9d\x84\xe8\xee\x85\x19\xf3\x73\x5a"
+	"\xd2\x41\x92\xde\x87\x5f\x52\x62\x91\xbe\x90\x1e\xce\x54\x13\x68"
+	"\x35\x3e\x2b\xe5\xa2\x1e\xc0\xc1\x2f\x9c\x52\xd9\xe1\x5c\xe4\xfd"
+	"\x21\xa3\x5a\x51\xb3\x01\x9d\x22\x2c\x6c\xa8\xb9\xda\xfb\x78\xa8"
+	"\x24\x1f\xef\xe9\x1c\x38\x04\xf5\x8b\x80\xca\xe6\xb9\x76\x27\x31"
+	"\xe1\x24\xf0\x07\xf9\xa9\x11\x77\x9a\x8a\xc1\x87\x21\x49\x1b\x6e"
+	"\x94\x94\x4e\xe7\x3a\x10\x00\xd1\xd7\x02\xbf\x53\xe7\x88\x4e\xab"
+	"\x63\x35\x61\x39\x81\x45\x21\x85\x35\x4b\x44\xca\xc0\xdb\x8f\xa3"
+	"\x6a\xc7\x90\x12\x7a\xd5\x94\xd7\xfe\x30\xb2\x0f\x51\x52\xd0\xe6"
+	"\xa7\xbe\x52\x2d\x45\xba\xed\xbc\x3c\x95\x35\x50\x3f\x83\x97\xa8"
+	"\x8f\x7e\xfb\x2e\xa3\x5b\xe1\x2c\xb9\x15\x79\x62\x28\x8f\x02\x47"
+	"\x31\x63\x2f\x45\xa7\xa7\x21\xa4\x26\x17\x2f\x46\x72\x22\x44\xed"
+	"\x3a\xff\x0a\x80\x27\xb7\xaa\xa3\x9e\xe3\xb7\x71\xd2\xd9\x98\xa2"
+	"\x6a\x5b\x18\x70\x6b\xfa\xf3\x9f\xcd\xa9\x4c\xca\x97\x76\x41\x98"
+	"\xb2\x8b\x98\x23\x88\xe7\x1e\xa3\xd3\x56\x9a\x48\xf1\xd8\xf5\xd5"
+	"\xf5\xd2\xff\x60\x52\x82\xeb\xe8\x92\x5c\x36\xfc\x32\xfe\x46\x2d"
+	"\x9a\xbd\xb8\xc2\x37\x63\xee\xbe\x69\x4c\x98\x3d\x3d\xa3\x76\xe7"
+	"\xbe\x8b\xb9\xe2\x07\x4b\x9a\x55\x44\x71\x6e\x7d\x7f\xb0\x31\x55"
+	"\xb8\x74\x82\x9c\x47\xf9\xdc\x9a\x21\xd3\xbb\x47\x22\x05\x3b\x4b"
+	"\x00\x31\xe1\x7f\x9d\xcf\xd1\xde\xeb\xd6\x2a\xd9\x0b\xa8\x34\x03"
+	"\xc3\x66\x34\x1f\xcb\xe8\xd8\xf2\xf9\x4a\x3f\x6e\x8e\x3f\x8b\xce"
+	"\xef\x9d\xe9\xf9\x92\x33\x7d\x8a\x61\x2f\x5c\xaf\x5d\x4c\x66\x30"
+	"\x37\x09\x3f\xd0\x5e\xe6\x43\xef\x03\x63\x63\xc5\x39\x2b\xa8\x09"
+	"\x5a\x86\x78\x5c\xa0\xa0\x5c\xa1\xba\xb7\xbc\xdb\xd7\x70\x60\x81"
+	"\x20\x19\x72\x82\x85\xed\x96\x58\xa9\xdb\xa2\xcc\x03\xfc\x00\x92"
+	"\x46\x3c\x79\x30\xce\xe0\x8f\xa0\x91\xd5\x16\xcc\x46\xce\xf2\x4a"
+	"\x62\xaa\x1d\x80\x2f\xf5\x45\x7b\x9e\x97\xd7\x94\x39\x73\x6d\x5a"
+	"\x25\xe4\x46\xb9\x6c\x58\xcc\xa7\xc9\x9b\x81\x9a\x98\x05\x0b\x82"
+	"\xb4\xb1\xc5\x08\x71\x15\x1f\x26\x86\x26\x7b\xa8\x47\xaf\x80\x42"
+	"\x2d\xd1\x68\x07\xb6\xa3\x81\xc5\x40\x6e\xf7\xf6\x66\x81\x2d\x1e"
+	"\x65\x01\xae\x2c\xaa\x59\x7c\x90\xa4\xfd\x34\x04\x73\x3a\x40\x1a"
+	"\x2b\x9f\x35\x4b\x25\x17\x8f\xe5\xe6\x99\x0f\x1e\x23\xed\x95\xfe"
+	"\xf6\xa3\x90\xd3\xca\xd4\x22\xb4\x8b\x66\xac\xe9\xf3\xaf\xc8\x1b"
+	"\xaa\x9f\x92\xc0\x19\x3c\x01\x66\xc6\x07\xed\x82\xbe\x60\x08\x6a"
+	"\x94\xfc\x79\xfa\x3c\xb5\x24\xb1\xc8\x7f\xf3\x53\x20\x90\x1f\x07"
+	"\x06\xd4\xf6\x7f\xeb\xcb\x96\x5f\xd8\x2b\xd2\x7e\x44\xaa\x62\x75"
+	"\x43\xfa\xc9\xfa\x27\x78\xe7\xe7\x61\xc2\xc2\xd2\x87\x24\x75\xab"
+	"\x22\x4d\xc4\xbe\xa2\x9e\xe6\x2e\xc3\xee\xd3\x37\x69\x02\x50\x13"
+	"\xcb\xa3\x65\xf2\xdd\xed\xbc\x15\x68\x20\x50\x6d\xe4\x8a\x8b\x9f"
+	"\x45\x39\xc5\xe4\xf1\x74\x7a\xf5\x0f\xa5\x94\x5a\x5a\x3c\x0c\xd0"
+	"\xb1\x5e\x27\xd5\x8a\x98\x15\x24\x65\x24\x15\xcb\x7e\xee\x62\x0b"
+	"\xbd\xf4\xb0\x32\x31\xb3\xc3\x21\x58\xe5\x7a\x69\x0e\x28\x9e\x00"
+	"\x75\x71\x47\x81\x52\x9f\x6d\xc8\x80\x19\x1d\xaf\x76\x9f\x3a\x11"
+	"\xa0\x6d\xe8\x43\xba\x73\xef\x85\x61\x09\x7a\xe2\x82\x44\xaa\xf2"
+	"\x3a\x56\x08\x46\x04\x7e\x65\x83\xcf\xbc\xaa\x8a\xa3\xb4\xf8\x44"
+	"\xb0\x43\x0e\xcd\x25\x40\x0b\xd7\x7c\x8c\xf9\xae\x42\xc9\xea\x2e"
+	"\x3e\x83\x6a\xd8\xd4\x44\x23\x14\x33\x27\x00\x49\xdb\x61\xb5\x51"
+	"\x52\xe4\x54\xbe\x05\xc9\xd6\xe3\xc2\x1a\x07\xf3\xbf\xd3\xb1\x1d"
+	"\xb4\x88\xda\x62\x09\xb8\x94\x2a\xcc\x24\x22\x46\xe9\x6f\x99\x6d"
+	"\xbf\x24\xa3\x9a\xc3\x3f\x42\x88\x5f\x36\x45\x68\xce\x95\xb3\xe5"
+	"\x7f\x9c\xe3\xd6\xe5\xb9\xd5\x40\x36\xb8\x36\xc8\x88\x9a\xf7\xcf"
+	"\xe0\x76\x56\xb3\x9a\x0d\x68\xc0\x60\x94\x9e\xdb\x14\x81\x95\xb3"
+	"\xdd\xe5\xeb\xf2\x14\x18\x56\x74\x7b\x81\x9d\xb1\xd2\xed\xef\xf1"
+	"\xf8\xfc\x41\x4c\x66\x77\xbd\xc9\x16\x32\x3f\x8f\x9a\xa7\xc2\xe1"
+	"\x1c\x1f\x44\x48\x54\xd3\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x04"
+	"\x0c\x1a\x20\x28\x2f"
+};
+
+void __init fips_signature_selftest_mldsa(void)
+{
+	fips_signature_selftest("MLDSA",
+				nist_mldsa_fips204_35_key,
+				sizeof(nist_mldsa_fips204_35_key) - 1,
+				nist_mldsa_fips204_35_data,
+				sizeof(nist_mldsa_fips204_35_data) - 1,
+				nist_mldsa_fips204_35_sig,
+				sizeof(nist_mldsa_fips204_35_sig) - 1);
+}


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 01/12] crypto: Add ML-DSA crypto_sig support
  2026-01-20 14:50 ` [PATCH v13 01/12] crypto: Add ML-DSA crypto_sig support David Howells
@ 2026-01-20 17:37   ` Jarkko Sakkinen
  2026-01-20 20:52   ` Eric Biggers
  1 sibling, 0 replies; 37+ messages in thread
From: Jarkko Sakkinen @ 2026-01-20 17:37 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 Tue, Jan 20, 2026 at 02:50:47PM +0000, David Howells wrote:
> 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>
> 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  |  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");
> 

Went through it, not much else to say, as it just binds the callbacks:

Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>

BR, Jarkko

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself
  2026-01-20 14:50 ` [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself David Howells
@ 2026-01-20 17:53   ` Jarkko Sakkinen
  2026-01-21 12:31     ` David Howells
  2026-01-20 21:12   ` Eric Biggers
  1 sibling, 1 reply; 37+ messages in thread
From: Jarkko Sakkinen @ 2026-01-20 17:53 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 Tue, Jan 20, 2026 at 02:50:48PM +0000, David Howells wrote:
> The ML-DSA public key algorithm really wants to calculate the message
> digest itself, rather than having the digest precalculated and fed to it
> separately as RSA does[*].  The kernel's PKCS#7 parser, however, is
> designed around the latter approach.
> 
>   [*] ML-DSA does allow for an "external mu", but CMS doesn't yet have that
>   standardised.
> 
> Fix this by noting in the public_key_signature struct when the signing
> algorithm is going to want this and then, rather than doing the digest of
> the authenticatedAttributes ourselves and overwriting the sig->digest with
> that, replace sig->digest with a copy of the contents of the
> authenticatedAttributes section and adjust the digest length to match.
> 
> This will then be fed to the public key algorithm as normal which can do
> what it wants with the data.
> 
> 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 | 48 ++++++++++++++++++---------
>  include/crypto/public_key.h           |  1 +
>  3 files changed, 36 insertions(+), 17 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 6d6475e3a9bf..0f9f515b784d 100644
> --- a/crypto/asymmetric_keys/pkcs7_verify.c
> +++ b/crypto/asymmetric_keys/pkcs7_verify.c
> @@ -70,8 +70,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;
> @@ -97,20 +95,40 @@ 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->digest, 0, sig->digest_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->digest);
> -		if (ret < 0)
> -			goto error;
> +		if (sig->algo_does_hash) {
> +			kfree(sig->digest);
> +
> +			ret = -ENOMEM;
> +			sig->digest = kmalloc(umax(sinfo->authattrs_len, sig->digest_size),
> +					      GFP_KERNEL);
> +			if (!sig->digest)
> +				goto error_no_desc;
> +
> +			sig->digest_size = sinfo->authattrs_len;
> +			memcpy(sig->digest, sinfo->authattrs, sinfo->authattrs_len);
> +			((u8 *)sig->digest)[0] = ASN1_CONS_BIT | ASN1_SET;
> +			ret = 0;
> +		} else {
> +			u8 tag = ASN1_CONS_BIT | ASN1_SET;
> +
> +			ret = crypto_shash_init(desc);
> +			if (ret < 0)
> +				goto error;
> +			ret = crypto_shash_update(desc, &tag, 1);
> +			if (ret < 0)
> +				goto error;
> +			ret = crypto_shash_finup(desc, sinfo->authattrs + 1,
> +						 sinfo->authattrs_len - 1,
> +						 sig->digest);
> +			if (ret < 0)
> +				goto error;
> +		}
>  		pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
>  	}
>  
> diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
> index 81098e00c08f..e4ec8003a3a4 100644
> --- a/include/crypto/public_key.h
> +++ b/include/crypto/public_key.h
> @@ -46,6 +46,7 @@ struct public_key_signature {
>  	u8 *digest;
>  	u32 s_size;		/* Number of bytes in signature */
>  	u32 digest_size;	/* Number of bytes in digest */
> +	bool algo_does_hash;	/* Public key algo does its own hashing */

I'd use the wording you used already in commit message, which
factors more descriptive than what you have here. E.g., name
it "external_digest".

It would be easier to digest this when revisiting the code later...

>  	const char *pkey_algo;
>  	const char *hash_algo;
>  	const char *encoding;
> 

Allocation scheme is not the prettiest but I neither have
anything other to offer, so other than the rename request,
I think this is acceptable.

BR, Jarkko

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 12/12] pkcs7: Add ML-DSA FIPS selftest
  2026-01-20 14:50 ` [PATCH v13 12/12] pkcs7: Add ML-DSA FIPS selftest David Howells
@ 2026-01-20 17:54   ` Jarkko Sakkinen
  2026-01-20 17:55     ` Jarkko Sakkinen
  2026-01-20 21:43   ` Eric Biggers
  1 sibling, 1 reply; 37+ messages in thread
From: Jarkko Sakkinen @ 2026-01-20 17:54 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 Tue, Jan 20, 2026 at 02:50:58PM +0000, David Howells wrote:
> Add a FIPS selftest for ML-DSA.
> 
> This is testcase (tcId) 35 from the ML-DSA-sigVer-FIPS204 JSON set[1],
> packaged into a rudimentary X.509 cert and PKCS#7 message.
> 
> Note that only this particular testcase can be used because the current
> ML-DSA implementation assumes an empty context string.
> 
> [1] https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-sigVer-FIPS204
> 
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> ---
>  crypto/asymmetric_keys/Kconfig          |   6 +
>  crypto/asymmetric_keys/Makefile         |   1 +
>  crypto/asymmetric_keys/selftest.c       |   1 +
>  crypto/asymmetric_keys/selftest.h       |   6 +
>  crypto/asymmetric_keys/selftest_mldsa.c | 688 ++++++++++++++++++++++++
>  5 files changed, 702 insertions(+)
>  create mode 100644 crypto/asymmetric_keys/selftest_mldsa.c
> 
> diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
> index e1345b8f39f1..c698a7a39fe2 100644
> --- a/crypto/asymmetric_keys/Kconfig
> +++ b/crypto/asymmetric_keys/Kconfig
> @@ -103,4 +103,10 @@ config FIPS_SIGNATURE_SELFTEST_ECDSA
>  	depends on CRYPTO_SHA256=y || CRYPTO_SHA256=FIPS_SIGNATURE_SELFTEST
>  	depends on CRYPTO_ECDSA=y || CRYPTO_ECDSA=FIPS_SIGNATURE_SELFTEST
>  
> +config FIPS_SIGNATURE_SELFTEST_MLDSA
> +	bool
> +	default y
> +	depends on FIPS_SIGNATURE_SELFTEST
> +	depends on CRYPTO_MLDSA=y || CRYPTO_MLDSA=FIPS_SIGNATURE_SELFTEST
> +
>  endif # ASYMMETRIC_KEY_TYPE
> diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
> index c5aed382ee8a..25623d100b74 100644
> --- a/crypto/asymmetric_keys/Makefile
> +++ b/crypto/asymmetric_keys/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_FIPS_SIGNATURE_SELFTEST) += x509_selftest.o
>  x509_selftest-y += selftest.o
>  x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_RSA) += selftest_rsa.o
>  x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_ECDSA) += selftest_ecdsa.o
> +x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_MLDSA) += selftest_mldsa.o
>  
>  $(obj)/x509_cert_parser.o: \
>  	$(obj)/x509.asn1.h \
> diff --git a/crypto/asymmetric_keys/selftest.c b/crypto/asymmetric_keys/selftest.c
> index 98dc5cdfdebe..d31cf5efefc7 100644
> --- a/crypto/asymmetric_keys/selftest.c
> +++ b/crypto/asymmetric_keys/selftest.c
> @@ -62,6 +62,7 @@ static int __init fips_signature_selftest_init(void)
>  {
>  	fips_signature_selftest_rsa();
>  	fips_signature_selftest_ecdsa();
> +	fips_signature_selftest_mldsa();
>  	return 0;
>  }
>  
> diff --git a/crypto/asymmetric_keys/selftest.h b/crypto/asymmetric_keys/selftest.h
> index 4139f05906cb..d515224fcfb3 100644
> --- a/crypto/asymmetric_keys/selftest.h
> +++ b/crypto/asymmetric_keys/selftest.h
> @@ -20,3 +20,9 @@ void __init fips_signature_selftest_ecdsa(void);
>  #else
>  static inline void __init fips_signature_selftest_ecdsa(void) { }
>  #endif
> +
> +#ifdef CONFIG_FIPS_SIGNATURE_SELFTEST_MLDSA
> +void __init fips_signature_selftest_mldsa(void);
> +#else
> +static inline void __init fips_signature_selftest_mldsa(void) { }
> +#endif
> diff --git a/crypto/asymmetric_keys/selftest_mldsa.c b/crypto/asymmetric_keys/selftest_mldsa.c
> new file mode 100644
> index 000000000000..9927a4423067
> --- /dev/null
> +++ b/crypto/asymmetric_keys/selftest_mldsa.c
> @@ -0,0 +1,688 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/* Self-tests for PKCS#7 RSA signature verification.
> + *
> + * Copyright (C) 2024 Joachim Vandersmissen <git@jvdsn.com>
> + */
> +
> +#include <linux/module.h>
> +#include "selftest.h"
> +
> +/*
> + * Set of X.509 certificates to provide public keys for the tests. These will
> + * be loaded into a temporary keyring for the duration of the testing.
> + */
> +static const u8 nist_mldsa_fips204_35_key[] __initconst = {
> +	"\x30\x82\x15\x6a\x30\x82\x08\x67\xa0\x03\x02\x01\x02\x02\x04\x01"
> +	"\x23\x40\x23\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x03\x12"
> +	"\x30\x0f\x31\x0d\x30\x0b\x06\x03\x55\x04\x03\x0c\x04\x46\x72\x65"
> +	"\x64\x30\x20\x17\x0d\x32\x36\x30\x31\x30\x31\x30\x30\x30\x30\x30"
> +	"\x30\x5a\x18\x0f\x32\x31\x39\x39\x30\x31\x30\x31\x30\x30\x30\x30"
> +	"\x30\x30\x5a\x30\x20\x31\x1e\x30\x1c\x06\x03\x55\x04\x03\x0c\x15"
> +	"\x6e\x69\x73\x74\x5f\x6d\x6c\x64\x73\x61\x5f\x66\x69\x70\x73\x32"
> +	"\x30\x34\x5f\x33\x35\x30\x82\x07\xb2\x30\x0b\x06\x09\x60\x86\x48"
> +	"\x01\x65\x03\x04\x03\x12\x03\x82\x07\xa1\x00\x91\x52\xc0\xc6\x86"
> +	"\x77\x60\x8f\x42\x6f\xb1\x6f\x8f\x75\xf7\x6c\x64\x70\x99\xd9\xd5"
> +	"\x94\x31\xf4\x6f\x12\xa2\xf2\x93\x6e\x6e\x1f\x7e\x2d\xd2\x8f\x99"
> +	"\xc8\x05\x81\x94\xc3\xfa\xe6\xdf\xf2\x87\xf5\x9b\xe5\x6b\x04\xb3"
> +	"\xfd\x92\xda\xbd\x7b\xd3\xa3\xdf\x48\x3f\xec\xed\x84\xd3\x18\x80"
> +	"\x90\x06\xda\x91\x46\x8d\x77\xd7\xc6\xeb\x9a\x51\x81\x75\x47\x7a"
> +	"\x0e\x2b\x43\x56\x97\xc2\x69\xf1\x6f\xbb\x56\x99\x6b\x64\x55\xf0"
> +	"\x4b\x3c\xc1\x1e\xb5\xd6\x65\x5d\x07\x3d\x96\xbf\x4b\x4c\xdb\x9e"
> +	"\x31\xe9\x93\xf0\xf1\x0c\x65\x59\x83\x21\x20\x5e\x11\x15\xfa\x60"
> +	"\xa1\xf3\xca\x5a\xd0\x49\x21\x8b\x16\xfd\xf7\xb5\xe2\xbf\x41\x79"
> +	"\x8d\x58\x39\x52\x3b\xcf\x1d\xe3\x11\x05\x57\x79\xce\xb2\x07\x69"
> +	"\xb8\x2e\x0a\xce\x7b\xb4\xed\x00\xcc\xed\x66\x5e\x42\x21\xf0\x48"
> +	"\xea\xfa\x77\x4c\x7e\x9a\x49\x8d\xa2\x67\x5f\x9b\xe9\xf7\x2b\x58"
> +	"\xa1\xe7\x30\xfa\xda\xad\x39\xe2\x31\xe4\x6d\x88\x4a\x22\xee\xe5"
> +	"\xc3\x3a\xe2\xe6\x74\x04\xd5\x7e\xdb\xa0\xb9\x4a\x4f\x27\xd2\x08"
> +	"\x1f\x46\x62\x66\xd6\x54\xc0\xb8\x37\xbe\x74\x65\x87\x34\x55\x5a"
> +	"\x06\x82\x82\x7d\x65\xc3\x46\x4e\x96\x90\xdf\x6b\xb8\x1a\xdc\x11"
> +	"\x79\x02\xc5\x48\x06\xb7\x3b\xcb\x6c\x44\xa9\x35\xbc\xe9\xea\x8f"
> +	"\xc8\x9e\xaa\x27\xd0\x4a\x67\xe0\xf6\xe6\x0a\x94\x78\xdb\x70\xc9"
> +	"\xf5\xd5\x87\xca\xd5\xb6\x2e\x55\xea\xff\xd4\xcf\xad\x4d\xd3\x67"
> +	"\x2b\xb7\xaa\x80\x9b\x7f\x56\x0a\xd1\xea\xbd\xbd\x20\x88\x01\x00"
> +	"\xaa\x2f\xcc\x7d\x0a\x31\x6b\xe5\x66\xee\x87\xaf\xbf\x08\xc7\xa7"
> +	"\xd3\x50\xde\x31\xd2\x3d\xfd\xf5\x87\x74\x76\x30\x31\x9c\x3f\x14"
> +	"\x00\x22\xf9\x70\xba\x6c\x4e\xdd\x84\x64\xdb\xaa\x5e\xb0\x22\xff"
> +	"\x87\x25\x2f\x55\xab\xbd\xdf\xac\x6d\x31\xd8\x53\xb3\x50\x56\xea"
> +	"\x48\xad\x33\x94\xa5\xe6\x85\x21\x06\x10\xbb\xa8\x96\xdd\xc9\x00"
> +	"\x99\x93\xe2\x0e\xa1\xb0\x66\x41\xe4\xd5\x24\x2d\xd0\x8f\x6e\xff"
> +	"\xdd\x6f\x0c\xcd\x8e\x5c\xb9\x8b\x6b\x66\xeb\x2b\x38\x52\x01\x4a"
> +	"\xc2\x80\xc5\x44\x48\x87\xcd\x6b\xcd\xea\xb5\x94\x7f\x8f\x19\x86"
> +	"\xb7\xf9\x65\xb5\x08\x51\x77\xe7\x73\x2f\xd4\xf9\x74\xd8\x7c\xc3"
> +	"\x03\x24\xcf\x42\xaf\x25\xdc\x73\x68\xa1\x34\x9e\x26\x86\xa6\x05"
> +	"\x5f\xe2\x6f\xcc\x5d\x1f\xa1\x1d\xed\x9f\x1c\x24\x65\x6d\x43\x6c"
> +	"\xdd\x1a\xc4\x10\xf6\x00\x8b\x0f\xf2\x33\xb5\x53\x79\x17\x9f\x47"
> +	"\x67\x4a\x52\xad\x56\xd1\x38\x85\xef\x03\xd7\x22\x3b\x39\xe6\xb8"
> +	"\x63\x4d\x52\x89\xcf\xd9\x46\xd9\x7b\x7b\xfb\xf2\x28\xa6\xe9\x38"
> +	"\x42\xbe\xb3\x75\xd7\x6e\x01\xbb\xff\xc2\xe6\x76\x58\xe3\x63\x65"
> +	"\x76\x1a\xde\xc0\x72\xe3\x3a\x8e\x9d\x53\xf9\x2d\x74\x1a\xe7\x0c"
> +	"\xe7\x8b\xd1\x90\xbd\x91\xc3\xa8\xe3\x09\x35\xcc\x25\x00\xa6\xdb"
> +	"\x87\x5c\x45\x6c\x1d\x15\xf1\x1b\x16\xe8\x79\xb1\xb4\x63\x35\x22"
> +	"\x66\x69\x5e\xad\xcb\x75\x77\xff\xfc\xfe\x6f\x5d\x72\x12\xcf\x07"
> +	"\x39\x94\x04\x03\x9a\x0d\x15\xa6\x97\x85\x5b\x82\x77\xe9\x45\xc2"
> +	"\xa2\x70\x14\x89\x61\x07\x0e\xe9\x5c\x13\x53\x38\x7f\xa6\x14\xea"
> +	"\xec\x62\xb4\x41\xdf\x38\x5f\xff\x80\x7f\x29\xd9\x41\x63\x75\x12"
> +	"\xb4\x87\x73\xfc\x48\x5a\x52\x1d\x55\x5f\xec\x22\x76\x57\x5f\x10"
> +	"\x95\xc0\x23\x7e\x66\x34\x77\x73\xbf\xf4\x37\x1b\x3e\x9f\x10\x4b"
> +	"\x09\x6b\x6e\xb8\x06\x8d\xff\xd2\xcf\xb3\xc0\x61\x31\xf0\xaf\xd3"
> +	"\xae\xfc\x36\x03\x5f\x92\x21\xc2\xdc\x03\x63\x75\x08\xd3\x9d\xc0"
> +	"\x0a\xc7\xac\x36\x2c\x15\xf2\xf5\x16\xc7\x71\x59\x34\xf5\xf8\x01"
> +	"\x82\xd2\x8e\xeb\x1a\xe2\x63\xce\xf7\x24\xe5\xb1\x14\x10\x0c\x74"
> +	"\xea\xd0\x0e\xc3\x6c\x7e\x1e\x7e\x04\xb6\x5f\x79\x20\x91\xe5\x22"
> +	"\xb2\x5f\x8d\xe2\x25\xf5\x07\x0a\x57\xb3\x04\x53\x60\x54\x28\x29"
> +	"\x64\xd6\x66\x5b\x38\x78\xcb\xd5\x93\xc8\xd8\x40\xed\x84\x9f\x14"
> +	"\xc8\xf6\x16\xbc\xc1\x4d\xcb\xb4\xf2\xf0\x85\x97\x93\xb8\x0c\xbe"
> +	"\x30\xb8\x3a\x31\x6a\x6e\x8b\x64\x64\x51\x2e\xaf\x53\xda\xf6\xdf"
> +	"\x66\x1b\xc9\x24\xb1\xf7\x34\x64\x53\xd5\x27\xed\xc3\x7d\xc1\x42"
> +	"\x15\x25\x71\x41\x14\xd6\x6c\xb0\xe3\x82\x07\x25\x88\x70\x6a\x03"
> +	"\x6d\xff\xef\x9f\xf3\x0f\xe3\xc7\xe8\x1d\x00\x99\x53\x72\x33\x14"
> +	"\x8e\x03\xa4\xdf\xb6\xfc\xde\xd3\x30\x2f\xe8\xa8\xe0\xb2\x21\x90"
> +	"\x3c\x97\xbf\x3a\xf8\xd8\x86\x01\xea\x90\xf0\x9f\xae\x83\xe5\x6a"
> +	"\x78\x2f\x3c\xb2\x4c\x48\x51\x3a\x50\xf4\xae\xf1\x2e\x39\x8b\xeb"
> +	"\x5e\xd9\x44\x97\x94\xb5\x9b\x54\x34\x20\x0a\x8f\x09\x89\x2e\x0a"
> +	"\x0b\xac\x13\x66\x91\x99\xe6\x75\xb3\x8e\x39\x21\x1d\xcc\xf4\x83"
> +	"\x2e\x71\xcb\x11\x2a\xc2\x77\xb6\xe4\x3e\xd7\x83\x64\x7b\xd9\x44"
> +	"\x52\xf7\x96\xbd\x77\x96\x83\xec\xf0\xa9\xaf\x0d\x8b\xd7\xbb\x3e"
> +	"\xdd\x8d\xd3\xf7\x8b\x81\xbd\x3a\x87\x2c\x72\x11\xa9\x31\x86\xfd"
> +	"\x9a\x54\x21\xb8\x0c\x57\xcc\x83\xf2\xff\xb8\x9e\x1e\x21\xdf\xbb"
> +	"\x1f\x71\x0f\xbe\xdd\x52\xf0\x02\xe5\xed\x67\xba\x26\x1b\xdc\x6d"
> +	"\x35\x86\x81\x9a\xfa\xbf\xbe\xc4\x52\x81\x99\xa3\xf5\x58\x95\x9a"
> +	"\x9a\x03\x22\xe5\xdd\xe4\x56\x38\x2b\x7f\x26\x26\x1d\x45\xde\xe1"
> +	"\x22\x94\x5d\xad\x8a\x64\xc6\x2a\xe2\xa8\x00\x7f\xba\x75\x97\x9b"
> +	"\x77\xd4\x2c\xe9\xbf\x25\xf8\x54\xcb\xb0\xe3\xce\xc4\x62\x7a\x13"
> +	"\x46\x69\xb9\xd4\x4b\x01\x08\x72\x9a\x85\xb8\xf9\x5f\x7d\x30\xa1"
> +	"\x76\x18\x48\x0f\x3d\x01\xd0\xf1\xa5\x48\xaf\x79\x8b\x5e\x71\x28"
> +	"\x37\x75\xc5\xa8\x3d\x79\x0d\x25\xb6\x3d\xf4\xba\xa5\x82\x8c\xfd"
> +	"\x77\x1a\xf2\x0e\x06\xb3\x04\xea\x62\x34\x4a\x09\xd5\x7a\x29\xa6"
> +	"\xa9\xfe\x25\x82\x23\xe1\x68\x6a\xd5\xd3\x11\x60\xfd\x64\x29\x0c"
> +	"\x71\x2d\xcb\xc2\xf3\x20\x6e\x29\x4f\xf6\xf3\x6e\x56\x08\x4a\x20"
> +	"\x31\xdb\x1d\xdd\xdc\x1a\x8d\xdc\x40\x19\x65\xf3\x8a\xea\x45\x76"
> +	"\x4f\xf0\x9f\x1c\x6c\x07\x88\xdd\x0c\x7b\x1d\x4f\x8d\x9c\x60\xf0"
> +	"\x27\x2e\x7f\x50\x8b\xd0\x34\x92\x9a\x19\x10\xbd\x46\x06\x33\x70"
> +	"\x1c\x65\xaf\xf6\x85\xb6\xb8\xa3\x67\x55\xc0\xab\xd8\xc7\x47\x42"
> +	"\xae\x80\x45\xc9\x88\x9e\xa5\x05\x72\x42\x6a\x5b\x09\xb8\x30\x05"
> +	"\x43\x62\xe6\xb3\xdf\x3d\x84\x98\xc2\xfe\xd9\xea\x59\xba\x90\xf0"
> +	"\xad\x8f\xeb\x87\x33\x53\xe3\x33\x60\xf6\x32\x3f\x39\xa4\x06\xfe"
> +	"\x78\x27\xe8\xac\x2f\xfd\xde\x6b\xb6\xf7\x26\xca\x1c\x14\x64\x3c"
> +	"\x4e\x85\x41\xd5\x7d\x6a\x18\xaf\xca\x73\xca\xdc\x53\xb7\x29\x1e"
> +	"\x4b\x37\x71\xf2\xb2\x9d\xec\xbd\xf2\xf7\x21\x38\x6b\xd2\x2e\xf5"
> +	"\xc1\xb9\x7c\x54\x86\xad\xf2\x60\x9a\xb3\x87\x2d\xb0\x69\xf1\xd0"
> +	"\x3e\x94\x2b\xb7\x61\x93\x04\x3d\xba\x68\xd3\x1b\x20\xe0\x41\x2c"
> +	"\x0a\x4a\xf5\x15\xa6\x20\xd2\x7b\x7e\x4b\xc1\x15\x3d\xde\xbb\xb3"
> +	"\xe8\x79\x9c\xd1\x02\x54\x4f\xdf\xa3\x40\xaf\xa4\x66\x16\x04\xfa"
> +	"\x68\x21\x2c\xfc\x0c\x15\x7e\x06\x0f\x1c\xc1\xbd\xd6\xa0\x29\x85"
> +	"\x38\x0b\x61\xb6\x08\xd4\xc7\x45\x9b\x49\x4d\xd5\x3d\xc8\x00\x9b"
> +	"\xab\xc7\x6f\x62\x39\x7e\x96\x2d\x18\xac\xab\xec\xd4\x98\x9b\x86"
> +	"\x18\x59\x2f\x9d\xda\x47\x47\x0e\x19\x8c\xe2\xd9\x6f\x62\x3e\x9d"
> +	"\x3f\x73\x13\xb4\x62\x39\x31\x9a\x54\x04\x76\x7c\x5f\xf9\xe7\x79"
> +	"\x5b\x4a\xf6\x95\x82\x64\xaa\x7d\xf3\x83\x00\x72\xc5\xd9\xc3\xaa"
> +	"\x75\x0c\x42\x2d\x9a\x1c\x3c\x6e\x44\xf2\x52\x9c\x91\xe0\xea\xf3"
> +	"\x06\x18\xe8\x61\x63\x04\x7e\x29\x9d\xa6\x1e\x3e\xce\x10\x38\xac"
> +	"\xde\xb8\x52\x67\x14\x8a\x32\xdb\x71\x40\x5f\x0c\xd6\x2d\x52\xa4"
> +	"\xd2\x9d\x4d\xf3\x21\xa0\x45\x2a\x19\xda\x75\x70\xae\xbd\x4a\x7b"
> +	"\x3a\x2f\x5f\xc5\xbd\x79\x28\x2d\xbc\xff\x43\x3c\x3f\xe4\x23\xa7"
> +	"\x77\xa6\xf1\x2b\x62\x75\xb5\xab\x85\x0c\x76\xec\xdd\x42\xc9\xdf"
> +	"\x67\xb4\x0b\x95\x61\xd1\xf8\x55\xdb\x54\xfa\xcd\x98\xb2\x0d\xc6"
> +	"\x15\xfe\xb4\xea\x3f\xae\xe9\xcc\x90\xf1\x08\x15\x88\xca\xe8\x32"
> +	"\x0f\xa1\xca\x4a\xd1\x21\xe4\xf3\x11\x76\xdf\xed\xec\x3e\x61\x09"
> +	"\x56\x7f\xf1\x88\x39\x34\x41\x76\x5b\x9a\x88\xad\x04\x40\x67\x55"
> +	"\x2e\x8d\xc1\xe1\x91\x2f\x6a\xc0\xd5\x54\x46\x24\x7a\x48\x14\x56"
> +	"\x98\x74\xec\x7c\x3d\x6a\x28\x8b\xbc\xce\xe6\x47\x5f\x9a\x84\x0b"
> +	"\xa4\x40\xdf\x6f\x6a\x9e\xd4\x7f\x0b\x12\x24\xbb\xbe\x4a\xce\x0b"
> +	"\xd8\x7c\xf6\x0c\x69\xcd\x63\xfa\xd2\xfb\x8e\xc2\x80\x5c\xb8\x0b"
> +	"\x2d\x5d\xd0\x31\x25\x41\xdb\xc1\x02\x04\xcc\x55\x74\xf9\xe4\xe7"
> +	"\x56\xcb\xc8\x73\x70\xdd\x66\xeb\x9f\x6e\x09\x57\xa0\xab\xd7\x1a"
> +	"\x15\xe0\xeb\x18\xf4\xe2\xe1\xc7\x3a\x38\xfd\x3d\x36\x44\xe4\xd9"
> +	"\xa7\x4b\xf8\x5a\xa1\xd5\xb4\x2a\x68\xa3\x05\x74\x58\x11\x17\xdb"
> +	"\x27\xe1\xd5\x5f\x7d\x01\x6d\xa0\x8d\x0e\x6b\x4f\x88\x1b\xcd\xde"
> +	"\x48\xab\x47\x3e\xd0\x73\xd8\x55\xf1\x90\x91\xa8\xc6\x9b\xd9\xd3"
> +	"\x2e\xf5\x7e\xde\xb3\xe8\xfb\x4f\x80\xec\x87\xa3\xa3\x02\x78\x54"
> +	"\xe0\x33\x8d\x24\x88\xc9\x5d\xab\x6b\x67\x72\x01\xb0\xc0\x94\x26"
> +	"\x9b\x1a\xf4\xc3\x21\x8d\x4b\xfd\xac\xea\x35\xe5\xb9\x93\x1c\xe6"
> +	"\x36\x69\x80\x8f\x20\xb7\x3d\x42\x90\xbd\xea\x77\x38\xbf\xa8\xa8"
> +	"\x29\x05\x32\x32\x1d\x20\xf1\x3f\x39\x9c\x92\x6e\x2e\x39\xd1\x27"
> +	"\x55\x59\xe4\x79\x3a\xf4\x4e\x14\x38\x78\x80\xa3\x42\x30\x40\x30"
> +	"\x0c\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x02\x30\x00\x30\x0e\x06"
> +	"\x03\x55\x1d\x0f\x01\x01\x00\x04\x04\x03\x02\x07\x80\x30\x20\x06"
> +	"\x03\x55\x1d\x0e\x01\x01\x00\x04\x16\x04\x14\x2b\x73\x93\x2c\xf0"
> +	"\x6c\x34\x1a\xa7\x2c\xce\xa4\xe0\xac\x35\xa9\x6c\xcc\x00\x23\x30"
> +	"\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x03\x12\x03\x82\x0c\xee"
> +	"\x00\x6e\x8c\x4b\x20\x61\xc2\xcd\xf2\x71\x54\xbf\x70\x85\xf6\x3c"
> +	"\xb1\x5d\xa3\xce\xc8\x2d\x52\xca\xd1\xa6\x50\x80\x68\x75\x05\x25"
> +	"\x24\xda\xa1\xef\xdf\xf4\x6f\xde\x5e\xff\x63\xef\xf5\x70\x74\x7c"
> +	"\x69\xfd\x23\x4b\xa3\xaa\x3b\xa9\xa8\x0f\x48\x8b\xc4\x8f\x95\x9f"
> +	"\xf5\x6a\xb3\x17\x35\x5f\xfe\x91\x7b\xdd\xd3\xbb\xf7\x3b\xf0\xa8"
> +	"\x22\x09\xbe\x25\x48\xcd\xca\x1a\x37\xc4\xde\x57\x18\x56\x30\x19"
> +	"\xa9\x26\x99\x13\x9a\x6d\x6a\x69\xe9\x64\x83\x2d\xdd\x70\xf5\xe8"
> +	"\x03\x75\xdc\x9f\xe0\xba\x8e\x22\xae\x3a\xd8\xaa\xd9\x45\x84\x71"
> +	"\xcd\x37\x61\xb1\xb9\x04\xe8\xbb\xba\x72\xfa\x8a\x07\x1d\xf1\x82"
> +	"\x55\x17\xff\xa2\x2e\x2b\xbf\xf9\x9a\x0f\x86\x94\x06\xd9\x07\xdb"
> +	"\xc3\x16\x92\x90\xce\xd1\x4e\xb8\xee\x7a\x2b\x6c\xe7\xc2\x6a\x0a"
> +	"\xe2\x8b\x32\x5e\xd4\x61\x38\x90\xaf\xce\xbb\x38\xe6\xe9\xd5\x43"
> +	"\x74\xc9\xeb\x48\xd0\xe6\x00\x30\xa1\x1e\x75\x03\xb9\x06\xe9\x16"
> +	"\x35\x7c\x6f\x81\xd5\x9f\x89\xcc\x36\x33\x75\xcb\xf0\x1e\xd0\xd8"
> +	"\x51\x54\xd5\x5c\xb8\xfc\xe7\xb2\x17\xd5\xed\xeb\xe9\x36\x85\xe0"
> +	"\xbe\x43\x4c\xb0\xc5\x67\xc8\x97\x62\xb3\x80\x89\xec\x2c\xf3\x4c"
> +	"\x93\x87\x9c\x0b\x23\x5d\x44\x25\x6a\x10\x3f\x21\x08\x7d\x8d\xfc"
> +	"\x99\x8d\xc5\xbe\xbe\x57\x5c\x5d\x4d\x27\x7b\xa2\x2e\x81\xcd\x0a"
> +	"\xf1\x49\x2b\x43\xda\xc4\x36\x5c\xc6\x91\x75\xd8\x95\xa6\x9b\xbf"
> +	"\xe9\x21\x45\x3c\x07\xae\x56\xcd\xf5\x1b\x91\x56\xe4\x49\x40\x12"
> +	"\x58\x8a\xa4\xac\x32\x53\x93\xbe\xe9\x8a\x65\xef\x71\xe3\x07\xc8"
> +	"\x4d\xb9\x35\x85\x4d\x06\x9b\xa4\x11\x6a\x67\x7a\x5b\x49\xee\xea"
> +	"\xf2\x0d\x16\x49\x2b\x74\x46\x78\xcc\x59\x12\x0c\x80\x6f\xae\x7d"
> +	"\x23\x30\x87\x7f\x16\x52\x04\x11\x41\x0b\xba\x48\xbf\x49\xaa\x08"
> +	"\xf4\x44\x00\x75\x4a\x05\x79\x79\x66\x31\x94\x44\x9e\x66\xf5\xc0"
> +	"\xd7\xa1\xeb\xb5\xda\xc4\xb6\x5c\xf9\x20\x0b\x21\x89\xf6\x0f\xa5"
> +	"\x29\x48\xcb\x7a\x83\xd5\xfd\x54\x45\xaf\xa3\x0d\x99\xe9\x14\x30"
> +	"\x06\x8a\x53\x51\x08\x0d\xa4\x24\xa6\xf4\xae\x5f\x8e\x1b\x7b\xa6"
> +	"\x48\x1c\xfb\x39\xfc\x34\x2a\xcf\xa0\x84\xb3\x79\xb7\xc7\x4d\x64"
> +	"\x0e\x0c\x04\x87\x31\x9f\xf6\x97\x02\x8b\xe8\xc2\x13\x21\x8e\xfc"
> +	"\x85\x7c\xac\xfa\xc4\x44\x10\x3f\x2f\x93\x02\x74\x44\x1f\x18\xdc"
> +	"\x2e\x17\xca\x18\x27\x86\x55\xfb\xc0\x79\x4b\x50\x08\x33\x62\x4c"
> +	"\x58\x29\x20\x98\x95\x9f\x8c\x7a\xf7\x82\xe1\x41\x43\xf3\x5c\x55"
> +	"\x54\xe3\x22\x60\xf2\xa4\x85\x17\x88\x93\x6b\x6d\xc7\x48\xf6\xc0"
> +	"\x0b\x4b\xf0\x86\xc6\x64\xae\xd9\x22\x08\x75\x35\xce\xf4\x7b\xad"
> +	"\xf2\xb6\x7d\x50\x6e\xba\xf6\x46\x30\x7b\xbc\x60\xc3\xf7\xf7\xeb"
> +	"\x39\x44\x6a\x34\xde\xb4\x6f\x43\x3f\xfb\xcb\x23\x60\xfb\x55\x57"
> +	"\xaa\x9a\x2e\x33\x29\x37\xd7\x9a\xb6\x85\xa2\xad\x9b\x25\x42\x38"
> +	"\x83\x44\x85\x0e\xec\x19\x74\xa3\xdc\x73\x4b\x30\xb9\x6b\x05\x63"
> +	"\xcd\xdb\xa3\x18\xed\xfd\xc2\x94\x1b\xdf\x1f\x64\x6c\xd6\x29\x05"
> +	"\x58\xe0\x77\xb9\x1b\xd5\x40\xe6\xff\x3b\x7e\x13\x2b\xef\xed\x35"
> +	"\x8e\x06\x69\x13\x8f\xe4\x93\x59\x34\x54\x50\x16\x3c\xbb\x5b\xe2"
> +	"\xa4\x7a\xd5\x35\x60\x3a\x13\x8e\x7c\x37\xf6\xb8\xfd\x1f\xa1\x1d"
> +	"\xd4\x25\x19\x54\xba\xe7\x8e\x7c\x59\x40\xc3\x7a\xf2\x2c\x94\x78"
> +	"\xca\x02\x0a\x1d\x21\x4f\x97\x57\xbc\x06\x36\x23\xce\x8d\xce\xdd"
> +	"\x39\x5d\x6b\x7b\xc1\xa8\x06\x90\x4e\xbf\xaf\x28\xf0\xf8\xc5\xa6"
> +	"\x3a\x0c\x1c\xc6\x31\x4f\xe8\x05\x79\x1d\x76\x57\x05\xf5\xfa\x33"
> +	"\x17\x1a\xb4\xc8\x51\xc2\x6e\x42\xc0\xf9\xdc\xcf\x9c\x28\x37\xc1"
> +	"\x11\x42\x1d\x0f\x5f\xdc\xf9\xa9\xeb\xa0\x9c\x25\xdb\x0d\x79\x65"
> +	"\xdc\x91\xdc\x4e\x63\x84\x1a\x76\xae\x9a\x68\x7a\xd8\xb6\xe4\x90"
> +	"\x68\xcf\x74\xfa\xaf\xd8\xa6\x6c\x91\x39\xd3\xc3\xa6\xbe\x06\x56"
> +	"\x3c\xb5\x7f\xe7\x73\x30\x14\x79\x57\x4c\x68\xeb\x32\x94\xe3\x35"
> +	"\xf9\xf1\xbb\x7c\xfd\xf5\x0e\xa1\x13\x92\xf0\x4f\x5f\x3b\xe9\x9c"
> +	"\xb2\x4b\x07\xa8\x91\x17\x34\x02\xef\x38\xf7\x44\xdd\xf9\x27\xf0"
> +	"\x60\x1f\x70\xba\x50\xf8\xab\x84\x5f\xf2\xa0\x12\x40\x1a\x99\xcf"
> +	"\x4f\x03\x36\x4c\x30\x82\xd4\x21\x81\x91\x9e\x87\xd4\xac\x3b\x3b"
> +	"\xe1\xf9\x5a\xb6\x90\xfc\xda\x10\x6c\x87\xc6\x3c\x7b\xed\xf1\x29"
> +	"\x08\xd6\xa0\xee\xc3\xb6\x72\x46\x1b\xb1\x38\xec\xfd\x48\x01\x9a"
> +	"\x07\x7e\xf4\xe5\x90\x94\x8a\xbd\x08\x3e\x28\xef\x4d\x06\x2f\x8e"
> +	"\x58\x3b\x69\xcb\x79\x80\x3b\x70\xde\x5d\xea\x1f\x60\x00\x51\xd9"
> +	"\xed\xef\x2a\xed\x93\xa5\xd5\xbb\x5a\xb7\xb5\xb1\x96\x84\x62\x25"
> +	"\xf6\xb0\x73\xdf\xbe\x40\x13\xb4\xc8\x14\xae\x15\x20\x7d\xbb\x76"
> +	"\x0b\x97\xe6\xbc\xb7\x61\x7e\xb2\x6c\xd3\xb5\xa4\x1b\xa6\xb5\xdd"
> +	"\x88\x45\x1b\x5b\xcc\xf5\x52\xdc\x49\x3f\x85\xa1\xcf\x3a\xfa\xae"
> +	"\x80\x81\x89\xb2\xfe\xdf\x04\x47\x8e\xde\x57\x94\x82\xa7\x11\xb2"
> +	"\x2b\x55\xd4\x8a\xb2\x18\x9e\x6c\x14\xf6\xf8\x69\x84\x5d\x88\xf7"
> +	"\x8a\xf5\x40\x20\x24\x60\x5f\xa3\xe2\x47\x32\xf9\x93\x17\x09\xac"
> +	"\x35\x9d\xfa\x74\x78\x17\xb1\x2c\x37\xb0\xdc\x0b\xe0\x8b\x5a\xcf"
> +	"\x9d\x3f\x09\x6e\x44\xf4\xdb\xa0\x23\x34\x76\xb2\x66\xf4\x2b\x92"
> +	"\x04\x0a\x9c\x88\x49\x6c\x80\xfb\x99\x6c\x70\xfb\xd5\xdc\xce\x10"
> +	"\xd1\x1a\x72\x2b\x4e\x9e\x34\xe0\x60\xf0\x06\x04\xd2\x55\x78\xc4"
> +	"\xea\xe8\x6b\x4a\x43\x7a\x14\xc7\x2c\x83\x34\x63\xf4\x4c\xa5\xee"
> +	"\xb3\xf0\x02\x78\x57\x44\x69\x37\xed\xda\x22\xb6\x3f\x86\x15\x81"
> +	"\xeb\x1f\xae\x69\x75\x29\x8c\x04\x83\xff\x80\xad\x45\x18\x88\x6a"
> +	"\x78\x43\x1b\x93\xf8\xd4\x19\x89\x1d\xbb\x85\x6b\x2f\x08\xdf\xc2"
> +	"\x27\x72\xbe\x36\xdb\x30\x7f\x3b\x36\xfe\x81\x60\xad\xb9\xc1\xf8"
> +	"\x9b\x80\x31\xba\xb2\x42\xaa\x5b\x41\x68\x06\x40\x41\xe1\xaf\xf6"
> +	"\x3f\x73\x67\xdd\x83\x92\x6d\xb6\x4b\x21\xe1\x97\x7c\x62\x46\x36"
> +	"\xfd\x93\x8e\x26\x54\x20\x95\xb8\xdd\x35\xb8\x87\xe8\xd7\x01\x10"
> +	"\x89\x20\xaa\x0f\x0c\x5e\x3d\xd1\xc1\xc6\x98\x15\x38\xc5\x73\xe3"
> +	"\xbf\x08\x51\x83\x32\x56\x5d\x1a\xa9\x0c\x4f\x2f\x16\x51\x16\xc9"
> +	"\x2e\x39\x8c\x5c\xe8\x95\x22\xc1\x19\xf9\x8b\x38\x53\xc6\x55\x8a"
> +	"\x07\x13\xae\x00\xc3\xc2\xe0\x8b\x0c\xdd\xb8\xf3\xdd\xca\x21\x1f"
> +	"\xfe\xdb\x9b\x28\x8f\x9e\xd8\x96\x02\x6a\x2b\x35\x89\x6e\xcb\x65"
> +	"\xf3\xde\x3a\xa5\x3f\x38\xd9\x8f\xbf\xa2\xb9\xc3\x6b\xaa\x2a\x28"
> +	"\x7a\xc6\xe6\xa0\xfc\xe3\x37\xfa\x60\xf7\xdd\x4e\xcd\x5d\x64\xa8"
> +	"\x4b\xd2\x30\x40\x68\x92\x5f\xa3\x72\x9f\x4d\xd8\x71\xae\x2c\xd7"
> +	"\x59\x60\xd9\x14\x88\x93\x9d\xd7\x56\x1e\x6b\xa0\x46\x23\x69\x82"
> +	"\x95\xb2\xa0\x66\xe4\xc2\x7b\xee\x44\x51\x93\xb8\x4d\x8b\xa4\x24"
> +	"\x57\x94\xaf\xb6\x26\x02\x7b\x00\xd9\x84\xda\x51\xcc\xce\x4c\x63"
> +	"\x90\x98\xb3\x13\x2a\x85\xec\x77\x52\x69\x79\x9f\x37\xb8\xa3\xfb"
> +	"\x2b\x76\x39\x1a\x6a\x99\xd7\x0f\xa5\xc7\xa3\x55\xc3\x99\x59\x47"
> +	"\x2b\x36\x1e\xe9\xf0\x8d\x85\xb9\x0d\x26\x57\x50\xce\x0a\xf6\xdc"
> +	"\xb2\x60\x21\xe8\x76\xfd\x15\x7a\x9a\xe4\x7c\xd8\x17\x0e\x58\x6b"
> +	"\x86\xf6\x7f\xf0\x69\xf8\x1c\xc3\x6c\x5a\xf7\xe9\xd5\xf0\x5d\xfc"
> +	"\x50\x5a\x89\x7a\xad\xaa\xa5\x39\xe4\x08\x42\xf6\xc2\x23\x90\xf0"
> +	"\x66\x39\x8b\x27\xe3\x05\x21\x43\x21\xc9\xe6\xd6\x21\xa2\xda\x34"
> +	"\x5b\x34\x58\xe6\xef\x93\x02\x96\xa4\xa4\x86\x12\x12\xdd\x67\x10"
> +	"\xc4\x5e\xf3\xca\x79\xfd\x65\x29\xee\xe6\xb9\x1c\x0a\x20\x98\x74"
> +	"\xd6\xc4\x3f\x10\xe0\xee\x31\x53\x05\xa8\xb4\x2d\xa1\xde\x26\x30"
> +	"\x80\xc6\x13\x9d\xf0\x67\x51\xd1\xfb\x09\x22\x02\x2b\x51\x92\x3e"
> +	"\x36\x36\x6c\x5b\xcf\x00\xf9\xa4\xa0\x20\x06\x46\x87\x3b\xc5\x19"
> +	"\x8d\x43\x7b\x57\xd7\xe0\xa4\x2e\xe9\x6d\xe7\x64\x1a\x77\x1f\xf7"
> +	"\x99\x5b\xc8\x43\x39\x62\xbc\x1f\xff\xb4\x4a\x2a\x5c\x06\x3f\x04"
> +	"\xb0\xea\x22\x83\xa5\x50\xae\x4a\xf8\x90\xd0\x4a\x61\xe2\xba\x45"
> +	"\x0d\x7a\xba\xeb\xfe\xd1\x22\x61\x8b\xa2\x46\x9c\x74\x10\xd0\x66"
> +	"\x92\x7c\x01\x56\x3a\x30\xb9\xc3\x3e\x57\x1a\x0c\xdb\xa6\xc3\x64"
> +	"\xd5\xff\x06\xa3\x46\x33\x8a\x1a\x6d\x5d\x07\x0d\xbf\x88\xf2\x38"
> +	"\x41\xf9\x2d\xbc\xb2\x55\x6d\xa0\xf7\xc1\x9e\x64\x51\xf8\xb4\xea"
> +	"\x35\x8b\x11\x80\xe3\x6c\xa2\xb6\x3b\xed\xaa\xdd\xf3\x69\xfa\xa2"
> +	"\x53\x1f\x22\xa8\x28\x8f\x57\xe1\x41\xbf\xcc\xb3\x3d\x86\x47\x7a"
> +	"\xa3\xc1\xd4\xfe\x0e\xfa\x6b\x95\x4e\x1a\xbf\x33\x50\x9d\x2a\x7d"
> +	"\x28\x0a\x64\x4d\x26\xae\x17\x65\x65\xe8\x55\xd0\x63\xf4\x1d\x03"
> +	"\x5c\x9f\xe9\x1b\x25\x12\x7c\x06\x41\xc0\x90\xb9\x9c\x17\x02\xf8"
> +	"\x7a\xef\xe5\x63\x7d\x8b\x38\x7a\x3c\x85\xdc\xdf\xad\x47\x5e\xef"
> +	"\x0d\x96\x7d\xed\xf2\xc5\x00\x1a\xd2\x09\xef\x1e\xff\xc3\x8b\xd0"
> +	"\xbc\xb8\x36\x76\x13\x33\xbd\xda\xa0\x1e\x02\x6c\x44\x8a\xd8\x7c"
> +	"\x3e\x7d\xc9\x66\x5e\xf3\xbe\xb1\x72\x8e\xfc\xbc\xe5\x99\x30\x89"
> +	"\x88\x91\x34\x3f\x9d\x2f\xfe\xa5\x1e\xb1\xef\x82\x23\x62\x91\x25"
> +	"\x22\x0a\x8a\xdb\x39\xe4\x5b\xf8\x2a\x75\xb7\x38\xff\xef\xca\x45"
> +	"\x9a\x57\xfb\xb3\xfe\xfb\x6d\x8f\x2e\xb1\x62\x64\x6d\x39\x57\x8d"
> +	"\x95\xe7\x79\xdd\x98\x3e\x68\xaa\x12\x50\x7b\x0e\xa2\x2b\x89\x52"
> +	"\x9f\xca\xd5\xc1\x22\xc2\x6f\x54\x83\xbd\xd7\x2c\xbb\xba\x50\xda"
> +	"\xad\x42\x93\xe7\x86\x9d\x60\xf5\x33\x1b\x7f\xaa\x75\x65\xbd\xa8"
> +	"\x34\x15\x6d\x1c\xf7\x47\x1f\x94\xdc\xab\xa8\x14\x93\x69\xdd\x2c"
> +	"\x3b\xf9\x21\x11\x36\x80\x63\xec\xc9\x8e\x78\x48\xb4\x31\xac\xa0"
> +	"\x48\x00\x3e\xed\x6f\xb3\xb0\x15\xc9\x24\x72\x24\x5b\x51\x7c\x65"
> +	"\xbb\x24\xb6\xb1\x53\xfd\x3f\x36\x7a\x6c\xbf\xec\x90\xcc\xd9\x01"
> +	"\x03\x30\x9e\xe3\x4a\x97\xcc\x3a\x35\xc6\x4a\x2b\xd3\x18\xbc\xb1"
> +	"\x1f\x64\x08\xa0\xf8\x84\x34\x36\x3a\x91\x1a\x28\x72\x98\xdd\x1a"
> +	"\xbe\xb1\x32\x77\x95\x72\x7e\xc5\xc1\xd7\x3b\xf8\x1e\x55\xc2\xdd"
> +	"\xed\x24\xdb\x1b\x9b\x0e\xd1\x07\x01\x85\x41\x90\x3c\x90\x6a\xf2"
> +	"\x0a\x8b\x4b\x7e\x9e\x87\xed\xa8\xa8\x8c\x5a\x4c\x4d\xc3\xb5\xec"
> +	"\x7a\x4d\xe1\x51\xf0\x00\x64\xb9\xc3\x6e\x61\x2a\x41\xd5\x2e\x0e"
> +	"\xf1\x1e\x87\xe5\xd5\xe4\xcc\x1a\x36\x7e\x5d\x96\x02\x14\xce\xaf"
> +	"\xa2\xbb\x61\x05\xf4\x2e\x64\xba\x17\xff\x18\xc8\xe1\x17\x8a\x02"
> +	"\x6b\x22\xe5\xd4\xd0\x68\xf6\x9c\x10\xf0\x2d\x4f\x82\xb3\x21\xb4"
> +	"\xaa\x7f\xff\x6b\x7e\x9a\xf2\x12\x44\x4a\xa5\xbb\x16\xb6\x56\x6e"
> +	"\xb1\x20\xb4\xb0\x34\x8f\xe4\x94\xb2\xf6\x7f\x9f\x05\xd0\x42\x30"
> +	"\x04\xdb\x11\xb8\xd7\x5a\x1b\xb6\x06\xed\x6e\x9c\x69\x6d\x2c\x0f"
> +	"\x6f\x7f\xf3\x9c\x76\x2e\xad\xc2\xd6\xc6\xfd\x93\xc1\xee\x25\xbb"
> +	"\xc8\xc6\xb5\xd1\x37\x65\xdd\xe5\x78\xb0\x89\x0a\x91\x4a\xe1\x17"
> +	"\x61\x43\x18\x47\xf3\xc2\x2a\x22\xc2\x56\x4e\x01\x31\xa3\x0b\xc7"
> +	"\xe6\x53\x27\xa8\xc8\x32\x25\x69\x7c\x8b\x8e\xb1\x2b\xc6\xc9\x85"
> +	"\x05\x1d\x67\x1e\xc6\x10\xa3\x60\x46\xbf\x9d\x5b\x3f\xda\x1f\xd3"
> +	"\x8b\x1a\x95\x88\xa2\x16\xb0\xdd\x7f\x46\x2f\x5f\xef\xa0\x17\x0e"
> +	"\x5e\x19\x20\x8c\xeb\x97\x52\xc8\xe0\xdc\xc0\x40\x0a\xd1\x84\xc1"
> +	"\xa6\xb2\xf4\x6c\xc7\x8d\xc9\xd4\xb8\xc3\xe3\xe5\xf9\x8a\xc5\xdb"
> +	"\x04\x2a\x89\xa5\x92\x64\x3f\x91\xd0\x60\x97\x8a\x42\x2d\x4b\x2c"
> +	"\xf8\xa7\xe2\x68\xf9\xd3\x94\x1c\x24\xe8\x80\xff\x05\xa7\x02\xab"
> +	"\x66\xd7\xb9\xa3\xeb\xd5\x0f\xf7\x26\x4f\x8f\x6b\x5a\xb2\x7c\xda"
> +	"\x1a\xb3\x83\x5f\xbc\xcc\xfc\x50\xc8\x24\x8c\x38\x9d\x80\x79\x50"
> +	"\x9d\x84\xe8\xee\x85\x19\xf3\x73\x5a\xd2\x41\x92\xde\x87\x5f\x52"
> +	"\x62\x91\xbe\x90\x1e\xce\x54\x13\x68\x35\x3e\x2b\xe5\xa2\x1e\xc0"
> +	"\xc1\x2f\x9c\x52\xd9\xe1\x5c\xe4\xfd\x21\xa3\x5a\x51\xb3\x01\x9d"
> +	"\x22\x2c\x6c\xa8\xb9\xda\xfb\x78\xa8\x24\x1f\xef\xe9\x1c\x38\x04"
> +	"\xf5\x8b\x80\xca\xe6\xb9\x76\x27\x31\xe1\x24\xf0\x07\xf9\xa9\x11"
> +	"\x77\x9a\x8a\xc1\x87\x21\x49\x1b\x6e\x94\x94\x4e\xe7\x3a\x10\x00"
> +	"\xd1\xd7\x02\xbf\x53\xe7\x88\x4e\xab\x63\x35\x61\x39\x81\x45\x21"
> +	"\x85\x35\x4b\x44\xca\xc0\xdb\x8f\xa3\x6a\xc7\x90\x12\x7a\xd5\x94"
> +	"\xd7\xfe\x30\xb2\x0f\x51\x52\xd0\xe6\xa7\xbe\x52\x2d\x45\xba\xed"
> +	"\xbc\x3c\x95\x35\x50\x3f\x83\x97\xa8\x8f\x7e\xfb\x2e\xa3\x5b\xe1"
> +	"\x2c\xb9\x15\x79\x62\x28\x8f\x02\x47\x31\x63\x2f\x45\xa7\xa7\x21"
> +	"\xa4\x26\x17\x2f\x46\x72\x22\x44\xed\x3a\xff\x0a\x80\x27\xb7\xaa"
> +	"\xa3\x9e\xe3\xb7\x71\xd2\xd9\x98\xa2\x6a\x5b\x18\x70\x6b\xfa\xf3"
> +	"\x9f\xcd\xa9\x4c\xca\x97\x76\x41\x98\xb2\x8b\x98\x23\x88\xe7\x1e"
> +	"\xa3\xd3\x56\x9a\x48\xf1\xd8\xf5\xd5\xf5\xd2\xff\x60\x52\x82\xeb"
> +	"\xe8\x92\x5c\x36\xfc\x32\xfe\x46\x2d\x9a\xbd\xb8\xc2\x37\x63\xee"
> +	"\xbe\x69\x4c\x98\x3d\x3d\xa3\x76\xe7\xbe\x8b\xb9\xe2\x07\x4b\x9a"
> +	"\x55\x44\x71\x6e\x7d\x7f\xb0\x31\x55\xb8\x74\x82\x9c\x47\xf9\xdc"
> +	"\x9a\x21\xd3\xbb\x47\x22\x05\x3b\x4b\x00\x31\xe1\x7f\x9d\xcf\xd1"
> +	"\xde\xeb\xd6\x2a\xd9\x0b\xa8\x34\x03\xc3\x66\x34\x1f\xcb\xe8\xd8"
> +	"\xf2\xf9\x4a\x3f\x6e\x8e\x3f\x8b\xce\xef\x9d\xe9\xf9\x92\x33\x7d"
> +	"\x8a\x61\x2f\x5c\xaf\x5d\x4c\x66\x30\x37\x09\x3f\xd0\x5e\xe6\x43"
> +	"\xef\x03\x63\x63\xc5\x39\x2b\xa8\x09\x5a\x86\x78\x5c\xa0\xa0\x5c"
> +	"\xa1\xba\xb7\xbc\xdb\xd7\x70\x60\x81\x20\x19\x72\x82\x85\xed\x96"
> +	"\x58\xa9\xdb\xa2\xcc\x03\xfc\x00\x92\x46\x3c\x79\x30\xce\xe0\x8f"
> +	"\xa0\x91\xd5\x16\xcc\x46\xce\xf2\x4a\x62\xaa\x1d\x80\x2f\xf5\x45"
> +	"\x7b\x9e\x97\xd7\x94\x39\x73\x6d\x5a\x25\xe4\x46\xb9\x6c\x58\xcc"
> +	"\xa7\xc9\x9b\x81\x9a\x98\x05\x0b\x82\xb4\xb1\xc5\x08\x71\x15\x1f"
> +	"\x26\x86\x26\x7b\xa8\x47\xaf\x80\x42\x2d\xd1\x68\x07\xb6\xa3\x81"
> +	"\xc5\x40\x6e\xf7\xf6\x66\x81\x2d\x1e\x65\x01\xae\x2c\xaa\x59\x7c"
> +	"\x90\xa4\xfd\x34\x04\x73\x3a\x40\x1a\x2b\x9f\x35\x4b\x25\x17\x8f"
> +	"\xe5\xe6\x99\x0f\x1e\x23\xed\x95\xfe\xf6\xa3\x90\xd3\xca\xd4\x22"
> +	"\xb4\x8b\x66\xac\xe9\xf3\xaf\xc8\x1b\xaa\x9f\x92\xc0\x19\x3c\x01"
> +	"\x66\xc6\x07\xed\x82\xbe\x60\x08\x6a\x94\xfc\x79\xfa\x3c\xb5\x24"
> +	"\xb1\xc8\x7f\xf3\x53\x20\x90\x1f\x07\x06\xd4\xf6\x7f\xeb\xcb\x96"
> +	"\x5f\xd8\x2b\xd2\x7e\x44\xaa\x62\x75\x43\xfa\xc9\xfa\x27\x78\xe7"
> +	"\xe7\x61\xc2\xc2\xd2\x87\x24\x75\xab\x22\x4d\xc4\xbe\xa2\x9e\xe6"
> +	"\x2e\xc3\xee\xd3\x37\x69\x02\x50\x13\xcb\xa3\x65\xf2\xdd\xed\xbc"
> +	"\x15\x68\x20\x50\x6d\xe4\x8a\x8b\x9f\x45\x39\xc5\xe4\xf1\x74\x7a"
> +	"\xf5\x0f\xa5\x94\x5a\x5a\x3c\x0c\xd0\xb1\x5e\x27\xd5\x8a\x98\x15"
> +	"\x24\x65\x24\x15\xcb\x7e\xee\x62\x0b\xbd\xf4\xb0\x32\x31\xb3\xc3"
> +	"\x21\x58\xe5\x7a\x69\x0e\x28\x9e\x00\x75\x71\x47\x81\x52\x9f\x6d"
> +	"\xc8\x80\x19\x1d\xaf\x76\x9f\x3a\x11\xa0\x6d\xe8\x43\xba\x73\xef"
> +	"\x85\x61\x09\x7a\xe2\x82\x44\xaa\xf2\x3a\x56\x08\x46\x04\x7e\x65"
> +	"\x83\xcf\xbc\xaa\x8a\xa3\xb4\xf8\x44\xb0\x43\x0e\xcd\x25\x40\x0b"
> +	"\xd7\x7c\x8c\xf9\xae\x42\xc9\xea\x2e\x3e\x83\x6a\xd8\xd4\x44\x23"
> +	"\x14\x33\x27\x00\x49\xdb\x61\xb5\x51\x52\xe4\x54\xbe\x05\xc9\xd6"
> +	"\xe3\xc2\x1a\x07\xf3\xbf\xd3\xb1\x1d\xb4\x88\xda\x62\x09\xb8\x94"
> +	"\x2a\xcc\x24\x22\x46\xe9\x6f\x99\x6d\xbf\x24\xa3\x9a\xc3\x3f\x42"
> +	"\x88\x5f\x36\x45\x68\xce\x95\xb3\xe5\x7f\x9c\xe3\xd6\xe5\xb9\xd5"
> +	"\x40\x36\xb8\x36\xc8\x88\x9a\xf7\xcf\xe0\x76\x56\xb3\x9a\x0d\x68"
> +	"\xc0\x60\x94\x9e\xdb\x14\x81\x95\xb3\xdd\xe5\xeb\xf2\x14\x18\x56"
> +	"\x74\x7b\x81\x9d\xb1\xd2\xed\xef\xf1\xf8\xfc\x41\x4c\x66\x77\xbd"
> +	"\xc9\x16\x32\x3f\x8f\x9a\xa7\xc2\xe1\x1c\x1f\x44\x48\x54\xd3\xe0"
> +	"\x00\x00\x00\x00\x00\x00\x00\x00\x04\x0c\x1a\x20\x28\x2f"
> +};
> +
> +static const u8 nist_mldsa_fips204_35_data[] __initconst = {
> +	"\x88\x45\xad\x39\x4b\xce\x60\xb2\x84\x76\xb2\x13\x99\xb0\xd4\x72"
> +	"\x6b\xb3\xfe\x5f\x4d\x43\xde\x87\x62\xa4\xce\x19\x1b\xba\x7c\x13"
> +	"\xb5\x2e\x1e\xc9\x59\x02\x99\x0b\x89\x7b\xe9\xe9\x6a\x9a\x25\x8f"
> +	"\xdb\xd4\x6b\xaa\xe2\x2a\x3d\xa7\x0e\x07\x3b\xe5\xda\xea\x2d\x6e"
> +	"\x60\x1c\xad\xbe\x3f\xb0\x47\xd7\x5e\xe0\x8a\x8a\xeb\xec\x8e\x9e"
> +	"\x89\xa8\x03\x49\x29\xdd\x30\x63\xed\x5d\x79\xa1\xd9\xf7\xec\x13"
> +	"\x06\xd5\xd6\xf9\x38\xae\x37\xdf\x1d\x95\x87\x12\x8d\x2a\x05\x88"
> +	"\xa8\x15\xdc\xc6\xfe\x33\x44\x36\x16\xe6\x6c\x76\x8f\x65\x6c\xe6"
> +	"\xf3\x18\xb5\xf1\x74\x37\xb3\x66\x6f\x01\x7c\x6d\x14\x47\x4a\x59"
> +	"\xd4\x09\x06\x46\xde\xe0\x2b\xbc\xc6\x4a\x31\xec\x14\xa6\xe0\x9a"
> +	"\x03\x9c\x5a\xd8\x84\xda\x91\xaf\x5b\xba\xa7\x2a\xef\x0a\x81\x47"
> +	"\xd3\x81\x1d\x70\xff\x70\x82\x4d\xf0\x3a\xcb\x06\xe7\x0e\x20\x16"
> +	"\x2b\x6c\x78\x95\x8e\x1d\xdb\xf2\x79\x06\xb6\x60\x2e\x1c\xf6\x92"
> +	"\x50\x18\xfb\x35\xbd\x0c\x07\x7b\x31\xe9\xf5\x5f\xcc\x0b\xb6\x12"
> +	"\x1b\xd5\x46\xe6\x9d\xd2\x5f\xce\xb6\xdb\x7c\x07\xeb\xb4\x37\xe6"
> +	"\x9a\x98\x11\x9d\x21\x3c\xec\x71\x53\x15\x68\xee\xec\x91\xcd\xf6"
> +	"\x0d\xa2\x14\x65\x02\x90\x2b\x62\xb5\x1c\x71\xa9\x7e\x5a\x90\x99"
> +	"\xd7\xe1\xf1\x9a\x01\xc3\xb4\x2f\x3b\x48\x77\xc8\x34\x15\xea\x28"
> +	"\x85\xfb\x61\x7c\x4d\x0e\xc8\x8b\x32\x12\x60\xd5\x6b\x27\xba\xca"
> +	"\xdd\x9c\x04\xd7\xba\x52\xf1\x6f\x1e\x62\x74\xca\x1c\x5d\x75\x16"
> +	"\xf1\xdd\xd1\x38\x25\x6e\x36\xdb\xb8\xab\xec\xf3\x33\xd2\x91\xaf"
> +	"\x13\x94\x26\xaa\x2b\xdc\x05\x57\x33\x87\xea\x84\xea\x81\x37\x1f"
> +	"\x06\x94\xa8\xfd\xd7\xce\x5e\x03\x46\x2f\xb3\xbf\xa9\x25\xf6\x09"
> +	"\xe6\x5f\x4c\x54\x7d\x7b\xaa\x99\xda\xa9\x07\x84\x72\x7d\x0b\x6c"
> +	"\x6b\x96\x18\x2a\xdb\x78\x0f\x5f\xe8\xa3\x25\xd6\x76\xe0\x00\x3b"
> +	"\x0b\x5c\x02\xf6\xee\xa3\xb5\x1e\xbe\x83\x76\xe7\x2e\x47\xa7\x6c"
> +	"\x05\x2a\xa0\xaa\x60\x02\x65\xe9\x55\x3a\xf7\x33\x9a\x69\x1d\x50"
> +	"\x91\x35\xcb\x19\xea\x11\x97\x0c\x40\x79\x2c\x41\x61\x64\x9a\xdf"
> +	"\xd6\xbf\x40\x94\x31\x92\x71\xd6\x76\xec\x07\x85\xaf\xf5\x98\xeb"
> +	"\xc5\xd7\x4c\xc8\x26\x7e\x2c\x45\xbf\xd2\x3c\xd1\xd9\xdc\xd5\x5d"
> +	"\xc0\xa7\x29\x32\x55\xe3\x28\xdd\xfe\xf2\x97\x16\x57\x56\xde\x7c"
> +	"\x4b\x06\x1d\x37\xc1\x5a\x87\xff\xf2\x95\x77\x5a\x6f\x6f\xc9\x0d"
> +	"\x02\x5f\xdc\x8e\x72\xe3\xf1\xe2\x0e\x0d\x23\xae\x7d\x1e\xdb\x36"
> +	"\x2c\xab\x41\xa2\xe9\xd8\xbc\x9c\x35\x9b\x16\x47\xc5\x37\xeb\x21"
> +	"\xa0\x15\x34\x32\x8d\x0a\x28\x8c\xa8\x07\x0f\x7e\xf7\xbc\x9b\x08"
> +	"\xdc\x3d\x91\x5a\x90\x69\x23\x37\x91\x6a\x98\x9b\x70\x9a\xea\x1d"
> +	"\x8c\x1a\x6a\x19\x27\xb7\x74\xbd\x06\xd1\x0c\x0d\x0f\x4e\x06\xce"
> +	"\x37\x86\xe1\xb0\x55\x77\x3b\x0b\x2f\x5c\xea\x01\xc8\x2f\x5e\xb5"
> +	"\x14\x1e\xcc\xfe\x8a\xd3\x8f\xbe\xed\xe6\xd1\xcc\x74\x52\x93\x7c"
> +	"\x6c\x60\xcb\xcf\x4f\xfe\x3c\x58\x18\xf5\xed\xb7\x75\x61\xa3\xd8"
> +	"\x9e\x81\x5f\xa2\xca\x73\x2e\x02\x55\x31\xae\x91\xcf\x53\x00\x1c"
> +	"\x13\x60\x63\x6b\x07\xfc\x36\x74\xc0\x96\x71\xb9\xd6\xe5\xef\x9c"
> +	"\x77\xa1\x1f\x75\x6f\xa6\xdc\xd0\xcc\xd3\xcb\x86\x72\xfd\xee\x89"
> +	"\xae\xc4\x9c\x65\xfd\x1b\x7a\xbd\xf6\xcf\x49\xa6\x43\xfb\xd6\x21"
> +	"\xb8\x21\x8e\xbe\xdc\xaf\xe0\xb0\xc6\x61\x87\x82\xba\x2d\x43\x0a"
> +	"\x3d\xb4\xb5\xac\x07\xa8\xbd\x06\x60\xfc\x24\x50\x56\xa2\x31\x54"
> +	"\x55\x86\xb4\xb6\x07\x2c\x3d\x63\x70\xa4\x0e\xbb\x22\xda\xba\x1b"
> +	"\x1f\x9f\x49\x75\x50\x2b\xa7\x6c\xd7\x95\xeb\x1a\x13\x51\x54\xd4"
> +	"\x1d\xaa\x5d\x74\x49\x63\xaa\x86\x29\x05\xd8\xaf\x15\x94\x9c\x4b"
> +	"\x17\x37\xa2\xab\x77\x4f\xfe\xb2\xfb\xfd\x19\xb1\xb2\x67\x68\x49"
> +	"\x53\x23\x50\xbe\x26\xd1\x53\xc1\x4b\xc0\xc4\x4e\xde\xa2\x6a\xf0"
> +	"\x47\x9e\x82\x7b\x9a\xa8\xf7\x6d\x68\x83\x46\x9c\x25\xf5\x47\xed"
> +	"\x53\xb6\x52\x7f\x85\xe3\xe9\x99\xb3\x3d\x53\x6e\xbc\x67\x36\x41"
> +	"\x9a\x3e\xa7\xfa\x55\xbc\xff\xa6\xa2\xd5\xa2\x10\x6b\x07\xff\x9f"
> +	"\x2f\x80\xb5\x14\xe4\x04\x2e\xee\x98\xd7\x38\x9a\x4e\x9a\x43\x0b"
> +	"\x93\xb2\xa3\x24\x94\x76\x6e\x09\xca\x37\x83\xb4\xd2\x81\x71\xec"
> +	"\xd7\xa2\x09\xff\x72\xc9\xf4\x3e\x62\x3b\x70\xc3\xc5\xc9\xdd\x26"
> +	"\x8a\x75\x91\xdc\xf3\xd6\x41\x38\x80\x28\xdd\xd9\x42\x91\x2a\x08"
> +	"\x9a\xfe\x64\x2b\xc0\xcd\x80\x25\x8f\x97\xfa\xd6\xae\xee\x31\xa8"
> +	"\x10\xc6\x45\xfc\x89\x0c\xea\x3b\xce\xc9\xcc\xf2\xef\x83\xd5\x5c"
> +	"\x12\x1e\xb2\xf7\x72\xed\xec\xcf\x71\x1b\xe8\xdd\x12\x0f\x02\x4c"
> +	"\x1b\xcd\x5c\x17\xee\x3c\x26\x4d\xf5\xd6\x19\xad\x9c\xf2\x41\x77"
> +	"\x75\x0c\xe6\xb0\x3b\x4c\x75\x6d\xde\x34\x39\xb0\x59\xdf\x11\xe7"
> +	"\x77\x69\xe5\x30\xfb\x4a\x69\xf8\xcf\xee\x44\xe7\x5a\xca\x04\xab"
> +	"\xcc\x42\xbd\x23\xf7\x79\xb6\x00\xfd\x57\x62\x57\x34\xf6\x3b\x39"
> +	"\xbd\x74\x77\xa1\x9d\x0d\xb9\x32\x30\xdd\x29\xf2\x4d\x72\xc5\x40"
> +	"\x8c\x6d\xa6\x94\x19\xcf\x5b\xee\x0a\x82\x3e\xb5\x7d\x99\xd5\xf9"
> +	"\xe0\x91\x5a\x1f\x0b\x90\x18\x73\xd6\xd7\xf2\x53\x68\xc1\x83\x3b"
> +	"\x0c\xdf\xf1\x0a\xef\x1b\xcb\x17\x94\x83\x31\xb6\x81\x90\x0a\x23"
> +	"\x30\x92\xb3\xd0\xae\xd2\x20\x7d\x78\x96\xb0\xe5\xe6\xef\x72\x3b"
> +	"\x38\xbf\x45\x87\xbd\x06\x8b\x93\x62\x08\xf1\x2b\x0e\x91\x09\x87"
> +	"\xbd\xd9\x42\xda\xfd\xbc\xfa\x52\x66\xae\x10\x7a\xaf\x2d\x1f\x85"
> +	"\xae\x3f\x47\x8a\x17\xc7\xfc\x73\x6c\xb0\x8c\xa8\x24\x87\x2c\x88"
> +	"\x11\x5f\x13\x06\x75\x20\x7b\x80\x4a\x5d\x4e\xba\x79\xf7\x44\xee"
> +	"\xb1\x16\xb2\x3a\x19\x1a\xe6\xd0\xe0\xb8\xfb\x78\x3c\x44\xaf\xb5"
> +	"\x69\x8a\x72\xf3\x1c\xd1\x9c\x61\x7a\x61\xa5\xfe\x98\xdd\x2c\x67"
> +	"\x29\xc8\xed\xd4\x3c\x95\x13\x83\x53\x30\xd7\x12\x82\xf5\xe1\xef"
> +	"\x5c\xe6\x97\xa6\x5f\x6d\xb7\x9e\xeb\xef\xd0\x2d\x9e\x3a\x00\xb8"
> +	"\xcb\x7d\x6d\x1d\x34\x0c\x9c\x00\x30\xd1\x61\xd4\x70\x87\x50\x4b"
> +	"\x8e\x43\x39\x98\x95\xf7\xe4\x96\xe6\x21\xe0\xd9\x96\x44\x54\xb5"
> +	"\x04\x47\x9a\xd3\x40\x6f\x33\x95\x7f\x2c\x9e\x43\x04\x9d\xc0\xcc"
> +	"\xc8\x67\x71\xf2\xf0\x05\x00\x65\x50\xad\x8d\x68\xa1\x1c\x2d\xcf"
> +	"\x15\x65\x72\x30\x53\x19\xb2\xff\x36\x29\x9e\x95\x5d\x35\x44\x73"
> +	"\x8a\x82\xf5\xc4\x13\x69\x1b\x76\x78\xee\xec\xf2\x6f\x6a\xbf\x1d"
> +	"\xc2\xfb\x79\x48\x11\x4b\x4e\xbd\x2b\x84\x5c\x0b\x7b\x78\x54\x3d"
> +	"\xa0\xfc\xd2\x61\x39\xf0\xca\x8e\xae\x83\x7b\xa2\xd7\xde\x84\x93"
> +	"\x34\x19\x0e\xb1\x72\xe5\x70\x5c\xe3\x2f\xb4\xdd\xf8\xc9\xfa\xf4"
> +	"\x90\xc3\xd1\xf3\xfd\xf4\x37\xd1\xad\xeb\x2e\x82\xa7\x31\xec\xdf"
> +	"\x62\x54\xd4\x75\x6d\xe4\x00\x71\xef\xd0\x55\x71\xc1\x77\x79\xdc"
> +	"\x06\x23\xd4\xc3\xbd\xe6\xe8\x09\x8f\x7c\x96\x73\x57\x60\x2d\x38"
> +	"\xa0\x75\x55\x71\xa6\x00\x18\x65\x87\x8e\xd9\xe5\xfd\xc6\x4d\x43"
> +	"\x5e\x85\xe2\xd5\x6a\x8c\x55\xb7\xc6\x7a\x75\x86\x4a\x88\x00\xc9"
> +	"\xb6\x53\x37\x0e\xbb\xd8\x62\xe8\xf9\x3f\x50\x12\x9e\xae\x84\x04"
> +	"\x02\xe0\xfb\x58\x29\xe4\x8b\xd7\x83\x10\x4a\x08\xe8\x12\xa4\xd8"
> +	"\xa1\x77\x94\x82\xcb\x4f\x24\x5a\xdd\x0c\xb9\xf6\x64\xd8\xc7\x11"
> +	"\x83\x5e\x98\xee\x60\xa2\x41\x4b\xd5\x02\x5e\xdf\x32\x40\xf4\xb3"
> +	"\x35\xb5\xeb\x65\xbf\x08\x63\x9b\xcf\x5b\xfa\x6b\x2f\x61\xda\xe1"
> +	"\xef\x7d"
> +};
> +
> +static const u8 nist_mldsa_fips204_35_sig[] __initconst = {
> +	"\x30\x82\x0d\x61\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x07\x02\xa0"
> +	"\x82\x0d\x52\x30\x82\x0d\x4e\x02\x01\x01\x31\x0d\x30\x0b\x06\x09"
> +	"\x60\x86\x48\x01\x65\x03\x04\x02\x03\x30\x0b\x06\x09\x2a\x86\x48"
> +	"\x86\xf7\x0d\x01\x07\x01\x31\x82\x0d\x2b\x30\x82\x0d\x27\x02\x01"
> +	"\x01\x30\x17\x30\x0f\x31\x0d\x30\x0b\x06\x03\x55\x04\x03\x0c\x04"
> +	"\x46\x72\x65\x64\x02\x04\x01\x23\x40\x23\x30\x0b\x06\x09\x60\x86"
> +	"\x48\x01\x65\x03\x04\x02\x03\x30\x0b\x06\x09\x60\x86\x48\x01\x65"
> +	"\x03\x04\x03\x12\x04\x82\x0c\xed\x6e\x8c\x4b\x20\x61\xc2\xcd\xf2"
> +	"\x71\x54\xbf\x70\x85\xf6\x3c\xb1\x5d\xa3\xce\xc8\x2d\x52\xca\xd1"
> +	"\xa6\x50\x80\x68\x75\x05\x25\x24\xda\xa1\xef\xdf\xf4\x6f\xde\x5e"
> +	"\xff\x63\xef\xf5\x70\x74\x7c\x69\xfd\x23\x4b\xa3\xaa\x3b\xa9\xa8"
> +	"\x0f\x48\x8b\xc4\x8f\x95\x9f\xf5\x6a\xb3\x17\x35\x5f\xfe\x91\x7b"
> +	"\xdd\xd3\xbb\xf7\x3b\xf0\xa8\x22\x09\xbe\x25\x48\xcd\xca\x1a\x37"
> +	"\xc4\xde\x57\x18\x56\x30\x19\xa9\x26\x99\x13\x9a\x6d\x6a\x69\xe9"
> +	"\x64\x83\x2d\xdd\x70\xf5\xe8\x03\x75\xdc\x9f\xe0\xba\x8e\x22\xae"
> +	"\x3a\xd8\xaa\xd9\x45\x84\x71\xcd\x37\x61\xb1\xb9\x04\xe8\xbb\xba"
> +	"\x72\xfa\x8a\x07\x1d\xf1\x82\x55\x17\xff\xa2\x2e\x2b\xbf\xf9\x9a"
> +	"\x0f\x86\x94\x06\xd9\x07\xdb\xc3\x16\x92\x90\xce\xd1\x4e\xb8\xee"
> +	"\x7a\x2b\x6c\xe7\xc2\x6a\x0a\xe2\x8b\x32\x5e\xd4\x61\x38\x90\xaf"
> +	"\xce\xbb\x38\xe6\xe9\xd5\x43\x74\xc9\xeb\x48\xd0\xe6\x00\x30\xa1"
> +	"\x1e\x75\x03\xb9\x06\xe9\x16\x35\x7c\x6f\x81\xd5\x9f\x89\xcc\x36"
> +	"\x33\x75\xcb\xf0\x1e\xd0\xd8\x51\x54\xd5\x5c\xb8\xfc\xe7\xb2\x17"
> +	"\xd5\xed\xeb\xe9\x36\x85\xe0\xbe\x43\x4c\xb0\xc5\x67\xc8\x97\x62"
> +	"\xb3\x80\x89\xec\x2c\xf3\x4c\x93\x87\x9c\x0b\x23\x5d\x44\x25\x6a"
> +	"\x10\x3f\x21\x08\x7d\x8d\xfc\x99\x8d\xc5\xbe\xbe\x57\x5c\x5d\x4d"
> +	"\x27\x7b\xa2\x2e\x81\xcd\x0a\xf1\x49\x2b\x43\xda\xc4\x36\x5c\xc6"
> +	"\x91\x75\xd8\x95\xa6\x9b\xbf\xe9\x21\x45\x3c\x07\xae\x56\xcd\xf5"
> +	"\x1b\x91\x56\xe4\x49\x40\x12\x58\x8a\xa4\xac\x32\x53\x93\xbe\xe9"
> +	"\x8a\x65\xef\x71\xe3\x07\xc8\x4d\xb9\x35\x85\x4d\x06\x9b\xa4\x11"
> +	"\x6a\x67\x7a\x5b\x49\xee\xea\xf2\x0d\x16\x49\x2b\x74\x46\x78\xcc"
> +	"\x59\x12\x0c\x80\x6f\xae\x7d\x23\x30\x87\x7f\x16\x52\x04\x11\x41"
> +	"\x0b\xba\x48\xbf\x49\xaa\x08\xf4\x44\x00\x75\x4a\x05\x79\x79\x66"
> +	"\x31\x94\x44\x9e\x66\xf5\xc0\xd7\xa1\xeb\xb5\xda\xc4\xb6\x5c\xf9"
> +	"\x20\x0b\x21\x89\xf6\x0f\xa5\x29\x48\xcb\x7a\x83\xd5\xfd\x54\x45"
> +	"\xaf\xa3\x0d\x99\xe9\x14\x30\x06\x8a\x53\x51\x08\x0d\xa4\x24\xa6"
> +	"\xf4\xae\x5f\x8e\x1b\x7b\xa6\x48\x1c\xfb\x39\xfc\x34\x2a\xcf\xa0"
> +	"\x84\xb3\x79\xb7\xc7\x4d\x64\x0e\x0c\x04\x87\x31\x9f\xf6\x97\x02"
> +	"\x8b\xe8\xc2\x13\x21\x8e\xfc\x85\x7c\xac\xfa\xc4\x44\x10\x3f\x2f"
> +	"\x93\x02\x74\x44\x1f\x18\xdc\x2e\x17\xca\x18\x27\x86\x55\xfb\xc0"
> +	"\x79\x4b\x50\x08\x33\x62\x4c\x58\x29\x20\x98\x95\x9f\x8c\x7a\xf7"
> +	"\x82\xe1\x41\x43\xf3\x5c\x55\x54\xe3\x22\x60\xf2\xa4\x85\x17\x88"
> +	"\x93\x6b\x6d\xc7\x48\xf6\xc0\x0b\x4b\xf0\x86\xc6\x64\xae\xd9\x22"
> +	"\x08\x75\x35\xce\xf4\x7b\xad\xf2\xb6\x7d\x50\x6e\xba\xf6\x46\x30"
> +	"\x7b\xbc\x60\xc3\xf7\xf7\xeb\x39\x44\x6a\x34\xde\xb4\x6f\x43\x3f"
> +	"\xfb\xcb\x23\x60\xfb\x55\x57\xaa\x9a\x2e\x33\x29\x37\xd7\x9a\xb6"
> +	"\x85\xa2\xad\x9b\x25\x42\x38\x83\x44\x85\x0e\xec\x19\x74\xa3\xdc"
> +	"\x73\x4b\x30\xb9\x6b\x05\x63\xcd\xdb\xa3\x18\xed\xfd\xc2\x94\x1b"
> +	"\xdf\x1f\x64\x6c\xd6\x29\x05\x58\xe0\x77\xb9\x1b\xd5\x40\xe6\xff"
> +	"\x3b\x7e\x13\x2b\xef\xed\x35\x8e\x06\x69\x13\x8f\xe4\x93\x59\x34"
> +	"\x54\x50\x16\x3c\xbb\x5b\xe2\xa4\x7a\xd5\x35\x60\x3a\x13\x8e\x7c"
> +	"\x37\xf6\xb8\xfd\x1f\xa1\x1d\xd4\x25\x19\x54\xba\xe7\x8e\x7c\x59"
> +	"\x40\xc3\x7a\xf2\x2c\x94\x78\xca\x02\x0a\x1d\x21\x4f\x97\x57\xbc"
> +	"\x06\x36\x23\xce\x8d\xce\xdd\x39\x5d\x6b\x7b\xc1\xa8\x06\x90\x4e"
> +	"\xbf\xaf\x28\xf0\xf8\xc5\xa6\x3a\x0c\x1c\xc6\x31\x4f\xe8\x05\x79"
> +	"\x1d\x76\x57\x05\xf5\xfa\x33\x17\x1a\xb4\xc8\x51\xc2\x6e\x42\xc0"
> +	"\xf9\xdc\xcf\x9c\x28\x37\xc1\x11\x42\x1d\x0f\x5f\xdc\xf9\xa9\xeb"
> +	"\xa0\x9c\x25\xdb\x0d\x79\x65\xdc\x91\xdc\x4e\x63\x84\x1a\x76\xae"
> +	"\x9a\x68\x7a\xd8\xb6\xe4\x90\x68\xcf\x74\xfa\xaf\xd8\xa6\x6c\x91"
> +	"\x39\xd3\xc3\xa6\xbe\x06\x56\x3c\xb5\x7f\xe7\x73\x30\x14\x79\x57"
> +	"\x4c\x68\xeb\x32\x94\xe3\x35\xf9\xf1\xbb\x7c\xfd\xf5\x0e\xa1\x13"
> +	"\x92\xf0\x4f\x5f\x3b\xe9\x9c\xb2\x4b\x07\xa8\x91\x17\x34\x02\xef"
> +	"\x38\xf7\x44\xdd\xf9\x27\xf0\x60\x1f\x70\xba\x50\xf8\xab\x84\x5f"
> +	"\xf2\xa0\x12\x40\x1a\x99\xcf\x4f\x03\x36\x4c\x30\x82\xd4\x21\x81"
> +	"\x91\x9e\x87\xd4\xac\x3b\x3b\xe1\xf9\x5a\xb6\x90\xfc\xda\x10\x6c"
> +	"\x87\xc6\x3c\x7b\xed\xf1\x29\x08\xd6\xa0\xee\xc3\xb6\x72\x46\x1b"
> +	"\xb1\x38\xec\xfd\x48\x01\x9a\x07\x7e\xf4\xe5\x90\x94\x8a\xbd\x08"
> +	"\x3e\x28\xef\x4d\x06\x2f\x8e\x58\x3b\x69\xcb\x79\x80\x3b\x70\xde"
> +	"\x5d\xea\x1f\x60\x00\x51\xd9\xed\xef\x2a\xed\x93\xa5\xd5\xbb\x5a"
> +	"\xb7\xb5\xb1\x96\x84\x62\x25\xf6\xb0\x73\xdf\xbe\x40\x13\xb4\xc8"
> +	"\x14\xae\x15\x20\x7d\xbb\x76\x0b\x97\xe6\xbc\xb7\x61\x7e\xb2\x6c"
> +	"\xd3\xb5\xa4\x1b\xa6\xb5\xdd\x88\x45\x1b\x5b\xcc\xf5\x52\xdc\x49"
> +	"\x3f\x85\xa1\xcf\x3a\xfa\xae\x80\x81\x89\xb2\xfe\xdf\x04\x47\x8e"
> +	"\xde\x57\x94\x82\xa7\x11\xb2\x2b\x55\xd4\x8a\xb2\x18\x9e\x6c\x14"
> +	"\xf6\xf8\x69\x84\x5d\x88\xf7\x8a\xf5\x40\x20\x24\x60\x5f\xa3\xe2"
> +	"\x47\x32\xf9\x93\x17\x09\xac\x35\x9d\xfa\x74\x78\x17\xb1\x2c\x37"
> +	"\xb0\xdc\x0b\xe0\x8b\x5a\xcf\x9d\x3f\x09\x6e\x44\xf4\xdb\xa0\x23"
> +	"\x34\x76\xb2\x66\xf4\x2b\x92\x04\x0a\x9c\x88\x49\x6c\x80\xfb\x99"
> +	"\x6c\x70\xfb\xd5\xdc\xce\x10\xd1\x1a\x72\x2b\x4e\x9e\x34\xe0\x60"
> +	"\xf0\x06\x04\xd2\x55\x78\xc4\xea\xe8\x6b\x4a\x43\x7a\x14\xc7\x2c"
> +	"\x83\x34\x63\xf4\x4c\xa5\xee\xb3\xf0\x02\x78\x57\x44\x69\x37\xed"
> +	"\xda\x22\xb6\x3f\x86\x15\x81\xeb\x1f\xae\x69\x75\x29\x8c\x04\x83"
> +	"\xff\x80\xad\x45\x18\x88\x6a\x78\x43\x1b\x93\xf8\xd4\x19\x89\x1d"
> +	"\xbb\x85\x6b\x2f\x08\xdf\xc2\x27\x72\xbe\x36\xdb\x30\x7f\x3b\x36"
> +	"\xfe\x81\x60\xad\xb9\xc1\xf8\x9b\x80\x31\xba\xb2\x42\xaa\x5b\x41"
> +	"\x68\x06\x40\x41\xe1\xaf\xf6\x3f\x73\x67\xdd\x83\x92\x6d\xb6\x4b"
> +	"\x21\xe1\x97\x7c\x62\x46\x36\xfd\x93\x8e\x26\x54\x20\x95\xb8\xdd"
> +	"\x35\xb8\x87\xe8\xd7\x01\x10\x89\x20\xaa\x0f\x0c\x5e\x3d\xd1\xc1"
> +	"\xc6\x98\x15\x38\xc5\x73\xe3\xbf\x08\x51\x83\x32\x56\x5d\x1a\xa9"
> +	"\x0c\x4f\x2f\x16\x51\x16\xc9\x2e\x39\x8c\x5c\xe8\x95\x22\xc1\x19"
> +	"\xf9\x8b\x38\x53\xc6\x55\x8a\x07\x13\xae\x00\xc3\xc2\xe0\x8b\x0c"
> +	"\xdd\xb8\xf3\xdd\xca\x21\x1f\xfe\xdb\x9b\x28\x8f\x9e\xd8\x96\x02"
> +	"\x6a\x2b\x35\x89\x6e\xcb\x65\xf3\xde\x3a\xa5\x3f\x38\xd9\x8f\xbf"
> +	"\xa2\xb9\xc3\x6b\xaa\x2a\x28\x7a\xc6\xe6\xa0\xfc\xe3\x37\xfa\x60"
> +	"\xf7\xdd\x4e\xcd\x5d\x64\xa8\x4b\xd2\x30\x40\x68\x92\x5f\xa3\x72"
> +	"\x9f\x4d\xd8\x71\xae\x2c\xd7\x59\x60\xd9\x14\x88\x93\x9d\xd7\x56"
> +	"\x1e\x6b\xa0\x46\x23\x69\x82\x95\xb2\xa0\x66\xe4\xc2\x7b\xee\x44"
> +	"\x51\x93\xb8\x4d\x8b\xa4\x24\x57\x94\xaf\xb6\x26\x02\x7b\x00\xd9"
> +	"\x84\xda\x51\xcc\xce\x4c\x63\x90\x98\xb3\x13\x2a\x85\xec\x77\x52"
> +	"\x69\x79\x9f\x37\xb8\xa3\xfb\x2b\x76\x39\x1a\x6a\x99\xd7\x0f\xa5"
> +	"\xc7\xa3\x55\xc3\x99\x59\x47\x2b\x36\x1e\xe9\xf0\x8d\x85\xb9\x0d"
> +	"\x26\x57\x50\xce\x0a\xf6\xdc\xb2\x60\x21\xe8\x76\xfd\x15\x7a\x9a"
> +	"\xe4\x7c\xd8\x17\x0e\x58\x6b\x86\xf6\x7f\xf0\x69\xf8\x1c\xc3\x6c"
> +	"\x5a\xf7\xe9\xd5\xf0\x5d\xfc\x50\x5a\x89\x7a\xad\xaa\xa5\x39\xe4"
> +	"\x08\x42\xf6\xc2\x23\x90\xf0\x66\x39\x8b\x27\xe3\x05\x21\x43\x21"
> +	"\xc9\xe6\xd6\x21\xa2\xda\x34\x5b\x34\x58\xe6\xef\x93\x02\x96\xa4"
> +	"\xa4\x86\x12\x12\xdd\x67\x10\xc4\x5e\xf3\xca\x79\xfd\x65\x29\xee"
> +	"\xe6\xb9\x1c\x0a\x20\x98\x74\xd6\xc4\x3f\x10\xe0\xee\x31\x53\x05"
> +	"\xa8\xb4\x2d\xa1\xde\x26\x30\x80\xc6\x13\x9d\xf0\x67\x51\xd1\xfb"
> +	"\x09\x22\x02\x2b\x51\x92\x3e\x36\x36\x6c\x5b\xcf\x00\xf9\xa4\xa0"
> +	"\x20\x06\x46\x87\x3b\xc5\x19\x8d\x43\x7b\x57\xd7\xe0\xa4\x2e\xe9"
> +	"\x6d\xe7\x64\x1a\x77\x1f\xf7\x99\x5b\xc8\x43\x39\x62\xbc\x1f\xff"
> +	"\xb4\x4a\x2a\x5c\x06\x3f\x04\xb0\xea\x22\x83\xa5\x50\xae\x4a\xf8"
> +	"\x90\xd0\x4a\x61\xe2\xba\x45\x0d\x7a\xba\xeb\xfe\xd1\x22\x61\x8b"
> +	"\xa2\x46\x9c\x74\x10\xd0\x66\x92\x7c\x01\x56\x3a\x30\xb9\xc3\x3e"
> +	"\x57\x1a\x0c\xdb\xa6\xc3\x64\xd5\xff\x06\xa3\x46\x33\x8a\x1a\x6d"
> +	"\x5d\x07\x0d\xbf\x88\xf2\x38\x41\xf9\x2d\xbc\xb2\x55\x6d\xa0\xf7"
> +	"\xc1\x9e\x64\x51\xf8\xb4\xea\x35\x8b\x11\x80\xe3\x6c\xa2\xb6\x3b"
> +	"\xed\xaa\xdd\xf3\x69\xfa\xa2\x53\x1f\x22\xa8\x28\x8f\x57\xe1\x41"
> +	"\xbf\xcc\xb3\x3d\x86\x47\x7a\xa3\xc1\xd4\xfe\x0e\xfa\x6b\x95\x4e"
> +	"\x1a\xbf\x33\x50\x9d\x2a\x7d\x28\x0a\x64\x4d\x26\xae\x17\x65\x65"
> +	"\xe8\x55\xd0\x63\xf4\x1d\x03\x5c\x9f\xe9\x1b\x25\x12\x7c\x06\x41"
> +	"\xc0\x90\xb9\x9c\x17\x02\xf8\x7a\xef\xe5\x63\x7d\x8b\x38\x7a\x3c"
> +	"\x85\xdc\xdf\xad\x47\x5e\xef\x0d\x96\x7d\xed\xf2\xc5\x00\x1a\xd2"
> +	"\x09\xef\x1e\xff\xc3\x8b\xd0\xbc\xb8\x36\x76\x13\x33\xbd\xda\xa0"
> +	"\x1e\x02\x6c\x44\x8a\xd8\x7c\x3e\x7d\xc9\x66\x5e\xf3\xbe\xb1\x72"
> +	"\x8e\xfc\xbc\xe5\x99\x30\x89\x88\x91\x34\x3f\x9d\x2f\xfe\xa5\x1e"
> +	"\xb1\xef\x82\x23\x62\x91\x25\x22\x0a\x8a\xdb\x39\xe4\x5b\xf8\x2a"
> +	"\x75\xb7\x38\xff\xef\xca\x45\x9a\x57\xfb\xb3\xfe\xfb\x6d\x8f\x2e"
> +	"\xb1\x62\x64\x6d\x39\x57\x8d\x95\xe7\x79\xdd\x98\x3e\x68\xaa\x12"
> +	"\x50\x7b\x0e\xa2\x2b\x89\x52\x9f\xca\xd5\xc1\x22\xc2\x6f\x54\x83"
> +	"\xbd\xd7\x2c\xbb\xba\x50\xda\xad\x42\x93\xe7\x86\x9d\x60\xf5\x33"
> +	"\x1b\x7f\xaa\x75\x65\xbd\xa8\x34\x15\x6d\x1c\xf7\x47\x1f\x94\xdc"
> +	"\xab\xa8\x14\x93\x69\xdd\x2c\x3b\xf9\x21\x11\x36\x80\x63\xec\xc9"
> +	"\x8e\x78\x48\xb4\x31\xac\xa0\x48\x00\x3e\xed\x6f\xb3\xb0\x15\xc9"
> +	"\x24\x72\x24\x5b\x51\x7c\x65\xbb\x24\xb6\xb1\x53\xfd\x3f\x36\x7a"
> +	"\x6c\xbf\xec\x90\xcc\xd9\x01\x03\x30\x9e\xe3\x4a\x97\xcc\x3a\x35"
> +	"\xc6\x4a\x2b\xd3\x18\xbc\xb1\x1f\x64\x08\xa0\xf8\x84\x34\x36\x3a"
> +	"\x91\x1a\x28\x72\x98\xdd\x1a\xbe\xb1\x32\x77\x95\x72\x7e\xc5\xc1"
> +	"\xd7\x3b\xf8\x1e\x55\xc2\xdd\xed\x24\xdb\x1b\x9b\x0e\xd1\x07\x01"
> +	"\x85\x41\x90\x3c\x90\x6a\xf2\x0a\x8b\x4b\x7e\x9e\x87\xed\xa8\xa8"
> +	"\x8c\x5a\x4c\x4d\xc3\xb5\xec\x7a\x4d\xe1\x51\xf0\x00\x64\xb9\xc3"
> +	"\x6e\x61\x2a\x41\xd5\x2e\x0e\xf1\x1e\x87\xe5\xd5\xe4\xcc\x1a\x36"
> +	"\x7e\x5d\x96\x02\x14\xce\xaf\xa2\xbb\x61\x05\xf4\x2e\x64\xba\x17"
> +	"\xff\x18\xc8\xe1\x17\x8a\x02\x6b\x22\xe5\xd4\xd0\x68\xf6\x9c\x10"
> +	"\xf0\x2d\x4f\x82\xb3\x21\xb4\xaa\x7f\xff\x6b\x7e\x9a\xf2\x12\x44"
> +	"\x4a\xa5\xbb\x16\xb6\x56\x6e\xb1\x20\xb4\xb0\x34\x8f\xe4\x94\xb2"
> +	"\xf6\x7f\x9f\x05\xd0\x42\x30\x04\xdb\x11\xb8\xd7\x5a\x1b\xb6\x06"
> +	"\xed\x6e\x9c\x69\x6d\x2c\x0f\x6f\x7f\xf3\x9c\x76\x2e\xad\xc2\xd6"
> +	"\xc6\xfd\x93\xc1\xee\x25\xbb\xc8\xc6\xb5\xd1\x37\x65\xdd\xe5\x78"
> +	"\xb0\x89\x0a\x91\x4a\xe1\x17\x61\x43\x18\x47\xf3\xc2\x2a\x22\xc2"
> +	"\x56\x4e\x01\x31\xa3\x0b\xc7\xe6\x53\x27\xa8\xc8\x32\x25\x69\x7c"
> +	"\x8b\x8e\xb1\x2b\xc6\xc9\x85\x05\x1d\x67\x1e\xc6\x10\xa3\x60\x46"
> +	"\xbf\x9d\x5b\x3f\xda\x1f\xd3\x8b\x1a\x95\x88\xa2\x16\xb0\xdd\x7f"
> +	"\x46\x2f\x5f\xef\xa0\x17\x0e\x5e\x19\x20\x8c\xeb\x97\x52\xc8\xe0"
> +	"\xdc\xc0\x40\x0a\xd1\x84\xc1\xa6\xb2\xf4\x6c\xc7\x8d\xc9\xd4\xb8"
> +	"\xc3\xe3\xe5\xf9\x8a\xc5\xdb\x04\x2a\x89\xa5\x92\x64\x3f\x91\xd0"
> +	"\x60\x97\x8a\x42\x2d\x4b\x2c\xf8\xa7\xe2\x68\xf9\xd3\x94\x1c\x24"
> +	"\xe8\x80\xff\x05\xa7\x02\xab\x66\xd7\xb9\xa3\xeb\xd5\x0f\xf7\x26"
> +	"\x4f\x8f\x6b\x5a\xb2\x7c\xda\x1a\xb3\x83\x5f\xbc\xcc\xfc\x50\xc8"
> +	"\x24\x8c\x38\x9d\x80\x79\x50\x9d\x84\xe8\xee\x85\x19\xf3\x73\x5a"
> +	"\xd2\x41\x92\xde\x87\x5f\x52\x62\x91\xbe\x90\x1e\xce\x54\x13\x68"
> +	"\x35\x3e\x2b\xe5\xa2\x1e\xc0\xc1\x2f\x9c\x52\xd9\xe1\x5c\xe4\xfd"
> +	"\x21\xa3\x5a\x51\xb3\x01\x9d\x22\x2c\x6c\xa8\xb9\xda\xfb\x78\xa8"
> +	"\x24\x1f\xef\xe9\x1c\x38\x04\xf5\x8b\x80\xca\xe6\xb9\x76\x27\x31"
> +	"\xe1\x24\xf0\x07\xf9\xa9\x11\x77\x9a\x8a\xc1\x87\x21\x49\x1b\x6e"
> +	"\x94\x94\x4e\xe7\x3a\x10\x00\xd1\xd7\x02\xbf\x53\xe7\x88\x4e\xab"
> +	"\x63\x35\x61\x39\x81\x45\x21\x85\x35\x4b\x44\xca\xc0\xdb\x8f\xa3"
> +	"\x6a\xc7\x90\x12\x7a\xd5\x94\xd7\xfe\x30\xb2\x0f\x51\x52\xd0\xe6"
> +	"\xa7\xbe\x52\x2d\x45\xba\xed\xbc\x3c\x95\x35\x50\x3f\x83\x97\xa8"
> +	"\x8f\x7e\xfb\x2e\xa3\x5b\xe1\x2c\xb9\x15\x79\x62\x28\x8f\x02\x47"
> +	"\x31\x63\x2f\x45\xa7\xa7\x21\xa4\x26\x17\x2f\x46\x72\x22\x44\xed"
> +	"\x3a\xff\x0a\x80\x27\xb7\xaa\xa3\x9e\xe3\xb7\x71\xd2\xd9\x98\xa2"
> +	"\x6a\x5b\x18\x70\x6b\xfa\xf3\x9f\xcd\xa9\x4c\xca\x97\x76\x41\x98"
> +	"\xb2\x8b\x98\x23\x88\xe7\x1e\xa3\xd3\x56\x9a\x48\xf1\xd8\xf5\xd5"
> +	"\xf5\xd2\xff\x60\x52\x82\xeb\xe8\x92\x5c\x36\xfc\x32\xfe\x46\x2d"
> +	"\x9a\xbd\xb8\xc2\x37\x63\xee\xbe\x69\x4c\x98\x3d\x3d\xa3\x76\xe7"
> +	"\xbe\x8b\xb9\xe2\x07\x4b\x9a\x55\x44\x71\x6e\x7d\x7f\xb0\x31\x55"
> +	"\xb8\x74\x82\x9c\x47\xf9\xdc\x9a\x21\xd3\xbb\x47\x22\x05\x3b\x4b"
> +	"\x00\x31\xe1\x7f\x9d\xcf\xd1\xde\xeb\xd6\x2a\xd9\x0b\xa8\x34\x03"
> +	"\xc3\x66\x34\x1f\xcb\xe8\xd8\xf2\xf9\x4a\x3f\x6e\x8e\x3f\x8b\xce"
> +	"\xef\x9d\xe9\xf9\x92\x33\x7d\x8a\x61\x2f\x5c\xaf\x5d\x4c\x66\x30"
> +	"\x37\x09\x3f\xd0\x5e\xe6\x43\xef\x03\x63\x63\xc5\x39\x2b\xa8\x09"
> +	"\x5a\x86\x78\x5c\xa0\xa0\x5c\xa1\xba\xb7\xbc\xdb\xd7\x70\x60\x81"
> +	"\x20\x19\x72\x82\x85\xed\x96\x58\xa9\xdb\xa2\xcc\x03\xfc\x00\x92"
> +	"\x46\x3c\x79\x30\xce\xe0\x8f\xa0\x91\xd5\x16\xcc\x46\xce\xf2\x4a"
> +	"\x62\xaa\x1d\x80\x2f\xf5\x45\x7b\x9e\x97\xd7\x94\x39\x73\x6d\x5a"
> +	"\x25\xe4\x46\xb9\x6c\x58\xcc\xa7\xc9\x9b\x81\x9a\x98\x05\x0b\x82"
> +	"\xb4\xb1\xc5\x08\x71\x15\x1f\x26\x86\x26\x7b\xa8\x47\xaf\x80\x42"
> +	"\x2d\xd1\x68\x07\xb6\xa3\x81\xc5\x40\x6e\xf7\xf6\x66\x81\x2d\x1e"
> +	"\x65\x01\xae\x2c\xaa\x59\x7c\x90\xa4\xfd\x34\x04\x73\x3a\x40\x1a"
> +	"\x2b\x9f\x35\x4b\x25\x17\x8f\xe5\xe6\x99\x0f\x1e\x23\xed\x95\xfe"
> +	"\xf6\xa3\x90\xd3\xca\xd4\x22\xb4\x8b\x66\xac\xe9\xf3\xaf\xc8\x1b"
> +	"\xaa\x9f\x92\xc0\x19\x3c\x01\x66\xc6\x07\xed\x82\xbe\x60\x08\x6a"
> +	"\x94\xfc\x79\xfa\x3c\xb5\x24\xb1\xc8\x7f\xf3\x53\x20\x90\x1f\x07"
> +	"\x06\xd4\xf6\x7f\xeb\xcb\x96\x5f\xd8\x2b\xd2\x7e\x44\xaa\x62\x75"
> +	"\x43\xfa\xc9\xfa\x27\x78\xe7\xe7\x61\xc2\xc2\xd2\x87\x24\x75\xab"
> +	"\x22\x4d\xc4\xbe\xa2\x9e\xe6\x2e\xc3\xee\xd3\x37\x69\x02\x50\x13"
> +	"\xcb\xa3\x65\xf2\xdd\xed\xbc\x15\x68\x20\x50\x6d\xe4\x8a\x8b\x9f"
> +	"\x45\x39\xc5\xe4\xf1\x74\x7a\xf5\x0f\xa5\x94\x5a\x5a\x3c\x0c\xd0"
> +	"\xb1\x5e\x27\xd5\x8a\x98\x15\x24\x65\x24\x15\xcb\x7e\xee\x62\x0b"
> +	"\xbd\xf4\xb0\x32\x31\xb3\xc3\x21\x58\xe5\x7a\x69\x0e\x28\x9e\x00"
> +	"\x75\x71\x47\x81\x52\x9f\x6d\xc8\x80\x19\x1d\xaf\x76\x9f\x3a\x11"
> +	"\xa0\x6d\xe8\x43\xba\x73\xef\x85\x61\x09\x7a\xe2\x82\x44\xaa\xf2"
> +	"\x3a\x56\x08\x46\x04\x7e\x65\x83\xcf\xbc\xaa\x8a\xa3\xb4\xf8\x44"
> +	"\xb0\x43\x0e\xcd\x25\x40\x0b\xd7\x7c\x8c\xf9\xae\x42\xc9\xea\x2e"
> +	"\x3e\x83\x6a\xd8\xd4\x44\x23\x14\x33\x27\x00\x49\xdb\x61\xb5\x51"
> +	"\x52\xe4\x54\xbe\x05\xc9\xd6\xe3\xc2\x1a\x07\xf3\xbf\xd3\xb1\x1d"
> +	"\xb4\x88\xda\x62\x09\xb8\x94\x2a\xcc\x24\x22\x46\xe9\x6f\x99\x6d"
> +	"\xbf\x24\xa3\x9a\xc3\x3f\x42\x88\x5f\x36\x45\x68\xce\x95\xb3\xe5"
> +	"\x7f\x9c\xe3\xd6\xe5\xb9\xd5\x40\x36\xb8\x36\xc8\x88\x9a\xf7\xcf"
> +	"\xe0\x76\x56\xb3\x9a\x0d\x68\xc0\x60\x94\x9e\xdb\x14\x81\x95\xb3"
> +	"\xdd\xe5\xeb\xf2\x14\x18\x56\x74\x7b\x81\x9d\xb1\xd2\xed\xef\xf1"
> +	"\xf8\xfc\x41\x4c\x66\x77\xbd\xc9\x16\x32\x3f\x8f\x9a\xa7\xc2\xe1"
> +	"\x1c\x1f\x44\x48\x54\xd3\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x04"
> +	"\x0c\x1a\x20\x28\x2f"
> +};
> +
> +void __init fips_signature_selftest_mldsa(void)
> +{
> +	fips_signature_selftest("MLDSA",
> +				nist_mldsa_fips204_35_key,
> +				sizeof(nist_mldsa_fips204_35_key) - 1,
> +				nist_mldsa_fips204_35_data,
> +				sizeof(nist_mldsa_fips204_35_data) - 1,
> +				nist_mldsa_fips204_35_sig,
> +				sizeof(nist_mldsa_fips204_35_sig) - 1);
> +}
> 

I might test this in 1-2 weeks. RSASSA-PSS does not require a selftest?

BR, Jarkko

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 12/12] pkcs7: Add ML-DSA FIPS selftest
  2026-01-20 17:54   ` Jarkko Sakkinen
@ 2026-01-20 17:55     ` Jarkko Sakkinen
  0 siblings, 0 replies; 37+ messages in thread
From: Jarkko Sakkinen @ 2026-01-20 17:55 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 Tue, Jan 20, 2026 at 07:54:41PM +0200, Jarkko Sakkinen wrote:
> On Tue, Jan 20, 2026 at 02:50:58PM +0000, David Howells wrote:
> > Add a FIPS selftest for ML-DSA.
> > 
> > This is testcase (tcId) 35 from the ML-DSA-sigVer-FIPS204 JSON set[1],
> > packaged into a rudimentary X.509 cert and PKCS#7 message.
> > 
> > Note that only this particular testcase can be used because the current
> > ML-DSA implementation assumes an empty context string.
> > 
> > [1] https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ML-DSA-sigVer-FIPS204
> > 
> > Signed-off-by: David Howells <dhowells@redhat.com>
> > cc: Lukas Wunner <lukas@wunner.de>
> > cc: Ignat Korchagin <ignat@cloudflare.com>
> > cc: Herbert Xu <herbert@gondor.apana.org.au>
> > cc: keyrings@vger.kernel.org
> > cc: linux-crypto@vger.kernel.org
> > ---
> >  crypto/asymmetric_keys/Kconfig          |   6 +
> >  crypto/asymmetric_keys/Makefile         |   1 +
> >  crypto/asymmetric_keys/selftest.c       |   1 +
> >  crypto/asymmetric_keys/selftest.h       |   6 +
> >  crypto/asymmetric_keys/selftest_mldsa.c | 688 ++++++++++++++++++++++++
> >  5 files changed, 702 insertions(+)
> >  create mode 100644 crypto/asymmetric_keys/selftest_mldsa.c
> > 
> > diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
> > index e1345b8f39f1..c698a7a39fe2 100644
> > --- a/crypto/asymmetric_keys/Kconfig
> > +++ b/crypto/asymmetric_keys/Kconfig
> > @@ -103,4 +103,10 @@ config FIPS_SIGNATURE_SELFTEST_ECDSA
> >  	depends on CRYPTO_SHA256=y || CRYPTO_SHA256=FIPS_SIGNATURE_SELFTEST
> >  	depends on CRYPTO_ECDSA=y || CRYPTO_ECDSA=FIPS_SIGNATURE_SELFTEST
> >  
> > +config FIPS_SIGNATURE_SELFTEST_MLDSA
> > +	bool
> > +	default y
> > +	depends on FIPS_SIGNATURE_SELFTEST
> > +	depends on CRYPTO_MLDSA=y || CRYPTO_MLDSA=FIPS_SIGNATURE_SELFTEST
> > +
> >  endif # ASYMMETRIC_KEY_TYPE
> > diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
> > index c5aed382ee8a..25623d100b74 100644
> > --- a/crypto/asymmetric_keys/Makefile
> > +++ b/crypto/asymmetric_keys/Makefile
> > @@ -30,6 +30,7 @@ obj-$(CONFIG_FIPS_SIGNATURE_SELFTEST) += x509_selftest.o
> >  x509_selftest-y += selftest.o
> >  x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_RSA) += selftest_rsa.o
> >  x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_ECDSA) += selftest_ecdsa.o
> > +x509_selftest-$(CONFIG_FIPS_SIGNATURE_SELFTEST_MLDSA) += selftest_mldsa.o
> >  
> >  $(obj)/x509_cert_parser.o: \
> >  	$(obj)/x509.asn1.h \
> > diff --git a/crypto/asymmetric_keys/selftest.c b/crypto/asymmetric_keys/selftest.c
> > index 98dc5cdfdebe..d31cf5efefc7 100644
> > --- a/crypto/asymmetric_keys/selftest.c
> > +++ b/crypto/asymmetric_keys/selftest.c
> > @@ -62,6 +62,7 @@ static int __init fips_signature_selftest_init(void)
> >  {
> >  	fips_signature_selftest_rsa();
> >  	fips_signature_selftest_ecdsa();
> > +	fips_signature_selftest_mldsa();
> >  	return 0;
> >  }
> >  
> > diff --git a/crypto/asymmetric_keys/selftest.h b/crypto/asymmetric_keys/selftest.h
> > index 4139f05906cb..d515224fcfb3 100644
> > --- a/crypto/asymmetric_keys/selftest.h
> > +++ b/crypto/asymmetric_keys/selftest.h
> > @@ -20,3 +20,9 @@ void __init fips_signature_selftest_ecdsa(void);
> >  #else
> >  static inline void __init fips_signature_selftest_ecdsa(void) { }
> >  #endif
> > +
> > +#ifdef CONFIG_FIPS_SIGNATURE_SELFTEST_MLDSA
> > +void __init fips_signature_selftest_mldsa(void);
> > +#else
> > +static inline void __init fips_signature_selftest_mldsa(void) { }
> > +#endif
> > diff --git a/crypto/asymmetric_keys/selftest_mldsa.c b/crypto/asymmetric_keys/selftest_mldsa.c
> > new file mode 100644
> > index 000000000000..9927a4423067
> > --- /dev/null
> > +++ b/crypto/asymmetric_keys/selftest_mldsa.c
> > @@ -0,0 +1,688 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/* Self-tests for PKCS#7 RSA signature verification.
> > + *
> > + * Copyright (C) 2024 Joachim Vandersmissen <git@jvdsn.com>
> > + */
> > +
> > +#include <linux/module.h>
> > +#include "selftest.h"
> > +
> > +/*
> > + * Set of X.509 certificates to provide public keys for the tests. These will
> > + * be loaded into a temporary keyring for the duration of the testing.
> > + */
> > +static const u8 nist_mldsa_fips204_35_key[] __initconst = {
> > +	"\x30\x82\x15\x6a\x30\x82\x08\x67\xa0\x03\x02\x01\x02\x02\x04\x01"
> > +	"\x23\x40\x23\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x03\x12"
> > +	"\x30\x0f\x31\x0d\x30\x0b\x06\x03\x55\x04\x03\x0c\x04\x46\x72\x65"
> > +	"\x64\x30\x20\x17\x0d\x32\x36\x30\x31\x30\x31\x30\x30\x30\x30\x30"
> > +	"\x30\x5a\x18\x0f\x32\x31\x39\x39\x30\x31\x30\x31\x30\x30\x30\x30"
> > +	"\x30\x30\x5a\x30\x20\x31\x1e\x30\x1c\x06\x03\x55\x04\x03\x0c\x15"
> > +	"\x6e\x69\x73\x74\x5f\x6d\x6c\x64\x73\x61\x5f\x66\x69\x70\x73\x32"
> > +	"\x30\x34\x5f\x33\x35\x30\x82\x07\xb2\x30\x0b\x06\x09\x60\x86\x48"
> > +	"\x01\x65\x03\x04\x03\x12\x03\x82\x07\xa1\x00\x91\x52\xc0\xc6\x86"
> > +	"\x77\x60\x8f\x42\x6f\xb1\x6f\x8f\x75\xf7\x6c\x64\x70\x99\xd9\xd5"
> > +	"\x94\x31\xf4\x6f\x12\xa2\xf2\x93\x6e\x6e\x1f\x7e\x2d\xd2\x8f\x99"
> > +	"\xc8\x05\x81\x94\xc3\xfa\xe6\xdf\xf2\x87\xf5\x9b\xe5\x6b\x04\xb3"
> > +	"\xfd\x92\xda\xbd\x7b\xd3\xa3\xdf\x48\x3f\xec\xed\x84\xd3\x18\x80"
> > +	"\x90\x06\xda\x91\x46\x8d\x77\xd7\xc6\xeb\x9a\x51\x81\x75\x47\x7a"
> > +	"\x0e\x2b\x43\x56\x97\xc2\x69\xf1\x6f\xbb\x56\x99\x6b\x64\x55\xf0"
> > +	"\x4b\x3c\xc1\x1e\xb5\xd6\x65\x5d\x07\x3d\x96\xbf\x4b\x4c\xdb\x9e"
> > +	"\x31\xe9\x93\xf0\xf1\x0c\x65\x59\x83\x21\x20\x5e\x11\x15\xfa\x60"
> > +	"\xa1\xf3\xca\x5a\xd0\x49\x21\x8b\x16\xfd\xf7\xb5\xe2\xbf\x41\x79"
> > +	"\x8d\x58\x39\x52\x3b\xcf\x1d\xe3\x11\x05\x57\x79\xce\xb2\x07\x69"
> > +	"\xb8\x2e\x0a\xce\x7b\xb4\xed\x00\xcc\xed\x66\x5e\x42\x21\xf0\x48"
> > +	"\xea\xfa\x77\x4c\x7e\x9a\x49\x8d\xa2\x67\x5f\x9b\xe9\xf7\x2b\x58"
> > +	"\xa1\xe7\x30\xfa\xda\xad\x39\xe2\x31\xe4\x6d\x88\x4a\x22\xee\xe5"
> > +	"\xc3\x3a\xe2\xe6\x74\x04\xd5\x7e\xdb\xa0\xb9\x4a\x4f\x27\xd2\x08"
> > +	"\x1f\x46\x62\x66\xd6\x54\xc0\xb8\x37\xbe\x74\x65\x87\x34\x55\x5a"
> > +	"\x06\x82\x82\x7d\x65\xc3\x46\x4e\x96\x90\xdf\x6b\xb8\x1a\xdc\x11"
> > +	"\x79\x02\xc5\x48\x06\xb7\x3b\xcb\x6c\x44\xa9\x35\xbc\xe9\xea\x8f"
> > +	"\xc8\x9e\xaa\x27\xd0\x4a\x67\xe0\xf6\xe6\x0a\x94\x78\xdb\x70\xc9"
> > +	"\xf5\xd5\x87\xca\xd5\xb6\x2e\x55\xea\xff\xd4\xcf\xad\x4d\xd3\x67"
> > +	"\x2b\xb7\xaa\x80\x9b\x7f\x56\x0a\xd1\xea\xbd\xbd\x20\x88\x01\x00"
> > +	"\xaa\x2f\xcc\x7d\x0a\x31\x6b\xe5\x66\xee\x87\xaf\xbf\x08\xc7\xa7"
> > +	"\xd3\x50\xde\x31\xd2\x3d\xfd\xf5\x87\x74\x76\x30\x31\x9c\x3f\x14"
> > +	"\x00\x22\xf9\x70\xba\x6c\x4e\xdd\x84\x64\xdb\xaa\x5e\xb0\x22\xff"
> > +	"\x87\x25\x2f\x55\xab\xbd\xdf\xac\x6d\x31\xd8\x53\xb3\x50\x56\xea"
> > +	"\x48\xad\x33\x94\xa5\xe6\x85\x21\x06\x10\xbb\xa8\x96\xdd\xc9\x00"
> > +	"\x99\x93\xe2\x0e\xa1\xb0\x66\x41\xe4\xd5\x24\x2d\xd0\x8f\x6e\xff"
> > +	"\xdd\x6f\x0c\xcd\x8e\x5c\xb9\x8b\x6b\x66\xeb\x2b\x38\x52\x01\x4a"
> > +	"\xc2\x80\xc5\x44\x48\x87\xcd\x6b\xcd\xea\xb5\x94\x7f\x8f\x19\x86"
> > +	"\xb7\xf9\x65\xb5\x08\x51\x77\xe7\x73\x2f\xd4\xf9\x74\xd8\x7c\xc3"
> > +	"\x03\x24\xcf\x42\xaf\x25\xdc\x73\x68\xa1\x34\x9e\x26\x86\xa6\x05"
> > +	"\x5f\xe2\x6f\xcc\x5d\x1f\xa1\x1d\xed\x9f\x1c\x24\x65\x6d\x43\x6c"
> > +	"\xdd\x1a\xc4\x10\xf6\x00\x8b\x0f\xf2\x33\xb5\x53\x79\x17\x9f\x47"
> > +	"\x67\x4a\x52\xad\x56\xd1\x38\x85\xef\x03\xd7\x22\x3b\x39\xe6\xb8"
> > +	"\x63\x4d\x52\x89\xcf\xd9\x46\xd9\x7b\x7b\xfb\xf2\x28\xa6\xe9\x38"
> > +	"\x42\xbe\xb3\x75\xd7\x6e\x01\xbb\xff\xc2\xe6\x76\x58\xe3\x63\x65"
> > +	"\x76\x1a\xde\xc0\x72\xe3\x3a\x8e\x9d\x53\xf9\x2d\x74\x1a\xe7\x0c"
> > +	"\xe7\x8b\xd1\x90\xbd\x91\xc3\xa8\xe3\x09\x35\xcc\x25\x00\xa6\xdb"
> > +	"\x87\x5c\x45\x6c\x1d\x15\xf1\x1b\x16\xe8\x79\xb1\xb4\x63\x35\x22"
> > +	"\x66\x69\x5e\xad\xcb\x75\x77\xff\xfc\xfe\x6f\x5d\x72\x12\xcf\x07"
> > +	"\x39\x94\x04\x03\x9a\x0d\x15\xa6\x97\x85\x5b\x82\x77\xe9\x45\xc2"
> > +	"\xa2\x70\x14\x89\x61\x07\x0e\xe9\x5c\x13\x53\x38\x7f\xa6\x14\xea"
> > +	"\xec\x62\xb4\x41\xdf\x38\x5f\xff\x80\x7f\x29\xd9\x41\x63\x75\x12"
> > +	"\xb4\x87\x73\xfc\x48\x5a\x52\x1d\x55\x5f\xec\x22\x76\x57\x5f\x10"
> > +	"\x95\xc0\x23\x7e\x66\x34\x77\x73\xbf\xf4\x37\x1b\x3e\x9f\x10\x4b"
> > +	"\x09\x6b\x6e\xb8\x06\x8d\xff\xd2\xcf\xb3\xc0\x61\x31\xf0\xaf\xd3"
> > +	"\xae\xfc\x36\x03\x5f\x92\x21\xc2\xdc\x03\x63\x75\x08\xd3\x9d\xc0"
> > +	"\x0a\xc7\xac\x36\x2c\x15\xf2\xf5\x16\xc7\x71\x59\x34\xf5\xf8\x01"
> > +	"\x82\xd2\x8e\xeb\x1a\xe2\x63\xce\xf7\x24\xe5\xb1\x14\x10\x0c\x74"
> > +	"\xea\xd0\x0e\xc3\x6c\x7e\x1e\x7e\x04\xb6\x5f\x79\x20\x91\xe5\x22"
> > +	"\xb2\x5f\x8d\xe2\x25\xf5\x07\x0a\x57\xb3\x04\x53\x60\x54\x28\x29"
> > +	"\x64\xd6\x66\x5b\x38\x78\xcb\xd5\x93\xc8\xd8\x40\xed\x84\x9f\x14"
> > +	"\xc8\xf6\x16\xbc\xc1\x4d\xcb\xb4\xf2\xf0\x85\x97\x93\xb8\x0c\xbe"
> > +	"\x30\xb8\x3a\x31\x6a\x6e\x8b\x64\x64\x51\x2e\xaf\x53\xda\xf6\xdf"
> > +	"\x66\x1b\xc9\x24\xb1\xf7\x34\x64\x53\xd5\x27\xed\xc3\x7d\xc1\x42"
> > +	"\x15\x25\x71\x41\x14\xd6\x6c\xb0\xe3\x82\x07\x25\x88\x70\x6a\x03"
> > +	"\x6d\xff\xef\x9f\xf3\x0f\xe3\xc7\xe8\x1d\x00\x99\x53\x72\x33\x14"
> > +	"\x8e\x03\xa4\xdf\xb6\xfc\xde\xd3\x30\x2f\xe8\xa8\xe0\xb2\x21\x90"
> > +	"\x3c\x97\xbf\x3a\xf8\xd8\x86\x01\xea\x90\xf0\x9f\xae\x83\xe5\x6a"
> > +	"\x78\x2f\x3c\xb2\x4c\x48\x51\x3a\x50\xf4\xae\xf1\x2e\x39\x8b\xeb"
> > +	"\x5e\xd9\x44\x97\x94\xb5\x9b\x54\x34\x20\x0a\x8f\x09\x89\x2e\x0a"
> > +	"\x0b\xac\x13\x66\x91\x99\xe6\x75\xb3\x8e\x39\x21\x1d\xcc\xf4\x83"
> > +	"\x2e\x71\xcb\x11\x2a\xc2\x77\xb6\xe4\x3e\xd7\x83\x64\x7b\xd9\x44"
> > +	"\x52\xf7\x96\xbd\x77\x96\x83\xec\xf0\xa9\xaf\x0d\x8b\xd7\xbb\x3e"
> > +	"\xdd\x8d\xd3\xf7\x8b\x81\xbd\x3a\x87\x2c\x72\x11\xa9\x31\x86\xfd"
> > +	"\x9a\x54\x21\xb8\x0c\x57\xcc\x83\xf2\xff\xb8\x9e\x1e\x21\xdf\xbb"
> > +	"\x1f\x71\x0f\xbe\xdd\x52\xf0\x02\xe5\xed\x67\xba\x26\x1b\xdc\x6d"
> > +	"\x35\x86\x81\x9a\xfa\xbf\xbe\xc4\x52\x81\x99\xa3\xf5\x58\x95\x9a"
> > +	"\x9a\x03\x22\xe5\xdd\xe4\x56\x38\x2b\x7f\x26\x26\x1d\x45\xde\xe1"
> > +	"\x22\x94\x5d\xad\x8a\x64\xc6\x2a\xe2\xa8\x00\x7f\xba\x75\x97\x9b"
> > +	"\x77\xd4\x2c\xe9\xbf\x25\xf8\x54\xcb\xb0\xe3\xce\xc4\x62\x7a\x13"
> > +	"\x46\x69\xb9\xd4\x4b\x01\x08\x72\x9a\x85\xb8\xf9\x5f\x7d\x30\xa1"
> > +	"\x76\x18\x48\x0f\x3d\x01\xd0\xf1\xa5\x48\xaf\x79\x8b\x5e\x71\x28"
> > +	"\x37\x75\xc5\xa8\x3d\x79\x0d\x25\xb6\x3d\xf4\xba\xa5\x82\x8c\xfd"
> > +	"\x77\x1a\xf2\x0e\x06\xb3\x04\xea\x62\x34\x4a\x09\xd5\x7a\x29\xa6"
> > +	"\xa9\xfe\x25\x82\x23\xe1\x68\x6a\xd5\xd3\x11\x60\xfd\x64\x29\x0c"
> > +	"\x71\x2d\xcb\xc2\xf3\x20\x6e\x29\x4f\xf6\xf3\x6e\x56\x08\x4a\x20"
> > +	"\x31\xdb\x1d\xdd\xdc\x1a\x8d\xdc\x40\x19\x65\xf3\x8a\xea\x45\x76"
> > +	"\x4f\xf0\x9f\x1c\x6c\x07\x88\xdd\x0c\x7b\x1d\x4f\x8d\x9c\x60\xf0"
> > +	"\x27\x2e\x7f\x50\x8b\xd0\x34\x92\x9a\x19\x10\xbd\x46\x06\x33\x70"
> > +	"\x1c\x65\xaf\xf6\x85\xb6\xb8\xa3\x67\x55\xc0\xab\xd8\xc7\x47\x42"
> > +	"\xae\x80\x45\xc9\x88\x9e\xa5\x05\x72\x42\x6a\x5b\x09\xb8\x30\x05"
> > +	"\x43\x62\xe6\xb3\xdf\x3d\x84\x98\xc2\xfe\xd9\xea\x59\xba\x90\xf0"
> > +	"\xad\x8f\xeb\x87\x33\x53\xe3\x33\x60\xf6\x32\x3f\x39\xa4\x06\xfe"
> > +	"\x78\x27\xe8\xac\x2f\xfd\xde\x6b\xb6\xf7\x26\xca\x1c\x14\x64\x3c"
> > +	"\x4e\x85\x41\xd5\x7d\x6a\x18\xaf\xca\x73\xca\xdc\x53\xb7\x29\x1e"
> > +	"\x4b\x37\x71\xf2\xb2\x9d\xec\xbd\xf2\xf7\x21\x38\x6b\xd2\x2e\xf5"
> > +	"\xc1\xb9\x7c\x54\x86\xad\xf2\x60\x9a\xb3\x87\x2d\xb0\x69\xf1\xd0"
> > +	"\x3e\x94\x2b\xb7\x61\x93\x04\x3d\xba\x68\xd3\x1b\x20\xe0\x41\x2c"
> > +	"\x0a\x4a\xf5\x15\xa6\x20\xd2\x7b\x7e\x4b\xc1\x15\x3d\xde\xbb\xb3"
> > +	"\xe8\x79\x9c\xd1\x02\x54\x4f\xdf\xa3\x40\xaf\xa4\x66\x16\x04\xfa"
> > +	"\x68\x21\x2c\xfc\x0c\x15\x7e\x06\x0f\x1c\xc1\xbd\xd6\xa0\x29\x85"
> > +	"\x38\x0b\x61\xb6\x08\xd4\xc7\x45\x9b\x49\x4d\xd5\x3d\xc8\x00\x9b"
> > +	"\xab\xc7\x6f\x62\x39\x7e\x96\x2d\x18\xac\xab\xec\xd4\x98\x9b\x86"
> > +	"\x18\x59\x2f\x9d\xda\x47\x47\x0e\x19\x8c\xe2\xd9\x6f\x62\x3e\x9d"
> > +	"\x3f\x73\x13\xb4\x62\x39\x31\x9a\x54\x04\x76\x7c\x5f\xf9\xe7\x79"
> > +	"\x5b\x4a\xf6\x95\x82\x64\xaa\x7d\xf3\x83\x00\x72\xc5\xd9\xc3\xaa"
> > +	"\x75\x0c\x42\x2d\x9a\x1c\x3c\x6e\x44\xf2\x52\x9c\x91\xe0\xea\xf3"
> > +	"\x06\x18\xe8\x61\x63\x04\x7e\x29\x9d\xa6\x1e\x3e\xce\x10\x38\xac"
> > +	"\xde\xb8\x52\x67\x14\x8a\x32\xdb\x71\x40\x5f\x0c\xd6\x2d\x52\xa4"
> > +	"\xd2\x9d\x4d\xf3\x21\xa0\x45\x2a\x19\xda\x75\x70\xae\xbd\x4a\x7b"
> > +	"\x3a\x2f\x5f\xc5\xbd\x79\x28\x2d\xbc\xff\x43\x3c\x3f\xe4\x23\xa7"
> > +	"\x77\xa6\xf1\x2b\x62\x75\xb5\xab\x85\x0c\x76\xec\xdd\x42\xc9\xdf"
> > +	"\x67\xb4\x0b\x95\x61\xd1\xf8\x55\xdb\x54\xfa\xcd\x98\xb2\x0d\xc6"
> > +	"\x15\xfe\xb4\xea\x3f\xae\xe9\xcc\x90\xf1\x08\x15\x88\xca\xe8\x32"
> > +	"\x0f\xa1\xca\x4a\xd1\x21\xe4\xf3\x11\x76\xdf\xed\xec\x3e\x61\x09"
> > +	"\x56\x7f\xf1\x88\x39\x34\x41\x76\x5b\x9a\x88\xad\x04\x40\x67\x55"
> > +	"\x2e\x8d\xc1\xe1\x91\x2f\x6a\xc0\xd5\x54\x46\x24\x7a\x48\x14\x56"
> > +	"\x98\x74\xec\x7c\x3d\x6a\x28\x8b\xbc\xce\xe6\x47\x5f\x9a\x84\x0b"
> > +	"\xa4\x40\xdf\x6f\x6a\x9e\xd4\x7f\x0b\x12\x24\xbb\xbe\x4a\xce\x0b"
> > +	"\xd8\x7c\xf6\x0c\x69\xcd\x63\xfa\xd2\xfb\x8e\xc2\x80\x5c\xb8\x0b"
> > +	"\x2d\x5d\xd0\x31\x25\x41\xdb\xc1\x02\x04\xcc\x55\x74\xf9\xe4\xe7"
> > +	"\x56\xcb\xc8\x73\x70\xdd\x66\xeb\x9f\x6e\x09\x57\xa0\xab\xd7\x1a"
> > +	"\x15\xe0\xeb\x18\xf4\xe2\xe1\xc7\x3a\x38\xfd\x3d\x36\x44\xe4\xd9"
> > +	"\xa7\x4b\xf8\x5a\xa1\xd5\xb4\x2a\x68\xa3\x05\x74\x58\x11\x17\xdb"
> > +	"\x27\xe1\xd5\x5f\x7d\x01\x6d\xa0\x8d\x0e\x6b\x4f\x88\x1b\xcd\xde"
> > +	"\x48\xab\x47\x3e\xd0\x73\xd8\x55\xf1\x90\x91\xa8\xc6\x9b\xd9\xd3"
> > +	"\x2e\xf5\x7e\xde\xb3\xe8\xfb\x4f\x80\xec\x87\xa3\xa3\x02\x78\x54"
> > +	"\xe0\x33\x8d\x24\x88\xc9\x5d\xab\x6b\x67\x72\x01\xb0\xc0\x94\x26"
> > +	"\x9b\x1a\xf4\xc3\x21\x8d\x4b\xfd\xac\xea\x35\xe5\xb9\x93\x1c\xe6"
> > +	"\x36\x69\x80\x8f\x20\xb7\x3d\x42\x90\xbd\xea\x77\x38\xbf\xa8\xa8"
> > +	"\x29\x05\x32\x32\x1d\x20\xf1\x3f\x39\x9c\x92\x6e\x2e\x39\xd1\x27"
> > +	"\x55\x59\xe4\x79\x3a\xf4\x4e\x14\x38\x78\x80\xa3\x42\x30\x40\x30"
> > +	"\x0c\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x02\x30\x00\x30\x0e\x06"
> > +	"\x03\x55\x1d\x0f\x01\x01\x00\x04\x04\x03\x02\x07\x80\x30\x20\x06"
> > +	"\x03\x55\x1d\x0e\x01\x01\x00\x04\x16\x04\x14\x2b\x73\x93\x2c\xf0"
> > +	"\x6c\x34\x1a\xa7\x2c\xce\xa4\xe0\xac\x35\xa9\x6c\xcc\x00\x23\x30"
> > +	"\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x03\x12\x03\x82\x0c\xee"
> > +	"\x00\x6e\x8c\x4b\x20\x61\xc2\xcd\xf2\x71\x54\xbf\x70\x85\xf6\x3c"
> > +	"\xb1\x5d\xa3\xce\xc8\x2d\x52\xca\xd1\xa6\x50\x80\x68\x75\x05\x25"
> > +	"\x24\xda\xa1\xef\xdf\xf4\x6f\xde\x5e\xff\x63\xef\xf5\x70\x74\x7c"
> > +	"\x69\xfd\x23\x4b\xa3\xaa\x3b\xa9\xa8\x0f\x48\x8b\xc4\x8f\x95\x9f"
> > +	"\xf5\x6a\xb3\x17\x35\x5f\xfe\x91\x7b\xdd\xd3\xbb\xf7\x3b\xf0\xa8"
> > +	"\x22\x09\xbe\x25\x48\xcd\xca\x1a\x37\xc4\xde\x57\x18\x56\x30\x19"
> > +	"\xa9\x26\x99\x13\x9a\x6d\x6a\x69\xe9\x64\x83\x2d\xdd\x70\xf5\xe8"
> > +	"\x03\x75\xdc\x9f\xe0\xba\x8e\x22\xae\x3a\xd8\xaa\xd9\x45\x84\x71"
> > +	"\xcd\x37\x61\xb1\xb9\x04\xe8\xbb\xba\x72\xfa\x8a\x07\x1d\xf1\x82"
> > +	"\x55\x17\xff\xa2\x2e\x2b\xbf\xf9\x9a\x0f\x86\x94\x06\xd9\x07\xdb"
> > +	"\xc3\x16\x92\x90\xce\xd1\x4e\xb8\xee\x7a\x2b\x6c\xe7\xc2\x6a\x0a"
> > +	"\xe2\x8b\x32\x5e\xd4\x61\x38\x90\xaf\xce\xbb\x38\xe6\xe9\xd5\x43"
> > +	"\x74\xc9\xeb\x48\xd0\xe6\x00\x30\xa1\x1e\x75\x03\xb9\x06\xe9\x16"
> > +	"\x35\x7c\x6f\x81\xd5\x9f\x89\xcc\x36\x33\x75\xcb\xf0\x1e\xd0\xd8"
> > +	"\x51\x54\xd5\x5c\xb8\xfc\xe7\xb2\x17\xd5\xed\xeb\xe9\x36\x85\xe0"
> > +	"\xbe\x43\x4c\xb0\xc5\x67\xc8\x97\x62\xb3\x80\x89\xec\x2c\xf3\x4c"
> > +	"\x93\x87\x9c\x0b\x23\x5d\x44\x25\x6a\x10\x3f\x21\x08\x7d\x8d\xfc"
> > +	"\x99\x8d\xc5\xbe\xbe\x57\x5c\x5d\x4d\x27\x7b\xa2\x2e\x81\xcd\x0a"
> > +	"\xf1\x49\x2b\x43\xda\xc4\x36\x5c\xc6\x91\x75\xd8\x95\xa6\x9b\xbf"
> > +	"\xe9\x21\x45\x3c\x07\xae\x56\xcd\xf5\x1b\x91\x56\xe4\x49\x40\x12"
> > +	"\x58\x8a\xa4\xac\x32\x53\x93\xbe\xe9\x8a\x65\xef\x71\xe3\x07\xc8"
> > +	"\x4d\xb9\x35\x85\x4d\x06\x9b\xa4\x11\x6a\x67\x7a\x5b\x49\xee\xea"
> > +	"\xf2\x0d\x16\x49\x2b\x74\x46\x78\xcc\x59\x12\x0c\x80\x6f\xae\x7d"
> > +	"\x23\x30\x87\x7f\x16\x52\x04\x11\x41\x0b\xba\x48\xbf\x49\xaa\x08"
> > +	"\xf4\x44\x00\x75\x4a\x05\x79\x79\x66\x31\x94\x44\x9e\x66\xf5\xc0"
> > +	"\xd7\xa1\xeb\xb5\xda\xc4\xb6\x5c\xf9\x20\x0b\x21\x89\xf6\x0f\xa5"
> > +	"\x29\x48\xcb\x7a\x83\xd5\xfd\x54\x45\xaf\xa3\x0d\x99\xe9\x14\x30"
> > +	"\x06\x8a\x53\x51\x08\x0d\xa4\x24\xa6\xf4\xae\x5f\x8e\x1b\x7b\xa6"
> > +	"\x48\x1c\xfb\x39\xfc\x34\x2a\xcf\xa0\x84\xb3\x79\xb7\xc7\x4d\x64"
> > +	"\x0e\x0c\x04\x87\x31\x9f\xf6\x97\x02\x8b\xe8\xc2\x13\x21\x8e\xfc"
> > +	"\x85\x7c\xac\xfa\xc4\x44\x10\x3f\x2f\x93\x02\x74\x44\x1f\x18\xdc"
> > +	"\x2e\x17\xca\x18\x27\x86\x55\xfb\xc0\x79\x4b\x50\x08\x33\x62\x4c"
> > +	"\x58\x29\x20\x98\x95\x9f\x8c\x7a\xf7\x82\xe1\x41\x43\xf3\x5c\x55"
> > +	"\x54\xe3\x22\x60\xf2\xa4\x85\x17\x88\x93\x6b\x6d\xc7\x48\xf6\xc0"
> > +	"\x0b\x4b\xf0\x86\xc6\x64\xae\xd9\x22\x08\x75\x35\xce\xf4\x7b\xad"
> > +	"\xf2\xb6\x7d\x50\x6e\xba\xf6\x46\x30\x7b\xbc\x60\xc3\xf7\xf7\xeb"
> > +	"\x39\x44\x6a\x34\xde\xb4\x6f\x43\x3f\xfb\xcb\x23\x60\xfb\x55\x57"
> > +	"\xaa\x9a\x2e\x33\x29\x37\xd7\x9a\xb6\x85\xa2\xad\x9b\x25\x42\x38"
> > +	"\x83\x44\x85\x0e\xec\x19\x74\xa3\xdc\x73\x4b\x30\xb9\x6b\x05\x63"
> > +	"\xcd\xdb\xa3\x18\xed\xfd\xc2\x94\x1b\xdf\x1f\x64\x6c\xd6\x29\x05"
> > +	"\x58\xe0\x77\xb9\x1b\xd5\x40\xe6\xff\x3b\x7e\x13\x2b\xef\xed\x35"
> > +	"\x8e\x06\x69\x13\x8f\xe4\x93\x59\x34\x54\x50\x16\x3c\xbb\x5b\xe2"
> > +	"\xa4\x7a\xd5\x35\x60\x3a\x13\x8e\x7c\x37\xf6\xb8\xfd\x1f\xa1\x1d"
> > +	"\xd4\x25\x19\x54\xba\xe7\x8e\x7c\x59\x40\xc3\x7a\xf2\x2c\x94\x78"
> > +	"\xca\x02\x0a\x1d\x21\x4f\x97\x57\xbc\x06\x36\x23\xce\x8d\xce\xdd"
> > +	"\x39\x5d\x6b\x7b\xc1\xa8\x06\x90\x4e\xbf\xaf\x28\xf0\xf8\xc5\xa6"
> > +	"\x3a\x0c\x1c\xc6\x31\x4f\xe8\x05\x79\x1d\x76\x57\x05\xf5\xfa\x33"
> > +	"\x17\x1a\xb4\xc8\x51\xc2\x6e\x42\xc0\xf9\xdc\xcf\x9c\x28\x37\xc1"
> > +	"\x11\x42\x1d\x0f\x5f\xdc\xf9\xa9\xeb\xa0\x9c\x25\xdb\x0d\x79\x65"
> > +	"\xdc\x91\xdc\x4e\x63\x84\x1a\x76\xae\x9a\x68\x7a\xd8\xb6\xe4\x90"
> > +	"\x68\xcf\x74\xfa\xaf\xd8\xa6\x6c\x91\x39\xd3\xc3\xa6\xbe\x06\x56"
> > +	"\x3c\xb5\x7f\xe7\x73\x30\x14\x79\x57\x4c\x68\xeb\x32\x94\xe3\x35"
> > +	"\xf9\xf1\xbb\x7c\xfd\xf5\x0e\xa1\x13\x92\xf0\x4f\x5f\x3b\xe9\x9c"
> > +	"\xb2\x4b\x07\xa8\x91\x17\x34\x02\xef\x38\xf7\x44\xdd\xf9\x27\xf0"
> > +	"\x60\x1f\x70\xba\x50\xf8\xab\x84\x5f\xf2\xa0\x12\x40\x1a\x99\xcf"
> > +	"\x4f\x03\x36\x4c\x30\x82\xd4\x21\x81\x91\x9e\x87\xd4\xac\x3b\x3b"
> > +	"\xe1\xf9\x5a\xb6\x90\xfc\xda\x10\x6c\x87\xc6\x3c\x7b\xed\xf1\x29"
> > +	"\x08\xd6\xa0\xee\xc3\xb6\x72\x46\x1b\xb1\x38\xec\xfd\x48\x01\x9a"
> > +	"\x07\x7e\xf4\xe5\x90\x94\x8a\xbd\x08\x3e\x28\xef\x4d\x06\x2f\x8e"
> > +	"\x58\x3b\x69\xcb\x79\x80\x3b\x70\xde\x5d\xea\x1f\x60\x00\x51\xd9"
> > +	"\xed\xef\x2a\xed\x93\xa5\xd5\xbb\x5a\xb7\xb5\xb1\x96\x84\x62\x25"
> > +	"\xf6\xb0\x73\xdf\xbe\x40\x13\xb4\xc8\x14\xae\x15\x20\x7d\xbb\x76"
> > +	"\x0b\x97\xe6\xbc\xb7\x61\x7e\xb2\x6c\xd3\xb5\xa4\x1b\xa6\xb5\xdd"
> > +	"\x88\x45\x1b\x5b\xcc\xf5\x52\xdc\x49\x3f\x85\xa1\xcf\x3a\xfa\xae"
> > +	"\x80\x81\x89\xb2\xfe\xdf\x04\x47\x8e\xde\x57\x94\x82\xa7\x11\xb2"
> > +	"\x2b\x55\xd4\x8a\xb2\x18\x9e\x6c\x14\xf6\xf8\x69\x84\x5d\x88\xf7"
> > +	"\x8a\xf5\x40\x20\x24\x60\x5f\xa3\xe2\x47\x32\xf9\x93\x17\x09\xac"
> > +	"\x35\x9d\xfa\x74\x78\x17\xb1\x2c\x37\xb0\xdc\x0b\xe0\x8b\x5a\xcf"
> > +	"\x9d\x3f\x09\x6e\x44\xf4\xdb\xa0\x23\x34\x76\xb2\x66\xf4\x2b\x92"
> > +	"\x04\x0a\x9c\x88\x49\x6c\x80\xfb\x99\x6c\x70\xfb\xd5\xdc\xce\x10"
> > +	"\xd1\x1a\x72\x2b\x4e\x9e\x34\xe0\x60\xf0\x06\x04\xd2\x55\x78\xc4"
> > +	"\xea\xe8\x6b\x4a\x43\x7a\x14\xc7\x2c\x83\x34\x63\xf4\x4c\xa5\xee"
> > +	"\xb3\xf0\x02\x78\x57\x44\x69\x37\xed\xda\x22\xb6\x3f\x86\x15\x81"
> > +	"\xeb\x1f\xae\x69\x75\x29\x8c\x04\x83\xff\x80\xad\x45\x18\x88\x6a"
> > +	"\x78\x43\x1b\x93\xf8\xd4\x19\x89\x1d\xbb\x85\x6b\x2f\x08\xdf\xc2"
> > +	"\x27\x72\xbe\x36\xdb\x30\x7f\x3b\x36\xfe\x81\x60\xad\xb9\xc1\xf8"
> > +	"\x9b\x80\x31\xba\xb2\x42\xaa\x5b\x41\x68\x06\x40\x41\xe1\xaf\xf6"
> > +	"\x3f\x73\x67\xdd\x83\x92\x6d\xb6\x4b\x21\xe1\x97\x7c\x62\x46\x36"
> > +	"\xfd\x93\x8e\x26\x54\x20\x95\xb8\xdd\x35\xb8\x87\xe8\xd7\x01\x10"
> > +	"\x89\x20\xaa\x0f\x0c\x5e\x3d\xd1\xc1\xc6\x98\x15\x38\xc5\x73\xe3"
> > +	"\xbf\x08\x51\x83\x32\x56\x5d\x1a\xa9\x0c\x4f\x2f\x16\x51\x16\xc9"
> > +	"\x2e\x39\x8c\x5c\xe8\x95\x22\xc1\x19\xf9\x8b\x38\x53\xc6\x55\x8a"
> > +	"\x07\x13\xae\x00\xc3\xc2\xe0\x8b\x0c\xdd\xb8\xf3\xdd\xca\x21\x1f"
> > +	"\xfe\xdb\x9b\x28\x8f\x9e\xd8\x96\x02\x6a\x2b\x35\x89\x6e\xcb\x65"
> > +	"\xf3\xde\x3a\xa5\x3f\x38\xd9\x8f\xbf\xa2\xb9\xc3\x6b\xaa\x2a\x28"
> > +	"\x7a\xc6\xe6\xa0\xfc\xe3\x37\xfa\x60\xf7\xdd\x4e\xcd\x5d\x64\xa8"
> > +	"\x4b\xd2\x30\x40\x68\x92\x5f\xa3\x72\x9f\x4d\xd8\x71\xae\x2c\xd7"
> > +	"\x59\x60\xd9\x14\x88\x93\x9d\xd7\x56\x1e\x6b\xa0\x46\x23\x69\x82"
> > +	"\x95\xb2\xa0\x66\xe4\xc2\x7b\xee\x44\x51\x93\xb8\x4d\x8b\xa4\x24"
> > +	"\x57\x94\xaf\xb6\x26\x02\x7b\x00\xd9\x84\xda\x51\xcc\xce\x4c\x63"
> > +	"\x90\x98\xb3\x13\x2a\x85\xec\x77\x52\x69\x79\x9f\x37\xb8\xa3\xfb"
> > +	"\x2b\x76\x39\x1a\x6a\x99\xd7\x0f\xa5\xc7\xa3\x55\xc3\x99\x59\x47"
> > +	"\x2b\x36\x1e\xe9\xf0\x8d\x85\xb9\x0d\x26\x57\x50\xce\x0a\xf6\xdc"
> > +	"\xb2\x60\x21\xe8\x76\xfd\x15\x7a\x9a\xe4\x7c\xd8\x17\x0e\x58\x6b"
> > +	"\x86\xf6\x7f\xf0\x69\xf8\x1c\xc3\x6c\x5a\xf7\xe9\xd5\xf0\x5d\xfc"
> > +	"\x50\x5a\x89\x7a\xad\xaa\xa5\x39\xe4\x08\x42\xf6\xc2\x23\x90\xf0"
> > +	"\x66\x39\x8b\x27\xe3\x05\x21\x43\x21\xc9\xe6\xd6\x21\xa2\xda\x34"
> > +	"\x5b\x34\x58\xe6\xef\x93\x02\x96\xa4\xa4\x86\x12\x12\xdd\x67\x10"
> > +	"\xc4\x5e\xf3\xca\x79\xfd\x65\x29\xee\xe6\xb9\x1c\x0a\x20\x98\x74"
> > +	"\xd6\xc4\x3f\x10\xe0\xee\x31\x53\x05\xa8\xb4\x2d\xa1\xde\x26\x30"
> > +	"\x80\xc6\x13\x9d\xf0\x67\x51\xd1\xfb\x09\x22\x02\x2b\x51\x92\x3e"
> > +	"\x36\x36\x6c\x5b\xcf\x00\xf9\xa4\xa0\x20\x06\x46\x87\x3b\xc5\x19"
> > +	"\x8d\x43\x7b\x57\xd7\xe0\xa4\x2e\xe9\x6d\xe7\x64\x1a\x77\x1f\xf7"
> > +	"\x99\x5b\xc8\x43\x39\x62\xbc\x1f\xff\xb4\x4a\x2a\x5c\x06\x3f\x04"
> > +	"\xb0\xea\x22\x83\xa5\x50\xae\x4a\xf8\x90\xd0\x4a\x61\xe2\xba\x45"
> > +	"\x0d\x7a\xba\xeb\xfe\xd1\x22\x61\x8b\xa2\x46\x9c\x74\x10\xd0\x66"
> > +	"\x92\x7c\x01\x56\x3a\x30\xb9\xc3\x3e\x57\x1a\x0c\xdb\xa6\xc3\x64"
> > +	"\xd5\xff\x06\xa3\x46\x33\x8a\x1a\x6d\x5d\x07\x0d\xbf\x88\xf2\x38"
> > +	"\x41\xf9\x2d\xbc\xb2\x55\x6d\xa0\xf7\xc1\x9e\x64\x51\xf8\xb4\xea"
> > +	"\x35\x8b\x11\x80\xe3\x6c\xa2\xb6\x3b\xed\xaa\xdd\xf3\x69\xfa\xa2"
> > +	"\x53\x1f\x22\xa8\x28\x8f\x57\xe1\x41\xbf\xcc\xb3\x3d\x86\x47\x7a"
> > +	"\xa3\xc1\xd4\xfe\x0e\xfa\x6b\x95\x4e\x1a\xbf\x33\x50\x9d\x2a\x7d"
> > +	"\x28\x0a\x64\x4d\x26\xae\x17\x65\x65\xe8\x55\xd0\x63\xf4\x1d\x03"
> > +	"\x5c\x9f\xe9\x1b\x25\x12\x7c\x06\x41\xc0\x90\xb9\x9c\x17\x02\xf8"
> > +	"\x7a\xef\xe5\x63\x7d\x8b\x38\x7a\x3c\x85\xdc\xdf\xad\x47\x5e\xef"
> > +	"\x0d\x96\x7d\xed\xf2\xc5\x00\x1a\xd2\x09\xef\x1e\xff\xc3\x8b\xd0"
> > +	"\xbc\xb8\x36\x76\x13\x33\xbd\xda\xa0\x1e\x02\x6c\x44\x8a\xd8\x7c"
> > +	"\x3e\x7d\xc9\x66\x5e\xf3\xbe\xb1\x72\x8e\xfc\xbc\xe5\x99\x30\x89"
> > +	"\x88\x91\x34\x3f\x9d\x2f\xfe\xa5\x1e\xb1\xef\x82\x23\x62\x91\x25"
> > +	"\x22\x0a\x8a\xdb\x39\xe4\x5b\xf8\x2a\x75\xb7\x38\xff\xef\xca\x45"
> > +	"\x9a\x57\xfb\xb3\xfe\xfb\x6d\x8f\x2e\xb1\x62\x64\x6d\x39\x57\x8d"
> > +	"\x95\xe7\x79\xdd\x98\x3e\x68\xaa\x12\x50\x7b\x0e\xa2\x2b\x89\x52"
> > +	"\x9f\xca\xd5\xc1\x22\xc2\x6f\x54\x83\xbd\xd7\x2c\xbb\xba\x50\xda"
> > +	"\xad\x42\x93\xe7\x86\x9d\x60\xf5\x33\x1b\x7f\xaa\x75\x65\xbd\xa8"
> > +	"\x34\x15\x6d\x1c\xf7\x47\x1f\x94\xdc\xab\xa8\x14\x93\x69\xdd\x2c"
> > +	"\x3b\xf9\x21\x11\x36\x80\x63\xec\xc9\x8e\x78\x48\xb4\x31\xac\xa0"
> > +	"\x48\x00\x3e\xed\x6f\xb3\xb0\x15\xc9\x24\x72\x24\x5b\x51\x7c\x65"
> > +	"\xbb\x24\xb6\xb1\x53\xfd\x3f\x36\x7a\x6c\xbf\xec\x90\xcc\xd9\x01"
> > +	"\x03\x30\x9e\xe3\x4a\x97\xcc\x3a\x35\xc6\x4a\x2b\xd3\x18\xbc\xb1"
> > +	"\x1f\x64\x08\xa0\xf8\x84\x34\x36\x3a\x91\x1a\x28\x72\x98\xdd\x1a"
> > +	"\xbe\xb1\x32\x77\x95\x72\x7e\xc5\xc1\xd7\x3b\xf8\x1e\x55\xc2\xdd"
> > +	"\xed\x24\xdb\x1b\x9b\x0e\xd1\x07\x01\x85\x41\x90\x3c\x90\x6a\xf2"
> > +	"\x0a\x8b\x4b\x7e\x9e\x87\xed\xa8\xa8\x8c\x5a\x4c\x4d\xc3\xb5\xec"
> > +	"\x7a\x4d\xe1\x51\xf0\x00\x64\xb9\xc3\x6e\x61\x2a\x41\xd5\x2e\x0e"
> > +	"\xf1\x1e\x87\xe5\xd5\xe4\xcc\x1a\x36\x7e\x5d\x96\x02\x14\xce\xaf"
> > +	"\xa2\xbb\x61\x05\xf4\x2e\x64\xba\x17\xff\x18\xc8\xe1\x17\x8a\x02"
> > +	"\x6b\x22\xe5\xd4\xd0\x68\xf6\x9c\x10\xf0\x2d\x4f\x82\xb3\x21\xb4"
> > +	"\xaa\x7f\xff\x6b\x7e\x9a\xf2\x12\x44\x4a\xa5\xbb\x16\xb6\x56\x6e"
> > +	"\xb1\x20\xb4\xb0\x34\x8f\xe4\x94\xb2\xf6\x7f\x9f\x05\xd0\x42\x30"
> > +	"\x04\xdb\x11\xb8\xd7\x5a\x1b\xb6\x06\xed\x6e\x9c\x69\x6d\x2c\x0f"
> > +	"\x6f\x7f\xf3\x9c\x76\x2e\xad\xc2\xd6\xc6\xfd\x93\xc1\xee\x25\xbb"
> > +	"\xc8\xc6\xb5\xd1\x37\x65\xdd\xe5\x78\xb0\x89\x0a\x91\x4a\xe1\x17"
> > +	"\x61\x43\x18\x47\xf3\xc2\x2a\x22\xc2\x56\x4e\x01\x31\xa3\x0b\xc7"
> > +	"\xe6\x53\x27\xa8\xc8\x32\x25\x69\x7c\x8b\x8e\xb1\x2b\xc6\xc9\x85"
> > +	"\x05\x1d\x67\x1e\xc6\x10\xa3\x60\x46\xbf\x9d\x5b\x3f\xda\x1f\xd3"
> > +	"\x8b\x1a\x95\x88\xa2\x16\xb0\xdd\x7f\x46\x2f\x5f\xef\xa0\x17\x0e"
> > +	"\x5e\x19\x20\x8c\xeb\x97\x52\xc8\xe0\xdc\xc0\x40\x0a\xd1\x84\xc1"
> > +	"\xa6\xb2\xf4\x6c\xc7\x8d\xc9\xd4\xb8\xc3\xe3\xe5\xf9\x8a\xc5\xdb"
> > +	"\x04\x2a\x89\xa5\x92\x64\x3f\x91\xd0\x60\x97\x8a\x42\x2d\x4b\x2c"
> > +	"\xf8\xa7\xe2\x68\xf9\xd3\x94\x1c\x24\xe8\x80\xff\x05\xa7\x02\xab"
> > +	"\x66\xd7\xb9\xa3\xeb\xd5\x0f\xf7\x26\x4f\x8f\x6b\x5a\xb2\x7c\xda"
> > +	"\x1a\xb3\x83\x5f\xbc\xcc\xfc\x50\xc8\x24\x8c\x38\x9d\x80\x79\x50"
> > +	"\x9d\x84\xe8\xee\x85\x19\xf3\x73\x5a\xd2\x41\x92\xde\x87\x5f\x52"
> > +	"\x62\x91\xbe\x90\x1e\xce\x54\x13\x68\x35\x3e\x2b\xe5\xa2\x1e\xc0"
> > +	"\xc1\x2f\x9c\x52\xd9\xe1\x5c\xe4\xfd\x21\xa3\x5a\x51\xb3\x01\x9d"
> > +	"\x22\x2c\x6c\xa8\xb9\xda\xfb\x78\xa8\x24\x1f\xef\xe9\x1c\x38\x04"
> > +	"\xf5\x8b\x80\xca\xe6\xb9\x76\x27\x31\xe1\x24\xf0\x07\xf9\xa9\x11"
> > +	"\x77\x9a\x8a\xc1\x87\x21\x49\x1b\x6e\x94\x94\x4e\xe7\x3a\x10\x00"
> > +	"\xd1\xd7\x02\xbf\x53\xe7\x88\x4e\xab\x63\x35\x61\x39\x81\x45\x21"
> > +	"\x85\x35\x4b\x44\xca\xc0\xdb\x8f\xa3\x6a\xc7\x90\x12\x7a\xd5\x94"
> > +	"\xd7\xfe\x30\xb2\x0f\x51\x52\xd0\xe6\xa7\xbe\x52\x2d\x45\xba\xed"
> > +	"\xbc\x3c\x95\x35\x50\x3f\x83\x97\xa8\x8f\x7e\xfb\x2e\xa3\x5b\xe1"
> > +	"\x2c\xb9\x15\x79\x62\x28\x8f\x02\x47\x31\x63\x2f\x45\xa7\xa7\x21"
> > +	"\xa4\x26\x17\x2f\x46\x72\x22\x44\xed\x3a\xff\x0a\x80\x27\xb7\xaa"
> > +	"\xa3\x9e\xe3\xb7\x71\xd2\xd9\x98\xa2\x6a\x5b\x18\x70\x6b\xfa\xf3"
> > +	"\x9f\xcd\xa9\x4c\xca\x97\x76\x41\x98\xb2\x8b\x98\x23\x88\xe7\x1e"
> > +	"\xa3\xd3\x56\x9a\x48\xf1\xd8\xf5\xd5\xf5\xd2\xff\x60\x52\x82\xeb"
> > +	"\xe8\x92\x5c\x36\xfc\x32\xfe\x46\x2d\x9a\xbd\xb8\xc2\x37\x63\xee"
> > +	"\xbe\x69\x4c\x98\x3d\x3d\xa3\x76\xe7\xbe\x8b\xb9\xe2\x07\x4b\x9a"
> > +	"\x55\x44\x71\x6e\x7d\x7f\xb0\x31\x55\xb8\x74\x82\x9c\x47\xf9\xdc"
> > +	"\x9a\x21\xd3\xbb\x47\x22\x05\x3b\x4b\x00\x31\xe1\x7f\x9d\xcf\xd1"
> > +	"\xde\xeb\xd6\x2a\xd9\x0b\xa8\x34\x03\xc3\x66\x34\x1f\xcb\xe8\xd8"
> > +	"\xf2\xf9\x4a\x3f\x6e\x8e\x3f\x8b\xce\xef\x9d\xe9\xf9\x92\x33\x7d"
> > +	"\x8a\x61\x2f\x5c\xaf\x5d\x4c\x66\x30\x37\x09\x3f\xd0\x5e\xe6\x43"
> > +	"\xef\x03\x63\x63\xc5\x39\x2b\xa8\x09\x5a\x86\x78\x5c\xa0\xa0\x5c"
> > +	"\xa1\xba\xb7\xbc\xdb\xd7\x70\x60\x81\x20\x19\x72\x82\x85\xed\x96"
> > +	"\x58\xa9\xdb\xa2\xcc\x03\xfc\x00\x92\x46\x3c\x79\x30\xce\xe0\x8f"
> > +	"\xa0\x91\xd5\x16\xcc\x46\xce\xf2\x4a\x62\xaa\x1d\x80\x2f\xf5\x45"
> > +	"\x7b\x9e\x97\xd7\x94\x39\x73\x6d\x5a\x25\xe4\x46\xb9\x6c\x58\xcc"
> > +	"\xa7\xc9\x9b\x81\x9a\x98\x05\x0b\x82\xb4\xb1\xc5\x08\x71\x15\x1f"
> > +	"\x26\x86\x26\x7b\xa8\x47\xaf\x80\x42\x2d\xd1\x68\x07\xb6\xa3\x81"
> > +	"\xc5\x40\x6e\xf7\xf6\x66\x81\x2d\x1e\x65\x01\xae\x2c\xaa\x59\x7c"
> > +	"\x90\xa4\xfd\x34\x04\x73\x3a\x40\x1a\x2b\x9f\x35\x4b\x25\x17\x8f"
> > +	"\xe5\xe6\x99\x0f\x1e\x23\xed\x95\xfe\xf6\xa3\x90\xd3\xca\xd4\x22"
> > +	"\xb4\x8b\x66\xac\xe9\xf3\xaf\xc8\x1b\xaa\x9f\x92\xc0\x19\x3c\x01"
> > +	"\x66\xc6\x07\xed\x82\xbe\x60\x08\x6a\x94\xfc\x79\xfa\x3c\xb5\x24"
> > +	"\xb1\xc8\x7f\xf3\x53\x20\x90\x1f\x07\x06\xd4\xf6\x7f\xeb\xcb\x96"
> > +	"\x5f\xd8\x2b\xd2\x7e\x44\xaa\x62\x75\x43\xfa\xc9\xfa\x27\x78\xe7"
> > +	"\xe7\x61\xc2\xc2\xd2\x87\x24\x75\xab\x22\x4d\xc4\xbe\xa2\x9e\xe6"
> > +	"\x2e\xc3\xee\xd3\x37\x69\x02\x50\x13\xcb\xa3\x65\xf2\xdd\xed\xbc"
> > +	"\x15\x68\x20\x50\x6d\xe4\x8a\x8b\x9f\x45\x39\xc5\xe4\xf1\x74\x7a"
> > +	"\xf5\x0f\xa5\x94\x5a\x5a\x3c\x0c\xd0\xb1\x5e\x27\xd5\x8a\x98\x15"
> > +	"\x24\x65\x24\x15\xcb\x7e\xee\x62\x0b\xbd\xf4\xb0\x32\x31\xb3\xc3"
> > +	"\x21\x58\xe5\x7a\x69\x0e\x28\x9e\x00\x75\x71\x47\x81\x52\x9f\x6d"
> > +	"\xc8\x80\x19\x1d\xaf\x76\x9f\x3a\x11\xa0\x6d\xe8\x43\xba\x73\xef"
> > +	"\x85\x61\x09\x7a\xe2\x82\x44\xaa\xf2\x3a\x56\x08\x46\x04\x7e\x65"
> > +	"\x83\xcf\xbc\xaa\x8a\xa3\xb4\xf8\x44\xb0\x43\x0e\xcd\x25\x40\x0b"
> > +	"\xd7\x7c\x8c\xf9\xae\x42\xc9\xea\x2e\x3e\x83\x6a\xd8\xd4\x44\x23"
> > +	"\x14\x33\x27\x00\x49\xdb\x61\xb5\x51\x52\xe4\x54\xbe\x05\xc9\xd6"
> > +	"\xe3\xc2\x1a\x07\xf3\xbf\xd3\xb1\x1d\xb4\x88\xda\x62\x09\xb8\x94"
> > +	"\x2a\xcc\x24\x22\x46\xe9\x6f\x99\x6d\xbf\x24\xa3\x9a\xc3\x3f\x42"
> > +	"\x88\x5f\x36\x45\x68\xce\x95\xb3\xe5\x7f\x9c\xe3\xd6\xe5\xb9\xd5"
> > +	"\x40\x36\xb8\x36\xc8\x88\x9a\xf7\xcf\xe0\x76\x56\xb3\x9a\x0d\x68"
> > +	"\xc0\x60\x94\x9e\xdb\x14\x81\x95\xb3\xdd\xe5\xeb\xf2\x14\x18\x56"
> > +	"\x74\x7b\x81\x9d\xb1\xd2\xed\xef\xf1\xf8\xfc\x41\x4c\x66\x77\xbd"
> > +	"\xc9\x16\x32\x3f\x8f\x9a\xa7\xc2\xe1\x1c\x1f\x44\x48\x54\xd3\xe0"
> > +	"\x00\x00\x00\x00\x00\x00\x00\x00\x04\x0c\x1a\x20\x28\x2f"
> > +};
> > +
> > +static const u8 nist_mldsa_fips204_35_data[] __initconst = {
> > +	"\x88\x45\xad\x39\x4b\xce\x60\xb2\x84\x76\xb2\x13\x99\xb0\xd4\x72"
> > +	"\x6b\xb3\xfe\x5f\x4d\x43\xde\x87\x62\xa4\xce\x19\x1b\xba\x7c\x13"
> > +	"\xb5\x2e\x1e\xc9\x59\x02\x99\x0b\x89\x7b\xe9\xe9\x6a\x9a\x25\x8f"
> > +	"\xdb\xd4\x6b\xaa\xe2\x2a\x3d\xa7\x0e\x07\x3b\xe5\xda\xea\x2d\x6e"
> > +	"\x60\x1c\xad\xbe\x3f\xb0\x47\xd7\x5e\xe0\x8a\x8a\xeb\xec\x8e\x9e"
> > +	"\x89\xa8\x03\x49\x29\xdd\x30\x63\xed\x5d\x79\xa1\xd9\xf7\xec\x13"
> > +	"\x06\xd5\xd6\xf9\x38\xae\x37\xdf\x1d\x95\x87\x12\x8d\x2a\x05\x88"
> > +	"\xa8\x15\xdc\xc6\xfe\x33\x44\x36\x16\xe6\x6c\x76\x8f\x65\x6c\xe6"
> > +	"\xf3\x18\xb5\xf1\x74\x37\xb3\x66\x6f\x01\x7c\x6d\x14\x47\x4a\x59"
> > +	"\xd4\x09\x06\x46\xde\xe0\x2b\xbc\xc6\x4a\x31\xec\x14\xa6\xe0\x9a"
> > +	"\x03\x9c\x5a\xd8\x84\xda\x91\xaf\x5b\xba\xa7\x2a\xef\x0a\x81\x47"
> > +	"\xd3\x81\x1d\x70\xff\x70\x82\x4d\xf0\x3a\xcb\x06\xe7\x0e\x20\x16"
> > +	"\x2b\x6c\x78\x95\x8e\x1d\xdb\xf2\x79\x06\xb6\x60\x2e\x1c\xf6\x92"
> > +	"\x50\x18\xfb\x35\xbd\x0c\x07\x7b\x31\xe9\xf5\x5f\xcc\x0b\xb6\x12"
> > +	"\x1b\xd5\x46\xe6\x9d\xd2\x5f\xce\xb6\xdb\x7c\x07\xeb\xb4\x37\xe6"
> > +	"\x9a\x98\x11\x9d\x21\x3c\xec\x71\x53\x15\x68\xee\xec\x91\xcd\xf6"
> > +	"\x0d\xa2\x14\x65\x02\x90\x2b\x62\xb5\x1c\x71\xa9\x7e\x5a\x90\x99"
> > +	"\xd7\xe1\xf1\x9a\x01\xc3\xb4\x2f\x3b\x48\x77\xc8\x34\x15\xea\x28"
> > +	"\x85\xfb\x61\x7c\x4d\x0e\xc8\x8b\x32\x12\x60\xd5\x6b\x27\xba\xca"
> > +	"\xdd\x9c\x04\xd7\xba\x52\xf1\x6f\x1e\x62\x74\xca\x1c\x5d\x75\x16"
> > +	"\xf1\xdd\xd1\x38\x25\x6e\x36\xdb\xb8\xab\xec\xf3\x33\xd2\x91\xaf"
> > +	"\x13\x94\x26\xaa\x2b\xdc\x05\x57\x33\x87\xea\x84\xea\x81\x37\x1f"
> > +	"\x06\x94\xa8\xfd\xd7\xce\x5e\x03\x46\x2f\xb3\xbf\xa9\x25\xf6\x09"
> > +	"\xe6\x5f\x4c\x54\x7d\x7b\xaa\x99\xda\xa9\x07\x84\x72\x7d\x0b\x6c"
> > +	"\x6b\x96\x18\x2a\xdb\x78\x0f\x5f\xe8\xa3\x25\xd6\x76\xe0\x00\x3b"
> > +	"\x0b\x5c\x02\xf6\xee\xa3\xb5\x1e\xbe\x83\x76\xe7\x2e\x47\xa7\x6c"
> > +	"\x05\x2a\xa0\xaa\x60\x02\x65\xe9\x55\x3a\xf7\x33\x9a\x69\x1d\x50"
> > +	"\x91\x35\xcb\x19\xea\x11\x97\x0c\x40\x79\x2c\x41\x61\x64\x9a\xdf"
> > +	"\xd6\xbf\x40\x94\x31\x92\x71\xd6\x76\xec\x07\x85\xaf\xf5\x98\xeb"
> > +	"\xc5\xd7\x4c\xc8\x26\x7e\x2c\x45\xbf\xd2\x3c\xd1\xd9\xdc\xd5\x5d"
> > +	"\xc0\xa7\x29\x32\x55\xe3\x28\xdd\xfe\xf2\x97\x16\x57\x56\xde\x7c"
> > +	"\x4b\x06\x1d\x37\xc1\x5a\x87\xff\xf2\x95\x77\x5a\x6f\x6f\xc9\x0d"
> > +	"\x02\x5f\xdc\x8e\x72\xe3\xf1\xe2\x0e\x0d\x23\xae\x7d\x1e\xdb\x36"
> > +	"\x2c\xab\x41\xa2\xe9\xd8\xbc\x9c\x35\x9b\x16\x47\xc5\x37\xeb\x21"
> > +	"\xa0\x15\x34\x32\x8d\x0a\x28\x8c\xa8\x07\x0f\x7e\xf7\xbc\x9b\x08"
> > +	"\xdc\x3d\x91\x5a\x90\x69\x23\x37\x91\x6a\x98\x9b\x70\x9a\xea\x1d"
> > +	"\x8c\x1a\x6a\x19\x27\xb7\x74\xbd\x06\xd1\x0c\x0d\x0f\x4e\x06\xce"
> > +	"\x37\x86\xe1\xb0\x55\x77\x3b\x0b\x2f\x5c\xea\x01\xc8\x2f\x5e\xb5"
> > +	"\x14\x1e\xcc\xfe\x8a\xd3\x8f\xbe\xed\xe6\xd1\xcc\x74\x52\x93\x7c"
> > +	"\x6c\x60\xcb\xcf\x4f\xfe\x3c\x58\x18\xf5\xed\xb7\x75\x61\xa3\xd8"
> > +	"\x9e\x81\x5f\xa2\xca\x73\x2e\x02\x55\x31\xae\x91\xcf\x53\x00\x1c"
> > +	"\x13\x60\x63\x6b\x07\xfc\x36\x74\xc0\x96\x71\xb9\xd6\xe5\xef\x9c"
> > +	"\x77\xa1\x1f\x75\x6f\xa6\xdc\xd0\xcc\xd3\xcb\x86\x72\xfd\xee\x89"
> > +	"\xae\xc4\x9c\x65\xfd\x1b\x7a\xbd\xf6\xcf\x49\xa6\x43\xfb\xd6\x21"
> > +	"\xb8\x21\x8e\xbe\xdc\xaf\xe0\xb0\xc6\x61\x87\x82\xba\x2d\x43\x0a"
> > +	"\x3d\xb4\xb5\xac\x07\xa8\xbd\x06\x60\xfc\x24\x50\x56\xa2\x31\x54"
> > +	"\x55\x86\xb4\xb6\x07\x2c\x3d\x63\x70\xa4\x0e\xbb\x22\xda\xba\x1b"
> > +	"\x1f\x9f\x49\x75\x50\x2b\xa7\x6c\xd7\x95\xeb\x1a\x13\x51\x54\xd4"
> > +	"\x1d\xaa\x5d\x74\x49\x63\xaa\x86\x29\x05\xd8\xaf\x15\x94\x9c\x4b"
> > +	"\x17\x37\xa2\xab\x77\x4f\xfe\xb2\xfb\xfd\x19\xb1\xb2\x67\x68\x49"
> > +	"\x53\x23\x50\xbe\x26\xd1\x53\xc1\x4b\xc0\xc4\x4e\xde\xa2\x6a\xf0"
> > +	"\x47\x9e\x82\x7b\x9a\xa8\xf7\x6d\x68\x83\x46\x9c\x25\xf5\x47\xed"
> > +	"\x53\xb6\x52\x7f\x85\xe3\xe9\x99\xb3\x3d\x53\x6e\xbc\x67\x36\x41"
> > +	"\x9a\x3e\xa7\xfa\x55\xbc\xff\xa6\xa2\xd5\xa2\x10\x6b\x07\xff\x9f"
> > +	"\x2f\x80\xb5\x14\xe4\x04\x2e\xee\x98\xd7\x38\x9a\x4e\x9a\x43\x0b"
> > +	"\x93\xb2\xa3\x24\x94\x76\x6e\x09\xca\x37\x83\xb4\xd2\x81\x71\xec"
> > +	"\xd7\xa2\x09\xff\x72\xc9\xf4\x3e\x62\x3b\x70\xc3\xc5\xc9\xdd\x26"
> > +	"\x8a\x75\x91\xdc\xf3\xd6\x41\x38\x80\x28\xdd\xd9\x42\x91\x2a\x08"
> > +	"\x9a\xfe\x64\x2b\xc0\xcd\x80\x25\x8f\x97\xfa\xd6\xae\xee\x31\xa8"
> > +	"\x10\xc6\x45\xfc\x89\x0c\xea\x3b\xce\xc9\xcc\xf2\xef\x83\xd5\x5c"
> > +	"\x12\x1e\xb2\xf7\x72\xed\xec\xcf\x71\x1b\xe8\xdd\x12\x0f\x02\x4c"
> > +	"\x1b\xcd\x5c\x17\xee\x3c\x26\x4d\xf5\xd6\x19\xad\x9c\xf2\x41\x77"
> > +	"\x75\x0c\xe6\xb0\x3b\x4c\x75\x6d\xde\x34\x39\xb0\x59\xdf\x11\xe7"
> > +	"\x77\x69\xe5\x30\xfb\x4a\x69\xf8\xcf\xee\x44\xe7\x5a\xca\x04\xab"
> > +	"\xcc\x42\xbd\x23\xf7\x79\xb6\x00\xfd\x57\x62\x57\x34\xf6\x3b\x39"
> > +	"\xbd\x74\x77\xa1\x9d\x0d\xb9\x32\x30\xdd\x29\xf2\x4d\x72\xc5\x40"
> > +	"\x8c\x6d\xa6\x94\x19\xcf\x5b\xee\x0a\x82\x3e\xb5\x7d\x99\xd5\xf9"
> > +	"\xe0\x91\x5a\x1f\x0b\x90\x18\x73\xd6\xd7\xf2\x53\x68\xc1\x83\x3b"
> > +	"\x0c\xdf\xf1\x0a\xef\x1b\xcb\x17\x94\x83\x31\xb6\x81\x90\x0a\x23"
> > +	"\x30\x92\xb3\xd0\xae\xd2\x20\x7d\x78\x96\xb0\xe5\xe6\xef\x72\x3b"
> > +	"\x38\xbf\x45\x87\xbd\x06\x8b\x93\x62\x08\xf1\x2b\x0e\x91\x09\x87"
> > +	"\xbd\xd9\x42\xda\xfd\xbc\xfa\x52\x66\xae\x10\x7a\xaf\x2d\x1f\x85"
> > +	"\xae\x3f\x47\x8a\x17\xc7\xfc\x73\x6c\xb0\x8c\xa8\x24\x87\x2c\x88"
> > +	"\x11\x5f\x13\x06\x75\x20\x7b\x80\x4a\x5d\x4e\xba\x79\xf7\x44\xee"
> > +	"\xb1\x16\xb2\x3a\x19\x1a\xe6\xd0\xe0\xb8\xfb\x78\x3c\x44\xaf\xb5"
> > +	"\x69\x8a\x72\xf3\x1c\xd1\x9c\x61\x7a\x61\xa5\xfe\x98\xdd\x2c\x67"
> > +	"\x29\xc8\xed\xd4\x3c\x95\x13\x83\x53\x30\xd7\x12\x82\xf5\xe1\xef"
> > +	"\x5c\xe6\x97\xa6\x5f\x6d\xb7\x9e\xeb\xef\xd0\x2d\x9e\x3a\x00\xb8"
> > +	"\xcb\x7d\x6d\x1d\x34\x0c\x9c\x00\x30\xd1\x61\xd4\x70\x87\x50\x4b"
> > +	"\x8e\x43\x39\x98\x95\xf7\xe4\x96\xe6\x21\xe0\xd9\x96\x44\x54\xb5"
> > +	"\x04\x47\x9a\xd3\x40\x6f\x33\x95\x7f\x2c\x9e\x43\x04\x9d\xc0\xcc"
> > +	"\xc8\x67\x71\xf2\xf0\x05\x00\x65\x50\xad\x8d\x68\xa1\x1c\x2d\xcf"
> > +	"\x15\x65\x72\x30\x53\x19\xb2\xff\x36\x29\x9e\x95\x5d\x35\x44\x73"
> > +	"\x8a\x82\xf5\xc4\x13\x69\x1b\x76\x78\xee\xec\xf2\x6f\x6a\xbf\x1d"
> > +	"\xc2\xfb\x79\x48\x11\x4b\x4e\xbd\x2b\x84\x5c\x0b\x7b\x78\x54\x3d"
> > +	"\xa0\xfc\xd2\x61\x39\xf0\xca\x8e\xae\x83\x7b\xa2\xd7\xde\x84\x93"
> > +	"\x34\x19\x0e\xb1\x72\xe5\x70\x5c\xe3\x2f\xb4\xdd\xf8\xc9\xfa\xf4"
> > +	"\x90\xc3\xd1\xf3\xfd\xf4\x37\xd1\xad\xeb\x2e\x82\xa7\x31\xec\xdf"
> > +	"\x62\x54\xd4\x75\x6d\xe4\x00\x71\xef\xd0\x55\x71\xc1\x77\x79\xdc"
> > +	"\x06\x23\xd4\xc3\xbd\xe6\xe8\x09\x8f\x7c\x96\x73\x57\x60\x2d\x38"
> > +	"\xa0\x75\x55\x71\xa6\x00\x18\x65\x87\x8e\xd9\xe5\xfd\xc6\x4d\x43"
> > +	"\x5e\x85\xe2\xd5\x6a\x8c\x55\xb7\xc6\x7a\x75\x86\x4a\x88\x00\xc9"
> > +	"\xb6\x53\x37\x0e\xbb\xd8\x62\xe8\xf9\x3f\x50\x12\x9e\xae\x84\x04"
> > +	"\x02\xe0\xfb\x58\x29\xe4\x8b\xd7\x83\x10\x4a\x08\xe8\x12\xa4\xd8"
> > +	"\xa1\x77\x94\x82\xcb\x4f\x24\x5a\xdd\x0c\xb9\xf6\x64\xd8\xc7\x11"
> > +	"\x83\x5e\x98\xee\x60\xa2\x41\x4b\xd5\x02\x5e\xdf\x32\x40\xf4\xb3"
> > +	"\x35\xb5\xeb\x65\xbf\x08\x63\x9b\xcf\x5b\xfa\x6b\x2f\x61\xda\xe1"
> > +	"\xef\x7d"
> > +};
> > +
> > +static const u8 nist_mldsa_fips204_35_sig[] __initconst = {
> > +	"\x30\x82\x0d\x61\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x07\x02\xa0"
> > +	"\x82\x0d\x52\x30\x82\x0d\x4e\x02\x01\x01\x31\x0d\x30\x0b\x06\x09"
> > +	"\x60\x86\x48\x01\x65\x03\x04\x02\x03\x30\x0b\x06\x09\x2a\x86\x48"
> > +	"\x86\xf7\x0d\x01\x07\x01\x31\x82\x0d\x2b\x30\x82\x0d\x27\x02\x01"
> > +	"\x01\x30\x17\x30\x0f\x31\x0d\x30\x0b\x06\x03\x55\x04\x03\x0c\x04"
> > +	"\x46\x72\x65\x64\x02\x04\x01\x23\x40\x23\x30\x0b\x06\x09\x60\x86"
> > +	"\x48\x01\x65\x03\x04\x02\x03\x30\x0b\x06\x09\x60\x86\x48\x01\x65"
> > +	"\x03\x04\x03\x12\x04\x82\x0c\xed\x6e\x8c\x4b\x20\x61\xc2\xcd\xf2"
> > +	"\x71\x54\xbf\x70\x85\xf6\x3c\xb1\x5d\xa3\xce\xc8\x2d\x52\xca\xd1"
> > +	"\xa6\x50\x80\x68\x75\x05\x25\x24\xda\xa1\xef\xdf\xf4\x6f\xde\x5e"
> > +	"\xff\x63\xef\xf5\x70\x74\x7c\x69\xfd\x23\x4b\xa3\xaa\x3b\xa9\xa8"
> > +	"\x0f\x48\x8b\xc4\x8f\x95\x9f\xf5\x6a\xb3\x17\x35\x5f\xfe\x91\x7b"
> > +	"\xdd\xd3\xbb\xf7\x3b\xf0\xa8\x22\x09\xbe\x25\x48\xcd\xca\x1a\x37"
> > +	"\xc4\xde\x57\x18\x56\x30\x19\xa9\x26\x99\x13\x9a\x6d\x6a\x69\xe9"
> > +	"\x64\x83\x2d\xdd\x70\xf5\xe8\x03\x75\xdc\x9f\xe0\xba\x8e\x22\xae"
> > +	"\x3a\xd8\xaa\xd9\x45\x84\x71\xcd\x37\x61\xb1\xb9\x04\xe8\xbb\xba"
> > +	"\x72\xfa\x8a\x07\x1d\xf1\x82\x55\x17\xff\xa2\x2e\x2b\xbf\xf9\x9a"
> > +	"\x0f\x86\x94\x06\xd9\x07\xdb\xc3\x16\x92\x90\xce\xd1\x4e\xb8\xee"
> > +	"\x7a\x2b\x6c\xe7\xc2\x6a\x0a\xe2\x8b\x32\x5e\xd4\x61\x38\x90\xaf"
> > +	"\xce\xbb\x38\xe6\xe9\xd5\x43\x74\xc9\xeb\x48\xd0\xe6\x00\x30\xa1"
> > +	"\x1e\x75\x03\xb9\x06\xe9\x16\x35\x7c\x6f\x81\xd5\x9f\x89\xcc\x36"
> > +	"\x33\x75\xcb\xf0\x1e\xd0\xd8\x51\x54\xd5\x5c\xb8\xfc\xe7\xb2\x17"
> > +	"\xd5\xed\xeb\xe9\x36\x85\xe0\xbe\x43\x4c\xb0\xc5\x67\xc8\x97\x62"
> > +	"\xb3\x80\x89\xec\x2c\xf3\x4c\x93\x87\x9c\x0b\x23\x5d\x44\x25\x6a"
> > +	"\x10\x3f\x21\x08\x7d\x8d\xfc\x99\x8d\xc5\xbe\xbe\x57\x5c\x5d\x4d"
> > +	"\x27\x7b\xa2\x2e\x81\xcd\x0a\xf1\x49\x2b\x43\xda\xc4\x36\x5c\xc6"
> > +	"\x91\x75\xd8\x95\xa6\x9b\xbf\xe9\x21\x45\x3c\x07\xae\x56\xcd\xf5"
> > +	"\x1b\x91\x56\xe4\x49\x40\x12\x58\x8a\xa4\xac\x32\x53\x93\xbe\xe9"
> > +	"\x8a\x65\xef\x71\xe3\x07\xc8\x4d\xb9\x35\x85\x4d\x06\x9b\xa4\x11"
> > +	"\x6a\x67\x7a\x5b\x49\xee\xea\xf2\x0d\x16\x49\x2b\x74\x46\x78\xcc"
> > +	"\x59\x12\x0c\x80\x6f\xae\x7d\x23\x30\x87\x7f\x16\x52\x04\x11\x41"
> > +	"\x0b\xba\x48\xbf\x49\xaa\x08\xf4\x44\x00\x75\x4a\x05\x79\x79\x66"
> > +	"\x31\x94\x44\x9e\x66\xf5\xc0\xd7\xa1\xeb\xb5\xda\xc4\xb6\x5c\xf9"
> > +	"\x20\x0b\x21\x89\xf6\x0f\xa5\x29\x48\xcb\x7a\x83\xd5\xfd\x54\x45"
> > +	"\xaf\xa3\x0d\x99\xe9\x14\x30\x06\x8a\x53\x51\x08\x0d\xa4\x24\xa6"
> > +	"\xf4\xae\x5f\x8e\x1b\x7b\xa6\x48\x1c\xfb\x39\xfc\x34\x2a\xcf\xa0"
> > +	"\x84\xb3\x79\xb7\xc7\x4d\x64\x0e\x0c\x04\x87\x31\x9f\xf6\x97\x02"
> > +	"\x8b\xe8\xc2\x13\x21\x8e\xfc\x85\x7c\xac\xfa\xc4\x44\x10\x3f\x2f"
> > +	"\x93\x02\x74\x44\x1f\x18\xdc\x2e\x17\xca\x18\x27\x86\x55\xfb\xc0"
> > +	"\x79\x4b\x50\x08\x33\x62\x4c\x58\x29\x20\x98\x95\x9f\x8c\x7a\xf7"
> > +	"\x82\xe1\x41\x43\xf3\x5c\x55\x54\xe3\x22\x60\xf2\xa4\x85\x17\x88"
> > +	"\x93\x6b\x6d\xc7\x48\xf6\xc0\x0b\x4b\xf0\x86\xc6\x64\xae\xd9\x22"
> > +	"\x08\x75\x35\xce\xf4\x7b\xad\xf2\xb6\x7d\x50\x6e\xba\xf6\x46\x30"
> > +	"\x7b\xbc\x60\xc3\xf7\xf7\xeb\x39\x44\x6a\x34\xde\xb4\x6f\x43\x3f"
> > +	"\xfb\xcb\x23\x60\xfb\x55\x57\xaa\x9a\x2e\x33\x29\x37\xd7\x9a\xb6"
> > +	"\x85\xa2\xad\x9b\x25\x42\x38\x83\x44\x85\x0e\xec\x19\x74\xa3\xdc"
> > +	"\x73\x4b\x30\xb9\x6b\x05\x63\xcd\xdb\xa3\x18\xed\xfd\xc2\x94\x1b"
> > +	"\xdf\x1f\x64\x6c\xd6\x29\x05\x58\xe0\x77\xb9\x1b\xd5\x40\xe6\xff"
> > +	"\x3b\x7e\x13\x2b\xef\xed\x35\x8e\x06\x69\x13\x8f\xe4\x93\x59\x34"
> > +	"\x54\x50\x16\x3c\xbb\x5b\xe2\xa4\x7a\xd5\x35\x60\x3a\x13\x8e\x7c"
> > +	"\x37\xf6\xb8\xfd\x1f\xa1\x1d\xd4\x25\x19\x54\xba\xe7\x8e\x7c\x59"
> > +	"\x40\xc3\x7a\xf2\x2c\x94\x78\xca\x02\x0a\x1d\x21\x4f\x97\x57\xbc"
> > +	"\x06\x36\x23\xce\x8d\xce\xdd\x39\x5d\x6b\x7b\xc1\xa8\x06\x90\x4e"
> > +	"\xbf\xaf\x28\xf0\xf8\xc5\xa6\x3a\x0c\x1c\xc6\x31\x4f\xe8\x05\x79"
> > +	"\x1d\x76\x57\x05\xf5\xfa\x33\x17\x1a\xb4\xc8\x51\xc2\x6e\x42\xc0"
> > +	"\xf9\xdc\xcf\x9c\x28\x37\xc1\x11\x42\x1d\x0f\x5f\xdc\xf9\xa9\xeb"
> > +	"\xa0\x9c\x25\xdb\x0d\x79\x65\xdc\x91\xdc\x4e\x63\x84\x1a\x76\xae"
> > +	"\x9a\x68\x7a\xd8\xb6\xe4\x90\x68\xcf\x74\xfa\xaf\xd8\xa6\x6c\x91"
> > +	"\x39\xd3\xc3\xa6\xbe\x06\x56\x3c\xb5\x7f\xe7\x73\x30\x14\x79\x57"
> > +	"\x4c\x68\xeb\x32\x94\xe3\x35\xf9\xf1\xbb\x7c\xfd\xf5\x0e\xa1\x13"
> > +	"\x92\xf0\x4f\x5f\x3b\xe9\x9c\xb2\x4b\x07\xa8\x91\x17\x34\x02\xef"
> > +	"\x38\xf7\x44\xdd\xf9\x27\xf0\x60\x1f\x70\xba\x50\xf8\xab\x84\x5f"
> > +	"\xf2\xa0\x12\x40\x1a\x99\xcf\x4f\x03\x36\x4c\x30\x82\xd4\x21\x81"
> > +	"\x91\x9e\x87\xd4\xac\x3b\x3b\xe1\xf9\x5a\xb6\x90\xfc\xda\x10\x6c"
> > +	"\x87\xc6\x3c\x7b\xed\xf1\x29\x08\xd6\xa0\xee\xc3\xb6\x72\x46\x1b"
> > +	"\xb1\x38\xec\xfd\x48\x01\x9a\x07\x7e\xf4\xe5\x90\x94\x8a\xbd\x08"
> > +	"\x3e\x28\xef\x4d\x06\x2f\x8e\x58\x3b\x69\xcb\x79\x80\x3b\x70\xde"
> > +	"\x5d\xea\x1f\x60\x00\x51\xd9\xed\xef\x2a\xed\x93\xa5\xd5\xbb\x5a"
> > +	"\xb7\xb5\xb1\x96\x84\x62\x25\xf6\xb0\x73\xdf\xbe\x40\x13\xb4\xc8"
> > +	"\x14\xae\x15\x20\x7d\xbb\x76\x0b\x97\xe6\xbc\xb7\x61\x7e\xb2\x6c"
> > +	"\xd3\xb5\xa4\x1b\xa6\xb5\xdd\x88\x45\x1b\x5b\xcc\xf5\x52\xdc\x49"
> > +	"\x3f\x85\xa1\xcf\x3a\xfa\xae\x80\x81\x89\xb2\xfe\xdf\x04\x47\x8e"
> > +	"\xde\x57\x94\x82\xa7\x11\xb2\x2b\x55\xd4\x8a\xb2\x18\x9e\x6c\x14"
> > +	"\xf6\xf8\x69\x84\x5d\x88\xf7\x8a\xf5\x40\x20\x24\x60\x5f\xa3\xe2"
> > +	"\x47\x32\xf9\x93\x17\x09\xac\x35\x9d\xfa\x74\x78\x17\xb1\x2c\x37"
> > +	"\xb0\xdc\x0b\xe0\x8b\x5a\xcf\x9d\x3f\x09\x6e\x44\xf4\xdb\xa0\x23"
> > +	"\x34\x76\xb2\x66\xf4\x2b\x92\x04\x0a\x9c\x88\x49\x6c\x80\xfb\x99"
> > +	"\x6c\x70\xfb\xd5\xdc\xce\x10\xd1\x1a\x72\x2b\x4e\x9e\x34\xe0\x60"
> > +	"\xf0\x06\x04\xd2\x55\x78\xc4\xea\xe8\x6b\x4a\x43\x7a\x14\xc7\x2c"
> > +	"\x83\x34\x63\xf4\x4c\xa5\xee\xb3\xf0\x02\x78\x57\x44\x69\x37\xed"
> > +	"\xda\x22\xb6\x3f\x86\x15\x81\xeb\x1f\xae\x69\x75\x29\x8c\x04\x83"
> > +	"\xff\x80\xad\x45\x18\x88\x6a\x78\x43\x1b\x93\xf8\xd4\x19\x89\x1d"
> > +	"\xbb\x85\x6b\x2f\x08\xdf\xc2\x27\x72\xbe\x36\xdb\x30\x7f\x3b\x36"
> > +	"\xfe\x81\x60\xad\xb9\xc1\xf8\x9b\x80\x31\xba\xb2\x42\xaa\x5b\x41"
> > +	"\x68\x06\x40\x41\xe1\xaf\xf6\x3f\x73\x67\xdd\x83\x92\x6d\xb6\x4b"
> > +	"\x21\xe1\x97\x7c\x62\x46\x36\xfd\x93\x8e\x26\x54\x20\x95\xb8\xdd"
> > +	"\x35\xb8\x87\xe8\xd7\x01\x10\x89\x20\xaa\x0f\x0c\x5e\x3d\xd1\xc1"
> > +	"\xc6\x98\x15\x38\xc5\x73\xe3\xbf\x08\x51\x83\x32\x56\x5d\x1a\xa9"
> > +	"\x0c\x4f\x2f\x16\x51\x16\xc9\x2e\x39\x8c\x5c\xe8\x95\x22\xc1\x19"
> > +	"\xf9\x8b\x38\x53\xc6\x55\x8a\x07\x13\xae\x00\xc3\xc2\xe0\x8b\x0c"
> > +	"\xdd\xb8\xf3\xdd\xca\x21\x1f\xfe\xdb\x9b\x28\x8f\x9e\xd8\x96\x02"
> > +	"\x6a\x2b\x35\x89\x6e\xcb\x65\xf3\xde\x3a\xa5\x3f\x38\xd9\x8f\xbf"
> > +	"\xa2\xb9\xc3\x6b\xaa\x2a\x28\x7a\xc6\xe6\xa0\xfc\xe3\x37\xfa\x60"
> > +	"\xf7\xdd\x4e\xcd\x5d\x64\xa8\x4b\xd2\x30\x40\x68\x92\x5f\xa3\x72"
> > +	"\x9f\x4d\xd8\x71\xae\x2c\xd7\x59\x60\xd9\x14\x88\x93\x9d\xd7\x56"
> > +	"\x1e\x6b\xa0\x46\x23\x69\x82\x95\xb2\xa0\x66\xe4\xc2\x7b\xee\x44"
> > +	"\x51\x93\xb8\x4d\x8b\xa4\x24\x57\x94\xaf\xb6\x26\x02\x7b\x00\xd9"
> > +	"\x84\xda\x51\xcc\xce\x4c\x63\x90\x98\xb3\x13\x2a\x85\xec\x77\x52"
> > +	"\x69\x79\x9f\x37\xb8\xa3\xfb\x2b\x76\x39\x1a\x6a\x99\xd7\x0f\xa5"
> > +	"\xc7\xa3\x55\xc3\x99\x59\x47\x2b\x36\x1e\xe9\xf0\x8d\x85\xb9\x0d"
> > +	"\x26\x57\x50\xce\x0a\xf6\xdc\xb2\x60\x21\xe8\x76\xfd\x15\x7a\x9a"
> > +	"\xe4\x7c\xd8\x17\x0e\x58\x6b\x86\xf6\x7f\xf0\x69\xf8\x1c\xc3\x6c"
> > +	"\x5a\xf7\xe9\xd5\xf0\x5d\xfc\x50\x5a\x89\x7a\xad\xaa\xa5\x39\xe4"
> > +	"\x08\x42\xf6\xc2\x23\x90\xf0\x66\x39\x8b\x27\xe3\x05\x21\x43\x21"
> > +	"\xc9\xe6\xd6\x21\xa2\xda\x34\x5b\x34\x58\xe6\xef\x93\x02\x96\xa4"
> > +	"\xa4\x86\x12\x12\xdd\x67\x10\xc4\x5e\xf3\xca\x79\xfd\x65\x29\xee"
> > +	"\xe6\xb9\x1c\x0a\x20\x98\x74\xd6\xc4\x3f\x10\xe0\xee\x31\x53\x05"
> > +	"\xa8\xb4\x2d\xa1\xde\x26\x30\x80\xc6\x13\x9d\xf0\x67\x51\xd1\xfb"
> > +	"\x09\x22\x02\x2b\x51\x92\x3e\x36\x36\x6c\x5b\xcf\x00\xf9\xa4\xa0"
> > +	"\x20\x06\x46\x87\x3b\xc5\x19\x8d\x43\x7b\x57\xd7\xe0\xa4\x2e\xe9"
> > +	"\x6d\xe7\x64\x1a\x77\x1f\xf7\x99\x5b\xc8\x43\x39\x62\xbc\x1f\xff"
> > +	"\xb4\x4a\x2a\x5c\x06\x3f\x04\xb0\xea\x22\x83\xa5\x50\xae\x4a\xf8"
> > +	"\x90\xd0\x4a\x61\xe2\xba\x45\x0d\x7a\xba\xeb\xfe\xd1\x22\x61\x8b"
> > +	"\xa2\x46\x9c\x74\x10\xd0\x66\x92\x7c\x01\x56\x3a\x30\xb9\xc3\x3e"
> > +	"\x57\x1a\x0c\xdb\xa6\xc3\x64\xd5\xff\x06\xa3\x46\x33\x8a\x1a\x6d"
> > +	"\x5d\x07\x0d\xbf\x88\xf2\x38\x41\xf9\x2d\xbc\xb2\x55\x6d\xa0\xf7"
> > +	"\xc1\x9e\x64\x51\xf8\xb4\xea\x35\x8b\x11\x80\xe3\x6c\xa2\xb6\x3b"
> > +	"\xed\xaa\xdd\xf3\x69\xfa\xa2\x53\x1f\x22\xa8\x28\x8f\x57\xe1\x41"
> > +	"\xbf\xcc\xb3\x3d\x86\x47\x7a\xa3\xc1\xd4\xfe\x0e\xfa\x6b\x95\x4e"
> > +	"\x1a\xbf\x33\x50\x9d\x2a\x7d\x28\x0a\x64\x4d\x26\xae\x17\x65\x65"
> > +	"\xe8\x55\xd0\x63\xf4\x1d\x03\x5c\x9f\xe9\x1b\x25\x12\x7c\x06\x41"
> > +	"\xc0\x90\xb9\x9c\x17\x02\xf8\x7a\xef\xe5\x63\x7d\x8b\x38\x7a\x3c"
> > +	"\x85\xdc\xdf\xad\x47\x5e\xef\x0d\x96\x7d\xed\xf2\xc5\x00\x1a\xd2"
> > +	"\x09\xef\x1e\xff\xc3\x8b\xd0\xbc\xb8\x36\x76\x13\x33\xbd\xda\xa0"
> > +	"\x1e\x02\x6c\x44\x8a\xd8\x7c\x3e\x7d\xc9\x66\x5e\xf3\xbe\xb1\x72"
> > +	"\x8e\xfc\xbc\xe5\x99\x30\x89\x88\x91\x34\x3f\x9d\x2f\xfe\xa5\x1e"
> > +	"\xb1\xef\x82\x23\x62\x91\x25\x22\x0a\x8a\xdb\x39\xe4\x5b\xf8\x2a"
> > +	"\x75\xb7\x38\xff\xef\xca\x45\x9a\x57\xfb\xb3\xfe\xfb\x6d\x8f\x2e"
> > +	"\xb1\x62\x64\x6d\x39\x57\x8d\x95\xe7\x79\xdd\x98\x3e\x68\xaa\x12"
> > +	"\x50\x7b\x0e\xa2\x2b\x89\x52\x9f\xca\xd5\xc1\x22\xc2\x6f\x54\x83"
> > +	"\xbd\xd7\x2c\xbb\xba\x50\xda\xad\x42\x93\xe7\x86\x9d\x60\xf5\x33"
> > +	"\x1b\x7f\xaa\x75\x65\xbd\xa8\x34\x15\x6d\x1c\xf7\x47\x1f\x94\xdc"
> > +	"\xab\xa8\x14\x93\x69\xdd\x2c\x3b\xf9\x21\x11\x36\x80\x63\xec\xc9"
> > +	"\x8e\x78\x48\xb4\x31\xac\xa0\x48\x00\x3e\xed\x6f\xb3\xb0\x15\xc9"
> > +	"\x24\x72\x24\x5b\x51\x7c\x65\xbb\x24\xb6\xb1\x53\xfd\x3f\x36\x7a"
> > +	"\x6c\xbf\xec\x90\xcc\xd9\x01\x03\x30\x9e\xe3\x4a\x97\xcc\x3a\x35"
> > +	"\xc6\x4a\x2b\xd3\x18\xbc\xb1\x1f\x64\x08\xa0\xf8\x84\x34\x36\x3a"
> > +	"\x91\x1a\x28\x72\x98\xdd\x1a\xbe\xb1\x32\x77\x95\x72\x7e\xc5\xc1"
> > +	"\xd7\x3b\xf8\x1e\x55\xc2\xdd\xed\x24\xdb\x1b\x9b\x0e\xd1\x07\x01"
> > +	"\x85\x41\x90\x3c\x90\x6a\xf2\x0a\x8b\x4b\x7e\x9e\x87\xed\xa8\xa8"
> > +	"\x8c\x5a\x4c\x4d\xc3\xb5\xec\x7a\x4d\xe1\x51\xf0\x00\x64\xb9\xc3"
> > +	"\x6e\x61\x2a\x41\xd5\x2e\x0e\xf1\x1e\x87\xe5\xd5\xe4\xcc\x1a\x36"
> > +	"\x7e\x5d\x96\x02\x14\xce\xaf\xa2\xbb\x61\x05\xf4\x2e\x64\xba\x17"
> > +	"\xff\x18\xc8\xe1\x17\x8a\x02\x6b\x22\xe5\xd4\xd0\x68\xf6\x9c\x10"
> > +	"\xf0\x2d\x4f\x82\xb3\x21\xb4\xaa\x7f\xff\x6b\x7e\x9a\xf2\x12\x44"
> > +	"\x4a\xa5\xbb\x16\xb6\x56\x6e\xb1\x20\xb4\xb0\x34\x8f\xe4\x94\xb2"
> > +	"\xf6\x7f\x9f\x05\xd0\x42\x30\x04\xdb\x11\xb8\xd7\x5a\x1b\xb6\x06"
> > +	"\xed\x6e\x9c\x69\x6d\x2c\x0f\x6f\x7f\xf3\x9c\x76\x2e\xad\xc2\xd6"
> > +	"\xc6\xfd\x93\xc1\xee\x25\xbb\xc8\xc6\xb5\xd1\x37\x65\xdd\xe5\x78"
> > +	"\xb0\x89\x0a\x91\x4a\xe1\x17\x61\x43\x18\x47\xf3\xc2\x2a\x22\xc2"
> > +	"\x56\x4e\x01\x31\xa3\x0b\xc7\xe6\x53\x27\xa8\xc8\x32\x25\x69\x7c"
> > +	"\x8b\x8e\xb1\x2b\xc6\xc9\x85\x05\x1d\x67\x1e\xc6\x10\xa3\x60\x46"
> > +	"\xbf\x9d\x5b\x3f\xda\x1f\xd3\x8b\x1a\x95\x88\xa2\x16\xb0\xdd\x7f"
> > +	"\x46\x2f\x5f\xef\xa0\x17\x0e\x5e\x19\x20\x8c\xeb\x97\x52\xc8\xe0"
> > +	"\xdc\xc0\x40\x0a\xd1\x84\xc1\xa6\xb2\xf4\x6c\xc7\x8d\xc9\xd4\xb8"
> > +	"\xc3\xe3\xe5\xf9\x8a\xc5\xdb\x04\x2a\x89\xa5\x92\x64\x3f\x91\xd0"
> > +	"\x60\x97\x8a\x42\x2d\x4b\x2c\xf8\xa7\xe2\x68\xf9\xd3\x94\x1c\x24"
> > +	"\xe8\x80\xff\x05\xa7\x02\xab\x66\xd7\xb9\xa3\xeb\xd5\x0f\xf7\x26"
> > +	"\x4f\x8f\x6b\x5a\xb2\x7c\xda\x1a\xb3\x83\x5f\xbc\xcc\xfc\x50\xc8"
> > +	"\x24\x8c\x38\x9d\x80\x79\x50\x9d\x84\xe8\xee\x85\x19\xf3\x73\x5a"
> > +	"\xd2\x41\x92\xde\x87\x5f\x52\x62\x91\xbe\x90\x1e\xce\x54\x13\x68"
> > +	"\x35\x3e\x2b\xe5\xa2\x1e\xc0\xc1\x2f\x9c\x52\xd9\xe1\x5c\xe4\xfd"
> > +	"\x21\xa3\x5a\x51\xb3\x01\x9d\x22\x2c\x6c\xa8\xb9\xda\xfb\x78\xa8"
> > +	"\x24\x1f\xef\xe9\x1c\x38\x04\xf5\x8b\x80\xca\xe6\xb9\x76\x27\x31"
> > +	"\xe1\x24\xf0\x07\xf9\xa9\x11\x77\x9a\x8a\xc1\x87\x21\x49\x1b\x6e"
> > +	"\x94\x94\x4e\xe7\x3a\x10\x00\xd1\xd7\x02\xbf\x53\xe7\x88\x4e\xab"
> > +	"\x63\x35\x61\x39\x81\x45\x21\x85\x35\x4b\x44\xca\xc0\xdb\x8f\xa3"
> > +	"\x6a\xc7\x90\x12\x7a\xd5\x94\xd7\xfe\x30\xb2\x0f\x51\x52\xd0\xe6"
> > +	"\xa7\xbe\x52\x2d\x45\xba\xed\xbc\x3c\x95\x35\x50\x3f\x83\x97\xa8"
> > +	"\x8f\x7e\xfb\x2e\xa3\x5b\xe1\x2c\xb9\x15\x79\x62\x28\x8f\x02\x47"
> > +	"\x31\x63\x2f\x45\xa7\xa7\x21\xa4\x26\x17\x2f\x46\x72\x22\x44\xed"
> > +	"\x3a\xff\x0a\x80\x27\xb7\xaa\xa3\x9e\xe3\xb7\x71\xd2\xd9\x98\xa2"
> > +	"\x6a\x5b\x18\x70\x6b\xfa\xf3\x9f\xcd\xa9\x4c\xca\x97\x76\x41\x98"
> > +	"\xb2\x8b\x98\x23\x88\xe7\x1e\xa3\xd3\x56\x9a\x48\xf1\xd8\xf5\xd5"
> > +	"\xf5\xd2\xff\x60\x52\x82\xeb\xe8\x92\x5c\x36\xfc\x32\xfe\x46\x2d"
> > +	"\x9a\xbd\xb8\xc2\x37\x63\xee\xbe\x69\x4c\x98\x3d\x3d\xa3\x76\xe7"
> > +	"\xbe\x8b\xb9\xe2\x07\x4b\x9a\x55\x44\x71\x6e\x7d\x7f\xb0\x31\x55"
> > +	"\xb8\x74\x82\x9c\x47\xf9\xdc\x9a\x21\xd3\xbb\x47\x22\x05\x3b\x4b"
> > +	"\x00\x31\xe1\x7f\x9d\xcf\xd1\xde\xeb\xd6\x2a\xd9\x0b\xa8\x34\x03"
> > +	"\xc3\x66\x34\x1f\xcb\xe8\xd8\xf2\xf9\x4a\x3f\x6e\x8e\x3f\x8b\xce"
> > +	"\xef\x9d\xe9\xf9\x92\x33\x7d\x8a\x61\x2f\x5c\xaf\x5d\x4c\x66\x30"
> > +	"\x37\x09\x3f\xd0\x5e\xe6\x43\xef\x03\x63\x63\xc5\x39\x2b\xa8\x09"
> > +	"\x5a\x86\x78\x5c\xa0\xa0\x5c\xa1\xba\xb7\xbc\xdb\xd7\x70\x60\x81"
> > +	"\x20\x19\x72\x82\x85\xed\x96\x58\xa9\xdb\xa2\xcc\x03\xfc\x00\x92"
> > +	"\x46\x3c\x79\x30\xce\xe0\x8f\xa0\x91\xd5\x16\xcc\x46\xce\xf2\x4a"
> > +	"\x62\xaa\x1d\x80\x2f\xf5\x45\x7b\x9e\x97\xd7\x94\x39\x73\x6d\x5a"
> > +	"\x25\xe4\x46\xb9\x6c\x58\xcc\xa7\xc9\x9b\x81\x9a\x98\x05\x0b\x82"
> > +	"\xb4\xb1\xc5\x08\x71\x15\x1f\x26\x86\x26\x7b\xa8\x47\xaf\x80\x42"
> > +	"\x2d\xd1\x68\x07\xb6\xa3\x81\xc5\x40\x6e\xf7\xf6\x66\x81\x2d\x1e"
> > +	"\x65\x01\xae\x2c\xaa\x59\x7c\x90\xa4\xfd\x34\x04\x73\x3a\x40\x1a"
> > +	"\x2b\x9f\x35\x4b\x25\x17\x8f\xe5\xe6\x99\x0f\x1e\x23\xed\x95\xfe"
> > +	"\xf6\xa3\x90\xd3\xca\xd4\x22\xb4\x8b\x66\xac\xe9\xf3\xaf\xc8\x1b"
> > +	"\xaa\x9f\x92\xc0\x19\x3c\x01\x66\xc6\x07\xed\x82\xbe\x60\x08\x6a"
> > +	"\x94\xfc\x79\xfa\x3c\xb5\x24\xb1\xc8\x7f\xf3\x53\x20\x90\x1f\x07"
> > +	"\x06\xd4\xf6\x7f\xeb\xcb\x96\x5f\xd8\x2b\xd2\x7e\x44\xaa\x62\x75"
> > +	"\x43\xfa\xc9\xfa\x27\x78\xe7\xe7\x61\xc2\xc2\xd2\x87\x24\x75\xab"
> > +	"\x22\x4d\xc4\xbe\xa2\x9e\xe6\x2e\xc3\xee\xd3\x37\x69\x02\x50\x13"
> > +	"\xcb\xa3\x65\xf2\xdd\xed\xbc\x15\x68\x20\x50\x6d\xe4\x8a\x8b\x9f"
> > +	"\x45\x39\xc5\xe4\xf1\x74\x7a\xf5\x0f\xa5\x94\x5a\x5a\x3c\x0c\xd0"
> > +	"\xb1\x5e\x27\xd5\x8a\x98\x15\x24\x65\x24\x15\xcb\x7e\xee\x62\x0b"
> > +	"\xbd\xf4\xb0\x32\x31\xb3\xc3\x21\x58\xe5\x7a\x69\x0e\x28\x9e\x00"
> > +	"\x75\x71\x47\x81\x52\x9f\x6d\xc8\x80\x19\x1d\xaf\x76\x9f\x3a\x11"
> > +	"\xa0\x6d\xe8\x43\xba\x73\xef\x85\x61\x09\x7a\xe2\x82\x44\xaa\xf2"
> > +	"\x3a\x56\x08\x46\x04\x7e\x65\x83\xcf\xbc\xaa\x8a\xa3\xb4\xf8\x44"
> > +	"\xb0\x43\x0e\xcd\x25\x40\x0b\xd7\x7c\x8c\xf9\xae\x42\xc9\xea\x2e"
> > +	"\x3e\x83\x6a\xd8\xd4\x44\x23\x14\x33\x27\x00\x49\xdb\x61\xb5\x51"
> > +	"\x52\xe4\x54\xbe\x05\xc9\xd6\xe3\xc2\x1a\x07\xf3\xbf\xd3\xb1\x1d"
> > +	"\xb4\x88\xda\x62\x09\xb8\x94\x2a\xcc\x24\x22\x46\xe9\x6f\x99\x6d"
> > +	"\xbf\x24\xa3\x9a\xc3\x3f\x42\x88\x5f\x36\x45\x68\xce\x95\xb3\xe5"
> > +	"\x7f\x9c\xe3\xd6\xe5\xb9\xd5\x40\x36\xb8\x36\xc8\x88\x9a\xf7\xcf"
> > +	"\xe0\x76\x56\xb3\x9a\x0d\x68\xc0\x60\x94\x9e\xdb\x14\x81\x95\xb3"
> > +	"\xdd\xe5\xeb\xf2\x14\x18\x56\x74\x7b\x81\x9d\xb1\xd2\xed\xef\xf1"
> > +	"\xf8\xfc\x41\x4c\x66\x77\xbd\xc9\x16\x32\x3f\x8f\x9a\xa7\xc2\xe1"
> > +	"\x1c\x1f\x44\x48\x54\xd3\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x04"
> > +	"\x0c\x1a\x20\x28\x2f"
> > +};
> > +
> > +void __init fips_signature_selftest_mldsa(void)
> > +{
> > +	fips_signature_selftest("MLDSA",
> > +				nist_mldsa_fips204_35_key,
> > +				sizeof(nist_mldsa_fips204_35_key) - 1,
> > +				nist_mldsa_fips204_35_data,
> > +				sizeof(nist_mldsa_fips204_35_data) - 1,
> > +				nist_mldsa_fips204_35_sig,
> > +				sizeof(nist_mldsa_fips204_35_sig) - 1);
> > +}
> > 
> 
> I might test this in 1-2 weeks. RSASSA-PSS does not require a selftest?

Oops, I had a blind spot, and missed the patch sorry :-)

BR, Jarkko

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing
  2026-01-20 14:50 ` [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing David Howells
@ 2026-01-20 18:31   ` Ignat Korchagin
  2026-01-20 18:54     ` David Howells
  2026-01-20 21:51   ` Vitaly Chikunov
  2026-01-20 22:14   ` Eric Biggers
  2 siblings, 1 reply; 37+ messages in thread
From: Ignat Korchagin @ 2026-01-20 18:31 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, 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

Hi David,

On Tue, Jan 20, 2026 at 2:52 PM David Howells <dhowells@redhat.com> wrote:
>
> Limit the set of crypto combinations that may be used for module signing as
> no indication of hash algorithm used for signing is added to the hash of
> the data, so in theory a data blob hashed with a different algorithm can be
> substituted provided it has the same hash output.
>
> This also rejects the use of less secure algorithms.
>
> 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/public_key.c | 55 +++++++++++++++++++++++++++--
>  1 file changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index 13a5616becaa..90b98e1a952d 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -24,6 +24,52 @@ MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
>  MODULE_AUTHOR("Red Hat, Inc.");
>  MODULE_LICENSE("GPL");
>
> +struct public_key_restriction {
> +       const char      *pkey_algo;     /* Signing algorithm (e.g. "rsa") */
> +       const char      *pkey_enc;      /* Signature encoding (e.g. "pkcs1") */
> +       const char      *hash_algo;     /* Content hash algorithm (e.g. "sha256") */
> +};
> +
> +static const struct public_key_restriction public_key_restrictions[] = {
> +       /* algo                 encoding        hash */
> +       { "rsa",                "pkcs1",        "sha256" },
> +       { "rsa",                "pkcs1",        "sha384" },
> +       { "rsa",                "pkcs1",        "sha512" },
> +       { "rsa",                "emsa-pss",     "sha512" },

Don't we want to allow sha256 for emsa-pss?

> +       { "ecdsa",              "x962",         "sha256" },
> +       { "ecdsa",              "x962",         "sha384" },
> +       { "ecdsa",              "x962",         "sha512" },
> +       { "ecrdsa",             "raw",          "sha256" },
> +       { "ecrdsa",             "raw",          "sha384" },
> +       { "ecrdsa",             "raw",          "sha512" },
> +       { "mldsa44",            "raw",          "sha512" },
> +       { "mldsa65",            "raw",          "sha512" },
> +       { "mldsa87",            "raw",          "sha512" },
> +       /* ML-DSA may also do its own hashing over the entire message. */
> +       { "mldsa44",            "raw",          "-" },
> +       { "mldsa65",            "raw",          "-" },
> +       { "mldsa87",            "raw",          "-" },
> +};
> +
> +/*
> + * Determine if a particular key/hash combination is allowed.
> + */
> +static int is_public_key_sig_allowed(const struct public_key_signature *sig)
> +{
> +       for (int i = 0; i < ARRAY_SIZE(public_key_restrictions); i++) {
> +               if (strcmp(public_key_restrictions[i].pkey_algo, sig->pkey_algo) != 0)
> +                       continue;
> +               if (strcmp(public_key_restrictions[i].pkey_enc, sig->encoding) != 0)
> +                       continue;
> +               if (strcmp(public_key_restrictions[i].hash_algo, sig->hash_algo) != 0)
> +                       continue;
> +               return 0;
> +       }
> +       pr_warn_once("Public key signature combo (%s,%s,%s) rejected\n",
> +                    sig->pkey_algo, sig->encoding, sig->hash_algo);
> +       return -EKEYREJECTED;
> +}
> +
>  /*
>   * Provide a part of a description of the key for /proc/keys.
>   */
> @@ -391,12 +437,17 @@ int public_key_verify_signature(const struct public_key *pkey,
>         bool issig;
>         int ret;
>
> -       pr_devel("==>%s()\n", __func__);
> -
>         BUG_ON(!pkey);
>         BUG_ON(!sig);
>         BUG_ON(!sig->s);
>
> +       ret = is_public_key_sig_allowed(sig);
> +       if (ret < 0)
> +               return ret;
> +
> +       pr_devel("==>%s(%s,%s,%s)\n",
> +                __func__, sig->pkey_algo, sig->encoding, sig->hash_algo);
> +
>         /*
>          * If the signature specifies a public key algorithm, it *must* match
>          * the key's actual public key algorithm.
>

Ignat

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing
  2026-01-20 18:31   ` Ignat Korchagin
@ 2026-01-20 18:54     ` David Howells
  0 siblings, 0 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 18:54 UTC (permalink / raw)
  To: Ignat Korchagin
  Cc: dhowells, Lukas Wunner, 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

Ignat Korchagin <ignat@cloudflare.com> wrote:

> > +       { "rsa",                "emsa-pss",     "sha512" },
> 
> Don't we want to allow sha256 for emsa-pss?

We do.  I already added that for v14.

David


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 01/12] crypto: Add ML-DSA crypto_sig support
  2026-01-20 14:50 ` [PATCH v13 01/12] crypto: Add ML-DSA crypto_sig support David Howells
  2026-01-20 17:37   ` Jarkko Sakkinen
@ 2026-01-20 20:52   ` Eric Biggers
  1 sibling, 0 replies; 37+ messages in thread
From: Eric Biggers @ 2026-01-20 20:52 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel

On Tue, Jan 20, 2026 at 02:50:47PM +0000, David Howells wrote:
> +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).

The selection of CRYPTO_LIB_SHA3 is unnecessary.

> +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;
> +};

'key_set' should have type 'bool'.   Or just use pk_len == 0 to mean the
key hasn't been set yet.

- Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself
  2026-01-20 14:50 ` [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself David Howells
  2026-01-20 17:53   ` Jarkko Sakkinen
@ 2026-01-20 21:12   ` Eric Biggers
  2026-01-23 11:37     ` David Howells
  1 sibling, 1 reply; 37+ messages in thread
From: Eric Biggers @ 2026-01-20 21:12 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel

On Tue, Jan 20, 2026 at 02:50:48PM +0000, David Howells wrote:
> replace sig->digest with a copy of the contents of the
> authenticatedAttributes section and adjust the digest length to match.

As I mentioned on v11, it's misleading to start using the term digest
for something that isn't a digest.

Naturally, this confusing introduction of non-digest digests seems to
have already caused a bug: IMA calls pkcs7_get_digest() to calculate the
digest of the module.  But now that's no longer necessarily a digest.
It could be the entire signed attributes.

For security-critical code like this we need to have a clear design, not
just patch in hacks that overload existing code like this.

I'll also note that this commit doesn't fully implement "Allow the
signing algo to calculate the digest itself" as claimed, since only the
signed attributes case is handled.  It looks like the next patch is
intended to handle the other case.  But it's not made clear at all that
it's a two-part thing; this patch implies that it's complete.

- Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 04/12] pkcs7, x509: Add ML-DSA support
  2026-01-20 14:50 ` [PATCH v13 04/12] pkcs7, x509: Add ML-DSA support David Howells
@ 2026-01-20 21:17   ` Eric Biggers
  0 siblings, 0 replies; 37+ messages in thread
From: Eric Biggers @ 2026-01-20 21:17 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel

On Tue, Jan 20, 2026 at 02:50:50PM +0000, David Howells wrote:
> Add support for ML-DSA keys and signatures to the PKCS#7 and X.509
> implementations.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>

Please mention exactly what is supported.  Which versions of ML-DSA,
which hash algorithms, signed attributes, etc.

- Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 05/12] modsign: Enable ML-DSA module signing
  2026-01-20 14:50 ` [PATCH v13 05/12] modsign: Enable ML-DSA module signing David Howells
@ 2026-01-20 21:38   ` Eric Biggers
  2026-01-21 14:21     ` David Howells
  0 siblings, 1 reply; 37+ messages in thread
From: Eric Biggers @ 2026-01-20 21:38 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel

On Tue, Jan 20, 2026 at 02:50:51PM +0000, David Howells wrote:
> The ML-DSA algorithm uses its own internal choice of digest (SHAKE256)
> without regard to what's specified in the CMS message.  This is, in theory,
> configurable, but there's currently no hook in the crypto_sig API to do
> that, though possibly it could be done by parameterising the name of the
> algorithm, e.g. ("mldsa87(sha512)").

As I mentioned on v11, this paragraph doesn't really make sense, since
the XOF is part of the ML-DSA specification.  Sure, you saw some
component of ML-DSA which could, in principle, swapped out with some
other component to create a new algorithm which would not be "ML-DSA".
But the XOF isn't really unique there.

> +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
> +	  with a SHAKE256 'hash' of the authenticatedAttributes.

Let me reiterate my comment from v11:

    Also unclear why the above help text mentions anything about SHAKE256 or
    the authenticatedAttributes.  That's an implementation detail.  (And
    the CMS specification calls them signed attributes anyway.)

I'll also note that your signing program doesn't actually produce signed
attributes if the OpenSSL version is sufficiently new.

> +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
> +	  with a SHAKE256 'hash' of the authenticatedAttributes.
> +
> +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
> +	  with a SHAKE256 'hash' of the authenticatedAttributes.

Do all three ML-DSA parameter sets really need to be supported for
module signing?  How will distros decide which one to use?

Any chance that ML-DSA-65 would be good enough for everyone?  That's the
one that I'm seeing recommended the most.

> 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;

If OpenSSL 3.5 is the last version that doesn't support the noattr case,
that would mean that OpenSSL 3.6 does support it, right?  OpenSSL 3.6
was released several months ago.  Yet the above code requires version 4.

Either way, this version-dependent logic is a bit fragile: users will
suddenly get different behavior on OpenSSL version updates.  And once
everyone has updated, the old code will no longer be tested.

How about we just support the new way only?  That would be simpler, and
it sounds like it's already supported by the latest OpenSSL.

- Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 12/12] pkcs7: Add ML-DSA FIPS selftest
  2026-01-20 14:50 ` [PATCH v13 12/12] pkcs7: Add ML-DSA FIPS selftest David Howells
  2026-01-20 17:54   ` Jarkko Sakkinen
@ 2026-01-20 21:43   ` Eric Biggers
  1 sibling, 0 replies; 37+ messages in thread
From: Eric Biggers @ 2026-01-20 21:43 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel

On Tue, Jan 20, 2026 at 02:50:58PM +0000, David Howells wrote:
> Add a FIPS selftest for ML-DSA.

I already did that.  See mldsa_mod_init() in lib/crypto/mldsa.c.

You may be misunderstanding what FIPS 140 requires.  It requires a
self-test for the underlying algorithm, i.e. ML-DSA in this case.  It
doesn't require a self-test for code that uses the algorithm, i.e. the
CMS and X.509 code in this case.

The CMS and X.509 code needs to be tested of course, but that's just
standard software development.  Nothing to do with FIPS 140.  The test
should just be a standard KUnit test.

- Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing
  2026-01-20 14:50 ` [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing David Howells
  2026-01-20 18:31   ` Ignat Korchagin
@ 2026-01-20 21:51   ` Vitaly Chikunov
  2026-01-20 23:18     ` David Howells
  2026-01-20 22:14   ` Eric Biggers
  2 siblings, 1 reply; 37+ messages in thread
From: Vitaly Chikunov @ 2026-01-20 21:51 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, 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

David,

On Tue, Jan 20, 2026 at 02:50:57PM +0000, David Howells wrote:
> Limit the set of crypto combinations that may be used for module signing as
> no indication of hash algorithm used for signing is added to the hash of
> the data, so in theory a data blob hashed with a different algorithm can be
> substituted provided it has the same hash output.
> 
> This also rejects the use of less secure algorithms.
> 
> 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/public_key.c | 55 +++++++++++++++++++++++++++--
>  1 file changed, 53 insertions(+), 2 deletions(-)
> 
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index 13a5616becaa..90b98e1a952d 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -24,6 +24,52 @@ MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
>  MODULE_AUTHOR("Red Hat, Inc.");
>  MODULE_LICENSE("GPL");
>  
> +struct public_key_restriction {
> +	const char	*pkey_algo;	/* Signing algorithm (e.g. "rsa") */
> +	const char	*pkey_enc;	/* Signature encoding (e.g. "pkcs1") */
> +	const char	*hash_algo;	/* Content hash algorithm (e.g. "sha256") */
> +};
> +
> +static const struct public_key_restriction public_key_restrictions[] = {
> +	/* algo			encoding	hash */
> +	{ "rsa",		"pkcs1",	"sha256" },
> +	{ "rsa",		"pkcs1",	"sha384" },
> +	{ "rsa",		"pkcs1",	"sha512" },
> +	{ "rsa",		"emsa-pss",	"sha512" },
> +	{ "ecdsa",		"x962",		"sha256" },
> +	{ "ecdsa",		"x962",		"sha384" },
> +	{ "ecdsa",		"x962",		"sha512" },
> +	{ "ecrdsa",		"raw",		"sha256" },
> +	{ "ecrdsa",		"raw",		"sha384" },
> +	{ "ecrdsa",		"raw",		"sha512" },

Why such hash choice? Aren't it should be streebog256 and streebog512?

Thanks,

> +	{ "mldsa44",		"raw",		"sha512" },
> +	{ "mldsa65",		"raw",		"sha512" },
> +	{ "mldsa87",		"raw",		"sha512" },
> +	/* ML-DSA may also do its own hashing over the entire message. */
> +	{ "mldsa44",		"raw",		"-" },
> +	{ "mldsa65",		"raw",		"-" },
> +	{ "mldsa87",		"raw",		"-" },
> +};
> +
> +/*
> + * Determine if a particular key/hash combination is allowed.
> + */
> +static int is_public_key_sig_allowed(const struct public_key_signature *sig)
> +{
> +	for (int i = 0; i < ARRAY_SIZE(public_key_restrictions); i++) {
> +		if (strcmp(public_key_restrictions[i].pkey_algo, sig->pkey_algo) != 0)
> +			continue;
> +		if (strcmp(public_key_restrictions[i].pkey_enc, sig->encoding) != 0)
> +			continue;
> +		if (strcmp(public_key_restrictions[i].hash_algo, sig->hash_algo) != 0)
> +			continue;
> +		return 0;
> +	}
> +	pr_warn_once("Public key signature combo (%s,%s,%s) rejected\n",
> +		     sig->pkey_algo, sig->encoding, sig->hash_algo);
> +	return -EKEYREJECTED;
> +}
> +
>  /*
>   * Provide a part of a description of the key for /proc/keys.
>   */
> @@ -391,12 +437,17 @@ int public_key_verify_signature(const struct public_key *pkey,
>  	bool issig;
>  	int ret;
>  
> -	pr_devel("==>%s()\n", __func__);
> -
>  	BUG_ON(!pkey);
>  	BUG_ON(!sig);
>  	BUG_ON(!sig->s);
>  
> +	ret = is_public_key_sig_allowed(sig);
> +	if (ret < 0)
> +		return ret;
> +
> +	pr_devel("==>%s(%s,%s,%s)\n",
> +		 __func__, sig->pkey_algo, sig->encoding, sig->hash_algo);
> +
>  	/*
>  	 * If the signature specifies a public key algorithm, it *must* match
>  	 * the key's actual public key algorithm.
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing
  2026-01-20 14:50 ` [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing David Howells
  2026-01-20 18:31   ` Ignat Korchagin
  2026-01-20 21:51   ` Vitaly Chikunov
@ 2026-01-20 22:14   ` Eric Biggers
  2 siblings, 0 replies; 37+ messages in thread
From: Eric Biggers @ 2026-01-20 22:14 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel

On Tue, Jan 20, 2026 at 02:50:57PM +0000, David Howells wrote:
> Limit the set of crypto combinations that may be used for module signing as
> no indication of hash algorithm used for signing is added to the hash of
> the data, so in theory a data blob hashed with a different algorithm can be
> substituted provided it has the same hash output.
> 
> This also rejects the use of less secure algorithms.
> 
> 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/public_key.c | 55 +++++++++++++++++++++++++++--
>  1 file changed, 53 insertions(+), 2 deletions(-)
> 
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index 13a5616becaa..90b98e1a952d 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -24,6 +24,52 @@ MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
>  MODULE_AUTHOR("Red Hat, Inc.");
>  MODULE_LICENSE("GPL");
>  
> +struct public_key_restriction {
> +	const char	*pkey_algo;	/* Signing algorithm (e.g. "rsa") */
> +	const char	*pkey_enc;	/* Signature encoding (e.g. "pkcs1") */
> +	const char	*hash_algo;	/* Content hash algorithm (e.g. "sha256") */
> +};
> +
> +static const struct public_key_restriction public_key_restrictions[] = {
> +	/* algo			encoding	hash */
> +	{ "rsa",		"pkcs1",	"sha256" },
> +	{ "rsa",		"pkcs1",	"sha384" },
> +	{ "rsa",		"pkcs1",	"sha512" },
> +	{ "rsa",		"emsa-pss",	"sha512" },
> +	{ "ecdsa",		"x962",		"sha256" },
> +	{ "ecdsa",		"x962",		"sha384" },
> +	{ "ecdsa",		"x962",		"sha512" },
> +	{ "ecrdsa",		"raw",		"sha256" },
> +	{ "ecrdsa",		"raw",		"sha384" },
> +	{ "ecrdsa",		"raw",		"sha512" },
> +	{ "mldsa44",		"raw",		"sha512" },
> +	{ "mldsa65",		"raw",		"sha512" },
> +	{ "mldsa87",		"raw",		"sha512" },
> +	/* ML-DSA may also do its own hashing over the entire message. */
> +	{ "mldsa44",		"raw",		"-" },
> +	{ "mldsa65",		"raw",		"-" },
> +	{ "mldsa87",		"raw",		"-" },
> +};

Have you read software_key_determine_akcipher()?  It's the place where
the encoding and hash_algo are validated currently.  This commit adds a
second set of slightly different checks alongside the existing ones.
It's unclear whether the existing checks were considered.

Also, the ML-DSA and RSASSA-PSS support is new in this patchset, and
this commit is a fix for it.  Instead of committing buggy code that is
fixed by a later commit, it's preferable to commit correct code in the
first place.

- Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
  2026-01-20 14:50 ` [PATCH v13 07/12] crypto: Add RSASSA-PSS support David Howells
@ 2026-01-20 22:41   ` Eric Biggers
  2026-01-20 23:15     ` David Howells
  2026-01-21  2:14     ` Eric Biggers
  0 siblings, 2 replies; 37+ messages in thread
From: Eric Biggers @ 2026-01-20 22:41 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel,
	Tadeusz Struk, David S. Miller

On Tue, Jan 20, 2026 at 02:50:53PM +0000, David Howells wrote:
> Add support for RSASSA-PSS [RFC8017 sec 8.1] signature verification support
> to the RSA driver in crypto/.

This additional feature significantly increases the scope of your
patchset, especially considering that the kernel previously didn't
implement RSASSA-PSS at all.  This patchset also doesn't include any
explanation for why this additional feature is needed.  It might make
sense to add this feature, but it needs to be properly explained, and it
would be preferable for it to be its own patchset.

> The verification function requires an info string formatted as a
> space-separated list of key=value pairs.  The following parameters need to
> be provided:
> 
>  (1) sighash=<algo>
> 
>      The hash algorithm to be used to digest the data.
> 
>  (2) pss_mask=<type>,...
> 
>      The mask generation function (MGF) and its parameters.
> 
>  (3) pss_salt=<len>
> 
>      The length of the salt used.
> 
> The only MGF currently supported is "mgf1".  This takes an additional
> parameter indicating the mask-generating hash (which need not be the same
> as the data hash).  E.g.:
> 
>      "sighash=sha256 pss_mask=mgf1,sha256 pss_salt=32"

One of the issues with RSASSA-PSS is the excessive flexibility in the
parameters, which often end up being attacker controlled.  Therefore
many implementations of RSASSA-PSS restrict the allowed parameters to
something reasonable, e.g. restricting the allowed hash algorithms,
requiring the two hash algorithms to be the same, and requiring the salt
size to match the digest size.  We should do likewise if possible.

> +		case rsassa_pss_verify_pss_mask:
> +			if (memcmp(args[0].from, "mgf1", 4) != 0)
> +				return -ENOPKG;

Out-of-bounds read.

As I mentioned in another reply, error-prone string parsing isn't a
great choice.  C has native support for function parameters.

> +static int emsa_pss_verify(struct rsassa_pss_ctx *ctx,
> +			   const u8 *M, unsigned int M_len,
> +			   const u8 *EM, unsigned int emLen)
> +{
> +	unsigned int emBits, hLen, sLen, DB_len;
> +	const u8 *maskedDB, *H;
> +	u8 *mHash, *dbMask, *DB, *salt, *Mprime, *Hprime;
> +	int err, i;
> +
> +	emBits = 8 - fls(EM[0]);
> +	emBits = emLen * 8 - emBits;

This does not implement EMSA-PSS-VERIFY correctly.  Please check the
specification.  emBits is supposed to be determined solely from the
public key.

Please also add KUnit tests for this code, including edge cases.

FYI: it will take a couple more passes to properly review this:
unfortunately this encoding scheme is a bit complicated, and some of
your implementation choices like using strings instead of
straightforward function parameters don't particularly help.  These are
just a couple things I noticed in a first pass.

- Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
  2026-01-20 22:41   ` Eric Biggers
@ 2026-01-20 23:15     ` David Howells
  2026-01-20 23:36       ` Eric Biggers
  2026-01-21  2:14     ` Eric Biggers
  1 sibling, 1 reply; 37+ messages in thread
From: David Howells @ 2026-01-20 23:15 UTC (permalink / raw)
  To: Eric Biggers
  Cc: dhowells, Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen,
	Herbert Xu, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen, Jason A . Donenfeld, Ard Biesheuvel,
	Stephan Mueller, linux-crypto, keyrings, linux-modules,
	linux-kernel, Tadeusz Struk, David S. Miller

Eric Biggers <ebiggers@kernel.org> wrote:

> As I mentioned in another reply, error-prone string parsing isn't a
> great choice.  C has native support for function parameters.

But is constrained that it has to work with KEYCTL_PKEY_VERIFY's info
parameter.

David


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing
  2026-01-20 21:51   ` Vitaly Chikunov
@ 2026-01-20 23:18     ` David Howells
  0 siblings, 0 replies; 37+ messages in thread
From: David Howells @ 2026-01-20 23:18 UTC (permalink / raw)
  To: Vitaly Chikunov
  Cc: dhowells, Lukas Wunner, Ignat Korchagin, 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

Vitaly Chikunov <vt@altlinux.org> wrote:

> > +static const struct public_key_restriction public_key_restrictions[] = {
> > +	/* algo			encoding	hash */
> > +	{ "rsa",		"pkcs1",	"sha256" },
> > +	{ "rsa",		"pkcs1",	"sha384" },
> > +	{ "rsa",		"pkcs1",	"sha512" },
> > +	{ "rsa",		"emsa-pss",	"sha512" },
> > +	{ "ecdsa",		"x962",		"sha256" },
> > +	{ "ecdsa",		"x962",		"sha384" },
> > +	{ "ecdsa",		"x962",		"sha512" },
> > +	{ "ecrdsa",		"raw",		"sha256" },
> > +	{ "ecrdsa",		"raw",		"sha384" },
> > +	{ "ecrdsa",		"raw",		"sha512" },
> 
> Why such hash choice? Aren't it should be streebog256 and streebog512?

Maybe?  I don't have any example ecrdsa (assuming you're talking about that
specifically), nor does it seem that it was added to the choice of module
signing.  Possibly I should drop the encoding column - or just have a list of
hashes that we accept - but we might want to limit the hashes that can use
with ML-DSA more strictly (ie. only allow SHA512).

David


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
  2026-01-20 23:15     ` David Howells
@ 2026-01-20 23:36       ` Eric Biggers
  2026-01-21  8:11         ` Ignat Korchagin
  0 siblings, 1 reply; 37+ messages in thread
From: Eric Biggers @ 2026-01-20 23:36 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel,
	Tadeusz Struk, David S. Miller

On Tue, Jan 20, 2026 at 11:15:57PM +0000, David Howells wrote:
> Eric Biggers <ebiggers@kernel.org> wrote:
> 
> > As I mentioned in another reply, error-prone string parsing isn't a
> > great choice.  C has native support for function parameters.
> 
> But is constrained that it has to work with KEYCTL_PKEY_VERIFY's info
> parameter.

The cover letter of this patchset summarizes it as "These patches add
ML-DSA module signing and RSASSA-PSS module signing."  Adding
KEYCTL_PKEY_VERIFY support for these algorithms would be a significant
new UAPI feature that would need its own justification and its own
documentation and test updates.

However, it was established pretty clearly in past discussions that
KEYCTL_PKEY_* are a mistake and basically exist only for backwards
compatibility with iwd.

So I don't understand why you're advocating for adding new features to
them.

- Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
  2026-01-20 22:41   ` Eric Biggers
  2026-01-20 23:15     ` David Howells
@ 2026-01-21  2:14     ` Eric Biggers
  2026-01-21  8:15       ` Ignat Korchagin
  1 sibling, 1 reply; 37+ messages in thread
From: Eric Biggers @ 2026-01-21  2:14 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel,
	Tadeusz Struk, David S. Miller

On Tue, Jan 20, 2026 at 02:41:11PM -0800, Eric Biggers wrote:
> On Tue, Jan 20, 2026 at 02:50:53PM +0000, David Howells wrote:
> > Add support for RSASSA-PSS [RFC8017 sec 8.1] signature verification support
> > to the RSA driver in crypto/.
> 
> This additional feature significantly increases the scope of your
> patchset, especially considering that the kernel previously didn't
> implement RSASSA-PSS at all.  This patchset also doesn't include any
> explanation for why this additional feature is needed.  It might make
> sense to add this feature, but it needs to be properly explained, and it
> would be preferable for it to be its own patchset.
> 
> > The verification function requires an info string formatted as a
> > space-separated list of key=value pairs.  The following parameters need to
> > be provided:
> > 
> >  (1) sighash=<algo>
> > 
> >      The hash algorithm to be used to digest the data.
> > 
> >  (2) pss_mask=<type>,...
> > 
> >      The mask generation function (MGF) and its parameters.
> > 
> >  (3) pss_salt=<len>
> > 
> >      The length of the salt used.
> > 
> > The only MGF currently supported is "mgf1".  This takes an additional
> > parameter indicating the mask-generating hash (which need not be the same
> > as the data hash).  E.g.:
> > 
> >      "sighash=sha256 pss_mask=mgf1,sha256 pss_salt=32"
> 
> One of the issues with RSASSA-PSS is the excessive flexibility in the
> parameters, which often end up being attacker controlled.  Therefore
> many implementations of RSASSA-PSS restrict the allowed parameters to
> something reasonable, e.g. restricting the allowed hash algorithms,
> requiring the two hash algorithms to be the same, and requiring the salt
> size to match the digest size.  We should do likewise if possible.

Looking into this a bit more, I'm increasingly skeptical that RSASSA-PSS
would be a worthwhile addition, especially when integrated into CMS and
X.509.  It seems that while in theory it's an improvement over PKCS#1
v1.5 padding, the specifications were messed up and it has way too many
unnecessary and error-prone parameters.  Here are some references that
describe some of the issues in RSASSA-PSS:

    * https://boringssl-review.googlesource.com/c/boringssl/+/81656
    * https://www.metzdowd.com/pipermail/cryptography/2019-November/035449.html

It seems it might not be very widely used either.

I think the fact that this patchset implements RSASSA-PSS verification
incorrectly (by not verifying that the leading bit is zero) further
validates these concerns.

With RSA also being two generations behind the current generation of
signature algorithms (RSA => elliptic curves => lattices), I'm wondering
what the motivation for this feature is.

- Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
  2026-01-20 23:36       ` Eric Biggers
@ 2026-01-21  8:11         ` Ignat Korchagin
  0 siblings, 0 replies; 37+ messages in thread
From: Ignat Korchagin @ 2026-01-21  8:11 UTC (permalink / raw)
  To: Eric Biggers
  Cc: David Howells, Lukas Wunner, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel,
	Tadeusz Struk, David S. Miller

On Tue, Jan 20, 2026 at 11:36 PM Eric Biggers <ebiggers@kernel.org> wrote:
>
> On Tue, Jan 20, 2026 at 11:15:57PM +0000, David Howells wrote:
> > Eric Biggers <ebiggers@kernel.org> wrote:
> >
> > > As I mentioned in another reply, error-prone string parsing isn't a
> > > great choice.  C has native support for function parameters.
> >
> > But is constrained that it has to work with KEYCTL_PKEY_VERIFY's info
> > parameter.
>
> The cover letter of this patchset summarizes it as "These patches add
> ML-DSA module signing and RSASSA-PSS module signing."  Adding
> KEYCTL_PKEY_VERIFY support for these algorithms would be a significant
> new UAPI feature that would need its own justification and its own
> documentation and test updates.
>
> However, it was established pretty clearly in past discussions that
> KEYCTL_PKEY_* are a mistake and basically exist only for backwards
> compatibility with iwd.

I disagree that it was "established". It is some folks opinion here,
but I find it quite useful and hope it would be actually extended by
good algorithm support.

> So I don't understand why you're advocating for adding new features to
> them.
>
> - Eric

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
  2026-01-21  2:14     ` Eric Biggers
@ 2026-01-21  8:15       ` Ignat Korchagin
  0 siblings, 0 replies; 37+ messages in thread
From: Ignat Korchagin @ 2026-01-21  8:15 UTC (permalink / raw)
  To: Eric Biggers
  Cc: David Howells, Lukas Wunner, Jarkko Sakkinen, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel,
	Tadeusz Struk, David S. Miller

On Wed, Jan 21, 2026 at 2:14 AM Eric Biggers <ebiggers@kernel.org> wrote:
>
> On Tue, Jan 20, 2026 at 02:41:11PM -0800, Eric Biggers wrote:
> > On Tue, Jan 20, 2026 at 02:50:53PM +0000, David Howells wrote:
> > > Add support for RSASSA-PSS [RFC8017 sec 8.1] signature verification support
> > > to the RSA driver in crypto/.
> >
> > This additional feature significantly increases the scope of your
> > patchset, especially considering that the kernel previously didn't
> > implement RSASSA-PSS at all.  This patchset also doesn't include any

I just wanted to point out that RSASSA-PSS "existed" as supported in
kernel documentation [1] for quite a while now. So it is a matter of
actually fixing "the bug" of it not being implemented as it should
have been from UAPI perspective

> > explanation for why this additional feature is needed.  It might make
> > sense to add this feature, but it needs to be properly explained, and it
> > would be preferable for it to be its own patchset.

This does seems reasonable to separate ML-DSA and RSASSA-PSS into
separate patchsets

> > > The verification function requires an info string formatted as a
> > > space-separated list of key=value pairs.  The following parameters need to
> > > be provided:
> > >
> > >  (1) sighash=<algo>
> > >
> > >      The hash algorithm to be used to digest the data.
> > >
> > >  (2) pss_mask=<type>,...
> > >
> > >      The mask generation function (MGF) and its parameters.
> > >
> > >  (3) pss_salt=<len>
> > >
> > >      The length of the salt used.
> > >
> > > The only MGF currently supported is "mgf1".  This takes an additional
> > > parameter indicating the mask-generating hash (which need not be the same
> > > as the data hash).  E.g.:
> > >
> > >      "sighash=sha256 pss_mask=mgf1,sha256 pss_salt=32"
> >
> > One of the issues with RSASSA-PSS is the excessive flexibility in the
> > parameters, which often end up being attacker controlled.  Therefore
> > many implementations of RSASSA-PSS restrict the allowed parameters to
> > something reasonable, e.g. restricting the allowed hash algorithms,
> > requiring the two hash algorithms to be the same, and requiring the salt
> > size to match the digest size.  We should do likewise if possible.
>
> Looking into this a bit more, I'm increasingly skeptical that RSASSA-PSS
> would be a worthwhile addition, especially when integrated into CMS and
> X.509.  It seems that while in theory it's an improvement over PKCS#1
> v1.5 padding, the specifications were messed up and it has way too many
> unnecessary and error-prone parameters.  Here are some references that
> describe some of the issues in RSASSA-PSS:
>
>     * https://boringssl-review.googlesource.com/c/boringssl/+/81656
>     * https://www.metzdowd.com/pipermail/cryptography/2019-November/035449.html
>
> It seems it might not be very widely used either.
>
> I think the fact that this patchset implements RSASSA-PSS verification
> incorrectly (by not verifying that the leading bit is zero) further
> validates these concerns.
>
> With RSA also being two generations behind the current generation of
> signature algorithms (RSA => elliptic curves => lattices), I'm wondering
> what the motivation for this feature is.
>
> - Eric

[1]: https://docs.kernel.org/security/keys/core.html

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself
  2026-01-20 17:53   ` Jarkko Sakkinen
@ 2026-01-21 12:31     ` David Howells
  2026-01-24 11:46       ` Jarkko Sakkinen
  0 siblings, 1 reply; 37+ messages in thread
From: David Howells @ 2026-01-21 12:31 UTC (permalink / raw)
  To: Jarkko Sakkinen
  Cc: dhowells, 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

Jarkko Sakkinen <jarkko@kernel.org> wrote:

> I'd use the wording you used already in commit message, which
> factors more descriptive than what you have here. E.g., name
> it "external_digest".

ML-DSA uses "external" to mean that the caller does the
digestion/hashing/XOF-ing/whatever Eric wants to call it, but the caller also
has to put other stuff into the digest/hash/XOF/thing that then gets passed to
ML-DSA if it does this.

For added confusion, the NIST FIPS tests seem to consider what this patch does
as 'external' but an "external mu" as 'internal':

	"tgId": 1,
	"testType": "AFT",
	"parameterSet": "ML-DSA-44",
	"signatureInterface": "external",
	"preHash": "pure",

vs:

	"tgId": 7,
	"testType": "AFT",
	"parameterSet": "ML-DSA-44",
	"signatureInterface": "internal",
	"externalMu": true,

I haven't come up with a better name that particularly describes this.  Maybe
use "no_prehash" or "algo_takes_hash" or "algo_takes_data"?

Maybe better than using a true/false value, use an enum?

	enum public_key_hash {
		ALGO_SIGNS_HASH, /* RSA, ECDSA, ... */
		ALGO_SIGNS_DATA, /* MLDSA, ... */
	};

David


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 05/12] modsign: Enable ML-DSA module signing
  2026-01-20 21:38   ` Eric Biggers
@ 2026-01-21 14:21     ` David Howells
  0 siblings, 0 replies; 37+ messages in thread
From: David Howells @ 2026-01-21 14:21 UTC (permalink / raw)
  To: Eric Biggers
  Cc: dhowells, Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen,
	Herbert Xu, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen, Jason A . Donenfeld, Ard Biesheuvel,
	Stephan Mueller, linux-crypto, keyrings, linux-modules,
	linux-kernel

Eric Biggers <ebiggers@kernel.org> wrote:

> If OpenSSL 3.5 is the last version that doesn't support the noattr case,
> that would mean that OpenSSL 3.6 does support it, right?  OpenSSL 3.6
> was released several months ago.  Yet the above code requires version 4.

3.5 and 3.6 support ML-DSA, but not with CMS_NOATTR, so I need to update this.
Version 4 will support ML-DSA with CMS_NOATTR, but that's not yet tagged.

> How about we just support the new way only?  That would be simpler, and
> it sounds like it's already supported by the latest OpenSSL.

Depends what you mean by "latest OpenSSL".  Latest in git, yes; latest in
distributions that people can simply install as an rpm/deb/etc., no.

Now, assuming OpenSSL releases v4 sometime in the spring, I would probably be
fine with saying you have to have OpenSSL v4 if you want ML-DSA; but others
might have a different opinion.

David


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself
  2026-01-20 21:12   ` Eric Biggers
@ 2026-01-23 11:37     ` David Howells
  0 siblings, 0 replies; 37+ messages in thread
From: David Howells @ 2026-01-23 11:37 UTC (permalink / raw)
  To: Eric Biggers
  Cc: dhowells, Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen,
	Herbert Xu, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen, Jason A . Donenfeld, Ard Biesheuvel,
	Stephan Mueller, linux-crypto, keyrings, linux-modules,
	linux-kernel

Eric Biggers <ebiggers@kernel.org> wrote:

> As I mentioned on v11, it's misleading to start using the term digest
> for something that isn't a digest.

I can call it 'm' if you like.  I don't want to call it 'message' as that is
overused here.

> Naturally, this confusing introduction of non-digest digests seems to
> have already caused a bug: IMA calls pkcs7_get_digest() to calculate the
> digest of the module.  But now that's no longer necessarily a digest.
> It could be the entire signed attributes.

The next patch deals with that, but I can move the error check forward...

> I'll also note that this commit doesn't fully implement "Allow the
> signing algo to calculate the digest itself" as claimed, since only the
> signed attributes case is handled.  It looks like the next patch is
> intended to handle the other case.  But it's not made clear at all that
> it's a two-part thing; this patch implies that it's complete.

... or just squash the two patches together.

David


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself
  2026-01-21 12:31     ` David Howells
@ 2026-01-24 11:46       ` Jarkko Sakkinen
  0 siblings, 0 replies; 37+ messages in thread
From: Jarkko Sakkinen @ 2026-01-24 11:46 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 Wed, Jan 21, 2026 at 12:31:35PM +0000, David Howells wrote:
> Jarkko Sakkinen <jarkko@kernel.org> wrote:
> 
> > I'd use the wording you used already in commit message, which
> > factors more descriptive than what you have here. E.g., name
> > it "external_digest".
> 
> ML-DSA uses "external" to mean that the caller does the
> digestion/hashing/XOF-ing/whatever Eric wants to call it, but the caller also
> has to put other stuff into the digest/hash/XOF/thing that then gets passed to
> ML-DSA if it does this.
> 
> For added confusion, the NIST FIPS tests seem to consider what this patch does
> as 'external' but an "external mu" as 'internal':
> 
> 	"tgId": 1,
> 	"testType": "AFT",
> 	"parameterSet": "ML-DSA-44",
> 	"signatureInterface": "external",
> 	"preHash": "pure",
> 
> vs:
> 
> 	"tgId": 7,
> 	"testType": "AFT",
> 	"parameterSet": "ML-DSA-44",
> 	"signatureInterface": "internal",
> 	"externalMu": true,
> 
> I haven't come up with a better name that particularly describes this.  Maybe
> use "no_prehash" or "algo_takes_hash" or "algo_takes_data"?
> 
> Maybe better than using a true/false value, use an enum?
> 
> 	enum public_key_hash {
> 		ALGO_SIGNS_HASH, /* RSA, ECDSA, ... */
> 		ALGO_SIGNS_DATA, /* MLDSA, ... */
> 	};

I think this would be better idea, as it makes the states more explicit.

And I was actually considering to suggest enum so yeah, I'm on board
with this suggestion.

> 
> David
> 

BR, Jarkko

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2026-01-24 11:46 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-20 14:50 [PATCH v13 00/12] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing David Howells
2026-01-20 14:50 ` [PATCH v13 01/12] crypto: Add ML-DSA crypto_sig support David Howells
2026-01-20 17:37   ` Jarkko Sakkinen
2026-01-20 20:52   ` Eric Biggers
2026-01-20 14:50 ` [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself David Howells
2026-01-20 17:53   ` Jarkko Sakkinen
2026-01-21 12:31     ` David Howells
2026-01-24 11:46       ` Jarkko Sakkinen
2026-01-20 21:12   ` Eric Biggers
2026-01-23 11:37     ` David Howells
2026-01-20 14:50 ` [PATCH v13 03/12] pkcs7: Allow direct signing of data with ML-DSA David Howells
2026-01-20 14:50 ` [PATCH v13 04/12] pkcs7, x509: Add ML-DSA support David Howells
2026-01-20 21:17   ` Eric Biggers
2026-01-20 14:50 ` [PATCH v13 05/12] modsign: Enable ML-DSA module signing David Howells
2026-01-20 21:38   ` Eric Biggers
2026-01-21 14:21     ` David Howells
2026-01-20 14:50 ` [PATCH v13 06/12] crypto: Add supplementary info param to asymmetric key signature verification David Howells
2026-01-20 14:50 ` [PATCH v13 07/12] crypto: Add RSASSA-PSS support David Howells
2026-01-20 22:41   ` Eric Biggers
2026-01-20 23:15     ` David Howells
2026-01-20 23:36       ` Eric Biggers
2026-01-21  8:11         ` Ignat Korchagin
2026-01-21  2:14     ` Eric Biggers
2026-01-21  8:15       ` Ignat Korchagin
2026-01-20 14:50 ` [PATCH v13 08/12] pkcs7, x509: " David Howells
2026-01-20 14:50 ` [PATCH v13 09/12] modsign: Enable RSASSA-PSS module signing David Howells
2026-01-20 14:50 ` [PATCH v13 10/12] pkcs7: Add FIPS selftest for RSASSA-PSS David Howells
2026-01-20 14:50 ` [PATCH v13 11/12] x509, pkcs7: Limit crypto combinations that may be used for module signing David Howells
2026-01-20 18:31   ` Ignat Korchagin
2026-01-20 18:54     ` David Howells
2026-01-20 21:51   ` Vitaly Chikunov
2026-01-20 23:18     ` David Howells
2026-01-20 22:14   ` Eric Biggers
2026-01-20 14:50 ` [PATCH v13 12/12] pkcs7: Add ML-DSA FIPS selftest David Howells
2026-01-20 17:54   ` Jarkko Sakkinen
2026-01-20 17:55     ` Jarkko Sakkinen
2026-01-20 21:43   ` Eric Biggers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox