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

This commit is contained in:
st4rk 2018-05-04 00:15:29 -07:00
parent e7373548fa
commit 8b9e65e76f
4 changed files with 192 additions and 55 deletions

231
ipl/hos.c
View file

@ -59,6 +59,13 @@ static const u8 ckey_keyseed[0x10] =
static const u8 key8_keyseed[] = static const u8 key8_keyseed[] =
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 }; { 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() static void _se_lock()
{ {
for (u32 i = 0; i < 16; i++) 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);*/ gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
} }
//Key derivation for < 4.0.0 // <-- key derivation algorithm
static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw) static int keygen(u8 *keyblob, u32 kb, void *tsec_fw)
{ {
u8 *tmp = (u8 *)malloc(0x10); u8 *tmp = (u8 *)malloc(0x10);
@ -97,13 +104,8 @@ static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw)
//Get TSEC key. //Get TSEC key.
if (tsec_query(tmp, 1, tsec_fw) < 0) if (tsec_query(tmp, 1, tsec_fw) < 0)
return 0; return 0;
se_aes_key_set(13, tmp, 0x10);
//Derive keyblob key from TSEC+SBK. se_aes_key_set(13, tmp, 0x10);
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);
//TODO: verify keyblob CMAC. //TODO: verify keyblob CMAC.
//se_aes_unwrap_key(11, 13, cmac_keyseed); //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)) //if (!memcmp(keyblob, tmp, 0x10))
// return 0; // return 0;
//Decrypt keyblob and set keyslots. switch(kb) {
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10); // 1.0.0~2.0.0 FW
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); case 0: {
se_aes_key_set(12, keyblob + 0x20, 0x10);
//TODO: for some reason SE likes to hang if we don't execute an operation here. //Derive keyblob key from TSEC+SBK.
memcpy(tmp, mkey_keyseed_retail, 0x10); memcpy(tmp, keyblob_keyseeds[kb], 0x10);
se_aes_crypt_block_ecb(12, 0, tmp, tmp); 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. se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
memcpy(tmp, mkey_keyseed_retail, 0x10); se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10);
se_aes_unwrap_key(12, 12, tmp); se_aes_key_set(12, keyblob + 0x20, 0x10);
memcpy(tmp, key8_keyseed, 0x10); //TODO: for some reason SE likes to hang if we don't execute an operation here.
se_key_acc_ctrl(8, 0x15); memcpy(tmp, mkey_keyseed_retail, 0x10);
se_aes_unwrap_key(8, 12, tmp); se_aes_crypt_block_ecb(12, 0, tmp, tmp);
//Generate console specific key. //Generate retail master key.
memcpy(tmp, ckey_keyseed, 0x10); memcpy(tmp, mkey_keyseed_retail, 0x10);
se_aes_unwrap_key(13, 13, tmp); 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); free(tmp);
} }
typedef struct _launch_ctxt_t typedef struct _launch_ctxt_t
{ {
void *keyblob; void *keyblob;
@ -324,13 +427,17 @@ int hos_launch(ini_sec_t *cfg)
if (!_read_emmc_pkg1(&ctxt)) if (!_read_emmc_pkg1(&ctxt))
return 0; return 0;
//XXX: remove this once we support 3+. //Read package1 and the correct keyblob.
if (ctxt.pkg1_id->kb > 0) if (!_read_emmc_pkg1(&ctxt))
return 0; return 0;
//XXX: remove this once we support 3+.
//if (ctxt.pkg1_id->kb > 0)
// return 0;
DPRINTF("loaded pkg1 and keyblob\n"); DPRINTF("loaded pkg1 and keyblob\n");
//Generate keys. //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"); DPRINTF("generated keys\n");
//Decrypt and unpack package1 if we require parts of it. //Decrypt and unpack package1 if we require parts of it.
if (!ctxt.warmboot || !ctxt.secmon) if (!ctxt.warmboot || !ctxt.secmon)
@ -347,41 +454,57 @@ DPRINTF("decrypted and unpacked pkg1\n");
//Set warmboot address in PMC. //Set warmboot address in PMC.
PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000; PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000;
//Replace 'SecureMonitor' if requested. //Replace 'SecureMonitor' if requested.
if (ctxt.secmon) if (ctxt.secmon) {
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size); memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
}
else else
{ {
//Else we patch it to allow for an unsigned package2. //Else we patch it to allow for an unsigned package2.
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset; patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++) if (secmon_patchset != NULL) {
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val; 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");
//Read package2. DPRINTF("loaded warmboot.bin and secmon\n");
if (!_read_emmc_pkg2(&ctxt))
return 0; //Read package2.
DPRINTF("read pkg2\n"); if (!_read_emmc_pkg2(&ctxt))
//Decrypt package2 and parse KIP1 blobs in INI1 section. return 0;
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
LIST_INIT(kip1_info); DPRINTF("read pkg2\n");
pkg2_parse_kips(&kip1_info, pkg2_hdr); //Decrypt package2 and parse KIP1 blobs in INI1 section.
DPRINTF("parsed ini1\n"); pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
//Use the kernel included in package2 in case we didn't load one already.
if (!ctxt.kernel) LIST_INIT(kip1_info);
{ pkg2_parse_kips(&kip1_info, pkg2_hdr);
ctxt.kernel = pkg2_hdr->data;
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; 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'. //Clear 'BootConfig'.
memset((void *)0x4003D000, 0, 0x3000); memset((void *)0x4003D000, 0, 0x3000);

View file

@ -171,6 +171,10 @@ void config_se_brom()
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F; SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
//Lock SSK (although it's not set and unused anyways). //Lock SSK (although it's not set and unused anyways).
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E; 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() void config_hw()

View file

@ -40,6 +40,13 @@ PATCHSET_DEF(_secmon_2_patchset,
{ 0xAC8 + 0xB58, _NOP() } //Sections SHA2. { 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: <wb, ldr, sm> * package1.1 header: <wb, ldr, sm>
* package1.1 layout: * 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 { "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 { "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.1 { "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 { "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //5.0.0
{ NULL, 0, 0, 0, 0 } //End. { NULL, 0, 0, 0, 0 } //End.
}; };

View file

@ -41,5 +41,8 @@
#define APBDEV_PMC_SCRATCH188 0x810 #define APBDEV_PMC_SCRATCH188 0x810
#define APBDEV_PMC_SCRATCH190 0x818 #define APBDEV_PMC_SCRATCH190 0x818
#define APBDEV_PMC_SCRATCH200 0x840 #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 #endif