Apache client authentication: browser not sending certificate when CA name not matching by case

apache-2.4mod-sslopensslssl-certificate

Using Apache 2.4.

We have two valid CA certificates whose distinguished names differ only by the case of one character (say CA1 with dn: cn=MyCA,O=myOrg and CA2 with dn: cn=MyCA,O=MyOrg).

These two certificates are both in the file referred by the SSLCACertificateFile Apache directive, as we need to authenticate client certificates signed by both CAs. This does not happen: only browsers with client certificates signed by CA1 or CA2 are able to access, depending on the order of the CA certificates in the file. So, if only clients from CA1 are able to authenticate themselves, after switching the order in SSLCACertificateFile and reloading Apache, only clients from CA2 are able to authenticate.

If we perform a SSL handshake by openssl s_client -connect <server>:<port> -prexit, we notice that only one of the CA distinguished names is sent in the list of accepted CAs, and the dn that is sent depends on the order in which the CAs certificate are in the SSLCACertificateFile. This makes sense as the Openssl computed hash for the two distinguished names is the same, as distinguished names should not be case sensitive.

But it seems that the browser performs a case-sensitive match, instead, as in the Apache logs the certificate installed in the browser is not sent when the "advertised CA" is CA1 and the client certificate is signed by CA2, and vice-versa. We tried with Firefox on Windows and Linux, and Internet Explorer and Chrome on Windows.

Otherwise, the curl command line browser has not this problem, when we invoke the https URL with the client certificate and key in PEM format.

Best Answer

Without really digging I'd say you can't convince browsers to do case-insensitive search here. In case of a simple web service, you could create another VirtualHost where all the clients are distributed (say https://detect-cert.example.com).

This would mean client negotiates TLS once, then it has a redirect, then another TLS negotiation.

VirtualHost detect-cert.example.com:

  • make sure you accept optional_no_ca certificates from browsers
  • no SSLCACertificateFile
  • look at either SSL_CLIENT_I_DN or SSL_CLIENT_CERT_CHAIN_<n> environment variable
  • redirect (HTTP 302) a browser to either ca1clients.example.com or ca2clients.example.com

VirtualHost ca1clients.example.com:

  • make sure you require certificates from browsers
  • SSLCACertificateFile CA_lowercase.pem

VirtualHost ca2clients.example.com:

  • make sure you require
  • SSLCACertificateFile CA_uppercase.pem

But your web application needs to support two domain names at the same time (for example through X-Forwarded-Host header). It should never tell a browser that entered through ca2clients.example.com to reenter through ca1clients.example.com. Another difficulty would be users exchanging links between themselves (for example emailing links to some content).