| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|---|
ESP HTTP Client Mutual TLS Authentication Example
This example demonstrates mutual TLS (mTLS) authentication using esp_http_client. The server verifies the client's identity via a client certificate, and the client verifies the server using a CA certificate.
Two client key modes are supported, selectable via Kconfig:
| Mode | Kconfig | Client key source |
|---|---|---|
| Software keys (default) | EXAMPLE_MUTUAL_AUTH_USE_HW_RSA_DS=n |
PEM files embedded in firmware |
| DS peripheral | EXAMPLE_MUTUAL_AUTH_USE_HW_RSA_DS=y |
Hardware Digital Signature peripheral via esp_secure_cert partition |
How it works
- Device connects to Wi-Fi or Ethernet (via
protocol_examples_common) - Prompts for HTTPS server URL on serial console
- Performs HTTPS GET with mutual TLS — sends client certificate to server
- Logs the HTTP status code
Quick start (software key mode)
idf.py set-target esp32c3
idf.py build flash monitor
When prompted, enter the URL of an HTTPS server that requires client certificates. The pre-generated certificates in main/certs/ are used automatically.
Certificates
Pre-generated certificates with 10-year lifetime are in main/certs/. A single CA signs both client and server certificates. See main/certs/README.md for OpenSSL commands to regenerate.
| File | Purpose | Embedded in firmware? |
|---|---|---|
ca_cert.pem |
CA certificate (verifies server) | Yes (both modes) |
client_cert.pem |
Client certificate | Yes (software mode only) |
client_key.pem |
Client private key | Yes (software mode only) |
server_cert.pem |
Server certificate (pytest) | No |
server_key.pem |
Server private key (pytest) | No |
DS peripheral mode
The DS (Digital Signature) peripheral holds the client private key in hardware. The client certificate and DS context are stored in the esp_secure_cert partition.
Prerequisites
- ESP32-C3 or other chip with
SOC_DIG_SIGN_SUPPORTED esp-secure-cert-tool(pip install esp-secure-cert-tool)
Provisioning
- Generate DS partition and HMAC key (from the example directory):
configure_esp_secure_cert.py \
--device-cert main/certs/client_cert.pem \
--target_chip esp32c3 \
--configure_ds --priv_key_algo RSA 2048 \
--skip_flash --keep_ds_data_on_host \
--private-key main/certs/client_key.pem \
--efuse_key_id 1
Copy the output files to main/certs/esp_secure_cert_data/:
esp_secure_cert.binhmac_key.bin
- Burn HMAC key to eFuse:
# QEMU
idf.py qemu efuse-burn-key --do-not-confirm BLOCK_KEY1 \
main/certs/esp_secure_cert_data/hmac_key.bin HMAC_DOWN_DIGITAL_SIGNATURE
# Hardware (irreversible!)
idf.py efuse-burn-key --do-not-confirm BLOCK_KEY1 \
main/certs/esp_secure_cert_data/hmac_key.bin HMAC_DOWN_DIGITAL_SIGNATURE
- Build and flash:
idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.ci.qemu_ds" build flash monitor
QEMU testing
Three QEMU tests are included:
test_mutual_auth_software_keys— software key mTLS, expects HTTP 200test_mutual_auth_ds— DS peripheral mTLS, expects HTTP 200test_mutual_auth_ds_fails_wrong_credentials— DS with wrong server CA, expects failure
The tests start a local HTTPS server with mutual TLS, inject the URL via serial, and verify device output.
Troubleshooting
TLS handshake failed: BAD_SIGNATURE
The client certificate is not signed by the CA the server expects. Regenerate certs using the commands in main/certs/README.md.
ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL
The HMAC key in eFuse does not match the key used to create the DS partition. For QEMU, delete the eFuse image and regenerate it from the current hmac_key.bin.