This adds another compliance check for the X.509 subject name. Only commonName, and optionally serialNumber, are permitted in the certificate subject name. See RFC 6487 section 4.4 and 4.5.
It seems the one CA who was not compliant with this requirement got their act together, so now is an opportune time to get this in. OK? Index: cert.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v retrieving revision 1.114 diff -u -p -r1.114 cert.c --- cert.c 29 Jun 2023 10:28:25 -0000 1.114 +++ cert.c 9 Jul 2023 13:38:02 -0000 @@ -595,14 +595,13 @@ certificate_policies(struct parse *p, X5 /* * Lightweight version of cert_parse_pre() for ASPA, ROA, and RSC EE certs. - * This only parses the RFC 3779 extensions since these are necessary for - * validation. * Returns cert on success and NULL on failure. */ struct cert * cert_parse_ee_cert(const char *fn, X509 *x) { struct parse p; + X509_NAME *xn; X509_EXTENSION *ext; int index; @@ -616,6 +615,13 @@ cert_parse_ee_cert(const char *fn, X509 goto out; } + if ((xn = X509_get_subject_name(x)) == NULL) { + warnx("%s: X509_get_subject_name", fn); + goto out; + } + if (!x509_valid_subject(fn, xn)) + goto out; + if (X509_get_key_usage(x) != KU_DIGITAL_SIGNATURE) { warnx("%s: RFC 6487 section 4.8.4: KU must be digitalSignature", fn); @@ -669,6 +675,7 @@ cert_parse_pre(const char *fn, const uns const X509_ALGOR *palg; const ASN1_BIT_STRING *piuid = NULL, *psuid = NULL; const ASN1_OBJECT *cobj; + const X509_NAME *xn; ASN1_OBJECT *obj; EVP_PKEY *pkey; struct parse p; @@ -726,6 +733,13 @@ cert_parse_pre(const char *fn, const uns fn); goto out; } + + if ((xn = X509_get_subject_name(x)) == NULL) { + warnx("%s: X509_get_subject_name", p.fn); + goto out; + } + if (!x509_valid_subject(p.fn, xn)) + goto out; /* Look for X509v3 extensions. */ Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v retrieving revision 1.188 diff -u -p -r1.188 extern.h --- extern.h 29 Jun 2023 14:33:35 -0000 1.188 +++ extern.h 9 Jul 2023 13:38:02 -0000 @@ -839,6 +839,7 @@ int x509_location(const char *, const GENERAL_NAME *, char **); int x509_inherits(X509 *); int x509_any_inherits(X509 *); +int x509_valid_subject(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 retrieving revision 1.73 diff -u -p -r1.73 x509.c --- x509.c 23 Jun 2023 15:32:15 -0000 1.73 +++ x509.c 9 Jul 2023 13:38:02 -0000 @@ -861,6 +861,80 @@ x509_location(const char *fn, const char } /* + * Check that the subject only contains commonName and serialNumber. + * Return 0 on failure. + */ +int +x509_valid_subject(const char *fn, const X509_NAME *xn) +{ + X509_NAME_ENTRY *ne; + ASN1_OBJECT *ao; + ASN1_STRING *as; + int cn = 0, sn = 0; + int i, nid; + + for (i = 0; i < X509_NAME_entry_count(xn); i++) { + if ((ne = X509_NAME_get_entry(xn, i)) == NULL) { + warnx("%s: X509_NAME_get_entry", fn); + return 0; + } + if ((ao = X509_NAME_ENTRY_get_object(ne)) == NULL) { + warnx("%s: X509_NAME_ENTRY_get_object", fn); + return 0; + } + + nid = OBJ_obj2nid(ao); + switch (nid) { + case NID_commonName: + if (cn++ > 0) { + warnx("%s: duplicate commonName in subject", + fn); + return 0; + } + if ((as = X509_NAME_ENTRY_get_data(ne)) == NULL) { + warnx("%s: X509_NAME_ENTRY_get_data failed", + fn); + return 0; + } +/* + * The following check can be enabled after AFRINIC re-issues CA certs. + * https://lists.afrinic.net/pipermail/dbwg/2023-March/000436.html + */ +#if 0 + if (as->type != V_ASN1_PRINTABLESTRING) { + warnx("%s: RFC 6487 section 4.5: commonName is" + " not PrintableString", fn); + return 0; + } +#endif + break; + case NID_serialNumber: + if (sn++ > 0) { + warnx("%s: duplicate serialNumber in subject", + fn); + return 0; + } + break; + case NID_undef: + warnx("%s: OBJ_obj2nid failed", fn); + return 0; + default: + warnx("%s: RFC 6487 section 4.5: invalid attribute " + "(NID: %d)", fn, nid); + return 0; + } + } + + if (!cn) { + warnx("%s: RFC 6487 section 4.5: subject missing commonName", + fn); + return 0; + } + + return 1; +} + +/* * Convert an ASN1_INTEGER into a hexstring. * Returned string needs to be freed by the caller. */