1. 程式人生 > >TLS/HTTPS 證書生成與驗證

TLS/HTTPS 證書生成與驗證

tls協議 形式 用戶輸入 兩臺 node linu get alias acer

https://www.cnblogs.com/kyrios/p/tls-and-certificates.html

最近在研究基於ssl的傳輸加密,涉及到了key和證書相關的話題,走了不少彎路,現在總結一下做個備忘

科普:TLS、SSL、HTTPS以及證書

不少人可能聽過其中的超過3個名詞,但它們究竟有什麽關聯呢?

  • TLS是傳輸層安全協議(Transport Layer Security)的縮寫,是一種對基於網絡的傳輸的加密協議,可以在受信任的第三方公證基礎上做雙方的身份認證。TLS可以用在TCP上,也可以用在無連接的UDP報文上。協議規定了身份認證、算法協商、密鑰交換等的實現。
  • SSL是TLS的前身,現在已不再更新
  • HTTPS是在基於TLS/SSL的安全套接字上的的應用層協議,除了傳輸層進行了加密外,其它與常規HTTP協議基本保持一致
  • 證書是TLS協議中用來對身份進行驗證的機制,是一種數字簽名形式的文件,包含證書擁有者的公鑰及第三方的證書信息。

證書分為2類:自簽名證書和CA證書。一般自簽名證書不能用來進行身份認證,如果一個server端使用自簽名證書,client端要麽被設置為無條件信任任何證書,要麽需要將自簽名證書的公鑰和私鑰加入受信任列表。但這樣一來就增加了server的私鑰泄露風險。

TLS基於CA的身份認證基本原理是:首先驗證方需要信任CA提供方自己的證書(CAcert),比如證書在操作系統的受信任證書列表中,或者用戶通過“安裝根證書”等方式將 CA的公鑰和私鑰加入受信任列表;然後CA對被驗證方的原始證書進行簽名(私鑰加密),生成最終的證書;驗證方得到最終的證書後,利用CAcert中包含的公鑰進行解密,得到被驗證方的原始證書。

根據RSA的加密原理,如果用CA的公鑰解密成功,說明該證書的確是用CA的私鑰加密的,可以認為被驗證方是可信的。

下面我們以客戶端單方對服務器端進行身份認證場景,來講解如何做證書的生成。

證書的生成

證書的生成可以用linux的OpenSSL工具鏈。對於一個網站,首先必須有自己的私鑰,私鑰的生成方式為:

openssl genrsa -out ssl.key 2048

私鑰必須妥善保管,既不能丟失,也不能泄露。如果發生丟失和泄露,必須馬上重新生成,以使舊的證書失效。

如果要對私鑰進行傳輸/備份,建議先對私鑰進行密碼加密:

openssl rsa -in ssl.key -des3 -out encrypted.key

利用私鑰就可以生成證書了。OpenSSL使用x509命令生成證書。這裏需要區分兩個概念:證書(certificate)和證書請求(certificate sign request)

  • 證書是自簽名或CA簽名過的憑據,用來進行身份認證
  • 證書請求是對簽名的請求,需要使用私鑰進行簽名

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證書,被簽名的其它證書就被信任了。在驗證方進行驗證時,CA證書來自操作系統的信任證書庫,或者指定的證書列表。

生成自簽名證書的方法為:

openssl x509 -req -in sign.csr -extensions v3_ca -signkey sign.key -out sign.crt

利用CA證書進行簽名

使用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連接。

TLS/HTTPS 證書生成與驗證