參考:TLS/SSL 協議詳解(6) SSL 數字證書的一些細節1 證書驗證
地址:https://wonderful.blog.csdn.net/article/details/77867063
參考:TLS/SSL協議詳解 (7) SSL 數字證書的一些細節2
地址:https://wonderful.blog.csdn.net/article/details/77867210
目錄
- 證書生成
- 證書驗證(如何保證你是證書的擁有者)
- 證書是否能被偽造或盜用
- 證書鏈
- 證書格式
- 私鑰格式
- 證書類型
- 證書拓展
證書關系到了SSL的眾多安全性,比如身份認證,密鑰交換。所以有必要單拉出一章來講證書。本章完善一下前幾節中的身份認證的一些缺點。
首先,通過前面講解,我們知道,證書需要幾個重要的字段。例如“擁有者”、“頒發者”、“截止日期”。另外,生成證書的時候會自動生成一份“公鑰”以及對應的“私鑰”。現在假設我開了一個網站,準備用SSL加密的,需要讓全世界信任我這個網站,那么我就需要一個證書,這時候我該怎么做?
證書生成
假設目前全世界就Google有那么一個root證書(根證書),名字叫做“Google”,顯然,它的“頒發者”也是“Google”,因為根證書都是用工具生成的,并且根據第四章的知識,你應該知道,根證書沒有頒發者,所以理所當然的,頒發者也是它自己。現在,全世界都信任這個證書,換句話說,瀏覽器里面都信任這個證書(約定俗成的)。我們也想和谷歌一樣,有一個全世界都信任的證書,怎么做?
-
第一步:給Google錢。
-
第二步:告訴谷歌,我想要的證書名字叫做“www.dp.com”或者其他的你網站的域名。
-
第三步:等著谷歌返回給你:證書、公鑰、私鑰。
谷歌收到錢后是怎么做的呢?首先肯定對你的網站、公司進行調查,確保你不是壞人,以免全世界都信任你了你卻干壞事,這會讓谷歌丟臉。
-
第一步:用工具生成一對公鑰和私鑰。
-
第二步:構造證書,把公鑰嵌入到證書里面(即證書里面其實有一個字段是公鑰,明文的)
-
第三步:最重要的一步,谷歌拿自己的根證書簽名一個第二步構造好的證書。
所謂簽名:就是對第二步的證書做摘要,MD5或者SHA1,或者MD5+SHA1,得到結果,然后拿自己根證書的私鑰加密這個結果,然后添加到證書最后面。
- 第四步:把證書和私鑰交給你。
這就是一個證書的生成過程。后續將講解為什么這么生成證書。
證書驗證(如何保證你是證書的擁有者)
上一節我們花很多錢,讓谷歌生用自己的證書為我們簽名了一個證書。現在我們可以把谷歌給我們的證書,安裝到我們的網站中了。如果有一個客戶端,訪問我們的網站,我們發送我們的證書給客戶端,客戶端如何驗證呢?(注意,第四章的驗證比較簡單,這里才是真正的驗證)
之前說過,客戶端信任了許多根證書,比如客戶端信任一個叫做“Google”的證書。首先瀏覽器收到我們的證書之后,查看它的頒發者,哦,是“Google”,于是到信任的根證書里面找一個名字叫做“Google”的證書,通過字符串比較,我們很容易找到“Google”這個證書。然后進行驗證:
-
第一步:對我們的證書(除了“簽名值”)全部內容進行MD5/SHA1,得到結果1。
-
第二步:用“Google”證書中的公鑰,對我們證書中的“簽名值”進行解密,得到結果2。
-
第三步:比較 結果1和結果2 ,發現一樣,那么認證通過。理論上,如果中間沒人改動我們的證書,那么,結果1和結果2 都是“asdfghjklqwertyu”。
證書是否能被偽造或盜用
那么上面的操作,如何保證了服務器身份能夠被客戶端認證呢?我們換個角度來思考,假設我是壞人,有一個網站叫做"www.dp.com",它的證書是Google簽發的,我想欺騙客戶端說自己是“www.dp.com”,怎么辦?
第一種方法:
我們想到,既然瀏覽器信任一個叫做“Google”的證書以及“www.dp.com”,那我就在我的網站導入“www.dp.com”它不就行了嗎,因為證書都是公開的,我隨時隨地能獲得“www.dp.com”的證書?
但是根據第四章中“密鑰的協商、交換”一節中提到的那樣,公鑰和私鑰是一對的,我雖然得到了“www.dp.com”證書,證書中也有“www.dp.com”的公鑰,但是我沒有它對應私鑰,而SSL的RSA算法握手時需要私鑰操作。
比如,我雖然把“www.dp.com”證書發給客戶端,客戶端的確認證了,然后客戶端用“www.dp.com”證書中的公鑰加密一個密鑰,按握手要求,服務器需要用私鑰來解密,可是我沒有對應私鑰,以沒辦法解密!后面的會話都解密不了,即SSL握手完成不了。
對于ECDHE算法來說和RSA有點區別,由于私鑰不參與秘鑰協商(前向安全算法都不需要私鑰進行秘鑰協商),所以為了保證服務器是證書的擁有者(即擁有私鑰),SSL協議規定,服務器在握手時,需要用私鑰簽名握手數據(server key exchange),客戶端需要用公鑰驗證這個簽名的握手數據。可見,如果服務器沒有私鑰,那么也就不能完成簽名這步,或者簽名的值客戶端無法驗證,握手無法繼續。
第二種方法:
那我就也用工具,隨便生成一個根證書,名字叫做“Google”,對應該證書,也會隨機生成一個公鑰和私鑰,然后模仿谷歌的,拿這個根證書的私鑰簽名一個證書:頒發者填寫“Google”,擁有者填寫“www.dp.com” ,然后做MD5/SHA1,得到結果“asdfghjklqwertyu”,拿剛才自己生成的“Google”證書的私鑰,對這個結果加密,得到“lkjhgfd”:
我把這個證書發給客戶端,客戶端找到叫做“Google”的證書,拿它的公鑰解密這個簽名值,問題來了,這個由于這個簽名值是由我剛才假冒的“Google”證書的私鑰簽名的,所以,正宗的“Google”正宗的公鑰解密得到的結果,壓根不是“asdfghjklqwertyu”,當客戶端對我們這個證書做摘要,結果是“asdfghjklqwertyu”,但是對簽名解密的結果卻是另外一個值,那么瀏覽器就不信任你了。
第三種方法:
看來生成證書的方法行不通,那只能隨便找一個證書,修改里面的頒發者和擁有者。
但是問題又出現了,被修改證書的簽名值沒辦法更改,因為簽名值是拿其頒發者私鑰進行加密的,我們沒有頒發者Google的私鑰。瀏覽器會對被篡改證書的簽名用Google的公鑰解密,然后對比瀏覽器自己對證書計算的摘要,不一樣,瀏覽器就不認了,如果我們要改簽名值,就需要頒發者即“Google”的私鑰,不過這顯然不可能。
上面偽造身份的結果的是失敗的,其安全性都是基于那個“簽名值”,簽名值是用頒發者自己的私鑰加密的,只要頒發者的私鑰不泄密,那么不可能有人偽造證書。
證書鏈
之所以存在證書鏈這個東西,是因為驗證證書的時候需要。
假設如上圖所示,“Google”簽名了一個“Android”,然后“Android”簽名了一個“CyanogenMod”,我們瀏覽器只信任“Google”,如果服務器只發送一個叫做“CyanogenMod”,那么我們無法查找到叫做“Android”的根證書,無法驗證服務器的身份。此時,作為服務器,我們可發送“Android”+“CyanogenMod”,這樣,客戶端會首先驗證Android是否是CyanogenMod的頒發者(驗證簽名),如果是,那么在自己的根證書里面找“Android”的頒發者“Google”,然后驗證“Android”是否是由“Google”頒發的。
證書格式
編碼格式
證書編碼格式多種,但是不要根據文件后綴名(der,cer)等區分證書格式。
總的來說,證書分為2種,一種是二進制的、一種是進行base64編碼的證書。前者使用notepad或者任意文本編輯器打開,顯示亂碼,后者則顯示正常的base64編碼后的數據。下圖為經過base64編碼后的證書,由BEGAIN和END包括。(老司機可能就發現了,有點像長了一點的迅雷下載鏈接)
至于是否換行完全取決于base64的規范(詳見wiki中關于base64 https://en.wikipedia.org/wiki/Base64)。
所謂二進制證書,也就是原始的asn1格式的證書,如果熟悉asn1編碼方式,直接看2進制會看到明顯的’30 82 …’等asn1的類型長度標識,這里不再贅述,但是二進制不適合網絡傳輸,所以普遍采用base64將其編碼。
其次還有一種格式叫pfx(PKCS12)格式的證書,與其說是證書,不如叫它證書+私鑰的package比較合適,一個文件即包含證書(證書鏈),也包含私鑰。pfx本身可被加密,所以可能需要輸入密鑰才能解析pfx。所以,解析pfx或者打開pfx時,可能需要用戶輸入2個密碼,一個是pfx本身的密碼,另一個是私鑰的密碼(私鑰見下文)。
另一種證書格式稱之為p7b,他是多個證書組織成的格式(一般是證書鏈)。在windows下可以由windows自帶程序解析,我們可以提取出其中各個證書。
私鑰格式
私鑰格式也分為 二進制 和 base64編碼,不再贅述。
但是私鑰本身可以被加密。
被加密的私鑰格式如下:
當采用pfx格式證書時,由于pfx格式文件本身可能需要密鑰來解密,而里面的私鑰也可能需要密鑰解密,所以解析程序往往可能讓你輸入2個密鑰,這2個密鑰是用來解密不同層級數據的,注意不要感到疑惑或者將兩者混淆。
證書類型
簽名算法一般采用RSA或者ECC。較老的有DH算法等,目前已不多見。
但是注意,被稱為RSA證書并不是指證書是被RSA算法簽名的,而是指證書本身的公鑰、私鑰是RSA。同理ECC證書指的是證書的公鑰和私鑰具有橢圓曲線屬性。證書的簽名值的類型并不影響證書的屬性。
例如,上級證書A是ECC證書,即證書公鑰私鑰是ECC屬性的,那么由它生產的證書B的簽名必然采用ECC簽名,但是B本身可以使用RSA公鑰私鑰或者ECC公鑰私鑰。
證書拓展
使用wireshark解析SSL證書,我們可以清晰的看到數字證書各個字段,這里我們關心證書中的extension:
1:keyusage/extkeyusage
用以描述證書的用法,改證書可以進行證書的簽發?CRL的簽發?客戶端認證?服務器認證?一般嚴格的CA機構都謹慎設置這個字段,避免自己簽發的證書被濫用。
2:subectkeyidentifier
自己公鑰進行hash運算后的值,可以快速判斷證書。
3:authoritykeyidentifier
上級證書的公鑰進行hash運算后的值。一般來說,兩個上下級關系的證書,下級證書的authoritykeyidentifier值就是上級證書的subectkeyidentifier值。
4:subjectAltname
證書的別名。例如一個網站有多個域名,例如www.baidu.com和www.hao123.com對應的都是一個服務器,common name只能寫一個,為了不讓瀏覽器告警,可以在subjectAltname拓展中添加這個網站的其他域名。瀏覽器收到這個證書,除了判斷host和common name是否一致外,也會判斷host和subjectAltname是否有一致項,有的話就成功。
5:basicConstraints
一般CA證書里面ca:Ture。