---
date: 2024-11-28 10:54
updated: 2024-12-03 11:57
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签名。
