2018-02-24 00:09:44 +00:00
|
|
|
#include <string.h>
|
2018-02-19 09:27:50 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
#include "utils.h"
|
2018-02-24 15:25:38 +00:00
|
|
|
#include "interrupt.h"
|
2018-02-24 16:13:42 +00:00
|
|
|
#include "se.h"
|
|
|
|
#include "memory_map.h"
|
2018-02-27 21:29:47 +00:00
|
|
|
#include "arm.h"
|
2018-02-17 22:54:00 +00:00
|
|
|
#include "se.h"
|
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
void trigger_se_rsa_op(void *buf, size_t size);
|
2018-02-19 09:27:50 +00:00
|
|
|
void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size);
|
2018-02-17 22:54:00 +00:00
|
|
|
|
|
|
|
/* Globals for driver. */
|
2018-02-26 08:42:21 +00:00
|
|
|
static unsigned int (*g_se_callback)(void);
|
2018-02-17 22:54:00 +00:00
|
|
|
|
2018-02-26 08:42:21 +00:00
|
|
|
static unsigned int g_se_modulus_sizes[KEYSLOT_RSA_MAX];
|
|
|
|
static unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX];
|
2018-02-17 22:54:00 +00:00
|
|
|
|
2018-02-19 21:00:12 +00:00
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
/* Initialize a SE linked list. */
|
|
|
|
void ll_init(se_ll_t *ll, void *buffer, size_t size) {
|
|
|
|
ll->num_entries = 0; /* 1 Entry. */
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
if (buffer != NULL) {
|
2018-02-25 19:00:50 +00:00
|
|
|
ll->addr_info.address = (uint32_t) get_physical_address(buffer);
|
2018-02-19 09:27:50 +00:00
|
|
|
ll->addr_info.size = (uint32_t) size;
|
|
|
|
} else {
|
|
|
|
ll->addr_info.address = 0;
|
|
|
|
ll->addr_info.size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
flush_dcache_range((uint8_t *)ll, (uint8_t *)ll + sizeof(*ll));
|
|
|
|
}
|
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
void set_security_engine_callback(unsigned int (*callback)(void)) {
|
|
|
|
if (callback == NULL || g_se_callback != NULL) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
g_se_callback = callback;
|
|
|
|
}
|
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
/* Fires on Security Engine operation completion. */
|
|
|
|
void se_operation_completed(void) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->INT_ENABLE_REG = 0;
|
2018-02-19 09:27:50 +00:00
|
|
|
if (g_se_callback != NULL) {
|
|
|
|
g_se_callback();
|
|
|
|
g_se_callback = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-28 01:07:30 +00:00
|
|
|
void se_check_error_status_reg(void) {
|
|
|
|
if (SECURITY_ENGINE->ERR_STATUS_REG) {
|
|
|
|
generic_panic();
|
|
|
|
}
|
|
|
|
}
|
2018-02-21 18:57:51 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
void se_check_for_error(void) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (SECURITY_ENGINE->INT_STATUS_REG & 0x10000 || SECURITY_ENGINE->FLAGS_REG & 3 || SECURITY_ENGINE->ERR_STATUS_REG) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-25 19:00:50 +00:00
|
|
|
void se_trigger_interrupt(void) {
|
2018-02-24 15:25:38 +00:00
|
|
|
intr_set_pending(INTERRUPT_ID_USER_SECURITY_ENGINE);
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
|
|
|
|
2018-02-21 18:57:51 +00:00
|
|
|
void se_verify_flags_cleared(void) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (SECURITY_ENGINE->FLAGS_REG & 3) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-21 18:57:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
/* Set the flags for an AES keyslot. */
|
|
|
|
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
/* Misc flags. */
|
|
|
|
if (flags & ~0x80) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->AES_KEYSLOT_FLAGS[keyslot] = ~flags;
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
/* Disable keyslot reads. */
|
|
|
|
if (flags & 0x80) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->AES_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the flags for an RSA keyslot. */
|
|
|
|
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_RSA_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
/* Misc flags. */
|
|
|
|
if (flags & ~0x80) {
|
|
|
|
/* TODO: Why are flags assigned this way? */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->RSA_KEYSLOT_FLAGS[keyslot] = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
/* Disable keyslot reads. */
|
|
|
|
if (flags & 0x80) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->RSA_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear_aes_keyslot(unsigned int keyslot) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
/* Zero out the whole keyslot and IV. */
|
|
|
|
for (unsigned int i = 0; i < 0x10; i++) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
|
|
|
|
SECURITY_ENGINE->AES_KEYTABLE_DATA = 0;
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear_rsa_keyslot(unsigned int keyslot) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_RSA_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
/* Zero out the whole keyslot. */
|
|
|
|
for (unsigned int i = 0; i < 0x40; i++) {
|
|
|
|
/* Select Keyslot Modulus[i] */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->RSA_KEYTABLE_ADDR = (keyslot << 7) | i | 0x40;
|
|
|
|
SECURITY_ENGINE->RSA_KEYTABLE_DATA = 0;
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
|
|
|
for (unsigned int i = 0; i < 0x40; i++) {
|
|
|
|
/* Select Keyslot Expontent[i] */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
|
|
|
|
SECURITY_ENGINE->RSA_KEYTABLE_DATA = 0;
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
for (size_t i = 0; i < (key_size >> 2); i++) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
|
|
|
|
SECURITY_ENGINE->AES_KEYTABLE_DATA = read32le(key, 4 * i);
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
for (size_t i = 0; i < (modulus_size >> 2); i++) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->RSA_KEYTABLE_ADDR = (keyslot << 7) | 0x40 | i;
|
|
|
|
SECURITY_ENGINE->RSA_KEYTABLE_DATA = read32be(modulus, 4 * i);
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
for (size_t i = 0; i < (exp_size >> 2); i++) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
|
|
|
|
SECURITY_ENGINE->RSA_KEYTABLE_DATA = read32be(exponent, 4 * i);
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
g_se_modulus_sizes[keyslot] = modulus_size;
|
|
|
|
g_se_exp_sizes[keyslot] = exp_size;
|
|
|
|
}
|
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
for (size_t i = 0; i < (iv_size >> 2); i++) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
|
|
|
|
SECURITY_ENGINE->AES_KEYTABLE_DATA = read32le(iv, 4 * i);
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
void clear_aes_keyslot_iv(unsigned int keyslot) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
for (size_t i = 0; i < (0x10 >> 2); i++) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->AES_KEYTABLE_ADDR = (keyslot << 4) | 8;
|
|
|
|
SECURITY_ENGINE->AES_KEYTABLE_DATA = 0;
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
void set_se_ctr(const void *ctr) {
|
2018-02-17 22:54:00 +00:00
|
|
|
for (unsigned int i = 0; i < 4; i++) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSIZE_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB);
|
|
|
|
SECURITY_ENGINE->CRYPTO_REG = keyslot_src << 24;
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
SECURITY_ENGINE->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8;
|
2018-02-18 23:02:37 +00:00
|
|
|
|
|
|
|
flush_dcache_range(wrapped_key, (const uint8_t *)wrapped_key + wrapped_key_size);
|
2018-02-28 03:59:51 +00:00
|
|
|
trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size);
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
|
|
|
|
2018-02-23 03:58:39 +00:00
|
|
|
void se_aes_crypt_insecure_internal(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, unsigned int crypt_config, bool encrypt, unsigned int (*callback)(void)) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-19 21:00:12 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-19 21:00:12 +00:00
|
|
|
if (size == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-19 21:00:12 +00:00
|
|
|
/* Setup Config register. */
|
|
|
|
if (encrypt) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
|
2018-02-19 21:00:12 +00:00
|
|
|
} else {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY);
|
2018-02-19 21:00:12 +00:00
|
|
|
}
|
2018-02-25 19:00:50 +00:00
|
|
|
|
2018-02-19 21:00:12 +00:00
|
|
|
/* Setup Crypto register. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CRYPTO_REG = crypt_config | (keyslot << 24) | (encrypt << 8);
|
2018-02-25 19:00:50 +00:00
|
|
|
|
2018-02-19 21:00:12 +00:00
|
|
|
/* Mark this encryption as insecure -- this makes the SE not a secure busmaster. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CRYPTO_REG |= 0x80000000;
|
2018-02-25 19:00:50 +00:00
|
|
|
|
2018-02-19 21:00:12 +00:00
|
|
|
/* Appropriate number of blocks. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = (size >> 4) - 1;
|
2018-02-25 19:00:50 +00:00
|
|
|
|
2018-02-19 21:00:12 +00:00
|
|
|
/* Set the callback, for after the async operation. */
|
|
|
|
set_security_engine_callback(callback);
|
2018-02-25 19:00:50 +00:00
|
|
|
|
2018-02-19 21:26:37 +00:00
|
|
|
/* Enable SE Interrupt firing for async op. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->INT_ENABLE_REG = 0x10;
|
2018-02-25 19:00:50 +00:00
|
|
|
|
2018-02-19 21:00:12 +00:00
|
|
|
/* Setup Input/Output lists */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->IN_LL_ADDR_REG = in_ll_paddr;
|
|
|
|
SECURITY_ENGINE->OUT_LL_ADDR_REG = out_ll_paddr;
|
2018-02-25 19:00:50 +00:00
|
|
|
|
2018-02-19 21:00:12 +00:00
|
|
|
/* Set registers for operation. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->ERR_STATUS_REG = SECURITY_ENGINE->ERR_STATUS_REG;
|
|
|
|
SECURITY_ENGINE->INT_STATUS_REG = SECURITY_ENGINE->INT_STATUS_REG;
|
|
|
|
SECURITY_ENGINE->OPERATION_REG = 1;
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-19 21:00:12 +00:00
|
|
|
/* Ensure writes go through. */
|
|
|
|
__asm__ __volatile__ ("dsb ish" : : : "memory");
|
|
|
|
}
|
|
|
|
|
|
|
|
void se_aes_ctr_crypt_insecure(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, const void *ctr, unsigned int (*callback)(void)) {
|
|
|
|
/* Unknown what this write does, but official code writes it for CTR mode. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->_0x80C = 1;
|
2018-02-19 21:00:12 +00:00
|
|
|
set_se_ctr(ctr);
|
2018-02-23 03:58:39 +00:00
|
|
|
se_aes_crypt_insecure_internal(keyslot, out_ll_paddr, in_ll_paddr, size, 0x81E, true, callback);
|
2018-02-19 21:00:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void se_aes_cbc_encrypt_insecure(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, const void *iv, unsigned int (*callback)(void)) {
|
|
|
|
set_aes_keyslot_iv(keyslot, iv, 0x10);
|
2018-02-23 03:58:39 +00:00
|
|
|
se_aes_crypt_insecure_internal(keyslot, out_ll_paddr, in_ll_paddr, size, 0x44, true, callback);
|
2018-02-19 21:00:12 +00:00
|
|
|
}
|
|
|
|
|
2018-02-26 21:09:35 +00:00
|
|
|
void se_aes_cbc_decrypt_insecure(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, const void *iv, unsigned int (*callback)(void)) {
|
2018-02-19 21:00:12 +00:00
|
|
|
set_aes_keyslot_iv(keyslot, iv, 0x10);
|
2018-02-23 03:58:39 +00:00
|
|
|
se_aes_crypt_insecure_internal(keyslot, out_ll_paddr, in_ll_paddr, size, 0x66, false, callback);
|
2018-02-19 21:00:12 +00:00
|
|
|
}
|
2018-02-17 22:54:00 +00:00
|
|
|
|
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void)) {
|
|
|
|
uint8_t stack_buf[KEYSIZE_RSA_MAX];
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_RSA_MAX || size > KEYSIZE_RSA_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
/* Endian swap the input. */
|
2018-02-18 23:02:37 +00:00
|
|
|
for (size_t i = size; i > 0; i--) {
|
|
|
|
stack_buf[i] = *((uint8_t *)buf + size - i);
|
2018-02-17 22:54:00 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-18 23:02:37 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_RSA | DST_RSAREG);
|
|
|
|
SECURITY_ENGINE->RSA_CONFIG = keyslot << 24;
|
|
|
|
SECURITY_ENGINE->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1;
|
|
|
|
SECURITY_ENGINE->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2;
|
2018-02-18 23:02:37 +00:00
|
|
|
|
2018-02-17 22:54:00 +00:00
|
|
|
set_security_engine_callback(callback);
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-19 21:26:37 +00:00
|
|
|
/* Enable SE Interrupt firing for async op. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->INT_ENABLE_REG = 0x10;
|
2018-02-18 23:02:37 +00:00
|
|
|
|
|
|
|
flush_dcache_range(stack_buf, stack_buf + KEYSIZE_RSA_MAX);
|
2018-02-17 22:54:00 +00:00
|
|
|
trigger_se_rsa_op(stack_buf, size);
|
2018-02-18 23:02:37 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
while (!(SECURITY_ENGINE->INT_STATUS_REG & 2)) { /* Wait a while */ }
|
2018-02-18 23:02:37 +00:00
|
|
|
}
|
2018-02-19 09:27:50 +00:00
|
|
|
|
2018-02-23 01:05:22 +00:00
|
|
|
void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
|
|
uint8_t stack_buf[KEYSIZE_RSA_MAX];
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_RSA_MAX || src_size > KEYSIZE_RSA_MAX || dst_size > KEYSIZE_RSA_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-23 01:05:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Endian swap the input. */
|
2018-02-23 07:12:44 +00:00
|
|
|
for (size_t i = src_size; i > 0; i--) {
|
|
|
|
stack_buf[i] = *((uint8_t *)src + src_size - i);
|
2018-02-23 01:05:22 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_RSA | DST_RSAREG);
|
|
|
|
SECURITY_ENGINE->RSA_CONFIG = keyslot << 24;
|
|
|
|
SECURITY_ENGINE->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1;
|
|
|
|
SECURITY_ENGINE->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2;
|
2018-02-23 01:05:22 +00:00
|
|
|
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:05:22 +00:00
|
|
|
flush_dcache_range(stack_buf, stack_buf + KEYSIZE_RSA_MAX);
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, NULL, 0, stack_buf, src_size);
|
2018-02-23 01:05:22 +00:00
|
|
|
se_get_exp_mod_output(dst, dst_size);
|
|
|
|
}
|
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
void se_get_exp_mod_output(void *buf, size_t size) {
|
|
|
|
size_t num_dwords = (size >> 2);
|
|
|
|
if (num_dwords < 1) {
|
|
|
|
return;
|
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
uint32_t *p_out = ((uint32_t *)buf) + num_dwords - 1;
|
2018-02-23 07:12:44 +00:00
|
|
|
uint32_t offset = 0;
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
/* Copy endian swapped output. */
|
|
|
|
while (num_dwords) {
|
2018-02-23 01:50:19 +00:00
|
|
|
*p_out = read32be(SECURITY_ENGINE->RSA_OUTPUT, offset);
|
2018-02-19 09:27:50 +00:00
|
|
|
offset += 4;
|
|
|
|
p_out--;
|
|
|
|
num_dwords--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void trigger_se_rsa_op(void *buf, size_t size) {
|
|
|
|
se_ll_t in_ll;
|
2018-02-25 19:00:50 +00:00
|
|
|
ll_init(&in_ll, (void *)buf, size);
|
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
/* Set the input LL. */
|
2018-02-26 21:09:35 +00:00
|
|
|
SECURITY_ENGINE->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll);
|
2018-02-25 19:00:50 +00:00
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
/* Set registers for operation. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->ERR_STATUS_REG = SECURITY_ENGINE->ERR_STATUS_REG;
|
|
|
|
SECURITY_ENGINE->INT_STATUS_REG = SECURITY_ENGINE->INT_STATUS_REG;
|
|
|
|
SECURITY_ENGINE->OPERATION_REG = 1;
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
/* Ensure writes go through. */
|
|
|
|
__asm__ __volatile__ ("dsb ish" : : : "memory");
|
|
|
|
}
|
|
|
|
|
|
|
|
void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
|
|
se_ll_t in_ll;
|
|
|
|
se_ll_t out_ll;
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-25 19:00:50 +00:00
|
|
|
ll_init(&in_ll, (void *)src, src_size);
|
2018-02-19 09:27:50 +00:00
|
|
|
ll_init(&out_ll, dst, dst_size);
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
/* Set the LLs. */
|
2018-02-26 21:09:35 +00:00
|
|
|
SECURITY_ENGINE->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll);
|
|
|
|
SECURITY_ENGINE->OUT_LL_ADDR_REG = (uint32_t) get_physical_address(&out_ll);
|
|
|
|
|
2018-02-19 09:27:50 +00:00
|
|
|
/* Set registers for operation. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->ERR_STATUS_REG = SECURITY_ENGINE->ERR_STATUS_REG;
|
|
|
|
SECURITY_ENGINE->INT_STATUS_REG = SECURITY_ENGINE->INT_STATUS_REG;
|
|
|
|
SECURITY_ENGINE->OPERATION_REG = op;
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
while (!(SECURITY_ENGINE->INT_STATUS_REG & 0x10)) { /* Wait a while */ }
|
2018-02-19 09:27:50 +00:00
|
|
|
se_check_for_error();
|
|
|
|
}
|
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
|
|
|
|
/* Secure AES Functionality. */
|
|
|
|
void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
2018-02-26 05:12:49 +00:00
|
|
|
uint8_t block[0x10] = {0};
|
2018-02-23 00:17:12 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
if (src_size > sizeof(block) || dst_size > sizeof(block)) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-19 09:27:50 +00:00
|
|
|
}
|
2018-02-26 05:12:49 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Load src data into block. */
|
|
|
|
memcpy(block, src, src_size);
|
|
|
|
flush_dcache_range(block, block + sizeof(block));
|
2018-02-26 05:12:49 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Trigger AES operation. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block));
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Copy output data into dst. */
|
|
|
|
flush_dcache_range(block, block + sizeof(block));
|
|
|
|
memcpy(dst, block, dst_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-19 09:27:50 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
unsigned int num_blocks = src_size >> 4;
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Unknown what this write does, but official code writes it for CTR mode. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->_0x80C = 1;
|
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
|
|
|
|
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x91E;
|
2018-02-23 07:12:44 +00:00
|
|
|
set_se_ctr(ctr);
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Handle any aligned blocks. */
|
|
|
|
size_t aligned_size = (size_t)num_blocks << 4;
|
|
|
|
if (aligned_size) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 1;
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, dst, dst_size, src, aligned_size);
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Handle final, unaligned block. */
|
|
|
|
if (aligned_size < dst_size && aligned_size < src_size) {
|
|
|
|
size_t last_block_size = dst_size - aligned_size;
|
|
|
|
if (src_size < dst_size) {
|
|
|
|
last_block_size = src_size - aligned_size;
|
|
|
|
}
|
2018-02-25 19:00:50 +00:00
|
|
|
se_perform_aes_block_operation(dst + aligned_size, last_block_size, (uint8_t *)src + aligned_size, src_size - aligned_size);
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
2018-02-19 09:27:50 +00:00
|
|
|
}
|
2018-02-23 00:17:12 +00:00
|
|
|
|
|
|
|
void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Set configuration high (256-bit vs 128-bit) based on parameter. */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (config_high << 16);
|
|
|
|
SECURITY_ENGINE->CRYPTO_REG = keyslot << 24;
|
2018-02-23 07:12:44 +00:00
|
|
|
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
|
2018-02-23 00:17:12 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
|
|
se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
|
|
se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0x202);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY);
|
|
|
|
SECURITY_ENGINE->CRYPTO_REG = keyslot << 24;
|
2018-02-23 07:12:44 +00:00
|
|
|
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void shift_left_xor_rb(uint8_t *key) {
|
|
|
|
uint8_t prev_high_bit = 0;
|
2018-02-23 02:03:05 +00:00
|
|
|
for (unsigned int i = 0; i < 0x10; i++) {
|
|
|
|
uint8_t cur_byte = key[0xF - i];
|
|
|
|
key[0xF - i] = (cur_byte << 1) | (prev_high_bit);
|
2018-02-26 21:09:35 +00:00
|
|
|
prev_high_bit = cur_byte >> 7;
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
|
|
|
if (prev_high_bit) {
|
|
|
|
key[0xF] ^= 0x87;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Generate the derived key, to be XOR'd with final output block. */
|
|
|
|
uint8_t derived_key[0x10];
|
|
|
|
memset(derived_key, 0, sizeof(derived_key));
|
|
|
|
se_aes_128_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key));
|
|
|
|
shift_left_xor_rb(derived_key);
|
|
|
|
if (data_size & 0xF) {
|
|
|
|
shift_left_xor_rb(derived_key);
|
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
|
|
|
|
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | (0x145);
|
2018-02-23 00:17:12 +00:00
|
|
|
clear_aes_keyslot_iv(keyslot);
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
unsigned int num_blocks = (data_size + 0xF) >> 4;
|
|
|
|
/* Handle aligned blocks. */
|
|
|
|
if (num_blocks > 1) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 2;
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CRYPTO_REG |= 0x80;
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Create final block. */
|
|
|
|
uint8_t last_block[0x10];
|
|
|
|
memset(last_block, 0, sizeof(last_block));
|
|
|
|
if (data_size & 0xF) {
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
memcpy(last_block, data + (data_size & ~0xF), data_size & 0xF);
|
|
|
|
last_block[data_size & 0xF] = 0x80; /* Last block = data || 100...0 */
|
|
|
|
} else if (data_size >= 0x10) {
|
|
|
|
memcpy(last_block, data + data_size - 0x10, 0x10);
|
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
for (unsigned int i = 0; i < 0x10; i++) {
|
|
|
|
last_block[i] ^= derived_key[i];
|
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Perform last operation. */
|
|
|
|
flush_dcache_range(last_block, last_block + sizeof(last_block));
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, NULL, 0, last_block, sizeof(last_block));
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 00:17:12 +00:00
|
|
|
/* Copy output CMAC. */
|
|
|
|
for (unsigned int i = 0; i < (cmac_size >> 2); i++) {
|
2018-02-23 01:50:19 +00:00
|
|
|
((uint32_t *)cmac)[i] = read32le(SECURITY_ENGINE->HASH_RESULT_REG, i << 2);
|
2018-02-23 00:17:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
|
|
|
|
se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0);
|
|
|
|
}
|
|
|
|
void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
|
|
|
|
se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0x202);
|
|
|
|
}
|
|
|
|
|
2018-02-28 01:07:30 +00:00
|
|
|
void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) {
|
2018-02-28 01:40:47 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
|
|
|
|
generic_panic();
|
|
|
|
}
|
|
|
|
|
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
|
|
|
|
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x144;
|
|
|
|
set_aes_keyslot_iv(keyslot, iv, 0x10);
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = (src_size >> 4) - 1;
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
|
2018-02-28 01:07:30 +00:00
|
|
|
}
|
|
|
|
|
2018-02-23 01:05:22 +00:00
|
|
|
/* SHA256 Implementation. */
|
|
|
|
void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
|
|
|
|
/* Setup config for SHA256, size = BITS(src_size) */
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
|
|
|
|
SECURITY_ENGINE->SHA_CONFIG_REG = 1;
|
|
|
|
SECURITY_ENGINE->SHA_MSG_LENGTH_REG = (unsigned int)(src_size << 3);
|
|
|
|
SECURITY_ENGINE->_0x20C = 0;
|
|
|
|
SECURITY_ENGINE->_0x210 = 0;
|
|
|
|
SECURITY_ENGINE->SHA_MSG_LEFT_REG = 0;
|
|
|
|
SECURITY_ENGINE->_0x218 = (unsigned int)(src_size << 3);
|
|
|
|
SECURITY_ENGINE->_0x21C = 0;
|
|
|
|
SECURITY_ENGINE->_0x220 = 0;
|
|
|
|
SECURITY_ENGINE->_0x224 = 0;
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:05:22 +00:00
|
|
|
/* Trigger the operation. */
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:05:22 +00:00
|
|
|
/* Copy output hash. */
|
|
|
|
for (unsigned int i = 0; i < (0x20 >> 2); i++) {
|
2018-02-23 01:50:19 +00:00
|
|
|
((uint32_t *)dst)[i] = read32be(SECURITY_ENGINE->HASH_RESULT_REG, i << 2);
|
2018-02-23 01:05:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RNG API */
|
|
|
|
void se_initialize_rng(unsigned int keyslot) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-23 01:05:22 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:05:22 +00:00
|
|
|
/* To initialize the RNG, we'll perform an RNG operation into an output buffer. */
|
|
|
|
/* This will be discarded, when done. */
|
|
|
|
uint8_t output_buf[0x10];
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->RNG_SRC_CONFIG_REG = 3; /* Entropy enable + Entropy lock enable */
|
|
|
|
SECURITY_ENGINE->RNG_RESEED_INTERVAL_REG = 70001;
|
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_RNG | DST_MEMORY);
|
|
|
|
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x108;
|
|
|
|
SECURITY_ENGINE->RNG_CONFIG_REG = 5;
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, output_buf, 0x10, NULL, 0);
|
2018-02-23 01:05:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
|
2018-02-23 01:50:19 +00:00
|
|
|
if (keyslot >= KEYSLOT_AES_MAX) {
|
2018-02-24 14:20:45 +00:00
|
|
|
generic_panic();
|
2018-02-23 01:05:22 +00:00
|
|
|
}
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:05:22 +00:00
|
|
|
uint32_t num_blocks = size >> 4;
|
|
|
|
size_t aligned_size = num_blocks << 4;
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_RNG | DST_MEMORY);
|
|
|
|
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x108;
|
|
|
|
SECURITY_ENGINE->RNG_CONFIG_REG = 4;
|
2018-02-26 21:09:35 +00:00
|
|
|
|
2018-02-23 01:05:22 +00:00
|
|
|
if (num_blocks >= 1) {
|
2018-02-23 01:50:19 +00:00
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 1;
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, dst, aligned_size, NULL, 0);
|
2018-02-23 01:05:22 +00:00
|
|
|
}
|
|
|
|
if (size > aligned_size) {
|
|
|
|
se_perform_aes_block_operation(dst + aligned_size, size - aligned_size, NULL, 0);
|
|
|
|
}
|
2018-02-23 00:17:12 +00:00
|
|
|
|
2018-02-24 16:13:42 +00:00
|
|
|
}
|
2018-02-28 01:07:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* SE context save API. */
|
|
|
|
void se_set_in_context_save_mode(bool is_context_save_mode) {
|
2018-02-28 01:40:47 +00:00
|
|
|
uint32_t val = SECURITY_ENGINE->_0x0;
|
|
|
|
if (is_context_save_mode) {
|
|
|
|
val |= 0x10000;
|
|
|
|
} else {
|
|
|
|
val &= 0xFFFEFFFF;
|
|
|
|
}
|
|
|
|
SECURITY_ENGINE->_0x0 = val;
|
|
|
|
/* Perform a useless read from flags reg. */
|
|
|
|
(void)(SECURITY_ENGINE->FLAGS_REG);
|
2018-02-28 01:07:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) {
|
2018-02-28 01:40:47 +00:00
|
|
|
if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) {
|
|
|
|
generic_panic();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup Config. */
|
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_RNG | DST_KEYTAB);
|
|
|
|
SECURITY_ENGINE->CRYPTO_REG = (rng_keyslot << 24) | 0x108;
|
|
|
|
SECURITY_ENGINE->RNG_CONFIG_REG = 4;
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
|
|
|
|
/* Generate low part of key. */
|
|
|
|
SECURITY_ENGINE->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8);
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
2018-02-28 01:40:47 +00:00
|
|
|
/* Generate high part of key. */
|
|
|
|
SECURITY_ENGINE->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8) | 1;
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
2018-02-28 01:40:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void se_generate_srk(unsigned int srkgen_keyslot) {
|
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_RNG | DST_SRK);
|
|
|
|
SECURITY_ENGINE->CRYPTO_REG = (srkgen_keyslot << 24) | 0x108;
|
|
|
|
SECURITY_ENGINE->RNG_CONFIG_REG = 6;
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
2018-02-28 01:07:30 +00:00
|
|
|
}
|
|
|
|
|
2018-02-28 01:40:47 +00:00
|
|
|
void se_encrypt_with_srk(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
|
|
uint8_t output[0x80];
|
|
|
|
uint8_t *aligned_out = (uint8_t *)(((uintptr_t)output + 0x7F) & ~0x3F);
|
|
|
|
if (dst_size > 0x10) {
|
|
|
|
generic_panic();
|
|
|
|
}
|
|
|
|
if (src_size) {
|
|
|
|
flush_dcache_range((uint8_t *)src, (uint8_t *)src + src_size);
|
|
|
|
}
|
|
|
|
if (dst_size) {
|
|
|
|
flush_dcache_range(aligned_out, aligned_out + 0x10);
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, dst_size, src, src_size);
|
2018-02-28 01:40:47 +00:00
|
|
|
flush_dcache_range(aligned_out, aligned_out + 0x10);
|
|
|
|
memcpy(dst, aligned_out, dst_size);
|
|
|
|
} else {
|
2018-02-28 03:05:45 +00:00
|
|
|
trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, 0, src, src_size);
|
2018-02-28 01:40:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) {
|
2018-02-28 03:05:45 +00:00
|
|
|
uint8_t _work_buf[0x80];
|
|
|
|
uint8_t *work_buf = (uint8_t *)(((uintptr_t)_work_buf + 0x7F) & ~0x3F);
|
|
|
|
|
2018-02-28 01:40:47 +00:00
|
|
|
/* Generate the SRK (context save encryption key). */
|
|
|
|
se_generate_random_key(srkgen_keyslot, rng_keyslot);
|
|
|
|
se_generate_srk(srkgen_keyslot);
|
|
|
|
|
2018-02-28 03:05:45 +00:00
|
|
|
flush_dcache_range(work_buf, work_buf + 0x10);
|
|
|
|
se_generate_random(rng_keyslot, work_buf, 0x10);
|
|
|
|
flush_dcache_range(work_buf, work_buf + 0x10);
|
|
|
|
|
|
|
|
/* Save random initial block. */
|
|
|
|
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
|
|
|
|
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
se_encrypt_with_srk(dst, 0x10, work_buf, 0x10);
|
|
|
|
|
|
|
|
/* Save Sticky Bits. */
|
|
|
|
for (unsigned int i = 0; i < 0x2; i++) {
|
|
|
|
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT);
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save AES Key Table. */
|
|
|
|
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
|
|
|
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
se_encrypt_with_srk(dst + 0x30 + (i * 0x20), 0x10, NULL, 0);
|
|
|
|
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_HIGH_BITS);
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save AES Original IVs. */
|
|
|
|
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
|
|
|
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_ORIGINAL_IV);
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save AES Updated IVs */
|
|
|
|
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
|
|
|
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_UPDATED_IV);
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save RSA Keytable. */
|
|
|
|
uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430;
|
|
|
|
for (unsigned int rsa_key = 0; rsa_key < KEYSLOT_RSA_MAX; rsa_key++) {
|
|
|
|
for (unsigned int mod_exp = 0; mod_exp < 2; mod_exp++) {
|
|
|
|
for (unsigned int sub_block = 0; sub_block < 0x10; sub_block++) {
|
|
|
|
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_RSA) | ((2 * rsa_key + (1 - mod_exp)) << CTX_SAVE_RSA_KEY_INDEX_SHIFT) | (sub_block << CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT);
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
se_encrypt_with_srk(rsa_ctx_out, 0x10, NULL, 0);
|
|
|
|
rsa_ctx_out += 0x10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save "Known Pattern. " */
|
|
|
|
static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
|
|
|
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10);
|
|
|
|
|
|
|
|
/* Save SRK into PMC registers. */
|
|
|
|
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK);
|
|
|
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
|
|
|
se_encrypt_with_srk(work_buf, 0, NULL, 0);
|
|
|
|
SECURITY_ENGINE->CONFIG_REG = 0;
|
|
|
|
se_encrypt_with_srk(work_buf, 0, NULL, 0);
|
2018-02-28 01:07:30 +00:00
|
|
|
}
|