get Authority Information Access (AIA) from CA & EE certs
authorjob <job@openbsd.org>
Tue, 16 Feb 2021 07:58:30 +0000 (07:58 +0000)
committerjob <job@openbsd.org>
Tue, 16 Feb 2021 07:58:30 +0000 (07:58 +0000)
In the context of the RPKI, the AIA extension identifies the publication
point of the certificate of the issuer of the certificate in which the
extension appears. A single reference to the publication point of the
immediate superior certificate MUST be present, except for a
"self-signed" certificate.

Thanks tb@ for review

OK claudio@

usr.sbin/rpki-client/cert.c
usr.sbin/rpki-client/extern.h
usr.sbin/rpki-client/gbr.c
usr.sbin/rpki-client/mft.c
usr.sbin/rpki-client/roa.c
usr.sbin/rpki-client/x509.c

index 130794e..6e3d7bf 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cert.c,v 1.25 2021/02/08 09:22:53 claudio Exp $ */
+/*     $OpenBSD: cert.c,v 1.26 2021/02/16 07:58:30 job Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -1079,6 +1079,11 @@ cert_parse_inner(X509 **xp, const char *fn, int ta)
                case NID_crl_distribution_points:
                        /* ignored here, handled later */
                        break;
+               case NID_info_access:
+                       free(p.res->aia);
+                       p.res->aia = x509_get_aia(x, p.fn);
+                       c = (p.res->aia != NULL);
+                       break;
                case NID_authority_key_identifier:
                        free(p.res->aki);
                        p.res->aki = x509_get_aki_ext(ext, p.fn);
@@ -1223,6 +1228,7 @@ cert_free(struct cert *p)
        free(p->notify);
        free(p->ips);
        free(p->as);
+       free(p->aia);
        free(p->aki);
        free(p->ski);
        X509_free(p->x509);
@@ -1279,6 +1285,7 @@ cert_buffer(struct ibuf *b, const struct cert *p)
        io_str_buffer(b, p->notify);
        io_str_buffer(b, p->repo);
        io_str_buffer(b, p->crl);
+       io_str_buffer(b, p->aia);
        io_str_buffer(b, p->aki);
        io_str_buffer(b, p->ski);
 }
@@ -1347,6 +1354,7 @@ cert_read(int fd)
        io_str_read(fd, &p->notify);
        io_str_read(fd, &p->repo);
        io_str_read(fd, &p->crl);
+       io_str_read(fd, &p->aia);
        io_str_read(fd, &p->aki);
        io_str_read(fd, &p->ski);
        assert(p->ski);
index edd446e..9b17ee7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: extern.h,v 1.42 2021/02/08 09:22:53 claudio Exp $ */
+/*     $OpenBSD: extern.h,v 1.43 2021/02/16 07:58:30 job Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -116,6 +116,7 @@ struct cert {
        char            *mft; /* manifest (rsync:// uri) */
        char            *notify; /* RRDP notify (https:// uri) */
        char            *crl; /* CRL location (rsync:// or NULL) */
+       char            *aia; /* AIA (or NULL, for trust anchor) */
        char            *aki; /* AKI (or NULL, for trust anchor) */
        char            *ski; /* SKI */
        int              valid; /* validated resources */
@@ -155,8 +156,9 @@ struct mft {
        struct mftfile  *files; /* file and hash */
        size_t           filesz; /* number of filenames */
        int              stale; /* if a stale manifest */
-       char            *ski; /* SKI */
+       char            *aia; /* AIA */
        char            *aki; /* AKI */
+       char            *ski; /* SKI */
 };
 
 /*
@@ -181,8 +183,9 @@ struct roa {
        struct roa_ip   *ips; /* IP prefixes */
        size_t           ipsz; /* number of IP prefixes */
        int              valid; /* validated resources */
-       char            *ski; /* SKI */
+       char            *aia; /* AIA */
        char            *aki; /* AKI */
+       char            *ski; /* SKI */
        char            *tal; /* basename of TAL for this cert */
 };
 
