Index | Thread | Search

From:
Theo Buehler <tb@theobuehler.org>
Subject:
rpki-client: rework handling of expiry
To:
tech@openbsd.org
Date:
Tue, 6 Oct 2026 12:11:43 +0200

Download raw body.

Thread
  • Theo Buehler:

    rpki-client: rework handling of expiry

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;
 }