Add basic support to fusee for multiple tsec_root_keys.

This commit is contained in:
Michael Scire 2019-01-30 04:14:00 -08:00
parent 3d6405be85
commit f78fd29e38
9 changed files with 81 additions and 52 deletions

View File

@ -24,11 +24,12 @@
#define ATMOSPHERE_TARGET_FIRMWARE_500 5
#define ATMOSPHERE_TARGET_FIRMWARE_600 6
#define ATMOSPHERE_TARGET_FIRMWARE_620 7
#define ATMOSPHERE_TARGET_FIRMWARE_700 8
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_620
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_700
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_620
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_700
/* TODO: What should this be, for release? */
#define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT

View File

@ -197,12 +197,14 @@ void extkeys_initialize_keyset(fusee_extkeys_t *keyset, FILE *f) {
continue;
}
int matched_key = 0;
if (strcmp(key, "tsec_root_key") == 0 || strcmp(key, "tsec_root_key_00") == 0) {
parse_hex_key(keyset->tsec_root_key, value, sizeof(keyset->tsec_root_key));
matched_key = 1;
} else {
char test_name[0x100] = {0};
for (unsigned int i = 0; i < 0x20 && !matched_key; i++) {
snprintf(test_name, sizeof(test_name), "tsec_root_key_%02x", i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->tsec_root_keys[i], value, sizeof(keyset->tsec_root_keys[i]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "master_kek_%02x", i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->master_keks[i], value, sizeof(keyset->master_keks[i]));
@ -213,4 +215,3 @@ void extkeys_initialize_keyset(fusee_extkeys_t *keyset, FILE *f) {
}
}
}
}

View File

@ -22,7 +22,7 @@
#include "masterkey.h"
typedef struct {
unsigned char tsec_root_key[0x10];
unsigned char tsec_root_keys[0x20][0x10];
unsigned char master_keks[0x20][0x10];
} fusee_extkeys_t;

View File

@ -54,8 +54,9 @@ static const uint8_t AL16 masterkey_4x_seed[0x10] = {
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
};
static const uint8_t AL16 new_master_kek_seeds[1][0x10] = {
static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_600_610][0x10] = {
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, /* MasterKek seed 06. */
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* MasterKek seed 07. */
};
static nx_dec_keyblob_t AL16 g_dec_keyblobs[32];
@ -118,7 +119,7 @@ int load_package1_key(uint32_t revision) {
}
/* Derive all Switch keys. */
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_key, void *tsec_root_key, unsigned int *out_keygen_type) {
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_key, void *tsec_root_keys, unsigned int *out_keygen_type) {
uint8_t AL16 work_buffer[0x10];
uint8_t AL16 zeroes[0x10] = {0};
@ -142,14 +143,31 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
/* Do 6.2.0+ keygen. */
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620) {
uint32_t desired_keyblob;
switch (target_firmware) {
case ATMOSPHERE_TARGET_FIRMWARE_620:
desired_keyblob = MASTERKEY_REVISION_620;
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
desired_keyblob = MASTERKEY_REVISION_700_CURRENT;
break;
default:
fatal_error("Unknown target firmware: %02x!", target_firmware);
break;
}
/* Try emulation result. */
for (unsigned int rev = MASTERKEY_REVISION_620; rev < MASTERKEY_REVISION_MAX; rev++) {
void *tsec_root_key = (void *)((uintptr_t)tsec_root_keys + 0x10 * (rev - MASTERKEY_REVISION_620));
if (memcmp(tsec_root_key, zeroes, 0x10) != 0) {
/* We got a valid key from emulation. */
set_aes_keyslot(0xC, tsec_root_key, 0x10);
for (unsigned int rev = MASTERKEY_REVISION_620_CURRENT; rev < MASTERKEY_REVISION_MAX; rev++) {
se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, new_master_kek_seeds[rev - MASTERKEY_REVISION_620_CURRENT], 0x10);
se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, new_master_kek_seeds[rev - MASTERKEY_REVISION_620], 0x10);
memcpy(g_dec_keyblobs[rev].master_kek, work_buffer, 0x10);
}
} else {
}
if (memcmp(g_dec_keyblobs[desired_keyblob].master_kek, zeroes, 0x10) == 0) {
/* Try reading the keys from a file. */
const char *keyfile = fuse_get_retail_type() != 0 ? "atmosphere/prod.keys" : "atmosphere/dev.keys";
FILE *extkey_file = fopen(keyfile, "r");
@ -159,20 +177,18 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
}
extkeys_initialize_keyset(&extkeys, extkey_file);
fclose(extkey_file);
if (memcmp(extkeys.tsec_root_key, zeroes, 0x10) != 0) {
set_aes_keyslot(0xC, extkeys.tsec_root_key, 0x10);
for (unsigned int rev = MASTERKEY_REVISION_620_CURRENT; rev < MASTERKEY_REVISION_MAX; rev++) {
se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, new_master_kek_seeds[rev - MASTERKEY_REVISION_620_CURRENT], 0x10);
for (unsigned int rev = MASTERKEY_REVISION_620; rev < MASTERKEY_REVISION_MAX; rev++) {
if (memcmp(extkeys.tsec_root_keys[rev - MASTERKEY_REVISION_620], zeroes, 0x10) != 0) {
set_aes_keyslot(0xC, extkeys.tsec_root_keys[rev - MASTERKEY_REVISION_620], 0x10);
se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, new_master_kek_seeds[rev - MASTERKEY_REVISION_620], 0x10);
memcpy(g_dec_keyblobs[rev].master_kek, work_buffer, 0x10);
}
} else {
for (unsigned int rev = MASTERKEY_REVISION_620_CURRENT; rev < MASTERKEY_REVISION_MAX; rev++) {
memcpy(g_dec_keyblobs[rev].master_kek, extkeys.master_keks[rev], 0x10);
}
}
}
if (memcmp(g_dec_keyblobs[available_revision].master_kek, zeroes, 0x10) == 0) {
fatal_error("Error: failed to derive master_kek_%02x!", available_revision);
}

