mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
Finish implementing Security Engine context save
This commit is contained in:
parent
a8a2f8c3f6
commit
fba3d1c2d9
2 changed files with 106 additions and 16 deletions
|
@ -322,7 +322,7 @@ void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, co
|
||||||
|
|
||||||
|
|
||||||
flush_dcache_range(stack_buf, stack_buf + KEYSIZE_RSA_MAX);
|
flush_dcache_range(stack_buf, stack_buf + KEYSIZE_RSA_MAX);
|
||||||
trigger_se_blocking_op(1, NULL, 0, stack_buf, src_size);
|
trigger_se_blocking_op(OP_START, NULL, 0, stack_buf, src_size);
|
||||||
se_get_exp_mod_output(dst, dst_size);
|
se_get_exp_mod_output(dst, dst_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +395,7 @@ void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src,
|
||||||
|
|
||||||
/* Trigger AES operation. */
|
/* Trigger AES operation. */
|
||||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||||
trigger_se_blocking_op(1, block, sizeof(block), block, sizeof(block));
|
trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block));
|
||||||
|
|
||||||
/* Copy output data into dst. */
|
/* Copy output data into dst. */
|
||||||
flush_dcache_range(block, block + sizeof(block));
|
flush_dcache_range(block, block + sizeof(block));
|
||||||
|
@ -419,7 +419,7 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
|
||||||
size_t aligned_size = (size_t)num_blocks << 4;
|
size_t aligned_size = (size_t)num_blocks << 4;
|
||||||
if (aligned_size) {
|
if (aligned_size) {
|
||||||
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 1;
|
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 1;
|
||||||
trigger_se_blocking_op(1, dst, dst_size, src, aligned_size);
|
trigger_se_blocking_op(OP_START, dst, dst_size, src, aligned_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle final, unaligned block. */
|
/* Handle final, unaligned block. */
|
||||||
|
@ -497,7 +497,7 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
|
||||||
/* Handle aligned blocks. */
|
/* Handle aligned blocks. */
|
||||||
if (num_blocks > 1) {
|
if (num_blocks > 1) {
|
||||||
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 2;
|
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 2;
|
||||||
trigger_se_blocking_op(1, NULL, 0, data, data_size);
|
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
|
||||||
SECURITY_ENGINE->CRYPTO_REG |= 0x80;
|
SECURITY_ENGINE->CRYPTO_REG |= 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +518,7 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
|
||||||
|
|
||||||
/* Perform last operation. */
|
/* Perform last operation. */
|
||||||
flush_dcache_range(last_block, last_block + sizeof(last_block));
|
flush_dcache_range(last_block, last_block + sizeof(last_block));
|
||||||
trigger_se_blocking_op(1, NULL, 0, last_block, sizeof(last_block));
|
trigger_se_blocking_op(OP_START, NULL, 0, last_block, sizeof(last_block));
|
||||||
|
|
||||||
/* Copy output CMAC. */
|
/* Copy output CMAC. */
|
||||||
for (unsigned int i = 0; i < (cmac_size >> 2); i++) {
|
for (unsigned int i = 0; i < (cmac_size >> 2); i++) {
|
||||||
|
@ -542,7 +542,7 @@ void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, co
|
||||||
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x144;
|
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x144;
|
||||||
set_aes_keyslot_iv(keyslot, iv, 0x10);
|
set_aes_keyslot_iv(keyslot, iv, 0x10);
|
||||||
SECURITY_ENGINE->BLOCK_COUNT_REG = (src_size >> 4) - 1;
|
SECURITY_ENGINE->BLOCK_COUNT_REG = (src_size >> 4) - 1;
|
||||||
trigger_se_blocking_op(1, dst, dst_size, src, src_size);
|
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SHA256 Implementation. */
|
/* SHA256 Implementation. */
|
||||||
|
@ -560,7 +560,7 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
|
||||||
SECURITY_ENGINE->_0x224 = 0;
|
SECURITY_ENGINE->_0x224 = 0;
|
||||||
|
|
||||||
/* Trigger the operation. */
|
/* Trigger the operation. */
|
||||||
trigger_se_blocking_op(1, NULL, 0, src, src_size);
|
trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);
|
||||||
|
|
||||||
/* Copy output hash. */
|
/* Copy output hash. */
|
||||||
for (unsigned int i = 0; i < (0x20 >> 2); i++) {
|
for (unsigned int i = 0; i < (0x20 >> 2); i++) {
|
||||||
|
@ -584,7 +584,7 @@ void se_initialize_rng(unsigned int keyslot) {
|
||||||
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x108;
|
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x108;
|
||||||
SECURITY_ENGINE->RNG_CONFIG_REG = 5;
|
SECURITY_ENGINE->RNG_CONFIG_REG = 5;
|
||||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||||
trigger_se_blocking_op(1, output_buf, 0x10, NULL, 0);
|
trigger_se_blocking_op(OP_START, output_buf, 0x10, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
|
void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
|
||||||
|
@ -600,7 +600,7 @@ void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
|
||||||
|
|
||||||
if (num_blocks >= 1) {
|
if (num_blocks >= 1) {
|
||||||
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 1;
|
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 1;
|
||||||
trigger_se_blocking_op(1, dst, aligned_size, NULL, 0);
|
trigger_se_blocking_op(OP_START, dst, aligned_size, NULL, 0);
|
||||||
}
|
}
|
||||||
if (size > aligned_size) {
|
if (size > aligned_size) {
|
||||||
se_perform_aes_block_operation(dst + aligned_size, size - aligned_size, NULL, 0);
|
se_perform_aes_block_operation(dst + aligned_size, size - aligned_size, NULL, 0);
|
||||||
|
@ -635,10 +635,10 @@ void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot)
|
||||||
|
|
||||||
/* Generate low part of key. */
|
/* Generate low part of key. */
|
||||||
SECURITY_ENGINE->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8);
|
SECURITY_ENGINE->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8);
|
||||||
trigger_se_blocking_op(1, NULL, 0, NULL, 0);
|
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
||||||
/* Generate high part of key. */
|
/* Generate high part of key. */
|
||||||
SECURITY_ENGINE->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8) | 1;
|
SECURITY_ENGINE->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8) | 1;
|
||||||
trigger_se_blocking_op(1, NULL, 0, NULL, 0);
|
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void se_generate_srk(unsigned int srkgen_keyslot) {
|
void se_generate_srk(unsigned int srkgen_keyslot) {
|
||||||
|
@ -646,7 +646,7 @@ void se_generate_srk(unsigned int srkgen_keyslot) {
|
||||||
SECURITY_ENGINE->CRYPTO_REG = (srkgen_keyslot << 24) | 0x108;
|
SECURITY_ENGINE->CRYPTO_REG = (srkgen_keyslot << 24) | 0x108;
|
||||||
SECURITY_ENGINE->RNG_CONFIG_REG = 6;
|
SECURITY_ENGINE->RNG_CONFIG_REG = 6;
|
||||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||||
trigger_se_blocking_op(1, NULL, 0, NULL, 0);
|
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void se_encrypt_with_srk(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
void se_encrypt_with_srk(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
|
@ -660,18 +660,86 @@ void se_encrypt_with_srk(void *dst, size_t dst_size, const void *src, size_t src
|
||||||
}
|
}
|
||||||
if (dst_size) {
|
if (dst_size) {
|
||||||
flush_dcache_range(aligned_out, aligned_out + 0x10);
|
flush_dcache_range(aligned_out, aligned_out + 0x10);
|
||||||
trigger_se_blocking_op(3, aligned_out, dst_size, src, src_size);
|
trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, dst_size, src, src_size);
|
||||||
flush_dcache_range(aligned_out, aligned_out + 0x10);
|
flush_dcache_range(aligned_out, aligned_out + 0x10);
|
||||||
memcpy(dst, aligned_out, dst_size);
|
memcpy(dst, aligned_out, dst_size);
|
||||||
} else {
|
} else {
|
||||||
trigger_se_blocking_op(3, aligned_out, 0, src, src_size);
|
trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, 0, src, src_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) {
|
void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) {
|
||||||
|
uint8_t _work_buf[0x80];
|
||||||
|
uint8_t *work_buf = (uint8_t *)(((uintptr_t)_work_buf + 0x7F) & ~0x3F);
|
||||||
|
|
||||||
/* Generate the SRK (context save encryption key). */
|
/* Generate the SRK (context save encryption key). */
|
||||||
se_generate_random_key(srkgen_keyslot, rng_keyslot);
|
se_generate_random_key(srkgen_keyslot, rng_keyslot);
|
||||||
se_generate_srk(srkgen_keyslot);
|
se_generate_srk(srkgen_keyslot);
|
||||||
|
|
||||||
/* TODO: Encrypt SE context with SRK. */
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef EXOSPHERE_SE_H
|
#ifndef EXOSPHERE_SE_H
|
||||||
#define EXOSPHERE_SE_H
|
#define EXOSPHERE_SE_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -58,6 +59,23 @@
|
||||||
#define OP_CTX_SAVE 3
|
#define OP_CTX_SAVE 3
|
||||||
#define OP_RESTART_IN 4
|
#define OP_RESTART_IN 4
|
||||||
|
|
||||||
|
#define CTX_SAVE_SRC_SHIFT 29
|
||||||
|
#define CTX_SAVE_SRC_STICKY_BITS (0 << CTX_SAVE_SRC_SHIFT)
|
||||||
|
#define CTX_SAVE_SRC_KEYTABLE_AES (2 << CTX_SAVE_SRC_SHIFT)
|
||||||
|
#define CTX_SAVE_SRC_KEYTABLE_RSA (1 << CTX_SAVE_SRC_SHIFT)
|
||||||
|
#define CTX_SAVE_SRC_MEM (4 << CTX_SAVE_SRC_SHIFT)
|
||||||
|
#define CTX_SAVE_SRC_SRK (6 << CTX_SAVE_SRC_SHIFT)
|
||||||
|
|
||||||
|
#define CTX_SAVE_KEY_LOW_BITS 0
|
||||||
|
#define CTX_SAVE_KEY_HIGH_BITS 1
|
||||||
|
#define CTX_SAVE_KEY_ORIGINAL_IV 2
|
||||||
|
#define CTX_SAVE_KEY_UPDATED_IV 3
|
||||||
|
|
||||||
|
#define CTX_SAVE_STICKY_BIT_INDEX_SHIFT 24
|
||||||
|
#define CTX_SAVE_KEY_INDEX_SHIFT 8
|
||||||
|
#define CTX_SAVE_RSA_KEY_INDEX_SHIFT 16
|
||||||
|
#define CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT 12
|
||||||
|
|
||||||
#define RSA_2048_BYTES 0x100
|
#define RSA_2048_BYTES 0x100
|
||||||
|
|
||||||
typedef struct security_engine {
|
typedef struct security_engine {
|
||||||
|
@ -74,7 +92,9 @@ typedef struct security_engine {
|
||||||
unsigned int _0x28;
|
unsigned int _0x28;
|
||||||
unsigned int _0x2C;
|
unsigned int _0x2C;
|
||||||
unsigned char HASH_RESULT_REG[0x20];
|
unsigned char HASH_RESULT_REG[0x20];
|
||||||
unsigned char _0x50[0x1B0];
|
unsigned char _0x50[0x20];
|
||||||
|
unsigned int CONTEXT_SAVE_CONFIG_REG;
|
||||||
|
unsigned char _0x74[0x18C];
|
||||||
unsigned int SHA_CONFIG_REG;
|
unsigned int SHA_CONFIG_REG;
|
||||||
unsigned int SHA_MSG_LENGTH_REG;
|
unsigned int SHA_MSG_LENGTH_REG;
|
||||||
unsigned int _0x20C;
|
unsigned int _0x20C;
|
||||||
|
@ -125,6 +145,8 @@ typedef struct security_engine {
|
||||||
unsigned char _0x820[0x17E0];
|
unsigned char _0x820[0x17E0];
|
||||||
} security_engine_t;
|
} security_engine_t;
|
||||||
|
|
||||||
|
static_assert(sizeof(security_engine_t) == 0x2000, "Mis-defined Security Engine Registers!");
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
|
|
Loading…
Reference in a new issue