cURL / Mailing Lists / curl-users / Single Mail

curl-users

Re: Using client certificate and private key problem

From: jayjwa <jayjwa_at_atr2.ath.cx>
Date: Fri, 15 Dec 2006 04:55:39 -0500

(warning: long post)

On Thu, 14 Dec 2006, Ivan Balashov wrote:

-> I hope anyone can clarify the matter of using a client certificate with
-> Curl. I am given a public key in a ".cer" file (DER format). To use it with
-> Curl I converted it into PEM format using openssl tool:

Who gave you this key? Keys are actually private, so maybe you mean
"certificate"? Is there a matching key? Or possibly it's a root CA that you're
to trust?

The general method is you create a key & password, then use this to make a
certificate request. This certificate req. gets sent out to an SSL Root
Authority, someone like Verisign, Entrust, etc. You pay for this, can be alot.
They send you back a certificate. The benefit is people already know these
Root Authorities and have what's called their CA root certificate in their
web-browsers. Your certificate can be verified against the Root Auth. There's
something called a CRL, a revolk list for certificates that aren't in use
anymore because of whatever reason.

You can usually make a cheater key & cert pair that's good enough for most
purposes:

openssl genrsa -out test-key.pem 1024

makes test-key.pem with no password, to add a pass use extra -des3 option...

openssl req -new -key test-key.pem -x509 -out test-cert.pem

You'll be asked to fill out details for what it is you're securing and you'll
skip the send-away-to-Root-Auth. step and end up with both a key and cert.
This isn't good enough for curl because they're really bogus, they aren't
associated with any Root Authority that people trust (kind of like verifying
yourself). All the openssl-related examples here assume you've a correctly
configured openssl.cnf.

I think there are places you can go to, to do this for free instead of paying
hundreds of dollars to one of the well-known Root CA's. Maybe here is one?
http://www.cacert.org/

The other route is create & maintain your own root CA, and ask curl to trust
your root CA by added it to your curl's ca-bundle file (that comes with the
curl distro sources). This is what I did, because I have alot of services to
secure, plus my own personal key (for SMIME and so on). I think if this is
done properly (including CRL, place to get the root CA) that it's an
acceptable alternative. Some people may disagree. The only thing is, when you
browse to one of my sites, you'll be greeted with a daemon that's sending a
certifcate signed by my root CA. This will pop up a message in a web-browser
asking the user what to do, decline, accept the cert, accept it once, etc. To
solve this, I created a CGI and URL that imports the root ca to the user's
browser, and I let people know that might visit me that I'm using my own root
CA and give them a copy of the root CA (can put it in your finger banner,
place a URL to it in your .signature, and so on).

Basically, curl is happy when the signing root CA of the key/cert pair
you're using is in its ca-bundle file. You can read more about keys, certs,
and SSL on the openssl website or look in linux howto's.

-> When I'm trying to use it in Curl I get the error that the private key
-> cannot be set. Here is the output:
->
-> curl -v -E client.pem -k https://www.security.com
->
-> curl: (58) unable to set private key file: 'client.pem' type PEM

I think it's generally easier to do 'curl --key my-key.pem --cert my-cert.pem
-v https://www.whereever.com/page.html'. If there's a password on the key
you'll be prompted for it:

