跳转至

安全通信协议实现

学习目标

完成本教程后,你将能够:

  • 理解TLS/SSL和DTLS协议的工作原理和安全机制
  • 掌握mbedTLS库在嵌入式系统中的配置和使用
  • 能够实现基于TLS的安全TCP通信
  • 能够实现基于DTLS的安全UDP通信
  • 掌握数字证书的生成、管理和验证方法
  • 了解安全通信的性能优化和资源管理技巧
  • 能够构建完整的安全通信系统

前置要求

知识要求

  • 掌握C语言编程
  • 了解TCP/IP网络协议栈
  • 理解对称加密和非对称加密原理
  • 熟悉数字证书和PKI体系
  • 了解哈希算法和数字签名

环境要求

  • 开发板:STM32F4系列或ESP32(支持网络)
  • 开发工具:STM32CubeIDE或ESP-IDF
  • 网络环境:以太网或WiFi连接
  • 测试工具:OpenSSL命令行工具
  • 抓包工具:Wireshark(用于分析加密流量)

准备工作

1. 硬件准备

开发板清单: - STM32F407开发板 + W5500以太网模块 或 ESP32开发板 × 1 - USB数据线 × 1 - 网线 × 1(如使用以太网) - 路由器 × 1

硬件连接(STM32 + W5500):

W5500      →    STM32F407
MOSI       →    PA7 (SPI1_MOSI)
MISO       →    PA6 (SPI1_MISO)
SCK        →    PA5 (SPI1_SCK)
CS         →    PA4 (SPI1_NSS)
RST        →    PC4
INT        →    PC5
3.3V       →    3.3V
GND        →    GND

2. 软件准备

安装mbedTLS库

对于STM32项目:

# 下载mbedTLS源码
git clone https://github.com/ARMmbed/mbedtls.git
cd mbedtls
git checkout mbedtls-2.28

# 将以下文件添加到项目:
# - mbedtls/library/*.c
# - mbedtls/include/mbedtls/*.h

对于ESP32项目:

# ESP-IDF已经包含mbedTLS
# 在menuconfig中启用:
# Component config → mbedTLS → Enable mbedTLS

生成测试证书

# 生成CA私钥
openssl genrsa -out ca_key.pem 2048

# 生成CA证书
openssl req -new -x509 -days 3650 -key ca_key.pem -out ca_cert.pem \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=Test/CN=Test CA"

# 生成服务器私钥
openssl genrsa -out server_key.pem 2048

# 生成服务器证书请求
openssl req -new -key server_key.pem -out server_csr.pem \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=Test/CN=192.168.1.100"

# 签发服务器证书
openssl x509 -req -days 365 -in server_csr.pem \
  -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial \
  -out server_cert.pem

# 生成客户端私钥和证书(可选,用于双向认证)
openssl genrsa -out client_key.pem 2048
openssl req -new -key client_key.pem -out client_csr.pem \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=Test/CN=Client"
openssl x509 -req -days 365 -in client_csr.pem \
  -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial \
  -out client_cert.pem

步骤说明

步骤1: 理解TLS/SSL协议原理

TLS(Transport Layer Security)和SSL(Secure Sockets Layer)是保护网络通信安全的加密协议。

1.1 TLS协议架构

graph TD
    A[应用层] --> B[TLS记录协议]
    B --> C[TLS握手协议]
    B --> D[TLS密码变更协议]
    B --> E[TLS警报协议]
    C --> F[传输层 TCP]
    D --> F
    E --> F
    F --> G[网络层 IP]

核心组件: - 记录协议(Record Protocol):提供数据加密、完整性保护和压缩 - 握手协议(Handshake Protocol):协商加密参数、认证通信双方 - 密码变更协议(Change Cipher Spec):通知对方切换加密算法 - 警报协议(Alert Protocol):传递错误和警告信息

1.2 TLS握手流程

sequenceDiagram
    participant Client as 客户端
    participant Server as 服务器

    Client->>Server: 1. ClientHello (支持的加密套件)
    Server->>Client: 2. ServerHello (选择的加密套件)
    Server->>Client: 3. Certificate (服务器证书)
    Server->>Client: 4. ServerHelloDone

    Client->>Client: 5. 验证服务器证书
    Client->>Server: 6. ClientKeyExchange (预主密钥)
    Client->>Server: 7. ChangeCipherSpec
    Client->>Server: 8. Finished (握手完成)

    Server->>Server: 9. 计算主密钥
    Server->>Client: 10. ChangeCipherSpec
    Server->>Client: 11. Finished

    Note over Client,Server: 握手完成,开始加密通信

    Client->>Server: 加密的应用数据
    Server->>Client: 加密的应用数据

握手过程详解

  1. ClientHello:客户端发送支持的TLS版本、加密套件列表、随机数
  2. ServerHello:服务器选择TLS版本和加密套件,发送随机数
  3. Certificate:服务器发送数字证书(包含公钥)
  4. ServerHelloDone:服务器握手消息发送完毕
  5. 证书验证:客户端验证服务器证书的有效性
  6. ClientKeyExchange:客户端生成预主密钥,用服务器公钥加密后发送
  7. ChangeCipherSpec:客户端通知切换到加密模式
  8. Finished:客户端发送握手完成消息(已加密)
  9. 密钥计算:服务器用私钥解密预主密钥,计算主密钥
  10. ChangeCipherSpec:服务器通知切换到加密模式
  11. Finished:服务器发送握手完成消息(已加密)

1.3 DTLS协议特点

DTLS(Datagram TLS)是TLS在UDP上的实现,主要特点:

// DTLS vs TLS 对比

// TLS特点:
// - 基于TCP,可靠传输
// - 有序数据流
// - 连接导向
// - 适合:HTTPS、FTPS、SMTPS

// DTLS特点:
// - 基于UDP,不可靠传输
// - 无序数据报
// - 无连接
// - 增加了重传和排序机制
// - 适合:VoIP、视频流、IoT设备