View File

@ -20,7 +20,7 @@
/* This is glue code to enable master key support across versions. */
/* TODO: Update to 0x8 on release of new master key. */
#define MASTERKEY_REVISION_MAX 0x7
#define MASTERKEY_REVISION_MAX 0x8
#define MASTERKEY_REVISION_100_230 0x00
#define MASTERKEY_REVISION_300 0x01
@ -28,7 +28,8 @@
#define MASTERKEY_REVISION_400_410 0x03
#define MASTERKEY_REVISION_500_510 0x04
#define MASTERKEY_REVISION_600_610 0x05
#define MASTERKEY_REVISION_620_CURRENT 0x06
#define MASTERKEY_REVISION_620 0x06
#define MASTERKEY_REVISION_700_CURRENT 0x07
#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)

View File

@ -212,7 +212,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
}
}
static void nxboot_set_bootreason() {
static void nxboot_set_bootreason(void *bootreason_base) {
boot_reason_t boot_reason = {0};
FILE *boot0;
nvboot_config_table *bct;
@ -264,7 +264,7 @@ static void nxboot_set_bootreason() {
boot_reason.boot_reason_state = 0x04;
/* Set in memory. */
memcpy((void *)MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE, &boot_reason, sizeof(boot_reason));
memcpy(bootreason_base, &boot_reason, sizeof(boot_reason));
/* Clean up. */
free(bct);
@ -412,7 +412,12 @@ uint32_t nxboot_main(void) {
/* Get the TSEC keys. */
uint8_t tsec_key[0x10] = {0};
uint8_t tsec_root_key[0x10] = {0};
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
/* TODO: what to do here? */
if (tsec_get_key(tsec_key, 1, tsec_fw, tsec_fw_size) != 0) {
fatal_error("[NXBOOT]: Failed to get TSEC key!\n");
}
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
uint8_t tsec_keys[0x20] = {0};
/* Emulate the TSEC payload on 6.2.0+. */
@ -438,9 +443,9 @@ uint32_t nxboot_main(void) {
nxboot_configure_exosphere(target_firmware, keygen_type);
/* Initialize Boot Reason on older firmware versions. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Initializing Boot Reason...\n");
nxboot_set_bootreason();
nxboot_set_bootreason((void *)MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(target_firmware));
}
/* Read the warmboot firmware from a file, otherwise from Atmosphere's implementation. */

View File

@ -19,12 +19,14 @@
#include "utils.h"
#define MAILBOX_NX_BOOTLOADER_BASE 0x40002000
#define MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE (MAILBOX_NX_BOOTLOADER_BASE + 0xE10)
#define MAKE_MAILBOX_NX_BOOTLOADER_REG(n) MAKE_REG32(MAILBOX_NX_BOOTLOADER_BASE + n)
#define MAILBOX_NX_BOOTLOADER_BASE_100_620 0x40002E00
#define MAILBOX_NX_BOOTLOADER_BASE_700 0x40000000
#define MAILBOX_NX_BOOTLOADER_BASE(targetfw) ((targetfw >= ATMOSPHERE_TARGET_FIRMWARE_700) ? (MAILBOX_NX_BOOTLOADER_BASE_700) : (MAILBOX_NX_BOOTLOADER_BASE_100_620))
#define MAKE_MAILBOX_NX_BOOTLOADER_REG(targetfw, n) MAKE_REG32(MAILBOX_NX_BOOTLOADER_BASE(targetfw) + n)
#define MAILBOX_NX_BOOTLOADER_SETUP_STATE MAKE_MAILBOX_NX_BOOTLOADER_REG(0xEF8)
#define MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE MAKE_MAILBOX_NX_BOOTLOADER_REG(0xEFC)
#define MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(targetfw) (MAILBOX_NX_BOOTLOADER_BASE(targetfw) + 0x10)
#define MAILBOX_NX_BOOTLOADER_SETUP_STATE(targetfw) MAKE_MAILBOX_NX_BOOTLOADER_REG(targetfw, 0xF8)
#define MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(targetfw) MAKE_MAILBOX_NX_BOOTLOADER_REG(targetfw, 0xFC)
#define NX_BOOTLOADER_STATE_INIT 0
#define NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG 1

View File

@ -28,6 +28,7 @@
#include "sysreg.h"
void nxboot_finish(uint32_t boot_memaddr) {
uint32_t target_firmware = MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware;
volatile tegra_se_t *se = se_get_regs();
/* Clear used keyslots. */
@ -36,7 +37,7 @@ void nxboot_finish(uint32_t boot_memaddr) {
/* Lock keyslots. */
set_aes_keyslot_flags(KEYSLOT_SWITCH_MASTERKEY, 0xFF);
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
} else {
set_aes_keyslot_flags(KEYSLOT_SWITCH_4XOLDDEVICEKEY, 0xFF);
@ -61,11 +62,11 @@ void nxboot_finish(uint32_t boot_memaddr) {
se->_0x0 &= 0xFFFFFFFB;
/* Boot up Exosphère. */
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 0;
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_LOADED_PACKAGE2;
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(target_firmware) = 0;
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_LOADED_PACKAGE2;
} else {
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X;
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X;
}
/* Terminate the display. */
@ -88,15 +89,15 @@ void nxboot_finish(uint32_t boot_memaddr) {
}
/* Wait for Exosphère to wake up. */
while (MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE == 0) {
while (MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(target_firmware) == 0) {
udelay(1);
}
/* Signal Exosphère. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_FINISHED;
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_FINISHED;
} else {
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_FINISHED_4X;
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_FINISHED_4X;
}
/* Halt ourselves in waitevent state. */

View File

@ -26,6 +26,7 @@ enum RoServiceCmd {
Ro_Cmd_LoadNrr = 2,
Ro_Cmd_UnloadNrr = 3,
Ro_Cmd_Initialize = 4,
Ro_Cmd_LoadNrrEx = 10,
};
class RelocatableObjectsService final : public IServiceObject {
@ -47,6 +48,7 @@ class RelocatableObjectsService final : public IServiceObject {
Result LoadNrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size);
Result UnloadNrr(PidDescriptor pid_desc, u64 nrr_address);
Result Initialize(PidDescriptor pid_desc, CopiedHandle process_h);
Result LoadNrrEx(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size);
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MakeServiceCommandMeta<Ro_Cmd_LoadNro, &RelocatableObjectsService::LoadNro>(),