基於上篇博文【SSL雙向驗證】的環境基礎,進行消息的具體梳理.html
環境基礎信息:算法
1. 單臺Linux CentOS7.2系統,安裝一個EMQTTD的實例broker。 2. emq的版本2.3.11。 3. 客戶端分爲mosquitto_pub,以及MQTT.fx 1.7.1的subscriber。 4. 證書是經過openssl(version:1.0.2k-fips)生成的,rootCA是自簽名的,subscriber和publisher的證書是經過rootCA簽署的。 5. 抓包工具wireshark(version: 2.6.6,下載地址https://www.wireshark.org/download/win64/),分析SSL/TLS通訊的消息流.
第一步:經過wireshark抓取SSL雙向驗證的消息緩存
下面是我測試過程當中,獲得的消息流程,個人測試環境,在TLS的兩層消息結構(record layer,handshake layer)中的握手協議環節,獲得的cipher suite的值是:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384。服務器
先簡單介紹下,這個cipher suite的含義,這個應該是SSL/TLS協議中比較難以理解的一個概念。這個說簡單點,就是祕鑰協商(Key agreement)的頂層設計,後續的消息流程都是密切的基於這個cipher suite的值而有較大的不一樣,準確的說,祕鑰交換(Key exchange)和上訴紅色部分關係最爲密切.app
一、祕鑰協商和祕鑰交換這兩個概念,看到不少地方的討論和描述中,彷佛沒有區分的很明確,依據個人理解,祕鑰協商和祕鑰交換,確實有很大的關聯性,不可能徹底割裂或者分離關係,只是兩個概念描述的側重點不一樣,祕鑰協商更多表述怎麼作這個邏輯,而祕鑰交換,更多側重怎麼作的實際動做或者流程。ide
二、cipher suite的簡單介紹工具
就拿我這個測試的cipher suite值說明吧。測試
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384ui
鍵值交換籤名協議 數據加密算法 信息認證碼算法this
更詳細的介紹,能夠對照下面這個圖:
祕鑰協商/交換,是爲了在握手的過程當中,基於給定的cipher suite完成shared secret的生成過程,這個祕鑰就是用來爲後續數據傳輸的時候對稱加密用的密碼。信息驗證碼協議,是爲了保證數據傳輸的時候的數據一致性或者完整性的。
在咱們這個測試中,基於上述cipher suite獲得的消息流以下:
C->S: Client Hello S->C: Server Hello S->C: Certificate,Server Key Exchange, Certificate Request, Server Hello Done C->S: Certificate, Client Key Exchange C->S: Certificate Verify,Change Cipher Spec,Encrypted Handshake Message S->C: Change Cipher Spec,Encrypted Handshake Message C->S: Application Data S->C: Application Data
a. C->S: Client Hello
b. S->C: Server Hello
c. S->C: Certificate,Server Key Exchange, Certificate Request, Server Hello Done (這裏的Certificate Request,就是服務端要求客戶端上報證書)
d. C->S: Certificate, Client Key Exchange (這個環節很重要,體現了雙向SSL驗證的特徵了,服務端要求的身份驗證,即但願校驗客戶端的證書的過程)
e. C->S: Certificate Verify,Change Cipher Spec,Encrypted Handshake Message
這個消息,其實理解起來彷佛有點很差理解。爲什麼客戶端要上報Certificate Verify呢?
1). certificate Verify消息必須在client key exchange後面由客戶端發出去給服務器端。 2). 這個消息,是客戶端構建的,內容是客戶端收發的全部的handshake消息(不含當前這個Verify的消息)拼接後的內容進行hash,而後用證書對應的私鑰進行簽名後所得的內容S1。 3). 這個消息,服務端會進行驗證。驗證的邏輯,經過對服務端緩存的客戶端消息,以及服務端發送的全部handshake消息,一樣進行拼接而後計算hash值h2,用客戶端的證書中的公鑰解析Verify中的簽名S1獲得對應的hash值h1,對比h1和和 ,若相同,則驗證經過,不然失敗。
能夠參考這個連接中的內容,其實,他的解釋或者介紹,也是基於RFC文檔中的內容進行的,只是比較白話了,相對好懂些。
f. S->C: Change Cipher Spec,Encrypted Handshake Message
g.C->S: Application Data
第二步:單向SSL驗證(客戶端驗證服務端的合法性)
1. 配合broker
## Path to the file containing the user's private PEM-encoded key. ## ## See: http://erlang.org/doc/man/ssl.html ## ## Value: File #listener.ssl.external.keyfile = /etc/emqttd/certs/key.pem listener.ssl.external.keyfile = /opt/certs/server.key ## Path to a file containing the user certificate. ## ## See: http://erlang.org/doc/man/ssl.html ## ## Value: File #listener.ssl.external.certfile = /etc/emqttd/certs/cert.pem listener.ssl.external.certfile = /opt/certs/server.crt ## Path to the file containing PEM-encoded CA certificates. The CA certificates ## are used during server authentication and when building the client certificate chain. ## ## Value: File ## listener.ssl.external.cacertfile = /etc/emqttd/certs/cacert.pem listener.ssl.external.cacertfile = /opt/certs/rootCA.crt ## The Ephemeral Diffie-Helman key exchange is a very effective way of ## ensuring Forward Secrecy by exchanging a set of keys that never hit ## the wire. Since the DH key is effectively signed by the private key, ## it needs to be at least as strong as the private key. In addition, ## the default DH groups that most of the OpenSSL installations have ## are only a handful (since they are distributed with the OpenSSL ## package that has been built for the operating system it’s running on) ## and hence predictable (not to mention, 1024 bits only). ## In order to escape this situation, first we need to generate a fresh, ## strong DH group, store it in a file and then use the option above, ## to force our SSL application to use the new DH group. Fortunately, ## OpenSSL provides us with a tool to do that. Simply run: ## openssl dhparam -out dh-params.pem 2048 ## ## Value: File ## listener.ssl.external.dhfile = /etc/emqttd/certs/dh-params.pem ## A server only does x509-path validation in mode verify_peer, ## as it then sends a certificate request to the client (this ## message is not sent if the verify option is verify_none). ## You can then also want to specify option fail_if_no_peer_cert. ## More information at: http://erlang.org/doc/man/ssl.html ## ## Value: verify_peer | verify_none listener.ssl.external.verify = verify_none #主要是在雙向驗證的基礎上將此配置改成verify_none ## Used together with {verify, verify_peer} by an SSL server. If set to true, ## the server fails if the client does not have a certificate to send, that is, ## sends an empty certificate. ## ## Value: true | false ## listener.ssl.external.fail_if_no_peer_cert = true
2. 經過wireshark抓取SSL消息流
具體的經過wireshark抓取SSL消息流
C->S: Client Hello S->C: Server Hello S->C: Certificate, Server Key Exchange, Server Hello Done C->S: Client Key Exchange C->S: Change Cipher Spec, Encrypted Handshake Message S->C: Change Cipher Spec, Encrypted Handshake Message C->S: Application Data S->C: Application Data ...... S->C: Encrypted Alert C->S: Encrypted Alert
最後,補充一下,關於DH祕鑰交換的流程圖,ECDH交換和DH交換流程邏輯相同,只是算法中交換的參數計算邏輯不一樣而已,從DH升級到ECDH是能夠平滑作到的。
ECDH祕鑰交換說明:
假設密鑰交換雙方爲Alice、Bob,其有共享曲線參數(橢圓曲線E、階N、基點G),對於於上圖中的common paint黃色信息,是你們共有的,只是每次協商時,值不一樣,可是雙方都是知道的。
1.Alice生成隨機整數a (對應上圖中的orange),計算A=a*G(這個A,對應上圖中orange-tan)。Bob生成隨機整數b(對應上圖中的blue-green),計算B=b*G(這個B,對應上圖中的light-blue)。
2.Alice將A傳遞給Bob。A的傳遞能夠公開,即攻擊者能夠獲取A。因爲橢圓曲線的離散對數問題是難題,因此攻擊者不能夠經過A、G計算出a。Bob將B傳遞給Alice。同理,B的傳遞能夠公開。
3.Bob收到Alice傳遞的A,計算Q=b*A (這裏的Q,對應上圖中yellow-brown)
4.Alice收到Bob傳遞的B,計算Q‘=a*B(這裏的Q‘,對應上圖中yellow-brown)
Alice、Bob雙方即得Q=b*A=b*(a*G)=(b*a)*G=(a*b)*G=a*(b*G)=a*B=Q' (交換律和結合律),即雙方獲得一致的密鑰Q。
到此,整個祕鑰交換爲核心的SSL消息流,大致就算是弄清楚了。