DTLS关键机制: - 记录序列号:防止重放攻击 - 握手重传:处理UDP丢包 - 分片重组:处理大消息 - Cookie机制:防止DoS攻击

步骤2: 配置mbedTLS库

mbedTLS是一个轻量级的TLS/SSL库,适合嵌入式系统。

2.1 mbedTLS配置文件

创建 mbedtls_config.h

#ifndef MBEDTLS_CONFIG_H
#define MBEDTLS_CONFIG_H

// 1. 系统配置
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C

// 2. 加密算法
#define MBEDTLS_AES_C                    // AES加密
#define MBEDTLS_SHA256_C                 // SHA-256哈希
#define MBEDTLS_MD_C                     // 消息摘要
#define MBEDTLS_CIPHER_C                 // 密码算法

// 3. 公钥算法
#define MBEDTLS_RSA_C                    // RSA算法
#define MBEDTLS_PK_C                     // 公钥抽象层
#define MBEDTLS_PK_PARSE_C               // 公钥解析
#define MBEDTLS_BIGNUM_C                 // 大数运算

// 4. X.509证书
#define MBEDTLS_X509_USE_C               // X.509证书
#define MBEDTLS_X509_CRT_PARSE_C         // 证书解析
#define MBEDTLS_ASN1_PARSE_C             // ASN.1解析
#define MBEDTLS_ASN1_WRITE_C             // ASN.1写入
#define MBEDTLS_OID_C                    // OID支持

// 5. TLS/SSL
#define MBEDTLS_SSL_TLS_C                // TLS核心
#define MBEDTLS_SSL_CLI_C                // TLS客户端
#define MBEDTLS_SSL_SRV_C                // TLS服务器
#define MBEDTLS_SSL_PROTO_TLS1_2         // TLS 1.2

// 6. DTLS支持(可选)
#define MBEDTLS_SSL_PROTO_DTLS           // DTLS协议
#define MBEDTLS_SSL_DTLS_ANTI_REPLAY     // 防重放
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY    // Hello验证

// 7. 随机数生成
#define MBEDTLS_ENTROPY_C                // 熵源
#define MBEDTLS_CTR_DRBG_C               // 随机数生成器

// 8. 网络支持
#define MBEDTLS_NET_C                    // 网络抽象层

// 9. 调试支持
#define MBEDTLS_DEBUG_C                  // 调试输出
#define MBEDTLS_ERROR_C                  // 错误字符串

// 10. 性能优化
#define MBEDTLS_AES_ROM_TABLES           // 使用ROM表
#define MBEDTLS_SSL_MAX_CONTENT_LEN 4096 // 最大内容长度

// 11. 内存配置
#define MBEDTLS_MEM_ALLOC   pvPortMalloc  // 使用FreeRTOS内存分配
#define MBEDTLS_MEM_FREE    vPortFree

#include "mbedtls/check_config.h"

#endif /* MBEDTLS_CONFIG_H */

2.2 mbedTLS初始化

#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"

// mbedTLS上下文
typedef struct {
    mbedtls_entropy_context entropy;      // 熵源
    mbedtls_ctr_drbg_context ctr_drbg;   // 随机数生成器
    mbedtls_ssl_context ssl;              // SSL上下文
    mbedtls_ssl_config conf;              // SSL配置
    mbedtls_x509_crt cacert;              // CA证书
    mbedtls_x509_crt clicert;             // 客户端证书(可选)
    mbedtls_pk_context pkey;              // 私钥(可选)
    mbedtls_net_context server_fd;        // 网络连接
} tls_context_t;

static tls_context_t g_tls_ctx;

/**
 * @brief 调试回调函数
 * @param ctx 上下文
 * @param level 调试级别
 * @param file 文件名
 * @param line 行号
 * @param str 调试信息
 */
static void tls_debug_callback(void *ctx, int level,
                               const char *file, int line,
                               const char *str) {
    printf("%s:%04d: %s", file, line, str);
}

/**
 * @brief 初始化mbedTLS
 * @return 0: 成功, 负数: 错误码
 */
int tls_init(void) {
    int ret;
    const char *pers = "tls_client";

    printf("Initializing mbedTLS...\n");

    // 1. 初始化上下文
    mbedtls_net_init(&g_tls_ctx.server_fd);
    mbedtls_ssl_init(&g_tls_ctx.ssl);
    mbedtls_ssl_config_init(&g_tls_ctx.conf);
    mbedtls_x509_crt_init(&g_tls_ctx.cacert);
    mbedtls_x509_crt_init(&g_tls_ctx.clicert);
    mbedtls_pk_init(&g_tls_ctx.pkey);
    mbedtls_ctr_drbg_init(&g_tls_ctx.ctr_drbg);
    mbedtls_entropy_init(&g_tls_ctx.entropy);

    // 2. 初始化随机数生成器
    ret = mbedtls_ctr_drbg_seed(&g_tls_ctx.ctr_drbg,
                                mbedtls_entropy_func,
                                &g_tls_ctx.entropy,
                                (const unsigned char *)pers,
                                strlen(pers));
    if (ret != 0) {
        printf("mbedtls_ctr_drbg_seed failed: -0x%04x\n", -ret);
        return ret;
    }

    printf("mbedTLS initialized successfully\n");

    return 0;
}

/**
 * @brief 清理mbedTLS资源
 */
void tls_cleanup(void) {
    mbedtls_net_free(&g_tls_ctx.server_fd);
    mbedtls_x509_crt_free(&g_tls_ctx.cacert);
    mbedtls_x509_crt_free(&g_tls_ctx.clicert);
    mbedtls_pk_free(&g_tls_ctx.pkey);
    mbedtls_ssl_free(&g_tls_ctx.ssl);
    mbedtls_ssl_config_free(&g_tls_ctx.conf);
    mbedtls_ctr_drbg_free(&g_tls_ctx.ctr_drbg);
    mbedtls_entropy_free(&g_tls_ctx.entropy);

    printf("mbedTLS cleaned up\n");
}

