1. 程式人生 > >SSL與CA

SSL與CA

某專案的業務系統要求在使用者使用的過程使用數字證書。在剛接手這個任務時,我對箇中的知識幾乎不瞭解,於是到處搜刮相關資料,網上此類文章甚多,但都比較零散,而且個人認為其中絕大部分未能盡釋所疑。在經歷了數天的鬱悶及實踐以後,終有所悟,作此文以記。

1          對稱加密與非對稱加密

對稱加密方法的加密與解密採用相同的金鑰,因此任何人只要獲得其中的金鑰,就可以對密文進行解密。而非對稱加密方法有兩個不同金鑰,任意一個都可以成為加密金鑰,另外一個就是解密金鑰,用一個金鑰加密的密文必須用另一個金鑰才可以解密。


2          公鑰與私鑰

在非對稱加密方法的兩個金鑰中,保管其中一個金鑰,禁止洩漏他人,除了金鑰擁有者以外,任何人都不知道,此即私鑰。另一個金鑰則公之於眾,任何人都可以獲得,此即公鑰。可知,用私鑰加密的密文必須用公鑰解密,反之亦然。


3          數字簽名

數字簽名是基於非對稱加密方法來實現的。擁有私鑰的一方使用私鑰對某一份內容加密後傳送給其他人(個體或群休),因為任何人都可以擁有與該私鑰對應的公鑰,擁有公鑰者使用公鑰對接收到的密文進行解密,如果能正確解密,則說明此份內容必然是擁有私鑰的一方發出。另一方面,如果擁有公鑰的實體希望把一份內容傳送給擁有私鑰的一方而不希望其它任何人看到,則可以利用該公鑰加密此份內容。因為只有私鑰擁有者才可以將密文解密,所以能保證任何其他人無法檢視其內容。


4          數字證書

數字證書是以數字簽名的方式通過第三方權威認證機構有效地進行網上身份認證,以幫助各個實體識別對方身份及表明自身身份的證書,具有防抵賴功能及真實、安全、保密和防篡改的特性。在此,我們最主要的是需要知道數字證書是一個檔案,該檔案儲存了某個實體(個人、機構或裝置等)的資訊及該實體所擁有私鑰對應的公鑰。


5          SSL協議這裡

主要介紹SSL握手協議以建立安全通訊通道的過程。


1)        客戶端的瀏覽器向伺服器傳送客戶端 SSL 協議的版本號,加密演算法的種類,產生的隨機數,以及其他伺服器和客戶端之間通訊所需要的各種資訊。

2)        伺服器向客戶端傳送 SSL 協議的版本號,加密演算法的種類,隨機數以及其他相關資訊,同時伺服器還將向客戶端傳送自己的證書。

3)        客戶利用伺服器傳過來的資訊驗證伺服器的合法性。伺服器的合法性包括:證書是否過期,發行伺服器證書的 CA 是否可靠,發行者證書的公鑰能否正確解開伺服器證書的“發行者的數字簽名”,伺服器證書上的域名是否和伺服器的實際域名相匹配。如果合法性驗證沒有通過,通訊將斷開;如果合法性驗證通過,將繼續進行第4)步。

4)        客戶端隨機產生一個用於後面通訊的“對稱密碼”,然後用伺服器的公鑰(伺服器的公鑰從步驟2)中的伺服器的證書中獲得)對其加密,然後將加密後的“預主密碼”傳給伺服器。

5)        如果伺服器要求客戶的身份認證(在握手過程中為可選),使用者可以建立一個隨機數然後對其進行資料簽名,將這個含有簽名的隨機數和客戶自己的證書以及加密過的“預主密碼”一起傳給伺服器。

6)        如果伺服器要求客戶的身份認證,伺服器必須檢驗客戶證書和簽名隨機數的合法性。具體的合法性驗證過程包括:客戶的證書使用日期是否有效,為客戶提供證書的 CA 是否可靠,發行 CA 的公鑰能否正確解開客戶證書的發行 CA 的數字簽名,檢查客戶的證書是否在證書廢止列表(CRL)中。檢驗如果沒有通過,通訊立刻中斷;如果驗證通過,伺服器將用自己的私鑰解開加密的“預主密碼”,然後執行一系列步驟來產生主通訊密碼(客戶端也將通過同樣的方法產生相同的主通訊密碼)。

