24

I'm trying to connect to a secure webservice throught a proxy using the curl command, but I get the follow error:

Unable to load client cert -8018.

Complete log:

[e-ballo@myserver]#   curl  -v -x proxy01.net:8080 https://endPointURL.com/SOAP --key ./cert.crt --cert ./cert.crt -capath=/etc/pki/tls/certs
* About to connect() to proxy proxy01.net port 8080 (#0)
*   Trying 10.0.3.64... connected
* Connected to proxy01.net (10.0.3.64) port 8080 (#0)
* Establish HTTP proxy tunnel to endPointURL.com:443
> CONNECT endPointURL.com:443 HTTP/1.1
> Host: endPointURL.com:443
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.3.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Proxy-Connection: Keep-Alive
>
< HTTP/1.0 200 Connection established
<
* Proxy replied OK to CONNECT request
* Initializing NSS with certpath: sql:/home/e-ballo/
* Unable to initialize NSS database
* Initializing NSS with certpath: none
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* Unable to load client cert -8018.
* NSS error -8018
* Closing connection #0
curl: (58) Unable to load client cert -8018.

Any idea what this error means ? and how can I fix it ?

Thanks in advance,

eballo
  • 769
  • 1
  • 11
  • 20

2 Answers2

29

I also experienced this issue on RHEL 6. curl was compiled with NSS, which you can see by checking the version:

$ curl -V
curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.3.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps scp sftp 
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz

The solution is to provide curl with a reference to the NSS database that stores the client certificate you want to use.

Create the certificate

I was starting from a Java keystore, which was created with this command (the alias value will be used to reference the certificate later):

keytool -genkeypair -alias myclient -keyalg RSA -keystore client_keystore.jks

Now, this JKS keystore needs to be converted to a pkcs12 format:

keytool -importkeystore -srckeystore client_keystore.jks \
    -destkeystore client_keystore.p12 -srcstoretype jks \
    -deststoretype pkcs12

Import the certificate into an NSS database

Next, create an NSS database in a directory of your choice:

mkdir /home/user/nss
certutil -N -d /home/user/nss

This certutil command creates 3 .db files, including cert8.db. This is the "old" db format but should still work. View the certutil documentation if you need to create a cert9.db file instead.

Use pk12util to import client_keystore.p12 into the NSS database

pk12util -i client_keystore.p12 -d /home/user/nss

Optionally, view the stored certificate in the database:

certutil -L -d /home/user/nss -n myclient

Use the certificate from curl

The certificate is now ready to be used by curl, but we need to let curl know where to find it. As specified in the curl manual, create an SSL_DIR environment variable:

export SSL_DIR=/home/user/nss

Finally, the curl command:

curl -vk --cert myclient https://localhost:8443/my/url

Note: the -k option is specified here because the server is using a self-signed certificate. See the curl manual for how to specify a cacert.

Remember to add the client certificate to the server's truststore if needed.

Reference

bparry
  • 1,456
  • 13
  • 9
  • curl's man page says it's possible to use a local file rather than a nss nickname even when curl is built with NSS. `If curl is built against the NSS SSL library then this option can tell curl the nickname of the certificate ... If you want to use a file from the current directory, please precede it with "./" prefix, in order to avoid confusion with a nickname. ` Do we need to import the file into the NSS database? – spkvn May 17 '19 at 02:05
10

I already fixed this problem, so I will post the solution. Maybe can help to somebody.

My version of curl was compiled with the Netscape Security System (NSS) libraries instead of the openSSL libraries. Versions of curl compiled with these two libraries use different certificate access methods. I was calling a flat file, which is the openSSL method. Another solution will be get NSS installed, (already there on most Red Hat derivatives) and create a cert9.db file, import your certificate and key (after converting to a P12 with openssl -don't forget to add a "freindlyName" or nickname) into that db using pk12util. Then you call the cert by it's nickname and give the password for the db.

The other option is get or compile a version of curl using the openssl libraries. RedHat 5, ubuntu or windows versions of curl are frequently already compiled that way. Red Hat 6 comes with curl compiled for NSS.

eballo
  • 769
  • 1
  • 11
  • 20
  • 2
    I have already created the db, imported the certificate. And was able to run curl via command line. However I need to do `export SSL_DIR={path}. How can I automate this when using PHP? – Severino Lorilla Jr. Jun 22 '18 at 02:57