Check the SIA signedObject in ROA/MFT/ASPA/TAK/GBR EE certificates
authorjob <job@openbsd.org>
Fri, 4 Nov 2022 09:43:13 +0000 (09:43 +0000)
committerjob <job@openbsd.org>
Fri, 4 Nov 2022 09:43:13 +0000 (09:43 +0000)
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@

usr.sbin/rpki-client/aspa.c
usr.sbin/rpki-client/extern.h
usr.sbin/rpki-client/gbr.c
usr.sbin/rpki-client/mft.c
usr.sbin/rpki-client/print.c
usr.sbin/rpki-client/roa.c
usr.sbin/rpki-client/tak.c
usr.sbin/rpki-client/x509.c

index 5ed3d9a..aab730b 100644 (file)
@@ -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 <job@fastly.com>
  * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
@@ -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);
index 96d0025..0225448 100644 (file)
@@ -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 <kristaps@bsd.lv>
  *
@@ -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 **);
index db0616f..5cce585 100644 (file)
@@ -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 <claudio@openbsd.org>
  *
@@ -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);
index 7fde67f..b86775e 100644 (file)
@@ -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 <tb@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -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);
index b56bd99..e38411a 100644 (file)
@@ -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 <claudio@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -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);
        }
 
index 982ab60..4a40126 100644 (file)
@@ -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 <tb@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -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);
index d621aca..cd1f643 100644 (file)
@@ -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 <job@fastly.com>
  * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
@@ -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;
        }
 
index 7ebf9e8..efa9d69 100644 (file)
@@ -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 <tb@openbsd.org>
  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
@@ -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 = &notify_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.
  */