diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 11:06:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 11:06:39 -0400 |
commit | bb2cbf5e9367d8598fecd0c48dead69560750223 (patch) | |
tree | fb2c620451b90f41a31726bdd82077813f941e39 /crypto | |
parent | e7fda6c4c3c1a7d6996dd75fd84670fa0b5d448f (diff) | |
parent | 478d085524c57cf4283699f529d5a4c22188ea69 (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/Kconfig | 34 | ||||
-rw-r--r-- | crypto/asymmetric_keys/Makefile | 37 | ||||
-rw-r--r-- | crypto/asymmetric_keys/asymmetric_keys.h | 2 | ||||
-rw-r--r-- | crypto/asymmetric_keys/asymmetric_type.c | 78 | ||||
-rw-r--r-- | crypto/asymmetric_keys/mscode.asn1 | 28 | ||||
-rw-r--r-- | crypto/asymmetric_keys/mscode_parser.c | 126 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7.asn1 | 127 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_key_type.c | 100 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_parser.c | 396 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_parser.h | 61 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_trust.c | 166 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_verify.c | 321 | ||||
-rw-r--r-- | crypto/asymmetric_keys/verify_pefile.c | 457 | ||||
-rw-r--r-- | crypto/asymmetric_keys/verify_pefile.h | 42 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509.asn1 | 2 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 20 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_parser.h | 13 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 115 |
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 | ||
23 | config PUBLIC_KEY_ALGO_RSA | 23 | config 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 | ||
39 | config 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 | |||
48 | config 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 | |||
61 | config 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 | |||
40 | endif # ASYMMETRIC_KEY_TYPE | 70 | endif # 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 | ||
26 | clean-files += x509-asn1.c x509-asn1.h | 26 | clean-files += x509-asn1.c x509-asn1.h |
27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h | 27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h |
28 | |||
29 | # | ||
30 | # PKCS#7 message handling | ||
31 | # | ||
32 | obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o | ||
33 | pkcs7_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 | |||
42 | clean-files += pkcs7-asn1.c pkcs7-asn1.h | ||
43 | |||
44 | # | ||
45 | # PKCS#7 parser testing key | ||
46 | # | ||
47 | obj-$(CONFIG_PKCS7_TEST_KEY) += pkcs7_test_key.o | ||
48 | pkcs7_test_key-y := \ | ||
49 | pkcs7_key_type.o | ||
50 | |||
51 | # | ||
52 | # Signed PE binary-wrapped key handling | ||
53 | # | ||
54 | obj-$(CONFIG_SIGNED_PE_FILE_VERIFICATION) += verify_signed_pefile.o | ||
55 | |||
56 | verify_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 | |||
64 | clean-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 | ||
12 | int asymmetric_keyid_match(const char *kid, const char *id); | ||
13 | |||
12 | static inline const char *asymmetric_key_id(const struct key *key) | 14 | static 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); | |||
23 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | 23 | static 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 | */ | ||
29 | int 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 | } | ||
52 | EXPORT_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 | */ | ||
170 | static 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 | */ |
192 | static void asymmetric_key_destroy(struct key *key) | 182 | static 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 | |||
12 | MSCode ::= 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 | |||
23 | ContentType ::= OBJECT IDENTIFIER ({ mscode_note_content_type }) | ||
24 | |||
25 | DigestAlgorithmIdentifier ::= 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 | */ | ||
24 | int 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 | */ | ||
46 | int 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 | */ | ||
78 | int 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 | */ | ||
117 | int 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 @@ | |||
1 | PKCS7ContentInfo ::= SEQUENCE { | ||
2 | contentType ContentType, | ||
3 | content [0] EXPLICIT SignedData OPTIONAL | ||
4 | } | ||
5 | |||
6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) | ||
7 | |||
8 | SignedData ::= 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 | |||
23 | ContentInfo ::= SEQUENCE { | ||
24 | contentType ContentType, | ||
25 | content [0] EXPLICIT Data OPTIONAL | ||
26 | } | ||
27 | |||
28 | Data ::= ANY ({ pkcs7_note_data }) | ||
29 | |||
30 | DigestAlgorithmIdentifiers ::= CHOICE { | ||
31 | daSet SET OF DigestAlgorithmIdentifier, | ||
32 | daSequence SEQUENCE OF DigestAlgorithmIdentifier | ||
33 | } | ||
34 | |||
35 | DigestAlgorithmIdentifier ::= SEQUENCE { | ||
36 | algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
37 | parameters ANY OPTIONAL | ||
38 | } | ||
39 | |||
40 | -- | ||
41 | -- Certificates and certificate lists | ||
42 | -- | ||
43 | ExtendedCertificatesAndCertificates ::= SET OF ExtendedCertificateOrCertificate | ||
44 | |||
45 | ExtendedCertificateOrCertificate ::= CHOICE { | ||
46 | certificate Certificate, -- X.509 | ||
47 | extendedCertificate [0] IMPLICIT ExtendedCertificate -- PKCS#6 | ||
48 | } | ||
49 | |||
50 | ExtendedCertificate ::= Certificate -- cheating | ||
51 | |||
52 | Certificates ::= SEQUENCE OF Certificate | ||
53 | |||
54 | CertificateRevocationLists ::= SET OF CertificateList | ||
55 | |||
56 | CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly | ||
57 | |||
58 | CRLSequence ::= SEQUENCE OF CertificateList | ||
59 | |||
60 | Certificate ::= ANY ({ pkcs7_extract_cert }) -- X.509 | ||
61 | |||
62 | -- | ||
63 | -- Signer information | ||
64 | -- | ||
65 | SignerInfos ::= CHOICE { | ||
66 | siSet SET OF SignerInfo, | ||
67 | siSequence SEQUENCE OF SignerInfo | ||
68 | } | ||
69 | |||
70 | SignerInfo ::= 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 | |||
91 | IssuerAndSerialNumber ::= SEQUENCE { | ||
92 | issuer Name ({ pkcs7_sig_note_issuer }), | ||
93 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) | ||
94 | } | ||
95 | |||
96 | CertificateSerialNumber ::= INTEGER | ||
97 | |||
98 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute | ||
99 | |||
100 | AuthenticatedAttribute ::= SEQUENCE { | ||
101 | type OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
102 | values SET OF ANY ({ pkcs7_sig_note_authenticated_attr }) | ||
103 | } | ||
104 | |||
105 | UnauthenticatedAttribute ::= SEQUENCE { | ||
106 | type OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
107 | values SET OF ANY | ||
108 | } | ||
109 | |||
110 | DigestEncryptionAlgorithmIdentifier ::= SEQUENCE { | ||
111 | algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
112 | parameters ANY OPTIONAL | ||
113 | } | ||
114 | |||
115 | EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature }) | ||
116 | |||
117 | --- | ||
118 | --- X.500 Name | ||
119 | --- | ||
120 | Name ::= SEQUENCE OF RelativeDistinguishedName | ||
121 | |||
122 | RelativeDistinguishedName ::= SET OF AttributeValueAssertion | ||
123 | |||
124 | AttributeValueAssertion ::= 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 | */ | ||
24 | static 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 | |||
62 | error_free: | ||
63 | pkcs7_free_message(pkcs7); | ||
64 | error: | ||
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 | */ | ||
73 | static 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 | */ | ||
89 | static int __init pkcs7_key_init(void) | ||
90 | { | ||
91 | return register_key_type(&key_type_pkcs7); | ||
92 | } | ||
93 | |||
94 | static void __exit pkcs7_key_cleanup(void) | ||
95 | { | ||
96 | unregister_key_type(&key_type_pkcs7); | ||
97 | } | ||
98 | |||
99 | module_init(pkcs7_key_init); | ||
100 | module_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 | |||
22 | struct 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 | */ | ||
38 | void 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 | } | ||
64 | EXPORT_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 | */ | ||
71 | struct 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 | |||
109 | error_decode: | ||
110 | mpi_free(ctx->sinfo->sig.mpi[0]); | ||
111 | kfree(ctx->sinfo->sig.digest); | ||
112 | kfree(ctx->sinfo); | ||
113 | error_no_sinfo: | ||
114 | kfree(ctx); | ||
115 | error_no_ctx: | ||
116 | pkcs7_free_message(msg); | ||
117 | error_no_sig: | ||
118 | return ERR_PTR(ret); | ||
119 | } | ||
120 | EXPORT_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 | */ | ||
133 | int 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 | } | ||
147 | EXPORT_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 | */ | ||
153 | int 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 | */ | ||
172 | int 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 | */ | ||
201 | int 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 | */ | ||
221 | int 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 | */ | ||
261 | int 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 | */ | ||
280 | int 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 | */ | ||
298 | int 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 | */ | ||
321 | int 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 | */ | ||
336 | int 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 | */ | ||
349 | int 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 | */ | ||
362 | int 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 | */ | ||
383 | int 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 | |||
21 | struct 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 | |||
51 | struct 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 | */ | ||
26 | int 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 | |||
91 | matched: | ||
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 | |||
102 | verified: | ||
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 | */ | ||
138 | int 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 | } | ||
166 | EXPORT_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 | */ | ||
25 | static 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 | |||
114 | error: | ||
115 | kfree(digest); | ||
116 | error_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 | */ | ||
128 | static 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 | */ | ||
175 | static 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 | */ | ||
258 | static 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 | */ | ||
295 | int 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 | } | ||
321 | EXPORT_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 | */ | ||
26 | static 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 | */ | ||
126 | static 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 | */ | ||
191 | static 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 | */ | ||
228 | static 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 | */ | ||
305 | static 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 | |||
366 | error: | ||
367 | kfree(desc); | ||
368 | error_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 | */ | ||
402 | int 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 | |||
454 | error: | ||
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 | |||
16 | struct 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 | */ | ||
42 | extern 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 | ||
7 | TBSCertificate ::= SEQUENCE { | 7 | TBSCertificate ::= 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 | } |
56 | EXPORT_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: | |||
97 | error_no_cert: | 99 | error_no_cert: |
98 | return ERR_PTR(ret); | 100 | return ERR_PTR(ret); |
99 | } | 101 | } |
102 | EXPORT_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 | */ | ||
219 | int 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 | */ |
216 | int x509_extract_name_segment(void *context, size_t hdrlen, | 232 | int 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 | ||
15 | struct x509_certificate { | 15 | struct 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 | ||
27 | static bool use_builtin_keys; | ||
28 | static char *ca_keyid; | ||
29 | |||
30 | #ifndef MODULE | ||
31 | static 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 | */ | ||
56 | struct 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 | } | ||
99 | EXPORT_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, | |||
103 | EXPORT_SYMBOL_GPL(x509_check_signature); | 178 | EXPORT_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 | */ | ||
189 | static 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 | */ |
108 | static int x509_key_preparse(struct key_preparsed_payload *prep) | 215 | static 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 | ||