描述(Description)
- SRS版本(Version):
4.0
- 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)
- SRS的配置如下(Config):
使用 Wiki 中一对一通话的命令及默认配置启动的srs、signaling、httpx三个服务。
一对一通话
重现(Replay)
- 使用 webrtc-rs 创建 PeerConnection;
- 使用 SRS 提供的 play 接口提交 local SDP 并设置 SRS 端 SDP 为 remote desc;
- DTLS 握手失败,报错 Bad Certificate
期望行为(Expect)
DLTS 握手成功,能获得 RemoteTrack对象 并读取 RTP 数据。
问题分析及临时解决
我使用 wireshark 对 DTLS 握手情况进行了记录,在 ClientHello 阶段,webrtc-rs 提供了以下hash算法:
可以看到并不包括sha1;而在 ServerHello 之后返回证书时,提供的是使用 ecdsa-with-sha1 的方式进行签名的证书。
我尝试将 srs_app_rtc_dtls.cpp:322 的 EVP_sha1() 修改为 EVP_sha256(),发现 webrtc-rs 可以成功握手并拉流,浏览器端推拉流均无问题。
据我了解 sha1 算法已经不推荐使用,请问我有必要提个 PR 把这个改成 sha256 吗?不知道是否会影响兼容性。
PS:感谢 Winlin 大佬直播指点,我在研究直播连麦。
3条答案
按热度按时间wvmv3b1j1#
返回的算法中,可以加几个算法,这样可以协商出支持的。
你看看DTLS的标准,别只是抓包看哈。
你是什么浏览器?看起来是浏览器的版本问题,而不是sha1太老的问题。
加解密算法不是说换就换的,搞不好你这个问题解决了,一大片人会有新的问题。
dvtswwa32#
返回的算法中,可以加几个算法,这样可以协商出支持的。
你看看DTLS的标准,别只是抓包看哈。
你是什么浏览器?看起来是浏览器的版本问题,而不是sha1太老的问题。
加解密算法不是说换就换的,搞不好你这个问题解决了,一大片人会有新的问题。
感谢回复。
我也查阅了一些标准,参考 DTLS 1.2 的 RFC6347 的 4.2.6 CertificateVerify and Finished Messages 章节:
CertificateVerify and Finished messages have the same format as in TLS.
所以,DTLS 的证书验证也应该参考 TLS 的 RFC5246 标准 。在该标准的 7.4.2. 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.
即: 如果客户端提供了“signature_algorithms”扩展,那么服务器提供的所有证书必须由该扩展中出现的散列/签名算法对签名。
所以,从抓包来看,我的客户端(使用的不是浏览器,是一个 WebRTC 的 Rust 实现, https://github.com/webrtc-rs/webrtc )提供了“signature_algorithms”扩展,而其中并不包含 SHA1 算法,服务端不应该返回由 SHA1 签名的算法。也就是 SRS 并没有按照 DTLS 标准实现。
我在 srs_app_rtc_dtls.cpp:276 看到了:
这里只是对于曲线函数写了需要从客户端提供的算法里选择,而在生成证书时,也应该加上一个 TODO,根据客户端提供的哈希算法生成证书。
目前看,SRS 应该是暂时默认使用 SHA1。而根据 Deprecating MD5 and SHA-1 Signature Hashes in TLS 1.2 and DTLS 1.2 (RFC9155),SHA1 已经不应该出现在 TLS 1.2 / DTLS 1.2 中了,所以我觉得即便是默认实现也并不应该使用 SHA1。
当然这个标准作为草案也有几年了,只是去年12月份才成为 Proposed Standard。个人了解,这个草案出现之前 SHA1 就已经不被推荐了,很多软件就已经在替换了,具体要多大程度向下兼容请大佬们定夺吧。
再次感谢回复 :)
5sxhfpxr3#
你看看Chrome怎么选的,别假设所谓的大佬有所有问题的答案。