Docker-nginx: ssl_verify_client broken from nginx:1.12

Created on 3 Jun 2017  路  4Comments  路  Source: nginxinc/docker-nginx

server {
...
ssl_client_certificate /certs/t1_t2_coagent_ca.crt;
ssl_verify_client on;
ssl_verify_depth 3;
...
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
response:

400 The SSL certificate error

400 Bad Request


The SSL certificate error


nginx/1.12.0


ps:
1)all alpine based images can return index.html;
2)nginx:1.11 is OK

Most helpful comment

Thanks, that clarifies things a lot!

First of all, this is not a bug in nginx :-)

Enabling debug in error log in nginx, I could see the following error when trying to auth using generated certificates:

2017/06/06 15:59:58 [info] 6#6: *2 client SSL certificate verify error: (26:unsupported certificate purpose) while reading client request headers, client: 172.17.0.1, server: localhost, request: "GET / HTTP/1.1", host: "server:3001"

And this did not happen when I compiled the same nginx with an old openssl version - which led me thinking that some bug might have been fixed or introduced in openssl. I've also checked old nginx version against openssl 1.1.0 - which exhibited the same exact problem of not validating the certificates.

I've took a closer look on the certificates. The ca.crt generated has the following (via openssl x509 -in ./certs/ca.crt -noout -purpose):

Certificate purposes:
SSL client : Yes
SSL client CA : Yes
SSL server : Yes
SSL server CA : Yes

Although coagent.crt and all the following ones:

Certificate purposes:
SSL client : Yes
SSL client CA : No
SSL server : Yes
SSL server CA : No

So it looks like that prior to 1.1.0 openssl did not actually check the purposes of the certificates when checking if they are valid:

/cert/certs # openssl version
OpenSSL 1.0.2k 26 Jan 2017
/cert/certs # openssl x509 -in ./ca.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : Yes (WARNING code=3)
SSL server : Yes
SSL server CA : Yes (WARNING code=3)
/cert/certs # openssl x509 -in ./coagent.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : No
SSL server : Yes
SSL server CA : No
/cert/certs # openssl verify -verbose -CAfile ./ca.crt coagent.crt
coagent.crt: OK
/cert/certs # cat ./ca.crt ./coagent.crt > ca_coagent.crt
/cert/certs # openssl verify -verbose -CAfile ./ca_coagent.crt ./t1.crt
./t1.crt: OK
/cert/certs # cat ./ca.crt ./coagent.crt ./t1.crt > ca_coagent_t1.crt
/cert/certs # openssl x509 -in ./t1.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : No
SSL server : Yes
SSL server CA : No
/cert/certs # openssl verify -verbose -CAfile ./ca_coagent_t1.crt ./v1.crt
./v1.crt: OK

However things are different in 1.1.0:

root@deb9-test1:/etc/nginx/cert/certs# openssl version
OpenSSL 1.1.0e 16 Feb 2017
root@deb9-test1:/etc/nginx/cert/certs# openssl x509 -in ./ca.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : Yes (WARNING code=3)
SSL server : Yes
SSL server CA : Yes (WARNING code=3)
root@deb9-test1:/etc/nginx/cert/certs# openssl x509 -in ./coagent.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : No
SSL server : Yes
SSL server CA : No
root@deb9-test1:/etc/nginx/cert/certs# openssl verify -verbose -CAfile ./ca.crt coagent.crt
coagent.crt: OK
root@deb9-test1:/etc/nginx/cert/certs# cat ./ca.crt ./coagent.crt > ca_coagent.crt
root@deb9-test1:/etc/nginx/cert/certs# openssl verify -verbose -CAfile ./ca_coagent.crt ./t1.crt
C = US, ST = Denial, L = Springfield, O = Dis, CN = coagent
error 24 at 1 depth lookup: invalid CA certificate
error ./t1.crt: verification failed
root@deb9-test1:/etc/nginx/cert/certs# cat ./ca.crt ./coagent.crt ./t1.crt > ca_coagent_t1.crt
root@deb9-test1:/etc/nginx/cert/certs# openssl x509 -in ./t1.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : No
SSL server : Yes
SSL server CA : No
root@deb9-test1:/etc/nginx/cert/certs# openssl verify -verbose -CAfile ./ca_coagent_t1.crt ./v1.crt
C = US, ST = Denial, L = Springfield, O = Dis, CN = t1
error 24 at 1 depth lookup: invalid CA certificate
C = US, ST = Denial, L = Springfield, O = Dis, CN = coagent
error 24 at 2 depth lookup: invalid CA certificate
error ./v1.crt: verification failed

So the problem here is that openssl has fixed the bug, and now actually checks for the purposes of the certificates. I guess prior to that clients could generate new leaf certificates and if you did not set the ssl_verify_depth in nginx properly, you could have been abused...

Anyway, I've re-generated the certificates with:

openssl x509 -req -days 365 -in coagent.csr -CA ca.crt -CAkey ca.key -set_serial 1002 -out coagent.crt -extfile ./openssl.cnf -extensions v3_ca

where openssl.cnf is:

[ v3_ca ]
basicConstraints = CA:true
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid

Now the certificates have SSL client CA: Yes and SSL server CA: Yes and validation goes just fine. But I guess you would want to set it only for the intermediaries, not the actual clients.

