Keytool配置 Tomcat的HTTPS雙向認證
證照生成
keytool 簡介
Keytool是一個Java資料證照的管理工具, Keytool將金鑰(key)和證照(certificates)存在一個稱為keystore的檔案中。
在keystore裡,包含兩種資料:
- 金鑰實體(Key entity)——金鑰(secret key)又或者是私鑰和配對公鑰(採用非對稱加密)
- 可信任的證照實體(trusted certificate entries)——只包含公鑰
我們常說的證照就是就是上面的公鑰,公鑰是公開給其它人使用的
- 證照字尾解釋
jks
是Java的keytool證照工具支援的證照私鑰格式;pfx
是微軟支援的私鑰格式(p12是pfx的新格式);cer
/crt
是證照的公鑰格式(cer是crt證照的微軟形式)csr
數字證照籤名請求檔案(Cerificate Signing Request)
Tips:
.der
.cer
: 此證照檔案是二進位制格式,只含有證照資訊,不包含私鑰。.crt
: 此證照檔案是二進位制格式或文字格式,一般為文字格式,功能與.der
及.cer
證照檔案相同。.pem
: 此證照檔案一般是文字格式,可以存放證照或私鑰,或者兩者都包含。.pem
檔案如果只包含私鑰,一般用.key
檔案代替。.pfx
.p12
: 此證照檔案是二進位制格式,同時包含證照和私鑰,且一般有密碼保護。.keystore
.truststore
: 兩者本質都是keystore,都是儲存金鑰的容器:- 不過兩者存放的金鑰所有者不同,keystore是儲存自己的公鑰和私鑰而,truststore是儲存自己信任物件的公鑰。約定通過檔名稱區分型別以及用途
truststore
是必須的,如果我們沒有顯式的指定,那麼java會預設指定為$JAVA_HOME/lib/security/cacerts
這個檔案- java 在jdk 中已經預設在 $JAVA_HOME/lib/security/cacerts 這個檔案中預置了常用的證照
- 不同語言需要的證照格式並不一致,比如說Java採用jks,.Net採用pfx和cer,Php則採用pem和cer;
- 區別證照的不是字尾名,而是檔案的格式和內容。
keytool 命令詳解
-
金鑰和證照管理工具
-certreq 生成證照請求 -changealias 更改條目的別名 -delete 刪除條目 -exportcert 匯出證照(簡寫 export) -genkeypair 生成金鑰對(簡寫 genkey) -genseckey 生成金鑰 -gencert 根據證照請求生成證照 -importcert 匯入證照或證照鏈(簡寫 import) -importpass 匯入口令 -importkeystore 從其他金鑰庫匯入一個或所有條目 -keypasswd 更改條目的金鑰口令 -list 列出金鑰庫中的條目 -printcert 列印證照內容 -printcertreq 列印證照請求的內容 -printcrl 列印 CRL 檔案的內容 -storepasswd 更改金鑰庫的儲存口令
Tips:
-
使用
ketytool --help
獲取所有可用命令 -
使用
keytool -command_name -help
來獲取 command_name 的用法 -
常用引數
-genkey 產生金鑰對(genkeypair 簡寫);表示要建立一個新的金鑰;alias和keystore預設時,在使用者主目錄中建立一個”.keystore”檔案,且別名為mykey,包含使用者的公鑰、私鑰證照 -alias 產生證照別名,和keystore關聯的唯一別名,不區分大小寫(預設 `mykey`) -keystore 指定金鑰庫檔案的名稱(預設在使用者主目錄建立證照庫) -keyalg 指定金鑰的演算法(可選擇金鑰演算法:`RSA`、`DSA`、`EC`,預設`DSA`) -keysize 指定金鑰長度(與keyalg預設對應關係:`RSA=2048`、`DSA=2048`、`EC=256`) -sigalg 指定簽名演算法(MD5和 SHA1的簽名演算法已經不安全) -validity 指定證照有效期天數(預設 `90`天) -storepass 指定金鑰庫口令,推薦與keypass一致(獲取keystore資訊所需的密碼) -storetype 指定金鑰庫的型別,可用型別為:JKS、PKCS12等。(jdk9以前,預設為JKS。自jdk9開始,預設為PKCS12) -keypass 指定別名條目口令(私鑰的密碼) -dname 指定證照發行者資訊(其中 CN 要和伺服器的域名相同,本地測試則使用localhost,其他的可以不填) -list 顯示金鑰庫中的證照資訊 -v 詳細輸出,顯示金鑰庫中的證照詳細資訊 -file 指定匯出或匯出的檔名 -export 將別名指定的證照匯出到檔案(exportcert 簡寫) -import 將已簽名數字證照匯入金鑰庫(importcert 簡寫) -printcert 檢視匯出的證照資訊 -delete 刪除金鑰庫中某條目 -keypasswd 修改金鑰庫中指定條目口令 -storepasswd 修改keystore口令 -ext X.509 擴充套件
-
所有密碼長度必須大於或等於 6 位
-
keyalg 指定加密演算法;可以選擇的金鑰演算法有:RSA、DSA(預設)、EC。
-
sigalg 指定簽名演算法(MD5和 SHA1的簽名演算法已經不安全):
- keyalg = RSA 時,簽名演算法有:MD5withRSA、SHA1withRSA、SHA256withRSA(預設)、SHA384withRSA、SHA512withRSA
- keyalg = DSA 時,簽名演算法有:SHA1withDSA、SHA256withDSA(預設)
-
dname 表明了金鑰的發行者身份(Distinguished Names)
- CN = 域名或IP(Common Name) 注:生成伺服器證照時,CN要和伺服器的域名相同,本地測試則使用localhost,其他的可以不填(客戶端證照無要求)
- OU = 組織單位名稱(Organization Unit)
- O = 組織名稱(Organization Name)
- L = 城市或區域名稱(Locality Name)
- ST = 州或省份名稱(State Name)
- C = 國家的簡寫(Country,CN 代表中國)
建立證照
建立祕鑰庫(keystore),祕鑰庫是儲存一個或多個金鑰條目的檔案,每個金鑰條目應該以一個別名標識,它包含金鑰和證照相關資訊。
-
Usage:
keytool -genkey -alias <alias> -keyalg RSA [-sigalg SHA256withRSA] [-keysize 2048] -keypass <keypasswd> -keystore <keystore_file> -storetype JKS|PKCS12 -storepass <keystore_passwd> -validity 3650 -dname "CN=github.com,OU=github.com,Inc.,O=Github, Inc.,L=San Francisco,ST=California,C=US" -ext SAN=dns:github.com,dns:www.github.com,ip:127.0.0.1
-
Options:
-genkey 產生金鑰對(genkeypair 簡寫) -alias 證照別名;和keystore關聯的唯一別名,這個alias通常不區分大小寫(預設`mykey`) -keyalg 指定加密演算法,RSA:非對稱加密(預設`DSA`) -sigalg 指定簽名演算法,可選; -keysize 指定金鑰長度,可選; -keypass 指定別名條目口令(私鑰的密碼) -storetype 生成證照型別,可用的證照庫型別為:JKS、PKCS12等。 -keystore 指定產生的金鑰庫的位置; -storepass 指定金鑰庫的存取口令,推薦與keypass一致 -validity 證照有效期天數;(預設為 90天) -dname 表明了金鑰的發行者身份(Distinguished Names)生成證照時,其中 CN 要和伺服器的域名相同,本地測試則使用localhost,其他的可以不填 -ext X.509 擴充套件
Tips:
- 此處需要注意:MD5和SHA1的簽名演算法已經不安全;
- 如果Tomcat所在伺服器的域名不是“localhost”時,瀏覽器會彈出警告視窗,提示使用者證照與所在域不匹配。
- 伺服器證照 dname的 CN應改為對應的域名,如“www.github.com”;在本地做開發測試時,CN應填入“localhost”;
- 客戶端證照 dname的 CN可以是任意值,且不用使用 -ext擴充套件。
建立證照栗子
-
生成伺服器證照
keytool -genkey -alias server -keyalg RSA -keypass 123456 -keystore ~/ssl/tomcat.jks [-storetype JKS] -storepass 123456 -validity 3650 -dname "CN=localhost" -ext SAN=ip:127.0.0.1
-
生成客戶端證照,以便讓伺服器來驗證它。為了能將證照順利匯入至IE和Firefox,證照格式應該是PKCS12(客戶端的CN可以是任意值)
keytool -genkey -alias client -keyalg RSA -keypass 123456 -keystore ~/ssl/client.p12 -storetype PKCS12 -storepass 123456 -validity 3650 -dname "CN=client"
匯出證照資訊
此證照檔案不包含私鑰;分為自簽名證照和認證證照,下面分別介紹了兩中證照的生成方式
- 認證證照與匯出的伺服器自簽名證照作用一致,使用時取其中一種證照即可。兩者主要區別為是否經證照機構認證;
- 使用自簽名證照則無需生成證照籤名請求(CSR),使用認證證照則無需匯出伺服器自簽名證照;
- 大部分認證證照都是收費的;
匯出自簽名證照
自簽名證照沒有經過證照認證機構進行認證,但並不影響使用,我們可以使用相應的命令對證照進行匯出;
-
Usage:
keytool -export -alias <alias> -keystore <keystore_file> -storepass <keystore_passwd> -file <file_cer> [-rfc]
-
Options:
-export 執行證照匯出操作(exportcert 簡寫) -alias 金鑰庫中的證照條目別名(jks裡可以儲存多對公私鑰檔案,通過別名指定匯出的公鑰證照) -keystore 指定金鑰庫檔案 -storepass 金鑰庫口令 -file 匯出檔案的輸出路徑 -rfc 使用Base64格式輸出(輸出pem編碼格式的證照,文字格式),不適用則匯出的證照為DER編碼格式
匯出證照栗子
-
匯出伺服器證照
此處為伺服器的自簽名證照匯出, 如果需要使用認證證照,則生成證照籤名請求
keytool -export -alias server -keystore ~/ssl/tomcat.jks -storepass 123456 -file ~/ssl/server.cer
-
匯出客戶端證照
雙向認證: 服務端信任客戶端,由於不能直接將PKCS12格式的證照庫匯入,所以必須先把客戶端證照匯出為一個單獨的CER檔案
keytool -export -alias client -keystore ~/ssl/client.p12 -storepass 123456 -file ~/ssl/client.cer -rfc
獲取認證證照(生成證照籤名請求)
如果想得到證照認證機構的認證,則不使用上述的自簽名證照,需要使用步驟匯出數字證照並簽發申請(Cerificate Signing Request),經證照認證機構認證並頒發後,再將認證後的證照匯入本地金鑰庫與信任庫。
-
Usage:
keytool -certreq -alias <alias> -keystore <keystore_file> -storepass <keystore_passwd> -file <file_csr>
-
Options:
-certreq 執行證照籤發申請匯出操作 -alias 金鑰庫中的證照條目別名 -keystore 金鑰庫檔名稱 -storepass 金鑰庫口令 -file 輸出的csr檔案路徑
生成證照籤名請求栗子
-
生成證照籤名請求(CSR)
keytool -certreq -alias server -keystore ~/ssl/tomcat.jks -storepass 123456 -file ~/ssl/certreq.csr
-
檢視生成的CSR證照請求
keytool -printcertreq -file certreq.csr
匯入證照庫
雙向認證: 將各自的公鑰證照分別匯入對方的信任庫,使客戶端和服務端相互信任。
-
Usage:
keytool -import [-trustcacerts] -alias <alias_cer> -keystore <keystore_file> -storepass <keystore_passwd> -file <file_cer>
-
Options:
-import 執行證照匯入操作(importcert 簡寫) -alias 指定匯入金鑰庫中的證照別名(指定的條目別名不能與金鑰庫中已存在的條目別名重複(匯入簽發證照除外)) -trustcacerts 將證照匯入信任庫(信任來自 cacerts 的證照) -keystore 金鑰庫名稱 -storepass 金鑰庫口令 -file 輸入檔名
匯入證照栗子
-
安裝伺服器證照(將伺服器公鑰證照匯入客戶端)
雙向認證: 客戶端信任服務端: 在客戶機器上雙擊證照檔案完成匯入操作(window中匯入)
- 將伺服器公鑰證照 server.cer 發往客戶端機器 >> 雙擊該證照進入“證照資訊”頁 >> 點選【安裝證照】進入“證照匯入嚮導”首頁 >> 點選【下一步】>> 選中【將所有的證照都放入下列儲存】,然後單擊【瀏覽】 >> 選擇【受信任的根證照頒發機構】b並點選【確定】 >> 點選【下一步】 >> 點選【完成】。然後彈出提示【匯入完成】。
- 將客戶端證照 client.p12 發往客戶端機器 >> 雙擊該證照進入“證照匯入嚮導”首頁 >> 點選【下一步】>> 點選【下一步】>> 輸入證照密碼(keystore密碼)並點選【下一步】 >> 點選【下一步】 >> 點選【完成】。然後彈出提示【匯入完成】。
-
證照匯入信任庫(將客戶端公鑰證照匯入信任庫)
雙向認證: 服務端信任客戶端:
keytool -import -alias clientCert -keystore ~/ssl/truststore.jks -storepass 123456 -file ~/ssl/client.cer
此步驟會生成信任證照 truststore.jks檔案, 檔案存放需要信任的公鑰證照,如客戶端證照(也可以將 keystore值改為伺服器金鑰庫,即tomcat.jks。此時的tomcat.jks 就同時是服務的金鑰庫和信任庫)
檢視證照
-
Usage:
# 檢視單個證照(cer | crt) keytool -printcert -file <cert_file> [-v|-rfc] # 檢視金鑰庫中的證照條目 keytool -list [-alias <alias_name>] -keystore <keystore_file> -storepass <keystore_passwd> [-v|-rfc] # 檢視生成的CSR證照請求 keytool -printcertreq -file <certreq_file>
-
Options:
-alias 金鑰庫中的證照條目別名; -keystore 指定金鑰庫檔案; -storepass 金鑰庫口令; -printcert 執行證照列印命令; -list 預設情況下,命令列印證照的 MD5 指紋。 而如果指定了 -v 選項,將以可讀格式列印證照, 如果指定了 -rfc 選項,將以可列印的編碼格式輸出證照。
檢視栗子證照
-
檢視證照資訊
keytool -printcert -file ~/ssl/client.cer [-v|-rfc]
-
檢視金鑰庫
keytool -list -keystore ~/ssl/tomcat.jks -storepass 123456 -v
-
檢視base64的內容(即PEM編碼)
keytool -list -keystore ~/ssl/tomcat.jks -storepass 123456 -rfc
其他keytool命令
# 刪除keystore裡面指定證照條目
keytool -delete -alias <alias> -keystore <keystore_file> -storepass <keystore_passwd>
# 修改條目別名
keytool -changealias -keystore <keystore_file> -alias <old_alias> -destalias <new_alias>
# 修改條目密碼
keytool -keypasswd -alias <alias> -keypass <old_keypasswd> -new <new_keypasswd> -keystore <keystore_file> -storepass <keystore_passwd>
# 修改keysore密碼
keytool -storepasswd -new <new_storepasswd> -keystore <keystore_file> -storepass <old_storepasswd>
# 列出信任的CA證照(檢視 JVM的信任庫中的證照,storepass 預設為changeit)
## 該證照檔案存在於JAVA_HOME\jre\lib\security目錄下,是Java系統的CA證照倉庫,可以用 'alias' 來檢視證照是否真的匯入到JVM中
keytool -list -v [-alias clientCer] -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
# 匯入新的CA到信任證照,匯入到 JRE的信任證照庫
## 常出現的異常:“未找到可信任的證照” -- 主要原因為在客戶端未將伺服器下發的證照匯入到JVM中。
keytool -import -trustcacerts -alias clientCer -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -file ~/ssl/client.cer
Tomcat服務認證配置
開啟Tomcat_HOME/conf/server.xml,找到如下原註釋內容,並修改如下:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS"
keystoreFile="~/ssl/tomcat.jks" keystorePass="123456"
truststoreFile="~/ssl/truststore.jks" truststorePass="123456"
/>
Tips:
- 其中
clientAuth
指定是否需要驗證客戶端證照 false
: 表示單向SSL驗證,即服務端認證;true
: 表示強制雙向SSL驗證,必須驗證客戶端證照;want
: 表示可以驗證客戶端證照,但如果客戶端沒有有效證照,也不強制驗證。- 如果設定了clientAuth="true",則需要強制驗證客戶端證照。可通過雙擊
p12
檔案將證照匯入至瀏覽器; - 瀏覽器的HTTP預設埠為
80
, HTTPS預設埠為443
; keystoreFile
/keystorePass
: 伺服器證照檔案和密碼;truststoreFile
/truststorePass
: 信任證照檔案和密碼;用來驗證客戶端的。
SSL單向證照認證配置
- 建立伺服器證照
- 匯出伺服器公鑰證照
- 將伺服器公鑰證照匯入客戶端(客戶端信任伺服器)
- 配置 Tomcat
開啟Tomcat_HOME/conf/server.xml,找到如下原註釋內容,並修改如下:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="~/ssl/tomcat.jks" keystorePass="123456"()
/>
SSL雙向證照認證配置
-
建立伺服器證照,建立客戶端證照
-
匯出伺服器公鑰證照,匯出客戶端公鑰證照
-
將伺服器公鑰證照匯入客戶端(客戶端信任伺服器)
-
將客戶端公鑰證照匯入信任庫(伺服器信任客戶端)
-
配置 Tomcat,並開啟雙向認證():
開啟Tomcat_HOME/conf/server.xml,找到如下原註釋內容,並修改如下:<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="true" sslProtocol="TLS" keystoreFile="~/ssl/tomcat.jks" keystorePass="123456" truststoreFile="~/ssl/truststore.jks" truststorePass="123456" />
配置Tomcat服務 HTTP自動跳轉到 HTTPS(按需選配)
開啟Tomcat_HOME/conf/web.xml,在 與 加入如下程式碼:
<login-config>
<!-- Authorization setting for SSL -->
<auth-method>CLIENT-CERT</auth-method>
<realm-name>Client Cert Users-only Area</realm-name>
</login-config>
<security-constraint>
<!-- Authorization setting for SSL -->
<web-resource-collection >
<web-resource-name >SSL</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
測試
- 啟動 Tomcat專案
- 訪問 專案地址,本地配置如: https://localhost:8443/
- 如果遇到“不安全”的提示,可能是客戶端未安裝伺服器證照
常見問題
瀏覽器訪問時提示:
-
此伺服器無法證實它是“192.168..” - 您計算機的作業系統不信任其安全證照 。。。
--客戶端未匯入伺服器證照 -
此伺服器無法證實它就是“192.168..” - 它的安全證照沒有指定主題備用名稱 。。。
--生成伺服器證照庫未使用 -ext引數 -
“192.168..”不接受您的登入證照,或者您可能沒有提供登入證照。。。
--Tomcat配置未指定信任證照庫(truststore)
Reference