Merge branch 'bugfix/dport_protect_crypto' into 'master'

add protection for crypto registers in DPORT

See merge request !928
This commit is contained in:
Ivan Grokhotkov
2017-08-30 11:45:35 +08:00
16 changed files with 440 additions and 240 deletions

View File

@@ -69,21 +69,23 @@ static BaseType_t oldInterruptLevel[2];
void IRAM_ATTR esp_dport_access_stall_other_cpu_start(void)
{
#ifndef CONFIG_FREERTOS_UNICORE
int cpu_id = xPortGetCoreID();
if (dport_core_state[0] == DPORT_CORE_STATE_IDLE
|| dport_core_state[1] == DPORT_CORE_STATE_IDLE) {
|| dport_core_state[1] == DPORT_CORE_STATE_IDLE) {
return;
}
BaseType_t intLvl = portENTER_CRITICAL_NESTED();
int cpu_id = xPortGetCoreID();
#ifdef DPORT_ACCESS_BENCHMARK
ccount_start[cpu_id] = XTHAL_GET_CCOUNT();
#endif
BaseType_t intLvl=portENTER_CRITICAL_NESTED();
oldInterruptLevel[cpu_id]=intLvl;
if (dport_access_ref[cpu_id] == 0) {
portENTER_CRITICAL_ISR(&g_dport_mux);
portENTER_CRITICAL_ISR(&g_dport_mux);
oldInterruptLevel[cpu_id]=intLvl;
dport_access_start[cpu_id] = 0;
dport_access_end[cpu_id] = 0;
@@ -100,6 +102,11 @@ void IRAM_ATTR esp_dport_access_stall_other_cpu_start(void)
}
dport_access_ref[cpu_id]++;
if (dport_access_ref[cpu_id] > 1) {
/* Interrupts are already disabled by the parent, we're nested here. */
portEXIT_CRITICAL_NESTED(intLvl);
}
#endif /* CONFIG_FREERTOS_UNICORE */
}
@@ -124,9 +131,9 @@ void IRAM_ATTR esp_dport_access_stall_other_cpu_end(void)
dport_access_end[cpu_id] = 1;
portEXIT_CRITICAL_ISR(&g_dport_mux);
portEXIT_CRITICAL_NESTED(oldInterruptLevel[cpu_id]);
}
portEXIT_CRITICAL_NESTED(oldInterruptLevel[cpu_id]);
#ifdef DPORT_ACCESS_BENCHMARK
ccount_end[cpu_id] = XTHAL_GET_CCOUNT();

View File

