espsecure
espsecure is a tool for manipulating data that relates to the secure boot and flash encryption features of ESP32 and later Espressif chips.
For more details, see the ESP-IDF documentation which explains this tool and how to use it to enable the relevant features:
Skipping Padding During Data Signing and Verification
By default, espsecure sign-data pads the input so the signed output is always a multiple of 4096 bytes (SECTOR_SIZE), which may not be desirable for all use cases (e.g. When performing Secure boot over custom data with limited size requirements).
Use the --skip-padding argument to sign and verify files without adding sector alignment padding.
espsecure sign-data --version 2 --keyfile <keyfile> --skip-padding --output <signed_image> <datafile>
If you used --skip-padding to sign, you must also use it to verify:
espsecure verify-signature --version 2 --skip-padding --keyfile <keyfile> <signed_image>
Note
Only use --skip-padding if you know your use case supports non-sector-aligned images.
Remote Signing Using an External HSM
An external Hardware Security Module (HSM) can be used for remote signing of images in secure boot v2 scheme.
You must install esptool package with the hsm extra using the command pip install 'esptool[hsm]' to use this feature. esp_hsm_sign provides a PKCS #11 interface to communicate with the external HSM and is integrated in espsecure.
The following command should be used to get an image signed using an external HSM.
espsecure sign-data --version 2 --hsm --hsm-config <hsm_config_file> --output <signed_image> <datafile>
The above command first extracts the public key from the HSM, generates a signature for an image using the HSM, and then creates a signature block and appends it to the image to generate a signed image.
If the public key is not stored in the external HSM, you can specify the --pub-key argument to supply the public key.
espsecure sign-data --version 2 --hsm --hsm-config <hsm_config_file> --pub-key <public_key> --output <signed_image> <datafile>
Note
In case you are using ESP-IDF, then an unsigned application can be generated by disabling CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES configuration option in the project settings.
Verifying the Signed Image
Once the signed image is generated, we can verify it using the following command:
espsecure verify-signature --version 2 --hsm --hsm-config <hsm_config_file> <signed_image>
If the public key is not stored in the external HSM, you can specify the --keyfile argument to supply the public key.
espsecure verify-signature --version 2 --keyfile <public_key> <signed_image>
HSM Config File
An HSM config file is required with the fields (pkcs11_lib, credentials, slot, label, label_pubkey)
populated corresponding to the HSM used.
To access an HSM token of a selected slot, you will also need to pass in the token User PIN and thus you will be prompted to type in the User PIN.
Alternatively, you could also add a credentials field in the HSM config file to store the (plaintext) User PIN to automate the signing workflow.
Below is a sample HSM config file (hsm_config.ini) for using SoftHSMv2 as an external HSM:
# hsm_config.ini
# Config file for the external Hardware Security Module
# to be used to generate signature.
[hsm_config]
# PKCS11 shared object/library module of the HSM vendor
pkcs11_lib = /usr/local/lib/softhsm/libsofthsm2.so
# HSM login credentials
credentials = 1234
# Slot number to be used
slot = 1108821954
# Label of the object used to store the private key
label = Private Key for Digital Signature
# Label of the object used to store corresponding public key
# label_pubkey is the same as label if the label for public key
# is not explicitly specified while key-pair generation.
label_pubkey = Public Key for Digital Signature
Secure Debug Controller (SDC)
The Secure Debug Controller (SDC) is a hardware peripheral available on ESP32-S31 that enables secure debugging on locked devices. When a ESP32-S31 device is locked (e.g., Download mode is disabled), SDC can enable relevant debugging interfaces after successful authentication using a certificate-based mechanism.
Enabling the Secure Debug Controller
Before any other SDC step, the SDC feature itself must be enabled on the device by burning the SDC_ENA eFuse to 1. This is the very first provisioning step: until SDC_ENA is set, the device does not act on SDC commands and esptool read-sdc-chip-info (and certificate verification) will fail.
espefuse -p $PORT burn-efuse SDC_ENA 1
Replace $PORT with your device port (e.g., /dev/ttyUSB0).
Warning
Burning eFuses is an irreversible operation.
SDC Public Key Digest Generation
The SDC public key digest is the digest of the public key corresponding to the SDC private key. The SDC private key is used to generate the SDC certificate, while the public key digest is burned to the device eFuse and used by SDC to authenticate the certificate.
The SDC public key digest must be burned to the device eFuse before the SDC certificate can be used. Use the digest-sdc-public-key command to generate this digest.
Generating a Private Key
Before generating the SDC public key digest, you need an SDC private key. To generate a new SDC private key (ECDSA P-256), you can use:
espsecure generate-signing-key --version 2 --scheme ecdsa256 private_key.pemOpenSSL command:
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
Basic Usage
To generate the SDC public key digest from a private key file:
espsecure digest-sdc-public-key -k private_key.pem -o sdc_pub_key_digest.bin
To generate from a public key file:
espsecure digest-sdc-public-key --pub-key public_key.pem -o sdc_pub_key_digest.bin
To generate from an HSM (see Remote Signing Using an External HSM for HSM setup instructions):
espsecure digest-sdc-public-key --hsm --hsm-config hsm_config.ini -o sdc_pub_key_digest.bin
To extract a public key from a private key (for use with --pub-key):
espsecure extract-public-key --version 2 --keyfile private_key.pem public_key.pem
Note
Only one of --keyfile, --pub-key, or --hsm can be provided.
Run espsecure digest-sdc-public-key -h for the full list of options.
Burning the Digest to eFuse
After generating the digest file, burn it to the device eFuse using espefuse burn-key with the SDC_KEY_DIGEST key purpose. The burn-key command automatically sets the key purpose, making it easier than using burn-block-data. For ESP32-S31, use:
espefuse -p $PORT burn-key BLOCK_KEY0 sdc_pub_key_digest.bin SDC_KEY_DIGEST
Replace BLOCK_KEY0 with the appropriate eFuse key block name for your chip (e.g., BLOCK_KEY0, BLOCK_KEY1, etc.) and $PORT with your device port (e.g., /dev/ttyUSB0).
Warning
Burning eFuses is an irreversible operation. Ensure you have the correct digest file before proceeding. The digest must match the public key used to generate the SDC certificate.
SDC Certificate Generation
The SDC certificate enables secure debugging on ESP32-S31 devices where SDC is enabled. The generate-sdc-certificate command creates this certificate for authentication with SDC.
Once authenticated, SDC opens the relevant debug interfaces as configured in the certificate.
Important
The same ECDSA private key whose public key digest is burned into the device eFuse must be used to generate the SDC certificate. The certificate will only be accepted by the device if it was signed with the key matching the digest stored in eFuse.
The certificate is bound to the target device through its chip information, passed with --chip-info. To produce chip_info.bin (64 bytes), connect to the target debugging device and run:
esptool -p $PORT --no-stub read-sdc-chip-info
The --no-stub option is required because a locked SDC device only accepts ROM bootloader commands and rejects the flasher stub upload.
Example command to generate an SDC certificate that re-enables JTAG:
espsecure generate-sdc-certificate -k private_key.pem --chip-info chip_info.bin --enable-jtag --output sdc_cert.bin
Run espsecure generate-sdc-certificate -h for the full list of options (--enable-jtag, --enable-download-reuse, --enable-force-spi-boot, --output, --usc, …).
Using an External HSM
You can also sign the SDC certificate using a private key stored in an HSM. See Remote Signing Using an External HSM for HSM installation and setup instructions.
espsecure generate-sdc-certificate --hsm --hsm-config hsm_config.ini --mac <mac_address>
USC Configuration (JSON)
The Unlock Security Configuration (USC) defines what SDC does after successful authentication. You can provide a JSON file to configure the USC bits using the --usc argument. This is useful for managing complex configurations or future extensions (e.g., PMA/PMP settings).
The JSON file is versioned so the format can evolve. Settings are grouped, and each entry is a {"key", "value"} pair (with an optional "description" for documentation). Only the config_flags group is used today; the layout leaves room for future groups (e.g. PMA/PMP entries) without breaking older files:
{
"version": 1,
"groups": [
{
"group": "config_flags",
"entries": [
{"key": "enable_jtag", "value": true, "description": "Enable JTAG debugging"},
{"key": "enable_download_reuse", "value": false, "description": "Enable download mode reuse"},
{"key": "enable_force_spi_boot", "value": false, "description": "Force SPI boot"}
]
}
]
}
The recognised config_flags keys are enable_jtag, enable_download_reuse, and enable_force_spi_boot (all boolean).
Note
The top-level version field is required; a file without "version": 1 is rejected. When a JSON file is provided via --usc, the values in the JSON file override any corresponding CLI arguments (--enable-jtag, etc.). If a flag is not present in the JSON file, the CLI argument value (or default) will be used.
espsecure generate-sdc-certificate -k private_key.pem --usc usc_config.json --chip-info chip_info.bin
Using MAC Address and SDC Session Counter
If the device base MAC address and SDC session counter are known, you can generate the SDC certificate offline, without extracting the chip information from the device. Provide --mac (and --sdc-session-counter if it is not 0) instead of --chip-info.
Pass the MAC address in the same human-readable order reported by espefuse summary (the MAC eFuse) or esptool read-mac, for example 00:11:22:33:44:55. espsecure reverses the bytes internally to match the device’s eFuse byte order when deriving the chip information.
Example:
espsecure generate-sdc-certificate -k private_key.pem --mac 00:11:22:33:44:55 --sdc-session-counter 0 --enable-jtag --enable-download-reuse
Note
The SDC session counter must match the value burned in the device eFuse (SDC_SESSION_COUNTER). After each debugging session, user has the option to end the current debugging session by incrementing the SDC session counter (burning the eFuse to the new value). This will require generating a new certificate using the updated counter value for further debugging sessions. SDC_SESSION_COUNTER is a 3-bit write-only eFuse; since eFuse bits can only be burned from 0 to 1, the counter advances 0 → 1 → 3 → 7 (one additional bit per session), so a total of 4 SDC debugging sessions can be performed. The --sdc-session-counter value must equal the current eFuse value (0, 1, 3, or 7).