Re: [PATCH 4/8] akcipher: Move the RSA DER encoding to the crypto layer

From: Tadeusz Struk
Date: Mon Feb 22 2016 - 15:03:59 EST


On 02/19/2016 09:18 AM, David Howells wrote:
> Move the RSA EMSA-PKCS1-v1_5 encoding from the asymmetric-key public_key
> subtype to the rsa crypto module. This means that the public_key subtype
> no longer has any dependencies on public key type.
>
> To make this work, I've made the following changes:
>
> (1) An indicator as to the hash algorithm employed must be passed to the
> public key algorithm. I have made this a string, equivalent to the
> name in the matching crypto module and placed it in akcipher_request.
>
> (2) The RSA module builds the EMSA-PKCS1-v1_5 encoded message (EM) and
> then compares that to the 'decrypted' signature. This function can
> then be reused for signing.
>
> (3) The destination buffer in akcipher_request is now an input buffer
> holding the message digest (M) for the verify operation. The output
> of the verify operation is purely the error code.
>
> (4) The crypto driver in crypto/asymmetric_keys/rsa.c is now reduced to
> something that doesn't care about what the encryption actually does
> and and has been merged into public_key.c.
>
> (5) The test drivers set a NULL hash algorithm as I'm not sure what they
> should be.
>
> (6) CONFIG_PUBLIC_KEY_ALGO_RSA is gone. Module signing must set
> CONFIG_CRYPTO_RSA=y instead.
>
> Thoughts:
>
> (*) Should the encoding style (eg. raw, EMSA-PKCS1-v1_5) also be passed to
> the public key algorithm?

I wonder if this should be merged with the crypto/rsa-pkcs1pad.c template
that we already have. Looks like the two do the same padding now.
Should we merge then and pass the hash param as a separate template param,
e.g the public_key would allocate "pkcs1pad(rsa, sha1)"?

