[PATCH v13 07/12] crypto: Add RSASSA-PSS support

David Howells posted 12 patches 2 weeks, 4 days ago
There is a newer version of this series
[PATCH v13 07/12] crypto: Add RSASSA-PSS support
Posted by David Howells 2 weeks, 4 days ago
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
Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
Posted by Eric Biggers 2 weeks, 4 days ago
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
Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
Posted by Eric Biggers 2 weeks, 4 days ago
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
Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
Posted by Ignat Korchagin 2 weeks, 3 days ago
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
Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
Posted by David Howells 2 weeks, 4 days ago
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
Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
Posted by Eric Biggers 2 weeks, 4 days ago
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
Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
Posted by Ignat Korchagin 2 weeks, 3 days ago
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