aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2015-08-05 10:22:27 -0400
committerDavid Howells <dhowells@redhat.com>2015-08-12 12:01:01 -0400
commit99db44350672c8a5ee9a7b0a6f4cd6ff10136065 (patch)
tree4a135d2e049e6e9db195b96a56d03363774b1f7b
parentf29299b4801076e14bb149cb2fc44bd8dc2f51cc (diff)
PKCS#7: Appropriately restrict authenticated attributes and content type
A PKCS#7 or CMS message can have per-signature authenticated attributes that are digested as a lump and signed by the authorising key for that signature. If such attributes exist, the content digest isn't itself signed, but rather it is included in a special authattr which then contributes to the signature. Further, we already require the master message content type to be pkcs7_signedData - but there's also a separate content type for the data itself within the SignedData object and this must be repeated inside the authattrs for each signer [RFC2315 9.2, RFC5652 11.1]. We should really validate the authattrs if they exist or forbid them entirely as appropriate. To this end: (1) Alter the PKCS#7 parser to reject any message that has more than one signature where at least one signature has authattrs and at least one that does not. (2) Validate authattrs if they are present and strongly restrict them. Only the following authattrs are permitted and all others are rejected: (a) contentType. This is checked to be an OID that matches the content type in the SignedData object. (b) messageDigest. This must match the crypto digest of the data. (c) signingTime. If present, we check that this is a valid, parseable UTCTime or GeneralTime and that the date it encodes fits within the validity window of the matching X.509 cert. (d) S/MIME capabilities. We don't check the contents. (e) Authenticode SP Opus Info. We don't check the contents. (f) Authenticode Statement Type. We don't check the contents. The message is rejected if (a) or (b) are missing. If the message is an Authenticode type, the message is rejected if (e) is missing; if not Authenticode, the message is rejected if (d) - (f) are present. The S/MIME capabilities authattr (d) unfortunately has to be allowed to support kernels already signed by the pesign program. This only affects kexec. sign-file suppresses them (CMS_NOSMIMECAP). The message is also rejected if an authattr is given more than once or if it contains more than one element in its set of values. (3) Add a parameter to pkcs7_verify() to select one of the following restrictions and pass in the appropriate option from the callers: (*) VERIFYING_MODULE_SIGNATURE This requires that the SignedData content type be pkcs7-data and forbids authattrs. sign-file sets CMS_NOATTR. We could be more flexible and permit authattrs optionally, but only permit minimal content. (*) VERIFYING_FIRMWARE_SIGNATURE This requires that the SignedData content type be pkcs7-data and requires authattrs. In future, this will require an attribute holding the target firmware name in addition to the minimal set. (*) VERIFYING_UNSPECIFIED_SIGNATURE This requires that the SignedData content type be pkcs7-data but allows either no authattrs or only permits the minimal set. (*) VERIFYING_KEXEC_PE_SIGNATURE This only supports the Authenticode SPC_INDIRECT_DATA content type and requires at least an SpcSpOpusInfo authattr in addition to the minimal set. It also permits an SPC_STATEMENT_TYPE authattr (and an S/MIME capabilities authattr because the pesign program doesn't remove these). (*) VERIFYING_KEY_SIGNATURE (*) VERIFYING_KEY_SELF_SIGNATURE These are invalid in this context but are included for later use when limiting the use of X.509 certs. (4) The pkcs7_test key type is given a module parameter to select between the above options for testing purposes. For example: echo 1 >/sys/module/pkcs7_test_key/parameters/usage keyctl padd pkcs7_test foo @s </tmp/stuff.pkcs7 will attempt to check the signature on stuff.pkcs7 as if it contains a firmware blob (1 being VERIFYING_FIRMWARE_SIGNATURE). Suggested-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Marcel Holtmann <marcel@holtmann.org> Reviewed-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--arch/x86/kernel/kexec-bzimage64.c4
-rw-r--r--crypto/asymmetric_keys/asymmetric_type.c11
-rw-r--r--crypto/asymmetric_keys/pkcs7.asn16
-rw-r--r--crypto/asymmetric_keys/pkcs7_key_type.c14
-rw-r--r--crypto/asymmetric_keys/pkcs7_parser.c138
-rw-r--r--crypto/asymmetric_keys/pkcs7_parser.h15
-rw-r--r--crypto/asymmetric_keys/pkcs7_verify.c65
-rw-r--r--crypto/asymmetric_keys/verify_pefile.c7
-rw-r--r--include/crypto/pkcs7.h10
-rw-r--r--include/crypto/public_key.h14
-rw-r--r--include/keys/system_keyring.h4
-rw-r--r--include/linux/oid_registry.h4
-rw-r--r--include/linux/verify_pefile.h6
-rw-r--r--kernel/module_signing.c3
-rw-r--r--kernel/system_keyring.c6
-rwxr-xr-xscripts/sign-file.c5
16 files changed, 285 insertions, 27 deletions
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index ca83f7ac388b..fab22e72808c 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -536,7 +536,9 @@ static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
536 int ret; 536 int ret;
537 537
538 ret = verify_pefile_signature(kernel, kernel_len, 538 ret = verify_pefile_signature(kernel, kernel_len,
539 system_trusted_keyring, &trusted); 539 system_trusted_keyring,
540 VERIFYING_KEXEC_PE_SIGNATURE,
541 &trusted);
540 if (ret < 0) 542 if (ret < 0)
541 return ret; 543 return ret;
542 if (!trusted) 544 if (!trusted)
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index b0e4ed23d668..1916680ad81b 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -12,6 +12,7 @@
12 */ 12 */
13#include <keys/asymmetric-subtype.h> 13#include <keys/asymmetric-subtype.h>
14#include <keys/asymmetric-parser.h> 14#include <keys/asymmetric-parser.h>
15#include <crypto/public_key.h>
15#include <linux/seq_file.h> 16#include <linux/seq_file.h>
16#include <linux/module.h> 17#include <linux/module.h>
17#include <linux/slab.h> 18#include <linux/slab.h>
@@ -20,6 +21,16 @@
20 21
21MODULE_LICENSE("GPL"); 22MODULE_LICENSE("GPL");
22 23
24const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = {
25 [VERIFYING_MODULE_SIGNATURE] = "mod sig",
26 [VERIFYING_FIRMWARE_SIGNATURE] = "firmware sig",
27 [VERIFYING_KEXEC_PE_SIGNATURE] = "kexec PE sig",
28 [VERIFYING_KEY_SIGNATURE] = "key sig",
29 [VERIFYING_KEY_SELF_SIGNATURE] = "key self sig",
30 [VERIFYING_UNSPECIFIED_SIGNATURE] = "unspec sig",
31};
32EXPORT_SYMBOL_GPL(key_being_used_for);
33
23static LIST_HEAD(asymmetric_key_parsers); 34static LIST_HEAD(asymmetric_key_parsers);
24static DECLARE_RWSEM(asymmetric_key_parsers_sem); 35static DECLARE_RWSEM(asymmetric_key_parsers_sem);
25 36
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1
index 6bf8ff4f7414..1eca740b816a 100644
--- a/crypto/asymmetric_keys/pkcs7.asn1
+++ b/crypto/asymmetric_keys/pkcs7.asn1
@@ -8,7 +8,7 @@ ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID })
8SignedData ::= SEQUENCE { 8SignedData ::= SEQUENCE {
9 version INTEGER ({ pkcs7_note_signeddata_version }), 9 version INTEGER ({ pkcs7_note_signeddata_version }),
10 digestAlgorithms DigestAlgorithmIdentifiers, 10 digestAlgorithms DigestAlgorithmIdentifiers,
11 contentInfo ContentInfo, 11 contentInfo ContentInfo ({ pkcs7_note_content }),
12 certificates CHOICE { 12 certificates CHOICE {
13 certSet [0] IMPLICIT ExtendedCertificatesAndCertificates, 13 certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
14 certSequence [2] IMPLICIT Certificates 14 certSequence [2] IMPLICIT Certificates
@@ -21,7 +21,7 @@ SignedData ::= SEQUENCE {
21} 21}
22 22
23ContentInfo ::= SEQUENCE { 23ContentInfo ::= SEQUENCE {
24 contentType ContentType, 24 contentType ContentType ({ pkcs7_note_OID }),
25 content [0] EXPLICIT Data OPTIONAL 25 content [0] EXPLICIT Data OPTIONAL
26} 26}
27 27
@@ -111,7 +111,7 @@ AuthenticatedAttribute ::= SEQUENCE {
111} 111}
112 112
113UnauthenticatedAttribute ::= SEQUENCE { 113UnauthenticatedAttribute ::= SEQUENCE {
114 type OBJECT IDENTIFIER ({ pkcs7_note_OID }), 114 type OBJECT IDENTIFIER,
115 values SET OF ANY 115 values SET OF ANY
116} 116}
117 117
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c
index 3d13b042da73..10d34dbd00b9 100644
--- a/crypto/asymmetric_keys/pkcs7_key_type.c
+++ b/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -14,16 +14,23 @@
14#include <linux/err.h> 14#include <linux/err.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/key-type.h> 16#include <linux/key-type.h>
17#include <keys/asymmetric-type.h>
17#include <crypto/pkcs7.h> 18#include <crypto/pkcs7.h>
18#include <keys/user-type.h> 19#include <keys/user-type.h>
19#include <keys/system_keyring.h> 20#include <keys/system_keyring.h>
20#include "pkcs7_parser.h" 21#include "pkcs7_parser.h"
21 22
23static unsigned pkcs7_usage;
24module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO);
25MODULE_PARM_DESC(pkcs7_usage,
26 "Usage to specify when verifying the PKCS#7 message");
27
22/* 28/*
23 * Preparse a PKCS#7 wrapped and validated data blob. 29 * Preparse a PKCS#7 wrapped and validated data blob.
24 */ 30 */
25static int pkcs7_preparse(struct key_preparsed_payload *prep) 31static int pkcs7_preparse(struct key_preparsed_payload *prep)
26{ 32{
33 enum key_being_used_for usage = pkcs7_usage;
27 struct pkcs7_message *pkcs7; 34 struct pkcs7_message *pkcs7;
28 const void *data, *saved_prep_data; 35 const void *data, *saved_prep_data;
29 size_t datalen, saved_prep_datalen; 36 size_t datalen, saved_prep_datalen;
@@ -32,6 +39,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
32 39
33 kenter(""); 40 kenter("");
34 41
42 if (usage >= NR__KEY_BEING_USED_FOR) {
43 pr_err("Invalid usage type %d\n", usage);
44 return -EINVAL;
45 }
46
35 saved_prep_data = prep->data; 47 saved_prep_data = prep->data;
36 saved_prep_datalen = prep->datalen; 48 saved_prep_datalen = prep->datalen;
37 pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); 49 pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
@@ -40,7 +52,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
40 goto error; 52 goto error;
41 } 53 }
42 54
43 ret = pkcs7_verify(pkcs7); 55 ret = pkcs7_verify(pkcs7, usage);
44 if (ret < 0) 56 if (ret < 0)
45 goto error_free; 57 goto error_free;
46 58
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 826e2f3f507b..e6298b7a945a 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -81,6 +81,30 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7)
81} 81}
82EXPORT_SYMBOL_GPL(pkcs7_free_message); 82EXPORT_SYMBOL_GPL(pkcs7_free_message);
83 83
84/*
85 * Check authenticatedAttributes are provided or not provided consistently.
86 */
87static int pkcs7_check_authattrs(struct pkcs7_message *msg)
88{
89 struct pkcs7_signed_info *sinfo;
90 bool want;
91
92 sinfo = msg->signed_infos;
93 if (sinfo->authattrs) {
94 want = true;
95 msg->have_authattrs = true;
96 }
97
98 for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
99 if (!!sinfo->authattrs != want)
100 goto inconsistent;
101 return 0;
102
103inconsistent:
104 pr_warn("Inconsistently supplied authAttrs\n");
105 return -EINVAL;
106}
107
84/** 108/**
85 * pkcs7_parse_message - Parse a PKCS#7 message 109 * pkcs7_parse_message - Parse a PKCS#7 message
86 * @data: The raw binary ASN.1 encoded message to be parsed 110 * @data: The raw binary ASN.1 encoded message to be parsed
@@ -113,6 +137,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
113 goto out; 137 goto out;
114 } 138 }
115 139
140 ret = pkcs7_check_authattrs(ctx->msg);
141 if (ret < 0)
142 goto out;
143
116 msg = ctx->msg; 144 msg = ctx->msg;
117 ctx->msg = NULL; 145 ctx->msg = NULL;
118 146
@@ -381,6 +409,25 @@ int pkcs7_note_certificate_list(void *context, size_t hdrlen,
381} 409}
382 410
383/* 411/*
412 * Note the content type.
413 */
414int pkcs7_note_content(void *context, size_t hdrlen,
415 unsigned char tag,
416 const void *value, size_t vlen)
417{
418 struct pkcs7_parse_context *ctx = context;
419
420 if (ctx->last_oid != OID_data &&
421 ctx->last_oid != OID_msIndirectData) {
422 pr_warn("Unsupported data type %d\n", ctx->last_oid);
423 return -EINVAL;
424 }
425
426 ctx->msg->data_type = ctx->last_oid;
427 return 0;
428}
429
430/*
384 * Extract the data from the message and store that and its content type OID in 431 * Extract the data from the message and store that and its content type OID in
385 * the context. 432 * the context.
386 */ 433 */
@@ -395,31 +442,90 @@ int pkcs7_note_data(void *context, size_t hdrlen,
395 ctx->msg->data = value; 442 ctx->msg->data = value;
396 ctx->msg->data_len = vlen; 443 ctx->msg->data_len = vlen;
397 ctx->msg->data_hdrlen = hdrlen; 444 ctx->msg->data_hdrlen = hdrlen;
398 ctx->msg->data_type = ctx->last_oid;
399 return 0; 445 return 0;
400} 446}
401 447
402/* 448/*
403 * Parse authenticated attributes 449 * Parse authenticated attributes.
404 */ 450 */
405int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, 451int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen,
406 unsigned char tag, 452 unsigned char tag,
407 const void *value, size_t vlen) 453 const void *value, size_t vlen)
408{ 454{
409 struct pkcs7_parse_context *ctx = context; 455 struct pkcs7_parse_context *ctx = context;
456 struct pkcs7_signed_info *sinfo = ctx->sinfo;
457 enum OID content_type;
410 458
411 pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); 459 pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
412 460
413 switch (ctx->last_oid) { 461 switch (ctx->last_oid) {
462 case OID_contentType:
463 if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set))
464 goto repeated;
465 content_type = look_up_OID(value, vlen);
466 if (content_type != ctx->msg->data_type) {
467 pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n",
468 ctx->msg->data_type, sinfo->index,
469 content_type);
470 return -EBADMSG;
471 }
472 return 0;
473
474 case OID_signingTime:
475 if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set))
476 goto repeated;
477 /* Should we check that the signing time is consistent
478 * with the signer's X.509 cert?
479 */
480 return x509_decode_time(&sinfo->signing_time,
481 hdrlen, tag, value, vlen);
482
414 case OID_messageDigest: 483 case OID_messageDigest:
484 if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))
485 goto repeated;
415 if (tag != ASN1_OTS) 486 if (tag != ASN1_OTS)
416 return -EBADMSG; 487 return -EBADMSG;
417 ctx->sinfo->msgdigest = value; 488 sinfo->msgdigest = value;
418 ctx->sinfo->msgdigest_len = vlen; 489 sinfo->msgdigest_len = vlen;
490 return 0;
491
492 case OID_smimeCapabilites:
493 if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set))
494 goto repeated;
495 if (ctx->msg->data_type != OID_msIndirectData) {
496 pr_warn("S/MIME Caps only allowed with Authenticode\n");
497 return -EKEYREJECTED;
498 }
499 return 0;
500
501 /* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE
502 * char URLs and cont[1] 8-bit char URLs.
503 *
504 * Microsoft StatementType seems to contain a list of OIDs that
505 * are also used as extendedKeyUsage types in X.509 certs.
506 */
507 case OID_msSpOpusInfo:
508 if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
509 goto repeated;
510 goto authenticode_check;
511 case OID_msStatementType:
512 if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set))
513 goto repeated;
514 authenticode_check:
515 if (ctx->msg->data_type != OID_msIndirectData) {
516 pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n");
517 return -EKEYREJECTED;
518 }
519 /* I'm not sure how to validate these */
419 return 0; 520 return 0;
420 default: 521 default:
421 return 0; 522 return 0;
422 } 523 }
524
525repeated:
526 /* We permit max one item per AuthenticatedAttribute and no repeats */
527 pr_warn("Repeated/multivalue AuthAttrs not permitted\n");
528 return -EKEYREJECTED;
423} 529}
424 530
425/* 531/*
@@ -430,10 +536,25 @@ int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
430 const void *value, size_t vlen) 536 const void *value, size_t vlen)
431{ 537{
432 struct pkcs7_parse_context *ctx = context; 538 struct pkcs7_parse_context *ctx = context;
539 struct pkcs7_signed_info *sinfo = ctx->sinfo;
540
541 if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||
542 !test_bit(sinfo_has_message_digest, &sinfo->aa_set) ||
543 (ctx->msg->data_type == OID_msIndirectData &&
544 !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) {
545 pr_warn("Missing required AuthAttr\n");
546 return -EBADMSG;
547 }
548
549 if (ctx->msg->data_type != OID_msIndirectData &&
550 test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) {
551 pr_warn("Unexpected Authenticode AuthAttr\n");
552 return -EBADMSG;
553 }
433 554
434 /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ 555 /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
435 ctx->sinfo->authattrs = value - (hdrlen - 1); 556 sinfo->authattrs = value - (hdrlen - 1);
436 ctx->sinfo->authattrs_len = vlen + (hdrlen - 1); 557 sinfo->authattrs_len = vlen + (hdrlen - 1);
437 return 0; 558 return 0;
438} 559}
439 560
@@ -511,6 +632,11 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
511 struct pkcs7_signed_info *sinfo = ctx->sinfo; 632 struct pkcs7_signed_info *sinfo = ctx->sinfo;
512 struct asymmetric_key_id *kid; 633 struct asymmetric_key_id *kid;
513 634
635 if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) {
636 pr_warn("Authenticode requires AuthAttrs\n");
637 return -EBADMSG;
638 }
639
514 /* Generate cert issuer + serial number key ID */ 640 /* Generate cert issuer + serial number key ID */
515 if (!ctx->expect_skid) { 641 if (!ctx->expect_skid) {
516 kid = asymmetric_key_generate_id(ctx->raw_serial, 642 kid = asymmetric_key_generate_id(ctx->raw_serial,
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
index 790dd7cec82c..a66b19ebcf47 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.h
+++ b/crypto/asymmetric_keys/pkcs7_parser.h
@@ -21,9 +21,9 @@
21struct pkcs7_signed_info { 21struct pkcs7_signed_info {
22 struct pkcs7_signed_info *next; 22 struct pkcs7_signed_info *next;
23 struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ 23 struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
24 unsigned index; 24 unsigned index;
25 bool trusted; 25 bool trusted;
26 bool unsupported_crypto; /* T if not usable due to missing crypto */ 26 bool unsupported_crypto; /* T if not usable due to missing crypto */
27 27
28 /* Message digest - the digest of the Content Data (or NULL) */ 28 /* Message digest - the digest of the Content Data (or NULL) */
29 const void *msgdigest; 29 const void *msgdigest;
@@ -32,6 +32,14 @@ struct pkcs7_signed_info {
32 /* Authenticated Attribute data (or NULL) */ 32 /* Authenticated Attribute data (or NULL) */
33 unsigned authattrs_len; 33 unsigned authattrs_len;
34 const void *authattrs; 34 const void *authattrs;
35 unsigned long aa_set;
36#define sinfo_has_content_type 0
37#define sinfo_has_signing_time 1
38#define sinfo_has_message_digest 2
39#define sinfo_has_smime_caps 3
40#define sinfo_has_ms_opus_info 4
41#define sinfo_has_ms_statement_type 5
42 time64_t signing_time;
35 43
36 /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1] 44 /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1]
37 * or issuing cert's SKID [CMS ver 3]. 45 * or issuing cert's SKID [CMS ver 3].
@@ -53,6 +61,7 @@ struct pkcs7_message {
53 struct x509_certificate *crl; /* Revocation list */ 61 struct x509_certificate *crl; /* Revocation list */
54 struct pkcs7_signed_info *signed_infos; 62 struct pkcs7_signed_info *signed_infos;
55 u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */ 63 u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */
64 bool have_authattrs; /* T if have authattrs */
56 65
57 /* Content Data (or NULL) */ 66 /* Content Data (or NULL) */
58 enum OID data_type; /* Type of Data */ 67 enum OID data_type; /* Type of Data */
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 404f89a0f852..d20c0b4b880e 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -70,9 +70,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
70 * message digest attribute amongst them which corresponds to the 70 * message digest attribute amongst them which corresponds to the
71 * digest we just calculated. 71 * digest we just calculated.
72 */ 72 */
73 if (sinfo->msgdigest) { 73 if (sinfo->authattrs) {
74 u8 tag; 74 u8 tag;
75 75
76 if (!sinfo->msgdigest) {
77 pr_warn("Sig %u: No messageDigest\n", sinfo->index);
78 ret = -EKEYREJECTED;
79 goto error;
80 }
81
76 if (sinfo->msgdigest_len != sinfo->sig.digest_size) { 82 if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
77 pr_debug("Sig %u: Invalid digest size (%u)\n", 83 pr_debug("Sig %u: Invalid digest size (%u)\n",
78 sinfo->index, sinfo->msgdigest_len); 84 sinfo->index, sinfo->msgdigest_len);
@@ -314,6 +320,18 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
314 pr_devel("Using X.509[%u] for sig %u\n", 320 pr_devel("Using X.509[%u] for sig %u\n",
315 sinfo->signer->index, sinfo->index); 321 sinfo->signer->index, sinfo->index);
316 322
323 /* Check that the PKCS#7 signing time is valid according to the X.509
324 * certificate. We can't, however, check against the system clock
325 * since that may not have been set yet and may be wrong.
326 */
327 if (test_bit(sinfo_has_signing_time, &sinfo->aa_set)) {
328 if (sinfo->signing_time < sinfo->signer->valid_from ||
329 sinfo->signing_time > sinfo->signer->valid_to) {
330 pr_warn("Message signed outside of X.509 validity window\n");
331 return -EKEYREJECTED;
332 }
333 }
334
317 /* Verify the PKCS#7 binary against the key */ 335 /* Verify the PKCS#7 binary against the key */
318 ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); 336 ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
319 if (ret < 0) 337 if (ret < 0)
@@ -328,6 +346,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
328/** 346/**
329 * pkcs7_verify - Verify a PKCS#7 message 347 * pkcs7_verify - Verify a PKCS#7 message
330 * @pkcs7: The PKCS#7 message to be verified 348 * @pkcs7: The PKCS#7 message to be verified
349 * @usage: The use to which the key is being put
331 * 350 *
332 * Verify a PKCS#7 message is internally consistent - that is, the data digest 351 * Verify a PKCS#7 message is internally consistent - that is, the data digest
333 * matches the digest in the AuthAttrs and any signature in the message or one 352 * matches the digest in the AuthAttrs and any signature in the message or one
@@ -339,6 +358,9 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
339 * 358 *
340 * Returns, in order of descending priority: 359 * Returns, in order of descending priority:
341 * 360 *
361 * (*) -EKEYREJECTED if a key was selected that had a usage restriction at
362 * odds with the specified usage, or:
363 *
342 * (*) -EKEYREJECTED if a signature failed to match for which we found an 364 * (*) -EKEYREJECTED if a signature failed to match for which we found an
343 * appropriate X.509 certificate, or: 365 * appropriate X.509 certificate, or:
344 * 366 *
@@ -350,7 +372,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
350 * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified 372 * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified
351 * (note that a signature chain may be of zero length), or: 373 * (note that a signature chain may be of zero length), or:
352 */ 374 */
353int pkcs7_verify(struct pkcs7_message *pkcs7) 375int pkcs7_verify(struct pkcs7_message *pkcs7,
376 enum key_being_used_for usage)
354{ 377{
355 struct pkcs7_signed_info *sinfo; 378 struct pkcs7_signed_info *sinfo;
356 struct x509_certificate *x509; 379 struct x509_certificate *x509;
@@ -359,6 +382,44 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
359 382
360 kenter(""); 383 kenter("");
361 384
385 switch (usage) {
386 case VERIFYING_MODULE_SIGNATURE:
387 if (pkcs7->data_type != OID_data) {
388 pr_warn("Invalid module sig (not pkcs7-data)\n");
389 return -EKEYREJECTED;
390 }
391 if (pkcs7->have_authattrs) {
392 pr_warn("Invalid module sig (has authattrs)\n");
393 return -EKEYREJECTED;
394 }
395 break;
396 case VERIFYING_FIRMWARE_SIGNATURE:
397 if (pkcs7->data_type != OID_data) {
398 pr_warn("Invalid firmware sig (not pkcs7-data)\n");
399 return -EKEYREJECTED;
400 }
401 if (!pkcs7->have_authattrs) {
402 pr_warn("Invalid firmware sig (missing authattrs)\n");
403 return -EKEYREJECTED;
404 }
405 break;
406 case VERIFYING_KEXEC_PE_SIGNATURE:
407 if (pkcs7->data_type != OID_msIndirectData) {
408 pr_warn("Invalid kexec sig (not Authenticode)\n");
409 return -EKEYREJECTED;
410 }
411 /* Authattr presence checked in parser */
412 break;
413 case VERIFYING_UNSPECIFIED_SIGNATURE:
414 if (pkcs7->data_type != OID_data) {
415 pr_warn("Invalid unspecified sig (not pkcs7-data)\n");
416 return -EKEYREJECTED;
417 }
418 break;
419 default:
420 return -EINVAL;
421 }
422
362 for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { 423 for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
363 ret = x509_get_sig_params(x509); 424 ret = x509_get_sig_params(x509);
364 if (ret < 0) 425 if (ret < 0)
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index 2421f46184ce..897b734dabf9 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -393,6 +393,7 @@ error_no_desc:
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_keyring: Signing certificates to use as starting points
396 * @usage: The use to which the key is being put.
396 * @_trusted: Set to true if trustworth, false otherwise 397 * @_trusted: Set to true if trustworth, false otherwise
397 * 398 *
398 * Validate that the certificate chain inside the PKCS#7 message inside the PE 399 * Validate that the certificate chain inside the PKCS#7 message inside the PE
@@ -417,7 +418,9 @@ error_no_desc:
417 * May also return -ENOMEM. 418 * May also return -ENOMEM.
418 */ 419 */
419int verify_pefile_signature(const void *pebuf, unsigned pelen, 420int verify_pefile_signature(const void *pebuf, unsigned pelen,
420 struct key *trusted_keyring, bool *_trusted) 421 struct key *trusted_keyring,
422 enum key_being_used_for usage,
423 bool *_trusted)
421{ 424{
422 struct pkcs7_message *pkcs7; 425 struct pkcs7_message *pkcs7;
423 struct pefile_context ctx; 426 struct pefile_context ctx;
@@ -462,7 +465,7 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
462 if (ret < 0) 465 if (ret < 0)
463 goto error; 466 goto error;
464 467
465 ret = pkcs7_verify(pkcs7); 468 ret = pkcs7_verify(pkcs7, usage);
466 if (ret < 0) 469 if (ret < 0)
467 goto error; 470 goto error;
468 471
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h
index e235ab4957ee..441aff9b5aa7 100644
--- a/include/crypto/pkcs7.h
+++ b/include/crypto/pkcs7.h
@@ -9,6 +9,11 @@
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#ifndef _CRYPTO_PKCS7_H
13#define _CRYPTO_PKCS7_H
14
15#include <crypto/public_key.h>
16
12struct key; 17struct key;
13struct pkcs7_message; 18struct pkcs7_message;
14 19
@@ -33,7 +38,10 @@ extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
33/* 38/*
34 * pkcs7_verify.c 39 * pkcs7_verify.c
35 */ 40 */
36extern int pkcs7_verify(struct pkcs7_message *pkcs7); 41extern int pkcs7_verify(struct pkcs7_message *pkcs7,
42 enum key_being_used_for usage);
37 43
38extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7, 44extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7,
39 const void *data, size_t datalen); 45 const void *data, size_t datalen);
46
47#endif /* _CRYPTO_PKCS7_H */
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index fda097e079a4..067c242b1e15 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -40,6 +40,20 @@ enum pkey_id_type {
40extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST]; 40extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST];
41 41
42/* 42/*
43 * The use to which an asymmetric key is being put.
44 */
45enum key_being_used_for {
46 VERIFYING_MODULE_SIGNATURE,
47 VERIFYING_FIRMWARE_SIGNATURE,
48 VERIFYING_KEXEC_PE_SIGNATURE,
49 VERIFYING_KEY_SIGNATURE,
50 VERIFYING_KEY_SELF_SIGNATURE,
51 VERIFYING_UNSPECIFIED_SIGNATURE,
52 NR__KEY_BEING_USED_FOR
53};
54extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
55
56/*
43 * Cryptographic data for the public-key subtype of the asymmetric key type. 57 * Cryptographic data for the public-key subtype of the asymmetric key type.
44 * 58 *
45 * Note that this may include private part of the key as well as the public 59 * Note that this may include private part of the key as well as the public
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 9791c907cdb7..b20cd885c1fd 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -15,6 +15,7 @@
15#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING 15#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
16 16
17#include <linux/key.h> 17#include <linux/key.h>
18#include <crypto/public_key.h>
18 19
19extern struct key *system_trusted_keyring; 20extern struct key *system_trusted_keyring;
20static inline struct key *get_system_trusted_keyring(void) 21static inline struct key *get_system_trusted_keyring(void)
@@ -30,7 +31,8 @@ static inline struct key *get_system_trusted_keyring(void)
30 31
31#ifdef CONFIG_SYSTEM_DATA_VERIFICATION 32#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
32extern int system_verify_data(const void *data, unsigned long len, 33extern int system_verify_data(const void *data, unsigned long len,
33 const void *raw_pkcs7, size_t pkcs7_len); 34 const void *raw_pkcs7, size_t pkcs7_len,
35 enum key_being_used_for usage);
34#endif 36#endif
35 37
36#endif /* _KEYS_SYSTEM_KEYRING_H */ 38#endif /* _KEYS_SYSTEM_KEYRING_H */
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
index c2bbf672b84e..93e0ff92fb9b 100644
--- a/include/linux/oid_registry.h
+++ b/include/linux/oid_registry.h
@@ -41,7 +41,7 @@ enum OID {
41 OID_signed_data, /* 1.2.840.113549.1.7.2 */ 41 OID_signed_data, /* 1.2.840.113549.1.7.2 */
42 /* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */ 42 /* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */
43 OID_email_address, /* 1.2.840.113549.1.9.1 */ 43 OID_email_address, /* 1.2.840.113549.1.9.1 */
44 OID_content_type, /* 1.2.840.113549.1.9.3 */ 44 OID_contentType, /* 1.2.840.113549.1.9.3 */
45 OID_messageDigest, /* 1.2.840.113549.1.9.4 */ 45 OID_messageDigest, /* 1.2.840.113549.1.9.4 */
46 OID_signingTime, /* 1.2.840.113549.1.9.5 */ 46 OID_signingTime, /* 1.2.840.113549.1.9.5 */
47 OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */ 47 OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */
@@ -54,6 +54,8 @@ enum OID {
54 54
55 /* Microsoft Authenticode & Software Publishing */ 55 /* Microsoft Authenticode & Software Publishing */
56 OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */ 56 OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */
57 OID_msStatementType, /* 1.3.6.1.4.1.311.2.1.11 */
58 OID_msSpOpusInfo, /* 1.3.6.1.4.1.311.2.1.12 */
57 OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */ 59 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 */ 60 OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */
59 OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ 61 OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
diff --git a/include/linux/verify_pefile.h b/include/linux/verify_pefile.h
index ac34819214f9..da2049b5161c 100644
--- a/include/linux/verify_pefile.h
+++ b/include/linux/verify_pefile.h
@@ -12,7 +12,11 @@
12#ifndef _LINUX_VERIFY_PEFILE_H 12#ifndef _LINUX_VERIFY_PEFILE_H
13#define _LINUX_VERIFY_PEFILE_H 13#define _LINUX_VERIFY_PEFILE_H
14 14
15#include <crypto/public_key.h>
16
15extern int verify_pefile_signature(const void *pebuf, unsigned pelen, 17extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
16 struct key *trusted_keyring, bool *_trusted); 18 struct key *trusted_keyring,
19 enum key_being_used_for usage,
20 bool *_trusted);
17 21
18#endif /* _LINUX_VERIFY_PEFILE_H */ 22#endif /* _LINUX_VERIFY_PEFILE_H */
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index 70ad463f6df0..bd62f5cda746 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -72,5 +72,6 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
72 return -EBADMSG; 72 return -EBADMSG;
73 } 73 }
74 74
75 return system_verify_data(mod, modlen, mod + modlen, sig_len); 75 return system_verify_data(mod, modlen, mod + modlen, sig_len,
76 VERIFYING_MODULE_SIGNATURE);
76} 77}
diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c
index 95f2dcbc7616..2570598b784d 100644
--- a/kernel/system_keyring.c
+++ b/kernel/system_keyring.c
@@ -113,9 +113,11 @@ late_initcall(load_system_certificate_list);
113 * @len: Size of @data. 113 * @len: Size of @data.
114 * @raw_pkcs7: The PKCS#7 message that is the signature. 114 * @raw_pkcs7: The PKCS#7 message that is the signature.
115 * @pkcs7_len: The size of @raw_pkcs7. 115 * @pkcs7_len: The size of @raw_pkcs7.
116 * @usage: The use to which the key is being put.
116 */ 117 */
117int system_verify_data(const void *data, unsigned long len, 118int system_verify_data(const void *data, unsigned long len,
118 const void *raw_pkcs7, size_t pkcs7_len) 119 const void *raw_pkcs7, size_t pkcs7_len,
120 enum key_being_used_for usage)
119{ 121{
120 struct pkcs7_message *pkcs7; 122 struct pkcs7_message *pkcs7;
121 bool trusted; 123 bool trusted;
@@ -132,7 +134,7 @@ int system_verify_data(const void *data, unsigned long len,
132 goto error; 134 goto error;
133 } 135 }
134 136
135 ret = pkcs7_verify(pkcs7); 137 ret = pkcs7_verify(pkcs7, usage);
136 if (ret < 0) 138 if (ret < 0)
137 goto error; 139 goto error;
138 140
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index de213e5c0cd3..e9741e879bbd 100755
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -111,7 +111,7 @@ int main(int argc, char **argv)
111 bool sign_only = false; 111 bool sign_only = false;
112 unsigned char buf[4096]; 112 unsigned char buf[4096];
113 unsigned long module_size, cms_size; 113 unsigned long module_size, cms_size;
114 unsigned int use_keyid = 0; 114 unsigned int use_keyid = 0, use_signed_attrs = CMS_NOATTR;
115 const EVP_MD *digest_algo; 115 const EVP_MD *digest_algo;
116 EVP_PKEY *private_key; 116 EVP_PKEY *private_key;
117 CMS_ContentInfo *cms; 117 CMS_ContentInfo *cms;
@@ -216,7 +216,8 @@ int main(int argc, char **argv)
216 ERR(!cms, "CMS_sign"); 216 ERR(!cms, "CMS_sign");
217 217
218 ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, 218 ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
219 CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP | use_keyid), 219 CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP |
220 use_keyid | use_signed_attrs),
220 "CMS_sign_add_signer"); 221 "CMS_sign_add_signer");
221 ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0, 222 ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
222 "CMS_final"); 223 "CMS_final");