aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2014-07-22 16:52:33 -0400
committerDavid Howells <dhowells@redhat.com>2014-07-22 16:53:21 -0400
commit1ca72c96dbad332ebd89b5756640f881ff0e6e9e (patch)
treee256d23f3ed8217b18bd36e78fdda242954d2d60
parenta19e3c22b34ae599eafd9fd05c887fc8e7ec2e3a (diff)
parent22d01afb210ff77fc480a1fc531cd59a4f32157a (diff)
Merge tag 'keys-pkcs7-20140708' into keys-next
Here's a set of changes that implement a PKCS#7 message parser in the kernel. The PKCS#7 message parsing will then be used to limit kexec to authenticated kernels only if so configured. The changes provide the following facilities: (1) Parse an ASN.1 PKCS#7 message and pick out useful bits such as the data content and the X.509 certificates used to sign it and all the data signatures. (2) Verify all the data signatures against the set of X.509 certificates available in the message. (3) Follow the certificate chains and verify that: (a) for every self-signed X.509 certificate, check that it validly signed itself, and: (b) for every non-self-signed certificate, if we have a 'parent' certificate, the former is validly signed by the latter. (4) Look for intersections between the certificate chains and the trusted keyring, if any intersections are found, verify that the trusted certificates signed the intersection point in the chain. (5) For testing purposes, a key type can be made available that will take a PKCS#7 message, check that the message is trustworthy, and if so, add its data content into the key. Note that (5) has to be altered to take account of the preparsing patches already committed to this branch. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--crypto/asymmetric_keys/Kconfig22
-rw-r--r--crypto/asymmetric_keys/Makefile22
-rw-r--r--crypto/asymmetric_keys/pkcs7.asn1127
-rw-r--r--crypto/asymmetric_keys/pkcs7_key_type.c99
-rw-r--r--crypto/asymmetric_keys/pkcs7_parser.c396
-rw-r--r--crypto/asymmetric_keys/pkcs7_parser.h61
-rw-r--r--crypto/asymmetric_keys/pkcs7_trust.c219
-rw-r--r--crypto/asymmetric_keys/pkcs7_verify.c323
-rw-r--r--crypto/asymmetric_keys/x509.asn12
-rw-r--r--crypto/asymmetric_keys/x509_cert_parser.c20
-rw-r--r--crypto/asymmetric_keys/x509_parser.h13
-rw-r--r--include/crypto/pkcs7.h36
-rw-r--r--include/linux/oid_registry.h1
13 files changed, 1339 insertions, 2 deletions
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 03a6eb95ab50..b6df198d1b6f 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -37,4 +37,26 @@ config X509_CERTIFICATE_PARSER
37 data and provides the ability to instantiate a crypto key from a 37 data and provides the ability to instantiate a crypto key from a
38 public key packet found inside the certificate. 38 public key packet found inside the certificate.
39 39
40config PKCS7_MESSAGE_PARSER
41 tristate "PKCS#7 message parser"
42 depends on X509_CERTIFICATE_PARSER
43 select ASN1
44 select OID_REGISTRY
45 help
46 This option provides support for parsing PKCS#7 format messages for
47 signature data and provides the ability to verify the signature.
48
49config PKCS7_TEST_KEY
50 tristate "PKCS#7 testing key type"
51 depends on PKCS7_MESSAGE_PARSER
52 select SYSTEM_TRUSTED_KEYRING
53 help
54 This option provides a type of key that can be loaded up from a
55 PKCS#7 message - provided the message is signed by a trusted key. If
56 it is, the PKCS#7 wrapper is discarded and reading the key returns
57 just the payload. If it isn't, adding the key will fail with an
58 error.
59
60 This is intended for testing the PKCS#7 parser.
61
40endif # ASYMMETRIC_KEY_TYPE 62endif # ASYMMETRIC_KEY_TYPE
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index 0727204aab68..92d0e9af24d5 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -25,3 +25,25 @@ $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
25 25
26clean-files += x509-asn1.c x509-asn1.h 26clean-files += x509-asn1.c x509-asn1.h
27clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h 27clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
28
29#
30# PKCS#7 message handling
31#
32obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o
33pkcs7_message-y := \
34 pkcs7-asn1.o \
35 pkcs7_parser.o \
36 pkcs7_trust.o \
37 pkcs7_verify.o
38
39$(obj)/pkcs7_parser.o: $(obj)/pkcs7-asn1.h
40$(obj)/pkcs7-asn1.o: $(obj)/pkcs7-asn1.c $(obj)/pkcs7-asn1.h
41
42clean-files += pkcs7-asn1.c pkcs7-asn1.h
43
44#
45# PKCS#7 parser testing key
46#
47obj-$(CONFIG_PKCS7_TEST_KEY) += pkcs7_test_key.o
48pkcs7_test_key-y := \
49 pkcs7_key_type.o
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1
new file mode 100644
index 000000000000..a5a14ef28c86
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs7.asn1
@@ -0,0 +1,127 @@
1PKCS7ContentInfo ::= SEQUENCE {
2 contentType ContentType,
3 content [0] EXPLICIT SignedData OPTIONAL
4}
5
6ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID })
7
8SignedData ::= SEQUENCE {
9 version INTEGER,
10 digestAlgorithms DigestAlgorithmIdentifiers,
11 contentInfo ContentInfo,
12 certificates CHOICE {
13 certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
14 certSequence [2] IMPLICIT Certificates
15 } OPTIONAL ({ pkcs7_note_certificate_list }),
16 crls CHOICE {
17 crlSet [1] IMPLICIT CertificateRevocationLists,
18 crlSequence [3] IMPLICIT CRLSequence
19 } OPTIONAL,
20 signerInfos SignerInfos
21}
22
23ContentInfo ::= SEQUENCE {
24 contentType ContentType,
25 content [0] EXPLICIT Data OPTIONAL
26}
27
28Data ::= ANY ({ pkcs7_note_data })
29
30DigestAlgorithmIdentifiers ::= CHOICE {
31 daSet SET OF DigestAlgorithmIdentifier,
32 daSequence SEQUENCE OF DigestAlgorithmIdentifier
33}
34
35DigestAlgorithmIdentifier ::= SEQUENCE {
36 algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
37 parameters ANY OPTIONAL
38}
39
40--
41-- Certificates and certificate lists
42--
43ExtendedCertificatesAndCertificates ::= SET OF ExtendedCertificateOrCertificate
44
45ExtendedCertificateOrCertificate ::= CHOICE {
46 certificate Certificate, -- X.509
47 extendedCertificate [0] IMPLICIT ExtendedCertificate -- PKCS#6
48}
49
50ExtendedCertificate ::= Certificate -- cheating
51
52Certificates ::= SEQUENCE OF Certificate
53
54CertificateRevocationLists ::= SET OF CertificateList
55
56CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly
57
58CRLSequence ::= SEQUENCE OF CertificateList
59
60Certificate ::= ANY ({ pkcs7_extract_cert }) -- X.509
61
62--
63-- Signer information
64--
65SignerInfos ::= CHOICE {
66 siSet SET OF SignerInfo,
67 siSequence SEQUENCE OF SignerInfo
68}
69
70SignerInfo ::= SEQUENCE {
71 version INTEGER,
72 issuerAndSerialNumber IssuerAndSerialNumber,
73 digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }),
74 authenticatedAttributes CHOICE {
75 aaSet [0] IMPLICIT SetOfAuthenticatedAttribute
76 ({ pkcs7_sig_note_set_of_authattrs }),
77 aaSequence [2] EXPLICIT SEQUENCE OF AuthenticatedAttribute
78 -- Explicit because easier to compute digest on
79 -- sequence of attributes and then reuse encoded
80 -- sequence in aaSequence.
81 } OPTIONAL,
82 digestEncryptionAlgorithm
83 DigestEncryptionAlgorithmIdentifier ({ pkcs7_sig_note_pkey_algo }),
84 encryptedDigest EncryptedDigest,
85 unauthenticatedAttributes CHOICE {
86 uaSet [1] IMPLICIT SET OF UnauthenticatedAttribute,
87 uaSequence [3] IMPLICIT SEQUENCE OF UnauthenticatedAttribute
88 } OPTIONAL
89} ({ pkcs7_note_signed_info })
90
91IssuerAndSerialNumber ::= SEQUENCE {
92 issuer Name ({ pkcs7_sig_note_issuer }),
93 serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial })
94}
95
96CertificateSerialNumber ::= INTEGER
97
98SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute
99
100AuthenticatedAttribute ::= SEQUENCE {
101 type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
102 values SET OF ANY ({ pkcs7_sig_note_authenticated_attr })
103}
104
105UnauthenticatedAttribute ::= SEQUENCE {
106 type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
107 values SET OF ANY
108}
109
110DigestEncryptionAlgorithmIdentifier ::= SEQUENCE {
111 algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
112 parameters ANY OPTIONAL
113}
114
115EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature })
116
117---
118--- X.500 Name
119---
120Name ::= SEQUENCE OF RelativeDistinguishedName
121
122RelativeDistinguishedName ::= SET OF AttributeValueAssertion
123
124AttributeValueAssertion ::= SEQUENCE {
125 attributeType OBJECT IDENTIFIER ({ pkcs7_note_OID }),
126 attributeValue ANY
127}
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c
new file mode 100644
index 000000000000..c2091f7bd15d
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -0,0 +1,99 @@
1/* Testing module to load key from trusted PKCS#7 message
2 *
3 * Copyright (C) 2014 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) "PKCS7key: "fmt
13#include <linux/key.h>
14#include <linux/key-type.h>
15#include <crypto/pkcs7.h>
16#include <keys/user-type.h>
17#include <keys/system_keyring.h>
18#include "pkcs7_parser.h"
19
20/*
21 * Preparse a PKCS#7 wrapped and validated data blob.
22 */
23static int pkcs7_preparse(struct key_preparsed_payload *prep)
24{
25 struct pkcs7_message *pkcs7;
26 const void *data, *saved_prep_data;
27 size_t datalen, saved_prep_datalen;
28 bool trusted;
29 int ret;
30
31 kenter("");
32
33 saved_prep_data = prep->data;
34 saved_prep_datalen = prep->datalen;
35 pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
36 if (IS_ERR(pkcs7)) {
37 ret = PTR_ERR(pkcs7);
38 goto error;
39 }
40
41 ret = pkcs7_verify(pkcs7);
42 if (ret < 0)
43 goto error_free;
44
45 ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
46 if (ret < 0)
47 goto error_free;
48 if (!trusted)
49 pr_warn("PKCS#7 message doesn't chain back to a trusted key\n");
50
51 ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false);
52 if (ret < 0)
53 goto error_free;
54
55 prep->data = data;
56 prep->datalen = datalen;
57 ret = user_preparse(prep);
58 prep->data = saved_prep_data;
59 prep->datalen = saved_prep_datalen;
60
61error_free:
62 pkcs7_free_message(pkcs7);
63error:
64 kleave(" = %d", ret);
65 return ret;
66}
67
68/*
69 * user defined keys take an arbitrary string as the description and an
70 * arbitrary blob of data as the payload
71 */
72struct key_type key_type_pkcs7 = {
73 .name = "pkcs7_test",
74 .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
75 .preparse = pkcs7_preparse,
76 .free_preparse = user_free_preparse,
77 .instantiate = generic_key_instantiate,
78 .match = user_match,
79 .revoke = user_revoke,
80 .destroy = user_destroy,
81 .describe = user_describe,
82 .read = user_read,
83};
84
85/*
86 * Module stuff
87 */
88static int __init pkcs7_key_init(void)
89{
90 return register_key_type(&key_type_pkcs7);
91}
92
93static void __exit pkcs7_key_cleanup(void)
94{
95 unregister_key_type(&key_type_pkcs7);
96}
97
98module_init(pkcs7_key_init);
99module_exit(pkcs7_key_cleanup);
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
new file mode 100644
index 000000000000..42e56aa7d277
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -0,0 +1,396 @@
1/* PKCS#7 parser
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) "PKCS7: "fmt
13#include <linux/kernel.h>
14#include <linux/export.h>
15#include <linux/slab.h>
16#include <linux/err.h>
17#include <linux/oid_registry.h>
18#include "public_key.h"
19#include "pkcs7_parser.h"
20#include "pkcs7-asn1.h"
21
22struct pkcs7_parse_context {
23 struct pkcs7_message *msg; /* Message being constructed */
24 struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */
25 struct pkcs7_signed_info **ppsinfo;
26 struct x509_certificate *certs; /* Certificate cache */
27 struct x509_certificate **ppcerts;
28 unsigned long data; /* Start of data */
29 enum OID last_oid; /* Last OID encountered */
30 unsigned x509_index;
31 unsigned sinfo_index;
32};
33
34/**
35 * pkcs7_free_message - Free a PKCS#7 message
36 * @pkcs7: The PKCS#7 message to free
37 */
38void pkcs7_free_message(struct pkcs7_message *pkcs7)
39{
40 struct x509_certificate *cert;
41 struct pkcs7_signed_info *sinfo;
42
43 if (pkcs7) {
44 while (pkcs7->certs) {
45 cert = pkcs7->certs;
46 pkcs7->certs = cert->next;
47 x509_free_certificate(cert);
48 }
49 while (pkcs7->crl) {
50 cert = pkcs7->crl;
51 pkcs7->crl = cert->next;
52 x509_free_certificate(cert);
53 }
54 while (pkcs7->signed_infos) {
55 sinfo = pkcs7->signed_infos;
56 pkcs7->signed_infos = sinfo->next;
57 mpi_free(sinfo->sig.mpi[0]);
58 kfree(sinfo->sig.digest);
59 kfree(sinfo);
60 }
61 kfree(pkcs7);
62 }
63}
64EXPORT_SYMBOL_GPL(pkcs7_free_message);
65
66/**
67 * pkcs7_parse_message - Parse a PKCS#7 message
68 * @data: The raw binary ASN.1 encoded message to be parsed
69 * @datalen: The size of the encoded message
70 */
71struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
72{
73 struct pkcs7_parse_context *ctx;
74 struct pkcs7_message *msg;
75 long ret;
76
77 ret = -ENOMEM;
78 msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
79 if (!msg)
80 goto error_no_sig;
81 ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
82 if (!ctx)
83 goto error_no_ctx;
84 ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
85 if (!ctx->sinfo)
86 goto error_no_sinfo;
87
88 ctx->msg = msg;
89 ctx->data = (unsigned long)data;
90 ctx->ppcerts = &ctx->certs;
91 ctx->ppsinfo = &ctx->msg->signed_infos;
92
93 /* Attempt to decode the signature */
94 ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
95 if (ret < 0)
96 goto error_decode;
97
98 while (ctx->certs) {
99 struct x509_certificate *cert = ctx->certs;
100 ctx->certs = cert->next;
101 x509_free_certificate(cert);
102 }
103 mpi_free(ctx->sinfo->sig.mpi[0]);
104 kfree(ctx->sinfo->sig.digest);
105 kfree(ctx->sinfo);
106 kfree(ctx);
107 return msg;
108
109error_decode:
110 mpi_free(ctx->sinfo->sig.mpi[0]);
111 kfree(ctx->sinfo->sig.digest);
112 kfree(ctx->sinfo);
113error_no_sinfo:
114 kfree(ctx);
115error_no_ctx:
116 pkcs7_free_message(msg);
117error_no_sig:
118 return ERR_PTR(ret);
119}
120EXPORT_SYMBOL_GPL(pkcs7_parse_message);
121
122/**
123 * pkcs7_get_content_data - Get access to the PKCS#7 content
124 * @pkcs7: The preparsed PKCS#7 message to access
125 * @_data: Place to return a pointer to the data
126 * @_data_len: Place to return the data length
127 * @want_wrapper: True if the ASN.1 object header should be included in the data
128 *
129 * Get access to the data content of the PKCS#7 message, including, optionally,
130 * the header of the ASN.1 object that contains it. Returns -ENODATA if the
131 * data object was missing from the message.
132 */
133int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
134 const void **_data, size_t *_data_len,
135 bool want_wrapper)
136{
137 size_t wrapper;
138
139 if (!pkcs7->data)
140 return -ENODATA;
141
142 wrapper = want_wrapper ? pkcs7->data_hdrlen : 0;
143 *_data = pkcs7->data - wrapper;
144 *_data_len = pkcs7->data_len + wrapper;
145 return 0;
146}
147EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
148
149/*
150 * Note an OID when we find one for later processing when we know how
151 * to interpret it.
152 */
153int pkcs7_note_OID(void *context, size_t hdrlen,
154 unsigned char tag,
155 const void *value, size_t vlen)
156{
157 struct pkcs7_parse_context *ctx = context;
158
159 ctx->last_oid = look_up_OID(value, vlen);
160 if (ctx->last_oid == OID__NR) {
161 char buffer[50];
162 sprint_oid(value, vlen, buffer, sizeof(buffer));
163 printk("PKCS7: Unknown OID: [%lu] %s\n",
164 (unsigned long)value - ctx->data, buffer);
165 }
166 return 0;
167}
168
169/*
170 * Note the digest algorithm for the signature.
171 */
172int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
173 unsigned char tag,
174 const void *value, size_t vlen)
175{
176 struct pkcs7_parse_context *ctx = context;
177
178 switch (ctx->last_oid) {
179 case OID_md4:
180 ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4;
181 break;
182 case OID_md5:
183 ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5;
184 break;
185 case OID_sha1:
186 ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1;
187 break;
188 case OID_sha256:
189 ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256;
190 break;
191 default:
192 printk("Unsupported digest algo: %u\n", ctx->last_oid);
193 return -ENOPKG;
194 }
195 return 0;
196}
197
198/*
199 * Note the public key algorithm for the signature.
200 */
201int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
202 unsigned char tag,
203 const void *value, size_t vlen)
204{
205 struct pkcs7_parse_context *ctx = context;
206
207 switch (ctx->last_oid) {
208 case OID_rsaEncryption:
209 ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA;
210 break;
211 default:
212 printk("Unsupported pkey algo: %u\n", ctx->last_oid);
213 return -ENOPKG;
214 }
215 return 0;
216}
217
218/*
219 * Extract a certificate and store it in the context.
220 */
221int pkcs7_extract_cert(void *context, size_t hdrlen,
222 unsigned char tag,
223 const void *value, size_t vlen)
224{
225 struct pkcs7_parse_context *ctx = context;
226 struct x509_certificate *x509;
227
228 if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) {
229 pr_debug("Cert began with tag %02x at %lu\n",
230 tag, (unsigned long)ctx - ctx->data);
231 return -EBADMSG;
232 }
233
234 /* We have to correct for the header so that the X.509 parser can start
235 * from the beginning. Note that since X.509 stipulates DER, there
236 * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which
237 * stipulates BER).
238 */
239 value -= hdrlen;
240 vlen += hdrlen;
241
242 if (((u8*)value)[1] == 0x80)
243 vlen += 2; /* Indefinite length - there should be an EOC */
244
245 x509 = x509_cert_parse(value, vlen);
246 if (IS_ERR(x509))
247 return PTR_ERR(x509);
248
249 pr_debug("Got cert for %s\n", x509->subject);
250 pr_debug("- fingerprint %s\n", x509->fingerprint);
251
252 x509->index = ++ctx->x509_index;
253 *ctx->ppcerts = x509;
254 ctx->ppcerts = &x509->next;
255 return 0;
256}
257
258/*
259 * Save the certificate list
260 */
261int pkcs7_note_certificate_list(void *context, size_t hdrlen,
262 unsigned char tag,
263 const void *value, size_t vlen)
264{
265 struct pkcs7_parse_context *ctx = context;
266
267 pr_devel("Got cert list (%02x)\n", tag);
268
269 *ctx->ppcerts = ctx->msg->certs;
270 ctx->msg->certs = ctx->certs;
271 ctx->certs = NULL;
272 ctx->ppcerts = &ctx->certs;
273 return 0;
274}
275
276/*
277 * Extract the data from the message and store that and its content type OID in
278 * the context.
279 */
280int pkcs7_note_data(void *context, size_t hdrlen,
281 unsigned char tag,
282 const void *value, size_t vlen)
283{
284 struct pkcs7_parse_context *ctx = context;
285
286 pr_debug("Got data\n");
287
288 ctx->msg->data = value;
289 ctx->msg->data_len = vlen;
290 ctx->msg->data_hdrlen = hdrlen;
291 ctx->msg->data_type = ctx->last_oid;
292 return 0;
293}
294
295/*
296 * Parse authenticated attributes
297 */
298int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen,
299 unsigned char tag,
300 const void *value, size_t vlen)
301{
302 struct pkcs7_parse_context *ctx = context;
303
304 pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
305
306 switch (ctx->last_oid) {
307 case OID_messageDigest:
308 if (tag != ASN1_OTS)
309 return -EBADMSG;
310 ctx->sinfo->msgdigest = value;
311 ctx->sinfo->msgdigest_len = vlen;
312 return 0;
313 default:
314 return 0;
315 }
316}
317
318/*
319 * Note the set of auth attributes for digestion purposes [RFC2315 9.3]
320 */
321int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
322 unsigned char tag,
323 const void *value, size_t vlen)
324{
325 struct pkcs7_parse_context *ctx = context;
326
327 /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
328 ctx->sinfo->authattrs = value - (hdrlen - 1);
329 ctx->sinfo->authattrs_len = vlen + (hdrlen - 1);
330 return 0;
331}
332
333/*
334 * Note the issuing certificate serial number
335 */
336int pkcs7_sig_note_serial(void *context, size_t hdrlen,
337 unsigned char tag,
338 const void *value, size_t vlen)
339{
340 struct pkcs7_parse_context *ctx = context;
341 ctx->sinfo->raw_serial = value;
342 ctx->sinfo->raw_serial_size = vlen;
343 return 0;
344}
345
346/*
347 * Note the issuer's name
348 */
349int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
350 unsigned char tag,
351 const void *value, size_t vlen)
352{
353 struct pkcs7_parse_context *ctx = context;
354 ctx->sinfo->raw_issuer = value;
355 ctx->sinfo->raw_issuer_size = vlen;
356 return 0;
357}
358
359/*
360 * Note the signature data
361 */
362int pkcs7_sig_note_signature(void *context, size_t hdrlen,
363 unsigned char tag,
364 const void *value, size_t vlen)
365{
366 struct pkcs7_parse_context *ctx = context;
367 MPI mpi;
368
369 BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA);
370
371 mpi = mpi_read_raw_data(value, vlen);
372 if (!mpi)
373 return -ENOMEM;
374
375 ctx->sinfo->sig.mpi[0] = mpi;
376 ctx->sinfo->sig.nr_mpi = 1;
377 return 0;
378}
379
380/*
381 * Note a signature information block
382 */
383int pkcs7_note_signed_info(void *context, size_t hdrlen,
384 unsigned char tag,
385 const void *value, size_t vlen)
386{
387 struct pkcs7_parse_context *ctx = context;
388
389 ctx->sinfo->index = ++ctx->sinfo_index;
390 *ctx->ppsinfo = ctx->sinfo;
391 ctx->ppsinfo = &ctx->sinfo->next;
392 ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
393 if (!ctx->sinfo)
394 return -ENOMEM;
395 return 0;
396}
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
new file mode 100644
index 000000000000..d25f4d15370f
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs7_parser.h
@@ -0,0 +1,61 @@
1/* PKCS#7 crypto data parser internal definitions
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#include <linux/oid_registry.h>
13#include <crypto/pkcs7.h>
14#include "x509_parser.h"
15
16#define kenter(FMT, ...) \
17 pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
18#define kleave(FMT, ...) \
19 pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
20
21struct pkcs7_signed_info {
22 struct pkcs7_signed_info *next;
23 struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
24 unsigned index;
25 bool trusted;
26
27 /* Message digest - the digest of the Content Data (or NULL) */
28 const void *msgdigest;
29 unsigned msgdigest_len;
30
31 /* Authenticated Attribute data (or NULL) */
32 unsigned authattrs_len;
33 const void *authattrs;
34
35 /* Issuing cert serial number and issuer's name */
36 const void *raw_serial;
37 unsigned raw_serial_size;
38 unsigned raw_issuer_size;
39 const void *raw_issuer;
40
41 /* Message signature.
42 *
43 * This contains the generated digest of _either_ the Content Data or
44 * the Authenticated Attributes [RFC2315 9.3]. If the latter, one of
45 * the attributes contains the digest of the the Content Data within
46 * it.
47 */
48 struct public_key_signature sig;
49};
50
51struct pkcs7_message {
52 struct x509_certificate *certs; /* Certificate list */
53 struct x509_certificate *crl; /* Revocation list */
54 struct pkcs7_signed_info *signed_infos;
55
56 /* Content Data (or NULL) */
57 enum OID data_type; /* Type of Data */
58 size_t data_len; /* Length of Data */
59 size_t data_hdrlen; /* Length of Data ASN.1 header */
60 const void *data; /* Content Data (or 0) */
61};
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
new file mode 100644
index 000000000000..b6b045131403
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -0,0 +1,219 @@
1/* Validate the trust chain of a PKCS#7 message.
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) "PKCS7: "fmt
13#include <linux/kernel.h>
14#include <linux/export.h>
15#include <linux/slab.h>
16#include <linux/err.h>
17#include <linux/asn1.h>
18#include <linux/key.h>
19#include <keys/asymmetric-type.h>
20#include "public_key.h"
21#include "pkcs7_parser.h"
22
23/*
24 * Request an asymmetric key.
25 */
26static struct key *pkcs7_request_asymmetric_key(
27 struct key *keyring,
28 const char *signer, size_t signer_len,
29 const char *authority, size_t auth_len)
30{
31 key_ref_t key;
32 char *id;
33
34 kenter(",%zu,,%zu", signer_len, auth_len);
35
36 /* Construct an identifier. */
37 id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL);
38 if (!id)
39 return ERR_PTR(-ENOMEM);
40
41 memcpy(id, signer, signer_len);
42 id[signer_len + 0] = ':';
43 id[signer_len + 1] = ' ';
44 memcpy(id + signer_len + 2, authority, auth_len);
45 id[signer_len + 2 + auth_len] = 0;
46
47 pr_debug("Look up: \"%s\"\n", id);
48
49 key = keyring_search(make_key_ref(keyring, 1),
50 &key_type_asymmetric, id);
51 if (IS_ERR(key))
52 pr_debug("Request for module key '%s' err %ld\n",
53 id, PTR_ERR(key));
54 kfree(id);
55
56 if (IS_ERR(key)) {
57 switch (PTR_ERR(key)) {
58 /* Hide some search errors */
59 case -EACCES:
60 case -ENOTDIR:
61 case -EAGAIN:
62 return ERR_PTR(-ENOKEY);
63 default:
64 return ERR_CAST(key);
65 }
66 }
67
68 pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key)));
69 return key_ref_to_ptr(key);
70}
71
72/**
73 * Check the trust on one PKCS#7 SignedInfo block.
74 */
75int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
76 struct pkcs7_signed_info *sinfo,
77 struct key *trust_keyring)
78{
79 struct public_key_signature *sig = &sinfo->sig;
80 struct x509_certificate *x509, *last = NULL, *p;
81 struct key *key;
82 bool trusted;
83 int ret;
84
85 kenter(",%u,", sinfo->index);
86
87 for (x509 = sinfo->signer; x509; x509 = x509->signer) {
88 if (x509->seen) {
89 if (x509->verified) {
90 trusted = x509->trusted;
91 goto verified;
92 }
93 kleave(" = -ENOKEY [cached]");
94 return -ENOKEY;
95 }
96 x509->seen = true;
97
98 /* Look to see if this certificate is present in the trusted
99 * keys.
100 */
101 key = pkcs7_request_asymmetric_key(
102 trust_keyring,
103 x509->subject, strlen(x509->subject),
104 x509->fingerprint, strlen(x509->fingerprint));
105 if (!IS_ERR(key))
106 /* One of the X.509 certificates in the PKCS#7 message
107 * is apparently the same as one we already trust.
108 * Verify that the trusted variant can also validate
109 * the signature on the descendant.
110 */
111 goto matched;
112 if (key == ERR_PTR(-ENOMEM))
113 return -ENOMEM;
114
115 /* Self-signed certificates form roots of their own, and if we
116 * don't know them, then we can't accept them.
117 */
118 if (x509->next == x509) {
119 kleave(" = -ENOKEY [unknown self-signed]");
120 return -ENOKEY;
121 }
122
123 might_sleep();
124 last = x509;
125 sig = &last->sig;
126 }
127
128 /* No match - see if the root certificate has a signer amongst the
129 * trusted keys.
130 */
131 if (!last || !last->issuer || !last->authority) {
132 kleave(" = -ENOKEY [no backref]");
133 return -ENOKEY;
134 }
135
136 key = pkcs7_request_asymmetric_key(
137 trust_keyring,
138 last->issuer, strlen(last->issuer),
139 last->authority, strlen(last->authority));
140 if (IS_ERR(key))
141 return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY;
142 x509 = last;
143
144matched:
145 ret = verify_signature(key, sig);
146 trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags);
147 key_put(key);
148 if (ret < 0) {
149 if (ret == -ENOMEM)
150 return ret;
151 kleave(" = -EKEYREJECTED [verify %d]", ret);
152 return -EKEYREJECTED;
153 }
154
155verified:
156 x509->verified = true;
157 for (p = sinfo->signer; p != x509; p = p->signer) {
158 p->verified = true;
159 p->trusted = trusted;
160 }
161 sinfo->trusted = trusted;
162 kleave(" = 0");
163 return 0;
164}
165
166/**
167 * pkcs7_validate_trust - Validate PKCS#7 trust chain
168 * @pkcs7: The PKCS#7 certificate to validate
169 * @trust_keyring: Signing certificates to use as starting points
170 * @_trusted: Set to true if trustworth, false otherwise
171 *
172 * Validate that the certificate chain inside the PKCS#7 message intersects
173 * keys we already know and trust.
174 *
175 * Returns, in order of descending priority:
176 *
177 * (*) -EKEYREJECTED if a signature failed to match for which we have a valid
178 * key, or:
179 *
180 * (*) 0 if at least one signature chain intersects with the keys in the trust
181 * keyring, or:
182 *
183 * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
184 * chain.
185 *
186 * (*) -ENOKEY if we couldn't find a match for any of the signature chains in
187 * the message.
188 *
189 * May also return -ENOMEM.
190 */
191int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
192 struct key *trust_keyring,
193 bool *_trusted)
194{
195 struct pkcs7_signed_info *sinfo;
196 struct x509_certificate *p;
197 int cached_ret = 0, ret;
198
199 for (p = pkcs7->certs; p; p = p->next)
200 p->seen = false;
201
202 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
203 ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
204 if (ret < 0) {
205 if (ret == -ENOPKG) {
206 cached_ret = -ENOPKG;
207 } else if (ret == -ENOKEY) {
208 if (cached_ret == 0)
209 cached_ret = -ENOKEY;
210 } else {
211 return ret;
212 }
213 }
214 *_trusted |= sinfo->trusted;
215 }
216
217 return cached_ret;
218}
219EXPORT_SYMBOL_GPL(pkcs7_validate_trust);
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
new file mode 100644
index 000000000000..51ff36f3a913
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -0,0 +1,323 @@
1/* Verify the signature on a PKCS#7 message.
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) "PKCS7: "fmt
13#include <linux/kernel.h>
14#include <linux/export.h>
15#include <linux/slab.h>
16#include <linux/err.h>
17#include <linux/asn1.h>
18#include <crypto/hash.h>
19#include "public_key.h"
20#include "pkcs7_parser.h"
21
22/*
23 * Digest the relevant parts of the PKCS#7 data
24 */
25static int pkcs7_digest(struct pkcs7_message *pkcs7,
26 struct pkcs7_signed_info *sinfo)
27{
28 struct crypto_shash *tfm;
29 struct shash_desc *desc;
30 size_t digest_size, desc_size;
31 void *digest;
32 int ret;
33
34 kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo);
35
36 if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
37 !hash_algo_name[sinfo->sig.pkey_hash_algo])
38 return -ENOPKG;
39
40 /* Allocate the hashing algorithm we're going to need and find out how
41 * big the hash operational data will be.
42 */
43 tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig.pkey_hash_algo],
44 0, 0);
45 if (IS_ERR(tfm))
46 return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
47
48 desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
49 sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm);
50
51 ret = -ENOMEM;
52 digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
53 if (!digest)
54 goto error_no_desc;
55
56 desc = digest + digest_size;
57 desc->tfm = tfm;
58 desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
59
60 /* Digest the message [RFC2315 9.3] */
61 ret = crypto_shash_init(desc);
62 if (ret < 0)
63 goto error;
64 ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest);
65 if (ret < 0)
66 goto error;
67 pr_devel("MsgDigest = [%*ph]\n", 8, digest);
68
69 /* However, if there are authenticated attributes, there must be a
70 * message digest attribute amongst them which corresponds to the
71 * digest we just calculated.
72 */
73 if (sinfo->msgdigest) {
74 u8 tag;
75
76 if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
77 pr_debug("Sig %u: Invalid digest size (%u)\n",
78 sinfo->index, sinfo->msgdigest_len);
79 ret = -EBADMSG;
80 goto error;
81 }
82
83 if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) {
84 pr_debug("Sig %u: Message digest doesn't match\n",
85 sinfo->index);
86 ret = -EKEYREJECTED;
87 goto error;
88 }
89
90 /* We then calculate anew, using the authenticated attributes
91 * as the contents of the digest instead. Note that we need to
92 * convert the attributes from a CONT.0 into a SET before we
93 * hash it.
94 */
95 memset(digest, 0, sinfo->sig.digest_size);
96
97 ret = crypto_shash_init(desc);
98 if (ret < 0)
99 goto error;
100 tag = ASN1_CONS_BIT | ASN1_SET;
101 ret = crypto_shash_update(desc, &tag, 1);
102 if (ret < 0)
103 goto error;
104 ret = crypto_shash_finup(desc, sinfo->authattrs,
105 sinfo->authattrs_len, digest);
106 if (ret < 0)
107 goto error;
108 pr_devel("AADigest = [%*ph]\n", 8, digest);
109 }
110
111 sinfo->sig.digest = digest;
112 digest = NULL;
113
114error:
115 kfree(digest);
116error_no_desc:
117 crypto_free_shash(tfm);
118 kleave(" = %d", ret);
119 return ret;
120}
121
122/*
123 * Find the key (X.509 certificate) to use to verify a PKCS#7 message. PKCS#7
124 * uses the issuer's name and the issuing certificate serial number for
125 * matching purposes. These must match the certificate issuer's name (not
126 * subject's name) and the certificate serial number [RFC 2315 6.7].
127 */
128static int pkcs7_find_key(struct pkcs7_message *pkcs7,
129 struct pkcs7_signed_info *sinfo)
130{
131 struct x509_certificate *x509;
132 unsigned certix = 1;
133
134 kenter("%u,%u,%u",
135 sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size);
136
137 for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
138 /* I'm _assuming_ that the generator of the PKCS#7 message will
139 * encode the fields from the X.509 cert in the same way in the
140 * PKCS#7 message - but I can't be 100% sure of that. It's
141 * possible this will need element-by-element comparison.
142 */
143 if (x509->raw_serial_size != sinfo->raw_serial_size ||
144 memcmp(x509->raw_serial, sinfo->raw_serial,
145 sinfo->raw_serial_size) != 0)
146 continue;
147 pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
148 sinfo->index, certix);
149
150 if (x509->raw_issuer_size != sinfo->raw_issuer_size ||
151 memcmp(x509->raw_issuer, sinfo->raw_issuer,
152 sinfo->raw_issuer_size) != 0) {
153 pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n",
154 sinfo->index);
155 continue;
156 }
157
158 if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
159 pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
160 sinfo->index);
161 continue;
162 }
163
164 sinfo->signer = x509;
165 return 0;
166 }
167 pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n",
168 sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial);
169 return -ENOKEY;
170}
171
172/*
173 * Verify the internal certificate chain as best we can.
174 */
175static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
176 struct pkcs7_signed_info *sinfo)
177{
178 struct x509_certificate *x509 = sinfo->signer, *p;
179 int ret;
180
181 kenter("");
182
183 for (p = pkcs7->certs; p; p = p->next)
184 p->seen = false;
185
186 for (;;) {
187 pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint);
188 x509->seen = true;
189 ret = x509_get_sig_params(x509);
190 if (ret < 0)
191 return ret;
192
193 if (x509->issuer)
194 pr_debug("- issuer %s\n", x509->issuer);
195 if (x509->authority)
196 pr_debug("- authkeyid %s\n", x509->authority);
197
198 if (!x509->authority ||
199 (x509->subject &&
200 strcmp(x509->subject, x509->issuer) == 0)) {
201 /* If there's no authority certificate specified, then
202 * the certificate must be self-signed and is the root
203 * of the chain. Likewise if the cert is its own
204 * authority.
205 */
206 pr_debug("- no auth?\n");
207 if (x509->raw_subject_size != x509->raw_issuer_size ||
208 memcmp(x509->raw_subject, x509->raw_issuer,
209 x509->raw_issuer_size) != 0)
210 return 0;
211
212 ret = x509_check_signature(x509->pub, x509);
213 if (ret < 0)
214 return ret;
215 x509->signer = x509;
216 pr_debug("- self-signed\n");
217 return 0;
218 }
219
220 /* Look through the X.509 certificates in the PKCS#7 message's
221 * list to see if the next one is there.
222 */
223 pr_debug("- want %s\n", x509->authority);
224 for (p = pkcs7->certs; p; p = p->next) {
225 pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint);
226 if (p->raw_subject_size == x509->raw_issuer_size &&
227 strcmp(p->fingerprint, x509->authority) == 0 &&
228 memcmp(p->raw_subject, x509->raw_issuer,
229 x509->raw_issuer_size) == 0)
230 goto found_issuer;
231 }
232
233 /* We didn't find the root of this chain */
234 pr_debug("- top\n");
235 return 0;
236
237 found_issuer:
238 pr_debug("- issuer %s\n", p->subject);
239 if (p->seen) {
240 pr_warn("Sig %u: X.509 chain contains loop\n",
241 sinfo->index);
242 return 0;
243 }
244 ret = x509_check_signature(p->pub, x509);
245 if (ret < 0)
246 return ret;
247 x509->signer = p;
248 if (x509 == p) {
249 pr_debug("- self-signed\n");
250 return 0;
251 }
252 x509 = p;
253 might_sleep();
254 }
255}
256
257/*
258 * Verify one signed information block from a PKCS#7 message.
259 */
260static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
261 struct pkcs7_signed_info *sinfo)
262{
263 int ret;
264
265 kenter(",%u", sinfo->index);
266
267 /* First of all, digest the data in the PKCS#7 message and the
268 * signed information block
269 */
270 ret = pkcs7_digest(pkcs7, sinfo);
271 if (ret < 0)
272 return ret;
273
274 /* Find the key for the signature */
275 ret = pkcs7_find_key(pkcs7, sinfo);
276 if (ret < 0)
277 return ret;
278
279 pr_devel("Using X.509[%u] for sig %u\n",
280 sinfo->signer->index, sinfo->index);
281
282 /* Verify the PKCS#7 binary against the key */
283 ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
284 if (ret < 0)
285 return ret;
286
287 pr_devel("Verified signature %u\n", sinfo->index);
288
289 /* Verify the internal certificate chain */
290 return pkcs7_verify_sig_chain(pkcs7, sinfo);
291}
292
293/**
294 * pkcs7_verify - Verify a PKCS#7 message
295 * @pkcs7: The PKCS#7 message to be verified
296 */
297int pkcs7_verify(struct pkcs7_message *pkcs7)
298{
299 struct pkcs7_signed_info *sinfo;
300 struct x509_certificate *x509;
301 int ret, n;
302
303 kenter("");
304
305 for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
306 ret = x509_get_sig_params(x509);
307 if (ret < 0)
308 return ret;
309 pr_debug("X.509[%u] %s\n", n, x509->authority);
310 }
311
312 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
313 ret = pkcs7_verify_one(pkcs7, sinfo);
314 if (ret < 0) {
315 kleave(" = %d", ret);
316 return ret;
317 }
318 }
319
320 kleave(" = 0");
321 return 0;
322}
323EXPORT_SYMBOL_GPL(pkcs7_verify);
diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1
index bf32b3dff088..aae0cde414e2 100644
--- a/crypto/asymmetric_keys/x509.asn1
+++ b/crypto/asymmetric_keys/x509.asn1
@@ -6,7 +6,7 @@ Certificate ::= SEQUENCE {
6 6
7TBSCertificate ::= SEQUENCE { 7TBSCertificate ::= SEQUENCE {
8 version [ 0 ] Version DEFAULT, 8 version [ 0 ] Version DEFAULT,
9 serialNumber CertificateSerialNumber, 9 serialNumber CertificateSerialNumber ({ x509_note_serial }),
10 signature AlgorithmIdentifier ({ x509_note_pkey_algo }), 10 signature AlgorithmIdentifier ({ x509_note_pkey_algo }),
11 issuer Name ({ x509_note_issuer }), 11 issuer Name ({ x509_note_issuer }),
12 validity Validity, 12 validity Validity,
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 29893162497c..ac72348c186a 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -11,6 +11,7 @@
11 11
12#define pr_fmt(fmt) "X.509: "fmt 12#define pr_fmt(fmt) "X.509: "fmt
13#include <linux/kernel.h> 13#include <linux/kernel.h>
14#include <linux/export.h>
14#include <linux/slab.h> 15#include <linux/slab.h>
15#include <linux/err.h> 16#include <linux/err.h>
16#include <linux/oid_registry.h> 17#include <linux/oid_registry.h>
@@ -52,6 +53,7 @@ void x509_free_certificate(struct x509_certificate *cert)
52 kfree(cert); 53 kfree(cert);
53 } 54 }
54} 55}
56EXPORT_SYMBOL_GPL(x509_free_certificate);
55 57
56/* 58/*
57 * Parse an X.509 certificate 59 * Parse an X.509 certificate
@@ -97,6 +99,7 @@ error_no_ctx:
97error_no_cert: 99error_no_cert:
98 return ERR_PTR(ret); 100 return ERR_PTR(ret);
99} 101}
102EXPORT_SYMBOL_GPL(x509_cert_parse);
100 103
101/* 104/*
102 * Note an OID when we find one for later processing when we know how 105 * Note an OID when we find one for later processing when we know how
@@ -211,6 +214,19 @@ int x509_note_signature(void *context, size_t hdrlen,
211} 214}
212 215
213/* 216/*
217 * Note the certificate serial number
218 */
219int x509_note_serial(void *context, size_t hdrlen,
220 unsigned char tag,
221 const void *value, size_t vlen)
222{
223 struct x509_parse_context *ctx = context;
224 ctx->cert->raw_serial = value;
225 ctx->cert->raw_serial_size = vlen;
226 return 0;
227}
228
229/*
214 * Note some of the name segments from which we'll fabricate a name. 230 * Note some of the name segments from which we'll fabricate a name.
215 */ 231 */
216int x509_extract_name_segment(void *context, size_t hdrlen, 232int x509_extract_name_segment(void *context, size_t hdrlen,
@@ -322,6 +338,8 @@ int x509_note_issuer(void *context, size_t hdrlen,
322 const void *value, size_t vlen) 338 const void *value, size_t vlen)
323{ 339{
324 struct x509_parse_context *ctx = context; 340 struct x509_parse_context *ctx = context;
341 ctx->cert->raw_issuer = value;
342 ctx->cert->raw_issuer_size = vlen;
325 return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); 343 return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
326} 344}
327 345
@@ -330,6 +348,8 @@ int x509_note_subject(void *context, size_t hdrlen,
330 const void *value, size_t vlen) 348 const void *value, size_t vlen)
331{ 349{
332 struct x509_parse_context *ctx = context; 350 struct x509_parse_context *ctx = context;
351 ctx->cert->raw_subject = value;
352 ctx->cert->raw_subject_size = vlen;
333 return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); 353 return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
334} 354}
335 355
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 87d9cc26f630..1b76f207c1f3 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -14,7 +14,9 @@
14 14
15struct x509_certificate { 15struct x509_certificate {
16 struct x509_certificate *next; 16 struct x509_certificate *next;
17 struct x509_certificate *signer; /* Certificate that signed this one */
17 struct public_key *pub; /* Public key details */ 18 struct public_key *pub; /* Public key details */
19 struct public_key_signature sig; /* Signature parameters */
18 char *issuer; /* Name of certificate issuer */ 20 char *issuer; /* Name of certificate issuer */
19 char *subject; /* Name of certificate subject */ 21 char *subject; /* Name of certificate subject */
20 char *fingerprint; /* Key fingerprint as hex */ 22 char *fingerprint; /* Key fingerprint as hex */
@@ -25,7 +27,16 @@ struct x509_certificate {
25 unsigned tbs_size; /* Size of signed data */ 27 unsigned tbs_size; /* Size of signed data */
26 unsigned raw_sig_size; /* Size of sigature */ 28 unsigned raw_sig_size; /* Size of sigature */
27 const void *raw_sig; /* Signature data */ 29 const void *raw_sig; /* Signature data */
28 struct public_key_signature sig; /* Signature parameters */ 30 const void *raw_serial; /* Raw serial number in ASN.1 */
31 unsigned raw_serial_size;
32 unsigned raw_issuer_size;
33 const void *raw_issuer; /* Raw issuer name in ASN.1 */
34 const void *raw_subject; /* Raw subject name in ASN.1 */
35 unsigned raw_subject_size;
36 unsigned index;
37 bool seen; /* Infinite recursion prevention */
38 bool verified;
39 bool trusted;
29}; 40};
30 41
31/* 42/*
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h
new file mode 100644
index 000000000000..691c79172a26
--- /dev/null
+++ b/include/crypto/pkcs7.h
@@ -0,0 +1,36 @@
1/* PKCS#7 crypto data parser
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
12struct key;
13struct pkcs7_message;
14
15/*
16 * pkcs7_parser.c
17 */
18extern struct pkcs7_message *pkcs7_parse_message(const void *data,
19 size_t datalen);
20extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
21
22extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
23 const void **_data, size_t *_datalen,
24 bool want_wrapper);
25
26/*
27 * pkcs7_trust.c
28 */
29extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
30 struct key *trust_keyring,
31 bool *_trusted);
32
33/*
34 * pkcs7_verify.c
35 */
36extern int pkcs7_verify(struct pkcs7_message *pkcs7);
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
index 6926db724258..edeff85cb1e8 100644
--- a/include/linux/oid_registry.h
+++ b/include/linux/oid_registry.h
@@ -55,6 +55,7 @@ enum OID {
55 OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ 55 OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
56 OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ 56 OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
57 OID_sha1, /* 1.3.14.3.2.26 */ 57 OID_sha1, /* 1.3.14.3.2.26 */
58 OID_sha256, /* 2.16.840.1.101.3.4.2.1 */
58 59
59 /* Distinguished Name attribute IDs [RFC 2256] */ 60 /* Distinguished Name attribute IDs [RFC 2256] */
60 OID_commonName, /* 2.5.4.3 */ 61 OID_commonName, /* 2.5.4.3 */