user4736500
user4736500

Reputation: 41

curl SSL certificate error: verifcation failed

Please help me understand why I cannot successfully curl this url via https:

I am using Ubuntu 12.04.5 with curl 7.22.0, libcurl 7.22.0 and OpenSSL 1.0.1-4ubuntu5.25

$ curl -v https://www.onevanilla.com/
* About to connect() to www.onevanilla.com port 443 (#0)
*   Trying 199.83.128.4... connected
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS alert, Server hello (2):
* SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
* Closing connection #0
curl: (60) SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

So I try to manually get the cert:

$ openssl s_client -connect www.onevanilla.com:443 </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /tmp/www.onevanilla.com.pem

and then:

$ curl -v --cacert /tmp/www.onevanilla.com.pem https://www.onevanilla.com

but I get the same result:

* About to connect() to www.onevanilla.com port 443 (#0)
*   Trying 199.83.128.4... connected
* successfully set certificate verify locations:
*   CAfile: /tmp/www.onevanilla.com.pem
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS alert, Server hello (2):
* SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
* Closing connection #0
curl: (60) SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

I can verify the certificate with openssl:

$ openssl s_client -host www.onevanilla.com -port 443 -CApath /etc/ssl/certs

and this returns Verify return code: 0 (ok)

I've also run sudo update-ca-certificates --fresh just to be sure, but no luck.

So it seems to me like the cert is valid (not expired, hostname matches CN), but I can never get a successful response using curl (unless of course I use -k or --insecure options). Can someone please explain?

Upvotes: 4

Views: 20712

Answers (2)

Steffen Ullrich
Steffen Ullrich

Reputation: 123561

You've run into a problem caused by a long standing issue where OpenSSL is not properly handling situations with multiple trust path. If you look into the report from SSLLabs you'll see, that the server provides the following chain:

[0] /O=www.onevanilla.com/OU=Domain Control Validated/CN=www.onevanilla.com SAN=DNS:www.onevanilla.com,DNS:onevanilla.com
[1] /C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certificates.godaddy.com/repository/CN=Go Daddy Secure Certification Authority/serialNumber=07969287
[2] /C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
[3] /L=ValiCert Validation Network/O=ValiCert, Inc./OU=ValiCert Class 2 Policy Validation Authority/CN=http://www.valicert.com//emailAddress=info@valicert.com

Browsers have included a root certificate for Go Daddy Class 2 Certification Authority and thus can build a trust path with [0],[1] and the root certificate and thus they will ignore the certificates [2] and [3]. OpenSSL instead will ignore only certificate [3] because it is self-signed and therefore should not have been included in the chain at all. It will then attempt to verify the chain [0],[1],[2] and will fail because it does not find a root certificate signing [2]. It will not attempt to verify the shorter chain [0],[1] instead.

For more details about this problem see Python Urllib2 SSL error and http://kriscience.blogspot.de/2013/03/supporting-trusted-but-untrusted.html and the OpenSSL bug report.

What you can do: get the missing certificate from https://certs.godaddy.com/repository/valicert_class2_root.crt and use it in the --cacert parameter.

Upvotes: 4

frasertweedale
frasertweedale

Reputation: 5674

The curl --cacert <cert> option is used to specify a certificate authority to use to verify the server certificate. The certificate you copied from the s_client output is the server certificate, and using it as as the --cacert argument fails because the server certifiate is not self-signed, but signed by a different certificate authority (in your case, Go Daddy).

Invoke curl with the --capath option to specify the trusted root CA(s). This is analogous to the s_client -CApath <dir> option.

$ curl -v --capath /etc/ssl/certs https://www.onevanilla.com

Upvotes: 4

Related Questions