joakimb
joakimb

Reputation: 563

Access server with client certificate using s_client but not curl?

I am using nginx for my web server with client certificate authentication. The relevant part of the config is:

ssl_certificate        /usr/local/etc/nginx/certs/ssl.crt;
ssl_certificate_key    /usr/local/etc/nginx/certs/ssl.key;
ssl_client_certificate /usr/local/etc/nginx/certs/server_chain.crt;
ssl_verify_client on;
ssl_verify_depth 2;

The client certificates are signed by another server that has a certificate from a root CA. I.e, I want to accept clients that have a certificate chain as follows:

CA -> intermediate CA -> client

Therefore the file server_chain.crt is made by:

cat intermediate_ca.crt root_ca.crt > server_chain.crt

Now, I can sucessfully access the server by issuing the command:

openssl s_client -connect localhost:443 -tls1 -cert client.crt \
    -key client.key -CApath root_ca.crt -state -debug`

and then typing GET /api

But if I try to reach the same service by using:

curl -v -s -k --key client.key --cert client.crt https://localhost/api

I get:

<html>
<head><title>400 No required SSL certificate was sent</title></head> 
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<center>No required SSL certificate was sent</center>
<hr><center>nginx/1.6.0</center>
</body>
</html>

I also can not access the localhost/api page from a web browser with a client certificate installed. Something that works if I turn off client verification.

Any ideas on what's wrong?

Upvotes: 4

Views: 11240

Answers (3)

Arjun S Babu
Arjun S Babu

Reputation: 21

Could you try specifying the path. Old version of curl seems to have some bug:

curl -v -s -k --key ./client.key --cert ./client.crt https://localhost/api

https://help.mulesoft.com/s/article/Received-No-required-SSL-certificate-was-sent-Error-Sending-a-Request-Via-Client-Certificate-Enabled-DLB-Due-to-Curl-Version

Upvotes: 2

Chris Cogdon
Chris Cogdon

Reputation: 8005

This might have changed since then, but as of today, the installed curl can use client side certificates. But because it's linking to Mac OS's SSL libraries there's a couple of gotchas:

  1. The certificate needs to be in PKCS12 format. You can convert what you have with the following:
     cat client.key client.crt intermediate_ca.crt > bundle.pem
     openssl pkcs12 -export -in bundle.pem -out bundle.p12
  1. Run curl with the --cert bundle.p12:*password* option

  2. The showstopper gotcha. Either curl or the underlying libraries do NOT correctly send intermediate certificates: only the client-side certificate is sent. You can verify this with a packet capture on packets going towards the server: the issuer and subject names are visible in cleartext.

Upvotes: 1

joakimb
joakimb

Reputation: 563

Ok, so the error was totally unrelated to nginx. Turns out curl has no engine for running ssl by default on OS X. Therefore, curl never sent any certificate to the server.

Upvotes: 4

Related Questions