linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: keyrings@vger.kernel.org
Cc: dhowells@redhat.com, linux-security-module@vger.kernel.org,
	zohar@linux.vnet.ibm.com, linux-kernel@vger.kernel.org,
	tadeusz.struk@intel.com
Subject: [PATCH 4/8] akcipher: Move the RSA DER encoding to the crypto layer
Date: Fri, 19 Feb 2016 17:18:36 +0000	[thread overview]
Message-ID: <20160219171836.17223.9507.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <20160219171806.17223.91381.stgit@warthog.procyon.org.uk>

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?

Signed-off-by: David Howells <dhowells@redhat.com>
---

 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@redhat.com)
- *
- * 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

  parent reply	other threads:[~2016-02-19 17:21 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-19 17:18 [PATCH 0/8] X.509: Software public key subtype changes David Howells
2016-02-19 17:18 ` [PATCH 1/8] crypto: KEYS: convert public key and digsig asym to the akcipher api David Howells
2016-02-19 17:18 ` [PATCH 2/8] integrity: convert digsig to " David Howells
2016-02-19 17:18 ` [PATCH 3/8] crypto: public_key: remove MPIs from public_key_signature struct David Howells
2016-02-19 17:18 ` David Howells [this message]
2016-02-22 19:59   ` [PATCH 4/8] akcipher: Move the RSA DER encoding to the crypto layer Tadeusz Struk
2016-02-22 22:28   ` David Howells
2016-02-22 23:35     ` Tadeusz Struk
2016-02-23  0:01     ` Andrew Zaborowski
2016-02-23 10:53     ` David Howells
2016-02-24 17:12       ` [PATCH 0/2] KEYS: Use pkcs1pad for padding in software_pkey Tadeusz Struk
2016-02-24 17:12         ` [PATCH 1/2] crypto: Add hash param to pkcs1pad Tadeusz Struk
2016-02-24 17:12         ` [PATCH 2/2] crypto: remove padding logic from rsa.c Tadeusz Struk
2016-02-27 18:40           ` Herbert Xu
2016-02-28  3:20             ` Tadeusz Struk
2016-02-26 14:00         ` David Howells
2016-02-26 15:02         ` David Howells
2016-02-24 17:28       ` [PATCH 0/2] KEYS: Use pkcs1pad for padding in software_pkey David Howells
2016-02-23 10:55     ` [PATCH 4/8] akcipher: Move the RSA DER encoding to the crypto layer David Howells
2016-02-23 11:25       ` Andrew Zaborowski
2016-02-26 11:42       ` David Howells
2016-02-24  5:04   ` Mimi Zohar
2016-02-24  5:59     ` Mimi Zohar
2016-02-29 15:37     ` David Howells
2016-02-19 17:18 ` [PATCH 5/8] X.509: Make algo identifiers text instead of enum David Howells
2016-02-19 17:18 ` [PATCH 6/8] X.509: Make the public_key asymmetric key type internal data private David Howells
2016-02-19 17:18 ` [PATCH 7/8] X.509: Rename public_key.c to software_pkey.c David Howells
2016-02-19 17:19 ` [PATCH 8/8] X.509: Rename public_key* to software_pkey* David Howells
2016-02-22 18:57 ` [PATCH 0/8] X.509: Software public key subtype changes Mimi Zohar
2016-02-22 19:59 ` Tadeusz Struk
2016-02-22 22:29 ` David Howells
2016-02-23  0:03   ` Mimi Zohar
2016-02-23 10:16   ` David Howells
2016-02-23 12:28     ` Mimi Zohar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160219171836.17223.9507.stgit@warthog.procyon.org.uk \
    --to=dhowells@redhat.com \
    --cc=keyrings@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=tadeusz.struk@intel.com \
    --cc=zohar@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).