You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求mbed-TLS中双向TLS(Mutual TLS)的使用示例

mbed-TLS 双向TLS(Mutual TLS)嵌入式实现示例与实践经验

核心实现逻辑

双向TLS的核心是服务器和客户端互相验证对方证书,基于mbed-TLS的实现步骤统一,嵌入式场景下重点在于资源适配:

  • 初始化mbed-TLS核心组件(SSL上下文、X509证书解析、随机数生成器)
  • 强制开启双向认证模式(服务器要求客户端提供证书,客户端验证服务器证书)
  • 双方各自加载自身证书链、私钥,以及用于验证对方的CA根证书
  • 绑定嵌入式平台的网络IO函数,完成SSL握手与数据传输

嵌入式适配要点

  • 内存优化:
    • 在mbed-TLS配置头文件中关闭不必要的加密套件(比如只保留MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256这类轻量套件)
    • 降低TLS版本至TLS 1.2(避免TLS 1.3的额外内存开销)
    • 禁用动态内存分配,改用静态内存池(配置MBEDTLS_MEMORY_BUFFER_ALLOC_C)
  • 存储适配:
    • 证书和私钥预编译进Flash,读取时直接拷贝到RAM缓冲区,避免文件系统依赖
  • 硬件加速:
    • 若平台支持硬件加密(比如STM32的CRYP模块),启用对应的mbed-TLS硬件抽象层,大幅降低CPU占用

关键代码片段

服务器端核心实现

#include "mbedtls/ssl.h"
#include "mbedtls/x509_crt.h"
#include "mbedtls/pk.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ctr_drbg.h"

int main(void) {
    mbedtls_ssl_context ssl;
    mbedtls_ssl_config conf;
    mbedtls_x509_crt srvcert, cacert;
    mbedtls_pk_context pkey;
    mbedtls_net_ctx listen_fd, client_fd;
    mbedtls_ctr_drbg_context rng;
    int ret;

    // 初始化组件
    mbedtls_net_init(&listen_fd);
    mbedtls_net_init(&client_fd);
    mbedtls_ssl_init(&ssl);
    mbedtls_ssl_config_init(&conf);
    mbedtls_x509_crt_init(&srvcert);
    mbedtls_x509_crt_init(&cacert);
    mbedtls_pk_init(&pkey);
    mbedtls_ctr_drbg_init(&rng);

    // 初始化随机数生成器(嵌入式需提供自定义熵源)
    mbedtls_ctr_drbg_seed(&rng, mbedtls_entropy_func, NULL, NULL, 0);

    // 配置双向认证:要求客户端必须提供有效证书
    mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
    mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &rng);

    // 加载CA根证书(用于验证客户端证书)
    if ((ret = mbedtls_x509_crt_parse_file(&cacert, "/flash/ca.crt")) != 0) {
        // 错误处理:比如日志输出、复位
        goto exit;
    }
    mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);

    // 加载服务器证书链和私钥
    if ((ret = mbedtls_x509_crt_parse_file(&srvcert, "/flash/server.crt")) != 0 ||
        (ret = mbedtls_pk_parse_keyfile(&pkey, "/flash/server.key", NULL, NULL, 0)) != 0) {
        goto exit;
    }
    mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey);

    // 绑定网络IO(嵌入式需实现自定义send/recv,此处用mbedtls_net示例)
    mbedtls_ssl_setup(&ssl, &conf);
    mbedtls_ssl_set_bio(&ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL);

    // 执行SSL握手
    while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            // 握手失败处理
            goto exit;
        }
    }

    // 可选:额外校验客户端证书的字段(比如CN、有效期)
    if (mbedtls_ssl_get_verify_result(&ssl) != 0) {
        // 客户端证书验证不通过
        mbedtls_ssl_close_notify(&ssl);
        goto exit;
    }

    // 后续数据收发:用mbedtls_ssl_read/write替代普通socket读写
    uint8_t buf[1024];
    while ((ret = mbedtls_ssl_read(&ssl, buf, sizeof(buf))) > 0) {
        mbedtls_ssl_write(&ssl, buf, ret); // 回显示例
    }