All 4 comments

Which images are that? Can you provide a simple test scenario e.g. using self-signed certificates? ssl_verify_client are definitely not broken in numerous setups we have with 1.12.0+.

cert.zip
use:
./nginx_restart.sh
./docker_curl.sh
cd cert
./curl_test.sh (you should use your ip instead of 192.168.0.107 )

Thanks, that clarifies things a lot!

First of all, this is not a bug in nginx :-)

Enabling debug in error log in nginx, I could see the following error when trying to auth using generated certificates:

2017/06/06 15:59:58 [info] 6#6: *2 client SSL certificate verify error: (26:unsupported certificate purpose) while reading client request headers, client: 172.17.0.1, server: localhost, request: "GET / HTTP/1.1", host: "server:3001"

And this did not happen when I compiled the same nginx with an old openssl version - which led me thinking that some bug might have been fixed or introduced in openssl. I've also checked old nginx version against openssl 1.1.0 - which exhibited the same exact problem of not validating the certificates.

I've took a closer look on the certificates. The ca.crt generated has the following (via openssl x509 -in ./certs/ca.crt -noout -purpose):

Certificate purposes:
SSL client : Yes
SSL client CA : Yes
SSL server : Yes
SSL server CA : Yes

Although coagent.crt and all the following ones:

Certificate purposes:
SSL client : Yes
SSL client CA : No
SSL server : Yes
SSL server CA : No

So it looks like that prior to 1.1.0 openssl did not actually check the purposes of the certificates when checking if they are valid:

/cert/certs # openssl version
OpenSSL 1.0.2k 26 Jan 2017
/cert/certs # openssl x509 -in ./ca.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : Yes (WARNING code=3)
SSL server : Yes
SSL server CA : Yes (WARNING code=3)
/cert/certs # openssl x509 -in ./coagent.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : No
SSL server : Yes
SSL server CA : No
/cert/certs # openssl verify -verbose -CAfile ./ca.crt coagent.crt
coagent.crt: OK
/cert/certs # cat ./ca.crt ./coagent.crt > ca_coagent.crt
/cert/certs # openssl verify -verbose -CAfile ./ca_coagent.crt ./t1.crt
./t1.crt: OK
/cert/certs # cat ./ca.crt ./coagent.crt ./t1.crt > ca_coagent_t1.crt
/cert/certs # openssl x509 -in ./t1.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : No
SSL server : Yes
SSL server CA : No
/cert/certs # openssl verify -verbose -CAfile ./ca_coagent_t1.crt ./v1.crt
./v1.crt: OK

However things are different in 1.1.0:

root@deb9-test1:/etc/nginx/cert/certs# openssl version
OpenSSL 1.1.0e 16 Feb 2017
root@deb9-test1:/etc/nginx/cert/certs# openssl x509 -in ./ca.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : Yes (WARNING code=3)
SSL server : Yes
SSL server CA : Yes (WARNING code=3)
root@deb9-test1:/etc/nginx/cert/certs# openssl x509 -in ./coagent.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : No
SSL server : Yes
SSL server CA : No
root@deb9-test1:/etc/nginx/cert/certs# openssl verify -verbose -CAfile ./ca.crt coagent.crt
coagent.crt: OK
root@deb9-test1:/etc/nginx/cert/certs# cat ./ca.crt ./coagent.crt > ca_coagent.crt
root@deb9-test1:/etc/nginx/cert/certs# openssl verify -verbose -CAfile ./ca_coagent.crt ./t1.crt
C = US, ST = Denial, L = Springfield, O = Dis, CN = coagent
error 24 at 1 depth lookup: invalid CA certificate
error ./t1.crt: verification failed
root@deb9-test1:/etc/nginx/cert/certs# cat ./ca.crt ./coagent.crt ./t1.crt > ca_coagent_t1.crt
root@deb9-test1:/etc/nginx/cert/certs# openssl x509 -in ./t1.crt -noout -purpose |grep ^SSL
SSL client : Yes
SSL client CA : No
SSL server : Yes
SSL server CA : No
root@deb9-test1:/etc/nginx/cert/certs# openssl verify -verbose -CAfile ./ca_coagent_t1.crt ./v1.crt
C = US, ST = Denial, L = Springfield, O = Dis, CN = t1
error 24 at 1 depth lookup: invalid CA certificate
C = US, ST = Denial, L = Springfield, O = Dis, CN = coagent
error 24 at 2 depth lookup: invalid CA certificate
error ./v1.crt: verification failed

So the problem here is that openssl has fixed the bug, and now actually checks for the purposes of the certificates. I guess prior to that clients could generate new leaf certificates and if you did not set the ssl_verify_depth in nginx properly, you could have been abused...

Anyway, I've re-generated the certificates with:

openssl x509 -req -days 365 -in coagent.csr -CA ca.crt -CAkey ca.key -set_serial 1002 -out coagent.crt -extfile ./openssl.cnf -extensions v3_ca

where openssl.cnf is:

[ v3_ca ]
basicConstraints = CA:true
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid

Now the certificates have SSL client CA: Yes and SSL server CA: Yes and validation goes just fine. But I guess you would want to set it only for the intermediaries, not the actual clients.

Thanks!

Was this page helpful?
0 / 5 - 0 ratings