Skip to content

Commit e68503b

Browse files
committed
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>
1 parent ad3043f commit e68503b

File tree

15 files changed

+155
-173
lines changed

15 files changed

+155
-173
lines changed

arch/x86/kernel/kexec-bzimage64.c

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
#include <linux/kernel.h>
2020
#include <linux/mm.h>
2121
#include <linux/efi.h>
22-
#include <linux/verify_pefile.h>
23-
#include <keys/system_keyring.h>
22+
#include <linux/verification.h>
2423

2524
#include <asm/bootparam.h>
2625
#include <asm/setup.h>
@@ -529,18 +528,9 @@ static int bzImage64_cleanup(void *loader_data)
529528
#ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
530529
static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
531530
{
532-
bool trusted;
533-
int ret;
534-
535-
ret = verify_pefile_signature(kernel, kernel_len,
536-
system_trusted_keyring,
537-
VERIFYING_KEXEC_PE_SIGNATURE,
538-
&trusted);
539-
if (ret < 0)
540-
return ret;
541-
if (!trusted)
542-
return -EKEYREJECTED;
543-
return 0;
531+
return verify_pefile_signature(kernel, kernel_len,
532+
NULL,
533+
VERIFYING_KEXEC_PE_SIGNATURE);
544534
}
545535
#endif
546536

certs/system_keyring.c

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,16 +108,25 @@ late_initcall(load_system_certificate_list);
108108
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
109109

110110
/**
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).
113113
* @len: Size of @data.
114114
* @raw_pkcs7: The PKCS#7 message that is the signature.
115115
* @pkcs7_len: The size of @raw_pkcs7.
116+
* @trusted_keys: Trusted keys to use (NULL for system_trusted_keyring).
116117
* @usage: The use to which the key is being put.
118+
* @view_content: Callback to gain access to content.
119+
* @ctx: Context for callback.
117120
*/
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)
121130
{
122131
struct pkcs7_message *pkcs7;
123132
bool trusted;
@@ -128,7 +137,7 @@ int system_verify_data(const void *data, unsigned long len,
128137
return PTR_ERR(pkcs7);
129138

130139
/* The data should be detached - so we need to supply it. */
131-
if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
140+
if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
132141
pr_err("PKCS#7 signature with non-detached data\n");
133142
ret = -EBADMSG;
134143
goto error;
@@ -138,20 +147,36 @@ int system_verify_data(const void *data, unsigned long len,
138147
if (ret < 0)
139148
goto error;
140149

141-
ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
150+
if (!trusted_keys)
151+
trusted_keys = system_trusted_keyring;
152+
ret = pkcs7_validate_trust(pkcs7, trusted_keys, &trusted);
142153
if (ret < 0)
143154
goto error;
144155

145-
if (!trusted) {
156+
if (!trusted && untrusted_error) {
146157
pr_err("PKCS#7 signature not signed with a trusted key\n");
147-
ret = -ENOKEY;
158+
ret = untrusted_error;
159+
goto error;
160+
}
161+
162+
if (view_content) {
163+
size_t asn1hdrlen;
164+
165+
ret = pkcs7_get_content_data(pkcs7, &data, &len, &asn1hdrlen);
166+
if (ret < 0) {
167+
if (ret == -ENODATA)
168+
pr_devel("PKCS#7 message does not contain data\n");
169+
goto error;
170+
}
171+
172+
ret = view_content(ctx, data, len, asn1hdrlen);
148173
}
149174

150175
error:
151176
pkcs7_free_message(pkcs7);
152177
pr_devel("<==%s() = %d\n", __func__, ret);
153178
return ret;
154179
}
155-
EXPORT_SYMBOL_GPL(system_verify_data);
180+
EXPORT_SYMBOL_GPL(verify_pkcs7_signature);
156181

157182
#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */

crypto/asymmetric_keys/Kconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ config PKCS7_MESSAGE_PARSER
4040

4141
config PKCS7_TEST_KEY
4242
tristate "PKCS#7 testing key type"
43-
depends on PKCS7_MESSAGE_PARSER
44-
select SYSTEM_TRUSTED_KEYRING
43+
depends on SYSTEM_DATA_VERIFICATION
4544
help
4645
This option provides a type of key that can be loaded up from a
4746
PKCS#7 message - provided the message is signed by a trusted key. If
@@ -54,6 +53,7 @@ config PKCS7_TEST_KEY
5453
config SIGNED_PE_FILE_VERIFICATION
5554
bool "Support for PE file signature verification"
5655
depends on PKCS7_MESSAGE_PARSER=y
56+
depends on SYSTEM_DATA_VERIFICATION
5757
select ASN1
5858
select OID_REGISTRY
5959
help

crypto/asymmetric_keys/mscode_parser.c

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,13 @@
2121
/*
2222
* Parse a Microsoft Individual Code Signing blob
2323
*/
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)
2526
{
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-
}
27+
struct pefile_context *ctx = _ctx;
3628

29+
content_data -= asn1hdrlen;
30+
data_len += asn1hdrlen;
3731
pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
3832
content_data);
3933

@@ -129,7 +123,6 @@ int mscode_note_digest(void *context, size_t hdrlen,
129123
{
130124
struct pefile_context *ctx = context;
131125

132-
ctx->digest = value;
133-
ctx->digest_len = vlen;
134-
return 0;
126+
ctx->digest = kmemdup(value, vlen, GFP_KERNEL);
127+
return ctx->digest ? 0 : -ENOMEM;
135128
}

crypto/asymmetric_keys/pkcs7_key_type.c

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,9 @@
1313
#include <linux/key.h>
1414
#include <linux/err.h>
1515
#include <linux/module.h>
16+
#include <linux/verification.h>
1617
#include <linux/key-type.h>
17-
#include <keys/asymmetric-type.h>
18-
#include <crypto/pkcs7.h>
1918
#include <keys/user-type.h>
20-
#include <keys/system_keyring.h>
21-
#include "pkcs7_parser.h"
2219

2320
MODULE_LICENSE("GPL");
2421
MODULE_DESCRIPTION("PKCS#7 testing key type");
@@ -29,59 +26,46 @@ MODULE_PARM_DESC(pkcs7_usage,
2926
"Usage to specify when verifying the PKCS#7 message");
3027

3128
/*
32-
* Preparse a PKCS#7 wrapped and validated data blob.
29+
* Retrieve the PKCS#7 message content.
3330
*/
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)
3533
{
36-
enum key_being_used_for usage = pkcs7_usage;
37-
struct pkcs7_message *pkcs7;
38-
const void *data, *saved_prep_data;
39-
size_t datalen, saved_prep_datalen;
40-
bool trusted;
34+
struct key_preparsed_payload *prep = ctx;
35+
const void *saved_prep_data;
36+
size_t saved_prep_datalen;
4137
int ret;
4238

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-
5039
saved_prep_data = prep->data;
5140
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-
7241
prep->data = data;
73-
prep->datalen = datalen;
42+
prep->datalen = len;
43+
7444
ret = user_preparse(prep);
45+
7546
prep->data = saved_prep_data;
7647
prep->datalen = saved_prep_datalen;
77-
78-
error_free:
79-
pkcs7_free_message(pkcs7);
80-
error:
81-
kleave(" = %d", ret);
8248
return ret;
8349
}
8450

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+
8569
/*
8670
* user defined keys take an arbitrary string as the description and an
8771
* arbitrary blob of data as the payload

crypto/asymmetric_keys/pkcs7_parser.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -168,24 +168,25 @@ EXPORT_SYMBOL_GPL(pkcs7_parse_message);
168168
* @pkcs7: The preparsed PKCS#7 message to access
169169
* @_data: Place to return a pointer to the data
170170
* @_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
172172
*
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.
176178
*/
177179
int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
178180
const void **_data, size_t *_data_len,
179-
bool want_wrapper)
181+
size_t *_headerlen)
180182
{
181-
size_t wrapper;
182-
183183
if (!pkcs7->data)
184184
return -ENODATA;
185185

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;
189190
return 0;
190191
}
191192
EXPORT_SYMBOL_GPL(pkcs7_get_content_data);