步骤3: 实现TLS客户端

实现一个完整的TLS客户端,连接到HTTPS服务器。

3.1 加载证书

// CA证书(PEM格式)
const char *ca_cert_pem = 
"-----BEGIN CERTIFICATE-----\n"
"MIIDXTCCAkWgAwIBAgIJAKL0UG+mRKSzMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\n"
// ... 证书内容 ...
"-----END CERTIFICATE-----\n";

/**
 * @brief 加载CA证书
 * @return 0: 成功, 负数: 错误码
 */
int tls_load_ca_cert(void) {
    int ret;

    printf("Loading CA certificate...\n");

    // 解析CA证书
    ret = mbedtls_x509_crt_parse(&g_tls_ctx.cacert,
                                 (const unsigned char *)ca_cert_pem,
                                 strlen(ca_cert_pem) + 1);
    if (ret != 0) {
        printf("mbedtls_x509_crt_parse failed: -0x%04x\n", -ret);
        return ret;
    }

    printf("CA certificate loaded successfully\n");

    return 0;
}

/**
 * @brief 加载客户端证书和私钥(用于双向认证)
 * @param cert_pem 客户端证书(PEM格式)
 * @param key_pem 客户端私钥(PEM格式)
 * @return 0: 成功, 负数: 错误码
 */
int tls_load_client_cert(const char *cert_pem, const char *key_pem) {
    int ret;

    printf("Loading client certificate and key...\n");

    // 1. 解析客户端证书
    ret = mbedtls_x509_crt_parse(&g_tls_ctx.clicert,
                                 (const unsigned char *)cert_pem,
                                 strlen(cert_pem) + 1);
    if (ret != 0) {
        printf("mbedtls_x509_crt_parse failed: -0x%04x\n", -ret);
        return ret;
    }

    // 2. 解析私钥
    ret = mbedtls_pk_parse_key(&g_tls_ctx.pkey,
                               (const unsigned char *)key_pem,
                               strlen(key_pem) + 1,
                               NULL, 0);  // 无密码保护
    if (ret != 0) {
        printf("mbedtls_pk_parse_key failed: -0x%04x\n", -ret);
        return ret;
    }

    printf("Client certificate and key loaded successfully\n");

    return 0;
}

3.2 配置TLS连接

/**
 * @brief 配置TLS客户端
 * @param hostname 服务器主机名(用于SNI和证书验证)
 * @return 0: 成功, 负数: 错误码
 */
int tls_config_client(const char *hostname) {
    int ret;

    printf("Configuring TLS client...\n");

    // 1. 设置默认配置
    ret = mbedtls_ssl_config_defaults(&g_tls_ctx.conf,
                                      MBEDTLS_SSL_IS_CLIENT,
                                      MBEDTLS_SSL_TRANSPORT_STREAM,
                                      MBEDTLS_SSL_PRESET_DEFAULT);
    if (ret != 0) {
        printf("mbedtls_ssl_config_defaults failed: -0x%04x\n", -ret);
        return ret;
    }

    // 2. 设置认证模式
    mbedtls_ssl_conf_authmode(&g_tls_ctx.conf, MBEDTLS_SSL_VERIFY_REQUIRED);

    // 3. 设置CA证书
    mbedtls_ssl_conf_ca_chain(&g_tls_ctx.conf, &g_tls_ctx.cacert, NULL);

    // 4. 设置客户端证书(可选,用于双向认证)
    // mbedtls_ssl_conf_own_cert(&g_tls_ctx.conf, 
    //                          &g_tls_ctx.clicert, 
    //                          &g_tls_ctx.pkey);

    // 5. 设置随机数生成器
    mbedtls_ssl_conf_rng(&g_tls_ctx.conf,
                        mbedtls_ctr_drbg_random,
                        &g_tls_ctx.ctr_drbg);

    // 6. 设置调试回调
    mbedtls_ssl_conf_dbg(&g_tls_ctx.conf, tls_debug_callback, NULL);
    mbedtls_debug_set_threshold(2);  // 调试级别:0-4

    // 7. 设置超时(DTLS需要)
    // mbedtls_ssl_conf_handshake_timeout(&g_tls_ctx.conf, 1000, 60000);

    // 8. 应用配置到SSL上下文
    ret = mbedtls_ssl_setup(&g_tls_ctx.ssl, &g_tls_ctx.conf);
    if (ret != 0) {
        printf("mbedtls_ssl_setup failed: -0x%04x\n", -ret);
        return ret;
    }

    // 9. 设置主机名(用于SNI和证书验证)
    ret = mbedtls_ssl_set_hostname(&g_tls_ctx.ssl, hostname);
    if (ret != 0) {
        printf("mbedtls_ssl_set_hostname failed: -0x%04x\n", -ret);
        return ret;
    }

    printf("TLS client configured successfully\n");

    return 0;
}

3.3 建立TLS连接

/**
 * @brief 连接到TLS服务器
 * @param host 服务器地址
 * @param port 服务器端口
 * @return 0: 成功, 负数: 错误码
 */
