# Proxy\_ssl\_certificate not exchanging client certificates

**URL:** <https://www.ruby-forum.com/t/proxy-ssl-certificate-not-exchanging-client-certificates/241760>\
**Category:** NGINX\
**Created:** [April 28, 2015, 11:17pm UTC](https://www.ruby-forum.com/t/proxy-ssl-certificate-not-exchanging-client-certificates/241760 "2015-04-28T23:17:57Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![musicdenotation](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/ea666f/32.png) [@musicdenotation](https://www.ruby-forum.com/u/musicdenotation)\
**Post date:** [April 28, 2015, 11:17pm UTC](https://www.ruby-forum.com/t/proxy-ssl-certificate-not-exchanging-client-certificates/241760/1 "2015-04-28T23:17:57Z")

</div>

I was excited to see proxy\_ssl\_certificate and friends land in Nginx  
1.7.8,  
and decided to revisit Nginx as a candidate for proxy caching an  
upstream  
server requiring client authentication. I’ve included the debugging  
configuration I’ve been playing around with at the end of this post.

This particular upstream server does not trigger client authentication  
for  
all endpoints. For example, I can issue

* * *

## http http://NGINX\_PROXY\_IP/test/path Host:UPSTREAM\_SERVER

and get back the proxied response without error. However, for endpoints  
that  
require client authentication (triggered by the server after it examines  
the  
request path), nginx never gets a response. I’ve verified that the  
upstream  
server is working as expected using both wget:

* * *

## wget --verbose --debug --save-headers -O - –ca-certificate=PATH\_TO\_SERVER\_CERTFICATE –certificate=PATH\_TO\_CLIENT\_CERTIFICATE –private-key=PATH\_TO\_CLIENT\_PRIVATE\_KEY https://UPSTREAM\_SERVER/path/requiring/client/authentication

## and openssl’s s\_client:

## echo -e “GET https://UPSTREAM\_SERVER/path/requiring/client/authentication HTTP/1.0\r\n\r\n” | openssl s\_client -ign\_eof -connect UPSTREAM\_SERVER:443 -state -debug -cert PATH\_TO\_CLIENT\_CERTIFICATE -key PATH\_TO\_CLIENT\_PRIVATE\_KEY

In the latter case, it’s apparent that the server triggers renegotiation  
after seeing the requested path, and openssl’s s\_client responds  
accordingly  
by sending the client certificate, completing the exchange moments  
later.  
However, when invoking the same via the Nginx proxy:

* * *

## http http://NGINX\_PROXY\_IP/ Host:UPSTREAM\_SERVER/path/requiring/client/authentication

the upstream connection eventually closes after sending no data – the  
same  
behaviour it exhibits when no client certificates are provided via wget  
or  
openssl’s s\_client.

I’m using nginx.debug and have verified that the client certificate  
files  
are read (throwing errors if the wrong path is specified). I’ve also  
used  
ltrace and verified that Nginx appears to inject the client certificate  
via  
SSL\_CTX\_use\_certificate (taking a somewhat different path than wget’s  
SSL\_CTX\_use\_certificate\_file).

Have I failed to configure Nginx with the requisite client certificates?  
Is  
there anyway to see the level of debugging from openssl’s s\_client but  
via  
Nginx?

Here’s the configuration in question:

* * *

user nginx;  
worker\_processes 1;  
daemon off;

error\_log /var/log/nginx/error.log debug;  
pid /var/run/nginx.pid;

events {  
worker\_connections 1024;  
}

http {  
proxy\_cache\_methods GET HEAD;  
proxy\_cache\_min\_uses 1;

```
server {
    listen 80;

    proxy_http_version 1.1;
    proxy_ssl_protocols 'TLSv1.2';
    proxy_ssl_certificate PATH_TO_CLIENT_CERTIFICATE;
    proxy_ssl_certificate_key PATH_TO_CLIENT_PRIVATE_KEY;
    proxy_ssl_session_reuse off;
    proxy_ssl_trusted_certificate PATH_TO_SERVER_CERTFICATE;
    proxy_ssl_verify on;

    location / {
        resolver 8.8.8.8;
        proxy_pass https://$host$request_uri;
        proxy_cache rest-cache;

        add_header rt-Fastcgi-Cache $upstream_cache_status;
        proxy_set_header Host $host;
        proxy_ignore_headers Set-Cookie;
    }
}

```

}

---

<div class="post-metadata">

**Author:** ![lieut\_data](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/6bbea6/32.png) [@lieut\_data](https://www.ruby-forum.com/u/lieut_data)\
**Post date:** [April 29, 2015, 2:06pm UTC](https://www.ruby-forum.com/t/proxy-ssl-certificate-not-exchanging-client-certificates/241760/2 "2015-04-29T14:06:00Z")

</div>

Hello!

On Tue, Apr 28, 2015 at 05:17:32PM -0400, lieut\_data wrote:

> * * *
> 
> and get back the proxied response without error. However, for endpoints that  
> require client authentication (triggered by the server after it examines the  
> request path), nginx never gets a response. I’ve verified that the upstream  
> server is working as expected using both wget:

What nginx doesn’t support (or, rather, explicitly forbids) is  
renegotiation. On the other hand, renegotiation is required if  
one needs to ask for a client certificate only for some URIs, so  
it’s likely used in your case. You should see something like “SSL  
renegotiation disabled” in logs at notice level.

–  
Maxim D.

> **[nginx](http://nginx.org/)**

---

<div class="post-metadata">

**Author:** ![lieut\_data](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/6bbea6/32.png) [@lieut\_data](https://www.ruby-forum.com/u/lieut_data)\
**Post date:** [April 29, 2015, 11:10pm UTC](https://www.ruby-forum.com/t/proxy-ssl-certificate-not-exchanging-client-certificates/241760/3 "2015-04-29T23:10:02Z")

</div>

Thanks for getting back to me so quickly!

## Maxim D. Wrote:

> What nginx doesn’t support (or, rather, explicitly forbids) is  
> renegotiation. On the other hand, renegotiation is required if  
> one needs to ask for a client certificate only for some URIs, so  
> it’s likely used in your case. You should see something like “SSL  
> renegotiation disabled” in logs at notice level.

Yes, this is exactly the problem. With your hint, I commented out the  
relevant code in ngx\_ssl\_handshake and ngx\_ssl\_handle\_recv – and  
proxying  
worked flawlessly. (Interestingly, I never saw the log you identified  
because of SSL3\_FLAGS\_NO\_RENEGOTIATE\_CIPHERS having been set on the  
openssl  
connection object.)

I think I understand the gist of why nginx forbids client-initiated  
renegotiation (denial of service concerns? security concerns?), but I’m  
not  
well-versed in openssl enough to know if the same concerns apply to  
server-initiated renegotiation with nginx as the client, especially when  
it  
applies to cipher renegotiation as noted above.

Would nginx be open to a patch that would make this use case feasible?  
Perhaps as a modification to only disable these renegotiations when  
nginx is  
the server in the SSL equation?

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,258464,258520#msg-258520](http://forum.nginx.org/read.php?2,258464,258520#msg-258520)

---

<div class="post-metadata">

**Author:** ![lieut\_data](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/6bbea6/32.png) [@lieut\_data](https://www.ruby-forum.com/u/lieut_data)\
**Post date:** [May 7, 2015, 3:32pm UTC](https://www.ruby-forum.com/t/proxy-ssl-certificate-not-exchanging-client-certificates/241760/4 "2015-05-07T15:32:34Z")

</div>

Hello!

On Wed, Apr 29, 2015 at 05:09:26PM -0400, lieut\_data wrote:

> Yes, this is exactly the problem. With your hint, I commented out the
> 
> Would nginx be open to a patch that would make this use case feasible?  
> Perhaps as a modification to only disable these renegotiations when nginx is  
> the server in the SSL equation?

The renegotiation is disabled for security reasons since  
CVE-2009-3555. While CVE-2009-3555 is believed to be mitigated by  
Secure Renegotiation extension, renegotiation itself, even secure,  
still allows various bad side effects if allowed: in particular,  
peer credentials and/or ciphers used may be changed unexpectedly.

I don’t think we care much about the above happening on an  
upstream connection though, so patches are welcome. (Actually,  
original patch I submitted back in 2009 did not touch upstream  
connections at all, but Igor decided to disable renegotiation  
completely.)

–  
Maxim D.

> **[nginx](http://nginx.org/)**
