Reputation: 41
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
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
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