crypto/asymmetric_keys/verify_pefile.c

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include <linux/err.h>
1717
#include <linux/pe.h>
1818
#include <linux/asn1.h>
19-
#include <crypto/pkcs7.h>
19+
#include <linux/verification.h>
2020
#include <crypto/hash.h>
2121
#include "verify_pefile.h"
2222

@@ -392,9 +392,8 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
392392
* verify_pefile_signature - Verify the signature on a PE binary image
393393
* @pebuf: Buffer containing the PE binary image
394394
* @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
396396
* @usage: The use to which the key is being put.
397-
* @_trusted: Set to true if trustworth, false otherwise
398397
*
399398
* Validate that the certificate chain inside the PKCS#7 message inside the PE
400399
* binary image intersects keys we already know and trust.
@@ -418,14 +417,10 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
418417
* May also return -ENOMEM.
419418
*/
420419
int verify_pefile_signature(const void *pebuf, unsigned pelen,
421-
struct key *trusted_keyring,
422-
enum key_being_used_for usage,
423-
bool *_trusted)
420+
struct key *trusted_keys,
421+
enum key_being_used_for usage)
424422
{
425-
struct pkcs7_message *pkcs7;
426423
struct pefile_context ctx;
427-
const void *data;
428-
size_t datalen;
429424
int ret;
430425

431426
kenter("");
@@ -439,19 +434,10 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
439434
if (ret < 0)
440435
return ret;
441436

442-
pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len);
443-
if (IS_ERR(pkcs7))
444-
return PTR_ERR(pkcs7);
445-
ctx.pkcs7 = pkcs7;
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);
437+
ret = verify_pkcs7_signature(NULL, 0,
438+
pebuf + ctx.sig_offset, ctx.sig_len,
439+
trusted_keys, -EKEYREJECTED, usage,
440+
mscode_parse, &ctx);
455441
if (ret < 0)
456442
goto error;
457443

@@ -462,16 +448,8 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
462448
* contents.
463449
*/
464450
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);
473451

474452
error:
475-
pkcs7_free_message(ctx.pkcs7);
453+
kfree(ctx.digest);
476454
return ret;
477455
}

0 commit comments

Comments
 (0)