aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-06 11:06:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-06 11:06:39 -0400
commitbb2cbf5e9367d8598fecd0c48dead69560750223 (patch)
treefb2c620451b90f41a31726bdd82077813f941e39 /crypto
parente7fda6c4c3c1a7d6996dd75fd84670fa0b5d448f (diff)
parent478d085524c57cf4283699f529d5a4c22188ea69 (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris: "In this release: - PKCS#7 parser for the key management subsystem from David Howells - appoint Kees Cook as seccomp maintainer - bugfixes and general maintenance across the subsystem" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (94 commits) X.509: Need to export x509_request_asymmetric_key() netlabel: shorter names for the NetLabel catmap funcs/structs netlabel: fix the catmap walking functions netlabel: fix the horribly broken catmap functions netlabel: fix a problem when setting bits below the previously lowest bit PKCS#7: X.509 certificate issuer and subject are mandatory fields in the ASN.1 tpm: simplify code by using %*phN specifier tpm: Provide a generic means to override the chip returned timeouts tpm: missing tpm_chip_put in tpm_get_random() tpm: Properly clean sysfs entries in error path tpm: Add missing tpm_do_selftest to ST33 I2C driver PKCS#7: Use x509_request_asymmetric_key() Revert "selinux: fix the default socket labeling in sock_graft()" X.509: x509_request_asymmetric_keys() doesn't need string length arguments PKCS#7: fix sparse non static symbol warning KEYS: revert encrypted key change ima: add support for measuring and appraising firmware firmware_class: perform new LSM checks security: introduce kernel_fw_from_file hook PKCS#7: Missing inclusion of linux/err.h ...
Diffstat (limited to 'crypto')
-rw-r--r--crypto/asymmetric_keys/Kconfig34
-rw-r--r--crypto/asymmetric_keys/Makefile37
-rw-r--r--crypto/asymmetric_keys/asymmetric_keys.h2
-rw-r--r--crypto/asymmetric_keys/asymmetric_type.c78
-rw-r--r--crypto/asymmetric_keys/mscode.asn128
-rw-r--r--crypto/asymmetric_keys/mscode_parser.c126
-rw-r--r--crypto/asymmetric_keys/pkcs7.asn1127
-rw-r--r--crypto/asymmetric_keys/pkcs7_key_type.c100
-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.c166
-rw-r--r--crypto/asymmetric_keys/pkcs7_verify.c321
-rw-r--r--crypto/asymmetric_keys/verify_pefile.c457
-rw-r--r--crypto/asymmetric_keys/verify_pefile.h42
-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--crypto/asymmetric_keys/x509_public_key.c115
18 files changed, 2075 insertions, 50 deletions
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 03a6eb95ab50..4870f28403f5 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -22,7 +22,6 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
22 22
23config PUBLIC_KEY_ALGO_RSA 23config PUBLIC_KEY_ALGO_RSA
24 tristate "RSA public-key algorithm" 24 tristate "RSA public-key algorithm"
25 select MPILIB_EXTRA
26 select MPILIB 25 select MPILIB
27 help 26 help
28 This option enables support for the RSA algorithm (PKCS#1, RFC3447). 27 This option enables support for the RSA algorithm (PKCS#1, RFC3447).
@@ -33,8 +32,39 @@ config X509_CERTIFICATE_PARSER
33 select ASN1 32 select ASN1
34 select OID_REGISTRY 33 select OID_REGISTRY
35 help 34 help
36 This option procides support for parsing X.509 format blobs for key 35 This option provides support for parsing X.509 format blobs for key
37 data and provides the ability to instantiate a crypto key from a 36 data and provides the ability to instantiate a crypto key from a
38 public key packet found inside the certificate. 37 public key packet found inside the certificate.
39 38
39config PKCS7_MESSAGE_PARSER
40 tristate "PKCS#7 message parser"
41 depends on X509_CERTIFICATE_PARSER
42 select ASN1
43 select OID_REGISTRY
44 help
45 This option provides support for parsing PKCS#7 format messages for
46 signature data and provides the ability to verify the signature.
47
48config PKCS7_TEST_KEY
49 tristate "PKCS#7 testing key type"
50 depends on PKCS7_MESSAGE_PARSER
51 select SYSTEM_TRUSTED_KEYRING
52 help
53 This option provides a type of key that can be loaded up from a
54 PKCS#7 message - provided the message is signed by a trusted key. If
55 it is, the PKCS#7 wrapper is discarded and reading the key returns
56 just the payload. If it isn't, adding the key will fail with an
57 error.
58
59 This is intended for testing the PKCS#7 parser.
60
61config SIGNED_PE_FILE_VERIFICATION
62 bool "Support for PE file signature verification"
63 depends on PKCS7_MESSAGE_PARSER=y
64 select ASN1
65 select OID_REGISTRY
66 help
67 This option provides support for verifying the signature(s) on a
68 signed PE binary.
69
40endif # ASYMMETRIC_KEY_TYPE 70endif # ASYMMETRIC_KEY_TYPE
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index 0727204aab68..e47fcd9ac5e8 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -25,3 +25,40 @@ $(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
50
51#
52# Signed PE binary-wrapped key handling
53#
54obj-$(CONFIG_SIGNED_PE_FILE_VERIFICATION) += verify_signed_pefile.o
55
56verify_signed_pefile-y := \
57 verify_pefile.o \
58 mscode_parser.o \
59 mscode-asn1.o
60
61$(obj)/mscode_parser.o: $(obj)/mscode-asn1.h $(obj)/mscode-asn1.h
62$(obj)/mscode-asn1.o: $(obj)/mscode-asn1.c $(obj)/mscode-asn1.h
63
64clean-files += mscode-asn1.c mscode-asn1.h
diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h
index 515b63430812..a63c551c6557 100644
--- a/crypto/asymmetric_keys/asymmetric_keys.h
+++ b/crypto/asymmetric_keys/asymmetric_keys.h
@@ -9,6 +9,8 @@
9 * 2 of the Licence, or (at your option) any later version. 9 * 2 of the Licence, or (at your option) any later version.
10 */ 10 */
11 11
12int asymmetric_keyid_match(const char *kid, const char *id);
13
12static inline const char *asymmetric_key_id(const struct key *key) 14static inline const char *asymmetric_key_id(const struct key *key)
13{ 15{
14 return key->type_data.p[1]; 16 return key->type_data.p[1];
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index b77eb5304788..eb8cd46961a5 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -23,6 +23,35 @@ static LIST_HEAD(asymmetric_key_parsers);
23static DECLARE_RWSEM(asymmetric_key_parsers_sem); 23static DECLARE_RWSEM(asymmetric_key_parsers_sem);
24 24
25/* 25/*
26 * Match asymmetric key id with partial match
27 * @id: key id to match in a form "id:<id>"
28 */
29int asymmetric_keyid_match(const char *kid, const char *id)
30{
31 size_t idlen, kidlen;
32
33 if (!kid || !id)
34 return 0;
35
36 /* make it possible to use id as in the request: "id:<id>" */
37 if (strncmp(id, "id:", 3) == 0)
38 id += 3;
39
40 /* Anything after here requires a partial match on the ID string */
41 idlen = strlen(id);
42 kidlen = strlen(kid);
43 if (idlen > kidlen)
44 return 0;
45
46 kid += kidlen - idlen;
47 if (strcasecmp(id, kid) != 0)
48 return 0;
49
50 return 1;
51}
52EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
53
54/*
26 * Match asymmetric keys on (part of) their name 55 * Match asymmetric keys on (part of) their name
27 * We have some shorthand methods for matching keys. We allow: 56 * We have some shorthand methods for matching keys. We allow:
28 * 57 *
@@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
34{ 63{
35 const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); 64 const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
36 const char *spec = description; 65 const char *spec = description;
37 const char *id, *kid; 66 const char *id;
38 ptrdiff_t speclen; 67 ptrdiff_t speclen;
39 size_t idlen, kidlen;
40 68
41 if (!subtype || !spec || !*spec) 69 if (!subtype || !spec || !*spec)
42 return 0; 70 return 0;
@@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
55 speclen = id - spec; 83 speclen = id - spec;
56 id++; 84 id++;
57 85
58 /* Anything after here requires a partial match on the ID string */ 86 if (speclen == 2 && memcmp(spec, "id", 2) == 0)
59 kid = asymmetric_key_id(key); 87 return asymmetric_keyid_match(asymmetric_key_id(key), id);
60 if (!kid)
61 return 0;
62
63 idlen = strlen(id);
64 kidlen = strlen(kid);
65 if (idlen > kidlen)
66 return 0;
67
68 kid += kidlen - idlen;
69 if (strcasecmp(id, kid) != 0)
70 return 0;
71
72 if (speclen == 2 &&
73 memcmp(spec, "id", 2) == 0)
74 return 1;
75 88
76 if (speclen == subtype->name_len && 89 if (speclen == subtype->name_len &&
77 memcmp(spec, subtype->name, speclen) == 0) 90 memcmp(spec, subtype->name, speclen) == 0)
@@ -156,7 +169,7 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
156 pr_devel("==>%s()\n", __func__); 169 pr_devel("==>%s()\n", __func__);
157 170
158 if (subtype) { 171 if (subtype) {
159 subtype->destroy(prep->payload); 172 subtype->destroy(prep->payload[0]);
160 module_put(subtype->owner); 173 module_put(subtype->owner);
161 } 174 }
162 kfree(prep->type_data[1]); 175 kfree(prep->type_data[1]);
@@ -164,29 +177,6 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
164} 177}
165 178
166/* 179/*
167 * Instantiate a asymmetric_key defined key. The key was preparsed, so we just
168 * have to transfer the data here.
169 */
170static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
171{
172 int ret;
173
174 pr_devel("==>%s()\n", __func__);
175
176 ret = key_payload_reserve(key, prep->quotalen);
177 if (ret == 0) {
178 key->type_data.p[0] = prep->type_data[0];
179 key->type_data.p[1] = prep->type_data[1];
180 key->payload.data = prep->payload;
181 prep->type_data[0] = NULL;
182 prep->type_data[1] = NULL;
183 prep->payload = NULL;
184 }
185 pr_devel("<==%s() = %d\n", __func__, ret);
186 return ret;
187}
188
189/*
190 * dispose of the data dangling from the corpse of a asymmetric key 180 * dispose of the data dangling from the corpse of a asymmetric key
191 */ 181 */
192static void asymmetric_key_destroy(struct key *key) 182static void asymmetric_key_destroy(struct key *key)
@@ -205,7 +195,7 @@ struct key_type key_type_asymmetric = {
205 .name = "asymmetric", 195 .name = "asymmetric",
206 .preparse = asymmetric_key_preparse, 196 .preparse = asymmetric_key_preparse,
207 .free_preparse = asymmetric_key_free_preparse, 197 .free_preparse = asymmetric_key_free_preparse,
208 .instantiate = asymmetric_key_instantiate, 198 .instantiate = generic_key_instantiate,
209 .match = asymmetric_key_match, 199 .match = asymmetric_key_match,
210 .destroy = asymmetric_key_destroy, 200 .destroy = asymmetric_key_destroy,
211 .describe = asymmetric_key_describe, 201 .describe = asymmetric_key_describe,
diff --git a/crypto/asymmetric_keys/mscode.asn1 b/crypto/asymmetric_keys/mscode.asn1
new file mode 100644
index 000000000000..6d09ba48c41c
--- /dev/null
+++ b/crypto/asymmetric_keys/mscode.asn1
@@ -0,0 +1,28 @@
1--- Microsoft individual code signing data blob 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
12MSCode ::= SEQUENCE {
13 type SEQUENCE {
14 contentType ContentType,
15 parameters ANY
16 },
17 content SEQUENCE {
18 digestAlgorithm DigestAlgorithmIdentifier,
19 digest OCTET STRING ({ mscode_note_digest })
20 }
21}
22
23ContentType ::= OBJECT IDENTIFIER ({ mscode_note_content_type })
24
25DigestAlgorithmIdentifier ::= SEQUENCE {
26 algorithm OBJECT IDENTIFIER ({ mscode_note_digest_algo }),
27 parameters ANY OPTIONAL
28}
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c
new file mode 100644
index 000000000000..214a992123cd
--- /dev/null
+++ b/crypto/asymmetric_keys/mscode_parser.c
@@ -0,0 +1,126 @@
1/* Parse a Microsoft Individual Code Signing blob
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) "MSCODE: "fmt
13#include <linux/kernel.h>
14#include <linux/slab.h>
15#include <linux/err.h>
16#include <linux/oid_registry.h>
17#include <crypto/pkcs7.h>
18#include "verify_pefile.h"
19#include "mscode-asn1.h"
20
21/*
22 * Parse a Microsoft Individual Code Signing blob
23 */
24int mscode_parse(struct pefile_context *ctx)
25{
26 const void *content_data;
27 size_t data_len;
28 int ret;
29
30 ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1);
31
32 if (ret) {
33 pr_debug("PKCS#7 message does not contain data\n");
34 return ret;
35 }
36
37 pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
38 content_data);
39
40 return asn1_ber_decoder(&mscode_decoder, ctx, content_data, data_len);
41}
42
43/*
44 * Check the content type OID
45 */
46int mscode_note_content_type(void *context, size_t hdrlen,
47 unsigned char tag,
48 const void *value, size_t vlen)
49{
50 enum OID oid;
51
52 oid = look_up_OID(value, vlen);
53 if (oid == OID__NR) {
54 char buffer[50];
55
56 sprint_oid(value, vlen, buffer, sizeof(buffer));
57 pr_err("Unknown OID: %s\n", buffer);
58 return -EBADMSG;
59 }
60
61 /*
62 * pesign utility had a bug where it was putting
63 * OID_msIndividualSPKeyPurpose instead of OID_msPeImageDataObjId
64 * So allow both OIDs.
65 */
66 if (oid != OID_msPeImageDataObjId &&
67 oid != OID_msIndividualSPKeyPurpose) {
68 pr_err("Unexpected content type OID %u\n", oid);
69 return -EBADMSG;
70 }
71
72 return 0;
73}
74
75/*
76 * Note the digest algorithm OID
77 */
78int mscode_note_digest_algo(void *context, size_t hdrlen,
79 unsigned char tag,
80 const void *value, size_t vlen)
81{
82 struct pefile_context *ctx = context;
83 char buffer[50];
84 enum OID oid;
85
86 oid = look_up_OID(value, vlen);
87 switch (oid) {
88 case OID_md4:
89 ctx->digest_algo = HASH_ALGO_MD4;
90 break;
91 case OID_md5:
92 ctx->digest_algo = HASH_ALGO_MD5;
93 break;
94 case OID_sha1:
95 ctx->digest_algo = HASH_ALGO_SHA1;
96 break;
97 case OID_sha256:
98 ctx->digest_algo = HASH_ALGO_SHA256;
99 break;
100
101 case OID__NR:
102 sprint_oid(value, vlen, buffer, sizeof(buffer));
103 pr_err("Unknown OID: %s\n", buffer);
104 return -EBADMSG;
105
106 default:
107 pr_err("Unsupported content type: %u\n", oid);
108 return -ENOPKG;
109 }
110
111 return 0;
112}
113
114/*
115 * Note the digest we're guaranteeing with this certificate
116 */
117int mscode_note_digest(void *context, size_t hdrlen,
118 unsigned char tag,
119 const void *value, size_t vlen)
120{
121 struct pefile_context *ctx = context;
122
123 ctx->digest = value;
124 ctx->digest_len = vlen;
125 return 0;
126}
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..3de5fb011de0
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -0,0 +1,100 @@
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/err.h>
15#include <linux/key-type.h>
16#include <crypto/pkcs7.h>
17#include <keys/user-type.h>
18#include <keys/system_keyring.h>
19#include "pkcs7_parser.h"
20
21/*
22 * Preparse a PKCS#7 wrapped and validated data blob.
23 */
24static int pkcs7_preparse(struct key_preparsed_payload *prep)
25{
26 struct pkcs7_message *pkcs7;
27 const void *data, *saved_prep_data;
28 size_t datalen, saved_prep_datalen;
29 bool trusted;
30 int ret;
31
32 kenter("");
33
34 saved_prep_data = prep->data;
35 saved_prep_datalen = prep->datalen;
36 pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
37 if (IS_ERR(pkcs7)) {
38 ret = PTR_ERR(pkcs7);
39 goto error;
40 }
41
42 ret = pkcs7_verify(pkcs7);
43 if (ret < 0)
44 goto error_free;
45
46 ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
47 if (ret < 0)
48 goto error_free;
49 if (!trusted)
50 pr_warn("PKCS#7 message doesn't chain back to a trusted key\n");
51
52 ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false);
53 if (ret < 0)
54 goto error_free;
55
56 prep->data = data;
57 prep->datalen = datalen;
58 ret = user_preparse(prep);
59 prep->data = saved_prep_data;
60 prep->datalen = saved_prep_datalen;
61
62error_free:
63 pkcs7_free_message(pkcs7);
64error:
65 kleave(" = %d", ret);
66 return ret;
67}
68
69/*
70 * user defined keys take an arbitrary string as the description and an
71 * arbitrary blob of data as the payload
72 */
73static struct key_type key_type_pkcs7 = {
74 .name = "pkcs7_test",
75 .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
76 .preparse = pkcs7_preparse,
77 .free_preparse = user_free_preparse,
78 .instantiate = generic_key_instantiate,
79 .match = user_match,
80 .revoke = user_revoke,
81 .destroy = user_destroy,
82 .describe = user_describe,
83 .read = user_read,
84};
85
86/*
87 * Module stuff
88 */
89static int __init pkcs7_key_init(void)
90{
91 return register_key_type(&key_type_pkcs7);
92}
93
94static void __exit pkcs7_key_cleanup(void)
95{
96 unregister_key_type(&key_type_pkcs7);
97}
98
99module_init(pkcs7_key_init);
100module_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..e666eb011a85
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -0,0 +1,166 @@
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 * Check the trust on one PKCS#7 SignedInfo block.
25 */
26int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
27 struct pkcs7_signed_info *sinfo,
28 struct key *trust_keyring)
29{
30 struct public_key_signature *sig = &sinfo->sig;
31 struct x509_certificate *x509, *last = NULL, *p;
32 struct key *key;
33 bool trusted;
34 int ret;
35
36 kenter(",%u,", sinfo->index);
37
38 for (x509 = sinfo->signer; x509; x509 = x509->signer) {
39 if (x509->seen) {
40 if (x509->verified) {
41 trusted = x509->trusted;
42 goto verified;
43 }
44 kleave(" = -ENOKEY [cached]");
45 return -ENOKEY;
46 }
47 x509->seen = true;
48
49 /* Look to see if this certificate is present in the trusted
50 * keys.
51 */
52 key = x509_request_asymmetric_key(trust_keyring, x509->subject,
53 x509->fingerprint);
54 if (!IS_ERR(key))
55 /* One of the X.509 certificates in the PKCS#7 message
56 * is apparently the same as one we already trust.
57 * Verify that the trusted variant can also validate
58 * the signature on the descendant.
59 */
60 goto matched;
61 if (key == ERR_PTR(-ENOMEM))
62 return -ENOMEM;
63
64 /* Self-signed certificates form roots of their own, and if we
65 * don't know them, then we can't accept them.
66 */
67 if (x509->next == x509) {
68 kleave(" = -ENOKEY [unknown self-signed]");
69 return -ENOKEY;
70 }
71
72 might_sleep();
73 last = x509;
74 sig = &last->sig;
75 }
76
77 /* No match - see if the root certificate has a signer amongst the
78 * trusted keys.
79 */
80 if (!last || !last->issuer || !last->authority) {
81 kleave(" = -ENOKEY [no backref]");
82 return -ENOKEY;
83 }
84
85 key = x509_request_asymmetric_key(trust_keyring, last->issuer,
86 last->authority);
87 if (IS_ERR(key))
88 return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY;
89 x509 = last;
90
91matched:
92 ret = verify_signature(key, sig);
93 trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags);
94 key_put(key);
95 if (ret < 0) {
96 if (ret == -ENOMEM)
97 return ret;
98 kleave(" = -EKEYREJECTED [verify %d]", ret);
99 return -EKEYREJECTED;
100 }
101
102verified:
103 x509->verified = true;
104 for (p = sinfo->signer; p != x509; p = p->signer) {
105 p->verified = true;
106 p->trusted = trusted;
107 }
108 sinfo->trusted = trusted;
109 kleave(" = 0");
110 return 0;
111}
112
113/**
114 * pkcs7_validate_trust - Validate PKCS#7 trust chain
115 * @pkcs7: The PKCS#7 certificate to validate
116 * @trust_keyring: Signing certificates to use as starting points
117 * @_trusted: Set to true if trustworth, false otherwise
118 *
119 * Validate that the certificate chain inside the PKCS#7 message intersects
120 * keys we already know and trust.
121 *
122 * Returns, in order of descending priority:
123 *
124 * (*) -EKEYREJECTED if a signature failed to match for which we have a valid
125 * key, or:
126 *
127 * (*) 0 if at least one signature chain intersects with the keys in the trust
128 * keyring, or:
129 *
130 * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
131 * chain.
132 *
133 * (*) -ENOKEY if we couldn't find a match for any of the signature chains in
134 * the message.
135 *
136 * May also return -ENOMEM.
137 */
138int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
139 struct key *trust_keyring,
140 bool *_trusted)
141{
142 struct pkcs7_signed_info *sinfo;
143 struct x509_certificate *p;
144 int cached_ret = 0, ret;
145
146 for (p = pkcs7->certs; p; p = p->next)
147 p->seen = false;
148
149 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
150 ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
151 if (ret < 0) {
152 if (ret == -ENOPKG) {
153 cached_ret = -ENOPKG;
154 } else if (ret == -ENOKEY) {
155 if (cached_ret == 0)
156 cached_ret = -ENOKEY;
157 } else {
158 return ret;
159 }
160 }
161 *_trusted |= sinfo->trusted;
162 }
163
164 return cached_ret;
165}
166EXPORT_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..c62cf8006e1f
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -0,0 +1,321 @@
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 pr_debug("- issuer %s\n", x509->issuer);
194 if (x509->authority)
195 pr_debug("- authkeyid %s\n", x509->authority);
196
197 if (!x509->authority ||
198 strcmp(x509->subject, x509->issuer) == 0) {
199 /* If there's no authority certificate specified, then
200 * the certificate must be self-signed and is the root
201 * of the chain. Likewise if the cert is its own
202 * authority.
203 */
204 pr_debug("- no auth?\n");
205 if (x509->raw_subject_size != x509->raw_issuer_size ||
206 memcmp(x509->raw_subject, x509->raw_issuer,
207 x509->raw_issuer_size) != 0)
208 return 0;
209
210 ret = x509_check_signature(x509->pub, x509);
211 if (ret < 0)
212 return ret;
213 x509->signer = x509;
214 pr_debug("- self-signed\n");
215 return 0;
216 }
217
218 /* Look through the X.509 certificates in the PKCS#7 message's
219 * list to see if the next one is there.
220 */
221 pr_debug("- want %s\n", x509->authority);
222 for (p = pkcs7->certs; p; p = p->next) {
223 pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint);
224 if (p->raw_subject_size == x509->raw_issuer_size &&
225 strcmp(p->fingerprint, x509->authority) == 0 &&
226 memcmp(p->raw_subject, x509->raw_issuer,
227 x509->raw_issuer_size) == 0)
228 goto found_issuer;
229 }
230
231 /* We didn't find the root of this chain */
232 pr_debug("- top\n");
233 return 0;
234
235 found_issuer:
236 pr_debug("- issuer %s\n", p->subject);
237 if (p->seen) {
238 pr_warn("Sig %u: X.509 chain contains loop\n",
239 sinfo->index);
240 return 0;
241 }
242 ret = x509_check_signature(p->pub, x509);
243 if (ret < 0)
244 return ret;
245 x509->signer = p;
246 if (x509 == p) {
247 pr_debug("- self-signed\n");
248 return 0;
249 }
250 x509 = p;
251 might_sleep();
252 }
253}
254
255/*
256 * Verify one signed information block from a PKCS#7 message.
257 */
258static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
259 struct pkcs7_signed_info *sinfo)
260{
261 int ret;
262
263 kenter(",%u", sinfo->index);
264
265 /* First of all, digest the data in the PKCS#7 message and the
266 * signed information block
267 */
268 ret = pkcs7_digest(pkcs7, sinfo);
269 if (ret < 0)
270 return ret;
271
272 /* Find the key for the signature */
273 ret = pkcs7_find_key(pkcs7, sinfo);
274 if (ret < 0)
275 return ret;
276
277 pr_devel("Using X.509[%u] for sig %u\n",
278 sinfo->signer->index, sinfo->index);
279
280 /* Verify the PKCS#7 binary against the key */
281 ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
282 if (ret < 0)
283 return ret;
284
285 pr_devel("Verified signature %u\n", sinfo->index);
286
287 /* Verify the internal certificate chain */
288 return pkcs7_verify_sig_chain(pkcs7, sinfo);
289}
290
291/**
292 * pkcs7_verify - Verify a PKCS#7 message
293 * @pkcs7: The PKCS#7 message to be verified
294 */
295int pkcs7_verify(struct pkcs7_message *pkcs7)
296{
297 struct pkcs7_signed_info *sinfo;
298 struct x509_certificate *x509;
299 int ret, n;
300
301 kenter("");
302
303 for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
304 ret = x509_get_sig_params(x509);
305 if (ret < 0)
306 return ret;
307 pr_debug("X.509[%u] %s\n", n, x509->authority);
308 }
309
310 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
311 ret = pkcs7_verify_one(pkcs7, sinfo);
312 if (ret < 0) {
313 kleave(" = %d", ret);
314 return ret;
315 }
316 }
317
318 kleave(" = 0");
319 return 0;
320}
321EXPORT_SYMBOL_GPL(pkcs7_verify);
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
new file mode 100644
index 000000000000..79175e6ea0b2
--- /dev/null
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -0,0 +1,457 @@
1/* Parse a signed PE binary
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) "PEFILE: "fmt
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/err.h>
17#include <linux/pe.h>
18#include <linux/asn1.h>
19#include <crypto/pkcs7.h>
20#include <crypto/hash.h>
21#include "verify_pefile.h"
22
23/*
24 * Parse a PE binary.
25 */
26static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
27 struct pefile_context *ctx)
28{
29 const struct mz_hdr *mz = pebuf;
30 const struct pe_hdr *pe;
31 const struct pe32_opt_hdr *pe32;
32 const struct pe32plus_opt_hdr *pe64;
33 const struct data_directory *ddir;
34 const struct data_dirent *dde;
35 const struct section_header *secs, *sec;
36 size_t cursor, datalen = pelen;
37
38 kenter("");
39
40#define chkaddr(base, x, s) \
41 do { \
42 if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \
43 return -ELIBBAD; \
44 } while (0)
45
46 chkaddr(0, 0, sizeof(*mz));
47 if (mz->magic != MZ_MAGIC)
48 return -ELIBBAD;
49 cursor = sizeof(*mz);
50
51 chkaddr(cursor, mz->peaddr, sizeof(*pe));
52 pe = pebuf + mz->peaddr;
53 if (pe->magic != PE_MAGIC)
54 return -ELIBBAD;
55 cursor = mz->peaddr + sizeof(*pe);
56
57 chkaddr(0, cursor, sizeof(pe32->magic));
58 pe32 = pebuf + cursor;
59 pe64 = pebuf + cursor;
60
61 switch (pe32->magic) {
62 case PE_OPT_MAGIC_PE32:
63 chkaddr(0, cursor, sizeof(*pe32));
64 ctx->image_checksum_offset =
65 (unsigned long)&pe32->csum - (unsigned long)pebuf;
66 ctx->header_size = pe32->header_size;
67 cursor += sizeof(*pe32);
68 ctx->n_data_dirents = pe32->data_dirs;
69 break;
70
71 case PE_OPT_MAGIC_PE32PLUS:
72 chkaddr(0, cursor, sizeof(*pe64));
73 ctx->image_checksum_offset =
74 (unsigned long)&pe64->csum - (unsigned long)pebuf;
75 ctx->header_size = pe64->header_size;
76 cursor += sizeof(*pe64);
77 ctx->n_data_dirents = pe64->data_dirs;
78 break;
79
80 default:
81 pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic);
82 return -ELIBBAD;
83 }
84
85 pr_debug("checksum @ %x\n", ctx->image_checksum_offset);
86 pr_debug("header size = %x\n", ctx->header_size);
87
88 if (cursor >= ctx->header_size || ctx->header_size >= datalen)
89 return -ELIBBAD;
90
91 if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde))
92 return -ELIBBAD;
93
94 ddir = pebuf + cursor;
95 cursor += sizeof(*dde) * ctx->n_data_dirents;
96
97 ctx->cert_dirent_offset =
98 (unsigned long)&ddir->certs - (unsigned long)pebuf;
99 ctx->certs_size = ddir->certs.size;
100
101 if (!ddir->certs.virtual_address || !ddir->certs.size) {
102 pr_debug("Unsigned PE binary\n");
103 return -EKEYREJECTED;
104 }
105
106 chkaddr(ctx->header_size, ddir->certs.virtual_address,
107 ddir->certs.size);
108 ctx->sig_offset = ddir->certs.virtual_address;
109 ctx->sig_len = ddir->certs.size;
110 pr_debug("cert = %x @%x [%*ph]\n",
111 ctx->sig_len, ctx->sig_offset,
112 ctx->sig_len, pebuf + ctx->sig_offset);
113
114 ctx->n_sections = pe->sections;
115 if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec))
116 return -ELIBBAD;
117 ctx->secs = secs = pebuf + cursor;
118
119 return 0;
120}
121
122/*
123 * Check and strip the PE wrapper from around the signature and check that the
124 * remnant looks something like PKCS#7.
125 */
126static int pefile_strip_sig_wrapper(const void *pebuf,
127 struct pefile_context *ctx)
128{
129 struct win_certificate wrapper;
130 const u8 *pkcs7;
131
132 if (ctx->sig_len < sizeof(wrapper)) {
133 pr_debug("Signature wrapper too short\n");
134 return -ELIBBAD;
135 }
136
137 memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper));
138 pr_debug("sig wrapper = { %x, %x, %x }\n",
139 wrapper.length, wrapper.revision, wrapper.cert_type);
140
141 /* Both pesign and sbsign round up the length of certificate table
142 * (in optional header data directories) to 8 byte alignment.
143 */
144 if (round_up(wrapper.length, 8) != ctx->sig_len) {
145 pr_debug("Signature wrapper len wrong\n");
146 return -ELIBBAD;
147 }
148 if (wrapper.revision != WIN_CERT_REVISION_2_0) {
149 pr_debug("Signature is not revision 2.0\n");
150 return -ENOTSUPP;
151 }
152 if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
153 pr_debug("Signature certificate type is not PKCS\n");
154 return -ENOTSUPP;
155 }
156
157 /* Looks like actual pkcs signature length is in wrapper->length.
158 * size obtained from data dir entries lists the total size of
159 * certificate table which is also aligned to octawrod boundary.
160 *
161 * So set signature length field appropriately.
162 */
163 ctx->sig_len = wrapper.length;
164 ctx->sig_offset += sizeof(wrapper);
165 ctx->sig_len -= sizeof(wrapper);
166 if (ctx->sig_len == 0) {
167 pr_debug("Signature data missing\n");
168 return -EKEYREJECTED;
169 }
170
171 /* What's left should a PKCS#7 cert */
172 pkcs7 = pebuf + ctx->sig_offset;
173 if (pkcs7[0] == (ASN1_CONS_BIT | ASN1_SEQ)) {
174 if (pkcs7[1] == 0x82 &&
175 pkcs7[2] == (((ctx->sig_len - 4) >> 8) & 0xff) &&
176 pkcs7[3] == ((ctx->sig_len - 4) & 0xff))
177 return 0;
178 if (pkcs7[1] == 0x80)
179 return 0;
180 if (pkcs7[1] > 0x82)
181 return -EMSGSIZE;
182 }
183
184 pr_debug("Signature data not PKCS#7\n");
185 return -ELIBBAD;
186}
187
188/*
189 * Compare two sections for canonicalisation.
190 */
191static int pefile_compare_shdrs(const void *a, const void *b)
192{
193 const struct section_header *shdra = a;
194 const struct section_header *shdrb = b;
195 int rc;
196
197 if (shdra->data_addr > shdrb->data_addr)
198 return 1;
199 if (shdrb->data_addr > shdra->data_addr)
200 return -1;
201
202 if (shdra->virtual_address > shdrb->virtual_address)
203 return 1;
204 if (shdrb->virtual_address > shdra->virtual_address)
205 return -1;
206
207 rc = strcmp(shdra->name, shdrb->name);
208 if (rc != 0)
209 return rc;
210
211 if (shdra->virtual_size > shdrb->virtual_size)
212 return 1;
213 if (shdrb->virtual_size > shdra->virtual_size)
214 return -1;
215
216 if (shdra->raw_data_size > shdrb->raw_data_size)
217 return 1;
218 if (shdrb->raw_data_size > shdra->raw_data_size)
219 return -1;
220
221 return 0;
222}
223
224/*
225 * Load the contents of the PE binary into the digest, leaving out the image
226 * checksum and the certificate data block.
227 */
228static int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen,
229 struct pefile_context *ctx,
230 struct shash_desc *desc)
231{
232 unsigned *canon, tmp, loop, i, hashed_bytes;
233 int ret;
234
235 /* Digest the header and data directory, but leave out the image
236 * checksum and the data dirent for the signature.
237 */
238 ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset);
239 if (ret < 0)
240 return ret;
241
242 tmp = ctx->image_checksum_offset + sizeof(uint32_t);
243 ret = crypto_shash_update(desc, pebuf + tmp,
244 ctx->cert_dirent_offset - tmp);
245 if (ret < 0)
246 return ret;
247
248 tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent);
249 ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp);
250 if (ret < 0)
251 return ret;
252
253 canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL);
254 if (!canon)
255 return -ENOMEM;
256
257 /* We have to canonicalise the section table, so we perform an
258 * insertion sort.
259 */
260 canon[0] = 0;
261 for (loop = 1; loop < ctx->n_sections; loop++) {
262 for (i = 0; i < loop; i++) {
263 if (pefile_compare_shdrs(&ctx->secs[canon[i]],
264 &ctx->secs[loop]) > 0) {
265 memmove(&canon[i + 1], &canon[i],
266 (loop - i) * sizeof(canon[0]));
267 break;
268 }
269 }
270 canon[i] = loop;
271 }
272
273 hashed_bytes = ctx->header_size;
274 for (loop = 0; loop < ctx->n_sections; loop++) {
275 i = canon[loop];
276 if (ctx->secs[i].raw_data_size == 0)
277 continue;
278 ret = crypto_shash_update(desc,
279 pebuf + ctx->secs[i].data_addr,
280 ctx->secs[i].raw_data_size);
281 if (ret < 0) {
282 kfree(canon);
283 return ret;
284 }
285 hashed_bytes += ctx->secs[i].raw_data_size;
286 }
287 kfree(canon);
288
289 if (pelen > hashed_bytes) {
290 tmp = hashed_bytes + ctx->certs_size;
291 ret = crypto_shash_update(desc,
292 pebuf + hashed_bytes,
293 pelen - tmp);
294 if (ret < 0)
295 return ret;
296 }
297
298 return 0;
299}
300
301/*
302 * Digest the contents of the PE binary, leaving out the image checksum and the
303 * certificate data block.
304 */
305static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
306 struct pefile_context *ctx)
307{
308 struct crypto_shash *tfm;
309 struct shash_desc *desc;
310 size_t digest_size, desc_size;
311 void *digest;
312 int ret;
313
314 kenter(",%u", ctx->digest_algo);
315
316 /* Allocate the hashing algorithm we're going to need and find out how
317 * big the hash operational data will be.
318 */
319 tfm = crypto_alloc_shash(hash_algo_name[ctx->digest_algo], 0, 0);
320 if (IS_ERR(tfm))
321 return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
322
323 desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
324 digest_size = crypto_shash_digestsize(tfm);
325
326 if (digest_size != ctx->digest_len) {
327 pr_debug("Digest size mismatch (%zx != %x)\n",
328 digest_size, ctx->digest_len);
329 ret = -EBADMSG;
330 goto error_no_desc;
331 }
332 pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size);
333
334 ret = -ENOMEM;
335 desc = kzalloc(desc_size + digest_size, GFP_KERNEL);
336 if (!desc)
337 goto error_no_desc;
338
339 desc->tfm = tfm;
340 desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
341 ret = crypto_shash_init(desc);
342 if (ret < 0)
343 goto error;
344
345 ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc);
346 if (ret < 0)
347 goto error;
348
349 digest = (void *)desc + desc_size;
350 ret = crypto_shash_final(desc, digest);
351 if (ret < 0)
352 goto error;
353
354 pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest);
355
356 /* Check that the PE file digest matches that in the MSCODE part of the
357 * PKCS#7 certificate.
358 */
359 if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) {
360 pr_debug("Digest mismatch\n");
361 ret = -EKEYREJECTED;
362 } else {
363 pr_debug("The digests match!\n");
364 }
365
366error:
367 kfree(desc);
368error_no_desc:
369 crypto_free_shash(tfm);
370 kleave(" = %d", ret);
371 return ret;
372}
373
374/**
375 * verify_pefile_signature - Verify the signature on a PE binary image
376 * @pebuf: Buffer containing the PE binary image
377 * @pelen: Length of the binary image
378 * @trust_keyring: Signing certificates to use as starting points
379 * @_trusted: Set to true if trustworth, false otherwise
380 *
381 * Validate that the certificate chain inside the PKCS#7 message inside the PE
382 * binary image intersects keys we already know and trust.
383 *
384 * Returns, in order of descending priority:
385 *
386 * (*) -ELIBBAD if the image cannot be parsed, or:
387 *
388 * (*) -EKEYREJECTED if a signature failed to match for which we have a valid
389 * key, or:
390 *
391 * (*) 0 if at least one signature chain intersects with the keys in the trust
392 * keyring, or:
393 *
394 * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
395 * chain.
396 *
397 * (*) -ENOKEY if we couldn't find a match for any of the signature chains in
398 * the message.
399 *
400 * May also return -ENOMEM.
401 */
402int verify_pefile_signature(const void *pebuf, unsigned pelen,
403 struct key *trusted_keyring, bool *_trusted)
404{
405 struct pkcs7_message *pkcs7;
406 struct pefile_context ctx;
407 const void *data;
408 size_t datalen;
409 int ret;
410
411 kenter("");
412
413 memset(&ctx, 0, sizeof(ctx));
414 ret = pefile_parse_binary(pebuf, pelen, &ctx);
415 if (ret < 0)
416 return ret;
417
418 ret = pefile_strip_sig_wrapper(pebuf, &ctx);
419 if (ret < 0)
420 return ret;
421
422 pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len);
423 if (IS_ERR(pkcs7))
424 return PTR_ERR(pkcs7);
425 ctx.pkcs7 = pkcs7;
426
427 ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false);
428 if (ret < 0 || datalen == 0) {
429 pr_devel("PKCS#7 message does not contain data\n");
430 ret = -EBADMSG;
431 goto error;
432 }
433
434 ret = mscode_parse(&ctx);
435 if (ret < 0)
436 goto error;
437
438 pr_debug("Digest: %u [%*ph]\n",
439 ctx.digest_len, ctx.digest_len, ctx.digest);
440
441 /* Generate the digest and check against the PKCS7 certificate
442 * contents.
443 */
444 ret = pefile_digest_pe(pebuf, pelen, &ctx);
445 if (ret < 0)
446 goto error;
447
448 ret = pkcs7_verify(pkcs7);
449 if (ret < 0)
450 goto error;
451
452 ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted);
453
454error:
455 pkcs7_free_message(ctx.pkcs7);
456 return ret;
457}
diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h
new file mode 100644
index 000000000000..55d5f7ebc45a
--- /dev/null
+++ b/crypto/asymmetric_keys/verify_pefile.h
@@ -0,0 +1,42 @@
1/* PE Binary parser bits
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#include <linux/verify_pefile.h>
13#include <crypto/pkcs7.h>
14#include <crypto/hash_info.h>
15
16struct pefile_context {
17 unsigned header_size;
18 unsigned image_checksum_offset;
19 unsigned cert_dirent_offset;
20 unsigned n_data_dirents;
21 unsigned n_sections;
22 unsigned certs_size;
23 unsigned sig_offset;
24 unsigned sig_len;
25 const struct section_header *secs;
26 struct pkcs7_message *pkcs7;
27
28 /* PKCS#7 MS Individual Code Signing content */
29 const void *digest; /* Digest */
30 unsigned digest_len; /* Digest length */
31 enum hash_algo digest_algo; /* Digest algorithm */
32};
33
34#define kenter(FMT, ...) \
35 pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
36#define kleave(FMT, ...) \
37 pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
38
39/*
40 * mscode_parser.c
41 */
42extern int mscode_parse(struct pefile_context *ctx);
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/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 382ef0d2ff2e..f3d62307e6ee 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -18,11 +18,86 @@
18#include <linux/asn1_decoder.h> 18#include <linux/asn1_decoder.h>
19#include <keys/asymmetric-subtype.h> 19#include <keys/asymmetric-subtype.h>
20#include <keys/asymmetric-parser.h> 20#include <keys/asymmetric-parser.h>
21#include <keys/system_keyring.h>
21#include <crypto/hash.h> 22#include <crypto/hash.h>
22#include "asymmetric_keys.h" 23#include "asymmetric_keys.h"
23#include "public_key.h" 24#include "public_key.h"
24#include "x509_parser.h" 25#include "x509_parser.h"
25 26
27static bool use_builtin_keys;
28static char *ca_keyid;
29
30#ifndef MODULE
31static int __init ca_keys_setup(char *str)
32{
33 if (!str) /* default system keyring */
34 return 1;
35
36 if (strncmp(str, "id:", 3) == 0)
37 ca_keyid = str; /* owner key 'id:xxxxxx' */
38 else if (strcmp(str, "builtin") == 0)
39 use_builtin_keys = true;
40
41 return 1;
42}
43__setup("ca_keys=", ca_keys_setup);
44#endif
45
46/**
47 * x509_request_asymmetric_key - Request a key by X.509 certificate params.
48 * @keyring: The keys to search.
49 * @subject: The name of the subject to whom the key belongs.
50 * @key_id: The subject key ID as a hex string.
51 *
52 * Find a key in the given keyring by subject name and key ID. These might,
53 * for instance, be the issuer name and the authority key ID of an X.509
54 * certificate that needs to be verified.
55 */
56struct key *x509_request_asymmetric_key(struct key *keyring,
57 const char *subject,
58 const char *key_id)
59{
60 key_ref_t key;
61 size_t subject_len = strlen(subject), key_id_len = strlen(key_id);
62 char *id;
63
64 /* Construct an identifier "<subjname>:<keyid>". */
65 id = kmalloc(subject_len + 2 + key_id_len + 1, GFP_KERNEL);
66 if (!id)
67 return ERR_PTR(-ENOMEM);
68
69 memcpy(id, subject, subject_len);
70 id[subject_len + 0] = ':';
71 id[subject_len + 1] = ' ';
72 memcpy(id + subject_len + 2, key_id, key_id_len);
73 id[subject_len + 2 + key_id_len] = 0;
74
75 pr_debug("Look up: \"%s\"\n", id);
76
77 key = keyring_search(make_key_ref(keyring, 1),
78 &key_type_asymmetric, id);
79 if (IS_ERR(key))
80 pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key));
81 kfree(id);
82
83 if (IS_ERR(key)) {
84 switch (PTR_ERR(key)) {
85 /* Hide some search errors */
86 case -EACCES:
87 case -ENOTDIR:
88 case -EAGAIN:
89 return ERR_PTR(-ENOKEY);
90 default:
91 return ERR_CAST(key);
92 }
93 }
94
95 pr_devel("<==%s() = 0 [%x]\n", __func__,
96 key_serial(key_ref_to_ptr(key)));
97 return key_ref_to_ptr(key);
98}
99EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
100
26/* 101/*
27 * Set up the signature parameters in an X.509 certificate. This involves 102 * Set up the signature parameters in an X.509 certificate. This involves
28 * digesting the signed data and extracting the signature. 103 * digesting the signed data and extracting the signature.
@@ -103,6 +178,38 @@ int x509_check_signature(const struct public_key *pub,
103EXPORT_SYMBOL_GPL(x509_check_signature); 178EXPORT_SYMBOL_GPL(x509_check_signature);
104 179
105/* 180/*
181 * Check the new certificate against the ones in the trust keyring. If one of
182 * those is the signing key and validates the new certificate, then mark the
183 * new certificate as being trusted.
184 *
185 * Return 0 if the new certificate was successfully validated, 1 if we couldn't
186 * find a matching parent certificate in the trusted list and an error if there
187 * is a matching certificate but the signature check fails.
188 */
189static int x509_validate_trust(struct x509_certificate *cert,
190 struct key *trust_keyring)
191{
192 struct key *key;
193 int ret = 1;
194
195 if (!trust_keyring)
196 return -EOPNOTSUPP;
197
198 if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid))
199 return -EPERM;
200
201 key = x509_request_asymmetric_key(trust_keyring,
202 cert->issuer, cert->authority);
203 if (!IS_ERR(key)) {
204 if (!use_builtin_keys
205 || test_bit(KEY_FLAG_BUILTIN, &key->flags))
206 ret = x509_check_signature(key->payload.data, cert);
207 key_put(key);
208 }
209 return ret;
210}
211
212/*
106 * Attempt to parse a data blob for a key as an X509 certificate. 213 * Attempt to parse a data blob for a key as an X509 certificate.
107 */ 214 */
108static int x509_key_preparse(struct key_preparsed_payload *prep) 215static int x509_key_preparse(struct key_preparsed_payload *prep)
@@ -155,9 +262,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
155 /* Check the signature on the key if it appears to be self-signed */ 262 /* Check the signature on the key if it appears to be self-signed */
156 if (!cert->authority || 263 if (!cert->authority ||
157 strcmp(cert->fingerprint, cert->authority) == 0) { 264 strcmp(cert->fingerprint, cert->authority) == 0) {
158 ret = x509_check_signature(cert->pub, cert); 265 ret = x509_check_signature(cert->pub, cert); /* self-signed */
159 if (ret < 0) 266 if (ret < 0)
160 goto error_free_cert; 267 goto error_free_cert;
268 } else if (!prep->trusted) {
269 ret = x509_validate_trust(cert, get_system_trusted_keyring());
270 if (!ret)
271 prep->trusted = 1;
161 } 272 }
162 273
163 /* Propose a description */ 274 /* Propose a description */
@@ -177,7 +288,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
177 __module_get(public_key_subtype.owner); 288 __module_get(public_key_subtype.owner);
178 prep->type_data[0] = &public_key_subtype; 289 prep->type_data[0] = &public_key_subtype;
179 prep->type_data[1] = cert->fingerprint; 290 prep->type_data[1] = cert->fingerprint;
180 prep->payload = cert->pub; 291 prep->payload[0] = cert->pub;
181 prep->description = desc; 292 prep->description = desc;
182 prep->quotalen = 100; 293 prep->quotalen = 100;
183 294