From d0beae376fc1e658ba202eeb0d8e072920c379a5 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 19 Feb 2018 13:26:37 -0800 Subject: [PATCH] SMCCryptAes + Skeleton blocking AES API --- exosphere/se.c | 6 +++++ exosphere/se.h | 9 ++++++- exosphere/smc_api.c | 17 ++++++++++++ exosphere/smc_user.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ exosphere/smc_user.h | 4 +++ 5 files changed, 96 insertions(+), 1 deletion(-) diff --git a/exosphere/se.c b/exosphere/se.c index e7bcc6604..42513d0cb 100644 --- a/exosphere/se.c +++ b/exosphere/se.c @@ -222,6 +222,9 @@ void se_aes_crypt_insecure_internal(unsigned int keyslot, uint32_t out_ll_paddr, /* Set the callback, for after the async operation. */ set_security_engine_callback(callback); + /* Enable SE Interrupt firing for async op. */ + g_security_engine->INT_ENABLE_REG = 0x10; + /* Setup Input/Output lists */ g_security_engine->IN_LL_ADDR_REG = in_ll_paddr; g_security_engine->OUT_LL_ADDR_REG = out_ll_paddr; @@ -284,6 +287,9 @@ void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*cal g_security_engine->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2; set_security_engine_callback(callback); + + /* Enable SE Interrupt firing for async op. */ + g_security_engine->INT_ENABLE_REG = 0x10; flush_dcache_range(stack_buf, stack_buf + KEYSIZE_RSA_MAX); trigger_se_rsa_op(stack_buf, size); diff --git a/exosphere/se.h b/exosphere/se.h index 115eeec88..926f606a8 100644 --- a/exosphere/se.h +++ b/exosphere/se.h @@ -125,11 +125,18 @@ void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size); void set_se_ctr(const void *ctr); -/* AES API */ +/* Insecure AES API */ 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)); 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)); 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)); +/* Secure AES API */ +void se_compute_aes_128_cmac(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); +void se_compute_aes_256_cmac(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_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); +void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); +void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); + void se_crypt_aes(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config, unsigned int mode, unsigned int (*callback)(void)); diff --git a/exosphere/smc_api.c b/exosphere/smc_api.c index 212ccb09a..1f3038d6e 100644 --- a/exosphere/smc_api.c +++ b/exosphere/smc_api.c @@ -180,6 +180,8 @@ uint32_t smc_wrapper_async(smc_args_t *args, uint32_t (*handler)(smc_args_t *), if (result == 0) { /* Pass the status check key back to userland. */ args->X[1] = key; + /* Early return, leaving g_is_smc_in_progress == 1 */ + return result; } else { /* No status to check. */ clear_smc_callback(key); @@ -247,6 +249,21 @@ uint32_t smc_load_aes_key(smc_args_t *args) { return smc_wrapper_sync(args, user_load_aes_key); } +uint32_t smc_crypt_aes_status_check(void *buf, uint64_t size) { + /* Buf and size are unused. */ + if (get_crypt_aes_done() == 0) { + return 3; + } + /* smc_crypt_aes is done now. */ + g_is_smc_in_progress = 0; + return 0; +} + +uint32_t smc_crypt_aes(smc_args_t *args) { + return smc_wrapper_async(args, user_crypt_aes, smc_crypt_aes_status_check); +} + + uint32_t smc_cpu_on(smc_args_t *args) { return cpu_on((uint32_t)args->X[1], args->X[2], args->X[3]); diff --git a/exosphere/smc_user.c b/exosphere/smc_user.c index 74ae455e3..64c8b11eb 100644 --- a/exosphere/smc_user.c +++ b/exosphere/smc_user.c @@ -5,6 +5,9 @@ #include "smc_user.h" #include "se.h" +/* Globals. */ +int g_crypt_aes_done = 0; + uint32_t user_load_aes_key(smc_args_t *args) { uint64_t sealed_kek[2]; uint64_t wrapped_key[2]; @@ -27,3 +30,61 @@ uint32_t user_load_aes_key(smc_args_t *args) { decrypt_data_into_keyslot(keyslot, 9, wrapped_key, 0x10); return 0; } + + +void set_crypt_aes_done(int done) { + g_crypt_aes_done = done & 1; +} + +int get_crypt_aes_done(void) { + return g_crypt_aes_done; +} + +uint32_t crypt_aes_done_handler(void) { + se_check_for_error(); + + set_crypt_aes_done(1); + + /* TODO: Manually trigger an SE interrupt (0x2C) */ +} + +uint32_t user_crypt_aes(smc_args_t *args) { + uint32_t keyslot = args->X[1] & 3; + uint32_t mode = (args->X[1] >> 4) & 3; + + uint64_t iv_ctr[2]; + iv_ctr[0] = args->X[2]; + iv_ctr[1] = args->X[3]; + + uint32_t in_ll_paddr = (uint32_t)(args->X[4]); + uint32_t out_ll_paddr = (uint32_t)(args->X[5]); + + size_t size = args->X[6]; + if (size & 0xF) { + panic(); + } + + set_crypt_aes_done(0); + + uint64_t result = 0; + switch (mode) { + case 0: /* CBC Encryption */ + se_aes_cbc_encrypt_insecure(keyslot, out_ll_paddr, in_ll_paddr, size, iv_ctr, crypt_aes_done_handler); + result = 0; + break; + case 1: /* CBC Decryption */ + se_aes_cbc_decrypt_insecure(keyslot, out_ll_paddr, in_ll_paddr, size, iv_ctr, crypt_aes_done_handler); + result = 0; + break; + case 2: /* CTR "Encryption" */ + se_aes_ctr_crypt_insecure(keyslot, out_ll_paddr, in_ll_paddr, size, iv_ctr, crypt_aes_done_handler); + result = 0; + break; + case 3: + default: + result = 1; + break; + } + + return result; +} \ No newline at end of file diff --git a/exosphere/smc_user.h b/exosphere/smc_user.h index c1815f39e..11c365970 100644 --- a/exosphere/smc_user.h +++ b/exosphere/smc_user.h @@ -18,4 +18,8 @@ uint32_t user_unwrap_rsa_wrapped_titlekey(smc_args_t *args); uint32_t user_load_titlekey(smc_args_t *args); uint32_t user_unwrap_aes_wrapped_titlekey(smc_args_t *args); + +void set_crypt_aes_done(int done); +int get_crypt_aes_done(void); + #endif \ No newline at end of file