MQTT研究之EMQ:【wireshark抓包分析】


基於上篇博文【SSL雙向驗證】的環境基礎,進行消息的具體梳理.

環境基礎信息:

1. 單台Linux CentOS7.2系統,安裝一個EMQTTD的實例broker。
2. emq的版本2.3.113. 客戶端分為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)和上訴紅色部分關系最為密切.

1、秘鑰協商和秘鑰交換這兩個概念,看到很多地方的討論和描述中,似乎沒有區分的很明確,依據我的理解,秘鑰協商和秘鑰交換,確實有很大的關聯性,不可能完全割裂或者分離關系,只是兩個概念描述的側重點不同,秘鑰協商更多表述怎么做這個邏輯,而秘鑰交換,更多側重怎么做的實際動作或者流程

2、cipher suite的簡單介紹

就拿我這個測試的cipher suite值說明吧。

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384

        鍵值交換簽名協議       數據加密算法       信息認證碼算法

更詳細的介紹,可以對照下面這個圖:

秘鑰協商/交換,是為了在握手的過程中,基於給定的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消息流,大體就算是弄清楚了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM