應用 openssl 工具進行 SSL 故障分析

圖文還原HTTPS原理:https://mp.weixin.qq.com/s/3NKOCOeIUF2SGJnY7II9hA

SSL 握手協議

首先簡單的介紹一下 SSL 協議建立連接的過程。如圖 1 所示,主要有如下幾個過程:
應用 openssl 工具進行 SSL 故障分析
SSL 身份認證及協商密鑰的過程:

  • 客戶端發起請求,包含一個hello消息,並附上客戶端支持的密碼算法和 SSL 協議的版本消息以及用於生成密鑰的隨機數。
  • 服務器收到消息後,服務器端選擇加密壓縮算法並生成服務器端的隨機數,將該信息反饋給客戶端;接着服務器端將自身的數字證書(在圖 1 中使用了一個 X.509 數字證書)發送到客戶端;完成上述動作後後服務器端會發送“hello done”消息給客戶端。此外如果服務器需要對客戶端進行身份認證,服務器端還會發送一個請求客戶端證書的消息。
  • 一旦客戶端收到”hello done” , 就開始對服務器端的數字證書進行認證並檢查服務器端選中的算法是可行的。如果服務器要求認證客戶端身份,客戶端還會發送自己的公鑰證書。
  • 如果對服務器的身份認證通過,客戶端會發起密鑰交換的請求。
  • 服務器端和客戶端根據先前協商的算法和交換隨機數生成對稱密鑰進行後續的通信。

s_client 簡介

openssl 提供了 SSL 協議的一個開放源代碼的實現,包含三部分:ssl 庫,加解密庫和命令行工具。在命令行工具中 s_client 是一個以 SSL 協議連接遠程服務器的客戶端程序,該工具可以用於測試診斷。雖然 s_client 只提供了一些基礎功能,但是其內部具體實現中使用了 ssl 庫的大部分接口。

s_client命令行的語法爲:

openssl s_client [-connect host:port>] [-verify depth] [-cert filename] [-key filename] 
 [-CApath directory] [-CAfile filename][-reconnect] [-pause] [-showcerts] [-debug] [-msg] 
 [-nbio_test] [-state] [-nbio] [-crlf] [-ign_eof] [-quiet]

常用參數的具體用途如下:

  • -connect host:port :指定遠程服務器的地址和端口,如果沒有該參數,默認值爲 localhost:443 ;
  • -cert filename:若服務器端需要驗證客戶端的身份,通過 -cert 指定客戶端的證書文件。
  • -key filename:指定私鑰文件;
  • -verify depth:打開服務器證書驗證並定義證書驗證過程中的最大深度。
  • -showcerts:顯示服務器證書鏈;
  • -CAfile filename:指定用於驗證服務器證書的根證書;
  • -state:打印出 SSL 會話的狀態。

s_client 在 SSL 握手協議中的應用

在連接 SSL 服務器時最常見的問題就是客戶端認證服務器端身份失敗,有多種原因造成這些失敗,以下列舉了常見的錯誤並解析瞭如何應用 s_client 進行確診。

  • 服務器的證書在傳輸過程中被篡改

1、提取服務器的證書:
在 linux 平臺下創建腳本 retrieve-cert.sh 並存入一下清單 1 中的內容。該腳本的輸出內容就是服務器端的 X509 證書經過 Base64 編碼後的內容,執行腳本並將腳本輸出存入文件 server.pem 中。

清單 1. 提取證書

###usage: retrieve-cert.sh remote.host.name [port] 
 SSLHOST=$1 
 SSLPORT=${2:-443} 
 echo |\ 
 openssl s_client -connect ${SSLHOST}:${SSLPORT} 2>&1 |\ 
 sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'

2、驗證獲取的證書,在命令行下執行”openss verify server.pem”。
如果證書內容被篡改,那麼執行後的結果如清單 2 所示:

清單 2. 證書驗證失敗

[root@wks547385wss openssl]# openssl verify server.pem 
 unable to load certificate 
 19280:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:tasn_dec.c:947: 
 19280:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 
 error:tasn_dec.c:304:Type=X509 
 19280:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:pem_oth.c:82:

否則的話,我們就能得到認證通過,結果如下:
清單 3. 證書驗證成功

[root@wks547385wss openssl]# openssl verify server.pem 

 server.pem: OK

  • 客戶端沒有保存認證服務器端的證書的根證書;

1. 使用參數-state檢查是否在握手協議的證書認證時失敗
清單 4. 顯示 SSL 握手協議狀態

[root@wks547385wss openssl]# openssl s_client  -connect www6.software.ibm.com:443 -state 
 CONNECTED(00000003) 
 SSL_connect:before/connect initialization 
 SSL_connect:SSLv2/v3 write client hello A 
 SSL_connect:SSLv3 read server hello A 
 depth=1 /C=US/O=Equifax/OU=Equifax Secure Certificate Authority 
 verify error:num=19:self signed certificate in certificate chain 
 verify return:0 
 SSL_connect:SSLv3 read server certificate A 
 SSL_connect:SSLv3 read server done A 
 SSL_connect:SSLv3 write client key exchange A 
 SSL_connect:SSLv3 write change cipher spec A 
 SSL_connect:SSLv3 write finished A 
 SSL_connect:SSLv3 flush data 
 SSL_connect:SSLv3 read finished A

2. 運用 s_client 參數-showcerts獲取服務器端的根證書,服務器端的證書鏈將會全部顯示出來,在證書鏈的末端就是根證書,保存證書文件爲serverCA.pem 。

清單 5. 獲取服務器端的根證書

[root@wkswss openssl]# openssl s_client -connect www6.software.ibm.com:443 – showcerts 
…
 s:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority 
 i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority 
 -----BEGIN CERTIFICATE----- 
 MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV 
 UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy 
 dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 
 MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx 
 dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B 
 AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f 
 BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A 
 cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC 
 AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ 
 MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm 
 aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw 
 ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj 
 IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF 
 MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA 
 A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y 
 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh 
 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 
 -----END CERTIFICATE-----

3. 運用 s_client 參數-CAfile CA.pem再次連接服務器

清單 6. 設定服務器證書文件建立 SSL 連接

[root@wkswss openssl]# openssl s_client -CAfile serverCA.pem -connect 
 www6.software.ibm.com:443 -state 
 CONNECTED(00000003) 
 SSL_connect:before/connect initialization 
 SSL_connect:SSLv2/v3 write client hello A 
 SSL_connect:SSLv3 read server hello A 
 depth=1 /C=US/O=Equifax/OU=Equifax Secure Certificate Authority 
 verify return:1 
 depth=0 /C=US/O=IBM/CN=www6.software.ibm.com 
 verify return:1 
 SSL_connect:SSLv3 read server certificate A 
 SSL_connect:SSLv3 read server done A 
 SSL_connect:SSLv3 write client key exchange A 
 SSL_connect:SSLv3 write change cipher spec A 
 SSL_connect:SSLv3 write finished A 
 SSL_connect:SSLv3 flush data 
 SSL_connect:SSLv3 read finished A 
……
 SSL-Session: 
    Protocol  : TLSv1 
    Cipher    : DES-CBC3-SHA 
    Session-ID: 00365044871540E334826923BF9C531CE659274858585858499C14380000000C 
    Session-ID-ctx: 
    Master-Key: 
 D065F1F2297560F1CD4CCC0D7A58E647CC9F596BCEC545CF90DD54659CB36C53CDAC977E5784C6 
 A273BA28B486E578B9 
    Key-Arg   : None 
    Krb5 Principal: None 
    Start Time: 1234986898 
    Timeout   : 300 (sec) 
    Verify return code: 0 (ok)
  • 客戶端擁有認證服務器證書的根證書,但是服務器被防火牆隔離,防火牆在收到來自客戶端的 SSL 連接請求時返回防火牆的證書。這種情況下的症狀跟服務器證書被篡改非常相似,但是區別在於應用上述提及的方法仍然不能定位錯誤。

1. 客戶端已經擁有服務器 build.rchland.ibm.com 的根證書rochCA.pem,當客戶端試圖連接服務器客戶時,對服務器的證書認證卻不能通過。

清單 7. 認證失敗

[root@wks547385wss openssl]# openssl s_client -CAfile roch.pem -state -connect 
 build.rchland.ibm.com:443 
 CONNECTED(00000003) 
 SSL_connect:before/connect initialization 
 SSL_connect:SSLv2/v3 write client hello A 
 SSL_connect:SSLv3 read server hello A 
 depth=0 /serialNumber=93e352/CN=rch-fw-1a.rchland.ibm.com/unstructuredName= 
 rch-fw-1a.rchland.ibm.com 
 verify error:num=18:self signed certificate 
 verify return:1 
 depth=0 /serialNumber=93e352/CN=rch-fw-1a.rchland.ibm.com/unstructuredName= 
 rch-fw-1a.rchland.ibm.com 
 verify return:1 
 SSL_connect:SSLv3 read server certificate A 
 SSL_connect:SSLv3 read server done A 
 SSL_connect:SSLv3 write client key exchange A 
 SSL_connect:SSLv3 write change cipher spec A 
 SSL_connect:SSLv3 write finished A 
 SSL_connect:SSLv3 flush data 
 SSL_connect:SSLv3 read finished A 
…

2. 使用x509工具,查看根證書的具體內容,特別是證書籤發者和持有者的身份,如清單 10 所示。

清單 8. 解碼根證書

[root@wks547385wss openssl]# openssl x509 -text -in roch.pem 
 Certificate: 
    Data: 
        Version: 3 (0x2) 
        Serial Number: 903804111 (0x35def4cf) 
        Signature Algorithm: sha1WithRSAEncryption 
        Issuer: C=US, O=Equifax, OU=Equifax Secure Certificate Authority 
        Validity 
            Not Before: Aug 22 16:41:51 1998 GMT 
            Not After : Aug 22 16:41:51 2018 GMT 
        Subject: C=US, O=Equifax, OU=Equifax Secure Certificate Authority 
        Subject Public Key Info: 
            Public Key Algorithm: rsaEncryption 
            RSA Public Key: (1024 bit)

有了上述的證書籤發者信息後,我們的問題就迎刃而解了,客戶端收到了來自防火牆的證書,該證書和防火牆後面的服務器的數字證書來自不同的簽發者。

結束語

openssl 提供的 ssl 庫被廣泛的運用的同時,也增加了程序員在診斷通訊故障的難度。巧妙的運用 s_client 無疑給程序員帶來了一把利刃,特別是缺乏調試工具的環境下,如嵌入式系統。

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