proxy_ssl_verify error: 'upstream SSL certificate does not match "test.example.com" while SSL handshaking to upstream', for CN/SAN 'matched' client & server certs ?
Maxim Dounin
mdounin at mdounin.ru
Mon Jun 1 15:42:32 UTC 2020
Hello!
On Fri, May 29, 2020 at 07:09:45PM -0700, PGNet Dev wrote:
> I'm running
>
> nginx -V
> nginx version: nginx/1.19.0 (pgnd Build)
> built with OpenSSL 1.1.1g 21 Apr 2020
> TLS SNI support enabled
> ...
>
> It serves as front-end SSL termination, site host, and reverse-proxy to backend apps.
>
> I'm trying to get a backend app to proxy_ssl_verify the proxy connection to it.
>
> I have two self-signed certs:
>
> One for "TLS Web Client Authentication, E-mail Protection"
>
> openssl x509 -in test.example.com.client.crt -text | egrep "Subject.*CN|DNS|TLS"
> Subject: C = US, ST = NY, L = New_York, O = example2.com, OU = myCA, CN = test.example.com, emailAddress = ssl at example2.com
> TLS Web Client Authentication, E-mail Protection
> DNS:test.example.com, DNS:www.test.example.com, DNS:localhost
>
> and the other, for "TLS Web Server Authentication"
>
> openssl x509 -in test.example.com.server.crt -text | egrep "Subject.*CN|DNS|TLS"
> Subject: C = US, ST = NY, L = New_York, O = example2.com, OU = myCA, CN = test.example.com, emailAddress = ssl at example2.com
> TLS Web Server Authentication
> DNS:test.example.com, DNS:www.test.example.com, DNS:localhost
>
> The certs 'match' CN & SAN, differing in "X509v3 Extended Key Usage".
>
> Both are verified "OK" with my local CA cert
>
> openssl verify -CAfile myCA.crt.pem test.example.com.server.crt
> test.example.com.server.crt: OK
>
> openssl verify -CAfile /myCA.crt.pem test.example.com.client.crt
> test.example.com.client.crt: OK
>
> My main nginx config includes,
>
> upstream test.example.com {
> server test.example.com:11111;
> }
> server {
>
> listen 10.10.10.1:443 ssl http2;
> server_name example.com;
> ...
>
> ssl_verify_client on;
> ssl_client_certificate "/etc/ssl/nginx/myCA.crt";
> ssl_verify_depth 2;
> ssl_certificate "/etc/ssl/nginx/example.com.server.crt";
> ssl_certificate_key "/etc/ssl/nginx/example.com.server.key";
> ssl_trusted_certificate "/etc/ssl/nginx/myCA.crt";
>
> location /app1 {
> proxy_pass https://test.example.com;
> proxy_ssl_certificate "/etc/ssl/nginx/test.example.com.client.crt";
> proxy_ssl_certificate_key "/etc/ssl/nginx/test.example.com.client.key";
> proxy_ssl_trusted_certificate "/etc/ssl/nginx/myCA.crt";
> proxy_ssl_verify on;
> proxy_ssl_verify_depth 2;
> include includes/reverse-proxy.inc;
> }
> }
>
> and the upstream config,
>
> server {
> listen 127.0.0.1:11111 ssl http2;
> server_name test.example.com;
>
> root /data/webapps/demo_app/;
> index index.php;
> expires -1;
>
> ssl_certificate "/etc/ssl/nginx/test.example.com.server.crt";
> ssl_certificate_key "/etc/ssl/nginx/test.example.com.server.key";
>
> ssl_client_certificate "/etc/ssl/nginx/myCA.crt";
> ssl_verify_client optional;
> ssl_verify_depth 2;
>
> location ~ \.php {
> try_files $uri =404;
> fastcgi_pass phpfpm;
> fastcgi_index index.php;
> fastcgi_param PATH_INFO $fastcgi_script_name;
> include fastcgi_params;
> }
>
> }
>
> access to
>
> https://example.com/app1
>
> responds,
>
> 502 Bad Gateway
>
> logs, show an SSL handshake fail
>
> ...
> 2020/05/29 19:00:06 [debug] 29419#29419: *7 SSL: TLSv1.3, cipher: "TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD"
> 2020/05/29 19:00:06 [debug] 29419#29419: *7 http upstream ssl handshake: "/app1/?"
> 2020/05/29 19:00:06 [debug] 29419#29419: *7 X509_check_host(): no match
> 2020/05/29 19:00:06 [error] 29419#29419: *7 upstream SSL certificate does not match "test.example.com" while SSL handshaking to upstream, client: 10.10.10.73, server: example.com, request: "GET /app1/ HTTP/2.0", upstream: "https://127.0.0.1:11111/app1/", host: "example.com"
> 2020/05/29 19:00:06 [debug] 29419#29419: *7 http next upstream, 2
> ...
>
> If I toggle
>
> - ssl_verify_client on;
> + ssl_verify_client off;
>
> then I'm able to connect to the backend site, as expected.
>
> What exactly is NOT matching in the handshake? CN & SAN do ...
>
> &/or, is there a config problem above?
Most likely the problem is that the certificate returned depends
on the name provided via Server Name Indication (SNI). That is,
that the server block in the upstream server configuration is not
the default one, and the default one returns a different
certificate.
Usage of Server Name Indication for upstream SSL connections isn't
enabled by default, and this isn't switched on in your
configuration. Try
proxy_ssl_server_name on;
to see if it helps. See http://nginx.org/r/proxy_ssl_server_name
for details.
You may also try the following patch to provide somewhat better
debug logging when checking upstream server SSL certificates:
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1591025575 -10800
# Mon Jun 01 18:32:55 2020 +0300
# Node ID eaa39944438dbb10507760890bddc45c19a5ad6f
# Parent 8cadaf7e7231865f2f81c03cb785c045dda6bf8b
SSL: added verify callback to ngx_ssl_trusted_certificate().
This ensures that certificate verification is properly logged to debug
log during upstream server certificate verification. This should help
with debugging various certificate issues.
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -920,6 +920,8 @@ ngx_int_t
ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
ngx_int_t depth)
{
+ SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_ssl_verify_callback);
+
SSL_CTX_set_verify_depth(ssl->ctx, depth);
if (cert->len == 0) {
--
Maxim Dounin
http://mdounin.ru/
More information about the nginx
mailing list