From 8b9e65e76fc46ad1e56f01f1a8bda1dacd4de133 Mon Sep 17 00:00:00 2001 From: st4rk Date: Fri, 4 May 2018 00:15:29 -0700 Subject: [PATCH] keygen for 3.0.x, 4.0.x, 5.0.x added, 3.0.X FW booting, fixed TSEC wrong offset for 4.0.X --- ipl/hos.c | 231 ++++++++++++++++++++++++++++++++++++++++------------- ipl/main.c | 4 + ipl/pkg1.c | 9 ++- ipl/pmc.h | 3 + 4 files changed, 192 insertions(+), 55 deletions(-) diff --git a/ipl/hos.c b/ipl/hos.c index ce2965e..5f9b787 100755 --- a/ipl/hos.c +++ b/ipl/hos.c @@ -59,6 +59,13 @@ static const u8 ckey_keyseed[0x10] = static const u8 key8_keyseed[] = { 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 }; +static const u8 new_masterkey_seed[0x10] = + { 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 }; + +static const u8 new_per_console_key[0x10] = + { 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 }; + + static void _se_lock() { for (u32 i = 0; i < 16; i++) @@ -86,8 +93,8 @@ static void _se_lock() gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/ } -//Key derivation for < 4.0.0 -static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw) +// <-- key derivation algorithm +static int keygen(u8 *keyblob, u32 kb, void *tsec_fw) { u8 *tmp = (u8 *)malloc(0x10); @@ -97,13 +104,8 @@ static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw) //Get TSEC key. if (tsec_query(tmp, 1, tsec_fw) < 0) return 0; - se_aes_key_set(13, tmp, 0x10); - //Derive keyblob key from TSEC+SBK. - memcpy(tmp, keyblob_keyseeds[kb], 0x10); - se_aes_crypt_block_ecb(13, 0, tmp, tmp); - se_aes_unwrap_key(13, 14, tmp); - se_aes_key_clear(14); + se_aes_key_set(13, tmp, 0x10); //TODO: verify keyblob CMAC. //se_aes_unwrap_key(11, 13, cmac_keyseed); @@ -111,33 +113,134 @@ static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw) //if (!memcmp(keyblob, tmp, 0x10)) // return 0; - //Decrypt keyblob and set keyslots. - se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10); - se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); - se_aes_key_set(12, keyblob + 0x20, 0x10); + switch(kb) { + // 1.0.0~2.0.0 FW + case 0: { - //TODO: for some reason SE likes to hang if we don't execute an operation here. - memcpy(tmp, mkey_keyseed_retail, 0x10); - se_aes_crypt_block_ecb(12, 0, tmp, tmp); + //Derive keyblob key from TSEC+SBK. + memcpy(tmp, keyblob_keyseeds[kb], 0x10); + se_aes_crypt_block_ecb(13, 0, tmp, tmp); + se_aes_unwrap_key(13, 14, tmp); + se_aes_key_clear(14); - //Generate retail master key. - memcpy(tmp, mkey_keyseed_retail, 0x10); - se_aes_unwrap_key(12, 12, tmp); + se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10); + se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); + se_aes_key_set(12, keyblob + 0x20, 0x10); - memcpy(tmp, key8_keyseed, 0x10); - se_key_acc_ctrl(8, 0x15); - se_aes_unwrap_key(8, 12, tmp); + //TODO: for some reason SE likes to hang if we don't execute an operation here. + memcpy(tmp, mkey_keyseed_retail, 0x10); + se_aes_crypt_block_ecb(12, 0, tmp, tmp); - //Generate console specific key. - memcpy(tmp, ckey_keyseed, 0x10); - se_aes_unwrap_key(13, 13, tmp); + //Generate retail master key. + memcpy(tmp, mkey_keyseed_retail, 0x10); + se_aes_unwrap_key(12, 12, tmp); + + //Generate console specific key. + memcpy(tmp, ckey_keyseed, 0x10); + se_aes_unwrap_key(13, 13, tmp); + + memcpy(tmp, key8_keyseed, 0x10); + se_key_acc_ctrl(8, 0x15); + se_aes_unwrap_key(8, 12, tmp); + + se_key_acc_ctrl(12, 0xFF); + se_key_acc_ctrl(13, 0xFF); + } + break; + // 3.0.0~3.0.1 FW + case 1: + case 2: { + + // keyslot 10 + memcpy(tmp, keyblob_keyseeds[0], 0x10); + se_aes_crypt_block_ecb(13, 0, tmp, tmp); + se_aes_unwrap_key(10, 14, tmp); + + // keyslot 13 + memcpy(tmp, keyblob_keyseeds[kb], 0x10); + se_aes_crypt_block_ecb(13, 0, tmp, tmp); + se_aes_unwrap_key(13, 14, tmp); + + se_aes_key_clear(14); + se_aes_key_clear(15); + + se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10); + se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); + se_aes_key_set(12, keyblob + 0x20, 0x10); + + //TODO: for some reason SE likes to hang if we don't execute an operation here. + memcpy(tmp, mkey_keyseed_retail, 0x10); + se_aes_crypt_block_ecb(12, 0, tmp, tmp); + + //Generate retail master key. + memcpy(tmp, mkey_keyseed_retail, 0x10); + se_aes_unwrap_key(12, 12, tmp); + + //Generate console specific key. + memcpy(tmp, ckey_keyseed, 0x10); + se_aes_unwrap_key(13, 10, tmp); + se_aes_key_clear(10); + + memcpy(tmp, key8_keyseed, 0x10); + se_key_acc_ctrl(8, 0x15); + se_aes_unwrap_key(8, 12, tmp); + + se_key_acc_ctrl(12, 0xFF); + se_key_acc_ctrl(13, 0xFF); + } + break; + + // 4.0.0~5.0.1 FW + case 3: + case 4: { + se_key_acc_ctrl(14, 0x15); + se_key_acc_ctrl(15, 0x15); + + // keyslot 15 + memcpy(tmp, keyblob_keyseeds[0], 0x10); + se_aes_crypt_block_ecb(13, 0, tmp, tmp); + se_aes_unwrap_key(15, 14, tmp); + + // keyslot 13 + memcpy(tmp, keyblob_keyseeds[kb], 0x10); + se_aes_crypt_block_ecb(13, 0, tmp, tmp); + se_aes_unwrap_key(13, 14, tmp); + + se_aes_key_clear(14); + + se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10); + + // keyslot 11 + se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); + se_aes_key_set(12, keyblob + 0x20, 0x10); + + // keyslot 14 + memcpy(tmp, new_masterkey_seed, 0x10); + se_aes_unwrap_key(14, 12, tmp); + + // keyslot 12 + memcpy(tmp, mkey_keyseed_retail, 0x10); + se_aes_unwrap_key(12, 12, tmp); + + // keyslot 13 + memcpy(tmp, new_per_console_key, 0x10); + se_aes_unwrap_key(13, 15, tmp); + + // keyslot 15 + memcpy(tmp, ckey_keyseed, 0x10); + se_aes_unwrap_key(15, 13, tmp); + + se_key_acc_ctrl(12, 0xFF); + se_key_acc_ctrl(15, 0xFF); + } + break; + } - se_key_acc_ctrl(12, 0xFF); - se_key_acc_ctrl(13, 0xFF); free(tmp); } + typedef struct _launch_ctxt_t { void *keyblob; @@ -324,13 +427,17 @@ int hos_launch(ini_sec_t *cfg) if (!_read_emmc_pkg1(&ctxt)) return 0; - //XXX: remove this once we support 3+. - if (ctxt.pkg1_id->kb > 0) + //Read package1 and the correct keyblob. + if (!_read_emmc_pkg1(&ctxt)) return 0; + //XXX: remove this once we support 3+. + //if (ctxt.pkg1_id->kb > 0) + // return 0; + DPRINTF("loaded pkg1 and keyblob\n"); //Generate keys. - _keygen_1(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off); + keygen(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off); DPRINTF("generated keys\n"); //Decrypt and unpack package1 if we require parts of it. if (!ctxt.warmboot || !ctxt.secmon) @@ -347,41 +454,57 @@ DPRINTF("decrypted and unpacked pkg1\n"); //Set warmboot address in PMC. PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000; //Replace 'SecureMonitor' if requested. - if (ctxt.secmon) + if (ctxt.secmon) { memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size); + } else { //Else we patch it to allow for an unsigned package2. patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset; - for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++) - *(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val; - } -DPRINTF("loaded warmboot.bin and secmon\n"); + if (secmon_patchset != NULL) { + for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++) + *(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val; - //Read package2. - if (!_read_emmc_pkg2(&ctxt)) - return 0; -DPRINTF("read pkg2\n"); - //Decrypt package2 and parse KIP1 blobs in INI1 section. - pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2); + DPRINTF("loaded warmboot.bin and secmon\n"); + + //Read package2. + if (!_read_emmc_pkg2(&ctxt)) + return 0; - LIST_INIT(kip1_info); - pkg2_parse_kips(&kip1_info, pkg2_hdr); -DPRINTF("parsed ini1\n"); - //Use the kernel included in package2 in case we didn't load one already. - if (!ctxt.kernel) - { - ctxt.kernel = pkg2_hdr->data; - ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; + DPRINTF("read pkg2\n"); + //Decrypt package2 and parse KIP1 blobs in INI1 section. + pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2); + + LIST_INIT(kip1_info); + pkg2_parse_kips(&kip1_info, pkg2_hdr); + + DPRINTF("parsed ini1\n"); + + //Use the kernel included in package2 in case we didn't load one already. + if (!ctxt.kernel) + { + ctxt.kernel = pkg2_hdr->data; + ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; + } + + //Merge extra KIP1s into loaded ones. + LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link) + pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1); + + //Rebuild and encrypt package2. + pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info); + DPRINTF("rebuilt pkg2\n"); + } else { + //Read package2. + if (!_read_emmc_pkg2(&ctxt)) + return 0; + + DPRINTF("read pkg2\n"); + memcpy((void *)0xA9800000, ctxt.pkg2, ctxt.pkg2_size); + } } - //Merge extra KIP1s into loaded ones. - LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link) - pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1); - //Rebuild and encrypt package2. - pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info); -DPRINTF("rebuilt pkg2\n"); //Clear 'BootConfig'. memset((void *)0x4003D000, 0, 0x3000); diff --git a/ipl/main.c b/ipl/main.c index d8491a2..417e3fb 100755 --- a/ipl/main.c +++ b/ipl/main.c @@ -171,6 +171,10 @@ void config_se_brom() SE(SE_INT_STATUS_REG_OFFSET) = 0x1F; //Lock SSK (although it's not set and unused anyways). SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E; + // Clear the boot reason to avoid problems later + PMC(APBDEV_PMC_SCRATCH200) = 0x0; + PMC(APBDEV_PMC_RST_STATUS_0) = 0x0; + PMC(APBDEV_PMC_SCRATCH49_0) = 0x0; } void config_hw() diff --git a/ipl/pkg1.c b/ipl/pkg1.c index 2125ae0..7e927b3 100755 --- a/ipl/pkg1.c +++ b/ipl/pkg1.c @@ -40,6 +40,13 @@ PATCHSET_DEF(_secmon_2_patchset, { 0xAC8 + 0xB58, _NOP() } //Sections SHA2. ); +PATCHSET_DEF(_secmon_3_patchset, + //Patch package2 decryption and signature/hash checks. + { 0xAC8 + 0xA30, _NOP() }, //Header signature. + { 0xAC8 + 0xAC0, _NOP() }, //Version. + { 0xAC8 + 0xADC, _NOP() } //Sections SHA2. +); + /* * package1.1 header: * package1.1 layout: @@ -56,7 +63,7 @@ static const pkg1_id_t _pkg1_ids[] = { { "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, _secmon_2_patchset }, //2.0.0 { "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.0 { "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.1 - { "20170921172629", 3, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //4.0.0 + { "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //4.0.0 { "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //5.0.0 { NULL, 0, 0, 0, 0 } //End. }; diff --git a/ipl/pmc.h b/ipl/pmc.h index 520b74b..5bc3cf3 100755 --- a/ipl/pmc.h +++ b/ipl/pmc.h @@ -41,5 +41,8 @@ #define APBDEV_PMC_SCRATCH188 0x810 #define APBDEV_PMC_SCRATCH190 0x818 #define APBDEV_PMC_SCRATCH200 0x840 +#define APBDEV_PMC_RST_STATUS_0 0x1B4 +#define APBDEV_PMC_SECURE_SCRATCH49_0 0x3A4 +#define APBDEV_PMC_SCRATCH49_0 0x244 #endif