詳解 WebRTC 傳輸安全機制:一文讀懂 DTLS 協議

做者|進學html

審校|泰一git

DTLS (Datagram Transport Layer Security) 基於 UDP 場景下數據包可能丟失或從新排序的現實狀況下,爲 UDP 定製和改進的 TLS 協議。在 WebRTC 中使用 DTLS 的地方包括兩部分:協商和管理 SRTP 密鑰和爲 DataChannel 提供加密通道。github

本文結合實際數據包分析 WebRTC 使用 DTLS 進行 SRTP 密鑰協商的流程。並對在實際項目中使用 DTLS 遇到的問題進行總結。web

DTLS 協議簡介

在分析 DTLS 在 WebRTC 中的應用以前,先介紹下 DTLS 協議的基本原理。DTLS 協議由兩層組成: Record 協議 和 Handshake 協議算法

  1. Record 協議:使用對稱密鑰對傳輸數據進行加密,並使用 HMAC 對數據進行完整性校驗,實現了數據的安全傳輸。
  2. Handshake 協議:使用非對稱加密算法,完成 Record 協議使用的對稱密鑰的協商。

HandShake

TLS 握手協議流程以下,參考 RFC5246安全

DTLS 握手協議流程以下,參考 RFC6347服務器

TLS 和 DTLS 的握手過程基本上是一致的,差異以及特別說明以下:網絡

  • DTLS 中 HelloVerifyRequest 是爲防止 DoS 攻擊增長的消息。
  • TLS 沒有發送 CertificateRequest,這個也不是必須的,是反向驗證即服務器驗證客戶端。
  • DTLS 的 RecordLayer 新增了 SequenceNumber 和 Epoch,以及 ClientHello 中新增了 Cookie,以及 Handshake 中新增了 Fragment 信息(防止超過 UDP 的 MTU),都是爲了適應 UDP 的丟包以及容易被攻擊作的改進。參考 RFC 6347
  • DTLS 最後的 Alert 是將客戶端的 Encrypted Alert 消息,解密以後直接響應給客戶端的,實際上 Server 應該回應加密的消息,這裏咱們的服務器迴應明文是爲了解析客戶端加密的那個 Alert 包是什麼。

RecordLayer 協議是和 DTLS 傳輸相關的協議,UDP 之上是 RecordLayer,RecordLayer 之上是 Handshake 或 ChangeCipherSpec 或 ApplicationData。RecordLayer 協議定義參考 RFC4347,實際上有三種 RecordLayer 的包:併發

  • DTLSPlaintext,DTLS 明文的 RecordLayer。
  • DTLSCompressed,壓縮的數據,通常不用。
  • DTLSCiphertext,加密的數據,在 ChangeCipherSpec 以後就是這種了。

沒有明確的字段說明是哪一種消息,不過能夠根據上下文以及內容判斷。好比 ChangeCipherSpec 是能夠經過類型,它確定是一個 Plaintext。除了 Finished 的其餘握手,通常都是 Plaintext。dom

SRTP 密鑰協商

角色協商

在 DTLS 協議,通訊的雙方有 ClientServer 之分。在 WebRTC 中 DTLS 協商的身份是在 SDP 中描述的。描述以下,參考 SDP-Anatomy 中 DTLS 參數

a=setup:active

setup 屬性在 RFC4145

setup:active,做爲 client,主動發起協商

setup:passive, 做爲 sever,等待發起協商

setup:actpass, 做爲 client,主動發起協商。做爲 server,等待發起協商。

算法協商 - Hello 消息

