Index | Thread | Search

From:
Theo Buehler <tb@theobuehler.org>
Subject:
rpki-client: allow UTF8String for BGPsec router cert subjects
To:
tech@openbsd.org
Date:
Tue, 18 Nov 2025 12:22:53 +0100

Download raw body.

Thread
The diff below allows BGPsec router certs to have a UTF8String in
their subject's commonName, making sure we won't reject those once we
enable the check for the PrintableString type. Since no certs with
UTF8String currently exist, I'm not keen on adding additional checks, a
few possibilities are listed in a comment.

Index: cert.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
diff -u -p -r1.206 cert.c
--- cert.c	16 Oct 2025 06:46:31 -0000	1.206
+++ cert.c	18 Nov 2025 10:54:55 -0000
@@ -227,14 +227,14 @@ cert_check_subject_and_issuer(const char
 		warnx("%s: X509_get_subject_name", fn);
 		return 0;
 	}
-	if (!x509_valid_name(fn, "subject", name))
+	if (!x509_valid_cert_subject(fn, name, cert->purpose))
 		return 0;
 
 	if ((name = X509_get_issuer_name(cert->x509)) == NULL) {
 		warnx("%s: X509_get_issuer_name", fn);
 		return 0;
 	}
-	if (!x509_valid_name(fn, "issuer", name))
+	if (!x509_valid_issuer(fn, name))
 		return 0;
 
 	return 1;
Index: crl.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/crl.c,v
diff -u -p -r1.50 crl.c
--- crl.c	8 Jul 2025 13:25:54 -0000	1.50
+++ crl.c	18 Nov 2025 10:54:55 -0000
@@ -234,7 +234,7 @@ crl_parse(const char *fn, const unsigned
 		warnx("%s: X509_CRL_get_issuer", fn);
 		goto out;
 	}
-	if (!x509_valid_name(fn, "issuer", name))
+	if (!x509_valid_issuer(fn, name))
 		goto out;
 
 	if (!crl_check_sigalg(fn, crl))
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
diff -u -p -r1.267 extern.h
--- extern.h	13 Nov 2025 15:18:53 -0000	1.267
+++ extern.h	18 Nov 2025 10:54:55 -0000
@@ -981,7 +981,9 @@ int		 x509_location(const char *, const 
 		    char **);
 int		 x509_inherits(X509 *);
 int		 x509_any_inherits(X509 *);
-int		 x509_valid_name(const char *, const char *, const X509_NAME *);
+int		 x509_valid_cert_subject(const char *, const X509_NAME *,
+		    enum cert_purpose);
+int		 x509_valid_issuer(const char *, const X509_NAME *);
 time_t		 x509_find_expires(time_t, struct auth *, struct crl_tree *);
 
 /* printers */
Index: x509.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/x509.c,v
diff -u -p -r1.122 x509.c
--- x509.c	18 Nov 2025 09:18:20 -0000	1.122
+++ x509.c	18 Nov 2025 10:54:55 -0000
@@ -403,8 +403,9 @@ valid_printable_string(const char *fn, c
  * Check that subject or issuer only contain commonName and serialNumber.
  * Return 0 on failure.
  */
-int
-x509_valid_name(const char *fn, const char *descr, const X509_NAME *xn)
+static int
+x509_valid_name_internal(const char *fn, const char *descr, const X509_NAME *xn,
+    int allow_utf8)
 {
 	const X509_NAME_ENTRY *ne;
 	const ASN1_OBJECT *ao;
@@ -435,10 +436,14 @@ x509_valid_name(const char *fn, const ch
 				    fn);
 				return 0;
 			}
-			/*
-			 * XXX - For some reason RFC 8209, section 3.1.1 decided
-			 * to allow UTF8String for BGPsec Router Certificates.
-			 */
+			if (allow_utf8 && as->type == V_ASN1_UTF8STRING) {
+				/*
+				 * XXX - What to check here? No embedded NUL?
+				 * Actually attempt to validate UTF-8? Insist
+				 * on printable string alphabet?
+				 */
+				continue;
+			}
 			if (!valid_printable_string(fn, descr, as))
 				return 0;
 			break;
@@ -466,6 +471,25 @@ x509_valid_name(const char *fn, const ch
 	}
 
 	return 1;
+}
+
+int
+x509_valid_cert_subject(const char *fn, const X509_NAME *xn,
+    enum cert_purpose purpose)
+{
+	/*
+	 * For some reason RFC 8209, section 3.1.1 decided to allow UTF8String
+	 * for the subject of BGPsec Router Certificates, although RECOMMENDED
+	 * contents fit in a PrintableString.
+	 */
+	return x509_valid_name_internal(fn, "subject", xn,
+	    purpose == CERT_PURPOSE_BGPSEC_ROUTER);
+}
+
+int
+x509_valid_issuer(const char *fn, const X509_NAME *xn)
+{
+	return x509_valid_name_internal(fn, "issuer", xn, 0);
 }
 
 /*