int tls_connect(const char *host, const char *port) {
    int ret;

    printf("Connecting to %s:%s...\n", host, port);

    // 1. 建立TCP连接
    ret = mbedtls_net_connect(&g_tls_ctx.server_fd, host, port,
                             MBEDTLS_NET_PROTO_TCP);
    if (ret != 0) {
        printf("mbedtls_net_connect failed: -0x%04x\n", -ret);
        return ret;
    }

    printf("TCP connection established\n");

    // 2. 设置BIO回调
    mbedtls_ssl_set_bio(&g_tls_ctx.ssl, &g_tls_ctx.server_fd,
                       mbedtls_net_send, mbedtls_net_recv, NULL);

    // 3. 执行TLS握手
    printf("Performing TLS handshake...\n");

    while ((ret = mbedtls_ssl_handshake(&g_tls_ctx.ssl)) != 0) {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
            ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            printf("mbedtls_ssl_handshake failed: -0x%04x\n", -ret);
            return ret;
        }
    }

    printf("TLS handshake completed\n");

    // 4. 验证服务器证书
    uint32_t flags = mbedtls_ssl_get_verify_result(&g_tls_ctx.ssl);
    if (flags != 0) {
        char vrfy_buf[512];
        mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf),
                                     "  ! ", flags);
        printf("Certificate verification failed:\n%s\n", vrfy_buf);
        return -1;
    }

    printf("Certificate verification passed\n");

    // 5. 打印连接信息
    printf("TLS connection established:\n");
    printf("  Protocol: %s\n", mbedtls_ssl_get_version(&g_tls_ctx.ssl));
    printf("  Ciphersuite: %s\n", 
           mbedtls_ssl_get_ciphersuite(&g_tls_ctx.ssl));

    return 0;
}

/**
 * @brief 发送TLS数据
 * @param data 数据缓冲区
 * @param len 数据长度
 * @return 发送的字节数,负数表示错误
 */
int tls_send(const unsigned char *data, size_t len) {
    int ret;

    while ((ret = mbedtls_ssl_write(&g_tls_ctx.ssl, data, len)) <= 0) {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
            ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            printf("mbedtls_ssl_write failed: -0x%04x\n", -ret);
            return ret;
        }
    }

    return ret;
}

/**
 * @brief 接收TLS数据
 * @param buf 接收缓冲区
 * @param len 缓冲区大小
 * @return 接收的字节数,负数表示错误
 */
int tls_recv(unsigned char *buf, size_t len) {
    int ret;

    do {
        ret = mbedtls_ssl_read(&g_tls_ctx.ssl, buf, len);

        if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
            ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
            continue;
        }

        if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
            printf("Connection closed by peer\n");
            return 0;
        }

        if (ret < 0) {
            printf("mbedtls_ssl_read failed: -0x%04x\n", -ret);
            return ret;
        }

        if (ret == 0) {
            printf("EOF\n");
            return 0;
        }

        break;
    } while (1);

    return ret;
}

/**
 * @brief 关闭TLS连接
 */
void tls_close(void) {
    int ret;

    printf("Closing TLS connection...\n");

    // 发送关闭通知
    do {
        ret = mbedtls_ssl_close_notify(&g_tls_ctx.ssl);
    } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);

    // 关闭TCP连接
    mbedtls_net_free(&g_tls_ctx.server_fd);

    printf("TLS connection closed\n");
}

3.4 TLS客户端使用示例

/**
 * @brief TLS客户端示例
 */
void tls_client_example(void) {
    int ret;
    unsigned char buf[1024];

    // 1. 初始化mbedTLS
    ret = tls_init();
    if (ret != 0) {
        goto exit;
    }

    // 2. 加载CA证书
    ret = tls_load_ca_cert();
    if (ret != 0) {
        goto exit;
    }

    // 3. 配置TLS客户端
    ret = tls_config_client("www.example.com");
    if (ret != 0) {
        goto exit;
    }

    // 4. 连接到服务器
    ret = tls_connect("www.example.com", "443");
    if (ret != 0) {
        goto exit;
    }

    // 5. 发送HTTPS请求
    const char *request = 
        "GET / HTTP/1.1\r\n"
        "Host: www.example.com\r\n"
        "Connection: close\r\n"
        "\r\n";

    ret = tls_send((const unsigned char *)request, strlen(request));
    if (ret < 0) {
        goto exit;
    }

    printf("Sent %d bytes\n", ret);

    // 6. 接收响应
    printf("\nReceiving response:\n");
    printf("-----------------------------------\n");

    do {
        ret = tls_recv(buf, sizeof(buf) - 1);
        if (ret <= 0) {
            break;
        }

        buf[ret] = '\0';
        printf("%s", buf);
    } while (1);

    printf("\n-----------------------------------\n");

    // 7. 关闭连接
    tls_close();

exit:
    // 8. 清理资源
    tls_cleanup();
}

步骤4: 实现DTLS通信

DTLS用于保护UDP通信,适合实时性要求高的场景。

4.1 配置DTLS客户端

/**
 * @brief 配置DTLS客户端
 * @param hostname 服务器主机名
 * @return 0: 成功, 负数: 错误码
 */
int dtls_config_client(const char *hostname) {
    int ret;

    printf("Configuring DTLS client...\n");

    // 1. 设置DTLS配置
    ret = mbedtls_ssl_config_defaults(&g_tls_ctx.conf,
                                      MBEDTLS_SSL_IS_CLIENT,
                                      MBEDTLS_SSL_TRANSPORT_DATAGRAM,  // UDP
                                      MBEDTLS_SSL_PRESET_DEFAULT);
    if (ret != 0) {
        printf("mbedtls_ssl_config_defaults failed: -0x%04x\n", -ret);
        return ret;
    }

    // 2. 设置认证模式
    mbedtls_ssl_conf_authmode(&g_tls_ctx.conf, MBEDTLS_SSL_VERIFY_REQUIRED);

    // 3. 设置CA证书
    mbedtls_ssl_conf_ca_chain(&g_tls_ctx.conf, &g_tls_ctx.cacert, NULL);

    // 4. 设置随机数生成器
    mbedtls_ssl_conf_rng(&g_tls_ctx.conf,
                        mbedtls_ctr_drbg_random,
                        &g_tls_ctx.ctr_drbg);

    // 5. 设置握手超时(DTLS特有)
    mbedtls_ssl_conf_handshake_timeout(&g_tls_ctx.conf,
                                       1000,   // 最小超时:1秒
                                       60000); // 最大超时:60秒

    // 6. 设置DTLS Cookie(防DoS攻击)
    // 服务器端需要

    // 7. 设置防重放攻击
    mbedtls_ssl_conf_dtls_anti_replay(&g_tls_ctx.conf,
                                      MBEDTLS_SSL_ANTI_REPLAY_ENABLED);

    // 8. 应用配置
    ret = mbedtls_ssl_setup(&g_tls_ctx.ssl, &g_tls_ctx.conf);
    if (ret != 0) {
        printf("mbedtls_ssl_setup failed: -0x%04x\n", -ret);
        return ret;
    }

    // 9. 设置主机名
    ret = mbedtls_ssl_set_hostname(&g_tls_ctx.ssl, hostname);
    if (ret != 0) {
        printf("mbedtls_ssl_set_hostname failed: -0x%04x\n", -ret);
        return ret;
    }

    printf("DTLS client configured successfully\n");

    return 0;
}

