Let’s Encrypt证书更新后W801(W80X_SDK_v1.00.10)https请求mbedtls再次报错0x7780问题

之前曾经记录过一篇关于W801上https客户端访问ssl握手报错问题解决过程的文章:W801(W80X_SDK_v1.00.10)https请求mbedtls报错0x7780问题解决记录,这个小设备这几年也一直在用,直到最近一次服务端(Caddy v2.10.0 h1:fonubSaQKF1YANl8TXqGcn4IbIRUDdfAkpcsfI/vX5U=)用的Let’s Encrypt免费ssl证书更新后,发现这个问题ssl握手失败0x7780的错误居然又出现了!

一开始还没发现出问题,更新了SSL证书后,其它PC客户端访问都没有问题,过了几天后才注意到W801上的请求都没有了,于是用官方的Upgrade_Tools_V1.4.18连上串口,查看了下日志,果然,发现又出现了似曾相识的报错:

  . Seeding the random number generator... ok
  . Connecting to tcp... ok
  . Setting up the SSL/TLS structure... ok
  . Performing the SSL/TLS handshake... failed
	! mbedtls_ssl_handshake returned -0x7780

start free ssl(200197cc)...
HTTPWrapperSSLConnect ret -30592
https connect error

由于时间久远,当时的一些问题排查过程、细节已经记不清了,于是又翻了自己当年的博客回顾了一下。

可以肯定的是,W801的固件这些年一直没动过,而服务端的caddy软件这些年也没有过版本变更,近期唯一的变化就是更新了lets的证书!

为了确认这点,根据自己博客当时的记录,改写了下W801固件连接的服务端地址,使用telegram官方的api.telegram.org服务验证,结果是能顺利发出请求并收到api调用成功回复的,于是开始思考问题…

更新Let’s Encrypt证书的时候,我基本都是直接覆盖,所以也没法找回旧版证书做对比了,再说,找回来也是个过期的证书,估计意义不大。

思考了一下,决定故技重施,又去mbedtls的github上下载了和W801 SDK(版本是1.00.10,没记错的话,期间也看了下联盛德官网,W80X系列MCU的SDK都更新到2.4了,跨度有点大,设备又急用,所以还是决定不要为了解决问题而引入更大的变更风险)内置的一样版本2.7.10的源码,依旧是用VS2022升级打开,编译,然后依旧是那个test程序,在直接用GitHub原版代码的情况下,直接访问新证书的服务端,结果是不会报同样的SSL握手错误,但是会报一个不受信任的CA证书问题,而且看起来这个test或者mbedtls本身并没有默认开启严格校验证书,因为即使是报了CA的错,还是正常收到HTTP 200的响应了。

从PC端跑同样版本的代码,也出现了问题的结果来看,这次更新后的lets证书肯定是引入了某种变化,于是AI一问,得到了答案:https://webhosting.today/2026/04/15/lets-encrypt-changes-its-root-certificates-on-may-13-client-auth-ends-july-8/,说是lets今年5月做过Gen Y证书迁移,虽然时间和我的没有完全对上,但是也差不多是附近的事,另外就是我的lets证书其实是域名提供上porkbun负责维护更新的,不知道是不是和他们也有什么关系,总之确实是出现过变更,也问了下AI由于证书变更确实会导致SSL的cipher发生变化。

接下来,我的思路是这样,由于W801嵌入式设备不方便断点调试(嵌入式叫仿真),不断的加串口log又过于低效,所以我决定先用PC版复现W801上同样的问题,就像当年排查时一样,mbedtls的代码应该大差不差,而有出入的其实是W801上mbedtls的config.h,应该是出于嵌入式设备空间的考虑,默认关掉了很多feature,导致支持的cipher很少。之前就是这么定位的,这次我想应该还是cipher不匹配导致握手报错的,不过打开了mbedtls的详细日志MBEDTLS_DEBUG_C后,可以看到:

  . Seeding the random number generator... ok
  . Connecting to tcp... ok
  . Setting up the SSL/TLS structure... ok
  . Performing the SSL/TLS handshake...ssl_tls.c:6850: => handshake