curl --key crypto/jayjwa-key.pem --cert crypto/jayjwa-crt.pem -O -v
https://atr2.ath.cx/index.shtml
* About to connect() to atr2.ath.cx port 443 (#0)
* Trying 69.95.5.10... connected
* Connected to atr2.ath.cx (69.95.5.10) port 443 (#0)
Enter PEM pass phrase:
* successfully set certificate verify locations:
* CAfile: /usr/share/curl/ca-bundle.pem
   CApath: /var/ssl/certs
* SSLv2, Client hello (1):
} [data not shown]
* SSLv3, TLS handshake, Server hello (2):
{ [data not shown]
* SSLv3, TLS handshake, CERT (11):
{ [data not shown]
* SSLv3, TLS handshake, Server key exchange (12):
{ [data not shown]
* SSLv3, TLS handshake, Request CERT (13):
{ [data not shown]
* SSLv3, TLS handshake, Server finished (14):
{ [data not shown]
* SSLv3, TLS handshake, CERT (11):
} [data not shown]
* SSLv3, TLS handshake, Client key exchange (16):
} [data not shown]
* SSLv3, TLS handshake, CERT verify (15):
} [data not shown]
* SSLv3, TLS change cipher, Client hello (1):
} [data not shown]
* SSLv3, TLS handshake, Finished (20):
} [data not shown]
* SSLv3, TLS change cipher, Client hello (1):
{ [data not shown]
* SSLv3, TLS handshake, Finished (20):
{ [data not shown]
* SSL connection using DHE-RSA-AES256-SHA
* Server certificate:
* subject: /C=US/ST=Undisclosed/L=Undisclosed/O=Atr2 Research
Group/OU=HTTPD
Webserver/website/CN=atr2.ath.cx/emailAddress=jayjwa-at-hotmail.com
* start date: 2004-05-12 04:15:27 GMT
* expire date: 2014-05-10 04:15:27 GMT
* common name: atr2.ath.cx (matched)
* issuer: /C=US/ST=Undisclosed/L=Undisclosed/O=Atr2 Research
Group/OU=Root Certificate
Authority/CN=atr2.ath.cx/emailAddress=ca-at-atr2.ath.cx
* SSL certificate verify ok.
> GET /index.shtml HTTP/1.1
> User-Agent: curl/7.16.0 (i686-pc-linux-gnu) libcurl/7.16.0 OpenSSL/0.9.8d
zlib/1.2.3 c-ares/1.3.1 libidn/0.6.5
> Host: atr2.ath.cx
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 15 Dec 2006 09:20:50 GMT
< Server: Apache/2.2.3 (Unix) mod_ssl/2.2.3 OpenSSL/0.9.8d DAV/2 PHP/5.2.0
SVN/1.4.2
< Accept-Ranges: bytes
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
< Content-Type: text/html
   % Total % Received % Xferd Average Speed Time Time Time
Current
                                  Dload Upload Total Spent Left
Speed
   0 0 0 0 0 0 0 0 --:--:-- 0:00:07 --:--:--
0{ [data not shown]
100 17162 0 17162 0 0 2289 0 --:--:-- 0:00:07 --:--:--
1289k* Connection #0 to host atr2.ath.cx left intact

* Closing connection #0

-> So my question is, where is the private key that I should use, given that
-> original ".cer" file contains only a public key? I'm not sure if I have to
-> use private key at all, but can anyone advise if I should also get a private
-> key on order to use this client certificate?

Depends on what's really in the file. If you created the certifcate using the
key/request/sign/certificate method, then you should have the matching key
already somewhere. If what you have is really a root certificate that someone
is asking you to trust (like your boss for a work website, a sysadmin gives
you it for his network, etc), then you can add it to curl's ca-bundle file and
just do 'curl -O -v https://www.whereever.com/page.html':

curl -O -v https://atr2.ath.cx/index.shtml
* About to connect() to atr2.ath.cx port 443 (#0)
* Trying 69.95.5.10... connected
* Connected to atr2.ath.cx (69.95.5.10) port 443 (#0)
* successfully set certificate verify locations:
* CAfile: /usr/share/curl/ca-bundle.pem
   CApath: /var/ssl/certs
* SSLv2, Client hello (1):
} [data not shown]
* SSLv3, TLS handshake, Server hello (2):
{ [data not shown]
* SSLv3, TLS handshake, CERT (11):
{ [data not shown]
* SSLv3, TLS handshake, Server key exchange (12):
{ [data not shown]
* SSLv3, TLS handshake, Request CERT (13):
{ [data not shown]
* SSLv3, TLS handshake, Server finished (14):
{ [data not shown]
* SSLv3, TLS handshake, CERT (11):
} [data not shown]
* SSLv3, TLS handshake, Client key exchange (16):
} [data not shown]
* SSLv3, TLS change cipher, Client hello (1):
} [data not shown]
* SSLv3, TLS handshake, Finished (20):
} [data not shown]
* SSLv3, TLS change cipher, Client hello (1):
{ [data not shown]
* SSLv3, TLS handshake, Finished (20):
{ [data not shown]
* SSL connection using DHE-RSA-AES256-SHA
* Server certificate:
* subject: /C=US/ST=Undisclosed/L=Undisclosed/O=Atr2 Research
Group/OU=HTTPD
Webserver/website/CN=atr2.ath.cx/emailAddress=jayjwa-at-hotmail.com
* start date: 2004-05-12 04:15:27 GMT
* expire date: 2014-05-10 04:15:27 GMT
* common name: atr2.ath.cx (matched)
* issuer: /C=US/ST=Undisclosed/L=Undisclosed/O=Atr2 Research
Group/OU=Root Certificate
Authority/CN=atr2.ath.cx/emailAddress=ca-at-atr2.ath.cx
* SSL certificate verify ok.
> GET /index.shtml HTTP/1.1
> User-Agent: curl/7.16.0 (i686-pc-linux-gnu) libcurl/7.16.0 OpenSSL/0.9.8d
zlib/1.2.3 c-ares/1.3.1 libidn/0.6.5
> Host: atr2.ath.cx
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 15 Dec 2006 09:25:35 GMT
< Server: Apache/2.2.3 (Unix) mod_ssl/2.2.3 OpenSSL/0.9.8d DAV/2 PHP/5.2.0
SVN/1.4.2
< Accept-Ranges: bytes
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
< Content-Type: text/html
   % Total % Received % Xferd Average Speed Time Time Time
Current
                                  Dload Upload Total Spent Left
Speed
   0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:--
0{ [data not shown]
100 17162 0 17162 0 0 27545 0 --:--:-- --:--:-- --:--:--
1289k* Connection #0 to host atr2.ath.cx left intact

* Closing connection #0

Don't use "-k", that means "insecure", which is probably not what you want if
you're using certifcates. If you're trying to securely identify yourself to a
website, then likely what you want to do is the --key, --cert option command
line, making a key, then sending away a cert. request to get your certicate
back. If you want to just test, I think the CA.pl tool in the openssl distro
can make a demo certificate authority (demoCA). If your certifcate is really a
root cert. that you're being asked to trust, then stick it in your curl
ca-bundle file, like in the second example.

There may be more to it than this, but this is how I learned it (for better or
worse); hope something here helps.

-- 
Linux 2.6.19 on Pentium II (Klamath) up 31.30
Linux 2.6.19 on Intel(R) Pentium(R) 4 CPU 2.80GHz up 30.01
Minix 2.0.4 (currently offline)
Received on 2006-12-15