From 61f88868795335a539d08e1583da02a5b7ed2038 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 19 Feb 2018 21:47:11 -0800 Subject: [PATCH] Implement titlekey SMCs (with skeleton tkey API) --- exosphere/se.h | 6 ++-- exosphere/smc_api.c | 43 +++++++++++++++++++++++ exosphere/smc_user.c | 83 ++++++++++++++++++++++++++++++++++++++++++-- exosphere/titlekey.h | 15 ++++++++ 4 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 exosphere/titlekey.h diff --git a/exosphere/se.h b/exosphere/se.h index 6dce6dfa7..ef452485e 100644 --- a/exosphere/se.h +++ b/exosphere/se.h @@ -138,10 +138,10 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo 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); +/* Hash API */ +void se_calculate_sha256(void *dst, 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)); - - +/* RSA API */ void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void)); void se_get_exp_mod_output(void *buf, size_t size); diff --git a/exosphere/smc_api.c b/exosphere/smc_api.c index d6865d82c..de493c703 100644 --- a/exosphere/smc_api.c +++ b/exosphere/smc_api.c @@ -7,6 +7,7 @@ #include "smc_user.h" #include "se.h" #include "userpage.h" +#include "titlekey.h" #define SMC_USER_HANDLERS 0x13 #define SMC_PRIV_HANDLERS 0x9 @@ -305,7 +306,49 @@ uint32_t smc_rsa_oaep(smc_args_t *args) { return smc_wrapper_async(args, user_rsa_oaep, smc_exp_mod_get_result); } +uint32_t smc_unwrap_rsa_wrapped_titlekey_get_result(void *buf, uint64_t size) { + uint64_t *p_sealed_key = (uint64_t *)buf; + uint8_t rsa_wrapped_titlekey[0x100]; + uint8_t aes_wrapped_titlekey[0x10]; + uint8_t titlekey[0x10]; + uint64_t sealed_titlekey[2]; + if (get_exp_mod_done() != 1) { + return 3; + } + + if (size != 0x10) { + return 2; + } + + se_get_exp_mod_output(wrapped_titlekey, 0x100); + if (tkey_rsa_unwrap(aes_wrapped_titlekey, 0x10, rsa_wrapped_titlekey, 0x100) != 0x10) { + /* Failed to extract RSA wrapped key. */ + g_is_smc_in_progress = 0; + return 2; + } + + tkey_aes_unwrap(titlekey, 0x10, aes_wrapped_titlekey, 0x10); + tkey_seal(sealed_titlekey, 0x10, titlekey, 0x10); + + p_sealed_key[0] = sealed_titlekey[0]; + p_sealed_key[1] = sealed_titlekey[1]; + + /* smc_unwrap_aes_wrapped_titlekey is done now. */ + g_is_smc_in_progress = 0; + return 0; +} +uint32_t smc_unwrap_rsa_wrapped_titlekey(smc_args_t *args) { + return smc_wrapper_async(args, user_unwrap_rsa_wrapped_titlekey, smc_unwrap_rsa_wrapped_titlekey_get_result); +} + +uint32_t smc_load_titlekey(smc_args_t *args) { + return smc_wrapper_sync(args, user_load_titlekey); +} + +uint32_t smc_unwrap_aes_wrapped_titlekey(smc_args_t *args) { + return smc_wrapper_sync(args, user_unwrap_aes_wrapped_titlekey); +} 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 dbae79ecb..a2693f4e0 100644 --- a/exosphere/smc_user.c +++ b/exosphere/smc_user.c @@ -6,6 +6,7 @@ #include "smc_user.h" #include "se.h" #include "userpage.h" +#include "titlekey.h" /* Globals. */ int g_crypt_aes_done = 0; @@ -187,9 +188,7 @@ uint32_t user_rsa_oaep(smc_args_t *args) { uint8_t input[0x100]; upage_ref_t page_ref; - - size_t exponent_size = (size_t)args->X[4]; - + void *user_input = (void *)args->X[1]; void *user_modulus = (void *)args->X[2]; @@ -210,4 +209,82 @@ uint32_t user_rsa_oaep(smc_args_t *args) { se_exp_mod(0, input, 0x100, exp_mod_done_handler); return 0; +} + +uint32_t user_unwrap_rsa_wrapped_titlekey(smc_args_t *args) { + uint8_t modulus[0x100]; + uint8_t wrapped_key[0x100]; + + upage_ref_t page_ref; + + void *user_wrapped_key = (void *)args->X[1]; + void *user_modulus = (void *)args->X[2]; + unsigned int master_key_rev = (unsigned int)args->X[7]; + + /* TODO: Validate Master Key Revision. */ + + /* Copy user data into secure memory. */ + if (upage_init(&page_ref, user_wrapped_key) == 0) { + return 2; + } + if (user_copy_to_secure(&page_ref, wrapped_key, user_wrapped_key, 0x100) == 0) { + return 2; + } + if (user_copy_to_secure(&page_ref, modulus, user_modulus, 0x100) == 0) { + return 2; + } + + set_exp_mod_done(0); + + /* Expected salt occupies args->X[3] to args->X[6]. */ + tkey_set_expected_salt(&args->X[3]); + + tkey_set_master_key_rev(master_key_rev); + + /* Hardcode RSA keyslot 0. */ + set_rsa_keyslot(0, modulus, 0x100, g_rsa_private_exponent, 0x100); + se_exp_mod(0, wrapped_key, 0x100, exp_mod_done_handler); + + return 0; + +} + +uint32_t user_load_titlekey(smc_args_t *args) { + uint64_t sealed_titlekey[2]; + + uint32_t keyslot = (uint32_t)args->X[1]; + if (keyslot > 3) { + return 2; + } + + /* Copy keydata */ + sealed_titlekey[0] = args->X[2]; + sealed_titlekey[1] = args->X[3]; + + /* Unseal the key. */ + tkey_unseal(keyslot, sealed_titlekey, 0x10); + return 0; + +} + +uint32_t user_unwrap_aes_wrapped_titlekey(smc_args_t *args) { + uint64_t aes_wrapped_titlekey[2]; + uint8_t titlekey[0x10]; + uint64_t sealed_titlekey[2]; + + aes_wrapped_titlekey[0] = args->X[1]; + aes_wrapped_titlekey[1] = args->X[2]; + unsigned int master_key_rev = (unsigned int)args->X[3]; + + + /* TODO: Validate Master Key Revision. */ + tkey_set_master_key_rev(master_key_rev); + + + tkey_aes_unwrap(titlekey, 0x10, aes_wrapped_titlekey, 0x10); + tkey_seal(sealed_titlekey, 0x10, titlekey, 0x10); + + args->X[1] = sealed_titlekey[0]; + args->X[2] = sealed_titlekey[1]; + } \ No newline at end of file diff --git a/exosphere/titlekey.h b/exosphere/titlekey.h new file mode 100644 index 000000000..93c2547ed --- /dev/null +++ b/exosphere/titlekey.h @@ -0,0 +1,15 @@ +#ifndef EXOSPHERE_TITLEKEY_H +#define EXOSPHERE_TITLEKEY_H + +#include + +void tkey_set_expected_salt(uint64_t *salt); +void tkey_set_master_key_rev(unsigned int master_key_rev); + +size_t tkey_rsa_unwrap(void *dst, size_t dst_size, void *src, size_t src_size); + +void tkey_aes_unwrap(void *dst, size_t dst_size, const void *src, size_t src_size); +void tkey_seal(void *dst, size_t dst_size, const void *src, size_t src_size); +void tkey_unseal(unsigned int keyslot, const void *src, size_t src_size); + +#endif \ No newline at end of file