From: Theo Buehler Subject: rpki-client: rework handling of expiry To: tech@openbsd.org Date: Tue, 6 Oct 2026 12:11:43 +0200 The cert->expires field was added as a hack for filemode. We can use it in normal mode and avoid some lock contention on the CRL tree. On insertion of a CA cert, we can calculate its expiry time and use that and the CRL's notafter to determine the one of all signed objects. This way x509_find_expires() can run without locks and without need to walk up the full chain while looking up the same CRLs over and over again. For TAs the expiry will be the notAfter, and intermediate CAs will use the minimum of their notAfter, the expiry moment of their issuer and the relevant CRL's nextupdate. Similarly for signed objects. The handling of the BRK's expiry in the BRK tree doesn't seem right either. I think they should use the the expiry of the entire validating chain rather than their notAfter. That needs some fiddling left for a follow-up. Index: cert.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v diff -u -p -r1.244 cert.c --- cert.c 13 Jul 2026 10:53:12 -0000 1.244 +++ cert.c 6 Oct 2026 09:58:03 -0000 @@ -1983,10 +1983,12 @@ auth_find(struct auth_tree *auths, int i struct auth * auth_insert(const char *fn, struct auth_tree *auths, struct cert *cert, - struct auth *issuer) + struct auth *issuer, struct crl *crl) { struct auth *na; int error; + + cert->expires = x509_find_expires(cert->notafter, issuer, crl); na = calloc(1, sizeof(*na)); if (na == NULL) Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v diff -u -p -r1.301 extern.h --- extern.h 6 Oct 2026 06:55:41 -0000 1.301 +++ extern.h 6 Oct 2026 09:58:03 -0000 @@ -573,7 +573,7 @@ RB_HEAD(auth_tree, auth); struct auth *auth_find(struct auth_tree *, int); struct auth *auth_insert(const char *, struct auth_tree *, struct cert *, - struct auth *); + struct auth *, struct crl *); enum http_result { HTTP_FAILED, /* anything else */ @@ -1005,7 +1005,7 @@ int x509_inherits(X509 *); int x509_any_inherits(X509 *); int x509_valid_subject_name(const char *, const X509_NAME *); int x509_valid_issuer_name(const char *, const X509_NAME *); -time_t x509_find_expires(time_t, struct auth *, struct crl_tree *); +time_t x509_find_expires(time_t, struct auth *, struct crl *); /* printers */ char *nid2str(int); Index: filemode.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v diff -u -p -r1.91 filemode.c --- filemode.c 24 Sep 2026 14:44:03 -0000 1.91 +++ filemode.c 6 Oct 2026 09:58:03 -0000 @@ -230,7 +230,7 @@ parse_load_certchain(char *uri) goto fail; } cert->talid = a->cert->talid; - a = auth_insert(uri, &auths, cert, a); + a = auth_insert(uri, &auths, cert, a, crl); uripath_add(uri, cert); stack[i - 1] = NULL; } @@ -270,7 +270,7 @@ parse_load_ta(struct tal *tal) goto out; cert->talid = tal->id; - auth_insert(file, &auths, cert, NULL); + auth_insert(file, &auths, cert, NULL, NULL); for (i = 0; i < tal->num_uris; i++) { if (strncasecmp(tal->uri[i], RSYNC_PROTO, RSYNC_PROTO_LEN) != 0) continue; @@ -434,7 +434,7 @@ proc_parser_file(char *file, unsigned ch time_t *notbefore = NULL, *expires = NULL, *notafter = NULL; time_t now; struct auth *a = NULL; - struct crl *c; + struct crl *c = NULL; const char *errstr = NULL, *valid; int status = 0; char filehash[SHA256_DIGEST_LENGTH]; @@ -645,7 +645,7 @@ proc_parser_file(char *file, unsigned ch if (expires != NULL) { if ((status && aia != NULL) || is_ta) - *expires = x509_find_expires(*notafter, a, &crls); + *expires = x509_find_expires(*notafter, a, c); switch (type) { case RTYPE_ASPA: Index: parser.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v diff -u -p -r1.189 parser.c --- parser.c 24 Sep 2026 14:44:03 -0000 1.189 +++ parser.c 6 Oct 2026 09:58:03 -0000 @@ -227,7 +227,7 @@ proc_parser_roa(char *file, const unsign roa->talid = a->cert->talid; - roa->expires = x509_find_expires(cert->notafter, a, &crls); + roa->expires = x509_find_expires(cert->notafter, a, crl); cert_free(cert); return roa; @@ -269,7 +269,7 @@ proc_parser_spl(char *file, const unsign spl->talid = a->cert->talid; - spl->expires = x509_find_expires(cert->notafter, a, &crls); + spl->expires = x509_find_expires(cert->notafter, a, crl); cert_free(cert); return spl; @@ -653,7 +653,7 @@ proc_parser_cert(char *file, const unsig errx(1, "%s: corrupted entity", file); memcpy(cert->mfthash, entp->data, entp->datasz); - auth_insert(file, &auths, cert, a); + auth_insert(file, &auths, cert, a, crl); } return cert; @@ -742,7 +742,7 @@ proc_parser_root_cert(struct entity *ent free(file2); cert1->talid = entp->talid; - auth_insert(file1, &auths, cert1, NULL); + auth_insert(file1, &auths, cert1, NULL, NULL); *out_cert = cert1; return file1; @@ -756,7 +756,7 @@ proc_parser_root_cert(struct entity *ent cert2->talid = entp->talid; if ((cert2->path = strdup(file2)) == NULL) err(1, NULL); - auth_insert(file2, &auths, cert2, NULL); + auth_insert(file2, &auths, cert2, NULL, NULL); } *out_cert = cert2; @@ -793,7 +793,7 @@ proc_parser_aspa(char *file, const unsig aspa->talid = a->cert->talid; - aspa->expires = x509_find_expires(cert->notafter, a, &crls); + aspa->expires = x509_find_expires(cert->notafter, a, crl); cert_free(cert); return aspa; @@ -838,7 +838,7 @@ proc_parser_tak(char *file, const unsign tak->talid = a->cert->talid; - tak->expires = x509_find_expires(cert->notafter, a, &crls); + tak->expires = x509_find_expires(cert->notafter, a, crl); cert_free(cert); return tak; Index: x509.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/x509.c,v diff -u -p -r1.135 x509.c --- x509.c 20 Sep 2026 20:04:03 -0000 1.135 +++ x509.c 6 Oct 2026 09:58:03 -0000 @@ -604,20 +604,15 @@ x509_check_tbs_sigalg(const char *fn, co * Find the closest expiry moment by walking the chain of authorities. */ time_t -x509_find_expires(time_t notafter, struct auth *a, struct crl_tree *crls) +x509_find_expires(time_t notafter, struct auth *a, struct crl *crl) { - struct crl *crl; time_t expires; expires = notafter; - - for (; a != NULL; a = a->issuer) { - if (expires > a->cert->notafter) - expires = a->cert->notafter; - crl = crl_get(crls, a); - if (crl != NULL && expires > crl->nextupdate) - expires = crl->nextupdate; - } + if (a != NULL && expires > a->cert->expires) + expires = a->cert->expires; + if (crl != NULL && expires > crl->nextupdate) + expires = crl->nextupdate; return expires; }