Seva Alekseyev
Seva Alekseyev

Reputation: 61388

What exactly goes into CURLOPT_CAINFO/CAPATH?

Trying to make CURL in PHP work with a self signed certificate. I've made a copy of the cert file available to the client code, and I specify the path to the cert file both in CURLOPT_CAINFO and CURLOPT_CAPATH. Still, I'm getting error 60: SSL certificate problem: unable to get local issuer certificate.


Here are the repro steps. All on Linux (Debian Stretch in my case). Replace example.com with a relevant hostname.

First, I'd generate a private key:

openssl genrsa -out key.pem 2048

Compose a config file:

[req]
prompt=no
distinguished_name=dn
req_extensions=ext
x509_extensions=ext

[dn]
[email protected]
CN=example.com
O=Seva Alekseyev
L=Chicago
ST=IL
C=US

[ext]
keyUsage=digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth
subjectAltName=@alt

[alt]
DNS=example.com

Save as req.txt, generate a self signed cert:

openssl req -x509 -new -config req.txt -days 3650 -key key.pem -out example.cer

Install example.cer and key.pem in Apache under hostname example.com. Browse to make sure the basic setup works (modulo the scary security message).

Now, the client. Placed a copy of example.cer under $path. The PHP code goes:

$cu = curl_init("https://example.com/");
curl_setopt_array($cu, array(
    CURLOPT_HEADER => false,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CAINFO => "$path/example.cer",
    CURLOPT_CAPATH => "$path/example.cer"
    ));
$r = curl_exec($cu);
$c = curl_errno($cu);
$s = curl_error($cu);
curl_close($cu);

echo "$c $s";

Then the error message.

What am I missing here? Some guides suggest the value of CURLOPT_CAINFO/CAPATH should a folder instead, with serial-based symlinks pointing to cert files. Tried that too, same error. The document at https://curl.haxx.se/docs/sslcerts.html says:

Get a CA certificate that can verify the remote server and use the proper option to point out this CA cert for verification when connecting.

But there's no CA there, no cert chain. The signing cert is itself. Should I somehow transform the cert so that CURL sees it as a CA one? Should I generate a fake CA cert first, and sign the SSL cert with that one?


Command line curl, as in curl --cacert example.cer https://example.com/, pops the same message.


Related question here, but I'd rather not mess with systemwide settings.

Upvotes: 0

Views: 3050

Answers (2)

Seva Alekseyev
Seva Alekseyev

Reputation: 61388

The keyUsage line under [ext] must include keyCertSign, like this:

keyUsage=digitalSignature,keyEncipherment,keyCertSign

Otherwise, it's not a CA cert as far as OpenSSL is concerned.

OBTW, the basicConstraints=CA:true line under [ext], suggested by Steffen, is not necessary, I've checked. At least with CURL 7.52.1 and OpenSSL 1.0.2r it's not.

In the client code, CURLOPT_CAPATH is not necessary, either. CURL supports two alternative ways of specifying the root CA cert bundle. CURLOPT_CAINFO makes CURL read and parse a single file, potentially with multiple certificates in it. CURLOPT_CAPATH makes CURL scan a directory with certificate files identified by their serial numbers - or symlinks to those, as generated by c_rehash. Since in my scenario the effective root CA cert bundle has exactly one cert, the one file approach is sufficient.

Doesn't work under Windows, at least with command line CURL 7.55.1. The Windows version of CURL uses the built-in Schannel library for its SSL implementation, and ignores the --cacert option, instead relying on Windows' built-in trusted CA store. See here.

It might be possible to rebuild CURL for Windows against a different SSL implementation, but the trouble is hardly worth it. Windows comes with its own fleet of HTTP(S) clients.

Upvotes: 1

Steffen Ullrich
Steffen Ullrich

Reputation: 123531

The certificates pointed to by CURLOPT_CAINFO/CAPATH are expected to be CA certificates - at least when OpenSSL is used. This means that your self-signed certificate need also to be a CA certificate, i.e. it should not only be for serverAuth but also have basic constraints CA:true.

Upvotes: 0

Related Questions