Opened 6 years ago

Closed 20 months ago

#1593 closed defect (wontfix)

Error selecting client certificate for proxy service

Reported by: Sergey Owned by:
Priority: major Milestone:
Component: nginx-module Version: 1.15.x
Keywords: Cc:
uname -a: Linux host1 3.16.0-5-amd64 #1 SMP Debian 3.16.51-3+deb8u1 (2018-01-08) x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.15.1
built by gcc 4.9.2 (Debian 4.9.2-10+deb8u1)
built with OpenSSL 1.0.1t 3 May 2016
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'

Description

Test case

Certificate Verification Server

# cat debug_cert.conf

log_format ssl '[$time_local] rem_adr=$remote_addr upst_adr=$upstream_addr $upstream_status: $request response_time $upstream_response_time msec $msec request_time $request_time ssl: $ssl_client_s_dn';

server {
    listen 443 ssl;
    server_name localhost;
    ssl_certificate      /etc/nginx/ssl/server.crt;
    ssl_certificate_key  /etc/nginx/ssl/server.nopass.key;
    ssl_client_certificate /etc/nginx/ssl/ca.crt;
    ssl_verify_client on;



    client_max_body_size 3m;

    fastcgi_param SSL_VERIFIED $ssl_client_verify;
    fastcgi_param SSL_CLIENT_SERIAL $ssl_client_serial;
    fastcgi_param SSL_CLIENT_CERT $ssl_client_cert;
    fastcgi_param SSL_DN $ssl_client_s_dn;

    access_log /var/log/nginx/debug.access.log  ssl;
    error_log /var/log/nginx/debug.error.log;

    location / {
        root /var/www/html;
        index index.html;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

}

Proxy

server {
  listen 9999;
  server_name host1;

  access_log   /var/log/nginx/test_access.log upstreamlog;
  error_log   /var/log/nginx/test_error.log;

    location /test1 {
        proxy_pass https://localhost:443/test1;
        proxy_ssl_certificate /etc/nginx/ssl/client01.crt;
        proxy_ssl_certificate_key /etc/nginx/ssl/client01.key;
    }
    location /test2 {
        proxy_pass https://localhost:443/test2;
        proxy_ssl_certificate /etc/nginx/ssl/client02.crt;
        proxy_ssl_certificate_key /etc/nginx/ssl/client02.key;
    }
}

We periodicaly call from the browser different locations (/test1 and /test2)

# curl http://host1:9999/test1
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.15.1</center>
</body>
</html>

# curl http://host1:9999/test2
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.15.1</center>
</body>
</html>

According to the configuration, the location test1 corresponds to the Client01 certificate. Location test2 corresponds to the Client02 certificate

But in logs for Certificate Verification Server the location does not always match the certificate

[09/Jul/2018:10:04:38 +0300] rem_adr=127.0.0.1 upst_adr=- -: GET /test1 HTTP/1.0 response_time - msec 1531119878.304 request_time 0.000 ssl: emailAddress=support@site.com,CN=etc,OU=Client02,O=Companyname,L=Moscow,ST=Moscow,C=RU
[09/Jul/2018:10:04:39 +0300] rem_adr=127.0.0.1 upst_adr=- -: GET /test2 HTTP/1.0 response_time - msec 1531119879.551 request_time 0.000 ssl: emailAddress=support@site.com,CN=etc,OU=Client02,O=Companyname,L=Moscow,ST=Moscow,C=RU

[09/Jul/2018:10:06:36 +0300] rem_adr=127.0.0.1 upst_adr=- -: GET /test1 HTTP/1.0 response_time - msec 1531119996.240 request_time 0.000 ssl: emailAddress=support@site.com,CN=etc,OU=Client01,O=Companyname,L=Moscow,ST=Moscow,C=RU
[09/Jul/2018:10:06:39 +0300] rem_adr=127.0.0.1 upst_adr=- -: GET /test2 HTTP/1.0 response_time - msec 1531119999.504 request_time 0.000 ssl: emailAddress=support@site.com,CN=etc,OU=Client01,O=Companyname,L=Moscow,ST=Moscow,C=RU

Change History (4)

comment:1 by Maxim Dounin, 6 years ago

Resolution: wontfix
Status: newclosed

Both locations use localhost:443 as an upstream server, and hence can reuse each other SSL sessions. As such, in the configuration provided the certificate (as well as other SSL parameters) will be determined by the location where the session was initially negotiated.

Switching off proxy_ssl_session_reuse should resolve this. Alternatively, the configuration can be changed to use distinct upstream names and hence distinct SSL session caches:

upstream localhost1 {
    server 127.0.0.1:443;
}

upstream localhost2 {
    server 127.0.0.1:443;
}

server {
    ...

    location /test1 {
        proxy_pass https://localhost1/test1;
        proxy_set_header Host localhost;
        proxy_ssl_certificate /etc/nginx/ssl/client01.crt;
        proxy_ssl_certificate_key /etc/nginx/ssl/client01.key;
    }
    location /test2 {
        proxy_pass https://localhost2/test2;
        proxy_set_header Host localhost;
        proxy_ssl_certificate /etc/nginx/ssl/client02.crt;
        proxy_ssl_certificate_key /etc/nginx/ssl/client02.key;
    }
}

comment:2 by olijaun@…, 3 years ago

I think this is really bad behavior and should be changed. I get that you may want to do some optimizations regarding ssl sessions. But you have two completely different certificates: one for client01 and one for client02.

If nginx uses another certificate than the configured one then this is simply a bug to me and not an optimization.

And even if you wanted such a behavior then the default should be to NOT optimize.

But why would you want that? You might want it if /test1 and /test2 both use the same certificate. OK. Fair enough. But tell me any meaningful scenario where you care to configure two different certificates and then don't bother when a different one is used from time to time... This makes no sense at all.

comment:3 by olijaun@…, 3 years ago

Resolution: wontfix
Status: closedreopened

As stated in my comment above. This is clearly a bug.

Last edited 3 years ago by olijaun@… (previous) (diff)

comment:4 by Maxim Dounin, 20 months ago

Resolution: wontfix
Status: reopenedclosed

As explained in comment:1, this is how SSL session reuse works: it does not take into account any SSL settings, including certificates, protocols, ciphers, and/or SNI names requested. If this is not acceptable in the particular configuration, it can be turned off with the proxy_ssl_session_reuse directive.

Note: See TracTickets for help on using tickets.