必须先调用 mbedtls_ssl_init 和 mbedtls_ssl_config_init 初始化上下文与配置,再调用 mbedtls_ssl_setup;未初始化会导致空指针解引用崩溃;出错后仍需调用 mbedtls_ssl_free 和 mbedtls_ssl_config_free 防止内存泄漏。

初始化mbedtls上下文前必须调用 mbedtls_ssl_init 和 mbedtls_ssl_config_init
很多人直接堆栈变量或 memset 0 后就调用 mbedtls_ssl_handshake,结果崩溃或返回 MBEDTLS_ERR_SSL_BAD_INPUT_DATA。mbedtls 不是纯函数式库,所有核心结构体(mbedtls_ssl_context、mbedtls_ssl_config)都依赖显式初始化,内部指针默认为 NULL,未初始化就传给 API 会触发空解引用。
- 必须按顺序调用:
mbedtls_ssl_init→mbedtls_ssl_config_init→mbedtls_ssl_setup - 出错后不能跳过清理:哪怕
mbedtls_ssl_setup失败,也要先调用mbedtls_ssl_free和mbedtls_ssl_config_free,否则内存泄漏 - 配置对象(
mbedtls_ssl_config)可复用,但 SSL 上下文(mbedtls_ssl_context)每个连接必须独立实例化
设置证书和密钥时注意 PEM/DER 格式与内存生命周期
使用 mbedtls_x509_crt_parse 或 mbedtls_pk_parse_key 加载证书/私钥时,常见错误是传入栈上临时字符串、或没加 PEM 尾缀("-----END CERTIFICATE-----"),导致解析返回 MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT。
- PEM 数据必须以
\0结尾,且包含完整首尾标记;若从文件读取,记得用fread+\0补位,别直接传fgets截断结果 - 私钥若带密码,需提供回调函数给
mbedtls_pk_parse_key,否则返回MBEDTLS_ERR_PK_PASSWORD_REQUIRED - 证书链要按“叶子→中间→根”顺序加载,反了会导致验证失败;用
mbedtls_x509_crt_parse多次调用即可,它支持拼接 - 所有证书/密钥数据内存必须在 SSL 运行期间持续有效——不能是局部数组、不能在
mbedtls_ssl_setup后释放
阻塞式 socket 下必须正确处理 mbedtls_ssl_read 的返回值
不同于 OpenSSL 的 SSL_read,mbedtls_ssl_read 在握手未完成时返回 MBEDTLS_ERR_SSL_WANT_READ,网络层收不到数据时也返回这个码,容易误判为“连接已断”。
- 只要返回值
,必须检查是否为 <code>MBEDTLS_ERR_SSL_WANT_READ或MBEDTLS_ERR_SSL_WANT_WRITE,其它负值才是真实错误 - 遇到
WANT_READ时,应继续等待 socket 可读(如select或poll),而不是重试或关闭连接 - 读到 0 字节不表示 EOF,只表示对端关闭 TLS 层(即发送了 close_notify),此时应调用
mbedtls_ssl_close_notify并清理 - 不要假设一次
mbedtls_ssl_read能读满缓冲区——它可能只解密出几个字节,尤其在小包或分片场景下
启用 SNI 需手动调用 mbedtls_ssl_set_hostname,且仅对客户端有效
服务端若要根据域名返回不同证书,得自己解析 ClientHello 中的 SNI 扩展并切换 mbedtls_ssl_config,mbedtls 不自动做这事。而客户端不设主机名,某些 CDN 或多租户服务会拒绝握手,报错 MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE(alert 47 = unrecognized_name)。
- 客户端必须在
mbedtls_ssl_setup后、mbedtls_ssl_handshake前调用mbedtls_ssl_set_hostname,参数是目标域名(如"api.example.com") - 服务端想支持多域名,得在
mbedtls_ssl_conf_sni注册回调函数,在回调里根据hostname参数动态调用mbedtls_ssl_conf_own_cert切换证书 - 如果服务端没配 SNI 回调,又收到带 SNI 的 ClientHello,mbedtls 默认接受但不会切换证书——这意味着你可能用错证书而不自知
真正麻烦的不是写几行 setup 代码,而是证书路径权限、系统时间偏差导致证书校验失败、以及网络层粘包/半包怎么喂给 mbedtls —— 这些问题不会报清楚的错误码,只会让 mbedtls_ssl_handshake 卡在 WANT_READ 里不动。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











