介紹了SSL雙向認證的一些基本問題,以及使用Nginx+PHP基於它搭建https的Webservice。
之前的方式只是實現1:1的模式,昨天同事繼續實現了n:1的模式,這里我再整理記錄下。
由於nginx的ssl_client_certificate參數只能指定一個客戶端公鑰,如果增加一個客戶端進行通信就要重新配一個server。
n:1的模式是通過CA的級聯證書模式實現的,首先自己生成一套CA根級證書,再借助其生成二級證書作為client證書。
此時client私鑰簽名不僅可以通過對應的client公鑰驗證,還可通過根證書的公鑰進行驗證。
看到這里應該豁然開朗了吧,下面簡單介紹下具體怎么操作:
1 准備工作
1.1 openssl目錄准備
一般情況下openssl的配置文件都在這個目錄/etc/pki/tls,so:
mkdir /etc/pki/ca_linvo
cd /etc/pki/ca_linvo
mkdir root server client newcerts
echo 01 > serial
echo 01 > crlnumber
touch index.txt
1.2 openssl配置准備
修改openssl配置
vi /etc/pki/tls/openssl.cnf
找到這句注釋掉,替換為下面那句
#default_ca = CA_default
default_ca = CA_linvo
把整個部分拷貝一份,改成上面的名字[ CA_linvo ]
修改里面的如下參數:
dir = /etc/pki/ca_linvo
certificate = $dir/root/ca.crt
private_key = $dir/root/ca.key
保存退出
2 創建CA根級證書
生成csr:openssl req -new -key /etc/pki/ca_linvo/root/ca.key -out /etc/pki/ca_linvo/root/ca.csr
生成crt:openssl x509 -req -days 3650 -in /etc/pki/ca_linvo/root/ca.csr -signkey /etc/pki/ca_linvo/root/ca.key -out /etc/pki/ca_linvo/root/ca.crt
生成crl:openssl ca -gencrl -out /etc/pki/ca_linvo/root/ca.crl -crldays 7
生成的根級證書文件都在/etc/pki/ca_linvo/root/目錄下
注意:創建證書時,建議證書密碼設置長度>=6位,因為java的keytool工具貌似對它有要求。
3 創建server證書
生成key:openssl genrsa -out /etc/pki/ca_linvo/server/server.key
生成csr:openssl req -new -key /etc/pki/ca_linvo/server/server.key -out /etc/pki/ca_linvo/server/server.csr
生成crt:openssl ca -in /etc/pki/ca_linvo/server/server.csr -cert /etc/pki/ca_linvo/root/ca.crt -keyfile /etc/pki/ca_linvo/root/ca.key -out /etc/pki/ca_linvo/server/server.crt -days 3650
說明:
1、這里生成的crt是剛才ca根級證書下的級聯證書,其實server證書主要用於配置正常單向的https,所以不使用級聯模式也可以:
openssl rsa -in /etc/pki/ca_linvo/server/server.key -out /etc/pki/ca_linvo/server/server.key
openssl x509 -req -in /etc/pki/ca_linvo/server/server.csr -signkey /etc/pki/ca_linvo/server/server.key -out /etc/pki/ca_linvo/server/server.crt -days 3650
2、-days 參數可根據需要設置證書的有效期,例如默認365天
4 創建client證書
生成key:openssl genrsa -des3 -out /etc/pki/ca_linvo/client/client.key 1024
生成csr:openssl req -new -key /etc/pki/ca_linvo/client/client.key -out /etc/pki/ca_linvo/client/client.csr
生成crt:openssl ca -in /etc/pki/ca_linvo/client/client.csr -cert /etc/pki/ca_linvo/root/ca.crt -keyfile /etc/pki/ca_linvo/root/ca.key -out /etc/pki/ca_linvo/client/client.crt -days 3650
說明:
1、這里就必須使用級聯證書,並且可以重復該步驟,創建多套client證書
2、生成crt時可能會遇到如下報錯:
openssl TXT_DB error number 2 failed to update database
可參照這里進行操作。
我使用的是方法一,即將index.txt.attr中unique_subject = no
5 配置nginx
這里只列出server段的關鍵部分:
ssl_certificate /etc/pki/ca_linvo/server/server.crt;#server公鑰
ssl_certificate_key /etc/pki/ca_linvo/server/server.key;#server私鑰
ssl_client_certificate /etc/pki/ca_linvo/root/ca.crt;#根級證書公鑰,用於驗證各個二級client
ssl_verify_client on;
重啟Nginx
6 測試
6.1 瀏覽器測試
6.2 php curl測試
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何證書,不是CA機構頒布的也沒關系
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); // 檢查證書中是否設置域名,如果不想驗證也可設為0
- curl_setopt($ch, CURLOPT_VERBOSE, '1'); //debug模式,方便出錯調試
- curl_setopt($ch, CURLOPT_SSLCERT, CLIENT_CRT); //client.crt文件路徑,這里我用常量代替
- curl_setopt($ch, CURLOPT_SSLCERTPASSWD, CRT_PWD); //client證書密碼
- curl_setopt($ch, CURLOPT_SSLKEY, CLIENT_KEY); //client.key文件路徑
6.3 php soap測試
首先需要構建client的pem格式證書,通過openssl命令也可以,不過因為我們已經有了crt和key,所以手動合並也很簡單:
新建一個文件,把crt中-----BEGIN CERTIFICATE-----和-----END CERTIFICATE-----之間的base64內容(包括這兩個分割線)拷貝進去,然后把key中-----BEGIN RSA PRIVATE KEY-----和-----END RSA PRIVATE KEY-----之間的內容也復制進去,然后保存為client.pem即可。
其實更省事的話可以如下命令,直接合並兩個文件:
cat /etc/pki/ca_linvo/client/client.crt /etc/pki/ca_linvo/client/client.key > /etc/pki/ca_linvo/client/client.pem
有了pem文件,下面可以使用php內置的SoapClient進行調用,構造函數需要設置第二個參數:
- $header = array(
- 'local_cert' => CLIENT_PEM, //client.pem文件路徑
- 'passphrase' => CRT_PWD //client證書密碼
- );
- $client = new SoapClient(FILE_WSDL, $header); //FILE_WSDL為要訪問的https地址
上一篇博客里最后說到local_cert設置成遠程路徑的話會報錯,好像是因為第一次獲取wsdl時並沒有使用client證書的原因,需要將wsdl保持成本地文件進行調用;
但是這次測試卻沒問題,不用另存為本地文件,直接遠程獲取即可。
本來認為是之前的證書有問題,但是使用之前的那套證書依然可以,很是詭異~~~~~