coding--SSL理解總結

SSL協議簡介

SSL(Secure Socket Layer)netscape公司設計的主要用於web的安全傳輸協議。這種協議在WEB上獲得了廣泛的應用。SL協議分爲兩部分:Handshake ProtocolRecord Protocol,。其中Handshake Protocol用來協商密鑰,協議的大部分內容就是通信雙方如何利用它來安全的協商出一份密鑰;Record Protocol則定義了傳輸的格式。SSL協議可以理解爲工作在傳輸層之上、應用層之下。

SSL握手過程

SSL協議的握手過程完成身份認證、密碼協商兩個功能,單向認證場景下不需要驗證客戶端身份,交互過程如下:

1) SSL客戶端(也是TCP的客戶端)在TCP鏈接建立之後,發出一個“Client Hello”來發起握手,這個消息裏面包含了自己可實現的算法列表和其它一些需要的消息;

2) SSL的服務端會迴應一個“Server Hello”,這裏面確定了這次通信所需要的算法;服務端發過去證書certificate(裏面包含了身份和自己的公鑰);

3) Client在收到這個消息後會生成一個通信密碼,用SSL服務端的公鑰加密後發到服務端;

4) SSL服務器端用自己的私鑰解密後,會話密鑰協商成功,雙方可以用同一份會話密鑰來通信。

SSL雙向認證過程要複雜得多,分爲互相驗證證書、協商加密方案、協商密鑰三大步驟:

1)  客戶端發送一個連接請求給SSL服務端。

2)  服務端將自己的證書,以及同證書相關的信息發送給客戶端。

3)   客戶端驗證服務端證書,驗證通過則發送客戶端證書到服務端,此時客戶端獲得服務端公鑰。

4)  服務器驗證客戶的證書,如果沒有通過驗證,拒絕連接;如果通過驗證,服務端獲得用戶的公鑰。

5)  客戶端生成一個通信密碼方案列表,用服務端的公鑰加密後傳過去。

6)  服務器從客戶發送過來的密碼方案中,選擇一種加密程度最高的密碼方案,用客戶的公鑰加過密後通知客戶端。

8)  客戶端針對這個密碼方案,選擇一個通話密鑰,接着用服務端的公鑰加過密後發送給服務器。

9)  服務器接收到端送過來的消息,用自己的私鑰解密,獲得通話密鑰。

10)  服務器、端接下來的通訊都是用對稱密碼方案,對稱密鑰是加過密的。

證書文件說明

1)  證書文件類型

.cer/.crt是用於存放證書,它是2進制形式存放的,不含私鑰。

.pemcrt/cer的區別是它以AsciiBASE64)來表示。

pfx/p12用於存放個人證書/私鑰,通常包含保護密碼,2進制方式。

p10是證書請求。

p7rCA對證書請求的回覆,只用於導入。

p7b以樹狀展示證書鏈(certificate chain),同時也支持單個證書,不含私鑰。

2)        X509證書鏈

X509證書是最通用一種證書個數,用到三類文件:keycsrcrt

Key文件是私鑰文件,openssl格式,通常使用rsa算法,密鑰長度要求20481024已經被破解。

csr文件是證書請求文件,用於申請證書,可以設定讀取該文件的密碼。

crt文件是經過根證書CA認證過的證書文件,(windowscsr就是crt文件),csr文件使用自己的key來簽署得到crt文件。

3)        證書轉換:

X509P12的轉換:

openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

PKCS#12 PEM的轉換:

openssl pkcs12 [-nocerts] -nodes -in cert.p12 –out cert.pem

x509pfx

pkcs12 -export –in keys/client1.crt -inkey keys/client1.key -out keys/client1.pfx

PFX格式文件中提取私鑰格式文件(.key):

openssl pkcs12 -in mycert.pfx -nocerts -nodes -out mycert.key

 證書製作過程

SUSE11環境的OPENSSL工具爲例製作證書,先創建一個專門生成SSL證書的目錄,下面所有操作均在該目錄下執行。

1)        製作根證書私鑰

openssl genrsa –des3 –out ca.key 2048(有密碼)

openssl genrsa -out ca.key 2048  (無密碼)

2)        製作自簽名根證書

openssl req -new -x509 -days 3650 -key ca.key -out ca.crt

其中要提示輸入一些證書的基本信息,如紅框部分。包括國家代碼、省份、城市、公司名稱、項目/部門名稱、證書名稱等信息。這些內容,最好根據項目的實際情況進行填寫。當然,也可以不設置,直接回車即可。

3)        製作服務端私鑰

openssl genrsa -out zte.key 2048

4)        製作服務端證書

openssl req -new -key zte.key -out srv.csr

