第一步: 客戶端發送ClientHello消息,發起SSL連接請求,告訴服務器自己支持的SSL選項(加密方式等)。
- *** ClientHello, TLSv1
第二步: 服務器響應請求,回覆ServerHello消息,和客戶端確認SSL加密方式:
- *** ServerHello, TLSv1
第三步: 服務端向客戶端發佈自己的公鑰。
第四步: 客戶端與服務端的協通溝通完畢,服務端發送ServerHelloDone消息:
- *** ServerHelloDone
第五步: 客戶端使用服務端給予的公鑰,創建會話用密鑰(SSL證書認證完成後,爲了提高性能,所有的信息交互就可能會使用對稱加密算法),並通過ClientKeyExchange消息發給服務器:
- *** ClientKeyExchange, RSA PreMasterSecret, TLSv1
第六步: 客戶端通知服務器改變加密算法,通過ChangeCipherSpec消息發給服務端:
- main, WRITE: TLSv1 Change Cipher Spec, length = 1
第七步: 客戶端發送Finished消息,告知服務器請檢查加密算法的變更請求:
- *** Finished
第八步:服務端確認算法變更,返回ChangeCipherSpec消息
- main, READ: TLSv1 Change Cipher Spec, length = 1
第九步:服務端發送Finished消息,加密算法生效:
- *** Finished
那麼如何讓服務端也認證客戶端的身份,即雙向握手呢?其實很簡單,在服務端代碼中,把這一行:
- ((SSLServerSocket) _socket).setNeedClientAuth(false);
改成:
- ((SSLServerSocket) _socket).setNeedClientAuth(true);
通過比對單向認證的日誌輸出,我們可以發現雙向認證時,多出了服務端認證客戶端證書的步驟:
- *** CertificateRequest
- Cert Types: RSA, DSS
- Cert Authorities:
- <CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn>
- <CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn>
- *** ServerHelloDone
- *** CertificateVerify
- main, WRITE: TLSv1 Handshake, length = 134
- main, WRITE: TLSv1 Change Cipher Spec, length = 1
在 @*** ServerHelloDone@ 之前,服務端向客戶端發起了需要證書的請求 @*** CertificateRequest@ 。
在客戶端向服務端發出 @Change Cipher Spec@ 請求之前,多了一步客戶端證書認證的過程 @*** CertificateVerify@ 。
客戶端與服務端互相認證證書的情景,可參考下圖: