Instead of tracking certificates by SKI track them by an internal identifier.
authorclaudio <claudio@openbsd.org>
Mon, 20 May 2024 15:51:43 +0000 (15:51 +0000)
committerclaudio <claudio@openbsd.org>
Mon, 20 May 2024 15:51:43 +0000 (15:51 +0000)
The certificate SKI is not strictly unique so using it as a unique id is
problematic. It is also not really needed to do that since in theory we
already know the path (but this got lost in the privsep communication).
So add a cert id and pass this id back and forth between main process and
the parser. With this id we can lookup the authentication chain in the
parser and this even works with multiple paths to the same resource.
Since we no longer lookup by SKI the valid_aki_ski function is replaced
by find_issuer() which does the lookup by certid.

The loop protection is now extended to allow each TAL to reach each file
once but still triggers if a file is reaccessed by the tree of a TAL.

In filemode the lookup now uses an AIA uri based lookup tree. Again this
replaces the SKI based lookups from before.

Done together with tb@
OK tb@ job@

usr.sbin/rpki-client/cert.c
usr.sbin/rpki-client/extern.h
usr.sbin/rpki-client/filemode.c
usr.sbin/rpki-client/main.c
usr.sbin/rpki-client/mft.c
usr.sbin/rpki-client/parser.c
usr.sbin/rpki-client/repo.c
usr.sbin/rpki-client/validate.c

index c4f347f..3eb769f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cert.c,v 1.130 2024/04/21 19:27:44 claudio Exp $ */
+/*     $OpenBSD: cert.c,v 1.131 2024/05/20 15:51:43 claudio Exp $ */
 /*
  * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
  * Copyright (c) 2021 Job Snijders <job@openbsd.org>
@@ -34,6 +34,8 @@ extern ASN1_OBJECT    *carepo_oid;    /* 1.3.6.1.5.5.7.48.5 (caRepository) */
 extern ASN1_OBJECT     *manifest_oid;  /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
 extern ASN1_OBJECT     *notify_oid;    /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
 
+static int certid = TALSZ_MAX;
+
 /*
  * Append an IP address structure to our list of results.
  * This will also constrain us to having at most one inheritance
@@ -1103,6 +1105,7 @@ cert_buffer(struct ibuf *b, const struct cert *p)
        io_simple_buffer(b, &p->notafter, sizeof(p->notafter));
        io_simple_buffer(b, &p->purpose, sizeof(p->purpose));
        io_simple_buffer(b, &p->talid, sizeof(p->talid));
+       io_simple_buffer(b, &p->certid, sizeof(p->certid));
        io_simple_buffer(b, &p->repoid, sizeof(p->repoid));
        io_simple_buffer(b, &p->ipsz, sizeof(p->ipsz));
        io_simple_buffer(b, &p->asz, sizeof(p->asz));
@@ -1136,6 +1139,7 @@ cert_read(struct ibuf *b)
        io_read_buf(b, &p->notafter, sizeof(p->notafter));
        io_read_buf(b, &p->purpose, sizeof(p->purpose));
        io_read_buf(b, &p->talid, sizeof(p->talid));
+       io_read_buf(b, &p->certid, sizeof(p->certid));
        io_read_buf(b, &p->repoid, sizeof(p->repoid));
        io_read_buf(b, &p->ipsz, sizeof(p->ipsz));
        io_read_buf(b, &p->asz, sizeof(p->asz));
@@ -1167,7 +1171,11 @@ cert_read(struct ibuf *b)
 static inline int
 authcmp(struct auth *a, struct auth *b)
 {
-       return strcmp(a->cert->ski, b->cert->ski);
+       if (a->cert->certid > b->cert->certid)
+               return 1;
+       if (a->cert->certid < b->cert->certid)
+               return -1;
+       return 0;
 }
 
 RB_GENERATE_STATIC(auth_tree, auth, entry, authcmp);
@@ -1185,33 +1193,48 @@ auth_tree_free(struct auth_tree *auths)
 }
 
 struct auth *
-auth_find(struct auth_tree *auths, const char *aki)
+auth_find(struct auth_tree *auths, int id)
 {
        struct auth a;
        struct cert c;
 
-       /* we look up the cert where the ski == aki */
-       c.ski = (char *)aki;
+       c.certid = id;
        a.cert = &c;
 
        return RB_FIND(auth_tree, auths, &a);
 }
 
 struct auth *
