文章分享

開放、平等、協(xié)作、快速、分享

當(dāng)前位置:首頁>文章分享

借助mbedTLS了解DTLS握手協(xié)議

摘錄:HCTech 無錫和控電子   時(shí)間:2020-08-07   訪問量:3688

借助mbedTLS了解DTLS握手協(xié)議

借助mbedTLS了解DTLS握手協(xié)議

https://zhuanlan.zhihu.com/p/24028871


引子

本文將會(huì)利用mbedTLS協(xié)議棧,通過dump協(xié)議棧調(diào)試信息,抓包,代碼分析等方式來對(duì)DTLS的握手協(xié)議進(jìn)行介紹。

DTLS簡介

簡單說,DTLS(Datagram Transport Layer Security)實(shí)現(xiàn)了在UDP協(xié)議之上的TLS安全層。由于基于TCP的SSL/TLS沒有辦法處理UDP報(bào)文的丟包及重排序(這些問題一般交給UDP的上層應(yīng)用解決),DTLS在原本TLS的基礎(chǔ)上做了一些小改動(dòng)(復(fù)用大部分TLS的代碼)來解決如下UDP上實(shí)現(xiàn)TLS的問題:

  1. TLS記錄層內(nèi)記錄的強(qiáng)關(guān)聯(lián)性及無序號(hào)

  2. 握手協(xié)議的可靠性

    • 包丟失重傳機(jī)制(UDP無重傳機(jī)制)

    • 無法按序接收(握手需要對(duì)包按順序處理,而UDP包的到達(dá)并非按序,包頭沒有TCP那樣的Seq/Ack number)

    • 握手協(xié)議包長(證書之類傳輸可能達(dá)到KB級(jí)別)導(dǎo)致的UDP分包組包(類似于UDP在IP層的分包)

  3. 重復(fù)包(Replay)檢測

由于UDP/DTLS相較于TCP/TLS的輕量化及較小的開銷,目前被更多的運(yùn)用的嵌入式環(huán)境中。例如CoAP使用DTLS來實(shí)現(xiàn)安全通路,CoAP及其上層的LWM2M則運(yùn)用在物聯(lián)網(wǎng)和云端的通訊上。

如果你已經(jīng)很熟悉TLS,那么看到這里后就請忽略此文:)

如何借助mbedTLS來分析握手協(xié)議

mbedTLS(前身PolarSSL)是面向嵌入式系統(tǒng),實(shí)現(xiàn)的一套易用的加解密算法和SSL/TLS庫。mbedTLS系統(tǒng)開銷極小,對(duì)于系統(tǒng)資源要求不高。mbedTLS是開源項(xiàng)目,并且使用Apache 2.0許可證,使得用戶既可以講mbedTLS使用在開源項(xiàng)目中,也可以應(yīng)用于商業(yè)項(xiàng)目。目前使用mbedTLS的項(xiàng)目很多,例如Monkey HTTP Daemon,LinkSYS路由器。

我們在這里簡單的利用mbedTLS自帶的dtls_client/dtls_server的測試程序來分析握手協(xié)議。這里要說明的是mbedTLS這個(gè)自帶的DTLS 測試程序,服務(wù)器只在localhost做bind,客戶端也只連接到localhost。實(shí)際上是個(gè)loopback測試。并且使用了TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384的Cipher Suite,也就是用橢圓曲線(EC)的DH算法來實(shí)現(xiàn)密鑰(Session Key)的協(xié)商,用RSA來實(shí)現(xiàn)密鑰協(xié)商時(shí)交換的EC類型,DH公鑰等數(shù)據(jù)的簽名加密。所以握手的流程和其他一些加密方式會(huì)有所差別。比如和單純的RSA密鑰交換方式比起來,會(huì)多一個(gè)“Server Key Exchange”報(bào)文。

下載mbedTLS

$git clone https://github.com/ARMmbed/mbedtls

打開調(diào)試

在program/dtls_client.c, dtls_server.c里,增大DEBUG_LEVEL,然后將my_debug里加上時(shí)間戳信息。使能協(xié)議棧的內(nèi)部調(diào)試信息,方便對(duì)比客戶端和服務(wù)端的流程:

#define DEBUG_LEVEL 100

static void my_debug( void *ctx, int level,
                      const char *file, int line,
                      const char *str )
{
    struct timeval tv;

    ((void) level);

    gettimeofday(&tv, NULL);
    //strftime(outstr, sizeof(outstr), "%H:%M:%S", tmp);

    mbedtls_fprintf( (FILE *) ctx, "[%06ld.%ld]%s:%04d: %s", tv.tv_sec, tv.tv_usec, file, line, str );
    fflush(  (FILE *) ctx  );
}