@@ -191,8 +194,9 @@ struct roa {
  */
 struct gbr {
        char            *vcard;
-       char            *ski; /* SKI */
+       char            *aia; /* AIA */
        char            *aki; /* AKI */
+       char            *ski; /* SKI */
 };
 
 /*
@@ -248,7 +252,7 @@ struct auth *auth_find(struct auth_tree *, const char *);
 
 /*
  * Resource types specified by the RPKI profiles.
- * There are others (e.g., gbr) that we don't consider.
+ * There might be others we don't consider.
  */
 enum rtype {
        RTYPE_EOF = 0,
@@ -418,9 +422,11 @@ void                io_str_read(int, char **);
 
 /* X509 helpers. */
 
+char           *x509_get_aia(X509 *, const char *);
 char           *x509_get_aki_ext(X509_EXTENSION *, const char *);
 char           *x509_get_ski_ext(X509_EXTENSION *, const char *);
-int             x509_get_ski_aki(X509 *, const char *, char **, char **);
+int             x509_get_extensions(X509 *, const char *, char **, char **,
+                       char **);
 char           *x509_get_crl(X509 *, const char *);
 char           *x509_crl_get_aki(X509_CRL *);
 
index 550f11e..0d5e304 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: gbr.c,v 1.4 2021/02/04 08:58:19 claudio Exp $ */
+/*     $OpenBSD: gbr.c,v 1.5 2021/02/16 07:58:30 job Exp $ */
 /*
  * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
  *
@@ -62,7 +62,8 @@ gbr_parse(X509 **x509, const char *fn)
                err(1, NULL);
        if ((p.res->vcard = strndup(cms, cmsz)) == NULL)
                err(1, NULL);
-       if (!x509_get_ski_aki(*x509, fn, &p.res->ski, &p.res->aki)) {
+       if (!x509_get_extensions(*x509, fn, &p.res->ski, &p.res->aki,
+           &p.res->aia)) {
                gbr_free(p.res);
                X509_free(*x509);
                *x509 = NULL;
@@ -83,6 +84,7 @@ gbr_free(struct gbr *p)
 
        if (p == NULL)
                return;
+       free(p->aia);
        free(p->aki);
        free(p->ski);
        free(p->vcard);
index 6e357c3..de903b5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mft.c,v 1.25 2021/02/04 08:58:19 claudio Exp $ */
+/*     $OpenBSD: mft.c,v 1.26 2021/02/16 07:58:30 job Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -395,7 +395,8 @@ mft_parse(X509 **x509, const char *fn)
                err(1, NULL);
        if ((p.res->file = strdup(fn)) == NULL)
                err(1, NULL);
-       if (!x509_get_ski_aki(*x509, fn, &p.res->ski, &p.res->aki))
+       if (!x509_get_extensions(*x509, fn, &p.res->ski, &p.res->aki,
+           &p.res->aia))
                goto out;
 
        /*
@@ -509,6 +510,7 @@ mft_free(struct mft *p)
                for (i = 0; i < p->filesz; i++)
                        free(p->files[i].file);
 
+       free(p->aia);
        free(p->aki);
        free(p->ski);
        free(p->file);
@@ -534,6 +536,7 @@ mft_buffer(struct ibuf *b, const struct mft *p)
                io_simple_buffer(b, p->files[i].hash, SHA256_DIGEST_LENGTH);
        }
 
+       io_str_buffer(b, p->aia);
        io_str_buffer(b, p->aki);
        io_str_buffer(b, p->ski);
 }
@@ -564,9 +567,10 @@ mft_read(int fd)
                io_simple_read(fd, p->files[i].hash, SHA256_DIGEST_LENGTH);
        }
 
+       io_str_read(fd, &p->aia);
        io_str_read(fd, &p->aki);
        io_str_read(fd, &p->ski);
-       assert(p->aki && p->ski);
+       assert(p->aia && p->aki && p->ski);
 
        return p;
 }
index 0b9e61d..1ee9187 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roa.c,v 1.13 2021/02/04 08:58:19 claudio Exp $ */
+/*     $OpenBSD: roa.c,v 1.14 2021/02/16 07:58:30 job Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -349,7 +349,8 @@ roa_parse(X509 **x509, const char *fn)
 
        if ((p.res = calloc(1, sizeof(struct roa))) == NULL)
                err(1, NULL);
-       if (!x509_get_ski_aki(*x509, fn, &p.res->ski, &p.res->aki))
+       if (!x509_get_extensions(*x509, fn, &p.res->ski, &p.res->aki,
+           &p.res->aia))
                goto out;
        if (!roa_parse_econtent(cms, cmsz, &p))
                goto out;
@@ -377,6 +378,7 @@ roa_free(struct roa *p)
 
        if (p == NULL)
                return;
+       free(p->aia);
        free(p->aki);
        free(p->ski);
        free(p->ips);
@@ -405,6 +407,7 @@ roa_buffer(struct ibuf *b, const struct roa *p)
                ip_addr_buffer(b, &p->ips[i].addr);
        }
 
+       io_str_buffer(b, p->aia);
        io_str_buffer(b, p->aki);
        io_str_buffer(b, p->ski);
        io_str_buffer(b, p->tal);
@@ -439,10 +442,11 @@ roa_read(int fd)
                ip_addr_read(fd, &p->ips[i].addr);
        }
 
+       io_str_read(fd, &p->aia);
        io_str_read(fd, &p->aki);
        io_str_read(fd, &p->ski);
        io_str_read(fd, &p->tal);
-       assert(p->aki && p->ski && p->tal);
+       assert(p->aia && p->aki && p->ski && p->tal);
 
        return p;
 }
index d14a4ac..89a99e3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: x509.c,v 1.14 2020/09/12 15:46:48 claudio Exp $ */
+/*     $OpenBSD: x509.c,v 1.15 2021/02/16 07:58:30 job Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -169,18 +169,66 @@ out:
 }
 
 /*
- * Wraps around x509_get_ski_ext and x509_get_aki_ext.
+ * Parse the Authority Information Access (AIA) extension
+ * See RFC 6487, section 4.8.7 for details.
+ * Returns NULL on failure, on success returns the AIA URI
+ * (which has to be freed after use).
+ */
+char *
+x509_get_aia(X509 *x, const char *fn)
+{
+       ACCESS_DESCRIPTION              *ad;
+       AUTHORITY_INFO_ACCESS           *info;
+       char                            *aia = NULL;
+
+       info = X509_get_ext_d2i(x, NID_info_access, NULL, NULL);
+       if (info == NULL) {
+               warnx("%s: RFC 6487 section 4.8.7: AIA: extension missing", fn);
+               return NULL;
+       }
+       if (sk_ACCESS_DESCRIPTION_num(info) != 1) {
+               warnx("%s: RFC 6487 section 4.8.7: AIA: "
+                   "want 1 element, have %d", fn,
+                   sk_ACCESS_DESCRIPTION_num(info));
+               goto out;
+       }
+
+       ad = sk_ACCESS_DESCRIPTION_value(info, 0);
+       if (OBJ_obj2nid(ad->method) != NID_ad_ca_issuers) {
+               warnx("%s: RFC 6487 section 4.8.7: AIA: "
+                   "expected caIssuers, have %d", fn, OBJ_obj2nid(ad->method));
+               goto out;
+       }
+       if (ad->location->type != GEN_URI) {
+               warnx("%s: RFC 6487 section 4.8.7: AIA: "
+                   "want GEN_URI type, have %d", fn, ad->location->type);
+               goto out;
+       }
+
+       aia = strndup(
+           ASN1_STRING_get0_data(ad->location->d.uniformResourceIdentifier),
+           ASN1_STRING_length(ad->location->d.uniformResourceIdentifier));
+       if (aia == NULL)
+               err(1, NULL);
+
+out:
+       AUTHORITY_INFO_ACCESS_free(info);
+       return aia;
+}
+
+/*
+ * Wraps around x509_get_ski_ext, x509_get_aki_ext, and x509_get_aia.
  * Returns zero on failure (out pointers are NULL) or non-zero on
  * success (out pointers must be freed).
  */
 int
-x509_get_ski_aki(X509 *x, const char *fn, char **ski, char **aki)
+x509_get_extensions(X509 *x, const char *fn, char **aia, char **aki, char **ski)
 {
        X509_EXTENSION          *ext = NULL;
        const ASN1_OBJECT       *obj;
        int                      extsz, i;
 
-       *ski = *aki = NULL;
+       *aia = *aki = *ski = NULL;
 
        if ((extsz = X509_get_ext_count(x)) < 0)
                cryptoerrx("X509_get_ext_count");
@@ -199,21 +247,20 @@ x509_get_ski_aki(X509 *x, const char *fn, char **ski, char **aki)
                        free(*aki);
                        *aki = x509_get_aki_ext(ext, fn);
                        break;
+               case NID_info_access:
+                       free(*aia);
+                       *aia = x509_get_aia(x, fn);
+                       break;
                }
        }
 
-       if (*aki == NULL) {
-               cryptowarnx("%s: RFC 6487 section 4.8.3: AKI: "
-                   "missing AKI X509 extension", fn);
-               free(*ski);
-               *ski = NULL;
-               return 0;
-       }
-       if (*ski == NULL) {
-               cryptowarnx("%s: RFC 6487 section 4.8.2: AKI: "
-                   "missing SKI X509 extension", fn);
+       if (*aia == NULL || *aki == NULL || *ski == NULL) {
+               cryptowarnx("%s: RFC 6487 section 4.8: "
+                   "missing AIA, AKI or SKI X509 extension", fn);
+               free(*aia);
                free(*aki);
-               *aki = NULL;
+               free(*ski);
+               *aia = *aki = *ski = NULL;
                return 0;
        }