-auth_insert(struct auth_tree *auths, struct cert *cert, struct auth *issuer)
+auth_insert(const char *fn, struct auth_tree *auths, struct cert *cert,
+    struct auth *issuer)
 {
        struct auth *na;
 
-       na = malloc(sizeof(*na));
+       na = calloc(1, sizeof(*na));
        if (na == NULL)
                err(1, NULL);
 
+       if (issuer == NULL) {
+               cert->certid = cert->talid;
+       } else {
+               cert->certid = ++certid;
+               if (certid > CERTID_MAX)
+                       errx(1, "%s: too many certificates in store", fn);
+               na->depth = issuer->depth + 1;
+       }
+
+       if (na->depth >= MAX_CERT_DEPTH) {
+               warnx("%s: maximum certificate chain depth exhausted", fn);
+               free(na);
+               return NULL;
+       }
+
        na->issuer = issuer;
        na->cert = cert;
        na->any_inherits = x509_any_inherits(cert->x509);
 
        if (RB_INSERT(auth_tree, auths, na) != NULL)
-               err(1, "auth tree corrupted");
+               errx(1, "auth tree corrupted");
 
        return na;
 }
index 9dd6997..6bdaab9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: extern.h,v 1.217 2024/04/21 19:27:44 claudio Exp $ */
+/*     $OpenBSD: extern.h,v 1.218 2024/05/20 15:51:43 claudio Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -24,6 +24,9 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
+#define CTASSERT(x)    extern char  _ctassert[(x) ? 1 : -1 ] \
+                           __attribute__((__unused__))
+
 enum cert_as_type {
        CERT_AS_ID, /* single identifier */
        CERT_AS_INHERIT, /* inherit from issuer */
@@ -120,6 +123,7 @@ struct cert {
        struct cert_as  *as; /* list of AS numbers and ranges */
        size_t           asz; /* length of "asz" */
        int              talid; /* cert is covered by which TAL */
+       int              certid;
        unsigned int     repoid; /* repository of this cert file */
        char            *repo; /* CA repository (rsync:// uri) */
        char            *mft; /* manifest (rsync:// uri) */
@@ -212,6 +216,7 @@ struct mft {
        size_t           filesz; /* number of filenames */
        unsigned int     repoid;
        int              talid;
+       int              certid;
 };
 
 /*
@@ -495,14 +500,16 @@ struct auth {
        struct cert     *cert; /* owner information */
        struct auth     *issuer; /* pointer to issuer or NULL for TA cert */
        int              any_inherits;
+       int              depth;
 };
 /*
  * Tree of auth sorted by ski
  */
 RB_HEAD(auth_tree, auth);
 
