Merge branch 'feature/jtag_reenable' into 'master'

Feature/jtag reenable

Closes IDF-802

See merge request espressif/esp-idf!10524
This commit is contained in:
Angus Gratton 2020-10-15 14:46:49 +08:00
commit f45e8bab35
4 changed files with 171 additions and 1 deletions

View File

@ -12,9 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#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;
}

View File

@ -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

View File

@ -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];

View File

@ -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
-------------------