7)        伺服器和客戶端用相同的主密碼即“通話密碼”,一個對稱金鑰用於 SSL 協議的安全資料通訊的加解密通訊。同時在 SSL 通訊過程中還要完成資料通訊的完整性,防止資料通訊中的任何變化。

8)        客戶端向伺服器端發出資訊,指明後面的資料通訊將使用的步驟7)中的主密碼為對稱金鑰,同時通知伺服器客戶端的握手過程結束。

9)        伺服器向客戶端發出資訊,指明後面的資料通訊將使用的步驟7)中的主密碼為對稱金鑰,同時通知客戶端伺服器端的握手過程結束。

10)     SSL 的握手部分結束,SSL 安全通道的資料通訊開始,客戶和伺服器開始使用相同的對稱金鑰進行資料通訊,同時進行通訊完整性的檢驗。

6          從何處獲得證書

基本的原理差不多就這些,下一個問題是從哪裡獲得數字證書?從前面的SSL握手過程可以知道,客戶端需要檢視伺服器的證書,以證明伺服器的身份,而伺服器端也要(當然這需要伺服器有相關的配置)檢視客戶端證書以證明客戶的身份。因此我們至少需要兩個證書:伺服器證書和客戶證書。事實上,每一個客戶都可以擁有自己的證書以證明自己的身份。當一個實體需要一個證書的時候,需要向相關的權威認證機構申請,比如GDCA,由該權威機構向該實體頒發證書。所謂權威機構就是已經被另一個權威機構證明是真實有效的機構,因此這是一個遞迴的過程,在最頂層有一個虛擬的根機構,被稱為RootCA。申請證書需要一定的費用,根據證書型別的不同而不同,從GDCA的網站上得知,個人證書是50元/年,而網站證書則需要10000元/年。如果申請一個有效其為10年的證書,這是一筆不小的費用。那麼能不能不申請而獲得證書呢?


7          自己做CA

首先要說明,不管你的證書是由哪個機構頒發的,對於通訊過程來說都是安全的。因此對於某個特定範圍的圈子來說,完全可以由該圈子中公認的機構做CA。對於一個企業來說,企業及其客戶所組成的圈子中,企業可以認為是具有權威性的,於是就可以作為一個權威機構向其客戶頒發證書。據瞭解,廣東發展銀行及中國建設銀行客戶所用的數字證書就是該銀行頒發的。在這裡需要使用一個軟體openssl。Openssl的功能相當強大,偶對其中的功能也不甚瞭解,只瞭解其中與CA認證相關的部分功能,基本上可以滿足自己做CA的要求。在使用openssl前,先要設定一個環境變數OPENSSL_CONF,使其指向openssl安裝目錄下的openssl.cnf檔案。產生證書的過程大致為:生成金鑰對->生成簽證請求->簽證。簽證後的證書就為數字證書,其中儲存有對應實體的公鑰資訊。


下面是使用opensll實現CA並簽發證書的過程:

1)        生成CA金鑰

CA作為一個權威機構,他本身也是使用證書來標識自己,CA本身也擁有私鑰。在簽發數字證書的過程中,CA的私鑰主要用於加密使用者證書請求中的使用者資訊及公鑰。genrsa -out cakey.pem 1024該命令會產生長度為1024位元組的私鑰檔案cakey.pem。


2)        生成CA證書請求req -new -out careq.csr -key cakey.pem此命令會根據cakey.pem產生該證書的請求檔案careq.csr。

3)        用CA私鑰自簽名x509 -req -in careq.csr -out cacert.pem -signkey cakey.pem -days 3650該命令會根據輸入的證書請求及CA私鑰,生成CA證書。至此,作為CA所要求的證書已經準備好,所得到的cakey.pem可用於將來頒發證書,而cacert.pem證書作為使用者的可信任證書,需要分發給每一個由該CA機構頒發證書的實體。