編譯

在Ubuntu上可以直接編譯。

$ make

編譯結(jié)果為

  • 服務(wù)器:program/ssl/dtls_server

  • 客戶端: program/ssl/dtls_client

抓包

打開wireshark之類的抓包工具,對(duì)本地網(wǎng)卡進(jìn)行抓包。先跑server,后跑client。在抓包結(jié)束后,加dtls的display filter既可以:

Wireshark抓包截圖: (導(dǎo)出pcapng包下載

有了TLS協(xié)議棧的調(diào)試信息,Wireshark的實(shí)際的抓包數(shù)據(jù)再加上源代碼,我們就很容易來分析DTLS的握手協(xié)議。當(dāng)然gdb拿過來直接調(diào)試也行,不過需要把DEBUG宏在編譯時(shí)打開:

$ make DEBUG=1

DTLS握手協(xié)議分析

DTLS握手協(xié)議和TLS類似。DTLS協(xié)議在UDP之上實(shí)現(xiàn)了客戶機(jī)與服務(wù)器雙方的握手連接,在握手過程中驗(yàn)證對(duì)方的身份,并且使用RSA或者DH(Diffie-Hellman)實(shí)現(xiàn)會(huì)話密鑰的建立,以便在后面的數(shù)據(jù)傳輸中對(duì)數(shù)據(jù)加密。它利用cookie驗(yàn)證機(jī)制和證書實(shí)現(xiàn)了通信雙方的身份認(rèn)證;并且用在報(bào)文段頭部加上序號(hào),緩存亂序到達(dá)的報(bào)文段;還利用重傳機(jī)制實(shí)現(xiàn)了可靠傳送。在握手完成后,通信雙方就可以利用握手階段協(xié)商好的會(huì)話密鑰來對(duì)應(yīng)用數(shù)據(jù)進(jìn)行加解密。

簡易握手流程圖:

從流程圖上看,有(1)(3)兩個(gè)“Client Hello”請求,他兩之間的區(qū)別是第二個(gè)包含有(2)”Hello Verify Request”里服務(wù)端發(fā)來的Cookie。要使得DTLS握手正真開始,服務(wù)端必須要判斷發(fā)送請求的客戶端是否是有效客戶端。通過這樣的Cookie交互,可以很大程度上保護(hù)服務(wù)端不受DoS的攻擊。如果利用Cookie,服務(wù)端會(huì)在收到每個(gè)客戶請求后返回一個(gè)體積大很多的證書給被攻擊者,超大量證書有可能造成被攻擊者的癱瘓。當(dāng)首次建立連接時(shí),(1)請求包中的cookie為空,服務(wù)端根據(jù)客戶端的源IP地址通過哈希方法隨機(jī)生成一個(gè)cookie,并填入(2)”Hello Verify Request”包中發(fā)送給客戶端??蛻舳耸盏紺ookie后,再次發(fā)送帶有該Cookie的“Client Hello”包(3),服務(wù)端收到該包后便檢查報(bào)文段里面的cookie值和之前發(fā)給該客戶端的Cookie值是否完全相同,若是,則通過Cookie驗(yàn)證,繼續(xù)進(jìn)行握手連接;若不是,則拒絕建立連接。所以說(1)(2)步驟只在第一次連接時(shí)發(fā)生,之后在Cookie有效的情況下,DTLS握手從步驟(3)開始。

  • 客戶端的實(shí)現(xiàn)都在ssl_cli.c里,狀態(tài)機(jī)由mbedtls_ssl_handshake_client_step()處理

  • 服務(wù)端的實(shí)現(xiàn)則在ssl_srv.c里,狀態(tài)機(jī)由mbedtls_ssl_handshake_server_step()處理

(3)”Client Hello”由函數(shù)ssl_write_client_hello()實(shí)現(xiàn)報(bào)文填充和發(fā)送,內(nèi)容主要包含:

  1. Random 32字節(jié)隨機(jī)數(shù),前4字節(jié)為當(dāng)前時(shí)間+28字節(jié)隨機(jī)數(shù)

  2. Cookie,從報(bào)文(2)中獲得

  3. Cipher Suite,客戶端可以支持的密鑰交換,數(shù)據(jù)加密方式

  4. Compression methods,是否壓縮,及壓縮方式

  5. Extension,例如服務(wù)器主機(jī)名;支持的簽名加密方式,EC曲線類型等

服務(wù)端收到報(bào)文(3)后,會(huì)調(diào)用函數(shù)ssl_parse_client_hello()做一系列協(xié)商工作:
將Random保存;驗(yàn)證Cookie是否和客戶端的IP匹配;根據(jù)客戶端提供的Cipher Suite找最佳匹配的,能提供的Cipher算法集合。在mbedTLS的例子里使用了ECDHE_RSA_WITH_AES_256_GCM_SHA384(ECDHE密鑰協(xié)商算法、RSA簽名、GCM-AES對(duì)稱密鑰加密傳輸數(shù)據(jù)、SHA384哈希簽名)。如果協(xié)商沒有問題,服務(wù)端就調(diào)用ssl_write_server_hello()會(huì)發(fā)送報(bào)文(4)”Server Hello”,告訴客戶端使用什么Cipher Suite做握手,什么壓縮方式,然后利用隨機(jī)數(shù)生成一個(gè)Session ID。并且以客戶端同樣的方式生成的Random隨機(jī)數(shù),將隨機(jī)數(shù)和Session ID放入報(bào)文中。緊接著服務(wù)端會(huì)接連發(fā)送報(bào)文(5)(6)(7)

(5)”Certification”服務(wù)端會(huì)將他自己的證書發(fā)送給客戶端。證書中的肯定有一個(gè)證書的Subject是和Server Name相匹配的(commonName=”localhost”,organizationName=”PolarSSL”)。測試程序中其實(shí)發(fā)送了3個(gè)證書,subject分別是localhost, PolarSSL Test CA及PolarSSL Test EC CA。PolarSSL Test CA實(shí)際上是localhost的父證書,這里就涉及到一個(gè)CA Chain的概念。現(xiàn)實(shí)情況中(例如瀏覽器訪問HTTPS服務(wù)器),服務(wù)器發(fā)給客戶端的證書一般是終端用戶證書(end-user CA),客戶端需要通過證書認(rèn)證來檢查服務(wù)器是否可信。首先客戶端在自己安裝(瀏覽器安裝時(shí)都會(huì)默認(rèn)安裝可靠證書)的一系列中間證書(intermediate CA)和根證書(ROOT CA)中查找該終端用戶證書的父證書,以及該父證書的父證書,直到追溯到根證書,建立起這些證書的關(guān)系:CA Chain。然后使用該終端用戶證書的父證書的公鑰來驗(yàn)證終端用戶證書的完整性,然后找到父證書的父證書,以同樣的方式驗(yàn)證父證書完整性,直到遇到根證書。一般來講,終端客戶證書的Issuer都會(huì)和某個(gè)中間或者根證書的Subject相匹配,也就意味著客戶證書是由某個(gè)中間或根證書發(fā)行機(jī)構(gòu)簽發(fā),并且終端客戶證書中的簽名是由父證書擁有者的私鑰加密的。由于根證書的Subject和Issuer都是自己,所以客戶端的根證書一定要保證是Trust CA頒發(fā)的,否則沒有辦法自己驗(yàn)證自己。

回到我們的例子,客戶端在初始化的時(shí)候加載了PolarSSL Test CA的根證書(當(dāng)然只是測試的根證書),這個(gè)和現(xiàn)實(shí)的情況類似??蛻舳耸盏?5)”Certification”報(bào)文后,很快就可以查找到”localhost”這個(gè)終端用戶證書的根證書是”PolarSSL Test CA”,一次便驗(yàn)證通過了。驗(yàn)證的代碼在:mbedtls_x509_crt_verify_with_profile()。驗(yàn)證通過后,客戶端實(shí)際上就獲得了證書中的公鑰。證書驗(yàn)證完畢,說明服務(wù)端的身份沒有問題,可以進(jìn)行下一步密鑰協(xié)商。