ClienHello 和 ServerHello 協商 DTLS 的 Version、CipherSuites、Random、以及 Extensions。

  • Version:Client 給出本身能支持的、或者要使用的最高版本,好比 DTLS1.2。Server 收到這個信息後,根據本身能支持的、或者要使用的版本回應,好比 DTLS1.0。最終以協商的版本也就是 DTLS1.0 爲準。
  • CipherSuites:Client 給出本身能支持的加密套件 CipherSuites,Server 收到後選擇本身能支持的迴應一個,好比 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014),加密套件肯定了證書的類型、密鑰生成算法、摘要算法等。
  • Random:雙方的隨機數,參與到生成 MasterSecret。MasterSecret 會用來生成主密鑰,導出 SRTP 密鑰。詳見 [導出 SRTP 密鑰]
  • Extensions:Client 給出本身要使用的擴展協議,Server 能夠迴應本身支持的。好比 Client 雖然設置了 SessionTicket TLS 這個擴展,可是 Server 沒有迴應,因此最終並不會使用這個擴展。

Cipher Suite

在 Hello 消息中加密套接字使用 IANA 中的註冊的名字。IANA 名字由 Protocol,Key Exchange Algorithm,Authentication Algorithm,Encryption Algorithm ,Hash Algorithm 的描述組成。例如,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 的含義以下:

  • Protocol: Transport Layer Security (TLS)
  • Key Exchange: Elliptic Curve Diffie-Hellman Ephemeral (ECDHE)
  • Authentication: Rivest Shamir Adleman algorithm (RSA)
  • Encryption: Advanced Encryption Standard with 128bit key in Galois/Counter mode (AES 128 GCM)
  • Hash: Secure Hash Algorithm 256 (SHA256)

加密套接字在 ciphersuite.info 能夠查到。在查到 IANA 名字的同時,也能夠查到在 OpenSSL 中的名字。TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 在 OpenSSL 中的名字爲 ECDHE-RSA-AES128-GCM-SHA256 Note: 關於 Authentication (認證)、KeyExchange (密鑰交換)、Encryption (加密)、MAC (Message Authentication Code) 消息摘要等,能夠參考 RSA 密鑰協商

Extension

DTLS 的擴展協議,是在 ClientHello 和 ServerHello 的 Extensions 信息中指定的,全部的 TLS 擴展參考 TLS Extensions。下面列出幾個 WebRTC 用到的擴展:

  • use_srtp: DTLS 握手完成後 (Finished),使用 SRTP 傳輸數據,DTLS 生成 SRTP 的密鑰。 RFC5764。ClientHello 中的擴展信息定義了 RFC5764 4.1.2. SRTP Protection Profilessrtp_mki
  • supported_groups,原來的名字爲 elliptic_curves,描述支持的 ECC 加密算法,參考 RFC8422 5.1.1.Supported Elliptic Curves Extension,通常用的是 secp256r1。
  • signature_algorithms,DTLS1.2 的擴展,指定使用的 Hash 和 Signature 算法,參考 RFC5246 7.4.1.4.1. Signature Algorithms。DTLS1.0,RSA 用的是 md5sha1 摘要算法,DSA 用的是 sha1 摘要算法。
  • extended_master_secret,擴展 MasterSecret 的生成方式,參考 RFC7627。在 KeyExchange 中,會加入一些常量來生成 MasterSecret。TLS 定義了擴展方式,若是用這個擴展,DTLS 的方式和 TLS 會有些不一樣。
  • renegotiation_info, 參考 RFC5746

除了這些擴展協議,和 SRTP 密鑰導出相關的還有:

RFC5705: Keying Material Exporters for Transport Layer Security (TLS),DTLS 如何從 MasterSecret 導出 Key,好比 SRTP 的 Key。 RFC5764: DTLS Extension to Establish Keys for the SRTP,DTLS 的 use_srtp 擴展的詳細規範,包括 ClientHello 擴展定義、Profile 定義、Key 的計算。

身份驗證 - Certificate

數字證書是由一些公承認信的證書頒發機構簽發的,不易僞造。數字證書能夠用於接收者驗證對端的身份,接收者收到某個對端的證書時,會對簽名頒發機構的數字簽名進行檢查,通常來講,接收者事先就會預先安裝不少經常使用的簽名頒發機構的證書(含有公開密鑰),利用預先的公開密鑰能夠對簽名進行驗證。

Server 端經過 Hello 消息,協商交換密鑰的方法後,將 Server 證書發送給 Client,用於 Client 對 Server 的身份進行校驗。Server 發送的證書必須適用於協商的 KeyExchange 使用的加密套接字,以及 Hello 消息擴展中描述的 Hash/Signature 算法對。

