diff options
author | David Howells <dhowells@redhat.com> | 2016-04-06 11:14:24 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2016-04-06 11:14:24 -0400 |
commit | e68503bd6836ba765dc8e0ee77ea675fedc07e41 (patch) | |
tree | 31ebec81d2f52adc89796dd063468235bfd1cc0e /crypto | |
parent | ad3043fda39db0361d9601685356db4512e914be (diff) |
KEYS: Generalise system_verify_data() to provide access to internal content
Generalise system_verify_data() to provide access to internal content
through a callback. This allows all the PKCS#7 stuff to be hidden inside
this function and removed from the PE file parser and the PKCS#7 test key.
If external content is not required, NULL should be passed as data to the
function. If the callback is not required, that can be set to NULL.
The function is now called verify_pkcs7_signature() to contrast with
verify_pefile_signature() and the definitions of both have been moved into
linux/verification.h along with the key_being_used_for enum.
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/asymmetric_keys/Kconfig | 4 | ||||
-rw-r--r-- | crypto/asymmetric_keys/mscode_parser.c | 21 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_key_type.c | 72 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_parser.c | 21 | ||||
-rw-r--r-- | crypto/asymmetric_keys/verify_pefile.c | 40 | ||||
-rw-r--r-- | crypto/asymmetric_keys/verify_pefile.h | 5 |
6 files changed, 59 insertions, 104 deletions
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 91a7e047a765..f7d2ef9789d8 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig | |||
@@ -40,8 +40,7 @@ config PKCS7_MESSAGE_PARSER | |||
40 | 40 | ||
41 | config PKCS7_TEST_KEY | 41 | config PKCS7_TEST_KEY |
42 | tristate "PKCS#7 testing key type" | 42 | tristate "PKCS#7 testing key type" |
43 | depends on PKCS7_MESSAGE_PARSER | 43 | depends on SYSTEM_DATA_VERIFICATION |
44 | select SYSTEM_TRUSTED_KEYRING | ||
45 | help | 44 | help |
46 | This option provides a type of key that can be loaded up from a | 45 | This option provides a type of key that can be loaded up from a |
47 | PKCS#7 message - provided the message is signed by a trusted key. If | 46 | PKCS#7 message - provided the message is signed by a trusted key. If |
@@ -54,6 +53,7 @@ config PKCS7_TEST_KEY | |||
54 | config SIGNED_PE_FILE_VERIFICATION | 53 | config SIGNED_PE_FILE_VERIFICATION |
55 | bool "Support for PE file signature verification" | 54 | bool "Support for PE file signature verification" |
56 | depends on PKCS7_MESSAGE_PARSER=y | 55 | depends on PKCS7_MESSAGE_PARSER=y |
56 | depends on SYSTEM_DATA_VERIFICATION | ||
57 | select ASN1 | 57 | select ASN1 |
58 | select OID_REGISTRY | 58 | select OID_REGISTRY |
59 | help | 59 | help |
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c index 3242cbfaeaa2..6a76d5c70ef6 100644 --- a/crypto/asymmetric_keys/mscode_parser.c +++ b/crypto/asymmetric_keys/mscode_parser.c | |||
@@ -21,19 +21,13 @@ | |||
21 | /* | 21 | /* |
22 | * Parse a Microsoft Individual Code Signing blob | 22 | * Parse a Microsoft Individual Code Signing blob |
23 | */ | 23 | */ |
24 | int mscode_parse(struct pefile_context *ctx) | 24 | int mscode_parse(void *_ctx, const void *content_data, size_t data_len, |
25 | size_t asn1hdrlen) | ||
25 | { | 26 | { |
26 | const void *content_data; | 27 | struct pefile_context *ctx = _ctx; |
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 | 28 | ||
29 | content_data -= asn1hdrlen; | ||
30 | data_len += asn1hdrlen; | ||
37 | pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len), | 31 | pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len), |
38 | content_data); | 32 | content_data); |
39 | 33 | ||
@@ -129,7 +123,6 @@ int mscode_note_digest(void *context, size_t hdrlen, | |||
129 | { | 123 | { |
130 | struct pefile_context *ctx = context; | 124 | struct pefile_context *ctx = context; |
131 | 125 | ||
132 | ctx->digest = value; | 126 | ctx->digest = kmemdup(value, vlen, GFP_KERNEL); |
133 | ctx->digest_len = vlen; | 127 | return ctx->digest ? 0 : -ENOMEM; |
134 | return 0; | ||
135 | } | 128 | } |
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c index e2d0edbbc71a..ab9bf5363ecd 100644 --- a/crypto/asymmetric_keys/pkcs7_key_type.c +++ b/crypto/asymmetric_keys/pkcs7_key_type.c | |||
@@ -13,12 +13,9 @@ | |||
13 | #include <linux/key.h> | 13 | #include <linux/key.h> |
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/verification.h> | ||
16 | #include <linux/key-type.h> | 17 | #include <linux/key-type.h> |
17 | #include <keys/asymmetric-type.h> | ||
18 | #include <crypto/pkcs7.h> | ||
19 | #include <keys/user-type.h> | 18 | #include <keys/user-type.h> |
20 | #include <keys/system_keyring.h> | ||
21 | #include "pkcs7_parser.h" | ||
22 | 19 | ||
23 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
24 | MODULE_DESCRIPTION("PKCS#7 testing key type"); | 21 | MODULE_DESCRIPTION("PKCS#7 testing key type"); |
@@ -29,60 +26,47 @@ MODULE_PARM_DESC(pkcs7_usage, | |||
29 | "Usage to specify when verifying the PKCS#7 message"); | 26 | "Usage to specify when verifying the PKCS#7 message"); |
30 | 27 | ||
31 | /* | 28 | /* |
32 | * Preparse a PKCS#7 wrapped and validated data blob. | 29 | * Retrieve the PKCS#7 message content. |
33 | */ | 30 | */ |
34 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | 31 | static int pkcs7_view_content(void *ctx, const void *data, size_t len, |
32 | size_t asn1hdrlen) | ||
35 | { | 33 | { |
36 | enum key_being_used_for usage = pkcs7_usage; | 34 | struct key_preparsed_payload *prep = ctx; |
37 | struct pkcs7_message *pkcs7; | 35 | const void *saved_prep_data; |
38 | const void *data, *saved_prep_data; | 36 | size_t saved_prep_datalen; |
39 | size_t datalen, saved_prep_datalen; | ||
40 | bool trusted; | ||
41 | int ret; | 37 | int ret; |
42 | 38 | ||
43 | kenter(""); | ||
44 | |||
45 | if (usage >= NR__KEY_BEING_USED_FOR) { | ||
46 | pr_err("Invalid usage type %d\n", usage); | ||
47 | return -EINVAL; | ||
48 | } | ||
49 | |||
50 | saved_prep_data = prep->data; | 39 | saved_prep_data = prep->data; |
51 | saved_prep_datalen = prep->datalen; | 40 | saved_prep_datalen = prep->datalen; |
52 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); | ||
53 | if (IS_ERR(pkcs7)) { | ||
54 | ret = PTR_ERR(pkcs7); | ||
55 | goto error; | ||
56 | } | ||
57 | |||
58 | ret = pkcs7_verify(pkcs7, usage); | ||
59 | if (ret < 0) | ||
60 | goto error_free; | ||
61 | |||
62 | ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); | ||
63 | if (ret < 0) | ||
64 | goto error_free; | ||
65 | if (!trusted) | ||
66 | pr_warn("PKCS#7 message doesn't chain back to a trusted key\n"); | ||
67 | |||
68 | ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false); | ||
69 | if (ret < 0) | ||
70 | goto error_free; | ||
71 | |||
72 | prep->data = data; | 41 | prep->data = data; |
73 | prep->datalen = datalen; | 42 | prep->datalen = len; |
43 | |||
74 | ret = user_preparse(prep); | 44 | ret = user_preparse(prep); |
45 | |||
75 | prep->data = saved_prep_data; | 46 | prep->data = saved_prep_data; |
76 | prep->datalen = saved_prep_datalen; | 47 | prep->datalen = saved_prep_datalen; |
77 | |||
78 | error_free: | ||
79 | pkcs7_free_message(pkcs7); | ||
80 | error: | ||
81 | kleave(" = %d", ret); | ||
82 | return ret; | 48 | return ret; |
83 | } | 49 | } |
84 | 50 | ||
85 | /* | 51 | /* |
52 | * Preparse a PKCS#7 wrapped and validated data blob. | ||
53 | */ | ||
54 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | ||
55 | { | ||
56 | enum key_being_used_for usage = pkcs7_usage; | ||
57 | |||
58 | if (usage >= NR__KEY_BEING_USED_FOR) { | ||
59 | pr_err("Invalid usage type %d\n", usage); | ||
60 | return -EINVAL; | ||
61 | } | ||
62 | |||
63 | return verify_pkcs7_signature(NULL, 0, | ||
64 | prep->data, prep->datalen, | ||
65 | NULL, -ENOKEY, usage, | ||
66 | pkcs7_view_content, prep); | ||
67 | } | ||
68 | |||
69 | /* | ||
86 | * user defined keys take an arbitrary string as the description and an | 70 | * user defined keys take an arbitrary string as the description and an |
87 | * arbitrary blob of data as the payload | 71 | * arbitrary blob of data as the payload |
88 | */ | 72 | */ |
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 835701613125..af4cd8649117 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c | |||
@@ -168,24 +168,25 @@ EXPORT_SYMBOL_GPL(pkcs7_parse_message); | |||
168 | * @pkcs7: The preparsed PKCS#7 message to access | 168 | * @pkcs7: The preparsed PKCS#7 message to access |
169 | * @_data: Place to return a pointer to the data | 169 | * @_data: Place to return a pointer to the data |
170 | * @_data_len: Place to return the data length | 170 | * @_data_len: Place to return the data length |
171 | * @want_wrapper: True if the ASN.1 object header should be included in the data | 171 | * @_headerlen: Size of ASN.1 header not included in _data |
172 | * | 172 | * |
173 | * Get access to the data content of the PKCS#7 message, including, optionally, | 173 | * Get access to the data content of the PKCS#7 message. The size of the |
174 | * the header of the ASN.1 object that contains it. Returns -ENODATA if the | 174 | * header of the ASN.1 object that contains it is also provided and can be used |
175 | * data object was missing from the message. | 175 | * to adjust *_data and *_data_len to get the entire object. |
176 | * | ||
177 | * Returns -ENODATA if the data object was missing from the message. | ||
176 | */ | 178 | */ |
177 | int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, | 179 | int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, |
178 | const void **_data, size_t *_data_len, | 180 | const void **_data, size_t *_data_len, |
179 | bool want_wrapper) | 181 | size_t *_headerlen) |
180 | { | 182 | { |
181 | size_t wrapper; | ||
182 | |||
183 | if (!pkcs7->data) | 183 | if (!pkcs7->data) |
184 | return -ENODATA; | 184 | return -ENODATA; |
185 | 185 | ||
186 | wrapper = want_wrapper ? pkcs7->data_hdrlen : 0; | 186 | *_data = pkcs7->data; |
187 | *_data = pkcs7->data - wrapper; | 187 | *_data_len = pkcs7->data_len; |
188 | *_data_len = pkcs7->data_len + wrapper; | 188 | if (_headerlen) |
189 | *_headerlen = pkcs7->data_hdrlen; | ||
189 | return 0; | 190 | return 0; |
190 | } | 191 | } |
191 | EXPORT_SYMBOL_GPL(pkcs7_get_content_data); | 192 | EXPORT_SYMBOL_GPL(pkcs7_get_content_data); |
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index 7e8c2338ae25..265351075b0e 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/pe.h> | 17 | #include <linux/pe.h> |
18 | #include <linux/asn1.h> | 18 | #include <linux/asn1.h> |
19 | #include <crypto/pkcs7.h> | 19 | #include <linux/verification.h> |
20 | #include <crypto/hash.h> | 20 | #include <crypto/hash.h> |
21 | #include "verify_pefile.h" | 21 | #include "verify_pefile.h" |
22 | 22 | ||
@@ -392,9 +392,8 @@ error_no_desc: | |||
392 | * verify_pefile_signature - Verify the signature on a PE binary image | 392 | * verify_pefile_signature - Verify the signature on a PE binary image |
393 | * @pebuf: Buffer containing the PE binary image | 393 | * @pebuf: Buffer containing the PE binary image |
394 | * @pelen: Length of the binary image | 394 | * @pelen: Length of the binary image |
395 | * @trust_keyring: Signing certificates to use as starting points | 395 | * @trust_keys: Signing certificate(s) to use as starting points |
396 | * @usage: The use to which the key is being put. | 396 | * @usage: The use to which the key is being put. |
397 | * @_trusted: Set to true if trustworth, false otherwise | ||
398 | * | 397 | * |
399 | * Validate that the certificate chain inside the PKCS#7 message inside the PE | 398 | * Validate that the certificate chain inside the PKCS#7 message inside the PE |
400 | * binary image intersects keys we already know and trust. | 399 | * binary image intersects keys we already know and trust. |
@@ -418,14 +417,10 @@ error_no_desc: | |||
418 | * May also return -ENOMEM. | 417 | * May also return -ENOMEM. |
419 | */ | 418 | */ |
420 | int verify_pefile_signature(const void *pebuf, unsigned pelen, | 419 | int verify_pefile_signature(const void *pebuf, unsigned pelen, |
421 | struct key *trusted_keyring, | 420 | struct key *trusted_keys, |
422 | enum key_being_used_for usage, | 421 | enum key_being_used_for usage) |
423 | bool *_trusted) | ||
424 | { | 422 | { |
425 | struct pkcs7_message *pkcs7; | ||
426 | struct pefile_context ctx; | 423 | struct pefile_context ctx; |
427 | const void *data; | ||
428 | size_t datalen; | ||
429 | int ret; | 424 | int ret; |
430 | 425 | ||
431 | kenter(""); | 426 | kenter(""); |
@@ -439,19 +434,10 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen, | |||
439 | if (ret < 0) | 434 | if (ret < 0) |
440 | return ret; | 435 | return ret; |
441 | 436 | ||
442 | pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len); | 437 | ret = verify_pkcs7_signature(NULL, 0, |
443 | if (IS_ERR(pkcs7)) | 438 | pebuf + ctx.sig_offset, ctx.sig_len, |
444 | return PTR_ERR(pkcs7); | 439 | trusted_keys, -EKEYREJECTED, usage, |
445 | ctx.pkcs7 = pkcs7; | 440 | mscode_parse, &ctx); |
446 | |||
447 | ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false); | ||
448 | if (ret < 0 || datalen == 0) { | ||
449 | pr_devel("PKCS#7 message does not contain data\n"); | ||
450 | ret = -EBADMSG; | ||
451 | goto error; | ||
452 | } | ||
453 | |||
454 | ret = mscode_parse(&ctx); | ||
455 | if (ret < 0) | 441 | if (ret < 0) |
456 | goto error; | 442 | goto error; |
457 | 443 | ||
@@ -462,16 +448,8 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen, | |||
462 | * contents. | 448 | * contents. |
463 | */ | 449 | */ |
464 | ret = pefile_digest_pe(pebuf, pelen, &ctx); | 450 | ret = pefile_digest_pe(pebuf, pelen, &ctx); |
465 | if (ret < 0) | ||
466 | goto error; | ||
467 | |||
468 | ret = pkcs7_verify(pkcs7, usage); | ||
469 | if (ret < 0) | ||
470 | goto error; | ||
471 | |||
472 | ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted); | ||
473 | 451 | ||
474 | error: | 452 | error: |
475 | pkcs7_free_message(ctx.pkcs7); | 453 | kfree(ctx.digest); |
476 | return ret; | 454 | return ret; |
477 | } | 455 | } |
diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h index a133eb81a492..cd4d20930728 100644 --- a/crypto/asymmetric_keys/verify_pefile.h +++ b/crypto/asymmetric_keys/verify_pefile.h | |||
@@ -9,7 +9,6 @@ | |||
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 | #include <linux/verify_pefile.h> | ||
13 | #include <crypto/pkcs7.h> | 12 | #include <crypto/pkcs7.h> |
14 | #include <crypto/hash_info.h> | 13 | #include <crypto/hash_info.h> |
15 | 14 | ||
@@ -23,7 +22,6 @@ struct pefile_context { | |||
23 | unsigned sig_offset; | 22 | unsigned sig_offset; |
24 | unsigned sig_len; | 23 | unsigned sig_len; |
25 | const struct section_header *secs; | 24 | const struct section_header *secs; |
26 | struct pkcs7_message *pkcs7; | ||
27 | 25 | ||
28 | /* PKCS#7 MS Individual Code Signing content */ | 26 | /* PKCS#7 MS Individual Code Signing content */ |
29 | const void *digest; /* Digest */ | 27 | const void *digest; /* Digest */ |
@@ -39,4 +37,5 @@ struct pefile_context { | |||
39 | /* | 37 | /* |
40 | * mscode_parser.c | 38 | * mscode_parser.c |
41 | */ | 39 | */ |
42 | extern int mscode_parse(struct pefile_context *ctx); | 40 | extern int mscode_parse(void *_ctx, const void *content_data, size_t data_len, |
41 | size_t asn1hdrlen); | ||