-struct auth    *auth_find(struct auth_tree *, const char *);
-struct auth    *auth_insert(struct auth_tree *, struct cert *, struct auth *);
+struct auth    *auth_find(struct auth_tree *, int);
+struct auth    *auth_insert(const char *, struct auth_tree *, struct cert *,
+                   struct auth *);
 
 enum http_result {
        HTTP_FAILED,    /* anything else */
@@ -560,6 +567,7 @@ struct entity {
        size_t           datasz;        /* length of optional data blob */
        unsigned int     repoid;        /* repository identifier */
        int              talid;         /* tal identifier */
+       int              certid;
        enum rtype       type;          /* type of entity (not RTYPE_EOF) */
        enum location    location;      /* which directory the file lives in */
 };
@@ -731,10 +739,6 @@ void                crl_tree_free(struct crl_tree *);
 
 /* Validation of our objects. */
 
-struct auth    *valid_ski_aki(const char *, struct auth_tree *,
-                   const char *, const char *, const char *);
-int             valid_ta(const char *, struct auth_tree *,
-                   const struct cert *);
 int             valid_cert(const char *, struct auth *, const struct cert *);
 int             valid_roa(const char *, struct cert *, struct roa *);
 int             valid_filehash(int, const char *, size_t);
@@ -826,7 +830,7 @@ void                 proc_http(char *, int) __attribute__((noreturn));
 void            proc_rrdp(int) __attribute__((noreturn));
 
 /* Repository handling */
-int             filepath_add(struct filepath_tree *, char *, time_t);
+int             filepath_add(struct filepath_tree *, char *, int, time_t);
 void            rrdp_clear(unsigned int);
 void            rrdp_session_save(unsigned int, struct rrdp_session *);
 void            rrdp_session_free(struct rrdp_session *);
@@ -981,6 +985,7 @@ int mkpathat(int, const char *);
 
 /* Maximum number of TAL files we'll load. */
 #define        TALSZ_MAX               8
+#define        CERTID_MAX              1000000
 
 /*
  * Maximum number of elements in the sbgp-ipAddrBlock (IP) and
index 5590079..7ebeaea 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: filemode.c,v 1.41 2024/04/21 19:27:44 claudio Exp $ */
+/*     $OpenBSD: filemode.c,v 1.42 2024/05/20 15:51:43 claudio Exp $ */
 /*
  * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -47,6 +47,50 @@ static struct crl_tree        crlt = RB_INITIALIZER(&crlt);
 
 struct tal             *talobj[TALSZ_MAX];
 
+struct uripath {
+       RB_ENTRY(uripath)        entry;
+       const char              *uri;
+       struct cert             *cert;
+};
+
+static RB_HEAD(uripath_tree, uripath) uritree;
+
+static inline int
+uripathcmp(const struct uripath *a, const struct uripath *b)
+{
+       return strcmp(a->uri, b->uri);
+}
+
+RB_PROTOTYPE(uripath_tree, uripath, entry, uripathcmp);
+
+static void
+uripath_add(const char *uri, struct cert *cert)
+{
+       struct uripath *up;
+
+       if ((up = calloc(1, sizeof(*up))) == NULL)
+               err(1, NULL);
+       if ((up->uri = strdup(uri)) == NULL)
+               err(1, NULL);
+       up->cert = cert;
+       if (RB_INSERT(uripath_tree, &uritree, up) != NULL)
+               errx(1, "corrupt AIA lookup tree");
+}
+
+static struct cert *
+uripath_lookup(const char *uri)
+{
+       struct uripath needle = { .uri = uri };
+       struct uripath *up;
+
+       up = RB_FIND(uripath_tree, &uritree, &needle);
+       if (up == NULL)
+               return NULL;
+       return up->cert;
+}
+
+RB_GENERATE(uripath_tree, uripath, entry, uripathcmp);
+
 /*
  * Use the X509 CRL Distribution Points to locate the CRL needed for
  * verification.
@@ -132,7 +176,7 @@ parse_load_cert(char *uri)
  * tree. Once the TA is located in the chain the chain is validated in
  * reverse order.
  */
-static void
+static struct auth *
 parse_load_certchain(char *uri)
 {
        struct cert *stack[MAX_CERT_DEPTH] = { 0 };
@@ -144,18 +188,16 @@ parse_load_certchain(char *uri)
        int i;
 
        for (i = 0; i < MAX_CERT_DEPTH; i++) {
+               if ((cert = uripath_lookup(uri)) != NULL) {
+                       a = auth_find(&auths, cert->certid);
+                       break;
+               }
                filestack[i] = uri;
                stack[i] = cert = parse_load_cert(uri);
                if (cert == NULL || cert->purpose != CERT_PURPOSE_CA) {
-                       warnx("failed to build authority chain");
+                       warnx("failed to build authority chain: %s", uri);
                        goto fail;
                }
-               if (auth_find(&auths, cert->ski) != NULL) {
-                       assert(i == 0);
-                       goto fail;
-               }
-               if ((a = auth_find(&auths, cert->aki)) != NULL)
-                       break;  /* found chain to TA */
                uri = cert->aia;
        }
 
@@ -166,9 +208,9 @@ parse_load_certchain(char *uri)
        }
 
        /* TA found play back the stack and add all certs */
-       for (; i >= 0; i--) {
-               cert = stack[i];
-               uri = filestack[i];
+       for (; i > 0; i--) {
+               cert = stack[i - 1];
+               uri = filestack[i - 1];
 
                crl = crl_get(&crlt, a);
                if (!valid_x509(uri, ctx, cert->x509, a, crl, &errstr) ||
@@ -178,14 +220,16 @@ parse_load_certchain(char *uri)
                        goto fail;
                }
                cert->talid = a->cert->talid;
-               a = auth_insert(&auths, cert, a);
+               a = auth_insert(uri, &auths, cert, a);
+               uripath_add(uri, cert);
                stack[i] = NULL;
        }
 
-       return;
+       return a;
 fail:
        for (i = 0; i < MAX_CERT_DEPTH; i++)
                cert_free(stack[i]);
+       return NULL;
 }
 
 static void
@@ -195,7 +239,7 @@ parse_load_ta(struct tal *tal)
        struct cert *cert;
        unsigned char *f = NULL;
        char *file;
-       size_t flen;
+       size_t flen, i;
 
        /* does not matter which URI, all end with same filename */
        filename = strrchr(tal->uri[0], '/');
@@ -217,11 +261,14 @@ parse_load_ta(struct tal *tal)
                goto out;
 
        cert->talid = tal->id;
+       auth_insert(file, &auths, cert, NULL);
+       for (i = 0; i < tal->urisz; i++) {
+               if (strncasecmp(tal->uri[i], RSYNC_PROTO, RSYNC_PROTO_LEN) != 0)
+                       continue;
+               /* Add all rsync uri since any of them could be used as AIA. */
+               uripath_add(tal->uri[i], cert);
+       }
 
-       if (!valid_ta(file, &auths, cert))
-               cert_free(cert);
-       else
-               auth_insert(&auths, cert, NULL);
 out:
        free(file);
        free(f);
@@ -297,7 +344,7 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
        struct spl *spl = NULL;
        struct tak *tak = NULL;
        struct tal *tal = NULL;
-       char *aia = NULL, *aki = NULL;
+       char *aia = NULL;
        char *crl_uri = NULL;
        time_t *expires = NULL, *notafter = NULL;
        struct auth *a;
@@ -349,7 +396,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
                if (aspa == NULL)
                        break;
                aia = aspa->aia;
-               aki = aspa->aki;
                expires = &aspa->expires;
                notafter = &aspa->notafter;
                break;
@@ -363,7 +409,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
                if (cert == NULL)
                        break;
                aia = cert->aia;
-               aki = cert->aki;
                x509 = cert->x509;
                if (X509_up_ref(x509) == 0)
                        errx(1, "%s: X509_up_ref failed", __func__);
@@ -381,7 +426,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
                if (mft == NULL)
                        break;
                aia = mft->aia;
-               aki = mft->aki;
                expires = &mft->expires;
                notafter = &mft->nextupdate;
                break;
@@ -390,7 +434,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
                if (gbr == NULL)
                        break;
                aia = gbr->aia;
-               aki = gbr->aki;
                expires = &gbr->expires;
                notafter = &gbr->notafter;
                break;
@@ -399,7 +442,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
                if (geofeed == NULL)
                        break;
                aia = geofeed->aia;
-               aki = geofeed->aki;
                expires = &geofeed->expires;
                notafter = &geofeed->notafter;
                break;
@@ -408,7 +450,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
                if (roa == NULL)
                        break;
                aia = roa->aia;
-               aki = roa->aki;
                expires = &roa->expires;
                notafter = &roa->notafter;
                break;
@@ -417,7 +458,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
                if (rsc == NULL)
                        break;
                aia = rsc->aia;
-               aki = rsc->aki;
                expires = &rsc->expires;
                notafter = &rsc->notafter;
                break;
@@ -426,7 +466,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
                if (spl == NULL)
                        break;
                aia = spl->aia;
-               aki = spl->aki;
                expires = &spl->expires;
                notafter = &spl->notafter;
                break;
@@ -435,7 +474,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
                if (tak == NULL)
                        break;
                aia = tak->aia;
-               aki = tak->aki;
                expires = &tak->expires;
                notafter = &tak->notafter;
                break;
@@ -453,9 +491,7 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
        if (aia != NULL) {
                x509_get_crl(x509, file, &crl_uri);
                parse_load_crl(crl_uri);
-               if (auth_find(&auths, aki) == NULL)
-                       parse_load_certchain(aia);
-               a = auth_find(&auths, aki);
+               a = parse_load_certchain(aia);
                c = crl_get(&crlt, a);
 
                if ((status = valid_x509(file, ctx, x509, a, c, &errstr))) {
index 3a124ef..ffd0100 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: main.c,v 1.257 2024/04/08 14:02:13 tb Exp $ */
+/*     $OpenBSD: main.c,v 1.258 2024/05/20 15:51:43 claudio Exp $ */
 /*
  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -156,6 +156,7 @@ entity_read_req(struct ibuf *b, struct entity *ent)
        io_read_buf(b, &ent->location, sizeof(ent->location));
        io_read_buf(b, &ent->repoid, sizeof(ent->repoid));
        io_read_buf(b, &ent->talid, sizeof(ent->talid));
+       io_read_buf(b, &ent->certid, sizeof(ent->certid));
        io_read_str(b, &ent->path);
        io_read_str(b, &ent->file);
        io_read_str(b, &ent->mftaki);
@@ -176,6 +177,7 @@ entity_write_req(const struct entity *ent)
        io_simple_buffer(b, &ent->location, sizeof(ent->location));
        io_simple_buffer(b, &ent->repoid, sizeof(ent->repoid));
        io_simple_buffer(b, &ent->talid, sizeof(ent->talid));
+       io_simple_buffer(b, &ent->certid, sizeof(ent->certid));
        io_str_buffer(b, ent->path);
        io_str_buffer(b, ent->file);
        io_str_buffer(b, ent->mftaki);
@@ -191,7 +193,7 @@ entity_write_repo(const struct repo *rp)
        enum location loc = DIR_UNKNOWN;
        unsigned int repoid;
        char *path, *altpath;
-       int talid = 0;
+       int talid = 0, certid = 0;
 
        repoid = repo_id(rp);
        path = repo_basedir(rp, 0);
@@ -201,6 +203,7 @@ entity_write_repo(const struct repo *rp)
        io_simple_buffer(b, &loc, sizeof(loc));
        io_simple_buffer(b, &repoid, sizeof(repoid));
        io_simple_buffer(b, &talid, sizeof(talid));
+       io_simple_buffer(b, &certid, sizeof(certid));
        io_str_buffer(b, path);
        io_str_buffer(b, altpath);
        io_buf_buffer(b, NULL, 0); /* ent->mftaki */
@@ -233,7 +236,7 @@ entityq_flush(struct entityq *q, struct repo *rp)
  */
 static void
 entityq_add(char *path, char *file, enum rtype type, enum location loc,
-    struct repo *rp, unsigned char *data, size_t datasz, int talid,
+    struct repo *rp, unsigned char *data, size_t datasz, int talid, int certid,
     char *mftaki)
 {
        struct entity   *p;
@@ -244,6 +247,7 @@ entityq_add(char *path, char *file, enum rtype type, enum location loc,
        p->type = type;
        p->location = loc;
        p->talid = talid;
+       p->certid = certid;
        p->mftaki = mftaki;
        p->path = path;
        if (rp != NULL)
@@ -419,7 +423,7 @@ queue_add_from_mft(const struct mft *mft)
                if ((mftaki = strdup(mft->aki)) == NULL)
                        err(1, NULL);
                entityq_add(npath, nfile, f->type, f->location, rp, NULL, 0,
-                   mft->talid, mftaki);
+                   mft->talid, mft->certid, mftaki);
        }
 }
 
@@ -442,7 +446,7 @@ queue_add_file(const char *file, enum rtype type, int talid)
        if ((nfile = strdup(file)) == NULL)
                err(1, NULL);
        /* Not in a repository, so directly add to queue. */
-       entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, buf, len, talid,
+       entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, buf, len, talid, 0,
            NULL);
 }
 