/**
 * @brief 连接到DTLS服务器
 * @param host 服务器地址
 * @param port 服务器端口
 * @return 0: 成功, 负数: 错误码
 */
int dtls_connect(const char *host, const char *port) {
    int ret;

    printf("Connecting to DTLS server %s:%s...\n", host, port);

    // 1. 建立UDP连接
    ret = mbedtls_net_connect(&g_tls_ctx.server_fd, host, port,
                             MBEDTLS_SSL_TRANSPORT_DATAGRAM);
    if (ret != 0) {
        printf("mbedtls_net_connect failed: -0x%04x\n", -ret);
        return ret;
    }

    printf("UDP connection established\n");

    // 2. 设置BIO回调(DTLS使用特殊的recv_timeout)
    mbedtls_ssl_set_bio(&g_tls_ctx.ssl, &g_tls_ctx.server_fd,
                       mbedtls_net_send, mbedtls_net_recv,
                       mbedtls_net_recv_timeout);

    // 3. 设置定时器回调(DTLS需要)
    mbedtls_ssl_set_timer_cb(&g_tls_ctx.ssl,
                            &g_timer,
                            mbedtls_timing_set_delay,
                            mbedtls_timing_get_delay);

    // 4. 执行DTLS握手
    printf("Performing DTLS handshake...\n");

    while ((ret = mbedtls_ssl_handshake(&g_tls_ctx.ssl)) != 0) {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
            ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
            printf("mbedtls_ssl_handshake failed: -0x%04x\n", -ret);
            return ret;
        }
    }

    printf("DTLS handshake completed\n");

    // 5. 验证证书
    uint32_t flags = mbedtls_ssl_get_verify_result(&g_tls_ctx.ssl);
    if (flags != 0) {
        char vrfy_buf[512];
        mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf),
                                     "  ! ", flags);
        printf("Certificate verification failed:\n%s\n", vrfy_buf);
        return -1;
    }

    printf("DTLS connection established\n");

    return 0;
}

4.2 DTLS数据传输

/**
 * @brief 发送DTLS数据
 * @param data 数据缓冲区
 * @param len 数据长度
 * @return 发送的字节数,负数表示错误
 */
int dtls_send(const unsigned char *data, size_t len) {
    int ret;

    // DTLS发送(与TLS类似,但处理UDP特性)
    while ((ret = mbedtls_ssl_write(&g_tls_ctx.ssl, data, len)) <= 0) {
        if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
            ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
            continue;
        }

        if (ret == MBEDTLS_ERR_SSL_TIMEOUT) {
            printf("DTLS send timeout\n");
            return ret;
        }

        printf("mbedtls_ssl_write failed: -0x%04x\n", -ret);
        return ret;
    }

    return ret;
}

/**
 * @brief 接收DTLS数据
 * @param buf 接收缓冲区
 * @param len 缓冲区大小
 * @param timeout_ms 超时时间(毫秒)
 * @return 接收的字节数,负数表示错误
 */
int dtls_recv(unsigned char *buf, size_t len, uint32_t timeout_ms) {
    int ret;

    // 设置接收超时
    mbedtls_ssl_conf_read_timeout(&g_tls_ctx.conf, timeout_ms);

    ret = mbedtls_ssl_read(&g_tls_ctx.ssl, buf, len);

    if (ret == MBEDTLS_ERR_SSL_TIMEOUT) {
        return 0;  // 超时,无数据
    }

    if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
        ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
        return 0;  // 需要重试
    }

    if (ret < 0) {
        printf("mbedtls_ssl_read failed: -0x%04x\n", -ret);
        return ret;
    }

    return ret;
}

/**
 * @brief DTLS通信示例
 */
void dtls_example(void) {
    int ret;
    unsigned char send_buf[256];
    unsigned char recv_buf[256];

    // 1. 初始化
    ret = tls_init();
    if (ret != 0) {
        goto exit;
    }

    // 2. 加载证书
    ret = tls_load_ca_cert();
    if (ret != 0) {
        goto exit;
    }

    // 3. 配置DTLS
    ret = dtls_config_client("dtls.server.com");
    if (ret != 0) {
        goto exit;
    }

    // 4. 连接
    ret = dtls_connect("192.168.1.100", "4433");
    if (ret != 0) {
        goto exit;
    }

    // 5. 发送数据
    const char *message = "Hello from DTLS client!";
    snprintf((char *)send_buf, sizeof(send_buf), "%s", message);

    ret = dtls_send(send_buf, strlen((char *)send_buf));
    if (ret < 0) {
        goto exit;
    }

    printf("Sent: %s\n", send_buf);

    // 6. 接收响应
    ret = dtls_recv(recv_buf, sizeof(recv_buf) - 1, 5000);
    if (ret > 0) {
        recv_buf[ret] = '\0';
        printf("Received: %s\n", recv_buf);
    }

    // 7. 关闭连接
    tls_close();

exit:
    tls_cleanup();
}

步骤5: 证书管理

证书管理是TLS/DTLS安全的关键。

5.1 证书验证

/**
 * @brief 自定义证书验证回调
 * @param data 用户数据
 * @param crt 证书
 * @param depth 证书链深度
 * @param flags 验证标志
 * @return 0: 通过, 非0: 失败
 */
