summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2015-07-20 16:16:26 -0400
committerDavid Howells <dhowells@redhat.com>2015-08-07 11:26:13 -0400
commitb92e6570a992c7d793a209db282f68159368201c (patch)
tree37f9f533b4d28508fca8c1f6c1229c0182d47acc /crypto
parentc05cae9a58dca6dcbc6e66b228a9589c6b60880c (diff)
X.509: Extract both parts of the AuthorityKeyIdentifier
Extract both parts of the AuthorityKeyIdentifier, not just the keyIdentifier, as the second part can be used to match X.509 certificates by issuer and serialNumber. Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Vivek Goyal <vgoyal@redhat.com>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/asymmetric_keys/Makefile8
-rw-r--r--crypto/asymmetric_keys/pkcs7_trust.c4
-rw-r--r--crypto/asymmetric_keys/pkcs7_verify.c12
-rw-r--r--crypto/asymmetric_keys/x509_akid.asn135
-rw-r--r--crypto/asymmetric_keys/x509_cert_parser.c142
-rw-r--r--crypto/asymmetric_keys/x509_parser.h5
-rw-r--r--crypto/asymmetric_keys/x509_public_key.c8
7 files changed, 145 insertions, 69 deletions
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
15obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o 15obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o
16x509_key_parser-y := \ 16x509_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
26clean-files += x509-asn1.c x509-asn1.h 31clean-files += x509-asn1.c x509-asn1.h
32clean-files += x509_akid-asn1.c x509_akid-asn1.h
27clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h 33clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
28 34
29# 35#
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 1d29376072da..0f6463b6692b 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -85,8 +85,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
85 /* No match - see if the root certificate has a signer amongst the 85 /* No match - see if the root certificate has a signer amongst the
86 * trusted keys. 86 * trusted keys.
87 */ 87 */
88 if (last && last->authority) { 88 if (last && last->akid_skid) {
89 key = x509_request_asymmetric_key(trust_keyring, last->authority, 89 key = x509_request_asymmetric_key(trust_keyring, last->akid_skid,
90 false); 90 false);
91 if (!IS_ERR(key)) { 91 if (!IS_ERR(key)) {
92 x509 = last; 92 x509 = last;
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index cd455450b069..a4d083f7e9e1 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -187,11 +187,11 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
187 goto maybe_missing_crypto_in_x509; 187 goto maybe_missing_crypto_in_x509;
188 188
189 pr_debug("- issuer %s\n", x509->issuer); 189 pr_debug("- issuer %s\n", x509->issuer);
190 if (x509->authority) 190 if (x509->akid_skid)
191 pr_debug("- authkeyid %*phN\n", 191 pr_debug("- authkeyid %*phN\n",
192 x509->authority->len, x509->authority->data); 192 x509->akid_skid->len, x509->akid_skid->data);
193 193
194 if (!x509->authority || 194 if (!x509->akid_skid ||
195 strcmp(x509->subject, x509->issuer) == 0) { 195 strcmp(x509->subject, x509->issuer) == 0) {
196 /* If there's no authority certificate specified, then 196 /* If there's no authority certificate specified, then
197 * the certificate must be self-signed and is the root 197 * the certificate must be self-signed and is the root
@@ -216,13 +216,13 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
216 * list to see if the next one is there. 216 * list to see if the next one is there.
217 */ 217 */
218 pr_debug("- want %*phN\n", 218 pr_debug("- want %*phN\n",
219 x509->authority->len, x509->authority->data); 219 x509->akid_skid->len, x509->akid_skid->data);
220 for (p = pkcs7->certs; p; p = p->next) { 220 for (p = pkcs7->certs; p; p = p->next) {
221 if (!p->skid) 221 if (!p->skid)
222 continue; 222 continue;
223 pr_debug("- cmp [%u] %*phN\n", 223 pr_debug("- cmp [%u] %*phN\n",
224 p->index, p->skid->len, p->skid->data); 224 p->index, p->skid->len, p->skid->data);
225 if (asymmetric_key_id_same(p->skid, x509->authority)) 225 if (asymmetric_key_id_same(p->skid, x509->akid_skid))
226 goto found_issuer; 226 goto found_issuer;
227 } 227 }
228 228
@@ -338,8 +338,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
338 ret = x509_get_sig_params(x509); 338 ret = x509_get_sig_params(x509);
339 if (ret < 0) 339 if (ret < 0)
340 return ret; 340 return ret;
341 pr_debug("X.509[%u] %*phN\n",
342 n, x509->authority->len, x509->authority->data);
343 } 341 }
344 342
345 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { 343 for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
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
4AuthorityKeyIdentifier ::= SEQUENCE {
5 keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL,
6 authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL,
7 authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL
8 }
9
10KeyIdentifier ::= OCTET STRING ({ x509_akid_note_kid })
11
12CertificateSerialNumber ::= INTEGER ({ x509_akid_note_serial })
13
14GeneralNames ::= SEQUENCE OF GeneralName
15
16GeneralName ::= 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
28Name ::= SEQUENCE OF RelativeDistinguishedName
29
30RelativeDistinguishedName ::= SET OF AttributeValueAssertion
31
32AttributeValueAssertion ::= 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..6c130dd56f35 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
23struct x509_parse_context { 24struct 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
@@ -449,57 +466,8 @@ int x509_process_extension(void *context, size_t hdrlen,
449 466
450 if (ctx->last_oid == OID_authorityKeyIdentifier) { 467 if (ctx->last_oid == OID_authorityKeyIdentifier) {
451 /* Get hold of the CA key fingerprint */ 468 /* Get hold of the CA key fingerprint */
452 if (ctx->cert->authority || vlen < 5) 469 ctx->raw_akid = v;
453 return -EBADMSG; 470 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; 471 return 0;
504 } 472 }
505 473
@@ -569,3 +537,71 @@ int x509_note_not_after(void *context, size_t hdrlen,
569 struct x509_parse_context *ctx = context; 537 struct x509_parse_context *ctx = context;
570 return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); 538 return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
571} 539}
540
541/*
542 * Note a key identifier-based AuthorityKeyIdentifier
543 */
544int x509_akid_note_kid(void *context, size_t hdrlen,
545 unsigned char tag,
546 const void *value, size_t vlen)
547{
548 struct x509_parse_context *ctx = context;
549 struct asymmetric_key_id *kid;
550
551 pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
552
553 if (ctx->cert->akid_skid)
554 return 0;
555
556 kid = asymmetric_key_generate_id(ctx->cert->raw_issuer,
557 ctx->cert->raw_issuer_size,
558 value, vlen);
559 if (IS_ERR(kid))
560 return PTR_ERR(kid);
561 pr_debug("authkeyid %*phN\n", kid->len, kid->data);
562 ctx->cert->akid_skid = kid;
563 return 0;
564}
565
566/*
567 * Note a directoryName in an AuthorityKeyIdentifier
568 */
569int x509_akid_note_name(void *context, size_t hdrlen,
570 unsigned char tag,
571 const void *value, size_t vlen)
572{
573 struct x509_parse_context *ctx = context;
574
575 pr_debug("AKID: name: %*phN\n", (int)vlen, value);
576
577 ctx->akid_raw_issuer = value;
578 ctx->akid_raw_issuer_size = vlen;
579 return 0;
580}
581
582/*
583 * Note a serial number in an AuthorityKeyIdentifier
584 */
585int x509_akid_note_serial(void *context, size_t hdrlen,
586 unsigned char tag,
587 const void *value, size_t vlen)
588{
589 struct x509_parse_context *ctx = context;
590 struct asymmetric_key_id *kid;
591
592 pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
593
594 if (!ctx->akid_raw_issuer || ctx->cert->akid_id)
595 return 0;
596
597 kid = asymmetric_key_generate_id(value,
598 vlen,
599 ctx->akid_raw_issuer,
600 ctx->akid_raw_issuer_size);
601 if (IS_ERR(kid))
602 return PTR_ERR(kid);
603
604 pr_debug("authkeyid %*phN\n", kid->len, kid->data);
605 ctx->cert->akid_id = kid;
606 return 0;
607}
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 3dfe6b5d6f0b..dcdb5c94f514 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -19,9 +19,10 @@ 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 asymmetric_key_id *akid_skid; /* CA AuthKeyId matching ->skid (optional) */
25 struct tm valid_from; 26 struct tm valid_from;
26 struct tm valid_to; 27 struct tm valid_to;
27 const void *tbs; /* Signed data */ 28 const void *tbs; /* Signed data */
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 24f17e6c5904..bb55d6074d5f 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -227,10 +227,10 @@ static int x509_validate_trust(struct x509_certificate *cert,
227 if (!trust_keyring) 227 if (!trust_keyring)
228 return -EOPNOTSUPP; 228 return -EOPNOTSUPP;
229 229
230 if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid)) 230 if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
231 return -EPERM; 231 return -EPERM;
232 232
233 key = x509_request_asymmetric_key(trust_keyring, cert->authority, 233 key = x509_request_asymmetric_key(trust_keyring, cert->akid_skid,
234 false); 234 false);
235 if (!IS_ERR(key)) { 235 if (!IS_ERR(key)) {
236 if (!use_builtin_keys 236 if (!use_builtin_keys
@@ -287,8 +287,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
287 cert->pub->id_type = PKEY_ID_X509; 287 cert->pub->id_type = PKEY_ID_X509;
288 288
289 /* Check the signature on the key if it appears to be self-signed */ 289 /* Check the signature on the key if it appears to be self-signed */
290 if (!cert->authority || 290 if (!cert->akid_skid ||
291 asymmetric_key_id_same(cert->skid, cert->authority)) { 291 asymmetric_key_id_same(cert->skid, cert->akid_skid)) {
292 ret = x509_check_signature(cert->pub, cert); /* self-signed */ 292 ret = x509_check_signature(cert->pub, cert); /* self-signed */
293 if (ret < 0) 293 if (ret < 0)
294 goto error_free_cert; 294 goto error_free_cert;