在 WebRTC 中,通訊的雙方一般將沒法得到由知名根證書頒發機構 (CA) 簽名的身份驗證證書,自簽名證書一般是惟一的選擇。RFC4572 定義一種機制,經過在 SDP 中增長自簽名證書的安全哈希,稱爲 "證書指紋",在保證 SDP 安全傳輸的前提下,若是提供的證書的指紋與 SDP 中的指紋匹配,則能夠信任自簽名證書。在實際的應用場景中,SDP 在安全的信令通道 (https) 完成交換的,SDP 的安全完整是能夠作到的。這樣在 DTLS 協商過程當中,可使用證書的指紋,完成通訊雙方的身份校驗。證書指紋在 SDP 中的描述以下,參考 SDP-Anatomy 中 DTLS 參數

a=fingerprint:sha-256 49:66:12:17:0D:1C:91:AE:57:4C:C6:36:DD:D5:97:D2:7D:62:C9:9A:7F:B9:A3:F4:70:03:E7:43:91:73:23:5E

密鑰交換 - KeyExchange

ServerKeyExchange 用來將 Server 端使用的公鑰,發送給 Client 端。分爲兩種狀況:

  1. RSA 算法:若是服務端使用的是 RSA 算法,能夠不發送這個消息,由於 RSA 算法使用的公鑰已經在 Certificate 中描述。
  2. DH 算法,是根據對方的公鑰和本身私鑰計算共享密鑰。由於 Client 和 Server 都只知道本身的私鑰,和對方的公鑰;而他們的私鑰都不一樣,根據特殊的數學特性,他們能計算出一樣的共享密鑰。關於 DH 算法如何計算出共享密鑰,參考 DH 算法

ClientKeyExchange 用來將 Client 使用的公鑰,發送給 Server 端。

  1. RSA 算法:若是密鑰協商使用的 RSA 算法,發送使用 server 端 RSA 公鑰,對 premaster secret 加密發送給 server 端。
  2. DH 算法:若是密鑰協商使用的 DH 算法,而且在證書中沒有描述,在將客戶端使用的 DH 算法公鑰發送給 Server 端,以便計算出共享密鑰。 KeyExchange 的結果是,Client 和 Server 獲取到了 RSA Key, 或經過 DH 算法計算出共享密鑰。詳見 [導出 SRTP 密鑰] 的過程

證書驗證 - CertificateVerify

使用 ClientRequest 中描述的 Hash/Signature 算法,對收到和發送的 HandShake 消息簽名發送個 Server。Server 端對簽名進行校驗。

加密驗證 - Finished

當 Server 和 Client 完成對稱密鑰的交換後,經過 ChangeCipherSpec 通知對端進入加密階段,epoch 加 1。

隨後 Client 使用交換的密鑰,對 "client finished" 加密,使用 Finished 消息,發送給服務端。Server 使用交換的密鑰,對 "server finished" 進行加密發送給客戶端。一旦驗證了 finished 消息後,就能夠正常通訊了。

導出 SRTP 密鑰

上面介紹了 DTLS 的過程,如下經過結合上面例子給出的實際數據,詳細說明 SRTP 密鑰的導出步驟。

協商後的加密算法

加密套件:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) 橢圓曲線算法爲:secp256r1,橢圓曲線的點壓縮算法爲:uncompressed。 橢圓曲線算法的基礎知識的介紹在 ECC 橢圓曲線加密算法 - ECDH,ECDHE,ECDSA ,由文檔中咱們能夠知道,肯定橢圓曲線加密算法有以下參數:

  • 素數 p,用於肯定有限域的範圍
  • 橢圓曲線方程中的 a,b 參數
  • 用於生成子羣的的基點 G
  • 子羣的階 n
  • 子羣的輔助因子 h 定義爲六元組(p,a,b,G,n,h)

經過在 SECG-SEC2 2.4.2 Recommended Parameters secp256r1 中能夠查到 secp256r1 對應的參數以下:

