fix(core): use secure-unprivileged SAES XOR key for storage encryption

[no changelog]
tychovrahe/coresplit/merged
tychovrahe 2 weeks ago committed by cepetr
parent 14a89de6da
commit bb562525fa

@ -40,6 +40,7 @@ typedef enum {
MPU_MODE_SECRET, // + secret area (priviledeg RW)
MPU_MODE_STORAGE, // + both storage areas (privilehed RW)
MPU_MODE_ASSETS, // + assets (privileged RW)
MPU_MODE_SAES, // + unprivileged SAES code
MPU_MODE_APP, // + unprivileged DMA2D (RW) & Assets (RO)
} mpu_mode_t;

@ -24,10 +24,17 @@
#include <stddef.h>
#include <stdint.h>
// only some of the keys are supported depending on execution environment
typedef enum {
SECURE_AES_KEY_DHUK,
SECURE_AES_KEY_DHUK_SP, // secure-privileged
SECURE_AES_KEY_DHUK_SN, // secure-nonprivileged
SECURE_AES_KEY_DHUK_NP, // nonsecure-privileged
SECURE_AES_KEY_DHUK_NN, // nonsecure-nonprivileged
SECURE_AES_KEY_BHK,
SECURE_AES_KEY_XORK,
SECURE_AES_KEY_XORK_SP, // secure-privileged
SECURE_AES_KEY_XORK_SN, // secure-nonprivileged
SECURE_AES_KEY_XORK_NP, // nonsecure-privileged
SECURE_AES_KEY_XORK_NN, // nonsecure-nonprivileged
} secure_aes_keysel_t;
// Initializes secure AES module

