@@ -13,13 +13,15 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/


#include <stdio.h>
#include "key_derivation.h"
#include "masterkey.h"
#include "se.h"
#include "exocfg.h"
#include "fuse.h"
#include "tsec.h"
#include "extkeys.h"
#include "utils.h"

#define AL16 ALIGN(16)
@@ -53,6 +55,10 @@ 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] = {
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, /* MasterKek seed 06. */
};

static nx_dec_keyblob_t AL16 g_dec_keyblobs[32];

static int get_tsec_key(void *dst, const void *tsec_fw, size_t tsec_fw_size, uint32_t tsec_key_id) {
@@ -108,45 +114,79 @@ static int decrypt_keyblob(const nx_keyblob_t *keyblobs, uint32_t revision, uint
}

int load_package1_key(uint32_t revision) {
if (revision > MASTERKEY_REVISION_600_CURRENT) {
if (revision > MASTERKEY_REVISION_600_610) {
return -1;
}

set_aes_keyslot(0xB, g_dec_keyblobs[revision].keys[8], 0x10);
set_aes_keyslot(0xB, g_dec_keyblobs[revision].package1_key, 0x10);
return 0;
}

/* Derive all Switch keys. */
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_fw, size_t tsec_fw_size) {
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_fw, size_t tsec_fw_size, unsigned int *out_keygen_type) {
uint8_t AL16 tsec_key[0x10];
uint8_t AL16 work_buffer[0x10];
uint8_t AL16 zeroes[0x10] = {0};

/* TODO: Set keyslot flags properly in preparation of derivation. */
set_aes_keyslot_flags(0xE, 0x15);
set_aes_keyslot_flags(0xD, 0x15);

/* Set TSEC key. */
if (get_tsec_key(work_buffer, tsec_fw, tsec_fw_size, 1) != 0) {
if (get_tsec_key(tsec_key, tsec_fw, tsec_fw_size, 1) != 0) {
return -1;
}

set_aes_keyslot(0xD, work_buffer, 0x10);

set_aes_keyslot(0xD, tsec_key, 0x10);
/* Decrypt all keyblobs, setting keyslot 0xF correctly. */
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
for (unsigned int rev = 0; rev <= MASTERKEY_REVISION_600_610; rev++) {
int ret = decrypt_keyblob(keyblobs, rev, available_revision);
if (ret) {
return ret;
}
}



/* TODO: Eventually do 6.2.0+ keygen properly? */
*out_keygen_type = 0;
if (target_firmware >= EXOSPHERE_TARGET_FIRMWARE_620) {
const char *keyfile = fuse_get_retail_type() != 0 ? "atmosphere/prod.keys" : "atmosphere/dev.keys";
FILE *extkey_file = fopen(keyfile, "r");
AL16 fusee_extkeys_t extkeys = {0};
if (extkey_file == NULL) {
fatal_error("Error: failed to read %s, needed for 6.2.0+ key derivation!", keyfile);
}
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);
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);
}
}

/* Clear the SBK. */
clear_aes_keyslot(0xE);

/* Get needed data. */
set_aes_keyslot(0xC, g_dec_keyblobs[MASTERKEY_REVISION_600_CURRENT].keys[0], 0x10);
set_aes_keyslot(0xC, g_dec_keyblobs[available_revision].master_kek, 0x10);

/* Also set the Package1 key for the revision that is stored on the eMMC boot0 partition. */
load_package1_key(available_revision);
if (target_firmware < EXOSPHERE_TARGET_FIRMWARE_620) {
load_package1_key(available_revision);
}

/* Derive keys for Exosphere, lock critical keyslots. */
switch (target_firmware) {
@@ -164,6 +204,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
break;
case EXOSPHERE_TARGET_FIRMWARE_500:
case EXOSPHERE_TARGET_FIRMWARE_600:
case EXOSPHERE_TARGET_FIRMWARE_620:
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
@@ -28,7 +28,14 @@ typedef enum BisPartition {
} BisPartition;

typedef struct {
uint8_t keys[9][0x10];
union {
uint8_t keys[9][0x10];
struct {
uint8_t master_kek[0x10];
uint8_t _keys[7][0x10];
uint8_t package1_key[0x10];
};
};
} nx_dec_keyblob_t;

typedef struct nx_keyblob_t {
@@ -40,7 +47,7 @@ typedef struct nx_keyblob_t {
};
} nx_keyblob_t;

int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_fw, size_t tsec_fw_size);
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_fw, size_t tsec_fw_size, unsigned int *out_keygen_type);
int load_package1_key(uint32_t revision);
void finalize_nx_keydata(uint32_t target_firmware);
void derive_bis_key(void *dst, BisPartition partition_id, uint32_t target_firmware);
@@ -26,7 +26,6 @@ static unsigned int g_mkey_revision = 0;
static bool g_determined_mkey_revision = false;

static uint8_t g_old_masterkeys[MASTERKEY_REVISION_MAX][0x10];
static uint8_t g_old_devicekeys[MASTERKEY_NUM_NEW_DEVICE_KEYS - 1][0x10];

/* TODO: Extend with new vectors, as needed. */
/* Dev unit keys. */
@@ -38,6 +37,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] =
{0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3}, /* Master key 02 encrypted with Master key 03. */
{0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA}, /* Master key 03 encrypted with Master key 04. */
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
};