(6)”Server Key Exchange”是Session Key協(xié)商的重要一步ssl_write_server_key_exchange(),測試程序中使用了ECDHE_RSA的協(xié)商方式。服務(wù)端首先要將在(3)”Client Hello”階段和客戶端協(xié)商使用的EC曲線類型找出來,這里協(xié)商的曲線類型是secp512r1(0x0019)。利用該曲線類型,加載對(duì)應(yīng)于該曲線的參數(shù)p,b,G(x,y),n (服務(wù)端和客戶端參數(shù)相同,參考:library/ecp_curves.c)。調(diào)用mbedtls_ecdh_gen_public(),首先生成一個(gè)隨機(jī)數(shù)私鑰a(范圍[1, n-1]),然后計(jì)算Qs=aG,產(chǎn)生ECDHE的Public Key Qs,再用服務(wù)端的私鑰(和localhost證書中的公鑰配對(duì)的)對(duì)Qs做簽名(SHA512做哈希,RSA加密)。最后將曲線類型,公鑰Qs,簽名算法及簽名寫入(6)的報(bào)文中,發(fā)送給客戶端。由于ECDHE(Elliptic curve Diffie–Hellman)算法較為復(fù)雜,我也不是非常理解,在這里就不深入討論了。具體可以參考:
WikiPage
總之,ECDHE算法很快,而且不需要暴露預(yù)主密碼(premaster secret,馬上談到)。后面客戶端也會(huì)做同樣的操作,生成自己的私鑰b,計(jì)算Qc。雙方交換Q后,可以計(jì)算得到相同的預(yù)主密碼:bQs=baG=abG=aQc。之后雙方就可以用這個(gè)abG預(yù)主密碼和之前(3)(4)報(bào)文中的客戶端、服務(wù)端的Random來生成對(duì)稱密鑰Session Key(master secret)。預(yù)主密碼如何生成密鑰,可以參考mbedtls_ssl_derive_keys():

