Index | Thread | Search

From:
Theo Buehler <tb@theobuehler.org>
Subject:
rpki-client: cert_check_purpose tweaks
To:
tech@openbsd.org
Date:
Thu, 19 Jun 2025 13:50:24 +0200

Download raw body.

Thread
I want the cert->purpose to be already available and valid when parsing
the extensions, so I can branch on that if needed. So hoist the call in
cert_parse_pre() above the extension checking proper and make sure
that cert_check_purpose() prints an error if we don't know what kind
of cert we have. The double warning in cert_parse_ee_cert() isn't new
except for the one warnx() that I added in the cert_check_purpose()
exit path.

Index: cert.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
diff -u -p -r1.163 cert.c
--- cert.c	19 Jun 2025 10:26:34 -0000	1.163
+++ cert.c	19 Jun 2025 11:22:45 -0000
@@ -872,10 +872,13 @@ cert_check_purpose(const char *fn, X509 
 	for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
 		if (OBJ_cmp(bgpsec_oid, sk_ASN1_OBJECT_value(eku, i)) == 0) {
 			purpose = CERT_PURPOSE_BGPSEC_ROUTER;
-			break;
+			goto out;
 		}
 	}
 
+	warnx("%s: unknown certificate purpose", fn);
+	assert(purpose == CERT_PURPOSE_INVALID);
+
  out:
 	BASIC_CONSTRAINTS_free(bc);
 	EXTENDED_KEY_USAGE_free(eku);
@@ -913,6 +916,7 @@ cert_parse_ee_cert(const char *fn, int t
 	 * appropriate for an EE cert. Covers RFC 6487, 4.8.1, 4.8.4, 4.8.5.
 	 */
 	if ((cert->purpose = cert_check_purpose(fn, x)) != CERT_PURPOSE_EE) {
+		/* XXX - double warning */
 		warnx("%s: expected EE cert, got %s", fn,
 		    purpose2str(cert->purpose));
 		goto out;
@@ -1018,6 +1022,13 @@ cert_parse_pre(const char *fn, const uns
 	if (!cert_check_subject_and_issuer(fn, x))
 		goto out;
 
+	/*
+	 * Check issuance, basic constraints and (extended) key usage bits are
+	 * appropriate for a resource cert. Covers RFC 6487 4.8.1, 4.8.4, 4.8.5.
+	 */
+	if ((cert->purpose = cert_check_purpose(fn, x)) == CERT_PURPOSE_INVALID)
+		goto out;
+
 	/* Look for X509v3 extensions. */
 	if ((extsz = X509_get_ext_count(x)) <= 0) {
 		warnx("%s: certificate without X.509v3 extensions", fn);
@@ -1114,7 +1125,6 @@ cert_parse_pre(const char *fn, const uns
 		goto out;
 
 	/* Validation on required fields. */
-	cert->purpose = cert_check_purpose(fn, x);
 	switch (cert->purpose) {
 	case CERT_PURPOSE_TA:
 		/* XXX - caller should indicate if it expects TA or CA cert */