/* Retail unit keys. */
@@ -49,6 +49,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
{0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */
{0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
};

static bool check_mkey_revision(unsigned int revision, bool is_retail) {
@@ -119,33 +120,3 @@ unsigned int mkey_get_keyslot(unsigned int revision) {
return KEYSLOT_SWITCH_TEMPKEY;
}
}

void set_old_devkey(unsigned int revision, const uint8_t *key) {
if (revision < MASTERKEY_REVISION_400_410 || MASTERKEY_REVISION_600_CURRENT <= revision) {
generic_panic();
}

memcpy(g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], key, 0x10);
}

unsigned int devkey_get_keyslot(unsigned int revision) {
if (!g_determined_mkey_revision || revision >= MASTERKEY_REVISION_MAX) {
generic_panic();
}

if (revision > g_mkey_revision) {
generic_panic();
}

if (revision >= 1) {
if (revision == MASTERKEY_REVISION_600_CURRENT) {
return KEYSLOT_SWITCH_DEVICEKEY;
} else {
/* Load into a temp keyslot. */
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
return KEYSLOT_SWITCH_TEMPKEY;
}
} else {
return KEYSLOT_SWITCH_4XOLDDEVICEKEY;
}
}
@@ -19,15 +19,16 @@

/* This is glue code to enable master key support across versions. */

/* TODO: Update to 0x7 on release of new master key. */
#define MASTERKEY_REVISION_MAX 0x6
/* TODO: Update to 0x8 on release of new master key. */
#define MASTERKEY_REVISION_MAX 0x7

#define MASTERKEY_REVISION_100_230 0x00
#define MASTERKEY_REVISION_300 0x01
#define MASTERKEY_REVISION_301_302 0x02
#define MASTERKEY_REVISION_400_410 0x03
#define MASTERKEY_REVISION_500_510 0x04
#define MASTERKEY_REVISION_600_CURRENT 0x05
#define MASTERKEY_REVISION_600_610 0x05
#define MASTERKEY_REVISION_620_CURRENT 0x06

#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)

@@ -90,12 +90,16 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
}
}

static void nxboot_configure_exosphere(uint32_t target_firmware) {
static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int keygen_type) {
exosphere_config_t exo_cfg = {0};

exo_cfg.magic = MAGIC_EXOSPHERE_BOOTCONFIG;
exo_cfg.target_firmware = target_firmware;
exo_cfg.flags = EXOSPHERE_FLAGS_DEFAULT;
if (keygen_type) {
exo_cfg.flags = EXOSPHERE_FLAGS_DEFAULT | EXOSPHERE_FLAG_PERFORM_620_KEYGEN;
} else {
exo_cfg.flags = EXOSPHERE_FLAGS_DEFAULT;
}

if (ini_parse_string(get_loader_ctx()->bct0, exosphere_ini_handler, &exo_cfg) < 0) {
fatal_error("[NXBOOT]: Failed to parse BCT.ini!\n");
@@ -307,20 +311,21 @@ uint32_t nxboot_main(void) {

print(SCREEN_LOG_LEVEL_MANDATORY, "[NXBOOT]: Loaded firmware from eMMC...\n");

/* Derive keydata. */
unsigned int keygen_type = 0;
if (derive_nx_keydata(target_firmware, g_keyblobs, available_revision, tsec_fw, tsec_fw_size, &keygen_type) != 0) {
fatal_error("[NXBOOT]: Key derivation failed!\n");
}

/* Setup boot configuration for Exosphère. */
nxboot_configure_exosphere(target_firmware);
nxboot_configure_exosphere(target_firmware, keygen_type);

/* Initialize Boot Reason on older firmware versions. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < EXOSPHERE_TARGET_FIRMWARE_400) {
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Initializing Boot Reason...\n");
nxboot_set_bootreason();
}

/* Derive keydata. */
if (derive_nx_keydata(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware, g_keyblobs, available_revision, tsec_fw, tsec_fw_size) != 0) {
fatal_error("[NXBOOT]: Key derivation failed!\n");
}

/* Read the warmboot firmware from a file, otherwise from PK1. */
if (loader_ctx->warmboot_path[0] != '\0') {
warmboot_fw_size = get_file_size(loader_ctx->warmboot_path);
@@ -214,7 +214,7 @@ static bool package2_validate_metadata(package2_meta_t *metadata, uint8_t data[]

/* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_600_CURRENT) {
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_620_CURRENT) {
return true;
}

@@ -34,15 +34,17 @@
#define PACKAGE2_MAXVER_302 0x5
#define PACKAGE2_MAXVER_400_410 0x6
#define PACKAGE2_MAXVER_500_510 0x7
#define PACKAGE2_MAXVER_600_CURRENT 0x8
#define PACKAGE2_MAXVER_600_610 0x8
#define PACKAGE2_MAXVER_620_CURRENT 0x9

#define PACKAGE2_MINVER_100 0x3
#define PACKAGE2_MINVER_200 0x4
#define PACKAGE2_MINVER_300 0x5
#define PACKAGE2_MINVER_302 0x6
#define PACKAGE2_MINVER_400_410 0x7
#define PACKAGE2_MINVER_500_510 0x8
#define PACKAGE2_MINVER_600_CURRENT 0x9
#define PACKAGE2_MINVER_600_610 0x9
#define PACKAGE2_MINVER_620_CURRENT 0xA

#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))