@@ -478,7 +482,7 @@ queue_add_from_tal(struct tal *tal)
        data = tal->pkey;
        tal->pkey = NULL;
        entityq_add(NULL, nfile, RTYPE_CER, DIR_VALID, repo, data,
-           tal->pkeysz, tal->id, NULL);
+           tal->pkeysz, tal->id, tal->id, NULL);
 }
 
 /*
@@ -547,7 +551,7 @@ queue_add_from_cert(const struct cert *cert)
        }
 
        entityq_add(npath, nfile, RTYPE_MFT, DIR_UNKNOWN, repo, NULL, 0,
-           cert->talid, NULL);
+           cert->talid, cert->certid, NULL);
 }
 
 /*
@@ -591,7 +595,7 @@ entity_process(struct ibuf *b, struct stats *st, struct vrp_tree *tree,
        if (filemode)
                goto done;
 
-       if (filepath_add(&fpt, file, mtime) == 0) {
+       if (filepath_add(&fpt, file, talid, mtime) == 0) {
                warnx("%s: File already visited", file);
                goto done;
        }
index 8b6bf28..64db5f6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mft.c,v 1.114 2024/05/15 09:19:48 tb Exp $ */
+/*     $OpenBSD: mft.c,v 1.115 2024/05/20 15:51:43 claudio Exp $ */
 /*
  * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -537,6 +537,7 @@ mft_buffer(struct ibuf *b, const struct mft *p)
 
        io_simple_buffer(b, &p->repoid, sizeof(p->repoid));
        io_simple_buffer(b, &p->talid, sizeof(p->talid));
+       io_simple_buffer(b, &p->certid, sizeof(p->certid));
        io_str_buffer(b, p->path);
 
        io_str_buffer(b, p->aia);
@@ -569,6 +570,7 @@ mft_read(struct ibuf *b)
 
        io_read_buf(b, &p->repoid, sizeof(p->repoid));
        io_read_buf(b, &p->talid, sizeof(p->talid));
+       io_read_buf(b, &p->certid, sizeof(p->certid));
        io_read_str(b, &p->path);
 
        io_read_str(b, &p->aia);
index f482d67..98b1eac 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parser.c,v 1.135 2024/04/21 19:27:44 claudio Exp $ */
+/*     $OpenBSD: parser.c,v 1.136 2024/05/20 15:51:43 claudio Exp $ */
 /*
  * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -86,6 +86,39 @@ repo_add(unsigned int id, char *path, char *validpath)
                errx(1, "repository already added: id %d, %s", id, path);
 }
 
+/*
+ * Return the issuer by its certificate id, or NULL on failure.
+ * Make sure the AKI is the same as the AKI listed on the Manifest,
+ * and that the SKI of the cert matches with the AKI.
+ */
+static struct auth *
+find_issuer(const char *fn, int id, const char *aki, const char *mftaki)
+{
+       struct auth *a;
+
+       a = auth_find(&auths, id);
+       if (a == NULL) {
+               warnx("%s: RFC 6487: unknown cert with SKI %s", fn, aki);
+               return NULL;
+       }
+
+       if (mftaki != NULL) {
+               if (strcmp(aki, mftaki) != 0) {
+                       warnx("%s: AKI %s doesn't match Manifest AKI %s", fn,
+                           aki, mftaki);
+                       return NULL;
+               }
+       }
+
+       if (strcmp(aki, a->cert->ski) != 0) {
+               warnx("%s: AKI %s doesn't match issuer SKI %s", fn,
+                   aki, a->cert->ski);
+               return NULL;
+       }
+
+       return a;
+}
+
 /*
  * Build access path to file based on repoid, path, location and file values.
  */
