mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-24 07:40:26 +01:00
Flesh out the SE driver, some
This commit is contained in:
parent
4b2d17a42a
commit
77ff68a69d
189
exosphere/se.c
Normal file
189
exosphere/se.c
Normal file
@ -0,0 +1,189 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "se.h"
|
||||
|
||||
void trigger_se_rsa_op(void *buf, unsigned int size);
|
||||
void trigger_se_aes_op(unsigned int op, char *dst, unsigned int dst_size, const unsigned char *src, unsigned int src_size);
|
||||
|
||||
/* Globals for driver. */
|
||||
security_engine_t *g_security_engine;
|
||||
|
||||
unsigned int (*g_se_callback)(void);
|
||||
|
||||
unsigned int g_se_modulus_sizes[KEYSLOT_RSA_MAX];
|
||||
unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX];
|
||||
|
||||
/* Set the global security engine pointer. */
|
||||
void set_security_engine_address(security_engine_t *security_engine) {
|
||||
g_security_engine = security_engine;
|
||||
}
|
||||
|
||||
void set_security_engine_callback(unsigned int (*callback)(void)) {
|
||||
if (callback == NULL || g_se_callback != NULL) {
|
||||
panic();
|
||||
}
|
||||
|
||||
g_se_callback = callback;
|
||||
}
|
||||
|
||||
/* Set the flags for an AES keyslot. */
|
||||
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||
if (g_security_engine == NULL || keyslot >= KEYSLOT_AES_MAX) {
|
||||
panic();
|
||||
}
|
||||
|
||||
/* Misc flags. */
|
||||
if (flags & ~0x80) {
|
||||
g_security_engine->AES_KEYSLOT_FLAGS[keyslot] = ~flags;
|
||||
}
|
||||
|
||||
/* Disable keyslot reads. */
|
||||
if (flags & 0x80) {
|
||||
g_security_engine->AES_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the flags for an RSA keyslot. */
|
||||
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
||||
if (g_security_engine == NULL || keyslot >= KEYSLOT_RSA_MAX) {
|
||||
panic();
|
||||
}
|
||||
|
||||
/* Misc flags. */
|
||||
if (flags & ~0x80) {
|
||||
/* TODO: Why are flags assigned this way? */
|
||||
g_security_engine->RSA_KEYSLOT_FLAGS[keyslot] = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
|
||||
}
|
||||
|
||||
/* Disable keyslot reads. */
|
||||
if (flags & 0x80) {
|
||||
g_security_engine->RSA_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_aes_keyslot(unsigned int keyslot) {
|
||||
if (g_security_engine == NULL || keyslot >= KEYSLOT_AES_MAX) {
|
||||
panic();
|
||||
}
|
||||
|
||||
/* Zero out the whole keyslot and IV. */
|
||||
for (unsigned int i = 0; i < 0x10; i++) {
|
||||
g_security_engine->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
|
||||
g_security_engine->AES_KEYTABLE_DATA = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_rsa_keyslot(unsigned int keyslot) {
|
||||
if (g_security_engine == NULL || keyslot >= KEYSLOT_RSA_MAX) {
|
||||
panic();
|
||||
}
|
||||
|
||||
/* Zero out the whole keyslot. */
|
||||
for (unsigned int i = 0; i < 0x40; i++) {
|
||||
/* Select Keyslot Modulus[i] */
|
||||
g_security_engine->RSA_KEYTABLE_ADDR = (keyslot << 7) | i | 0x40;
|
||||
g_security_engine->RSA_KEYTABLE_DATA = 0;
|
||||
}
|
||||
for (unsigned int i = 0; i < 0x40; i++) {
|
||||
/* Select Keyslot Expontent[i] */
|
||||
g_security_engine->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
|
||||
g_security_engine->RSA_KEYTABLE_DATA = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set_aes_keyslot(unsigned int keyslot, const unsigned char *key, unsigned int key_size) {
|
||||
if (g_security_engine == NULL || keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
|
||||
panic();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < (key_size >> 2); i++) {
|
||||
g_security_engine->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
|
||||
g_security_engine->AES_KEYTABLE_DATA = read32le(key, 4 * i);
|
||||
}
|
||||
}
|
||||
|
||||
void set_rsa_keyslot(unsigned int keyslot, const unsigned char *modulus, unsigned int modulus_size, const unsigned char *exp, unsigned int exp_size) {
|
||||
if (g_security_engine == NULL || keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
|
||||
panic();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < (modulus_size >> 2); i++) {
|
||||
g_security_engine->RSA_KEYTABLE_ADDR = (keyslot << 7) | 0x40 | i;
|
||||
g_security_engine->RSA_KEYTABLE_DATA = read32be(modulus, 4 * i);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < (exp_size >> 2); i++) {
|
||||
g_security_engine->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
|
||||
g_security_engine->RSA_KEYTABLE_DATA = read32be(exp, 4 * i);
|
||||
}
|
||||
|
||||
g_se_modulus_sizes[keyslot] = modulus_size;
|
||||
g_se_exp_sizes[keyslot] = exp_size;
|
||||
}
|
||||
|
||||
|
||||
void set_aes_keyslot_iv(unsigned int keyslot, const unsigned char *iv, unsigned int iv_size) {
|
||||
if (g_security_engine == NULL || keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
|
||||
panic();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < (iv_size >> 2); i++) {
|
||||
g_security_engine->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
|
||||
g_security_engine->AES_KEYTABLE_DATA = read32le(iv, 4 * i);
|
||||
}
|
||||
}
|
||||
|
||||
void set_se_ctr(const char *ctr) {
|
||||
if (g_security_engine == NULL) {
|
||||
panic();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < 4; i++) {
|
||||
g_security_engine->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
|
||||
}
|
||||
}
|
||||
|
||||
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const unsigned char *wrapped_key, unsigned int wrapped_key_size) {
|
||||
if (g_security_engine == NULL || keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSIZE_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
|
||||
panic();
|
||||
}
|
||||
|
||||
g_security_engine->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB);
|
||||
g_security_engine->CRYPTO_REG = keyslot_src << 24;
|
||||
g_security_engine->BLOCK_COUNT_REG = 0;
|
||||
g_se_callback->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8;
|
||||
|
||||
/* TODO: Cache flush the wrapped key. */
|
||||
|
||||
trigger_se_aes_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size);
|
||||
}
|
||||
|
||||
|
||||
void se_crypt_aes(unsigned int keyslot, unsigned char *dst, unsigned int dst_size, const unsigned char *src, unsigned int src_size, unsigned int config, unsigned int mode, unsigned int (*callback)(void));
|
||||
|
||||
void se_exp_mod(unsigned int keyslot, unsigned char *buf, unsigned int size, unsigned int (*callback)(void)) {
|
||||
unsigned char stack_buf[KEYSIZE_RSA_MAX];
|
||||
|
||||
if (g_security_engine == NULL || keyslot >= KEYSLOT_RSA_MAX || size > KEYSIZE_RSA_MAX) {
|
||||
panic();
|
||||
}
|
||||
|
||||
/* Endian swap the input. */
|
||||
for (unsigned int i = size; i > 0; i--) {
|
||||
stack_buf[i] = buf[size - i];
|
||||
}
|
||||
|
||||
/* TODO: Flush cache for stack copy. */
|
||||
|
||||
g_security_engine->CONFIG_REG = (ALG_RSA | DST_RSAREG);
|
||||
g_security_engine->RSA_CONFIG = keyslot << 24;
|
||||
g_security_engine->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1;
|
||||
g_security_engine->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2;
|
||||
|
||||
set_security_engine_callback(callback);
|
||||
|
||||
trigger_se_rsa_op(stack_buf, size);
|
||||
|
||||
while (!(g_security_engine->INT_STATUS_REG & 2)) { /* Wait a while */ }
|
||||
}
|
100
exosphere/se.h
100
exosphere/se.h
@ -3,12 +3,94 @@
|
||||
|
||||
/* Exosphere driver for the Tegra X1 security engine. */
|
||||
|
||||
#define KEYSLOT_AES_MAX 0x10
|
||||
#define KEYSLOT_RSA_MAX 0x2
|
||||
|
||||
#define KEYSIZE_AES_MAX 0x20
|
||||
#define KEYSIZE_RSA_MAX 0x100
|
||||
|
||||
#define ALG_SHIFT (12)
|
||||
#define ALG_DEC_SHIFT (8)
|
||||
#define ALG_NOP (0 << ALG_SHIFT)
|
||||
#define ALG_AES_ENC (1 << ALG_SHIFT)
|
||||
#define ALG_AES_DEC ((1 << ALG_DEC_SHIFT) | ALG_NOP)
|
||||
#define ALG_RNG (2 << ALG_SHIFT)
|
||||
#define ALG_SHA (3 << ALG_SHIFT)
|
||||
#define ALG_RSA (4 << ALG_SHIFT)
|
||||
|
||||
#define DST_SHIFT (2)
|
||||
#define DST_MEMORY (0 << DST_SHIFT)
|
||||
#define DST_HASHREG (1 << DST_SHIFT)
|
||||
#define DST_KEYTAB (2 << DST_SHIFT)
|
||||
#define DST_SRK (3 << DST_SHIFT)
|
||||
#define DST_RSAREG (4 << DST_SHIFT)
|
||||
|
||||
|
||||
|
||||
#define OP_ABORT 0
|
||||
#define OP_START 1
|
||||
#define OP_RESTART 2
|
||||
#define OP_CTX_SAVE 3
|
||||
#define OP_RESTART_IN 4
|
||||
|
||||
|
||||
typedef struct security_engine {
|
||||
unsigned int _0x0;
|
||||
unsigned int _0x4;
|
||||
unsigned int OPERATION_REG;
|
||||
unsigned int INT_ENABLE_REG;
|
||||
unsigned int INT_STATUS_REG;
|
||||
unsigned int CONFIG_REG;
|
||||
unsigned int IN_LL_ADDR_REG;
|
||||
unsigned int _0x1C;
|
||||
unsigned int _0x20;
|
||||
unsigned int OUT_LL_ADDR_REG;
|
||||
unsigned int _0x28;
|
||||
unsigned int _0x2C;
|
||||
unsigned char cmacOutput[0x10];
|
||||
unsigned char reserved0x40[0x240];
|
||||
unsigned int AES_KEY_READ_DISABLE_REG;
|
||||
unsigned int AES_KEYSLOT_FLAGS[0x10];
|
||||
unsigned char _0x2C4[0x3C];
|
||||
unsigned int _0x300;
|
||||
unsigned int CRYPTO_REG;
|
||||
unsigned int CRYPTO_CTR_REG[4];
|
||||
unsigned int BLOCK_COUNT_REG;
|
||||
unsigned int AES_KEYTABLE_ADDR;
|
||||
unsigned int AES_KEYTABLE_DATA;
|
||||
unsigned int _0x324;
|
||||
unsigned int _0x328;
|
||||
unsigned int _0x32C;
|
||||
unsigned int CRYPTO_KEYTABLE_DST_REG;
|
||||
unsigned char _0x334[0xCC];
|
||||
unsigned int RSA_CONFIG;
|
||||
unsigned int RSA_KEY_SIZE_REG;
|
||||
unsigned int RSA_EXP_SIZE_REG;
|
||||
unsigned int RSA_KEY_READ_DISABLE_REG;
|
||||
unsigned int RSA_KEYSLOT_FLAGS[2];
|
||||
unsigned int _0x418;
|
||||
unsigned int _0x41C;
|
||||
unsigned int RSA_KEYTABLE_ADDR;
|
||||
unsigned int RSA_KEYTABLE_DATA;
|
||||
unsigned int RSA_OUTPUT;
|
||||
unsigned char _0x42C[0x3D4];
|
||||
unsigned int FLAGS_REG;
|
||||
unsigned int ERR_STATUS_REG;
|
||||
unsigned int _0x808;
|
||||
unsigned int _0x80C;
|
||||
unsigned int _0x810;
|
||||
unsigned int _0x814;
|
||||
unsigned int _0x818;
|
||||
unsigned int _0x81C;
|
||||
unsigned char _0x820[0x17E0];
|
||||
} security_engine_t;
|
||||
|
||||
/* TODO: Define constants for the C driver. */
|
||||
|
||||
|
||||
/* WIP, API subject to change. */
|
||||
|
||||
#define KEYSLOT_AES_MAX 0x10
|
||||
#define KEYSLOT_RSA_MAX 0x2
|
||||
|
||||
|
||||
void set_security_engine_address(void *security_engine);
|
||||
|
||||
@ -17,14 +99,14 @@ void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags);
|
||||
void clear_aes_keyslot(unsigned int keyslot);
|
||||
void clear_rsa_keyslot(unsigned int keyslot);
|
||||
|
||||
void set_aes_keyslot(unsigned int keyslot, const char *key, unsigned int key_size);
|
||||
void crypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const char *wrapped_key, unsigned int wrapped_key_size);
|
||||
void set_rsa_keyslot(unsigned int keyslot, const char *modulus, unsigned int modulus_size, const char *exp, unsigned int exp_size);
|
||||
void set_aes_keyslot_iv(unsigned int keyslot, const char *iv, unsigned int iv_size);
|
||||
void set_se_ctr(const unsigned int *ctr);
|
||||
void set_aes_keyslot(unsigned int keyslot, const unsigned char *key, unsigned int key_size);
|
||||
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const unsigned char *wrapped_key, unsigned int wrapped_key_size);
|
||||
void set_rsa_keyslot(unsigned int keyslot, const unsigned char *modulus, unsigned int modulus_size, const unsigned char *exp, unsigned int exp_size);
|
||||
void set_aes_keyslot_iv(unsigned int keyslot, const unsigned char *iv, unsigned int iv_size);
|
||||
void set_se_ctr(const char *ctr);
|
||||
|
||||
void se_crypt_aes(unsigned int keyslot, char *dst, unsigned int dst_size, const char *src, unsigned int src_size, unsigned int config, unsigned int mode, unsigned int (*callback)(void));
|
||||
void se_exp_mod(unsigned int keyslot, char *buf, unsigned int size, unsigned int (*callback)(void));
|
||||
void se_crypt_aes(unsigned int keyslot, unsigned char *dst, unsigned int dst_size, const unsigned char *src, unsigned int src_size, unsigned int config, unsigned int mode, unsigned int (*callback)(void));
|
||||
void se_exp_mod(unsigned int keyslot, unsigned char *buf, unsigned int size, unsigned int (*callback)(void));
|
||||
|
||||
/* TODO: SE context save API, consider extending AES API for secure world vs non-secure world operations. */
|
||||
/* In particular, smc_crypt_aes takes in raw DMA lists, and we need to support that. */
|
||||
|
9
exosphere/utils.h
Normal file
9
exosphere/utils.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef EXOSPHERE_UTILS_H
|
||||
#define EXOSPHERE_UTILS_H
|
||||
|
||||
void panic(void);
|
||||
|
||||
unsigned int read32le(const unsigned char *dword, unsigned int offset);
|
||||
unsigned int read32be(const unsigned char *dword, unsigned int offset);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user