srs icon indicating copy to clipboard operation
srs copied to clipboard

WebRTC: DTLS 握手失败

Open gengteng opened this issue 3 years ago • 3 comments

描述(Description)

  1. SRS版本(Version): 4.0

  2. SRS的日志如下(Log):

[2022-02-21 02:16:20.381][Trace][1][5n0z5y32] DTLS: State Passive RECV, done=0, arq=0/0, r0=1, r1=0, len=155, cnt=22, size=142, hs=1
[2022-02-21 02:16:20.384][Trace][1][5n0z5y32] DTLS: State Passive SEND, done=0, arq=0/0, r0=-1, r1=2, len=707, cnt=22, size=110, hs=2
[2022-02-21 02:16:20.395][Trace][1][5n0z5y32] DTLS: State Passive RECV, done=0, arq=0/0, r0=1, r1=0, len=15, cnt=21, size=2, hs=2
[2022-02-21 02:16:20.395][Error][1][5n0z5y32][0] DTLS: SSL3 alert method=read type=fatal, desc=BC(bad certificate), where=16388, ret=554, r1=0
[2022-02-21 02:16:20.395][Error][1][5n0z5y32][0] DTLS: Error method=SSL_accept state=SSLERR(error), where=8194, ret=-1, r1=1
[2022-02-21 02:16:20.396][Warn][1][07x85974][0] handle udp pkt, count=1/1, err: code=5009 : size=15, data=[15 fe fd 00 00 00 00 00] : on_dtls size=15, data=[15 fe fd 00 00 00 00 00 00 00 01 00 02 02 2a] : do handshake : handshake r0=-1, r1=1
thread [1][07x85974]: cycle() [src/app/srs_app_listener.cpp:630][errno=0]
thread [1][5n0z5y32]: on_dtls() [src/app/srs_app_rtc_dtls.cpp:481][errno=0]
thread [1][5n0z5y32]: do_on_dtls() [src/app/srs_app_rtc_dtls.cpp:517][errno=0]
thread [1][5n0z5y32]: do_handshake() [src/app/srs_app_rtc_dtls.cpp:581][errno=0]
[2022-02-21 02:16:23.287][Trace][1][nqx10e10] Hybrid cpu=0.00%,0MB, cid=8,9, timer=61,10,111, clock=0,39,8,0,1,0,0,0,0, free=1, objs=(pkt:213,raw:122,fua:90,msg:214,oth:0,buf:106)
  1. SRS的配置如下(Config):
使用 Wiki 中一对一通话的命令及默认配置启动的srs、signaling、httpx三个服务。

一对一通话

重现(Replay)

  1. 使用 webrtc-rs 创建 PeerConnection;
  2. 使用 SRS 提供的 play 接口提交 local SDP 并设置 SRS 端 SDP 为 remote desc;
  3. DTLS 握手失败,报错 Bad Certificate

期望行为(Expect)

DLTS 握手成功,能获得 RemoteTrack对象 并读取 RTP 数据。

问题分析及临时解决

我使用 wireshark 对 DTLS 握手情况进行了记录,在 ClientHello 阶段,webrtc-rs 提供了以下hash算法:

截屏2022-02-21 10 42 14

可以看到并不包括sha1;而在 ServerHello 之后返回证书时,提供的是使用 ecdsa-with-sha1 的方式进行签名的证书。

截屏2022-02-21 10 42 41

我尝试将 srs_app_rtc_dtls.cpp:322 的 EVP_sha1() 修改为 EVP_sha256(),发现 webrtc-rs 可以成功握手并拉流,浏览器端推拉流均无问题。

据我了解 sha1 算法已经不推荐使用,请问我有必要提个 PR 把这个改成 sha256 吗?不知道是否会影响兼容性。

PS:感谢 Winlin 大佬直播指点,我在研究直播连麦。

gengteng avatar Feb 21 '22 03:02 gengteng

In the returned algorithm, several algorithms can be added so that support can be negotiated.

Take a look at the DTLS standard, don't just rely on packet capture.

What browser are you using? It seems to be a version issue with the browser, rather than a problem with SHA1 being too old.

Encryption and decryption algorithms cannot be changed easily. If you solve this problem, there is a possibility that a large number of people will encounter new problems.

TRANS_BY_GPT3

winlinvip avatar Feb 26 '22 00:02 winlinvip

In the returned algorithm, several algorithms can be added so that support can be negotiated.

Take a look at the DTLS standard, don't just rely on packet capture.

What browser are you using? It seems to be a version issue with the browser, rather than a problem with SHA1 being too old.

Encryption and decryption algorithms cannot be changed easily. If you solve this problem, there is a possibility that a lot of people will have new issues.

Thank you for your response.

I also consulted some standards, referring to section 4.2.6 "CertificateVerify and Finished Messages" of RFC6347 for DTLS 1.2.

CertificateVerify and Finished messages have the same format as in TLS.

Therefore, the certificate verification for DTLS should also refer to the RFC5246 standard for TLS. In section 7.4.2 "Server Certificate" of this standard, the following requirements are specified for the server certificate:

If the client provided a "signature_algorithms" extension, then all certificates provided by the server MUST be signed by a hash/signature algorithm pair that appears in that extension.

That is: If the client provides the "signature_algorithms" extension, then all certificates provided by the server must be signed using the hash/signature algorithms appearing in that extension.

Therefore, from the packet capture, it can be seen that my client (using a WebRTC Rust implementation, https://github.com/webrtc-rs/webrtc) provides the "signature_algorithms" extension, which does not include the SHA1 algorithm. The server should not return certificates signed with the SHA1 algorithm. In other words, SRS did not implement according to the DTLS standard.

I saw it in srs_app_rtc_dtls.cpp:276.

// TODO: FIXME: Parse ClientHello and choose the curve.

Here, we only wrote the requirement to select the curve function from the algorithm provided by the client. When generating the certificate, a TODO should also be added to generate the certificate based on the hash algorithm provided by the client.

Currently, it seems that SRS should temporarily default to using SHA1. However, according to the "Deprecating MD5 and SHA-1 Signature Hashes in TLS 1.2 and DTLS 1.2" (RFC9155), SHA1 should no longer be used in TLS 1.2 / DTLS 1.2. Therefore, I believe that even the default implementation should not use SHA1.

Of course, this standard has been in draft form for several years, but it only became a Proposed Standard in December of last year. From my understanding, even before this draft appeared, SHA1 was already not recommended, and many software applications had already replaced it. The extent of backward compatibility should be determined by the experts.

Thank you again for your response :)

TRANS_BY_GPT3

gengteng avatar Feb 27 '22 06:02 gengteng

Take a look at how Chrome is selected, don't assume that so-called experts have all the answers to every problem.

TRANS_BY_GPT3

winlinvip avatar Feb 28 '22 00:02 winlinvip