mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
feat(esp_http_client_mutual_auth): add mutual TLS example
Closes https://github.com/espressif/esp-idf/issues/18393
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
| 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
|
||||
|
||||
1. Device connects to Wi-Fi or Ethernet (via `protocol_examples_common`)
|
||||
2. Prompts for HTTPS server URL on serial console
|
||||
3. Performs HTTPS GET with mutual TLS — sends client certificate to server
|
||||
4. Logs the HTTP status code
|
||||
|
||||
## Quick start (software key mode)
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
1. **Generate DS partition and HMAC key** (from the example directory):
|
||||
|
||||
```bash
|
||||
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.bin`
|
||||
- `hmac_key.bin`
|
||||
|
||||
2. **Burn HMAC key to eFuse:**
|
||||
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
|
||||
3. **Build and flash:**
|
||||
|
||||
```bash
|
||||
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 200
|
||||
- `test_mutual_auth_ds` — DS peripheral mTLS, expects HTTP 200
|
||||
- `test_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`.
|
||||
Reference in New Issue
Block a user