master = PRF( premaster, "master secret", randbytes )[0..47]

因?yàn)閜remaster secret不需要做交換,而是在本地計(jì)算產(chǎn)生,所以說ECDHE的密鑰協(xié)商方式比RSA更安全。

(7)”Server Hello Done”會(huì)緊接著(6)發(fā)送,內(nèi)容很簡單,標(biāo)示了handshake type 14,,告訴客戶端Hello階段結(jié)束。

(8)”Client Key Exchange”客戶端在收到(6)報(bào)文后,獲取服務(wù)端發(fā)送過來的EC曲線類型和Qs,使用和服務(wù)端一樣的流程生成私鑰b,計(jì)算公鑰Qc=bG,將Qc放入該報(bào)文,并發(fā)送給服務(wù)端。此時(shí)不需要再做簽名,后面”Finish”報(bào)文會(huì)再次讓雙方驗(yàn)證密鑰的一致性。

(9)”Change Cipher Spec”客戶端接著發(fā)送該報(bào)文,告訴服務(wù)端Session Key我已經(jīng)生成,雙方可以用密鑰Session Key(master secret)開始加密通訊了。

(10)”Finished”該報(bào)文由客戶端發(fā)送mbedtls_ssl_write_finished(),這是第一個(gè)用Session Key加密的密文,內(nèi)容是一段驗(yàn)證數(shù)據(jù):

valid_data = PRF(master_secret, "client finished", MD5(handshake_messages) + SHA(handshake_messages))[0..11]

handshake_messages實(shí)際上是客戶端在握手階段發(fā)出的所有報(bào)文(不包含該Finished報(bào)文),服務(wù)端在收到該報(bào)文后,會(huì)以同樣的方式計(jì)算出valid_data,并且做比較。以確認(rèn)雙方協(xié)商的密鑰一致。確認(rèn)完畢后,服務(wù)端以同樣的方式發(fā)送(11)”Change Cipher Spec”和(12)”Finished”給客戶端。最后完成握手。

完成握手后,雙發(fā)就可以發(fā)送加密的Application Data數(shù)據(jù)包來進(jìn)行安全通訊,并且報(bào)文中都包含一個(gè)sequence number來標(biāo)識(shí)順序。

到這里握手協(xié)議部分就介紹完了,如果大家想要深入研究算法,去看mbedTLS的代碼不失為一個(gè)好途徑。

結(jié)尾

記得很早以前,我是看過SSL/TLS的協(xié)議,握手也是了解過。沒想到,最近看CoAP,很多細(xì)節(jié)現(xiàn)在都回想不起來。好記心不如爛筆頭,寫下來也是分享,今后碰到問題也可以做個(gè)參考。

參考文獻(xiàn)


上一篇:SSL和TLS部署注意事項(xiàng)

下一篇:DTLS協(xié)議中client/server的認(rèn)證過程和密鑰協(xié)商過程

在線咨詢

點(diǎn)擊這里給我發(fā)消息 售前咨詢專員

點(diǎn)擊這里給我發(fā)消息 售后服務(wù)專員

在線咨詢

免費(fèi)通話

24小時(shí)免費(fèi)咨詢

請輸入您的聯(lián)系電話,座機(jī)請加區(qū)號(hào)

免費(fèi)通話

微信掃一掃

微信聯(lián)系
返回頂部