Trying to get an HTTPS session working using client certificates from a self-signed CA. The connection should check that all certificates are valid, both client and server side.
The process I followed is roundly as follows:
Create Certificate Authority
openssl genrsa -out CA.key 4096
openssl req -new -key CA.key -out CA.csr
openssl x509 -req -days 365 -in CA.csr -out CA.crt -signkey CA.key
Create Server Certificate
openssl genrsa -out server.key 4096
openssl req -new -key server.key -out server.csr
openssl ca -in server.csr -cert CA.crt -keyfile CA.key -out server.crt
Create Client Certificate
openssl genrsa -out client.key 4096
openssl req -new -key client.key -out client.csr
openssl ca -in client.csr -cert CA.crt -keyfile CA.key -out client.crt
Configure Apache
<VirtualHost _default_:443>
SSLEngine on
SSLCertificateFile "server.crt"
SSLCertificateKeyFile "server.key"
SSLCACertificateFile "CA.crt"
<Directory "/var/www">
SSLVerifyClient optional
SSLVerifyDepth 10
SSLOptions +StdEnvVars +ExportCertData
</Directory>
</VirtualHost>
Now I try and make a test connection:
wget \
--post-data 'id=1234' \
--certificate=client.crt \
--ca-certificate=CA.crt \
https://test.example.com:443
The resulting output from wget shows (over and over), in part:
HTTP request sent, awaiting response... No data received.
Retrying.
Checking the SSL error log from Apache give me the following messages:
[debug] ssl_engine_io.c(1606): [client xx.xx.xx.xx] total of 41 bytes in buffer, eos=1
[client xx.xx.xx.xx] Requesting connection re-negotiation
[debug] ssl_engine_io.c(1908): OpenSSL: I/O error, 5 bytes expected to read on BIO#80b075190 [mem: 80b0ca003]
[debug] ssl_engine_kernel.c(771): [client xx.xx.xx.xx] Performing full renegotiation: complete handshake protocol (client does support secure renegotiation)
[debug] ssl_engine_kernel.c(1892): OpenSSL: Handshake: start
[debug] ssl_engine_kernel.c(1900): OpenSSL: Loop: SSL renegotiate ciphers
[debug] ssl_engine_kernel.c(1900): OpenSSL: Loop: SSLv3 write hello request A
[debug] ssl_engine_kernel.c(1900): OpenSSL: Loop: SSLv3 flush data
[debug] ssl_engine_kernel.c(1900): OpenSSL: Loop: SSLv3 write hello request C
[info] [client xx.xx.xx.xx] Awaiting re-negotiation handshake
[debug] ssl_engine_kernel.c(1892): OpenSSL: Handshake: start
[debug] ssl_engine_kernel.c(1900): OpenSSL: Loop: before accept initialization
[debug] ssl_engine_io.c(1908): OpenSSL: I/O error, 5 bytes expected to read on BIO#80b075190 [mem: 80b0ca003]
[debug] ssl_engine_kernel.c(1929): OpenSSL: Exit: error in SSLv3 read client hello B
[error] [client xx.xx.xx.xx] Re-negotiation handshake failed: Not accepted by client!?
[debug] ssl_engine_io.c(1650): [client xx.xx.xx.xx] read from buffered SSL brigade, mode 0, 8192 bytes
[debug] ssl_engine_io.c(1725): [client xx.xx.xx.xx] buffered SSL brigade exhausted
[debug] ssl_engine_io.c(1650): [client xx.xx.xx.xx] read from buffered SSL brigade, mode 2, 0 bytes
[info] [client XX:XX:XX:XX::xx] Connection to child 3 established (server register.kiosk.tain.com:443)
[info] Seeding PRNG with 656 bytes of entropy
[debug] ssl_engine_kernel.c(1892): OpenSSL: Handshake: start
[debug] ssl_engine_kernel.c(1900): OpenSSL: Loop: before/accept initialization
Run the openssl client to see if there's anything to help in here:
openssl s_client \
-showcerts \
-connect test.example.com:443 \
-cert client.crt \
-key client.key \
-CAfile CA.crt
In the reply I see the following:
---
Server certificate
subject=/C=XX/ST=XXXXX/O=XXXX/CN=test.example.com
issuer=/O=XXXX/L=XXXXX/ST=XXXXX/C=SE/CN=XXXX Certificate Authority
---
No client certificate CA names sent
---
SSL handshake has read 3846 bytes and written 519 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
"No client certificate CA names sent" looks different to what I am expecting. I want client certificates.
Where am I going wrong?
It's technically possible for a TLS certificate to be used as both a server certificate and a client certificate. The TLS certificate for this very site has its key usage set that way, for instance. But the server which requires a client certificate does so to authenticate the client.
In Chrome, go to Settings. On the Settings page, below Default browser, click Show advanced settings. Under HTTPS/SSL, click Manage certificates. In the Certificates window, on the Personal tab, you should see your Client Certificate.
It doesn't really make sense to talk about a "self-signed CA". Your title ("Self-signed client SSL certificates [...]") suggests you're talking about self-signed client certificate. You're not: you're talking about client certificates issued by your own CA.
You've put your SSLVerifyClient
directive within a Directory
section, which would imply a re-negotiation to get the client certificate, once the client has made a request trying to access that directory.
Since there is no DocumentRoot
directive in your configuration, it's not clear whether a request on /
will try to access this directory (this may depend on compilation options depending on how it was packaged, but /var/www
isn't the default value otherwise).
Putting SSLVerifyClient
directly in your virtual host should at least make openssl s_client
see a client-certificate request. Fixing the DocumentRoot
might not be enough, since you'd need to make the HTTP request to trigger the renegotiation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With