I am trying to verify a PIV certificate from a smart card using a certificate that includes a Name Constraints extension. If I inspect the -text
output everything looks like it should be fine but the two values have different case. Is it possible that OpenSSL is doing a case-sensitive comparison even though rfc5280 indicates that it should be case-insensitive? Here are the relevant text outputs:
Root CA (changed actual values to example
but preserved casing:
X509v3 Name Constraints: critical
Permitted:
email:example.com
email:.example.com
DNS:example.com
DirName:C = US, O = Example
PIV Certificate (again, changed actual values to example)
Subject: C = us, O = example, OU = people, CN = john.j.doe.123456
Here the Subject
C
and O
values have a different case than those in the DirName
constraint.
Here is the full output I'm getting from the openssl verify
$ openssl verify -noCAfile -CAfile root.crt -untrusted intermediate.crt piv-cert.crt
C = us, O = example, OU = people, CN = john.j.doe.123456
error 47 at 0 depth lookup: permitted subtree violation
error piv-cert.crt: verification failed
CodePudding user response:
No, it's not due to case; nc_dn
in v3_ncons.c calls the i2d routine which calls x509_name_canon
in x_name.c which calls asn1_string_canon
which drops unnecessary spaces and converts to lowercase, before comparing.
It's (probably, given your redaction) due to an additional check that CommonName in the leaf cert if it 'looks like' a DNS name must satisfy the DNS constraints, which your example respectively does and doesn't.
Specifically, NAME_CONSTRAINTS_check_CN
in v3_ncons.c is called for the leaf/EE cert, and (now) calls cn2dnsid
to check for DNS syntax (post-punycoding if applicable): all ASCII letters, digits, plus nonstandard underscore, plus dot not at beginning or end or consecutive (i.e. all DNS labels must be nonempty) plus hyphen not at beginning or end or adjacent to dot. If this passes it applies any DNS constraints.
This looks like it is intended for SSL/TLS server certificates -- and the commit that added an earlier version to 1.1.0 acknowledged 5280 doesn't call for CN check, while this refactoring for 1.1.1 briefly modified it to apply only if no SAN DNS was present (and thus checked), but immediately thereafter that SAN bypass was removed from the code at the same time the documentation was changed to describe it as happening, which looks like a mistake to me -- but the code doesn't attempt to limit it to such server certs (and probably can't, because EKU is optional).