static int cert_verify_callback(void *data, mbedtls_x509_crt *crt,
                                int depth, uint32_t *flags) {
    char buf[1024];

    printf("\nVerifying certificate at depth %d:\n", depth);

    // 打印证书信息
    mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "  ", crt);
    printf("%s\n", buf);

    // 检查证书有效期
    time_t now = time(NULL);
    if (now < crt->valid_from.year ||
        now > crt->valid_to.year) {
        printf("Certificate expired or not yet valid\n");
        *flags |= MBEDTLS_X509_BADCERT_EXPIRED;
        return -1;
    }

    // 检查证书用途
    if (depth == 0) {  // 服务器证书
        if (!(crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE)) {
            printf("Certificate missing key usage extension\n");
            *flags |= MBEDTLS_X509_BADCERT_KEY_USAGE;
            return -1;
        }
    }

    // 自定义验证逻辑
    // ...

    return 0;
}

/**
 * @brief 设置证书验证回调
 */
void tls_set_cert_verify_callback(void) {
    mbedtls_ssl_conf_verify(&g_tls_ctx.conf,
                           cert_verify_callback,
                           NULL);
}

5.2 证书固定(Certificate Pinning)

// 预期的证书指纹(SHA-256)
const unsigned char expected_cert_hash[32] = {
    0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
    0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
    0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0,
    0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0
};

/**
 * @brief 验证证书指纹
 * @param crt 证书
 * @return 0: 匹配, -1: 不匹配
 */
int verify_cert_pinning(mbedtls_x509_crt *crt) {
    unsigned char cert_hash[32];
    int ret;

    // 计算证书的SHA-256哈希
    ret = mbedtls_sha256_ret(crt->raw.p, crt->raw.len, cert_hash, 0);
    if (ret != 0) {
        printf("Failed to calculate certificate hash\n");
        return -1;
    }

    // 比较哈希值
    if (memcmp(cert_hash, expected_cert_hash, 32) != 0) {
        printf("Certificate pinning failed!\n");
        printf("Expected hash: ");
        for (int i = 0; i < 32; i++) {
            printf("%02X", expected_cert_hash[i]);
        }
        printf("\nActual hash:   ");
        for (int i = 0; i < 32; i++) {
            printf("%02X", cert_hash[i]);
        }
        printf("\n");
        return -1;
    }

    printf("Certificate pinning verified\n");
    return 0;
}

5.3 证书链验证

/**
 * @brief 验证完整的证书链
 * @param cert_chain 证书链
 * @param ca_cert CA证书
 * @return 0: 成功, 负数: 错误码
 */
int verify_cert_chain(mbedtls_x509_crt *cert_chain,
                     mbedtls_x509_crt *ca_cert) {
    uint32_t flags;
    int ret;

    printf("Verifying certificate chain...\n");

    // 验证证书链
    ret = mbedtls_x509_crt_verify(cert_chain, ca_cert, NULL,
                                  NULL, &flags, NULL, NULL);

    if (ret != 0) {
        char vrfy_buf[512];
        mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf),
                                     "  ! ", flags);
        printf("Certificate chain verification failed:\n%s\n", vrfy_buf);
        return ret;
    }

    printf("Certificate chain verified successfully\n");

    // 打印证书链信息
    mbedtls_x509_crt *cur = cert_chain;
    int depth = 0;

    while (cur != NULL) {
        char buf[1024];
        mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "  ", cur);
        printf("\nCertificate at depth %d:\n%s\n", depth, buf);

        cur = cur->next;
        depth++;
    }

    return 0;
}

步骤6: 性能优化

在资源受限的嵌入式系统中,需要优化TLS/DTLS性能。

6.1 会话恢复

// 会话缓存
static mbedtls_ssl_session saved_session;

/**
 * @brief 保存TLS会话
 * @return 0: 成功, 负数: 错误码
 */
int tls_save_session(void) {
    int ret;

    printf("Saving TLS session...\n");

    // 获取当前会话
    ret = mbedtls_ssl_get_session(&g_tls_ctx.ssl, &saved_session);
    if (ret != 0) {
        printf("mbedtls_ssl_get_session failed: -0x%04x\n", -ret);
        return ret;
    }

    printf("TLS session saved\n");

    return 0;
}

/**
 * @brief 恢复TLS会话
 * @return 0: 成功, 负数: 错误码
 */
int tls_resume_session(void) {
    int ret;

    printf("Resuming TLS session...\n");

    // 设置会话
    ret = mbedtls_ssl_set_session(&g_tls_ctx.ssl, &saved_session);
    if (ret != 0) {
        printf("mbedtls_ssl_set_session failed: -0x%04x\n", -ret);
        return ret;
    }

    printf("TLS session resumed\n");

    return 0;
}

/**
 * @brief 使用会话恢复的连接示例
 */
void tls_session_resume_example(void) {
    int ret;

    // 第一次连接
    printf("\n=== First Connection ===\n");
    ret = tls_connect("www.example.com", "443");
    if (ret != 0) {
        return;
    }

    // 保存会话
    tls_save_session();

    // 关闭连接
    tls_close();

    // 第二次连接(使用会话恢复)
    printf("\n=== Second Connection (Session Resume) ===\n");

    // 恢复会话
    tls_resume_session();

    // 重新连接(握手会更快)
    ret = tls_connect("www.example.com", "443");
    if (ret != 0) {
        return;
    }

    // 检查是否成功恢复会话
    if (mbedtls_ssl_session_reused(&g_tls_ctx.ssl)) {
        printf("Session successfully resumed!\n");
        printf("Handshake time reduced significantly\n");
    } else {
        printf("Session resume failed, full handshake performed\n");
    }

    tls_close();
}

6.2 内存优化

/**
 * @brief 配置mbedTLS内存使用
 */
