From 767a4b3606dbde51aa9089c96dce1635d2bab6fb Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sun, 25 Nov 2018 22:37:24 -0800 Subject: [PATCH] fusee/exo: BYOK support for 6.2.0. Proper support TODO. --- exosphere/src/package2.c | 5 +- exosphere/src/package2.h | 6 +- exosphere/src/smc_api.c | 1 + exosphere/src/smc_user.c | 3 +- fusee/fusee-secondary/src/extkeys.c | 216 +++++++++++++++++++++ fusee/fusee-secondary/src/extkeys.h | 32 +++ fusee/fusee-secondary/src/key_derivation.c | 63 ++++-- fusee/fusee-secondary/src/key_derivation.h | 11 +- fusee/fusee-secondary/src/masterkey.c | 33 +--- fusee/fusee-secondary/src/masterkey.h | 7 +- fusee/fusee-secondary/src/nxboot.c | 21 +- fusee/fusee-secondary/src/package2.c | 2 +- fusee/fusee-secondary/src/package2.h | 6 +- 13 files changed, 343 insertions(+), 63 deletions(-) create mode 100644 fusee/fusee-secondary/src/extkeys.c create mode 100644 fusee/fusee-secondary/src/extkeys.h diff --git a/exosphere/src/package2.c b/exosphere/src/package2.c index c6ef81dc2..706386de3 100644 --- a/exosphere/src/package2.c +++ b/exosphere/src/package2.c @@ -144,7 +144,7 @@ static void setup_se(void) { decrypt_data_into_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, new_master_kek_sources[0], 0x10); decrypt_data_into_keyslot(KEYSLOT_SWITCH_MASTERKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, masterkey_seed, 0x10); decrypt_data_into_keyslot(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, devicekek_4x_seed, 0x10); - clear_aes_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY); + clear_aes_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY); } /* Detect Master Key revision. */ @@ -346,7 +346,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) { /* 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; } @@ -466,6 +466,7 @@ static void copy_warmboot_bin_to_dram() { warmboot_src = (uint8_t *)0x4003B000; break; case EXOSPHERE_TARGET_FIRMWARE_600: + case EXOSPHERE_TARGET_FIRMWARE_620: warmboot_src = (uint8_t *)0x4003D800; break; } diff --git a/exosphere/src/package2.h b/exosphere/src/package2.h index 9553fa8fe..97ac7638c 100644 --- a/exosphere/src/package2.h +++ b/exosphere/src/package2.h @@ -67,7 +67,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(void) { #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 @@ -75,7 +76,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(void) { #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 typedef struct { union { diff --git a/exosphere/src/smc_api.c b/exosphere/src/smc_api.c index f391dc539..f39645e47 100644 --- a/exosphere/src/smc_api.c +++ b/exosphere/src/smc_api.c @@ -159,6 +159,7 @@ void set_version_specific_smcs(void) { break; case EXOSPHERE_TARGET_FIRMWARE_500: case EXOSPHERE_TARGET_FIRMWARE_600: + case EXOSPHERE_TARGET_FIRMWARE_620: /* No more LoadSecureExpModKey. */ g_smc_user_table[0xE].handler = NULL; g_smc_user_table[0xC].id = 0xC300D60C; diff --git a/exosphere/src/smc_user.c b/exosphere/src/smc_user.c index 5c2b9c2b6..4ebf6369f 100644 --- a/exosphere/src/smc_user.c +++ b/exosphere/src/smc_user.c @@ -49,6 +49,7 @@ static bool is_user_keyslot_valid(unsigned int keyslot) { case EXOSPHERE_TARGET_FIRMWARE_500: return keyslot <= 3; case EXOSPHERE_TARGET_FIRMWARE_600: + case EXOSPHERE_TARGET_FIRMWARE_620: default: return keyslot <= 5; } @@ -166,7 +167,7 @@ uint32_t user_generate_aes_kek(smc_args_t *args) { /* 5.0.0+ Bounds checking. */ if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) { if (is_personalized) { - if (master_key_rev > MASTERKEY_REVISION_MAX || (MASTERKEY_REVISION_300 <= master_key_rev + 1 && master_key_rev + 1 < MASTERKEY_REVISION_400_410)) { + if (master_key_rev >= MASTERKEY_REVISION_MAX || (MASTERKEY_REVISION_300 <= master_key_rev && master_key_rev < MASTERKEY_REVISION_400_410)) { return 2; } if (mask_id > 3 || usecase >= CRYPTOUSECASE_MAX_5X) { diff --git a/fusee/fusee-secondary/src/extkeys.c b/fusee/fusee-secondary/src/extkeys.c new file mode 100644 index 000000000..7315d4c5d --- /dev/null +++ b/fusee/fusee-secondary/src/extkeys.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include "extkeys.h" + +/** + * Reads a line from file f and parses out the key and value from it. + * The format of a line must match /^ *[A-Za-z0-9_] *[,=] *.+$/. + * If a line ends in \r, the final \r is stripped. + * The input file is assumed to have been opened with the 'b' flag. + * The input file is assumed to contain only ASCII. + * + * A line cannot exceed 512 bytes in length. + * Lines that are excessively long will be silently truncated. + * + * On success, *key and *value will be set to point to the key and value in + * the input line, respectively. + * *key and *value may also be NULL in case of empty lines. + * On failure, *key and *value will be set to NULL. + * End of file is considered failure. + * + * Because *key and *value will point to a static buffer, their contents must be + * copied before calling this function again. + * For the same reason, this function is not thread-safe. + * + * The key will be converted to lowercase. + * An empty key is considered a parse error, but an empty value is returned as + * success. + * + * This function assumes that the file can be trusted not to contain any NUL in + * the contents. + * + * Whitespace (' ', ASCII 0x20, as well as '\t', ASCII 0x09) at the beginning of + * the line, at the end of the line as well as around = (or ,) will be ignored. + * + * @param f the file to read + * @param key pointer to change to point to the key + * @param value pointer to change to point to the value + * @return 0 on success, + * 1 on end of file, + * -1 on parse error (line too long, line malformed) + * -2 on I/O error + */ +static int get_kv(FILE *f, char **key, char **value) { +#define SKIP_SPACE(p) do {\ + for (; *p == ' ' || *p == '\t'; ++p)\ + ;\ +} while(0); + static char line[1024]; + char *k, *v, *p, *end; + + *key = *value = NULL; + + errno = 0; + if (fgets(line, (int)sizeof(line), f) == NULL) { + if (feof(f)) + return 1; + else + return -2; + } + if (errno != 0) + return -2; + + if (*line == '\n' || *line == '\r' || *line == '\0') + return 0; + + /* Not finding \r or \n is not a problem. + * The line might just be exactly 512 characters long, we have no way to + * tell. + * Additionally, it's possible that the last line of a file is not actually + * a line (i.e., does not end in '\n'); we do want to handle those. + */ + if ((p = strchr(line, '\r')) != NULL || (p = strchr(line, '\n')) != NULL) { + end = p; + *p = '\0'; + } else { + end = line + strlen(line) + 1; + } + + p = line; + SKIP_SPACE(p); + k = p; + + /* Validate key and convert to lower case. */ + for (; *p != ' ' && *p != ',' && *p != '\t' && *p != '='; ++p) { + if (*p == '\0') + return -1; + + if (*p >= 'A' && *p <= 'Z') { + *p = 'a' + (*p - 'A'); + continue; + } + + if (*p != '_' && + (*p < '0' || *p > '9') && + (*p < 'a' || *p > 'z')) { + return -1; + } + } + + /* Bail if the final ++p put us at the end of string */ + if (*p == '\0') + return -1; + + /* We should be at the end of key now and either whitespace or [,=] + * follows. + */ + if (*p == '=' || *p == ',') { + *p++ = '\0'; + } else { + *p++ = '\0'; + SKIP_SPACE(p); + if (*p != '=' && *p != ',') + return -1; + *p++ = '\0'; + } + + /* Empty key is an error. */ + if (*k == '\0') + return -1; + + SKIP_SPACE(p); + v = p; + + /* Skip trailing whitespace */ + for (p = end - 1; *p == '\t' || *p == ' '; --p) + ; + + *(p + 1) = '\0'; + + *key = k; + *value = v; + + return 0; +#undef SKIP_SPACE +} + +static int ishex(char c) { + if ('a' <= c && c <= 'f') return 1; + if ('A' <= c && c <= 'F') return 1; + if ('0' <= c && c <= '9') return 1; + return 0; +} + +static char hextoi(char c) { + if ('a' <= c && c <= 'f') return c - 'a' + 0xA; + if ('A' <= c && c <= 'F') return c - 'A' + 0xA; + if ('0' <= c && c <= '9') return c - '0'; + return 0; +} + +void parse_hex_key(unsigned char *key, const char *hex, unsigned int len) { + if (strlen(hex) != 2 * len) { + fatal_error("Key (%s) must be %x hex digits!\n", hex, 2 * len); + } + + for (unsigned int i = 0; i < 2 * len; i++) { + if (!ishex(hex[i])) { + fatal_error("Key (%s) must be %x hex digits!\n", hex, 2 * len); + } + } + + memset(key, 0, len); + + for (unsigned int i = 0; i < 2 * len; i++) { + char val = hextoi(hex[i]); + if ((i & 1) == 0) { + val <<= 4; + } + key[i >> 1] |= val; + } +} + +void extkeys_initialize_keyset(fusee_extkeys_t *keyset, FILE *f) { + char *key, *value; + int ret; + + while ((ret = get_kv(f, &key, &value)) != 1 && ret != -2) { + if (ret == 0) { + if (key == NULL || value == NULL) { + 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), "master_kek_%02x", i); + if (strcmp(key, test_name) == 0) { + parse_hex_key(keyset->master_keks[i], value, sizeof(keyset->master_keks[i])); + matched_key = 1; + break; + } + } + } + } + } +} \ No newline at end of file diff --git a/fusee/fusee-secondary/src/extkeys.h b/fusee/fusee-secondary/src/extkeys.h new file mode 100644 index 000000000..651868995 --- /dev/null +++ b/fusee/fusee-secondary/src/extkeys.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_EXTKEYS_H +#define FUSEE_EXTKEYS_H + +#include +#include "utils.h" +#include "masterkey.h" + +typedef struct { + unsigned char tsec_root_key[0x10]; + unsigned char master_keks[0x20][0x10]; +} fusee_extkeys_t; + +void parse_hex_key(unsigned char *key, const char *hex, unsigned int len); +void extkeys_initialize_keyset(fusee_extkeys_t *keyset, FILE *f); + +#endif \ No newline at end of file diff --git a/fusee/fusee-secondary/src/key_derivation.c b/fusee/fusee-secondary/src/key_derivation.c index 825bc9d3e..b997e32a7 100644 --- a/fusee/fusee-secondary/src/key_derivation.c +++ b/fusee/fusee-secondary/src/key_derivation.c @@ -13,13 +13,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + +#include #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); diff --git a/fusee/fusee-secondary/src/key_derivation.h b/fusee/fusee-secondary/src/key_derivation.h index 5b64f76d1..0cc475037 100644 --- a/fusee/fusee-secondary/src/key_derivation.h +++ b/fusee/fusee-secondary/src/key_derivation.h @@ -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); diff --git a/fusee/fusee-secondary/src/masterkey.c b/fusee/fusee-secondary/src/masterkey.c index bf31ec581..3a4f6ae71 100644 --- a/fusee/fusee-secondary/src/masterkey.c +++ b/fusee/fusee-secondary/src/masterkey.c @@ -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; - } -} \ No newline at end of file diff --git a/fusee/fusee-secondary/src/masterkey.h b/fusee/fusee-secondary/src/masterkey.h index 531eebc58..0f1c20a0b 100644 --- a/fusee/fusee-secondary/src/masterkey.h +++ b/fusee/fusee-secondary/src/masterkey.h @@ -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) diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index 0380b3544..4851d3e3b 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -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,8 +311,14 @@ 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) { @@ -316,11 +326,6 @@ uint32_t nxboot_main(void) { 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); diff --git a/fusee/fusee-secondary/src/package2.c b/fusee/fusee-secondary/src/package2.c index 1d2fb3a5c..1f9cdad9b 100644 --- a/fusee/fusee-secondary/src/package2.c +++ b/fusee/fusee-secondary/src/package2.c @@ -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; } diff --git a/fusee/fusee-secondary/src/package2.h b/fusee/fusee-secondary/src/package2.h index c1314305b..b537f670d 100644 --- a/fusee/fusee-secondary/src/package2.h +++ b/fusee/fusee-secondary/src/package2.h @@ -34,7 +34,8 @@ #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 @@ -42,7 +43,8 @@ #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))