|
|
|
@ -11,14 +11,15 @@
|
|
|
|
|
static secbool bootloader_locked = secfalse;
|
|
|
|
|
|
|
|
|
|
secbool secret_verify_header(void) {
|
|
|
|
|
uint8_t header[sizeof(SECRET_HEADER_MAGIC)] = {0};
|
|
|
|
|
uint8_t *addr = (uint8_t *)flash_area_get_address(
|
|
|
|
|
&SECRET_AREA, 0, sizeof(SECRET_HEADER_MAGIC));
|
|
|
|
|
|
|
|
|
|
memcpy(header,
|
|
|
|
|
flash_area_get_address(&SECRET_AREA, 0, sizeof(SECRET_HEADER_MAGIC)),
|
|
|
|
|
sizeof(SECRET_HEADER_MAGIC));
|
|
|
|
|
if (addr == NULL) {
|
|
|
|
|
return secfalse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bootloader_locked =
|
|
|
|
|
memcmp(header, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0
|
|
|
|
|
memcmp(addr, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0
|
|
|
|
|
? sectrue
|
|
|
|
|
: secfalse;
|
|
|
|
|
return bootloader_locked;
|
|
|
|
@ -63,41 +64,60 @@ secbool secret_read(uint8_t *data, uint32_t offset, uint32_t len) {
|
|
|
|
|
if (sectrue != secret_verify_header()) {
|
|
|
|
|
return secfalse;
|
|
|
|
|
}
|
|
|
|
|
uint8_t *addr = (uint8_t *)flash_area_get_address(&SECRET_AREA, offset, len);
|
|
|
|
|
|
|
|
|
|
memcpy(data, flash_area_get_address(&SECRET_AREA, offset, len), len);
|
|
|
|
|
if (addr == NULL) {
|
|
|
|
|
return secfalse;
|
|
|
|
|
}
|
|
|
|
|
memcpy(data, addr, len);
|
|
|
|
|
|
|
|
|
|
return sectrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void secret_hide(void) {
|
|
|
|
|
static void secret_disable_access(void) {
|
|
|
|
|
FLASH->SECHDPCR |= FLASH_SECHDPCR_HDP1_ACCDIS_Msk;
|
|
|
|
|
FLASH->SECHDPCR |= FLASH_SECHDPCR_HDP2_ACCDIS_Msk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void secret_bhk_lock(void) {
|
|
|
|
|
// Locks the BHK register. Once locked, the BHK register can't be accessed by
|
|
|
|
|
// the software. BHK is made available to the SAES peripheral
|
|
|
|
|
static void secret_bhk_lock(void) {
|
|
|
|
|
TAMP_S->SECCFGR = 8 << TAMP_SECCFGR_BKPRWSEC_Pos | TAMP_SECCFGR_BHKLOCK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
secbool secret_bhk_locked(void) {
|
|
|
|
|
// Verifies that access to the register has been disabled
|
|
|
|
|
static secbool secret_bhk_locked(void) {
|
|
|
|
|
return ((TAMP_S->SECCFGR & TAMP_SECCFGR_BHKLOCK) == TAMP_SECCFGR_BHKLOCK) *
|
|
|
|
|
sectrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static secbool secret_present(uint32_t offset, uint32_t len) {
|
|
|
|
|
uint8_t *optiga_secret =
|
|
|
|
|
uint8_t *secret =
|
|
|
|
|
(uint8_t *)flash_area_get_address(&SECRET_AREA, offset, len);
|
|
|
|
|
|
|
|
|
|
int optiga_secret_empty_bytes = 0;
|
|
|
|
|
if (secret == NULL) {
|
|
|
|
|
return secfalse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int secret_empty_bytes = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
|
if (optiga_secret[i] == 0xFF) {
|
|
|
|
|
optiga_secret_empty_bytes++;
|
|
|
|
|
if (secret[i] == 0xFF) {
|
|
|
|
|
secret_empty_bytes++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return sectrue * (optiga_secret_empty_bytes != len);
|
|
|
|
|
return sectrue * (secret_empty_bytes != len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void secret_bhk_provision(void) {
|
|
|
|
|
// Provision the secret BHK from the secret storage to the BHK register
|
|
|
|
|
// which makes the BHK usable for encryption by the firmware, without having
|
|
|
|
|
// read access to it.
|
|
|
|
|
static void secret_bhk_load(void) {
|
|
|
|
|
if (sectrue == secret_bhk_locked()) {
|
|
|
|
|
delete_secrets();
|
|
|
|
|
NVIC_SystemReset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t secret[SECRET_BHK_LEN / sizeof(uint32_t)] = {0};
|
|
|
|
|
|
|
|
|
|
if (sectrue != secret_present(SECRET_BHK_OFFSET, SECRET_BHK_LEN)) {
|
|
|
|
@ -139,23 +159,18 @@ void secret_bhk_regenerate(void) {
|
|
|
|
|
ensure(flash_lock_write(), "Failed regenerating BHK");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
secbool secret_optiga_present(void) {
|
|
|
|
|
#ifdef USE_OPTIGA
|
|
|
|
|
// Checks that the optiga pairing secret is present in the secret storage.
|
|
|
|
|
// This functions only works when software has access to the secret storage,
|
|
|
|
|
// i.e. in bootloader. Access to secret storage is restricted by calling
|
|
|
|
|
// secret_hide.
|
|
|
|
|
static secbool secret_optiga_present(void) {
|
|
|
|
|
return secret_present(SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)) {
|
|
|
|
|
return secfalse;
|
|
|
|
|
}
|
|
|
|
|
secret_write(secret_enc, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
|
|
|
|
|
memzero(secret_enc, sizeof(secret_enc));
|
|
|
|
|
secret_optiga_backup();
|
|
|
|
|
return sectrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void secret_optiga_backup(void) {
|
|
|
|
|
// Backs up the optiga pairing secret from the secret storage to the backup
|
|
|
|
|
// register
|
|
|
|
|
static void secret_optiga_cache(void) {
|
|
|
|
|
uint32_t secret[SECRET_OPTIGA_KEY_LEN / sizeof(uint32_t)] = {0};
|
|
|
|
|
secbool ok = secret_read((uint8_t *)secret, SECRET_OPTIGA_KEY_OFFSET,
|
|
|
|
|
SECRET_OPTIGA_KEY_LEN);
|
|
|
|
@ -175,6 +190,18 @@ void secret_optiga_backup(void) {
|
|
|
|
|
memzero(secret, sizeof(secret));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)) {
|
|
|
|
|
return secfalse;
|
|
|
|
|
}
|
|
|
|
|
secret_write(secret_enc, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
|
|
|
|
|
memzero(secret_enc, sizeof(secret_enc));
|
|
|
|
|
secret_optiga_cache();
|
|
|
|
|
return sectrue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]) {
|
|
|
|
|
uint32_t secret[SECRET_OPTIGA_KEY_LEN / sizeof(uint32_t)] = {0};
|
|
|
|
|
|
|
|
|
@ -199,14 +226,56 @@ secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]) {
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void secret_optiga_hide(void) {
|
|
|
|
|
// Deletes the optiga pairing secret from the register
|
|
|
|
|
static void secret_optiga_uncache(void) {
|
|
|
|
|
volatile uint32_t *reg1 = &TAMP->BKP8R;
|
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
|
|
|
*reg1 = 0;
|
|
|
|
|
reg1++;
|
|
|
|
|
reg1[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void secret_erase(void) {
|
|
|
|
|
ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void secret_show_install_restricted_screen(void) {
|
|
|
|
|
// this should never happen on U5
|
|
|
|
|
__fatal_error("INTERNAL ERROR", "Install restricted", __FILE__, __LINE__,
|
|
|
|
|
__func__);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void secret_prepare_fw(secbool allow_run_with_secret, secbool trust_all) {
|
|
|
|
|
/**
|
|
|
|
|
* The BHK is copied to the backup registers, which are accessible by the SAES
|
|
|
|
|
* peripheral. The BHK register is locked, so the BHK can't be accessed by the
|
|
|
|
|
* software.
|
|
|
|
|
*
|
|
|
|
|
* When optiga is paired, pairing secret is copied to the backup registers
|
|
|
|
|
* and access to the secret storage is disabled. Otherwise, access to the
|
|
|
|
|
* secret storage kept to allow optiga pairing in prodtest.
|
|
|
|
|
*
|
|
|
|
|
* Access to the secret storage is disabled for non-official firmware in
|
|
|
|
|
* all-cases.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
secret_bhk_load();
|
|
|
|
|
secret_bhk_lock();
|
|
|
|
|
#ifdef USE_OPTIGA
|
|
|
|
|
secret_optiga_uncache();
|
|
|
|
|
if (sectrue == allow_run_with_secret) {
|
|
|
|
|
if (secfalse != secret_optiga_present()) {
|
|
|
|
|
secret_optiga_cache();
|
|
|
|
|
secret_disable_access();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
secret_disable_access();
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
secret_disable_access();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (sectrue != trust_all) {
|
|
|
|
|
secret_disable_access();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|