From 0c330cdfdb787c60c9d65db2b8a29d7e5c36748f Mon Sep 17 00:00:00 2001 From: wangzipai <38389763+wangzipai@users.noreply.github.com> Date: Thu, 28 Nov 2024 12:36:10 +0800 Subject: [PATCH] [PUBLISHER] Merge #21 --- .../Obsidian/踩过的坑/客户平台无法连接问题.md | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 content/Obsidian/踩过的坑/客户平台无法连接问题.md diff --git a/content/Obsidian/踩过的坑/客户平台无法连接问题.md b/content/Obsidian/踩过的坑/客户平台无法连接问题.md new file mode 100644 index 000000000..2eebf41ce --- /dev/null +++ b/content/Obsidian/踩过的坑/客户平台无法连接问题.md @@ -0,0 +1,192 @@ +--- +date created: 2024-11-28 10:54 +date updated: 2024-11-28 12:35 +tags: + - BUG + - mbedtls +share: "true" +link: "false" +--- + +# 解决过程 + +## MBEDTLS_SSL_VERIFY_NONE + +客户平台使用自签名的证书导致无法连接。按正常的思路将服务器的证书校验关闭就可以了。如下在连接中将参数设置为`MBEDTLS_SSL_VERIFY_NONE` + +```c +mbedtls_ssl_conf_authmode(&session->conf, MBEDTLS_SSL_VERIFY_NONE); +``` + +但是很奇怪的事情发生了,经过测试发现上面的设置好像没有什么帮助。使用wireshark抓包可以看到,提示证书损坏。 +![image.png](https://raw.githubusercontent.com/wangzipai/my_ob_pic/main/20241128110449.png) + +## LIBRWS_USING_MBED_TLS + +既然已经关闭证书校验了,为什么还会去验证证书呢。看了使用的rws库发现了宏`LIBRWS_USING_MBED_TLS`没有使用,于是怀疑是因为rws库没有关联mbedtls导致mbedtls中的证书校验关了,但是rws使用了另外的接口又去验证了平台的证书。打开这个宏发现编译报错,因为迭代了太多次导致这个宏无法使用了。于是继续从rws的`connect`函数进入,发现rws的`connect`关联到了`sal_connect`。 +![image.png|450](https://raw.githubusercontent.com/wangzipai/my_ob_pic/main/20241128111457.png) +而sal_connect又注册了mbedtls的connect接口。 +![image.png](https://raw.githubusercontent.com/wangzipai/my_ob_pic/main/20241128112006.png) +所以说饶了一圈又回到了原来的地方,`LIBRWS_USING_MBED_TLS`的开关并不影响wss的连接。 + +## MBEDTLS_SSL_ALERT_MSG_BAD_CERT + +抓包的bad certificate 对应mbedtls中的的宏`MBEDTLS_SSL_ALERT_MSG_BAD_CERT`,这个宏在项目中只有在一下两个地方有使用到。 +![image.png](https://raw.githubusercontent.com/wangzipai/my_ob_pic/main/20241128113615.png) +往上层找,可以看到这个两个函数都是在`mbedtls_ssl_parse_certificate`中被调用的,他的上层函数`mbedtls_ssl_handshake_client_step`是tls层中客户端的交互流程,`mbedtls_ssl_parse_certificate`本身则是ServerHello后的Certificate步骤。 +![image.png](https://raw.githubusercontent.com/wangzipai/my_ob_pic/main/20241128114116.png) +观察这个函数可以看到他是有对`authmode`这个参数做处理的,这个参数就是上面的[[客户平台无法连接问题#MBEDTLS_SSL_VERIFY_NONE|MBEDTLS_SSL_VERIFY_NONE]]传进来的。 + +```c +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + int crt_expected; +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + const int authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET + ? ssl->handshake->sni_authmode + : ssl->conf->authmode; +#else + const int authmode = ssl->conf->authmode; +#endif + void *rs_ctx = NULL; + mbedtls_x509_crt *chain = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + crt_expected = ssl_parse_certificate_coordinate( ssl, authmode ); + if( crt_expected == SSL_CERTIFICATE_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + goto exit; + } +... +} +``` + +但是函数`ssl_parse_certificate_coordinate`中又完全不对这个入参做处理,按照逻辑应该判断这个入参是否为`MBEDTLS_SSL_VERIFY_NONE`来判断是否需要返回跳过,这里应该是mbedtls库的一个BUG。 +![image.png](https://raw.githubusercontent.com/wangzipai/my_ob_pic/main/20241128115053.png) +尝试在这里让他返回跳过这个证书的步骤,直接到下一个状态。使用抓包工具发现bad certificate的提示消失了,但是出现了新的报错`MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR`,重复上面的过程发现这次在ServerKeyExchange、CertificateRequest、ServerHelloDone都需要相应的手动跳过流程。对mbedtls库的改动过大,应该还有其他的方法可以控制。 + +## MBEDTLS_MPI_MAX_SIZE + +观察客户的自签名证书: + +```sh +# wyq @ wangyq in ~ [0:19:37] +$ openssl x509 -in /mnt/d/cert.pem -text -noout +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 79:8c:ac:87:c3:92:46:8d:0d:6d:19:16:e7:36:01:47:05:57:25:5f + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=my, ST=ev, L=kl, O=ev, OU=ev + Validity + Not Before: Nov 18 14:19:18 2024 GMT + Not After : Nov 18 14:19:18 2025 GMT + Subject: C=my, ST=ev, L=kl, O=ev, OU=ev + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:b7:63:d6:ef:50:65:04:a1:24:67:b3:24:7d:6f: + 45:6e:16:f6:40:ca:3c:c5:a7:9b:86:5f:42:b9:6f: + 73:68:06:89:cb:7f:3d:c4:51:c3:c9:0d:c2:68:5b: + c9:f1:a1:22:6c:0f:39:5a:51:9e:ed:de:0a:83:11: + 0f:96:14:e2:7f:b4:92:1d:0a:97:e8:32:c7:60:f9: + ad:cb:87:bc:0f:e5:05:8b:4b:6b:71:5f:5a:82:69: + b5:09:8e:41:98:9f:de:af:26:d7:2b:db:60:b6:39: + 7c:e2:0f:98:51:c9:6c:ad:0e:7a:5d:61:5e:6e:4d: + fc:49:62:23:92:10:81:ec:23:cb:38:50:b7:b6:b0: + b7:77:0d:1d:59:4c:0f:f4:0e:e6:ae:d8:d2:da:51: + 41:54:86:a1:91:1d:74:7c:a1:00:29:62:25:0e:fd: + e8:c5:4a:f1:53:7b:56:01:6f:67:02:ab:6b:77:c0: + be:b3:57:75:50:c3:db:6d:03:e8:db:a7:54:2f:bc: + 2a:94:88:5f:3e:47:b9:61:c6:5b:0d:68:a4:18:f1: + 3f:df:0d:ab:54:1a:05:8c:25:0b:5c:ce:b2:80:39: + ac:fe:94:2f:64:c2:bb:f7:1c:42:e7:08:15:30:b8: + 33:ba:4e:13:56:1f:82:2a:74:98:e3:5c:8b:4d:6a: + 8f:14:1e:84:49:01:48:9c:14:3d:46:be:56:87:68: + 8b:db:5f:79:b4:11:ce:5e:da:d5:ab:53:9e:3b:9b: + 8e:03:e6:46:50:43:32:70:5a:db:08:5d:83:9f:16: + 37:4b:62:be:d3:d9:ae:ad:59:92:79:cd:0c:d8:e6: + 5b:b3:94:c9:03:a0:0c:d4:2c:0c:bb:d0:6d:d4:42: + 61:c1:11:2c:88:63:d4:70:e4:e7:6d:f3:8b:0e:97: + 14:c8:28:6a:25:07:de:75:36:27:91:71:65:84:bb: + c0:fe:8b:89:bb:bd:f2:d4:bd:a2:18:de:2d:fa:eb: + 14:cb:f8:b4:63:2d:d3:58:ab:93:89:26:f9:d2:db: + cf:75:a3:8c:02:22:d5:7f:2a:2e:12:50:34:90:87: + ae:9b:b0:44:d7:9f:4d:98:47:e2:cf:8b:2b:a6:23: + 77:c1:e8:0c:32:48:79:64:0c:c7:b9:b5:c3:d6:72: + d3:e9:01:c9:0e:06:01:b4:f3:ac:99:e5:b0:d0:12: + 04:39:60:ee:e2:e0:4d:05:ed:70:02:22:24:c9:96: + 01:59:66:ed:4b:b6:2c:e2:d3:3d:c2:52:32:84:1b: + 08:db:f5:6b:6f:22:09:f0:bb:2a:54:35:c2:09:68: + c9:ab:56:19:5a:73:62:7a:a7:06:3c:43:86:ff:69: + 8c:3d:27 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 34:91:00:5B:0B:15:EF:EB:E6:FC:7D:8A:85:AB:63:B4:C6:EA:3D:1E + X509v3 Authority Key Identifier: + 34:91:00:5B:0B:15:EF:EB:E6:FC:7D:8A:85:AB:63:B4:C6:EA:3D:1E + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 10:2e:4c:59:e0:50:39:a6:30:b4:cf:d9:0e:8d:d9:3d:7c:04: + 08:b4:fd:2d:cf:0f:eb:32:ae:21:e2:7d:83:85:68:60:20:ed: + f5:8c:bc:f2:52:8c:bd:c9:ee:2a:96:4f:9a:fd:2c:5d:59:dc: + 13:d9:68:30:cc:b8:27:46:35:10:eb:87:6c:56:4c:a8:60:78: + 65:f0:1f:73:b9:80:f5:5c:c6:7c:85:75:26:10:46:48:99:d2: + 87:32:eb:a2:61:1e:ff:2d:7b:15:8d:e4:1e:36:9b:78:56:06: + 8c:a9:13:01:49:f5:be:50:c3:cb:62:64:66:2d:1e:2f:5a:2d: + 2d:fc:62:ef:89:5a:91:53:87:67:51:69:9b:c0:5c:43:04:0d: + 48:2a:12:17:3d:97:ef:9a:9b:be:11:ab:0d:74:6c:44:34:a8: + d8:2d:7b:28:be:2c:ff:06:b5:69:14:39:10:96:c0:a8:43:1f: + c5:32:8b:79:92:95:19:30:b9:e4:4a:d0:35:7d:ff:ff:24:75: + 1e:82:d1:7a:e4:c1:4b:11:e2:2b:b3:a3:91:c3:08:40:1e:52: + ef:af:14:ad:f0:c7:39:ca:5d:b6:6b:fc:fa:ed:2c:ed:e1:8f: + 84:e7:9a:a6:21:20:60:e9:aa:cf:a9:cd:37:fc:5a:90:7a:bc: + 8d:56:77:e5:1f:25:30:fb:4d:ef:fa:c2:ae:34:ac:d1:f4:0b: + 4d:d0:9c:ba:86:67:1c:9e:fd:4c:8a:c2:3d:f4:91:93:45:59: + 51:75:b6:0c:63:94:a0:ac:37:dc:b4:28:4f:cb:cb:43:f7:b1: + 98:87:f7:3c:26:59:71:a3:ea:0e:25:10:b0:32:a0:35:34:73: + 8a:da:bb:4e:0b:f8:36:d4:2a:86:98:0d:44:0c:9e:5c:59:c7: + 19:13:3a:2b:ae:91:13:f9:27:5a:89:38:a0:c5:ed:e0:4a:d0: + a2:4f:c9:ee:6c:04:14:72:f3:36:73:ae:4c:9f:0d:9b:48:52: + 30:3b:fd:2f:99:13:3f:e5:23:c7:31:36:16:1c:d1:6c:0a:37: + 0e:ee:25:03:b1:b1:ac:03:33:10:fd:67:18:1f:b5:64:9d:51: + 67:b9:d1:5a:c9:ba:90:0d:30:cd:3e:4b:a6:3a:6c:87:5d:48: + 2b:4a:eb:7e:dc:d7:f9:a3:28:24:cc:47:86:9b:58:cf:bd:e6: + fa:cc:95:27:5c:47:2d:a1:e8:3b:61:d4:da:b1:2c:2c:e1:26: + a7:40:8b:86:45:c4:84:20:4f:cb:30:29:7c:1b:d5:87:82:38: + 52:2c:ac:c7:55:ae:98:23:79:ed:2b:b0:1e:99:27:d9:1b:bd: + 48:dd:61:6c:1e:45:a3:6d +``` + +发现客户使用的是一个 X.509 第三版的证书,使用 `SHA-256` 哈希算法和 `RSA` 加密算法签名证书,==公钥长度为 4096 位==。 + +问题出现了,正经人谁用这么长的公钥? + +根据 [NIST SP 800-57](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r5.pdf) 的建议,不同算法的安全性级别如下: + +| **安全性级别** | **RSA 密钥长度** | **ECC 密钥长度** | +| --------- | ------------ | ------------ | +| 112 位 | 2048 位 | 224 位 | +| 128 位 | 3072 位 | 256 位 | +| 192 位 | 7680 位 | 384 位 | +| 256 位 | 15360 位 | 512 位 | + +从表中可以看出,RSA 4096 位位于 ECC 384 位和 512 位之间,明明用ecc算法384位就能搞定的事情,非得增加mcu的负担。 + +修改`MBEDTLS_MPI_MAX_SIZE`宏从384到512。 + +```c +#define MBEDTLS_MPI_MAX_SIZE 512 +``` + +# 总结 + +这次的无法连接平台的问题,主要是mbedtls中对于tls的握手处理,把是否跳过验证的处理放到了解析证书的后面。导致即使使用`MBEDTLS_SSL_VERIFY_NONE`关闭了验证,实际上却因为`MBEDTLS_MPI_MAX_SIZE`大小不够而导致证书解析失败,从而导致无法连接平台。还有就是对客户平台的不了解,一开始以为客户无法提供自签名的证书,也没有想到客户不是使用主流的2048位的公钥的RSA签名。