Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+155 -173
+4 -14
arch/x86/kernel/kexec-bzimage64.c
··· 19 19 #include <linux/kernel.h> 20 20 #include <linux/mm.h> 21 21 #include <linux/efi.h> 22 - #include <linux/verify_pefile.h> 23 - #include <keys/system_keyring.h> 22 + #include <linux/verification.h> 24 23 25 24 #include <asm/bootparam.h> 26 25 #include <asm/setup.h> ··· 528 529 #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG 529 530 static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len) 530 531 { 531 - bool trusted; 532 - int ret; 533 - 534 - ret = verify_pefile_signature(kernel, kernel_len, 535 - system_trusted_keyring, 536 - VERIFYING_KEXEC_PE_SIGNATURE, 537 - &trusted); 538 - if (ret < 0) 539 - return ret; 540 - if (!trusted) 541 - return -EKEYREJECTED; 542 - return 0; 532 + return verify_pefile_signature(kernel, kernel_len, 533 + NULL, 534 + VERIFYING_KEXEC_PE_SIGNATURE); 543 535 } 544 536 #endif 545 537
+35 -10
certs/system_keyring.c
··· 108 108 #ifdef CONFIG_SYSTEM_DATA_VERIFICATION 109 109 110 110 /** 111 - * Verify a PKCS#7-based signature on system data. 112 - * @data: The data to be verified. 111 + * verify_pkcs7_signature - Verify a PKCS#7-based signature on system data. 112 + * @data: The data to be verified (NULL if expecting internal data). 113 113 * @len: Size of @data. 114 114 * @raw_pkcs7: The PKCS#7 message that is the signature. 115 115 * @pkcs7_len: The size of @raw_pkcs7. 116 + * @trusted_keys: Trusted keys to use (NULL for system_trusted_keyring). 116 117 * @usage: The use to which the key is being put. 118 + * @view_content: Callback to gain access to content. 119 + * @ctx: Context for callback. 117 120 */ 118 - int system_verify_data(const void *data, unsigned long len, 119 - const void *raw_pkcs7, size_t pkcs7_len, 120 - enum key_being_used_for usage) 121 + int verify_pkcs7_signature(const void *data, size_t len, 122 + const void *raw_pkcs7, size_t pkcs7_len, 123 + struct key *trusted_keys, 124 + int untrusted_error, 125 + enum key_being_used_for usage, 126 + int (*view_content)(void *ctx, 127 + const void *data, size_t len, 128 + size_t asn1hdrlen), 129 + void *ctx) 121 130 { 122 131 struct pkcs7_message *pkcs7; 123 132 bool trusted; ··· 137 128 return PTR_ERR(pkcs7); 138 129 139 130 /* The data should be detached - so we need to supply it. */ 140 - if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) { 131 + if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) { 141 132 pr_err("PKCS#7 signature with non-detached data\n"); 142 133 ret = -EBADMSG; 143 134 goto error; ··· 147 138 if (ret < 0) 148 139 goto error; 149 140 150 - ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); 141 + if (!trusted_keys) 142 + trusted_keys = system_trusted_keyring; 143 + ret = pkcs7_validate_trust(pkcs7, trusted_keys, &trusted); 151 144 if (ret < 0) 152 145 goto error; 153 146 154 - if (!trusted) { 147 + if (!trusted && untrusted_error) { 155 148 pr_err("PKCS#7 signature not signed with a trusted key\n"); 156 - ret = -ENOKEY; 149 + ret = untrusted_error; 150 + goto error; 151 + } 152 + 153 + if (view_content) { 154 + size_t asn1hdrlen; 155 + 156 + ret = pkcs7_get_content_data(pkcs7, &data, &len, &asn1hdrlen); 157 + if (ret < 0) { 158 + if (ret == -ENODATA) 159 + pr_devel("PKCS#7 message does not contain data\n"); 160 + goto error; 161 + } 162 + 163 + ret = view_content(ctx, data, len, asn1hdrlen); 157 164 } 158 165 159 166 error: ··· 177 152 pr_devel("<==%s() = %d\n", __func__, ret); 178 153 return ret; 179 154 } 180 - EXPORT_SYMBOL_GPL(system_verify_data); 155 + EXPORT_SYMBOL_GPL(verify_pkcs7_signature); 181 156 182 157 #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
+2 -2
crypto/asymmetric_keys/Kconfig
··· 40 40 41 41 config PKCS7_TEST_KEY 42 42 tristate "PKCS#7 testing key type" 43 - depends on PKCS7_MESSAGE_PARSER 44 - select SYSTEM_TRUSTED_KEYRING 43 + depends on SYSTEM_DATA_VERIFICATION 45 44 help 46 45 This option provides a type of key that can be loaded up from a 47 46 PKCS#7 message - provided the message is signed by a trusted key. If ··· 53 54 config SIGNED_PE_FILE_VERIFICATION 54 55 bool "Support for PE file signature verification" 55 56 depends on PKCS7_MESSAGE_PARSER=y 57 + depends on SYSTEM_DATA_VERIFICATION 56 58 select ASN1 57 59 select OID_REGISTRY 58 60 help
+7 -14
crypto/asymmetric_keys/mscode_parser.c
··· 21 21 /* 22 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 - size_t data_len; 28 - int ret; 27 + struct pefile_context *ctx = _ctx; 29 28 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 - 29 + content_data -= asn1hdrlen; 30 + data_len += asn1hdrlen; 37 31 pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len), 38 32 content_data); 39 33 ··· 123 129 { 124 130 struct pefile_context *ctx = context; 125 131 126 - ctx->digest = value; 127 - ctx->digest_len = vlen; 128 - return 0; 132 + ctx->digest = kmemdup(value, vlen, GFP_KERNEL); 133 + return ctx->digest ? 0 : -ENOMEM; 129 134 }
+28 -44
crypto/asymmetric_keys/pkcs7_key_type.c
··· 13 13 #include <linux/key.h> 14 14 #include <linux/err.h> 15 15 #include <linux/module.h> 16 + #include <linux/verification.h> 16 17 #include <linux/key-type.h> 17 - #include <keys/asymmetric-type.h> 18 - #include <crypto/pkcs7.h> 19 18 #include <keys/user-type.h> 20 - #include <keys/system_keyring.h> 21 - #include "pkcs7_parser.h" 22 19 23 20 MODULE_LICENSE("GPL"); 24 21 MODULE_DESCRIPTION("PKCS#7 testing key type"); ··· 26 29 "Usage to specify when verifying the PKCS#7 message"); 27 30 28 31 /* 32 + * Retrieve the PKCS#7 message content. 33 + */ 34 + static int pkcs7_view_content(void *ctx, const void *data, size_t len, 35 + size_t asn1hdrlen) 36 + { 37 + struct key_preparsed_payload *prep = ctx; 38 + const void *saved_prep_data; 39 + size_t saved_prep_datalen; 40 + int ret; 41 + 42 + saved_prep_data = prep->data; 43 + saved_prep_datalen = prep->datalen; 44 + prep->data = data; 45 + prep->datalen = len; 46 + 47 + ret = user_preparse(prep); 48 + 49 + prep->data = saved_prep_data; 50 + prep->datalen = saved_prep_datalen; 51 + return ret; 52 + } 53 + 54 + /* 29 55 * Preparse a PKCS#7 wrapped and validated data blob. 30 56 */ 31 57 static int pkcs7_preparse(struct key_preparsed_payload *prep) 32 58 { 33 59 enum key_being_used_for usage = pkcs7_usage; 34 - struct pkcs7_message *pkcs7; 35 - const void *data, *saved_prep_data; 36 - size_t datalen, saved_prep_datalen; 37 - bool trusted; 38 - int ret; 39 - 40 - kenter(""); 41 60 42 61 if (usage >= NR__KEY_BEING_USED_FOR) { 43 62 pr_err("Invalid usage type %d\n", usage); 44 63 return -EINVAL; 45 64 } 46 65 47 - saved_prep_data = prep->data; 48 - saved_prep_datalen = prep->datalen; 49 - pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); 50 - if (IS_ERR(pkcs7)) { 51 - ret = PTR_ERR(pkcs7); 52 - goto error; 53 - } 54 - 55 - ret = pkcs7_verify(pkcs7, usage); 56 - if (ret < 0) 57 - goto error_free; 58 - 59 - ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); 60 - if (ret < 0) 61 - goto error_free; 62 - if (!trusted) 63 - pr_warn("PKCS#7 message doesn't chain back to a trusted key\n"); 64 - 65 - ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false); 66 - if (ret < 0) 67 - goto error_free; 68 - 69 - prep->data = data; 70 - prep->datalen = datalen; 71 - ret = user_preparse(prep); 72 - prep->data = saved_prep_data; 73 - prep->datalen = saved_prep_datalen; 74 - 75 - error_free: 76 - pkcs7_free_message(pkcs7); 77 - error: 78 - kleave(" = %d", ret); 79 - return ret; 66 + return verify_pkcs7_signature(NULL, 0, 67 + prep->data, prep->datalen, 68 + NULL, -ENOKEY, usage, 69 + pkcs7_view_content, prep); 80 70 } 81 71 82 72 /*
+11 -10
crypto/asymmetric_keys/pkcs7_parser.c
··· 168 168 * @pkcs7: The preparsed PKCS#7 message to access 169 169 * @_data: Place to return a pointer to the data 170 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, 174 - * the header of the ASN.1 object that contains it. Returns -ENODATA if the 175 - * data object was missing from the message. 173 + * Get access to the data content of the PKCS#7 message. The size of the 174 + * header of the ASN.1 object that contains it is also provided and can be used 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 179 int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, 178 180 const void **_data, size_t *_data_len, 179 - bool want_wrapper) 181 + size_t *_headerlen) 180 182 { 181 - size_t wrapper; 182 - 183 183 if (!pkcs7->data) 184 184 return -ENODATA; 185 185 186 - wrapper = want_wrapper ? pkcs7->data_hdrlen : 0; 187 - *_data = pkcs7->data - wrapper; 188 - *_data_len = pkcs7->data_len + wrapper; 186 + *_data = pkcs7->data; 187 + *_data_len = pkcs7->data_len; 188 + if (_headerlen) 189 + *_headerlen = pkcs7->data_hdrlen; 189 190 return 0; 190 191 } 191 192 EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
+9 -31
crypto/asymmetric_keys/verify_pefile.c
··· 16 16 #include <linux/err.h> 17 17 #include <linux/pe.h> 18 18 #include <linux/asn1.h> 19 - #include <crypto/pkcs7.h> 19 + #include <linux/verification.h> 20 20 #include <crypto/hash.h> 21 21 #include "verify_pefile.h" 22 22 ··· 392 392 * verify_pefile_signature - Verify the signature on a PE binary image 393 393 * @pebuf: Buffer containing the PE binary image 394 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 396 * @usage: The use to which the key is being put. 397 - * @_trusted: Set to true if trustworth, false otherwise 398 397 * 399 398 * Validate that the certificate chain inside the PKCS#7 message inside the PE 400 399 * binary image intersects keys we already know and trust. ··· 417 418 * May also return -ENOMEM. 418 419 */ 419 420 int verify_pefile_signature(const void *pebuf, unsigned pelen, 420 - struct key *trusted_keyring, 421 - enum key_being_used_for usage, 422 - bool *_trusted) 421 + struct key *trusted_keys, 422 + enum key_being_used_for usage) 423 423 { 424 - struct pkcs7_message *pkcs7; 425 424 struct pefile_context ctx; 426 - const void *data; 427 - size_t datalen; 428 425 int ret; 429 426 430 427 kenter(""); ··· 434 439 if (ret < 0) 435 440 return ret; 436 441 437 - pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len); 438 - if (IS_ERR(pkcs7)) 439 - return PTR_ERR(pkcs7); 440 - ctx.pkcs7 = pkcs7; 441 - 442 - ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false); 443 - if (ret < 0 || datalen == 0) { 444 - pr_devel("PKCS#7 message does not contain data\n"); 445 - ret = -EBADMSG; 446 - goto error; 447 - } 448 - 449 - ret = mscode_parse(&ctx); 442 + ret = verify_pkcs7_signature(NULL, 0, 443 + pebuf + ctx.sig_offset, ctx.sig_len, 444 + trusted_keys, -EKEYREJECTED, usage, 445 + mscode_parse, &ctx); 450 446 if (ret < 0) 451 447 goto error; 452 448 ··· 448 462 * contents. 449 463 */ 450 464 ret = pefile_digest_pe(pebuf, pelen, &ctx); 451 - if (ret < 0) 452 - goto error; 453 - 454 - ret = pkcs7_verify(pkcs7, usage); 455 - if (ret < 0) 456 - goto error; 457 - 458 - ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted); 459 465 460 466 error: 461 - pkcs7_free_message(ctx.pkcs7); 467 + kfree(ctx.digest); 462 468 return ret; 463 469 }
+2 -3
crypto/asymmetric_keys/verify_pefile.h
··· 9 9 * 2 of the Licence, or (at your option) any later version. 10 10 */ 11 11 12 - #include <linux/verify_pefile.h> 13 12 #include <crypto/pkcs7.h> 14 13 #include <crypto/hash_info.h> 15 14 ··· 22 23 unsigned sig_offset; 23 24 unsigned sig_len; 24 25 const struct section_header *secs; 25 - struct pkcs7_message *pkcs7; 26 26 27 27 /* PKCS#7 MS Individual Code Signing content */ 28 28 const void *digest; /* Digest */ ··· 37 39 /* 38 40 * mscode_parser.c 39 41 */ 40 - extern int mscode_parse(struct pefile_context *ctx); 42 + extern int mscode_parse(void *_ctx, const void *content_data, size_t data_len, 43 + size_t asn1hdrlen);
+2 -1
include/crypto/pkcs7.h
··· 12 12 #ifndef _CRYPTO_PKCS7_H 13 13 #define _CRYPTO_PKCS7_H 14 14 15 + #include <linux/verification.h> 15 16 #include <crypto/public_key.h> 16 17 17 18 struct key; ··· 27 26 28 27 extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, 29 28 const void **_data, size_t *_datalen, 30 - bool want_wrapper); 29 + size_t *_headerlen); 31 30 32 31 /* 33 32 * pkcs7_trust.c
-14
include/crypto/public_key.h
··· 15 15 #define _LINUX_PUBLIC_KEY_H 16 16 17 17 /* 18 - * The use to which an asymmetric key is being put. 19 - */ 20 - enum key_being_used_for { 21 - VERIFYING_MODULE_SIGNATURE, 22 - VERIFYING_FIRMWARE_SIGNATURE, 23 - VERIFYING_KEXEC_PE_SIGNATURE, 24 - VERIFYING_KEY_SIGNATURE, 25 - VERIFYING_KEY_SELF_SIGNATURE, 26 - VERIFYING_UNSPECIFIED_SIGNATURE, 27 - NR__KEY_BEING_USED_FOR 28 - }; 29 - extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; 30 - 31 - /* 32 18 * Cryptographic data for the public-key subtype of the asymmetric key type. 33 19 * 34 20 * Note that this may include private part of the key as well as the public
+1
include/keys/asymmetric-type.h
··· 15 15 #define _KEYS_ASYMMETRIC_TYPE_H 16 16 17 17 #include <linux/key-type.h> 18 + #include <linux/verification.h> 18 19 19 20 extern struct key_type key_type_asymmetric; 20 21
+1 -6
include/keys/system_keyring.h
··· 15 15 #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING 16 16 17 17 #include <linux/key.h> 18 + #include <linux/verification.h> 18 19 #include <crypto/public_key.h> 19 20 20 21 extern struct key *system_trusted_keyring; ··· 28 27 { 29 28 return NULL; 30 29 } 31 - #endif 32 - 33 - #ifdef CONFIG_SYSTEM_DATA_VERIFICATION 34 - extern int system_verify_data(const void *data, unsigned long len, 35 - const void *raw_pkcs7, size_t pkcs7_len, 36 - enum key_being_used_for usage); 37 30 #endif 38 31 39 32 #ifdef CONFIG_IMA_MOK_KEYRING
+50
include/linux/verification.h
··· 1 + /* Signature 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_VERIFICATION_H 13 + #define _LINUX_VERIFICATION_H 14 + 15 + /* 16 + * The use to which an asymmetric key is being put. 17 + */ 18 + enum key_being_used_for { 19 + VERIFYING_MODULE_SIGNATURE, 20 + VERIFYING_FIRMWARE_SIGNATURE, 21 + VERIFYING_KEXEC_PE_SIGNATURE, 22 + VERIFYING_KEY_SIGNATURE, 23 + VERIFYING_KEY_SELF_SIGNATURE, 24 + VERIFYING_UNSPECIFIED_SIGNATURE, 25 + NR__KEY_BEING_USED_FOR 26 + }; 27 + extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; 28 + 29 + #ifdef CONFIG_SYSTEM_DATA_VERIFICATION 30 + 31 + struct key; 32 + 33 + extern int verify_pkcs7_signature(const void *data, size_t len, 34 + const void *raw_pkcs7, size_t pkcs7_len, 35 + struct key *trusted_keys, 36 + int untrusted_error, 37 + enum key_being_used_for usage, 38 + int (*view_content)(void *ctx, 39 + const void *data, size_t len, 40 + size_t asn1hdrlen), 41 + void *ctx); 42 + 43 + #ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION 44 + extern int verify_pefile_signature(const void *pebuf, unsigned pelen, 45 + struct key *trusted_keys, 46 + enum key_being_used_for usage); 47 + #endif 48 + 49 + #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ 50 + #endif /* _LINUX_VERIFY_PEFILE_H */
-22
include/linux/verify_pefile.h
··· 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 - #include <crypto/public_key.h> 16 - 17 - extern int verify_pefile_signature(const void *pebuf, unsigned pelen, 18 - struct key *trusted_keyring, 19 - enum key_being_used_for usage, 20 - bool *_trusted); 21 - 22 - #endif /* _LINUX_VERIFY_PEFILE_H */
+3 -2
kernel/module_signing.c
··· 80 80 return -EBADMSG; 81 81 } 82 82 83 - return system_verify_data(mod, modlen, mod + modlen, sig_len, 84 - VERIFYING_MODULE_SIGNATURE); 83 + return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len, 84 + NULL, -ENOKEY, VERIFYING_MODULE_SIGNATURE, 85 + NULL, NULL); 85 86 }