DTLS 握手 · 在 ICE 通路上建安全信道
DTLS 是「跑在 UDP 上的 TLS」。这一章读 g3doc/dtls_transport.md 与 dtls 源码:DtlsTransport 如何在 ICE 变 writable 后握手、怎么在同一条路上把 DTLS/SRTP/STUN 三种包多路复用区分开,以及握手产出的两样东西——SRTP 密钥材料与远端证书指纹。
DTLS 握手 · 在 ICE 通路上建安全信道
安全总览说 DTLS 负责「协商密钥」。这一章看它具体怎么在刚打通的 ICE 通路上握手,建起安全信道。
DTLS = 跑在 UDP 上的 TLS
DTLS(Datagram TLS) 就是为不可靠数据报(UDP)改造过的 TLS。TLS 保护 HTTPS,但它假设底层是可靠有序的 TCP;而 WebRTC 的媒体走 UDP(为了低延迟),包会丢、会乱序。DTLS 在 TLS 基础上加了应对丢包 / 乱序的机制(重传、显式序号),让 TLS 的那套「握手 → 建立密钥 → 加密」能在 UDP 上跑。它给 WebRTC 的,正是 TLS 那套久经考验的安全。
握手时机:ICE 通了才开始
关键的时序,g3doc/dtls_transport.md 讲得很清楚:
The DTLS handshake happens after the ICE transport becomes writable and has found a valid pair.
DTLS 握手必须等 ICE 先打通一条路。 逻辑上顺理成章:握手也是要收发包的,得先有一条能通的 Connection(writable 且找到有效候选对),DTLS 的握手消息才有路可走。所以通话建立的顺序是:先 ICE 打通(第 2 部分),P2PTransportChannel SignalIceTransportStateChanged 通知「路通了」,DTLS 才在这条路上启动握手。握手本身跑在 ICE 选定的那条通路上——ICE 是 DTLS 的「承运人」。
DtlsTransport:握手的执行者
执行握手的是 DtlsTransport(W3C 的 RTCDtlsTransport 在 C++ 的落地)。它的结构(g3doc/dtls_transport.md):
DtlsTransport(pc/)—— 对外的包装,可注册DtlsTransportObserverInterface观察者,通过DtlsTransportInformation汇报状态(连接状态、远端证书、SRTP 套件)。DtlsTransportInternal—— 接口,实现是DtlsTransportInternalImpl(dtls/)。它通过底层的 ICE 传输收发网络包,并驱动 BoringSSL 完成握手的状态机。
握手完成后,DtlsTransport 的状态变为 connected,并携带两样至关重要的产出(下面详述)。
一条路上三种包:多路复用
这里有个精妙的工程细节。DTLS 握手、SRTP 媒体、STUN 探测——三种包全都跑在同一条 ICE 通路上(BUNDLE时更是所有媒体挤一条)。收到一个 UDP 包,怎么知道它是哪种?
靠包的第一个字节区分——这是 RFC 5764 定义的多路复用(demultiplexing)方案。 DtlsTransportInternalImpl 会「demultiplex DTLS packets and SRTP packets」(g3doc/dtls_transport.md):
- 第一字节在某个范围 → STUN 包(连通性检查 / 保活),交给 ICE。
- 第一字节在另一范围 → DTLS 包(握手消息),交给 DTLS。
- 第一字节在再一个范围 → SRTP 包(加密媒体),解密后交给 RTP。
三种协议共用一个 UDP 端口、一条通路,靠首字节的取值范围岔开——既省了端口(呼应 BUNDLE 的节约哲学),又让 STUN 保活、DTLS 握手、SRTP 媒体能在同一条来之不易的路上和谐共处。这是 WebRTC「一条路承载一切」设计的又一处体现。
握手的两样产出
DTLS 握手成功,产出两样东西(g3doc/dtls_transport.md),它们是接下来两章的主题:
- 一套派生密钥(keying material) —— 用来给 SRTP 生成加密密钥(DTLS-SRTP)。
- 远端证书的指纹 —— 拿它和 SDP 里
a=fingerprint:那行比对,确认「握手的对端,正是信令里说的那个人」——防中间人。
小结与下一章
DTLS 是「跑在 UDP 上的 TLS」,给 WebRTC 提供久经考验的安全握手。它必须等 ICE 打通一条 writable 的路才开始,握手消息跑在这条 ICE 通路上。DtlsTransport / DtlsTransportInternalImpl 是执行者,驱动 BoringSSL。同一条路上,DTLS / SRTP / STUN 三种包靠首字节范围多路复用(RFC 5764)。握手产出两样:SRTP 密钥材料(下下章导出)和远端证书指纹(下一章用于防中间人)。
握手要用证书,而证书指纹是防中间人的关键。下一章看证书怎么生成、指纹怎么把 DTLS 安全和信令绑在一起。👉 证书与指纹。
参考资料
- [1] libwebrtc 源码.
g3doc/dtls_transport.md(握手时机、多路复用、DtlsTransport/DtlsTransportInternalImpl)。 - [2] libwebrtc 源码.
dtls/dtls_transport_internal_impl.h、api/dtls_transport_interface.h。 - [3] IETF RFC 6347「DTLS 1.2」、RFC 5764「DTLS-SRTP 多路复用」。