From: Claudio Jeker Subject: Re: rpki-client: split a few things out of ta_parse() To: Theo Buehler Cc: tech@openbsd.org Date: Mon, 19 Jan 2026 10:37:40 +0100 On Mon, Jan 19, 2026 at 08:47:54AM +0100, Theo Buehler wrote: > This pulls the non-inheritance check for TAs into cert_parse_extensions() > and adds a check that the INRs are a non-empty set. The latter is redundant > with existing checks for presence of at least one of ASIdentifiers and > IPAddrBlocks combined with non-inheritance but it does not hurt to be > explicit. > > The second change is splitting everything to do with the SPKI into a > helper since the current logic is messy and has completely unrelated > things interleaved. In a follow-up I'll also split out the validity > check. Later on ta_parse() will be renamed into something more > appropriate. OK claudio@ I wonder if the XXX in the ta_parse() comment is really needed. I understand that this no longer does a real parse but either we just rename the function (ta_check, ta_validate) or keep ta_parse and just drop the XXX. I guess you already have something in mind for this :) > Index: cert.c > =================================================================== > RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v > diff -u -p -r1.210 cert.c > --- cert.c 13 Jan 2026 21:36:17 -0000 1.210 > +++ cert.c 14 Jan 2026 20:11:20 -0000 > @@ -1738,6 +1738,19 @@ cert_parse_extensions(const char *fn, st > goto out; > } > > + if (cert->purpose == CERT_PURPOSE_TA) { > + if (x509_any_inherits(cert->x509)) { > + warnx("%s: RFC 8630, 2.3: Trust Anchor INRs " > + "must not inherit", fn); > + goto out; > + } > + if (cert->num_ips == 0 && cert->num_ases == 0) { > + warnx("%s: RFC 8630, 2.3: Trust Anchor INR set " > + "must not be empty", fn); > + goto out; > + } > + } > + > if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) { > if (ip != 0) { > warnx("%s: RFC 8209, 3.1.3.4: BGPsec Router cert " > @@ -1915,15 +1928,17 @@ cert_parse(const char *fn, const unsigne > return NULL; > } > > -struct cert * > -ta_parse(const char *fn, struct cert *p, const unsigned char *pkey, > +/* > + * Check that the subjectPublicKeyInfo from the TAL matches the one in the cert. > + * Verify that this key signed the cert. > + * Returns 1 on success and 0 on failure. > + */ > +static int > +ta_check_pubkey(const char *fn, struct cert *cert, const unsigned char *pkey, > size_t pkeysz) > { > EVP_PKEY *pk, *opk; > - time_t now = get_current_time(); > - > - if (p == NULL) > - return NULL; > + int rv = 0; > > /* first check pubkey against the one from the TAL */ > pk = d2i_PUBKEY(NULL, &pkey, pkeysz); > @@ -1931,7 +1946,7 @@ ta_parse(const char *fn, struct cert *p, > warnx("%s: RFC 6487 (trust anchor): bad TAL pubkey", fn); > goto badcert; > } > - if ((opk = X509_get0_pubkey(p->x509)) == NULL) { > + if ((opk = X509_get0_pubkey(cert->x509)) == NULL) { > warnx("%s: RFC 6487 (trust anchor): missing pubkey", fn); > goto badcert; > } > @@ -1941,37 +1956,52 @@ ta_parse(const char *fn, struct cert *p, > goto badcert; > } > > - if (p->notbefore > now) { > - warnx("%s: certificate not yet valid", fn); > - goto badcert; > - } > - if (p->notafter < now) { > - warnx("%s: certificate has expired", fn); > + /* > + * Do not replace with a <= 0 check since OpenSSL 3 broke that: > + * https://github.com/openssl/openssl/issues/24575 > + */ > + if (X509_verify(cert->x509, pk) != 1) { > + warnx("%s: failed to verify signature", fn); > goto badcert; > } > + > + rv = 1; > + badcert: > + EVP_PKEY_free(pk); > + return rv; > +} > + > +/* XXX - this really doesn't parse anything except the SPKI in the TAL. */ > +struct cert * > +ta_parse(const char *fn, struct cert *p, const unsigned char *pkey, > + size_t pkeysz) > +{ > + time_t now = get_current_time(); > + > + if (p == NULL) > + return NULL; > + > if (p->purpose != CERT_PURPOSE_TA) { > warnx("%s: expected trust anchor purpose, got %s", fn, > purpose2str(p->purpose)); > goto badcert; > } > - /* > - * Do not replace with a <= 0 check since OpenSSL 3 broke that: > - * https://github.com/openssl/openssl/issues/24575 > - */ > - if (X509_verify(p->x509, pk) != 1) { > - warnx("%s: failed to verify signature", fn); > + > + if (!ta_check_pubkey(fn, p, pkey, pkeysz)) > + goto badcert; > + > + if (p->notbefore > now) { > + warnx("%s: certificate not yet valid", fn); > goto badcert; > } > - if (x509_any_inherits(p->x509)) { > - warnx("%s: Trust anchor IP/AS resources may not inherit", fn); > + if (p->notafter < now) { > + warnx("%s: certificate has expired", fn); > goto badcert; > } > > - EVP_PKEY_free(pk); > return p; > > badcert: > - EVP_PKEY_free(pk); > cert_free(p); > return NULL; > } > -- :wq Claudio