8          伺服器證書與客戶端證書的製作伺服器證書與客戶端證書的製作稍有不同,這是由於伺服器對證書格式與客戶端證書格式要求不同導致的。對於Tomcat或WebSphere這樣的伺服器(偶只知道這兩種),通常都要求一種JKS格式的檔案,在該檔案中,儲存有伺服器私鑰、伺服器證書以及伺服器根證書鏈(從RootCA一直到伺服器證書頒發機構的一系列CA證書列表)。

8.1          伺服器證書要製作這一類證書,需要使用JDK提供的一個工具keytool。

下面是使用keytool製作證書庫的過程:

1)        生成初始金鑰庫keytool -genkey -alias serveralias -keystore server.jks -keyalg RSA輸入keystore密碼:changit您的名字與姓氏是什麼?  [Unknown]:  CN您的組織單位名稱是什麼?  [Unknown]:  OU您的組織名稱是什麼?  [Unknown]:  O您所在的城市或區域名稱是什麼?  [Unknown]:  L您所在的州或省份名稱是什麼?  [Unknown]:  ST該單位的兩字母國家程式碼是什麼  [Unknown]:  CNCN=CN, OU=OU, O=O, L=L, ST=ST, C=CN 正確嗎?  [否]:  y 輸入證書的主密碼        (如果和 keystore 密碼相同,按回車):在輸入上述的“名字與姓氏”時,要注意所輸入的值應該與伺服器的IP或域名一致,否則在客戶端驗證伺服器證書時會認為該證書與指定的伺服器實體不匹配,如果是IE就會彈出一個視窗提示使用者是否信任該證書。

2)        生成證書請求keytool –certreq -alias serveralias -sigalg MD5withRSA -file server.csr -keypass changeit -keystore  server.jks -storepass changeit最後生成的證書請求檔案為server.csr。把該請求傳送給證書頒發機構,該機構將會驗證證書請求中的實體資訊,然後實現簽證。因為我們是自己做CA,所以簽證這一步也是我們自己來做。

3)        實現簽證簽證仍然使用openssl,而不是keytool。在openssl中,輸入以下命令:x509 -req -in server.csr -out servercert.pem -CA cacert.pem -CAkey cakey.pem -days 3650輸出的servercert.pem檔案即是簽證後的證書,即證書請求響應。命令中用到的cakey.pem和cacert.pem是上面生成的CA金鑰檔案和CA根證書。完成CA簽證後,把證書請求響應連同CA根證書一起返回給申請者。申請者需要把CA根證書(鏈)及證書請求響應匯入到JKS庫中。此時使用的工具是keytool。keytool –import –trustcacerts –keystore server.jks –file cacert.jks –alias RootCAkeytool –import –trustcacerts –keystore server.jks –file servercert.jks –alias serveralias需要注意的是,首先匯入CA根證書(鏈),最後才匯入證書請求響應,而且匯入證書請求響應時的別名必須與生成JKS庫時使用的別名一致。至此,伺服器端的JKS檔案已經完成,可以配置到相應的伺服器中。

8.2          客戶端證書至於客戶端證書,既可以用openssl製作,也可以用keytool來製作,不過用keytool來生成的話,要麻煩一些,而且簽證的步驟必須由opensll來實現,因此這裡講述用openssl生成客戶端證書的過程。

1)        生成客戶端金鑰檔案genrsa -out clientkey.pem 1024該命令會產生clientkey.pem金鑰檔案。

2)        產生證書請求req -new -out clientreq.csr -key client-key.pem把證書請求傳送給CA以實現簽證,這裡同樣由自己做。

3)        實現簽證x509 -req -in clientreq.csr -out clientcert.pem -signkey clientkey.pem -CA cacert.pem -CAkey cakey.pem -CAcreateserial -days 3650簽證後的客戶端證書只包含了客戶端的公鑰及客戶實體的資訊,不包含私鑰。

