diff mbox series

[v2,06/19] crypto: rsassa-pkcs1 - Migrate to sig_alg backend

Message ID 743afd4f298a3fad03e42ab46f913d1f51cb8b7c.1725972335.git.lukas@wunner.de (mailing list archive)
State New
Headers show
Series Migrate to sig_alg and templatize ecdsa | expand

Commit Message

Lukas Wunner Sept. 10, 2024, 2:30 p.m. UTC
A sig_alg backend has just been introduced with the intent of moving all
asymmetric sign/verify algorithms to it one by one.

Migrate the sign/verify operations from rsa-pkcs1pad.c to a separate
rsassa-pkcs1.c which uses the new backend.

Consequently there are now two templates which build on the "rsa"
akcipher_alg:

* The existing "pkcs1pad" template, which is instantiated as an
  akcipher_instance and retains the encrypt/decrypt operations of
  RSAES-PKCS1-v1_5 (RFC 8017 sec 7.2).

* The new "pkcs1" template, which is instantiated as a sig_instance
  and contains the sign/verify operations of RSASSA-PKCS1-v1_5
  (RFC 8017 sec 8.2).

In a separate step, rsa-pkcs1pad.c could optionally be renamed to
rsaes-pkcs1.c for clarity.  Additional "oaep" and "pss" templates
could be added for RSAES-OAEP and RSASSA-PSS.

Note that it's currently allowed to allocate a "pkcs1pad(rsa)" transform
without specifying a hash algorithm.  That makes sense if the transform
is only used for encrypt/decrypt and continues to be supported.  But for
sign/verify, such transforms previously did not insert the Full Hash
Prefix into the padding.  The resulting message encoding was incompliant
with EMSA-PKCS1-v1_5 (RFC 8017 sec 9.2) and therefore nonsensical.

From here on in, it is no longer allowed to allocate a transform without
specifying a hash algorithm if the transform is used for sign/verify
operations.  This simplifies the code because the insertion of the Full
Hash Prefix is no longer optional, so various "if (digest_info)" clauses
can be removed.

