我正在尝试设置根证书颁发机构,从属证书颁发机构,并生成由Debian Squeeze上的Nginx 0.7.67接受的任何此CA签名的客户端证书.我的问题是根CA签名的客户端证书工作正常,而从属CA签名的一个导致“400 Bad Request.SSL证书错误”.
第1步:Nginx虚拟主机配置:
- 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/;
- }
- }
第2步:根和从属CA的PKI基础架构组织(基于this文章):
- # 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/
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
和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
第3步:自签名根CA证书生成:
- # 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 []:
第4步:从属CA证书生成:
- # 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,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 []:
步骤5:根CA证书的从属CA证书签名:
- # 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
步骤6:根CA(对于Nginx虚拟主机)生成和签名服务器证书:
- # 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,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
步骤7:客户端#1证书生成和根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,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
步骤8:客户端#1证书转换为PKCS12格式:
- # openssl pkcs12 -export -out certs/client1.p12 -inkey private/client1.key -in certs/client1.crt -certfile certs/rootca.crt
步骤9:下属CA生成和签署客户端#2证书:
- # 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,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
步骤10:客户端#2证书转换为PKCS12格式:
- # openssl pkcs12 -export -out certs/client2.p12 -inkey private/client2.key -in certs/client2.crt -certfile certs/subca.crt
步骤11:将服务器证书和私钥传递给Nginx(使用OS超级用户权限执行):
步骤12:将根CA和从属CA证书传递给Nginx(使用OS超级用户权限执行):
client.pem文件如下所示:
- # 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-----
看起来一切正常:
步骤13:在浏览器中安装* .p12证书(在我的情况下为Firefox)给出了我上面提到的问题.客户端#1 = 200 OK,客户端#2 = 400错误请求/ SSL证书错误.任何想法我该怎么办?
更新1:SSL连接测试尝试的结果:
- # 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,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@#.@..5up.
- 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)
- ---
客户端#2和根CA证书似乎一切正常,但请求返回400错误请求错误:
- # 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,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
客户端#2证书和从属CA证书的验证失败:
- # 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,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
- ...
串联CA证书和客户端#2仍然会出现400错误请求错误(但客户端#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,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
- ...
更新2:我已设法通过启用调试重新编译Nginx.以下是Client#1轨道成功连接的部分:
- 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,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"
以下是Client#2轨道不成功连接的部分:
- 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,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,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,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"
所以我得到OpenSSL错误#20然后#27.根据验证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.
解决方法
据我所理解,
- ssl_verify_depth 2;
应该做的伎俩.有关详情,请参见http://nginx.org/r/ssl_verify_depth.