curl can't verify cert using capath, but can with cacert option
- by phylae
I am trying to use curl to connect to a site using HTTPS. But curl is failing to verify the SSL cert.
$ curl --verbose --capath ./certs/ --head https://example.com/
* About to connect() to example.com port 443 (#0)
* Trying 1.1.1.1... connected
* Connected to example.com (1.1.1.1) port 443 (#0)
* successfully set certificate verify locations:
* CAfile: none
CApath: ./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
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
I know about the -k option. But I do actually want to verify the cert.
The certs directory has been properly hashed with c_rehash . and it contains:
A Verisign intermediate cert
Two self-signed certs
The above site should be verified with the Verisign intermediate cert.
When I use the --cacert option instead (and point directly to the Verisign cert) curl is able to verify the SSL cert.
$ curl --verbose --cacert ./certs/verisign-intermediate-ca.crt --head https://example.com/
* About to connect() to example.com port 443 (#0)
* Trying 1.1.1.1... connected
* Connected to example.com (1.1.1.1) port 443 (#0)
* successfully set certificate verify locations:
* CAfile: ./certs/verisign-intermediate-ca.crt
CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using RC4-SHA
* Server certificate:
* subject: C=US; ST=State; L=City; O=Company; OU=ou1; CN=example.com
* start date: 2011-04-17 00:00:00 GMT
* expire date: 2012-04-15 23:59:59 GMT
* common name: example.com (matched)
* issuer: C=US; O=VeriSign, Inc.; OU=VeriSign Trust Network; OU=Terms of use at https://www.verisign.com/rpa (c)10; CN=VeriSign Class 3 Secure Server CA - G3
* SSL certificate verify ok.
> HEAD / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
> Host: example.com
> Accept: */*
>
< HTTP/1.1 404 Not Found
HTTP/1.1 404 Not Found
< Cache-Control: must-revalidate,no-cache,no-store
Cache-Control: must-revalidate,no-cache,no-store
< Content-Type: text/html;charset=ISO-8859-1
Content-Type: text/html;charset=ISO-8859-1
< Content-Length: 1267
Content-Length: 1267
< Server: Jetty(7.2.2.v20101205)
Server: Jetty(7.2.2.v20101205)
<
* Connection #0 to host example.com left intact
* Closing connection #0
* SSLv3, TLS alert, Client hello (1):
In addition, if I try hitting one of the sites using a self signed cert and the --capath option, it also works. (Let me know if I should post an example of that.) This implies that curl is finding the cert directory, and it is properly hash.
Finally, I am able to verify the SSL cert with openssl, using its -CApath option.
$ openssl s_client -CApath ./certs/ -connect example.com:443
CONNECTED(00000003)
depth=3 /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
verify return:1
depth=2 /C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
verify return:1
depth=1 /C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 Secure Server CA - G3
verify return:1
depth=0 /C=US/ST=State/L=City/O=Company/OU=ou1/CN=example.com
verify return:1
---
Certificate chain
0 s:/C=US/ST=State/L=City/O=Company/OU=ou1/CN=example.com
i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 Secure Server CA - G3
---
Server certificate
-----BEGIN CERTIFICATE-----
<cert removed>
-----END CERTIFICATE-----
subject=/C=US/ST=State/L=City/O=Company/OU=ou1/CN=example.com
issuer=/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 Secure Server CA - G3
---
No client certificate CA names sent
---
SSL handshake has read 1563 bytes and written 435 bytes
---
New, TLSv1/SSLv3, Cipher is RC4-SHA
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : RC4-SHA
Session-ID: D65C4C6D52E183BF1E7543DA6D6A74EDD7D6E98EB7BD4D48450885188B127717
Session-ID-ctx:
Master-Key: 253D4A3477FDED5FD1353D16C1F65CFCBFD78276B6DA1A078F19A51E9F79F7DAB4C7C98E5B8F308FC89C777519C887E2
Key-Arg : None
Start Time: 1303258052
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
QUIT
DONE
How can I get curl to verify this cert using the --capath option?