@ -27,6 +27,8 @@ __attribute__((naked, no_stack_protector)) static uint32_t _invoke_app_callback(
__asm__ volatile(
"push {r1-r12, lr} \n"
"mrs r12, PSPLIM \n" // backup unprivileged stack lim
"push {r12} \n"
"mrs r12, PSP \n" // reserved frame on unprivileged stack (!@#
// TODO check PSP value???)
"push {r12} \n"
@ -86,8 +88,75 @@ __attribute__((naked, no_stack_protector)) void return_from_app_callback(
"MSR MSP, R1 \n"
"POP {R1} \n"
"MSR PSP, R1 \n"
"POP {R1} \n"
"MSR PSPLIM, R1 \n"
"POP {R1-R12, LR} \n"
"BX LR \n");
}
__attribute__((naked, no_stack_protector)) static uint32_t _invoke_unpriv(
uint32_t stack_addr, uint32_t stack_lim, void *callback) {
__asm__ volatile(
"push {r1-r12, lr} \n"
"mrs r12, PSPLIM \n" // backup unprivileged stack lim
"push {r12} \n"
"mrs r12, PSP \n" // backup unprivileged stack
"push {r12} \n"
"mov r12, r0 \n" // setup stack for unprivileged call inside
// kernel
"sub r12, r12, #32 \n"
"msr PSP, r12 \n"
"msr PSPLIM, r1 \n"
"mov r3, #0 \n"
"mov r4, r3 \n" // Clear registers r4-r11
"mov r5, r3 \n"
"mov r6, r3 \n"
"mov r7, r3 \n"
"mov r8, r3 \n"
"mov r9, r3 \n"
"mov r10, r3 \n"
"mov r11, r3 \n"
"str r3, [r12, #0] \n" // r0
"str r3, [r12, #4] \n" // r1"
"str r3, [r12, #8] \n" // r2"
"str r3, [r12, #12] \n" // r3"
"str r3, [r12, #16] \n" // r12"
"str r3, [r12, #20] \n" // lr"
"bic r3, r2, #1 \n"
"str r3, [r12, #24] \n" // return address
"ldr r1, = 0x01000000 \n"
"str r1, [r12, #28] \n" // xPSR
"ldr r1, = 0xE000EF34 \n" // FPU->FPPCCR
"ldr r0, [r1] \n"
"bic r0, r0, #1 \n" // Clear LSPACT to suppress lazy stacking to
"str r0, [r1] \n" // avoid potential PSP stack overwrite.
"mrs r1, CONTROL \n"
"bic r1, r1, #4 \n" // Clear FPCA to suppress lazy stacking to
"msr CONTROL, r1 \n" // avoid potential PSP stack overwrite.
// return to Secure Thread mode (use Secure PSP)
"ldr lr, = 0xFFFFFFFD \n"
"bx lr \n");
}
extern const void _eustack;
extern const void _sustack;
uint32_t invoke_unpriv(void *func) {
uint32_t *stack = (uint32_t *)&_eustack;
uint32_t *stack_lim = (uint32_t *)&_sustack;
uint32_t retval = _invoke_unpriv((uint32_t)stack, (uint32_t)stack_lim, func);
return retval;
}
#endif // SYSCALL_DISPATCH

@ -50,6 +50,9 @@ uint32_t invoke_app_callback(uint32_t args1, uint32_t arg2, uint32_t arg3,
void return_from_app_callback(uint32_t retval, uint32_t* msp);
// Invokes unprivileged function run
uint32_t invoke_unpriv(void* func);
#else // KERNEL_MODE
static inline uint32_t __attribute__((no_stack_protector))

@ -310,8 +310,11 @@ mpu_mode_t mpu_reconfig(mpu_mode_t mode) {
// clang-format off
switch (mode) {
case MPU_MODE_SAES:
SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals - SAES, TAMP
break;
default:
SET_REGION( 5, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Peripherals
SET_REGION( 5, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface
break;
}
// clang-format on
@ -341,6 +344,9 @@ mpu_mode_t mpu_reconfig(mpu_mode_t mode) {
case MPU_MODE_ASSETS:
SET_REGION( 6, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, NO );
break;
case MPU_MODE_SAES:
SET_REGION( 6, KERNEL_FLASH_U_START, KERNEL_FLASH_U_SIZE,FLASH_CODE, NO, YES ); // Unprivileged kernal flash
break;
case MPU_MODE_APP:
SET_REGION( 6, ASSETS_START, ASSETS_SIZE, FLASH_DATA, NO, YES );
break;
@ -356,8 +362,11 @@ mpu_mode_t mpu_reconfig(mpu_mode_t mode) {
// clang-format off
switch (mode) {
case MPU_MODE_APP:
// REGION ADDRESS SIZE TYPE WRITE UNPRIV
case MPU_MODE_SAES:
SET_REGION( 7, KERNEL_RAM_U_START, KERNEL_RAM_U_SIZE, SRAM, YES, YES ); // Unprivileged kernel SRAM
break;
case MPU_MODE_APP:
// DMA2D peripherals (Uprivileged, Read-Write, Non-Executable)
SET_REGION( 7, 0x5002B000, SIZE_3K, PERIPHERAL, YES, YES );
break;

@ -255,7 +255,8 @@ static void secret_optiga_cache(void) {
secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]) {
uint8_t secret_enc[SECRET_OPTIGA_KEY_LEN] = {0};
if (sectrue != secure_aes_ecb_encrypt_hw(secret, sizeof(secret_enc),
secret_enc, SECURE_AES_KEY_DHUK)) {
secret_enc,
SECURE_AES_KEY_DHUK_SP)) {
return secfalse;
}
secret_write(secret_enc, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
@ -282,7 +283,7 @@ secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]) {
}
secbool res = secure_aes_ecb_decrypt_hw(
(uint8_t *)secret, SECRET_OPTIGA_KEY_LEN, dest, SECURE_AES_KEY_DHUK);
(uint8_t *)secret, SECRET_OPTIGA_KEY_LEN, dest, SECURE_AES_KEY_DHUK_SP);
memzero(secret, sizeof(secret));
return res;

@ -17,33 +17,24 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mpu.h>
#include <secure_aes.h>
#include STM32_HAL_H
#include <stdio.h>
#include <stm32u5xx_hal_cryp.h>
#include <string.h>
#include "memzero.h"
#include "model.h"
#include "syscall.h"
#ifdef KERNEL_MODE
#include "memzero.h"
#define KERNEL_UNPRIVILEGED_SIZE 32
#define AES_BLOCK_SIZE 16
secbool secure_aes_init(void) {
RCC_OscInitTypeDef osc_init_def = {0};
osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_SHSI;
osc_init_def.SHSIState = RCC_SHSI_ON;
// Enable SHSI clock
if (HAL_RCC_OscConfig(&osc_init_def) != HAL_OK) {
return secfalse;
}
// Enable SAES peripheral clock
__HAL_RCC_SAES_CLK_ENABLE();
#ifdef KERNEL_MODE
return sectrue;
}
#include "irq.h"
static void secure_aes_load_bhk(void) {
TAMP->BKP0R;
@ -58,19 +49,182 @@ static void secure_aes_load_bhk(void) {
static uint32_t get_keysel(secure_aes_keysel_t key) {
switch (key) {
case SECURE_AES_KEY_DHUK:
case SECURE_AES_KEY_DHUK_SP:
case SECURE_AES_KEY_DHUK_SN:
case SECURE_AES_KEY_DHUK_NP:
case SECURE_AES_KEY_DHUK_NN:
return CRYP_KEYSEL_HW;
case SECURE_AES_KEY_BHK:
return CRYP_KEYSEL_SW;
case SECURE_AES_KEY_XORK:
case SECURE_AES_KEY_XORK_SP:
case SECURE_AES_KEY_XORK_SN:
case SECURE_AES_KEY_XORK_NP:
case SECURE_AES_KEY_XORK_NN:
return CRYP_KEYSEL_HSW;
default:
return 0;
}
}
static secbool is_key_supported(secure_aes_keysel_t key) {
switch (key) {
case SECURE_AES_KEY_DHUK_SP:
case SECURE_AES_KEY_BHK:
case SECURE_AES_KEY_XORK_SP:
return sectrue;
default:
return secfalse;
}
}
#ifdef SYSCALL_DISPATCH
__attribute__((section(".udata")))
uint32_t saes_input[KERNEL_UNPRIVILEGED_SIZE / sizeof(uint32_t)];
__attribute__((section(".udata")))
uint32_t saes_output[KERNEL_UNPRIVILEGED_SIZE / sizeof(uint32_t)];
__attribute__((section(".uflash"), used, naked, no_stack_protector)) uint32_t
saes_invoke(void) {
// reset the key loaded in SAES
MODIFY_REG(SAES->CR, AES_CR_KEYSEL, CRYP_KEYSEL_NORMAL);
while (HAL_IS_BIT_SET(SAES->SR, CRYP_FLAG_BUSY)) {
}
while (HAL_IS_BIT_SET(SAES->ISR, CRYP_FLAG_RNGEIF)) {
}
MODIFY_REG(SAES->CR,
AES_CR_KMOD | AES_CR_DATATYPE | AES_CR_KEYSIZE | AES_CR_CHMOD |
AES_CR_KEYSEL | AES_CR_KEYPROT,
CRYP_KEYMODE_NORMAL | CRYP_NO_SWAP | CRYP_KEYSIZE_256B |
CRYP_AES_ECB | CRYP_KEYSEL_HSW | CRYP_KEYPROT_DISABLE);
TAMP->BKP0R;
TAMP->BKP1R;
TAMP->BKP2R;
TAMP->BKP3R;
TAMP->BKP4R;
TAMP->BKP5R;
TAMP->BKP6R;
TAMP->BKP7R;
#define CRYP_OPERATINGMODE_ENCRYPT 0x00000000U /*!< Encryption mode(Mode 1) */
/* Set the operating mode and normal key selection */
MODIFY_REG(SAES->CR, AES_CR_MODE | AES_CR_KMOD,
CRYP_OPERATINGMODE_ENCRYPT | CRYP_KEYMODE_NORMAL);
SAES->CR |= AES_CR_EN;
for (int j = 0; j < KERNEL_UNPRIVILEGED_SIZE / AES_BLOCK_SIZE; j++) {
/* Write the input block in the IN FIFO */
SAES->DINR = saes_input[j * 4 + 0];
SAES->DINR = saes_input[j * 4 + 1];
SAES->DINR = saes_input[j * 4 + 2];
SAES->DINR = saes_input[j * 4 + 3];
while (HAL_IS_BIT_CLR(SAES->ISR, AES_ISR_CCF)) {
}
/* Clear CCF Flag */
SET_BIT(SAES->ICR, CRYP_CLEAR_CCF);
/* Read the output block from the output FIFO */
for (int i = 0U; i < 4U; i++) {
saes_output[j * 4 + i] = SAES->DOUTR;
}
}
SAES->CR &= ~AES_CR_EN;
// reset the key loaded in SAES
MODIFY_REG(SAES->CR, AES_CR_KEYSEL, CRYP_KEYSEL_NORMAL);
register uint32_t r0 __asm__("r0") = sectrue;
__asm__ volatile("svc %[svid]\n"
:
: [svid] "i"(SVC_CALLBACK_RETURN), "r"(r0)
: "memory");
return 0;
}
extern uint32_t sram2_u_start;
extern uint32_t sram2_u_end;
secbool unpriv_encrypt(const uint8_t* input, size_t size, uint8_t* output,
secure_aes_keysel_t key) {
if (size != KERNEL_UNPRIVILEGED_SIZE) {
return secfalse;
}
if (key != SECURE_AES_KEY_XORK_SN) {
return secfalse;
}
NVIC_SetPriority(SVCall_IRQn, IRQ_PRI_HIGHEST);
uint32_t basepri = __get_BASEPRI();
__set_BASEPRI(1);
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SAES);
for (uint32_t* m = &sram2_u_start; m < &sram2_u_end; m++) {
*m = 0;
}
for (int i = 0; i < KERNEL_UNPRIVILEGED_SIZE; i++) {
((uint8_t*)saes_input)[i] = input[i];
}
SAES->CR |= AES_CR_KEYSEL_0;
__HAL_RCC_SAES_CLK_DISABLE();
__HAL_RCC_SAES_FORCE_RESET();
__HAL_RCC_SAES_RELEASE_RESET();
__HAL_RCC_SAES_CLK_ENABLE();
secbool retval = invoke_unpriv(saes_invoke);
__HAL_RCC_SAES_CLK_DISABLE();
__HAL_RCC_SAES_FORCE_RESET();
__HAL_RCC_SAES_RELEASE_RESET();
__HAL_RCC_SAES_CLK_ENABLE();
for (int i = 0; i < KERNEL_UNPRIVILEGED_SIZE; i++) {
output[i] = ((uint8_t*)saes_output)[i];
}
for (int i = 0; i < KERNEL_UNPRIVILEGED_SIZE; i++) {
((uint8_t*)saes_input)[i] = 0;
((uint8_t*)saes_output)[i] = 0;
}
for (uint32_t* m = &sram2_u_start; m < &sram2_u_end; m++) {
*m = 0;
}
mpu_reconfig(mpu_mode);
__set_BASEPRI(basepri);
NVIC_SetPriority(SVCall_IRQn, IRQ_PRI_LOWEST);
return retval;
}
#endif
secbool secure_aes_ecb_encrypt_hw(const uint8_t* input, size_t size,
uint8_t* output, secure_aes_keysel_t key) {
#ifdef SYSCALL_DISPATCH
if (key == SECURE_AES_KEY_XORK_SN) {
return unpriv_encrypt(input, size, output, key);
}
#endif
if (sectrue != is_key_supported(key)) {
return secfalse;
}
CRYP_HandleTypeDef hcryp = {0};
uint32_t iv[] = {0, 0, 0, 0};
@ -136,8 +290,28 @@ secbool secure_aes_ecb_encrypt_hw(const uint8_t* input, size_t size,
return sectrue;
}
secbool secure_aes_init(void) {
RCC_OscInitTypeDef osc_init_def = {0};
osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_SHSI;
osc_init_def.SHSIState = RCC_SHSI_ON;
// Enable SHSI clock
if (HAL_RCC_OscConfig(&osc_init_def) != HAL_OK) {
return secfalse;
}
// Enable SAES peripheral clock
__HAL_RCC_SAES_CLK_ENABLE();
return sectrue;
}
secbool secure_aes_ecb_decrypt_hw(const uint8_t* input, size_t size,
uint8_t* output, secure_aes_keysel_t key) {
if (sectrue != is_key_supported(key)) {
return secfalse;
}
CRYP_HandleTypeDef hcryp = {0};
uint32_t iv[] = {0, 0, 0, 0};
@ -202,4 +376,4 @@ secbool secure_aes_ecb_decrypt_hw(const uint8_t* input, size_t size,
return sectrue;
}
#endif // KERNEL_MODE
#endif

@ -559,7 +559,7 @@ static void derive_kek_v4(const uint8_t *pin, size_t pin_len,
uint8_t pre_kek[SHA256_DIGEST_LENGTH] = {0};
pbkdf2_hmac_sha256_Final(&ctx, pre_kek);
ensure(secure_aes_ecb_encrypt_hw(pre_kek, SHA256_DIGEST_LENGTH, kek,
SECURE_AES_KEY_XORK),
SECURE_AES_KEY_XORK_SN),
"secure_aes derive kek failed");
memzero(pre_kek, sizeof(pre_kek));
#else
@ -617,7 +617,7 @@ static void stretch_pin(const uint8_t *pin, size_t pin_len,
uint8_t stretched_pin_tmp[SHA256_DIGEST_LENGTH] = {0};
pbkdf2_hmac_sha256_Final(&ctx, stretched_pin_tmp);
ensure(secure_aes_ecb_encrypt_hw(stretched_pin_tmp, SHA256_DIGEST_LENGTH,
stretched_pin, SECURE_AES_KEY_XORK),
stretched_pin, SECURE_AES_KEY_XORK_SN),
"secure_aes pin stretch failed");
memzero(stretched_pin_tmp, sizeof(stretched_pin_tmp));
#else

Loading…
Cancel
Save