轉自:http://www.cnblogs.com/kyrios/p/tls-and-certificates.htmlhtml
最近在研究基於ssl的傳輸加密,涉及到了key和證書相關的話題,走了很多彎路,如今總結一下作個備忘java
很多人可能聽過其中的超過3個名詞,但它們究竟有什麼關聯呢?node
證書分爲2類:自簽名證書和CA證書。通常自簽名證書不能用來進行身份認證,若是一個server端使用自簽名證書,client端要麼被設置爲無條件信任任何證書,要麼須要將自簽名證書的公鑰和私鑰加入受信任列表。但這樣一來就增長了server的私鑰泄露風險。linux
TLS基於CA的身份認證基本原理是:首先驗證方須要信任CA提供方本身的證書(CAcert),好比證書在操做系統的受信任證書列表中,或者用戶經過「安裝根證書」等方式將 CA的公鑰和私鑰加入受信任列表;而後CA對被驗證方的原始證書進行簽名(私鑰加密),生成最終的證書;驗證方獲得最終的證書後,利用CAcert中包含的公鑰進行解密,獲得被驗證方的原始證書。android
根據RSA的加密原理,若是用CA的公鑰解密成功,說明該證書的確是用CA的私鑰加密的,能夠認爲被驗證方是可信的。ios
下面咱們以客戶端單方對服務器端進行身份認證場景,來說解如何作證書的生成。nginx
證書的生成能夠用linux的OpenSSL工具鏈。對於一個網站,首先必須有本身的私鑰,私鑰的生成方式爲:算法
openssl genrsa -out ssl.key 2048
私鑰必須妥善保管,既不能丟失,也不能泄露。若是發生丟失和泄露,必須立刻從新生成,以使舊的證書失效。tomcat
若是要對私鑰進行傳輸/備份,建議先對私鑰進行密碼加密:安全
openssl rsa -in ssl.key -des3 -out encrypted.key
利用私鑰就能夠生成證書了。OpenSSL使用x509命令生成證書。這裏須要區分兩個概念:證書(certificate)和證書請求(certificate sign request)
x509命令能夠將證書和證書請求相互轉換,不過咱們這裏只用到從證書請求到證書的過程
從私鑰或已加密的私鑰都可以生成證書請求。生成證書請求的方法爲:
openssl req -new -key ssl.key -out ssl.csr
若是私鑰已加密,須要輸入密碼。req命令會經過命令行要求用戶輸入國家、地區、組織等信息,這些信息會附加在證書中展現給鏈接方。
接下來用私鑰對證書請求進行簽名。根據不一樣的場景,簽名的方式也略有不一樣
自簽名的原理是用私鑰對該私鑰生成的證書請求進行簽名,生成證書文件。該證書的簽發者就是本身,因此驗證方必須有該證書的私鑰才能對簽發信息進行驗證,因此要麼驗證方信任一切證書,面臨冒名頂替的風險,要麼被驗證方的私鑰(或加密過的私鑰)須要發送到驗證方手中,面臨私鑰泄露的風險。
固然自簽名也不是一無用處,好比須要內部通信的兩臺電腦須要使用加密又不想用第三方證書,能夠在兩端使用相同的私鑰和證書進行驗證(固然這樣就跟對稱加密沒有區別了)
自簽名的方法爲:
openssl x509 -req -in ssl.csr -signkey ssl.key -out ssl.crt
一樣若是ssl.key已加密,須要輸入密碼。
CA證書是一種特殊的自簽名證書,能夠用來對其它證書進行簽名。這樣當驗證方選擇信任了CA證書,被簽名的其它證書就被信任了。在驗證方進行驗證時,CA證書來自操做系統的信任證書庫,或者指定的證書列表。
生成自簽名證書的方法爲:
openssl x509 -req -in sign.csr -extensions v3_ca -signkey sign.key -out sign.crt
使用CA證書對其它證書進行簽名的方法爲:
openssl x509 -req -in ssl.csr -extensions v3_usr -CA sign.crt -CAkey sign.key -CAcreateserial -out ssl.crt
利用上述方法,受信任的機構就能夠用本身的私鑰(sign.key)對其餘人的證書進行簽名。咱們看到,只須要把證書請求(ssl.csr)發給證書機構,證書機構就能夠生成出簽名過的證書(ssl.crt)。目前購買證書籤名服務的價格大約爲100-400元/年。
可選的證書機構有:godaddy startssl namecheap
openssl默認使用PEM格式(形如-----BEGIN CERTIFICATE----- ... ... -----END CERTIFICATE---)存放證書和私鑰,nginx/node.js可使用該格式啓動服務。
但使用tomcat或java客戶端/android時,不能使用該格式的證書。jdk中包含了一個keytool命令,能夠完成整個的證書生成過程,不過這裏咱們只用openssl工具也能夠完成java的支持,即便用PKCS12格式對證書進行打包。
PKCS12格式文件,能夠包含多個證書/私鑰對,指定多個受信任的server(也能夠不包含證書),每一個server有一個alias name。咱們來看最簡單的只包含一個alias的文件生成:
openssl pkcs12 -export -in sign.crt -inkey sign.key -out sign.p12
上面的命令將CA證書及其私鑰導出爲sign.p12文件,導出時須要指定一個密碼。
java客戶端程序中對p12文件進行信任
若是咱們的服務器使用了本身建立的CA證書籤名的證書,或者使用了自簽名證書,客戶端在使用ssl時,須要將導出的證書文件加入到信任列表中。下面是一段導入證書的示例代碼:
1 javax.net.SocketFactory initSSLSocketFactory(InputStream keyin, char[] password) throws Exception { 2 java.security.KeyStore keyStore = java.security.KeyStore.getInstance("PKCS12"); 3 keyStore.load(keyin, password); 4 keyin.close(); 5 6 javax.net.ssl.TrustManagerFactory trustManagerFactory = javax.net.ssl.TrustManagerFactory.getInstance(javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm()); 7 trustManagerFactory.init(keyStore); 8 9 javax.net.ssl.SSLContext sslContext = javax.net.ssl.SSLContext.getInstance("SSL"); 10 11 sslContext.init(null, trustManagerFactory.getTrustManagers(), null); 12 13 return sslContext.getSocketFactory(); 14 }
咱們獲得了一個SocketFactory,能夠用它來初始化ssl/https鏈接。