diff --git a/bootloader/config/config.c b/bootloader/config/config.c index 34b148b..adcfee4 100644 --- a/bootloader/config/config.c +++ b/bootloader/config/config.c @@ -45,6 +45,7 @@ void set_default_configuration() h_cfg.brand = NULL; h_cfg.tagline = NULL; h_cfg.errors = 0; + h_cfg.eks = NULL; h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; h_cfg.rcm_patched = true; h_cfg.emummc_force_disable = false; diff --git a/bootloader/config/config.h b/bootloader/config/config.h index 0410a7e..012fea9 100644 --- a/bootloader/config/config.h +++ b/bootloader/config/config.h @@ -17,6 +17,7 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ +#include "../hos/hos.h" #include "../utils/types.h" typedef struct _hekate_config @@ -38,6 +39,7 @@ typedef struct _hekate_config bool rcm_patched; u32 sbar_time_keeping; u32 errors; + hos_eks_mbr_t *eks; } hekate_config; void set_default_configuration(); diff --git a/bootloader/hos/hos.c b/bootloader/hos/hos.c index 73c53e6..6ee6bac 100644 --- a/bootloader/hos/hos.c +++ b/bootloader/hos/hos.c @@ -183,7 +183,114 @@ void _sysctr0_reset() SYSCTR0(SYSCTR0_COUNTERID11) = 0; } -int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt) +void hos_eks_get() +{ + // Check if EKS already found and parsed. + if (!h_cfg.eks) + { + u8 *mbr = calloc(512 , 1); + + // Read EKS blob. + sdmmc_storage_read(&sd_storage, 0, 1, mbr); + + // Decrypt EKS blob. + hos_eks_mbr_t *eks = (hos_eks_mbr_t *)(mbr + 0x10); + se_aes_crypt_ecb(14, 0, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Check if valid and for this unit. + if (eks->enabled && + eks->magic == HOS_EKS_MAGIC && + eks->magic2 == HOS_EKS_MAGIC && + eks->sbk_low[0] == FUSE(FUSE_PRIVATE_KEY0) && + eks->sbk_low[1] == FUSE(FUSE_PRIVATE_KEY1)) + { + h_cfg.eks = eks; + return; + } + + free(mbr); + } +} + +void hos_eks_save(u32 kb) +{ + if (kb >= KB_FIRMWARE_VERSION_700) + { + // Only 6 Master keys for now. + u8 key_idx = kb - KB_FIRMWARE_VERSION_700; + if (key_idx > 5) + return; + + if (!h_cfg.eks) + h_cfg.eks = calloc(512 , 1); + + // If matching blob doesn't exist, create it. + if (!(h_cfg.eks->enabled & (1 << key_idx))) + { + // Get keys. + u8 *keys = (u8 *)calloc(0x1000, 1); + se_get_aes_keys(keys + 0x800, keys, 0x10); + + // Set magic and personalized info. + h_cfg.eks->magic = HOS_EKS_MAGIC; + h_cfg.eks->magic2 = HOS_EKS_MAGIC; + h_cfg.eks->enabled |= 1 << key_idx; + h_cfg.eks->sbk_low[0] = FUSE(FUSE_PRIVATE_KEY0); + h_cfg.eks->sbk_low[1] = FUSE(FUSE_PRIVATE_KEY1); + + // Copy new keys. + memcpy(h_cfg.eks->keys[key_idx].dkg, keys + 10 * 0x10, 0x10); + memcpy(h_cfg.eks->keys[key_idx].mkk, keys + 12 * 0x10, 0x10); + memcpy(h_cfg.eks->keys[key_idx].fdk, keys + 13 * 0x10, 0x10); + memcpy(h_cfg.eks->keys[key_idx].dkk, keys + 15 * 0x10, 0x10); + + // Encrypt EKS. + u8 *eks = calloc(512 , 1); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS to SD. + u8 *mbr = calloc(512 , 1); + sdmmc_storage_read(&sd_storage, 0, 1, mbr); + memcpy(mbr + 0x10, eks, sizeof(hos_eks_mbr_t)); + sdmmc_storage_write(&sd_storage, 0, 1, mbr); + + free(eks); + free(mbr); + free(keys); + } + } +} + +void hos_eks_clear(u32 kb) +{ + if (h_cfg.eks && kb >= KB_FIRMWARE_VERSION_700) + { + // Check if Current Master key is enabled. + u8 key_idx = kb - KB_FIRMWARE_VERSION_700; + if (h_cfg.eks->enabled & (1 << key_idx)) + { + // Disable current Master key version. + h_cfg.eks->enabled &= ~(1 << key_idx); + + // Encrypt EKS. + u8 *eks = calloc(512 , 1); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS to SD. + u8 *mbr = calloc(512 , 1); + sdmmc_storage_read(&sd_storage, 0, 1, mbr); + memcpy(mbr + 0x10, eks, sizeof(hos_eks_mbr_t)); + sdmmc_storage_write(&sd_storage, 0, 1, mbr); + + free(eks); + free(mbr); + } + } +} + +int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt) { u8 tmp[0x20]; u32 retries = 0; @@ -226,7 +333,27 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt) } if (kb >= KB_FIRMWARE_VERSION_700) + { + // Use HOS EKS if it exists. + u8 key_idx = kb - KB_FIRMWARE_VERSION_700; + if (h_cfg.eks && (h_cfg.eks->enabled & (1 << key_idx))) + { + // Set Device keygen key to slot 10. + se_aes_key_set(10, h_cfg.eks->keys[key_idx].dkg, 0x10); + // Set Master key to slot 12. + se_aes_key_set(12, h_cfg.eks->keys[key_idx].mkk, 0x10); + // Set FW Device key key to slot 13. + se_aes_key_set(13, h_cfg.eks->keys[key_idx].fdk, 0x10); + // Set Device key to slot 15. + se_aes_key_set(15, h_cfg.eks->keys[key_idx].dkk, 0x10); + + // Lock FDK. + se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG); + } + + se_aes_key_clear(8); se_aes_unwrap_key(8, 12, package2_keyseed); + } else if (kb == KB_FIRMWARE_VERSION_620) { // Set TSEC key. @@ -538,7 +665,7 @@ int hos_launch(ini_sec_t *cfg) return 0; } - if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt, &ctxt)) + if (!hos_keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt, &ctxt)) return 0; gfx_printf("Generated keys\n"); if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600) @@ -610,9 +737,16 @@ int hos_launch(ini_sec_t *cfg) { _hos_crit_error("Pkg2 decryption failed!"); if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700) + { EPRINTF("Is Sept updated?"); + + // Clear EKS slot, in case something went wrong with sept keygen. + hos_eks_clear(ctxt.pkg1_id->kb); + } return 0; } + else if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700) + hos_eks_save(ctxt.pkg1_id->kb); // Save EKS slot if it doesn't exist. LIST_INIT(kip1_info); if (!pkg2_parse_kips(&kip1_info, pkg2_hdr, &ctxt.new_pkg2)) diff --git a/bootloader/hos/hos.h b/bootloader/hos/hos.h index 573066b..c7addd6 100644 --- a/bootloader/hos/hos.h +++ b/bootloader/hos/hos.h @@ -24,6 +24,8 @@ #include "../config/ini.h" #include "../sec/tsec.h" +#include + #define KB_FIRMWARE_VERSION_100_200 0 #define KB_FIRMWARE_VERSION_300 1 #define KB_FIRMWARE_VERSION_301 2 @@ -38,6 +40,35 @@ #define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 #define HOS_PKG11_MAGIC 0x31314B50 +#define HOS_EKS_MAGIC 0x30534B45 + +typedef struct _exo_ctxt_t +{ + bool no_user_exceptions; + bool user_pmu; + bool *cal0_blank; + bool *cal0_allow_writes_sys; +} exo_ctxt_t; + +typedef struct _hos_eks_keys_t +{ + u8 dkg[0x10]; + u8 mkk[0x10]; + u8 fdk[0x10]; + u8 dkk[0x10]; +} hos_eks_keys_t; + +typedef struct _hos_eks_mbr_t +{ + u32 magic; + u32 enabled; + u32 sbk_low[2]; + hos_eks_keys_t keys[6]; + u32 magic2; + u32 rsvd2[3]; +} hos_eks_mbr_t; + +static_assert(sizeof(hos_eks_mbr_t) < 424, "HOS EKS storage bigger than MBR!"); typedef struct _launch_ctxt_t { @@ -80,7 +111,10 @@ typedef struct _merge_kip_t link_t link; } merge_kip_t; -int hos_launch(ini_sec_t *cfg); -int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt); +void hos_eks_get(); +void hos_eks_save(u32 kb); +void hos_eks_clear(u32 kb); +int hos_launch(ini_sec_t *cfg); +int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt); #endif diff --git a/bootloader/hos/sept.c b/bootloader/hos/sept.c index 63a968e..d2b726c 100644 --- a/bootloader/hos/sept.c +++ b/bootloader/hos/sept.c @@ -71,6 +71,8 @@ extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); void check_sept(ini_sec_t *cfg_sec) { + hos_eks_get(); + // Check if non-hekate payload is used for sept and restore it. if (h_cfg.sept_run) { @@ -112,6 +114,14 @@ void check_sept(ini_sec_t *cfg_sec) if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) { + u8 key_idx = pkg1_id->kb - KB_FIRMWARE_VERSION_700; + if (h_cfg.eks && (h_cfg.eks->enabled & (1 << key_idx))) + { + h_cfg.sept_run = true; + EMC(EMC_SCRATCH0) |= EMC_SEPT_RUN; + goto out_free; + } + sdmmc_storage_end(&storage); reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb, cfg_sec); } diff --git a/nyx/nyx_gui/config/config.c b/nyx/nyx_gui/config/config.c index 95f13e8..ddf0565 100644 --- a/nyx/nyx_gui/config/config.c +++ b/nyx/nyx_gui/config/config.c @@ -37,7 +37,6 @@ void set_default_configuration() h_cfg.autoboot = 0; h_cfg.autoboot_list = 0; h_cfg.bootwait = 3; - h_cfg.verification = 1; h_cfg.se_keygen_done = 0; h_cfg.sbar_time_keeping = 0; h_cfg.backlight = 100; @@ -47,6 +46,7 @@ void set_default_configuration() h_cfg.brand = NULL; h_cfg.tagline = NULL; h_cfg.errors = 0; + h_cfg.eks = NULL; h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; h_cfg.rcm_patched = fuse_check_patched_rcm(); h_cfg.emummc_force_disable = false; diff --git a/nyx/nyx_gui/config/config.h b/nyx/nyx_gui/config/config.h index e3899bd..09a1944 100644 --- a/nyx/nyx_gui/config/config.h +++ b/nyx/nyx_gui/config/config.h @@ -17,6 +17,7 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ +#include "../hos/hos.h" #include "../utils/types.h" typedef struct _hekate_config @@ -38,6 +39,7 @@ typedef struct _hekate_config bool rcm_patched; u32 sbar_time_keeping; u32 errors; + hos_eks_mbr_t *eks; } hekate_config; typedef struct _nyx_config diff --git a/nyx/nyx_gui/frontend/gui_tools.c b/nyx/nyx_gui/frontend/gui_tools.c index 690b153..589b5bc 100644 --- a/nyx/nyx_gui/frontend/gui_tools.c +++ b/nyx/nyx_gui/frontend/gui_tools.c @@ -510,8 +510,13 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn) lv_label_set_text(lb_desc, txt_buf); manual_system_maintenance(true); + // Clear EKS slot, in case something went wrong with sept keygen. + hos_eks_clear(kb); + goto out; } + else if (kb >= KB_FIRMWARE_VERSION_700) + hos_eks_save(kb); // Save EKS slot if it doesn't exist. // Display info. s_printf(txt_buf + strlen(txt_buf), diff --git a/nyx/nyx_gui/hos/hos.c b/nyx/nyx_gui/hos/hos.c index 44a41cf..cb17792 100644 --- a/nyx/nyx_gui/hos/hos.c +++ b/nyx/nyx_gui/hos/hos.c @@ -90,7 +90,113 @@ static const u8 master_keyseed_620[0x10] = static const u8 console_keyseed_4xx_5xx[0x10] = { 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 }; -int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) +void hos_eks_get() +{ + // Check if EKS already found and parsed. + if (!h_cfg.eks) + { + u8 *mbr = calloc(512 , 1); + + // Read EKS blob. + sdmmc_storage_read(&sd_storage, 0, 1, mbr); + + // Decrypt EKS blob. + hos_eks_mbr_t *eks = (hos_eks_mbr_t *)(mbr + 0x10); + se_aes_crypt_ecb(14, 0, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Check if valid and for this unit. + if (eks->enabled && + eks->magic == HOS_EKS_MAGIC && + eks->magic2 == HOS_EKS_MAGIC && + eks->sbk_low[0] == FUSE(FUSE_PRIVATE_KEY0) && + eks->sbk_low[1] == FUSE(FUSE_PRIVATE_KEY1)) + { + h_cfg.eks = eks; + return; + } + + free(mbr); + } +} + +void hos_eks_save(u32 kb) +{ + if (kb >= KB_FIRMWARE_VERSION_700) + { + // Only 6 Master keys for now. + u8 key_idx = kb - KB_FIRMWARE_VERSION_700; + if (key_idx > 5) + return; + + if (!h_cfg.eks) + h_cfg.eks = calloc(512 , 1); + + // If matching blob doesn't exist, create it. + if (!(h_cfg.eks->enabled & (1 << key_idx))) + { + // Get keys. + u8 *keys = (u8 *)calloc(0x1000, 1); + se_get_aes_keys(keys + 0x800, keys, 0x10); + + // Set magic and personalized info. + h_cfg.eks->magic = HOS_EKS_MAGIC; + h_cfg.eks->magic2 = HOS_EKS_MAGIC; + h_cfg.eks->enabled |= 1 << key_idx; + h_cfg.eks->sbk_low[0] = FUSE(FUSE_PRIVATE_KEY0); + h_cfg.eks->sbk_low[1] = FUSE(FUSE_PRIVATE_KEY1); + + // Copy new keys. + memcpy(h_cfg.eks->keys[key_idx].dkg, keys + 10 * 0x10, 0x10); + memcpy(h_cfg.eks->keys[key_idx].mkk, keys + 12 * 0x10, 0x10); + memcpy(h_cfg.eks->keys[key_idx].fdk, keys + 13 * 0x10, 0x10); + memcpy(h_cfg.eks->keys[key_idx].dkk, keys + 15 * 0x10, 0x10); + + // Encrypt EKS. + u8 *eks = calloc(512 , 1); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS to SD. + u8 *mbr = calloc(512 , 1); + sdmmc_storage_read(&sd_storage, 0, 1, mbr); + memcpy(mbr + 0x10, eks, sizeof(hos_eks_mbr_t)); + sdmmc_storage_write(&sd_storage, 0, 1, mbr); + + free(eks); + free(mbr); + free(keys); + } + } +} + +void hos_eks_clear(u32 kb) +{ + if (h_cfg.eks && kb >= KB_FIRMWARE_VERSION_700) + { + // Check if Current Master key is enabled. + u8 key_idx = kb - KB_FIRMWARE_VERSION_700; + if (h_cfg.eks->enabled & (1 << key_idx)) + { + // Disable current Master key version. + h_cfg.eks->enabled &= ~(1 << key_idx); + + // Encrypt EKS. + u8 *eks = calloc(512 , 1); + memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t)); + se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t)); + + // Write EKS to SD. + u8 *mbr = calloc(512 , 1); + sdmmc_storage_read(&sd_storage, 0, 1, mbr); + memcpy(mbr + 0x10, eks, sizeof(hos_eks_mbr_t)); + sdmmc_storage_write(&sd_storage, 0, 1, mbr); + + free(eks); + free(mbr); + } + } +} +int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) { u8 tmp[0x20]; u32 retries = 0; @@ -133,7 +239,27 @@ int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt) } if (kb >= KB_FIRMWARE_VERSION_700) + { + // Use HOS EKS if it exists. + u8 key_idx = kb - KB_FIRMWARE_VERSION_700; + if (h_cfg.eks && (h_cfg.eks->enabled & (1 << key_idx))) + { + // Set Device keygen key to slot 10. + se_aes_key_set(10, h_cfg.eks->keys[key_idx].dkg, 0x10); + // Set Master key to slot 12. + se_aes_key_set(12, h_cfg.eks->keys[key_idx].mkk, 0x10); + // Set FW Device key key to slot 13. + se_aes_key_set(13, h_cfg.eks->keys[key_idx].fdk, 0x10); + // Set Device key to slot 15. + se_aes_key_set(15, h_cfg.eks->keys[key_idx].dkk, 0x10); + + // Lock FDK. + se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG); + } + + se_aes_key_clear(8); se_aes_unwrap_key(8, 12, package2_keyseed); + } else if (kb == KB_FIRMWARE_VERSION_620) { // Set TSEC key. diff --git a/nyx/nyx_gui/hos/hos.h b/nyx/nyx_gui/hos/hos.h index a315e9d..ca8e605 100644 --- a/nyx/nyx_gui/hos/hos.h +++ b/nyx/nyx_gui/hos/hos.h @@ -24,6 +24,8 @@ #include "../config/ini.h" #include "../sec/tsec.h" +#include + #define KB_FIRMWARE_VERSION_100_200 0 #define KB_FIRMWARE_VERSION_300 1 #define KB_FIRMWARE_VERSION_301 2 @@ -38,6 +40,35 @@ #define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910 #define HOS_PKG11_MAGIC 0x31314B50 +#define HOS_EKS_MAGIC 0x30534B45 + +typedef struct _exo_ctxt_t +{ + bool no_user_exceptions; + bool user_pmu; + bool *cal0_blank; + bool *cal0_allow_writes_sys; +} exo_ctxt_t; + +typedef struct _hos_eks_keys_t +{ + u8 dkg[0x10]; + u8 mkk[0x10]; + u8 fdk[0x10]; + u8 dkk[0x10]; +} hos_eks_keys_t; + +typedef struct _hos_eks_mbr_t +{ + u32 magic; + u32 enabled; + u32 sbk_low[2]; + hos_eks_keys_t keys[6]; + u32 magic2; + u32 rsvd2[3]; +} hos_eks_mbr_t; + +static_assert(sizeof(hos_eks_mbr_t) < 424, "HOS EKS storage bigger than MBR!"); typedef struct _launch_ctxt_t { @@ -53,23 +84,19 @@ typedef struct _launch_ctxt_t void *pkg2; u32 pkg2_size; + bool new_pkg2; - bool new_pkg2; void *kernel; u32 kernel_size; link_t kip1_list; char* kip1_patches; - bool svcperm; - bool debugmode; - bool stock; - bool atmosphere; - bool exo_no_user_exceptions; - bool emuMMC; - ini_sec_t *cfg; } launch_ctxt_t; -int keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt); +void hos_eks_get(); +void hos_eks_save(u32 kb); +void hos_eks_clear(u32 kb); +int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt); #endif diff --git a/nyx/nyx_gui/hos/sept.c b/nyx/nyx_gui/hos/sept.c index 54acf98..ab728d8 100644 --- a/nyx/nyx_gui/hos/sept.c +++ b/nyx/nyx_gui/hos/sept.c @@ -70,6 +70,8 @@ extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); void check_sept() { + hos_eks_get(); + // Check if non-hekate payload is used for sept and restore it. if (h_cfg.sept_run) { @@ -107,6 +109,14 @@ void check_sept() if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) { + u8 key_idx = pkg1_id->kb - KB_FIRMWARE_VERSION_700; + if (h_cfg.eks && (h_cfg.eks->enabled & (1 << key_idx))) + { + h_cfg.sept_run = true; + EMC(EMC_SCRATCH0) |= EMC_SEPT_RUN; + goto out_free; + } + sdmmc_storage_end(&storage); reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb); }