4)        生成客戶端可匯入的客戶端證書pkcs12 -export -clcerts -in clientcert.pem -inkey clientkey.pem -out client.pfx這一步把客戶端的證書(公鑰)與私鑰捆綁在一起,生成client.pfx檔案,該檔案連同CA根證書一起傳送給客戶。

9          配置IE客戶端對於使用IE的客戶,需要把CA根證書及個人證書匯入到IE的證書列表中。在匯入CA根證書的時候,如果不是權威的CA根證書(自己當CA的那種),IE會提示是否信任該證書,確認後CA根證書會儲存在證書信任列表中。此後再匯入客戶自己的證書,IE將會認為這是可信的,因為CA根證書儲存在證書信任列表中了。在匯入含有私鑰的客戶證書時,IE會提示是否給私鑰加密以及設定私鑰是否可匯出等屬性,建議把私鑰加密並設定為不可匯出,並要求每次使用證書時輸入密碼。

10      配置WebSphere伺服器使用數字證書(憑記憶描述)開啟WebSphere的管理控制檯,進入到安全性->SSL頁面中,該頁面列出了目前所有的SSL配置庫,一般來說只有一個預設配置庫,我們修改該配置庫的引數即可。點選預設的配置庫連結,將含有伺服器證書的金鑰庫路徑及密碼,修改信任CA列表的金鑰庫路徑(一般來說可與伺服器證書的金鑰庫一致)及密碼,選中 “客戶機認證”選擇框即完成配置。

11      配置Apache使用數字證書(從別處參考)

11.1       編輯Apache的ssl.conf1)        指定伺服器證書位置SSLCertificateFile <path-to-certificates>/servercert.pem2)        指定伺服器證書key位置 SSLCertificateKeyFile <path-to-certificates>/serverkey.pem3)        證書目錄SSLCACertificatePath <path-to-certificates>4)        根證書位置SSLCACertificateFile <path-to-certificates>/cacert.pem 5)        開啟客戶端SSL請求 SSLVerifyClient require SSLVerifyDepth  1

11.2       啟動ssl apachectl startssl 會要求輸入server.key的密碼

12      在伺服器端讀取客戶端傳送的數字證書在某些情況下希望使用者使用數字證書時能夠自動登入系統,這就需要以使用者的數字證書序列號作為登入標識。下列程式碼演示在伺服器端讀取客戶端數字證書的方法(Tomcat或WebSphere)。javax.servlet.request.X509Certificate[]  certs  = (javax.servlet.request.X509Certificate[])  request.getAttribute(“javax.servlet.request.X509Certificate”);if(certs!=null){       //第一個證書為使用者個人證書javax.servlet.request.X509Certificate cert=( javax.servlet.request.X509Certificate)certs[0];//以16進位制形式列印其序列號System.out.println(cert.toString(16)); }elseSystem.out.println(“could not get certificate from client!”);上傳的數字證書有數個,包括使用者個人證書及其根證書鏈,第一個為使用者個人證書,接著為使用者個人證書的根證書,再接著為使用者個人證書根證書的根證書,依次類推。上述程式碼是網上可以找到的程式碼,而且可以正常通過編譯,但在實踐的過程中,偶發現javax.servlet.request.X509Certificate應該為java.servlet.request.X509Certificate,否則會引發型別轉換異常。不知道這是不是伺服器版本不同引起的問題,測試時使用的伺服器版本為WebShpere5.0.1。對於使用其它伺服器或語言的情況,在網上可以找到很多例子,偶還沒有使用或測試過,不敢罔言。

13      後記CA認證的配置過程事實上並不複雜,重要的是一些基本概念的理解。開始的時候,由於缺乏相關的知識及經驗,走了不少的彎路,浪費不少時間,特撰此文,以啟後來者。撰寫過程中,引用了不少他人的文章,由於記錄零散,作者無從考究,在此對這些作者一併表示感謝。我已經盡力把事情說得清楚明白,但由於表達能力問題,文中不妥之處肯定不少,給你的閱讀及理解造成障礙。如果這樣,請你告訴我,我定當盡力改進。如果因此而提高我的表達能力,那將是我最大的榮幸。