>
> Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
> ---
>
> crypto/asymmetric_keys/Kconfig | 7 -
> crypto/asymmetric_keys/Makefile | 1
> crypto/asymmetric_keys/public_key.c | 69 +++++++++--
> crypto/asymmetric_keys/rsa.c | 224 -----------------------------------
> crypto/rsa.c | 210 ++++++++++++++++++++++++++++-----
> crypto/testmgr.c | 5 -
> include/crypto/akcipher.h | 7 +
> include/crypto/public_key.h | 2
> init/Kconfig | 2
> 9 files changed, 248 insertions(+), 279 deletions(-)
> delete mode 100644 crypto/asymmetric_keys/rsa.c
>
> diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
> index 905d745c2f85..91a7e047a765 100644
> --- a/crypto/asymmetric_keys/Kconfig
> +++ b/crypto/asymmetric_keys/Kconfig
> @@ -12,7 +12,6 @@ if ASYMMETRIC_KEY_TYPE
> config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
> tristate "Asymmetric public-key crypto algorithm subtype"
> select MPILIB
> - select PUBLIC_KEY_ALGO_RSA
> select CRYPTO_HASH_INFO
> help
> This option provides support for asymmetric public key type handling.
> @@ -20,12 +19,6 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
> appropriate hash algorithms (such as SHA-1) must be available.
> ENOPKG will be reported if the requisite algorithm is unavailable.
>
> -config PUBLIC_KEY_ALGO_RSA
> - tristate "RSA public-key algorithm"
> - select CRYPTO_RSA
> - help
> - This option enables support for the RSA algorithm (PKCS#1, RFC3447).
> -
> config X509_CERTIFICATE_PARSER
> tristate "X.509 certificate parser"
> depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
> diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
> index b78a194ea014..f90486256f01 100644
> --- a/crypto/asymmetric_keys/Makefile
> +++ b/crypto/asymmetric_keys/Makefile
> @@ -7,7 +7,6 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
> asymmetric_keys-y := asymmetric_type.o signature.o
>
> obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
> -obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
>
> #
> # X.509 Certificate handling
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index b383629b9e62..66727a13d561 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -17,8 +17,10 @@
> #include <linux/kernel.h>
> #include <linux/slab.h>
> #include <linux/seq_file.h>
> +#include <linux/scatterlist.h>
> #include <keys/asymmetric-subtype.h>
> #include <crypto/public_key.h>
> +#include <crypto/akcipher.h>
>
> MODULE_LICENSE("GPL");
>
> @@ -35,12 +37,6 @@ const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = {
> };
> EXPORT_SYMBOL_GPL(pkey_id_type_name);
>
> -static int (*alg_verify[PKEY_ALGO__LAST])(const struct public_key *pkey,
> - const struct public_key_signature *sig) = {
> - NULL,
> - rsa_verify_signature
> -};
> -
> /*
> * Provide a part of a description of the key for /proc/keys.
> */
> @@ -68,24 +64,75 @@ void public_key_destroy(void *payload)
> }
> EXPORT_SYMBOL_GPL(public_key_destroy);
>
> +struct public_key_completion {
> + struct completion completion;
> + int err;
> +};
> +
> +static void public_key_verify_done(struct crypto_async_request *req, int err)
> +{
> + struct public_key_completion *compl = req->data;
> +
> + if (err == -EINPROGRESS)
> + return;
> +
> + compl->err = err;
> + complete(&compl->completion);
> +}
> +
> /*
> * Verify a signature using a public key.
> */
> int public_key_verify_signature(const struct public_key *pkey,
> const struct public_key_signature *sig)
> {
> + struct public_key_completion compl;
> + struct crypto_akcipher *tfm;
> + struct akcipher_request *req;
> + struct scatterlist sig_sg, digest_sg;
> + int ret = -ENOMEM;
> +
> + pr_devel("==>%s()\n", __func__);
> +
> BUG_ON(!pkey);
> BUG_ON(!sig);
> BUG_ON(!sig->digest);
> BUG_ON(!sig->s);
>
> - if (pkey->pkey_algo >= PKEY_ALGO__LAST)
> - return -ENOPKG;
> + tfm = crypto_alloc_akcipher(pkey_algo_name[sig->pkey_algo], 0, 0);
> + if (IS_ERR(tfm))
> + return PTR_ERR(tfm);
> +
> + req = akcipher_request_alloc(tfm, GFP_KERNEL);
> + if (!req)
> + goto error_free_tfm;
> +
> + ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
> + if (ret)
> + goto error_free_req;
> +
> + sg_init_one(&sig_sg, sig->s, sig->s_size);
> + sg_init_one(&digest_sg, sig->digest, sig->digest_size);
> + akcipher_request_set_crypt(req, &sig_sg, &digest_sg,
> + sig->s_size, sig->digest_size,
> + hash_algo_name[sig->pkey_hash_algo]);
> + init_completion(&compl.completion);
> + akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
> + CRYPTO_TFM_REQ_MAY_SLEEP,
> + public_key_verify_done, &compl);
>
> - if (!alg_verify[pkey->pkey_algo])
> - return -ENOPKG;
> + ret = crypto_akcipher_verify(req);
> + if (ret == -EINPROGRESS) {
> + wait_for_completion(&compl.completion);
> + ret = compl.err;
> + }
>
> - return alg_verify[pkey->pkey_algo](pkey, sig);
> +error_free_req:
> + akcipher_request_free(req);
> +error_free_tfm:
> + crypto_free_akcipher(tfm);
> + pr_devel("<==%s() = %d\n", __func__, ret);
> + return ret;
> }
> EXPORT_SYMBOL_GPL(public_key_verify_signature);
>
> diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
> deleted file mode 100644
> index 51502bca65e7..000000000000
> --- a/crypto/asymmetric_keys/rsa.c
> +++ /dev/null
> @@ -1,224 +0,0 @@
> -/* RSA asymmetric public-key algorithm [RFC3447]
> - *
> - * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
> - * Written by David Howells (dhowells@xxxxxxxxxx)
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public Licence
> - * as published by the Free Software Foundation; either version
> - * 2 of the Licence, or (at your option) any later version.
> - */
> -
> -#define pr_fmt(fmt) "RSA: "fmt
> -#include <linux/module.h>
> -#include <linux/slab.h>
> -#include <crypto/akcipher.h>
> -#include <crypto/public_key.h>
> -#include <crypto/algapi.h>
> -
> -MODULE_LICENSE("GPL");
> -MODULE_DESCRIPTION("RSA Public Key Algorithm");
> -
> -#define kenter(FMT, ...) \
> - pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
> -#define kleave(FMT, ...) \
> - pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
> -
> -/*
> - * 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_RIPE_MD_160[] = {
> - 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 struct {
> - const u8 *data;
> - size_t size;
> -} RSA_ASN1_templates[PKEY_HASH__LAST] = {
> -#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) }
> - [HASH_ALGO_MD5] = _(MD5),
> - [HASH_ALGO_SHA1] = _(SHA1),
> - [HASH_ALGO_RIPE_MD_160] = _(RIPE_MD_160),
> - [HASH_ALGO_SHA256] = _(SHA256),
> - [HASH_ALGO_SHA384] = _(SHA384),
> - [HASH_ALGO_SHA512] = _(SHA512),
> - [HASH_ALGO_SHA224] = _(SHA224),
> -#undef _
> -};
> -
> -struct rsa_completion {
> - struct completion completion;
> - int err;
> -};
> -
> -/*
> - * Perform the RSA signature verification.
> - * @H: Value of hash of data and metadata
> - * @EM: The computed signature value
> - * @k: The size of EM (EM[0] is an invalid location but should hold 0x00)
> - * @hash_size: The size of H
> - * @asn1_template: The DigestInfo ASN.1 template
> - * @asn1_size: Size of asm1_template[]
> - */
> -static int rsa_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
> - const u8 *asn1_template, size_t asn1_size)
> -{
> - unsigned PS_end, T_offset, i;
> -
> - kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size);
> -
> - if (k < 2 + 1 + asn1_size + hash_size)
> - return -EBADMSG;
> -
> - /* Decode the EMSA-PKCS1-v1_5
> - * note: leading zeros are stripped by the RSA implementation
> - */
> - if (EM[0] != 0x01) {
> - kleave(" = -EBADMSG [EM[0] == %02u]", EM[0]);
> - return -EBADMSG;
> - }
> -
> - T_offset = k - (asn1_size + hash_size);
> - PS_end = T_offset - 1;
> - if (EM[PS_end] != 0x00) {
> - kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]);
> - return -EBADMSG;
> - }
> -
> - for (i = 1; i < PS_end; i++) {
> - if (EM[i] != 0xff) {
> - kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]);
> - return -EBADMSG;
> - }
> - }
> -
> - if (crypto_memneq(asn1_template, EM + T_offset, asn1_size) != 0) {
> - kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]");
> - return -EBADMSG;
> - }
> -
> - if (crypto_memneq(H, EM + T_offset + asn1_size, hash_size) != 0) {
> - kleave(" = -EKEYREJECTED [EM[T] hash mismatch]");
> - return -EKEYREJECTED;
> - }
> -
> - kleave(" = 0");
> - return 0;
> -}
> -
> -static void public_key_verify_done(struct crypto_async_request *req, int err)
> -{
> - struct rsa_completion *compl = req->data;
> -
> - if (err == -EINPROGRESS)
> - return;
> -
> - compl->err = err;
> - complete(&compl->completion);
> -}
> -
> -int rsa_verify_signature(const struct public_key *pkey,
> - const struct public_key_signature *sig)
> -{
> - struct crypto_akcipher *tfm;
> - struct akcipher_request *req;
> - struct rsa_completion compl;
> - struct scatterlist sig_sg, sg_out;
> - void *outbuf = NULL;
> - unsigned int outlen = 0;
> - int ret = -ENOMEM;
> -
> - tfm = crypto_alloc_akcipher("rsa", 0, 0);
> - if (IS_ERR(tfm))
> - goto error_out;
> -
> - req = akcipher_request_alloc(tfm, GFP_KERNEL);
> - if (!req)
> - goto error_free_tfm;
> -
> - ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
> - if (ret)
> - goto error_free_req;
> -
> - ret = -EINVAL;
> - outlen = crypto_akcipher_maxsize(tfm);
> - if (!outlen)
> - goto error_free_req;
> -
> - /* Initialize the output buffer */
> - ret = -ENOMEM;
> - outbuf = kmalloc(outlen, GFP_KERNEL);
> - if (!outbuf)
> - goto error_free_req;
> -
> - sg_init_one(&sig_sg, sig->s, sig->s_size);
> - sg_init_one(&sg_out, outbuf, outlen);
> - akcipher_request_set_crypt(req, &sig_sg, &sg_out, sig->s_size, outlen);
> - init_completion(&compl.completion);
> - akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
> - CRYPTO_TFM_REQ_MAY_SLEEP,
> - public_key_verify_done, &compl);
> -
> - ret = crypto_akcipher_verify(req);
> - if (ret == -EINPROGRESS) {
> - wait_for_completion(&compl.completion);
> - ret = compl.err;
> - }
> -
> - if (ret)
> - goto error_free_req;
> -
> - /* Output from the operation is an encoded message (EM) of
> - * length k octets.
> - */
> - outlen = req->dst_len;
> - ret = rsa_verify(sig->digest, outbuf, outlen, sig->digest_size,
> - RSA_ASN1_templates[sig->pkey_hash_algo].data,
> - RSA_ASN1_templates[sig->pkey_hash_algo].size);
> -error_free_req:
> - akcipher_request_free(req);
> -error_free_tfm:
> - crypto_free_akcipher(tfm);
> -error_out:
> - kfree(outbuf);
> - return ret;
> -}
> -EXPORT_SYMBOL_GPL(rsa_verify_signature);
> diff --git a/crypto/rsa.c b/crypto/rsa.c
> index 77d737f52147..9a7c9ca9eafc 100644
> --- a/crypto/rsa.c
> +++ b/crypto/rsa.c
> @@ -16,6 +16,78 @@
> #include <crypto/algapi.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 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),
> + { NULL }
> +#undef _
> +};
> +
> +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;
> +}
> +
> +/*
> * RSAEP function [RFC3447 sec 5.1.1]
> * c = m^e mod n;
> */
> @@ -71,6 +143,13 @@ static int _rsa_verify(const struct rsa_key *key, MPI m, MPI s)
> return mpi_powm(m, s, key->e, key->n);
> }
>
> +static int rsa_max_size(struct crypto_akcipher *tfm)
> +{
> + struct rsa_key *pkey = akcipher_tfm_ctx(tfm);
> +
> + return pkey->n ? mpi_get_size(pkey->n) : -EINVAL;
> +}
> +
> static inline struct rsa_key *rsa_get_key(struct crypto_akcipher *tfm)
> {
> return akcipher_tfm_ctx(tfm);
> @@ -192,44 +271,122 @@ err_free_s:
> return ret;
> }
>
> -static int rsa_verify(struct akcipher_request *req)
> +static int rsa_verify_raw(struct akcipher_request *req, MPI EM)
> {
> struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> const struct rsa_key *pkey = rsa_get_key(tfm);
> - MPI s, m = mpi_alloc(0);
> - int ret = 0;
> - int sign;
> + MPI s, m_calc;
> + int ret;
>
> - if (!m)
> + m_calc = mpi_alloc(0);
> + if (!m_calc)
> return -ENOMEM;
>
> - if (unlikely(!pkey->n || !pkey->e)) {
> - ret = -EINVAL;
> - goto err_free_m;
> - }
> -
> ret = -ENOMEM;
> s = mpi_read_raw_from_sgl(req->src, req->src_len);
> - if (!s) {
> - ret = -ENOMEM;
> - goto err_free_m;
> - }
> + if (!s)
> + goto err_free_m_calc;
>
> - ret = _rsa_verify(pkey, m, s);
> + ret = _rsa_verify(pkey, m_calc, s);
> if (ret)
> goto err_free_s;
>
> - ret = mpi_write_to_sgl(m, req->dst, &req->dst_len, &sign);
> - if (ret)
> + ret = -EKEYREJECTED;
> + if (mpi_cmp(m_calc, EM) != 0)
> goto err_free_s;
>
> - if (sign < 0)
> - ret = -EBADMSG;
> -
> + ret = 0;
> err_free_s:
> mpi_free(s);
> -err_free_m:
> - mpi_free(m);
> +err_free_m_calc:
> + mpi_free(m_calc);
> + return ret;
> +}
> +
> +/*
> + * Turn Hash(M) into EM for a key of size k and a specified hash algorithm as
> + * per EMSA-PKCS1-v1_5:
> + *
> + * EM = 0x00 || 0x01 || PS || 0x00 || T
> + */
> +static MPI rsa_emsa_pkcs1_v1_5(struct scatterlist *H, int H_size, int k,
> + const char *hash_algo)
> +{
> + const struct rsa_asn1_template *asn1;
> + MPI EM;
> + int PS_end, T_offset;
> + u8 *buf;
> +
> + asn1 = rsa_lookup_asn1(hash_algo);
> + if (!asn1)
> + return ERR_PTR(-ENOPKG);
> +
> + if (k < 2 + 1 + asn1->size + H_size)
> + return ERR_PTR(-EMSGSIZE);
> +
> + T_offset = k - (asn1->size + H_size);
> + PS_end = T_offset - 1;
> + if (PS_end - 2 < 8)
> + return ERR_PTR(-EMSGSIZE);
> +
> + buf = kmalloc(k, GFP_KERNEL);
> + if (!buf)
> + return ERR_PTR(-ENOMEM);
> +
> + /* Set the initial zero and block type octets */
> + buf[0] = 0x00;
> + buf[1] = 0x01;
> +
> + /* Set the padding string and the divider */
> + memset(buf + 2, 0xff, PS_end - 2);
> + buf[PS_end] = 0x00;
> +
> + /* Set the DER-encoded DigestInfo */
> + memcpy(buf + T_offset, asn1->data, asn1->size);
> +
> + /* Finally set the */
> + if (sg_copy_to_buffer(H, sg_nents(H),
> + buf + T_offset + asn1->size,
> + H_size) != H_size) {
> + EM = ERR_PTR(-EMSGSIZE);
> + goto error_free_buf;
> + }
> +
> + EM = mpi_read_raw_data(buf, k);
> + if (!EM)
> + EM = ERR_PTR(-ENOMEM);
> +
> +error_free_buf:
> + kfree(buf);
> + return EM;
> +}
> +
> +static int rsa_verify_encoded(struct akcipher_request *req)
> +{
> + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> + const struct rsa_key *pkey = rsa_get_key(tfm);
> + MPI EM;
> + int ret, k;
> +
> + pr_devel("==>%s(%u,%u,%s)\n",
> + __func__, req->src_len, req->dst_len, req->hash_algo);
> +
> + if (unlikely(!pkey->n || !pkey->e || !req->hash_algo))
> + return -EINVAL;
> +
> + /* Find k - the size of E(M). */
> + k = rsa_max_size(tfm);
> + if (k < 0)
> + return k;
> +
> + EM = rsa_emsa_pkcs1_v1_5(req->dst, req->dst_len, k, req->hash_algo);
> + if (IS_ERR(EM))
> + return PTR_ERR(EM);
> +
> + ret = rsa_verify_raw(req, EM);
> +
> + mpi_free(EM);
> + pr_devel("<==%s() = %d\n", __func__, ret);
> return ret;
> }
>
> @@ -282,13 +439,6 @@ static int rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
> return ret;
> }
>
> -static int rsa_max_size(struct crypto_akcipher *tfm)
> -{
> - struct rsa_key *pkey = akcipher_tfm_ctx(tfm);
> -
> - return pkey->n ? mpi_get_size(pkey->n) : -EINVAL;
> -}
> -
> static void rsa_exit_tfm(struct crypto_akcipher *tfm)
> {
> struct rsa_key *pkey = akcipher_tfm_ctx(tfm);
> @@ -300,7 +450,7 @@ static struct akcipher_alg rsa = {
> .encrypt = rsa_enc,
> .decrypt = rsa_dec,
> .sign = rsa_sign,
> - .verify = rsa_verify,
> + .verify = rsa_verify_encoded,
> .set_priv_key = rsa_set_priv_key,
> .set_pub_key = rsa_set_pub_key,
> .max_size = rsa_max_size,
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index ae8c57fd8bc7..94879a3d2ef7 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -1882,7 +1882,7 @@ static int do_test_rsa(struct crypto_akcipher *tfm,
> sg_set_buf(&src_tab[1], vecs->m + 8, vecs->m_size - 8);
> sg_init_one(&dst, outbuf_enc, out_len_max);
> akcipher_request_set_crypt(req, src_tab, &dst, vecs->m_size,
> - out_len_max);
> + out_len_max, NULL);
> akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> tcrypt_complete, &result);
>
> @@ -1916,7 +1916,8 @@ static int do_test_rsa(struct crypto_akcipher *tfm,
> sg_init_one(&src, vecs->c, vecs->c_size);
> sg_init_one(&dst, outbuf_dec, out_len_max);
> init_completion(&result.completion);
> - akcipher_request_set_crypt(req, &src, &dst, vecs->c_size, out_len_max);
> + akcipher_request_set_crypt(req, &src, &dst, vecs->c_size, out_len_max,
> + NULL);
>
> /* Run RSA decrypt - m = c^d mod n;*/
> err = wait_async_op(&result, crypto_akcipher_decrypt(req));
> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> index 354de15cea6b..a59a6a0d6784 100644
> --- a/include/crypto/akcipher.h
> +++ b/include/crypto/akcipher.h
> @@ -27,6 +27,7 @@
> * result.
> * In case of error where the dst sgl size was insufficient,
> * it will be updated to the size required for the operation.
> + * @hash_algo: The hash algorithm used for sign/verify operations.
> * @__ctx: Start of private context data
> */
> struct akcipher_request {
> @@ -35,6 +36,7 @@ struct akcipher_request {
> struct scatterlist *dst;
> unsigned int src_len;
> unsigned int dst_len;
> + const char *hash_algo;
> void *__ctx[] CRYPTO_MINALIGN_ATTR;
> };
>
> @@ -241,17 +243,20 @@ static inline void akcipher_request_set_callback(struct akcipher_request *req,
> * @dst: ptr to output scatter list
> * @src_len: size of the src input scatter list to be processed
> * @dst_len: size of the dst output scatter list
> + * @hash_algo: The hash algorithm that was used for a signature (or NULL).
> */
> static inline void akcipher_request_set_crypt(struct akcipher_request *req,
> struct scatterlist *src,
> struct scatterlist *dst,
> unsigned int src_len,
> - unsigned int dst_len)
> + unsigned int dst_len,
> + const char *hash_algo)
> {
> req->src = src;
> req->dst = dst;
> req->src_len = src_len;
> req->dst_len = dst_len;
> + req->hash_algo = hash_algo;
> }
>
> /**
> diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
> index a1693ed77be6..80ab099a3edf 100644
> --- a/include/crypto/public_key.h
> +++ b/include/crypto/public_key.h
> @@ -91,6 +91,4 @@ extern struct key *x509_request_asymmetric_key(struct key *keyring,
> int public_key_verify_signature(const struct public_key *pkey,
> const struct public_key_signature *sig);
>
> -int rsa_verify_signature(const struct public_key *pkey,
> - const struct public_key_signature *sig);
> #endif /* _LINUX_PUBLIC_KEY_H */
> diff --git a/init/Kconfig b/init/Kconfig
> index 22320804fbaf..af4de4f1b02c 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -1757,9 +1757,9 @@ config SYSTEM_DATA_VERIFICATION
> select SYSTEM_TRUSTED_KEYRING
> select KEYS
> select CRYPTO
> + select CRYPTO_RSA
> select ASYMMETRIC_KEY_TYPE
> select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
> - select PUBLIC_KEY_ALGO_RSA
> select ASN1
> select OID_REGISTRY
> select X509_CERTIFICATE_PARSER
>


--
TS