@@ -3,7 +3,7 @@
* Based on mbedTLS FIPS-197 compliant version.
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Additions Copyright (C) 2016, Espressif Systems (Shanghai) PTE Ltd
* Additions Copyright (C) 2016-2017, Espressif Systems (Shanghai) PTE Ltd
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -26,35 +26,60 @@
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
*/
#include <string.h>
#include "mbedtls/aes.h"
#include "hwcrypto/aes.h"
#include "rom/aes.h"
#include "soc/dport_reg.h"
#include "soc/hwcrypto_reg.h"
#include <sys/lock.h>
static _lock_t aes_lock;
#include <freertos/FreeRTOS.h>
#include "soc/cpu.h"
#include <stdio.h>
/* AES uses a spinlock mux not a lock as the underlying block operation
only takes 208 cycles (to write key & compute block), +600 cycles
for DPORT protection but +3400 cycles again if you use a full sized lock.
For CBC, CFB, etc. this may mean that interrupts are disabled for a longer
period of time for bigger lengths. However at the moment this has to happen
anyway due to DPORT protection...
*/
static portMUX_TYPE aes_spinlock = portMUX_INITIALIZER_UNLOCKED;
void esp_aes_acquire_hardware( void )
{
/* newlib locks lazy initialize on ESP-IDF */
_lock_acquire(&aes_lock);
/* Enable AES hardware */
DPORT_REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_AES);
/* Clear reset on digital signature & secure boot units,
otherwise AES unit is held in reset also. */
DPORT_REG_CLR_BIT(DPORT_PERI_RST_EN_REG,
DPORT_PERI_EN_AES
| DPORT_PERI_EN_DIGITAL_SIGNATURE
| DPORT_PERI_EN_SECUREBOOT);
portENTER_CRITICAL(&aes_spinlock);
DPORT_STALL_OTHER_CPU_START();
{
/* Enable AES hardware */
_DPORT_REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_AES);
/* Clear reset on digital signature & secure boot units,
otherwise AES unit is held in reset also. */
_DPORT_REG_CLR_BIT(DPORT_PERI_RST_EN_REG,
DPORT_PERI_EN_AES
| DPORT_PERI_EN_DIGITAL_SIGNATURE
| DPORT_PERI_EN_SECUREBOOT);
}
DPORT_STALL_OTHER_CPU_END();
}
void esp_aes_release_hardware( void )
{
/* Disable AES hardware */
DPORT_REG_SET_BIT(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_AES);
/* Don't return other units to reset, as this pulls
reset on RSA & SHA units, respectively. */
DPORT_REG_CLR_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_AES);
_lock_release(&aes_lock);
DPORT_STALL_OTHER_CPU_START();
{
/* Disable AES hardware */
_DPORT_REG_SET_BIT(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_AES);
/* Don't return other units to reset, as this pulls
reset on RSA & SHA units, respectively. */
_DPORT_REG_CLR_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_AES);
}
DPORT_STALL_OTHER_CPU_END();
portEXIT_CRITICAL(&aes_spinlock);
}
void esp_aes_init( esp_aes_context *ctx )
@@ -71,55 +96,18 @@ void esp_aes_free( esp_aes_context *ctx )
bzero( ctx, sizeof( esp_aes_context ) );
}
/* Translate number of bits to an AES_BITS enum */
static int keybits_to_aesbits(unsigned int keybits)
{
switch (keybits) {
case 128:
return AES128;
case 192:
return AES192;
break;
case 256:
return AES256;
default:
return ( ERR_ESP_AES_INVALID_KEY_LENGTH );
}
}
/*
* AES key schedule (encryption)
* AES key schedule (same for encryption or decryption, as hardware handles schedule)
*
*/
int esp_aes_setkey_enc( esp_aes_context *ctx, const unsigned char *key,
unsigned int keybits )
int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key,
unsigned int keybits )
{
uint16_t keybytes = keybits / 8;
int aesbits = keybits_to_aesbits(keybits);
if (aesbits < 0) {
return aesbits;
if (keybits != 128 && keybits != 192 && keybits != 256) {
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
}
ctx->enc.aesbits = aesbits;
bzero(ctx->enc.key, sizeof(ctx->enc.key));
memcpy(ctx->enc.key, key, keybytes);
return 0;
}
/*
* AES key schedule (decryption)
*
*/
int esp_aes_setkey_dec( esp_aes_context *ctx, const unsigned char *key,
unsigned int keybits )
{
uint16_t keybytes = keybits / 8;
int aesbits = keybits_to_aesbits(keybits);
if (aesbits < 0) {
return aesbits;
}
ctx->dec.aesbits = aesbits;
bzero(ctx->dec.key, sizeof(ctx->dec.key));
memcpy(ctx->dec.key, key, keybytes);
ctx->key_bytes = keybits / 8;
memcpy(ctx->key, key, ctx->key_bytes);
return 0;
}
@@ -127,16 +115,41 @@ int esp_aes_setkey_dec( esp_aes_context *ctx, const unsigned char *key,
* Helper function to copy key from esp_aes_context buffer
* to hardware key registers.
*
* Only call when protected by esp_aes_acquire_hardware().
* Call only while holding esp_aes_acquire_hardware().
*/
static inline int esp_aes_setkey_hardware( esp_aes_context *ctx, int mode)
static inline void esp_aes_setkey_hardware( esp_aes_context *ctx, int mode)
{
if ( mode == ESP_AES_ENCRYPT ) {
ets_aes_setkey_enc(ctx->enc.key, ctx->enc.aesbits);
} else {
ets_aes_setkey_dec(ctx->dec.key, ctx->dec.aesbits);
const uint32_t MODE_DECRYPT_BIT = 4;
unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT;
memcpy((uint32_t *)AES_KEY_BASE, ctx->key, ctx->key_bytes);
DPORT_REG_WRITE(AES_MODE_REG, mode_reg_base + ((ctx->key_bytes / 8) - 2));
}
/* Run a single 16 byte block of AES, using the hardware engine.
*
* Call only while holding esp_aes_acquire_hardware().
*/
static inline void esp_aes_block(const void *input, void *output)
{
const uint32_t *input_words = (const uint32_t *)input;
uint32_t *output_words = (uint32_t *)output;
uint32_t *mem_block = (uint32_t *)AES_TEXT_BASE;
for(int i = 0; i < 4; i++) {
mem_block[i] = input_words[i];
}
return 0;
DPORT_REG_WRITE(AES_START_REG, 1);
DPORT_STALL_OTHER_CPU_START();
{
while (_DPORT_REG_READ(AES_IDLE_REG) != 1) { }
for (int i = 0; i < 4; i++) {
output_words[i] = mem_block[i];
}
}
DPORT_STALL_OTHER_CPU_END();
}
/*
@@ -148,7 +161,7 @@ void esp_aes_encrypt( esp_aes_context *ctx,
{
esp_aes_acquire_hardware();
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
ets_aes_crypt(input, output);
esp_aes_block(input, output);
esp_aes_release_hardware();
}
@@ -162,7 +175,7 @@ void esp_aes_decrypt( esp_aes_context *ctx,
{
esp_aes_acquire_hardware();
esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT);
ets_aes_crypt(input, output);
esp_aes_block(input, output);
esp_aes_release_hardware();
}
@@ -177,8 +190,9 @@ int esp_aes_crypt_ecb( esp_aes_context *ctx,
{
esp_aes_acquire_hardware();
esp_aes_setkey_hardware(ctx, mode);
ets_aes_crypt(input, output);
esp_aes_block(input, output);
esp_aes_release_hardware();
return 0;
}
@@ -194,6 +208,9 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx,
unsigned char *output )
{
int i;
uint32_t *output_words = (uint32_t *)output;
const uint32_t *input_words = (const uint32_t *)input;
uint32_t *iv_words = (uint32_t *)iv;
unsigned char temp[16];
if ( length % 16 ) {
@@ -201,34 +218,36 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx,
}
esp_aes_acquire_hardware();
esp_aes_setkey_hardware(ctx, mode);
if ( mode == ESP_AES_DECRYPT ) {
while ( length > 0 ) {
memcpy( temp, input, 16 );
ets_aes_crypt(input, output);
memcpy(temp, input_words, 16);
esp_aes_block(input_words, output_words);
for ( i = 0; i < 16; i++ ) {
output[i] = (unsigned char)( output[i] ^ iv[i] );
for ( i = 0; i < 4; i++ ) {
output_words[i] = output_words[i] ^ iv_words[i];
}
memcpy( iv, temp, 16 );
memcpy( iv_words, temp, 16 );
input += 16;
output += 16;
input_words += 4;
output_words += 4;
length -= 16;
}
} else {
} else { // ESP_AES_ENCRYPT
while ( length > 0 ) {
for ( i = 0; i < 16; i++ ) {
output[i] = (unsigned char)( input[i] ^ iv[i] );
for ( i = 0; i < 4; i++ ) {
output_words[i] = input_words[i] ^ iv_words[i];
}
ets_aes_crypt(output, output);
memcpy( iv, output, 16 );
esp_aes_block(output_words, output_words);
memcpy( iv_words, output_words, 16 );
input += 16;
output += 16;
input_words += 4;
output_words += 4;
length -= 16;
}
}
@@ -253,12 +272,13 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx,
size_t n = *iv_off;
esp_aes_acquire_hardware();
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
if ( mode == ESP_AES_DECRYPT ) {
while ( length-- ) {
if ( n == 0 ) {
ets_aes_crypt(iv, iv );
esp_aes_block(iv, iv );
}
c = *input++;
@@ -270,7 +290,7 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx,
} else {
while ( length-- ) {
if ( n == 0 ) {
ets_aes_crypt(iv, iv );
esp_aes_block(iv, iv );
}
iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
@@ -300,11 +320,12 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx,
unsigned char ov[17];
esp_aes_acquire_hardware();
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
while ( length-- ) {
memcpy( ov, iv, 16 );
ets_aes_crypt(iv, iv);
esp_aes_block(iv, iv);
if ( mode == ESP_AES_DECRYPT ) {
ov[16] = *input;
@@ -339,11 +360,12 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx,
size_t n = *nc_off;
esp_aes_acquire_hardware();
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
while ( length-- ) {
if ( n == 0 ) {
ets_aes_crypt(nonce_counter, stream_block);
esp_aes_block(nonce_counter, stream_block);
for ( i = 16; i > 0; i-- )
if ( ++nonce_counter[i - 1] != 0 ) {

View File

@@ -159,19 +159,23 @@ static void esp_sha_lock_engine_inner(sha_engine_state *engine)
_lock_acquire(&state_change_lock);
if (sha_engines_all_idle()) {
/* Enable SHA hardware */
DPORT_REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_SHA);
/* also clear reset on secure boot, otherwise SHA is held in reset */
DPORT_REG_CLR_BIT(DPORT_PERI_RST_EN_REG,
DPORT_PERI_EN_SHA
| DPORT_PERI_EN_SECUREBOOT);
ets_sha_enable();
DPORT_STALL_OTHER_CPU_START();
{
/* Enable SHA hardware */
_DPORT_REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_SHA);
/* also clear reset on secure boot, otherwise SHA is held in reset */
_DPORT_REG_CLR_BIT(DPORT_PERI_RST_EN_REG,
DPORT_PERI_EN_SHA
| DPORT_PERI_EN_SECUREBOOT);
ets_sha_enable();
}
DPORT_STALL_OTHER_CPU_END();
}
_lock_release(&state_change_lock);
assert( !engine->in_use && "in_use flag should be cleared" );
engine->in_use = true;
_lock_release(&state_change_lock);
}
@@ -187,8 +191,12 @@ void esp_sha_unlock_engine(esp_sha_type sha_type)
if (sha_engines_all_idle()) {
/* Disable SHA hardware */
/* Don't assert reset on secure boot, otherwise AES is held in reset */
DPORT_REG_SET_BIT(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_SHA);
DPORT_REG_CLR_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_SHA);
DPORT_STALL_OTHER_CPU_START();
{
_DPORT_REG_SET_BIT(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_SHA);
_DPORT_REG_CLR_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_SHA);
}
DPORT_STALL_OTHER_CPU_END();
}
_lock_release(&state_change_lock);
@@ -198,10 +206,16 @@ void esp_sha_unlock_engine(esp_sha_type sha_type)
void esp_sha_wait_idle(void)
{
while(REG_READ(SHA_1_BUSY_REG) == 1) {}
while(REG_READ(SHA_256_BUSY_REG) == 1) {}
while(REG_READ(SHA_384_BUSY_REG) == 1) {}
while(REG_READ(SHA_512_BUSY_REG) == 1) {}
DPORT_STALL_OTHER_CPU_START();
while(1) {
if(_DPORT_REG_READ(SHA_1_BUSY_REG) == 0
&& _DPORT_REG_READ(SHA_256_BUSY_REG) == 0
&& _DPORT_REG_READ(SHA_384_BUSY_REG) == 0
&& _DPORT_REG_READ(SHA_512_BUSY_REG) == 0) {
break;
}
}
DPORT_STALL_OTHER_CPU_END();
}
void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
@@ -211,23 +225,26 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
esp_sha_lock_memory_block();
esp_sha_wait_idle();
DPORT_STALL_OTHER_CPU_START(); // This block reads from DPORT memory (reg_addr_buf)
{
esp_sha_wait_idle();
REG_WRITE(SHA_LOAD_REG(sha_type), 1);
while(REG_READ(SHA_BUSY_REG(sha_type)) == 1) { }
_DPORT_REG_WRITE(SHA_LOAD_REG(sha_type), 1);
while(_DPORT_REG_READ(SHA_BUSY_REG(sha_type)) == 1) { }
uint32_t *digest_state_words = (uint32_t *)digest_state;
uint32_t *reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
if(sha_type == SHA2_384 || sha_type == SHA2_512) {
/* for these ciphers using 64-bit states, swap each pair of words */
for(int i = 0; i < sha_length(sha_type)/4; i += 2) {
digest_state_words[i+1] = reg_addr_buf[i];
digest_state_words[i]= reg_addr_buf[i+1];
uint32_t *digest_state_words = (uint32_t *)digest_state;
uint32_t *reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
if(sha_type == SHA2_384 || sha_type == SHA2_512) {
/* for these ciphers using 64-bit states, swap each pair of words */
for(int i = 0; i < sha_length(sha_type)/4; i += 2) {
digest_state_words[i+1] = reg_addr_buf[i];
digest_state_words[i]= reg_addr_buf[i+1];
}
} else {
memcpy(digest_state_words, reg_addr_buf, sha_length(sha_type));
}
} else {
memcpy(digest_state_words, reg_addr_buf, sha_length(sha_type));
}
asm volatile ("memw");
DPORT_STALL_OTHER_CPU_END();
esp_sha_unlock_memory_block();
}
@@ -250,9 +267,9 @@ void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_
asm volatile ("memw");
if(is_first_block) {
REG_WRITE(SHA_START_REG(sha_type), 1);
DPORT_REG_WRITE(SHA_START_REG(sha_type), 1);
} else {
REG_WRITE(SHA_CONTINUE_REG(sha_type), 1);
DPORT_REG_WRITE(SHA_CONTINUE_REG(sha_type), 1);
}
esp_sha_unlock_memory_block();
@@ -275,14 +292,23 @@ void esp_sha(esp_sha_type sha_type, const unsigned char *input, size_t ilen, uns
size_t chunk_len = (ilen > block_len) ? block_len : ilen;
esp_sha_lock_memory_block();
esp_sha_wait_idle();
ets_sha_update(&ctx, sha_type, input, chunk_len * 8);
DPORT_STALL_OTHER_CPU_START();
{
// This SHA ROM function reads DPORT regs
ets_sha_update(&ctx, sha_type, input, chunk_len * 8);
}
DPORT_STALL_OTHER_CPU_END();
esp_sha_unlock_memory_block();
input += chunk_len;
ilen -= chunk_len;
}
esp_sha_lock_memory_block();
esp_sha_wait_idle();
ets_sha_finish(&ctx, sha_type, output);
DPORT_STALL_OTHER_CPU_START();
{
ets_sha_finish(&ctx, sha_type, output);
}
DPORT_STALL_OTHER_CPU_END();
esp_sha_unlock_memory_block();
esp_sha_unlock_engine(sha_type);

View File

@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sdkconfig.h>
#ifndef _ESP_DPORT_ACCESS_H_
#define _ESP_DPORT_ACCESS_H_

View File

@@ -38,11 +38,6 @@ extern "C" {
#define ERR_ESP_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */
#define ERR_ESP_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */
typedef struct {
enum AES_BITS aesbits;
uint8_t key[32];
} key_context, KEY_CTX;
/**
* \brief AES context structure
*
@@ -52,10 +47,8 @@ typedef struct {
* generating an extra round key
*/
typedef struct {
int nr; /*!< number of rounds */
uint32_t *rk; /*!< AES round keys */
KEY_CTX enc;
KEY_CTX dec;
uint8_t key_bytes;
uint8_t key[32];
} esp_aes_context;
/**
@@ -94,7 +87,7 @@ void esp_aes_init( esp_aes_context *ctx );
void esp_aes_free( esp_aes_context *ctx );
/**
* \brief AES key schedule (encryption)
* \brief AES set key schedule (encryption or decryption)
*
* \param ctx AES context to be initialized
* \param key encryption key
@@ -102,18 +95,7 @@ void esp_aes_free( esp_aes_context *ctx );
*
* \return 0 if successful, or ERR_AES_INVALID_KEY_LENGTH
*/
int esp_aes_setkey_enc( esp_aes_context *ctx, const unsigned char *key, unsigned int keybits );
/**
* \brief AES key schedule (decryption)
*
* \param ctx AES context to be initialized
* \param key decryption key
* \param keybits must be 128, 192 or 256
*
* \return 0 if successful, or ERR_AES_INVALID_KEY_LENGTH
*/
int esp_aes_setkey_dec( esp_aes_context *ctx, const unsigned char *key, unsigned int keybits );
int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, unsigned int keybits );
/**
* \brief AES-ECB block encryption/decryption