summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-03-03 16:49:27 -0500
committerDavid Howells <dhowells@redhat.com>2016-03-03 16:49:27 -0500
commitd43de6c780a84def056afaf4fb3e66bdaa1efc00 (patch)
treef6221a2761cd7fbdb9c5bdc3e82b6dbfef90430a
parenta49de377e051eac5bc50a3b838614a05671da4e7 (diff)
akcipher: Move the RSA DER encoding check to the crypto layer
Move the RSA EMSA-PKCS1-v1_5 encoding from the asymmetric-key public_key subtype to the rsa crypto module's pkcs1pad template. This means that the public_key subtype no longer has any dependencies on public key type. To make this work, the following changes have been made: (1) The rsa pkcs1pad template is now used for RSA keys. This strips off the padding and returns just the message hash. (2) In a previous patch, the pkcs1pad template gained an optional second parameter that, if given, specifies the hash used. We now give this, and pkcs1pad checks the encoded message E(M) for the EMSA-PKCS1-v1_5 encoding and verifies that the correct digest OID is present. (3) 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. (4) 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 padding template? Should there be multiple padding templates registered that share most of the code? Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Tadeusz Struk <tadeusz.struk@intel.com> Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--crypto/asymmetric_keys/Kconfig7
-rw-r--r--crypto/asymmetric_keys/Makefile1
-rw-r--r--crypto/asymmetric_keys/public_key.c104
-rw-r--r--crypto/asymmetric_keys/rsa.c224
-rw-r--r--include/crypto/public_key.h2
-rw-r--r--init/Kconfig2
-rw-r--r--security/integrity/digsig_asymmetric.c1
7 files changed, 95 insertions, 246 deletions
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
12config ASYMMETRIC_PUBLIC_KEY_SUBTYPE 12config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
13 tristate "Asymmetric public-key crypto algorithm subtype" 13 tristate "Asymmetric public-key crypto algorithm subtype"
14 select MPILIB 14 select MPILIB
15 select PUBLIC_KEY_ALGO_RSA
16 select CRYPTO_HASH_INFO 15 select CRYPTO_HASH_INFO
17 help 16 help
18 This option provides support for asymmetric public key type handling. 17 This option provides support for asymmetric public key type handling.
@@ -20,12 +19,6 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
20 appropriate hash algorithms (such as SHA-1) must be available. 19 appropriate hash algorithms (such as SHA-1) must be available.
21 ENOPKG will be reported if the requisite algorithm is unavailable. 20 ENOPKG will be reported if the requisite algorithm is unavailable.
22 21
23config PUBLIC_KEY_ALGO_RSA
24 tristate "RSA public-key algorithm"
25 select CRYPTO_RSA
26 help
27 This option enables support for the RSA algorithm (PKCS#1, RFC3447).
28
29config X509_CERTIFICATE_PARSER 22config X509_CERTIFICATE_PARSER
30 tristate "X.509 certificate parser" 23 tristate "X.509 certificate parser"
31 depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE 24 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
7asymmetric_keys-y := asymmetric_type.o signature.o 7asymmetric_keys-y := asymmetric_type.o signature.o
8 8
9obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o 9obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
10obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
11 10
12# 11#
13# X.509 Certificate handling 12# X.509 Certificate handling
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index b383629b9e62..27ebc2f44394 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -17,8 +17,10 @@
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/seq_file.h> 19#include <linux/seq_file.h>
20#include <linux/scatterlist.h>
20#include <keys/asymmetric-subtype.h> 21#include <keys/asymmetric-subtype.h>
21#include <crypto/public_key.h> 22#include <crypto/public_key.h>
23#include <crypto/akcipher.h>
22 24
23MODULE_LICENSE("GPL"); 25MODULE_LICENSE("GPL");
24 26
@@ -35,12 +37,6 @@ const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = {
35}; 37};
36EXPORT_SYMBOL_GPL(pkey_id_type_name); 38EXPORT_SYMBOL_GPL(pkey_id_type_name);
37 39
38static int (*alg_verify[PKEY_ALGO__LAST])(const struct public_key *pkey,
39 const struct public_key_signature *sig) = {
40 NULL,
41 rsa_verify_signature
42};
43
44/* 40/*
45 * Provide a part of a description of the key for /proc/keys. 41 * Provide a part of a description of the key for /proc/keys.
46 */ 42 */
@@ -68,24 +64,110 @@ void public_key_destroy(void *payload)
68} 64}
69EXPORT_SYMBOL_GPL(public_key_destroy); 65EXPORT_SYMBOL_GPL(public_key_destroy);
70 66
67struct public_key_completion {
68 struct completion completion;
69 int err;
70};
71
72static void public_key_verify_done(struct crypto_async_request *req, int err)
73{
74 struct public_key_completion *compl = req->data;
75
76 if (err == -EINPROGRESS)
77 return;
78
79 compl->err = err;
80 complete(&compl->completion);
81}
82
71/* 83/*
72 * Verify a signature using a public key. 84 * Verify a signature using a public key.
73 */ 85 */
74int public_key_verify_signature(const struct public_key *pkey, 86int public_key_verify_signature(const struct public_key *pkey,
75 const struct public_key_signature *sig) 87 const struct public_key_signature *sig)
76{ 88{
89 struct public_key_completion compl;
90 struct crypto_akcipher *tfm;
91 struct akcipher_request *req;
92 struct scatterlist sig_sg, digest_sg;
93 const char *alg_name;
94 char alg_name_buf[CRYPTO_MAX_ALG_NAME];
95 void *output;
96 unsigned int outlen;
97 int ret = -ENOMEM;
98
99 pr_devel("==>%s()\n", __func__);
100
77 BUG_ON(!pkey); 101 BUG_ON(!pkey);
78 BUG_ON(!sig); 102 BUG_ON(!sig);
79 BUG_ON(!sig->digest); 103 BUG_ON(!sig->digest);
80 BUG_ON(!sig->s); 104 BUG_ON(!sig->s);
81 105
82 if (pkey->pkey_algo >= PKEY_ALGO__LAST) 106 alg_name = pkey_algo_name[sig->pkey_algo];
83 return -ENOPKG; 107 if (sig->pkey_algo == PKEY_ALGO_RSA) {
108 /* The data wangled by the RSA algorithm is typically padded
109 * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
110 * sec 8.2].
111 */
112 if (snprintf(alg_name_buf, CRYPTO_MAX_ALG_NAME,
113 "pkcs1pad(rsa,%s)",
114 hash_algo_name[sig->pkey_hash_algo]
115 ) >= CRYPTO_MAX_ALG_NAME)
116 return -EINVAL;
117 alg_name = alg_name_buf;
118 }
119
120 tfm = crypto_alloc_akcipher(alg_name, 0, 0);
121 if (IS_ERR(tfm))
122 return PTR_ERR(tfm);
123
124 req = akcipher_request_alloc(tfm, GFP_KERNEL);
125 if (!req)
126 goto error_free_tfm;
127
128 ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
129 if (ret)
130 goto error_free_req;
131
132 outlen = crypto_akcipher_maxsize(tfm);
133 output = kmalloc(outlen, GFP_KERNEL);
134 if (!output)
135 goto error_free_req;
136
137 sg_init_one(&sig_sg, sig->s, sig->s_size);
138 sg_init_one(&digest_sg, output, outlen);
139 akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size,
140 outlen);
141 init_completion(&compl.completion);
142 akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
143 CRYPTO_TFM_REQ_MAY_SLEEP,
144 public_key_verify_done, &compl);
145
146 /* Perform the verification calculation. This doesn't actually do the
147 * verification, but rather calculates the hash expected by the
148 * signature and returns that to us.
149 */
150 ret = crypto_akcipher_verify(req);
151 if (ret == -EINPROGRESS) {
152 wait_for_completion(&compl.completion);
153 ret = compl.err;
154 }
155 if (ret < 0)
156 goto out_free_output;
84 157
85 if (!alg_verify[pkey->pkey_algo]) 158 /* Do the actual verification step. */
86 return -ENOPKG; 159 if (req->dst_len != sig->digest_size ||
160 memcmp(sig->digest, output, sig->digest_size) != 0)
161 ret = -EKEYREJECTED;
87 162
88 return alg_verify[pkey->pkey_algo](pkey, sig); 163out_free_output:
164 kfree(output);
165error_free_req:
166 akcipher_request_free(req);
167error_free_tfm:
168 crypto_free_akcipher(tfm);
169 pr_devel("<==%s() = %d\n", __func__, ret);
170 return ret;
89} 171}
90EXPORT_SYMBOL_GPL(public_key_verify_signature); 172EXPORT_SYMBOL_GPL(public_key_verify_signature);
91 173
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 @@
1/* RSA asymmetric public-key algorithm [RFC3447]
2 *
3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#define pr_fmt(fmt) "RSA: "fmt
13#include <linux/module.h>
14#include <linux/slab.h>
15#include <crypto/akcipher.h>
16#include <crypto/public_key.h>
17#include <crypto/algapi.h>
18
19MODULE_LICENSE("GPL");
20MODULE_DESCRIPTION("RSA Public Key Algorithm");
21
22#define kenter(FMT, ...) \
23 pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
24#define kleave(FMT, ...) \
25 pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
26
27/*
28 * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
29 */
30static const u8 RSA_digest_info_MD5[] = {
31 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08,
32 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */
33 0x05, 0x00, 0x04, 0x10
34};
35
36static const u8 RSA_digest_info_SHA1[] = {
37 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
38 0x2B, 0x0E, 0x03, 0x02, 0x1A,
39 0x05, 0x00, 0x04, 0x14
40};
41
42static const u8 RSA_digest_info_RIPE_MD_160[] = {
43 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
44 0x2B, 0x24, 0x03, 0x02, 0x01,
45 0x05, 0x00, 0x04, 0x14
46};
47
48static const u8 RSA_digest_info_SHA224[] = {
49 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
50 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
51 0x05, 0x00, 0x04, 0x1C
52};
53
54static const u8 RSA_digest_info_SHA256[] = {
55 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
56 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
57 0x05, 0x00, 0x04, 0x20
58};
59
60static const u8 RSA_digest_info_SHA384[] = {
61 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
62 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
63 0x05, 0x00, 0x04, 0x30
64};
65
66static const u8 RSA_digest_info_SHA512[] = {
67 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
68 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
69 0x05, 0x00, 0x04, 0x40
70};
71
72static const struct {
73 const u8 *data;
74 size_t size;
75} RSA_ASN1_templates[PKEY_HASH__LAST] = {
76#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) }
77 [HASH_ALGO_MD5] = _(MD5),
78 [HASH_ALGO_SHA1] = _(SHA1),
79 [HASH_ALGO_RIPE_MD_160] = _(RIPE_MD_160),
80 [HASH_ALGO_SHA256] = _(SHA256),
81 [HASH_ALGO_SHA384] = _(SHA384),
82 [HASH_ALGO_SHA512] = _(SHA512),
83 [HASH_ALGO_SHA224] = _(SHA224),
84#undef _
85};
86
87struct rsa_completion {
88 struct completion completion;
89 int err;
90};
91
92/*
93 * Perform the RSA signature verification.
94 * @H: Value of hash of data and metadata
95 * @EM: The computed signature value
96 * @k: The size of EM (EM[0] is an invalid location but should hold 0x00)
97 * @hash_size: The size of H
98 * @asn1_template: The DigestInfo ASN.1 template
99 * @asn1_size: Size of asm1_template[]
100 */
101static int rsa_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
102 const u8 *asn1_template, size_t asn1_size)
103{
104 unsigned PS_end, T_offset, i;
105
106 kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size);
107
108 if (k < 2 + 1 + asn1_size + hash_size)
109 return -EBADMSG;
110
111 /* Decode the EMSA-PKCS1-v1_5
112 * note: leading zeros are stripped by the RSA implementation
113 */
114 if (EM[0] != 0x01) {
115 kleave(" = -EBADMSG [EM[0] == %02u]", EM[0]);
116 return -EBADMSG;
117 }
118
119 T_offset = k - (asn1_size + hash_size);
120 PS_end = T_offset - 1;
121 if (EM[PS_end] != 0x00) {
122 kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]);
123 return -EBADMSG;
124 }
125
126 for (i = 1; i < PS_end; i++) {
127 if (EM[i] != 0xff) {
128 kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]);
129 return -EBADMSG;
130 }
131 }
132
133 if (crypto_memneq(asn1_template, EM + T_offset, asn1_size) != 0) {
134 kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]");
135 return -EBADMSG;
136 }
137
138 if (crypto_memneq(H, EM + T_offset + asn1_size, hash_size) != 0) {
139 kleave(" = -EKEYREJECTED [EM[T] hash mismatch]");
140 return -EKEYREJECTED;
141 }
142
143 kleave(" = 0");
144 return 0;
145}
146
147static void public_key_verify_done(struct crypto_async_request *req, int err)
148{
149 struct rsa_completion *compl = req->data;
150
151 if (err == -EINPROGRESS)
152 return;
153
154 compl->err = err;
155 complete(&compl->completion);
156}
157
158int rsa_verify_signature(const struct public_key *pkey,
159 const struct public_key_signature *sig)
160{
161 struct crypto_akcipher *tfm;
162 struct akcipher_request *req;
163 struct rsa_completion compl;
164 struct scatterlist sig_sg, sg_out;
165 void *outbuf = NULL;
166 unsigned int outlen = 0;
167 int ret = -ENOMEM;
168
169 tfm = crypto_alloc_akcipher("rsa", 0, 0);
170 if (IS_ERR(tfm))
171 goto error_out;
172
173 req = akcipher_request_alloc(tfm, GFP_KERNEL);
174 if (!req)
175 goto error_free_tfm;
176
177 ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
178 if (ret)
179 goto error_free_req;
180
181 ret = -EINVAL;
182 outlen = crypto_akcipher_maxsize(tfm);
183 if (!outlen)
184 goto error_free_req;
185
186 /* Initialize the output buffer */
187 ret = -ENOMEM;
188 outbuf = kmalloc(outlen, GFP_KERNEL);
189 if (!outbuf)
190 goto error_free_req;
191
192 sg_init_one(&sig_sg, sig->s, sig->s_size);
193 sg_init_one(&sg_out, outbuf, outlen);
194 akcipher_request_set_crypt(req, &sig_sg, &sg_out, sig->s_size, outlen);
195 init_completion(&compl.completion);
196 akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
197 CRYPTO_TFM_REQ_MAY_SLEEP,
198 public_key_verify_done, &compl);
199
200 ret = crypto_akcipher_verify(req);
201 if (ret == -EINPROGRESS) {
202 wait_for_completion(&compl.completion);
203 ret = compl.err;
204 }
205
206 if (ret)
207 goto error_free_req;
208
209 /* Output from the operation is an encoded message (EM) of
210 * length k octets.
211 */
212 outlen = req->dst_len;
213 ret = rsa_verify(sig->digest, outbuf, outlen, sig->digest_size,
214 RSA_ASN1_templates[sig->pkey_hash_algo].data,
215 RSA_ASN1_templates[sig->pkey_hash_algo].size);
216error_free_req:
217 akcipher_request_free(req);
218error_free_tfm:
219 crypto_free_akcipher(tfm);
220error_out:
221 kfree(outbuf);
222 return ret;
223}
224EXPORT_SYMBOL_GPL(rsa_verify_signature);
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,
91int public_key_verify_signature(const struct public_key *pkey, 91int public_key_verify_signature(const struct public_key *pkey,
92 const struct public_key_signature *sig); 92 const struct public_key_signature *sig);
93 93
94int rsa_verify_signature(const struct public_key *pkey,
95 const struct public_key_signature *sig);
96#endif /* _LINUX_PUBLIC_KEY_H */ 94#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
1757 select SYSTEM_TRUSTED_KEYRING 1757 select SYSTEM_TRUSTED_KEYRING
1758 select KEYS 1758 select KEYS
1759 select CRYPTO 1759 select CRYPTO
1760 select CRYPTO_RSA
1760 select ASYMMETRIC_KEY_TYPE 1761 select ASYMMETRIC_KEY_TYPE
1761 select ASYMMETRIC_PUBLIC_KEY_SUBTYPE 1762 select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
1762 select PUBLIC_KEY_ALGO_RSA
1763 select ASN1 1763 select ASN1
1764 select OID_REGISTRY 1764 select OID_REGISTRY
1765 select X509_CERTIFICATE_PARSER 1765 select X509_CERTIFICATE_PARSER
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 2fa3bc681a1b..69a92e6db23d 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -103,6 +103,7 @@ int asymmetric_verify(struct key *keyring, const char *sig,
103 103
104 memset(&pks, 0, sizeof(pks)); 104 memset(&pks, 0, sizeof(pks));
105 105
106 pks.pkey_algo = PKEY_ALGO_RSA;
106 pks.pkey_hash_algo = hdr->hash_algo; 107 pks.pkey_hash_algo = hdr->hash_algo;
107 pks.digest = (u8 *)data; 108 pks.digest = (u8 *)data;
108 pks.digest_size = datalen; 109 pks.digest_size = datalen;