libressl/portable

SSL_get_certificate() returns wrong certificate

Opened this issue · 2 comments

When testing a workaround for issue #1058, I observed that freenginx OCSP stapling tests still fail even with the workaround in place (again, testing with LibreSSL 3.9.2). Digging further suggests that the culprit is SSL_get_certificate(), which returns wrong certificate for TLSv1.3 in configurations with multiple certificates.

With TLSv1.2, it works correctly (but only with OCSP stapling actually configured and requested by the client) due to the following code in ssl_check_clienthello_tlsext_late():

		/* Set current certificate to one we will use so
		 * SSL_get_certificate et al can pick it up.
		 */
		s->cert->key = certpkey;
		r = s->ctx->tlsext_status_cb(s,
		    s->ctx->tlsext_status_arg);

There seems to be no equivalent for TLSv1.3.

Please also note that SSL_get_certificate() returns wrong certificate in configurations with multiple certificates with TLSv1.2 as well, as long as OCSP stapling is not configured. This is not something freenginx currently use, but I've added a variable just for testing this specific issue - and was surprised it doesn't work properly in simple tests not only with TLSv1.3, but also with TLSv1.2 (but works with TLSv1.2 and OCSP stapling configured). The code quoted above seems to explain the reason.

It would be great to get this fixed.

Have I just run into a similar issue? While testing the reverse proxy function of my server, the last domain cert loaded in the the config is only being used or am I using the library wrong. *ctx =tls_server() ... *cfg=tls_config_new() ...set the the keys ... tls_configure(*ctx,*cfg) free the *cfg, loop adding the proxied domain certs. Then create a socket and call tls_accept_socket.
The reverse proxy works fine but not if you go to to the proxy server then the certs don't match.

Have I just run into a similar issue? While testing the reverse proxy function of my server, the last domain cert loaded in the the config is only being used or am I using the library wrong. *ctx =tls_server() ... *cfg=tls_config_new() ...set the the keys ... tls_configure(*ctx,*cfg) free the *cfg, loop adding the proxied domain certs. Then create a socket and call tls_accept_socket. The reverse proxy works fine but not if you go to to the proxy server then the certs don't match.

I'm not really familiar with libtls interface, but from the description it looks like you try to use multiple certificates for different entities in a single libtls context. From the code it looks like this is implemented by libtls by creating multiple SSL contexts internally and then using first SSL context which matches the server name as provided by the client.

This issue, however, is not about about certificates for different entities, but about multiple certificates for the same entity which use different algorithms, such as RSA and ECDSA. This is natively supported by a single SSL context, and mostly works in LibreSSL (with the notable exception described in #1058) - that is, the client sees correct certificate. But the certificate as returned via SSL_get_certificate() when using TLSv1.3 is wrong, which breaks OCSP stapling in such configurations.

Summing the above, I doubt it's the same issue.