There has been a previous attempt to forbid transform allocation without
specifying a hash algorithm, namely by commit c0d20d22e0ad ("crypto:
rsa-pkcs1pad - Require hash to be present").  It had to be rolled back
with commit b3a8c8a5ebb5 ("crypto: rsa-pkcs1pad: Allow hash to be
optional [ver #2]"), presumably because it broke allocation of a
transform which was solely used for encrypt/decrypt, not sign/verify.
Avoid such breakage by allowing transform allocation for encrypt/decrypt
with and without specifying a hash algorithm (and simply ignoring the
hash algorithm in the former case).

So again, specifying a hash algorithm is now mandatory for sign/verify,
but optional and ignored for encrypt/decrypt.

The new sig_alg API uses kernel buffers instead of sglists, which
avoids the overhead of copying signature and digest from sglists back
into kernel buffers.  rsassa-pkcs1.c is thus simplified quite a bit.

sig_alg is always synchronous, whereas the underlying "rsa" akcipher_alg
may be asynchronous.  So await the result of the akcipher_alg, similar
to crypto_akcipher_sync_{en,de}crypt().

As part of the migration, rename "rsa_digest_info" to "hash_prefix" to
adhere to the spec language in RFC 9580.  Otherwise keep the code
unmodified wherever possible to ease reviewing and bisecting.  Leave
several simplification and hardening opportunities to separate commits.

rsassa-pkcs1.c uses modern __free() syntax for allocation of buffers
which need to be freed by kfree_sensitive(), hence a DEFINE_FREE()
clause for kfree_sensitive() is introduced herein as a byproduct.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 crypto/Kconfig                      |   1 +
 crypto/Makefile                     |   1 +
 crypto/asymmetric_keys/public_key.c |  10 +-
 crypto/rsa-pkcs1pad.c               | 341 ++--------------------
 crypto/rsa.c                        |  17 +-
 crypto/rsassa-pkcs1.c               | 422 ++++++++++++++++++++++++++++
 crypto/testmgr.c                    |  22 +-
 crypto/testmgr.h                    |   3 +-
 include/crypto/internal/rsa.h       |   1 +
 include/linux/slab.h                |   1 +
 security/integrity/ima/ima_main.c   |   6 +-
 11 files changed, 480 insertions(+), 345 deletions(-)
 create mode 100644 crypto/rsassa-pkcs1.c

Comments

Jarkko Sakkinen Sept. 11, 2024, 12:56 p.m. UTC | #1
On Tue Sep 10, 2024 at 5:30 PM EEST, Lukas Wunner wrote:
> A sig_alg backend has just been introduced with the intent of moving all
> asymmetric sign/verify algorithms to it one by one.
>
> Migrate the sign/verify operations from rsa-pkcs1pad.c to a separate
> rsassa-pkcs1.c which uses the new backend.
>
> Consequently there are now two templates which build on the "rsa"
> akcipher_alg:
>
> * The existing "pkcs1pad" template, which is instantiated as an
>   akcipher_instance and retains the encrypt/decrypt operations of
>   RSAES-PKCS1-v1_5 (RFC 8017 sec 7.2).
>
> * The new "pkcs1" template, which is instantiated as a sig_instance
>   and contains the sign/verify operations of RSASSA-PKCS1-v1_5
>   (RFC 8017 sec 8.2).
>
> In a separate step, rsa-pkcs1pad.c could optionally be renamed to
> rsaes-pkcs1.c for clarity.  Additional "oaep" and "pss" templates
> could be added for RSAES-OAEP and RSASSA-PSS.
>
> Note that it's currently allowed to allocate a "pkcs1pad(rsa)" transform
> without specifying a hash algorithm.  That makes sense if the transform
> is only used for encrypt/decrypt and continues to be supported.  But for
> sign/verify, such transforms previously did not insert the Full Hash
> Prefix into the padding.  The resulting message encoding was incompliant
> with EMSA-PKCS1-v1_5 (RFC 8017 sec 9.2) and therefore nonsensical.
>
> From here on in, it is no longer allowed to allocate a transform without
> specifying a hash algorithm if the transform is used for sign/verify
> operations.  This simplifies the code because the insertion of the Full
> Hash Prefix is no longer optional, so various "if (digest_info)" clauses
> can be removed.
>
> There has been a previous attempt to forbid transform allocation without
> specifying a hash algorithm, namely by commit c0d20d22e0ad ("crypto:
> rsa-pkcs1pad - Require hash to be present").  It had to be rolled back
> with commit b3a8c8a5ebb5 ("crypto: rsa-pkcs1pad: Allow hash to be
> optional [ver #2]"), presumably because it broke allocation of a
> transform which was solely used for encrypt/decrypt, not sign/verify.
> Avoid such breakage by allowing transform allocation for encrypt/decrypt
> with and without specifying a hash algorithm (and simply ignoring the
> hash algorithm in the former case).
>
> So again, specifying a hash algorithm is now mandatory for sign/verify,
> but optional and ignored for encrypt/decrypt.
>
> The new sig_alg API uses kernel buffers instead of sglists, which
> avoids the overhead of copying signature and digest from sglists back
> into kernel buffers.  rsassa-pkcs1.c is thus simplified quite a bit.
>
> sig_alg is always synchronous, whereas the underlying "rsa" akcipher_alg
> may be asynchronous.  So await the result of the akcipher_alg, similar
> to crypto_akcipher_sync_{en,de}crypt().
>
> As part of the migration, rename "rsa_digest_info" to "hash_prefix" to
> adhere to the spec language in RFC 9580.  Otherwise keep the code
> unmodified wherever possible to ease reviewing and bisecting.  Leave
> several simplification and hardening opportunities to separate commits.
>
> rsassa-pkcs1.c uses modern __free() syntax for allocation of buffers
> which need to be freed by kfree_sensitive(), hence a DEFINE_FREE()
> clause for kfree_sensitive() is introduced herein as a byproduct.

Just a generic comment without micro managing: I'd put focus on this
commit message and edit it a few rounds to make it easier to follow.
Now it is somewhat convoluted, which is not in balance with +480
SLOC.

>
> Signed-off-by: Lukas Wunner <lukas@wunner.de>
> ---
>  crypto/Kconfig                      |   1 +
>  crypto/Makefile                     |   1 +
>  crypto/asymmetric_keys/public_key.c |  10 +-
>  crypto/rsa-pkcs1pad.c               | 341 ++--------------------
>  crypto/rsa.c                        |  17 +-
>  crypto/rsassa-pkcs1.c               | 422 ++++++++++++++++++++++++++++
>  crypto/testmgr.c                    |  22 +-
>  crypto/testmgr.h                    |   3 +-
>  include/crypto/internal/rsa.h       |   1 +
>  include/linux/slab.h                |   1 +
>  security/integrity/ima/ima_main.c   |   6 +-
>  11 files changed, 480 insertions(+), 345 deletions(-)
>  create mode 100644 crypto/rsassa-pkcs1.c
>
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index e8488b8c45e3..94ef57c9e936 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -250,6 +250,7 @@ config CRYPTO_RSA
>  	tristate "RSA (Rivest-Shamir-Adleman)"
>  	select CRYPTO_AKCIPHER
>  	select CRYPTO_MANAGER
> +	select CRYPTO_SIG
>  	select MPILIB
>  	select ASN1
>  	help
> diff --git a/crypto/Makefile b/crypto/Makefile
> index 4c99e5d376f6..7de29bf843e9 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -48,6 +48,7 @@ rsa_generic-y += rsaprivkey.asn1.o
>  rsa_generic-y += rsa.o
>  rsa_generic-y += rsa_helper.o
>  rsa_generic-y += rsa-pkcs1pad.o
> +rsa_generic-y += rsassa-pkcs1.o
>  obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o
>  
>  $(obj)/ecdsasignature.asn1.o: $(obj)/ecdsasignature.asn1.c $(obj)/ecdsasignature.asn1.h
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index 422940a6706a..3fb27ecd65f6 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -83,13 +83,19 @@ software_key_determine_akcipher(const struct public_key *pkey,
>  		if (strcmp(encoding, "pkcs1") == 0) {
>  			*sig = op == kernel_pkey_sign ||
>  			       op == kernel_pkey_verify;
> -			if (!hash_algo) {
> +			if (!*sig) {
> +				/*
> +				 * For encrypt/decrypt, hash_algo is not used
> +				 * but allowed to be set for historic reasons.
> +				 */
>  				n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
>  					     "pkcs1pad(%s)",
>  					     pkey->pkey_algo);
>  			} else {
> +				if (!hash_algo)
> +					return -EINVAL;
>  				n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
> -					     "pkcs1pad(%s,%s)",
> +					     "pkcs1(%s,%s)",
>  					     pkey->pkey_algo, hash_algo);
>  			}
>  			return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
> diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
> index 3c5fe8c93938..50bdb18e7b48 100644
> --- a/crypto/rsa-pkcs1pad.c
> +++ b/crypto/rsa-pkcs1pad.c
> @@ -16,101 +16,6 @@
>  #include <linux/random.h>
>  #include <linux/scatterlist.h>
>  
> -/*
> - * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
> - */
> -static const u8 rsa_digest_info_md5[] = {
> -	0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,
> -	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* OID */
> -	0x05, 0x00, 0x04, 0x10
> -};
> -
> -static const u8 rsa_digest_info_sha1[] = {
> -	0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
> -	0x2b, 0x0e, 0x03, 0x02, 0x1a,
> -	0x05, 0x00, 0x04, 0x14
> -};
> -
> -static const u8 rsa_digest_info_rmd160[] = {
> -	0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
> -	0x2b, 0x24, 0x03, 0x02, 0x01,
> -	0x05, 0x00, 0x04, 0x14
> -};
> -
> -static const u8 rsa_digest_info_sha224[] = {
> -	0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
> -	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
> -	0x05, 0x00, 0x04, 0x1c
> -};
> -
> -static const u8 rsa_digest_info_sha256[] = {
> -	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
> -	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
> -	0x05, 0x00, 0x04, 0x20
> -};
> -
> -static const u8 rsa_digest_info_sha384[] = {
> -	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
> -	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
> -	0x05, 0x00, 0x04, 0x30
> -};
> -
> -static const u8 rsa_digest_info_sha512[] = {
> -	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
> -	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
> -	0x05, 0x00, 0x04, 0x40
> -};
> -
> -static const u8 rsa_digest_info_sha3_256[] = {
> -	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
> -	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08,
> -	0x05, 0x00, 0x04, 0x20
> -};
> -
> -static const u8 rsa_digest_info_sha3_384[] = {
> -	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
> -	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09,
> -	0x05, 0x00, 0x04, 0x30
> -};
> -
> -static const u8 rsa_digest_info_sha3_512[] = {
> -	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
> -	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A,
> -	0x05, 0x00, 0x04, 0x40
> -};
> -
> -static const struct rsa_asn1_template {
> -	const char	*name;
> -	const u8	*data;
> -	size_t		size;
> -} rsa_asn1_templates[] = {
> -#define _(X) { #X, rsa_digest_info_##X, sizeof(rsa_digest_info_##X) }
> -	_(md5),
> -	_(sha1),
> -	_(rmd160),
> -	_(sha256),
> -	_(sha384),
> -	_(sha512),
> -	_(sha224),
> -#undef _
> -#define _(X) { "sha3-" #X, rsa_digest_info_sha3_##X, sizeof(rsa_digest_info_sha3_##X) }
> -	_(256),
> -	_(384),
> -	_(512),
> -#undef _
> -	{ NULL }
> -};
> -
> -static const struct rsa_asn1_template *rsa_lookup_asn1(const char *name)
> -{
> -	const struct rsa_asn1_template *p;
> -
> -	for (p = rsa_asn1_templates; p->name; p++)
> -		if (strcmp(name, p->name) == 0)
> -			return p;
> -	return NULL;
> -}
> -
>  struct pkcs1pad_ctx {
>  	struct crypto_akcipher *child;
>  	unsigned int key_size;
> @@ -118,7 +23,6 @@ struct pkcs1pad_ctx {
>  
>  struct pkcs1pad_inst_ctx {
>  	struct crypto_akcipher_spawn spawn;
> -	const struct rsa_asn1_template *digest_info;
>  };
>  
>  struct pkcs1pad_request {
> @@ -148,9 +52,9 @@ static unsigned int pkcs1pad_get_max_size(struct crypto_akcipher *tfm)
>  	struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
>  
>  	/*
> -	 * The maximum destination buffer size for the encrypt/sign operations
> +	 * The maximum destination buffer size for the encrypt operation
>  	 * will be the same as for RSA, even though it's smaller for
> -	 * decrypt/verify.
> +	 * decrypt.
>  	 */
>  
>  	return ctx->key_size;
> @@ -168,7 +72,7 @@ static void pkcs1pad_sg_set_buf(struct scatterlist *sg, void *buf, size_t len,
>  		sg_chain(sg, nsegs, next);
>  }
>  
> -static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err)
> +static int pkcs1pad_encrypt_complete(struct akcipher_request *req, int err)
>  {
>  	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>  	struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
> @@ -207,14 +111,14 @@ static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err)
>  	return err;
>  }
>  
> -static void pkcs1pad_encrypt_sign_complete_cb(void *data, int err)
> +static void pkcs1pad_encrypt_complete_cb(void *data, int err)
>  {
>  	struct akcipher_request *req = data;
>  
>  	if (err == -EINPROGRESS)
>  		goto out;
>  
> -	err = pkcs1pad_encrypt_sign_complete(req, err);
> +	err = pkcs1pad_encrypt_complete(req, err);
>  
>  out:
>  	akcipher_request_complete(req, err);
> @@ -255,7 +159,7 @@ static int pkcs1pad_encrypt(struct akcipher_request *req)
>  
>  	akcipher_request_set_tfm(&req_ctx->child_req, ctx->child);
>  	akcipher_request_set_callback(&req_ctx->child_req, req->base.flags,
> -			pkcs1pad_encrypt_sign_complete_cb, req);
> +			pkcs1pad_encrypt_complete_cb, req);
>  
>  	/* Reuse output buffer */
>  	akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg,
> @@ -263,7 +167,7 @@ static int pkcs1pad_encrypt(struct akcipher_request *req)
>  
>  	err = crypto_akcipher_encrypt(&req_ctx->child_req);
>  	if (err != -EINPROGRESS && err != -EBUSY)
> -		return pkcs1pad_encrypt_sign_complete(req, err);
> +		return pkcs1pad_encrypt_complete(req, err);
>  
>  	return err;
>  }
> @@ -368,195 +272,6 @@ static int pkcs1pad_decrypt(struct akcipher_request *req)
>  	return err;
>  }
>  
> -static int pkcs1pad_sign(struct akcipher_request *req)
> -{
> -	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> -	struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
> -	struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
> -	struct akcipher_instance *inst = akcipher_alg_instance(tfm);
> -	struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst);
> -	const struct rsa_asn1_template *digest_info = ictx->digest_info;
> -	int err;
> -	unsigned int ps_end, digest_info_size = 0;
> -
> -	if (!ctx->key_size)
> -		return -EINVAL;
> -
> -	if (digest_info)
> -		digest_info_size = digest_info->size;
> -
> -	if (req->src_len + digest_info_size > ctx->key_size - 11)
> -		return -EOVERFLOW;
> -
> -	if (req->dst_len < ctx->key_size) {
> -		req->dst_len = ctx->key_size;
> -		return -EOVERFLOW;
> -	}
> -
> -	req_ctx->in_buf = kmalloc(ctx->key_size - 1 - req->src_len,
> -				  GFP_KERNEL);
> -	if (!req_ctx->in_buf)
> -		return -ENOMEM;
> -
> -	ps_end = ctx->key_size - digest_info_size - req->src_len - 2;
> -	req_ctx->in_buf[0] = 0x01;
> -	memset(req_ctx->in_buf + 1, 0xff, ps_end - 1);
> -	req_ctx->in_buf[ps_end] = 0x00;
> -
> -	if (digest_info)
> -		memcpy(req_ctx->in_buf + ps_end + 1, digest_info->data,
> -		       digest_info->size);
> -
> -	pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf,
> -			ctx->key_size - 1 - req->src_len, req->src);
> -
> -	akcipher_request_set_tfm(&req_ctx->child_req, ctx->child);
> -	akcipher_request_set_callback(&req_ctx->child_req, req->base.flags,
> -			pkcs1pad_encrypt_sign_complete_cb, req);
> -
> -	/* Reuse output buffer */
> -	akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg,
> -				   req->dst, ctx->key_size - 1, req->dst_len);
> -
> -	err = crypto_akcipher_decrypt(&req_ctx->child_req);
> -	if (err != -EINPROGRESS && err != -EBUSY)
> -		return pkcs1pad_encrypt_sign_complete(req, err);
> -
> -	return err;
> -}
> -
> -static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
> -{
> -	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> -	struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
> -	struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
> -	struct akcipher_instance *inst = akcipher_alg_instance(tfm);
> -	struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst);
> -	const struct rsa_asn1_template *digest_info = ictx->digest_info;
> -	const unsigned int sig_size = req->src_len;
> -	const unsigned int digest_size = req->dst_len;
> -	unsigned int dst_len;
> -	unsigned int pos;
> -	u8 *out_buf;
> -
> -	if (err)
> -		goto done;
> -
> -	err = -EINVAL;
> -	dst_len = req_ctx->child_req.dst_len;
> -	if (dst_len < ctx->key_size - 1)
> -		goto done;
> -
> -	out_buf = req_ctx->out_buf;
> -	if (dst_len == ctx->key_size) {
> -		if (out_buf[0] != 0x00)
> -			/* Decrypted value had no leading 0 byte */
> -			goto done;
> -
> -		dst_len--;
> -		out_buf++;
> -	}
> -
> -	err = -EBADMSG;
> -	if (out_buf[0] != 0x01)
> -		goto done;
> -
> -	for (pos = 1; pos < dst_len; pos++)
> -		if (out_buf[pos] != 0xff)
> -			break;
> -
> -	if (pos < 9 || pos == dst_len || out_buf[pos] != 0x00)
> -		goto done;
> -	pos++;
> -
> -	if (digest_info) {
> -		if (digest_info->size > dst_len - pos)
> -			goto done;
> -		if (crypto_memneq(out_buf + pos, digest_info->data,
> -				  digest_info->size))
> -			goto done;
> -
> -		pos += digest_info->size;
> -	}
> -
> -	err = 0;
> -
> -	if (digest_size != dst_len - pos) {
> -		err = -EKEYREJECTED;
> -		req->dst_len = dst_len - pos;
> -		goto done;
> -	}
> -	/* Extract appended digest. */
> -	sg_pcopy_to_buffer(req->src,
> -			   sg_nents_for_len(req->src, sig_size + digest_size),
> -			   req_ctx->out_buf + ctx->key_size,
> -			   digest_size, sig_size);
> -	/* Do the actual verification step. */
> -	if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos,
> -		   digest_size) != 0)
> -		err = -EKEYREJECTED;
> -done:
> -	kfree_sensitive(req_ctx->out_buf);
> -
> -	return err;
> -}
> -
> -static void pkcs1pad_verify_complete_cb(void *data, int err)
> -{
> -	struct akcipher_request *req = data;
> -
> -	if (err == -EINPROGRESS)
> -		goto out;
> -
> -	err = pkcs1pad_verify_complete(req, err);
> -
> -out:
> -	akcipher_request_complete(req, err);
> -}
> -
> -/*
> - * The verify operation is here for completeness similar to the verification
> - * defined in RFC2313 section 10.2 except that block type 0 is not accepted,
> - * as in RFC2437.  RFC2437 section 9.2 doesn't define any operation to
> - * retrieve the DigestInfo from a signature, instead the user is expected
> - * to call the sign operation to generate the expected signature and compare
> - * signatures instead of the message-digests.
> - */
> -static int pkcs1pad_verify(struct akcipher_request *req)
> -{
> -	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> -	struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
> -	struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
> -	const unsigned int sig_size = req->src_len;
> -	const unsigned int digest_size = req->dst_len;
> -	int err;
> -
> -	if (WARN_ON(req->dst) || WARN_ON(!digest_size) ||
> -	    !ctx->key_size || sig_size != ctx->key_size)
> -		return -EINVAL;
> -
> -	req_ctx->out_buf = kmalloc(ctx->key_size + digest_size, GFP_KERNEL);
> -	if (!req_ctx->out_buf)
> -		return -ENOMEM;
> -
> -	pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf,
> -			    ctx->key_size, NULL);
> -
> -	akcipher_request_set_tfm(&req_ctx->child_req, ctx->child);
> -	akcipher_request_set_callback(&req_ctx->child_req, req->base.flags,
> -			pkcs1pad_verify_complete_cb, req);
> -
> -	/* Reuse input buffer, output to a new buffer */
> -	akcipher_request_set_crypt(&req_ctx->child_req, req->src,
> -				   req_ctx->out_sg, sig_size, ctx->key_size);
> -
> -	err = crypto_akcipher_encrypt(&req_ctx->child_req);
> -	if (err != -EINPROGRESS && err != -EBUSY)
> -		return pkcs1pad_verify_complete(req, err);
> -
> -	return err;
> -}
> -
>  static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm)
>  {
>  	struct akcipher_instance *inst = akcipher_alg_instance(tfm);
> @@ -598,7 +313,6 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
>  	struct akcipher_instance *inst;
>  	struct pkcs1pad_inst_ctx *ctx;
>  	struct akcipher_alg *rsa_alg;
> -	const char *hash_name;
>  	int err;
>  
>  	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AKCIPHER, &mask);
> @@ -624,36 +338,15 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
>  	}
>  
>  	err = -ENAMETOOLONG;
> -	hash_name = crypto_attr_alg_name(tb[2]);
> -	if (IS_ERR(hash_name)) {
> -		if (snprintf(inst->alg.base.cra_name,
> -			     CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
> -			     rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
> -			goto err_free_inst;
> -
> -		if (snprintf(inst->alg.base.cra_driver_name,
> -			     CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
> -			     rsa_alg->base.cra_driver_name) >=
> -			     CRYPTO_MAX_ALG_NAME)
> -			goto err_free_inst;
> -	} else {
> -		ctx->digest_info = rsa_lookup_asn1(hash_name);
> -		if (!ctx->digest_info) {
> -			err = -EINVAL;
> -			goto err_free_inst;
> -		}
> -
> -		if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
> -			     "pkcs1pad(%s,%s)", rsa_alg->base.cra_name,
> -			     hash_name) >= CRYPTO_MAX_ALG_NAME)
> -			goto err_free_inst;
> -
> -		if (snprintf(inst->alg.base.cra_driver_name,
> -			     CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)",
> -			     rsa_alg->base.cra_driver_name,
> -			     hash_name) >= CRYPTO_MAX_ALG_NAME)
> -			goto err_free_inst;
> -	}
> +	if (snprintf(inst->alg.base.cra_name,
> +		     CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
> +		     rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
> +		goto err_free_inst;
> +
> +	if (snprintf(inst->alg.base.cra_driver_name,
> +		     CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
> +		     rsa_alg->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
> +		goto err_free_inst;
>  
>  	inst->alg.base.cra_priority = rsa_alg->base.cra_priority;
>  	inst->alg.base.cra_ctxsize = sizeof(struct pkcs1pad_ctx);
> @@ -663,8 +356,6 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
>  
>  	inst->alg.encrypt = pkcs1pad_encrypt;
>  	inst->alg.decrypt = pkcs1pad_decrypt;
> -	inst->alg.sign = pkcs1pad_sign;
> -	inst->alg.verify = pkcs1pad_verify;
>  	inst->alg.set_pub_key = pkcs1pad_set_pub_key;
>  	inst->alg.set_priv_key = pkcs1pad_set_priv_key;
>  	inst->alg.max_size = pkcs1pad_get_max_size;
> diff --git a/crypto/rsa.c b/crypto/rsa.c
> index d9be9e86097e..89e9fd9f6d7f 100644
> --- a/crypto/rsa.c
> +++ b/crypto/rsa.c
> @@ -402,16 +402,25 @@ static int __init rsa_init(void)
>  		return err;
>  
>  	err = crypto_register_template(&rsa_pkcs1pad_tmpl);
> -	if (err) {
> -		crypto_unregister_akcipher(&rsa);
> -		return err;
> -	}
> +	if (err)
> +		goto err_unregister_rsa;
> +
> +	err = crypto_register_template(&rsassa_pkcs1_tmpl);
> +	if (err)
> +		goto err_unregister_rsa_pkcs1pad;
>  
>  	return 0;
> +
> +err_unregister_rsa_pkcs1pad:
> +	crypto_unregister_template(&rsa_pkcs1pad_tmpl);
> +err_unregister_rsa:
> +	crypto_unregister_akcipher(&rsa);
> +	return err;
>  }
>  
>  static void __exit rsa_exit(void)
>  {
> +	crypto_unregister_template(&rsassa_pkcs1_tmpl);
>  	crypto_unregister_template(&rsa_pkcs1pad_tmpl);
>  	crypto_unregister_akcipher(&rsa);
>  }
> diff --git a/crypto/rsassa-pkcs1.c b/crypto/rsassa-pkcs1.c
> new file mode 100644
> index 000000000000..779c080fc013
> --- /dev/null
> +++ b/crypto/rsassa-pkcs1.c
> @@ -0,0 +1,422 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * RSA Signature Scheme with Appendix - PKCS #1 v1.5 (RFC 8017 sec 8.2)
> + *
> + * https://www.rfc-editor.org/rfc/rfc8017#section-8.2
> + *
> + * Copyright (c) 2015 - 2024 Intel Corporation
> + */
> +
> +#include <linux/module.h>
> +#include <linux/scatterlist.h>
> +#include <crypto/akcipher.h>
> +#include <crypto/algapi.h>
> +#include <crypto/sig.h>
> +#include <crypto/internal/akcipher.h>
> +#include <crypto/internal/rsa.h>
> +#include <crypto/internal/sig.h>
> +
> +/*
> + * Full Hash Prefix for EMSA-PKCS1-v1_5 encoding method (RFC 9580 table 24)
> + *
> + * RSA keys are usually much larger than the hash of the message to be signed.
> + * The hash is therefore prepended by the Full Hash Prefix and a 0xff padding.
> + * The Full Hash Prefix is an ASN.1 SEQUENCE containing the hash algorithm OID.
> + *
> + * https://www.rfc-editor.org/rfc/rfc9580#table-24
> + */
> +
> +static const u8 hash_prefix_md5[] = {
> +	0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,	  /* SEQUENCE (SEQUENCE (OID */
> +	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05,	/*	<algorithm>, */
> +	0x05, 0x00, 0x04, 0x10		      /* NULL), OCTET STRING <hash>) */
> +};
> +
> +static const u8 hash_prefix_sha1[] = {
> +	0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
> +	0x2b, 0x0e, 0x03, 0x02, 0x1a,
> +	0x05, 0x00, 0x04, 0x14
> +};
> +
> +static const u8 hash_prefix_rmd160[] = {
> +	0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
> +	0x2b, 0x24, 0x03, 0x02, 0x01,
> +	0x05, 0x00, 0x04, 0x14
> +};
> +
> +static const u8 hash_prefix_sha224[] = {
> +	0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
> +	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
> +	0x05, 0x00, 0x04, 0x1c
> +};
> +
> +static const u8 hash_prefix_sha256[] = {
> +	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
> +	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
> +	0x05, 0x00, 0x04, 0x20
> +};
> +
> +static const u8 hash_prefix_sha384[] = {
> +	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
> +	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
> +	0x05, 0x00, 0x04, 0x30
> +};
> +
> +static const u8 hash_prefix_sha512[] = {
> +	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
> +	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
> +	0x05, 0x00, 0x04, 0x40
> +};
> +
> +static const u8 hash_prefix_sha3_256[] = {
> +	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
> +	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08,
> +	0x05, 0x00, 0x04, 0x20
> +};
> +
> +static const u8 hash_prefix_sha3_384[] = {
> +	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
> +	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09,
> +	0x05, 0x00, 0x04, 0x30
> +};
> +
> +static const u8 hash_prefix_sha3_512[] = {
> +	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
> +	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a,
> +	0x05, 0x00, 0x04, 0x40
> +};
> +
> +static const struct hash_prefix {
> +	const char	*name;
> +	const u8	*data;
> +	size_t		size;
> +} hash_prefixes[] = {
> +#define _(X) { #X, hash_prefix_##X, sizeof(hash_prefix_##X) }
> +	_(md5),
> +	_(sha1),
> +	_(rmd160),
> +	_(sha256),
> +	_(sha384),
> +	_(sha512),
> +	_(sha224),
> +#undef _
> +#define _(X) { "sha3-" #X, hash_prefix_sha3_##X, sizeof(hash_prefix_sha3_##X) }
> +	_(256),
> +	_(384),
> +	_(512),
> +#undef _
> +	{ NULL }
> +};
> +
> +static const struct hash_prefix *rsassa_pkcs1_find_hash_prefix(const char *name)
> +{
> +	const struct hash_prefix *p;
> +
> +	for (p = hash_prefixes; p->name; p++)
> +		if (strcmp(name, p->name) == 0)
> +			return p;
> +	return NULL;
> +}
> +
> +struct rsassa_pkcs1_ctx {
> +	struct crypto_akcipher *child;
> +	unsigned int key_size;
> +};
> +
> +struct rsassa_pkcs1_inst_ctx {
> +	struct crypto_akcipher_spawn spawn;
> +	const struct hash_prefix *hash_prefix;
> +};
> +
> +static int rsassa_pkcs1_sign(struct crypto_sig *tfm,
> +			     const void *src, unsigned int slen,
> +			     void *dst, unsigned int dlen)
> +{
> +	struct sig_instance *inst = sig_alg_instance(tfm);
> +	struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
> +	const struct hash_prefix *hash_prefix = ictx->hash_prefix;
> +	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
> +	unsigned int child_reqsize = crypto_akcipher_reqsize(ctx->child);
> +	struct akcipher_request *child_req __free(kfree_sensitive) = NULL;
> +	struct scatterlist in_sg[2], out_sg;
> +	struct crypto_wait cwait;
> +	unsigned int pad_len;
> +	unsigned int ps_end;
> +	unsigned int len;
> +	u8 *in_buf;
> +	int err;
> +
> +	if (!ctx->key_size)
> +		return -EINVAL;
> +
> +	if (dlen < ctx->key_size)
> +		return -EOVERFLOW;
> +
> +	if (slen + hash_prefix->size > ctx->key_size - 11)
> +		return -EOVERFLOW;
> +
> +	child_req = kmalloc(sizeof(*child_req) + child_reqsize +
> +			    ctx->key_size - 1 - slen, GFP_KERNEL);
> +	if (!child_req)
> +		return -ENOMEM;
> +
> +	/* RFC 8017 sec 8.2.1 step 1 - EMSA-PKCS1-v1_5 encoding generation */
> +	in_buf = (u8 *)(child_req + 1) + child_reqsize;
> +	ps_end = ctx->key_size - hash_prefix->size - slen - 2;
> +	in_buf[0] = 0x01;
> +	memset(in_buf + 1, 0xff, ps_end - 1);
> +	in_buf[ps_end] = 0x00;
> +	memcpy(in_buf + ps_end + 1, hash_prefix->data, hash_prefix->size);
> +
> +	/* RFC 8017 sec 8.2.1 step 2 - RSA signature */
> +	crypto_init_wait(&cwait);
> +	sg_init_table(in_sg, 2);
> +	sg_set_buf(&in_sg[0], in_buf, ctx->key_size - 1 - slen);
> +	sg_set_buf(&in_sg[1], src, slen);
> +	sg_init_one(&out_sg, dst, dlen);
> +	akcipher_request_set_tfm(child_req, ctx->child);
> +	akcipher_request_set_crypt(child_req, in_sg, &out_sg,
> +				   ctx->key_size - 1, dlen);
> +	akcipher_request_set_callback(child_req, CRYPTO_TFM_REQ_MAY_SLEEP,
> +				      crypto_req_done, &cwait);
> +
> +	err = crypto_akcipher_decrypt(child_req);
> +	err = crypto_wait_req(err, &cwait);
> +	if (err)
> +		return err;
> +
> +	len = child_req->dst_len;
> +	pad_len = ctx->key_size - len;
> +
> +	/* Four billion to one */
> +	if (unlikely(pad_len)) {
> +		memmove(dst + pad_len, dst, len);
> +		memset(dst, 0, pad_len);
> +	}
> +
> +	return 0;
> +}
> +
> +static int rsassa_pkcs1_verify(struct crypto_sig *tfm,
> +			       const void *src, unsigned int slen,
> +			       const void *digest, unsigned int dlen)
> +{
> +	struct sig_instance *inst = sig_alg_instance(tfm);
> +	struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
> +	const struct hash_prefix *hash_prefix = ictx->hash_prefix;
> +	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
> +	unsigned int child_reqsize = crypto_akcipher_reqsize(ctx->child);
> +	struct akcipher_request *child_req __free(kfree_sensitive) = NULL;
> +	struct scatterlist in_sg, out_sg;
> +	struct crypto_wait cwait;
> +	unsigned int dst_len;
> +	unsigned int pos;
> +	u8 *out_buf;
> +	int err;
> +
> +	/* RFC 8017 sec 8.2.2 step 1 - length checking */
> +	if (!ctx->key_size ||
> +	    slen != ctx->key_size ||
> +	    !dlen)
> +		return -EINVAL;
> +
> +	/* RFC 8017 sec 8.2.2 step 2 - RSA verification */
> +	child_req = kmalloc(sizeof(*child_req) + child_reqsize + ctx->key_size,
> +			    GFP_KERNEL);
> +	if (!child_req)
> +		return -ENOMEM;
> +
> +	out_buf = (u8 *)(child_req + 1) + child_reqsize;
> +
> +	crypto_init_wait(&cwait);
> +	sg_init_one(&in_sg, src, slen);
> +	sg_init_one(&out_sg, out_buf, ctx->key_size);
> +	akcipher_request_set_tfm(child_req, ctx->child);
> +	akcipher_request_set_crypt(child_req, &in_sg, &out_sg,
> +				   slen, ctx->key_size);
> +	akcipher_request_set_callback(child_req, CRYPTO_TFM_REQ_MAY_SLEEP,
> +				      crypto_req_done, &cwait);
> +
> +	err = crypto_akcipher_encrypt(child_req);
> +	err = crypto_wait_req(err, &cwait);
> +	if (err)
> +		return err;
> +
> +	/* RFC 8017 sec 8.2.2 step 3 - EMSA-PKCS1-v1_5 encoding verification */
> +	dst_len = child_req->dst_len;
> +	if (dst_len < ctx->key_size - 1)
> +		return -EINVAL;
> +
> +	if (dst_len == ctx->key_size) {
> +		if (out_buf[0] != 0x00)
> +			/* Encrypted value had no leading 0 byte */
> +			return -EINVAL;
> +
> +		dst_len--;
> +		out_buf++;
> +	}
> +
> +	if (out_buf[0] != 0x01)
> +		return -EBADMSG;
> +
> +	for (pos = 1; pos < dst_len; pos++)
> +		if (out_buf[pos] != 0xff)
> +			break;
> +
> +	if (pos < 9 || pos == dst_len || out_buf[pos] != 0x00)
> +		return -EBADMSG;
> +	pos++;
> +
> +	if (hash_prefix->size > dst_len - pos)
> +		return -EBADMSG;
> +	if (crypto_memneq(out_buf + pos, hash_prefix->data, hash_prefix->size))
> +		return -EBADMSG;
> +	pos += hash_prefix->size;
> +
> +	/* RFC 8017 sec 8.2.2 step 4 - comparison of digest with out_buf */
> +	if (dlen != dst_len - pos)
> +		return -EKEYREJECTED;
> +	if (memcmp(digest, out_buf + pos, dlen) != 0)
> +		return -EKEYREJECTED;
> +
> +	return 0;
> +}
> +
> +static unsigned int rsassa_pkcs1_max_size(struct crypto_sig *tfm)
> +{
> +	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
> +
> +	return ctx->key_size;
> +}
> +
> +static int rsassa_pkcs1_set_pub_key(struct crypto_sig *tfm,
> +				    const void *key, unsigned int keylen)
> +{
> +	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
> +
> +	return rsa_set_key(ctx->child, &ctx->key_size, RSA_PUB, key, keylen);
> +}
> +
> +static int rsassa_pkcs1_set_priv_key(struct crypto_sig *tfm,
> +				     const void *key, unsigned int keylen)
> +{
> +	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
> +
> +	return rsa_set_key(ctx->child, &ctx->key_size, RSA_PRIV, key, keylen);
> +}
> +
> +static int rsassa_pkcs1_init_tfm(struct crypto_sig *tfm)
> +{
> +	struct sig_instance *inst = sig_alg_instance(tfm);
> +	struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
> +	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
> +	struct crypto_akcipher *child_tfm;
> +
> +	child_tfm = crypto_spawn_akcipher(&ictx->spawn);
> +	if (IS_ERR(child_tfm))
> +		return PTR_ERR(child_tfm);
> +
> +	ctx->child = child_tfm;
> +
> +	return 0;
> +}
> +
> +static void rsassa_pkcs1_exit_tfm(struct crypto_sig *tfm)
> +{
> +	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
> +
> +	crypto_free_akcipher(ctx->child);
> +}
> +
> +static void rsassa_pkcs1_free(struct sig_instance *inst)
> +{
> +	struct rsassa_pkcs1_inst_ctx *ctx = sig_instance_ctx(inst);
> +	struct crypto_akcipher_spawn *spawn = &ctx->spawn;
> +
> +	crypto_drop_akcipher(spawn);
> +	kfree(inst);
> +}
> +
> +static int rsassa_pkcs1_create(struct crypto_template *tmpl, struct rtattr **tb)
> +{
> +	struct rsassa_pkcs1_inst_ctx *ctx;
> +	struct akcipher_alg *rsa_alg;
> +	struct sig_instance *inst;
> +	const char *hash_name;
> +	u32 mask;
> +	int err;
> +
> +	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SIG, &mask);
> +	if (err)
> +		return err;
> +
> +	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
> +	if (!inst)
> +		return -ENOMEM;
> +
> +	ctx = sig_instance_ctx(inst);
> +
> +	err = crypto_grab_akcipher(&ctx->spawn, sig_crypto_instance(inst),
> +				   crypto_attr_alg_name(tb[1]), 0, mask);
> +	if (err)
> +		goto err_free_inst;
> +
> +	rsa_alg = crypto_spawn_akcipher_alg(&ctx->spawn);
> +
> +	if (strcmp(rsa_alg->base.cra_name, "rsa") != 0) {
> +		err = -EINVAL;
> +		goto err_free_inst;
> +	}
> +
> +	hash_name = crypto_attr_alg_name(tb[2]);
> +	if (IS_ERR(hash_name)) {
> +		err = PTR_ERR(hash_name);
> +		goto err_free_inst;
> +	}
> +
> +	ctx->hash_prefix = rsassa_pkcs1_find_hash_prefix(hash_name);
> +	if (!ctx->hash_prefix) {
> +		err = -EINVAL;
> +		goto err_free_inst;
> +	}
> +
> +	err = -ENAMETOOLONG;
> +	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
> +		     "pkcs1(%s,%s)", rsa_alg->base.cra_name,
> +		     hash_name) >= CRYPTO_MAX_ALG_NAME)
> +		goto err_free_inst;
> +
> +	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
> +		     "pkcs1(%s,%s)", rsa_alg->base.cra_driver_name,
> +		     hash_name) >= CRYPTO_MAX_ALG_NAME)
> +		goto err_free_inst;
> +
> +	inst->alg.base.cra_priority = rsa_alg->base.cra_priority;
> +	inst->alg.base.cra_ctxsize = sizeof(struct rsassa_pkcs1_ctx);
> +
> +	inst->alg.init = rsassa_pkcs1_init_tfm;
> +	inst->alg.exit = rsassa_pkcs1_exit_tfm;
> +
> +	inst->alg.sign = rsassa_pkcs1_sign;
> +	inst->alg.verify = rsassa_pkcs1_verify;
> +	inst->alg.max_size = rsassa_pkcs1_max_size;
> +	inst->alg.set_pub_key = rsassa_pkcs1_set_pub_key;
> +	inst->alg.set_priv_key = rsassa_pkcs1_set_priv_key;
> +
> +	inst->free = rsassa_pkcs1_free;
> +
> +	err = sig_register_instance(tmpl, inst);
> +	if (err) {
> +err_free_inst:
> +		rsassa_pkcs1_free(inst);
> +	}
> +	return err;
> +}
> +
> +struct crypto_template rsassa_pkcs1_tmpl = {
> +	.name = "pkcs1",
> +	.create = rsassa_pkcs1_create,
> +	.module = THIS_MODULE,
> +};
> +
> +MODULE_ALIAS_CRYPTO("pkcs1");
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index 0542817a9456..91dc29e79dd6 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -5548,34 +5548,38 @@ static const struct alg_test_desc alg_test_descs[] = {
>  			.cipher = __VECS(fcrypt_pcbc_tv_template)
>  		}
>  	}, {
> -		.alg = "pkcs1pad(rsa,sha224)",
> +		.alg = "pkcs1(rsa,sha224)",
>  		.test = alg_test_null,
>  		.fips_allowed = 1,
>  	}, {
> -		.alg = "pkcs1pad(rsa,sha256)",
> -		.test = alg_test_akcipher,
> +		.alg = "pkcs1(rsa,sha256)",
> +		.test = alg_test_sig,
>  		.fips_allowed = 1,
>  		.suite = {
> -			.akcipher = __VECS(pkcs1pad_rsa_tv_template)
> +			.sig = __VECS(pkcs1_rsa_tv_template)
>  		}
>  	}, {
> -		.alg = "pkcs1pad(rsa,sha3-256)",
> +		.alg = "pkcs1(rsa,sha3-256)",
> +		.test = alg_test_null,
> +		.fips_allowed = 1,
> +	}, {
> +		.alg = "pkcs1(rsa,sha3-384)",
>  		.test = alg_test_null,
>  		.fips_allowed = 1,
>  	}, {
> -		.alg = "pkcs1pad(rsa,sha3-384)",
> +		.alg = "pkcs1(rsa,sha3-512)",
>  		.test = alg_test_null,
>  		.fips_allowed = 1,
>  	}, {
> -		.alg = "pkcs1pad(rsa,sha3-512)",
> +		.alg = "pkcs1(rsa,sha384)",
>  		.test = alg_test_null,
>  		.fips_allowed = 1,
>  	}, {
> -		.alg = "pkcs1pad(rsa,sha384)",
> +		.alg = "pkcs1(rsa,sha512)",
>  		.test = alg_test_null,
>  		.fips_allowed = 1,
>  	}, {
> -		.alg = "pkcs1pad(rsa,sha512)",
> +		.alg = "pkcs1pad(rsa)",
>  		.test = alg_test_null,
>  		.fips_allowed = 1,
>  	}, {
> diff --git a/crypto/testmgr.h b/crypto/testmgr.h
> index fd4823c26d93..d29d03fec852 100644
> --- a/crypto/testmgr.h
> +++ b/crypto/testmgr.h
> @@ -1268,7 +1268,7 @@ static const struct sig_testvec ecrdsa_tv_template[] = {
>  /*
>   * PKCS#1 RSA test vectors. Obtained from CAVS testing.
>   */
> -static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
> +static const struct sig_testvec pkcs1_rsa_tv_template[] = {
>  	{
>  	.key =
>  	"\x30\x82\x04\xa5\x02\x01\x00\x02\x82\x01\x01\x00\xd7\x1e\x77\x82"
> @@ -1380,7 +1380,6 @@ static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
>  	"\xda\x62\x8d\xe1\x2a\x71\x91\x43\x40\x61\x3c\x5a\xbe\x86\xfc\x5b"
>  	"\xe6\xf9\xa9\x16\x31\x1f\xaf\x25\x6d\xc2\x4a\x23\x6e\x63\x02\xa2",
>  	.c_size = 256,
> -	.siggen_sigver_test = true,
>  	}
>  };
>  
> diff --git a/include/crypto/internal/rsa.h b/include/crypto/internal/rsa.h
> index 754f687134df..071a1951b992 100644
> --- a/include/crypto/internal/rsa.h
> +++ b/include/crypto/internal/rsa.h
> @@ -82,4 +82,5 @@ static inline int rsa_set_key(struct crypto_akcipher *child,
>  }
>  
>  extern struct crypto_template rsa_pkcs1pad_tmpl;
> +extern struct crypto_template rsassa_pkcs1_tmpl;
>  #endif
> diff --git a/include/linux/slab.h b/include/linux/slab.h
> index eb2bf4629157..11b620b0ba1d 100644
> --- a/include/linux/slab.h
> +++ b/include/linux/slab.h
> @@ -280,6 +280,7 @@ void kfree_sensitive(const void *objp);
>  size_t __ksize(const void *objp);
>  
>  DEFINE_FREE(kfree, void *, if (!IS_ERR_OR_NULL(_T)) kfree(_T))
> +DEFINE_FREE(kfree_sensitive, void *, if (_T) kfree_sensitive(_T))
>  
>  /**
>   * ksize - Report actual allocation size of associated object
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index f04f43af651c..280a3feeba45 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -1114,7 +1114,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);
>  #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
>  
>  /**
> - * ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests
> + * ima_kernel_module_request - Prevent crypto-pkcs1(rsa,*) requests
>   * @kmod_name: kernel module name
>   *
>   * Avoid a verification loop where verifying the signature of the modprobe
> @@ -1128,7 +1128,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);
>   * algorithm on the fly, but crypto_larval_lookup() will try to use alg_name
>   * in order to load a kernel module with same name.
>   *
> - * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
> + * Since we don't have any real "crypto-pkcs1(rsa,*)" kernel modules,
>   * we are safe to fail such module request from crypto_larval_lookup(), and
>   * avoid the verification loop.
>   *
> @@ -1136,7 +1136,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data);
>   */
>  static int ima_kernel_module_request(char *kmod_name)
>  {
> -	if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
> +	if (strncmp(kmod_name, "crypto-pkcs1(rsa,", 17) == 0)
>  		return -EINVAL;
>  
>  	return 0;
Klara Modin Oct. 21, 2024, 4:08 p.m. UTC | #2
Hi,

On 2024-09-10 16:30, Lukas Wunner wrote:
> A sig_alg backend has just been introduced with the intent of moving all
> asymmetric sign/verify algorithms to it one by one.
> 
> Migrate the sign/verify operations from rsa-pkcs1pad.c to a separate
> rsassa-pkcs1.c which uses the new backend.
> 
> Consequently there are now two templates which build on the "rsa"
> akcipher_alg:
> 
> * The existing "pkcs1pad" template, which is instantiated as an
>    akcipher_instance and retains the encrypt/decrypt operations of
>    RSAES-PKCS1-v1_5 (RFC 8017 sec 7.2).
> 
> * The new "pkcs1" template, which is instantiated as a sig_instance
>    and contains the sign/verify operations of RSASSA-PKCS1-v1_5
>    (RFC 8017 sec 8.2).
> 
> In a separate step, rsa-pkcs1pad.c could optionally be renamed to
> rsaes-pkcs1.c for clarity.  Additional "oaep" and "pss" templates
> could be added for RSAES-OAEP and RSASSA-PSS.
> 
> Note that it's currently allowed to allocate a "pkcs1pad(rsa)" transform
> without specifying a hash algorithm.  That makes sense if the transform
> is only used for encrypt/decrypt and continues to be supported.  But for
> sign/verify, such transforms previously did not insert the Full Hash
> Prefix into the padding.  The resulting message encoding was incompliant
> with EMSA-PKCS1-v1_5 (RFC 8017 sec 9.2) and therefore nonsensical.
> 
>>From here on in, it is no longer allowed to allocate a transform without
> specifying a hash algorithm if the transform is used for sign/verify
> operations.  This simplifies the code because the insertion of the Full
> Hash Prefix is no longer optional, so various "if (digest_info)" clauses
> can be removed.
> 
> There has been a previous attempt to forbid transform allocation without
> specifying a hash algorithm, namely by commit c0d20d22e0ad ("crypto:
> rsa-pkcs1pad - Require hash to be present").  It had to be rolled back
> with commit b3a8c8a5ebb5 ("crypto: rsa-pkcs1pad: Allow hash to be
> optional [ver #2]"), presumably because it broke allocation of a
> transform which was solely used for encrypt/decrypt, not sign/verify.
> Avoid such breakage by allowing transform allocation for encrypt/decrypt
> with and without specifying a hash algorithm (and simply ignoring the
> hash algorithm in the former case).
> 
> So again, specifying a hash algorithm is now mandatory for sign/verify,
> but optional and ignored for encrypt/decrypt.
> 
> The new sig_alg API uses kernel buffers instead of sglists, which
> avoids the overhead of copying signature and digest from sglists back
> into kernel buffers.  rsassa-pkcs1.c is thus simplified quite a bit.
> 
> sig_alg is always synchronous, whereas the underlying "rsa" akcipher_alg
> may be asynchronous.  So await the result of the akcipher_alg, similar
> to crypto_akcipher_sync_{en,de}crypt().
> 
> As part of the migration, rename "rsa_digest_info" to "hash_prefix" to
> adhere to the spec language in RFC 9580.  Otherwise keep the code
> unmodified wherever possible to ease reviewing and bisecting.  Leave
> several simplification and hardening opportunities to separate commits.
> 
> rsassa-pkcs1.c uses modern __free() syntax for allocation of buffers
> which need to be freed by kfree_sensitive(), hence a DEFINE_FREE()
> clause for kfree_sensitive() is introduced herein as a byproduct.
> 
> Signed-off-by: Lukas Wunner <lukas@wunner.de>

This commit (1e562deacecca1f1bec7d23da526904a1e87525e in next-20241021) 
seems to break connecting to wpa2-enterprise with iwd.

I've only tested with one such network (eduroam, EAP-PEAP MSCHAPv2) and 
not yet with wpa_supplicant.

This appears in the kernel log repeatedly:

[  123.714646] wlan0: authenticate with b4:de:31:fa:2d:cc (local 
address=78:46:5c:01:28:85)
[  123.737991] wlan0: send auth to b4:de:31:fa:2d:cc (try 1/3)
[  123.763621] wlan0: authenticated
[  123.767600] wlan0: associate with b4:de:31:fa:2d:cc (try 1/3)
[  123.780873] wlan0: RX AssocResp from b4:de:31:fa:2d:cc (capab=0x1111 
status=0 aid=1)
[  123.809668] wlan0: associated
[  123.882344] wlan0: Limiting TX power to 30 (30 - 0) dBm as advertised 
by b4:de:31:fa:2d:cc
[  126.895233] wlan0: deauthenticating from b4:de:31:fa:2d:cc by local 
choice (Reason: 23=IEEE8021X_FAILED)

followed by this for a while:

[  127.214582] wlan0: authenticate with b4:de:31:fa:2d:cc (local 
address=78:46:5c:01:28:85)
[  127.237431] wlan0: send auth to b4:de:31:fa:2d:cc (try 1/3)
[  127.363430] wlan0: send auth to b4:de:31:fa:2d:cc (try 2/3)
[  127.467526] wlan0: send auth to b4:de:31:fa:2d:cc (try 3/3)
[  127.571506] wlan0: authentication with b4:de:31:fa:2d:cc timed out

Please let me know if there's anything else you need.

Regards,
Klara Modin
git bisect start
# status: waiting for both good and bad commits
# bad: [d49518711f816af793de9d4a1a0e13ad10b5ce91] i2c: spacemit: add support for SpacemiT K1 SoC
git bisect bad d49518711f816af793de9d4a1a0e13ad10b5ce91
# status: waiting for good commit(s), bad commit known
# good: [c55228220dd33e7627ad9736b6fce4df5e7eac98] Merge tag 'char-misc-6.12-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
git bisect good c55228220dd33e7627ad9736b6fce4df5e7eac98
# bad: [092d750e6edc08fdf25e858ac5aed09cfe4685be] Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
git bisect bad 092d750e6edc08fdf25e858ac5aed09cfe4685be
# good: [e0c1b92a36f6e500684f5e47d95eeb0719bad2ca] Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux.git
git bisect good e0c1b92a36f6e500684f5e47d95eeb0719bad2ca
# good: [a8a3d62d6fa4c374c9b1fc669ca1bc73f5370650] Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git
git bisect good a8a3d62d6fa4c374c9b1fc669ca1bc73f5370650
# good: [39ab20647d7b8516fcad91950d8491369ebd5ea3] Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
git bisect good 39ab20647d7b8516fcad91950d8491369ebd5ea3
# good: [2fe3f43cbfb72a5dd053663933542d190311210c] Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
git bisect good 2fe3f43cbfb72a5dd053663933542d190311210c
# good: [582173a1dcc0a38c210b20450a615d724026d18f] Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
git bisect good 582173a1dcc0a38c210b20450a615d724026d18f
# good: [07375e61c414d70a7332443e710e24f8dc5d6705] Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git
git bisect good 07375e61c414d70a7332443e710e24f8dc5d6705
# bad: [98091a826873bc5c114455f474121b67907e98ab] crypto: drivers - Correct multiple typos in comments
git bisect bad 98091a826873bc5c114455f474121b67907e98ab
# bad: [d6793ff974e07e4eea151d1f0805e92d042825a1] crypto: ecdsa - Move X9.62 signature decoding into template
git bisect bad d6793ff974e07e4eea151d1f0805e92d042825a1
# bad: [5e00481bf0a8b4dbd1588ae08f1ff82492011987] crypto: rsassa-pkcs1 - Harden digest length verification
git bisect bad 5e00481bf0a8b4dbd1588ae08f1ff82492011987
# good: [ef132350a3c2ae15349b7f748ce0859f0c2861be] crypto: ecdsa - Migrate to sig_alg backend
git bisect good ef132350a3c2ae15349b7f748ce0859f0c2861be
# good: [7964b0d4bd1271f82d6b455366a200d320f7dbf8] crypto: rsa-pkcs1pad - Deduplicate set_{pub,priv}_key callbacks
git bisect good 7964b0d4bd1271f82d6b455366a200d320f7dbf8
# bad: [1e562deacecca1f1bec7d23da526904a1e87525e] crypto: rsassa-pkcs1 - Migrate to sig_alg backend
git bisect bad 1e562deacecca1f1bec7d23da526904a1e87525e
# first bad commit: [1e562deacecca1f1bec7d23da526904a1e87525e] crypto: rsassa-pkcs1 - Migrate to sig_alg backend
Lukas Wunner Oct. 21, 2024, 7:02 p.m. UTC | #3
On Mon, Oct 21, 2024 at 06:08:03PM +0200, Klara Modin wrote:
> On 2024-09-10 16:30, Lukas Wunner wrote:
> > A sig_alg backend has just been introduced with the intent of moving all
> > asymmetric sign/verify algorithms to it one by one.
> > 
> > Migrate the sign/verify operations from rsa-pkcs1pad.c to a separate
> > rsassa-pkcs1.c which uses the new backend.
[...]
> This commit (1e562deacecca1f1bec7d23da526904a1e87525e in next-20241021)
> seems to break connecting to wpa2-enterprise with iwd.

Thanks for the report and sorry for the breakage.

There is one pending fix for an issue I inadvertently introduced
with my sig_alg rework:

https://lore.kernel.org/r/ff7a28cddfc28e7a3fb8292c680510f35ec54391.1728898147.git.lukas@wunner.de/

However it fixes a different commit than the one you found through
bisection, so I suspect it won't fix the problem, though it would
still be good if you could test it.

There is a *second* issue I discovered last week.  I cooked up
a fix this morning, but haven't written a commit message yet.
The patch is included below and it could indeed solve the
problem because it fixes an issue introduced by the commit you
identified as culprit.  So if you could test the patch below as well
I'd be grateful.

I'll now look at the config and dmesg output you've provided.
Just wanted to get this e-mail out the door quickly to point you
to potential fixes.

Thanks!

Lukas

-- >8 --

diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index c98c158..af19f9c 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -165,14 +165,22 @@ static int software_key_query(const struct kernel_pkey_params *params,
 {
 	struct crypto_akcipher *tfm;
 	struct public_key *pkey = params->key->payload.data[asym_crypto];
+	const char *hash_algo = params->hash_algo;
 	char alg_name[CRYPTO_MAX_ALG_NAME];
 	struct crypto_sig *sig;
 	u8 *key, *ptr;
 	int ret, len;
 	bool issig;
 
+	/*
+	 * Specifying hash_algo has historically been optional for pkcs1,
+	 * so use an arbitrary algorithm for backward compatibility.
+	 */
+	if (strcmp(params->encoding, "pkcs1") == 0 && !hash_algo)
+		hash_algo = "sha256";
+
 	ret = software_key_determine_akcipher(pkey, params->encoding,
-					      params->hash_algo, alg_name,
+					      hash_algo, alg_name,
 					      &issig, kernel_pkey_sign);
 	if (ret < 0)
 		return ret;
Klara Modin Oct. 22, 2024, 10:15 a.m. UTC | #4
On 2024-10-21 21:02, Lukas Wunner wrote:
> On Mon, Oct 21, 2024 at 06:08:03PM +0200, Klara Modin wrote:
>> On 2024-09-10 16:30, Lukas Wunner wrote:
>>> A sig_alg backend has just been introduced with the intent of moving all
>>> asymmetric sign/verify algorithms to it one by one.
>>>
>>> Migrate the sign/verify operations from rsa-pkcs1pad.c to a separate
>>> rsassa-pkcs1.c which uses the new backend.
> [...]
>> This commit (1e562deacecca1f1bec7d23da526904a1e87525e in next-20241021)
>> seems to break connecting to wpa2-enterprise with iwd.
> 
> Thanks for the report and sorry for the breakage.
> 
> There is one pending fix for an issue I inadvertently introduced
> with my sig_alg rework:
> 
> https://lore.kernel.org/r/ff7a28cddfc28e7a3fb8292c680510f35ec54391.1728898147.git.lukas@wunner.de/
> 
> However it fixes a different commit than the one you found through
> bisection, so I suspect it won't fix the problem, though it would
> still be good if you could test it.
> 
> There is a *second* issue I discovered last week.  I cooked up
> a fix this morning, but haven't written a commit message yet.
> The patch is included below and it could indeed solve the
> problem because it fixes an issue introduced by the commit you
> identified as culprit.  So if you could test the patch below as well
> I'd be grateful.
> 
> I'll now look at the config and dmesg output you've provided.
> Just wanted to get this e-mail out the door quickly to point you
> to potential fixes.
> 
> Thanks!
> 
> Lukas
> 
> -- >8 --
> 
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index c98c158..af19f9c 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -165,14 +165,22 @@ static int software_key_query(const struct kernel_pkey_params *params,
>   {
>   	struct crypto_akcipher *tfm;
>   	struct public_key *pkey = params->key->payload.data[asym_crypto];
> +	const char *hash_algo = params->hash_algo;
>   	char alg_name[CRYPTO_MAX_ALG_NAME];
>   	struct crypto_sig *sig;
>   	u8 *key, *ptr;
>   	int ret, len;
>   	bool issig;
>   
> +	/*
> +	 * Specifying hash_algo has historically been optional for pkcs1,
> +	 * so use an arbitrary algorithm for backward compatibility.
> +	 */
> +	if (strcmp(params->encoding, "pkcs1") == 0 && !hash_algo)
> +		hash_algo = "sha256";
> +
>   	ret = software_key_determine_akcipher(pkey, params->encoding,
> -					      params->hash_algo, alg_name,
> +					      hash_algo, alg_name,
>   					      &issig, kernel_pkey_sign);
>   	if (ret < 0)
>   		return ret;
> 

I don't think I have hit the first issue you mention but I'll apply the 
fix and see if it changes anything. I'll probably be able to test these 
two sometime tomorrow.

Thanks,
Klara Modin
Klara Modin Oct. 23, 2024, 10:19 a.m. UTC | #5
On 2024-10-21 21:02, Lukas Wunner wrote:
> On Mon, Oct 21, 2024 at 06:08:03PM +0200, Klara Modin wrote:
>> On 2024-09-10 16:30, Lukas Wunner wrote:
>>> A sig_alg backend has just been introduced with the intent of moving all
>>> asymmetric sign/verify algorithms to it one by one.
>>>
>>> Migrate the sign/verify operations from rsa-pkcs1pad.c to a separate
>>> rsassa-pkcs1.c which uses the new backend.
> [...]
>> This commit (1e562deacecca1f1bec7d23da526904a1e87525e in next-20241021)
>> seems to break connecting to wpa2-enterprise with iwd.
> 
> Thanks for the report and sorry for the breakage.
> 
> There is one pending fix for an issue I inadvertently introduced
> with my sig_alg rework:
> 
> https://lore.kernel.org/r/ff7a28cddfc28e7a3fb8292c680510f35ec54391.1728898147.git.lukas@wunner.de/
> 
> However it fixes a different commit than the one you found through
> bisection, so I suspect it won't fix the problem, though it would
> still be good if you could test it.
> 
> There is a *second* issue I discovered last week.  I cooked up
> a fix this morning, but haven't written a commit message yet.
> The patch is included below and it could indeed solve the
> problem because it fixes an issue introduced by the commit you
> identified as culprit.  So if you could test the patch below as well
> I'd be grateful.
> 
> I'll now look at the config and dmesg output you've provided.
> Just wanted to get this e-mail out the door quickly to point you
> to potential fixes.
> 
> Thanks!
> 
> Lukas
> 
> -- >8 --
> 
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index c98c158..af19f9c 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -165,14 +165,22 @@ static int software_key_query(const struct kernel_pkey_params *params,
>   {
>   	struct crypto_akcipher *tfm;
>   	struct public_key *pkey = params->key->payload.data[asym_crypto];
> +	const char *hash_algo = params->hash_algo;
>   	char alg_name[CRYPTO_MAX_ALG_NAME];
>   	struct crypto_sig *sig;
>   	u8 *key, *ptr;
>   	int ret, len;
>   	bool issig;
>   
> +	/*
> +	 * Specifying hash_algo has historically been optional for pkcs1,
> +	 * so use an arbitrary algorithm for backward compatibility.
> +	 */
> +	if (strcmp(params->encoding, "pkcs1") == 0 && !hash_algo)
> +		hash_algo = "sha256";
> +
>   	ret = software_key_determine_akcipher(pkey, params->encoding,
> -					      params->hash_algo, alg_name,
> +					      hash_algo, alg_name,
>   					      &issig, kernel_pkey_sign);
>   	if (ret < 0)
>   		return ret;
> 

Tested on top of yesterday's next-20241022.

With the first patch only there is no change, same behavior as previously.

With the second patch only I get an oops, similar as the one you 
mentioned in the first fix

With both patches everything seems to work as expected. Thanks!

(for both fixes)
Tested-by: Klara Modin <klarasmodin@gmail.com>
Lukas Wunner Oct. 25, 2024, 7:17 a.m. UTC | #6
On Wed, Oct 23, 2024 at 12:19:45PM +0200, Klara Modin wrote:
> On 2024-10-21 21:02, Lukas Wunner wrote:
> > On Mon, Oct 21, 2024 at 06:08:03PM +0200, Klara Modin wrote:
> > > This commit (1e562deacecca1f1bec7d23da526904a1e87525e in next-20241021)
> > > seems to break connecting to wpa2-enterprise with iwd.
[...]
> > There is a *second* issue I discovered last week.  I cooked up
> > a fix this morning, but haven't written a commit message yet.
> > The patch is included below and it could indeed solve the
> > problem because it fixes an issue introduced by the commit you
> > identified as culprit.
[...]
> Tested on top of yesterday's next-20241022.
> 
> With the first patch only there is no change, same behavior as previously.
> 
> With the second patch only I get an oops, similar as the one you mentioned
> in the first fix
> 
> With both patches everything seems to work as expected. Thanks!

Thanks a lot for your testing efforts, this helps greatly!

I've dug into the source code of iwd (Intel Wireless Daemon) and
the ell library it uses (Embedded Linux Library).

It turns out that the patch I sent you is sufficient when using
TLS 1.2 or newer for EAP (which I assume is true in your case).
But the patch is *not* sufficient for TLS 1.1 or earlier.

Normally RSA PKCS#1 encoding requires that the hash is prepended
by a Full Hash Prefix (an ASN.1 sequence which identifies the
hash algorithm used).  But it turns out there are legacy protocols
such as TLS 1.1 or earlier as well as IKEv1 which omit the
Full Hash Prefix.

The kernel supported this prior to 1e562deacecc.  Although TLS 1.1
was deprecated in 2021 by RFC 8996, I think we cannot just remove
support without advance notice.

So below is a new patch which reinstates support for these legacy
protocols.  It should also fix the issue you're seeing with TLS 1.2
or newer (which is caused by invoking KEYCTL_PKEY_QUERY without
specifying a hash algorithm).

The patch below replaces the one I sent on Monday.  You'll still
need the other pending fix:

https://lore.kernel.org/r/ff7a28cddfc28e7a3fb8292c680510f35ec54391.1728898147.git.lukas@wunner.de/

Would you mind testing this combination?  It did work in my own
testing, but if you could test it as well that would raise the
confidence.

I've looked at the source code of wpa_supplicant as well as
various IKEv1 daemons (strongswan, libreswan, isakmpd, raccoon)
and none of them seems to use the kernel's Key Retention Service,
so iwd is the only known user space application affected so far.

Thanks,

Lukas

-- >8 --

diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index c98c158..bbd07a9 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -93,7 +93,7 @@ static void public_key_destroy(void *payload0, void *payload3)
 					     pkey->pkey_algo);
 			} else {
 				if (!hash_algo)
-					return -EINVAL;
+					hash_algo = "none";
 				n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
 					     "pkcs1(%s,%s)",
 					     pkey->pkey_algo, hash_algo);
diff --git a/crypto/rsassa-pkcs1.c b/crypto/rsassa-pkcs1.c
index 9c28f1c..4d077fc9 100644
--- a/crypto/rsassa-pkcs1.c
+++ b/crypto/rsassa-pkcs1.c
@@ -27,6 +27,8 @@
  * https://www.rfc-editor.org/rfc/rfc9580#table-24
  */
 
+static const u8 hash_prefix_none[] = { };
+
 static const u8 hash_prefix_md5[] = {
 	0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,	  /* SEQUENCE (SEQUENCE (OID */
 	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05,	/*	<algorithm>, */
@@ -93,6 +95,7 @@
 	size_t		size;
 } hash_prefixes[] = {
 #define _(X) { #X, hash_prefix_##X, sizeof(hash_prefix_##X) }
+	_(none),
 	_(md5),
 	_(sha1),
 	_(rmd160),
@@ -119,9 +122,18 @@ static const struct hash_prefix *rsassa_pkcs1_find_hash_prefix(const char *name)
 	return NULL;
 }
 
-static unsigned int rsassa_pkcs1_hash_len(const struct hash_prefix *p)
+static bool rsassa_pkcs1_invalid_hash_len(unsigned int len,
+					  const struct hash_prefix *p)
 {
 	/*
+	 * Legacy protocols such as TLS 1.1 or earlier and IKE version 1
+	 * do not prepend a Full Hash Prefix to the hash.  In that case,
+	 * the size of the Full Hash Prefix is zero.
+	 */
+	if (p->data == hash_prefix_none)
+		return false;
+
+	/*
 	 * The final byte of the Full Hash Prefix encodes the hash length.
 	 *
 	 * This needs to be revisited should hash algorithms with more than
@@ -130,7 +142,7 @@ static unsigned int rsassa_pkcs1_hash_len(const struct hash_prefix *p)
 	 */
 	static_assert(HASH_MAX_DIGESTSIZE <= 127);
 
-	return p->data[p->size - 1];
+	return len != p->data[p->size - 1];
 }
 
 struct rsassa_pkcs1_ctx {
@@ -167,7 +179,7 @@ static int rsassa_pkcs1_sign(struct crypto_sig *tfm,
 	if (dlen < ctx->key_size)
 		return -EOVERFLOW;
 
-	if (slen != rsassa_pkcs1_hash_len(hash_prefix))
+	if (rsassa_pkcs1_invalid_hash_len(slen, hash_prefix))
 		return -EINVAL;
 
 	if (slen + hash_prefix->size > ctx->key_size - 11)
@@ -237,7 +249,7 @@ static int rsassa_pkcs1_verify(struct crypto_sig *tfm,
 	/* RFC 8017 sec 8.2.2 step 1 - length checking */
 	if (!ctx->key_size ||
 	    slen != ctx->key_size ||
-	    dlen != rsassa_pkcs1_hash_len(hash_prefix))
+	    rsassa_pkcs1_invalid_hash_len(dlen, hash_prefix))
 		return -EINVAL;
 
 	/* RFC 8017 sec 8.2.2 step 2 - RSA verification */
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 7d768f0..86126be 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -5540,6 +5540,12 @@ static int alg_test_null(const struct alg_test_desc *desc,
 			.cipher = __VECS(fcrypt_pcbc_tv_template)
 		}
 	}, {
+		.alg = "pkcs1(rsa,none)",
+		.test = alg_test_sig,
+		.suite = {
+			.sig = __VECS(pkcs1_rsa_none_tv_template)
+		}
+	}, {
 		.alg = "pkcs1(rsa,sha224)",
 		.test = alg_test_null,
 		.fips_allowed = 1,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 55aae18..d4c232a 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -1983,6 +1983,61 @@ struct kpp_testvec {
 };
 
 /*
+ * PKCS#1 RSA test vectors for hash algorithm "none"
+ * (i.e. the hash in "m" is not prepended by a Full Hash Prefix)
+ *
+ * Obtained from:
+ * https://vcsjones.dev/sometimes-valid-rsa-dotnet/
+ * https://gist.github.com/vcsjones/ab4c2327b53ed018eada76b75ef4fd99
+ */
+static const struct sig_testvec pkcs1_rsa_none_tv_template[] = {
+	{
+	.key =
+	"\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xa2\x63\x0b\x39\x44\xb8\xbb"
+	"\x23\xa7\x44\x49\xbb\x0e\xff\xa1\xf0\x61\x0a\x53\x93\xb0\x98\xdb"
+	"\xad\x2c\x0f\x4a\xc5\x6e\xff\x86\x3c\x53\x55\x0f\x15\xce\x04\x3f"
+	"\x2b\xfd\xa9\x96\x96\xd9\xbe\x61\x79\x0b\x5b\xc9\x4c\x86\x76\xe5"
+	"\xe0\x43\x4b\x22\x95\xee\xc2\x2b\x43\xc1\x9f\xd8\x68\xb4\x8e\x40"
+	"\x4f\xee\x85\x38\xb9\x11\xc5\x23\xf2\x64\x58\xf0\x15\x32\x6f\x4e"
+	"\x57\xa1\xae\x88\xa4\x02\xd7\x2a\x1e\xcd\x4b\xe1\xdd\x63\xd5\x17"
+	"\x89\x32\x5b\xb0\x5e\x99\x5a\xa8\x9d\x28\x50\x0e\x17\xee\x96\xdb"
+	"\x61\x3b\x45\x51\x1d\xcf\x12\x56\x0b\x92\x47\xfc\xab\xae\xf6\x66"
+	"\x3d\x47\xac\x70\x72\xe7\x92\xe7\x5f\xcd\x10\xb9\xc4\x83\x64\x94"
+	"\x19\xbd\x25\x80\xe1\xe8\xd2\x22\xa5\xd0\xba\x02\x7a\xa1\x77\x93"
+	"\x5b\x65\xc3\xee\x17\x74\xbc\x41\x86\x2a\xdc\x08\x4c\x8c\x92\x8c"
+	"\x91\x2d\x9e\x77\x44\x1f\x68\xd6\xa8\x74\x77\xdb\x0e\x5b\x32\x8b"
+	"\x56\x8b\x33\xbd\xd9\x63\xc8\x49\x9d\x3a\xc5\xc5\xea\x33\x0b\xd2"
+	"\xf1\xa3\x1b\xf4\x8b\xbe\xd9\xb3\x57\x8b\x3b\xde\x04\xa7\x7a\x22"
+	"\xb2\x24\xae\x2e\xc7\x70\xc5\xbe\x4e\x83\x26\x08\xfb\x0b\xbd\xa9"
+	"\x4f\x99\x08\xe1\x10\x28\x72\xaa\xcd\x02\x03\x01\x00\x01",
+	.key_len = 294,
+	.m =
+	"\x68\xb4\xf9\x26\x34\x31\x25\xdd\x26\x50\x13\x68\xc1\x99\x26\x71"
+	"\x19\xa2\xde\x81",
+	.m_size = 20,
+	.c =
+	"\x6a\xdb\x39\xe5\x63\xb3\x25\xde\x58\xca\xc3\xf1\x36\x9c\x0b\x36"
+	"\xb7\xd6\x69\xf9\xba\xa6\x68\x14\x8c\x24\x52\xd3\x25\xa5\xf3\xad"
+	"\xc9\x47\x44\xde\x06\xd8\x0f\x56\xca\x2d\xfb\x0f\xe9\x99\xe2\x9d"
+	"\x8a\xe8\x7f\xfb\x9a\x99\x96\xf1\x2c\x4a\xe4\xc0\xae\x4d\x29\x47"
+	"\x38\x96\x51\x2f\x6d\x8e\xb8\x88\xbd\x1a\x0a\x70\xbc\x23\x38\x67"
+	"\x62\x22\x01\x23\x71\xe5\xbb\x95\xea\x6b\x8d\x31\x62\xbf\xf0\xc4"
+	"\xb9\x46\xd6\x67\xfc\x4c\xe6\x1f\xd6\x5d\xf7\xa9\xad\x3a\xf1\xbf"
+	"\xa2\xf9\x66\xde\xb6\x8e\xec\x8f\x81\x8d\x1e\x3a\x12\x27\x6a\xfc"
+	"\xae\x92\x9f\xc3\x87\xc3\xba\x8d\x04\xb8\x8f\x0f\x61\x68\x9a\x96"
+	"\x2c\x80\x2c\x32\x40\xde\x9d\xb9\x9b\xe2\xe4\x45\x2e\x91\x47\x5c"
+	"\x47\xa4\x9d\x02\x57\x59\xf7\x75\x5d\x5f\x32\x82\x75\x5d\xe5\x78"
+	"\xc9\x19\x61\x46\x06\x9d\xa5\x1d\xd6\x32\x48\x9a\xdb\x09\x29\x81"
+	"\x14\x2e\xf0\x27\xe9\x37\x13\x74\xec\xa5\xcd\x67\x6b\x19\xf6\x88"
+	"\xf0\xc2\x8b\xa8\x7f\x2f\x76\x5a\x3e\x0c\x47\x5d\xe8\x82\x50\x27"
+	"\x40\xce\x27\x41\x45\xa0\xcf\xaa\x2f\xd3\xad\x3c\xbf\x73\xff\x93"
+	"\xe3\x78\x49\xd9\xa9\x78\x22\x81\x9a\xe5\xe2\x94\xe9\x40\xab\xf1",
+	.c_size = 256,
+	.public_key_vec = true,
+	},
+};
+
+/*
  * PKCS#1 RSA test vectors. Obtained from CAVS testing.
  */
 static const struct sig_testvec pkcs1_rsa_tv_template[] = {
Eric Biggers Oct. 25, 2024, 4:50 p.m. UTC | #7
On Fri, Oct 25, 2024 at 09:17:02AM +0200, Lukas Wunner wrote:
> So below is a new patch which reinstates support for these legacy
> protocols.  It should also fix the issue you're seeing with TLS 1.2
> or newer (which is caused by invoking KEYCTL_PKEY_QUERY without
> specifying a hash algorithm).
[...]
> I've looked at the source code of wpa_supplicant as well as
> various IKEv1 daemons (strongswan, libreswan, isakmpd, raccoon)
> and none of them seems to use the kernel's Key Retention Service,
> so iwd is the only known user space application affected so far.

Yes, based on historical mailing list discussions it appears that KEYCTL_PKEY_*
were added to the kernel for iwd, and iwd is their only user.  This design is a
huge mistake both on the part of iwd and the kernel community, for a variety of
reasons that have already been covered extensively in the discussions that occur
each time iwd breaks.  iwd should be using a real crypto library, like all the
other wireless daemons.

- Eric
Klara Modin Oct. 26, 2024, 9:40 a.m. UTC | #8
On 2024-10-25 09:17, Lukas Wunner wrote:
> On Wed, Oct 23, 2024 at 12:19:45PM +0200, Klara Modin wrote:
>> On 2024-10-21 21:02, Lukas Wunner wrote:
>>> On Mon, Oct 21, 2024 at 06:08:03PM +0200, Klara Modin wrote:
>>>> This commit (1e562deacecca1f1bec7d23da526904a1e87525e in next-20241021)
>>>> seems to break connecting to wpa2-enterprise with iwd.
> [...]
>>> There is a *second* issue I discovered last week.  I cooked up
>>> a fix this morning, but haven't written a commit message yet.
>>> The patch is included below and it could indeed solve the
>>> problem because it fixes an issue introduced by the commit you
>>> identified as culprit.
> [...]
>> Tested on top of yesterday's next-20241022.
>>
>> With the first patch only there is no change, same behavior as previously.
>>
>> With the second patch only I get an oops, similar as the one you mentioned
>> in the first fix
>>
>> With both patches everything seems to work as expected. Thanks!
> 
> Thanks a lot for your testing efforts, this helps greatly!
> 
> I've dug into the source code of iwd (Intel Wireless Daemon) and
> the ell library it uses (Embedded Linux Library).
> 
> It turns out that the patch I sent you is sufficient when using
> TLS 1.2 or newer for EAP (which I assume is true in your case).
> But the patch is *not* sufficient for TLS 1.1 or earlier.
> 
> Normally RSA PKCS#1 encoding requires that the hash is prepended
> by a Full Hash Prefix (an ASN.1 sequence which identifies the
> hash algorithm used).  But it turns out there are legacy protocols
> such as TLS 1.1 or earlier as well as IKEv1 which omit the
> Full Hash Prefix.
> 
> The kernel supported this prior to 1e562deacecc.  Although TLS 1.1
> was deprecated in 2021 by RFC 8996, I think we cannot just remove
> support without advance notice.
> 
> So below is a new patch which reinstates support for these legacy
> protocols.  It should also fix the issue you're seeing with TLS 1.2
> or newer (which is caused by invoking KEYCTL_PKEY_QUERY without
> specifying a hash algorithm).
> 
> The patch below replaces the one I sent on Monday.  You'll still
> need the other pending fix:
> 
> https://lore.kernel.org/r/ff7a28cddfc28e7a3fb8292c680510f35ec54391.1728898147.git.lukas@wunner.de/
> 
> Would you mind testing this combination?  It did work in my own
> testing, but if you could test it as well that would raise the
> confidence.
> 
> I've looked at the source code of wpa_supplicant as well as
> various IKEv1 daemons (strongswan, libreswan, isakmpd, raccoon)
> and none of them seems to use the kernel's Key Retention Service,
> so iwd is the only known user space application affected so far.
> 
> Thanks,
> 
> Lukas
> 

Thanks for the explanation. I'll probably be able to test this on Monday.

(by the way, I don't seem to be receiving your emails. It could perhaps 
be something on the gmail side. I'll add klara@kasm.eu to the CC which 
is on my own server, maybe that'll work better)

Regards,
Klara Modin

> -- >8 --
> 
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index c98c158..bbd07a9 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -93,7 +93,7 @@ static void public_key_destroy(void *payload0, void *payload3)
>   					     pkey->pkey_algo);
>   			} else {
>   				if (!hash_algo)
> -					return -EINVAL;
> +					hash_algo = "none";
>   				n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
>   					     "pkcs1(%s,%s)",
>   					     pkey->pkey_algo, hash_algo);
> diff --git a/crypto/rsassa-pkcs1.c b/crypto/rsassa-pkcs1.c
> index 9c28f1c..4d077fc9 100644
> --- a/crypto/rsassa-pkcs1.c
> +++ b/crypto/rsassa-pkcs1.c
> @@ -27,6 +27,8 @@
>    * https://www.rfc-editor.org/rfc/rfc9580#table-24
>    */
>   
> +static const u8 hash_prefix_none[] = { };
> +
>   static const u8 hash_prefix_md5[] = {
>   	0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,	  /* SEQUENCE (SEQUENCE (OID */
>   	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05,	/*	<algorithm>, */
> @@ -93,6 +95,7 @@
>   	size_t		size;
>   } hash_prefixes[] = {
>   #define _(X) { #X, hash_prefix_##X, sizeof(hash_prefix_##X) }
> +	_(none),
>   	_(md5),
>   	_(sha1),
>   	_(rmd160),
> @@ -119,9 +122,18 @@ static const struct hash_prefix *rsassa_pkcs1_find_hash_prefix(const char *name)
>   	return NULL;
>   }
>   
> -static unsigned int rsassa_pkcs1_hash_len(const struct hash_prefix *p)
> +static bool rsassa_pkcs1_invalid_hash_len(unsigned int len,
> +					  const struct hash_prefix *p)
>   {
>   	/*
> +	 * Legacy protocols such as TLS 1.1 or earlier and IKE version 1
> +	 * do not prepend a Full Hash Prefix to the hash.  In that case,
> +	 * the size of the Full Hash Prefix is zero.
> +	 */
> +	if (p->data == hash_prefix_none)
> +		return false;
> +
> +	/*
>   	 * The final byte of the Full Hash Prefix encodes the hash length.
>   	 *
>   	 * This needs to be revisited should hash algorithms with more than
> @@ -130,7 +142,7 @@ static unsigned int rsassa_pkcs1_hash_len(const struct hash_prefix *p)
>   	 */
>   	static_assert(HASH_MAX_DIGESTSIZE <= 127);
>   
> -	return p->data[p->size - 1];
> +	return len != p->data[p->size - 1];
>   }
>   
>   struct rsassa_pkcs1_ctx {
> @@ -167,7 +179,7 @@ static int rsassa_pkcs1_sign(struct crypto_sig *tfm,
>   	if (dlen < ctx->key_size)
>   		return -EOVERFLOW;
>   
> -	if (slen != rsassa_pkcs1_hash_len(hash_prefix))
> +	if (rsassa_pkcs1_invalid_hash_len(slen, hash_prefix))
>   		return -EINVAL;
>   
>   	if (slen + hash_prefix->size > ctx->key_size - 11)
> @@ -237,7 +249,7 @@ static int rsassa_pkcs1_verify(struct crypto_sig *tfm,
>   	/* RFC 8017 sec 8.2.2 step 1 - length checking */
>   	if (!ctx->key_size ||
>   	    slen != ctx->key_size ||
> -	    dlen != rsassa_pkcs1_hash_len(hash_prefix))
> +	    rsassa_pkcs1_invalid_hash_len(dlen, hash_prefix))
>   		return -EINVAL;
>   
>   	/* RFC 8017 sec 8.2.2 step 2 - RSA verification */
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index 7d768f0..86126be 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -5540,6 +5540,12 @@ static int alg_test_null(const struct alg_test_desc *desc,
>   			.cipher = __VECS(fcrypt_pcbc_tv_template)
>   		}
>   	}, {
> +		.alg = "pkcs1(rsa,none)",
> +		.test = alg_test_sig,
> +		.suite = {
> +			.sig = __VECS(pkcs1_rsa_none_tv_template)
> +		}
> +	}, {
>   		.alg = "pkcs1(rsa,sha224)",
>   		.test = alg_test_null,
>   		.fips_allowed = 1,
> diff --git a/crypto/testmgr.h b/crypto/testmgr.h
> index 55aae18..d4c232a 100644
> --- a/crypto/testmgr.h
> +++ b/crypto/testmgr.h
> @@ -1983,6 +1983,61 @@ struct kpp_testvec {
>   };
>   
>   /*
> + * PKCS#1 RSA test vectors for hash algorithm "none"
> + * (i.e. the hash in "m" is not prepended by a Full Hash Prefix)
> + *
> + * Obtained from:
> + * https://vcsjones.dev/sometimes-valid-rsa-dotnet/
> + * https://gist.github.com/vcsjones/ab4c2327b53ed018eada76b75ef4fd99
> + */
> +static const struct sig_testvec pkcs1_rsa_none_tv_template[] = {
> +	{
> +	.key =
> +	"\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xa2\x63\x0b\x39\x44\xb8\xbb"
> +	"\x23\xa7\x44\x49\xbb\x0e\xff\xa1\xf0\x61\x0a\x53\x93\xb0\x98\xdb"
> +	"\xad\x2c\x0f\x4a\xc5\x6e\xff\x86\x3c\x53\x55\x0f\x15\xce\x04\x3f"
> +	"\x2b\xfd\xa9\x96\x96\xd9\xbe\x61\x79\x0b\x5b\xc9\x4c\x86\x76\xe5"
> +	"\xe0\x43\x4b\x22\x95\xee\xc2\x2b\x43\xc1\x9f\xd8\x68\xb4\x8e\x40"
> +	"\x4f\xee\x85\x38\xb9\x11\xc5\x23\xf2\x64\x58\xf0\x15\x32\x6f\x4e"
> +	"\x57\xa1\xae\x88\xa4\x02\xd7\x2a\x1e\xcd\x4b\xe1\xdd\x63\xd5\x17"
> +	"\x89\x32\x5b\xb0\x5e\x99\x5a\xa8\x9d\x28\x50\x0e\x17\xee\x96\xdb"
> +	"\x61\x3b\x45\x51\x1d\xcf\x12\x56\x0b\x92\x47\xfc\xab\xae\xf6\x66"
> +	"\x3d\x47\xac\x70\x72\xe7\x92\xe7\x5f\xcd\x10\xb9\xc4\x83\x64\x94"
> +	"\x19\xbd\x25\x80\xe1\xe8\xd2\x22\xa5\xd0\xba\x02\x7a\xa1\x77\x93"
> +	"\x5b\x65\xc3\xee\x17\x74\xbc\x41\x86\x2a\xdc\x08\x4c\x8c\x92\x8c"
> +	"\x91\x2d\x9e\x77\x44\x1f\x68\xd6\xa8\x74\x77\xdb\x0e\x5b\x32\x8b"
> +	"\x56\x8b\x33\xbd\xd9\x63\xc8\x49\x9d\x3a\xc5\xc5\xea\x33\x0b\xd2"
> +	"\xf1\xa3\x1b\xf4\x8b\xbe\xd9\xb3\x57\x8b\x3b\xde\x04\xa7\x7a\x22"
> +	"\xb2\x24\xae\x2e\xc7\x70\xc5\xbe\x4e\x83\x26\x08\xfb\x0b\xbd\xa9"
> +	"\x4f\x99\x08\xe1\x10\x28\x72\xaa\xcd\x02\x03\x01\x00\x01",
> +	.key_len = 294,
> +	.m =
> +	"\x68\xb4\xf9\x26\x34\x31\x25\xdd\x26\x50\x13\x68\xc1\x99\x26\x71"
> +	"\x19\xa2\xde\x81",
> +	.m_size = 20,
> +	.c =
> +	"\x6a\xdb\x39\xe5\x63\xb3\x25\xde\x58\xca\xc3\xf1\x36\x9c\x0b\x36"
> +	"\xb7\xd6\x69\xf9\xba\xa6\x68\x14\x8c\x24\x52\xd3\x25\xa5\xf3\xad"
> +	"\xc9\x47\x44\xde\x06\xd8\x0f\x56\xca\x2d\xfb\x0f\xe9\x99\xe2\x9d"
> +	"\x8a\xe8\x7f\xfb\x9a\x99\x96\xf1\x2c\x4a\xe4\xc0\xae\x4d\x29\x47"
> +	"\x38\x96\x51\x2f\x6d\x8e\xb8\x88\xbd\x1a\x0a\x70\xbc\x23\x38\x67"
> +	"\x62\x22\x01\x23\x71\xe5\xbb\x95\xea\x6b\x8d\x31\x62\xbf\xf0\xc4"
> +	"\xb9\x46\xd6\x67\xfc\x4c\xe6\x1f\xd6\x5d\xf7\xa9\xad\x3a\xf1\xbf"
> +	"\xa2\xf9\x66\xde\xb6\x8e\xec\x8f\x81\x8d\x1e\x3a\x12\x27\x6a\xfc"
> +	"\xae\x92\x9f\xc3\x87\xc3\xba\x8d\x04\xb8\x8f\x0f\x61\x68\x9a\x96"
> +	"\x2c\x80\x2c\x32\x40\xde\x9d\xb9\x9b\xe2\xe4\x45\x2e\x91\x47\x5c"
> +	"\x47\xa4\x9d\x02\x57\x59\xf7\x75\x5d\x5f\x32\x82\x75\x5d\xe5\x78"
> +	"\xc9\x19\x61\x46\x06\x9d\xa5\x1d\xd6\x32\x48\x9a\xdb\x09\x29\x81"
> +	"\x14\x2e\xf0\x27\xe9\x37\x13\x74\xec\xa5\xcd\x67\x6b\x19\xf6\x88"
> +	"\xf0\xc2\x8b\xa8\x7f\x2f\x76\x5a\x3e\x0c\x47\x5d\xe8\x82\x50\x27"
> +	"\x40\xce\x27\x41\x45\xa0\xcf\xaa\x2f\xd3\xad\x3c\xbf\x73\xff\x93"
> +	"\xe3\x78\x49\xd9\xa9\x78\x22\x81\x9a\xe5\xe2\x94\xe9\x40\xab\xf1",
> +	.c_size = 256,
> +	.public_key_vec = true,
> +	},
> +};
> +
> +/*
>    * PKCS#1 RSA test vectors. Obtained from CAVS testing.
>    */
>   static const struct sig_testvec pkcs1_rsa_tv_template[] = {
>
Klara Modin Oct. 28, 2024, 11:45 a.m. UTC | #9
On 2024-10-25 09:17, Lukas Wunner wrote:
> On Wed, Oct 23, 2024 at 12:19:45PM +0200, Klara Modin wrote:
>> On 2024-10-21 21:02, Lukas Wunner wrote:
>>> On Mon, Oct 21, 2024 at 06:08:03PM +0200, Klara Modin wrote:
>>>> This commit (1e562deacecca1f1bec7d23da526904a1e87525e in next-20241021)
>>>> seems to break connecting to wpa2-enterprise with iwd.
> [...]
>>> There is a *second* issue I discovered last week.  I cooked up
>>> a fix this morning, but haven't written a commit message yet.
>>> The patch is included below and it could indeed solve the
>>> problem because it fixes an issue introduced by the commit you
>>> identified as culprit.
> [...]
>> Tested on top of yesterday's next-20241022.
>>
>> With the first patch only there is no change, same behavior as previously.
>>
>> With the second patch only I get an oops, similar as the one you mentioned
>> in the first fix
>>
>> With both patches everything seems to work as expected. Thanks!
> 
> Thanks a lot for your testing efforts, this helps greatly!
> 
> I've dug into the source code of iwd (Intel Wireless Daemon) and
> the ell library it uses (Embedded Linux Library).
> 
> It turns out that the patch I sent you is sufficient when using
> TLS 1.2 or newer for EAP (which I assume is true in your case).
> But the patch is *not* sufficient for TLS 1.1 or earlier.
> 
> Normally RSA PKCS#1 encoding requires that the hash is prepended
> by a Full Hash Prefix (an ASN.1 sequence which identifies the
> hash algorithm used).  But it turns out there are legacy protocols
> such as TLS 1.1 or earlier as well as IKEv1 which omit the
> Full Hash Prefix.
> 
> The kernel supported this prior to 1e562deacecc.  Although TLS 1.1
> was deprecated in 2021 by RFC 8996, I think we cannot just remove
> support without advance notice.
> 
> So below is a new patch which reinstates support for these legacy
> protocols.  It should also fix the issue you're seeing with TLS 1.2
> or newer (which is caused by invoking KEYCTL_PKEY_QUERY without
> specifying a hash algorithm).
> 
> The patch below replaces the one I sent on Monday.  You'll still
> need the other pending fix:
> 
> https://lore.kernel.org/r/ff7a28cddfc28e7a3fb8292c680510f35ec54391.1728898147.git.lukas@wunner.de/
> 
> Would you mind testing this combination?  It did work in my own
> testing, but if you could test it as well that would raise the
> confidence.
> 
> I've looked at the source code of wpa_supplicant as well as
> various IKEv1 daemons (strongswan, libreswan, isakmpd, raccoon)
> and none of them seems to use the kernel's Key Retention Service,
> so iwd is the only known user space application affected so far.
> 
> Thanks,
> 
> Lukas

This patch also fixes the issue for me (on top of next-20241028).

Thanks,
Tested-by: Klara Modin <klarasmodin@gmail.com>

> 
> -- >8 --
> 
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index c98c158..bbd07a9 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -93,7 +93,7 @@ static void public_key_destroy(void *payload0, void *payload3)
>   					     pkey->pkey_algo);
>   			} else {
>   				if (!hash_algo)
> -					return -EINVAL;
> +					hash_algo = "none";
>   				n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
>   					     "pkcs1(%s,%s)",
>   					     pkey->pkey_algo, hash_algo);
> diff --git a/crypto/rsassa-pkcs1.c b/crypto/rsassa-pkcs1.c
> index 9c28f1c..4d077fc9 100644
> --- a/crypto/rsassa-pkcs1.c
> +++ b/crypto/rsassa-pkcs1.c
> @@ -27,6 +27,8 @@
>    * https://www.rfc-editor.org/rfc/rfc9580#table-24
>    */
>   
> +static const u8 hash_prefix_none[] = { };
> +
>   static const u8 hash_prefix_md5[] = {
>   	0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,	  /* SEQUENCE (SEQUENCE (OID */
>   	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05,	/*	<algorithm>, */
> @@ -93,6 +95,7 @@
>   	size_t		size;
>   } hash_prefixes[] = {
>   #define _(X) { #X, hash_prefix_##X, sizeof(hash_prefix_##X) }
> +	_(none),
>   	_(md5),
>   	_(sha1),
>   	_(rmd160),
> @@ -119,9 +122,18 @@ static const struct hash_prefix *rsassa_pkcs1_find_hash_prefix(const char *name)
>   	return NULL;
>   }
>   
> -static unsigned int rsassa_pkcs1_hash_len(const struct hash_prefix *p)
> +static bool rsassa_pkcs1_invalid_hash_len(unsigned int len,
> +					  const struct hash_prefix *p)
>   {
>   	/*
> +	 * Legacy protocols such as TLS 1.1 or earlier and IKE version 1
> +	 * do not prepend a Full Hash Prefix to the hash.  In that case,
> +	 * the size of the Full Hash Prefix is zero.
> +	 */
> +	if (p->data == hash_prefix_none)
> +		return false;
> +
> +	/*
>   	 * The final byte of the Full Hash Prefix encodes the hash length.
>   	 *
>   	 * This needs to be revisited should hash algorithms with more than
> @@ -130,7 +142,7 @@ static unsigned int rsassa_pkcs1_hash_len(const struct hash_prefix *p)
>   	 */
>   	static_assert(HASH_MAX_DIGESTSIZE <= 127);
>   
> -	return p->data[p->size - 1];
> +	return len != p->data[p->size - 1];
>   }
>   
>   struct rsassa_pkcs1_ctx {
> @@ -167,7 +179,7 @@ static int rsassa_pkcs1_sign(struct crypto_sig *tfm,
>   	if (dlen < ctx->key_size)
>   		return -EOVERFLOW;
>   
> -	if (slen != rsassa_pkcs1_hash_len(hash_prefix))
> +	if (rsassa_pkcs1_invalid_hash_len(slen, hash_prefix))
>   		return -EINVAL;
>   
>   	if (slen + hash_prefix->size > ctx->key_size - 11)
> @@ -237,7 +249,7 @@ static int rsassa_pkcs1_verify(struct crypto_sig *tfm,
>   	/* RFC 8017 sec 8.2.2 step 1 - length checking */
>   	if (!ctx->key_size ||
>   	    slen != ctx->key_size ||
> -	    dlen != rsassa_pkcs1_hash_len(hash_prefix))
> +	    rsassa_pkcs1_invalid_hash_len(dlen, hash_prefix))
>   		return -EINVAL;
>   
>   	/* RFC 8017 sec 8.2.2 step 2 - RSA verification */
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index 7d768f0..86126be 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -5540,6 +5540,12 @@ static int alg_test_null(const struct alg_test_desc *desc,
>   			.cipher = __VECS(fcrypt_pcbc_tv_template)
>   		}
>   	}, {
> +		.alg = "pkcs1(rsa,none)",
> +		.test = alg_test_sig,
> +		.suite = {
> +			.sig = __VECS(pkcs1_rsa_none_tv_template)
> +		}
> +	}, {
>   		.alg = "pkcs1(rsa,sha224)",
>   		.test = alg_test_null,
>   		.fips_allowed = 1,
> diff --git a/crypto/testmgr.h b/crypto/testmgr.h
> index 55aae18..d4c232a 100644
> --- a/crypto/testmgr.h
> +++ b/crypto/testmgr.h
> @@ -1983,6 +1983,61 @@ struct kpp_testvec {
>   };
>   
>   /*
> + * PKCS#1 RSA test vectors for hash algorithm "none"
> + * (i.e. the hash in "m" is not prepended by a Full Hash Prefix)
> + *
> + * Obtained from:
> + * https://vcsjones.dev/sometimes-valid-rsa-dotnet/
> + * https://gist.github.com/vcsjones/ab4c2327b53ed018eada76b75ef4fd99
> + */
> +static const struct sig_testvec pkcs1_rsa_none_tv_template[] = {
> +	{
> +	.key =
> +	"\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xa2\x63\x0b\x39\x44\xb8\xbb"
> +	"\x23\xa7\x44\x49\xbb\x0e\xff\xa1\xf0\x61\x0a\x53\x93\xb0\x98\xdb"
> +	"\xad\x2c\x0f\x4a\xc5\x6e\xff\x86\x3c\x53\x55\x0f\x15\xce\x04\x3f"
> +	"\x2b\xfd\xa9\x96\x96\xd9\xbe\x61\x79\x0b\x5b\xc9\x4c\x86\x76\xe5"
> +	"\xe0\x43\x4b\x22\x95\xee\xc2\x2b\x43\xc1\x9f\xd8\x68\xb4\x8e\x40"
> +	"\x4f\xee\x85\x38\xb9\x11\xc5\x23\xf2\x64\x58\xf0\x15\x32\x6f\x4e"
> +	"\x57\xa1\xae\x88\xa4\x02\xd7\x2a\x1e\xcd\x4b\xe1\xdd\x63\xd5\x17"
> +	"\x89\x32\x5b\xb0\x5e\x99\x5a\xa8\x9d\x28\x50\x0e\x17\xee\x96\xdb"
> +	"\x61\x3b\x45\x51\x1d\xcf\x12\x56\x0b\x92\x47\xfc\xab\xae\xf6\x66"
> +	"\x3d\x47\xac\x70\x72\xe7\x92\xe7\x5f\xcd\x10\xb9\xc4\x83\x64\x94"
> +	"\x19\xbd\x25\x80\xe1\xe8\xd2\x22\xa5\xd0\xba\x02\x7a\xa1\x77\x93"
> +	"\x5b\x65\xc3\xee\x17\x74\xbc\x41\x86\x2a\xdc\x08\x4c\x8c\x92\x8c"
> +	"\x91\x2d\x9e\x77\x44\x1f\x68\xd6\xa8\x74\x77\xdb\x0e\x5b\x32\x8b"
> +	"\x56\x8b\x33\xbd\xd9\x63\xc8\x49\x9d\x3a\xc5\xc5\xea\x33\x0b\xd2"
> +	"\xf1\xa3\x1b\xf4\x8b\xbe\xd9\xb3\x57\x8b\x3b\xde\x04\xa7\x7a\x22"
> +	"\xb2\x24\xae\x2e\xc7\x70\xc5\xbe\x4e\x83\x26\x08\xfb\x0b\xbd\xa9"
> +	"\x4f\x99\x08\xe1\x10\x28\x72\xaa\xcd\x02\x03\x01\x00\x01",
> +	.key_len = 294,
> +	.m =
> +	"\x68\xb4\xf9\x26\x34\x31\x25\xdd\x26\x50\x13\x68\xc1\x99\x26\x71"
> +	"\x19\xa2\xde\x81",
> +	.m_size = 20,
> +	.c =
> +	"\x6a\xdb\x39\xe5\x63\xb3\x25\xde\x58\xca\xc3\xf1\x36\x9c\x0b\x36"
> +	"\xb7\xd6\x69\xf9\xba\xa6\x68\x14\x8c\x24\x52\xd3\x25\xa5\xf3\xad"
> +	"\xc9\x47\x44\xde\x06\xd8\x0f\x56\xca\x2d\xfb\x0f\xe9\x99\xe2\x9d"
> +	"\x8a\xe8\x7f\xfb\x9a\x99\x96\xf1\x2c\x4a\xe4\xc0\xae\x4d\x29\x47"
> +	"\x38\x96\x51\x2f\x6d\x8e\xb8\x88\xbd\x1a\x0a\x70\xbc\x23\x38\x67"
> +	"\x62\x22\x01\x23\x71\xe5\xbb\x95\xea\x6b\x8d\x31\x62\xbf\xf0\xc4"
> +	"\xb9\x46\xd6\x67\xfc\x4c\xe6\x1f\xd6\x5d\xf7\xa9\xad\x3a\xf1\xbf"
> +	"\xa2\xf9\x66\xde\xb6\x8e\xec\x8f\x81\x8d\x1e\x3a\x12\x27\x6a\xfc"
> +	"\xae\x92\x9f\xc3\x87\xc3\xba\x8d\x04\xb8\x8f\x0f\x61\x68\x9a\x96"
> +	"\x2c\x80\x2c\x32\x40\xde\x9d\xb9\x9b\xe2\xe4\x45\x2e\x91\x47\x5c"
> +	"\x47\xa4\x9d\x02\x57\x59\xf7\x75\x5d\x5f\x32\x82\x75\x5d\xe5\x78"
> +	"\xc9\x19\x61\x46\x06\x9d\xa5\x1d\xd6\x32\x48\x9a\xdb\x09\x29\x81"
> +	"\x14\x2e\xf0\x27\xe9\x37\x13\x74\xec\xa5\xcd\x67\x6b\x19\xf6\x88"
> +	"\xf0\xc2\x8b\xa8\x7f\x2f\x76\x5a\x3e\x0c\x47\x5d\xe8\x82\x50\x27"
> +	"\x40\xce\x27\x41\x45\xa0\xcf\xaa\x2f\xd3\xad\x3c\xbf\x73\xff\x93"
> +	"\xe3\x78\x49\xd9\xa9\x78\x22\x81\x9a\xe5\xe2\x94\xe9\x40\xab\xf1",
> +	.c_size = 256,
> +	.public_key_vec = true,
> +	},
> +};
> +
> +/*
>    * PKCS#1 RSA test vectors. Obtained from CAVS testing.
>    */
>   static const struct sig_testvec pkcs1_rsa_tv_template[] = {
>
diff mbox series

Patch

diff --git a/crypto/Kconfig b/crypto/Kconfig
index e8488b8c45e3..94ef57c9e936 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -250,6 +250,7 @@  config CRYPTO_RSA
 	tristate "RSA (Rivest-Shamir-Adleman)"
 	select CRYPTO_AKCIPHER
 	select CRYPTO_MANAGER
+	select CRYPTO_SIG
 	select MPILIB
 	select ASN1
 	help
diff --git a/crypto/Makefile b/crypto/Makefile
index 4c99e5d376f6..7de29bf843e9 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -48,6 +48,7 @@  rsa_generic-y += rsaprivkey.asn1.o
 rsa_generic-y += rsa.o
 rsa_generic-y += rsa_helper.o
 rsa_generic-y += rsa-pkcs1pad.o
+rsa_generic-y += rsassa-pkcs1.o
 obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o
 
 $(obj)/ecdsasignature.asn1.o: $(obj)/ecdsasignature.asn1.c $(obj)/ecdsasignature.asn1.h
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 422940a6706a..3fb27ecd65f6 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -83,13 +83,19 @@  software_key_determine_akcipher(const struct public_key *pkey,
 		if (strcmp(encoding, "pkcs1") == 0) {
 			*sig = op == kernel_pkey_sign ||
 			       op == kernel_pkey_verify;
-			if (!hash_algo) {
+			if (!*sig) {
+				/*
+				 * For encrypt/decrypt, hash_algo is not used
+				 * but allowed to be set for historic reasons.
+				 */
 				n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
 					     "pkcs1pad(%s)",
 					     pkey->pkey_algo);
 			} else {
+				if (!hash_algo)
+					return -EINVAL;
 				n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
-					     "pkcs1pad(%s,%s)",
+					     "pkcs1(%s,%s)",
 					     pkey->pkey_algo, hash_algo);
 			}
 			return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
index 3c5fe8c93938..50bdb18e7b48 100644
--- a/crypto/rsa-pkcs1pad.c
+++ b/crypto/rsa-pkcs1pad.c
@@ -16,101 +16,6 @@ 
 #include <linux/random.h>
 #include <linux/scatterlist.h>
 
-/*
- * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
- */
-static const u8 rsa_digest_info_md5[] = {
-	0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,
-	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* OID */
-	0x05, 0x00, 0x04, 0x10
-};
-
-static const u8 rsa_digest_info_sha1[] = {
-	0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
-	0x2b, 0x0e, 0x03, 0x02, 0x1a,
-	0x05, 0x00, 0x04, 0x14
-};
-
-static const u8 rsa_digest_info_rmd160[] = {
-	0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
-	0x2b, 0x24, 0x03, 0x02, 0x01,
-	0x05, 0x00, 0x04, 0x14
-};
-
-static const u8 rsa_digest_info_sha224[] = {
-	0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
-	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
-	0x05, 0x00, 0x04, 0x1c
-};
-
-static const u8 rsa_digest_info_sha256[] = {
-	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
-	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
-	0x05, 0x00, 0x04, 0x20
-};
-
-static const u8 rsa_digest_info_sha384[] = {
-	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
-	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
-	0x05, 0x00, 0x04, 0x30
-};
-
-static const u8 rsa_digest_info_sha512[] = {
-	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
-	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
-	0x05, 0x00, 0x04, 0x40
-};
-
-static const u8 rsa_digest_info_sha3_256[] = {
-	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
-	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08,
-	0x05, 0x00, 0x04, 0x20
-};
-
-static const u8 rsa_digest_info_sha3_384[] = {
-	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
-	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09,
-	0x05, 0x00, 0x04, 0x30
-};
-
-static const u8 rsa_digest_info_sha3_512[] = {
-	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
-	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A,
-	0x05, 0x00, 0x04, 0x40
-};
-
-static const struct rsa_asn1_template {
-	const char	*name;
-	const u8	*data;
-	size_t		size;
-} rsa_asn1_templates[] = {
-#define _(X) { #X, rsa_digest_info_##X, sizeof(rsa_digest_info_##X) }
-	_(md5),
-	_(sha1),
-	_(rmd160),
-	_(sha256),
-	_(sha384),
-	_(sha512),
-	_(sha224),
-#undef _
-#define _(X) { "sha3-" #X, rsa_digest_info_sha3_##X, sizeof(rsa_digest_info_sha3_##X) }
-	_(256),
-	_(384),
-	_(512),
-#undef _
-	{ NULL }
-};
-
-static const struct rsa_asn1_template *rsa_lookup_asn1(const char *name)
-{
-	const struct rsa_asn1_template *p;
-
-	for (p = rsa_asn1_templates; p->name; p++)
-		if (strcmp(name, p->name) == 0)
-			return p;
-	return NULL;
-}
-
 struct pkcs1pad_ctx {
 	struct crypto_akcipher *child;
 	unsigned int key_size;
@@ -118,7 +23,6 @@  struct pkcs1pad_ctx {
 
 struct pkcs1pad_inst_ctx {
 	struct crypto_akcipher_spawn spawn;
-	const struct rsa_asn1_template *digest_info;
 };
 
 struct pkcs1pad_request {
@@ -148,9 +52,9 @@  static unsigned int pkcs1pad_get_max_size(struct crypto_akcipher *tfm)
 	struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
 
 	/*
-	 * The maximum destination buffer size for the encrypt/sign operations
+	 * The maximum destination buffer size for the encrypt operation
 	 * will be the same as for RSA, even though it's smaller for
-	 * decrypt/verify.
+	 * decrypt.
 	 */
 
 	return ctx->key_size;
@@ -168,7 +72,7 @@  static void pkcs1pad_sg_set_buf(struct scatterlist *sg, void *buf, size_t len,
 		sg_chain(sg, nsegs, next);
 }
 
-static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err)
+static int pkcs1pad_encrypt_complete(struct akcipher_request *req, int err)
 {
 	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
 	struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
@@ -207,14 +111,14 @@  static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err)
 	return err;
 }
 
-static void pkcs1pad_encrypt_sign_complete_cb(void *data, int err)
+static void pkcs1pad_encrypt_complete_cb(void *data, int err)
 {
 	struct akcipher_request *req = data;
 
 	if (err == -EINPROGRESS)
 		goto out;
 
-	err = pkcs1pad_encrypt_sign_complete(req, err);
+	err = pkcs1pad_encrypt_complete(req, err);
 
 out:
 	akcipher_request_complete(req, err);
@@ -255,7 +159,7 @@  static int pkcs1pad_encrypt(struct akcipher_request *req)
 
 	akcipher_request_set_tfm(&req_ctx->child_req, ctx->child);
 	akcipher_request_set_callback(&req_ctx->child_req, req->base.flags,
-			pkcs1pad_encrypt_sign_complete_cb, req);
+			pkcs1pad_encrypt_complete_cb, req);
 
 	/* Reuse output buffer */
 	akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg,
@@ -263,7 +167,7 @@  static int pkcs1pad_encrypt(struct akcipher_request *req)
 
 	err = crypto_akcipher_encrypt(&req_ctx->child_req);
 	if (err != -EINPROGRESS && err != -EBUSY)
-		return pkcs1pad_encrypt_sign_complete(req, err);
+		return pkcs1pad_encrypt_complete(req, err);
 
 	return err;
 }
@@ -368,195 +272,6 @@  static int pkcs1pad_decrypt(struct akcipher_request *req)
 	return err;
 }
 
-static int pkcs1pad_sign(struct akcipher_request *req)
-{
-	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
-	struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
-	struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
-	struct akcipher_instance *inst = akcipher_alg_instance(tfm);
-	struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst);
-	const struct rsa_asn1_template *digest_info = ictx->digest_info;
-	int err;
-	unsigned int ps_end, digest_info_size = 0;
-
-	if (!ctx->key_size)
-		return -EINVAL;
-
-	if (digest_info)
-		digest_info_size = digest_info->size;
-
-	if (req->src_len + digest_info_size > ctx->key_size - 11)
-		return -EOVERFLOW;
-
-	if (req->dst_len < ctx->key_size) {
-		req->dst_len = ctx->key_size;
-		return -EOVERFLOW;
-	}
-
-	req_ctx->in_buf = kmalloc(ctx->key_size - 1 - req->src_len,
-				  GFP_KERNEL);
-	if (!req_ctx->in_buf)
-		return -ENOMEM;
-
-	ps_end = ctx->key_size - digest_info_size - req->src_len - 2;
-	req_ctx->in_buf[0] = 0x01;
-	memset(req_ctx->in_buf + 1, 0xff, ps_end - 1);
-	req_ctx->in_buf[ps_end] = 0x00;
-
-	if (digest_info)
-		memcpy(req_ctx->in_buf + ps_end + 1, digest_info->data,
-		       digest_info->size);
-
-	pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf,
-			ctx->key_size - 1 - req->src_len, req->src);
-
-	akcipher_request_set_tfm(&req_ctx->child_req, ctx->child);
-	akcipher_request_set_callback(&req_ctx->child_req, req->base.flags,
-			pkcs1pad_encrypt_sign_complete_cb, req);
-
-	/* Reuse output buffer */
-	akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg,
-				   req->dst, ctx->key_size - 1, req->dst_len);
-
-	err = crypto_akcipher_decrypt(&req_ctx->child_req);
-	if (err != -EINPROGRESS && err != -EBUSY)
-		return pkcs1pad_encrypt_sign_complete(req, err);
-
-	return err;
-}
-
-static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
-{
-	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
-	struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
-	struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
-	struct akcipher_instance *inst = akcipher_alg_instance(tfm);
-	struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst);
-	const struct rsa_asn1_template *digest_info = ictx->digest_info;
-	const unsigned int sig_size = req->src_len;
-	const unsigned int digest_size = req->dst_len;
-	unsigned int dst_len;
-	unsigned int pos;
-	u8 *out_buf;
-
-	if (err)
-		goto done;
-
-	err = -EINVAL;
-	dst_len = req_ctx->child_req.dst_len;
-	if (dst_len < ctx->key_size - 1)
-		goto done;
-
-	out_buf = req_ctx->out_buf;
-	if (dst_len == ctx->key_size) {
-		if (out_buf[0] != 0x00)
-			/* Decrypted value had no leading 0 byte */
-			goto done;
-
-		dst_len--;
-		out_buf++;
-	}
-
-	err = -EBADMSG;
-	if (out_buf[0] != 0x01)
-		goto done;
-
-	for (pos = 1; pos < dst_len; pos++)
-		if (out_buf[pos] != 0xff)
-			break;
-
-	if (pos < 9 || pos == dst_len || out_buf[pos] != 0x00)
-		goto done;
-	pos++;
-
-	if (digest_info) {
-		if (digest_info->size > dst_len - pos)
-			goto done;
-		if (crypto_memneq(out_buf + pos, digest_info->data,
-				  digest_info->size))
-			goto done;
-
-		pos += digest_info->size;
-	}
-
-	err = 0;
-
-	if (digest_size != dst_len - pos) {
-		err = -EKEYREJECTED;
-		req->dst_len = dst_len - pos;
-		goto done;
-	}
-	/* Extract appended digest. */
-	sg_pcopy_to_buffer(req->src,
-			   sg_nents_for_len(req->src, sig_size + digest_size),
-			   req_ctx->out_buf + ctx->key_size,
-			   digest_size, sig_size);
-	/* Do the actual verification step. */
-	if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos,
-		   digest_size) != 0)
-		err = -EKEYREJECTED;
-done:
-	kfree_sensitive(req_ctx->out_buf);
-
-	return err;
-}
-
-static void pkcs1pad_verify_complete_cb(void *data, int err)
-{
-	struct akcipher_request *req = data;
-
-	if (err == -EINPROGRESS)
-		goto out;
-
-	err = pkcs1pad_verify_complete(req, err);
-
-out:
-	akcipher_request_complete(req, err);
-}
-
-/*
- * The verify operation is here for completeness similar to the verification
- * defined in RFC2313 section 10.2 except that block type 0 is not accepted,
- * as in RFC2437.  RFC2437 section 9.2 doesn't define any operation to
- * retrieve the DigestInfo from a signature, instead the user is expected
- * to call the sign operation to generate the expected signature and compare
- * signatures instead of the message-digests.
- */
-static int pkcs1pad_verify(struct akcipher_request *req)
-{
-	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
-	struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
-	struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
-	const unsigned int sig_size = req->src_len;
-	const unsigned int digest_size = req->dst_len;
-	int err;
-
-	if (WARN_ON(req->dst) || WARN_ON(!digest_size) ||
-	    !ctx->key_size || sig_size != ctx->key_size)
-		return -EINVAL;
-
-	req_ctx->out_buf = kmalloc(ctx->key_size + digest_size, GFP_KERNEL);
-	if (!req_ctx->out_buf)
-		return -ENOMEM;
-
-	pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf,
-			    ctx->key_size, NULL);
-
-	akcipher_request_set_tfm(&req_ctx->child_req, ctx->child);
-	akcipher_request_set_callback(&req_ctx->child_req, req->base.flags,
-			pkcs1pad_verify_complete_cb, req);
-
-	/* Reuse input buffer, output to a new buffer */
-	akcipher_request_set_crypt(&req_ctx->child_req, req->src,
-				   req_ctx->out_sg, sig_size, ctx->key_size);
-
-	err = crypto_akcipher_encrypt(&req_ctx->child_req);
-	if (err != -EINPROGRESS && err != -EBUSY)
-		return pkcs1pad_verify_complete(req, err);
-
-	return err;
-}
-
 static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm)
 {
 	struct akcipher_instance *inst = akcipher_alg_instance(tfm);
@@ -598,7 +313,6 @@  static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
 	struct akcipher_instance *inst;
 	struct pkcs1pad_inst_ctx *ctx;
 	struct akcipher_alg *rsa_alg;
-	const char *hash_name;
 	int err;
 
 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AKCIPHER, &mask);
@@ -624,36 +338,15 @@  static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
 	}
 
 	err = -ENAMETOOLONG;
-	hash_name = crypto_attr_alg_name(tb[2]);
-	if (IS_ERR(hash_name)) {
-		if (snprintf(inst->alg.base.cra_name,
-			     CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
-			     rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
-			goto err_free_inst;
-
-		if (snprintf(inst->alg.base.cra_driver_name,
-			     CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
-			     rsa_alg->base.cra_driver_name) >=
-			     CRYPTO_MAX_ALG_NAME)
-			goto err_free_inst;
-	} else {
-		ctx->digest_info = rsa_lookup_asn1(hash_name);
-		if (!ctx->digest_info) {
-			err = -EINVAL;
-			goto err_free_inst;
-		}
-
-		if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
-			     "pkcs1pad(%s,%s)", rsa_alg->base.cra_name,
-			     hash_name) >= CRYPTO_MAX_ALG_NAME)
-			goto err_free_inst;
-
-		if (snprintf(inst->alg.base.cra_driver_name,
-			     CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)",
-			     rsa_alg->base.cra_driver_name,
-			     hash_name) >= CRYPTO_MAX_ALG_NAME)
-			goto err_free_inst;
-	}
+	if (snprintf(inst->alg.base.cra_name,
+		     CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
+		     rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
+		goto err_free_inst;
+
+	if (snprintf(inst->alg.base.cra_driver_name,
+		     CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
+		     rsa_alg->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+		goto err_free_inst;
 
 	inst->alg.base.cra_priority = rsa_alg->base.cra_priority;
 	inst->alg.base.cra_ctxsize = sizeof(struct pkcs1pad_ctx);
@@ -663,8 +356,6 @@  static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
 
 	inst->alg.encrypt = pkcs1pad_encrypt;
 	inst->alg.decrypt = pkcs1pad_decrypt;
-	inst->alg.sign = pkcs1pad_sign;
-	inst->alg.verify = pkcs1pad_verify;
 	inst->alg.set_pub_key = pkcs1pad_set_pub_key;
 	inst->alg.set_priv_key = pkcs1pad_set_priv_key;
 	inst->alg.max_size = pkcs1pad_get_max_size;
diff --git a/crypto/rsa.c b/crypto/rsa.c
index d9be9e86097e..89e9fd9f6d7f 100644
--- a/crypto/rsa.c
+++ b/crypto/rsa.c
@@ -402,16 +402,25 @@  static int __init rsa_init(void)
 		return err;
 
 	err = crypto_register_template(&rsa_pkcs1pad_tmpl);
-	if (err) {
-		crypto_unregister_akcipher(&rsa);
-		return err;
-	}
+	if (err)
+		goto err_unregister_rsa;
+
+	err = crypto_register_template(&rsassa_pkcs1_tmpl);
+	if (err)
+		goto err_unregister_rsa_pkcs1pad;
 
 	return 0;
+
+err_unregister_rsa_pkcs1pad:
+	crypto_unregister_template(&rsa_pkcs1pad_tmpl);
+err_unregister_rsa:
+	crypto_unregister_akcipher(&rsa);
+	return err;
 }
 
 static void __exit rsa_exit(void)
 {
+	crypto_unregister_template(&rsassa_pkcs1_tmpl);
 	crypto_unregister_template(&rsa_pkcs1pad_tmpl);
 	crypto_unregister_akcipher(&rsa);
 }
diff --git a/crypto/rsassa-pkcs1.c b/crypto/rsassa-pkcs1.c
new file mode 100644
index 000000000000..779c080fc013
--- /dev/null
+++ b/crypto/rsassa-pkcs1.c
@@ -0,0 +1,422 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * RSA Signature Scheme with Appendix - PKCS #1 v1.5 (RFC 8017 sec 8.2)
+ *
+ * https://www.rfc-editor.org/rfc/rfc8017#section-8.2
+ *
+ * Copyright (c) 2015 - 2024 Intel Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <crypto/akcipher.h>
+#include <crypto/algapi.h>
+#include <crypto/sig.h>
+#include <crypto/internal/akcipher.h>
+#include <crypto/internal/rsa.h>
+#include <crypto/internal/sig.h>
+
+/*
+ * Full Hash Prefix for EMSA-PKCS1-v1_5 encoding method (RFC 9580 table 24)
+ *
+ * RSA keys are usually much larger than the hash of the message to be signed.
+ * The hash is therefore prepended by the Full Hash Prefix and a 0xff padding.
+ * The Full Hash Prefix is an ASN.1 SEQUENCE containing the hash algorithm OID.
+ *
+ * https://www.rfc-editor.org/rfc/rfc9580#table-24
+ */
+
+static const u8 hash_prefix_md5[] = {
+	0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,	  /* SEQUENCE (SEQUENCE (OID */
+	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05,	/*	<algorithm>, */
+	0x05, 0x00, 0x04, 0x10		      /* NULL), OCTET STRING <hash>) */
+};
+
+static const u8 hash_prefix_sha1[] = {
+	0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
+	0x2b, 0x0e, 0x03, 0x02, 0x1a,
+	0x05, 0x00, 0x04, 0x14
+};
+
+static const u8 hash_prefix_rmd160[] = {
+	0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
+	0x2b, 0x24, 0x03, 0x02, 0x01,
+	0x05, 0x00, 0x04, 0x14
+};
+
+static const u8 hash_prefix_sha224[] = {
+	0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
+	0x05, 0x00, 0x04, 0x1c
+};
+
+static const u8 hash_prefix_sha256[] = {
+	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+	0x05, 0x00, 0x04, 0x20
+};
+
+static const u8 hash_prefix_sha384[] = {
+	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
+	0x05, 0x00, 0x04, 0x30
+};
+
+static const u8 hash_prefix_sha512[] = {
+	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
+	0x05, 0x00, 0x04, 0x40
+};
+
+static const u8 hash_prefix_sha3_256[] = {
+	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08,
+	0x05, 0x00, 0x04, 0x20
+};
+
+static const u8 hash_prefix_sha3_384[] = {
+	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09,
+	0x05, 0x00, 0x04, 0x30
+};
+
+static const u8 hash_prefix_sha3_512[] = {
+	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
+	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a,
+	0x05, 0x00, 0x04, 0x40
+};
+
+static const struct hash_prefix {
+	const char	*name;
+	const u8	*data;
+	size_t		size;
+} hash_prefixes[] = {
+#define _(X) { #X, hash_prefix_##X, sizeof(hash_prefix_##X) }
+	_(md5),
+	_(sha1),
+	_(rmd160),
+	_(sha256),
+	_(sha384),
+	_(sha512),
+	_(sha224),
+#undef _
+#define _(X) { "sha3-" #X, hash_prefix_sha3_##X, sizeof(hash_prefix_sha3_##X) }
+	_(256),
+	_(384),
+	_(512),
+#undef _
+	{ NULL }
+};
+
+static const struct hash_prefix *rsassa_pkcs1_find_hash_prefix(const char *name)
+{
+	const struct hash_prefix *p;
+
+	for (p = hash_prefixes; p->name; p++)
+		if (strcmp(name, p->name) == 0)
+			return p;
+	return NULL;
+}
+
+struct rsassa_pkcs1_ctx {
+	struct crypto_akcipher *child;
+	unsigned int key_size;
+};
+
+struct rsassa_pkcs1_inst_ctx {
+	struct crypto_akcipher_spawn spawn;
+	const struct hash_prefix *hash_prefix;
+};
+
+static int rsassa_pkcs1_sign(struct crypto_sig *tfm,
+			     const void *src, unsigned int slen,
+			     void *dst, unsigned int dlen)
+{
+	struct sig_instance *inst = sig_alg_instance(tfm);
+	struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
+	const struct hash_prefix *hash_prefix = ictx->hash_prefix;
+	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
+	unsigned int child_reqsize = crypto_akcipher_reqsize(ctx->child);
+	struct akcipher_request *child_req __free(kfree_sensitive) = NULL;
+	struct scatterlist in_sg[2], out_sg;
+	struct crypto_wait cwait;
+	unsigned int pad_len;
+	unsigned int ps_end;
+	unsigned int len;
+	u8 *in_buf;
+	int err;
+
+	if (!ctx->key_size)
+		return -EINVAL;
+
+	if (dlen < ctx->key_size)
+		return -EOVERFLOW;
+
+	if (slen + hash_prefix->size > ctx->key_size - 11)
+		return -EOVERFLOW;
+
+	child_req = kmalloc(sizeof(*child_req) + child_reqsize +
+			    ctx->key_size - 1 - slen, GFP_KERNEL);
+	if (!child_req)
+		return -ENOMEM;
+
+	/* RFC 8017 sec 8.2.1 step 1 - EMSA-PKCS1-v1_5 encoding generation */
+	in_buf = (u8 *)(child_req + 1) + child_reqsize;
+	ps_end = ctx->key_size - hash_prefix->size - slen - 2;
+	in_buf[0] = 0x01;
+	memset(in_buf + 1, 0xff, ps_end - 1);
+	in_buf[ps_end] = 0x00;
+	memcpy(in_buf + ps_end + 1, hash_prefix->data, hash_prefix->size);
+
+	/* RFC 8017 sec 8.2.1 step 2 - RSA signature */
+	crypto_init_wait(&cwait);
+	sg_init_table(in_sg, 2);
+	sg_set_buf(&in_sg[0], in_buf, ctx->key_size - 1 - slen);
+	sg_set_buf(&in_sg[1], src, slen);
+	sg_init_one(&out_sg, dst, dlen);
+	akcipher_request_set_tfm(child_req, ctx->child);
+	akcipher_request_set_crypt(child_req, in_sg, &out_sg,
+				   ctx->key_size - 1, dlen);
+	akcipher_request_set_callback(child_req, CRYPTO_TFM_REQ_MAY_SLEEP,
+				      crypto_req_done, &cwait);
+
+	err = crypto_akcipher_decrypt(child_req);
+	err = crypto_wait_req(err, &cwait);
+	if (err)
+		return err;
+
+	len = child_req->dst_len;
+	pad_len = ctx->key_size - len;
+
+	/* Four billion to one */
+	if (unlikely(pad_len)) {
+		memmove(dst + pad_len, dst, len);
+		memset(dst, 0, pad_len);
+	}
+
+	return 0;
+}
+
+static int rsassa_pkcs1_verify(struct crypto_sig *tfm,
+			       const void *src, unsigned int slen,
+			       const void *digest, unsigned int dlen)
+{
+	struct sig_instance *inst = sig_alg_instance(tfm);
+	struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
+	const struct hash_prefix *hash_prefix = ictx->hash_prefix;
+	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
+	unsigned int child_reqsize = crypto_akcipher_reqsize(ctx->child);
+	struct akcipher_request *child_req __free(kfree_sensitive) = NULL;
+	struct scatterlist in_sg, out_sg;
+	struct crypto_wait cwait;
+	unsigned int dst_len;
+	unsigned int pos;
+	u8 *out_buf;
+	int err;
+
+	/* RFC 8017 sec 8.2.2 step 1 - length checking */
+	if (!ctx->key_size ||
+	    slen != ctx->key_size ||
+	    !dlen)
+		return -EINVAL;
+
+	/* RFC 8017 sec 8.2.2 step 2 - RSA verification */
+	child_req = kmalloc(sizeof(*child_req) + child_reqsize + ctx->key_size,
+			    GFP_KERNEL);
+	if (!child_req)
+		return -ENOMEM;
+
+	out_buf = (u8 *)(child_req + 1) + child_reqsize;
+
+	crypto_init_wait(&cwait);
+	sg_init_one(&in_sg, src, slen);
+	sg_init_one(&out_sg, out_buf, ctx->key_size);
+	akcipher_request_set_tfm(child_req, ctx->child);
+	akcipher_request_set_crypt(child_req, &in_sg, &out_sg,
+				   slen, ctx->key_size);
+	akcipher_request_set_callback(child_req, CRYPTO_TFM_REQ_MAY_SLEEP,
+				      crypto_req_done, &cwait);
+
+	err = crypto_akcipher_encrypt(child_req);
+	err = crypto_wait_req(err, &cwait);
+	if (err)
+		return err;
+
+	/* RFC 8017 sec 8.2.2 step 3 - EMSA-PKCS1-v1_5 encoding verification */
+	dst_len = child_req->dst_len;
+	if (dst_len < ctx->key_size - 1)
+		return -EINVAL;
+
+	if (dst_len == ctx->key_size) {
+		if (out_buf[0] != 0x00)
+			/* Encrypted value had no leading 0 byte */
+			return -EINVAL;
+
+		dst_len--;
+		out_buf++;
+	}
+
+	if (out_buf[0] != 0x01)
+		return -EBADMSG;
+
+	for (pos = 1; pos < dst_len; pos++)
+		if (out_buf[pos] != 0xff)
+			break;
+
+	if (pos < 9 || pos == dst_len || out_buf[pos] != 0x00)
+		return -EBADMSG;
+	pos++;
+
+	if (hash_prefix->size > dst_len - pos)
+		return -EBADMSG;
+	if (crypto_memneq(out_buf + pos, hash_prefix->data, hash_prefix->size))
+		return -EBADMSG;
+	pos += hash_prefix->size;
+
+	/* RFC 8017 sec 8.2.2 step 4 - comparison of digest with out_buf */
+	if (dlen != dst_len - pos)
+		return -EKEYREJECTED;
+	if (memcmp(digest, out_buf + pos, dlen) != 0)
+		return -EKEYREJECTED;
+
+	return 0;
+}
+
+static unsigned int rsassa_pkcs1_max_size(struct crypto_sig *tfm)
+{
+	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
+
+	return ctx->key_size;
+}
+
+static int rsassa_pkcs1_set_pub_key(struct crypto_sig *tfm,
+				    const void *key, unsigned int keylen)
+{
+	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
+
+	return rsa_set_key(ctx->child, &ctx->key_size, RSA_PUB, key, keylen);
+}
+
+static int rsassa_pkcs1_set_priv_key(struct crypto_sig *tfm,
+				     const void *key, unsigned int keylen)
+{
+	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
+
+	return rsa_set_key(ctx->child, &ctx->key_size, RSA_PRIV, key, keylen);
+}
+
+static int rsassa_pkcs1_init_tfm(struct crypto_sig *tfm)
+{
+	struct sig_instance *inst = sig_alg_instance(tfm);
+	struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst);
+	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
+	struct crypto_akcipher *child_tfm;
+
+	child_tfm = crypto_spawn_akcipher(&ictx->spawn);
+	if (IS_ERR(child_tfm))
+		return PTR_ERR(child_tfm);
+
+	ctx->child = child_tfm;
+
+	return 0;
+}
+
+static void rsassa_pkcs1_exit_tfm(struct crypto_sig *tfm)
+{
+	struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm);
+
+	crypto_free_akcipher(ctx->child);
+}
+
+static void rsassa_pkcs1_free(struct sig_instance *inst)
+{
+	struct rsassa_pkcs1_inst_ctx *ctx = sig_instance_ctx(inst);
+	struct crypto_akcipher_spawn *spawn = &ctx->spawn;
+
+	crypto_drop_akcipher(spawn);
+	kfree(inst);
+}
+
+static int rsassa_pkcs1_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+	struct rsassa_pkcs1_inst_ctx *ctx;
+	struct akcipher_alg *rsa_alg;
+	struct sig_instance *inst;
+	const char *hash_name;
+	u32 mask;
+	int err;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SIG, &mask);
+	if (err)
+		return err;
+
+	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
+	if (!inst)
+		return -ENOMEM;
+
+	ctx = sig_instance_ctx(inst);
+
+	err = crypto_grab_akcipher(&ctx->spawn, sig_crypto_instance(inst),
+				   crypto_attr_alg_name(tb[1]), 0, mask);
+	if (err)
+		goto err_free_inst;
+
+	rsa_alg = crypto_spawn_akcipher_alg(&ctx->spawn);
+
+	if (strcmp(rsa_alg->base.cra_name, "rsa") != 0) {
+		err = -EINVAL;
+		goto err_free_inst;
+	}
+
+	hash_name = crypto_attr_alg_name(tb[2]);
+	if (IS_ERR(hash_name)) {
+		err = PTR_ERR(hash_name);
+		goto err_free_inst;
+	}
+
+	ctx->hash_prefix = rsassa_pkcs1_find_hash_prefix(hash_name);
+	if (!ctx->hash_prefix) {
+		err = -EINVAL;
+		goto err_free_inst;
+	}
+
+	err = -ENAMETOOLONG;
+	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
+		     "pkcs1(%s,%s)", rsa_alg->base.cra_name,
+		     hash_name) >= CRYPTO_MAX_ALG_NAME)
+		goto err_free_inst;
+
+	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+		     "pkcs1(%s,%s)", rsa_alg->base.cra_driver_name,
+		     hash_name) >= CRYPTO_MAX_ALG_NAME)
+		goto err_free_inst;
+
+	inst->alg.base.cra_priority = rsa_alg->base.cra_priority;
+	inst->alg.base.cra_ctxsize = sizeof(struct rsassa_pkcs1_ctx);
+
+	inst->alg.init = rsassa_pkcs1_init_tfm;
+	inst->alg.exit = rsassa_pkcs1_exit_tfm;
+
+	inst->alg.sign = rsassa_pkcs1_sign;
+	inst->alg.verify = rsassa_pkcs1_verify;
+	inst->alg.max_size = rsassa_pkcs1_max_size;
+	inst->alg.set_pub_key = rsassa_pkcs1_set_pub_key;
+	inst->alg.set_priv_key = rsassa_pkcs1_set_priv_key;
+
+	inst->free = rsassa_pkcs1_free;
+
+	err = sig_register_instance(tmpl, inst);
+	if (err) {
+err_free_inst:
+		rsassa_pkcs1_free(inst);
+	}
+	return err;
+}
+
+struct crypto_template rsassa_pkcs1_tmpl = {
+	.name = "pkcs1",
+	.create = rsassa_pkcs1_create,
+	.module = THIS_MODULE,
+};
+
+MODULE_ALIAS_CRYPTO("pkcs1");
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 0542817a9456..91dc29e79dd6 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -5548,34 +5548,38 @@  static const struct alg_test_desc alg_test_descs[] = {
 			.cipher = __VECS(fcrypt_pcbc_tv_template)
 		}
 	}, {
-		.alg = "pkcs1pad(rsa,sha224)",
+		.alg = "pkcs1(rsa,sha224)",
 		.test = alg_test_null,
 		.fips_allowed = 1,
 	}, {
-		.alg = "pkcs1pad(rsa,sha256)",
-		.test = alg_test_akcipher,
+		.alg = "pkcs1(rsa,sha256)",
+		.test = alg_test_sig,
 		.fips_allowed = 1,
 		.suite = {
-			.akcipher = __VECS(pkcs1pad_rsa_tv_template)
+			.sig = __VECS(pkcs1_rsa_tv_template)
 		}
 	}, {
-		.alg = "pkcs1pad(rsa,sha3-256)",
+		.alg = "pkcs1(rsa,sha3-256)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "pkcs1(rsa,sha3-384)",
 		.test = alg_test_null,
 		.fips_allowed = 1,
 	}, {
-		.alg = "pkcs1pad(rsa,sha3-384)",
+		.alg = "pkcs1(rsa,sha3-512)",
 		.test = alg_test_null,
 		.fips_allowed = 1,
 	}, {
-		.alg = "pkcs1pad(rsa,sha3-512)",
+		.alg = "pkcs1(rsa,sha384)",
 		.test = alg_test_null,
 		.fips_allowed = 1,
 	}, {
-		.alg = "pkcs1pad(rsa,sha384)",
+		.alg = "pkcs1(rsa,sha512)",
 		.test = alg_test_null,
 		.fips_allowed = 1,
 	}, {
-		.alg = "pkcs1pad(rsa,sha512)",
+		.alg = "pkcs1pad(rsa)",
 		.test = alg_test_null,
 		.fips_allowed = 1,
 	}, {
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index fd4823c26d93..d29d03fec852 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -1268,7 +1268,7 @@  static const struct sig_testvec ecrdsa_tv_template[] = {
 /*
  * PKCS#1 RSA test vectors. Obtained from CAVS testing.
  */
-static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
+static const struct sig_testvec pkcs1_rsa_tv_template[] = {
 	{
 	.key =
 	"\x30\x82\x04\xa5\x02\x01\x00\x02\x82\x01\x01\x00\xd7\x1e\x77\x82"
@@ -1380,7 +1380,6 @@  static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
 	"\xda\x62\x8d\xe1\x2a\x71\x91\x43\x40\x61\x3c\x5a\xbe\x86\xfc\x5b"
 	"\xe6\xf9\xa9\x16\x31\x1f\xaf\x25\x6d\xc2\x4a\x23\x6e\x63\x02\xa2",
 	.c_size = 256,
-	.siggen_sigver_test = true,
 	}
 };
 
diff --git a/include/crypto/internal/rsa.h b/include/crypto/internal/rsa.h
index 754f687134df..071a1951b992 100644
--- a/include/crypto/internal/rsa.h
+++ b/include/crypto/internal/rsa.h
@@ -82,4 +82,5 @@  static inline int rsa_set_key(struct crypto_akcipher *child,
 }
 
 extern struct crypto_template rsa_pkcs1pad_tmpl;
+extern struct crypto_template rsassa_pkcs1_tmpl;
 #endif
diff --git a/include/linux/slab.h b/include/linux/slab.h
index eb2bf4629157..11b620b0ba1d 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -280,6 +280,7 @@  void kfree_sensitive(const void *objp);
 size_t __ksize(const void *objp);
 
 DEFINE_FREE(kfree, void *, if (!IS_ERR_OR_NULL(_T)) kfree(_T))
+DEFINE_FREE(kfree_sensitive, void *, if (_T) kfree_sensitive(_T))
 
 /**
  * ksize - Report actual allocation size of associated object
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index f04f43af651c..280a3feeba45 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -1114,7 +1114,7 @@  EXPORT_SYMBOL_GPL(ima_measure_critical_data);
 #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
 
 /**
- * ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests
+ * ima_kernel_module_request - Prevent crypto-pkcs1(rsa,*) requests
  * @kmod_name: kernel module name
  *
  * Avoid a verification loop where verifying the signature of the modprobe
@@ -1128,7 +1128,7 @@  EXPORT_SYMBOL_GPL(ima_measure_critical_data);
  * algorithm on the fly, but crypto_larval_lookup() will try to use alg_name
  * in order to load a kernel module with same name.
  *
- * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules,
+ * Since we don't have any real "crypto-pkcs1(rsa,*)" kernel modules,
  * we are safe to fail such module request from crypto_larval_lookup(), and
  * avoid the verification loop.
  *
@@ -1136,7 +1136,7 @@  EXPORT_SYMBOL_GPL(ima_measure_critical_data);
  */
 static int ima_kernel_module_request(char *kmod_name)
 {
-	if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0)
+	if (strncmp(kmod_name, "crypto-pkcs1(rsa,", 17) == 0)
 		return -EINVAL;
 
 	return 0;