void tls_config_memory(void) {
    // 1. 使用静态内存池
    static unsigned char memory_buf[40000];
    mbedtls_memory_buffer_alloc_init(memory_buf, sizeof(memory_buf));

    // 2. 限制最大内容长度
    // 在mbedtls_config.h中设置:
    // #define MBEDTLS_SSL_MAX_CONTENT_LEN 4096

    // 3. 禁用不需要的加密套件
    // 只保留必要的加密算法

    // 4. 使用ROM表(减少RAM使用)
    // #define MBEDTLS_AES_ROM_TABLES

    printf("Memory configuration:\n");
    printf("  Buffer size: %d bytes\n", sizeof(memory_buf));
    printf("  Max content length: %d bytes\n", MBEDTLS_SSL_MAX_CONTENT_LEN);
}

/**
 * @brief 获取内存使用情况
 */
void tls_print_memory_usage(void) {
    size_t max_used, max_blocks;

    mbedtls_memory_buffer_alloc_max_get(&max_used, &max_blocks);

    printf("\nMemory usage:\n");
    printf("  Peak usage: %zu bytes\n", max_used);
    printf("  Peak blocks: %zu\n", max_blocks);
}

6.3 加密套件选择

/**
 * @brief 配置加密套件(优先选择性能好的)
 */
void tls_config_ciphersuites(void) {
    // 推荐的加密套件(按优先级排序)
    static const int ciphersuites[] = {
        // 1. ECDHE + AES-GCM(推荐,提供前向安全)
        MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
        MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,

        // 2. ECDHE + AES-CBC(兼容性好)
        MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
        MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,

        // 3. RSA + AES-GCM(无前向安全,但性能好)
        MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256,
        MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384,

        0  // 结束标记
    };

    // 设置加密套件
    mbedtls_ssl_conf_ciphersuites(&g_tls_ctx.conf, ciphersuites);

    printf("Configured ciphersuites:\n");
    for (int i = 0; ciphersuites[i] != 0; i++) {
        printf("  %s\n", 
               mbedtls_ssl_get_ciphersuite_name(ciphersuites[i]));
    }
}

/**
 * @brief 选择适合嵌入式的加密套件
 */
void tls_config_embedded_ciphersuites(void) {
    // 嵌入式优化的加密套件
    static const int embedded_ciphersuites[] = {
        // 使用AES硬件加速(如果MCU支持)
        MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256,

        // 使用较小的密钥长度(平衡安全性和性能)
        MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,

        0
    };

    mbedtls_ssl_conf_ciphersuites(&g_tls_ctx.conf, embedded_ciphersuites);
}

验证方法

1. TLS客户端验证

测试步骤: 1. 编译并下载程序到开发板 2. 确保开发板已连接到网络 3. 运行TLS客户端示例 4. 观察串口输出的连接过程 5. 验证是否成功建立TLS连接 6. 验证是否能正确收发数据

预期结果

Initializing mbedTLS...
mbedTLS initialized successfully
Loading CA certificate...
CA certificate loaded successfully
Configuring TLS client...
TLS client configured successfully
Connecting to www.example.com:443...
TCP connection established
Performing TLS handshake...
TLS handshake completed
Certificate verification passed
TLS connection established:
  Protocol: TLSv1.2
  Ciphersuite: TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256
Sent 78 bytes

Receiving response:
-----------------------------------
HTTP/1.1 200 OK
Content-Type: text/html
...
-----------------------------------

Closing TLS connection...
TLS connection closed

2. DTLS通信验证

测试步骤: 1. 在PC上启动DTLS测试服务器:

openssl s_server -dtls1_2 -accept 4433 \
  -cert server_cert.pem -key server_key.pem \
  -CAfile ca_cert.pem -Verify 0

  1. 运行DTLS客户端程序
  2. 观察握手过程
  3. 发送测试数据
  4. 验证数据是否正确加密传输

预期结果

Configuring DTLS client...
DTLS client configured successfully
Connecting to DTLS server 192.168.1.100:4433...
UDP connection established
Performing DTLS handshake...
DTLS handshake completed
DTLS connection established
Sent: Hello from DTLS client!
Received: Hello from DTLS server!

3. 证书验证测试

测试步骤: 1. 使用有效证书连接,验证通过 2. 使用过期证书连接,验证失败 3. 使用自签名证书连接,验证失败 4. 使用证书固定,验证指纹匹配

预期结果

Verifying certificate at depth 0:
  cert. version     : 3
  serial number     : 01
  issuer name       : C=CN, ST=Beijing, L=Beijing, O=Test, CN=Test CA
  subject name      : C=CN, ST=Beijing, L=Beijing, O=Test, CN=192.168.1.100
  issued  on        : 2024-01-01 00:00:00
  expires on        : 2025-01-01 00:00:00
  signed using      : RSA with SHA-256
  RSA key size      : 2048 bits

Certificate verification passed
Certificate pinning verified

4. 性能测试

测试指标: - 握手时间:首次连接 vs 会话恢复 - 内存使用:峰值内存占用 - 吞吐量:加密数据传输速率 - CPU使用率:加密解密开销

测试方法

void tls_performance_test(void) {
    uint32_t start_time, end_time;

    // 1. 测试握手时间
    start_time = HAL_GetTick();
    tls_connect("www.example.com", "443");
    end_time = HAL_GetTick();
    printf("Handshake time: %lu ms\n", end_time - start_time);

    // 2. 测试吞吐量
    unsigned char data[1024];
    memset(data, 0xAA, sizeof(data));

    start_time = HAL_GetTick();
    for (int i = 0; i < 100; i++) {
        tls_send(data, sizeof(data));
    }
    end_time = HAL_GetTick();

    uint32_t total_bytes = 100 * 1024;
    uint32_t elapsed_ms = end_time - start_time;
    float throughput = (float)total_bytes / elapsed_ms;  // KB/s

    printf("Throughput: %.2f KB/s\n", throughput);

    // 3. 打印内存使用
    tls_print_memory_usage();

    tls_close();
}

预期结果

=== Performance Test Results ===
Handshake time: 1250 ms
Throughput: 45.6 KB/s

Memory usage:
  Peak usage: 28672 bytes
  Peak blocks: 42