secp256r1使用的參數以下:
使用的素數p:
p=FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
=2224(232−1)+2192+296−1
橢圓曲線E:y^2=x^3+ax+b的參數定義以下:
a=FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC
b=5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B
基點G的非壓縮格式:
G=046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5
有限域的階n:
n=FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
輔助因子h:
h=01

經過 KeyExchange 交換橢圓曲線算法公鑰

ECDH Server Parameter

Pubkey:04b0ce3c5f2c4a9fbe7c2257c1328438f3378f74e9f528b6e27a00b44eee4c19e5e6b2cb6cab09f796bcf8c05102b2a4bcdc753d91cc4f431f558c845a1ba6f1ce

記爲 Spk

ECDH Client Paramter

PubKey: 0454e8fbef1503109d619c39be0ccaf89efa3c3962300476465cbc66b15152cd8a900c45d506420f0123e65d8fbb70cb60b497893f81c5c2a0ef2f4bc2da996d9e

記爲 Cpk

根據 ECDHE 算法計算共享密鑰 S(pre-master-secret)

假設 Server 的使用的橢圓曲線私鑰爲 Ds, Client 使用的 Dc,計算共享密鑰的以下,參考 ECC 橢圓曲線加密算法 - ECDH,ECDHE,ECDSA

S = Ds * Cpk = Dc * Spk

這個共享密鑰 S 就是咱們在 RFC 文檔中看到的 pre-master-secret

計算 master secret

計算 master secret 過程以下,可參考 Computing the Master Secret

master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random)[0..47];

計算出來的 master_secret 爲 48 Bytes,其中 ClientHello.randomServerHello.random 在 Hello 消息中給出。PRF 是僞隨機數函數 (pseudorandom function),在協商的加密套件中給出。

使用 master_secrete 導出 SRTP 加密參數字節序列

使用 RFC5705 4. Exporter Definition 給出的計算方式,使用參數 master_secretclient_randomserver_random 計算字節序列:

key_block = PRF(master_secret, "EXTRACTOR-dtls_srtp", client_random + server_random)[length]

DTLS-SRTP 4.2. Key Derivation 中描述了須要的字節序列長度。

2 * (SRTPSecurityParams.master_key_len + SRTPSecurityParams.master_salt_len) bytes of data

master_key_len 和 master_salt_len 的值,在 user_srtp 描述的 profile 中定義。咱們的實例中使用的 profile 爲 SRTP_AES128_CM_HMAC_SHA1_80,對應的 profile 配置爲:

SRTP_AES128_CM_HMAC_SHA1_80
        cipher: AES_128_CM
        cipher_key_length: 128
        cipher_salt_length: 112
        maximum_lifetime: 2^31
        auth_function: HMAC-SHA1
        auth_key_length: 160
        auth_tag_length: 80

也就是咱們須要 (128/8+112/8)*2 = 60 bytes 字節序列。

導出 SRTP 密鑰

計算出 SRTP 加密參數字節序列,在 DTLS-SRTP 4.2. Key Derivation 描述了字節序列的含義:

client_write_SRTP_master_key[SRTPSecurityParams.master_key_len]; // 128 bits
server_write_SRTP_master_key[SRTPSecurityParams.master_key_len]; // 128 bits
client_write_SRTP_master_salt[SRTPSecurityParams.master_salt_len]; // 112 bits
server_write_SRTP_master_salt[SRTPSecurityParams.master_salt_len]; // 112 bits

至此咱們獲得了,Client 和 Server 使用的 SRTP 加密參數:master_key 和 master_salt.

DTLS 超時重傳

