Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Two-way SSL - SSL_ERROR_UNKNOWN_CA_ALERT #1934

Closed
danhydro opened this issue Dec 11, 2018 · 3 comments
Closed

Two-way SSL - SSL_ERROR_UNKNOWN_CA_ALERT #1934

danhydro opened this issue Dec 11, 2018 · 3 comments

Comments

@danhydro
Copy link

I am running a Python3 app via Gunicorn with two-way SSL configured. This requires a local cert/key to verify the app as well as a ca_certs file to verify the client.

The service starts and responds to curl requests fine when I use self-signed certificates for both server and client authentication. However when I use certificates signed by another CA, I get an error SSL_ERROR_UNKNOWN_CA_ALERT.

A working setup, with self-signed certs:

# Server cert
openssl req \
       -newkey rsa:2048 -nodes -keyout domain.key \
       -x509 -days 365 -out domain.crt

# Client (CA) cert    
openssl req \
       -newkey rsa:2048 -nodes -keyout twoway.key \
       -x509 -days 365 -out twoway.crt

With Gunicorn configured as follows:

keyfile = domain.key
certfile = domain.crt
cert_reqs = ssl.CERT_REQUIRED
ca_certs=twoway.crt

And curling as follows:
curl -vk --key twoway.key --cert twoway.crt https://my.service

Produces a successful response:

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-SHA
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd
*  start date: Dec  7 18:35:54 2018 GMT
*  expire date: Dec  7 18:35:54 2019 GMT
*  issuer: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> GET /manage/info HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: gunicorn/19.9.0
< Date: Tue, 11 Dec 2018 18:26:19 GMT
< Connection: keep-alive
< Content-Type: application/json
< Content-Length: 73

A failing setup, with a different series of certs:

With Gunicorn configured as follows:

keyfile = my_service_key.key
certfile = my_service_cert.crt
cert_reqs = ssl.CERT_REQUIRED
ca_certs = my_trusted_clients.crt

And curling as follows:

curl -vk --key my_trusted_key.key --cert my_trusted_clients.crt https://my.service

Produces an error:

About to connect() to localhost port 5000 (#0)
Initializing NSS with certpath: sql/etc/pki/nssdb
warning: ignoring value of ssl.verifyhost
skipping SSL peer certificate verification
NSS: client certificate from file
    subject: CN=mycn,OU=abc,O=def,...
NSS error -12195
Closing connection #0
SSL connect error
curl: (35) SSL connect error

Any thoughts on whether I am configuring this the wrong way? And why self-signed certs are working but other certs are not?

Note this config worked previously when using Stunnel (SSL proxy)+bjoern (wsgi), where I set the stunnel verify level to 4 ("Ignore the chain and only verify the peer certificate."). If there is something similar in Python I believe that would get me in the right direction.

@javabrett
Copy link
Collaborator

  • When you change to CA-signed certs, is that both for server and client certs, or only one of those?
  • Does the problem reproduce with a client other than curl?
  • Which version of curl are you running?
  • Why do you send -k (--insecure) - may be answered above, is the server's cert still untrusted?
  • Are you aware of curl with nss doesn't send intermediate client certificates? curl/curl#851 ?

@danhydro
Copy link
Author

I managed to fix this by using stunnel again as an SSL reverse proxy - again specifying to ignore the cert chain and verify only the peer certificate itself. This isn't a gunicorn issue but rather python's ssl library and how it handles peer cert verification. To my knowledge I don't see a way to verify only the peer certificate itself and ignore the chain.

In regards to your questions @javabrett ,

  • These are CA-signed certs for both client and server
  • The problem reproduces with other clients such as openssl
  • curl 7.19.7 (2009)
  • Even though the issue is now resolved, that is still an interesting curl thread linked, thanks.

@javabrett
Copy link
Collaborator

It's likely that this sort of configuration will only be possible with a fully-configurable SSLContext, and its use when wrapping sockets - see #1140.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants