fusee: fix support for mariko key derivation/package1 parsing

This commit is contained in:
Michael Scire 2020-12-31 23:29:00 -08:00 committed by SciresM
parent f7898f3519
commit b7895ff2a7
8 changed files with 165 additions and 41 deletions

View file

@ -305,21 +305,6 @@ void fuse_get_hardware_info(void *dst) {
memcpy(dst, hw_info, 0x10);
}
/* Check if have a new ODM fuse format. */
bool fuse_is_new_format(void) {
return ((fuse_get_reserved_odm(4) & 0x800) && (fuse_get_reserved_odm(0) == 0x8E61ECAE) && (fuse_get_reserved_odm(1) == 0xF2BA3BB2));
}
/* Get the DeviceUniqueKeyGeneration. */
uint32_t fuse_get_device_unique_key_generation(void) {
if (fuse_is_new_format()) {
return (fuse_get_reserved_odm(2) & 0x1F);
} else {
return 0;
}
}
/* Get the SocType from the HardwareType. */
uint32_t fuse_get_soc_type(void) {
switch (fuse_get_hardware_type()) {
@ -336,6 +321,21 @@ uint32_t fuse_get_soc_type(void) {
}
}
/* Check if have a new ODM fuse format. */
bool fuse_is_new_format(void) {
return ((fuse_get_reserved_odm(4) & 0x800) && (fuse_get_reserved_odm(0) == 0x8E61ECAE) && (fuse_get_reserved_odm(1) == 0xF2BA3BB2));
}
/* Get the DeviceUniqueKeyGeneration. */
uint32_t fuse_get_device_unique_key_generation(void) {
if (fuse_get_soc_type() != 0 || fuse_is_new_format()) {
return (fuse_get_reserved_odm(2) & 0x1F);
} else {
return 0;
}
}
/* Get the Regulator type. */
uint32_t fuse_get_regulator(void) {
if (fuse_get_soc_type() == 1) {

View file

@ -61,13 +61,8 @@ static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_800 - MAST
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* MasterKek seed 07. */
};
static const uint8_t AL16 master_kek_seeds_mariko[MASTERKEY_REVISION_910_CURRENT - MASTERKEY_REVISION_500_510][0x10] = {
{0x77, 0x60, 0x5A, 0xD2, 0xEE, 0x6E, 0xF8, 0x3C, 0x3F, 0x72, 0xE2, 0x59, 0x9D, 0xAC, 0x5E, 0x56}, /* Mariko MasterKek seed 05. */
{0x1E, 0x80, 0xB8, 0x17, 0x3E, 0xC0, 0x60, 0xAA, 0x11, 0xBE, 0x1A, 0x4A, 0xA6, 0x6F, 0xE4, 0xAE}, /* Mariko MasterKek seed 06. */
{0x94, 0x08, 0x67, 0xBD, 0x0A, 0x00, 0x38, 0x84, 0x11, 0xD3, 0x1A, 0xDB, 0xDD, 0x8D, 0xF1, 0x8A}, /* Mariko MasterKek seed 07. */
{0x5C, 0x24, 0xE3, 0xB8, 0xB4, 0xF7, 0x00, 0xC2, 0x3C, 0xFD, 0x0A, 0xCE, 0x13, 0xC3, 0xDC, 0x23}, /* Mariko MasterKek seed 08. */
{0x86, 0x69, 0xF0, 0x09, 0x87, 0xC8, 0x05, 0xAE, 0xB5, 0x7B, 0x48, 0x74, 0xDE, 0x62, 0xA6, 0x13}, /* Mariko MasterKek seed 09. */
{0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82}, /* Mariko MasterKek seed 0A. */
static const uint8_t AL16 master_kek_seed_mariko[0x10] = { /* TODO: Update on next change of keys. */
0x0E, 0x44, 0x0C, 0xED, 0xB4, 0x36, 0xC0, 0x3F, 0xAA, 0x1D, 0xAE, 0xBF, 0x62, 0xB1, 0x09, 0x82, /* Mariko MasterKek seed 0A. */
};
static nx_dec_keyblob_t AL16 g_dec_keyblobs[32];
@ -227,7 +222,7 @@ int derive_nx_keydata_mariko(uint32_t target_firmware) {
/* Derive the device and master keys. */
/* NOTE: Keyslots 7 and 10 are chosen here so we don't overwrite critical key material (KEK, BEK, SBK and SSK). */
decrypt_data_into_keyslot(0xA, 0xE, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0x7, 0xC, &master_kek_seeds_mariko[target_firmware - MASTERKEY_REVISION_600_610], 0x10);
decrypt_data_into_keyslot(0x7, 0xC, master_kek_seed_mariko, 0x10);
decrypt_data_into_keyslot(0x7, 0x7, masterkey_seed, 0x10);
/* Setup master key revision, derive older master keys for use. */
@ -237,7 +232,7 @@ int derive_nx_keydata_mariko(uint32_t target_firmware) {
static void generate_specific_aes_key(void *dst, const void *wrapped_key, bool should_mask, uint32_t target_firmware, uint32_t generation) {
unsigned int keyslot = devkey_get_keyslot(generation);
if (fuse_get_bootrom_patch_version() < 0x7F) {
if (fuse_get_soc_type() == 0 && fuse_get_bootrom_patch_version() < 0x7F) {
/* On dev units, use a fixed "all-zeroes" seed. */
/* Yes, this data really is all-zero in actual TrustZone .rodata. */
static const uint8_t AL16 dev_specific_aes_key_source[0x10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

View file

@ -80,7 +80,7 @@ static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */
{0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
{0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
};
static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
@ -91,7 +91,7 @@ static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */
{0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 New Device Keygen Source. */
{0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
{0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
};
/* Determine the current SoC for Mariko specific code. */
@ -169,6 +169,8 @@ unsigned int mkey_get_keyslot(unsigned int revision) {
}
void derive_new_device_keys(bool is_retail, unsigned int keygen_keyslot, unsigned int target_firmware) {
const bool is_mariko = is_soc_mariko();
uint8_t work_buffer[0x10];
for (unsigned int revision = 0; revision < MASTERKEY_NUM_NEW_DEVICE_KEYS; revision++) {
const unsigned int relative_revision = revision + MASTERKEY_REVISION_400_410;
@ -178,13 +180,17 @@ void derive_new_device_keys(bool is_retail, unsigned int keygen_keyslot, unsigne
if (relative_revision > mkey_get_revision()) {
break;
} else if (relative_revision == mkey_get_revision()) {
/* On 7.0.0, sept will have derived this key for us already. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
/* On 7.0.0 erista, sept will have derived this key for us already. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0 || is_mariko) {
decrypt_data_into_keyslot(is_mariko ? KEYSLOT_SWITCH_DEVICEKEY_MARIKO : KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
}
} else {
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10);
set_old_devkey(relative_revision, work_buffer);
if (revision == 0 && is_mariko) {
set_aes_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, work_buffer, 0x10);
}
}
}
}
@ -209,6 +215,6 @@ unsigned int devkey_get_keyslot(unsigned int revision) {
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
return KEYSLOT_SWITCH_TEMPKEY;
} else {
return KEYSLOT_SWITCH_DEVICEKEY;
return is_soc_mariko() ? KEYSLOT_SWITCH_DEVICEKEY_MARIKO : KEYSLOT_SWITCH_DEVICEKEY;
}
}

View file

@ -907,9 +907,7 @@ uint32_t nxboot_main(void) {
}
/* Derive new device keys. */
if (!is_mariko) {
derive_new_device_keys(fuse_get_hardware_state() != 0, KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY, target_firmware);
}
/* Set the system partition's keys. */
if (fsdev_register_keys("system", target_firmware, BisPartition_UserSystem) != 0) {
@ -1001,7 +999,7 @@ uint32_t nxboot_main(void) {
/* Copy the warmboot firmware and set the address in PMC if necessary. */
if (warmboot_fw && (warmboot_fw_size > 0)) {
memcpy(warmboot_memaddr, warmboot_fw, warmboot_fw_size);
if (!is_mariko && (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0)) {
if (!is_mariko && (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0)) {
pmc->scratch1 = (uint32_t)warmboot_memaddr;
}
}
@ -1011,7 +1009,7 @@ uint32_t nxboot_main(void) {
/* TODO */
} else {
/* Set 3.0.0/3.0.1/3.0.2 warmboot security check. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware == ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
const package1loader_header_t *package1loader_header = (const package1loader_header_t *)package1loader;
if (!strcmp(package1loader_header->build_timestamp, "20170519101410")) {
pmc->secure_scratch32 = 0xE3; /* Warmboot 3.0.0 security check.*/

View file

@ -18,10 +18,38 @@
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include "../../../fusee/common/log.h"
#include "package1.h"
#include "bct.h"
#include "se.h"
static const uint8_t custom_public_key[0x100] = {
0x59, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0xFF,
};
static bool is_custom_public_key_erista(const void *bct) {
return memcmp((const uint8_t *)bct + 0x210, custom_public_key, sizeof(custom_public_key)) == 0;
}
//static bool is_custom_public_key_mariko(const void *bct) {
// return memcmp((const uint8_t *)bct + 0x10, custom_public_key, sizeof(custom_public_key)) == 0;
//}
int package1_read_and_parse_boot0_erista(void **package1loader, size_t *package1loader_size, nx_keyblob_t *keyblobs, uint32_t *revision, FILE *boot0) {
nvboot_config_table *bct; /* Normal firmware BCT, primary. TODO: check? */
nv_bootloader_info *pk1l_info; /* TODO: check? */
@ -50,6 +78,19 @@ int package1_read_and_parse_boot0_erista(void **package1loader, size_t *package1
free(bct);
return -1;
}
/* If custom public key, use bct-2 instead of bct 0. */
if (is_custom_public_key_erista(bct)) {
if (fseek(boot0, fpos + 0x4000 * 2, SEEK_SET) != 0) {
free(bct);
return -1;
}
if (fread(bct, sizeof(nvboot_config_table), 1, boot0) == 0) {
free(bct);
return -1;
}
}
if (bct->bootloader_used < 1 || pk1l_info->version < 1) {
free(bct);
errno = EILSEQ;
@ -91,7 +132,59 @@ int package1_read_and_parse_boot0_erista(void **package1loader, size_t *package1
}
int package1_read_and_parse_boot0_mariko(void **package1loader, size_t *package1loader_size, FILE *boot0) {
/* TODO */
/* TODO: Actually parse BOOT0 to locate package1ldr. */
size_t fpos, pk1l_offset;
fpos = ftell(boot0);
pk1l_offset = 0x100000;
/* Read the OEM header. */
pk11_mariko_oem_header_t oem_header;
if (fseek(boot0, fpos + pk1l_offset, SEEK_SET) != 0) {
return -1;
}
if (fread(&oem_header, sizeof(oem_header), 1, boot0) == 0) {
return -1;
}
/* Sanity check the size. */
if (oem_header.bl_size < 2 * sizeof(package1loader_header_t)) {
return -1;
}
/* Set the size. */
*package1loader_size = oem_header.bl_size;
/* Allocate pk11. */
(*package1loader) = memalign(0x10000, *package1loader_size);
if (*package1loader == NULL) {
errno = ENOMEM;
return -1;
}
/* Read pk11. */
if (fread(*package1loader, *package1loader_size, 1, boot0) == 0) {
return -1;
}
/* Copy the plaintext header. */
package1loader_header_t dec_header;
memcpy(&dec_header, *package1loader, sizeof(dec_header));
/* Decrypt the binary. */
const uint8_t __attribute__((aligned(16))) iv[16] = {0};
se_aes_128_cbc_decrypt(KEYSLOT_SWITCH_BEK_MARIKO, *package1loader, *package1loader_size, *package1loader, *package1loader_size, iv);
/* Validate the decryption. */
if (memcmp(&dec_header, (const uint8_t *)*package1loader + sizeof(dec_header), sizeof(dec_header)) != 0) {
print(SCREEN_LOG_LEVEL_DEBUG, "Decrypted package1loader is invalid...\n");
return -1;
}
/* Copy out the first header. */
memcpy(*package1loader, &dec_header, sizeof(dec_header));
return 0;
}

View file

@ -44,6 +44,19 @@ typedef struct {
uint8_t data[];
} package1_header_t;
typedef struct {
uint8_t aes_mac[0x10];
uint8_t rsa_sig[0x100];
uint8_t salt[0x20];
uint8_t hash[0x20];
uint32_t bl_version;
uint32_t bl_size;
uint32_t bl_load_addr;
uint32_t bl_entrypoint;
uint8_t _0x160[0x10];
uint8_t data[];
} pk11_mariko_oem_header_t;
int package1_read_and_parse_boot0_erista(void **package1loader, size_t *package1loader_size, nx_keyblob_t *keyblobs, uint32_t *revision, FILE *boot0);
int package1_read_and_parse_boot0_mariko(void **package1loader, size_t *package1loader_size, FILE *boot0);

View file

@ -591,6 +591,20 @@ void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, co
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
}
void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
generic_panic();
}
se->SE_CONFIG = (ALG_AES_DEC | DST_MEMORY) | (0x000 << 16);
se->SE_CRYPTO_CONFIG = (keyslot << 24) | 0x66;
set_aes_keyslot_iv(keyslot, iv, 0x10);
se->SE_CRYPTO_LAST_BLOCK = (src_size >> 4) - 1;
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
}
/* SHA256 Implementation. */
void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();

View file

@ -38,8 +38,12 @@
#define KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY 0xA
/* Mariko keyslots. */
#define KEYSLOT_SWITCH_DEVICEKEY_MARIKO 0x6
#define KEYSLOT_SWITCH_MASTERKEY_MARIKO 0x7
#define KEYSLOT_SWITCH_KEK_MARIKO 0xC
#define KEYSLOT_SWITCH_BEK_MARIKO 0xD
#define KEYSLOT_AES_MAX 0x10
#define KEYSLOT_RSA_MAX 0x2
@ -194,6 +198,7 @@ void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_si
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_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv);
void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv);
/* Hash API */
void se_calculate_sha256(void *dst, const void *src, size_t src_size);