diff options
48 files changed, 3025 insertions, 217 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 8b2ab548b6e4..90c12c591168 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
566 | possible to determine what the correct size should be. | 566 | possible to determine what the correct size should be. |
567 | This option provides an override for these situations. | 567 | This option provides an override for these situations. |
568 | 568 | ||
569 | ca_keys= [KEYS] This parameter identifies a specific key(s) on | ||
570 | the system trusted keyring to be used for certificate | ||
571 | trust validation. | ||
572 | format: { id:<keyid> | builtin } | ||
573 | |||
569 | ccw_timeout_log [S390] | 574 | ccw_timeout_log [S390] |
570 | See Documentation/s390/CommonIO for details. | 575 | See Documentation/s390/CommonIO for details. |
571 | 576 | ||
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index a4c33f1a7c6d..8727c194ca16 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt | |||
@@ -1150,20 +1150,24 @@ The structure has a number of fields, some of which are mandatory: | |||
1150 | const void *data; | 1150 | const void *data; |
1151 | size_t datalen; | 1151 | size_t datalen; |
1152 | size_t quotalen; | 1152 | size_t quotalen; |
1153 | time_t expiry; | ||
1153 | }; | 1154 | }; |
1154 | 1155 | ||
1155 | Before calling the method, the caller will fill in data and datalen with | 1156 | Before calling the method, the caller will fill in data and datalen with |
1156 | the payload blob parameters; quotalen will be filled in with the default | 1157 | the payload blob parameters; quotalen will be filled in with the default |
1157 | quota size from the key type and the rest will be cleared. | 1158 | quota size from the key type; expiry will be set to TIME_T_MAX and the |
1159 | rest will be cleared. | ||
1158 | 1160 | ||
1159 | If a description can be proposed from the payload contents, that should be | 1161 | If a description can be proposed from the payload contents, that should be |
1160 | attached as a string to the description field. This will be used for the | 1162 | attached as a string to the description field. This will be used for the |
1161 | key description if the caller of add_key() passes NULL or "". | 1163 | key description if the caller of add_key() passes NULL or "". |
1162 | 1164 | ||
1163 | The method can attach anything it likes to type_data[] and payload. These | 1165 | The method can attach anything it likes to type_data[] and payload. These |
1164 | are merely passed along to the instantiate() or update() operations. | 1166 | are merely passed along to the instantiate() or update() operations. If |
1167 | set, the expiry time will be applied to the key if it is instantiated from | ||
1168 | this data. | ||
1165 | 1169 | ||
1166 | The method should return 0 if success ful or a negative error code | 1170 | The method should return 0 if successful or a negative error code |
1167 | otherwise. | 1171 | otherwise. |
1168 | 1172 | ||
1169 | 1173 | ||
@@ -1172,7 +1176,9 @@ The structure has a number of fields, some of which are mandatory: | |||
1172 | This method is only required if the preparse() method is provided, | 1176 | This method is only required if the preparse() method is provided, |
1173 | otherwise it is unused. It cleans up anything attached to the | 1177 | otherwise it is unused. It cleans up anything attached to the |
1174 | description, type_data and payload fields of the key_preparsed_payload | 1178 | description, type_data and payload fields of the key_preparsed_payload |
1175 | struct as filled in by the preparse() method. | 1179 | struct as filled in by the preparse() method. It will always be called |
1180 | after preparse() returns successfully, even if instantiate() or update() | ||
1181 | succeed. | ||
1176 | 1182 | ||
1177 | 1183 | ||
1178 | (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); | 1184 | (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); |
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..c2091f7bd15d --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_key_type.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* Testing module to load key from trusted PKCS#7 message | ||
2 | * | ||
3 | * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "PKCS7key: "fmt | ||
13 | #include <linux/key.h> | ||
14 | #include <linux/key-type.h> | ||
15 | #include <crypto/pkcs7.h> | ||
16 | #include <keys/user-type.h> | ||
17 | #include <keys/system_keyring.h> | ||
18 | #include "pkcs7_parser.h" | ||
19 | |||
20 | /* | ||
21 | * Preparse a PKCS#7 wrapped and validated data blob. | ||
22 | */ | ||
23 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | ||
24 | { | ||
25 | struct pkcs7_message *pkcs7; | ||
26 | const void *data, *saved_prep_data; | ||
27 | size_t datalen, saved_prep_datalen; | ||
28 | bool trusted; | ||
29 | int ret; | ||
30 | |||
31 | kenter(""); | ||
32 | |||
33 | saved_prep_data = prep->data; | ||
34 | saved_prep_datalen = prep->datalen; | ||
35 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); | ||
36 | if (IS_ERR(pkcs7)) { | ||
37 | ret = PTR_ERR(pkcs7); | ||
38 | goto error; | ||
39 | } | ||
40 | |||
41 | ret = pkcs7_verify(pkcs7); | ||
42 | if (ret < 0) | ||
43 | goto error_free; | ||
44 | |||
45 | ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); | ||
46 | if (ret < 0) | ||
47 | goto error_free; | ||
48 | if (!trusted) | ||
49 | pr_warn("PKCS#7 message doesn't chain back to a trusted key\n"); | ||
50 | |||
51 | ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false); | ||
52 | if (ret < 0) | ||
53 | goto error_free; | ||
54 | |||
55 | prep->data = data; | ||
56 | prep->datalen = datalen; | ||
57 | ret = user_preparse(prep); | ||
58 | prep->data = saved_prep_data; | ||
59 | prep->datalen = saved_prep_datalen; | ||
60 | |||
61 | error_free: | ||
62 | pkcs7_free_message(pkcs7); | ||
63 | error: | ||
64 | kleave(" = %d", ret); | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * user defined keys take an arbitrary string as the description and an | ||
70 | * arbitrary blob of data as the payload | ||
71 | */ | ||
72 | struct key_type key_type_pkcs7 = { | ||
73 | .name = "pkcs7_test", | ||
74 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | ||
75 | .preparse = pkcs7_preparse, | ||
76 | .free_preparse = user_free_preparse, | ||
77 | .instantiate = generic_key_instantiate, | ||
78 | .match = user_match, | ||
79 | .revoke = user_revoke, | ||
80 | .destroy = user_destroy, | ||
81 | .describe = user_describe, | ||
82 | .read = user_read, | ||
83 | }; | ||
84 | |||
85 | /* | ||
86 | * Module stuff | ||
87 | */ | ||
88 | static int __init pkcs7_key_init(void) | ||
89 | { | ||
90 | return register_key_type(&key_type_pkcs7); | ||
91 | } | ||
92 | |||
93 | static void __exit pkcs7_key_cleanup(void) | ||
94 | { | ||
95 | unregister_key_type(&key_type_pkcs7); | ||
96 | } | ||
97 | |||
98 | module_init(pkcs7_key_init); | ||
99 | 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..b6b045131403 --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
@@ -0,0 +1,219 @@ | |||
1 | /* Validate the trust chain of a PKCS#7 message. | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "PKCS7: "fmt | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/export.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/asn1.h> | ||
18 | #include <linux/key.h> | ||
19 | #include <keys/asymmetric-type.h> | ||
20 | #include "public_key.h" | ||
21 | #include "pkcs7_parser.h" | ||
22 | |||
23 | /* | ||
24 | * Request an asymmetric key. | ||
25 | */ | ||
26 | static struct key *pkcs7_request_asymmetric_key( | ||
27 | struct key *keyring, | ||
28 | const char *signer, size_t signer_len, | ||
29 | const char *authority, size_t auth_len) | ||
30 | { | ||
31 | key_ref_t key; | ||
32 | char *id; | ||
33 | |||
34 | kenter(",%zu,,%zu", signer_len, auth_len); | ||
35 | |||
36 | /* Construct an identifier. */ | ||
37 | id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); | ||
38 | if (!id) | ||
39 | return ERR_PTR(-ENOMEM); | ||
40 | |||
41 | memcpy(id, signer, signer_len); | ||
42 | id[signer_len + 0] = ':'; | ||
43 | id[signer_len + 1] = ' '; | ||
44 | memcpy(id + signer_len + 2, authority, auth_len); | ||
45 | id[signer_len + 2 + auth_len] = 0; | ||
46 | |||
47 | pr_debug("Look up: \"%s\"\n", id); | ||
48 | |||
49 | key = keyring_search(make_key_ref(keyring, 1), | ||
50 | &key_type_asymmetric, id); | ||
51 | if (IS_ERR(key)) | ||
52 | pr_debug("Request for module key '%s' err %ld\n", | ||
53 | id, PTR_ERR(key)); | ||
54 | kfree(id); | ||
55 | |||
56 | if (IS_ERR(key)) { | ||
57 | switch (PTR_ERR(key)) { | ||
58 | /* Hide some search errors */ | ||
59 | case -EACCES: | ||
60 | case -ENOTDIR: | ||
61 | case -EAGAIN: | ||
62 | return ERR_PTR(-ENOKEY); | ||
63 | default: | ||
64 | return ERR_CAST(key); | ||
65 | } | ||
66 | } | ||
67 | |||
68 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); | ||
69 | return key_ref_to_ptr(key); | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * Check the trust on one PKCS#7 SignedInfo block. | ||
74 | */ | ||
75 | int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | ||
76 | struct pkcs7_signed_info *sinfo, | ||
77 | struct key *trust_keyring) | ||
78 | { | ||
79 | struct public_key_signature *sig = &sinfo->sig; | ||
80 | struct x509_certificate *x509, *last = NULL, *p; | ||
81 | struct key *key; | ||
82 | bool trusted; | ||
83 | int ret; | ||
84 | |||
85 | kenter(",%u,", sinfo->index); | ||
86 | |||
87 | for (x509 = sinfo->signer; x509; x509 = x509->signer) { | ||
88 | if (x509->seen) { | ||
89 | if (x509->verified) { | ||
90 | trusted = x509->trusted; | ||
91 | goto verified; | ||
92 | } | ||
93 | kleave(" = -ENOKEY [cached]"); | ||
94 | return -ENOKEY; | ||
95 | } | ||
96 | x509->seen = true; | ||
97 | |||
98 | /* Look to see if this certificate is present in the trusted | ||
99 | * keys. | ||
100 | */ | ||
101 | key = pkcs7_request_asymmetric_key( | ||
102 | trust_keyring, | ||
103 | x509->subject, strlen(x509->subject), | ||
104 | x509->fingerprint, strlen(x509->fingerprint)); | ||
105 | if (!IS_ERR(key)) | ||
106 | /* One of the X.509 certificates in the PKCS#7 message | ||
107 | * is apparently the same as one we already trust. | ||
108 | * Verify that the trusted variant can also validate | ||
109 | * the signature on the descendant. | ||
110 | */ | ||
111 | goto matched; | ||
112 | if (key == ERR_PTR(-ENOMEM)) | ||
113 | return -ENOMEM; | ||
114 | |||
115 | /* Self-signed certificates form roots of their own, and if we | ||
116 | * don't know them, then we can't accept them. | ||
117 | */ | ||
118 | if (x509->next == x509) { | ||
119 | kleave(" = -ENOKEY [unknown self-signed]"); | ||
120 | return -ENOKEY; | ||
121 | } | ||
122 | |||
123 | might_sleep(); | ||
124 | last = x509; | ||
125 | sig = &last->sig; | ||
126 | } | ||
127 | |||
128 | /* No match - see if the root certificate has a signer amongst the | ||
129 | * trusted keys. | ||
130 | */ | ||
131 | if (!last || !last->issuer || !last->authority) { | ||
132 | kleave(" = -ENOKEY [no backref]"); | ||
133 | return -ENOKEY; | ||
134 | } | ||
135 | |||
136 | key = pkcs7_request_asymmetric_key( | ||
137 | trust_keyring, | ||
138 | last->issuer, strlen(last->issuer), | ||
139 | last->authority, strlen(last->authority)); | ||
140 | if (IS_ERR(key)) | ||
141 | return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY; | ||
142 | x509 = last; | ||
143 | |||
144 | matched: | ||
145 | ret = verify_signature(key, sig); | ||
146 | trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags); | ||
147 | key_put(key); | ||
148 | if (ret < 0) { | ||
149 | if (ret == -ENOMEM) | ||
150 | return ret; | ||
151 | kleave(" = -EKEYREJECTED [verify %d]", ret); | ||
152 | return -EKEYREJECTED; | ||
153 | } | ||
154 | |||
155 | verified: | ||
156 | x509->verified = true; | ||
157 | for (p = sinfo->signer; p != x509; p = p->signer) { | ||
158 | p->verified = true; | ||
159 | p->trusted = trusted; | ||
160 | } | ||
161 | sinfo->trusted = trusted; | ||
162 | kleave(" = 0"); | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * pkcs7_validate_trust - Validate PKCS#7 trust chain | ||
168 | * @pkcs7: The PKCS#7 certificate to validate | ||
169 | * @trust_keyring: Signing certificates to use as starting points | ||
170 | * @_trusted: Set to true if trustworth, false otherwise | ||
171 | * | ||
172 | * Validate that the certificate chain inside the PKCS#7 message intersects | ||
173 | * keys we already know and trust. | ||
174 | * | ||
175 | * Returns, in order of descending priority: | ||
176 | * | ||
177 | * (*) -EKEYREJECTED if a signature failed to match for which we have a valid | ||
178 | * key, or: | ||
179 | * | ||
180 | * (*) 0 if at least one signature chain intersects with the keys in the trust | ||
181 | * keyring, or: | ||
182 | * | ||
183 | * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a | ||
184 | * chain. | ||
185 | * | ||
186 | * (*) -ENOKEY if we couldn't find a match for any of the signature chains in | ||
187 | * the message. | ||
188 | * | ||
189 | * May also return -ENOMEM. | ||
190 | */ | ||
191 | int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | ||
192 | struct key *trust_keyring, | ||
193 | bool *_trusted) | ||
194 | { | ||
195 | struct pkcs7_signed_info *sinfo; | ||
196 | struct x509_certificate *p; | ||
197 | int cached_ret = 0, ret; | ||
198 | |||
199 | for (p = pkcs7->certs; p; p = p->next) | ||
200 | p->seen = false; | ||
201 | |||
202 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | ||
203 | ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); | ||
204 | if (ret < 0) { | ||
205 | if (ret == -ENOPKG) { | ||
206 | cached_ret = -ENOPKG; | ||
207 | } else if (ret == -ENOKEY) { | ||
208 | if (cached_ret == 0) | ||
209 | cached_ret = -ENOKEY; | ||
210 | } else { | ||
211 | return ret; | ||
212 | } | ||
213 | } | ||
214 | *_trusted |= sinfo->trusted; | ||
215 | } | ||
216 | |||
217 | return cached_ret; | ||
218 | } | ||
219 | 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..51ff36f3a913 --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
@@ -0,0 +1,323 @@ | |||
1 | /* Verify the signature on a PKCS#7 message. | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "PKCS7: "fmt | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/export.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/asn1.h> | ||
18 | #include <crypto/hash.h> | ||
19 | #include "public_key.h" | ||
20 | #include "pkcs7_parser.h" | ||
21 | |||
22 | /* | ||
23 | * Digest the relevant parts of the PKCS#7 data | ||
24 | */ | ||
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 | if (x509->issuer) | ||
194 | pr_debug("- issuer %s\n", x509->issuer); | ||
195 | if (x509->authority) | ||
196 | pr_debug("- authkeyid %s\n", x509->authority); | ||
197 | |||
198 | if (!x509->authority || | ||
199 | (x509->subject && | ||
200 | strcmp(x509->subject, x509->issuer) == 0)) { | ||
201 | /* If there's no authority certificate specified, then | ||
202 | * the certificate must be self-signed and is the root | ||
203 | * of the chain. Likewise if the cert is its own | ||
204 | * authority. | ||
205 | */ | ||
206 | pr_debug("- no auth?\n"); | ||
207 | if (x509->raw_subject_size != x509->raw_issuer_size || | ||
208 | memcmp(x509->raw_subject, x509->raw_issuer, | ||
209 | x509->raw_issuer_size) != 0) | ||
210 | return 0; | ||
211 | |||
212 | ret = x509_check_signature(x509->pub, x509); | ||
213 | if (ret < 0) | ||
214 | return ret; | ||
215 | x509->signer = x509; | ||
216 | pr_debug("- self-signed\n"); | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | /* Look through the X.509 certificates in the PKCS#7 message's | ||
221 | * list to see if the next one is there. | ||
222 | */ | ||
223 | pr_debug("- want %s\n", x509->authority); | ||
224 | for (p = pkcs7->certs; p; p = p->next) { | ||
225 | pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint); | ||
226 | if (p->raw_subject_size == x509->raw_issuer_size && | ||
227 | strcmp(p->fingerprint, x509->authority) == 0 && | ||
228 | memcmp(p->raw_subject, x509->raw_issuer, | ||
229 | x509->raw_issuer_size) == 0) | ||
230 | goto found_issuer; | ||
231 | } | ||
232 | |||
233 | /* We didn't find the root of this chain */ | ||
234 | pr_debug("- top\n"); | ||
235 | return 0; | ||
236 | |||
237 | found_issuer: | ||
238 | pr_debug("- issuer %s\n", p->subject); | ||
239 | if (p->seen) { | ||
240 | pr_warn("Sig %u: X.509 chain contains loop\n", | ||
241 | sinfo->index); | ||
242 | return 0; | ||
243 | } | ||
244 | ret = x509_check_signature(p->pub, x509); | ||
245 | if (ret < 0) | ||
246 | return ret; | ||
247 | x509->signer = p; | ||
248 | if (x509 == p) { | ||
249 | pr_debug("- self-signed\n"); | ||
250 | return 0; | ||
251 | } | ||
252 | x509 = p; | ||
253 | might_sleep(); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * Verify one signed information block from a PKCS#7 message. | ||
259 | */ | ||
260 | static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | ||
261 | struct pkcs7_signed_info *sinfo) | ||
262 | { | ||
263 | int ret; | ||
264 | |||
265 | kenter(",%u", sinfo->index); | ||
266 | |||
267 | /* First of all, digest the data in the PKCS#7 message and the | ||
268 | * signed information block | ||
269 | */ | ||
270 | ret = pkcs7_digest(pkcs7, sinfo); | ||
271 | if (ret < 0) | ||
272 | return ret; | ||
273 | |||
274 | /* Find the key for the signature */ | ||
275 | ret = pkcs7_find_key(pkcs7, sinfo); | ||
276 | if (ret < 0) | ||
277 | return ret; | ||
278 | |||
279 | pr_devel("Using X.509[%u] for sig %u\n", | ||
280 | sinfo->signer->index, sinfo->index); | ||
281 | |||
282 | /* Verify the PKCS#7 binary against the key */ | ||
283 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); | ||
284 | if (ret < 0) | ||
285 | return ret; | ||
286 | |||
287 | pr_devel("Verified signature %u\n", sinfo->index); | ||
288 | |||
289 | /* Verify the internal certificate chain */ | ||
290 | return pkcs7_verify_sig_chain(pkcs7, sinfo); | ||
291 | } | ||
292 | |||
293 | /** | ||
294 | * pkcs7_verify - Verify a PKCS#7 message | ||
295 | * @pkcs7: The PKCS#7 message to be verified | ||
296 | */ | ||
297 | int pkcs7_verify(struct pkcs7_message *pkcs7) | ||
298 | { | ||
299 | struct pkcs7_signed_info *sinfo; | ||
300 | struct x509_certificate *x509; | ||
301 | int ret, n; | ||
302 | |||
303 | kenter(""); | ||
304 | |||
305 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { | ||
306 | ret = x509_get_sig_params(x509); | ||
307 | if (ret < 0) | ||
308 | return ret; | ||
309 | pr_debug("X.509[%u] %s\n", n, x509->authority); | ||
310 | } | ||
311 | |||
312 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | ||
313 | ret = pkcs7_verify_one(pkcs7, sinfo); | ||
314 | if (ret < 0) { | ||
315 | kleave(" = %d", ret); | ||
316 | return ret; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | kleave(" = 0"); | ||
321 | return 0; | ||
322 | } | ||
323 | 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..a0f7cd196c9b 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
@@ -18,11 +18,80 @@ | |||
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 | * Find a key in the given keyring by issuer and authority. | ||
48 | */ | ||
49 | static struct key *x509_request_asymmetric_key(struct key *keyring, | ||
50 | const char *signer, | ||
51 | size_t signer_len, | ||
52 | const char *authority, | ||
53 | size_t auth_len) | ||
54 | { | ||
55 | key_ref_t key; | ||
56 | char *id; | ||
57 | |||
58 | /* Construct an identifier. */ | ||
59 | id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL); | ||
60 | if (!id) | ||
61 | return ERR_PTR(-ENOMEM); | ||
62 | |||
63 | memcpy(id, signer, signer_len); | ||
64 | id[signer_len + 0] = ':'; | ||
65 | id[signer_len + 1] = ' '; | ||
66 | memcpy(id + signer_len + 2, authority, auth_len); | ||
67 | id[signer_len + 2 + auth_len] = 0; | ||
68 | |||
69 | pr_debug("Look up: \"%s\"\n", id); | ||
70 | |||
71 | key = keyring_search(make_key_ref(keyring, 1), | ||
72 | &key_type_asymmetric, id); | ||
73 | if (IS_ERR(key)) | ||
74 | pr_debug("Request for module key '%s' err %ld\n", | ||
75 | id, PTR_ERR(key)); | ||
76 | kfree(id); | ||
77 | |||
78 | if (IS_ERR(key)) { | ||
79 | switch (PTR_ERR(key)) { | ||
80 | /* Hide some search errors */ | ||
81 | case -EACCES: | ||
82 | case -ENOTDIR: | ||
83 | case -EAGAIN: | ||
84 | return ERR_PTR(-ENOKEY); | ||
85 | default: | ||
86 | return ERR_CAST(key); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | pr_devel("<==%s() = 0 [%x]\n", __func__, | ||
91 | key_serial(key_ref_to_ptr(key))); | ||
92 | return key_ref_to_ptr(key); | ||
93 | } | ||
94 | |||
26 | /* | 95 | /* |
27 | * Set up the signature parameters in an X.509 certificate. This involves | 96 | * Set up the signature parameters in an X.509 certificate. This involves |
28 | * digesting the signed data and extracting the signature. | 97 | * digesting the signed data and extracting the signature. |
@@ -103,6 +172,40 @@ int x509_check_signature(const struct public_key *pub, | |||
103 | EXPORT_SYMBOL_GPL(x509_check_signature); | 172 | EXPORT_SYMBOL_GPL(x509_check_signature); |
104 | 173 | ||
105 | /* | 174 | /* |
175 | * Check the new certificate against the ones in the trust keyring. If one of | ||
176 | * those is the signing key and validates the new certificate, then mark the | ||
177 | * new certificate as being trusted. | ||
178 | * | ||
179 | * Return 0 if the new certificate was successfully validated, 1 if we couldn't | ||
180 | * find a matching parent certificate in the trusted list and an error if there | ||
181 | * is a matching certificate but the signature check fails. | ||
182 | */ | ||
183 | static int x509_validate_trust(struct x509_certificate *cert, | ||
184 | struct key *trust_keyring) | ||
185 | { | ||
186 | struct key *key; | ||
187 | int ret = 1; | ||
188 | |||
189 | if (!trust_keyring) | ||
190 | return -EOPNOTSUPP; | ||
191 | |||
192 | if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid)) | ||
193 | return -EPERM; | ||
194 | |||
195 | key = x509_request_asymmetric_key(trust_keyring, | ||
196 | cert->issuer, strlen(cert->issuer), | ||
197 | cert->authority, | ||
198 | strlen(cert->authority)); | ||
199 | if (!IS_ERR(key)) { | ||
200 | if (!use_builtin_keys | ||
201 | || test_bit(KEY_FLAG_BUILTIN, &key->flags)) | ||
202 | ret = x509_check_signature(key->payload.data, cert); | ||
203 | key_put(key); | ||
204 | } | ||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | /* | ||
106 | * Attempt to parse a data blob for a key as an X509 certificate. | 209 | * Attempt to parse a data blob for a key as an X509 certificate. |
107 | */ | 210 | */ |
108 | static int x509_key_preparse(struct key_preparsed_payload *prep) | 211 | static int x509_key_preparse(struct key_preparsed_payload *prep) |
@@ -155,9 +258,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 */ | 258 | /* Check the signature on the key if it appears to be self-signed */ |
156 | if (!cert->authority || | 259 | if (!cert->authority || |
157 | strcmp(cert->fingerprint, cert->authority) == 0) { | 260 | strcmp(cert->fingerprint, cert->authority) == 0) { |
158 | ret = x509_check_signature(cert->pub, cert); | 261 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ |
159 | if (ret < 0) | 262 | if (ret < 0) |
160 | goto error_free_cert; | 263 | goto error_free_cert; |
264 | } else if (!prep->trusted) { | ||
265 | ret = x509_validate_trust(cert, get_system_trusted_keyring()); | ||
266 | if (!ret) | ||
267 | prep->trusted = 1; | ||
161 | } | 268 | } |
162 | 269 | ||
163 | /* Propose a description */ | 270 | /* Propose a description */ |
@@ -177,7 +284,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
177 | __module_get(public_key_subtype.owner); | 284 | __module_get(public_key_subtype.owner); |
178 | prep->type_data[0] = &public_key_subtype; | 285 | prep->type_data[0] = &public_key_subtype; |
179 | prep->type_data[1] = cert->fingerprint; | 286 | prep->type_data[1] = cert->fingerprint; |
180 | prep->payload = cert->pub; | 287 | prep->payload[0] = cert->pub; |
181 | prep->description = desc; | 288 | prep->description = desc; |
182 | prep->quotalen = 100; | 289 | prep->quotalen = 100; |
183 | 290 | ||
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 567983d2c0eb..7dd55b745c4d 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -174,7 +174,9 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen) | |||
174 | 174 | ||
175 | static struct key_type key_type_id_resolver = { | 175 | static struct key_type key_type_id_resolver = { |
176 | .name = "id_resolver", | 176 | .name = "id_resolver", |
177 | .instantiate = user_instantiate, | 177 | .preparse = user_preparse, |
178 | .free_preparse = user_free_preparse, | ||
179 | .instantiate = generic_key_instantiate, | ||
178 | .match = user_match, | 180 | .match = user_match, |
179 | .revoke = user_revoke, | 181 | .revoke = user_revoke, |
180 | .destroy = user_destroy, | 182 | .destroy = user_destroy, |
@@ -282,6 +284,8 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen, | |||
282 | desc, "", 0, idmap); | 284 | desc, "", 0, idmap); |
283 | mutex_unlock(&idmap->idmap_mutex); | 285 | mutex_unlock(&idmap->idmap_mutex); |
284 | } | 286 | } |
287 | if (!IS_ERR(rkey)) | ||
288 | set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); | ||
285 | 289 | ||
286 | kfree(desc); | 290 | kfree(desc); |
287 | return rkey; | 291 | return rkey; |
@@ -394,7 +398,9 @@ static const struct rpc_pipe_ops idmap_upcall_ops = { | |||
394 | 398 | ||
395 | static struct key_type key_type_id_resolver_legacy = { | 399 | static struct key_type key_type_id_resolver_legacy = { |
396 | .name = "id_legacy", | 400 | .name = "id_legacy", |
397 | .instantiate = user_instantiate, | 401 | .preparse = user_preparse, |
402 | .free_preparse = user_free_preparse, | ||
403 | .instantiate = generic_key_instantiate, | ||
398 | .match = user_match, | 404 | .match = user_match, |
399 | .revoke = user_revoke, | 405 | .revoke = user_revoke, |
400 | .destroy = user_destroy, | 406 | .destroy = user_destroy, |
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h new file mode 100644 index 000000000000..691c79172a26 --- /dev/null +++ b/include/crypto/pkcs7.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* PKCS#7 crypto data parser | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | struct key; | ||
13 | struct pkcs7_message; | ||
14 | |||
15 | /* | ||
16 | * pkcs7_parser.c | ||
17 | */ | ||
18 | extern struct pkcs7_message *pkcs7_parse_message(const void *data, | ||
19 | size_t datalen); | ||
20 | extern void pkcs7_free_message(struct pkcs7_message *pkcs7); | ||
21 | |||
22 | extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, | ||
23 | const void **_data, size_t *_datalen, | ||
24 | bool want_wrapper); | ||
25 | |||
26 | /* | ||
27 | * pkcs7_trust.c | ||
28 | */ | ||
29 | extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | ||
30 | struct key *trust_keyring, | ||
31 | bool *_trusted); | ||
32 | |||
33 | /* | ||
34 | * pkcs7_verify.c | ||
35 | */ | ||
36 | extern int pkcs7_verify(struct pkcs7_message *pkcs7); | ||
diff --git a/include/keys/big_key-type.h b/include/keys/big_key-type.h index d69bc8af3292..e0970a578188 100644 --- a/include/keys/big_key-type.h +++ b/include/keys/big_key-type.h | |||
@@ -16,7 +16,8 @@ | |||
16 | 16 | ||
17 | extern struct key_type key_type_big_key; | 17 | extern struct key_type key_type_big_key; |
18 | 18 | ||
19 | extern int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep); | 19 | extern int big_key_preparse(struct key_preparsed_payload *prep); |
20 | extern void big_key_free_preparse(struct key_preparsed_payload *prep); | ||
20 | extern void big_key_revoke(struct key *key); | 21 | extern void big_key_revoke(struct key *key); |
21 | extern void big_key_destroy(struct key *key); | 22 | extern void big_key_destroy(struct key *key); |
22 | extern void big_key_describe(const struct key *big_key, struct seq_file *m); | 23 | extern void big_key_describe(const struct key *big_key, struct seq_file *m); |
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h index 8dabc399bd1d..72665eb80692 100644 --- a/include/keys/system_keyring.h +++ b/include/keys/system_keyring.h | |||
@@ -17,7 +17,15 @@ | |||
17 | #include <linux/key.h> | 17 | #include <linux/key.h> |
18 | 18 | ||
19 | extern struct key *system_trusted_keyring; | 19 | extern struct key *system_trusted_keyring; |
20 | 20 | static inline struct key *get_system_trusted_keyring(void) | |
21 | { | ||
22 | return system_trusted_keyring; | ||
23 | } | ||
24 | #else | ||
25 | static inline struct key *get_system_trusted_keyring(void) | ||
26 | { | ||
27 | return NULL; | ||
28 | } | ||
21 | #endif | 29 | #endif |
22 | 30 | ||
23 | #endif /* _KEYS_SYSTEM_KEYRING_H */ | 31 | #endif /* _KEYS_SYSTEM_KEYRING_H */ |
diff --git a/include/keys/user-type.h b/include/keys/user-type.h index 5e452c84f1e6..3ab1873a4bfa 100644 --- a/include/keys/user-type.h +++ b/include/keys/user-type.h | |||
@@ -37,7 +37,8 @@ extern struct key_type key_type_logon; | |||
37 | 37 | ||
38 | struct key_preparsed_payload; | 38 | struct key_preparsed_payload; |
39 | 39 | ||
40 | extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep); | 40 | extern int user_preparse(struct key_preparsed_payload *prep); |
41 | extern void user_free_preparse(struct key_preparsed_payload *prep); | ||
41 | extern int user_update(struct key *key, struct key_preparsed_payload *prep); | 42 | extern int user_update(struct key *key, struct key_preparsed_payload *prep); |
42 | extern int user_match(const struct key *key, const void *criterion); | 43 | extern int user_match(const struct key *key, const void *criterion); |
43 | extern void user_revoke(struct key *key); | 44 | extern void user_revoke(struct key *key); |
diff --git a/include/linux/key-type.h b/include/linux/key-type.h index a74c3a84dfdd..44792ee649de 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h | |||
@@ -41,10 +41,11 @@ struct key_construction { | |||
41 | struct key_preparsed_payload { | 41 | struct key_preparsed_payload { |
42 | char *description; /* Proposed key description (or NULL) */ | 42 | char *description; /* Proposed key description (or NULL) */ |
43 | void *type_data[2]; /* Private key-type data */ | 43 | void *type_data[2]; /* Private key-type data */ |
44 | void *payload; /* Proposed payload */ | 44 | void *payload[2]; /* Proposed payload */ |
45 | const void *data; /* Raw data */ | 45 | const void *data; /* Raw data */ |
46 | size_t datalen; /* Raw datalen */ | 46 | size_t datalen; /* Raw datalen */ |
47 | size_t quotalen; /* Quota length for proposed payload */ | 47 | size_t quotalen; /* Quota length for proposed payload */ |
48 | time_t expiry; /* Expiry time of key */ | ||
48 | bool trusted; /* True if key is trusted */ | 49 | bool trusted; /* True if key is trusted */ |
49 | }; | 50 | }; |
50 | 51 | ||
@@ -159,5 +160,7 @@ static inline int key_negate_and_link(struct key *key, | |||
159 | return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey); | 160 | return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey); |
160 | } | 161 | } |
161 | 162 | ||
163 | extern int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep); | ||
164 | |||
162 | #endif /* CONFIG_KEYS */ | 165 | #endif /* CONFIG_KEYS */ |
163 | #endif /* _LINUX_KEY_TYPE_H */ | 166 | #endif /* _LINUX_KEY_TYPE_H */ |
diff --git a/include/linux/key.h b/include/linux/key.h index 017b0826642f..e1d4715f3222 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -170,6 +170,8 @@ struct key { | |||
170 | #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ | 170 | #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ |
171 | #define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ | 171 | #define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ |
172 | #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ | 172 | #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ |
173 | #define KEY_FLAG_BUILTIN 10 /* set if key is builtin */ | ||
174 | #define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */ | ||
173 | 175 | ||
174 | /* the key type and key description string | 176 | /* the key type and key description string |
175 | * - the desc is used to match a key against search criteria | 177 | * - the desc is used to match a key against search criteria |
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index 6926db724258..c2bbf672b84e 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h | |||
@@ -52,9 +52,15 @@ enum OID { | |||
52 | OID_md4, /* 1.2.840.113549.2.4 */ | 52 | OID_md4, /* 1.2.840.113549.2.4 */ |
53 | OID_md5, /* 1.2.840.113549.2.5 */ | 53 | OID_md5, /* 1.2.840.113549.2.5 */ |
54 | 54 | ||
55 | OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ | 55 | /* Microsoft Authenticode & Software Publishing */ |
56 | OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */ | ||
57 | OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */ | ||
58 | OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */ | ||
56 | OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ | 59 | OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ |
60 | |||
61 | OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ | ||
57 | OID_sha1, /* 1.3.14.3.2.26 */ | 62 | OID_sha1, /* 1.3.14.3.2.26 */ |
63 | OID_sha256, /* 2.16.840.1.101.3.4.2.1 */ | ||
58 | 64 | ||
59 | /* Distinguished Name attribute IDs [RFC 2256] */ | 65 | /* Distinguished Name attribute IDs [RFC 2256] */ |
60 | OID_commonName, /* 2.5.4.3 */ | 66 | OID_commonName, /* 2.5.4.3 */ |
diff --git a/include/linux/pe.h b/include/linux/pe.h new file mode 100644 index 000000000000..e170b95e763b --- /dev/null +++ b/include/linux/pe.h | |||
@@ -0,0 +1,448 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Red Hat, Inc. | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | * Author(s): Peter Jones <pjones@redhat.com> | ||
18 | */ | ||
19 | #ifndef __LINUX_PE_H | ||
20 | #define __LINUX_PE_H | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | |||
24 | #define MZ_MAGIC 0x5a4d /* "MZ" */ | ||
25 | |||
26 | struct mz_hdr { | ||
27 | uint16_t magic; /* MZ_MAGIC */ | ||
28 | uint16_t lbsize; /* size of last used block */ | ||
29 | uint16_t blocks; /* pages in file, 0x3 */ | ||
30 | uint16_t relocs; /* relocations */ | ||
31 | uint16_t hdrsize; /* header size in "paragraphs" */ | ||
32 | uint16_t min_extra_pps; /* .bss */ | ||
33 | uint16_t max_extra_pps; /* runtime limit for the arena size */ | ||
34 | uint16_t ss; /* relative stack segment */ | ||
35 | uint16_t sp; /* initial %sp register */ | ||
36 | uint16_t checksum; /* word checksum */ | ||
37 | uint16_t ip; /* initial %ip register */ | ||
38 | uint16_t cs; /* initial %cs relative to load segment */ | ||
39 | uint16_t reloc_table_offset; /* offset of the first relocation */ | ||
40 | uint16_t overlay_num; /* overlay number. set to 0. */ | ||
41 | uint16_t reserved0[4]; /* reserved */ | ||
42 | uint16_t oem_id; /* oem identifier */ | ||
43 | uint16_t oem_info; /* oem specific */ | ||
44 | uint16_t reserved1[10]; /* reserved */ | ||
45 | uint32_t peaddr; /* address of pe header */ | ||
46 | char message[64]; /* message to print */ | ||
47 | }; | ||
48 | |||
49 | struct mz_reloc { | ||
50 | uint16_t offset; | ||
51 | uint16_t segment; | ||
52 | }; | ||
53 | |||
54 | #define PE_MAGIC 0x00004550 /* "PE\0\0" */ | ||
55 | #define PE_OPT_MAGIC_PE32 0x010b | ||
56 | #define PE_OPT_MAGIC_PE32_ROM 0x0107 | ||
57 | #define PE_OPT_MAGIC_PE32PLUS 0x020b | ||
58 | |||
59 | /* machine type */ | ||
60 | #define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 | ||
61 | #define IMAGE_FILE_MACHINE_AM33 0x01d3 | ||
62 | #define IMAGE_FILE_MACHINE_AMD64 0x8664 | ||
63 | #define IMAGE_FILE_MACHINE_ARM 0x01c0 | ||
64 | #define IMAGE_FILE_MACHINE_ARMV7 0x01c4 | ||
65 | #define IMAGE_FILE_MACHINE_EBC 0x0ebc | ||
66 | #define IMAGE_FILE_MACHINE_I386 0x014c | ||
67 | #define IMAGE_FILE_MACHINE_IA64 0x0200 | ||
68 | #define IMAGE_FILE_MACHINE_M32R 0x9041 | ||
69 | #define IMAGE_FILE_MACHINE_MIPS16 0x0266 | ||
70 | #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 | ||
71 | #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 | ||
72 | #define IMAGE_FILE_MACHINE_POWERPC 0x01f0 | ||
73 | #define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 | ||
74 | #define IMAGE_FILE_MACHINE_R4000 0x0166 | ||
75 | #define IMAGE_FILE_MACHINE_SH3 0x01a2 | ||
76 | #define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 | ||
77 | #define IMAGE_FILE_MACHINE_SH3E 0x01a4 | ||
78 | #define IMAGE_FILE_MACHINE_SH4 0x01a6 | ||
79 | #define IMAGE_FILE_MACHINE_SH5 0x01a8 | ||
80 | #define IMAGE_FILE_MACHINE_THUMB 0x01c2 | ||
81 | #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 | ||
82 | |||
83 | /* flags */ | ||
84 | #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 | ||
85 | #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 | ||
86 | #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 | ||
87 | #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 | ||
88 | #define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010 | ||
89 | #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 | ||
90 | #define IMAGE_FILE_16BIT_MACHINE 0x0040 | ||
91 | #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 | ||
92 | #define IMAGE_FILE_32BIT_MACHINE 0x0100 | ||
93 | #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 | ||
94 | #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 | ||
95 | #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 | ||
96 | #define IMAGE_FILE_SYSTEM 0x1000 | ||
97 | #define IMAGE_FILE_DLL 0x2000 | ||
98 | #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 | ||
99 | #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 | ||
100 | |||
101 | struct pe_hdr { | ||
102 | uint32_t magic; /* PE magic */ | ||
103 | uint16_t machine; /* machine type */ | ||
104 | uint16_t sections; /* number of sections */ | ||
105 | uint32_t timestamp; /* time_t */ | ||
106 | uint32_t symbol_table; /* symbol table offset */ | ||
107 | uint32_t symbols; /* number of symbols */ | ||
108 | uint16_t opt_hdr_size; /* size of optional header */ | ||
109 | uint16_t flags; /* flags */ | ||
110 | }; | ||
111 | |||
112 | #define IMAGE_FILE_OPT_ROM_MAGIC 0x107 | ||
113 | #define IMAGE_FILE_OPT_PE32_MAGIC 0x10b | ||
114 | #define IMAGE_FILE_OPT_PE32_PLUS_MAGIC 0x20b | ||
115 | |||
116 | #define IMAGE_SUBSYSTEM_UNKNOWN 0 | ||
117 | #define IMAGE_SUBSYSTEM_NATIVE 1 | ||
118 | #define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 | ||
119 | #define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 | ||
120 | #define IMAGE_SUBSYSTEM_POSIX_CUI 7 | ||
121 | #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 | ||
122 | #define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 | ||
123 | #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 | ||
124 | #define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 | ||
125 | #define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE 13 | ||
126 | #define IMAGE_SUBSYSTEM_XBOX 14 | ||
127 | |||
128 | #define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040 | ||
129 | #define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080 | ||
130 | #define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100 | ||
131 | #define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 | ||
132 | #define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 | ||
133 | #define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 | ||
134 | #define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 | ||
135 | #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 | ||
136 | |||
137 | /* the fact that pe32 isn't padded where pe32+ is 64-bit means union won't | ||
138 | * work right. vomit. */ | ||
139 | struct pe32_opt_hdr { | ||
140 | /* "standard" header */ | ||
141 | uint16_t magic; /* file type */ | ||
142 | uint8_t ld_major; /* linker major version */ | ||
143 | uint8_t ld_minor; /* linker minor version */ | ||
144 | uint32_t text_size; /* size of text section(s) */ | ||
145 | uint32_t data_size; /* size of data section(s) */ | ||
146 | uint32_t bss_size; /* size of bss section(s) */ | ||
147 | uint32_t entry_point; /* file offset of entry point */ | ||
148 | uint32_t code_base; /* relative code addr in ram */ | ||
149 | uint32_t data_base; /* relative data addr in ram */ | ||
150 | /* "windows" header */ | ||
151 | uint32_t image_base; /* preferred load address */ | ||
152 | uint32_t section_align; /* alignment in bytes */ | ||
153 | uint32_t file_align; /* file alignment in bytes */ | ||
154 | uint16_t os_major; /* major OS version */ | ||
155 | uint16_t os_minor; /* minor OS version */ | ||
156 | uint16_t image_major; /* major image version */ | ||
157 | uint16_t image_minor; /* minor image version */ | ||
158 | uint16_t subsys_major; /* major subsystem version */ | ||
159 | uint16_t subsys_minor; /* minor subsystem version */ | ||
160 | uint32_t win32_version; /* reserved, must be 0 */ | ||
161 | uint32_t image_size; /* image size */ | ||
162 | uint32_t header_size; /* header size rounded up to | ||
163 | file_align */ | ||
164 | uint32_t csum; /* checksum */ | ||
165 | uint16_t subsys; /* subsystem */ | ||
166 | uint16_t dll_flags; /* more flags! */ | ||
167 | uint32_t stack_size_req;/* amt of stack requested */ | ||
168 | uint32_t stack_size; /* amt of stack required */ | ||
169 | uint32_t heap_size_req; /* amt of heap requested */ | ||
170 | uint32_t heap_size; /* amt of heap required */ | ||
171 | uint32_t loader_flags; /* reserved, must be 0 */ | ||
172 | uint32_t data_dirs; /* number of data dir entries */ | ||
173 | }; | ||
174 | |||
175 | struct pe32plus_opt_hdr { | ||
176 | uint16_t magic; /* file type */ | ||
177 | uint8_t ld_major; /* linker major version */ | ||
178 | uint8_t ld_minor; /* linker minor version */ | ||
179 | uint32_t text_size; /* size of text section(s) */ | ||
180 | uint32_t data_size; /* size of data section(s) */ | ||
181 | uint32_t bss_size; /* size of bss section(s) */ | ||
182 | uint32_t entry_point; /* file offset of entry point */ | ||
183 | uint32_t code_base; /* relative code addr in ram */ | ||
184 | /* "windows" header */ | ||
185 | uint64_t image_base; /* preferred load address */ | ||
186 | uint32_t section_align; /* alignment in bytes */ | ||
187 | uint32_t file_align; /* file alignment in bytes */ | ||
188 | uint16_t os_major; /* major OS version */ | ||
189 | uint16_t os_minor; /* minor OS version */ | ||
190 | uint16_t image_major; /* major image version */ | ||
191 | uint16_t image_minor; /* minor image version */ | ||
192 | uint16_t subsys_major; /* major subsystem version */ | ||
193 | uint16_t subsys_minor; /* minor subsystem version */ | ||
194 | uint32_t win32_version; /* reserved, must be 0 */ | ||
195 | uint32_t image_size; /* image size */ | ||
196 | uint32_t header_size; /* header size rounded up to | ||
197 | file_align */ | ||
198 | uint32_t csum; /* checksum */ | ||
199 | uint16_t subsys; /* subsystem */ | ||
200 | uint16_t dll_flags; /* more flags! */ | ||
201 | uint64_t stack_size_req;/* amt of stack requested */ | ||
202 | uint64_t stack_size; /* amt of stack required */ | ||
203 | uint64_t heap_size_req; /* amt of heap requested */ | ||
204 | uint64_t heap_size; /* amt of heap required */ | ||
205 | uint32_t loader_flags; /* reserved, must be 0 */ | ||
206 | uint32_t data_dirs; /* number of data dir entries */ | ||
207 | }; | ||
208 | |||
209 | struct data_dirent { | ||
210 | uint32_t virtual_address; /* relative to load address */ | ||
211 | uint32_t size; | ||
212 | }; | ||
213 | |||
214 | struct data_directory { | ||
215 | struct data_dirent exports; /* .edata */ | ||
216 | struct data_dirent imports; /* .idata */ | ||
217 | struct data_dirent resources; /* .rsrc */ | ||
218 | struct data_dirent exceptions; /* .pdata */ | ||
219 | struct data_dirent certs; /* certs */ | ||
220 | struct data_dirent base_relocations; /* .reloc */ | ||
221 | struct data_dirent debug; /* .debug */ | ||
222 | struct data_dirent arch; /* reservered */ | ||
223 | struct data_dirent global_ptr; /* global pointer reg. Size=0 */ | ||
224 | struct data_dirent tls; /* .tls */ | ||
225 | struct data_dirent load_config; /* load configuration structure */ | ||
226 | struct data_dirent bound_imports; /* no idea */ | ||
227 | struct data_dirent import_addrs; /* import address table */ | ||
228 | struct data_dirent delay_imports; /* delay-load import table */ | ||
229 | struct data_dirent clr_runtime_hdr; /* .cor (object only) */ | ||
230 | struct data_dirent reserved; | ||
231 | }; | ||
232 | |||
233 | struct section_header { | ||
234 | char name[8]; /* name or "/12\0" string tbl offset */ | ||
235 | uint32_t virtual_size; /* size of loaded section in ram */ | ||
236 | uint32_t virtual_address; /* relative virtual address */ | ||
237 | uint32_t raw_data_size; /* size of the section */ | ||
238 | uint32_t data_addr; /* file pointer to first page of sec */ | ||
239 | uint32_t relocs; /* file pointer to relocation entries */ | ||
240 | uint32_t line_numbers; /* line numbers! */ | ||
241 | uint16_t num_relocs; /* number of relocations */ | ||
242 | uint16_t num_lin_numbers; /* srsly. */ | ||
243 | uint32_t flags; | ||
244 | }; | ||
245 | |||
246 | /* they actually defined 0x00000000 as well, but I think we'll skip that one. */ | ||
247 | #define IMAGE_SCN_RESERVED_0 0x00000001 | ||
248 | #define IMAGE_SCN_RESERVED_1 0x00000002 | ||
249 | #define IMAGE_SCN_RESERVED_2 0x00000004 | ||
250 | #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* don't pad - obsolete */ | ||
251 | #define IMAGE_SCN_RESERVED_3 0x00000010 | ||
252 | #define IMAGE_SCN_CNT_CODE 0x00000020 /* .text */ | ||
253 | #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* .data */ | ||
254 | #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* .bss */ | ||
255 | #define IMAGE_SCN_LNK_OTHER 0x00000100 /* reserved */ | ||
256 | #define IMAGE_SCN_LNK_INFO 0x00000200 /* .drectve comments */ | ||
257 | #define IMAGE_SCN_RESERVED_4 0x00000400 | ||
258 | #define IMAGE_SCN_LNK_REMOVE 0x00000800 /* .o only - scn to be rm'd*/ | ||
259 | #define IMAGE_SCN_LNK_COMDAT 0x00001000 /* .o only - COMDAT data */ | ||
260 | #define IMAGE_SCN_RESERVED_5 0x00002000 /* spec omits this */ | ||
261 | #define IMAGE_SCN_RESERVED_6 0x00004000 /* spec omits this */ | ||
262 | #define IMAGE_SCN_GPREL 0x00008000 /* global pointer referenced data */ | ||
263 | /* spec lists 0x20000 twice, I suspect they meant 0x10000 for one of them */ | ||
264 | #define IMAGE_SCN_MEM_PURGEABLE 0x00010000 /* reserved for "future" use */ | ||
265 | #define IMAGE_SCN_16BIT 0x00020000 /* reserved for "future" use */ | ||
266 | #define IMAGE_SCN_LOCKED 0x00040000 /* reserved for "future" use */ | ||
267 | #define IMAGE_SCN_PRELOAD 0x00080000 /* reserved for "future" use */ | ||
268 | /* and here they just stuck a 1-byte integer in the middle of a bitfield */ | ||
269 | #define IMAGE_SCN_ALIGN_1BYTES 0x00100000 /* it does what it says on the box */ | ||
270 | #define IMAGE_SCN_ALIGN_2BYTES 0x00200000 | ||
271 | #define IMAGE_SCN_ALIGN_4BYTES 0x00300000 | ||
272 | #define IMAGE_SCN_ALIGN_8BYTES 0x00400000 | ||
273 | #define IMAGE_SCN_ALIGN_16BYTES 0x00500000 | ||
274 | #define IMAGE_SCN_ALIGN_32BYTES 0x00600000 | ||
275 | #define IMAGE_SCN_ALIGN_64BYTES 0x00700000 | ||
276 | #define IMAGE_SCN_ALIGN_128BYTES 0x00800000 | ||
277 | #define IMAGE_SCN_ALIGN_256BYTES 0x00900000 | ||
278 | #define IMAGE_SCN_ALIGN_512BYTES 0x00a00000 | ||
279 | #define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000 | ||
280 | #define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000 | ||
281 | #define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000 | ||
282 | #define IMAGE_SCN_ALIGN_8192BYTES 0x00e00000 | ||
283 | #define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* extended relocations */ | ||
284 | #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 /* scn can be discarded */ | ||
285 | #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* cannot be cached */ | ||
286 | #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* not pageable */ | ||
287 | #define IMAGE_SCN_MEM_SHARED 0x10000000 /* can be shared */ | ||
288 | #define IMAGE_SCN_MEM_EXECUTE 0x20000000 /* can be executed as code */ | ||
289 | #define IMAGE_SCN_MEM_READ 0x40000000 /* readable */ | ||
290 | #define IMAGE_SCN_MEM_WRITE 0x80000000 /* writeable */ | ||
291 | |||
292 | enum x64_coff_reloc_type { | ||
293 | IMAGE_REL_AMD64_ABSOLUTE = 0, | ||
294 | IMAGE_REL_AMD64_ADDR64, | ||
295 | IMAGE_REL_AMD64_ADDR32, | ||
296 | IMAGE_REL_AMD64_ADDR32N, | ||
297 | IMAGE_REL_AMD64_REL32, | ||
298 | IMAGE_REL_AMD64_REL32_1, | ||
299 | IMAGE_REL_AMD64_REL32_2, | ||
300 | IMAGE_REL_AMD64_REL32_3, | ||
301 | IMAGE_REL_AMD64_REL32_4, | ||
302 | IMAGE_REL_AMD64_REL32_5, | ||
303 | IMAGE_REL_AMD64_SECTION, | ||
304 | IMAGE_REL_AMD64_SECREL, | ||
305 | IMAGE_REL_AMD64_SECREL7, | ||
306 | IMAGE_REL_AMD64_TOKEN, | ||
307 | IMAGE_REL_AMD64_SREL32, | ||
308 | IMAGE_REL_AMD64_PAIR, | ||
309 | IMAGE_REL_AMD64_SSPAN32, | ||
310 | }; | ||
311 | |||
312 | enum arm_coff_reloc_type { | ||
313 | IMAGE_REL_ARM_ABSOLUTE, | ||
314 | IMAGE_REL_ARM_ADDR32, | ||
315 | IMAGE_REL_ARM_ADDR32N, | ||
316 | IMAGE_REL_ARM_BRANCH2, | ||
317 | IMAGE_REL_ARM_BRANCH1, | ||
318 | IMAGE_REL_ARM_SECTION, | ||
319 | IMAGE_REL_ARM_SECREL, | ||
320 | }; | ||
321 | |||
322 | enum sh_coff_reloc_type { | ||
323 | IMAGE_REL_SH3_ABSOLUTE, | ||
324 | IMAGE_REL_SH3_DIRECT16, | ||
325 | IMAGE_REL_SH3_DIRECT32, | ||
326 | IMAGE_REL_SH3_DIRECT8, | ||
327 | IMAGE_REL_SH3_DIRECT8_WORD, | ||
328 | IMAGE_REL_SH3_DIRECT8_LONG, | ||
329 | IMAGE_REL_SH3_DIRECT4, | ||
330 | IMAGE_REL_SH3_DIRECT4_WORD, | ||
331 | IMAGE_REL_SH3_DIRECT4_LONG, | ||
332 | IMAGE_REL_SH3_PCREL8_WORD, | ||
333 | IMAGE_REL_SH3_PCREL8_LONG, | ||
334 | IMAGE_REL_SH3_PCREL12_WORD, | ||
335 | IMAGE_REL_SH3_STARTOF_SECTION, | ||
336 | IMAGE_REL_SH3_SIZEOF_SECTION, | ||
337 | IMAGE_REL_SH3_SECTION, | ||
338 | IMAGE_REL_SH3_SECREL, | ||
339 | IMAGE_REL_SH3_DIRECT32_NB, | ||
340 | IMAGE_REL_SH3_GPREL4_LONG, | ||
341 | IMAGE_REL_SH3_TOKEN, | ||
342 | IMAGE_REL_SHM_PCRELPT, | ||
343 | IMAGE_REL_SHM_REFLO, | ||
344 | IMAGE_REL_SHM_REFHALF, | ||
345 | IMAGE_REL_SHM_RELLO, | ||
346 | IMAGE_REL_SHM_RELHALF, | ||
347 | IMAGE_REL_SHM_PAIR, | ||
348 | IMAGE_REL_SHM_NOMODE, | ||
349 | }; | ||
350 | |||
351 | enum ppc_coff_reloc_type { | ||
352 | IMAGE_REL_PPC_ABSOLUTE, | ||
353 | IMAGE_REL_PPC_ADDR64, | ||
354 | IMAGE_REL_PPC_ADDR32, | ||
355 | IMAGE_REL_PPC_ADDR24, | ||
356 | IMAGE_REL_PPC_ADDR16, | ||
357 | IMAGE_REL_PPC_ADDR14, | ||
358 | IMAGE_REL_PPC_REL24, | ||
359 | IMAGE_REL_PPC_REL14, | ||
360 | IMAGE_REL_PPC_ADDR32N, | ||
361 | IMAGE_REL_PPC_SECREL, | ||
362 | IMAGE_REL_PPC_SECTION, | ||
363 | IMAGE_REL_PPC_SECREL16, | ||
364 | IMAGE_REL_PPC_REFHI, | ||
365 | IMAGE_REL_PPC_REFLO, | ||
366 | IMAGE_REL_PPC_PAIR, | ||
367 | IMAGE_REL_PPC_SECRELLO, | ||
368 | IMAGE_REL_PPC_GPREL, | ||
369 | IMAGE_REL_PPC_TOKEN, | ||
370 | }; | ||
371 | |||
372 | enum x86_coff_reloc_type { | ||
373 | IMAGE_REL_I386_ABSOLUTE, | ||
374 | IMAGE_REL_I386_DIR16, | ||
375 | IMAGE_REL_I386_REL16, | ||
376 | IMAGE_REL_I386_DIR32, | ||
377 | IMAGE_REL_I386_DIR32NB, | ||
378 | IMAGE_REL_I386_SEG12, | ||
379 | IMAGE_REL_I386_SECTION, | ||
380 | IMAGE_REL_I386_SECREL, | ||
381 | IMAGE_REL_I386_TOKEN, | ||
382 | IMAGE_REL_I386_SECREL7, | ||
383 | IMAGE_REL_I386_REL32, | ||
384 | }; | ||
385 | |||
386 | enum ia64_coff_reloc_type { | ||
387 | IMAGE_REL_IA64_ABSOLUTE, | ||
388 | IMAGE_REL_IA64_IMM14, | ||
389 | IMAGE_REL_IA64_IMM22, | ||
390 | IMAGE_REL_IA64_IMM64, | ||
391 | IMAGE_REL_IA64_DIR32, | ||
392 | IMAGE_REL_IA64_DIR64, | ||
393 | IMAGE_REL_IA64_PCREL21B, | ||
394 | IMAGE_REL_IA64_PCREL21M, | ||
395 | IMAGE_REL_IA64_PCREL21F, | ||
396 | IMAGE_REL_IA64_GPREL22, | ||
397 | IMAGE_REL_IA64_LTOFF22, | ||
398 | IMAGE_REL_IA64_SECTION, | ||
399 | IMAGE_REL_IA64_SECREL22, | ||
400 | IMAGE_REL_IA64_SECREL64I, | ||
401 | IMAGE_REL_IA64_SECREL32, | ||
402 | IMAGE_REL_IA64_DIR32NB, | ||
403 | IMAGE_REL_IA64_SREL14, | ||
404 | IMAGE_REL_IA64_SREL22, | ||
405 | IMAGE_REL_IA64_SREL32, | ||
406 | IMAGE_REL_IA64_UREL32, | ||
407 | IMAGE_REL_IA64_PCREL60X, | ||
408 | IMAGE_REL_IA64_PCREL60B, | ||
409 | IMAGE_REL_IA64_PCREL60F, | ||
410 | IMAGE_REL_IA64_PCREL60I, | ||
411 | IMAGE_REL_IA64_PCREL60M, | ||
412 | IMAGE_REL_IA64_IMMGPREL6, | ||
413 | IMAGE_REL_IA64_TOKEN, | ||
414 | IMAGE_REL_IA64_GPREL32, | ||
415 | IMAGE_REL_IA64_ADDEND, | ||
416 | }; | ||
417 | |||
418 | struct coff_reloc { | ||
419 | uint32_t virtual_address; | ||
420 | uint32_t symbol_table_index; | ||
421 | union { | ||
422 | enum x64_coff_reloc_type x64_type; | ||
423 | enum arm_coff_reloc_type arm_type; | ||
424 | enum sh_coff_reloc_type sh_type; | ||
425 | enum ppc_coff_reloc_type ppc_type; | ||
426 | enum x86_coff_reloc_type x86_type; | ||
427 | enum ia64_coff_reloc_type ia64_type; | ||
428 | uint16_t data; | ||
429 | }; | ||
430 | }; | ||
431 | |||
432 | /* | ||
433 | * Definitions for the contents of the certs data block | ||
434 | */ | ||
435 | #define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 | ||
436 | #define WIN_CERT_TYPE_EFI_OKCS115 0x0EF0 | ||
437 | #define WIN_CERT_TYPE_EFI_GUID 0x0EF1 | ||
438 | |||
439 | #define WIN_CERT_REVISION_1_0 0x0100 | ||
440 | #define WIN_CERT_REVISION_2_0 0x0200 | ||
441 | |||
442 | struct win_certificate { | ||
443 | uint32_t length; | ||
444 | uint16_t revision; | ||
445 | uint16_t cert_type; | ||
446 | }; | ||
447 | |||
448 | #endif /* __LINUX_PE_H */ | ||
diff --git a/include/linux/verify_pefile.h b/include/linux/verify_pefile.h new file mode 100644 index 000000000000..ac34819214f9 --- /dev/null +++ b/include/linux/verify_pefile.h | |||
@@ -0,0 +1,18 @@ | |||
1 | /* Signed PE file verification | ||
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 | #ifndef _LINUX_VERIFY_PEFILE_H | ||
13 | #define _LINUX_VERIFY_PEFILE_H | ||
14 | |||
15 | extern int verify_pefile_signature(const void *pebuf, unsigned pelen, | ||
16 | struct key *trusted_keyring, bool *_trusted); | ||
17 | |||
18 | #endif /* _LINUX_VERIFY_PEFILE_H */ | ||
diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c index 52ebc70263f4..875f64e8935b 100644 --- a/kernel/system_keyring.c +++ b/kernel/system_keyring.c | |||
@@ -89,6 +89,7 @@ static __init int load_system_certificate_list(void) | |||
89 | pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", | 89 | pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", |
90 | PTR_ERR(key)); | 90 | PTR_ERR(key)); |
91 | } else { | 91 | } else { |
92 | set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags); | ||
92 | pr_notice("Loaded X.509 cert '%s'\n", | 93 | pr_notice("Loaded X.509 cert '%s'\n", |
93 | key_ref_to_ptr(key)->description); | 94 | key_ref_to_ptr(key)->description); |
94 | key_ref_put(key); | 95 | key_ref_put(key); |
diff --git a/lib/Kconfig b/lib/Kconfig index 334f7722a999..a8a775730c09 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
@@ -451,7 +451,8 @@ config MPILIB | |||
451 | 451 | ||
452 | config SIGNATURE | 452 | config SIGNATURE |
453 | tristate | 453 | tristate |
454 | depends on KEYS && CRYPTO | 454 | depends on KEYS |
455 | select CRYPTO | ||
455 | select CRYPTO_SHA1 | 456 | select CRYPTO_SHA1 |
456 | select MPILIB | 457 | select MPILIB |
457 | help | 458 | help |
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index 6e7a236525b6..ffeba8f9dda9 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/key-type.h> | 8 | #include <linux/key-type.h> |
9 | 9 | ||
10 | #include <keys/ceph-type.h> | 10 | #include <keys/ceph-type.h> |
11 | #include <keys/user-type.h> | ||
11 | #include <linux/ceph/decode.h> | 12 | #include <linux/ceph/decode.h> |
12 | #include "crypto.h" | 13 | #include "crypto.h" |
13 | 14 | ||
@@ -423,8 +424,7 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, | |||
423 | } | 424 | } |
424 | } | 425 | } |
425 | 426 | ||
426 | static int ceph_key_instantiate(struct key *key, | 427 | static int ceph_key_preparse(struct key_preparsed_payload *prep) |
427 | struct key_preparsed_payload *prep) | ||
428 | { | 428 | { |
429 | struct ceph_crypto_key *ckey; | 429 | struct ceph_crypto_key *ckey; |
430 | size_t datalen = prep->datalen; | 430 | size_t datalen = prep->datalen; |
@@ -435,10 +435,6 @@ static int ceph_key_instantiate(struct key *key, | |||
435 | if (datalen <= 0 || datalen > 32767 || !prep->data) | 435 | if (datalen <= 0 || datalen > 32767 || !prep->data) |
436 | goto err; | 436 | goto err; |
437 | 437 | ||
438 | ret = key_payload_reserve(key, datalen); | ||
439 | if (ret < 0) | ||
440 | goto err; | ||
441 | |||
442 | ret = -ENOMEM; | 438 | ret = -ENOMEM; |
443 | ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); | 439 | ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); |
444 | if (!ckey) | 440 | if (!ckey) |
@@ -450,7 +446,8 @@ static int ceph_key_instantiate(struct key *key, | |||
450 | if (ret < 0) | 446 | if (ret < 0) |
451 | goto err_ckey; | 447 | goto err_ckey; |
452 | 448 | ||
453 | key->payload.data = ckey; | 449 | prep->payload[0] = ckey; |
450 | prep->quotalen = datalen; | ||
454 | return 0; | 451 | return 0; |
455 | 452 | ||
456 | err_ckey: | 453 | err_ckey: |
@@ -459,12 +456,15 @@ err: | |||
459 | return ret; | 456 | return ret; |
460 | } | 457 | } |
461 | 458 | ||
462 | static int ceph_key_match(const struct key *key, const void *description) | 459 | static void ceph_key_free_preparse(struct key_preparsed_payload *prep) |
463 | { | 460 | { |
464 | return strcmp(key->description, description) == 0; | 461 | struct ceph_crypto_key *ckey = prep->payload[0]; |
462 | ceph_crypto_key_destroy(ckey); | ||
463 | kfree(ckey); | ||
465 | } | 464 | } |
466 | 465 | ||
467 | static void ceph_key_destroy(struct key *key) { | 466 | static void ceph_key_destroy(struct key *key) |
467 | { | ||
468 | struct ceph_crypto_key *ckey = key->payload.data; | 468 | struct ceph_crypto_key *ckey = key->payload.data; |
469 | 469 | ||
470 | ceph_crypto_key_destroy(ckey); | 470 | ceph_crypto_key_destroy(ckey); |
@@ -473,8 +473,10 @@ static void ceph_key_destroy(struct key *key) { | |||
473 | 473 | ||
474 | struct key_type key_type_ceph = { | 474 | struct key_type key_type_ceph = { |
475 | .name = "ceph", | 475 | .name = "ceph", |
476 | .instantiate = ceph_key_instantiate, | 476 | .preparse = ceph_key_preparse, |
477 | .match = ceph_key_match, | 477 | .free_preparse = ceph_key_free_preparse, |
478 | .instantiate = generic_key_instantiate, | ||
479 | .match = user_match, | ||
478 | .destroy = ceph_key_destroy, | 480 | .destroy = ceph_key_destroy, |
479 | }; | 481 | }; |
480 | 482 | ||
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index bf8584339048..f380b2c58178 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c | |||
@@ -46,7 +46,7 @@ const struct cred *dns_resolver_cache; | |||
46 | #define DNS_ERRORNO_OPTION "dnserror" | 46 | #define DNS_ERRORNO_OPTION "dnserror" |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * Instantiate a user defined key for dns_resolver. | 49 | * Preparse instantiation data for a dns_resolver key. |
50 | * | 50 | * |
51 | * The data must be a NUL-terminated string, with the NUL char accounted in | 51 | * The data must be a NUL-terminated string, with the NUL char accounted in |
52 | * datalen. | 52 | * datalen. |
@@ -58,17 +58,15 @@ const struct cred *dns_resolver_cache; | |||
58 | * "ip1,ip2,...#foo=bar" | 58 | * "ip1,ip2,...#foo=bar" |
59 | */ | 59 | */ |
60 | static int | 60 | static int |
61 | dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | 61 | dns_resolver_preparse(struct key_preparsed_payload *prep) |
62 | { | 62 | { |
63 | struct user_key_payload *upayload; | 63 | struct user_key_payload *upayload; |
64 | unsigned long derrno; | 64 | unsigned long derrno; |
65 | int ret; | 65 | int ret; |
66 | size_t datalen = prep->datalen, result_len = 0; | 66 | int datalen = prep->datalen, result_len = 0; |
67 | const char *data = prep->data, *end, *opt; | 67 | const char *data = prep->data, *end, *opt; |
68 | 68 | ||
69 | kenter("%%%d,%s,'%*.*s',%zu", | 69 | kenter("'%*.*s',%u", datalen, datalen, data, datalen); |
70 | key->serial, key->description, | ||
71 | (int)datalen, (int)datalen, data, datalen); | ||
72 | 70 | ||
73 | if (datalen <= 1 || !data || data[datalen - 1] != '\0') | 71 | if (datalen <= 1 || !data || data[datalen - 1] != '\0') |
74 | return -EINVAL; | 72 | return -EINVAL; |
@@ -95,8 +93,7 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
95 | opt_len = next_opt - opt; | 93 | opt_len = next_opt - opt; |
96 | if (!opt_len) { | 94 | if (!opt_len) { |
97 | printk(KERN_WARNING | 95 | printk(KERN_WARNING |
98 | "Empty option to dns_resolver key %d\n", | 96 | "Empty option to dns_resolver key\n"); |
99 | key->serial); | ||
100 | return -EINVAL; | 97 | return -EINVAL; |
101 | } | 98 | } |
102 | 99 | ||
@@ -125,30 +122,28 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
125 | goto bad_option_value; | 122 | goto bad_option_value; |
126 | 123 | ||
127 | kdebug("dns error no. = %lu", derrno); | 124 | kdebug("dns error no. = %lu", derrno); |
128 | key->type_data.x[0] = -derrno; | 125 | prep->type_data[0] = ERR_PTR(-derrno); |
129 | continue; | 126 | continue; |
130 | } | 127 | } |
131 | 128 | ||
132 | bad_option_value: | 129 | bad_option_value: |
133 | printk(KERN_WARNING | 130 | printk(KERN_WARNING |
134 | "Option '%*.*s' to dns_resolver key %d:" | 131 | "Option '%*.*s' to dns_resolver key:" |
135 | " bad/missing value\n", | 132 | " bad/missing value\n", |
136 | opt_nlen, opt_nlen, opt, key->serial); | 133 | opt_nlen, opt_nlen, opt); |
137 | return -EINVAL; | 134 | return -EINVAL; |
138 | } while (opt = next_opt + 1, opt < end); | 135 | } while (opt = next_opt + 1, opt < end); |
139 | } | 136 | } |
140 | 137 | ||
141 | /* don't cache the result if we're caching an error saying there's no | 138 | /* don't cache the result if we're caching an error saying there's no |
142 | * result */ | 139 | * result */ |
143 | if (key->type_data.x[0]) { | 140 | if (prep->type_data[0]) { |
144 | kleave(" = 0 [h_error %ld]", key->type_data.x[0]); | 141 | kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0])); |
145 | return 0; | 142 | return 0; |
146 | } | 143 | } |
147 | 144 | ||
148 | kdebug("store result"); | 145 | kdebug("store result"); |
149 | ret = key_payload_reserve(key, result_len); | 146 | prep->quotalen = result_len; |
150 | if (ret < 0) | ||
151 | return -EINVAL; | ||
152 | 147 | ||
153 | upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL); | 148 | upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL); |
154 | if (!upayload) { | 149 | if (!upayload) { |
@@ -159,13 +154,23 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
159 | upayload->datalen = result_len; | 154 | upayload->datalen = result_len; |
160 | memcpy(upayload->data, data, result_len); | 155 | memcpy(upayload->data, data, result_len); |
161 | upayload->data[result_len] = '\0'; | 156 | upayload->data[result_len] = '\0'; |
162 | rcu_assign_pointer(key->payload.data, upayload); | ||
163 | 157 | ||
158 | prep->payload[0] = upayload; | ||
164 | kleave(" = 0"); | 159 | kleave(" = 0"); |
165 | return 0; | 160 | return 0; |
166 | } | 161 | } |
167 | 162 | ||
168 | /* | 163 | /* |
164 | * Clean up the preparse data | ||
165 | */ | ||
166 | static void dns_resolver_free_preparse(struct key_preparsed_payload *prep) | ||
167 | { | ||
168 | pr_devel("==>%s()\n", __func__); | ||
169 | |||
170 | kfree(prep->payload[0]); | ||
171 | } | ||
172 | |||
173 | /* | ||
169 | * The description is of the form "[<type>:]<domain_name>" | 174 | * The description is of the form "[<type>:]<domain_name>" |
170 | * | 175 | * |
171 | * The domain name may be a simple name or an absolute domain name (which | 176 | * The domain name may be a simple name or an absolute domain name (which |
@@ -234,7 +239,9 @@ static long dns_resolver_read(const struct key *key, | |||
234 | 239 | ||
235 | struct key_type key_type_dns_resolver = { | 240 | struct key_type key_type_dns_resolver = { |
236 | .name = "dns_resolver", | 241 | .name = "dns_resolver", |
237 | .instantiate = dns_resolver_instantiate, | 242 | .preparse = dns_resolver_preparse, |
243 | .free_preparse = dns_resolver_free_preparse, | ||
244 | .instantiate = generic_key_instantiate, | ||
238 | .match = dns_resolver_match, | 245 | .match = dns_resolver_match, |
239 | .revoke = user_revoke, | 246 | .revoke = user_revoke, |
240 | .destroy = user_destroy, | 247 | .destroy = user_destroy, |
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index 9acec61f5433..9a32f55cf9b9 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c | |||
@@ -129,6 +129,7 @@ int dns_query(const char *type, const char *name, size_t namelen, | |||
129 | } | 129 | } |
130 | 130 | ||
131 | down_read(&rkey->sem); | 131 | down_read(&rkey->sem); |
132 | set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); | ||
132 | rkey->perm |= KEY_USR_VIEW; | 133 | rkey->perm |= KEY_USR_VIEW; |
133 | 134 | ||
134 | ret = key_validate(rkey); | 135 | ret = key_validate(rkey); |
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index 0ad080790a32..3907add75932 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c | |||
@@ -26,8 +26,10 @@ | |||
26 | #include "ar-internal.h" | 26 | #include "ar-internal.h" |
27 | 27 | ||
28 | static int rxrpc_vet_description_s(const char *); | 28 | static int rxrpc_vet_description_s(const char *); |
29 | static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *); | 29 | static int rxrpc_preparse(struct key_preparsed_payload *); |
30 | static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *); | 30 | static int rxrpc_preparse_s(struct key_preparsed_payload *); |
31 | static void rxrpc_free_preparse(struct key_preparsed_payload *); | ||
32 | static void rxrpc_free_preparse_s(struct key_preparsed_payload *); | ||
31 | static void rxrpc_destroy(struct key *); | 33 | static void rxrpc_destroy(struct key *); |
32 | static void rxrpc_destroy_s(struct key *); | 34 | static void rxrpc_destroy_s(struct key *); |
33 | static void rxrpc_describe(const struct key *, struct seq_file *); | 35 | static void rxrpc_describe(const struct key *, struct seq_file *); |
@@ -39,7 +41,9 @@ static long rxrpc_read(const struct key *, char __user *, size_t); | |||
39 | */ | 41 | */ |
40 | struct key_type key_type_rxrpc = { | 42 | struct key_type key_type_rxrpc = { |
41 | .name = "rxrpc", | 43 | .name = "rxrpc", |
42 | .instantiate = rxrpc_instantiate, | 44 | .preparse = rxrpc_preparse, |
45 | .free_preparse = rxrpc_free_preparse, | ||
46 | .instantiate = generic_key_instantiate, | ||
43 | .match = user_match, | 47 | .match = user_match, |
44 | .destroy = rxrpc_destroy, | 48 | .destroy = rxrpc_destroy, |
45 | .describe = rxrpc_describe, | 49 | .describe = rxrpc_describe, |
@@ -54,7 +58,9 @@ EXPORT_SYMBOL(key_type_rxrpc); | |||
54 | struct key_type key_type_rxrpc_s = { | 58 | struct key_type key_type_rxrpc_s = { |
55 | .name = "rxrpc_s", | 59 | .name = "rxrpc_s", |
56 | .vet_description = rxrpc_vet_description_s, | 60 | .vet_description = rxrpc_vet_description_s, |
57 | .instantiate = rxrpc_instantiate_s, | 61 | .preparse = rxrpc_preparse_s, |
62 | .free_preparse = rxrpc_free_preparse_s, | ||
63 | .instantiate = generic_key_instantiate, | ||
58 | .match = user_match, | 64 | .match = user_match, |
59 | .destroy = rxrpc_destroy_s, | 65 | .destroy = rxrpc_destroy_s, |
60 | .describe = rxrpc_describe, | 66 | .describe = rxrpc_describe, |
@@ -81,13 +87,13 @@ static int rxrpc_vet_description_s(const char *desc) | |||
81 | * parse an RxKAD type XDR format token | 87 | * parse an RxKAD type XDR format token |
82 | * - the caller guarantees we have at least 4 words | 88 | * - the caller guarantees we have at least 4 words |
83 | */ | 89 | */ |
84 | static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | 90 | static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep, |
85 | unsigned int toklen) | 91 | size_t datalen, |
92 | const __be32 *xdr, unsigned int toklen) | ||
86 | { | 93 | { |
87 | struct rxrpc_key_token *token, **pptoken; | 94 | struct rxrpc_key_token *token, **pptoken; |
88 | size_t plen; | 95 | size_t plen; |
89 | u32 tktlen; | 96 | u32 tktlen; |
90 | int ret; | ||
91 | 97 | ||
92 | _enter(",{%x,%x,%x,%x},%u", | 98 | _enter(",{%x,%x,%x,%x},%u", |
93 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), | 99 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), |
@@ -103,9 +109,7 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | |||
103 | return -EKEYREJECTED; | 109 | return -EKEYREJECTED; |
104 | 110 | ||
105 | plen = sizeof(*token) + sizeof(*token->kad) + tktlen; | 111 | plen = sizeof(*token) + sizeof(*token->kad) + tktlen; |
106 | ret = key_payload_reserve(key, key->datalen + plen); | 112 | prep->quotalen = datalen + plen; |
107 | if (ret < 0) | ||
108 | return ret; | ||
109 | 113 | ||
110 | plen -= sizeof(*token); | 114 | plen -= sizeof(*token); |
111 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 115 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
@@ -146,16 +150,16 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | |||
146 | token->kad->ticket[6], token->kad->ticket[7]); | 150 | token->kad->ticket[6], token->kad->ticket[7]); |
147 | 151 | ||
148 | /* count the number of tokens attached */ | 152 | /* count the number of tokens attached */ |
149 | key->type_data.x[0]++; | 153 | prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1); |
150 | 154 | ||
151 | /* attach the data */ | 155 | /* attach the data */ |
152 | for (pptoken = (struct rxrpc_key_token **)&key->payload.data; | 156 | for (pptoken = (struct rxrpc_key_token **)&prep->payload[0]; |
153 | *pptoken; | 157 | *pptoken; |
154 | pptoken = &(*pptoken)->next) | 158 | pptoken = &(*pptoken)->next) |
155 | continue; | 159 | continue; |
156 | *pptoken = token; | 160 | *pptoken = token; |
157 | if (token->kad->expiry < key->expiry) | 161 | if (token->kad->expiry < prep->expiry) |
158 | key->expiry = token->kad->expiry; | 162 | prep->expiry = token->kad->expiry; |
159 | 163 | ||
160 | _leave(" = 0"); | 164 | _leave(" = 0"); |
161 | return 0; | 165 | return 0; |
@@ -418,8 +422,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, | |||
418 | * parse an RxK5 type XDR format token | 422 | * parse an RxK5 type XDR format token |
419 | * - the caller guarantees we have at least 4 words | 423 | * - the caller guarantees we have at least 4 words |
420 | */ | 424 | */ |
421 | static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | 425 | static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep, |
422 | unsigned int toklen) | 426 | size_t datalen, |
427 | const __be32 *xdr, unsigned int toklen) | ||
423 | { | 428 | { |
424 | struct rxrpc_key_token *token, **pptoken; | 429 | struct rxrpc_key_token *token, **pptoken; |
425 | struct rxk5_key *rxk5; | 430 | struct rxk5_key *rxk5; |
@@ -432,9 +437,7 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | |||
432 | 437 | ||
433 | /* reserve some payload space for this subkey - the length of the token | 438 | /* reserve some payload space for this subkey - the length of the token |
434 | * is a reasonable approximation */ | 439 | * is a reasonable approximation */ |
435 | ret = key_payload_reserve(key, key->datalen + toklen); | 440 | prep->quotalen = datalen + toklen; |
436 | if (ret < 0) | ||
437 | return ret; | ||
438 | 441 | ||
439 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 442 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
440 | if (!token) | 443 | if (!token) |
@@ -520,14 +523,14 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | |||
520 | if (toklen != 0) | 523 | if (toklen != 0) |
521 | goto inval; | 524 | goto inval; |
522 | 525 | ||
523 | /* attach the payload to the key */ | 526 | /* attach the payload */ |
524 | for (pptoken = (struct rxrpc_key_token **)&key->payload.data; | 527 | for (pptoken = (struct rxrpc_key_token **)&prep->payload[0]; |
525 | *pptoken; | 528 | *pptoken; |
526 | pptoken = &(*pptoken)->next) | 529 | pptoken = &(*pptoken)->next) |
527 | continue; | 530 | continue; |
528 | *pptoken = token; | 531 | *pptoken = token; |
529 | if (token->kad->expiry < key->expiry) | 532 | if (token->kad->expiry < prep->expiry) |
530 | key->expiry = token->kad->expiry; | 533 | prep->expiry = token->kad->expiry; |
531 | 534 | ||
532 | _leave(" = 0"); | 535 | _leave(" = 0"); |
533 | return 0; | 536 | return 0; |
@@ -545,16 +548,17 @@ error: | |||
545 | * attempt to parse the data as the XDR format | 548 | * attempt to parse the data as the XDR format |
546 | * - the caller guarantees we have more than 7 words | 549 | * - the caller guarantees we have more than 7 words |
547 | */ | 550 | */ |
548 | static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datalen) | 551 | static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep) |
549 | { | 552 | { |
550 | const __be32 *xdr = data, *token; | 553 | const __be32 *xdr = prep->data, *token; |
551 | const char *cp; | 554 | const char *cp; |
552 | unsigned int len, tmp, loop, ntoken, toklen, sec_ix; | 555 | unsigned int len, tmp, loop, ntoken, toklen, sec_ix; |
556 | size_t datalen = prep->datalen; | ||
553 | int ret; | 557 | int ret; |
554 | 558 | ||
555 | _enter(",{%x,%x,%x,%x},%zu", | 559 | _enter(",{%x,%x,%x,%x},%zu", |
556 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), | 560 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), |
557 | datalen); | 561 | prep->datalen); |
558 | 562 | ||
559 | if (datalen > AFSTOKEN_LENGTH_MAX) | 563 | if (datalen > AFSTOKEN_LENGTH_MAX) |
560 | goto not_xdr; | 564 | goto not_xdr; |
@@ -635,13 +639,13 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal | |||
635 | 639 | ||
636 | switch (sec_ix) { | 640 | switch (sec_ix) { |
637 | case RXRPC_SECURITY_RXKAD: | 641 | case RXRPC_SECURITY_RXKAD: |
638 | ret = rxrpc_instantiate_xdr_rxkad(key, xdr, toklen); | 642 | ret = rxrpc_preparse_xdr_rxkad(prep, datalen, xdr, toklen); |
639 | if (ret != 0) | 643 | if (ret != 0) |
640 | goto error; | 644 | goto error; |
641 | break; | 645 | break; |
642 | 646 | ||
643 | case RXRPC_SECURITY_RXK5: | 647 | case RXRPC_SECURITY_RXK5: |
644 | ret = rxrpc_instantiate_xdr_rxk5(key, xdr, toklen); | 648 | ret = rxrpc_preparse_xdr_rxk5(prep, datalen, xdr, toklen); |
645 | if (ret != 0) | 649 | if (ret != 0) |
646 | goto error; | 650 | goto error; |
647 | break; | 651 | break; |
@@ -665,8 +669,9 @@ error: | |||
665 | } | 669 | } |
666 | 670 | ||
667 | /* | 671 | /* |
668 | * instantiate an rxrpc defined key | 672 | * Preparse an rxrpc defined key. |
669 | * data should be of the form: | 673 | * |
674 | * Data should be of the form: | ||
670 | * OFFSET LEN CONTENT | 675 | * OFFSET LEN CONTENT |
671 | * 0 4 key interface version number | 676 | * 0 4 key interface version number |
672 | * 4 2 security index (type) | 677 | * 4 2 security index (type) |
@@ -678,7 +683,7 @@ error: | |||
678 | * | 683 | * |
679 | * if no data is provided, then a no-security key is made | 684 | * if no data is provided, then a no-security key is made |
680 | */ | 685 | */ |
681 | static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep) | 686 | static int rxrpc_preparse(struct key_preparsed_payload *prep) |
682 | { | 687 | { |
683 | const struct rxrpc_key_data_v1 *v1; | 688 | const struct rxrpc_key_data_v1 *v1; |
684 | struct rxrpc_key_token *token, **pp; | 689 | struct rxrpc_key_token *token, **pp; |
@@ -686,7 +691,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
686 | u32 kver; | 691 | u32 kver; |
687 | int ret; | 692 | int ret; |
688 | 693 | ||
689 | _enter("{%x},,%zu", key_serial(key), prep->datalen); | 694 | _enter("%zu", prep->datalen); |
690 | 695 | ||
691 | /* handle a no-security key */ | 696 | /* handle a no-security key */ |
692 | if (!prep->data && prep->datalen == 0) | 697 | if (!prep->data && prep->datalen == 0) |
@@ -694,7 +699,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
694 | 699 | ||
695 | /* determine if the XDR payload format is being used */ | 700 | /* determine if the XDR payload format is being used */ |
696 | if (prep->datalen > 7 * 4) { | 701 | if (prep->datalen > 7 * 4) { |
697 | ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen); | 702 | ret = rxrpc_preparse_xdr(prep); |
698 | if (ret != -EPROTO) | 703 | if (ret != -EPROTO) |
699 | return ret; | 704 | return ret; |
700 | } | 705 | } |
@@ -743,9 +748,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
743 | goto error; | 748 | goto error; |
744 | 749 | ||
745 | plen = sizeof(*token->kad) + v1->ticket_length; | 750 | plen = sizeof(*token->kad) + v1->ticket_length; |
746 | ret = key_payload_reserve(key, plen + sizeof(*token)); | 751 | prep->quotalen = plen + sizeof(*token); |
747 | if (ret < 0) | ||
748 | goto error; | ||
749 | 752 | ||
750 | ret = -ENOMEM; | 753 | ret = -ENOMEM; |
751 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 754 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
@@ -762,15 +765,16 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
762 | memcpy(&token->kad->session_key, &v1->session_key, 8); | 765 | memcpy(&token->kad->session_key, &v1->session_key, 8); |
763 | memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length); | 766 | memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length); |
764 | 767 | ||
765 | /* attach the data */ | 768 | /* count the number of tokens attached */ |
766 | key->type_data.x[0]++; | 769 | prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1); |
767 | 770 | ||
768 | pp = (struct rxrpc_key_token **)&key->payload.data; | 771 | /* attach the data */ |
772 | pp = (struct rxrpc_key_token **)&prep->payload[0]; | ||
769 | while (*pp) | 773 | while (*pp) |
770 | pp = &(*pp)->next; | 774 | pp = &(*pp)->next; |
771 | *pp = token; | 775 | *pp = token; |
772 | if (token->kad->expiry < key->expiry) | 776 | if (token->kad->expiry < prep->expiry) |
773 | key->expiry = token->kad->expiry; | 777 | prep->expiry = token->kad->expiry; |
774 | token = NULL; | 778 | token = NULL; |
775 | ret = 0; | 779 | ret = 0; |
776 | 780 | ||
@@ -781,20 +785,55 @@ error: | |||
781 | } | 785 | } |
782 | 786 | ||
783 | /* | 787 | /* |
784 | * instantiate a server secret key | 788 | * Free token list. |
785 | * data should be a pointer to the 8-byte secret key | ||
786 | */ | 789 | */ |
787 | static int rxrpc_instantiate_s(struct key *key, | 790 | static void rxrpc_free_token_list(struct rxrpc_key_token *token) |
788 | struct key_preparsed_payload *prep) | 791 | { |
792 | struct rxrpc_key_token *next; | ||
793 | |||
794 | for (; token; token = next) { | ||
795 | next = token->next; | ||
796 | switch (token->security_index) { | ||
797 | case RXRPC_SECURITY_RXKAD: | ||
798 | kfree(token->kad); | ||
799 | break; | ||
800 | case RXRPC_SECURITY_RXK5: | ||
801 | if (token->k5) | ||
802 | rxrpc_rxk5_free(token->k5); | ||
803 | break; | ||
804 | default: | ||
805 | printk(KERN_ERR "Unknown token type %x on rxrpc key\n", | ||
806 | token->security_index); | ||
807 | BUG(); | ||
808 | } | ||
809 | |||
810 | kfree(token); | ||
811 | } | ||
812 | } | ||
813 | |||
814 | /* | ||
815 | * Clean up preparse data. | ||
816 | */ | ||
817 | static void rxrpc_free_preparse(struct key_preparsed_payload *prep) | ||
818 | { | ||
819 | rxrpc_free_token_list(prep->payload[0]); | ||
820 | } | ||
821 | |||
822 | /* | ||
823 | * Preparse a server secret key. | ||
824 | * | ||
825 | * The data should be the 8-byte secret key. | ||
826 | */ | ||
827 | static int rxrpc_preparse_s(struct key_preparsed_payload *prep) | ||
789 | { | 828 | { |
790 | struct crypto_blkcipher *ci; | 829 | struct crypto_blkcipher *ci; |
791 | 830 | ||
792 | _enter("{%x},,%zu", key_serial(key), prep->datalen); | 831 | _enter("%zu", prep->datalen); |
793 | 832 | ||
794 | if (prep->datalen != 8) | 833 | if (prep->datalen != 8) |
795 | return -EINVAL; | 834 | return -EINVAL; |
796 | 835 | ||
797 | memcpy(&key->type_data, prep->data, 8); | 836 | memcpy(&prep->type_data, prep->data, 8); |
798 | 837 | ||
799 | ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC); | 838 | ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC); |
800 | if (IS_ERR(ci)) { | 839 | if (IS_ERR(ci)) { |
@@ -805,36 +844,26 @@ static int rxrpc_instantiate_s(struct key *key, | |||
805 | if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0) | 844 | if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0) |
806 | BUG(); | 845 | BUG(); |
807 | 846 | ||
808 | key->payload.data = ci; | 847 | prep->payload[0] = ci; |
809 | _leave(" = 0"); | 848 | _leave(" = 0"); |
810 | return 0; | 849 | return 0; |
811 | } | 850 | } |
812 | 851 | ||
813 | /* | 852 | /* |
853 | * Clean up preparse data. | ||
854 | */ | ||
855 | static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep) | ||
856 | { | ||
857 | if (prep->payload[0]) | ||
858 | crypto_free_blkcipher(prep->payload[0]); | ||
859 | } | ||
860 | |||
861 | /* | ||
814 | * dispose of the data dangling from the corpse of a rxrpc key | 862 | * dispose of the data dangling from the corpse of a rxrpc key |
815 | */ | 863 | */ |
816 | static void rxrpc_destroy(struct key *key) | 864 | static void rxrpc_destroy(struct key *key) |
817 | { | 865 | { |
818 | struct rxrpc_key_token *token; | 866 | rxrpc_free_token_list(key->payload.data); |
819 | |||
820 | while ((token = key->payload.data)) { | ||
821 | key->payload.data = token->next; | ||
822 | switch (token->security_index) { | ||
823 | case RXRPC_SECURITY_RXKAD: | ||
824 | kfree(token->kad); | ||
825 | break; | ||
826 | case RXRPC_SECURITY_RXK5: | ||
827 | if (token->k5) | ||
828 | rxrpc_rxk5_free(token->k5); | ||
829 | break; | ||
830 | default: | ||
831 | printk(KERN_ERR "Unknown token type %x on rxrpc key\n", | ||
832 | token->security_index); | ||
833 | BUG(); | ||
834 | } | ||
835 | |||
836 | kfree(token); | ||
837 | } | ||
838 | } | 867 | } |
839 | 868 | ||
840 | /* | 869 | /* |
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index b4af4ebc5be2..8d4fbff8b87c 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
@@ -13,7 +13,9 @@ | |||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
14 | 14 | ||
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/sched.h> | ||
16 | #include <linux/rbtree.h> | 17 | #include <linux/rbtree.h> |
18 | #include <linux/cred.h> | ||
17 | #include <linux/key-type.h> | 19 | #include <linux/key-type.h> |
18 | #include <linux/digsig.h> | 20 | #include <linux/digsig.h> |
19 | 21 | ||
@@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX]; | |||
24 | static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { | 26 | static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { |
25 | "_evm", | 27 | "_evm", |
26 | "_module", | 28 | "_module", |
29 | #ifndef CONFIG_IMA_TRUSTED_KEYRING | ||
27 | "_ima", | 30 | "_ima", |
31 | #else | ||
32 | ".ima", | ||
33 | #endif | ||
28 | }; | 34 | }; |
29 | 35 | ||
30 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 36 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
@@ -56,3 +62,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | |||
56 | 62 | ||
57 | return -EOPNOTSUPP; | 63 | return -EOPNOTSUPP; |
58 | } | 64 | } |
65 | |||
66 | int integrity_init_keyring(const unsigned int id) | ||
67 | { | ||
68 | const struct cred *cred = current_cred(); | ||
69 | int err = 0; | ||
70 | |||
71 | keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), | ||
72 | KGIDT_INIT(0), cred, | ||
73 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
74 | KEY_USR_VIEW | KEY_USR_READ | | ||
75 | KEY_USR_WRITE | KEY_USR_SEARCH), | ||
76 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | ||
77 | if (!IS_ERR(keyring[id])) | ||
78 | set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags); | ||
79 | else { | ||
80 | err = PTR_ERR(keyring[id]); | ||
81 | pr_info("Can't allocate %s keyring (%d)\n", | ||
82 | keyring_name[id], err); | ||
83 | keyring[id] = NULL; | ||
84 | } | ||
85 | return err; | ||
86 | } | ||
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 81a27971d884..08758fbd496f 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
@@ -123,3 +123,13 @@ config IMA_APPRAISE | |||
123 | For more information on integrity appraisal refer to: | 123 | For more information on integrity appraisal refer to: |
124 | <http://linux-ima.sourceforge.net> | 124 | <http://linux-ima.sourceforge.net> |
125 | If unsure, say N. | 125 | If unsure, say N. |
126 | |||
127 | config IMA_TRUSTED_KEYRING | ||
128 | bool "Require all keys on the .ima keyring be signed" | ||
129 | depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING | ||
130 | depends on INTEGRITY_ASYMMETRIC_KEYS | ||
131 | select KEYS_DEBUG_PROC_KEYS | ||
132 | default y | ||
133 | help | ||
134 | This option requires that all keys added to the .ima | ||
135 | keyring be signed by a key on the system trusted keyring. | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index f79fa8be203c..c42056edfc97 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -249,4 +249,16 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op, | |||
249 | return -EINVAL; | 249 | return -EINVAL; |
250 | } | 250 | } |
251 | #endif /* CONFIG_IMA_LSM_RULES */ | 251 | #endif /* CONFIG_IMA_LSM_RULES */ |
252 | |||
253 | #ifdef CONFIG_IMA_TRUSTED_KEYRING | ||
254 | static inline int ima_init_keyring(const unsigned int id) | ||
255 | { | ||
256 | return integrity_init_keyring(id); | ||
257 | } | ||
258 | #else | ||
259 | static inline int ima_init_keyring(const unsigned int id) | ||
260 | { | ||
261 | return 0; | ||
262 | } | ||
263 | #endif /* CONFIG_IMA_TRUSTED_KEYRING */ | ||
252 | #endif | 264 | #endif |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index f474c608fa11..0d696431209c 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -325,8 +325,14 @@ static int __init init_ima(void) | |||
325 | 325 | ||
326 | hash_setup(CONFIG_IMA_DEFAULT_HASH); | 326 | hash_setup(CONFIG_IMA_DEFAULT_HASH); |
327 | error = ima_init(); | 327 | error = ima_init(); |
328 | if (!error) | 328 | if (error) |
329 | ima_initialized = 1; | 329 | goto out; |
330 | |||
331 | error = ima_init_keyring(INTEGRITY_KEYRING_IMA); | ||
332 | if (error) | ||
333 | goto out; | ||
334 | ima_initialized = 1; | ||
335 | out: | ||
330 | return error; | 336 | return error; |
331 | } | 337 | } |
332 | 338 | ||
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 33c0a70f6b15..09c440d9aaee 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
@@ -124,6 +124,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | |||
124 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 124 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
125 | const char *digest, int digestlen); | 125 | const char *digest, int digestlen); |
126 | 126 | ||
127 | int integrity_init_keyring(const unsigned int id); | ||
127 | #else | 128 | #else |
128 | 129 | ||
129 | static inline int integrity_digsig_verify(const unsigned int id, | 130 | static inline int integrity_digsig_verify(const unsigned int id, |
@@ -133,6 +134,10 @@ static inline int integrity_digsig_verify(const unsigned int id, | |||
133 | return -EOPNOTSUPP; | 134 | return -EOPNOTSUPP; |
134 | } | 135 | } |
135 | 136 | ||
137 | static inline int integrity_init_keyring(const unsigned int id) | ||
138 | { | ||
139 | return 0; | ||
140 | } | ||
136 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ | 141 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ |
137 | 142 | ||
138 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS | 143 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS |
diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 8137b27d641d..c2f91a0cf889 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c | |||
@@ -34,7 +34,9 @@ MODULE_LICENSE("GPL"); | |||
34 | struct key_type key_type_big_key = { | 34 | struct key_type key_type_big_key = { |
35 | .name = "big_key", | 35 | .name = "big_key", |
36 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 36 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
37 | .instantiate = big_key_instantiate, | 37 | .preparse = big_key_preparse, |
38 | .free_preparse = big_key_free_preparse, | ||
39 | .instantiate = generic_key_instantiate, | ||
38 | .match = user_match, | 40 | .match = user_match, |
39 | .revoke = big_key_revoke, | 41 | .revoke = big_key_revoke, |
40 | .destroy = big_key_destroy, | 42 | .destroy = big_key_destroy, |
@@ -43,11 +45,11 @@ struct key_type key_type_big_key = { | |||
43 | }; | 45 | }; |
44 | 46 | ||
45 | /* | 47 | /* |
46 | * Instantiate a big key | 48 | * Preparse a big key |
47 | */ | 49 | */ |
48 | int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | 50 | int big_key_preparse(struct key_preparsed_payload *prep) |
49 | { | 51 | { |
50 | struct path *path = (struct path *)&key->payload.data2; | 52 | struct path *path = (struct path *)&prep->payload; |
51 | struct file *file; | 53 | struct file *file; |
52 | ssize_t written; | 54 | ssize_t written; |
53 | size_t datalen = prep->datalen; | 55 | size_t datalen = prep->datalen; |
@@ -58,11 +60,9 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
58 | goto error; | 60 | goto error; |
59 | 61 | ||
60 | /* Set an arbitrary quota */ | 62 | /* Set an arbitrary quota */ |
61 | ret = key_payload_reserve(key, 16); | 63 | prep->quotalen = 16; |
62 | if (ret < 0) | ||
63 | goto error; | ||
64 | 64 | ||
65 | key->type_data.x[1] = datalen; | 65 | prep->type_data[1] = (void *)(unsigned long)datalen; |
66 | 66 | ||
67 | if (datalen > BIG_KEY_FILE_THRESHOLD) { | 67 | if (datalen > BIG_KEY_FILE_THRESHOLD) { |
68 | /* Create a shmem file to store the data in. This will permit the data | 68 | /* Create a shmem file to store the data in. This will permit the data |
@@ -73,7 +73,7 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
73 | file = shmem_kernel_file_setup("", datalen, 0); | 73 | file = shmem_kernel_file_setup("", datalen, 0); |
74 | if (IS_ERR(file)) { | 74 | if (IS_ERR(file)) { |
75 | ret = PTR_ERR(file); | 75 | ret = PTR_ERR(file); |
76 | goto err_quota; | 76 | goto error; |
77 | } | 77 | } |
78 | 78 | ||
79 | written = kernel_write(file, prep->data, prep->datalen, 0); | 79 | written = kernel_write(file, prep->data, prep->datalen, 0); |
@@ -93,24 +93,33 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
93 | } else { | 93 | } else { |
94 | /* Just store the data in a buffer */ | 94 | /* Just store the data in a buffer */ |
95 | void *data = kmalloc(datalen, GFP_KERNEL); | 95 | void *data = kmalloc(datalen, GFP_KERNEL); |
96 | if (!data) { | 96 | if (!data) |
97 | ret = -ENOMEM; | 97 | return -ENOMEM; |
98 | goto err_quota; | ||
99 | } | ||
100 | 98 | ||
101 | key->payload.data = memcpy(data, prep->data, prep->datalen); | 99 | prep->payload[0] = memcpy(data, prep->data, prep->datalen); |
102 | } | 100 | } |
103 | return 0; | 101 | return 0; |
104 | 102 | ||
105 | err_fput: | 103 | err_fput: |
106 | fput(file); | 104 | fput(file); |
107 | err_quota: | ||
108 | key_payload_reserve(key, 0); | ||
109 | error: | 105 | error: |
110 | return ret; | 106 | return ret; |
111 | } | 107 | } |
112 | 108 | ||
113 | /* | 109 | /* |
110 | * Clear preparsement. | ||
111 | */ | ||
112 | void big_key_free_preparse(struct key_preparsed_payload *prep) | ||
113 | { | ||
114 | if (prep->datalen > BIG_KEY_FILE_THRESHOLD) { | ||
115 | struct path *path = (struct path *)&prep->payload; | ||
116 | path_put(path); | ||
117 | } else { | ||
118 | kfree(prep->payload[0]); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | /* | ||
114 | * dispose of the links from a revoked keyring | 123 | * dispose of the links from a revoked keyring |
115 | * - called with the key sem write-locked | 124 | * - called with the key sem write-locked |
116 | */ | 125 | */ |
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 5fe443d120af..d252c5704f8a 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c | |||
@@ -811,7 +811,7 @@ static int encrypted_instantiate(struct key *key, | |||
811 | goto out; | 811 | goto out; |
812 | } | 812 | } |
813 | 813 | ||
814 | rcu_assign_keypointer(key, epayload); | 814 | prep->payload[0] = epayload; |
815 | out: | 815 | out: |
816 | kfree(datablob); | 816 | kfree(datablob); |
817 | return ret; | 817 | return ret; |
diff --git a/security/keys/key.c b/security/keys/key.c index 2048a110e7f1..b90a68c4e2c4 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -437,6 +437,11 @@ static int __key_instantiate_and_link(struct key *key, | |||
437 | /* disable the authorisation key */ | 437 | /* disable the authorisation key */ |
438 | if (authkey) | 438 | if (authkey) |
439 | key_revoke(authkey); | 439 | key_revoke(authkey); |
440 | |||
441 | if (prep->expiry != TIME_T_MAX) { | ||
442 | key->expiry = prep->expiry; | ||
443 | key_schedule_gc(prep->expiry + key_gc_delay); | ||
444 | } | ||
440 | } | 445 | } |
441 | } | 446 | } |
442 | 447 | ||
@@ -479,6 +484,7 @@ int key_instantiate_and_link(struct key *key, | |||
479 | prep.data = data; | 484 | prep.data = data; |
480 | prep.datalen = datalen; | 485 | prep.datalen = datalen; |
481 | prep.quotalen = key->type->def_datalen; | 486 | prep.quotalen = key->type->def_datalen; |
487 | prep.expiry = TIME_T_MAX; | ||
482 | if (key->type->preparse) { | 488 | if (key->type->preparse) { |
483 | ret = key->type->preparse(&prep); | 489 | ret = key->type->preparse(&prep); |
484 | if (ret < 0) | 490 | if (ret < 0) |
@@ -488,7 +494,7 @@ int key_instantiate_and_link(struct key *key, | |||
488 | if (keyring) { | 494 | if (keyring) { |
489 | ret = __key_link_begin(keyring, &key->index_key, &edit); | 495 | ret = __key_link_begin(keyring, &key->index_key, &edit); |
490 | if (ret < 0) | 496 | if (ret < 0) |
491 | goto error_free_preparse; | 497 | goto error; |
492 | } | 498 | } |
493 | 499 | ||
494 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); | 500 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); |
@@ -496,10 +502,9 @@ int key_instantiate_and_link(struct key *key, | |||
496 | if (keyring) | 502 | if (keyring) |
497 | __key_link_end(keyring, &key->index_key, edit); | 503 | __key_link_end(keyring, &key->index_key, edit); |
498 | 504 | ||
499 | error_free_preparse: | 505 | error: |
500 | if (key->type->preparse) | 506 | if (key->type->preparse) |
501 | key->type->free_preparse(&prep); | 507 | key->type->free_preparse(&prep); |
502 | error: | ||
503 | return ret; | 508 | return ret; |
504 | } | 509 | } |
505 | 510 | ||
@@ -811,11 +816,12 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
811 | prep.datalen = plen; | 816 | prep.datalen = plen; |
812 | prep.quotalen = index_key.type->def_datalen; | 817 | prep.quotalen = index_key.type->def_datalen; |
813 | prep.trusted = flags & KEY_ALLOC_TRUSTED; | 818 | prep.trusted = flags & KEY_ALLOC_TRUSTED; |
819 | prep.expiry = TIME_T_MAX; | ||
814 | if (index_key.type->preparse) { | 820 | if (index_key.type->preparse) { |
815 | ret = index_key.type->preparse(&prep); | 821 | ret = index_key.type->preparse(&prep); |
816 | if (ret < 0) { | 822 | if (ret < 0) { |
817 | key_ref = ERR_PTR(ret); | 823 | key_ref = ERR_PTR(ret); |
818 | goto error_put_type; | 824 | goto error_free_prep; |
819 | } | 825 | } |
820 | if (!index_key.description) | 826 | if (!index_key.description) |
821 | index_key.description = prep.description; | 827 | index_key.description = prep.description; |
@@ -941,6 +947,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
941 | prep.data = payload; | 947 | prep.data = payload; |
942 | prep.datalen = plen; | 948 | prep.datalen = plen; |
943 | prep.quotalen = key->type->def_datalen; | 949 | prep.quotalen = key->type->def_datalen; |
950 | prep.expiry = TIME_T_MAX; | ||
944 | if (key->type->preparse) { | 951 | if (key->type->preparse) { |
945 | ret = key->type->preparse(&prep); | 952 | ret = key->type->preparse(&prep); |
946 | if (ret < 0) | 953 | if (ret < 0) |
@@ -956,9 +963,9 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
956 | 963 | ||
957 | up_write(&key->sem); | 964 | up_write(&key->sem); |
958 | 965 | ||
966 | error: | ||
959 | if (key->type->preparse) | 967 | if (key->type->preparse) |
960 | key->type->free_preparse(&prep); | 968 | key->type->free_preparse(&prep); |
961 | error: | ||
962 | return ret; | 969 | return ret; |
963 | } | 970 | } |
964 | EXPORT_SYMBOL(key_update); | 971 | EXPORT_SYMBOL(key_update); |
@@ -1024,6 +1031,38 @@ void key_invalidate(struct key *key) | |||
1024 | EXPORT_SYMBOL(key_invalidate); | 1031 | EXPORT_SYMBOL(key_invalidate); |
1025 | 1032 | ||
1026 | /** | 1033 | /** |
1034 | * generic_key_instantiate - Simple instantiation of a key from preparsed data | ||
1035 | * @key: The key to be instantiated | ||
1036 | * @prep: The preparsed data to load. | ||
1037 | * | ||
1038 | * Instantiate a key from preparsed data. We assume we can just copy the data | ||
1039 | * in directly and clear the old pointers. | ||
1040 | * | ||
1041 | * This can be pointed to directly by the key type instantiate op pointer. | ||
1042 | */ | ||
1043 | int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | ||
1044 | { | ||
1045 | int ret; | ||
1046 | |||
1047 | pr_devel("==>%s()\n", __func__); | ||
1048 | |||
1049 | ret = key_payload_reserve(key, prep->quotalen); | ||
1050 | if (ret == 0) { | ||
1051 | key->type_data.p[0] = prep->type_data[0]; | ||
1052 | key->type_data.p[1] = prep->type_data[1]; | ||
1053 | rcu_assign_keypointer(key, prep->payload[0]); | ||
1054 | key->payload.data2[1] = prep->payload[1]; | ||
1055 | prep->type_data[0] = NULL; | ||
1056 | prep->type_data[1] = NULL; | ||
1057 | prep->payload[0] = NULL; | ||
1058 | prep->payload[1] = NULL; | ||
1059 | } | ||
1060 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
1061 | return ret; | ||
1062 | } | ||
1063 | EXPORT_SYMBOL(generic_key_instantiate); | ||
1064 | |||
1065 | /** | ||
1027 | * register_key_type - Register a type of key. | 1066 | * register_key_type - Register a type of key. |
1028 | * @ktype: The new key type. | 1067 | * @ktype: The new key type. |
1029 | * | 1068 | * |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index cd5bd0cef25d..e26f860e5f2e 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type, | |||
37 | return ret; | 37 | return ret; |
38 | if (ret == 0 || ret >= len) | 38 | if (ret == 0 || ret >= len) |
39 | return -EINVAL; | 39 | return -EINVAL; |
40 | if (type[0] == '.') | ||
41 | return -EPERM; | ||
42 | type[len - 1] = '\0'; | 40 | type[len - 1] = '\0'; |
43 | return 0; | 41 | return 0; |
44 | } | 42 | } |
@@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
86 | if (!*description) { | 84 | if (!*description) { |
87 | kfree(description); | 85 | kfree(description); |
88 | description = NULL; | 86 | description = NULL; |
87 | } else if ((description[0] == '.') && | ||
88 | (strncmp(type, "keyring", 7) == 0)) { | ||
89 | ret = -EPERM; | ||
90 | goto error2; | ||
89 | } | 91 | } |
90 | } | 92 | } |
91 | 93 | ||
@@ -404,12 +406,25 @@ long keyctl_invalidate_key(key_serial_t id) | |||
404 | key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); | 406 | key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); |
405 | if (IS_ERR(key_ref)) { | 407 | if (IS_ERR(key_ref)) { |
406 | ret = PTR_ERR(key_ref); | 408 | ret = PTR_ERR(key_ref); |
409 | |||
410 | /* Root is permitted to invalidate certain special keys */ | ||
411 | if (capable(CAP_SYS_ADMIN)) { | ||
412 | key_ref = lookup_user_key(id, 0, 0); | ||
413 | if (IS_ERR(key_ref)) | ||
414 | goto error; | ||
415 | if (test_bit(KEY_FLAG_ROOT_CAN_INVAL, | ||
416 | &key_ref_to_ptr(key_ref)->flags)) | ||
417 | goto invalidate; | ||
418 | goto error_put; | ||
419 | } | ||
420 | |||
407 | goto error; | 421 | goto error; |
408 | } | 422 | } |
409 | 423 | ||
424 | invalidate: | ||
410 | key_invalidate(key_ref_to_ptr(key_ref)); | 425 | key_invalidate(key_ref_to_ptr(key_ref)); |
411 | ret = 0; | 426 | ret = 0; |
412 | 427 | error_put: | |
413 | key_ref_put(key_ref); | 428 | key_ref_put(key_ref); |
414 | error: | 429 | error: |
415 | kleave(" = %ld", ret); | 430 | kleave(" = %ld", ret); |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 9cf2575f0d97..8314a7d2104d 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -73,6 +73,8 @@ static inline unsigned keyring_hash(const char *desc) | |||
73 | * can be treated as ordinary keys in addition to having their own special | 73 | * can be treated as ordinary keys in addition to having their own special |
74 | * operations. | 74 | * operations. |
75 | */ | 75 | */ |
76 | static int keyring_preparse(struct key_preparsed_payload *prep); | ||
77 | static void keyring_free_preparse(struct key_preparsed_payload *prep); | ||
76 | static int keyring_instantiate(struct key *keyring, | 78 | static int keyring_instantiate(struct key *keyring, |
77 | struct key_preparsed_payload *prep); | 79 | struct key_preparsed_payload *prep); |
78 | static void keyring_revoke(struct key *keyring); | 80 | static void keyring_revoke(struct key *keyring); |
@@ -84,6 +86,8 @@ static long keyring_read(const struct key *keyring, | |||
84 | struct key_type key_type_keyring = { | 86 | struct key_type key_type_keyring = { |
85 | .name = "keyring", | 87 | .name = "keyring", |
86 | .def_datalen = 0, | 88 | .def_datalen = 0, |
89 | .preparse = keyring_preparse, | ||
90 | .free_preparse = keyring_free_preparse, | ||
87 | .instantiate = keyring_instantiate, | 91 | .instantiate = keyring_instantiate, |
88 | .match = user_match, | 92 | .match = user_match, |
89 | .revoke = keyring_revoke, | 93 | .revoke = keyring_revoke, |
@@ -123,6 +127,21 @@ static void keyring_publish_name(struct key *keyring) | |||
123 | } | 127 | } |
124 | 128 | ||
125 | /* | 129 | /* |
130 | * Preparse a keyring payload | ||
131 | */ | ||
132 | static int keyring_preparse(struct key_preparsed_payload *prep) | ||
133 | { | ||
134 | return prep->datalen != 0 ? -EINVAL : 0; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Free a preparse of a user defined key payload | ||
139 | */ | ||
140 | static void keyring_free_preparse(struct key_preparsed_payload *prep) | ||
141 | { | ||
142 | } | ||
143 | |||
144 | /* | ||
126 | * Initialise a keyring. | 145 | * Initialise a keyring. |
127 | * | 146 | * |
128 | * Returns 0 on success, -EINVAL if given any data. | 147 | * Returns 0 on success, -EINVAL if given any data. |
@@ -130,17 +149,10 @@ static void keyring_publish_name(struct key *keyring) | |||
130 | static int keyring_instantiate(struct key *keyring, | 149 | static int keyring_instantiate(struct key *keyring, |
131 | struct key_preparsed_payload *prep) | 150 | struct key_preparsed_payload *prep) |
132 | { | 151 | { |
133 | int ret; | 152 | assoc_array_init(&keyring->keys); |
134 | 153 | /* make the keyring available by name if it has one */ | |
135 | ret = -EINVAL; | 154 | keyring_publish_name(keyring); |
136 | if (prep->datalen == 0) { | 155 | return 0; |
137 | assoc_array_init(&keyring->keys); | ||
138 | /* make the keyring available by name if it has one */ | ||
139 | keyring_publish_name(keyring); | ||
140 | ret = 0; | ||
141 | } | ||
142 | |||
143 | return ret; | ||
144 | } | 156 | } |
145 | 157 | ||
146 | /* | 158 | /* |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 7495a93b4b90..842e6f410d50 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include "internal.h" | 20 | #include "internal.h" |
21 | #include <keys/user-type.h> | 21 | #include <keys/user-type.h> |
22 | 22 | ||
23 | static int request_key_auth_preparse(struct key_preparsed_payload *); | ||
24 | static void request_key_auth_free_preparse(struct key_preparsed_payload *); | ||
23 | static int request_key_auth_instantiate(struct key *, | 25 | static int request_key_auth_instantiate(struct key *, |
24 | struct key_preparsed_payload *); | 26 | struct key_preparsed_payload *); |
25 | static void request_key_auth_describe(const struct key *, struct seq_file *); | 27 | static void request_key_auth_describe(const struct key *, struct seq_file *); |
@@ -33,6 +35,8 @@ static long request_key_auth_read(const struct key *, char __user *, size_t); | |||
33 | struct key_type key_type_request_key_auth = { | 35 | struct key_type key_type_request_key_auth = { |
34 | .name = ".request_key_auth", | 36 | .name = ".request_key_auth", |
35 | .def_datalen = sizeof(struct request_key_auth), | 37 | .def_datalen = sizeof(struct request_key_auth), |
38 | .preparse = request_key_auth_preparse, | ||
39 | .free_preparse = request_key_auth_free_preparse, | ||
36 | .instantiate = request_key_auth_instantiate, | 40 | .instantiate = request_key_auth_instantiate, |
37 | .describe = request_key_auth_describe, | 41 | .describe = request_key_auth_describe, |
38 | .revoke = request_key_auth_revoke, | 42 | .revoke = request_key_auth_revoke, |
@@ -40,6 +44,15 @@ struct key_type key_type_request_key_auth = { | |||
40 | .read = request_key_auth_read, | 44 | .read = request_key_auth_read, |
41 | }; | 45 | }; |
42 | 46 | ||
47 | int request_key_auth_preparse(struct key_preparsed_payload *prep) | ||
48 | { | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | void request_key_auth_free_preparse(struct key_preparsed_payload *prep) | ||
53 | { | ||
54 | } | ||
55 | |||
43 | /* | 56 | /* |
44 | * Instantiate a request-key authorisation key. | 57 | * Instantiate a request-key authorisation key. |
45 | */ | 58 | */ |
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index faa2caeb593f..eee340011f2b 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c | |||
@@ -27,7 +27,9 @@ static int logon_vet_description(const char *desc); | |||
27 | struct key_type key_type_user = { | 27 | struct key_type key_type_user = { |
28 | .name = "user", | 28 | .name = "user", |
29 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 29 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
30 | .instantiate = user_instantiate, | 30 | .preparse = user_preparse, |
31 | .free_preparse = user_free_preparse, | ||
32 | .instantiate = generic_key_instantiate, | ||
31 | .update = user_update, | 33 | .update = user_update, |
32 | .match = user_match, | 34 | .match = user_match, |
33 | .revoke = user_revoke, | 35 | .revoke = user_revoke, |
@@ -47,7 +49,9 @@ EXPORT_SYMBOL_GPL(key_type_user); | |||
47 | struct key_type key_type_logon = { | 49 | struct key_type key_type_logon = { |
48 | .name = "logon", | 50 | .name = "logon", |
49 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 51 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
50 | .instantiate = user_instantiate, | 52 | .preparse = user_preparse, |
53 | .free_preparse = user_free_preparse, | ||
54 | .instantiate = generic_key_instantiate, | ||
51 | .update = user_update, | 55 | .update = user_update, |
52 | .match = user_match, | 56 | .match = user_match, |
53 | .revoke = user_revoke, | 57 | .revoke = user_revoke, |
@@ -58,38 +62,37 @@ struct key_type key_type_logon = { | |||
58 | EXPORT_SYMBOL_GPL(key_type_logon); | 62 | EXPORT_SYMBOL_GPL(key_type_logon); |
59 | 63 | ||
60 | /* | 64 | /* |
61 | * instantiate a user defined key | 65 | * Preparse a user defined key payload |
62 | */ | 66 | */ |
63 | int user_instantiate(struct key *key, struct key_preparsed_payload *prep) | 67 | int user_preparse(struct key_preparsed_payload *prep) |
64 | { | 68 | { |
65 | struct user_key_payload *upayload; | 69 | struct user_key_payload *upayload; |
66 | size_t datalen = prep->datalen; | 70 | size_t datalen = prep->datalen; |
67 | int ret; | ||
68 | 71 | ||
69 | ret = -EINVAL; | ||
70 | if (datalen <= 0 || datalen > 32767 || !prep->data) | 72 | if (datalen <= 0 || datalen > 32767 || !prep->data) |
71 | goto error; | 73 | return -EINVAL; |
72 | |||
73 | ret = key_payload_reserve(key, datalen); | ||
74 | if (ret < 0) | ||
75 | goto error; | ||
76 | 74 | ||
77 | ret = -ENOMEM; | ||
78 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); | 75 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); |
79 | if (!upayload) | 76 | if (!upayload) |
80 | goto error; | 77 | return -ENOMEM; |
81 | 78 | ||
82 | /* attach the data */ | 79 | /* attach the data */ |
80 | prep->quotalen = datalen; | ||
81 | prep->payload[0] = upayload; | ||
83 | upayload->datalen = datalen; | 82 | upayload->datalen = datalen; |
84 | memcpy(upayload->data, prep->data, datalen); | 83 | memcpy(upayload->data, prep->data, datalen); |
85 | rcu_assign_keypointer(key, upayload); | 84 | return 0; |
86 | ret = 0; | ||
87 | |||
88 | error: | ||
89 | return ret; | ||
90 | } | 85 | } |
86 | EXPORT_SYMBOL_GPL(user_preparse); | ||
91 | 87 | ||
92 | EXPORT_SYMBOL_GPL(user_instantiate); | 88 | /* |
89 | * Free a preparse of a user defined key payload | ||
90 | */ | ||
91 | void user_free_preparse(struct key_preparsed_payload *prep) | ||
92 | { | ||
93 | kfree(prep->payload[0]); | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(user_free_preparse); | ||
93 | 96 | ||
94 | /* | 97 | /* |
95 | * update a user defined key | 98 | * update a user defined key |