jdk自帶的證書管理工具叫keytool,在jdk/bin目錄下,可以用來生成自簽名證書、導入導出證書、打印證書信息等。
1. 名詞
自簽名證書:用自己的私鑰簽發自己的公鑰即主體信息生成的證書。
證書簽名:對證書固定值進行hash后用密鑰對中的私鑰對hash值加密
keystore: keytool生成證書的存儲庫,用來存儲若干條目,每一條目包含公私鑰,主體信息等。默認為用戶目錄下.keystore,相當于一個有密碼保護的文件。
truststore: 與keystore格式相同,但是為區分只用來存放信任的證書,不存密鑰等信息。
der:證書編碼格式,證書結構體轉換為二進制格式。
pem:證書編碼格式,對der二進制編碼的base64字符,包含---begin---,----end----。// 命令中加-rfc可打印和生成此類文件
.csr:證書請求文件格式,包含公鑰和主體信息,發給ca,ca用私鑰對內容簽名并制作成證書返回。keytool在生成csr文件時需要指定證書(即公鑰與主體信息)。
.crt:一般用于linux系統的證書格式,包含公鑰和主體信息。
.cer:一般用于windows的證書文件格式,包含公鑰和主體信息。
.p12:證書交換格式,包含公鑰私鑰(私用密碼加密),用于交換傳輸。
2.具體使用
可以以一個完整例子來了解keytool命令。在socket或http協議傳輸數據時,如需加密傳輸會話內容,會在TCP上加上ssl/tls,http則改為https協議。此時服務端需要給客戶端提供證書以供客戶端驗證并協商會話密鑰,如果沒有正規CA簽發的證書,則需自簽名。
客戶端用簽發證書的根證書驗證,如果是自簽名一級證書,則客戶端需內置此自簽名證書,如果是自簽名二級證書,則用簽發它的跟證書驗證
- 生成自簽名證書
keytool -genkeypair -alias golove -keysize 2048 -keyalg RSA -validity 3650 -keystore teststore.jks -storetype JKS
- genkeypair:生成公私鑰對條目,私鑰不可見,公鑰會以證書格式保存在keystore中。
- alias: 指定別名,區分不同條目,默認mykey
- keysize: 密鑰長度
- keyalg: 公私鑰算法
- validity: 證書過期時間
- keystore: 指定存儲密鑰庫,若不存在會創建,若指定則在當前文件夾下生成。默認密鑰庫為用戶目錄下.keystore文件
- storetype: 密鑰庫類型 JKS PKCS等
輸入密鑰庫密碼和本條目密碼都為123456,以及其他主體信息會生成密鑰對保存在teststore.jks中。公鑰以證書格式保存,帶有主體信息。此時證書庫中可以看到公鑰信息(私鑰無法打印)
第一條主體信息:您的姓名與姓氏中填入服務器域名的完整信息而非name,如:www.golove.com。
- 導出自簽名證書
// 如果要生成pem編碼格式的證書直接加上 -rfc參數即可,證書詳細信息格式用 -v
keytool -export -alias golove -keystore teststore.jks -file golove.crt
現在可以將此證書分發給客戶端了,客戶端做相應配置,驗證域名或直接跳過驗證(因為是用它自身公鑰驗證,不能保證安全性,一般默認信任),使用此證書與服務端交換隨機數。
接下來稍微了解下keystore內容并生成一個跟證書來簽發二級證書。
- 查看keystore中證書條目列表
keytool -list -v -keystore teststore.jks
再看下剛才根據此條目導出的自簽證書,導出后已經包含了公鑰等其他信息形成了完整證書,但注意verifiedby字段還是自己
- 生成證書簽名請求(CSR文件)
keytool -certreq -alias golove -keystore teststore.jks -file temp_go_love.csr
用keystore中golove條目生成了證書簽名請求文件temp_go_love.csr,內包含golove條目的公鑰和主體信息,將證書簽名請求文件發給正規CA,CA用私鑰對公鑰和信息簽名后制作成證書文件返回就可以使用了。正規CA的公鑰瀏覽器內置,所以此時瀏覽器可以驗簽名成功。
但我們要自己模擬CA簽發二級證書,CA也是要有公私鑰對,所以先生成CA密鑰對。
- 生成一個自簽名證書作為CA根證書,名字與姓氏選項這里填入root
keytool -genkeypair -alias rootca -keysize 2048 -keyalg RSA -validity 3650 -keystore teststore.jks -storetype JKS
-使用CA證書給golove證書簽名,即用CA的私鑰簽名后與golove的公鑰生成一個證書
keytool -gencert -alias rootca -keystore teststore.jks -infile temp_go_love.csr -outfile golove_new.crt
此時已經生成了一個golove_new.crt的二級證書,以文件形式打開golove.crt和golove_new.crt兩個證書文件對比下內容。
golove.crt:
golove_new.crt:
可以看到簽發者已經變成root,公鑰等其他信息不變,但簽名值變了,說明已經用新的私鑰(root私鑰)替換原有(golove)簽名,在證書信任連上序號為2,此即二級證書。
- 將二級證書導回teststore庫中,并且直接替換原有別名為golove的條目
keytool -import -v -alias golove -file golove_new.crt -keystore teststore.jks
再次打印證書庫中條目列表可以看到別名為golovet的條目證書鏈變為2,發布者變為root.
此時可以將root證書導出給客戶端內置,服務端綁定二級證書,這樣客戶端驗證時可以用根證書驗證二級證書。其實大部分程序直接使用一級的自簽名證書即可,但若需要雙向驗證,服務端驗證客戶端時不同客戶端最好使用服務端的rootca私鑰來簽發,這樣服務端可以直接用一個rootca的證書驗證。實現了動態擴展且客戶端的證書不同。
-為了區分teststore,可以新建一個只放信任證書,不存儲密鑰的倉庫。將剛才的rootca證書和golove二級證書導入一個新倉庫(如果為了方便,也可以直接用一個密鑰庫,不需要此庫)
// 從teststore導出rootca證書
keytool -export -alias rootca -keystore teststore.jks -file rootca.crt
// 導入rootca證書到新庫
keytool -import -v -file rootca.crt -alias rootca -keystore truststore.jks
// 導入golove證書到新庫
keytool -import -v -file golove_new.crt -alias golove -keystore truststore.jks
keytool 常用命令:
// 以rfc模式打印,即base64可見字符,與pem編碼格式一樣。 -v為詳細輸出
keytool -printcert -rfc -file rootca.ctr
// 查看證書庫中證書條目列表 詳細信息
keytool -list -v -keystore teststore.jks
// 將證書庫中的條目導出為證書文件,如要生成可見字符編碼格式的證書文件 加上 -rfc 參數即可。
keytool -export -alias rootca -keystore teststore.jks -file rootca.ctr
// 刪除密鑰庫中的條目
keytool -delete -alias rootca -keystore teststore.keystore
// 修改證書庫密碼,輸入舊密碼或加參數 -storepass 111111
keytool -storepasswd -new 123456 -keystore truststore
// 修改某條目密碼
keytool -keypasswd -alias myCA -keypass 654321 -new newpass -storepass 123456 -keystore myCALib
還有一個問題,keytool不能打印出密鑰對中的私鑰,用-list查看密鑰庫列表也沒有完整的私鑰信息。要獲取私鑰,可以在java程序中加載密鑰庫,用jdk KeyStore類的相關方法獲取到公私鑰信息,然后做加解密的驗證等。
有不對的地方請指出...