From: Claudio Jeker Subject: rework rpki-client certificate discovery To: tech@openbsd.org Date: Wed, 15 May 2024 17:04:57 +0200 In rpki-client we use the SKI / AKI to find the signing certificate and build the validation stack based on this data. The problem is that the SKI is not strictly unique and for example the NRO TAL abuses this. Instead of indexing certs by SKI we now use a unique per certificate id which is then passed back and forth between main process and the parser. This way we never lose track on the cert that signed the current object and can look that one up via its id. This allows for multiple validation paths to co-exist. Now on top of this the filepath_add() api had to be extended since we now allow a file to be visited more then once as long as it is reached by a different TAL. Inside the same TAL an object can not be revisited. Last but not least the filemode had to be adjusted, now the code keeps track of the various AIA uri and uses an own rb tree to look them up. Once there is a hit the stack can be unrolled like before and all new certs are added to both the auth and the uripath trees. More cleanup needs to follow (I'm looking at you valid_aki_ski()) This was developped together with tb@ at a femto-hackathon. -- :wq Claudio Index: cert.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v diff -u -p -r1.130 cert.c --- cert.c 21 Apr 2024 19:27:44 -0000 1.130 +++ cert.c 15 May 2024 13:43:14 -0000 @@ -34,6 +34,8 @@ extern ASN1_OBJECT *carepo_oid; /* 1.3.6 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 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) + err(1, "%s: too many certificates", fn); + na->depth = issuer->depth + 1; + } + + if (na->depth >= MAX_CERT_DEPTH) { + warnx("%s: stack 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: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v diff -u -p -r1.217 extern.h --- extern.h 21 Apr 2024 19:27:44 -0000 1.217 +++ extern.h 15 May 2024 14:41:35 -0000 @@ -24,6 +24,9 @@ #include #include +#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,8 @@ void crl_tree_free(struct crl_tree *); /* Validation of our objects. */ -struct auth *valid_ski_aki(const char *, struct auth_tree *, +struct auth *valid_ski_aki(const char *, struct auth_tree *, int, 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 +832,7 @@ void proc_http(char *, int) __attribut 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 +987,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: filemode.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v diff -u -p -r1.41 filemode.c --- filemode.c 21 Apr 2024 19:27:44 -0000 1.41 +++ filemode.c 15 May 2024 14:42:41 -0000 @@ -47,6 +47,50 @@ static struct crl_tree crlt = RB_INITIA 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"); - goto fail; - } - if (auth_find(&auths, cert->ski) != NULL) { - assert(i == 0); + warnx("failed to build authority chain: %s", uri); 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 use 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 ch 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 ch 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 ch 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 ch 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 ch 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 ch 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 ch 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 ch 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 ch 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 ch 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 ch 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: main.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v diff -u -p -r1.257 main.c --- main.c 8 Apr 2024 14:02:13 -0000 1.257 +++ main.c 14 May 2024 14:58:48 -0000 @@ -156,6 +156,7 @@ entity_read_req(struct ibuf *b, struct e 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 *en 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 */ 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 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 rt 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 *c } 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 st 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: mft.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v diff -u -p -r1.113 mft.c --- mft.c 20 Apr 2024 15:45:41 -0000 1.113 +++ mft.c 14 May 2024 13:47:40 -0000 @@ -537,6 +537,7 @@ mft_buffer(struct ibuf *b, const struct 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: parser.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v diff -u -p -r1.135 parser.c --- parser.c 21 Apr 2024 19:27:44 -0000 1.135 +++ parser.c 15 May 2024 10:23:45 -0000 @@ -137,7 +137,8 @@ proc_parser_roa(char *file, const unsign 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 = valid_ski_aki(file, &auths, entp->certid, roa->ski, roa->aki, + entp->mftaki); crl = crl_get(&crlt, a); if (!valid_x509(file, ctx, x509, a, crl, &errstr)) { @@ -172,7 +173,8 @@ proc_parser_spl(char *file, const unsign 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 = valid_ski_aki(file, &auths, entp->certid, spl->ski, spl->aki, + entp->mftaki); crl = crl_get(&crlt, a); if (!valid_x509(file, ctx, x509, a, crl, &errstr)) { @@ -336,7 +338,7 @@ proc_parser_mft_pre(struct entity *entp, 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 = valid_ski_aki(file, &auths, entp->certid, mft->ski, mft->aki, NULL); if (!valid_x509(file, ctx, x509, a, *crl, errstr)) goto err; X509_free(x509); @@ -344,6 +346,7 @@ proc_parser_mft_pre(struct entity *entp, 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 +496,7 @@ proc_parser_mft(struct entity *entp, str */ 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 +510,8 @@ proc_parser_cert(char *file, const unsig if (cert == NULL) return NULL; - a = valid_ski_aki(file, &auths, cert->ski, cert->aki, mftaki); + a = valid_ski_aki(file, &auths, entp->certid, cert->ski, cert->aki, + entp->mftaki); crl = crl_get(&crlt, a); if (!valid_x509(file, ctx, cert->x509, a, crl, &errstr) || @@ -531,7 +535,7 @@ proc_parser_cert(char *file, const unsig * 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 +561,12 @@ proc_parser_root_cert(char *file, const 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 +587,8 @@ proc_parser_gbr(char *file, const unsign 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 = valid_ski_aki(file, &auths, entp->certid, gbr->ski, gbr->aki, + entp->mftaki); crl = crl_get(&crlt, a); /* return value can be ignored since nothing happens here */ @@ -623,7 +621,8 @@ proc_parser_aspa(char *file, const unsig 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 = valid_ski_aki(file, &auths, entp->certid, aspa->ski, aspa->aki, + entp->mftaki); crl = crl_get(&crlt, a); if (!valid_x509(file, ctx, x509, a, crl, &errstr)) { @@ -658,7 +657,8 @@ proc_parser_tak(char *file, const unsign 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 = valid_ski_aki(file, &auths, entp->certid, tak->ski, tak->aki, + entp->mftaki); crl = crl_get(&crlt, a); if (!valid_x509(file, ctx, x509, a, crl, &errstr)) { @@ -764,8 +764,7 @@ parse_entity(struct entityq *q, struct m 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: repo.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/repo.c,v diff -u -p -r1.57 repo.c --- repo.c 21 Apr 2024 19:27:44 -0000 1.57 +++ repo.c 15 May 2024 14:41:59 -0000 @@ -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, en * 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 p /* 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: validate.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v diff -u -p -r1.73 validate.c --- validate.c 19 Mar 2024 05:04:13 -0000 1.73 +++ validate.c 15 May 2024 12:36:15 -0000 @@ -85,11 +85,12 @@ valid_ip(struct auth *a, enum afi afi, * Return the issuer by its AKI, or NULL on failure. */ struct auth * -valid_ski_aki(const char *fn, struct auth_tree *auths, +valid_ski_aki(const char *fn, struct auth_tree *auths, int id, const char *ski, const char *aki, const char *mftaki) { struct auth *a; + /* XXX - ski is now unused. Inline these functions in parser.c? */ if (mftaki != NULL) { if (strcmp(aki, mftaki) != 0) { warnx("%s: AKI doesn't match Manifest AKI", fn); @@ -97,32 +98,16 @@ valid_ski_aki(const char *fn, struct aut } } - if (auth_find(auths, ski) != NULL) { - warnx("%s: RFC 6487: duplicate SKI", fn); - return NULL; - } - - a = auth_find(auths, aki); + a = auth_find(auths, id); if (a == NULL) - warnx("%s: RFC 6487: unknown AKI", fn); - - return a; -} + warnx("%s: RFC 6487: unknown cert", fn); -/* - * 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; + if (strcmp(aki, a->cert->ski) != 0) { + warnx("%s: AKI doesn't match with cert SKI", fn); + return NULL; } - return 1; + return a; } /*