ESP32 证书集成
ESP32 证书集成
本节介绍如何在 ESP32 中集成 TLS 证书,实现 MQTT 通信的加密传输。证书集成是 ESP32 安全通信的核心步骤。学习完成后,您将能够:
- 将 CA 证书嵌入 ESP32 固件
- 配置 ESP32 验证 MQTT Broker 证书
- 区分证书验证的不同模式
- 评估证书管理对固件开发的影响
在开始本节之前,请确保:
- MQTT TLS Broker 已配置
- 了解 WiFiClientSecure 库的基本用法
- 了解证书文件格式(PEM)
Certificate Types
Section titled “Certificate Types”ESP32 证书使用模式
Section titled “ESP32 证书使用模式”| 模式 | 验证级别 | 安全性 | 证书配置 | 适用场景 |
|---|---|---|---|---|
| 不验证 | 无验证 | ❌ 低 | 无需证书 | 开发测试 |
| CA 验证 | 服务器验证 | ✅ 中 | 嵌入 CA 证书 | 生产环境 |
| 双向验证 | 双向验证 | ✅ ✅ 高 | CA + 客户端证书 | 高安全场景 |
Root CA Certificate
Section titled “Root CA Certificate”获取 Let’s Encrypt Root CA
Section titled “获取 Let’s Encrypt Root CA”# 下载 Let's Encrypt ISRG Root X1 证书curl -O https://letsencrypt.org/certs/isrgrootx1.pem
# 查看证书内容cat isrgrootx1.pem
# 输出:# -----BEGIN CERTIFICATE-----# MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw# TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh# cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4# ...# -----END CERTIFICATE-----Embedding Certificate in Code
Section titled “Embedding Certificate in Code”方法 1:直接嵌入代码
Section titled “方法 1:直接嵌入代码”#ifndef CA_CERT_H#define CA_CERT_H
// Let's Encrypt ISRG Root X1 根证书static const char* rootCACertificate = "-----BEGIN CERTIFICATE-----\n" "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" // ... 完整证书内容 "-----END CERTIFICATE-----\n";
#endif证书转换脚本:
#!/bin/bash# convert-cert.sh - 将 PEM 证书转换为 C 字符串
CERT_FILE="$1"VAR_NAME="${2:-rootCACertificate}"
echo "// 自动生成: $(date)"echo "// 来源: $CERT_FILE"echo "#ifndef TLS_CERT_H"echo "#define TLS_CERT_H"echo ""echo "static const char* ${VAR_NAME} = "
while IFS= read -r line; do # 转义双引号和反斜杠 escaped=$(echo "$line" | sed 's/"/\\"/g') echo " \"${escaped}\\n\""done < "$CERT_FILE"
echo " \"\";"echo ""echo "#endif // TLS_CERT_H"# 使用示例chmod +x convert-cert.sh./convert-cert.sh isrgrootx1.pem > ca_cert.h方法 2:使用 PROGMEM 存储(节省 RAM)
Section titled “方法 2:使用 PROGMEM 存储(节省 RAM)”// 将证书存储在 Flash 而非 RAM#include <pgmspace.h>
static const char rootCA[] PROGMEM = R"EOF(-----BEGIN CERTIFICATE-----MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw...-----END CERTIFICATE-----)EOF";ESP32 MQTT TLS Code
Section titled “ESP32 MQTT TLS Code”完整代码示例
Section titled “完整代码示例”#include <WiFi.h>#include <WiFiClientSecure.h>#include <PubSubClient.h>#include "ca_cert.h" // 根证书
// WiFi 配置const char* ssid = "YourSSID";const char* password = "YourWiFiPassword";
// MQTT TLS 配置const char* mqtt_server = "mqtt.example.com"; // DynDNS 域名const int mqtt_port = 8883; // MQTTS 端口const char* mqtt_user = "esp32_device";const char* mqtt_pass = "device_password";const char* client_id = "esp32_factory_001";
WiFiClientSecure espClient;PubSubClient client(espClient);
void setup() { Serial.begin(115200);
// 连接 WiFi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.print("."); } Serial.println("\nWiFi 已连接");
// 配置 TLS 证书验证 // 方法 1:使用 CA 证书验证(推荐) espClient.setCACert(rootCACertificate);
// 方法 2:不验证证书(仅开发测试) // espClient.setInsecure();
// 配置 MQTT client.setServer(mqtt_server, mqtt_port); client.setCallback(callback);
// 连接 MQTT Broker connectToBroker();}
void connectToBroker() { while (!client.connected()) { Serial.print("连接到 MQTT Broker (TLS)...");
if (client.connect(client_id, mqtt_user, mqtt_pass)) { Serial.println("已连接 ✅");
// 发布在线消息 client.publish("esp32/status", "{\"status\": \"online\", \"tls\": true}");
// 订阅控制 Topic client.subscribe("esp32/control");
} else { Serial.print("连接失败, 状态码: "); Serial.print(client.state()); Serial.println(" 5 秒后重试"); delay(5000); } }}
void callback(char* topic, byte* payload, unsigned int length) { // 处理收到的消息 Serial.printf("收到消息 [%s]: ", topic); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println();}
void loop() { if (!client.connected()) { connectToBroker(); } client.loop();}Certificate Validation Modes
Section titled “Certificate Validation Modes”三种验证模式对比
Section titled “三种验证模式对比”WiFiClientSecure client;
// 模式 1: 不验证(开发测试用)client.setInsecure();// 特点: 所有证书都接受,无安全保障// 风险: 🔴 容易受中间人攻击
// 模式 2: CA 证书验证(生产推荐)client.setCACert(rootCA);// 特点: 验证服务器证书由可信 CA 签发// 安全: ✅ 防止中间人攻击
// 模式 3: 双向验证(最高安全)client.setCACert(rootCA);client.setCertificate(clientCert); // 设备证书client.setPrivateKey(privKey); // 设备私钥// 特点: 服务器也验证设备身份// 安全: ✅ ✅ 防止设备伪造验证模式选择指南
Section titled “验证模式选择指南”| 场景 | 推荐模式 | 理由 |
|---|---|---|
| 开发原型 | setInsecure() | 快速迭代 |
| 内网生产 | setCACert() | 验证服务器身份 |
| 互联网生产 | setCACert() | 防止中间人攻击 |
| 高安全 | 双向验证 | 设备和服务器互验证 |
Certificate Size Impact
Section titled “Certificate Size Impact”| 证书类型 | 典型大小 | RAM 占用 | 存储位置 |
|---|---|---|---|
| Let’s Encrypt Root | ~2KB | 代码段 | Flash (PROGMEM) |
| 服务器证书 | ~1.5KB | 运行时 | Flash |
| 私钥(双向) | ~1.5KB | 运行时 | Flash |
| 设备证书(双向) | ~1KB | 运行时 | Flash |
优化建议:
- 使用 PROGMEM 存储证书,减少 RAM 占用
- 仅包含需要的根证书
- 使用
ESP.getFreeHeap()监控 TLS 连接的内存使用
Pre-sales Key Points
Section titled “Pre-sales Key Points”证书集成要点
Section titled “证书集成要点”| 要点 | 说明 | 对买家的沟通 |
|---|---|---|
| 代码嵌入 | 证书作为字符串编译进固件 | ”安全证书已内置在固件中” |
| 验证模式 | 支持 CA 验证和双向验证 | ”设备会自动验证服务器身份” |
| 内存影响 | 证书占 ~2KB Flash | ”对固件大小影响很小” |
| 存储安全 | 证书固件中只读 | ”证书不可篡改,OTA 更新时更新” |
Summary
Section titled “Summary”本节介绍了 ESP32 证书集成:
- 证书获取:从 Let’s Encrypt 获取根证书
- 代码嵌入:证书转换为 C 字符串嵌入固件
- 三种模式:不验证(开发)、CA 验证(生产)、双向验证(高安全)
- 代码实现:espClient.setCACert() → 连接 8883 端口
- 内存影响:证书 ~2KB,可使用 PROGMEM 优化