From: job Date: Fri, 4 Nov 2022 09:43:13 +0000 (+0000) Subject: Check the SIA signedObject in ROA/MFT/ASPA/TAK/GBR EE certificates X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=2cf0e1225564d842848697d26c43141252c00c36;p=openbsd Check the SIA signedObject in ROA/MFT/ASPA/TAK/GBR EE certificates Unfortunately we can't yet error out when accessMethods other than signedObject are encountered in the SubjectInformationAccess extension because there is pollution in the ecosystem. OK tb@ --- diff --git a/usr.sbin/rpki-client/aspa.c b/usr.sbin/rpki-client/aspa.c index 5ed3d9a8324..aab730b8ce4 100644 --- a/usr.sbin/rpki-client/aspa.c +++ b/usr.sbin/rpki-client/aspa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aspa.c,v 1.6 2022/11/02 10:04:41 tb Exp $ */ +/* $OpenBSD: aspa.c,v 1.7 2022/11/04 09:43:13 job Exp $ */ /* * Copyright (c) 2022 Job Snijders * Copyright (c) 2022 Theo Buehler @@ -207,11 +207,14 @@ aspa_parse(X509 **x509, const char *fn, const unsigned char *der, size_t len) goto out; if (!x509_get_aki(*x509, fn, &p.res->aki)) goto out; + if (!x509_get_sia(*x509, fn, &p.res->sia)) + goto out; if (!x509_get_ski(*x509, fn, &p.res->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) { + if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL || + p.res->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " - "missing AIA, AKI or SKI X509 extension", fn); + "missing AIA, AKI, SIA, or SKI X509 extension", fn); goto out; } @@ -268,6 +271,7 @@ aspa_free(struct aspa *p) free(p->aia); free(p->aki); + free(p->sia); free(p->ski); free(p->providers); free(p); diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index 96d0025596d..022544841bc 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.157 2022/11/02 12:43:02 job Exp $ */ +/* $OpenBSD: extern.h,v 1.158 2022/11/04 09:43:13 job Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -213,6 +213,7 @@ struct mft { char *seqnum; /* manifestNumber */ char *aia; /* AIA */ char *aki; /* AKI */ + char *sia; /* SIA signedObject */ char *ski; /* SKI */ char *crl; /* CRL file name */ unsigned char crlhash[SHA256_DIGEST_LENGTH]; @@ -248,6 +249,7 @@ struct roa { int valid; /* validated resources */ char *aia; /* AIA */ char *aki; /* AKI */ + char *sia; /* SIA signedObject */ char *ski; /* SKI */ time_t expires; /* do not use after */ }; @@ -298,6 +300,7 @@ struct tak { struct takey *successor; char *aia; /* AIA */ char *aki; /* AKI */ + char *sia; /* SIA signed Object */ char *ski; /* SKI */ time_t expires; /* Not After of the TAK EE */ }; @@ -309,6 +312,7 @@ struct gbr { char *vcard; char *aia; /* AIA */ char *aki; /* AKI */ + char *sia; /* SIA signedObject */ char *ski; /* SKI */ }; @@ -325,6 +329,7 @@ struct aspa { int talid; /* TAL the ASPA is chained up to */ char *aia; /* AIA */ char *aki; /* AKI */ + char *sia; /* SIA signedObject */ char *ski; /* SKI */ uint32_t custasid; /* the customerASID */ struct aspa_provider *providers; /* the providers */ @@ -737,6 +742,7 @@ struct ibuf *io_buf_recvfd(int, struct ibuf **); void x509_init_oid(void); int x509_get_aia(X509 *, const char *, char **); int x509_get_aki(X509 *, const char *, char **); +int x509_get_sia(X509 *, const char *, char **); int x509_get_ski(X509 *, const char *, char **); int x509_get_expire(X509 *, const char *, time_t *); int x509_get_crl(X509 *, const char *, char **); diff --git a/usr.sbin/rpki-client/gbr.c b/usr.sbin/rpki-client/gbr.c index db0616fc89c..5cce58552ce 100644 --- a/usr.sbin/rpki-client/gbr.c +++ b/usr.sbin/rpki-client/gbr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gbr.c,v 1.16 2022/05/11 21:19:06 job Exp $ */ +/* $OpenBSD: gbr.c,v 1.17 2022/11/04 09:43:13 job Exp $ */ /* * Copyright (c) 2020 Claudio Jeker * @@ -67,11 +67,14 @@ gbr_parse(X509 **x509, const char *fn, const unsigned char *der, size_t len) goto out; if (!x509_get_aki(*x509, fn, &p.res->aki)) goto out; + if (!x509_get_sia(*x509, fn, &p.res->sia)) + goto out; if (!x509_get_ski(*x509, fn, &p.res->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) { + if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL || + p.res->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " - "missing AIA, AKI or SKI X509 extension", fn); + "missing AIA, AKI, SIA or SKI X509 extension", fn); goto out; } @@ -101,6 +104,7 @@ gbr_free(struct gbr *p) return; free(p->aia); free(p->aki); + free(p->sia); free(p->ski); free(p->vcard); free(p); diff --git a/usr.sbin/rpki-client/mft.c b/usr.sbin/rpki-client/mft.c index 7fde67f823f..b86775e7705 100644 --- a/usr.sbin/rpki-client/mft.c +++ b/usr.sbin/rpki-client/mft.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mft.c,v 1.76 2022/11/02 12:43:02 job Exp $ */ +/* $OpenBSD: mft.c,v 1.77 2022/11/04 09:43:13 job Exp $ */ /* * Copyright (c) 2022 Theo Buehler * Copyright (c) 2019 Kristaps Dzonsons @@ -368,11 +368,14 @@ mft_parse(X509 **x509, const char *fn, const unsigned char *der, size_t len) goto out; if (!x509_get_aki(*x509, fn, &p.res->aki)) goto out; + if (!x509_get_sia(*x509, fn, &p.res->sia)) + goto out; if (!x509_get_ski(*x509, fn, &p.res->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) { + if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL || + p.res->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " - "missing AIA, AKI or SKI X509 extension", fn); + "missing AIA, AKI, SIA, or SKI X509 extension", fn); goto out; } @@ -433,6 +436,7 @@ mft_free(struct mft *p) free(p->aia); free(p->aki); + free(p->sia); free(p->ski); free(p->path); free(p->files); diff --git a/usr.sbin/rpki-client/print.c b/usr.sbin/rpki-client/print.c index b56bd99d02f..e38411ad705 100644 --- a/usr.sbin/rpki-client/print.c +++ b/usr.sbin/rpki-client/print.c @@ -1,4 +1,4 @@ -/* $OpenBSD: print.c,v 1.17 2022/11/02 12:43:02 job Exp $ */ +/* $OpenBSD: print.c,v 1.18 2022/11/04 09:43:13 job Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -337,6 +337,7 @@ mft_print(const X509 *x, const struct mft *p) x509_print(x); printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); printf("\t\"aia\": \"%s\",\n", p->aia); + printf("\t\"sia\": \"%s\",\n", p->sia); printf("\t\"manifest_number\": \"%s\",\n", p->seqnum); printf("\t\"valid_since\": %lld,\n", (long long)p->valid_since); printf("\t\"valid_until\": %lld,\n", (long long)p->valid_until); @@ -345,6 +346,7 @@ mft_print(const X509 *x, const struct mft *p) printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); x509_print(x); printf("Authority info access: %s\n", p->aia); + printf("Subject info access: %s\n", p->sia); printf("Manifest Number: %s\n", p->seqnum); printf("Manifest valid since: %s\n", time2str(p->valid_since)); printf("Manifest valid until: %s\n", time2str(p->valid_until)); @@ -388,14 +390,17 @@ roa_print(const X509 *x, const struct roa *p) x509_print(x); printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); printf("\t\"aia\": \"%s\",\n", p->aia); + printf("\t\"sia\": \"%s\",\n", p->sia); printf("\t\"valid_until\": %lld,\n", (long long)p->expires); } else { printf("Subject key identifier: %s\n", pretty_key_id(p->ski)); x509_print(x); printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); printf("Authority info access: %s\n", p->aia); + printf("Subject info access: %s\n", p->sia); printf("ROA valid until: %s\n", time2str(p->expires)); printf("asID: %u\n", p->asid); + printf("IP address blocks:\n"); } for (i = 0; i < p->ipsz; i++) { @@ -432,6 +437,7 @@ gbr_print(const X509 *x, const struct gbr *p) x509_print(x); printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); printf("\t\"aia\": \"%s\",\n", p->aia); + printf("\t\"sia\": \"%s\",\n", p->sia); printf("\t\"vcard\": \""); for (i = 0; i < strlen(p->vcard); i++) { if (p->vcard[i] == '"') @@ -449,6 +455,7 @@ gbr_print(const X509 *x, const struct gbr *p) x509_print(x); printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); printf("Authority info access: %s\n", p->aia); + printf("Subject info access: %s\n", p->sia); printf("vcard:\n%s", p->vcard); } } @@ -580,6 +587,7 @@ aspa_print(const X509 *x, const struct aspa *p) x509_print(x); printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); printf("\t\"aia\": \"%s\",\n", p->aia); + printf("\t\"sia\": \"%s\",\n", p->sia); printf("\t\"customer_asid\": %u,\n", p->custasid); printf("\t\"provider_set\": [\n"); for (i = 0; i < p->providersz; i++) { @@ -599,6 +607,7 @@ aspa_print(const X509 *x, const struct aspa *p) x509_print(x); printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); printf("Authority info access: %s\n", p->aia); + printf("Subject info access: %s\n", p->sia); printf("Customer AS: %u\n", p->custasid); printf("Provider Set:\n"); for (i = 0; i < p->providersz; i++) { @@ -681,6 +690,7 @@ tak_print(const X509 *x, const struct tak *p) x509_print(x); printf("\t\"aki\": \"%s\",\n", pretty_key_id(p->aki)); printf("\t\"aia\": \"%s\",\n", p->aia); + printf("\t\"sia\": \"%s\",\n", p->sia); printf("\t\"valid_until\": %lld,\n", (long long)p->expires); printf("\t\"takeys\": [\n"); } else { @@ -689,6 +699,7 @@ tak_print(const X509 *x, const struct tak *p) x509_print(x); printf("Authority key identifier: %s\n", pretty_key_id(p->aki)); printf("Authority info access: %s\n", p->aia); + printf("Subject info access: %s\n", p->sia); printf("TAK EE certificate valid until: %s\n", tbuf); } diff --git a/usr.sbin/rpki-client/roa.c b/usr.sbin/rpki-client/roa.c index 982ab600cdd..4a40126531d 100644 --- a/usr.sbin/rpki-client/roa.c +++ b/usr.sbin/rpki-client/roa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: roa.c,v 1.54 2022/11/02 10:04:41 tb Exp $ */ +/* $OpenBSD: roa.c,v 1.55 2022/11/04 09:43:13 job Exp $ */ /* * Copyright (c) 2022 Theo Buehler * Copyright (c) 2019 Kristaps Dzonsons @@ -222,11 +222,14 @@ roa_parse(X509 **x509, const char *fn, const unsigned char *der, size_t len) goto out; if (!x509_get_aki(*x509, fn, &p.res->aki)) goto out; + if (!x509_get_sia(*x509, fn, &p.res->sia)) + goto out; if (!x509_get_ski(*x509, fn, &p.res->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) { + if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL || + p.res->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " - "missing AIA, AKI or SKI X509 extension", fn); + "missing AIA, AKI, SIA, or SKI X509 extension", fn); goto out; } @@ -287,6 +290,7 @@ roa_free(struct roa *p) return; free(p->aia); free(p->aki); + free(p->sia); free(p->ski); free(p->ips); free(p); diff --git a/usr.sbin/rpki-client/tak.c b/usr.sbin/rpki-client/tak.c index d621acac31e..cd1f643fc2b 100644 --- a/usr.sbin/rpki-client/tak.c +++ b/usr.sbin/rpki-client/tak.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tak.c,v 1.1 2022/11/02 12:43:02 job Exp $ */ +/* $OpenBSD: tak.c,v 1.2 2022/11/04 09:43:13 job Exp $ */ /* * Copyright (c) 2022 Job Snijders * Copyright (c) 2022 Theo Buehler @@ -247,11 +247,14 @@ tak_parse(X509 **x509, const char *fn, const unsigned char *der, size_t len) goto out; if (!x509_get_aki(*x509, fn, &p.res->aki)) goto out; + if (!x509_get_sia(*x509, fn, &p.res->sia)) + goto out; if (!x509_get_ski(*x509, fn, &p.res->ski)) goto out; - if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) { + if (p.res->aia == NULL || p.res->aki == NULL || p.res->sia == NULL || + p.res->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " - "missing AIA, AKI or SKI X509 extension", fn); + "missing AIA, AKI, SIA, or SKI X509 extension", fn); goto out; } diff --git a/usr.sbin/rpki-client/x509.c b/usr.sbin/rpki-client/x509.c index 7ebf9e8e529..efa9d691a38 100644 --- a/usr.sbin/rpki-client/x509.c +++ b/usr.sbin/rpki-client/x509.c @@ -1,4 +1,4 @@ -/* $OpenBSD: x509.c,v 1.53 2022/11/02 12:43:02 job Exp $ */ +/* $OpenBSD: x509.c,v 1.54 2022/11/04 09:43:13 job Exp $ */ /* * Copyright (c) 2022 Theo Buehler * Copyright (c) 2021 Claudio Jeker @@ -34,6 +34,7 @@ ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */ ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */ ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */ +ASN1_OBJECT *signedobj_oid; /* 1.3.6.1.5.5.7.48.11 (signedObject) */ ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */ ASN1_OBJECT *roa_oid; /* id-ct-routeOriginAuthz CMS content type */ ASN1_OBJECT *mft_oid; /* id-ct-rpkiManifest CMS content type */ @@ -63,6 +64,10 @@ static const struct { .oid = "1.3.6.1.5.5.7.48.10", .ptr = &manifest_oid, }, + { + .oid = "1.3.6.1.5.5.7.48.11", + .ptr = &signedobj_oid, + }, { .oid = "1.3.6.1.5.5.7.48.13", .ptr = ¬ify_oid, @@ -369,6 +374,55 @@ out: return rc; } +/* + * Parse the Subject Information Access (SIA) extension + * See RFC 6487, section 4.8.8 for details. + * Returns NULL on failure, on success returns the SIA signedObject URI + * (which has to be freed after use). + */ +int +x509_get_sia(X509 *x, const char *fn, char **sia) +{ + ACCESS_DESCRIPTION *ad; + AUTHORITY_INFO_ACCESS *info; + ASN1_OBJECT *oid; + int i, crit, rc = 0; + + *sia = NULL; + + info = X509_get_ext_d2i(x, NID_sinfo_access, &crit, NULL); + if (info == NULL) + return 1; + + if (crit != 0) { + warnx("%s: RFC 6487 section 4.8.8: " + "SIA: extension not non-critical", fn); + goto out; + } + + /* + * RFC 6487 4.8.8.2 disallows other accessMethods, however they + * do exist in the wild. + */ + for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) { + ad = sk_ACCESS_DESCRIPTION_value(info, i); + oid = ad->method; + + if (OBJ_cmp(oid, signedobj_oid) != 0) + continue; + + /* XXX: correctly deal with other (non-rsync) protocols. */ + if (!x509_location(fn, "SIA: signedObject", "rsync://", + ad->location, sia)) + goto out; + } + + rc = 1; + out: + AUTHORITY_INFO_ACCESS_free(info); + return rc; +} + /* * Extract the expire time (not-after) of a certificate. */