Lighttpd Returns Wrong Cert In Multi-cert Set-up
lighttpd (v. 1.4.45) running on freebsd 11
- Set up to use multiple SSL certs: a default set, and one used for a particular hostname sent in the SNI extension.
- Certs set (i.e., pemfile and ca-file) can be RSA, ECC, or a mix of both.
- All combinations work except for the case of the default set being RSA and the set used for the hostname being ECC.
- In this case, even though the client sends the right SNI, lighttpd will always return the RSA one. As such, the TLS/SSL handshake fails.
- Note: RSA/RSA, ECC/ECC and ECC/RSA combination work as expected. The default one is returned for most connections. The one associated with the hostname in the SNI extension is returned if extension is included.
Unfortunately this happened several months ago and we've decided not to support clients that use SNI extensions. This is partly due to the fact that not all the clients we support can be configured to use SNI extensions. So we no longer have the relevant conf file. We're going through our internal lists of issues for resolution and noticed that this has an external dependency. So we decided to raise this issue so that you are aware of it.
Since it was an experiment, we used a default/stock lighttpd configuration using a socket conditional as well as host conditionals within the socket conditional as described by your documentation. https://redmine.lighttpd.net/projects/1/wiki/docs_ssl#Server-Name-Indication-SNI. We used openssl to generate self-signed CA certs as well as the server cert (signed by these "root" CAs).
As stated previously, when the socket conditional/default certs are ECC type, then the host conditional certs can be ECC type or RSA type. If a client sends an SNI extension that matches the host conditional, then the associated cert will be returned. Otherwise, the socket conditional cert is returned.
But if the socket conditional certs are RSA, then the host conditional certs must also be of RSA type for the SNI extension matching to work correctly. If it is ECC type, then the socket conditional cert (of type RSA) is always returned, even though the client sent an SNI extension that matched the host conditional. Obviously, this would not match the client configuration and will fail.
Note that the socket conditional and host conditional certs always use different "root" CAs (even if they are both RSA types or ECC types).
- Status changed from New to Need Feedback
lighttpd accepts both types of certs as long as the version of openssl accepts them. There might have been something specific to your configuration, potentially related to the contents of the CA cert info. Perhaps #2692 which allows setting explicit SSL server certificate chain, part of lighttpd 1.4.48 already provides a means to address the issue you were seeing.
Related, though not the specific issue you reported:
Can I use both RSA and ECC certificates in apache?
Does a CA need to have the same type of key as the certificates it is signing? RSA / Elliptic Curve (EC/ECDH/ECDSA)
Thanks for the response. If I have some free cycles I'll try to reproduce the relevant certs and attach them here. However, I want to make clear that my lightttpd setup can accept both types of certs (RSA and ECC) without issues.
The problem occurs if I have an RSA one (with its RSA root CA) as the default. And an ECC one (with its ECC root CA) for a specific hostname (say, foobar). The RSA one is always returned even if a client specifies "foobar" in the SNI. So authentication fails because the "foobar" client is expecting ECC certs.
If I reverse the order: ECC one (with ECC root CA) for default, and RSA one (with RSA root CA) for host "barfoo", then an SNI with "barfoo" will return the ECC, and no SNI returns RSA, as expected. So correct certs are always returned and authentication proceeds.
FYI: I did a quick review of the code in mod_openssl. When SNI is provided, the callback set by SSL_CTX_set_tlsext_servername_callback() is called. This sets the URI authority to that provided in SNI and re-runs configuration to select certs. The code then calls SSL_use_certificate() and SSL_use_PrivateKey() using the values obtained from
ssl.pemfile configured for the SNI host. There is nothing special here to distinguish RSA or ECC certificates. I do not think that anything special needs to be done beyond this, but please correct me if I am mistaken in my understanding on how to use the openssl API here.
(Aside: I think you reversed what you meant to say in "If I reverse the order...")
I am hoping that #2692, with patch part of lighttpd 1.4.48 and allows setting explicit SSL server certificate chain already provides a means to address the issue you were seeing.
- Status changed from Need Feedback to Missing Feedback
Marking as Missing Feedback.
I am still watching this, so if you are able to reproduce the issue, please post about it and we'll take a look.
Please see my notes above about using more recent versions of openssl, and specifying the certificate chain with lighttpd 1.4.48 and later.
Please also check your
ssl.cipher-list ordering and try using
ssl.honor-cipher-order = "enable"
Also available in: Atom