Package1
Present on the firmware package titles (0100000000000819 and 010000000000081A) and installed into eMMC storage's boot partitions 0 and 1, "package1" contains the first Switch bootloader to run under the NVIDIA boot processor (an ARM7TDMI called "BPMP", "BPMP-Lite", "AVP" or "COP").
The boot ROM validates, copies to IRAM and executes this package by parsing it's information block from the BCT.
Bootloader
Split into two main stages, the bootloader is responsible for setting up hardware, generate keys and prepare the main CPU ("CCPLEX").
Stage 0
The code for this stage is stored in plaintext inside the package. By looking into the BCT's bootloader0_info (normal) or bootloader1_info (safe mode), the boot ROM starts executing this stage at address 0x40010020 in IRAM.
Initialization
The stack pointer is set.
// Set the stack pointer *(u32 *)sp = 0x40008000; // Jump to main bootloader_main(); // Infinite loop deadlock();
Main
The bootloader poisons the exception vectors, cleans up memory (.bss and init_array), sets up hardware devices (including the security engine and fuses), does all the necessary checks, generates keys and finally decrypts and executes the next stage.
// Poison all exception vectors *(u32 *)0x6000F200 = panic(); *(u32 *)0x6000F204 = panic(); *(u32 *)0x6000F208 = panic(); *(u32 *)0x6000F20C = panic(); *(u32 *)0x6000F210 = panic(); *(u32 *)0x6000F214 = panic(); *(u32 *)0x6000F218 = panic(); *(u32 *)0x6000F21C = panic(); u32 bss_addr_end = bss_addr_start; u32 bss_offset = 0; u32 bss_size = bss_addr_end - bss_addr_start; // Clear .bss region // Never happens due to bss_size being set to 0 while (bss_offset < bss_size) { *(u32 *)bss_addr_start + bss_offset = 0; bss_offset += 0x04; } u32 init_array_addr_end = init_array_addr_start; u32 init_array_offset = init_array_addr_start; // Call init methods // Never happens due to init_array_addr_end being set to init_array_addr_start while (init_array_offset < init_array_addr_end) { u32 init_method_offset = *(u32 *)init_array_offset; call_init_method(init_method_offset + init_array_offset); init_array_offset += 0x04; } // Setup I2S1, I2S2, I2S3, I2S4, DISPLAY and VIC enable_hw_devices(); // Program the SE clock and resets // Uses RST_DEVICES_V, CLK_OUT_ENB_V, CLK_SOURCE_SE and CLK_V_SE enable_se_clkrst(); // Set MISC_CLK_ENB // This makes fuse registers visible enable_misc_clk(0x01); // Read FUSE_SKU_INFO and compare with 0x83 check_sku(); // Check configuration fuses check_config_fuses(); u32 bct_iram_addr = 0x40000000; // Check bootloader version from BCT check_bootloader_ver(bct_iram_addr); // Check anti-downgrade fuses check_downgrade(); // Set FUSE_DIS_PGM // Disables fuse programming until next reboot disable_fuse_pgm(); // Setup memory controllers enable_mem(); // Setup the security engine's address set_se_addr(0x70012000); // Check SE global config check_se_status(); // Generate keys keygen(bct_iram_addr); u32 stage1_addr = 0x40013FE0; // Decrypt next stage stage1_addr = decrypt_stage1(stage1_addr); u32 stage1_sp = 0x40007000; // Set the stack pointer and jump to a stub responsible // for cleaning up and branching into the actual stage 1 exec_stage1_stub(stage1_addr, stage1_stub_addr, stage1_sp); return;
Panic
If a panic occurs, all sensitive memory contents are cleared, the security engine and fuse programming are disabled and the boot processor is left in a halted state.
// Clear all stack contents clear_stack(); // Terminate the security engine disable_se(); // Set FUSE_DIS_PGM // Disables fuse programming until next reboot disable_fuse_pgm(); // Clear temporary key storage memory clear_mem(); // Clear the stage 1 binary clear_stage1(); u32 FLOW_CTLR_HALT_COP_EVENTS = 0x60007004; u32 FLOW_MODE_STOP = 0x40000000; u32 HALT_COP_EVENT_JTAG = 0x10000000; // Halt the boot processor while (true) *(u32 *)FLOW_CTLR_HALT_COP_EVENTS = (FLOW_MODE_STOP | HALT_COP_EVENT_JTAG);
Anti-downgrade
See Anti-downgrade.
Key generation
After the security engine is ready and before decrypting the next stage, the bootloader initializes and generates several keys into hardware keyslots. For more details on the Switch's cryptosystem, please see this page.
Selection
Depending on FUSE_RESERVED_ODM4 and FUSE_SPARE_BIT_5 different static seeds are selected for key generation.
// Initialize keyslots 0x0C and 0x0D as readable init_keyslot(0x0C, 0x15); init_keyslot(0x0D, 0x15); // Find the BCT's data address from IRAM header u32 bct_data_addr = *(u32 *)bct_imem_addr + 0x4C; u32 bct_customer_data_addr = *(u32 *)bct_data_addr + 0x450; // Wrapper to get unit type from FUSE_RESERVED_ODM4 // This tells if the device is retail or debug bool is_retail = is_unit_retail(); u32 master_static_seed_addr = 0; u32 master_static_seed_size = 0; if (is_retail) { // Read FUSE_SPARE_BIT_5 // This tells which master key to use u32 master_key_ver = read_fuse_spare_bit_5(); // Invalid for retail if (!master_key_ver) panic(); else { master_static_seed_addr = static_seed1_addr; master_static_seed_size = 0x10; // Generate retail keys generate_retail_keys(bct_customer_data_addr, static_seed_addr, static_seed_size); } } else { // Read FUSE_SPARE_BIT_5 // This tells which master key to use u32 master_key_ver = read_fuse_spare_bit_5(); // Use debug key set if (!master_key_ver) { // Read the first byte of the BCT RSA PSS signature u8 rsa_pss_1_byte = *(u8 *)bct_data_addr + 0x210; if (rsa_pss_1_byte == 0x11) { master_static_seed_addr = static_seed6_addr; master_static_seed_size = 0x10; } else { master_static_seed_addr = static_seed7_addr; master_static_seed_size = 0x10; } // Generate debug keys generate_debug_keys(static_seed_addr, static_seed_size); } else { // Read the first byte of the BCT RSA PSS signature u8 rsa_pss_1_byte = *(u8 *)bct_data_addr + 0x210; if (rsa_pss_1_byte == 0x4F) // Different key as in retail mode { master_static_seed_addr = static_seed0_addr; master_static_seed_size = 0x10; } else // Same key as in retail mode { master_static_seed_addr = static_seed1_addr; master_static_seed_size = 0x10; } // Generate retail keys generate_retail_keys(bct_customer_data_addr, master_static_seed_addr, master_static_seed_size); } } // Initialize keyslots 0x0C and 0x0D as unreadable init_keyslot(0x0C, 0xFF); init_keyslot(0x0D, 0xFF); return;
generate_retail_keys
In order to generate retail keys, the bootloader starts by initializing TSEC and grabbing it's device key. Using static seeds and the SBK, the keyblob injected into the BCT's customer_data is validated and decrypted. The resulting keys will then be used to generate the master static key and the master device key.
See the pseudocode bellow for the detailed process.
u32 in_addr = 0; u32 in_size = 0; u32 out_addr = 0; u32 out_size = 0; u32 keyslot = 0; u32 keyslot_dst = 0; // Get the TSEC device key tsec_get_device_key(tsec_device_key_addr, 0x10); // Install the TSEC device key into keyslot 0x0D set_keyslot_data(0x0D, tsec_device_key_addr, 0x10); in_addr = static_seed2_addr; in_size = 0x10; out_addr = keyblob_device_key_addr; out_size = 0x10; keyslot = 0x0D; // Use the tsec_device_key (keyslot 0x0D) to decrypt the static_seed2 // This generates the keyblob_device_key aes_ecb_decrypt(out_addr, out_size, keyslot, in_addr, in_size); in_addr = keyblob_device_key_addr; in_size = 0x10; keyslot = 0x0E; keyslot_dst = 0x0D; // Use SBK (keyslot 0x0E) to further decrypt the // keyblob_device_key and install it into keyslot 0x0D // This will generate the keyblob_key decrypt_keyslot(keyslot_dst, keyslot, in_addr, in_size); // Clear SBK and SSK keyslots clear_keyslot(0x0E); clear_keyslot(0x0F); in_addr = static_seed4_addr; in_size = 0x10; keyslot = 0x0D; keyslot_dst = 0x0B; // Use keyblob_key (keyslot 0x0D) to decrypt the // static_seed4_addr and install it to keyslot 0x0B // This will generate the bct_mac_key decrypt_keyslot(keyslot_dst, keyslot, in_addr, in_size); in_addr = bct_customer_data_addr + 0x10; in_size = 0xA0; out_addr = mac_addr; out_size = 0x10; keyslot = 0x0B; // Use the bct_mac_key (keyslot 0x0B) to generate // CMAC over bct_customer_data_addr + 0x10 aes_cmac(out_addr, out_size, keyslot, in_addr, in_size); // Comapre the generated hash with the first // 0x10 bytes of bct_customer_data bool match = safe_memcmp(mac_addr, bct_customer_data_addr, 0x10); // Hashes don't match if (!match) panic(); in_addr = bct_customer_data_addr + 0x20; in_size = 0x90; ctr_addr = bct_customer_data_addr + 0x10; ctr_size = 0x10; out_addr = dec_payload_addr; out_size = 0x90; keyslot = 0x0D; // AES-CTR decrypt // Use the keyblob_key (keyslot 0x0D) to decrypt bct_customer_data_addr + 0x20 // using bct_customer_data_addr + 0x10 as CTR aes_ctr_decrypt(out_addr, out_size, keyslot, in_addr, in_size, ctr_addr, ctr_size); // Install the last decrypted keyblob key into keyslot 0x0B // This is the pk11_key set_keyslot_data(0x0B, dec_payload_addr + 0x80, 0x10); // Install the first decrypted keyblob key into keyslot 0x0C // This is the master_static_kek set_keyslot_data(0x0C, dec_payload_addr, 0x10); // Clear out the decrypted data memclear(dec_payload_addr, 0x90); in_addr = master_static_seed_addr; in_size = master_static_seed_size; keyslot = 0x0C; keyslot_dst = 0x0C; // Use the master_static_kek (keyslot 0x0C) to decrypt // master_static_seed and install it into keyslot 0x0C // This will generate the master_static_key decrypt_keyslot(keyslot_dst, keyslot, in_addr, in_size); in_addr = static_seed3_addr; in_size = 0x10; keyslot = 0x0D; keyslot_dst = 0x0D; // Use keyblob_key (keyslot 0x0D) to decrypt // static_seed3_addr and install it into keyslot 0x0D // This will generate the master_device_key decrypt_keyslot(keyslot_dst, keyslot, in_addr, in_size); return;
generate_debug_keys
In order to generate debug keys, the bootloader only uses static seeds, the SBK and the SSK.
See the pseudocode bellow for the detailed process.
u32 in_addr = 0; u32 in_size = 0; u32 keyslot = 0; u32 keyslot_dst = 0; in_addr = static_seed8_addr; in_size = 0x10; keyslot = 0x0E; keyslot_dst = 0x0B; // Use SBK (keyslot 0x0E) to decrypt the // static_seed8 and install it to keyslot 0x0B // This will generate debug_pk11_key decrypt_keyslot(keyslot_dst, keyslot, in_addr, in_size); in_addr = static_seed5_addr; in_size = 0x10; keyslot = 0x0E; keyslot_dst = 0x0C; // Use SBK (keyslot 0x0E) to decrypt the // static_seed5 and install it to keyslot 0x0C // This will generate debug_master_static_kek decrypt_keyslot(keyslot_dst, keyslot, in_addr, in_size); in_addr = static_seed9_addr; in_size = 0x10; keyslot = 0x0F; keyslot_dst = 0x0D; // Use SSK (keyslot 0x0F) to decrypt the // static_seed9 and install it to keyslot 0x0D // This will generate debug_keyblob_key decrypt_keyslot(keyslot_dst, keyslot, in_addr, in_size); // Clear SBK and SSK keyslots clear_keyslot(0x0E); clear_keyslot(0x0F); in_addr = master_static_seed_addr; in_size = master_static_seed_size; keyslot = 0x0C; keyslot_dst = 0x0C; // Use the debug_master_static_kek (keyslot 0x0C) to decrypt the // master_static_seed and install it to keyslot 0x0C // This will generate the master_static_key decrypt_keyslot(keyslot_dst, keyslot, in_addr, in_size); in_addr = static_seed3_addr; in_size = 0x10; keyslot = 0x0D; keyslot_dst = 0x0D; // Use debug_keyblob_key (keyslot 0x0D) to decrypt the // static_seed3 and install it to keyslot 0x0D // This will generate the master_device_key decrypt_keyslot(keyslot_dst, keyslot, in_addr, in_size); return;
Stage 1
Known as "package1.1", the code for this stage is stored encrypted inside the package. When decrypted, this stage is encapsulated in a header.
Header
Offset | Size | Description |
---|---|---|
0x0 | 4 | Magic "PK11" |
0x4 | 4 | Main size |
0x8 | 8 | Unknown |
0x10 | 4 | Section 0 size |
0x14 | 4 | Section 0 offset |
0x18 | 4 | Section 1 size |
0x1C | 4 | Section 1 offset |
Changelog
3.0.0
- The functions set_se_addr() and check_se_status() are now called right after enabling the security engine clocks and resets.
See Switch_System_Flaws#Stage_1_Bootloader.
- Keyslot 0x0A is now used instead of keyslot 0x0D for generating the master_device_key.