其中的需要填寫部分可以對比第二步中的方法。

5)        簽發證書

執行openss命令可以製作製作簡單的證書:

openssl x509 -req -in srv.csr -out srv.crt -signkey zte.key -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650

6)        製作客戶端私鑰證書

openssl genrsa -out client.key  2048

openssl req -new -key  client.key -out client.csr

openssl x509 -req -in clt.csr -out clt.crt -signkey zte.key -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650

如果要產生一個包含私鑰、證書的p12文件需要執行:

openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

說明:

SSL單向認證時,不需要製作客戶端證書,服務端需要部署根證書ca.crt、服務端私鑰srv.key、服務端證書srv.crt三個文件,客戶端可以部署根證書ca.crt,客戶端也可以不使用根證書。SSL雙向認證時,則需要製作客戶端證書、私鑰,客戶端需要部署ca.crtclient.keyclient.key三個文件。

SSL編程總結

網上很多文章推薦SSL握手過程使用阻塞方式,握手過程結束後再設置非阻塞方式,這種方法有個非常危險的場景,向一個SSL監聽端口建TCP鏈接後不發起SSL握手請求,這個SSL監聽進程會一直阻塞住。(不知道是否有超時函數可用)下面提到的SSL操作都是非阻塞的。

SSL_connect():一次調用發送client hello,返回值-1errno=2,需要繼續讀;此時SSL_pending()返回長度爲0,繼續讀、寫均返回-1,但抓包確認SSL握手可以完成。

SSL_accept():一次調用立即發送服務端證書,返回值-1errno=2,需要繼續讀;繼續SSL_read()仍然返回-1errno=2,抓包確認SSL握手可以正常完成。

根據函數說明SSL_write/SSL_read可以完成ssl握手過程,應用只需要根據select()結果執行後續讀寫操作,就可以完成握手過程;測試驗證確認這樣可以完成握手過程,但是握手過程中SSL_readSSL_write都返回-1errno=2,無法得知何時完成握手過程。

非阻塞SSL客戶端握手過程編碼:

(1)  SSL_connect()(返回值-1),發送client hello

(2)  select檢測句柄可讀,即爲收到服務端發送的server hello,執行SSL_connect()(返回值-1),則發送經過公鑰加密的密碼;

(3)  再次select檢測句柄可讀,即爲收到服務端發送的密碼確認,執行SSL_connect()(返回值1),握手成功;

(4)  修改鏈路爲正常establish狀態,執行後續操作。

非阻塞SSL服務端握手過程編碼:

(1)  tcp層完成3次握手後,select檢測到句柄可讀,即爲收到客戶端的client hello,執行SSL_accept()(返回值-1),發送server hello

(2)  select再次檢測句柄可讀,收到客戶端發送的密文密碼,執行SSL_accept()(返回值1),發送經過密碼確認,握手成功結束;

(3)  修改鏈路爲正常establish狀態,執行後續操作。

  • 客戶端校驗服務端證書:

默認爲SSL_VERIFY_NONE模式,客戶端可以不加載ca.crt信任根證書;

如果初始化爲SSL_VERIFY_PEER,則客戶端會加載信任根證書並認證服務端發過來的證書,認證失敗則會執行回調函數;

握手失敗時,應用可以調用SSL_get_verify_result()接口獲取失敗原因。

附:SSL會話初始化時,執行SSL_CTX_set_verify()設置證書認證模式,第二個參數爲SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT|SSL_VERIFY_CLIENT_ONCE,第三個參數指定校驗回調函數,NULL表示使用SSL自帶的校驗函數。

  • 服務端校驗客戶端端證書:

單向驗證時,服務端不要求客戶端發送證書、公鑰,也就不對客戶端證書進行認證;

服務端初始化爲SSL_VERIFY_PEER,則服務端要求雙向認證,客戶端必須發送證書、公鑰,服務端進行認證校驗;

還有一種,雙向不認證,兩層都配置SSL_VERIFY_NONE,客戶端驗證服務端證書不通過,但仍然可以繼續傳輸數據。

小結:

證書是用來驗證對端身份是否合法的,根證書又是用來驗證對端證書合法性的,如果不驗證對端證書,本地也就不需要根證書了。

服務端不驗證客戶端證書:服務端不需要CA證書、客戶端不需要配置證書私鑰;
服務端驗證客戶端證書:服務端需要CA證書、客戶端需要配置證書私鑰;
客戶端驗證服務端證書:客戶端需要CA證書、服務端需要證書私鑰;
客戶端不驗證服務端證書:客戶端不需要CA證書、服務端仍然需要證書私鑰。

參考:http://blog.csdn.net/dog250/article/details/5303388

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章