diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-08 15:41:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-08 15:41:25 -0400 |
commit | b793c005ceabf6db0b17494b0ec67ade6796bb34 (patch) | |
tree | 080c884f04254403ec9564742f591a9fd9b7e95a /crypto | |
parent | 6f0a2fc1feb19bd142961a39dc118e7e55418b3f (diff) | |
parent | 07f081fb5057b2ea98baeca3a47bf0eb33e94aa1 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"Highlights:
- PKCS#7 support added to support signed kexec, also utilized for
module signing. See comments in 3f1e1bea.
** NOTE: this requires linking against the OpenSSL library, which
must be installed, e.g. the openssl-devel on Fedora **
- Smack
- add IPv6 host labeling; ignore labels on kernel threads
- support smack labeling mounts which use binary mount data
- SELinux:
- add ioctl whitelisting (see
http://kernsec.org/files/lss2015/vanderstoep.pdf)
- fix mprotect PROT_EXEC regression caused by mm change
- Seccomp:
- add ptrace options for suspend/resume"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (57 commits)
PKCS#7: Add OIDs for sha224, sha284 and sha512 hash algos and use them
Documentation/Changes: Now need OpenSSL devel packages for module signing
scripts: add extract-cert and sign-file to .gitignore
modsign: Handle signing key in source tree
modsign: Use if_changed rule for extracting cert from module signing key
Move certificate handling to its own directory
sign-file: Fix warning about BIO_reset() return value
PKCS#7: Add MODULE_LICENSE() to test module
Smack - Fix build error with bringup unconfigured
sign-file: Document dependency on OpenSSL devel libraries
PKCS#7: Appropriately restrict authenticated attributes and content type
KEYS: Add a name for PKEY_ID_PKCS7
PKCS#7: Improve and export the X.509 ASN.1 time object decoder
modsign: Use extract-cert to process CONFIG_SYSTEM_TRUSTED_KEYS
extract-cert: Cope with multiple X.509 certificates in a single file
sign-file: Generate CMS message as signature instead of PKCS#7
PKCS#7: Support CMS messages also [RFC5652]
X.509: Change recorded SKID & AKID to not include Subject or Issuer
PKCS#7: Check content type and versions
MAINTAINERS: The keyrings mailing list has moved
...
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/Kconfig | 1 | ||||
-rw-r--r-- | crypto/asymmetric_keys/Makefile | 8 | ||||
-rw-r--r-- | crypto/asymmetric_keys/asymmetric_type.c | 11 | ||||
-rw-r--r-- | crypto/asymmetric_keys/mscode_parser.c | 9 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7.asn1 | 22 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_key_type.c | 17 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_parser.c | 277 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_parser.h | 20 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_trust.c | 10 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_verify.c | 145 | ||||
-rw-r--r-- | crypto/asymmetric_keys/public_key.c | 1 | ||||
-rw-r--r-- | crypto/asymmetric_keys/verify_pefile.c | 7 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_akid.asn1 | 35 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 231 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_parser.h | 12 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 95 |
16 files changed, 738 insertions, 163 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index b582ea7f78d3..48ee3e175dac 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig | |||
@@ -1635,5 +1635,6 @@ config CRYPTO_HASH_INFO | |||
1635 | 1635 | ||
1636 | source "drivers/crypto/Kconfig" | 1636 | source "drivers/crypto/Kconfig" |
1637 | source crypto/asymmetric_keys/Kconfig | 1637 | source crypto/asymmetric_keys/Kconfig |
1638 | source certs/Kconfig | ||
1638 | 1639 | ||
1639 | endif # if CRYPTO | 1640 | endif # if CRYPTO |
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index e47fcd9ac5e8..cd1406f9b14a 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile | |||
@@ -15,15 +15,21 @@ obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o | |||
15 | obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o | 15 | obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o |
16 | x509_key_parser-y := \ | 16 | x509_key_parser-y := \ |
17 | x509-asn1.o \ | 17 | x509-asn1.o \ |
18 | x509_akid-asn1.o \ | ||
18 | x509_rsakey-asn1.o \ | 19 | x509_rsakey-asn1.o \ |
19 | x509_cert_parser.o \ | 20 | x509_cert_parser.o \ |
20 | x509_public_key.o | 21 | x509_public_key.o |
21 | 22 | ||
22 | $(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h | 23 | $(obj)/x509_cert_parser.o: \ |
24 | $(obj)/x509-asn1.h \ | ||
25 | $(obj)/x509_akid-asn1.h \ | ||
26 | $(obj)/x509_rsakey-asn1.h | ||
23 | $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h | 27 | $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h |
28 | $(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h | ||
24 | $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h | 29 | $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h |
25 | 30 | ||
26 | clean-files += x509-asn1.c x509-asn1.h | 31 | clean-files += x509-asn1.c x509-asn1.h |
32 | clean-files += x509_akid-asn1.c x509_akid-asn1.h | ||
27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h | 33 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h |
28 | 34 | ||
29 | # | 35 | # |
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 | ||
21 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
22 | 23 | ||
24 | const 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 | }; | ||
32 | EXPORT_SYMBOL_GPL(key_being_used_for); | ||
33 | |||
23 | static LIST_HEAD(asymmetric_key_parsers); | 34 | static LIST_HEAD(asymmetric_key_parsers); |
24 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | 35 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); |
25 | 36 | ||
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c index 214a992123cd..adcef59eec0b 100644 --- a/crypto/asymmetric_keys/mscode_parser.c +++ b/crypto/asymmetric_keys/mscode_parser.c | |||
@@ -97,6 +97,15 @@ int mscode_note_digest_algo(void *context, size_t hdrlen, | |||
97 | case OID_sha256: | 97 | case OID_sha256: |
98 | ctx->digest_algo = HASH_ALGO_SHA256; | 98 | ctx->digest_algo = HASH_ALGO_SHA256; |
99 | break; | 99 | break; |
100 | case OID_sha384: | ||
101 | ctx->digest_algo = HASH_ALGO_SHA384; | ||
102 | break; | ||
103 | case OID_sha512: | ||
104 | ctx->digest_algo = HASH_ALGO_SHA512; | ||
105 | break; | ||
106 | case OID_sha224: | ||
107 | ctx->digest_algo = HASH_ALGO_SHA224; | ||
108 | break; | ||
100 | 109 | ||
101 | case OID__NR: | 110 | case OID__NR: |
102 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | 111 | sprint_oid(value, vlen, buffer, sizeof(buffer)); |
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1 index a5a14ef28c86..1eca740b816a 100644 --- a/crypto/asymmetric_keys/pkcs7.asn1 +++ b/crypto/asymmetric_keys/pkcs7.asn1 | |||
@@ -1,14 +1,14 @@ | |||
1 | PKCS7ContentInfo ::= SEQUENCE { | 1 | PKCS7ContentInfo ::= SEQUENCE { |
2 | contentType ContentType, | 2 | contentType ContentType ({ pkcs7_check_content_type }), |
3 | content [0] EXPLICIT SignedData OPTIONAL | 3 | content [0] EXPLICIT SignedData OPTIONAL |
4 | } | 4 | } |
5 | 5 | ||
6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) | 6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) |
7 | 7 | ||
8 | SignedData ::= SEQUENCE { | 8 | SignedData ::= SEQUENCE { |
9 | version INTEGER, | 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 | ||
23 | ContentInfo ::= SEQUENCE { | 23 | ContentInfo ::= 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 | ||
@@ -68,8 +68,8 @@ SignerInfos ::= CHOICE { | |||
68 | } | 68 | } |
69 | 69 | ||
70 | SignerInfo ::= SEQUENCE { | 70 | SignerInfo ::= SEQUENCE { |
71 | version INTEGER, | 71 | version INTEGER ({ pkcs7_note_signerinfo_version }), |
72 | issuerAndSerialNumber IssuerAndSerialNumber, | 72 | sid SignerIdentifier, -- CMS variant, not PKCS#7 |
73 | digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }), | 73 | digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }), |
74 | authenticatedAttributes CHOICE { | 74 | authenticatedAttributes CHOICE { |
75 | aaSet [0] IMPLICIT SetOfAuthenticatedAttribute | 75 | aaSet [0] IMPLICIT SetOfAuthenticatedAttribute |
@@ -88,6 +88,12 @@ SignerInfo ::= SEQUENCE { | |||
88 | } OPTIONAL | 88 | } OPTIONAL |
89 | } ({ pkcs7_note_signed_info }) | 89 | } ({ pkcs7_note_signed_info }) |
90 | 90 | ||
91 | SignerIdentifier ::= CHOICE { | ||
92 | -- RFC5652 sec 5.3 | ||
93 | issuerAndSerialNumber IssuerAndSerialNumber, | ||
94 | subjectKeyIdentifier [0] IMPLICIT SubjectKeyIdentifier | ||
95 | } | ||
96 | |||
91 | IssuerAndSerialNumber ::= SEQUENCE { | 97 | IssuerAndSerialNumber ::= SEQUENCE { |
92 | issuer Name ({ pkcs7_sig_note_issuer }), | 98 | issuer Name ({ pkcs7_sig_note_issuer }), |
93 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) | 99 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) |
@@ -95,6 +101,8 @@ IssuerAndSerialNumber ::= SEQUENCE { | |||
95 | 101 | ||
96 | CertificateSerialNumber ::= INTEGER | 102 | CertificateSerialNumber ::= INTEGER |
97 | 103 | ||
104 | SubjectKeyIdentifier ::= OCTET STRING ({ pkcs7_sig_note_skid }) | ||
105 | |||
98 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute | 106 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute |
99 | 107 | ||
100 | AuthenticatedAttribute ::= SEQUENCE { | 108 | AuthenticatedAttribute ::= SEQUENCE { |
@@ -103,7 +111,7 @@ AuthenticatedAttribute ::= SEQUENCE { | |||
103 | } | 111 | } |
104 | 112 | ||
105 | UnauthenticatedAttribute ::= SEQUENCE { | 113 | UnauthenticatedAttribute ::= SEQUENCE { |
106 | type OBJECT IDENTIFIER ({ pkcs7_note_OID }), | 114 | type OBJECT IDENTIFIER, |
107 | values SET OF ANY | 115 | values SET OF ANY |
108 | } | 116 | } |
109 | 117 | ||
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c index 3d13b042da73..e2d0edbbc71a 100644 --- a/crypto/asymmetric_keys/pkcs7_key_type.c +++ b/crypto/asymmetric_keys/pkcs7_key_type.c | |||
@@ -14,16 +14,26 @@ | |||
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 | ||
23 | MODULE_LICENSE("GPL"); | ||
24 | MODULE_DESCRIPTION("PKCS#7 testing key type"); | ||
25 | |||
26 | static unsigned pkcs7_usage; | ||
27 | module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO); | ||
28 | MODULE_PARM_DESC(pkcs7_usage, | ||
29 | "Usage to specify when verifying the PKCS#7 message"); | ||
30 | |||
22 | /* | 31 | /* |
23 | * Preparse a PKCS#7 wrapped and validated data blob. | 32 | * Preparse a PKCS#7 wrapped and validated data blob. |
24 | */ | 33 | */ |
25 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | 34 | static int pkcs7_preparse(struct key_preparsed_payload *prep) |
26 | { | 35 | { |
36 | enum key_being_used_for usage = pkcs7_usage; | ||
27 | struct pkcs7_message *pkcs7; | 37 | struct pkcs7_message *pkcs7; |
28 | const void *data, *saved_prep_data; | 38 | const void *data, *saved_prep_data; |
29 | size_t datalen, saved_prep_datalen; | 39 | size_t datalen, saved_prep_datalen; |
@@ -32,6 +42,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) | |||
32 | 42 | ||
33 | kenter(""); | 43 | kenter(""); |
34 | 44 | ||
45 | if (usage >= NR__KEY_BEING_USED_FOR) { | ||
46 | pr_err("Invalid usage type %d\n", usage); | ||
47 | return -EINVAL; | ||
48 | } | ||
49 | |||
35 | saved_prep_data = prep->data; | 50 | saved_prep_data = prep->data; |
36 | saved_prep_datalen = prep->datalen; | 51 | saved_prep_datalen = prep->datalen; |
37 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); | 52 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); |
@@ -40,7 +55,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) | |||
40 | goto error; | 55 | goto error; |
41 | } | 56 | } |
42 | 57 | ||
43 | ret = pkcs7_verify(pkcs7); | 58 | ret = pkcs7_verify(pkcs7, usage); |
44 | if (ret < 0) | 59 | if (ret < 0) |
45 | goto error_free; | 60 | goto error_free; |
46 | 61 | ||
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 3bd5a1e4c493..758acabf2d81 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c | |||
@@ -33,6 +33,9 @@ struct pkcs7_parse_context { | |||
33 | unsigned raw_serial_size; | 33 | unsigned raw_serial_size; |
34 | unsigned raw_issuer_size; | 34 | unsigned raw_issuer_size; |
35 | const void *raw_issuer; | 35 | const void *raw_issuer; |
36 | const void *raw_skid; | ||
37 | unsigned raw_skid_size; | ||
38 | bool expect_skid; | ||
36 | }; | 39 | }; |
37 | 40 | ||
38 | /* | 41 | /* |
@@ -78,6 +81,30 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7) | |||
78 | } | 81 | } |
79 | EXPORT_SYMBOL_GPL(pkcs7_free_message); | 82 | EXPORT_SYMBOL_GPL(pkcs7_free_message); |
80 | 83 | ||
84 | /* | ||
85 | * Check authenticatedAttributes are provided or not provided consistently. | ||
86 | */ | ||
87 | static 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 | |||
103 | inconsistent: | ||
104 | pr_warn("Inconsistently supplied authAttrs\n"); | ||
105 | return -EINVAL; | ||
106 | } | ||
107 | |||
81 | /** | 108 | /** |
82 | * pkcs7_parse_message - Parse a PKCS#7 message | 109 | * pkcs7_parse_message - Parse a PKCS#7 message |
83 | * @data: The raw binary ASN.1 encoded message to be parsed | 110 | * @data: The raw binary ASN.1 encoded message to be parsed |
@@ -110,6 +137,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) | |||
110 | goto out; | 137 | goto out; |
111 | } | 138 | } |
112 | 139 | ||
140 | ret = pkcs7_check_authattrs(ctx->msg); | ||
141 | if (ret < 0) | ||
142 | goto out; | ||
143 | |||
113 | msg = ctx->msg; | 144 | msg = ctx->msg; |
114 | ctx->msg = NULL; | 145 | ctx->msg = NULL; |
115 | 146 | ||
@@ -198,6 +229,14 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, | |||
198 | case OID_sha256: | 229 | case OID_sha256: |
199 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; | 230 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; |
200 | break; | 231 | break; |
232 | case OID_sha384: | ||
233 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384; | ||
234 | break; | ||
235 | case OID_sha512: | ||
236 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512; | ||
237 | break; | ||
238 | case OID_sha224: | ||
239 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224; | ||
201 | default: | 240 | default: |
202 | printk("Unsupported digest algo: %u\n", ctx->last_oid); | 241 | printk("Unsupported digest algo: %u\n", ctx->last_oid); |
203 | return -ENOPKG; | 242 | return -ENOPKG; |
@@ -226,6 +265,100 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, | |||
226 | } | 265 | } |
227 | 266 | ||
228 | /* | 267 | /* |
268 | * We only support signed data [RFC2315 sec 9]. | ||
269 | */ | ||
270 | int pkcs7_check_content_type(void *context, size_t hdrlen, | ||
271 | unsigned char tag, | ||
272 | const void *value, size_t vlen) | ||
273 | { | ||
274 | struct pkcs7_parse_context *ctx = context; | ||
275 | |||
276 | if (ctx->last_oid != OID_signed_data) { | ||
277 | pr_warn("Only support pkcs7_signedData type\n"); | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Note the SignedData version | ||
286 | */ | ||
287 | int pkcs7_note_signeddata_version(void *context, size_t hdrlen, | ||
288 | unsigned char tag, | ||
289 | const void *value, size_t vlen) | ||
290 | { | ||
291 | struct pkcs7_parse_context *ctx = context; | ||
292 | unsigned version; | ||
293 | |||
294 | if (vlen != 1) | ||
295 | goto unsupported; | ||
296 | |||
297 | ctx->msg->version = version = *(const u8 *)value; | ||
298 | switch (version) { | ||
299 | case 1: | ||
300 | /* PKCS#7 SignedData [RFC2315 sec 9.1] | ||
301 | * CMS ver 1 SignedData [RFC5652 sec 5.1] | ||
302 | */ | ||
303 | break; | ||
304 | case 3: | ||
305 | /* CMS ver 3 SignedData [RFC2315 sec 5.1] */ | ||
306 | break; | ||
307 | default: | ||
308 | goto unsupported; | ||
309 | } | ||
310 | |||
311 | return 0; | ||
312 | |||
313 | unsupported: | ||
314 | pr_warn("Unsupported SignedData version\n"); | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Note the SignerInfo version | ||
320 | */ | ||
321 | int pkcs7_note_signerinfo_version(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 | unsigned version; | ||
327 | |||
328 | if (vlen != 1) | ||
329 | goto unsupported; | ||
330 | |||
331 | version = *(const u8 *)value; | ||
332 | switch (version) { | ||
333 | case 1: | ||
334 | /* PKCS#7 SignerInfo [RFC2315 sec 9.2] | ||
335 | * CMS ver 1 SignerInfo [RFC5652 sec 5.3] | ||
336 | */ | ||
337 | if (ctx->msg->version != 1) | ||
338 | goto version_mismatch; | ||
339 | ctx->expect_skid = false; | ||
340 | break; | ||
341 | case 3: | ||
342 | /* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */ | ||
343 | if (ctx->msg->version == 1) | ||
344 | goto version_mismatch; | ||
345 | ctx->expect_skid = true; | ||
346 | break; | ||
347 | default: | ||
348 | goto unsupported; | ||
349 | } | ||
350 | |||
351 | return 0; | ||
352 | |||
353 | unsupported: | ||
354 | pr_warn("Unsupported SignerInfo version\n"); | ||
355 | return -EINVAL; | ||
356 | version_mismatch: | ||
357 | pr_warn("SignedData-SignerInfo version mismatch\n"); | ||
358 | return -EBADMSG; | ||
359 | } | ||
360 | |||
361 | /* | ||
229 | * Extract a certificate and store it in the context. | 362 | * Extract a certificate and store it in the context. |
230 | */ | 363 | */ |
231 | int pkcs7_extract_cert(void *context, size_t hdrlen, | 364 | int pkcs7_extract_cert(void *context, size_t hdrlen, |
@@ -284,6 +417,25 @@ int pkcs7_note_certificate_list(void *context, size_t hdrlen, | |||
284 | } | 417 | } |
285 | 418 | ||
286 | /* | 419 | /* |
420 | * Note the content type. | ||
421 | */ | ||
422 | int pkcs7_note_content(void *context, size_t hdrlen, | ||
423 | unsigned char tag, | ||
424 | const void *value, size_t vlen) | ||
425 | { | ||
426 | struct pkcs7_parse_context *ctx = context; | ||
427 | |||
428 | if (ctx->last_oid != OID_data && | ||
429 | ctx->last_oid != OID_msIndirectData) { | ||
430 | pr_warn("Unsupported data type %d\n", ctx->last_oid); | ||
431 | return -EINVAL; | ||
432 | } | ||
433 | |||
434 | ctx->msg->data_type = ctx->last_oid; | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | /* | ||
287 | * Extract the data from the message and store that and its content type OID in | 439 | * Extract the data from the message and store that and its content type OID in |
288 | * the context. | 440 | * the context. |
289 | */ | 441 | */ |
@@ -298,45 +450,119 @@ int pkcs7_note_data(void *context, size_t hdrlen, | |||
298 | ctx->msg->data = value; | 450 | ctx->msg->data = value; |
299 | ctx->msg->data_len = vlen; | 451 | ctx->msg->data_len = vlen; |
300 | ctx->msg->data_hdrlen = hdrlen; | 452 | ctx->msg->data_hdrlen = hdrlen; |
301 | ctx->msg->data_type = ctx->last_oid; | ||
302 | return 0; | 453 | return 0; |
303 | } | 454 | } |
304 | 455 | ||
305 | /* | 456 | /* |
306 | * Parse authenticated attributes | 457 | * Parse authenticated attributes. |
307 | */ | 458 | */ |
308 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, | 459 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, |
309 | unsigned char tag, | 460 | unsigned char tag, |
310 | const void *value, size_t vlen) | 461 | const void *value, size_t vlen) |
311 | { | 462 | { |
312 | struct pkcs7_parse_context *ctx = context; | 463 | struct pkcs7_parse_context *ctx = context; |
464 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | ||
465 | enum OID content_type; | ||
313 | 466 | ||
314 | pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); | 467 | pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); |
315 | 468 | ||
316 | switch (ctx->last_oid) { | 469 | switch (ctx->last_oid) { |
470 | case OID_contentType: | ||
471 | if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set)) | ||
472 | goto repeated; | ||
473 | content_type = look_up_OID(value, vlen); | ||
474 | if (content_type != ctx->msg->data_type) { | ||
475 | pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n", | ||
476 | ctx->msg->data_type, sinfo->index, | ||
477 | content_type); | ||
478 | return -EBADMSG; | ||
479 | } | ||
480 | return 0; | ||
481 | |||
482 | case OID_signingTime: | ||
483 | if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set)) | ||
484 | goto repeated; | ||
485 | /* Should we check that the signing time is consistent | ||
486 | * with the signer's X.509 cert? | ||
487 | */ | ||
488 | return x509_decode_time(&sinfo->signing_time, | ||
489 | hdrlen, tag, value, vlen); | ||
490 | |||
317 | case OID_messageDigest: | 491 | case OID_messageDigest: |
492 | if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set)) | ||
493 | goto repeated; | ||
318 | if (tag != ASN1_OTS) | 494 | if (tag != ASN1_OTS) |
319 | return -EBADMSG; | 495 | return -EBADMSG; |
320 | ctx->sinfo->msgdigest = value; | 496 | sinfo->msgdigest = value; |
321 | ctx->sinfo->msgdigest_len = vlen; | 497 | sinfo->msgdigest_len = vlen; |
498 | return 0; | ||
499 | |||
500 | case OID_smimeCapabilites: | ||
501 | if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set)) | ||
502 | goto repeated; | ||
503 | if (ctx->msg->data_type != OID_msIndirectData) { | ||
504 | pr_warn("S/MIME Caps only allowed with Authenticode\n"); | ||
505 | return -EKEYREJECTED; | ||
506 | } | ||
507 | return 0; | ||
508 | |||
509 | /* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE | ||
510 | * char URLs and cont[1] 8-bit char URLs. | ||
511 | * | ||
512 | * Microsoft StatementType seems to contain a list of OIDs that | ||
513 | * are also used as extendedKeyUsage types in X.509 certs. | ||
514 | */ | ||
515 | case OID_msSpOpusInfo: | ||
516 | if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) | ||
517 | goto repeated; | ||
518 | goto authenticode_check; | ||
519 | case OID_msStatementType: | ||
520 | if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set)) | ||
521 | goto repeated; | ||
522 | authenticode_check: | ||
523 | if (ctx->msg->data_type != OID_msIndirectData) { | ||
524 | pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n"); | ||
525 | return -EKEYREJECTED; | ||
526 | } | ||
527 | /* I'm not sure how to validate these */ | ||
322 | return 0; | 528 | return 0; |
323 | default: | 529 | default: |
324 | return 0; | 530 | return 0; |
325 | } | 531 | } |
532 | |||
533 | repeated: | ||
534 | /* We permit max one item per AuthenticatedAttribute and no repeats */ | ||
535 | pr_warn("Repeated/multivalue AuthAttrs not permitted\n"); | ||
536 | return -EKEYREJECTED; | ||
326 | } | 537 | } |
327 | 538 | ||
328 | /* | 539 | /* |
329 | * Note the set of auth attributes for digestion purposes [RFC2315 9.3] | 540 | * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3] |
330 | */ | 541 | */ |
331 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, | 542 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, |
332 | unsigned char tag, | 543 | unsigned char tag, |
333 | const void *value, size_t vlen) | 544 | const void *value, size_t vlen) |
334 | { | 545 | { |
335 | struct pkcs7_parse_context *ctx = context; | 546 | struct pkcs7_parse_context *ctx = context; |
547 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | ||
548 | |||
549 | if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) || | ||
550 | !test_bit(sinfo_has_message_digest, &sinfo->aa_set) || | ||
551 | (ctx->msg->data_type == OID_msIndirectData && | ||
552 | !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) { | ||
553 | pr_warn("Missing required AuthAttr\n"); | ||
554 | return -EBADMSG; | ||
555 | } | ||
556 | |||
557 | if (ctx->msg->data_type != OID_msIndirectData && | ||
558 | test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) { | ||
559 | pr_warn("Unexpected Authenticode AuthAttr\n"); | ||
560 | return -EBADMSG; | ||
561 | } | ||
336 | 562 | ||
337 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ | 563 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ |
338 | ctx->sinfo->authattrs = value - (hdrlen - 1); | 564 | sinfo->authattrs = value - (hdrlen - 1); |
339 | ctx->sinfo->authattrs_len = vlen + (hdrlen - 1); | 565 | sinfo->authattrs_len = vlen + (hdrlen - 1); |
340 | return 0; | 566 | return 0; |
341 | } | 567 | } |
342 | 568 | ||
@@ -367,6 +593,22 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen, | |||
367 | } | 593 | } |
368 | 594 | ||
369 | /* | 595 | /* |
596 | * Note the issuing cert's subjectKeyIdentifier | ||
597 | */ | ||
598 | int pkcs7_sig_note_skid(void *context, size_t hdrlen, | ||
599 | unsigned char tag, | ||
600 | const void *value, size_t vlen) | ||
601 | { | ||
602 | struct pkcs7_parse_context *ctx = context; | ||
603 | |||
604 | pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); | ||
605 | |||
606 | ctx->raw_skid = value; | ||
607 | ctx->raw_skid_size = vlen; | ||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | /* | ||
370 | * Note the signature data | 612 | * Note the signature data |
371 | */ | 613 | */ |
372 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, | 614 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, |
@@ -398,14 +640,27 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen, | |||
398 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | 640 | struct pkcs7_signed_info *sinfo = ctx->sinfo; |
399 | struct asymmetric_key_id *kid; | 641 | struct asymmetric_key_id *kid; |
400 | 642 | ||
643 | if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) { | ||
644 | pr_warn("Authenticode requires AuthAttrs\n"); | ||
645 | return -EBADMSG; | ||
646 | } | ||
647 | |||
401 | /* Generate cert issuer + serial number key ID */ | 648 | /* Generate cert issuer + serial number key ID */ |
402 | kid = asymmetric_key_generate_id(ctx->raw_serial, | 649 | if (!ctx->expect_skid) { |
403 | ctx->raw_serial_size, | 650 | kid = asymmetric_key_generate_id(ctx->raw_serial, |
404 | ctx->raw_issuer, | 651 | ctx->raw_serial_size, |
405 | ctx->raw_issuer_size); | 652 | ctx->raw_issuer, |
653 | ctx->raw_issuer_size); | ||
654 | } else { | ||
655 | kid = asymmetric_key_generate_id(ctx->raw_skid, | ||
656 | ctx->raw_skid_size, | ||
657 | "", 0); | ||
658 | } | ||
406 | if (IS_ERR(kid)) | 659 | if (IS_ERR(kid)) |
407 | return PTR_ERR(kid); | 660 | return PTR_ERR(kid); |
408 | 661 | ||
662 | pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data); | ||
663 | |||
409 | sinfo->signing_cert_id = kid; | 664 | sinfo->signing_cert_id = kid; |
410 | sinfo->index = ++ctx->sinfo_index; | 665 | sinfo->index = ++ctx->sinfo_index; |
411 | *ctx->ppsinfo = sinfo; | 666 | *ctx->ppsinfo = sinfo; |
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h index efc7dc9b8f9c..a66b19ebcf47 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.h +++ b/crypto/asymmetric_keys/pkcs7_parser.h | |||
@@ -21,9 +21,9 @@ | |||
21 | struct pkcs7_signed_info { | 21 | struct 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,8 +32,18 @@ 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 */ | 44 | /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1] |
45 | * or issuing cert's SKID [CMS ver 3]. | ||
46 | */ | ||
37 | struct asymmetric_key_id *signing_cert_id; | 47 | struct asymmetric_key_id *signing_cert_id; |
38 | 48 | ||
39 | /* Message signature. | 49 | /* Message signature. |
@@ -50,6 +60,8 @@ struct pkcs7_message { | |||
50 | struct x509_certificate *certs; /* Certificate list */ | 60 | struct x509_certificate *certs; /* Certificate list */ |
51 | struct x509_certificate *crl; /* Revocation list */ | 61 | struct x509_certificate *crl; /* Revocation list */ |
52 | struct pkcs7_signed_info *signed_infos; | 62 | struct pkcs7_signed_info *signed_infos; |
63 | u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */ | ||
64 | bool have_authattrs; /* T if have authattrs */ | ||
53 | 65 | ||
54 | /* Content Data (or NULL) */ | 66 | /* Content Data (or NULL) */ |
55 | enum OID data_type; /* Type of Data */ | 67 | enum OID data_type; /* Type of Data */ |
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index 1d29376072da..90d6d47965b0 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
@@ -54,7 +54,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
54 | /* Look to see if this certificate is present in the trusted | 54 | /* Look to see if this certificate is present in the trusted |
55 | * keys. | 55 | * keys. |
56 | */ | 56 | */ |
57 | key = x509_request_asymmetric_key(trust_keyring, x509->id, | 57 | key = x509_request_asymmetric_key(trust_keyring, |
58 | x509->id, x509->skid, | ||
58 | false); | 59 | false); |
59 | if (!IS_ERR(key)) { | 60 | if (!IS_ERR(key)) { |
60 | /* One of the X.509 certificates in the PKCS#7 message | 61 | /* One of the X.509 certificates in the PKCS#7 message |
@@ -85,8 +86,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
85 | /* No match - see if the root certificate has a signer amongst the | 86 | /* No match - see if the root certificate has a signer amongst the |
86 | * trusted keys. | 87 | * trusted keys. |
87 | */ | 88 | */ |
88 | if (last && last->authority) { | 89 | if (last && (last->akid_id || last->akid_skid)) { |
89 | key = x509_request_asymmetric_key(trust_keyring, last->authority, | 90 | key = x509_request_asymmetric_key(trust_keyring, |
91 | last->akid_id, | ||
92 | last->akid_skid, | ||
90 | false); | 93 | false); |
91 | if (!IS_ERR(key)) { | 94 | if (!IS_ERR(key)) { |
92 | x509 = last; | 95 | x509 = last; |
@@ -103,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
103 | */ | 106 | */ |
104 | key = x509_request_asymmetric_key(trust_keyring, | 107 | key = x509_request_asymmetric_key(trust_keyring, |
105 | sinfo->signing_cert_id, | 108 | sinfo->signing_cert_id, |
109 | NULL, | ||
106 | false); | 110 | false); |
107 | if (!IS_ERR(key)) { | 111 | if (!IS_ERR(key)) { |
108 | pr_devel("sinfo %u: Direct signer is key %x\n", | 112 | pr_devel("sinfo %u: Direct signer is key %x\n", |
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index cd455450b069..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); |
@@ -170,6 +176,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
170 | struct pkcs7_signed_info *sinfo) | 176 | struct pkcs7_signed_info *sinfo) |
171 | { | 177 | { |
172 | struct x509_certificate *x509 = sinfo->signer, *p; | 178 | struct x509_certificate *x509 = sinfo->signer, *p; |
179 | struct asymmetric_key_id *auth; | ||
173 | int ret; | 180 | int ret; |
174 | 181 | ||
175 | kenter(""); | 182 | kenter(""); |
@@ -187,11 +194,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
187 | goto maybe_missing_crypto_in_x509; | 194 | goto maybe_missing_crypto_in_x509; |
188 | 195 | ||
189 | pr_debug("- issuer %s\n", x509->issuer); | 196 | pr_debug("- issuer %s\n", x509->issuer); |
190 | if (x509->authority) | 197 | if (x509->akid_id) |
191 | pr_debug("- authkeyid %*phN\n", | 198 | pr_debug("- authkeyid.id %*phN\n", |
192 | x509->authority->len, x509->authority->data); | 199 | x509->akid_id->len, x509->akid_id->data); |
193 | 200 | if (x509->akid_skid) | |
194 | if (!x509->authority || | 201 | pr_debug("- authkeyid.skid %*phN\n", |
202 | x509->akid_skid->len, x509->akid_skid->data); | ||
203 | |||
204 | if ((!x509->akid_id && !x509->akid_skid) || | ||
195 | strcmp(x509->subject, x509->issuer) == 0) { | 205 | strcmp(x509->subject, x509->issuer) == 0) { |
196 | /* If there's no authority certificate specified, then | 206 | /* If there's no authority certificate specified, then |
197 | * the certificate must be self-signed and is the root | 207 | * the certificate must be self-signed and is the root |
@@ -215,21 +225,42 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
215 | /* Look through the X.509 certificates in the PKCS#7 message's | 225 | /* Look through the X.509 certificates in the PKCS#7 message's |
216 | * list to see if the next one is there. | 226 | * list to see if the next one is there. |
217 | */ | 227 | */ |
218 | pr_debug("- want %*phN\n", | 228 | auth = x509->akid_id; |
219 | x509->authority->len, x509->authority->data); | 229 | if (auth) { |
220 | for (p = pkcs7->certs; p; p = p->next) { | 230 | pr_debug("- want %*phN\n", auth->len, auth->data); |
221 | if (!p->skid) | 231 | for (p = pkcs7->certs; p; p = p->next) { |
222 | continue; | 232 | pr_debug("- cmp [%u] %*phN\n", |
223 | pr_debug("- cmp [%u] %*phN\n", | 233 | p->index, p->id->len, p->id->data); |
224 | p->index, p->skid->len, p->skid->data); | 234 | if (asymmetric_key_id_same(p->id, auth)) |
225 | if (asymmetric_key_id_same(p->skid, x509->authority)) | 235 | goto found_issuer_check_skid; |
226 | goto found_issuer; | 236 | } |
237 | } else { | ||
238 | auth = x509->akid_skid; | ||
239 | pr_debug("- want %*phN\n", auth->len, auth->data); | ||
240 | for (p = pkcs7->certs; p; p = p->next) { | ||
241 | if (!p->skid) | ||
242 | continue; | ||
243 | pr_debug("- cmp [%u] %*phN\n", | ||
244 | p->index, p->skid->len, p->skid->data); | ||
245 | if (asymmetric_key_id_same(p->skid, auth)) | ||
246 | goto found_issuer; | ||
247 | } | ||
227 | } | 248 | } |
228 | 249 | ||
229 | /* We didn't find the root of this chain */ | 250 | /* We didn't find the root of this chain */ |
230 | pr_debug("- top\n"); | 251 | pr_debug("- top\n"); |
231 | return 0; | 252 | return 0; |
232 | 253 | ||
254 | found_issuer_check_skid: | ||
255 | /* We matched issuer + serialNumber, but if there's an | ||
256 | * authKeyId.keyId, that must match the CA subjKeyId also. | ||
257 | */ | ||
258 | if (x509->akid_skid && | ||
259 | !asymmetric_key_id_same(p->skid, x509->akid_skid)) { | ||
260 | pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n", | ||
261 | sinfo->index, x509->index, p->index); | ||
262 | return -EKEYREJECTED; | ||
263 | } | ||
233 | found_issuer: | 264 | found_issuer: |
234 | pr_debug("- subject %s\n", p->subject); | 265 | pr_debug("- subject %s\n", p->subject); |
235 | if (p->seen) { | 266 | if (p->seen) { |
@@ -289,6 +320,18 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
289 | pr_devel("Using X.509[%u] for sig %u\n", | 320 | pr_devel("Using X.509[%u] for sig %u\n", |
290 | sinfo->signer->index, sinfo->index); | 321 | sinfo->signer->index, sinfo->index); |
291 | 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 | |||
292 | /* Verify the PKCS#7 binary against the key */ | 335 | /* Verify the PKCS#7 binary against the key */ |
293 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); | 336 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); |
294 | if (ret < 0) | 337 | if (ret < 0) |
@@ -303,6 +346,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
303 | /** | 346 | /** |
304 | * pkcs7_verify - Verify a PKCS#7 message | 347 | * pkcs7_verify - Verify a PKCS#7 message |
305 | * @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 | ||
306 | * | 350 | * |
307 | * 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 |
308 | * 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 |
@@ -314,6 +358,9 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
314 | * | 358 | * |
315 | * Returns, in order of descending priority: | 359 | * Returns, in order of descending priority: |
316 | * | 360 | * |
361 | * (*) -EKEYREJECTED if a key was selected that had a usage restriction at | ||
362 | * odds with the specified usage, or: | ||
363 | * | ||
317 | * (*) -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 |
318 | * appropriate X.509 certificate, or: | 365 | * appropriate X.509 certificate, or: |
319 | * | 366 | * |
@@ -325,7 +372,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
325 | * (*) 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 |
326 | * (note that a signature chain may be of zero length), or: | 373 | * (note that a signature chain may be of zero length), or: |
327 | */ | 374 | */ |
328 | int pkcs7_verify(struct pkcs7_message *pkcs7) | 375 | int pkcs7_verify(struct pkcs7_message *pkcs7, |
376 | enum key_being_used_for usage) | ||
329 | { | 377 | { |
330 | struct pkcs7_signed_info *sinfo; | 378 | struct pkcs7_signed_info *sinfo; |
331 | struct x509_certificate *x509; | 379 | struct x509_certificate *x509; |
@@ -334,12 +382,48 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) | |||
334 | 382 | ||
335 | kenter(""); | 383 | kenter(""); |
336 | 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 | |||
337 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { | 423 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { |
338 | ret = x509_get_sig_params(x509); | 424 | ret = x509_get_sig_params(x509); |
339 | if (ret < 0) | 425 | if (ret < 0) |
340 | return ret; | 426 | return ret; |
341 | pr_debug("X.509[%u] %*phN\n", | ||
342 | n, x509->authority->len, x509->authority->data); | ||
343 | } | 427 | } |
344 | 428 | ||
345 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | 429 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
@@ -359,3 +443,28 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) | |||
359 | return enopkg; | 443 | return enopkg; |
360 | } | 444 | } |
361 | EXPORT_SYMBOL_GPL(pkcs7_verify); | 445 | EXPORT_SYMBOL_GPL(pkcs7_verify); |
446 | |||
447 | /** | ||
448 | * pkcs7_supply_detached_data - Supply the data needed to verify a PKCS#7 message | ||
449 | * @pkcs7: The PKCS#7 message | ||
450 | * @data: The data to be verified | ||
451 | * @datalen: The amount of data | ||
452 | * | ||
453 | * Supply the detached data needed to verify a PKCS#7 message. Note that no | ||
454 | * attempt to retain/pin the data is made. That is left to the caller. The | ||
455 | * data will not be modified by pkcs7_verify() and will not be freed when the | ||
456 | * PKCS#7 message is freed. | ||
457 | * | ||
458 | * Returns -EINVAL if data is already supplied in the message, 0 otherwise. | ||
459 | */ | ||
460 | int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7, | ||
461 | const void *data, size_t datalen) | ||
462 | { | ||
463 | if (pkcs7->data) { | ||
464 | pr_debug("Data already supplied\n"); | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | pkcs7->data = data; | ||
468 | pkcs7->data_len = datalen; | ||
469 | return 0; | ||
470 | } | ||
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 2f6e4fb1a1ea..81efccbe22d5 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c | |||
@@ -39,6 +39,7 @@ EXPORT_SYMBOL_GPL(pkey_algo); | |||
39 | const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { | 39 | const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { |
40 | [PKEY_ID_PGP] = "PGP", | 40 | [PKEY_ID_PGP] = "PGP", |
41 | [PKEY_ID_X509] = "X509", | 41 | [PKEY_ID_X509] = "X509", |
42 | [PKEY_ID_PKCS7] = "PKCS#7", | ||
42 | }; | 43 | }; |
43 | EXPORT_SYMBOL_GPL(pkey_id_type_name); | 44 | EXPORT_SYMBOL_GPL(pkey_id_type_name); |
44 | 45 | ||
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 | */ |
419 | int verify_pefile_signature(const void *pebuf, unsigned pelen, | 420 | int 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/crypto/asymmetric_keys/x509_akid.asn1 b/crypto/asymmetric_keys/x509_akid.asn1 new file mode 100644 index 000000000000..1a33231a75a8 --- /dev/null +++ b/crypto/asymmetric_keys/x509_akid.asn1 | |||
@@ -0,0 +1,35 @@ | |||
1 | -- X.509 AuthorityKeyIdentifier | ||
2 | -- rfc5280 section 4.2.1.1 | ||
3 | |||
4 | AuthorityKeyIdentifier ::= SEQUENCE { | ||
5 | keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL, | ||
6 | authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL, | ||
7 | authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL | ||
8 | } | ||
9 | |||
10 | KeyIdentifier ::= OCTET STRING ({ x509_akid_note_kid }) | ||
11 | |||
12 | CertificateSerialNumber ::= INTEGER ({ x509_akid_note_serial }) | ||
13 | |||
14 | GeneralNames ::= SEQUENCE OF GeneralName | ||
15 | |||
16 | GeneralName ::= CHOICE { | ||
17 | otherName [0] ANY, | ||
18 | rfc822Name [1] IA5String, | ||
19 | dNSName [2] IA5String, | ||
20 | x400Address [3] ANY, | ||
21 | directoryName [4] Name ({ x509_akid_note_name }), | ||
22 | ediPartyName [5] ANY, | ||
23 | uniformResourceIdentifier [6] IA5String, | ||
24 | iPAddress [7] OCTET STRING, | ||
25 | registeredID [8] OBJECT IDENTIFIER | ||
26 | } | ||
27 | |||
28 | Name ::= SEQUENCE OF RelativeDistinguishedName | ||
29 | |||
30 | RelativeDistinguishedName ::= SET OF AttributeValueAssertion | ||
31 | |||
32 | AttributeValueAssertion ::= SEQUENCE { | ||
33 | attributeType OBJECT IDENTIFIER ({ x509_note_OID }), | ||
34 | attributeValue ANY ({ x509_extract_name_segment }) | ||
35 | } | ||
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index a668d90302d3..af71878dc15b 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "public_key.h" | 18 | #include "public_key.h" |
19 | #include "x509_parser.h" | 19 | #include "x509_parser.h" |
20 | #include "x509-asn1.h" | 20 | #include "x509-asn1.h" |
21 | #include "x509_akid-asn1.h" | ||
21 | #include "x509_rsakey-asn1.h" | 22 | #include "x509_rsakey-asn1.h" |
22 | 23 | ||
23 | struct x509_parse_context { | 24 | struct x509_parse_context { |
@@ -35,6 +36,10 @@ struct x509_parse_context { | |||
35 | u16 o_offset; /* Offset of organizationName (O) */ | 36 | u16 o_offset; /* Offset of organizationName (O) */ |
36 | u16 cn_offset; /* Offset of commonName (CN) */ | 37 | u16 cn_offset; /* Offset of commonName (CN) */ |
37 | u16 email_offset; /* Offset of emailAddress */ | 38 | u16 email_offset; /* Offset of emailAddress */ |
39 | unsigned raw_akid_size; | ||
40 | const void *raw_akid; /* Raw authorityKeyId in ASN.1 */ | ||
41 | const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */ | ||
42 | unsigned akid_raw_issuer_size; | ||
38 | }; | 43 | }; |
39 | 44 | ||
40 | /* | 45 | /* |
@@ -48,7 +53,8 @@ void x509_free_certificate(struct x509_certificate *cert) | |||
48 | kfree(cert->subject); | 53 | kfree(cert->subject); |
49 | kfree(cert->id); | 54 | kfree(cert->id); |
50 | kfree(cert->skid); | 55 | kfree(cert->skid); |
51 | kfree(cert->authority); | 56 | kfree(cert->akid_id); |
57 | kfree(cert->akid_skid); | ||
52 | kfree(cert->sig.digest); | 58 | kfree(cert->sig.digest); |
53 | mpi_free(cert->sig.rsa.s); | 59 | mpi_free(cert->sig.rsa.s); |
54 | kfree(cert); | 60 | kfree(cert); |
@@ -85,6 +91,18 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
85 | if (ret < 0) | 91 | if (ret < 0) |
86 | goto error_decode; | 92 | goto error_decode; |
87 | 93 | ||
94 | /* Decode the AuthorityKeyIdentifier */ | ||
95 | if (ctx->raw_akid) { | ||
96 | pr_devel("AKID: %u %*phN\n", | ||
97 | ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid); | ||
98 | ret = asn1_ber_decoder(&x509_akid_decoder, ctx, | ||
99 | ctx->raw_akid, ctx->raw_akid_size); | ||
100 | if (ret < 0) { | ||
101 | pr_warn("Couldn't decode AuthKeyIdentifier\n"); | ||
102 | goto error_decode; | ||
103 | } | ||
104 | } | ||
105 | |||
88 | /* Decode the public key */ | 106 | /* Decode the public key */ |
89 | ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, | 107 | ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, |
90 | ctx->key, ctx->key_size); | 108 | ctx->key, ctx->key_size); |
@@ -422,7 +440,6 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
422 | struct x509_parse_context *ctx = context; | 440 | struct x509_parse_context *ctx = context; |
423 | struct asymmetric_key_id *kid; | 441 | struct asymmetric_key_id *kid; |
424 | const unsigned char *v = value; | 442 | const unsigned char *v = value; |
425 | int i; | ||
426 | 443 | ||
427 | pr_debug("Extension: %u\n", ctx->last_oid); | 444 | pr_debug("Extension: %u\n", ctx->last_oid); |
428 | 445 | ||
@@ -437,9 +454,7 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
437 | 454 | ||
438 | ctx->cert->raw_skid_size = vlen; | 455 | ctx->cert->raw_skid_size = vlen; |
439 | ctx->cert->raw_skid = v; | 456 | ctx->cert->raw_skid = v; |
440 | kid = asymmetric_key_generate_id(ctx->cert->raw_subject, | 457 | kid = asymmetric_key_generate_id(v, vlen, "", 0); |
441 | ctx->cert->raw_subject_size, | ||
442 | v, vlen); | ||
443 | if (IS_ERR(kid)) | 458 | if (IS_ERR(kid)) |
444 | return PTR_ERR(kid); | 459 | return PTR_ERR(kid); |
445 | ctx->cert->skid = kid; | 460 | ctx->cert->skid = kid; |
@@ -449,117 +464,113 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
449 | 464 | ||
450 | if (ctx->last_oid == OID_authorityKeyIdentifier) { | 465 | if (ctx->last_oid == OID_authorityKeyIdentifier) { |
451 | /* Get hold of the CA key fingerprint */ | 466 | /* Get hold of the CA key fingerprint */ |
452 | if (ctx->cert->authority || vlen < 5) | 467 | ctx->raw_akid = v; |
453 | return -EBADMSG; | 468 | ctx->raw_akid_size = vlen; |
454 | |||
455 | /* Authority Key Identifier must be a Constructed SEQUENCE */ | ||
456 | if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5))) | ||
457 | return -EBADMSG; | ||
458 | |||
459 | /* Authority Key Identifier is not indefinite length */ | ||
460 | if (unlikely(vlen == ASN1_INDEFINITE_LENGTH)) | ||
461 | return -EBADMSG; | ||
462 | |||
463 | if (vlen < ASN1_INDEFINITE_LENGTH) { | ||
464 | /* Short Form length */ | ||
465 | if (v[1] != vlen - 2 || | ||
466 | v[2] != SEQ_TAG_KEYID || | ||
467 | v[3] > vlen - 4) | ||
468 | return -EBADMSG; | ||
469 | |||
470 | vlen = v[3]; | ||
471 | v += 4; | ||
472 | } else { | ||
473 | /* Long Form length */ | ||
474 | size_t seq_len = 0; | ||
475 | size_t sub = v[1] - ASN1_INDEFINITE_LENGTH; | ||
476 | |||
477 | if (sub > 2) | ||
478 | return -EBADMSG; | ||
479 | |||
480 | /* calculate the length from subsequent octets */ | ||
481 | v += 2; | ||
482 | for (i = 0; i < sub; i++) { | ||
483 | seq_len <<= 8; | ||
484 | seq_len |= v[i]; | ||
485 | } | ||
486 | |||
487 | if (seq_len != vlen - 2 - sub || | ||
488 | v[sub] != SEQ_TAG_KEYID || | ||
489 | v[sub + 1] > vlen - 4 - sub) | ||
490 | return -EBADMSG; | ||
491 | |||
492 | vlen = v[sub + 1]; | ||
493 | v += (sub + 2); | ||
494 | } | ||
495 | |||
496 | kid = asymmetric_key_generate_id(ctx->cert->raw_issuer, | ||
497 | ctx->cert->raw_issuer_size, | ||
498 | v, vlen); | ||
499 | if (IS_ERR(kid)) | ||
500 | return PTR_ERR(kid); | ||
501 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
502 | ctx->cert->authority = kid; | ||
503 | return 0; | 469 | return 0; |
504 | } | 470 | } |
505 | 471 | ||
506 | return 0; | 472 | return 0; |
507 | } | 473 | } |
508 | 474 | ||
509 | /* | 475 | /** |
510 | * Record a certificate time. | 476 | * x509_decode_time - Decode an X.509 time ASN.1 object |
477 | * @_t: The time to fill in | ||
478 | * @hdrlen: The length of the object header | ||
479 | * @tag: The object tag | ||
480 | * @value: The object value | ||
481 | * @vlen: The size of the object value | ||
482 | * | ||
483 | * Decode an ASN.1 universal time or generalised time field into a struct the | ||
484 | * kernel can handle and check it for validity. The time is decoded thus: | ||
485 | * | ||
486 | * [RFC5280 §4.1.2.5] | ||
487 | * CAs conforming to this profile MUST always encode certificate validity | ||
488 | * dates through the year 2049 as UTCTime; certificate validity dates in | ||
489 | * 2050 or later MUST be encoded as GeneralizedTime. Conforming | ||
490 | * applications MUST be able to process validity dates that are encoded in | ||
491 | * either UTCTime or GeneralizedTime. | ||
511 | */ | 492 | */ |
512 | static int x509_note_time(struct tm *tm, size_t hdrlen, | 493 | int x509_decode_time(time64_t *_t, size_t hdrlen, |
513 | unsigned char tag, | 494 | unsigned char tag, |
514 | const unsigned char *value, size_t vlen) | 495 | const unsigned char *value, size_t vlen) |
515 | { | 496 | { |
497 | static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30, | ||
498 | 31, 31, 30, 31, 30, 31 }; | ||
516 | const unsigned char *p = value; | 499 | const unsigned char *p = value; |
500 | unsigned year, mon, day, hour, min, sec, mon_len; | ||
517 | 501 | ||
518 | #define dec2bin(X) ((X) - '0') | 502 | #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; }) |
519 | #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) | 503 | #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) |
520 | 504 | ||
521 | if (tag == ASN1_UNITIM) { | 505 | if (tag == ASN1_UNITIM) { |
522 | /* UTCTime: YYMMDDHHMMSSZ */ | 506 | /* UTCTime: YYMMDDHHMMSSZ */ |
523 | if (vlen != 13) | 507 | if (vlen != 13) |
524 | goto unsupported_time; | 508 | goto unsupported_time; |
525 | tm->tm_year = DD2bin(p); | 509 | year = DD2bin(p); |
526 | if (tm->tm_year >= 50) | 510 | if (year >= 50) |
527 | tm->tm_year += 1900; | 511 | year += 1900; |
528 | else | 512 | else |
529 | tm->tm_year += 2000; | 513 | year += 2000; |
530 | } else if (tag == ASN1_GENTIM) { | 514 | } else if (tag == ASN1_GENTIM) { |
531 | /* GenTime: YYYYMMDDHHMMSSZ */ | 515 | /* GenTime: YYYYMMDDHHMMSSZ */ |
532 | if (vlen != 15) | 516 | if (vlen != 15) |
533 | goto unsupported_time; | 517 | goto unsupported_time; |
534 | tm->tm_year = DD2bin(p) * 100 + DD2bin(p); | 518 | year = DD2bin(p) * 100 + DD2bin(p); |
519 | if (year >= 1950 && year <= 2049) | ||
520 | goto invalid_time; | ||
535 | } else { | 521 | } else { |
536 | goto unsupported_time; | 522 | goto unsupported_time; |
537 | } | 523 | } |
538 | 524 | ||
539 | tm->tm_year -= 1900; | 525 | mon = DD2bin(p); |
540 | tm->tm_mon = DD2bin(p) - 1; | 526 | day = DD2bin(p); |
541 | tm->tm_mday = DD2bin(p); | 527 | hour = DD2bin(p); |
542 | tm->tm_hour = DD2bin(p); | 528 | min = DD2bin(p); |
543 | tm->tm_min = DD2bin(p); | 529 | sec = DD2bin(p); |
544 | tm->tm_sec = DD2bin(p); | ||
545 | 530 | ||
546 | if (*p != 'Z') | 531 | if (*p != 'Z') |
547 | goto unsupported_time; | 532 | goto unsupported_time; |
548 | 533 | ||
534 | mon_len = month_lengths[mon]; | ||
535 | if (mon == 2) { | ||
536 | if (year % 4 == 0) { | ||
537 | mon_len = 29; | ||
538 | if (year % 100 == 0) { | ||
539 | year /= 100; | ||
540 | if (year % 4 != 0) | ||
541 | mon_len = 28; | ||
542 | } | ||
543 | } | ||
544 | } | ||
545 | |||
546 | if (year < 1970 || | ||
547 | mon < 1 || mon > 12 || | ||
548 | day < 1 || day > mon_len || | ||
549 | hour < 0 || hour > 23 || | ||
550 | min < 0 || min > 59 || | ||
551 | sec < 0 || sec > 59) | ||
552 | goto invalid_time; | ||
553 | |||
554 | *_t = mktime64(year, mon, day, hour, min, sec); | ||
549 | return 0; | 555 | return 0; |
550 | 556 | ||
551 | unsupported_time: | 557 | unsupported_time: |
552 | pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n", | 558 | pr_debug("Got unsupported time [tag %02x]: '%*phN'\n", |
553 | tag, (int)vlen, (int)vlen, value); | 559 | tag, (int)vlen, value); |
560 | return -EBADMSG; | ||
561 | invalid_time: | ||
562 | pr_debug("Got invalid time [tag %02x]: '%*phN'\n", | ||
563 | tag, (int)vlen, value); | ||
554 | return -EBADMSG; | 564 | return -EBADMSG; |
555 | } | 565 | } |
566 | EXPORT_SYMBOL_GPL(x509_decode_time); | ||
556 | 567 | ||
557 | int x509_note_not_before(void *context, size_t hdrlen, | 568 | int x509_note_not_before(void *context, size_t hdrlen, |
558 | unsigned char tag, | 569 | unsigned char tag, |
559 | const void *value, size_t vlen) | 570 | const void *value, size_t vlen) |
560 | { | 571 | { |
561 | struct x509_parse_context *ctx = context; | 572 | struct x509_parse_context *ctx = context; |
562 | return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); | 573 | return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); |
563 | } | 574 | } |
564 | 575 | ||
565 | int x509_note_not_after(void *context, size_t hdrlen, | 576 | int x509_note_not_after(void *context, size_t hdrlen, |
@@ -567,5 +578,71 @@ int x509_note_not_after(void *context, size_t hdrlen, | |||
567 | const void *value, size_t vlen) | 578 | const void *value, size_t vlen) |
568 | { | 579 | { |
569 | struct x509_parse_context *ctx = context; | 580 | struct x509_parse_context *ctx = context; |
570 | return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); | 581 | return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); |
582 | } | ||
583 | |||
584 | /* | ||
585 | * Note a key identifier-based AuthorityKeyIdentifier | ||
586 | */ | ||
587 | int x509_akid_note_kid(void *context, size_t hdrlen, | ||
588 | unsigned char tag, | ||
589 | const void *value, size_t vlen) | ||
590 | { | ||
591 | struct x509_parse_context *ctx = context; | ||
592 | struct asymmetric_key_id *kid; | ||
593 | |||
594 | pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); | ||
595 | |||
596 | if (ctx->cert->akid_skid) | ||
597 | return 0; | ||
598 | |||
599 | kid = asymmetric_key_generate_id(value, vlen, "", 0); | ||
600 | if (IS_ERR(kid)) | ||
601 | return PTR_ERR(kid); | ||
602 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
603 | ctx->cert->akid_skid = kid; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * Note a directoryName in an AuthorityKeyIdentifier | ||
609 | */ | ||
610 | int x509_akid_note_name(void *context, size_t hdrlen, | ||
611 | unsigned char tag, | ||
612 | const void *value, size_t vlen) | ||
613 | { | ||
614 | struct x509_parse_context *ctx = context; | ||
615 | |||
616 | pr_debug("AKID: name: %*phN\n", (int)vlen, value); | ||
617 | |||
618 | ctx->akid_raw_issuer = value; | ||
619 | ctx->akid_raw_issuer_size = vlen; | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | /* | ||
624 | * Note a serial number in an AuthorityKeyIdentifier | ||
625 | */ | ||
626 | int x509_akid_note_serial(void *context, size_t hdrlen, | ||
627 | unsigned char tag, | ||
628 | const void *value, size_t vlen) | ||
629 | { | ||
630 | struct x509_parse_context *ctx = context; | ||
631 | struct asymmetric_key_id *kid; | ||
632 | |||
633 | pr_debug("AKID: serial: %*phN\n", (int)vlen, value); | ||
634 | |||
635 | if (!ctx->akid_raw_issuer || ctx->cert->akid_id) | ||
636 | return 0; | ||
637 | |||
638 | kid = asymmetric_key_generate_id(value, | ||
639 | vlen, | ||
640 | ctx->akid_raw_issuer, | ||
641 | ctx->akid_raw_issuer_size); | ||
642 | if (IS_ERR(kid)) | ||
643 | return PTR_ERR(kid); | ||
644 | |||
645 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
646 | ctx->cert->akid_id = kid; | ||
647 | return 0; | ||
571 | } | 648 | } |
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 3dfe6b5d6f0b..1de01eaec884 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h | |||
@@ -19,11 +19,12 @@ struct x509_certificate { | |||
19 | struct public_key_signature sig; /* Signature parameters */ | 19 | struct public_key_signature sig; /* Signature parameters */ |
20 | char *issuer; /* Name of certificate issuer */ | 20 | char *issuer; /* Name of certificate issuer */ |
21 | char *subject; /* Name of certificate subject */ | 21 | char *subject; /* Name of certificate subject */ |
22 | struct asymmetric_key_id *id; /* Serial number + issuer */ | 22 | struct asymmetric_key_id *id; /* Issuer + Serial number */ |
23 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ | 23 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ |
24 | struct asymmetric_key_id *authority; /* Authority key identifier (optional) */ | 24 | struct asymmetric_key_id *akid_id; /* CA AuthKeyId matching ->id (optional) */ |
25 | struct tm valid_from; | 25 | struct asymmetric_key_id *akid_skid; /* CA AuthKeyId matching ->skid (optional) */ |
26 | struct tm valid_to; | 26 | time64_t valid_from; |
27 | time64_t valid_to; | ||
27 | const void *tbs; /* Signed data */ | 28 | const void *tbs; /* Signed data */ |
28 | unsigned tbs_size; /* Size of signed data */ | 29 | unsigned tbs_size; /* Size of signed data */ |
29 | unsigned raw_sig_size; /* Size of sigature */ | 30 | unsigned raw_sig_size; /* Size of sigature */ |
@@ -48,6 +49,9 @@ struct x509_certificate { | |||
48 | */ | 49 | */ |
49 | extern void x509_free_certificate(struct x509_certificate *cert); | 50 | extern void x509_free_certificate(struct x509_certificate *cert); |
50 | extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); | 51 | extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); |
52 | extern int x509_decode_time(time64_t *_t, size_t hdrlen, | ||
53 | unsigned char tag, | ||
54 | const unsigned char *value, size_t vlen); | ||
51 | 55 | ||
52 | /* | 56 | /* |
53 | * x509_public_key.c | 57 | * x509_public_key.c |
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 24f17e6c5904..6d88dd15c98d 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
@@ -65,23 +65,37 @@ __setup("ca_keys=", ca_keys_setup); | |||
65 | /** | 65 | /** |
66 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. | 66 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. |
67 | * @keyring: The keys to search. | 67 | * @keyring: The keys to search. |
68 | * @kid: The key ID. | 68 | * @id: The issuer & serialNumber to look for or NULL. |
69 | * @skid: The subjectKeyIdentifier to look for or NULL. | ||
69 | * @partial: Use partial match if true, exact if false. | 70 | * @partial: Use partial match if true, exact if false. |
70 | * | 71 | * |
71 | * Find a key in the given keyring by subject name and key ID. These might, | 72 | * Find a key in the given keyring by identifier. The preferred identifier is |
72 | * for instance, be the issuer name and the authority key ID of an X.509 | 73 | * the issuer + serialNumber and the fallback identifier is the |
73 | * certificate that needs to be verified. | 74 | * subjectKeyIdentifier. If both are given, the lookup is by the former, but |
75 | * the latter must also match. | ||
74 | */ | 76 | */ |
75 | struct key *x509_request_asymmetric_key(struct key *keyring, | 77 | struct key *x509_request_asymmetric_key(struct key *keyring, |
76 | const struct asymmetric_key_id *kid, | 78 | const struct asymmetric_key_id *id, |
79 | const struct asymmetric_key_id *skid, | ||
77 | bool partial) | 80 | bool partial) |
78 | { | 81 | { |
79 | key_ref_t key; | 82 | struct key *key; |
80 | char *id, *p; | 83 | key_ref_t ref; |
81 | 84 | const char *lookup; | |
85 | char *req, *p; | ||
86 | int len; | ||
87 | |||
88 | if (id) { | ||
89 | lookup = id->data; | ||
90 | len = id->len; | ||
91 | } else { | ||
92 | lookup = skid->data; | ||
93 | len = skid->len; | ||
94 | } | ||
95 | |||
82 | /* Construct an identifier "id:<keyid>". */ | 96 | /* Construct an identifier "id:<keyid>". */ |
83 | p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL); | 97 | p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); |
84 | if (!id) | 98 | if (!req) |
85 | return ERR_PTR(-ENOMEM); | 99 | return ERR_PTR(-ENOMEM); |
86 | 100 | ||
87 | if (partial) { | 101 | if (partial) { |
@@ -92,32 +106,48 @@ struct key *x509_request_asymmetric_key(struct key *keyring, | |||
92 | *p++ = 'x'; | 106 | *p++ = 'x'; |
93 | } | 107 | } |
94 | *p++ = ':'; | 108 | *p++ = ':'; |
95 | p = bin2hex(p, kid->data, kid->len); | 109 | p = bin2hex(p, lookup, len); |
96 | *p = 0; | 110 | *p = 0; |
97 | 111 | ||
98 | pr_debug("Look up: \"%s\"\n", id); | 112 | pr_debug("Look up: \"%s\"\n", req); |
99 | 113 | ||
100 | key = keyring_search(make_key_ref(keyring, 1), | 114 | ref = keyring_search(make_key_ref(keyring, 1), |
101 | &key_type_asymmetric, id); | 115 | &key_type_asymmetric, req); |
102 | if (IS_ERR(key)) | 116 | if (IS_ERR(ref)) |
103 | pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key)); | 117 | pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); |
104 | kfree(id); | 118 | kfree(req); |
105 | 119 | ||
106 | if (IS_ERR(key)) { | 120 | if (IS_ERR(ref)) { |
107 | switch (PTR_ERR(key)) { | 121 | switch (PTR_ERR(ref)) { |
108 | /* Hide some search errors */ | 122 | /* Hide some search errors */ |
109 | case -EACCES: | 123 | case -EACCES: |
110 | case -ENOTDIR: | 124 | case -ENOTDIR: |
111 | case -EAGAIN: | 125 | case -EAGAIN: |
112 | return ERR_PTR(-ENOKEY); | 126 | return ERR_PTR(-ENOKEY); |
113 | default: | 127 | default: |
114 | return ERR_CAST(key); | 128 | return ERR_CAST(ref); |
129 | } | ||
130 | } | ||
131 | |||
132 | key = key_ref_to_ptr(ref); | ||
133 | if (id && skid) { | ||
134 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); | ||
135 | if (!kids->id[1]) { | ||
136 | pr_debug("issuer+serial match, but expected SKID missing\n"); | ||
137 | goto reject; | ||
138 | } | ||
139 | if (!asymmetric_key_id_same(skid, kids->id[1])) { | ||
140 | pr_debug("issuer+serial match, but SKID does not\n"); | ||
141 | goto reject; | ||
115 | } | 142 | } |
116 | } | 143 | } |
144 | |||
145 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); | ||
146 | return key; | ||
117 | 147 | ||
118 | pr_devel("<==%s() = 0 [%x]\n", __func__, | 148 | reject: |
119 | key_serial(key_ref_to_ptr(key))); | 149 | key_put(key); |
120 | return key_ref_to_ptr(key); | 150 | return ERR_PTR(-EKEYREJECTED); |
121 | } | 151 | } |
122 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); | 152 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); |
123 | 153 | ||
@@ -227,10 +257,11 @@ static int x509_validate_trust(struct x509_certificate *cert, | |||
227 | if (!trust_keyring) | 257 | if (!trust_keyring) |
228 | return -EOPNOTSUPP; | 258 | return -EOPNOTSUPP; |
229 | 259 | ||
230 | if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid)) | 260 | if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid)) |
231 | return -EPERM; | 261 | return -EPERM; |
232 | 262 | ||
233 | key = x509_request_asymmetric_key(trust_keyring, cert->authority, | 263 | key = x509_request_asymmetric_key(trust_keyring, |
264 | cert->akid_id, cert->akid_skid, | ||
234 | false); | 265 | false); |
235 | if (!IS_ERR(key)) { | 266 | if (!IS_ERR(key)) { |
236 | if (!use_builtin_keys | 267 | if (!use_builtin_keys |
@@ -271,14 +302,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
271 | } | 302 | } |
272 | 303 | ||
273 | pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); | 304 | pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); |
274 | pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", | 305 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); |
275 | cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, | ||
276 | cert->valid_from.tm_mday, cert->valid_from.tm_hour, | ||
277 | cert->valid_from.tm_min, cert->valid_from.tm_sec); | ||
278 | pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
279 | cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, | ||
280 | cert->valid_to.tm_mday, cert->valid_to.tm_hour, | ||
281 | cert->valid_to.tm_min, cert->valid_to.tm_sec); | ||
282 | pr_devel("Cert Signature: %s + %s\n", | 306 | pr_devel("Cert Signature: %s + %s\n", |
283 | pkey_algo_name[cert->sig.pkey_algo], | 307 | pkey_algo_name[cert->sig.pkey_algo], |
284 | hash_algo_name[cert->sig.pkey_hash_algo]); | 308 | hash_algo_name[cert->sig.pkey_hash_algo]); |
@@ -287,8 +311,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
287 | cert->pub->id_type = PKEY_ID_X509; | 311 | cert->pub->id_type = PKEY_ID_X509; |
288 | 312 | ||
289 | /* Check the signature on the key if it appears to be self-signed */ | 313 | /* Check the signature on the key if it appears to be self-signed */ |
290 | if (!cert->authority || | 314 | if ((!cert->akid_skid && !cert->akid_id) || |
291 | asymmetric_key_id_same(cert->skid, cert->authority)) { | 315 | asymmetric_key_id_same(cert->skid, cert->akid_skid) || |
316 | asymmetric_key_id_same(cert->id, cert->akid_id)) { | ||
292 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ | 317 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ |
293 | if (ret < 0) | 318 | if (ret < 0) |
294 | goto error_free_cert; | 319 | goto error_free_cert; |