exit:
    // 资源释放(嵌入式场景下需确保内存完全回收)
    mbedtls_ssl_free(&ssl);
    mbedtls_ssl_config_free(&conf);
    mbedtls_x509_crt_free(&srvcert);
    mbedtls_x509_crt_free(&cacert);
    mbedtls_pk_free(&pkey);
    mbedtls_net_free(&client_fd);
    mbedtls_net_free(&listen_fd);
    mbedtls_ctr_drbg_free(&rng);
    return ret;
}

客户端核心实现

#include "mbedtls/ssl.h"
#include "mbedtls/x509_crt.h"
#include "mbedtls/pk.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ctr_drbg.h"

int main(void) {
    mbedtls_ssl_context ssl;
    mbedtls_ssl_config conf;
    mbedtls_x509_crt clicert, cacert;
    mbedtls_pk_context pkey;
    mbedtls_net_ctx server_fd;
    mbedtls_ctr_drbg_context rng;
    int ret;

    // 初始化组件
    mbedtls_net_init(&server_fd);
    mbedtls_ssl_init(&ssl);
    mbedtls_ssl_config_init(&conf);
    mbedtls_x509_crt_init(&clicert);
    mbedtls_x509_crt_init(&cacert);
    mbedtls_pk_init(&pkey);
    mbedtls_ctr_drbg_init(&rng);

    // 初始化随机数生成器
    mbedtls_ctr_drbg_seed(&rng, mbedtls_entropy_func, NULL, NULL, 0);

    // 配置客户端验证服务器证书
    mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
    mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &rng);

    // 加载CA根证书(验证服务器证书)
    if ((ret = mbedtls_x509_crt_parse_file(&cacert, "/flash/ca.crt")) != 0) {
        goto exit;
    }
    mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);

    // 加载客户端证书和私钥(用于服务器验证)
    if ((ret = mbedtls_x509_crt_parse_file(&clicert, "/flash/client.crt")) != 0 ||
        (ret = mbedtls_pk_parse_keyfile(&pkey, "/flash/client.key", NULL, NULL, 0)) != 0) {
        goto exit;
    }
    mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey);

    // 连接服务器(嵌入式需替换为自定义网络连接逻辑)
    if ((ret = mbedtls_net_connect(&server_fd, "192.168.1.100", "443", MBEDTLS_NET_PROTO_TCP)) != 0) {
        goto exit;
    }

    // 绑定IO并设置SNI(可选,多域名服务器场景)
    mbedtls_ssl_setup(&ssl, &conf);
    mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
    mbedtls_ssl_set_hostname(&ssl, "embedded-server.local");

    // 执行握手
    while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            goto exit;
        }
    }

    // 数据收发示例
    uint8_t send_buf[] = "Hello Mutual TLS!";
    mbedtls_ssl_write(&ssl, send_buf, sizeof(send_buf)-1);

    uint8_t recv_buf[1024];
    ret = mbedtls_ssl_read(&ssl, recv_buf, sizeof(recv_buf));
    if (ret > 0) {
        // 处理接收数据
    }

exit:
    // 资源释放
    mbedtls_ssl_free(&ssl);
    mbedtls_ssl_config_free(&conf);
    mbedtls_x509_crt_free(&clicert);
    mbedtls_x509_crt_free(&cacert);
    mbedtls_pk_free(&pkey);
    mbedtls_net_free(&server_fd);
    mbedtls_ctr_drbg_free(&rng);
    return ret;
}

常见问题排查

  • 证书验证失败:检查CA证书是否正确、证书链是否完整、客户端/服务器证书是否由该CA签发
  • 内存溢出:调整mbed-TLS编译配置,减少MBEDTLS_SSL_MAX_FRAGMENT_LENGTH、关闭未使用的加密算法
  • 握手超时:嵌入式网络延迟高,需增加mbedtls_ssl_conf_read_timeout的超时值,正确处理WANT_READ/WANT_WRITE错误码(需重新调用握手函数)

内容的提问来源于stack exchange,提问作者PrismaDynamic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 07:04:59