I'm trying to set up root certification authority, subordinate certification authority and to generate the client certificates signed by any of this CA that nginx 0.7.67 on Debian Squeeze will accept. My problem is that root CA signed client certificate works fine while subordinate CA signed one results in "400 Bad Request. The SSL certificate error".
Step 1: nginx virtual host configuration:
server {
server_name test.local;
access_log /var/log/nginx/test.access.log;
listen 443 default ssl;
keepalive_timeout 70;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_client_certificate /etc/nginx/ssl/client.pem;
ssl_verify_client on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
location / {
proxy_pass http://testsite.local/;
}
}
Step 2: PKI infrastructure organization for both root and subordinate CA (based on this article):
# mkdir ~/pki && cd ~/pki
# mkdir rootCA subCA
# cp -v /etc/ssl/openssl.cnf rootCA/
# cd rootCA/
# mkdir certs private crl newcerts; touch serial; echo 01 > serial; touch index.txt; touch crlnumber; echo 01 > crlnumber
# cp -Rvp * ../subCA/
Almost no changes was made to rootCA/openssl.cnf:
[ CA_default ]
dir = . # Where everything is kept
...
certificate = $dir/certs/rootca.crt # The CA certificate
...
private_key = $dir/private/rootca.key # The private key
and to subCA/openssl.cnf:
[ CA_default ]
dir = . # Where everything is kept
...
certificate = $dir/certs/subca.crt # The CA certificate
...
private_key = $dir/private/subca.key # The private key
Step 3: Self-signed root CA certificate generation:
# openssl genrsa -out ./private/rootca.key -des3 2048
# openssl req -x509 -new -key ./private/rootca.key -out certs/rootca.crt -config openssl.cnf
Enter pass phrase for ./private/rootca.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:rootca
Email Address []:
Step 4: Subordinate CA certificate generation:
# cd ../subCA
# openssl genrsa -out ./private/subca.key -des3 2048
# openssl req -new -key ./private/subca.key -out subca.csr -config openssl.cnf
Enter pass phrase for ./private/subca.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:subca
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Step 5: Subordinate CA certificate signing by root CA certificate:
# cd ../rootCA/
# openssl ca -in ../subCA/subca.csr -extensions v3_ca -config openssl.cnf
Using configuration from openssl.cnf
Enter pass phrase for ./private/rootca.key:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 1 (0x1)
Validity
Not Before: Feb 4 10:49:43 2013 GMT
Not After : Feb 4 10:49:43 2014 GMT
Subject:
countryName = AU
stateOrProvinceName = Some-State
organizationName = Internet Widgits Pty Ltd
commonName = subca
X509v3 extensions:
X509v3 Subject Key Identifier:
C9:E2:AC:31:53:81:86:3F:CD:F8:3D:47:10:FC:E5:8E:C2:DA:A9:20
X509v3 Authority Key Identifier:
keyid:E9:50:E6:BF:57:03:EA:6E:8F:21:23:86:BB:44:3D:9F:8F:4A:8B:F2
DirName:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca
serial:9F:FB:56:66:8D:D3:8F:11
X509v3 Basic Constraints:
CA:TRUE
Certificate is to be certified until Feb 4 10:49:43 2014 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
...
# cd ../subCA/
# cp -v ../rootCA/newcerts/01.pem certs/subca.crt
Step 6: Server certificate
generation and signing by root CA (for nginx virtual host):
# cd ../rootCA
# openssl genrsa -out ./private/server.key -des3 2048
# openssl req -new -key ./private/server.key -out server.csr -config openssl.cnf
Enter pass phrase for ./private/server.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:test.local
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
# openssl ca -in server.csr -out certs/server.crt -config openssl.cnf
Step 7: Client #1 certificate
generation and signing by root CA:
# openssl genrsa -out ./private/client1.key -des3 2048
# openssl req -new -key ./private/client1.key -out client1.csr -config openssl.cnf
Enter pass phrase for ./private/client1.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:Client #1
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
# openssl ca -in client1.csr -out certs/client1.crt -config openssl.cnf
Step 8: Client #1 certificate converting to PKCS12 format:
# openssl pkcs12 -export -out certs/client1.p12 -inkey private/client1.key -in certs/client1.crt -certfile certs/rootca.crt
Step 9: Client #2 certificate
generation and signing by subordinate CA:
# cd ../subCA/
# openssl genrsa -out ./private/client2.key -des3 2048
# openssl req -new -key ./private/client2.key -out client2.csr -config openssl.cnf
Enter pass phrase for ./private/client2.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:Client #2
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
# openssl ca -in client2.csr -out certs/client2.crt -config openssl.cnf
Step 10: Client #2 certificate converting to PKCS12 format:
# openssl pkcs12 -export -out certs/client2.p12 -inkey private/client2.key -in certs/client2.crt -certfile certs/subca.crt
Step 11: Passing server certificate and private key to nginx (performed with OS superuser privileges):
# cd ../rootCA/
# cp -v certs/server.crt /etc/nginx/ssl/
# cp -v private/server.key /etc/nginx/ssl/
Step 12: Passing root and subordinate CA certificates to nginx (performed with OS superuser privileges):
# cat certs/rootca.crt > /etc/nginx/ssl/client.pem
# cat ../subCA/certs/subca.crt >> /etc/nginx/ssl/client.pem
client.pem file look like this:
# cat /etc/nginx/ssl/client.pem
-----BEGIN CERTIFICATE-----
MIID6TCCAtGgAwIBAgIJAJ/7VmaN048RMA0GCSqGSIb3DQEBBQUAMFYxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnJvb3RjYTAeFw0xMzAyMDQxMDM1NTda
...
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
...
-----BEGIN CERTIFICATE-----
MIID4DCCAsigAwIBAgIBATANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
dHkgTHRkMQ8wDQYDVQQDEwZyb290Y2EwHhcNMTMwMjA0MTA0OTQzWhcNMTQwMjA0
...
-----END CERTIFICATE-----
It looks like everything is working fine:
# service nginx reload
# Reloading nginx configuration: Enter PEM pass phrase:
# nginx.
#
Step 13: Installing *.p12 certificates in browser (Firefox in my case) gives the problem I've mentioned above. Client #1 = 200 OK, Client #2 = 400 Bad request/The SSL certificate error. Any ideas what should I do?
Update 1: Results of SSL connection test attempts:
# openssl s_client -connect test.local:443 -CAfile ~/pki/rootCA/certs/rootca.crt -cert ~/pki/rootCA/certs/client1.crt -key ~/pki/rootCA/private/client1.key -showcerts
Enter pass phrase for tmp/testcert/client1.key:
CONNECTED(00000003)
depth=1 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = rootca
verify return:1
depth=0 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = test.local
verify return:1
---
Certificate chain
0 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=test.local
i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca
-----BEGIN CERTIFICATE-----
MIIDpjCCAo6gAwIBAgIBAjANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
dHkgTHRkMQ8wDQYDVQQDEwZyb290Y2EwHhcNMTMwMjA0MTEwNjAzWhcNMTQwMjA0
...
-----END CERTIFICATE-----
1 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca
i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca
-----BEGIN CERTIFICATE-----
MIID6TCCAtGgAwIBAgIJAJ/7VmaN048RMA0GCSqGSIb3DQEBBQUAMFYxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnJvb3RjYTAeFw0xMzAyMDQxMDM1NTda
...
-----END CERTIFICATE-----
---
Server certificate
subject=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=test.local
issuer=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca
---
Acceptable client certificate CA names
/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca
/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=subca
---
SSL handshake has read 3395 bytes and written 2779 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: zlib compression
Expansion: zlib compression
SSL-Session:
Protocol : TLSv1
Cipher : AES256-SHA
Session-ID: 15BFC2029691262542FAE95A48078305E76EEE7D586400F8C4F7C516B0F9D967
Session-ID-ctx:
Master-Key: 23246CF166E8F3900793F0A2561879E5DB07291F32E99591BA1CF53E6229491FEAE6858BFC9AACAF271D9C3706F139C7
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket:
0000 - c2 5e 1d d2 b5 6d 40 23-b2 40 89 e4 35 75 70 07 .^...m@#
[email protected].
0010 - 1b bb 2b e6 e0 b5 ab 10-10 bf 46 6e aa 67 7f 58 ..+.......Fn.g.X
0020 - cf 0e 65 a4 67 5a 15 ba-aa 93 4e dd 3d 6e 73 4c ..e.gZ....N.=nsL
0030 - c5 56 f6 06 24 0f 48 e6-38 36 de f1 b5 31 c5 86 .V..$.H.86...1..
...
0440 - 4c 53 39 e3 92 84 d2 d0-e5 e2 f5 8a 6a a8 86 b1 LS9.........j...
Compression: 1 (zlib compression)
Start Time: 1359989684
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
Everything seems fine with Client #2 and root CA certificate but request returns 400 Bad Request error:
# openssl s_client -connect test.local:443 -CAfile ~/pki/rootCA/certs/rootca.crt -cert ~/pki/subCA/certs/client2.crt -key ~/pki/subCA/private/client2.key -showcerts
Enter pass phrase for tmp/testcert/client2.key:
CONNECTED(00000003)
depth=1 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = rootca
verify return:1
depth=0 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = test.local
verify return:1
...
Compression: 1 (zlib compression)
Start Time: 1359989989
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
GET / HTTP/1.0
HTTP/1.1 400 Bad Request
Server: nginx/0.7.67
Date: Mon, 04 Feb 2013 15:00:43 GMT
Content-Type: text/html
Content-Length: 231
Connection: close
<html>
<head><title>400 The SSL certificate error</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<center>The SSL certificate error</center>
<hr><center>nginx/0.7.67</center>
</body>
</html>
closed
Verification fails with Client #2 certificate and subordinate CA certificate:
# openssl s_client -connect test.local:443 -CAfile ~/pki/subCA/certs/subca.crt -cert ~/pki/subCA/certs/client2.crt -key ~/pki/subCA/private/client2.key -showcerts
Enter pass phrase for tmp/testcert/client2.key:
CONNECTED(00000003)
depth=1 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = rootca
verify error:num=19:self signed certificate in certificate chain
verify return:0
...
Compression: 1 (zlib compression)
Start Time: 1359990354
Timeout : 300 (sec)
Verify return code: 19 (self signed certificate in certificate chain)
---
GET / HTTP/1.0
HTTP/1.1 400 Bad Request
...
Still getting 400 Bad Request error with concatenated CA certificates and Client #2 (but still everything ok with Client #1):
# cat certs/rootca.crt ../subCA/certs/subca.crt > certs/concatenatedca.crt
# openssl s_client -connect test.local:443 -CAfile ~/pki/rootCA/certs/concatenatedca.crt -cert ~/pki/subCA/certs/client2.crt -key ~/pki/subCA/private/client2.key -showcerts
Enter pass phrase for tmp/testcert/client2.key:
CONNECTED(00000003)
depth=1 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = rootca
verify return:1
depth=0 C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = test.local
verify return:1
---
...
Compression: 1 (zlib compression)
Start Time: 1359990772
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
GET / HTTP/1.0
HTTP/1.1 400 Bad Request
...
Update 2: I've managed to recompile nginx with enabled debug. Here is the part of successfull conection by Client #1 track:
2013/02/05 14:08:23 [debug] 38701#0: *119 accept: <MY IP ADDRESS> fd:3
2013/02/05 14:08:23 [debug] 38701#0: *119 event timer add: 3: 60000:2856497512
2013/02/05 14:08:23 [debug] 38701#0: *119 kevent set event: 3: ft:-1 fl:0025
2013/02/05 14:08:23 [debug] 38701#0: *119 malloc: 28805200:660
2013/02/05 14:08:23 [debug] 38701#0: *119 malloc: 28834400:1024
2013/02/05 14:08:23 [debug] 38701#0: *119 posix_memalign: 28860000:4096 @16
2013/02/05 14:08:23 [debug] 38701#0: *119 http check ssl handshake
2013/02/05 14:08:23 [debug] 38701#0: *119 https ssl handshake: 0x16
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL server name: "test.local"
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL_do_handshake: -1
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL_get_error: 2
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL handshake handler: 0
2013/02/05 14:08:23 [debug] 38701#0: *119 verify:1, error:0, depth:1, subject:"/C=AU /ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca",issuer: "/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca"
2013/02/05 14:08:23 [debug] 38701#0: *119 verify:1, error:0, depth:0, subject:"/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=Client #1",issuer: "/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca"
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL_do_handshake: 1
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL: TLSv1, cipher: "AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1"
2013/02/05 14:08:23 [debug] 38701#0: *119 http process request line
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL_read: -1
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL_get_error: 2
2013/02/05 14:08:23 [debug] 38701#0: *119 http process request line
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL_read: 1
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL_read: 524
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL_read: -1
2013/02/05 14:08:23 [debug] 38701#0: *119 SSL_get_error: 2
2013/02/05 14:08:23 [debug] 38701#0: *119 http request line: "GET / HTTP/1.1"
And here is the part of unsuccessfull conection by Client #2 track:
2013/02/05 13:51:34 [debug] 38701#0: *112 accept: <MY_IP_ADDRESS> fd:3
2013/02/05 13:51:34 [debug] 38701#0: *112 event timer add: 3: 60000:2855488975
2013/02/05 13:51:34 [debug] 38701#0: *112 kevent set event: 3: ft:-1 fl:0025
2013/02/05 13:51:34 [debug] 38701#0: *112 malloc: 28805200:660
2013/02/05 13:51:34 [debug] 38701#0: *112 malloc: 28834400:1024
2013/02/05 13:51:34 [debug] 38701#0: *112 posix_memalign: 28860000:4096 @16
2013/02/05 13:51:34 [debug] 38701#0: *112 http check ssl handshake
2013/02/05 13:51:34 [debug] 38701#0: *112 https ssl handshake: 0x16
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL server name: "test.local"
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL_do_handshake: -1
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL_get_error: 2
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL handshake handler: 0
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL_do_handshake: -1
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL_get_error: 2
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL handshake handler: 0
2013/02/05 13:51:34 [debug] 38701#0: *112 verify:0, error:20, depth:1, subject:"/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=subca",issuer: "/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca"
2013/02/05 13:51:34 [debug] 38701#0: *112 verify:0, error:27, depth:1, subject:"/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=subca",issuer: "/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=rootca"
2013/02/05 13:51:34 [debug] 38701#0: *112 verify:1, error:27, depth:0, subject:"/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=Client #2",issuer: "/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=subca"
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL_do_handshake: 1
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL: TLSv1, cipher: "AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1"
2013/02/05 13:51:34 [debug] 38701#0: *112 http process request line
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL_read: 1
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL_read: 524
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL_read: -1
2013/02/05 13:51:34 [debug] 38701#0: *112 SSL_get_error: 2
2013/02/05 13:51:34 [debug] 38701#0: *112 http request line: "GET / HTTP/1.1"
So I'm getting OpenSSL error #20 and then #27. According to verify documentation:
20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: unable to get local issuer certificate
the issuer certificate could not be found: this occurs if the issuer certificate of an untrusted certificate cannot be found.
27 X509_V_ERR_CERT_UNTRUSTED: certificate not trusted
the root CA is not marked as trusted for the specified purpose.