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 <[email protected]>
> ---
>
> 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 ([email protected])
> - *
> - * 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
Tadeusz Struk <[email protected]> wrote:
> 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)"?
Ummm... Possibly. Is that how it's used?
warthog>git grep pkcs1pad -- Documentation
warthog1>
Anyway, the problem I have with this is that I want to get that knowledge out
of the asymmetric key in-software public key subtype. It knows "rsa", "dsa",
"ecdsa", ... because that's all the OIDs tell it.
I guess if I have to, I can stoop to converting "rsa" to "pkcs1pad(rsa, sha1)".
Can you do me a really quick merge? -rc5 is already out, and I want to get it
to James pronto - plus I have things that are pending on this change being
made.
Oh - and how does the padding template find the algorithm DER encoding string
to use? I have wondered whether it should be stored in with the hash
algorithm, but it probably makes more sense to keep it with the rsa module.
David
On 02/22/2016 02:28 PM, David Howells wrote:
> Tadeusz Struk <[email protected]> wrote:
>
>> 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)"?
>
> Ummm... Possibly. Is that how it's used?
>
> warthog>git grep pkcs1pad -- Documentation
> warthog1>
Yes, no docs. Sorry.
>
> Anyway, the problem I have with this is that I want to get that knowledge out
> of the asymmetric key in-software public key subtype. It knows "rsa", "dsa",
> "ecdsa", ... because that's all the OIDs tell it.
Rigth, for now the public_key would need to build the full algorithm string as
follows:
vsprintf(name, "pkcs1pad(%s, %s)", pkey_algo_name[sig->pkey_algo],
hash_algo_name[sig->pkey_hash_algo]);
Do you plan to add more padding schemes later?
>
> I guess if I have to, I can stoop to converting "rsa" to "pkcs1pad(rsa, sha1)".
>
> Can you do me a really quick merge? -rc5 is already out, and I want to get it
> to James pronto - plus I have things that are pending on this change being
> made.
Yes, I can start woring on a subsequent patch based on your changes in
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-rsa
Is that ok with you?
>
> Oh - and how does the padding template find the algorithm DER encoding string
> to use? I have wondered whether it should be stored in with the hash
> algorithm, but it probably makes more sense to keep it with the rsa module.
We can put everything into the crypto/rsa-pkcs1pad.c
This is where all the padding logic should be, I think.
Thanks,
--
TS
Hi,
On 22 February 2016 at 23:28, David Howells <[email protected]> wrote:
> Tadeusz Struk <[email protected]> wrote:
>
>> 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.
I think that'd be a good thing to do.
>> Should we merge then and pass the hash param as a separate template param,
>> e.g the public_key would allocate "pkcs1pad(rsa, sha1)"?
>
> Ummm... Possibly. Is that how it's used?
Currently it only does the padding and doesn't care about the hash.
The input is expected to be the entire DigestInfo struct.
AIUI Tadeusz is proposing adding the hashing as a new feature. Note
though that the hash paremeter won't make sense for the encrypt,
decrypt or verify operations.
Also note that TLS 1.0 uses the padding to sign data that is not a
DigestInfo structure and even for 1.2 there are situations where
you'll be hashing the data yourself over some time and then you'll
want the algorithm to only do the padding and RSA signing.
Cheers
Tadeusz Struk <[email protected]> wrote:
> > Ummm... Possibly. Is that how it's used?
> >
> > warthog>git grep pkcs1pad -- Documentation
> > warthog1>
>
> Yes, no docs. Sorry.
Can I suggest you at least stick a quick usage summary in the banner comment
at the top of the file?
> > Anyway, the problem I have with this is that I want to get that knowledge
> > out of the asymmetric key in-software public key subtype. It knows "rsa",
> > "dsa", "ecdsa", ... because that's all the OIDs tell it.
>
> Rigth, for now the public_key would need to build the full algorithm string as
> follows:
>
> vsprintf(name, "pkcs1pad(%s, %s)", pkey_algo_name[sig->pkey_algo],
> hash_algo_name[sig->pkey_hash_algo]);
Does this apply to anything other than RSA?
> Do you plan to add more padding schemes later?
No plans to, but one never knows. I'm *assuming* that OID_rsaEncryption and
OID_sha256WithRSAEncryption, for example, must implicitly specify the padding
scheme (RFC4055 suggests I'm right in this assumption).
We might have to suppose RSASSA-SSP at some point.
> Yes, I can start woring on a subsequent patch based on your changes in
> http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-rsa
> Is that ok with you?
Sure.
David
Andrew Zaborowski <[email protected]> wrote:
> AIUI Tadeusz is proposing adding the hashing as a new feature. Note
> though that the hash paremeter won't make sense for the encrypt,
> decrypt or verify operations.
The hash parameter is necessary for the verify operation. From my
perspective, I want a verify operation that takes the signature, the message
hash and the hash name and gives me back an error code.
David
Hi David,
On 23 February 2016 at 11:55, David Howells <[email protected]> wrote:
> Andrew Zaborowski <[email protected]> wrote:
>
>> AIUI Tadeusz is proposing adding the hashing as a new feature. Note
>> though that the hash paremeter won't make sense for the encrypt,
>> decrypt or verify operations.
>
> The hash parameter is necessary for the verify operation. From my
> perspective, I want a verify operation that takes the signature, the message
> hash and the hash name and gives me back an error code.
>From the certificates point of view yes, but the akcipher API only has
the four operations each of which has one input buffer and out output
buffer.
Without overhauling akcipher you could modify pkcs1pad so that sign
takes the hash as input, adds the DER struct in front of it to build
the signature, and the verify operation could at most check that the
DER string matches the hash type and return the hash. But I think
RFC2437 suggests that you rather compare the signatures, not the
hashes.
Cheers
This adds hash param to pkcs1pad.
The pkcs1pad template can work with or without the hash.
When hash param is provided then the verify operation will
also verify the output against the known digest.
Signed-off-by: Tadeusz Struk <[email protected]>
---
crypto/rsa-pkcs1pad.c | 182 ++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 156 insertions(+), 26 deletions(-)
diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
index 50f5c97..1cea67d 100644
--- a/crypto/rsa-pkcs1pad.c
+++ b/crypto/rsa-pkcs1pad.c
@@ -18,12 +18,89 @@
#include <linux/module.h>
#include <linux/random.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;
+}
+
struct pkcs1pad_ctx {
struct crypto_akcipher *child;
-
+ const char *hash_name;
unsigned int key_size;
};
+struct pkcs1pad_inst_ctx {
+ struct crypto_akcipher_spawn spawn;
+ const char *hash_name;
+};
+
struct pkcs1pad_request {
struct akcipher_request child_req;
@@ -339,13 +416,22 @@ 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);
+ const struct rsa_asn1_template *digest_info = NULL;
int err;
- unsigned int ps_end;
+ unsigned int ps_end, digest_size = 0;
if (!ctx->key_size)
return -EINVAL;
- if (req->src_len > ctx->key_size - 11)
+ if (ctx->hash_name) {
+ digest_info = rsa_lookup_asn1(ctx->hash_name);
+ if (!digest_info)
+ return -EINVAL;
+
+ digest_size = digest_info->size;
+ }
+
+ if (req->src_len + digest_size > ctx->key_size - 11)
return -EOVERFLOW;
if (req->dst_len < ctx->key_size) {
@@ -371,11 +457,16 @@ static int pkcs1pad_sign(struct akcipher_request *req)
if (!req_ctx->in_buf)
return -ENOMEM;
- ps_end = ctx->key_size - req->src_len - 2;
+ ps_end = ctx->key_size - digest_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);
@@ -408,6 +499,7 @@ 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);
+ const struct rsa_asn1_template *digest_info;
unsigned int pos;
if (err == -EOVERFLOW)
@@ -422,20 +514,33 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
goto done;
}
- if (req_ctx->out_buf[0] != 0x01) {
- err = -EINVAL;
+ err = -EBADMSG;
+ if (req_ctx->out_buf[0] != 0x01)
goto done;
- }
+
for (pos = 1; pos < req_ctx->child_req.dst_len; pos++)
if (req_ctx->out_buf[pos] != 0xff)
break;
+
if (pos < 9 || pos == req_ctx->child_req.dst_len ||
- req_ctx->out_buf[pos] != 0x00) {
- err = -EINVAL;
+ req_ctx->out_buf[pos] != 0x00)
goto done;
- }
pos++;
+ if (ctx->hash_name) {
+ digest_info = rsa_lookup_asn1(ctx->hash_name);
+ if (!digest_info)
+ goto done;
+
+ if (memcmp(req_ctx->out_buf + pos, digest_info->data,
+ digest_info->size))
+ goto done;
+
+ pos += digest_info->size;
+ }
+
+ err = 0;
+
if (req->dst_len < req_ctx->child_req.dst_len - pos)
err = -EOVERFLOW;
req->dst_len = req_ctx->child_req.dst_len - pos;
@@ -444,7 +549,6 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
sg_copy_from_buffer(req->dst,
sg_nents_for_len(req->dst, req->dst_len),
req_ctx->out_buf + pos, req->dst_len);
-
done:
kzfree(req_ctx->out_buf);
@@ -481,7 +585,7 @@ static int pkcs1pad_verify(struct akcipher_request *req)
struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
int err;
- if (!ctx->key_size || req->src_len != ctx->key_size)
+ if (!ctx->key_size || req->src_len < ctx->key_size)
return -EINVAL;
if (ctx->key_size > PAGE_SIZE)
@@ -518,6 +622,7 @@ static int pkcs1pad_verify(struct akcipher_request *req)
static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm)
{
struct akcipher_instance *inst = akcipher_alg_instance(tfm);
+ struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst);
struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
struct crypto_akcipher *child_tfm;
@@ -526,7 +631,7 @@ static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm)
return PTR_ERR(child_tfm);
ctx->child = child_tfm;
-
+ ctx->hash_name = ictx->hash_name;
return 0;
}
@@ -539,10 +644,11 @@ static void pkcs1pad_exit_tfm(struct crypto_akcipher *tfm)
static void pkcs1pad_free(struct akcipher_instance *inst)
{
- struct crypto_akcipher_spawn *spawn = akcipher_instance_ctx(inst);
+ struct pkcs1pad_inst_ctx *ctx = akcipher_instance_ctx(inst);
+ struct crypto_akcipher_spawn *spawn = &ctx->spawn;
crypto_drop_akcipher(spawn);
-
+ kfree(ctx->hash_name);
kfree(inst);
}
@@ -550,9 +656,11 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
{
struct crypto_attr_type *algt;
struct akcipher_instance *inst;
+ struct pkcs1pad_inst_ctx *ctx;
struct crypto_akcipher_spawn *spawn;
struct akcipher_alg *rsa_alg;
const char *rsa_alg_name;
+ const char *hash_name;
int err;
algt = crypto_get_attr_type(tb);
@@ -566,11 +674,18 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
if (IS_ERR(rsa_alg_name))
return PTR_ERR(rsa_alg_name);
- inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+ hash_name = crypto_attr_alg_name(tb[2]);
+ if (IS_ERR(hash_name))
+ hash_name = NULL;
+
+ inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
if (!inst)
return -ENOMEM;
- spawn = akcipher_instance_ctx(inst);
+ ctx = akcipher_instance_ctx(inst);
+ spawn = &ctx->spawn;
+ ctx->hash_name = hash_name ? kstrdup(hash_name, GFP_KERNEL) : NULL;
+
crypto_set_spawn(&spawn->base, akcipher_crypto_instance(inst));
err = crypto_grab_akcipher(spawn, rsa_alg_name, 0,
crypto_requires_sync(algt->type, algt->mask));
@@ -580,15 +695,28 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
rsa_alg = crypto_spawn_akcipher_alg(spawn);
err = -ENAMETOOLONG;
- if (snprintf(inst->alg.base.cra_name,
- CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
- rsa_alg->base.cra_name) >=
- CRYPTO_MAX_ALG_NAME ||
- snprintf(inst->alg.base.cra_driver_name,
- CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
- rsa_alg->base.cra_driver_name) >=
- CRYPTO_MAX_ALG_NAME)
+
+ if (!hash_name) {
+ if (snprintf(inst->alg.base.cra_name,
+ CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
+ rsa_alg->base.cra_name) >=
+ CRYPTO_MAX_ALG_NAME ||
+ snprintf(inst->alg.base.cra_driver_name,
+ CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
+ rsa_alg->base.cra_driver_name) >=
+ CRYPTO_MAX_ALG_NAME)
goto out_drop_alg;
+ } else {
+ 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 ||
+ 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 out_free_hash;
+ }
inst->alg.base.cra_flags = rsa_alg->base.cra_flags & CRYPTO_ALG_ASYNC;
inst->alg.base.cra_priority = rsa_alg->base.cra_priority;
@@ -610,10 +738,12 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
err = akcipher_register_instance(tmpl, inst);
if (err)
- goto out_drop_alg;
+ goto out_free_hash;
return 0;
+out_free_hash:
+ kfree(ctx->hash_name);
out_drop_alg:
crypto_drop_akcipher(spawn);
out_free_inst:
Hi David,
I have converted the software_pkey to make use of the pkcs1pad
template. The rsa.c is reverted back to what it was i.e. just
math primitives and all padding is done in rsa-pkcs1padd.c
software_pkey.c just allocates pksc1padd(alg,hash)
This is incremental series on top of the current
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-rsa
---
Tadeusz Struk (2):
crypto: Add hash param to pkcs1pad
crypto: remove paddings logic from rsa.c
crypto/asymmetric_keys/software_pkey.c | 28 ++++
crypto/rsa-pkcs1pad.c | 182 ++++++++++++++++++++++++----
crypto/rsa.c | 210 +++++---------------------------
crypto/testmgr.c | 5 -
include/crypto/akcipher.h | 7 -
5 files changed, 212 insertions(+), 220 deletions(-)
This reverts back the rsa.c to do the math primitives only.
It also reverts the akcipher api changes as the hash param
will be passed to the rsa-pkcs1 template.
All padding and encoding logic is moved to the rsa-pkcs1pad.
The software_pkey.c uses pkcs1pad template to allocate the akcipher
and the hash param is passed via pksc1pad.
Signed-off-by: Tadeusz Struk <[email protected]>
---
crypto/asymmetric_keys/software_pkey.c | 28 ++++
crypto/rsa.c | 210 +++++---------------------------
crypto/testmgr.c | 5 -
include/crypto/akcipher.h | 7 -
4 files changed, 56 insertions(+), 194 deletions(-)
diff --git a/crypto/asymmetric_keys/software_pkey.c b/crypto/asymmetric_keys/software_pkey.c
index 8732a41..69693fd 100644
--- a/crypto/asymmetric_keys/software_pkey.c
+++ b/crypto/asymmetric_keys/software_pkey.c
@@ -75,6 +75,9 @@ int software_pkey_verify_signature(const struct software_pkey *pkey,
struct crypto_akcipher *tfm;
struct akcipher_request *req;
struct scatterlist sig_sg, digest_sg;
+ char alg_name[CRYPTO_MAX_ALG_NAME];
+ void *output;
+ unsigned int outlen;
int ret = -ENOMEM;
pr_devel("==>%s()\n", __func__);
@@ -84,7 +87,11 @@ int software_pkey_verify_signature(const struct software_pkey *pkey,
BUG_ON(!sig->digest);
BUG_ON(!sig->s);
- tfm = crypto_alloc_akcipher(sig->pkey_algo, 0, 0);
+ if (snprintf(alg_name, CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)",
+ sig->pkey_algo, sig->hash_algo) >= CRYPTO_MAX_ALG_NAME)
+ return -EINVAL;
+
+ tfm = crypto_alloc_akcipher(alg_name, 0, 0);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
@@ -96,11 +103,15 @@ int software_pkey_verify_signature(const struct software_pkey *pkey,
if (ret)
goto error_free_req;
+ outlen = crypto_akcipher_maxsize(tfm);
+ output = kmalloc(outlen, GFP_KERNEL);
+ if (!output)
+ 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,
- sig->hash_algo);
+ sg_init_one(&digest_sg, output, outlen);
+ akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size,
+ outlen);
init_completion(&compl.completion);
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP,
@@ -112,6 +123,13 @@ int software_pkey_verify_signature(const struct software_pkey *pkey,
ret = compl.err;
}
+ if (!ret) {
+ if (memcmp(sig->digest, output, sig->digest_size) ||
+ req->dst_len != sig->digest_size)
+ ret = -EBADMSG;
+ }
+
+ kfree(output);
error_free_req:
akcipher_request_free(req);
error_free_tfm:
diff --git a/crypto/rsa.c b/crypto/rsa.c
index 9a7c9ca..77d737f 100644
--- a/crypto/rsa.c
+++ b/crypto/rsa.c
@@ -16,78 +16,6 @@
#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;
*/
@@ -143,13 +71,6 @@ 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);
@@ -271,122 +192,44 @@ err_free_s:
return ret;
}
-static int rsa_verify_raw(struct akcipher_request *req, MPI EM)
+static int rsa_verify(struct akcipher_request *req)
{
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
const struct rsa_key *pkey = rsa_get_key(tfm);
- MPI s, m_calc;
- int ret;
+ MPI s, m = mpi_alloc(0);
+ int ret = 0;
+ int sign;
- m_calc = mpi_alloc(0);
- if (!m_calc)
+ if (!m)
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)
- goto err_free_m_calc;
+ if (!s) {
+ ret = -ENOMEM;
+ goto err_free_m;
+ }
- ret = _rsa_verify(pkey, m_calc, s);
+ ret = _rsa_verify(pkey, m, s);
if (ret)
goto err_free_s;
- ret = -EKEYREJECTED;
- if (mpi_cmp(m_calc, EM) != 0)
+ ret = mpi_write_to_sgl(m, req->dst, &req->dst_len, &sign);
+ if (ret)
goto err_free_s;
- ret = 0;
+ if (sign < 0)
+ ret = -EBADMSG;
+
err_free_s:
mpi_free(s);
-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);
+err_free_m:
+ mpi_free(m);
return ret;
}
@@ -439,6 +282,13 @@ 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);
@@ -450,7 +300,7 @@ static struct akcipher_alg rsa = {
.encrypt = rsa_enc,
.decrypt = rsa_dec,
.sign = rsa_sign,
- .verify = rsa_verify_encoded,
+ .verify = rsa_verify,
.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 94879a3..ae8c57fd 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, NULL);
+ out_len_max);
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
tcrypt_complete, &result);
@@ -1916,8 +1916,7 @@ 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,
- NULL);
+ akcipher_request_set_crypt(req, &src, &dst, vecs->c_size, out_len_max);
/* 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 a59a6a0..354de15 100644
--- a/include/crypto/akcipher.h
+++ b/include/crypto/akcipher.h
@@ -27,7 +27,6 @@
* 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 {
@@ -36,7 +35,6 @@ struct akcipher_request {
struct scatterlist *dst;
unsigned int src_len;
unsigned int dst_len;
- const char *hash_algo;
void *__ctx[] CRYPTO_MINALIGN_ATTR;
};
@@ -243,20 +241,17 @@ 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,
- const char *hash_algo)
+ unsigned int dst_len)
{
req->src = src;
req->dst = dst;
req->src_len = src_len;
req->dst_len = dst_len;
- req->hash_algo = hash_algo;
}
/**
Tadeusz Struk <[email protected]> wrote:
> I have converted the software_pkey to make use of the pkcs1pad
> template. The rsa.c is reverted back to what it was i.e. just
> math primitives and all padding is done in rsa-pkcs1padd.c
> software_pkey.c just allocates pksc1padd(alg,hash)
Okay, thanks - I'll take a look at that later.
One thought that just occurred to me: would it make sense to make a second
crypto template in rsa-pkcs1pad.c and call it "rsassa-pkcs1-v1_5" that does
this padding variant? It can share most of its code with the generic pkcs1pad
algorithm.
We could then also add a third variant "rsassa-pss" at a later date.
David
Andrew Zaborowski <[email protected]> wrote:
> Without overhauling akcipher you could modify pkcs1pad so that sign
> takes the hash as input, adds the DER struct in front of it to build
> the signature, and the verify operation could at most check that the
> DER string matches the hash type and return the hash. But I think
> RFC2437 suggests that you rather compare the signatures, not the
> hashes.
Whilst that is true about what RFC2437 shows, I wonder how strict it wants to
be about that rather than it just being a convenient way of describing the
algorithm.
The advantage of doing it the way the RFC suggests is that you get to use the
EMSA-PKCS1-V1_5-ENCODE operation twice, thereby saving code and only having
one place for bugs to occur instead of two - but you can argue this either
way.
That said, I would be okay with it returning just the message hash with the
padding stripped off, providing the padding is validated in the crypto layer,
if that's necessary.
David
Tadeusz Struk <[email protected]> wrote:
> + if (memcmp(sig->digest, output, sig->digest_size) ||
I've added " != 0" after the memcmp().
> + req->dst_len != sig->digest_size)
> + ret = -EBADMSG;
Btw, this has to be -EKEYREJECTED; -EBADMSG would indicate that the container
is unparseable. I wonder if we should propose a -ESIGREJECTED error...
David
Tadeusz Struk <[email protected]> wrote:
> + if (memcmp(sig->digest, output, sig->digest_size) ||
> + req->dst_len != sig->digest_size)
You must always do the size check first!
David
Tadeusz Struk <[email protected]> wrote:
>
> diff --git a/crypto/rsa.c b/crypto/rsa.c
> index 9a7c9ca..77d737f 100644
> --- a/crypto/rsa.c
> +++ b/crypto/rsa.c
> @@ -16,78 +16,6 @@
> #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
> -};
Where did this come from? It's not in my tree.
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Hi Herbert,
On 02/27/2016 10:40 AM, Herbert Xu wrote:
> Tadeusz Struk <[email protected]> wrote:
>>
>> diff --git a/crypto/rsa.c b/crypto/rsa.c
>> index 9a7c9ca..77d737f 100644
>> --- a/crypto/rsa.c
>> +++ b/crypto/rsa.c
>> @@ -16,78 +16,6 @@
>> #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
>> -};
>
> Where did this come from? It's not in my tree.
These are generated on top of
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-rsa
Thanks,
--
TS