================================

故障排除

问题1: 握手失败

现象:TLS握手过程中断,返回错误码

可能原因: 1. 证书验证失败 2. 加密套件不匹配 3. 网络连接不稳定 4. 时间不同步

解决方法

// 1. 启用详细调试
mbedtls_debug_set_threshold(4);  // 最高调试级别

// 2. 检查错误码
if (ret != 0) {
    char error_buf[100];
    mbedtls_strerror(ret, error_buf, sizeof(error_buf));
    printf("Error: %s\n", error_buf);
}

// 3. 临时禁用证书验证(仅用于调试)
mbedtls_ssl_conf_authmode(&g_tls_ctx.conf, MBEDTLS_SSL_VERIFY_NONE);

// 4. 检查系统时间
time_t now = time(NULL);
printf("Current time: %s", ctime(&now));

问题2: 内存不足

现象:程序运行一段时间后崩溃或握手失败

可能原因: 1. 内存池太小 2. 内存泄漏 3. 缓冲区配置过大

解决方法

// 1. 增加内存池大小
static unsigned char memory_buf[60000];  // 从40000增加到60000

// 2. 减小最大内容长度
#define MBEDTLS_SSL_MAX_CONTENT_LEN 2048  // 从4096减小到2048

// 3. 检查内存泄漏
void check_memory_leak(void) {
    size_t before_used, before_blocks;
    size_t after_used, after_blocks;

    mbedtls_memory_buffer_alloc_cur_get(&before_used, &before_blocks);

    // 执行TLS操作
    tls_connect("www.example.com", "443");
    tls_close();

    mbedtls_memory_buffer_alloc_cur_get(&after_used, &after_blocks);

    if (after_used > before_used) {
        printf("Memory leak detected: %zu bytes\n", 
               after_used - before_used);
    }
}

// 4. 使用内存分析工具
mbedtls_memory_buffer_alloc_status();

问题3: DTLS丢包

现象:DTLS通信不稳定,频繁超时

可能原因: 1. 网络质量差 2. 超时时间设置不合理 3. MTU配置问题

解决方法

// 1. 增加握手超时时间
mbedtls_ssl_conf_handshake_timeout(&g_tls_ctx.conf,
                                   2000,    // 最小2秒
                                   120000); // 最大120秒

// 2. 设置合适的MTU
mbedtls_ssl_set_mtu(&g_tls_ctx.ssl, 1200);  // 考虑网络MTU

// 3. 启用重传
// DTLS会自动重传,但可以调整参数

// 4. 监控丢包率
static uint32_t sent_packets = 0;
static uint32_t recv_packets = 0;

void dtls_monitor_packet_loss(void) {
    float loss_rate = 1.0f - (float)recv_packets / sent_packets;
    printf("Packet loss rate: %.2f%%\n", loss_rate * 100);

    if (loss_rate > 0.1f) {  // 丢包率超过10%
        printf("Warning: High packet loss!\n");
    }
}

问题4: 证书验证失败

现象:证书验证返回错误标志

可能原因: 1. CA证书不正确 2. 证书链不完整 3. 证书已过期 4. 主机名不匹配

解决方法

// 1. 打印详细的验证错误
uint32_t flags = mbedtls_ssl_get_verify_result(&g_tls_ctx.ssl);
if (flags != 0) {
    char vrfy_buf[512];
    mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", flags);
    printf("Verification failed:\n%s\n", vrfy_buf);

    // 分析具体错误
    if (flags & MBEDTLS_X509_BADCERT_EXPIRED) {
        printf("Certificate has expired\n");
    }
    if (flags & MBEDTLS_X509_BADCERT_CN_MISMATCH) {
        printf("CN mismatch\n");
    }
    if (flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
        printf("Certificate not trusted\n");
    }
}

// 2. 检查证书链
mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(&g_tls_ctx.ssl);
if (cert) {
    char buf[1024];
    mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "  ", cert);
    printf("Server certificate:\n%s\n", buf);
}

// 3. 验证主机名
const char *expected_cn = "www.example.com";
if (mbedtls_x509_crt_check_cn(cert, expected_cn, strlen(expected_cn)) != 0) {
    printf("CN mismatch: expected %s\n", expected_cn);
}

总结

本教程详细介绍了在嵌入式系统中实现安全通信协议的方法:

  1. TLS/SSL协议:理解握手流程、加密机制和安全特性
  2. DTLS协议:掌握UDP上的安全通信实现
  3. mbedTLS库:配置和使用轻量级TLS库
  4. 证书管理:生成、验证和管理数字证书
  5. 性能优化:会话恢复、内存优化、加密套件选择
  6. 故障排除:常见问题的诊断和解决方法

通过本教程的学习,你应该能够在嵌入式设备上实现安全可靠的网络通信,保护数据传输的机密性和完整性。

延伸阅读

相关教程

  • 信息安全基础知识 - 加密算法和安全原理
  • 密钥管理与存储 - 密钥安全管理
  • 安全启动与固件验证 - 固件安全
  • 渗透测试与漏洞分析 - 安全测试方法

技术文档

工具和资源

参考资料

标准规范

  1. RFC 5246 - The Transport Layer Security (TLS) Protocol Version 1.2
  2. RFC 6347 - Datagram Transport Layer Security Version 1.2
  3. RFC 5280 - Internet X.509 Public Key Infrastructure Certificate
  4. RFC 2818 - HTTP Over TLS

技术书籍

  1. "Bulletproof SSL and TLS" by Ivan Ristić
  2. "Network Security with OpenSSL" by John Viega et al.
  3. "Implementing SSL/TLS Using Cryptography and PKI" by Joshua Davies

在线资源

  1. mbedTLS GitHub: https://github.com/ARMmbed/mbedtls
  2. TLS 1.3 RFC: https://tools.ietf.org/html/rfc8446
  3. Mozilla SSL Configuration Generator: https://ssl-config.mozilla.org/