ssl_cli.c:3400: client state: 0
ssl_tls.c:2574: => flush output
ssl_tls.c:2586: <= flush output
ssl_cli.c:3400: client state: 1
ssl_tls.c:2574: => flush output
ssl_tls.c:2586: <= flush output
ssl_cli.c:0777: => write client hello
ssl_cli.c:0815: client hello, max version: [3:3]
ssl_cli.c:0706: client hello, current time: 1576
ssl_cli.c:0824: dumping 'client hello, random bytes' (32 bytes)
ssl_cli.c:0824: 0000:  00 00 06 28 ce 96 a3 8d c3 71 2e c6 e9 9c 51 00  ...(.....q....Q.
ssl_cli.c:0824: 0010:  89 4d fd c2 5f 39 3c d4 b5 37 be 44 21 22 19 4b  .M.._9<..7.D!".K
ssl_cli.c:0877: client hello, session id len.: 0
ssl_cli.c:0878: dumping 'client hello, session id' (0 bytes)
ssl_cli.c:0925: client hello, add ciphersuite: c030
ssl_cli.c:0925: client hello, add ciphersuite: c028
ssl_cli.c:0925: client hello, add ciphersuite: c014
ssl_cli.c:0925: client hello, add ciphersuite: c02f
ssl_cli.c:0925: client hello, add ciphersuite: c027
ssl_cli.c:0925: client hello, add ciphersuite: c013
ssl_cli.c:0925: client hello, add ciphersuite: 009d
ssl_cli.c:0925: client hello, add ciphersuite: 003d
ssl_cli.c:0925: client hello, add ciphersuite: 0035
ssl_cli.c:0925: client hello, add ciphersuite: 009c
ssl_cli.c:0925: client hello, add ciphersuite: 003c
ssl_cli.c:0925: client hello, add ciphersuite: 002f
ssl_cli.c:0925: client hello, add ciphersuite: c012
ssl_cli.c:0925: client hello, add ciphersuite: 000a
ssl_cli.c:0937: client hello, got 14 ciphersuites (excluding SCSVs)
ssl_cli.c:0946: adding EMPTY_RENEGOTIATION_INFO_SCSV
ssl_cli.c:0995: client hello, compress len.: 1
ssl_cli.c:0997: client hello, compress alg.: 0
ssl_cli.c:0072: client hello, adding server name extension: test.com
ssl_cli.c:0189: client hello, adding signature_algorithms extension
ssl_cli.c:0274: client hello, adding supported_elliptic_curves extension
ssl_cli.c:0339: client hello, adding supported_point_formats extension
ssl_cli.c:1074: client hello, total extension length: 49
ssl_tls.c:2867: => write record
ssl_tls.c:3013: output record: msgtype = 22, version = [3:1], msglen = 124
ssl_tls.c:2574: => flush output
ssl_tls.c:2593: message length: 129, out_left: 129
ssl_tls.c:2599: ssl->f_send() returned 129 (-0xffffff7f)
ssl_tls.c:2626: <= flush output
ssl_tls.c:3025: <= write record
ssl_cli.c:1100: <= write client hello
ssl_cli.c:3400: client state: 2
ssl_tls.c:2574: => flush output
ssl_tls.c:2586: <= flush output
ssl_cli.c:1493: => parse server hello
ssl_tls.c:3904: => read record
ssl_tls.c:2358: => fetch input
ssl_tls.c:2516: in_left: 0, nb_want: 5
ssl_tls.c:2540: in_left: 0, nb_want: 5
ssl_tls.c:2541: ssl->f_recv(_timeout)() returned 5 (-0xfffffffb)
ssl_tls.c:2561: <= fetch input
ssl_tls.c:3663: input record: msgtype = 21, version = [3:3], msglen = 2
ssl_tls.c:2358: => fetch input
ssl_tls.c:2516: in_left: 5, nb_want: 7
ssl_tls.c:2540: in_left: 5, nb_want: 7
ssl_tls.c:2541: ssl->f_recv(_timeout)() returned 2 (-0xfffffffe)
ssl_tls.c:2561: <= fetch input
ssl_tls.c:4246: got an alert message, type: [2:40]
ssl_tls.c:4254: is a fatal alert message (msg 40)
ssl_tls.c:3922: mbedtls_ssl_read_record_layer() returned -30592 (-0x7780)
ssl_cli.c:1500: mbedtls_ssl_read_record() returned -30592 (-0x7780)
ssl_tls.c:6860: <= handshake
 failed
	! mbedtls_ssl_handshake returned -0x7780

ssl_tls.c:7623: => free
ssl_tls.c:7688: <= free
start free ssl(200197d0)...
HTTPWrapperSSLConnect ret -30592
https connect error

最后的fatal alert是40,翻了下记录,之前是80,还是有点区别的。

首先是mbedtls的config.h,我把W801里和硬件密码无关的define注释开关,原封不动的拷到了PC版测试程序上,再一试,果然复现了W801上同样的报错,省略耗时的比对试验过程,最后发现是这几个define造成的报错:

MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
MBEDTLS_ECDSA_C

https://binsec.tools/check/tls-ssl/,用这个新的查HTTPS服务器证书和握手cipher套件的工具可以看到,更新证书后的caddy服务器回报的TLS 1.2 cipher只有ECDHE相关的了,如果mbedtls编译时没有开启这组套件的话,就会造成握手exchange失败。

接下来的问题是这个新的CA证书,按照AI的说法,由于W801用的mbedtls属于古早版本了,没有内置lets新更换的root证书,这时需要走mbedtls_x509_crt_parse手动加载Let’s的新根证书从而给予信任。将根证书PEM内容复制进test代码里,然后加载发现报OID的错,由于可以断点调试,跟踪了下代码执行逻辑很快找到了问题:config.h里没有开启新根证书pem用的MBEDTLS_ECP_DP_SECP384R1_ENABLED,导致mbedtks库OID表里没有新lets根证书pem用的ID,所以parse报错。

加上后,PC端就可以正常握手并进行HTTP请求,获取响应了。

接下来是W801,由于SDK对mbedtls的http请求有过一次封装,所以找到HTTPClientWrapper.h代码,可以看到有个加载CA证书的define: MBEDTLS_DEMO_USE_CERT,开启后,将pem内容复制到这里,然后确保make lib生成了新的lib,然后再在sdk根路径make,生成app,然后将fls固件刷入W801,观察串口消息,问题解决。

博主友情提示:

如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。