@@ -137,7 +170,7 @@ proc_parser_roa(char *file, const unsigned char *der, size_t len,
        if ((roa = roa_parse(&x509, file, entp->talid, der, len)) == NULL)
                return NULL;
 
-       a = valid_ski_aki(file, &auths, roa->ski, roa->aki, entp->mftaki);
+       a = find_issuer(file, entp->certid, roa->aki, entp->mftaki);
        crl = crl_get(&crlt, a);
 
        if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
@@ -172,7 +205,7 @@ proc_parser_spl(char *file, const unsigned char *der, size_t len,
        if ((spl = spl_parse(&x509, file, entp->talid, der, len)) == NULL)
                return NULL;
 
-       a = valid_ski_aki(file, &auths, spl->ski, spl->aki, entp->mftaki);
+       a = find_issuer(file, entp->certid, spl->aki, entp->mftaki);
        crl = crl_get(&crlt, a);
 
        if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
@@ -336,7 +369,7 @@ proc_parser_mft_pre(struct entity *entp, char *file, struct crl **crl,
        if (*crl == NULL)
                *crl = parse_load_crl_from_mft(entp, mft, DIR_VALID, crlfile);
 
-       a = valid_ski_aki(file, &auths, mft->ski, mft->aki, NULL);
+       a = find_issuer(file, entp->certid, mft->aki, NULL);
        if (!valid_x509(file, ctx, x509, a, *crl, errstr))
                goto err;
        X509_free(x509);
@@ -344,6 +377,7 @@ proc_parser_mft_pre(struct entity *entp, char *file, struct crl **crl,
 
        mft->repoid = entp->repoid;
        mft->talid = a->cert->talid;
+       mft->certid = entp->certid;
 
        now = get_current_time();
        /* check that now is not before from */
@@ -493,7 +527,7 @@ proc_parser_mft(struct entity *entp, struct mft **mp, char **crlfile,
  */
 static struct cert *
 proc_parser_cert(char *file, const unsigned char *der, size_t len,
-    const char *mftaki)
+    const struct entity *entp)
 {
        struct cert     *cert;
        struct crl      *crl;
@@ -507,7 +541,7 @@ proc_parser_cert(char *file, const unsigned char *der, size_t len,
        if (cert == NULL)
                return NULL;
 
-       a = valid_ski_aki(file, &auths, cert->ski, cert->aki, mftaki);
+       a = find_issuer(file, entp->certid, cert->aki, entp->mftaki);
        crl = crl_get(&crlt, a);
 
        if (!valid_x509(file, ctx, cert->x509, a, crl, &errstr) ||
@@ -531,7 +565,7 @@ proc_parser_cert(char *file, const unsigned char *der, size_t len,
         * Add validated CA certs to the RPKI auth tree.
         */
        if (cert->purpose == CERT_PURPOSE_CA)
-               auth_insert(&auths, cert, a);
+               auth_insert(file, &auths, cert, a);
 
        return cert;
 }
@@ -557,19 +591,12 @@ proc_parser_root_cert(char *file, const unsigned char *der, size_t len,
        cert = ta_parse(file, cert, pkey, pkeysz);
        if (cert == NULL)
                return NULL;
-
-       if (!valid_ta(file, &auths, cert)) {
-               warnx("%s: certificate not a valid ta", file);
-               cert_free(cert);
-               return NULL;
-       }
-
        cert->talid = talid;
 
        /*
         * Add valid roots to the RPKI auth tree.
         */
-       auth_insert(&auths, cert, NULL);
+       auth_insert(file, &auths, cert, NULL);
 
        return cert;
 }
@@ -590,7 +617,7 @@ proc_parser_gbr(char *file, const unsigned char *der, size_t len,
        if ((gbr = gbr_parse(&x509, file, entp->talid, der, len)) == NULL)
                return NULL;
 
-       a = valid_ski_aki(file, &auths, gbr->ski, gbr->aki, entp->mftaki);
+       a = find_issuer(file, entp->certid, gbr->aki, entp->mftaki);
        crl = crl_get(&crlt, a);
 
        /* return value can be ignored since nothing happens here */
@@ -623,7 +650,7 @@ proc_parser_aspa(char *file, const unsigned char *der, size_t len,
        if ((aspa = aspa_parse(&x509, file, entp->talid, der, len)) == NULL)
                return NULL;
 
-       a = valid_ski_aki(file, &auths, aspa->ski, aspa->aki, entp->mftaki);
+       a = find_issuer(file, entp->certid, aspa->aki, entp->mftaki);
        crl = crl_get(&crlt, a);
 
        if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
@@ -658,7 +685,7 @@ proc_parser_tak(char *file, const unsigned char *der, size_t len,
        if ((tak = tak_parse(&x509, file, entp->talid, der, len)) == NULL)
                return NULL;
 
-       a = valid_ski_aki(file, &auths, tak->ski, tak->aki, entp->mftaki);
+       a = find_issuer(file, entp->certid, tak->aki, entp->mftaki);
        crl = crl_get(&crlt, a);
 
        if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
@@ -764,8 +791,7 @@ parse_entity(struct entityq *q, struct msgbuf *msgq)
                                    f, flen, entp->data, entp->datasz,
                                    entp->talid);
                        else
-                               cert = proc_parser_cert(file, f, flen,
-                                   entp->mftaki);
+                               cert = proc_parser_cert(file, f, flen, entp);
                        if (cert != NULL)
                                mtime = cert->notbefore;
                        io_simple_buffer(b, &mtime, sizeof(mtime));
index 14ea81d..43432cf 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: repo.c,v 1.57 2024/04/21 19:27:44 claudio Exp $ */
+/*     $OpenBSD: repo.c,v 1.58 2024/05/20 15:51:43 claudio Exp $ */
 /*
  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -116,13 +116,14 @@ static void                remove_contents(char *);
  * Database of all file path accessed during a run.
  */
 struct filepath {
-       RB_ENTRY(filepath)      entry;
+       RB_ENTRY(filepath)       entry;
        char                    *file;
        time_t                   mtime;
+       unsigned int             talmask;
 };
 
 static inline int
-filepathcmp(struct filepath *a, struct filepath *b)
+filepathcmp(const struct filepath *a, const struct filepath *b)
 {
        return strcmp(a->file, b->file);
 }
@@ -133,22 +134,28 @@ RB_PROTOTYPE(filepath_tree, filepath, entry, filepathcmp);
  * Functions to lookup which files have been accessed during computation.
  */
 int
-filepath_add(struct filepath_tree *tree, char *file, time_t mtime)
+filepath_add(struct filepath_tree *tree, char *file, int id, time_t mtime)
 {
-       struct filepath *fp;
+       struct filepath *fp, *rfp;
+
+       CTASSERT(TALSZ_MAX < 8 * sizeof(fp->talmask));
+       assert(id >= 0 && id < 8 * (int)sizeof(fp->talmask));
 
-       if ((fp = malloc(sizeof(*fp))) == NULL)
+       if ((fp = calloc(1, sizeof(*fp))) == NULL)
                err(1, NULL);
-       fp->mtime = mtime;
        if ((fp->file = strdup(file)) == NULL)
                err(1, NULL);
+       fp->mtime = mtime;
 
-       if (RB_INSERT(filepath_tree, tree, fp) != NULL) {
+       if ((rfp = RB_INSERT(filepath_tree, tree, fp)) != NULL) {
                /* already in the tree */
                free(fp->file);
                free(fp);
-               return 0;
+               if (rfp->talmask & (1 << id))
+                       return 0;
+               fp = rfp;
        }
+       fp->talmask |= (1 << id);
 
        return 1;
 }
@@ -906,7 +913,7 @@ rrdp_handle_file(unsigned int id, enum publish_type pt, char *uri,
 
        /* write new content or mark uri as deleted. */
        if (pt == PUB_DEL) {
-               filepath_add(&rr->deleted, uri, 0);
+               filepath_add(&rr->deleted, uri, 0, 0);
        } else {
                fp = filepath_find(&rr->deleted, uri);
                if (fp != NULL) {
index 73cf42e..f66518a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: validate.c,v 1.73 2024/03/19 05:04:13 tb Exp $ */
+/*     $OpenBSD: validate.c,v 1.74 2024/05/20 15:51:43 claudio Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -79,52 +79,6 @@ valid_ip(struct auth *a, enum afi afi,
        return valid_ip(a->issuer, afi, min, max);
 }
 
-/*
- * Make sure the AKI is the same as the AKI listed on the Manifest,
- * and that the SKI doesn't already exist.
- * Return the issuer by its AKI, or NULL on failure.
- */
-struct auth *
-valid_ski_aki(const char *fn, struct auth_tree *auths,
-    const char *ski, const char *aki, const char *mftaki)
-{
-       struct auth *a;
-
-       if (mftaki != NULL) {
-               if (strcmp(aki, mftaki) != 0) {
-                       warnx("%s: AKI doesn't match Manifest AKI", fn);
-                       return NULL;
-               }
-       }
-
-       if (auth_find(auths, ski) != NULL) {
-               warnx("%s: RFC 6487: duplicate SKI", fn);
-               return NULL;
-       }
-
-       a = auth_find(auths, aki);
-       if (a == NULL)
-               warnx("%s: RFC 6487: unknown AKI", fn);
-
-       return a;
-}
-
-/*
- * Validate a trust anchor by making sure that the SKI is unique.
- * Returns 1 if valid, 0 otherwise.
- */
-int
-valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert)
-{
-       /* SKI must not be a dupe. */
-       if (auth_find(auths, cert->ski) != NULL) {
-               warnx("%s: RFC 6487: duplicate SKI", fn);
-               return 0;
-       }
-
-       return 1;
-}
-
 /*
  * Validate a non-TA certificate: make sure its IP and AS resources are
  * fully covered by those in the authority key (which must exist).