X.509: Extract both parts of the AuthorityKeyIdentifier
authorDavid Howells <dhowells@redhat.com>
Mon, 20 Jul 2015 20:16:26 +0000 (21:16 +0100)
committerDavid Howells <dhowells@redhat.com>
Fri, 7 Aug 2015 15:26:13 +0000 (16:26 +0100)
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>
crypto/asymmetric_keys/Makefile
crypto/asymmetric_keys/pkcs7_trust.c
crypto/asymmetric_keys/pkcs7_verify.c
crypto/asymmetric_keys/x509_akid.asn1 [new file with mode: 0644]
crypto/asymmetric_keys/x509_cert_parser.c
crypto/asymmetric_keys/x509_parser.h
crypto/asymmetric_keys/x509_public_key.c

index e47fcd9ac5e86f56b85b88c8179d68a41ade078c..cd1406f9b14ab2b45615aed6574cade8c539161c 100644 (file)
@@ -15,15 +15,21 @@ obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
 obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o
 x509_key_parser-y := \
        x509-asn1.o \
+       x509_akid-asn1.o \
        x509_rsakey-asn1.o \
        x509_cert_parser.o \
        x509_public_key.o
 
-$(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h
+$(obj)/x509_cert_parser.o: \
+       $(obj)/x509-asn1.h \
+       $(obj)/x509_akid-asn1.h \
+       $(obj)/x509_rsakey-asn1.h
 $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h
+$(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h
 $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
 
 clean-files    += x509-asn1.c x509-asn1.h
+clean-files    += x509_akid-asn1.c x509_akid-asn1.h
 clean-files    += x509_rsakey-asn1.c x509_rsakey-asn1.h
 
 #
index 1d29376072da4a502e720fe10fc8fb34f6c4749a..0f6463b6692b3b60666bd55bb565a3ea2340d93e 100644 (file)
@@ -85,8 +85,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
        /* No match - see if the root certificate has a signer amongst the
         * trusted keys.
         */
-       if (last && last->authority) {
-               key = x509_request_asymmetric_key(trust_keyring, last->authority,
+       if (last && last->akid_skid) {
+               key = x509_request_asymmetric_key(trust_keyring, last->akid_skid,
                                                  false);
                if (!IS_ERR(key)) {
                        x509 = last;
index cd455450b069e3c58d1a202484e3ccba2d5d7da1..a4d083f7e9e17503a0375837eddf55b3c224842a 100644 (file)
@@ -187,11 +187,11 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                        goto maybe_missing_crypto_in_x509;
 
                pr_debug("- issuer %s\n", x509->issuer);
-               if (x509->authority)
+               if (x509->akid_skid)
                        pr_debug("- authkeyid %*phN\n",
-                                x509->authority->len, x509->authority->data);
+                                x509->akid_skid->len, x509->akid_skid->data);
 
-               if (!x509->authority ||
+               if (!x509->akid_skid ||
                    strcmp(x509->subject, x509->issuer) == 0) {
                        /* If there's no authority certificate specified, then
                         * the certificate must be self-signed and is the root
@@ -216,13 +216,13 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                 * list to see if the next one is there.
                 */
                pr_debug("- want %*phN\n",
-                        x509->authority->len, x509->authority->data);
+                        x509->akid_skid->len, x509->akid_skid->data);
                for (p = pkcs7->certs; p; p = p->next) {
                        if (!p->skid)
                                continue;
                        pr_debug("- cmp [%u] %*phN\n",
                                 p->index, p->skid->len, p->skid->data);
-                       if (asymmetric_key_id_same(p->skid, x509->authority))
+                       if (asymmetric_key_id_same(p->skid, x509->akid_skid))
                                goto found_issuer;
                }
 
@@ -338,8 +338,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
                ret = x509_get_sig_params(x509);
                if (ret < 0)
                        return ret;
-               pr_debug("X.509[%u] %*phN\n",
-                        n, x509->authority->len, x509->authority->data);
        }
 
        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 (file)
index 0000000..1a33231
--- /dev/null
@@ -0,0 +1,35 @@
+-- X.509 AuthorityKeyIdentifier
+-- rfc5280 section 4.2.1.1
+
+AuthorityKeyIdentifier ::= SEQUENCE {
+       keyIdentifier                   [0] IMPLICIT KeyIdentifier              OPTIONAL,
+       authorityCertIssuer             [1] IMPLICIT GeneralNames               OPTIONAL,
+       authorityCertSerialNumber       [2] IMPLICIT CertificateSerialNumber    OPTIONAL
+       }
+
+KeyIdentifier ::= OCTET STRING ({ x509_akid_note_kid })
+
+CertificateSerialNumber ::= INTEGER ({ x509_akid_note_serial })
+
+GeneralNames ::= SEQUENCE OF GeneralName
+
+GeneralName ::= CHOICE {
+       otherName                       [0] ANY,
+       rfc822Name                      [1] IA5String,
+       dNSName                         [2] IA5String,
+       x400Address                     [3] ANY,
+       directoryName                   [4] Name ({ x509_akid_note_name }),
+       ediPartyName                    [5] ANY,
+       uniformResourceIdentifier       [6] IA5String,
+       iPAddress                       [7] OCTET STRING,
+       registeredID                    [8] OBJECT IDENTIFIER
+       }
+
+Name ::= SEQUENCE OF RelativeDistinguishedName
+
+RelativeDistinguishedName ::= SET OF AttributeValueAssertion
+
+AttributeValueAssertion ::= SEQUENCE {
+       attributeType           OBJECT IDENTIFIER ({ x509_note_OID }),
+       attributeValue          ANY ({ x509_extract_name_segment })
+       }
index a668d90302d38c541fb5a78aa5442019cc739b21..6c130dd56f35913304a0207a1eacb7f63d980a1a 100644 (file)
@@ -18,6 +18,7 @@
 #include "public_key.h"
 #include "x509_parser.h"
 #include "x509-asn1.h"
+#include "x509_akid-asn1.h"
 #include "x509_rsakey-asn1.h"
 
 struct x509_parse_context {
@@ -35,6 +36,10 @@ struct x509_parse_context {
        u16             o_offset;               /* Offset of organizationName (O) */
        u16             cn_offset;              /* Offset of commonName (CN) */
        u16             email_offset;           /* Offset of emailAddress */
+       unsigned        raw_akid_size;
+       const void      *raw_akid;              /* Raw authorityKeyId in ASN.1 */
+       const void      *akid_raw_issuer;       /* Raw directoryName in authorityKeyId */
+       unsigned        akid_raw_issuer_size;
 };
 
 /*
@@ -48,7 +53,8 @@ void x509_free_certificate(struct x509_certificate *cert)
                kfree(cert->subject);
                kfree(cert->id);
                kfree(cert->skid);
-               kfree(cert->authority);
+               kfree(cert->akid_id);
+               kfree(cert->akid_skid);
                kfree(cert->sig.digest);
                mpi_free(cert->sig.rsa.s);
                kfree(cert);
@@ -85,6 +91,18 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
        if (ret < 0)
                goto error_decode;
 
+       /* Decode the AuthorityKeyIdentifier */
+       if (ctx->raw_akid) {
+               pr_devel("AKID: %u %*phN\n",
+                        ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid);
+               ret = asn1_ber_decoder(&x509_akid_decoder, ctx,
+                                      ctx->raw_akid, ctx->raw_akid_size);
+               if (ret < 0) {
+                       pr_warn("Couldn't decode AuthKeyIdentifier\n");
+                       goto error_decode;
+               }
+       }
+
        /* Decode the public key */
        ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx,
                               ctx->key, ctx->key_size);
@@ -422,7 +440,6 @@ int x509_process_extension(void *context, size_t hdrlen,
        struct x509_parse_context *ctx = context;
        struct asymmetric_key_id *kid;
        const unsigned char *v = value;
-       int i;
 
        pr_debug("Extension: %u\n", ctx->last_oid);
 
@@ -449,57 +466,8 @@ int x509_process_extension(void *context, size_t hdrlen,
 
        if (ctx->last_oid == OID_authorityKeyIdentifier) {
                /* Get hold of the CA key fingerprint */
-               if (ctx->cert->authority || vlen < 5)
-                       return -EBADMSG;
-
-               /* Authority Key Identifier must be a Constructed SEQUENCE */
-               if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5)))
-                       return -EBADMSG;
-
-               /* Authority Key Identifier is not indefinite length */
-               if (unlikely(vlen == ASN1_INDEFINITE_LENGTH))
-                       return -EBADMSG;
-
-               if (vlen < ASN1_INDEFINITE_LENGTH) {
-                       /* Short Form length */
-                       if (v[1] != vlen - 2 ||
-                           v[2] != SEQ_TAG_KEYID ||
-                           v[3] > vlen - 4)
-                               return -EBADMSG;
-
-                       vlen = v[3];
-                       v += 4;
-               } else {
-                       /* Long Form length */
-                       size_t seq_len = 0;
-                       size_t sub = v[1] - ASN1_INDEFINITE_LENGTH;
-
-                       if (sub > 2)
-                               return -EBADMSG;
-
-                       /* calculate the length from subsequent octets */
-                       v += 2;
-                       for (i = 0; i < sub; i++) {
-                               seq_len <<= 8;
-                               seq_len |= v[i];
-                       }
-
-                       if (seq_len != vlen - 2 - sub ||
-                           v[sub] != SEQ_TAG_KEYID ||
-                           v[sub + 1] > vlen - 4 - sub)
-                               return -EBADMSG;
-
-                       vlen = v[sub + 1];
-                       v += (sub + 2);
-               }
-
-               kid = asymmetric_key_generate_id(ctx->cert->raw_issuer,
-                                                ctx->cert->raw_issuer_size,
-                                                v, vlen);
-               if (IS_ERR(kid))
-                       return PTR_ERR(kid);
-               pr_debug("authkeyid %*phN\n", kid->len, kid->data);
-               ctx->cert->authority = kid;
+               ctx->raw_akid = v;
+               ctx->raw_akid_size = vlen;
                return 0;
        }
 
@@ -569,3 +537,71 @@ int x509_note_not_after(void *context, size_t hdrlen,
        struct x509_parse_context *ctx = context;
        return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
 }
+
+/*
+ * Note a key identifier-based AuthorityKeyIdentifier
+ */
+int x509_akid_note_kid(void *context, size_t hdrlen,
+                      unsigned char tag,
+                      const void *value, size_t vlen)
+{
+       struct x509_parse_context *ctx = context;
+       struct asymmetric_key_id *kid;
+
+       pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
+
+       if (ctx->cert->akid_skid)
+               return 0;
+
+       kid = asymmetric_key_generate_id(ctx->cert->raw_issuer,
+                                        ctx->cert->raw_issuer_size,
+                                        value, vlen);
+       if (IS_ERR(kid))
+               return PTR_ERR(kid);
+       pr_debug("authkeyid %*phN\n", kid->len, kid->data);
+       ctx->cert->akid_skid = kid;
+       return 0;
+}
+
+/*
+ * Note a directoryName in an AuthorityKeyIdentifier
+ */
+int x509_akid_note_name(void *context, size_t hdrlen,
+                       unsigned char tag,
+                       const void *value, size_t vlen)
+{
+       struct x509_parse_context *ctx = context;
+
+       pr_debug("AKID: name: %*phN\n", (int)vlen, value);
+
+       ctx->akid_raw_issuer = value;
+       ctx->akid_raw_issuer_size = vlen;
+       return 0;
+}
+
+/*
+ * Note a serial number in an AuthorityKeyIdentifier
+ */
+int x509_akid_note_serial(void *context, size_t hdrlen,
+                         unsigned char tag,
+                         const void *value, size_t vlen)
+{
+       struct x509_parse_context *ctx = context;
+       struct asymmetric_key_id *kid;
+
+       pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
+
+       if (!ctx->akid_raw_issuer || ctx->cert->akid_id)
+               return 0;
+
+       kid = asymmetric_key_generate_id(value,
+                                        vlen,
+                                        ctx->akid_raw_issuer,
+                                        ctx->akid_raw_issuer_size);
+       if (IS_ERR(kid))
+               return PTR_ERR(kid);
+
+       pr_debug("authkeyid %*phN\n", kid->len, kid->data);
+       ctx->cert->akid_id = kid;
+       return 0;
+}
index 3dfe6b5d6f0b90433d9aefb2a627d70068f4d928..dcdb5c94f5148b7dc9b0dc3723e36519d26c2404 100644 (file)
@@ -19,9 +19,10 @@ struct x509_certificate {
        struct public_key_signature sig;        /* Signature parameters */
        char            *issuer;                /* Name of certificate issuer */
        char            *subject;               /* Name of certificate subject */
-       struct asymmetric_key_id *id;           /* Serial number + issuer */
+       struct asymmetric_key_id *id;           /* Issuer + Serial number */
        struct asymmetric_key_id *skid;         /* Subject + subjectKeyId (optional) */
-       struct asymmetric_key_id *authority;    /* Authority key identifier (optional) */
+       struct asymmetric_key_id *akid_id;      /* CA AuthKeyId matching ->id (optional) */
+       struct asymmetric_key_id *akid_skid;    /* CA AuthKeyId matching ->skid (optional) */
        struct tm       valid_from;
        struct tm       valid_to;
        const void      *tbs;                   /* Signed data */
index 24f17e6c590488d66ca01ec1f0e6f93a3f013163..bb55d6074d5fd5fc268fb76bd99385413f226d69 100644 (file)
@@ -227,10 +227,10 @@ static int x509_validate_trust(struct x509_certificate *cert,
        if (!trust_keyring)
                return -EOPNOTSUPP;
 
-       if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid))
+       if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
                return -EPERM;
 
-       key = x509_request_asymmetric_key(trust_keyring, cert->authority,
+       key = x509_request_asymmetric_key(trust_keyring, cert->akid_skid,
                                          false);
        if (!IS_ERR(key))  {
                if (!use_builtin_keys
@@ -287,8 +287,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
        cert->pub->id_type = PKEY_ID_X509;
 
        /* Check the signature on the key if it appears to be self-signed */
-       if (!cert->authority ||
-           asymmetric_key_id_same(cert->skid, cert->authority)) {
+       if (!cert->akid_skid ||
+           asymmetric_key_id_same(cert->skid, cert->akid_skid)) {
                ret = x509_check_signature(cert->pub, cert); /* self-signed */
                if (ret < 0)
                        goto error_free_cert;