diff --git a/fusee/fusee-secondary/src/key_derivation.c b/fusee/fusee-secondary/src/key_derivation.c index 30357aeab..cb423b78e 100644 --- a/fusee/fusee-secondary/src/key_derivation.c +++ b/fusee/fusee-secondary/src/key_derivation.c @@ -33,6 +33,8 @@ static const uint8_t masterkey_4x_seed[0x10] = { 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 }; +static nx_dec_keyblob_t __attribute__((aligned(16))) 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) { return tsec_query((u32)tsec_fw, dst, tsec_key_id); } @@ -61,10 +63,43 @@ static bool safe_memcmp(uint8_t *a, uint8_t *b, size_t sz) { return different != 0; } +static int decrypt_keyblob(const nx_keyblob_t *keyblobs, uint32_t revision, uint32_t available_revision) { + nx_keyblob_t keyblob; + nx_dec_keyblob_t *dec = &g_dec_keyblobs[revision]; + uint8_t work_buffer[0x10]; + + if (get_keyblob(&keyblob, revision, keyblobs, available_revision) != 0) { + return -1; + } + + se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seeds[revision], 0x10); + decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, 0xE, work_buffer, 0x10); + decrypt_data_into_keyslot(0xB, KEYSLOT_SWITCH_TEMPKEY, keyblob_mac_seed, 0x10); + + /* Validate keyblob. */ + se_compute_aes_128_cmac(0xB, work_buffer, 0x10, keyblob.mac + sizeof(keyblob.mac), sizeof(keyblob) - sizeof(keyblob.mac)); + if (safe_memcmp(keyblob.mac, work_buffer, 0x10)) { + return -1; + } + + /* Decrypt keyblob. */ + se_aes_ctr_crypt(0xD, dec, sizeof(dec), keyblob.data, sizeof(keyblob.data), keyblob.ctr, sizeof(keyblob.ctr)); + return 0; +} + +int load_package1_key(uint32_t revision) { + if (revision > MASTERKEY_REVISION_500_CURRENT) { + return -1; + } + + set_aes_keyslot(0xB, g_dec_keyblobs[revision].keys[8], 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) { uint8_t work_buffer[0x10]; - nx_keyblob_t keyblob; + nx_dec_keyblob_t dec_keyblob; /* TODO: Set keyslot flags properly in preparation of derivation. */ set_aes_keyslot_flags(0xE, 0x15); @@ -75,13 +110,16 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui return -1; } set_aes_keyslot(0xD, work_buffer, 0x10); - - /* Get keyblob, always try to set up the highest possible master key. */ - /* TODO: Should we iterate, trying lower keys on failure? */ - if (get_keyblob(&keyblob, MASTERKEY_REVISION_500_CURRENT, keyblobs, available_revision) != 0) { - return -1; + + /* Decrypt all keyblobs. */ + for (unsigned int rev = MASTERKEY_REVISION_100_230; rev < MASTERKEY_REVISION_500_CURRENT; rev++) { + int ret = decrypt_keyblob(keyblobs, rev, available_revision); + if (ret) { + return ret; + } } + /* Always try to set up the highest possible master key. */ /* Derive both keyblob key 1, and keyblob key latest. */ se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seeds[MASTERKEY_REVISION_100_230], 0x10); decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10); @@ -90,24 +128,12 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui /* Clear the SBK. */ clear_aes_keyslot(0xE); - se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_mac_seed, 0x10); - decrypt_data_into_keyslot(0xB, 0xD, keyblob_mac_seed, 0x10); - - /* Validate keyblob. */ - se_compute_aes_128_cmac(0xB, work_buffer, 0x10, keyblob.mac + sizeof(keyblob.mac), sizeof(keyblob) - sizeof(keyblob.mac)); - if (safe_memcmp(keyblob.mac, work_buffer, 0x10)) { - return -1; - } - - /* Decrypt keyblob. */ - se_aes_ctr_crypt(0xD, keyblob.data, sizeof(keyblob.data), keyblob.data, sizeof(keyblob.data), keyblob.ctr, sizeof(keyblob.ctr)); + + /* Get latest keyblob. */ + dec_keyblob = g_dec_keyblobs[MASTERKEY_REVISION_500_CURRENT]; /* Get needed data. */ - set_aes_keyslot(0xC, keyblob.keys[0], 0x10); - set_aes_keyslot(0xB, keyblob.keys[8], 0x10); - - /* Clear keyblob. */ - memset(keyblob.data, 0, sizeof(keyblob.data)); + set_aes_keyslot(0xC, dec_keyblob.keys[0], 0x10); /* Derive keys for Exosphere, lock critical keyslots. */ switch (target_firmware) { diff --git a/fusee/fusee-secondary/src/key_derivation.h b/fusee/fusee-secondary/src/key_derivation.h index 1ef185417..86b35a82a 100644 --- a/fusee/fusee-secondary/src/key_derivation.h +++ b/fusee/fusee-secondary/src/key_derivation.h @@ -22,17 +22,22 @@ typedef enum BisPartition { BisPartition_UserSystem = 2, } BisPartition; +typedef struct { + uint8_t keys[9][0x10]; +} nx_dec_keyblob_t; + typedef struct nx_keyblob_t { uint8_t mac[0x10]; uint8_t ctr[0x10]; union { uint8_t data[0x90]; - uint8_t keys[9][0x10]; + nx_dec_keyblob_t dec_blob; }; } nx_keyblob_t; /* TSEC fw must be 0x100-byte-aligned. */ 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 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);