DTLS 是基於 UDP 的,不可避免會出現丟包,須要重傳。若是處理不當,會致使整個通訊雙方沒法創建會話,通話失敗。RFC6347 4.2.4 給出了超時和重傳機制。 在處理重傳時,如下幾點須要注意:

  1. 在 DTLS 協議中,爲了解決丟包和重傳問題,新增了 message_seq. 在發送 DTLS 重傳消息時,必定要更新其中的 message_seq,這樣對端將把包識別是一個重傳包,響應正確消息。不然,會默默丟棄這些包,不進行響應。
  2. 當 server 端收到 client 的 FINISHED 消息,併發送 FINISHED 消息給 client,更新 server 狀態爲協商完成,開始發送 SRTP 數據。此時發送給 client 的 FINISHED 消息,出現丟包。client 收到 SRTP 數據後丟棄。同時,再次發送 FINISHED 消息到 server,server 要正確響應。不然,會致使 DTLS 協商完成的假象,通話失敗。
  3. 使用 openssl 1.1.1 以前版本,沒法設置 DTLS 超時重傳時間,能夠超時重傳機制不可用,你們開始轉向使用 boringssl。openssl 1.1.1 開始版本已經支持設置 DTLS 超時重傳,達到和 boringssl 一樣的效果。參考 DTLS_set_timer_cb

OpenSSL 的 DTLS 功能

DTLS 是一個龐大的協議體系,其中包括了各類加密,簽名,證書,壓縮等多種算法。大多數項目是基於 OpenSSL 或 BoringSSL 實現的 DTLS 功能。在實際項目使用 OpenSSL 的 DTLS 功能,與協商有關的接口總結以下。

  1. X509_digest,計算證書 fingerprint,用在 SDP 協商中的 fingerprint 屬性。
  2. SSL_CTX_set_cipher_list,設置使用的加密套件,經過設置算法的描述,影響 Hello 消息中的 cipher list。
  3. SSL_CTX_set1_sigalgs_list 設置簽名算法。經過設置簽名算法的描述,影響 hello 消息中 signature_algorithms 擴展。signature_algorithms 對 DTLS 的 Hello 消息KeyExchangeCerficateVerify 消息。signature_algorithms 設置不正確,會出現 internal error,不容易定位問題。
  4. SSL_CTX_set_verify 設置是否校驗對端的證書。因爲在 RTC 中大多數據狀況下使用自簽證書,因此對證書的校驗,已校驗身份是須要的。
  5. SSL_CTX_set_tlsext_use_srtp 設置 srtp 擴展。srtp 擴展中的 profile,影響 srtp 加密時使用密鑰的協商和提取。
  6. SSL_set_options 使用 SSL_OP_NO_QUERY_MTU 和 [SSL_set_mtu] 設置 fragment 的大小。默認 OpenSSL 使用 fragment 較小。經過上面兩個接口,設置適合網絡狀況的 fragment。
  7. DTLS_set_timer_cb,設置超時重傳的 Callback,由 callback 設置更合理的超時重傳時間。

在開源項目 SRS 中已經支持了 WebRTC 的基礎協議,對 DTLS 協議感興趣的同窗,能夠基於 SRS 快速搭建本機環境,經過調試,進一步加深對 DTLS 的理解。

總結

本文經過 WebRTC 中 SRTP 密鑰的協商過程,來講明 DTLS 在 WebRTC 中的應用。DTLS 協議設計的各個加密算法的知識較多,加上 TLS 消息的在各類應用場景中的擴展,不免有理解和認知不到的地方,還須要進一步深刻探索。

參考文獻

  1. TLS 1.2
  2. DTLS 1.2
  3. TLS Session Hash Extension
  4. TCP-Based Media Transport in the Session Description Protocol
  5. TLS Extension
  6. SRTP Extension for DTLS
  7. OpenSSL Man
  8. ECC 橢圓曲線加密算法 - 介紹
  9. ECC 橢圓曲線加密算法 - 有限域和離散對數
  10. ECC 橢圓曲線加密算法 - ECDH、ECDHE 和 ECDSA

「視頻雲技術」你最值得關注的音視頻技術公衆號,每週推送來自阿里雲一線的實踐技術文章,在這裏與音視頻領域一流工程師交流切磋。公衆號後臺回覆【技術】可加入阿里雲視頻雲技術交流羣,和做者一塊兒探討音視頻技術,獲取更多行業最新信息。

相關文章
相關標籤/搜索