diff --git a/components/esp32s2/esp_hmac.c b/components/esp32s2/esp_hmac.c index ab5604dbe5..93f54a2a5c 100644 --- a/components/esp32s2/esp_hmac.c +++ b/components/esp32s2/esp_hmac.c @@ -12,9 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include "esp32s2/rom/hmac.h" #include "esp_hmac.h" #include "esp_crypto_lock.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" +#include "soc/hwcrypto_reg.h" +#include "soc/system_reg.h" +#include "esp_log.h" + +static const char *TAG = "esp_hmac"; static ets_efuse_block_t convert_key_type(hmac_key_id_t key_id) { return ETS_EFUSE_BLOCK_KEY0 + (ets_efuse_block_t) key_id; @@ -44,3 +52,55 @@ esp_err_t esp_hmac_calculate(hmac_key_id_t key_id, } } + +esp_err_t esp_hmac_jtag_enable(hmac_key_id_t key_id, const uint8_t *token) +{ + esp_err_t err; + + if ((!token) || (key_id >= HMAC_KEY_MAX)) + return ESP_ERR_INVALID_ARG; + + /* Check if JTAG is permanently disabled by HW Disable eFuse */ + if (esp_efuse_read_field_bit(ESP_EFUSE_HARD_DIS_JTAG)) { + ESP_LOGE(TAG, "JTAG disabled permanently."); + return ESP_FAIL; + } + + esp_crypto_dma_lock_acquire(); + + ets_hmac_enable(); + + /* Token updating into HMAC module. */ + for (int i = 0; i < 32; i += 4) { + uint32_t key_word; + memcpy(&key_word, &token[i], 4); + REG_WRITE(DPORT_JTAG_CTRL_0_REG + i, __builtin_bswap32(key_word)); + } + + err = ets_hmac_calculate_downstream(convert_key_type(key_id), ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG); + if (err != ETS_OK) { + ESP_LOGE(TAG, "HMAC downstream JTAG enable mode setting failed."); + return ESP_FAIL; + } + + ESP_LOGD(TAG, "HMAC computation in downstream mode is completed."); + + ets_hmac_disable(); + + esp_crypto_dma_lock_release(); + + return ESP_OK; +} + +esp_err_t esp_hmac_jtag_disable() +{ + esp_crypto_dma_lock_acquire(); + + REG_WRITE(HMAC_SET_INVALIDATE_JTAG_REG, 1); + + esp_crypto_dma_lock_release(); + + ESP_LOGD(TAG, "Invalidate JTAG result register. JTAG disabled."); + + return ESP_OK; +} diff --git a/components/esp32s2/include/esp_hmac.h b/components/esp32s2/include/esp_hmac.h index 6798ae8d1f..5fa836c47d 100644 --- a/components/esp32s2/include/esp_hmac.h +++ b/components/esp32s2/include/esp_hmac.h @@ -60,6 +60,38 @@ esp_err_t esp_hmac_calculate(hmac_key_id_t key_id, size_t message_len, uint8_t *hmac); +/** + * @brief + * Use HMAC peripheral in Downstream mode to re-enable the JTAG, if it is not permanently disable by HW. + * In downstream mode HMAC calculations perfomred by peripheral used internally and not provided back to user. + * + * @param key_id Determines which of the 6 key blocks in the efuses should be used for the HMAC calculation. + * The corresponding purpose field of the key block in the efuse must be set to HMAC downstream purpose. + * + * @param token Pre calculated HMAC value of the 32-byte 0x00 using SHA-256 and the known private HMAC key. The key is already + * programmed to a eFuse key block. The key block number is provided as the first parameter to this function. + * + * @return + * * ESP_OK, if the calculation was successful, + * if the calculated HMAC value matches with provided token, + * JTAG will be re-enable otherwise JTAG will remain disabled. + * Return value does not indicate the JTAG status. + * * ESP_FAIL, if the hmac calculation failed or JTAG is permanently disabled by EFUSE_HARD_DIS_JTAG eFuse parameter. + * * ESP_ERR_INVALID_ARG, invalid input arguments + */ +esp_err_t esp_hmac_jtag_enable(hmac_key_id_t key_id, + const uint8_t *token); + +/** + * @brief + * Disable the JTAG which might be enable using the HMAC downstream mode. This function just clear the result generated by + * JTAG key by calling esp_hmac_jtag_enable() API. + * + * @return + * * ESP_OK return ESP_OK after writing the HMAC_SET_INVALIDATE_JTAG_REG with value 1. + */ +esp_err_t esp_hmac_jtag_disable(void); + #ifdef __cplusplus } #endif diff --git a/components/esp32s2/test/test_hmac.c b/components/esp32s2/test/test_hmac.c index 96861996f5..6a4c2c75e8 100644 --- a/components/esp32s2/test/test_hmac.c +++ b/components/esp32s2/test/test_hmac.c @@ -14,6 +14,9 @@ #include "esp_hmac.h" #include "unity.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" +#include "esp_log.h" #if CONFIG_IDF_ENV_FPGA @@ -27,6 +30,7 @@ typedef struct { } hmac_result; static const ets_efuse_block_t key_block = ETS_EFUSE_BLOCK_KEY4; +static const char *TAG = "test_hmac"; static void setup_keyblock(void) { const uint8_t key_data[32] = { @@ -44,6 +48,64 @@ static void setup_keyblock(void) { } } +TEST_CASE("HMAC 'downstream' JTAG Enable mode", "[hw_crypto]") +{ + int ets_status; + + const uint8_t key_data[32] = { + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32 + }; + + // Results calculated with Python: + // + // import hmac, hashlib, binascii + // key = b"".join([chr(x).encode() for x in range(1,33)]) + // ", ".join("0x%x" % x for x in hmac.HMAC(key, b"\x00" * 32, hashlib.sha256).digest() ) + const uint8_t token_data[32] = { + 0xb2, 0xa4, 0x9b, 0x1c, 0xce, 0x1b, 0xe9, 0x22, 0xbb, 0x7e, 0x43, 0x12, 0x77, 0x41, 0x3e, 0x3e, + 0x8e, 0x6c, 0x3e, 0x8e, 0x6e, 0x17, 0x62, 0x5c, 0x50, 0xac, 0x66, 0xa9, 0xa8, 0x57, 0x94, 0x9b + }; + + ets_status = ets_efuse_write_key(ETS_EFUSE_BLOCK_KEY3, + ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG, + key_data, sizeof(key_data)); + + if (ets_status == ESP_OK) { + ESP_LOGI(TAG, "HMAC_DOWN_JTAG key programmed!"); + } else { + ESP_LOGW(TAG, "HMAC_DOWN_JTAG key programming failed, \ + maybe written already. Continuing"); + } + + TEST_ASSERT_MESSAGE(ESP_OK == esp_efuse_batch_write_begin(), + "Error programming security efuse.\n"); + + ets_status = esp_efuse_set_read_protect(ETS_EFUSE_BLOCK_KEY3); + if (ets_status != ESP_OK) { + ESP_LOGW(TAG, "EFUSE_BLOCK read protect setting failed. \ + Not a must prerequisite to run this test case. Continuing"); + } + + ets_status = esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG); + if (ets_status != ESP_OK) { + ESP_LOGI(TAG, "JTAG Disable temporarily failed. \ + May be disabled already. Continuing the test."); + } + + TEST_ASSERT_MESSAGE(ESP_OK == esp_efuse_batch_write_commit(), + "Error programming security efuse.\n"); + + TEST_ASSERT_EQUAL_HEX32_MESSAGE(ESP_OK, esp_hmac_jtag_enable(HMAC_KEY3, token_data), + "JTAG should be re-enabled now, please manually verify"); +} + +TEST_CASE("HMAC 'downstream' JTAG Disable", "[hw_crypto]") +{ + TEST_ASSERT_EQUAL_HEX32_MESSAGE(ESP_OK, esp_hmac_jtag_disable(), + "JTAG should be disabled now, please manually verify"); +} + TEST_CASE("HMAC 'upstream' MAC generation with zeroes", "[hw_crypto]") { uint8_t hmac[32]; diff --git a/docs/en/api-reference/peripherals/hmac.rst b/docs/en/api-reference/peripherals/hmac.rst index 9f632086dc..357f4c7e49 100644 --- a/docs/en/api-reference/peripherals/hmac.rst +++ b/docs/en/api-reference/peripherals/hmac.rst @@ -88,7 +88,23 @@ HMAC for Enabling JTAG Key Purpose values: 6, 5 The third application is using the HMAC as a key to enable JTAG if it was soft-disabled before. -This functionality is currently not implemented. +Following is the procedure to re-enable the JTAG + +Setup + +1. Generate a 256-bit HMAC secret key to use for JTAG re-enable. +2. Write the key to an eFuse block with key purpose HMAC_DOWN_ALL (5) or HMAC_DOWN_JTAG (6). This can be done using the ets_efuse_write_key() function in the firmware or using espefuse.py from the host. +3. Configure the eFuse key block to be read protected using the esp_efuse_set_read_protect(), so that software cannot read back the value. +4. Burn the "soft JTAG disable" bit by esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG). This will permanently disable JTAG unless the correct key value is provided by software. + +JTAG enable + +1. The key to re-enable JTAG is the output of the HMAC-SHA256 function using the secret key in eFuse and 32 0x00 bytes as the message. +2. Pass this key value when calling the :cpp:func:`esp_hmac_jtag_enable` function from the firmware. +3. To re-disable JTAG in the firmware, reset the system or call :cpp:func:`esp_hmac_jtag_disable`. + +For more details, check the chapter *HMAC Module* in the `{IDF_TARGET_NAME} Technical Reference Manual <{IDF_TARGET_TRM_EN_URL}>`_. + Application Outline -------------------