From ebd5581623e41f42ead738fa0f7a54b09b976cc9 Mon Sep 17 00:00:00 2001 From: job Date: Tue, 16 Feb 2021 07:58:30 +0000 Subject: [PATCH] get Authority Information Access (AIA) from CA & EE certs 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 | 10 ++++- usr.sbin/rpki-client/extern.h | 18 +++++--- usr.sbin/rpki-client/gbr.c | 6 ++- usr.sbin/rpki-client/mft.c | 10 +++-- usr.sbin/rpki-client/roa.c | 10 +++-- usr.sbin/rpki-client/x509.c | 77 ++++++++++++++++++++++++++++------- 6 files changed, 101 insertions(+), 30 deletions(-) diff --git a/usr.sbin/rpki-client/cert.c b/usr.sbin/rpki-client/cert.c index 130794eed28..6e3d7bf7a22 100644 --- a/usr.sbin/rpki-client/cert.c +++ b/usr.sbin/rpki-client/cert.c @@ -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 * @@ -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); diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index edd446e882a..9b17ee73212 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -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 * @@ -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 *); diff --git a/usr.sbin/rpki-client/gbr.c b/usr.sbin/rpki-client/gbr.c index 550f11e18ba..0d5e304b764 100644 --- a/usr.sbin/rpki-client/gbr.c +++ b/usr.sbin/rpki-client/gbr.c @@ -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 * @@ -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); diff --git a/usr.sbin/rpki-client/mft.c b/usr.sbin/rpki-client/mft.c index 6e357c3397f..de903b5d65a 100644 --- a/usr.sbin/rpki-client/mft.c +++ b/usr.sbin/rpki-client/mft.c @@ -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 * @@ -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; } diff --git a/usr.sbin/rpki-client/roa.c b/usr.sbin/rpki-client/roa.c index 0b9e61d5483..1ee9187e828 100644 --- a/usr.sbin/rpki-client/roa.c +++ b/usr.sbin/rpki-client/roa.c @@ -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 * @@ -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; } diff --git a/usr.sbin/rpki-client/x509.c b/usr.sbin/rpki-client/x509.c index d14a4ac5550..89a99e3ff14 100644 --- a/usr.sbin/rpki-client/x509.c +++ b/usr.sbin/rpki-client/x509.c @@ -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 * @@ -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; } -- 2.20.1