From c96ae0148e283b281c4e232acc428780fd728c9e Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 18 Jun 2019 22:22:40 -0700 Subject: [PATCH 01/15] Revise sept key generation methodology. --- exosphere/src/masterkey.c | 30 +- exosphere/src/package2.c | 109 +-- sept/sept-secondary/Makefile | 15 +- sept/sept-secondary/key_derivation/Makefile | 154 ++++ sept/sept-secondary/key_derivation/linker.ld | 17 + .../key_derivation/linker.specs | 7 + .../key_derivation/src/key_derivation.c | 149 ++++ .../key_derivation/src/key_derivation.h | 26 + sept/sept-secondary/key_derivation/src/pmc.h | 626 ++++++++++++++ sept/sept-secondary/key_derivation/src/se.c | 763 ++++++++++++++++++ sept/sept-secondary/key_derivation/src/se.h | 227 ++++++ .../sept-secondary/key_derivation/src/start.s | 99 +++ .../sept-secondary/key_derivation/src/utils.c | 24 + .../sept-secondary/key_derivation/src/utils.h | 122 +++ sept/sept-secondary/linker.ld | 4 +- sept/sept-secondary/src/cluster.c | 163 ++++ sept/sept-secondary/src/cluster.h | 23 + sept/sept-secondary/src/key_derivation.c | 93 +-- sept/sept-secondary/src/key_derivation.h | 5 +- sept/sept-secondary/src/main.c | 66 +- sept/sept-secondary/src/utils.c | 9 +- 21 files changed, 2533 insertions(+), 198 deletions(-) create mode 100644 sept/sept-secondary/key_derivation/Makefile create mode 100644 sept/sept-secondary/key_derivation/linker.ld create mode 100644 sept/sept-secondary/key_derivation/linker.specs create mode 100644 sept/sept-secondary/key_derivation/src/key_derivation.c create mode 100644 sept/sept-secondary/key_derivation/src/key_derivation.h create mode 100644 sept/sept-secondary/key_derivation/src/pmc.h create mode 100644 sept/sept-secondary/key_derivation/src/se.c create mode 100644 sept/sept-secondary/key_derivation/src/se.h create mode 100644 sept/sept-secondary/key_derivation/src/start.s create mode 100644 sept/sept-secondary/key_derivation/src/utils.c create mode 100644 sept/sept-secondary/key_derivation/src/utils.h create mode 100644 sept/sept-secondary/src/cluster.c create mode 100644 sept/sept-secondary/src/cluster.h diff --git a/exosphere/src/masterkey.c b/exosphere/src/masterkey.c index b894a7721..d1ef71c71 100644 --- a/exosphere/src/masterkey.c +++ b/exosphere/src/masterkey.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include #include @@ -83,7 +83,7 @@ void mkey_detect_revision(void) { if (g_determined_mkey_revision) { generic_panic(); } - + for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) { if (check_mkey_revision(rev, configitem_is_retail())) { g_determined_mkey_revision = true; @@ -91,7 +91,7 @@ void mkey_detect_revision(void) { break; } } - + /* We must have determined the master key, or we're not running on a Switch. */ if (!g_determined_mkey_revision) { /* Panic in bright red. */ @@ -135,23 +135,17 @@ void set_old_devkey(unsigned int revision, const uint8_t *key) { } unsigned int devkey_get_keyslot(unsigned int revision) { - if (!g_determined_mkey_revision || revision >= MASTERKEY_REVISION_MAX) { + if (!g_determined_mkey_revision || revision > g_mkey_revision) { generic_panic(); } - if (revision > g_mkey_revision) { - generic_panic(); - } - - if (revision >= 1) { - if (revision == MASTERKEY_REVISION_MAX) { - 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 { + if (revision < MASTERKEY_REVISION_400_410) { return KEYSLOT_SWITCH_4XOLDDEVICEKEY; + } else if (revision < g_mkey_revision) { + /* 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_DEVICEKEY; } -} \ No newline at end of file +} diff --git a/exosphere/src/package2.c b/exosphere/src/package2.c index 66d8828fe..4ee7f23bf 100644 --- a/exosphere/src/package2.c +++ b/exosphere/src/package2.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include "utils.h" @@ -43,6 +43,7 @@ static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */ {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */ {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */ + //{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ }; static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { @@ -51,6 +52,7 @@ static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */ {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */ {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */ + //{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ }; static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { @@ -58,45 +60,28 @@ static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS {0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.x New Device Keygen Source. */ {0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.x New Device Keygen Source. */ {0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 New Device Keygen Source. */ - {0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 6.2.0 New Device Keygen Source. */ -}; - -static const uint8_t new_master_kek_sources[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}, /* 6.2.0 Master Kek Source. */ - {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* 7.0.0 Master Kek Source. */ -}; - -static const uint8_t keyblob_key_seed_00[0x10] = { - 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 -}; - -static const uint8_t devicekey_seed[0x10] = { - 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 -}; - -static const uint8_t devicekey_4x_seed[0x10] = { - 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 -}; - -static const uint8_t masterkey_seed[0x10] = { - 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C -}; - -static const uint8_t devicekek_4x_seed[0x10] = { - 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 + {0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */ + //{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ }; static void derive_new_device_keys(unsigned int keygen_keyslot) { uint8_t work_buffer[0x10]; bool is_retail = configitem_is_retail(); for (unsigned int revision = 0; revision < MASTERKEY_NUM_NEW_DEVICE_KEYS; revision++) { + const unsigned int relative_revision = revision + MASTERKEY_REVISION_400_410; + se_aes_ecb_decrypt_block(keygen_keyslot, work_buffer, 0x10, new_device_key_sources[revision], 0x10); decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, mkey_get_keyslot(0), is_retail ? new_device_keygen_sources[revision] : new_device_keygen_sources_dev[revision], 0x10); - if (revision < MASTERKEY_NUM_NEW_DEVICE_KEYS - 1) { - se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10); - set_old_devkey(revision + MASTERKEY_REVISION_400_410, work_buffer); + if (relative_revision > mkey_get_revision()) { + break; + } else if (relative_revision == mkey_get_revision()) { + /* On 7.0.0, sept will have derived this key for us already. */ + if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_700) { + decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10); + } } else { - decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10); + se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10); + set_old_devkey(relative_revision, work_buffer); } } set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF); @@ -118,7 +103,8 @@ static void setup_se(void) { se->_0x0 &= 0xFFFEFFFF; /* Clear bit 16. */ (void)(se->FLAGS_REG); __dsb_sy(); - + + /* NOTE: On 8.1.0+, Nintendo does not make keyslots 0-5 unreadable. */ se->_0x4 = 0; se->AES_KEY_READ_DISABLE_REG = 0; se->RSA_KEY_READ_DISABLE_REG = 0; @@ -136,33 +122,6 @@ static void setup_se(void) { for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) { set_rsa_keyslot_flags(i, 0x41); } - - if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_620 && exosphere_should_perform_620_keygen()) { - unsigned int master_kek_source_ind; - switch (exosphere_get_target_firmware()) { - case ATMOSPHERE_TARGET_FIRMWARE_620: - master_kek_source_ind = MASTERKEY_REVISION_620 - MASTERKEY_REVISION_620; - break; - case ATMOSPHERE_TARGET_FIRMWARE_700: - case ATMOSPHERE_TARGET_FIRMWARE_800: - master_kek_source_ind = MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_620; - break; - default: - generic_panic(); - break; - } - /* Start by generating device keys. */ - se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_6XTSECKEY, work_buffer, 0x10, keyblob_key_seed_00, 0x10); - decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, KEYSLOT_SWITCH_6XSBK, work_buffer, 0x10); - decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY, KEYSLOT_SWITCH_4XOLDDEVICEKEY, devicekey_4x_seed, 0x10); - decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, KEYSLOT_SWITCH_4XOLDDEVICEKEY, devicekey_seed, 0x10); - - /* Next, generate the master kek, and from there master key/device kek. We use different keyslots than Nintendo, here. */ - decrypt_data_into_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, new_master_kek_sources[master_kek_source_ind], 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); - } /* Detect Master Key revision. */ mkey_detect_revision(); @@ -198,7 +157,7 @@ static void setup_se(void) { set_aes_keyslot_flags(KEYSLOT_SWITCH_SESSIONKEY, 0xFF); /* Generate test vector for our keys. */ - se_generate_stored_vector(); + se_generate_stored_vector(); } static void setup_boot_config(void) { @@ -287,7 +246,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) { if (metadata->magic != MAGIC_PK21) { return false; } - + /* Package2 size, version number is stored XORed in header CTR. */ /* Nintendo, what the fuck? */ @@ -500,16 +459,16 @@ static void copy_warmboot_bin_to_dram() { } uint8_t *warmboot_dst = (uint8_t *)0x8000D000; const size_t warmboot_size = 0x2000; - + /* Flush cache, to ensure warmboot is where we need it to be. */ flush_dcache_range(warmboot_src, warmboot_src + warmboot_size); __dsb_sy(); - + /* Copy warmboot. */ for (size_t i = 0; i < warmboot_size; i += sizeof(uint32_t)) { write32le(warmboot_dst, i, read32le(warmboot_src, i)); } - + /* Flush cache, to ensure warmboot is where we need it to be. */ flush_dcache_range(warmboot_dst, warmboot_dst + warmboot_size); __dsb_sy(); @@ -544,12 +503,12 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { /* Setup the Security Engine. */ setup_se(); - + /* Perform initial PMC register writes, if relevant. */ if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { - MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000; - MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF; - MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE; + MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000; + MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF; + MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE; MAKE_REG32(PMC_BASE + 0x334) |= 0x10; switch (exosphere_get_target_firmware()) { case ATMOSPHERE_TARGET_FIRMWARE_400: @@ -585,7 +544,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { /* memclear the initial copy of Exosphere running in IRAM (relocated to TZRAM by earlier code). */ /* memset((void *)reloc_list->reloc_base, 0, reloc_list->loaded_bin_size); */ - + /* Let NX Bootloader know that we're running. */ MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(exosphere_get_target_firmware()) = 1; @@ -597,7 +556,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { /* Load Boot Config into global. */ setup_boot_config(); - + /* Set sysctr0 registers based on bootconfig. */ if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { uint64_t sysctr0_val = bootconfig_get_value_for_sysctr0(); @@ -620,7 +579,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { /* Make PMC (2.x+), MC (4.x+) registers secure-only */ secure_additional_devices(); - + /* Remove the identity mapping for iRAM-C+D & TZRAM */ /* For our crt0 to work, this doesn't actually unmap TZRAM */ identity_unmap_iram_cd_tzram(); @@ -630,7 +589,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { flush_dcache_range((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, (uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(header)); memcpy(&header, NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, sizeof(header)); flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header)); - + /* Perform signature checks. */ /* Special exosphere patching enable: All-zeroes signature + decrypted header implies unsigned and decrypted package2. */ if (header.signature[0] == 0 && memcmp(header.signature, header.signature + 1, sizeof(header.signature) - 1) == 0 && header.metadata.magic == MAGIC_PK21) { @@ -641,7 +600,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { /* Decrypt header, get key revision required. */ uint32_t package2_mkey_rev = decrypt_and_validate_header(&header); - + /* Copy hash, if necessary. */ if (bootconfig_is_recovery_boot()) { bootconfig_set_package2_hash_for_recovery(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, get_package2_size(&header.metadata)); @@ -649,7 +608,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { /* Load Package2 Sections. */ load_package2_sections(&header.metadata, package2_mkey_rev); - + /* Clean up cache. */ flush_dcache_all(); invalidate_icache_all(); /* non-broadcasting */ @@ -660,7 +619,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { /* Remove the DRAM identity mapping. */ if (0) { identity_unmap_dram(); - } + } /* Synchronize with NX BOOTLOADER. */ if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) { diff --git a/sept/sept-secondary/Makefile b/sept/sept-secondary/Makefile index d41959363..03a8a5f8c 100644 --- a/sept/sept-secondary/Makefile +++ b/sept/sept-secondary/Makefile @@ -77,14 +77,15 @@ export TOPDIR := $(CURDIR) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ - $(AMS)/exosphere/rebootstub + $(AMS)/exosphere/rebootstub \ + $(TOPDIR)/key_derivation export DEPSDIR := $(CURDIR)/$(BUILD) CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) -BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin key_derivation.bin #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C @@ -111,15 +112,18 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) -.PHONY: $(BUILD) clean all check_rebootstub +.PHONY: $(BUILD) clean all check_rebootstub check_key_derivation #--------------------------------------------------------------------------------- -all: check_rebootstub $(BUILD) +all: check_rebootstub check_key_derivation $(BUILD) check_rebootstub: @$(MAKE) -C $(AMS)/exosphere/rebootstub all -$(BUILD): +check_key_derivation: + @$(MAKE) -C key_derivation + +$(BUILD): check_rebootstub check_key_derivation ifeq ($(strip $(SEPT_ENC_PATH)),) @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile @@ -132,6 +136,7 @@ endif clean: @echo clean ... @$(MAKE) -C $(AMS)/exosphere/rebootstub clean + @$(MAKE) -C key_derivation clean @rm -fr $(BUILD) $(TARGET).bin $(TARGET).enc $(TARGET).elf diff --git a/sept/sept-secondary/key_derivation/Makefile b/sept/sept-secondary/key_derivation/Makefile new file mode 100644 index 000000000..6939c5afc --- /dev/null +++ b/sept/sept-secondary/key_derivation/Makefile @@ -0,0 +1,154 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/devkitA64/base_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := src +DATA := data +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a -mtune=cortex-a57 -mgeneral-regs-only #<- important + +CFLAGS := \ + -g \ + -Os \ + -ffunction-sections \ + -fdata-sections \ + -fomit-frame-pointer \ + -fno-inline \ + -std=gnu11 \ + -Werror \ + -Wall \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(TOPDIR)/linker.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(OUTPUT).bin + +$(OUTPUT).bin : $(OUTPUT).elf + $(OBJCOPY) -S -O binary $< $@ + @echo built ... $(notdir $@) + +$(OUTPUT).elf : $(OFILES) + +%.elf: $(OFILES) + @echo linking $(notdir $@) + @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + @$(NM) -CSn $@ > $(notdir $*.lst) + +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/sept/sept-secondary/key_derivation/linker.ld b/sept/sept-secondary/key_derivation/linker.ld new file mode 100644 index 000000000..480bad8d9 --- /dev/null +++ b/sept/sept-secondary/key_derivation/linker.ld @@ -0,0 +1,17 @@ +OUTPUT_ARCH(aarch64) + +ENTRY(_start) +SECTIONS +{ + . = 0x4003D000; + + __start__ = ABSOLUTE(.); + + .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } + .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } + .bss : ALIGN(8) { __bss_start__ = .; *(.bss* COMMON); . = ALIGN(8); __bss_end__ = .; } + + . = ALIGN(4); + + __end__ = ABSOLUTE(.); +} \ No newline at end of file diff --git a/sept/sept-secondary/key_derivation/linker.specs b/sept/sept-secondary/key_derivation/linker.specs new file mode 100644 index 000000000..300990418 --- /dev/null +++ b/sept/sept-secondary/key_derivation/linker.specs @@ -0,0 +1,7 @@ +%rename link old_link + +*link: +%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections + +*startfile: +crti%O%s crtbegin%O%s diff --git a/sept/sept-secondary/key_derivation/src/key_derivation.c b/sept/sept-secondary/key_derivation/src/key_derivation.c new file mode 100644 index 000000000..65eb9290b --- /dev/null +++ b/sept/sept-secondary/key_derivation/src/key_derivation.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2018-2019 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 "pmc.h" +#include "se.h" + +#define AL16 __attribute__((aligned(16))) + +#define DERIVATION_ID_MAX 1 + +static const uint8_t AL16 keyblob_seed_00[0x10] = { + 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 +}; + +static const uint8_t AL16 masterkey_seed[0x10] = { + 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C +}; + +static const uint8_t AL16 devicekey_seed[0x10] = { + 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 +}; + +static const uint8_t AL16 devicekey_4x_seed[0x10] = { + 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 +}; + +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 master_kek_seeds[DERIVATION_ID_MAX][0x10] = { + {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, +}; + +static const uint8_t AL16 master_devkey_seeds[DERIVATION_ID_MAX][0x10] = { + {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, +}; + +void derive_keys(void) { + /* Set mailbox. */ + volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00; + const uint32_t derivation_id = *((volatile uint32_t *)0x4003E800); + + if (derivation_id < DERIVATION_ID_MAX) { + uint8_t *partial_se_state = (uint8_t *)0x4000FFC0; + uint8_t *enc_se_state = (uint8_t *)0x4003E000; + + volatile tegra_pmc_t *pmc = pmc_get_regs(); + uint32_t AL16 work_buffer[4]; + + /* Save a partial context, only the keyslots we want. */ + /* We can't avoid touching memory, but save to a location that the bootrom will overwrite during init. */ + se_set_in_context_save_mode(true); + se_save_partial_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, partial_se_state); + se_set_in_context_save_mode(false); + + /* Clear the copy of the root key still inside the SE. */ + clear_aes_keyslot(0xD); + + /* Copy SRK into keyslot 0xE, clear it. */ + { + work_buffer[0] = pmc->secure_scratch4; + pmc->secure_scratch4 = 0xCCCCCCCC; + work_buffer[1] = pmc->secure_scratch5; + pmc->secure_scratch5 = 0xCCCCCCCC; + work_buffer[2] = pmc->secure_scratch6; + pmc->secure_scratch6 = 0xCCCCCCCC; + work_buffer[3] = pmc->secure_scratch7; + pmc->secure_scratch7 = 0xCCCCCCCC; + set_aes_keyslot(0xE, work_buffer, 0x10); + for (size_t i = 0; i < 4; i++) { + work_buffer[i] = 0xCCCCCCCC; + } + } + + /* Decrypt SE state. */ + se_aes_128_cbc_decrypt(0xE, partial_se_state, 0x40, partial_se_state, 0x40); + + /* Clear keyslots to wipe IVs. */ + clear_aes_keyslot(0xE); + clear_aes_keyslot(0xF); + + /* Mov root key into keyslot 0xE. Clear first to wipe from IV. */ + set_aes_keyslot(0xE, partial_se_state + 0x30, 0x10); + for (size_t i = 0; i < 4; i++) { + *((volatile uint32_t *)(partial_se_state + 0x30)) = 0xCCCCCCCC; + } + + /* Derive master kek. */ + decrypt_data_into_keyslot(0xE, 0xE, master_kek_seeds[0], 0x10); + + /* Derive master key, device master key. */ + decrypt_data_into_keyslot(0xC, 0xE, masterkey_seed, 0x10); + decrypt_data_into_keyslot(0xE, 0xE, masterkey_4x_seed, 0x10); + + /* Derive Keyblob Key 00. */ + set_aes_keyslot(0xF, partial_se_state + 0x20, 0x10); + se_aes_ecb_decrypt_block(0xF, work_buffer, 0x10, keyblob_seed_00, 0x10); + set_aes_keyslot(0xF, partial_se_state + 0x10, 0x10); + decrypt_data_into_keyslot(0xF, 0xF, work_buffer, 0x10); + + /* Clear TSEC key + SBK. */ + for (size_t i = 0; i < 8; i++) { + *((volatile uint32_t *)(partial_se_state + 0x10)) = 0xCCCCCCCC; + } + + /* Derive device keys. */ + decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10); + decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10); + + /* Derive firmware specific device key. */ + se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[0], 0x10); + decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10); + + /* Clear work buffer. */ + for (size_t i = 0; i < 4; i++) { + work_buffer[i] = 0xCCCCCCCC; + } + + /* Save context for real. */ + se_set_in_context_save_mode(true); + se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, enc_se_state); + se_set_in_context_save_mode(false); + } + + /* Clear all keyslots. */ + for (size_t i = 0; i < 0x10; i++) { + clear_aes_keyslot(i); + } + + *(volatile uint32_t *)(0x4003FFC0) = 0xCACACACA; + + *mailbox = 7; + while (1) { /* Wait for sept to handle the rest. */ } +} diff --git a/sept/sept-secondary/key_derivation/src/key_derivation.h b/sept/sept-secondary/key_derivation/src/key_derivation.h new file mode 100644 index 000000000..cd6cece8d --- /dev/null +++ b/sept/sept-secondary/key_derivation/src/key_derivation.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2019 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 SEPT_KEYDERIVATION_H +#define SEPT_KEYDERIVATION_H + +#include +#include +#include + +void derive_keys(void); + +#endif diff --git a/sept/sept-secondary/key_derivation/src/pmc.h b/sept/sept-secondary/key_derivation/src/pmc.h new file mode 100644 index 000000000..f3a4f9379 --- /dev/null +++ b/sept/sept-secondary/key_derivation/src/pmc.h @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2018-2019 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_PMC_H +#define FUSEE_PMC_H + +#include + +#define PMC_BASE 0x7000E400 +#define MAKE_PMC_REG(n) MAKE_REG32(PMC_BASE + n) + +#define PMC_CONTROL_SDMMC1 (1 << 12) +#define PMC_CONTROL_SDMMC3 (1 << 13) +#define PMC_CONTROL_SDMMC4 (1 << 14) + +#define APBDEV_PMC_CONTROL MAKE_PMC_REG(0x00) +#define APBDEV_PM_0 MAKE_PMC_REG(0x14) +#define APBDEV_PMC_DPD_ENABLE_0 MAKE_PMC_REG(0x24) +#define APBDEV_PMC_PWRGATE_TOGGLE_0 MAKE_PMC_REG(0x30) +#define APBDEV_PMC_PWRGATE_STATUS_0 MAKE_PMC_REG(0x38) +#define APBDEV_PMC_NO_IOPOWER_0 MAKE_PMC_REG(0x44) +#define APBDEV_PMC_SCRATCH0_0 MAKE_PMC_REG(0x50) +#define APBDEV_PMC_SCRATCH1_0 MAKE_PMC_REG(0x54) +#define APBDEV_PMC_SCRATCH20_0 MAKE_PMC_REG(0xA0) +#define APBDEV_PMC_PWR_DET_VAL_0 MAKE_PMC_REG(0xE4) +#define APBDEV_PMC_DDR_PWR_0 MAKE_PMC_REG(0xE8) +#define APBDEV_PMC_CRYPTO_OP_0 MAKE_PMC_REG(0xF4) +#define APBDEV_PMC_WAKE2_STATUS_0 MAKE_PMC_REG(0x168) +#define APBDEV_PMC_OSC_EDPD_OVER_0 MAKE_PMC_REG(0x1A4) +#define APBDEV_PMC_RST_STATUS_0 MAKE_PMC_REG(0x1B4) +#define APBDEV_PMC_IO_DPD_REQ_0 MAKE_PMC_REG(0x1B8) +#define APBDEV_PMC_IO_DPD2_REQ_0 MAKE_PMC_REG(0x1C0) +#define APBDEV_PMC_VDDP_SEL_0 MAKE_PMC_REG(0x1CC) +#define APBDEV_PMC_SCRATCH49_0 MAKE_PMC_REG(0x244) +#define APBDEV_PMC_TSC_MULT_0 MAKE_PMC_REG(0x2B4) +#define APBDEV_PMC_REG_SHORT_0 MAKE_PMC_REG(0x2CC) +#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8) +#define APBDEV_PMC_SECURE_SCRATCH21_0 MAKE_PMC_REG(0x334) +#define APBDEV_PMC_SECURE_SCRATCH32_0 MAKE_PMC_REG(0x360) +#define APBDEV_PMC_SECURE_SCRATCH49_0 MAKE_PMC_REG(0x3A4) +#define APBDEV_PMC_CNTRL2_0 MAKE_PMC_REG(0x440) +#define APBDEV_PMC_IO_DPD4_REQ_0 MAKE_PMC_REG(0x464) +#define APBDEV_PMC_UTMIP_PAD_CFG1_0 MAKE_PMC_REG(0x4C4) +#define APBDEV_PMC_UTMIP_PAD_CFG3_0 MAKE_PMC_REG(0x4CC) +#define APBDEV_PMC_DDR_CNTRL_0 MAKE_PMC_REG(0x4E4) +#define APBDEV_PMC_SCRATCH43_0 MAKE_PMC_REG(0x22C) +#define APBDEV_PMC_SCRATCH188_0 MAKE_PMC_REG(0x810) +#define APBDEV_PMC_SCRATCH190_0 MAKE_PMC_REG(0x818) +#define APBDEV_PMC_SCRATCH200_0 MAKE_PMC_REG(0x840) + +#define APBDEV_PMC_SCRATCH45_0 MAKE_PMC_REG(0x234) +#define APBDEV_PMC_SCRATCH46_0 MAKE_PMC_REG(0x238) +#define APBDEV_PMC_SCRATCH33_0 MAKE_PMC_REG(0x120) +#define APBDEV_PMC_SCRATCH40_0 MAKE_PMC_REG(0x13C) + +typedef struct { + uint32_t cntrl; + uint32_t sec_disable; + uint32_t pmc_swrst; + uint32_t wake_mask; + uint32_t wake_lvl; + uint32_t wake_status; + uint32_t sw_wake_status; + uint32_t dpd_pads_oride; + uint32_t dpd_sample; + uint32_t dpd_enable; + uint32_t pwrgate_timer_off; + uint32_t clamp_status; + uint32_t pwrgate_toggle; + uint32_t remove_clamping; + uint32_t pwrgate_status; + uint32_t pwrgood_timer; + uint32_t blink_timer; + uint32_t no_iopower; + uint32_t pwr_det; + uint32_t pwr_det_latch; + uint32_t scratch0; + uint32_t scratch1; + uint32_t scratch2; + uint32_t scratch3; + uint32_t scratch4; + uint32_t scratch5; + uint32_t scratch6; + uint32_t scratch7; + uint32_t scratch8; + uint32_t scratch9; + uint32_t scratch10; + uint32_t scratch11; + uint32_t scratch12; + uint32_t scratch13; + uint32_t scratch14; + uint32_t scratch15; + uint32_t scratch16; + uint32_t scratch17; + uint32_t scratch18; + uint32_t scratch19; + uint32_t scratch20; + uint32_t scratch21; + uint32_t scratch22; + uint32_t scratch23; + uint32_t secure_scratch0; + uint32_t secure_scratch1; + uint32_t secure_scratch2; + uint32_t secure_scratch3; + uint32_t secure_scratch4; + uint32_t secure_scratch5; + uint32_t cpupwrgood_timer; + uint32_t cpupwroff_timer; + uint32_t pg_mask; + uint32_t pg_mask_1; + uint32_t auto_wake_lvl; + uint32_t auto_wake_lvl_mask; + uint32_t wake_delay; + uint32_t pwr_det_val; + uint32_t ddr_pwr; + uint32_t usb_debounce_del; + uint32_t usb_ao; + uint32_t crypto_op; + uint32_t pllp_wb0_override; + uint32_t scratch24; + uint32_t scratch25; + uint32_t scratch26; + uint32_t scratch27; + uint32_t scratch28; + uint32_t scratch29; + uint32_t scratch30; + uint32_t scratch31; + uint32_t scratch32; + uint32_t scratch33; + uint32_t scratch34; + uint32_t scratch35; + uint32_t scratch36; + uint32_t scratch37; + uint32_t scratch38; + uint32_t scratch39; + uint32_t scratch40; + uint32_t scratch41; + uint32_t scratch42; + uint32_t bo_mirror0; + uint32_t bo_mirror1; + uint32_t bo_mirror2; + uint32_t sys_33v_en; + uint32_t bo_mirror_access; + uint32_t gate; + uint32_t wake2_mask; + uint32_t wake2_lvl; + uint32_t wake2_stat; + uint32_t sw_wake2_stat; + uint32_t auto_wake2_lvl_mask; + uint32_t pg_mask2; + uint32_t pg_mask_ce1; + uint32_t pg_mask_ce2; + uint32_t pg_mask_ce3; + uint32_t pwrgate_timer_ce0; + uint32_t pwrgate_timer_ce1; + uint32_t pwrgate_timer_ce2; + uint32_t pwrgate_timer_ce3; + uint32_t pwrgate_timer_ce4; + uint32_t pwrgate_timer_ce5; + uint32_t pwrgate_timer_ce6; + uint32_t pcx_edpd_cntrl; + uint32_t osc_edpd_over; + uint32_t clk_out_cntrl; + uint32_t sata_pwrgate; + uint32_t sensor_ctrl; + uint32_t reset_status; + uint32_t io_dpd_req; + uint32_t io_dpd_stat; + uint32_t io_dpd2_req; + uint32_t io_dpd2_stat; + uint32_t sel_dpd_tim; + uint32_t vddp_sel; + uint32_t ddr_cfg; + uint32_t e_no_vttgen; + uint32_t _reserved0; + uint32_t pllm_wb0_ovrride_frq; + uint32_t test_pwrgate; + uint32_t pwrgate_timer_mult; + uint32_t dsi_sel_dpd; + uint32_t utmip_uhsic_triggers; + uint32_t utmip_uhsic_saved_st; + uint32_t utmip_pad_cfg; + uint32_t utmip_term_pad_cfg; + uint32_t utmip_uhsic_sleep_cfg; + uint32_t utmip_uhsic_sleepwalk_cfg; + uint32_t utmip_sleepwalk_p[3]; + uint32_t uhsic_sleepwalk_p0; + uint32_t utmip_uhsic_status; + uint32_t utmip_uhsic_fake; + uint32_t bo_mirror3[2]; + uint32_t secure_scratch6; + uint32_t secure_scratch7; + uint32_t scratch43; + uint32_t scratch44; + uint32_t scratch45; + uint32_t scratch46; + uint32_t scratch47; + uint32_t scratch48; + uint32_t scratch49; + uint32_t scratch50; + uint32_t scratch51; + uint32_t scratch52; + uint32_t scratch53; + uint32_t scratch54; + uint32_t scratch55; + uint32_t scratch0_eco; + uint32_t por_dpd_ctrl; + uint32_t scratch2_eco; + uint32_t utmip_uhsic_line_wakeup; + uint32_t utmip_bias_master_cntrl; + uint32_t utmip_master_config; + uint32_t td_pwrgate_inter_part_timer; + uint32_t utmip_uhsic2_triggers; + uint32_t utmip_uhsic2_saved_state; + uint32_t utmip_uhsic2_sleep_cfg; + uint32_t utmip_uhsic2_sleepwalk_cfg; + uint32_t uhsic2_sleepwalk_p1; + uint32_t utmip_uhsic2_status; + uint32_t utmip_uhsic2_fake; + uint32_t utmip_uhsic2_line_wakeup; + uint32_t utmip_master2_config; + uint32_t utmip_uhsic_rpd_cfg; + uint32_t pg_mask_ce0; + uint32_t pg_mask3[2]; + uint32_t pllm_wb0_override2; + uint32_t tsc_mult; + uint32_t cpu_vsense_override; + uint32_t glb_amap_cfg; + uint32_t sticky_bits; + uint32_t sec_disable2; + uint32_t weak_bias; + uint32_t reg_short; + uint32_t pg_mask_andor; + uint32_t _reserved1[11]; + uint32_t secure_scratch8; + uint32_t secure_scratch9; + uint32_t secure_scratch10; + uint32_t secure_scratch11; + uint32_t secure_scratch12; + uint32_t secure_scratch13; + uint32_t secure_scratch14; + uint32_t secure_scratch15; + uint32_t secure_scratch16; + uint32_t secure_scratch17; + uint32_t secure_scratch18; + uint32_t secure_scratch19; + uint32_t secure_scratch20; + uint32_t secure_scratch21; + uint32_t secure_scratch22; + uint32_t secure_scratch23; + uint32_t secure_scratch24; + uint32_t secure_scratch25; + uint32_t secure_scratch26; + uint32_t secure_scratch27; + uint32_t secure_scratch28; + uint32_t secure_scratch29; + uint32_t secure_scratch30; + uint32_t secure_scratch31; + uint32_t secure_scratch32; + uint32_t secure_scratch33; + uint32_t secure_scratch34; + uint32_t secure_scratch35; + uint32_t secure_scratch36; + uint32_t secure_scratch37; + uint32_t secure_scratch38; + uint32_t secure_scratch39; + uint32_t secure_scratch40; + uint32_t secure_scratch41; + uint32_t secure_scratch42; + uint32_t secure_scratch43; + uint32_t secure_scratch44; + uint32_t secure_scratch45; + uint32_t secure_scratch46; + uint32_t secure_scratch47; + uint32_t secure_scratch48; + uint32_t secure_scratch49; + uint32_t secure_scratch50; + uint32_t secure_scratch51; + uint32_t secure_scratch52; + uint32_t secure_scratch53; + uint32_t secure_scratch54; + uint32_t secure_scratch55; + uint32_t secure_scratch56; + uint32_t secure_scratch57; + uint32_t secure_scratch58; + uint32_t secure_scratch59; + uint32_t secure_scratch60; + uint32_t secure_scratch61; + uint32_t secure_scratch62; + uint32_t secure_scratch63; + uint32_t secure_scratch64; + uint32_t secure_scratch65; + uint32_t secure_scratch66; + uint32_t secure_scratch67; + uint32_t secure_scratch68; + uint32_t secure_scratch69; + uint32_t secure_scratch70; + uint32_t secure_scratch71; + uint32_t secure_scratch72; + uint32_t secure_scratch73; + uint32_t secure_scratch74; + uint32_t secure_scratch75; + uint32_t secure_scratch76; + uint32_t secure_scratch77; + uint32_t secure_scratch78; + uint32_t secure_scratch79; + uint32_t _reserved2[8]; + uint32_t cntrl2; + uint32_t _reserved3[2]; + uint32_t event_counter; + uint32_t fuse_control; + uint32_t scratch1_eco; + uint32_t _reserved4; + uint32_t io_dpd3_req; + uint32_t io_dpd3_status; + uint32_t io_dpd4_req; + uint32_t io_dpd4_status; + uint32_t _reserved5[30]; + uint32_t ddr_cntrl; + uint32_t _reserved6[70]; + uint32_t scratch56; + uint32_t scratch57; + uint32_t scratch58; + uint32_t scratch59; + uint32_t scratch60; + uint32_t scratch61; + uint32_t scratch62; + uint32_t scratch63; + uint32_t scratch64; + uint32_t scratch65; + uint32_t scratch66; + uint32_t scratch67; + uint32_t scratch68; + uint32_t scratch69; + uint32_t scratch70; + uint32_t scratch71; + uint32_t scratch72; + uint32_t scratch73; + uint32_t scratch74; + uint32_t scratch75; + uint32_t scratch76; + uint32_t scratch77; + uint32_t scratch78; + uint32_t scratch79; + uint32_t scratch80; + uint32_t scratch81; + uint32_t scratch82; + uint32_t scratch83; + uint32_t scratch84; + uint32_t scratch85; + uint32_t scratch86; + uint32_t scratch87; + uint32_t scratch88; + uint32_t scratch89; + uint32_t scratch90; + uint32_t scratch91; + uint32_t scratch92; + uint32_t scratch93; + uint32_t scratch94; + uint32_t scratch95; + uint32_t scratch96; + uint32_t scratch97; + uint32_t scratch98; + uint32_t scratch99; + uint32_t scratch100; + uint32_t scratch101; + uint32_t scratch102; + uint32_t scratch103; + uint32_t scratch104; + uint32_t scratch105; + uint32_t scratch106; + uint32_t scratch107; + uint32_t scratch108; + uint32_t scratch109; + uint32_t scratch110; + uint32_t scratch111; + uint32_t scratch112; + uint32_t scratch113; + uint32_t scratch114; + uint32_t scratch115; + uint32_t scratch116; + uint32_t scratch117; + uint32_t scratch118; + uint32_t scratch119; + uint32_t scratch120; + uint32_t scratch121; + uint32_t scratch122; + uint32_t scratch123; + uint32_t scratch124; + uint32_t scratch125; + uint32_t scratch126; + uint32_t scratch127; + uint32_t scratch128; + uint32_t scratch129; + uint32_t scratch130; + uint32_t scratch131; + uint32_t scratch132; + uint32_t scratch133; + uint32_t scratch134; + uint32_t scratch135; + uint32_t scratch136; + uint32_t scratch137; + uint32_t scratch138; + uint32_t scratch139; + uint32_t scratch140; + uint32_t scratch141; + uint32_t scratch142; + uint32_t scratch143; + uint32_t scratch144; + uint32_t scratch145; + uint32_t scratch146; + uint32_t scratch147; + uint32_t scratch148; + uint32_t scratch149; + uint32_t scratch150; + uint32_t scratch151; + uint32_t scratch152; + uint32_t scratch153; + uint32_t scratch154; + uint32_t scratch155; + uint32_t scratch156; + uint32_t scratch157; + uint32_t scratch158; + uint32_t scratch159; + uint32_t scratch160; + uint32_t scratch161; + uint32_t scratch162; + uint32_t scratch163; + uint32_t scratch164; + uint32_t scratch165; + uint32_t scratch166; + uint32_t scratch167; + uint32_t scratch168; + uint32_t scratch169; + uint32_t scratch170; + uint32_t scratch171; + uint32_t scratch172; + uint32_t scratch173; + uint32_t scratch174; + uint32_t scratch175; + uint32_t scratch176; + uint32_t scratch177; + uint32_t scratch178; + uint32_t scratch179; + uint32_t scratch180; + uint32_t scratch181; + uint32_t scratch182; + uint32_t scratch183; + uint32_t scratch184; + uint32_t scratch185; + uint32_t scratch186; + uint32_t scratch187; + uint32_t scratch188; + uint32_t scratch189; + uint32_t scratch190; + uint32_t scratch191; + uint32_t scratch192; + uint32_t scratch193; + uint32_t scratch194; + uint32_t scratch195; + uint32_t scratch196; + uint32_t scratch197; + uint32_t scratch198; + uint32_t scratch199; + uint32_t scratch200; + uint32_t scratch201; + uint32_t scratch202; + uint32_t scratch203; + uint32_t scratch204; + uint32_t scratch205; + uint32_t scratch206; + uint32_t scratch207; + uint32_t scratch208; + uint32_t scratch209; + uint32_t scratch210; + uint32_t scratch211; + uint32_t scratch212; + uint32_t scratch213; + uint32_t scratch214; + uint32_t scratch215; + uint32_t scratch216; + uint32_t scratch217; + uint32_t scratch218; + uint32_t scratch219; + uint32_t scratch220; + uint32_t scratch221; + uint32_t scratch222; + uint32_t scratch223; + uint32_t scratch224; + uint32_t scratch225; + uint32_t scratch226; + uint32_t scratch227; + uint32_t scratch228; + uint32_t scratch229; + uint32_t scratch230; + uint32_t scratch231; + uint32_t scratch232; + uint32_t scratch233; + uint32_t scratch234; + uint32_t scratch235; + uint32_t scratch236; + uint32_t scratch237; + uint32_t scratch238; + uint32_t scratch239; + uint32_t scratch240; + uint32_t scratch241; + uint32_t scratch242; + uint32_t scratch243; + uint32_t scratch244; + uint32_t scratch245; + uint32_t scratch246; + uint32_t scratch247; + uint32_t scratch248; + uint32_t scratch249; + uint32_t scratch250; + uint32_t scratch251; + uint32_t scratch252; + uint32_t scratch253; + uint32_t scratch254; + uint32_t scratch255; + uint32_t scratch256; + uint32_t scratch257; + uint32_t scratch258; + uint32_t scratch259; + uint32_t scratch260; + uint32_t scratch261; + uint32_t scratch262; + uint32_t scratch263; + uint32_t scratch264; + uint32_t scratch265; + uint32_t scratch266; + uint32_t scratch267; + uint32_t scratch268; + uint32_t scratch269; + uint32_t scratch270; + uint32_t scratch271; + uint32_t scratch272; + uint32_t scratch273; + uint32_t scratch274; + uint32_t scratch275; + uint32_t scratch276; + uint32_t scratch277; + uint32_t scratch278; + uint32_t scratch279; + uint32_t scratch280; + uint32_t scratch281; + uint32_t scratch282; + uint32_t scratch283; + uint32_t scratch284; + uint32_t scratch285; + uint32_t scratch286; + uint32_t scratch287; + uint32_t scratch288; + uint32_t scratch289; + uint32_t scratch290; + uint32_t scratch291; + uint32_t scratch292; + uint32_t scratch293; + uint32_t scratch294; + uint32_t scratch295; + uint32_t scratch296; + uint32_t scratch297; + uint32_t scratch298; + uint32_t scratch299; + uint32_t _reserved7[50]; + uint32_t secure_scratch80; + uint32_t secure_scratch81; + uint32_t secure_scratch82; + uint32_t secure_scratch83; + uint32_t secure_scratch84; + uint32_t secure_scratch85; + uint32_t secure_scratch86; + uint32_t secure_scratch87; + uint32_t secure_scratch88; + uint32_t secure_scratch89; + uint32_t secure_scratch90; + uint32_t secure_scratch91; + uint32_t secure_scratch92; + uint32_t secure_scratch93; + uint32_t secure_scratch94; + uint32_t secure_scratch95; + uint32_t secure_scratch96; + uint32_t secure_scratch97; + uint32_t secure_scratch98; + uint32_t secure_scratch99; + uint32_t secure_scratch100; + uint32_t secure_scratch101; + uint32_t secure_scratch102; + uint32_t secure_scratch103; + uint32_t secure_scratch104; + uint32_t secure_scratch105; + uint32_t secure_scratch106; + uint32_t secure_scratch107; + uint32_t secure_scratch108; + uint32_t secure_scratch109; + uint32_t secure_scratch110; + uint32_t secure_scratch111; + uint32_t secure_scratch112; + uint32_t secure_scratch113; + uint32_t secure_scratch114; + uint32_t secure_scratch115; + uint32_t secure_scratch116; + uint32_t secure_scratch117; + uint32_t secure_scratch118; + uint32_t secure_scratch119; +} tegra_pmc_t; + +static inline volatile tegra_pmc_t *pmc_get_regs(void) +{ + return (volatile tegra_pmc_t *)PMC_BASE; +} + +#endif diff --git a/sept/sept-secondary/key_derivation/src/se.c b/sept/sept-secondary/key_derivation/src/se.c new file mode 100644 index 000000000..e7db66ab0 --- /dev/null +++ b/sept/sept-secondary/key_derivation/src/se.c @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2018-2019 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 "utils.h" +#include "se.h" + +void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size); + +/* Globals for driver. */ +static unsigned int g_se_modulus_sizes[KEYSLOT_RSA_MAX]; +static unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX]; + +/* Initialize a SE linked list. */ +void NOINLINE ll_init(volatile se_ll_t *ll, void *buffer, size_t size) { + ll->num_entries = 0; /* 1 Entry. */ + + if (buffer != NULL) { + ll->addr_info.address = (uint32_t) get_physical_address(buffer); + ll->addr_info.size = (uint32_t) size; + } else { + ll->addr_info.address = 0; + ll->addr_info.size = 0; + } +} + +void se_check_error_status_reg(void) { + if (se_get_regs()->ERR_STATUS_REG) { + generic_panic(); + } +} + +void se_check_for_error(void) { + volatile tegra_se_t *se = se_get_regs(); + if (se->INT_STATUS_REG & 0x10000 || se->FLAGS_REG & 3 || se->ERR_STATUS_REG) { + generic_panic(); + } +} + +void se_verify_flags_cleared(void) { + if (se_get_regs()->FLAGS_REG & 3) { + generic_panic(); + } +} + +/* Set the flags for an AES keyslot. */ +void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + /* Misc flags. */ + if (flags & ~0x80) { + se->AES_KEYSLOT_FLAGS[keyslot] = ~flags; + } + + /* Disable keyslot reads. */ + if (flags & 0x80) { + se->AES_KEY_READ_DISABLE_REG &= ~(1 << keyslot); + } +} + +/* Set the flags for an RSA keyslot. */ +void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_RSA_MAX) { + generic_panic(); + } + + /* Misc flags. */ + if (flags & ~0x80) { + /* TODO: Why are flags assigned this way? */ + se->RSA_KEYSLOT_FLAGS[keyslot] = (((flags >> 4) & 4) | (flags & 3)) ^ 7; + } + + /* Disable keyslot reads. */ + if (flags & 0x80) { + se->RSA_KEY_READ_DISABLE_REG &= ~(1 << keyslot); + } +} + +void clear_aes_keyslot(unsigned int keyslot) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + /* Zero out the whole keyslot and IV. */ + for (unsigned int i = 0; i < 0x10; i++) { + se->AES_KEYTABLE_ADDR = (keyslot << 4) | i; + se->AES_KEYTABLE_DATA = 0; + } +} + +void clear_rsa_keyslot(unsigned int keyslot) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_RSA_MAX) { + generic_panic(); + } + + /* Zero out the whole keyslot. */ + for (unsigned int i = 0; i < 0x40; i++) { + /* Select Keyslot Modulus[i] */ + se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i | 0x40; + se->RSA_KEYTABLE_DATA = 0; + } + for (unsigned int i = 0; i < 0x40; i++) { + /* Select Keyslot Expontent[i] */ + se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i; + se->RSA_KEYTABLE_DATA = 0; + } +} + +void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) { + generic_panic(); + } + + for (size_t i = 0; i < (key_size >> 2); i++) { + se->AES_KEYTABLE_ADDR = (keyslot << 4) | i; + se->AES_KEYTABLE_DATA = read32le(key, 4 * i); + } +} + +void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) { + generic_panic(); + } + + for (size_t i = 0; i < (modulus_size >> 2); i++) { + se->RSA_KEYTABLE_ADDR = (keyslot << 7) | 0x40 | i; + se->RSA_KEYTABLE_DATA = read32be(modulus, (4 * (modulus_size >> 2)) - (4 * i) - 4); + } + + for (size_t i = 0; i < (exp_size >> 2); i++) { + se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i; + se->RSA_KEYTABLE_DATA = read32be(exponent, (4 * (exp_size >> 2)) - (4 * i) - 4); + } + + g_se_modulus_sizes[keyslot] = modulus_size; + g_se_exp_sizes[keyslot] = exp_size; +} + +void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) { + generic_panic(); + } + + for (size_t i = 0; i < (iv_size >> 2); i++) { + se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i; + se->AES_KEYTABLE_DATA = read32le(iv, 4 * i); + } +} + +void clear_aes_keyslot_iv(unsigned int keyslot) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + for (size_t i = 0; i < (0x10 >> 2); i++) { + se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i; + se->AES_KEYTABLE_DATA = 0; + } +} + +void set_se_ctr(const void *ctr) { + for (unsigned int i = 0; i < 4; i++) { + se_get_regs()->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4); + } +} + +void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSLOT_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) { + generic_panic(); + } + + se->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB); + se->CRYPTO_REG = keyslot_src << 24; + se->BLOCK_COUNT_REG = 0; + se->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8; + + trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size); +} + +void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { + volatile tegra_se_t *se = se_get_regs(); + uint8_t ALIGN(16) stack_buf[KEYSIZE_RSA_MAX]; + + if (keyslot >= KEYSLOT_RSA_MAX || src_size > KEYSIZE_RSA_MAX || dst_size > KEYSIZE_RSA_MAX) { + generic_panic(); + } + + /* Endian swap the input. */ + for (size_t i = 0; i < src_size; i++) { + stack_buf[i] = *((uint8_t *)src + src_size - i - 1); + } + + se->CONFIG_REG = (ALG_RSA | DST_RSAREG); + se->RSA_CONFIG = keyslot << 24; + se->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1; + se->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2; + + trigger_se_blocking_op(OP_START, NULL, 0, stack_buf, src_size); + se_get_exp_mod_output(dst, dst_size); +} + +void se_get_exp_mod_output(void *buf, size_t size) { + size_t num_dwords = (size >> 2); + + if (num_dwords < 1) { + return; + } + + uint32_t *p_out = ((uint32_t *)buf) + num_dwords - 1; + uint32_t offset = 0; + + /* Copy endian swapped output. */ + while (num_dwords) { + *p_out = read32be(se_get_regs()->RSA_OUTPUT, offset); + offset += 4; + p_out--; + num_dwords--; + } +} + +bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size) { + uint8_t message[RSA_2048_BYTES]; + uint8_t h_buf[0x24]; + + /* Hardcode RSA with keyslot 0. */ + const uint8_t public_exponent[4] = {0x00, 0x01, 0x00, 0x01}; + set_rsa_keyslot(0, modulus, modulus_size, public_exponent, sizeof(public_exponent)); + se_synchronous_exp_mod(0, message, sizeof(message), signature, signature_size); + + /* Validate sanity byte. */ + if (message[RSA_2048_BYTES - 1] != 0xBC) { + return false; + } + + /* Copy Salt into MGF1 Hash Buffer. */ + memset(h_buf, 0, sizeof(h_buf)); + memcpy(h_buf, message + RSA_2048_BYTES - 0x20 - 0x1, 0x20); + + /* Decrypt maskedDB (via inline MGF1). */ + uint8_t seed = 0; + uint8_t mgf1_buf[0x20]; + for (unsigned int ofs = 0; ofs < RSA_2048_BYTES - 0x20 - 1; ofs += 0x20) { + h_buf[sizeof(h_buf) - 1] = seed++; + se_calculate_sha256(mgf1_buf, h_buf, sizeof(h_buf)); + for (unsigned int i = ofs; i < ofs + 0x20 && i < RSA_2048_BYTES - 0x20 - 1; i++) { + message[i] ^= mgf1_buf[i - ofs]; + } + } + + /* Constant lmask for rsa-2048-pss. */ + message[0] &= 0x7F; + + /* Validate DB is of the form 0000...0001. */ + for (unsigned int i = 0; i < RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1; i++) { + if (message[i] != 0) { + return false; + } + } + if (message[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) { + return false; + } + + /* Check hash correctness. */ + uint8_t validate_buf[8 + 0x20 + 0x20]; + uint8_t validate_hash[0x20]; + + memset(validate_buf, 0, sizeof(validate_buf)); + se_calculate_sha256(&validate_buf[8], data, data_size); + memcpy(&validate_buf[0x28], &message[RSA_2048_BYTES - 0x20 - 0x20 - 1], 0x20); + se_calculate_sha256(validate_hash, validate_buf, sizeof(validate_buf)); + return memcmp(h_buf, validate_hash, 0x20) == 0; +} + +void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size) { + volatile tegra_se_t *se = se_get_regs(); + se_ll_t in_ll; + se_ll_t out_ll; + + ll_init(&in_ll, (void *)src, src_size); + ll_init(&out_ll, dst, dst_size); + + /* Set the LLs. */ + se->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll); + se->OUT_LL_ADDR_REG = (uint32_t) get_physical_address(&out_ll); + + /* Set registers for operation. */ + se->ERR_STATUS_REG = se->ERR_STATUS_REG; + se->INT_STATUS_REG = se->INT_STATUS_REG; + se->OPERATION_REG = op; + + while (!(se->INT_STATUS_REG & 0x10)) { /* Wait a while */ } + se_check_for_error(); +} + +/* Secure AES Functionality. */ +void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src, size_t src_size) { + uint8_t block[0x10] = {0}; + + if (src_size > sizeof(block) || dst_size > sizeof(block)) { + generic_panic(); + } + + /* Load src data into block. */ + if (src_size != 0) { + memcpy(block, src, src_size); + } + + /* Trigger AES operation. */ + se_get_regs()->BLOCK_COUNT_REG = 0; + trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block)); + + /* Copy output data into dst. */ + if (dst_size != 0) { + memcpy(dst, block, dst_size); + } +} + +void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) { + generic_panic(); + } + unsigned int num_blocks = src_size >> 4; + + /* Unknown what this write does, but official code writes it for CTR mode. */ + se->SPARE_0 = 1; + se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY); + se->CRYPTO_REG = (keyslot << 24) | 0x91E; + set_se_ctr(ctr); + + /* Handle any aligned blocks. */ + size_t aligned_size = (size_t)num_blocks << 4; + if (aligned_size) { + se->BLOCK_COUNT_REG = num_blocks - 1; + trigger_se_blocking_op(OP_START, dst, dst_size, src, aligned_size); + } + + /* Handle final, unaligned block. */ + if (aligned_size < dst_size && aligned_size < src_size) { + size_t last_block_size = dst_size - aligned_size; + if (src_size < dst_size) { + last_block_size = src_size - aligned_size; + } + se_perform_aes_block_operation(dst + aligned_size, last_block_size, (uint8_t *)src + aligned_size, src_size - aligned_size); + } +} + +void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) { + generic_panic(); + } + + /* Set configuration high (256-bit vs 128-bit) based on parameter. */ + se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (config_high << 16); + se->CRYPTO_REG = keyslot << 24 | 0x100; + se_perform_aes_block_operation(dst, 0x10, src, 0x10); +} + +void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { + se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0); +} + +void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { + se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0x202); +} + +void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) { + generic_panic(); + } + + se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY); + se->CRYPTO_REG = keyslot << 24; + se_perform_aes_block_operation(dst, 0x10, src, 0x10); +} + +void shift_left_xor_rb(uint8_t *key) { + uint8_t prev_high_bit = 0; + for (unsigned int i = 0; i < 0x10; i++) { + uint8_t cur_byte = key[0xF - i]; + key[0xF - i] = (cur_byte << 1) | (prev_high_bit); + prev_high_bit = cur_byte >> 7; + } + if (prev_high_bit) { + key[0xF] ^= 0x87; + } +} + +void shift_left_xor_rb_le(uint8_t *key) { + uint8_t prev_high_bit = 0; + for (unsigned int i = 0; i < 0x10; i++) { + uint8_t cur_byte = key[i]; + key[i] = (cur_byte << 1) | (prev_high_bit); + prev_high_bit = cur_byte >> 7; + } + if (prev_high_bit) { + key[0x0] ^= 0x87; + } +} + +void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + /* Generate the derived key, to be XOR'd with final output block. */ + uint8_t ALIGN(16) derived_key[0x10] = {0}; + se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high); + shift_left_xor_rb(derived_key); + if (data_size & 0xF) { + shift_left_xor_rb(derived_key); + } + + se->CONFIG_REG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16); + se->CRYPTO_REG = (keyslot << 24) | (0x145); + clear_aes_keyslot_iv(keyslot); + + unsigned int num_blocks = (data_size + 0xF) >> 4; + /* Handle aligned blocks. */ + if (num_blocks > 1) { + se->BLOCK_COUNT_REG = num_blocks - 2; + trigger_se_blocking_op(OP_START, NULL, 0, data, data_size); + se->CRYPTO_REG |= 0x80; + } + + /* Create final block. */ + uint8_t ALIGN(16) last_block[0x10] = {0}; + if (data_size & 0xF) { + memcpy(last_block, data + (data_size & ~0xF), data_size & 0xF); + last_block[data_size & 0xF] = 0x80; /* Last block = data || 100...0 */ + } else if (data_size >= 0x10) { + memcpy(last_block, data + data_size - 0x10, 0x10); + } + + for (unsigned int i = 0; i < 0x10; i++) { + last_block[i] ^= derived_key[i]; + } + + /* Perform last operation. */ + se->BLOCK_COUNT_REG = 0; + trigger_se_blocking_op(OP_START, NULL, 0, last_block, sizeof(last_block)); + + /* Copy output CMAC. */ + for (unsigned int i = 0; i < (cmac_size >> 2); i++) { + ((uint32_t *)cmac)[i] = read32le(se->HASH_RESULT_REG, i << 2); + } +} + +void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) { + se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0); +} +void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) { + se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0x202); +} + +void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) { + generic_panic(); + } + + se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16); + se->CRYPTO_REG = (keyslot << 24) | 0x144; + set_aes_keyslot_iv(keyslot, iv, 0x10); + se->BLOCK_COUNT_REG = (src_size >> 4) - 1; + trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size); +} + +void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) { + generic_panic(); + } + + se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY) | (0x000 << 16); + se->CRYPTO_REG = (keyslot << 24) | 0x66; + clear_aes_keyslot_iv(keyslot); + se->BLOCK_COUNT_REG = (src_size >> 4) - 1; + trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size); +} + +/* SHA256 Implementation. */ +void se_calculate_sha256(void *dst, const void *src, size_t src_size) { + volatile tegra_se_t *se = se_get_regs(); + + /* Setup config for SHA256, size = BITS(src_size) */ + se->CONFIG_REG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG); + se->SHA_CONFIG_REG = 1; + se->SHA_MSG_LENGTH_REG = (uint32_t)(src_size << 3); + se->_0x208 = 0; + se->_0x20C = 0; + se->_0x210 = 0; + se->SHA_MSG_LEFT_REG = (uint32_t)(src_size << 3); + se->_0x218 = 0; + se->_0x21C = 0; + se->_0x220 = 0; + + /* Trigger the operation. */ + trigger_se_blocking_op(OP_START, NULL, 0, src, src_size); + + /* Copy output hash. */ + for (unsigned int i = 0; i < (0x20 >> 2); i++) { + ((uint32_t *)dst)[i] = read32be(se->HASH_RESULT_REG, i << 2); + } +} + +/* RNG API */ +void se_initialize_rng(unsigned int keyslot) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + /* To initialize the RNG, we'll perform an RNG operation into an output buffer. */ + /* This will be discarded, when done. */ + uint8_t ALIGN(16) output_buf[0x10]; + + se->RNG_SRC_CONFIG_REG = 3; /* Entropy enable + Entropy lock enable */ + se->RNG_RESEED_INTERVAL_REG = 70001; + se->CONFIG_REG = (ALG_RNG | DST_MEMORY); + se->CRYPTO_REG = (keyslot << 24) | 0x108; + se->RNG_CONFIG_REG = 5; + se->BLOCK_COUNT_REG = 0; + trigger_se_blocking_op(OP_START, output_buf, 0x10, NULL, 0); +} + +void se_generate_random(unsigned int keyslot, void *dst, size_t size) { + volatile tegra_se_t *se = se_get_regs(); + + if (keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + uint32_t num_blocks = size >> 4; + size_t aligned_size = num_blocks << 4; + se->CONFIG_REG = (ALG_RNG | DST_MEMORY); + se->CRYPTO_REG = (keyslot << 24) | 0x108; + se->RNG_CONFIG_REG = 4; + + if (num_blocks >= 1) { + se->BLOCK_COUNT_REG = num_blocks - 1; + trigger_se_blocking_op(OP_START, dst, aligned_size, NULL, 0); + } + if (size > aligned_size) { + se_perform_aes_block_operation(dst + aligned_size, size - aligned_size, NULL, 0); + } +} + +void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) { + volatile tegra_se_t *se = se_get_regs(); + + if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) { + generic_panic(); + } + + /* Setup Config. */ + se->CONFIG_REG = (ALG_RNG | DST_KEYTAB); + se->CRYPTO_REG = (rng_keyslot << 24) | 0x108; + se->RNG_CONFIG_REG = 4; + se->BLOCK_COUNT_REG = 0; + + /* Generate low part of key. */ + se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8); + trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0); + /* Generate high part of key. */ + se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8) | 1; + trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0); +} + +/* SE context save API. */ +void se_set_in_context_save_mode(bool is_context_save_mode) { + volatile tegra_se_t *se = se_get_regs(); + + uint32_t val = se->_0x0; + if (is_context_save_mode) { + val |= 0x10000; + } else { + val &= 0xFFFEFFFF; + } + se->_0x0 = val; + /* Perform a useless read from flags reg. */ + (void)(se->FLAGS_REG); +} + +void se_generate_srk(unsigned int srkgen_keyslot) { + volatile tegra_se_t *se = se_get_regs(); + + se->CONFIG_REG = (ALG_RNG | DST_SRK); + se->CRYPTO_REG = (srkgen_keyslot << 24) | 0x108; + se->RNG_CONFIG_REG = 6; + se->BLOCK_COUNT_REG = 0; + trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0); +} + +void se_encrypt_with_srk(void *dst, size_t dst_size, const void *src, size_t src_size) { + uint8_t output[0x80]; + uint8_t *aligned_out = (uint8_t *)(((uintptr_t)output + 0x7F) & ~0x3F); + if (dst_size > 0x10) { + generic_panic(); + } + + if (dst_size) { + trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, dst_size, src, src_size); + memcpy(dst, aligned_out, dst_size); + } else { + trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, 0, src, src_size); + } +} + +void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) { + volatile tegra_se_t *se = se_get_regs(); + uint8_t _work_buf[0x80]; + uint8_t *work_buf = (uint8_t *)(((uintptr_t)_work_buf + 0x7F) & ~0x3F); + + /* Generate the SRK (context save encryption key). */ + se_generate_random_key(srkgen_keyslot, rng_keyslot); + se_generate_srk(srkgen_keyslot); + + se_generate_random(rng_keyslot, work_buf, 0x10); + + /* Save random initial block. */ + se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY); + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst, 0x10, work_buf, 0x10); + + /* Save Sticky Bits. */ + for (unsigned int i = 0; i < 0x2; i++) { + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0); + } + + /* Save AES Key Table. */ + for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) { + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst + 0x30 + (i * 0x20), 0x10, NULL, 0); + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_HIGH_BITS); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0); + } + + /* Save AES Original IVs. */ + for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) { + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_ORIGINAL_IV); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0); + } + + /* Save AES Updated IVs */ + for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) { + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_UPDATED_IV); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0); + } + + /* Save RSA Keytable. */ + uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430; + for (unsigned int rsa_key = 0; rsa_key < KEYSLOT_RSA_MAX; rsa_key++) { + for (unsigned int mod_exp = 0; mod_exp < 2; mod_exp++) { + for (unsigned int sub_block = 0; sub_block < 0x10; sub_block++) { + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_RSA) | ((2 * rsa_key + (1 - mod_exp)) << CTX_SAVE_RSA_KEY_INDEX_SHIFT) | (sub_block << CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(rsa_ctx_out, 0x10, NULL, 0); + rsa_ctx_out += 0x10; + } + } + } + + /* Save "Known Pattern. " */ + static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10); + + /* Save SRK into PMC registers. */ + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(work_buf, 0, NULL, 0); + se->CONFIG_REG = 0; + se_encrypt_with_srk(work_buf, 0, NULL, 0); +} + +void se_save_partial_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) { + volatile tegra_se_t *se = se_get_regs(); + uint8_t _work_buf[0x80]; + uint8_t *work_buf = (uint8_t *)(((uintptr_t)_work_buf + 0x7F) & ~0x3F); + + /* Generate the SRK (context save encryption key). */ + se_generate_random_key(srkgen_keyslot, rng_keyslot); + se_generate_srk(srkgen_keyslot); + + se_generate_random(rng_keyslot, work_buf, 0x10); + + /* Save known pattern. */ + static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst + 0x00, 0x10, context_save_known_pattern, 0x10); + + /* Save specific keyslots 0xC, 0xD, 0xE. */ + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xE << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst + 0x10, 0x10, NULL, 0); + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xC << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst + 0x20, 0x10, NULL, 0); + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xD << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(dst + 0x30, 0x10, NULL, 0); + + /* Save SRK into PMC registers. */ + se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK); + se->BLOCK_COUNT_REG = 0; + se_encrypt_with_srk(work_buf, 0, NULL, 0); + se->CONFIG_REG = 0; + se_encrypt_with_srk(work_buf, 0, NULL, 0); +} diff --git a/sept/sept-secondary/key_derivation/src/se.h b/sept/sept-secondary/key_derivation/src/se.h new file mode 100644 index 000000000..d3b3c7ca1 --- /dev/null +++ b/sept/sept-secondary/key_derivation/src/se.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2018-2019 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 + +#ifndef FUSEE_SE_H +#define FUSEE_SE_H + +#define SE_BASE 0x70012000 +#define MAKE_SE_REG(n) MAKE_REG32(SE_BASE + n) + +#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x2 +#define KEYSLOT_SWITCH_SRKGENKEY 0x8 +#define KEYSLOT_SWITCH_PACKAGE2KEY 0x8 +#define KEYSLOT_SWITCH_TEMPKEY 0x9 +#define KEYSLOT_SWITCH_SESSIONKEY 0xA +#define KEYSLOT_SWITCH_RNGKEY 0xB +#define KEYSLOT_SWITCH_MASTERKEY 0xC +#define KEYSLOT_SWITCH_DEVICEKEY 0xD + +/* This keyslot was added in 4.0.0. */ +#define KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY 0xD +#define KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY 0xE +#define KEYSLOT_SWITCH_4XOLDDEVICEKEY 0xF + +/* This keyslot was added in 5.0.0. */ +#define KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY 0xA + +#define KEYSLOT_AES_MAX 0x10 +#define KEYSLOT_RSA_MAX 0x2 + +#define KEYSIZE_AES_MAX 0x20 +#define KEYSIZE_RSA_MAX 0x100 + +#define ALG_SHIFT (12) +#define ALG_DEC_SHIFT (8) +#define ALG_NOP (0 << ALG_SHIFT) +#define ALG_AES_ENC (1 << ALG_SHIFT) +#define ALG_AES_DEC ((1 << ALG_DEC_SHIFT) | ALG_NOP) +#define ALG_RNG (2 << ALG_SHIFT) +#define ALG_SHA (3 << ALG_SHIFT) +#define ALG_RSA (4 << ALG_SHIFT) + +#define DST_SHIFT (2) +#define DST_MEMORY (0 << DST_SHIFT) +#define DST_HASHREG (1 << DST_SHIFT) +#define DST_KEYTAB (2 << DST_SHIFT) +#define DST_SRK (3 << DST_SHIFT) +#define DST_RSAREG (4 << DST_SHIFT) + +#define ENCMODE_SHIFT (24) +#define DECMODE_SHIFT (16) +#define ENCMODE_SHA256 (5 << ENCMODE_SHIFT) + +#define HASH_DISABLE (0x0) +#define HASH_ENABLE (0x1) + +#define OP_ABORT 0 +#define OP_START 1 +#define OP_RESTART 2 +#define OP_CTX_SAVE 3 +#define OP_RESTART_IN 4 + +#define CTX_SAVE_SRC_SHIFT 29 +#define CTX_SAVE_SRC_STICKY_BITS (0 << CTX_SAVE_SRC_SHIFT) +#define CTX_SAVE_SRC_KEYTABLE_AES (2 << CTX_SAVE_SRC_SHIFT) +#define CTX_SAVE_SRC_KEYTABLE_RSA (1 << CTX_SAVE_SRC_SHIFT) +#define CTX_SAVE_SRC_MEM (4 << CTX_SAVE_SRC_SHIFT) +#define CTX_SAVE_SRC_SRK (6 << CTX_SAVE_SRC_SHIFT) + +#define CTX_SAVE_KEY_LOW_BITS 0 +#define CTX_SAVE_KEY_HIGH_BITS 1 +#define CTX_SAVE_KEY_ORIGINAL_IV 2 +#define CTX_SAVE_KEY_UPDATED_IV 3 + +#define CTX_SAVE_STICKY_BIT_INDEX_SHIFT 24 +#define CTX_SAVE_KEY_INDEX_SHIFT 8 +#define CTX_SAVE_RSA_KEY_INDEX_SHIFT 16 +#define CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT 12 + +#define RSA_2048_BYTES 0x100 + +typedef struct { + uint32_t _0x0; + uint32_t _0x4; + uint32_t OPERATION_REG; + uint32_t INT_ENABLE_REG; + uint32_t INT_STATUS_REG; + uint32_t CONFIG_REG; + uint32_t IN_LL_ADDR_REG; + uint32_t _0x1C; + uint32_t _0x20; + uint32_t OUT_LL_ADDR_REG; + uint32_t _0x28; + uint32_t _0x2C; + uint8_t HASH_RESULT_REG[0x20]; + uint8_t _0x50[0x20]; + uint32_t CONTEXT_SAVE_CONFIG_REG; + uint8_t _0x74[0x18C]; + uint32_t SHA_CONFIG_REG; + uint32_t SHA_MSG_LENGTH_REG; + uint32_t _0x208; + uint32_t _0x20C; + uint32_t _0x210; + uint32_t SHA_MSG_LEFT_REG; + uint32_t _0x218; + uint32_t _0x21C; + uint32_t _0x220; + uint32_t _0x224; + uint8_t _0x228[0x58]; + uint32_t AES_KEY_READ_DISABLE_REG; + uint32_t AES_KEYSLOT_FLAGS[0x10]; + uint8_t _0x2C4[0x3C]; + uint32_t _0x300; + uint32_t CRYPTO_REG; + uint32_t CRYPTO_CTR_REG[4]; + uint32_t BLOCK_COUNT_REG; + uint32_t AES_KEYTABLE_ADDR; + uint32_t AES_KEYTABLE_DATA; + uint32_t _0x324; + uint32_t _0x328; + uint32_t _0x32C; + uint32_t CRYPTO_KEYTABLE_DST_REG; + uint8_t _0x334[0xC]; + uint32_t RNG_CONFIG_REG; + uint32_t RNG_SRC_CONFIG_REG; + uint32_t RNG_RESEED_INTERVAL_REG; + uint8_t _0x34C[0xB4]; + uint32_t RSA_CONFIG; + uint32_t RSA_KEY_SIZE_REG; + uint32_t RSA_EXP_SIZE_REG; + uint32_t RSA_KEY_READ_DISABLE_REG; + uint32_t RSA_KEYSLOT_FLAGS[2]; + uint32_t _0x418; + uint32_t _0x41C; + uint32_t RSA_KEYTABLE_ADDR; + uint32_t RSA_KEYTABLE_DATA; + uint8_t RSA_OUTPUT[0x100]; + uint8_t _0x528[0x2D8]; + uint32_t FLAGS_REG; + uint32_t ERR_STATUS_REG; + uint32_t _0x808; + uint32_t SPARE_0; + uint32_t _0x810; + uint32_t _0x814; + uint32_t _0x818; + uint32_t _0x81C; + uint8_t _0x820[0x17E0]; +} tegra_se_t; + +typedef struct { + uint32_t address; + uint32_t size; +} se_addr_info_t; + +typedef struct { + uint32_t num_entries; /* Set to total entries - 1 */ + se_addr_info_t addr_info; /* This should really be an array...but for our use case it works. */ +} se_ll_t; + +static inline volatile tegra_se_t *se_get_regs(void) { + return (volatile tegra_se_t *)SE_BASE; +} + +void se_check_error_status_reg(void); +void se_check_for_error(void); +void se_trigger_interrupt(void); + +void se_validate_stored_vector(void); +void se_generate_stored_vector(void); + +void se_verify_flags_cleared(void); + +void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags); +void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags); +void clear_aes_keyslot(unsigned int keyslot); +void clear_rsa_keyslot(unsigned int keyslot); + +void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size); +void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size); +void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size); +void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size); +void set_se_ctr(const void *ctr); + +/* Secure AES API */ +void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size); +void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size); +void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); +void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); +void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size); +void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); +void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv); +void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); + +/* Hash API */ +void se_calculate_sha256(void *dst, const void *src, size_t src_size); + +/* RSA API */ +void se_get_exp_mod_output(void *buf, size_t size); +void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); +bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size); + +/* RNG API */ +void se_initialize_rng(unsigned int keyslot); +void se_generate_random(unsigned int keyslot, void *dst, size_t size); + +/* SE context save API. */ +void se_generate_srk(unsigned int srkgen_keyslot); +void se_set_in_context_save_mode(bool is_context_save_mode); +void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot); +void se_save_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst); + +void se_save_partial_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst); + +#endif diff --git a/sept/sept-secondary/key_derivation/src/start.s b/sept/sept-secondary/key_derivation/src/start.s new file mode 100644 index 000000000..f41a9493e --- /dev/null +++ b/sept/sept-secondary/key_derivation/src/start.s @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018-2019 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 . + */ + + /* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */ +#define cpuactlr_el1 s3_1_c15_c2_0 +#define cpuectlr_el1 s3_1_c15_c2_1 + +.macro RESET_CORE + mov x0, #(1 << 63) + msr cpuactlr_el1, x0 /* disable regional clock gating */ + isb + mov x0, #3 + msr rmr_el3, x0 + isb + dsb sy + /* Nintendo forgot to copy-paste the branch instruction below. */ + 1: + wfi + b 1b +.endm + +.macro ERRATUM_INVALIDATE_BTB_AT_BOOT +/* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */ + /* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + /* The following comments are mine. */ + /* mask all interrupts */ + msr daifset, 0b1111 + + /* + Enable invalidates of branch target buffer, then flush + the entire instruction cache at the local level, and + with the reg change, the branch target buffer, then disable + invalidates of the branch target buffer again. + */ + mrs x0, cpuactlr_el1 + orr x0, x0, #1 + msr cpuactlr_el1, x0 + + dsb sy + isb + ic iallu + dsb sy + isb + + mrs x0, cpuactlr_el1 + bic x0, x0, #1 + msr cpuactlr_el1, x0 + +.rept 7 + nop /* wait long enough for the write to cpuactlr_el1 to have completed */ +.endr + + /* if the OS lock is set, disable it and request a warm reset */ + mrs x0, oslsr_el1 + ands x0, x0, #2 + b.eq 2f + mov x0, xzr + msr oslar_el1, x0 + + RESET_CORE + +.rept 65 + nop /* guard against speculative excecution */ +.endr + + 2: + /* set the OS lock */ + mov x0, #1 + msr oslar_el1, x0 +.endm + + +.section .text.start +.align 4 +.global _start +_start: + ERRATUM_INVALIDATE_BTB_AT_BOOT + msr spsel, #0 + ldr x0, =__start__ + mov sp, x0 + mov fp, #0x0 + bl derive_keys \ No newline at end of file diff --git a/sept/sept-secondary/key_derivation/src/utils.c b/sept/sept-secondary/key_derivation/src/utils.c new file mode 100644 index 000000000..cc6cec4b7 --- /dev/null +++ b/sept/sept-secondary/key_derivation/src/utils.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018-2019 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 "utils.h" +#include + +__attribute__ ((noreturn)) void generic_panic(void) { + while(1) { /* ... */ } +} diff --git a/sept/sept-secondary/key_derivation/src/utils.h b/sept/sept-secondary/key_derivation/src/utils.h new file mode 100644 index 000000000..6c8543bf8 --- /dev/null +++ b/sept/sept-secondary/key_derivation/src/utils.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2018-2019 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_UTILS_H +#define FUSEE_UTILS_H + +#include +#include +#include +#include + +#define BIT(n) (1u << (n)) +#define BITL(n) (1ull << (n)) +#define MASK(n) (BIT(n) - 1) +#define MASKL(n) (BITL(n) - 1) +#define MASK2(a,b) (MASK(a) & ~MASK(b)) +#define MASK2L(a,b) (MASKL(a) & ~MASKL(b)) + +#define MAKE_REG32(a) (*(volatile uint32_t *)(a)) + +#define ALIGN(m) __attribute__((aligned(m))) +#define PACKED __attribute__((packed)) + +#define ALINLINE __attribute__((always_inline)) +#define NOINLINE __attribute__((noinline)) + +#define SET_SYSREG(reg, val) do { temp_reg = (val); __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false) + +static inline uintptr_t get_physical_address(const void *addr) { + return (uintptr_t)addr; +} + +static inline uint32_t read32le(const volatile void *dword, size_t offset) { + uintptr_t addr = (uintptr_t)dword + offset; + volatile uint32_t *target = (uint32_t *)addr; + return *target; +} + +static inline uint32_t read32be(const volatile void *dword, size_t offset) { + return __builtin_bswap32(read32le(dword, offset)); +} + +static inline uint64_t read64le(const volatile void *qword, size_t offset) { + uintptr_t addr = (uintptr_t)qword + offset; + volatile uint64_t *target = (uint64_t *)addr; + return *target; +} + +static inline uint64_t read64be(const volatile void *qword, size_t offset) { + return __builtin_bswap64(read64le(qword, offset)); +} + +static inline void write32le(volatile void *dword, size_t offset, uint32_t value) { + uintptr_t addr = (uintptr_t)dword + offset; + volatile uint32_t *target = (uint32_t *)addr; + *target = value; +} + +static inline void write32be(volatile void *dword, size_t offset, uint32_t value) { + write32le(dword, offset, __builtin_bswap32(value)); +} + +static inline void write64le(volatile void *qword, size_t offset, uint64_t value) { + uintptr_t addr = (uintptr_t)qword + offset; + volatile uint64_t *target = (uint64_t *)addr; + *target = value; +} + +static inline void write64be(volatile void *qword, size_t offset, uint64_t value) { + write64le(qword, offset, __builtin_bswap64(value)); +} + +static inline bool check_32bit_additive_overflow(uint32_t a, uint32_t b) { + return __builtin_add_overflow_p(a, b, (uint32_t)0); +} + +static inline bool check_32bit_address_loadable(uintptr_t addr) { + /* FWIW the bootROM forbids loading anything between 0x40000000 and 0x40010000, using it for itself... */ + return (addr >= 0x40010000u && addr < 0x40040000u) || addr >= 0x80000000u; +} + +static inline bool check_32bit_address_range_loadable(uintptr_t addr, size_t size) { + return + !__builtin_add_overflow_p(addr, size, (uintptr_t)0) && /* the range doesn't overflow */ + check_32bit_address_loadable(addr) && check_32bit_address_loadable(addr + size) && /* bounds are valid */ + !(addr >= 0x40010000u && addr < 0x40040000u && addr + size >= 0x40040000u) /* the range doesn't cross MMIO */ + ; +} + +bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be); +static inline bool overlaps_a(const void *as, const void *ae, const void *bs, const void *be) { + return overlaps((uint64_t)(uintptr_t)as, (uint64_t)(uintptr_t)ae, (uint64_t)(uintptr_t)bs, (uint64_t)(uintptr_t)be); +} + +static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t size) { + extern uint8_t __chainloader_start__[], __chainloader_end__[]; + extern uint8_t __stack_bottom__[], __stack_top__[]; + extern uint8_t __start__[], __end__[]; + uint8_t *start = (uint8_t *)addr, *end = start + size; + + return overlaps_a(start, end, __chainloader_start__, __chainloader_end__) || + overlaps_a(start, end, __stack_bottom__, __stack_top__) || + overlaps_a(start, end, (void *)0xC0000000, (void *)0xC03C0000) || /* framebuffer */ + overlaps_a(start, end, __start__, __end__); +} + +__attribute__((noreturn)) void generic_panic(void); + +#endif diff --git a/sept/sept-secondary/linker.ld b/sept/sept-secondary/linker.ld index 27dba8fc7..f6597f78f 100644 --- a/sept/sept-secondary/linker.ld +++ b/sept/sept-secondary/linker.ld @@ -20,8 +20,8 @@ MEMORY SECTIONS { PROVIDE(__start__ = 0x40010000); - PROVIDE(__stack_top__ = 0x40010000); - PROVIDE(__stack_bottom__ = 0x4000C000); + PROVIDE(__stack_top__ = 0x4003C000); + PROVIDE(__stack_bottom__ = 0x40038000); PROVIDE(__heap_start__ = 0); PROVIDE(__heap_end__ = 0); diff --git a/sept/sept-secondary/src/cluster.c b/sept/sept-secondary/src/cluster.c new file mode 100644 index 000000000..cb29ec76b --- /dev/null +++ b/sept/sept-secondary/src/cluster.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 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 "cluster.h" +#include "flow.h" +#include "sysreg.h" +#include "i2c.h" +#include "car.h" +#include "mc.h" +#include "timers.h" +#include "pmc.h" +#include "max77620.h" + +void _cluster_enable_power() +{ + /* Reboot I2C5. */ + clkrst_reboot(CARDEVICE_I2C5); + i2c_init(I2C_5); + + uint8_t val = 0; + i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_AME_GPIO, &val, 1); + + val &= 0xDF; + i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_AME_GPIO, &val, 1); + val = 0x09; + i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_GPIO5, &val, 1); + + /* Enable power. */ + val = 0x20; + i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x02, &val, 1); + val = 0x8D; + i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x03, &val, 1); + val = 0xB7; + i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x00, &val, 1); + val = 0xB7; + i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x01, &val, 1); +} + +int _cluster_pmc_enable_partition(uint32_t part, uint32_t toggle) +{ + volatile tegra_pmc_t *pmc = pmc_get_regs(); + + /* Check if the partition has already been turned on. */ + if (pmc->pwrgate_status & part) + return 1; + + uint32_t i = 5001; + while (pmc->pwrgate_toggle & 0x100) + { + udelay(1); + i--; + if (i < 1) + return 0; + } + + pmc->pwrgate_toggle = (toggle | 0x100); + + i = 5001; + while (i > 0) + { + if (pmc->pwrgate_status & part) + break; + + udelay(1); + i--; + } + + return 1; +} + +void cluster_boot_cpu0(uint32_t entry) +{ + volatile tegra_car_t *car = car_get_regs(); + + /* Set ACTIVE_CLUSER to FAST. */ + FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 &= 0xFFFFFFFE; + + _cluster_enable_power(); + + if (!(car->pllx_base & 0x40000000)) + { + car->pllx_misc3 &= 0xFFFFFFF7; + udelay(2); + car->pllx_base = 0x80404E02; + car->pllx_base = 0x404E02; + car->pllx_misc = ((car->pllx_misc & 0xFFFBFFFF) | 0x40000); + car->pllx_base = 0x40404E02; + } + + while (!(car->pllx_base & 0x8000000)) { + /* Wait. */ + } + + /* Configure MSELECT source and enable clock. */ + car->clk_source_mselect = ((car->clk_source_mselect & 0x1FFFFF00) | 6); + car->clk_out_enb_v = ((car->clk_out_enb_v & 0xFFFFFFF7) | 8); + + /* Configure initial CPU clock frequency and enable clock. */ + car->cclk_brst_pol = 0x20008888; + car->super_cclk_div = 0x80000000; + car->clk_enb_v_set = 1; + + clkrst_reboot(CARDEVICE_CORESIGHT); + + /* CAR2PMC_CPU_ACK_WIDTH should be set to 0. */ + car->cpu_softrst_ctrl2 &= 0xFFFFF000; + + /* Enable CPU rail. */ + _cluster_pmc_enable_partition(1, 0); + + /* Enable cluster 0 non-CPU. */ + _cluster_pmc_enable_partition(0x8000, 15); + + /* Enable CE0. */ + _cluster_pmc_enable_partition(0x4000, 14); + + /* Request and wait for RAM repair. */ + FLOW_CTLR_RAM_REPAIR_0 = 1; + while (!(FLOW_CTLR_RAM_REPAIR_0 & 2)) { + /* Wait. */ + } + + MAKE_EXCP_VEC_REG(0x100) = 0; + + /* Set reset vector. */ + SB_AA64_RESET_LOW_0 = (entry | 1); + SB_AA64_RESET_HIGH_0 = 0; + + /* Non-secure reset vector write disable. */ + SB_CSR_0 = 2; + (void)SB_CSR_0; + + /* Set CPU_STRICT_TZ_APERTURE_CHECK. */ + /* NOTE: [4.0.0+] This was added, but it breaks Exosphère. */ + /* MAKE_MC_REG(MC_TZ_SECURITY_CTRL) = 1; */ + + /* Clear MSELECT reset. */ + car->rst_dev_v &= 0xFFFFFFF7; + + /* Clear NONCPU reset. */ + car->rst_cpug_cmplx_clr = 0x20000000; + + /* Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.*/ + /* NOTE: [5.0.0+] This was changed so only CPU0 reset is cleared. */ + /* car->rst_cpug_cmplx_clr = 0x411F000F; */ + car->rst_cpug_cmplx_clr = 0x41010001; +} diff --git a/sept/sept-secondary/src/cluster.h b/sept/sept-secondary/src/cluster.h new file mode 100644 index 000000000..2f87fbd90 --- /dev/null +++ b/sept/sept-secondary/src/cluster.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 naehrwert + * Copyright (c) 2018-2019 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_CLUSTER_H_ +#define FUSEE_CLUSTER_H_ + +void cluster_boot_cpu0(uint32_t entry); + +#endif diff --git a/sept/sept-secondary/src/key_derivation.c b/sept/sept-secondary/src/key_derivation.c index ea9c4f714..39f16cf28 100644 --- a/sept/sept-secondary/src/key_derivation.c +++ b/sept/sept-secondary/src/key_derivation.c @@ -17,64 +17,65 @@ #include #include "key_derivation.h" #include "se.h" +#include "cluster.h" +#include "timers.h" #include "fuse.h" #include "utils.h" -#define AL16 ALIGN(16) +#define u8 uint8_t +#define u32 uint32_t +#include "key_derivation_bin.h" +#undef u8 +#undef u32 -static const uint8_t AL16 keyblob_seed_00[0x10] = { - 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 -}; -static const uint8_t AL16 masterkey_seed[0x10] = { - 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C -}; +void derive_keys(void) { + /* Clear mailbox. */ + volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00; + while (*mailbox != 0) { + *mailbox = 0; + } -static const uint8_t AL16 devicekey_seed[0x10] = { - 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 -}; + /* Set derivation id. */ + *((volatile uint32_t *)0x4003E800) = 0x0; -static const uint8_t AL16 devicekey_4x_seed[0x10] = { - 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 -}; + /* Copy key derivation stub into IRAM high. */ + for (size_t i = 0; i < key_derivation_bin_size; i += sizeof(uint32_t)) { + write32le((void *)0x4003D000, i, read32le(key_derivation_bin, i)); + } -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 -}; + cluster_boot_cpu0(0x4003D000); -static const uint8_t AL16 new_master_kek_seed_7x[0x10] = { - 0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C -}; + while (*mailbox != 7) { + /* Wait until keys have been derived. */ + } +} -void derive_7x_keys(const void *tsec_key, void *tsec_root_key) { - uint8_t AL16 work_buffer[0x10]; +void load_keys(const uint8_t *se_state) { + /* Clear keyslot 0xA. */ + for (size_t i = 0; i < 0xA; i++) { + clear_aes_keyslot(0xA); + } + + /* Copy device keygen key out of state keyslot 0xA into keyslot 0xA. */ + set_aes_keyslot(0xA, se_state + 0x30 + (0xA * 0x20), 0x10); + + /* Clear keyslot 0xB. */ + clear_aes_keyslot(0xB); + + /* Copy master key out of state keyslot 0xC into keyslot 0xC. */ + set_aes_keyslot(0xC, se_state + 0x30 + (0xC * 0x20), 0x10); + + /* Copy firmware device key out of state keyslot 0xE into keyslot 0xD. */ + set_aes_keyslot(0xD, se_state + 0x30 + (0xE * 0x20), 0x10); + + /* Clear keyslot 0xE. */ + clear_aes_keyslot(0xE); + + /* Copy device key out of state keyslot 0xF into keyslot 0xF. */ + set_aes_keyslot(0xF, se_state + 0x30 + (0xF * 0x20), 0x10); /* Set keyslot flags properly in preparation of derivation. */ set_aes_keyslot_flags(0xE, 0x15); set_aes_keyslot_flags(0xD, 0x15); - - /* Set the TSEC key. */ - set_aes_keyslot(0xD, tsec_key, 0x10); - - /* Derive keyblob key 0. */ - se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seed_00, 0x10); - decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10); - - /* Clear the SBK. */ - clear_aes_keyslot(0xE); - - /* Derive the master kek. */ - set_aes_keyslot(0xC, tsec_root_key, 0x10); - decrypt_data_into_keyslot(0xC, 0xC, new_master_kek_seed_7x, 0x10); - - /* Derive keys for exosphere. */ - 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); - decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10); - - /* Clear master kek from memory. */ - for (size_t i = 0; i < sizeof(work_buffer); i++) { - work_buffer[i] = 0xCC; - } } diff --git a/sept/sept-secondary/src/key_derivation.h b/sept/sept-secondary/src/key_derivation.h index da77a1490..621d9dce5 100644 --- a/sept/sept-secondary/src/key_derivation.h +++ b/sept/sept-secondary/src/key_derivation.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef SEPT_KEYDERIVATION_H #define SEPT_KEYDERIVATION_H @@ -21,6 +21,7 @@ #include #include -void derive_7x_keys(const void *tsec_key, void *tsec_root_key); +void derive_keys(void); +void load_keys(const uint8_t *se_state); #endif diff --git a/sept/sept-secondary/src/main.c b/sept/sept-secondary/src/main.c index 2195644f3..50c4f7285 100644 --- a/sept/sept-secondary/src/main.c +++ b/sept/sept-secondary/src/main.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include "utils.h" #include "exception_handlers.h" #include "panic.h" @@ -39,9 +39,6 @@ extern void (*__program_exit_callback)(int rc); static void *g_framebuffer; -static uint32_t g_tsec_root_key[0x4] = {0}; -static uint32_t g_tsec_key[0x4] = {0}; - static bool has_rebooted(void) { return MAKE_REG32(0x4003FFFC) == 0xFAFAFAFA; } @@ -55,23 +52,15 @@ static void exfiltrate_keys_and_reboot_if_needed(void) { volatile tegra_pmc_t *pmc = pmc_get_regs(); uint8_t *enc_se_state = (uint8_t *)0x4003E000; uint8_t *dec_se_state = (uint8_t *)0x4003F000; - + if (!has_rebooted()) { /* Prepare for a reboot before doing anything else. */ prepare_for_reboot_to_self(); set_has_rebooted(true); - - /* Save the security engine context. */ - se_get_regs()->_0x4 = 0x0; - se_set_in_context_save_mode(true); - se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, enc_se_state); - se_set_in_context_save_mode(false); - - /* Clear all keyslots. */ - for (size_t k = 0; k < 0x10; k++) { - clear_aes_keyslot(k); - } - + + /* Derive keys. */ + derive_keys(); + reboot_to_self(); } else { /* Decrypt the security engine state. */ @@ -82,13 +71,10 @@ static void exfiltrate_keys_and_reboot_if_needed(void) { context_key[3] = pmc->secure_scratch7; set_aes_keyslot(0xC, context_key, sizeof(context_key)); se_aes_128_cbc_decrypt(0xC, dec_se_state, 0x840, enc_se_state, 0x840); - - /* Copy out tsec key + tsec root key. */ - for (size_t i = 0; i < 0x10; i += 4) { - g_tsec_key[i/4] = MAKE_REG32((uintptr_t)(dec_se_state) + 0x1B0 + i); - g_tsec_root_key[i/4] = MAKE_REG32((uintptr_t)(dec_se_state) + 0x1D0 + i); - } - + + /* Load keys in from decrypted state. */ + load_keys(dec_se_state); + /* Clear the security engine state. */ for (size_t i = 0; i < 0x840; i += 4) { MAKE_REG32((uintptr_t)(enc_se_state) + i) = 0xCCCCCCCC; @@ -101,11 +87,6 @@ static void exfiltrate_keys_and_reboot_if_needed(void) { pmc->secure_scratch5 = 0xCCCCCCCC; pmc->secure_scratch6 = 0xCCCCCCCC; pmc->secure_scratch7 = 0xCCCCCCCC; - - /* Clear all keyslots except for SBK/SSK. */ - for (size_t k = 0; k < 0xE; k++) { - clear_aes_keyslot(k); - } } } @@ -126,7 +107,7 @@ static void setup_env(void) { /* Set the framebuffer. */ display_init_framebuffer(g_framebuffer); - + /* Draw splash. */ draw_splash((volatile uint32_t *)g_framebuffer); @@ -136,7 +117,7 @@ static void setup_env(void) { /* Set up the exception handlers. */ setup_exception_handlers(); - + /* Mount the SD card. */ mount_sd(); } @@ -159,28 +140,19 @@ int main(void) { stage2_args_t *stage2_args; uint32_t stage2_version = 0; ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE; - + /* Extract keys from the security engine, which TSEC FW locked down. */ exfiltrate_keys_and_reboot_if_needed(); - + /* Override the global logging level. */ log_set_log_level(log_level); - + /* Initialize the display, console, etc. */ setup_env(); - - /* Derive keys. */ - derive_7x_keys(g_tsec_key, g_tsec_root_key); - - /* Cleanup keys in memory. */ - for (size_t i = 0; i < 0x10; i += 4) { - g_tsec_root_key[i/4] = 0xCCCCCCCC; - g_tsec_key[i/4] = 0xCCCCCCCC; - } - + /* Mark EMC scratch to say that sept has run. */ MAKE_EMC_REG(EMC_SCRATCH0) |= 0x80000000; - + /* Load the loader payload into DRAM. */ load_stage2(); @@ -194,10 +166,10 @@ int main(void) { stage2_args->display_initialized = false; strcpy(stage2_args->bct0, ""); g_chainloader_argc = 2; - + /* Wait a while. */ mdelay(1500); - + /* Deinitialize the display, console, etc. */ cleanup_env(); diff --git a/sept/sept-secondary/src/utils.c b/sept/sept-secondary/src/utils.c index fa939c0cb..b3c09d290 100644 --- a/sept/sept-secondary/src/utils.c +++ b/sept/sept-secondary/src/utils.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include #include "utils.h" @@ -66,13 +66,16 @@ __attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) { } void prepare_for_reboot_to_self(void) { + /* Write warmboot to scratch0. */ + APBDEV_PMC_SCRATCH0_0 = 0x00000001; + /* Patch SDRAM init to perform an SVC immediately after second write */ APBDEV_PMC_SCRATCH45_0 = 0x2E38DFFF; APBDEV_PMC_SCRATCH46_0 = 0x6001DC28; /* Set SVC handler to jump to reboot stub in IRAM. */ APBDEV_PMC_SCRATCH33_0 = 0x4003F000; APBDEV_PMC_SCRATCH40_0 = 0x6000F208; - + /* Copy reboot stub into IRAM high. */ for (size_t i = 0; i < rebootstub_bin_size; i += sizeof(uint32_t)) { write32le((void *)0x4003F000, i, read32le(rebootstub_bin, i)); @@ -82,7 +85,7 @@ void prepare_for_reboot_to_self(void) { __attribute__((noreturn)) void reboot_to_self(void) { /* Prep IRAM for reboot. */ prepare_for_reboot_to_self(); - + /* Trigger warm reboot. */ pmc_reboot(1 << 0); } From befd912a886d6389191546738dfe4a7a5ebdc015 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 18 Jun 2019 23:23:31 -0700 Subject: [PATCH 02/15] sept: update to support 8.1.0 --- common/include/atmosphere/target_fw.h | 7 +- exosphere/src/exocfg.c | 20 +-- exosphere/src/exocfg.h | 4 +- fusee/fusee-secondary/Makefile | 17 ++- fusee/fusee-secondary/linker.ld | 10 +- fusee/fusee-secondary/src/key_derivation.c | 33 +++-- fusee/fusee-secondary/src/masterkey.c | 8 +- fusee/fusee-secondary/src/masterkey.h | 9 +- fusee/fusee-secondary/src/nxboot.c | 122 +++++++++++------- fusee/fusee-secondary/src/package2.c | 12 +- fusee/fusee-secondary/src/package2.h | 10 +- fusee/fusee-secondary/src/start.s | 22 +++- sept/sept-secondary/KEYS_template.py | 26 +++- sept/sept-secondary/Makefile | 4 +- .../key_derivation/src/key_derivation.c | 8 +- sept/sept-secondary/sept_sign.py | 13 +- sept/sept-secondary/src/key_derivation.c | 4 +- sept/sept-secondary/src/key_derivation.h | 2 +- sept/sept-secondary/src/main.c | 8 +- sept/sept-secondary/src/start.s | 19 ++- 20 files changed, 218 insertions(+), 140 deletions(-) diff --git a/common/include/atmosphere/target_fw.h b/common/include/atmosphere/target_fw.h index 4f944b293..4e368c44f 100644 --- a/common/include/atmosphere/target_fw.h +++ b/common/include/atmosphere/target_fw.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef ATMOSPHERE_TARGET_FIRMWARE_H #define ATMOSPHERE_TARGET_FIRMWARE_H @@ -26,11 +26,12 @@ #define ATMOSPHERE_TARGET_FIRMWARE_620 7 #define ATMOSPHERE_TARGET_FIRMWARE_700 8 #define ATMOSPHERE_TARGET_FIRMWARE_800 9 +#define ATMOSPHERE_TARGET_FIRMWARE_810 10 -#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_800 +#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_810 #define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100 -#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_800 +#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_810 /* TODO: What should this be, for release? */ #define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT diff --git a/exosphere/src/exocfg.c b/exosphere/src/exocfg.c index 7cf9488bd..974766178 100644 --- a/exosphere/src/exocfg.c +++ b/exosphere/src/exocfg.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include @@ -34,13 +34,13 @@ unsigned int exosphere_load_config(void) { generic_panic(); } g_has_loaded_config = true; - + const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG.magic; - + if (magic == MAGIC_EXOSPHERE_CONFIG) { g_exosphere_cfg = MAILBOX_EXOSPHERE_CONFIG; } - + return g_exosphere_cfg.target_firmware; } @@ -48,7 +48,7 @@ unsigned int exosphere_get_target_firmware(void) { if (!g_has_loaded_config) { generic_panic(); } - + return g_exosphere_cfg.target_firmware; } @@ -56,15 +56,15 @@ unsigned int exosphere_should_perform_620_keygen(void) { if (!g_has_loaded_config) { generic_panic(); } - - return g_exosphere_cfg.target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620 && EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_PERFORM_620_KEYGEN); + + return false; } unsigned int exosphere_should_override_debugmode_priv(void) { if (!g_has_loaded_config) { generic_panic(); } - + return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV); } @@ -72,7 +72,7 @@ unsigned int exosphere_should_override_debugmode_user(void) { if (!g_has_loaded_config) { generic_panic(); } - + return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_USER); } @@ -80,7 +80,7 @@ unsigned int exosphere_should_disable_usermode_exception_handlers(void) { if (!g_has_loaded_config) { generic_panic(); } - + return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS); } diff --git a/exosphere/src/exocfg.h b/exosphere/src/exocfg.h index 316aa5646..16f37ec19 100644 --- a/exosphere/src/exocfg.h +++ b/exosphere/src/exocfg.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef EXOSPHERE_EXOSPHERE_CONFIG_H #define EXOSPHERE_EXOSPHERE_CONFIG_H @@ -36,7 +36,7 @@ /* Exosphere config in DRAM shares physical/virtual mapping. */ #define MAILBOX_EXOSPHERE_CONFIG_PHYS MAILBOX_EXOSPHERE_CONFIG -#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u) +#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN_DEPRECATED (1 << 0u) #define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u) #define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u) #define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u) diff --git a/fusee/fusee-secondary/Makefile b/fusee/fusee-secondary/Makefile index 844dc8cf0..64fa59ba3 100644 --- a/fusee/fusee-secondary/Makefile +++ b/fusee/fusee-secondary/Makefile @@ -99,7 +99,7 @@ SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip spl.kip boot.kip BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin \ exosphere.bin lp0fw.bin rebootstub.bin thermosphere.bin splash_screen.bmp \ - sept-primary.bin sept-secondary.enc emummc.kip \ + sept-primary.bin sept-secondary_00.enc sept-secondary_01.enc emummc.kip \ $(KIPFILES) #--------------------------------------------------------------------------------- @@ -198,22 +198,27 @@ fusee_primary.bin.o fusee_primary_bin.h: fusee-primary.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(_bin2o) - + sept_primary.bin.o sept_primary_bin.h: sept-primary.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(_bin2o) - -sept_secondary.enc.o sept_secondary_enc.h: sept-secondary.enc + +sept_secondary_00.enc.o sept_secondary_00.h: sept-secondary_00.enc #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(_bin2o) - + +sept_secondary_01.enc.o sept_secondary_01_enc.h: sept-secondary_01.enc +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(_bin2o) + %.bin.o %_bin.h: %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) - + %.bmp.o %_bmp.h: %.bmp #--------------------------------------------------------------------------------- @echo $(notdir $<) diff --git a/fusee/fusee-secondary/linker.ld b/fusee/fusee-secondary/linker.ld index 26e8cc445..54a44b73d 100644 --- a/fusee/fusee-secondary/linker.ld +++ b/fusee/fusee-secondary/linker.ld @@ -55,7 +55,7 @@ SECTIONS . = ALIGN(32); PROVIDE (__chainloader_end__ = ABSOLUTE(.)); } >low_iram :NONE - + .nxboot_loadable : { . = ALIGN(32); @@ -157,7 +157,7 @@ SECTIONS CONSTRUCTORS . = ALIGN(32); } >main - + __data_end__ = ABSOLUTE(.); PROVIDE (__total_size__ = (__data_end__ - __start__)); @@ -236,8 +236,10 @@ SECTIONS PROVIDE(__rebootstub_bin_size__ = rebootstub_bin_end - rebootstub_bin); PROVIDE(__sept_primary_bin_start__ = sept_primary_bin - __start__); PROVIDE(__sept_primary_bin_size__ = sept_primary_bin_end - sept_primary_bin); - PROVIDE(__sept_secondary_enc_start__ = sept_secondary_enc - __start__); - PROVIDE(__sept_secondary_enc_size__ = sept_secondary_enc_end - sept_secondary_enc); + PROVIDE(__sept_secondary_00_enc_start__ = sept_secondary_00_enc - __start__); + PROVIDE(__sept_secondary_00_enc_size__ = sept_secondary_00_enc_end - sept_secondary_00_enc); + PROVIDE(__sept_secondary_01_enc_start__ = sept_secondary_01_enc - __start__); + PROVIDE(__sept_secondary_01_enc_size__ = sept_secondary_01_enc_end - sept_secondary_01_enc); PROVIDE(__sm_kip_start__ = sm_kip - __start__); PROVIDE(__sm_kip_size__ = sm_kip_end - sm_kip); PROVIDE(__spl_kip_start__ = spl_kip - __start__); diff --git a/fusee/fusee-secondary/src/key_derivation.c b/fusee/fusee-secondary/src/key_derivation.c index 2a13a7c2c..d4de912be 100644 --- a/fusee/fusee-secondary/src/key_derivation.c +++ b/fusee/fusee-secondary/src/key_derivation.c @@ -54,7 +54,8 @@ 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[MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_600_610][0x10] = { +/* TODO: Bother adding 8.1.0 here? We'll never call into here... */ +static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_800 - 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. */ }; @@ -93,17 +94,17 @@ static int decrypt_keyblob(const nx_keyblob_t *keyblobs, uint32_t revision, uint 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, 0xE, work_buffer, 0x10); decrypt_data_into_keyslot(0xB, keyslot, 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(keyslot, &g_dec_keyblobs[revision], sizeof(g_dec_keyblobs[revision]), keyblob.data, sizeof(keyblob.data), keyblob.ctr, sizeof(keyblob.ctr)); return 0; @@ -113,7 +114,7 @@ int load_package1_key(uint32_t revision) { if (revision > MASTERKEY_REVISION_600_610) { return -1; } - + set_aes_keyslot(0xB, g_dec_keyblobs[revision].package1_key, 0x10); return 0; } @@ -122,17 +123,17 @@ int load_package1_key(uint32_t revision) { 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}; - + /* Initialize keygen type. */ *out_keygen_type = 0; /* TODO: Set keyslot flags properly in preparation of derivation. */ set_aes_keyslot_flags(0xE, 0x15); set_aes_keyslot_flags(0xD, 0x15); - + /* Set the TSEC key. */ set_aes_keyslot(0xD, tsec_key, 0x10); - + /* Decrypt all keyblobs, setting keyslot 0xF correctly. */ for (unsigned int rev = 0; rev <= MASTERKEY_REVISION_600_610; rev++) { int ret = decrypt_keyblob(keyblobs, rev, available_revision); @@ -150,13 +151,16 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui break; case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_800: - desired_keyblob = MASTERKEY_REVISION_700_CURRENT; + desired_keyblob = MASTERKEY_REVISION_700_800; + break; + case ATMOSPHERE_TARGET_FIRMWARE_810: + desired_keyblob = MASTERKEY_REVISION_810_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)); @@ -167,7 +171,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui memcpy(g_dec_keyblobs[rev].master_kek, work_buffer, 0x10); } } - + 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"; @@ -188,13 +192,13 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui } } } - - + + 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); @@ -225,6 +229,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui case ATMOSPHERE_TARGET_FIRMWARE_620: case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_800: + case ATMOSPHERE_TARGET_FIRMWARE_810: 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/masterkey.c b/fusee/fusee-secondary/src/masterkey.c index 28b6e3ee4..d2c5a06e7 100644 --- a/fusee/fusee-secondary/src/masterkey.c +++ b/fusee/fusee-secondary/src/masterkey.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include #include @@ -39,6 +39,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] = {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. */ {0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */ }; /* Retail unit keys. */ @@ -52,6 +53,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] = {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. */ {0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */ + {0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */ }; static bool check_mkey_revision(unsigned int revision, bool is_retail) { @@ -80,7 +82,7 @@ int mkey_detect_revision(bool is_retail) { if (g_determined_mkey_revision) { generic_panic(); } - + for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) { if (check_mkey_revision(rev, is_retail)) { g_determined_mkey_revision = true; @@ -88,7 +90,7 @@ int mkey_detect_revision(bool is_retail) { break; } } - + /* We must have determined the master key, or we're not running on a Switch. */ if (!g_determined_mkey_revision) { return -1; diff --git a/fusee/fusee-secondary/src/masterkey.h b/fusee/fusee-secondary/src/masterkey.h index 332dbcec5..0ee44eca4 100644 --- a/fusee/fusee-secondary/src/masterkey.h +++ b/fusee/fusee-secondary/src/masterkey.h @@ -13,14 +13,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef FUSEE_MASTERKEY_H #define FUSEE_MASTERKEY_H /* 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 0x8 +/* TODO: Update to 0xA on release of new master key. */ +#define MASTERKEY_REVISION_MAX 0x9 #define MASTERKEY_REVISION_100_230 0x00 #define MASTERKEY_REVISION_300 0x01 @@ -29,7 +29,8 @@ #define MASTERKEY_REVISION_500_510 0x04 #define MASTERKEY_REVISION_600_610 0x05 #define MASTERKEY_REVISION_620 0x06 -#define MASTERKEY_REVISION_700_CURRENT 0x07 +#define MASTERKEY_REVISION_700_800 0x07 +#define MASTERKEY_REVISION_810_CURRENT 0x08 #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 cc7f1cacd..2146a7062 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include #include @@ -53,7 +53,8 @@ #define u8 uint8_t #define u32 uint32_t #include "exosphere_bin.h" -#include "sept_secondary_enc.h" +#include "sept_secondary_00_enc.h" +#include "sept_secondary_01_enc.h" #include "lp0fw_bin.h" #include "emummc_kip.h" #include "lib/log.h" @@ -207,8 +208,15 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) { } case 0x0F: /* 7.0.0 - 7.0.1 */ return ATMOSPHERE_TARGET_FIRMWARE_700; - case 0x10: /* 8.0.0 */ - return ATMOSPHERE_TARGET_FIRMWARE_800; + case 0x10: { /* 8.0.0 - 8.1.0 */ + if (memcmp(package1loader_header->build_timestamp, "20190314", 8) == 0) { + return ATMOSPHERE_TARGET_FIRMWARE_800; + } else if (memcmp(package1loader_header->build_timestamp, "20190531", 8) == 0) { + return ATMOSPHERE_TARGET_FIRMWARE_810; + } else { + fatal_error("[NXBOOT] Unable to identify package1!\n"); + } + } default: fatal_error("[NXBOOT] Unable to identify package1!\n"); } @@ -216,7 +224,7 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) { static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) { emummc_config_t emummc_cfg = {.enabled = false, .id = 0, .sector = -1, .path = "", .nintendo_path = ""}; - + char *emummc_ini = calloc(1, 0x10000); if (!read_from_file(emummc_ini, 0xFFFF, "emummc/emummc.ini")) { free(emummc_ini); @@ -237,12 +245,12 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) { exo_emummc_config->base_cfg.fs_version = FS_VER_1_0_0; /* Will be filled out later. */ strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path)); exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0'; - + if (emummc_cfg.enabled) { if (emummc_cfg.sector != -1) { exo_emummc_config->base_cfg.type = EMUMMC_TYPE_PARTITION; exo_emummc_config->partition_cfg.start_sector = emummc_cfg.sector; - + /* Mount emulated NAND from SD card partition. */ if (nxfs_mount_emummc_partition(emummc_cfg.sector) < 0) { fatal_error("[NXBOOT] Failed to mount EmuMMC from SD card partition!\n"); @@ -258,24 +266,24 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) { char emummc_boot0_path[0x300 + 1] = {0}; char emummc_boot1_path[0x300 + 1] = {0}; char emummc_rawnand_path[0x300 + 1] = {0}; - + /* Prepare base folder path. */ snprintf(emummc_path, sizeof(emummc_path) - 1, "%s/%s", emummc_cfg.path, "eMMC"); - + /* Check if eMMC folder is present. */ if (!is_valid_folder(emummc_path)) { fatal_error("[NXBOOT] Failed to find EmuMMC eMMC folder!\n"); } - + /* Prepare expected file paths. */ snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0"); snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1"); - + /* Check if boot0 and boot1 image files are present. */ if (!is_valid_file(emummc_boot0_path) || !is_valid_file(emummc_boot1_path)) { fatal_error("[NXBOOT] Failed to find EmuMMC boot0/boot1 image files!\n"); } - + /* Find raw image files (single or multi part). */ for (int i = 0; i < 64; i++) { snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "%s/%02d", emummc_path, i); @@ -295,7 +303,7 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) { if ((num_parts == 0) || (part_limit == 0)) { fatal_error("[NXBOOT] Failed to find EmuMMC raw image files!\n"); } - + /* Mount emulated NAND from files. */ if (nxfs_mount_emummc_file(emummc_path, num_parts, part_limit) < 0) { fatal_error("[NXBOOT] Failed to mount EmuMMC from files!\n"); @@ -304,7 +312,7 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) { fatal_error("[NXBOOT] Invalid EmuMMC setting!\n"); } } - + return emummc_cfg.enabled; } @@ -337,7 +345,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) { if (ini_parse_string(get_loader_ctx()->bct0, stratosphere_ini_handler, &strat_cfg) < 0) { fatal_error("[NXBOOT] Failed to parse BCT.ini!\n"); } - + /* Enable NOGC patches if the user requested it, or if the user is booting into 4.0.0+ with 3.0.2- fuses. */ if (strat_cfg.has_nogc_config) { if (strat_cfg.enable_nogc) { @@ -353,7 +361,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) { static void nxboot_set_bootreason(void *bootreason_base) { boot_reason_t boot_reason = {0}; - FILE *boot0; + FILE *boot0; nvboot_config_table *bct; nv_bootloader_info *bootloader_info; @@ -362,7 +370,7 @@ static void nxboot_set_bootreason(void *bootreason_base) { if (bct == NULL) { fatal_error("[NXBOOT] Out of memory!\n"); } - + /* Open boot0. */ boot0 = fopen("boot0:/", "rb"); if (boot0 == NULL) { @@ -373,25 +381,25 @@ static void nxboot_set_bootreason(void *bootreason_base) { if (fread(bct, sizeof(nvboot_config_table), 1, boot0) == 0) { fatal_error("[NXBOOT] Failed to read the BCT!\n"); } - + /* Close boot0. */ fclose(boot0); - + /* Populate bootloader parameters. */ bootloader_info = &bct->bootloader[0]; boot_reason.bootloader_version = bootloader_info->version; boot_reason.bootloader_start_block = bootloader_info->start_blk; boot_reason.bootloader_start_page = bootloader_info->start_page; boot_reason.bootloader_attribute = bootloader_info->attribute; - + uint8_t power_key_intr = 0; uint8_t rtc_intr = 0; i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_ONOFFIRQ, &power_key_intr, 1); i2c_query(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_REG_RTCINT, &rtc_intr, 1); - + /* Set PMIC value. */ boot_reason.boot_reason_value = ((rtc_intr << 0x08) | power_key_intr); - + /* TODO: Find out what these mean. */ if (power_key_intr & 0x80) boot_reason.boot_reason_state = 0x01; @@ -401,10 +409,10 @@ static void nxboot_set_bootreason(void *bootreason_base) { boot_reason.boot_reason_state = 0x03; else if (rtc_intr & 0x04) boot_reason.boot_reason_state = 0x04; - + /* Set in memory. */ memcpy(bootreason_base, &boot_reason, sizeof(boot_reason)); - + /* Clean up. */ free(bct); } @@ -414,13 +422,13 @@ static void nxboot_move_bootconfig() { void *bootconfig; uint32_t bootconfig_addr; uint32_t bootconfig_size; - + /* Allocate memory for reading BootConfig. */ bootconfig = memalign(0x1000, 0x4000); if (bootconfig == NULL) { fatal_error("[NXBOOT] Out of memory!\n"); } - + /* Get BootConfig from the Package2 partition. */ bcfile = fopen("bcpkg21:/", "rb"); if (bcfile == NULL) { @@ -431,15 +439,15 @@ static void nxboot_move_bootconfig() { fatal_error("[NXBOOT] Failed to read BootConfig!\n"); } fclose(bcfile); - + /* Select the actual BootConfig size and destination address. */ bootconfig_addr = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_600) ? 0x4003D000 : 0x4003F800; bootconfig_size = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) ? 0x3000 : 0x1000; - + /* Copy the BootConfig into IRAM. */ memset((void *)bootconfig_addr, 0, bootconfig_size); memcpy((void *)bootconfig_addr, bootconfig, bootconfig_size); - + /* Clean up. */ free(bootconfig); } @@ -459,6 +467,8 @@ uint32_t nxboot_main(void) { size_t package2_size; void *tsec_fw; size_t tsec_fw_size; + const void *sept_secondary_enc = NULL; + size_t sept_secondary_enc_size = 0; void *warmboot_fw; size_t warmboot_fw_size; void *warmboot_memaddr; @@ -470,7 +480,7 @@ uint32_t nxboot_main(void) { FILE *boot0, *pk2file; void *exosphere_memaddr; exo_emummc_config_t exo_emummc_cfg; - + /* Configure emummc or mount the real NAND. */ if (!nxboot_configure_emummc(&exo_emummc_cfg)) { emummc = NULL; @@ -542,7 +552,7 @@ uint32_t nxboot_main(void) { fatal_error("[NXBOOT] Failed to read Package2!\n"); } fclose(pk2file); - + /* Read and parse boot0. */ print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Reading boot0...\n"); boot0 = fopen("boot0:/", "rb"); @@ -550,7 +560,7 @@ uint32_t nxboot_main(void) { fatal_error("[NXBOOT] Couldn't parse boot0: %s!\n", strerror(errno)); } fclose(boot0); - + /* Find the system's target firmware. */ uint32_t target_firmware = nxboot_get_target_firmware(package1loader); if (!target_firmware) @@ -561,26 +571,42 @@ uint32_t nxboot_main(void) { /* Read the TSEC firmware from a file, otherwise from PK1L. */ if (loader_ctx->tsecfw_path[0] != '\0') { tsec_fw_size = get_file_size(loader_ctx->tsecfw_path); - if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000)) { + if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000 && tsec_fw_size != 0x3300)) { fatal_error("[NXBOOT] TSEC firmware from %s has a wrong size!\n", loader_ctx->tsecfw_path); } else if (tsec_fw_size == 0) { fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path); } - + /* Allocate memory for the TSEC firmware. */ tsec_fw = memalign(0x100, tsec_fw_size); - + if (tsec_fw == NULL) { fatal_error("[NXBOOT] Out of memory!\n"); } if (read_from_file(tsec_fw, tsec_fw_size, loader_ctx->tsecfw_path) != tsec_fw_size) { fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path); } + + if (tsec_fw_size == 0x3000) { + sept_secondary_enc = sept_secondary_00_enc; + sept_secondary_enc_size = sept_secondary_00_enc_size; + } else if (tsec_fw_size == 0x3300) { + sept_secondary_enc = sept_secondary_01_enc; + sept_secondary_enc_size = sept_secondary_01_enc_size; + } else { + fatal_error("[NXBOOT] Unable to identify sept revision to run."); + } } else { if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) { fatal_error("[NXBOOT] Failed to read the TSEC firmware from Package1loader!\n"); } - if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) { + if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_810) { + sept_secondary_enc = sept_secondary_01_enc; + sept_secondary_enc_size = sept_secondary_01_enc_size; + tsec_fw_size = 0x3300; + } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) { + sept_secondary_enc = sept_secondary_00_enc; + sept_secondary_enc_size = sept_secondary_00_enc_size; tsec_fw_size = 0x3000; } else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) { tsec_fw_size = 0x2900; @@ -606,10 +632,10 @@ uint32_t nxboot_main(void) { get_and_clear_has_run_sept(); } else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) { uint8_t tsec_keys[0x20] = {0}; - + /* Emulate the TSEC payload on 6.2.0+. */ smmu_emulate_tsec((void *)tsec_keys, package1loader, package1loader_size, package1loader); - + /* Copy back the keys. */ memcpy((void *)tsec_key, (void *)tsec_keys, 0x10); memcpy((void *)tsec_root_keys, (void *)tsec_keys + 0x10, 0x10); @@ -619,11 +645,11 @@ uint32_t nxboot_main(void) { fatal_error("[NXBOOT] Failed to get TSEC key!\n"); } } - + //fatal_error("Ran sept!"); /* Display splash screen. */ display_splash_screen_bmp(loader_ctx->custom_splash_path, (void *)0xC0000000); - + /* Derive keydata. If on 7.0.0+, sept has already derived keys for us. */ unsigned int keygen_type = 0; if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { @@ -665,27 +691,27 @@ uint32_t nxboot_main(void) { if (warmboot_fw == NULL) { fatal_error("[NXBOOT] Out of memory!\n"); } - + memcpy(warmboot_fw, lp0fw_bin, warmboot_fw_size); - + if (warmboot_fw_size == 0) { fatal_error("[NXBOOT] Could not read the warmboot firmware from Package1!\n"); } } - + /* Patch warmboot firmware for atmosphere. */ if (warmboot_fw != NULL && warmboot_fw_size >= sizeof(warmboot_ams_header_t)) { warmboot_ams_header_t *ams_header = (warmboot_ams_header_t *)warmboot_fw; if (ams_header->ams_metadata.magic == WARMBOOT_MAGIC) { /* Set target firmware */ ams_header->ams_metadata.target_firmware = target_firmware; - + /* Set RSA modulus */ const uint8_t *pkc_modulus = fuse_get_retail_type() != 0 ? retail_pkc_modulus : dev_pkc_modulus; memcpy(ams_header->rsa_modulus, pkc_modulus, sizeof(ams_header->rsa_modulus)); } } - + /* Select the right address for the warmboot firmware. */ if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { @@ -708,7 +734,7 @@ uint32_t nxboot_main(void) { } print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Rebuilding package2...\n"); - + /* Parse stratosphere config. */ nxboot_configure_stratosphere(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware); @@ -770,10 +796,10 @@ uint32_t nxboot_main(void) { free(package2); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Powering on the CCPLEX...\n"); - + /* Unmount everything. */ nxfs_end(); - + /* Return the memory address for booting CPU0. */ return (uint32_t)exosphere_memaddr; } diff --git a/fusee/fusee-secondary/src/package2.c b/fusee/fusee-secondary/src/package2.c index de7af5b70..d9bd92ddc 100644 --- a/fusee/fusee-secondary/src/package2.c +++ b/fusee/fusee-secondary/src/package2.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include #include @@ -66,7 +66,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm if (thermosphere_size != 0 && package2->metadata.section_sizes[PACKAGE2_SECTION_UNUSED] != 0) { fatal_error(u8"Error: Package2 has no unused section for Thermosphère!\n"); } - + /* Load Kernel from SD, if possible. */ { size_t sd_kernel_size = get_file_size("atmosphere/kernel.bin"); @@ -88,13 +88,13 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm /* Perform any patches we want to the NX kernel. */ package2_patch_kernel(kernel, kernel_size, is_sd_kernel, (void *)&orig_ini1); - + /* Ensure we know where embedded INI is if present, and we don't if not. */ - if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) || + if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) || (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 == NULL)) { fatal_error("Error: inappropriate kernel embedded ini context"); } - + print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n"); if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800) { package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1); @@ -232,7 +232,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_700_CURRENT) { + if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_810_CURRENT) { return true; } diff --git a/fusee/fusee-secondary/src/package2.h b/fusee/fusee-secondary/src/package2.h index 1b3d6d492..7427ce85c 100644 --- a/fusee/fusee-secondary/src/package2.h +++ b/fusee/fusee-secondary/src/package2.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef FUSEE_PACKAGE2_H #define FUSEE_PACKAGE2_H @@ -36,7 +36,8 @@ #define PACKAGE2_MAXVER_500_510 0x7 #define PACKAGE2_MAXVER_600_610 0x8 #define PACKAGE2_MAXVER_620 0x9 -#define PACKAGE2_MAXVER_700_CURRENT 0xA +#define PACKAGE2_MAXVER_700_800 0xA +#define PACKAGE2_MAXVER_810_CURRENT 0xB #define PACKAGE2_MINVER_100 0x3 #define PACKAGE2_MINVER_200 0x4 @@ -46,7 +47,8 @@ #define PACKAGE2_MINVER_500_510 0x8 #define PACKAGE2_MINVER_600_610 0x9 #define PACKAGE2_MINVER_620 0xA -#define PACKAGE2_MINVER_700_CURRENT 0xB +#define PACKAGE2_MINVER_700_800 0xB +#define PACKAGE2_MINVER_810_CURRENT 0xC #define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull)) @@ -79,7 +81,7 @@ typedef struct { /* Package2 can be encrypted or unencrypted for these functions: */ static inline size_t package2_meta_get_size(const package2_meta_t *metadata) { - return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3]; + return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3]; } static inline uint8_t package2_meta_get_header_version(const package2_meta_t *metadata) { diff --git a/fusee/fusee-secondary/src/start.s b/fusee/fusee-secondary/src/start.s index f6da2a185..c93b588b1 100644 --- a/fusee/fusee-secondary/src/start.s +++ b/fusee/fusee-secondary/src/start.s @@ -14,7 +14,7 @@ * along with this program. If not, see . */ #include - + .macro CLEAR_GPR_REG_ITER mov r\@, #0 .endm @@ -27,7 +27,7 @@ .type _start, %function _start: b _crt0 - + .word (_metadata - _start) _crt0: @@ -67,7 +67,7 @@ _crt0: ldr r0, [r0] ldr r1, [r1] b main - + /* Fusee-secondary header. */ .align 5 _metadata: @@ -168,12 +168,20 @@ _content_headers: .asciz "sept_primary" .align 5 -/* sept_secondary content header */ -.word __sept_secondary_enc_start__ -.word __sept_secondary_enc_size__ +/* sept_secondary 00 content header */ +.word __sept_secondary_00_enc_start__ +.word __sept_secondary_00_enc_size__ .word CONTENT_TYPE_SP2 .word 0xCCCCCCCC -.asciz "sept_secondary" +.asciz "sept_secondary_00" +.align 5 + +/* sept_secondary 01 content header */ +.word __sept_secondary_01_enc_start__ +.word __sept_secondary_01_enc_size__ +.word CONTENT_TYPE_SP2 +.word 0xCCCCCCCC +.asciz "sept_secondary_01" .align 5 /* sm content header */ diff --git a/sept/sept-secondary/KEYS_template.py b/sept/sept-secondary/KEYS_template.py index 38cdcb0c4..a3ac39639 100644 --- a/sept/sept-secondary/KEYS_template.py +++ b/sept/sept-secondary/KEYS_template.py @@ -1,7 +1,19 @@ -HOVI_ENC_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000') -HOVI_ENC_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000') -HOVI_SIG_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000') -HOVI_SIG_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000') -HOVI_KEK_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000') -HOVI_KEK_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000') -IV = bytearray.fromhex('00000000000000000000000000000000') +NUM_KEYS = 2 + +HOVI_ENC_KEY_PRD = [ + bytearray.fromhex('00000000000000000000000000000000'), + bytearray.fromhex('00000000000000000000000000000000'), +] +HOVI_SIG_KEY_PRD = [ + bytearray.fromhex('00000000000000000000000000000000'), + bytearray.fromhex('00000000000000000000000000000000'), +] + +IV = [ + bytearray.fromhex('00000000000000000000000000000000'), + bytearray.fromhex('00000000000000000000000000000000'), +] + +assert len(HOVI_ENC_KEY_PRD) == NUM_KEYS +assert len(HOVI_SIG_KEY_PRD) == NUM_KEYS +assert len(IV) == NUM_KEYS \ No newline at end of file diff --git a/sept/sept-secondary/Makefile b/sept/sept-secondary/Makefile index 03a8a5f8c..b9721de5f 100644 --- a/sept/sept-secondary/Makefile +++ b/sept/sept-secondary/Makefile @@ -137,12 +137,12 @@ clean: @echo clean ... @$(MAKE) -C $(AMS)/exosphere/rebootstub clean @$(MAKE) -C key_derivation clean - @rm -fr $(BUILD) $(TARGET).bin $(TARGET).enc $(TARGET).elf + @rm -fr $(BUILD) $(TARGET).bin $(TARGET)_*.enc $(TARGET).elf #--------------------------------------------------------------------------------- else -.PHONY: all +.PHONY: all $(OUTPUT).bin DEPENDS := $(OFILES:.o=.d) diff --git a/sept/sept-secondary/key_derivation/src/key_derivation.c b/sept/sept-secondary/key_derivation/src/key_derivation.c index 65eb9290b..a94885f71 100644 --- a/sept/sept-secondary/key_derivation/src/key_derivation.c +++ b/sept/sept-secondary/key_derivation/src/key_derivation.c @@ -20,7 +20,7 @@ #define AL16 __attribute__((aligned(16))) -#define DERIVATION_ID_MAX 1 +#define DERIVATION_ID_MAX 2 static const uint8_t AL16 keyblob_seed_00[0x10] = { 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 @@ -44,10 +44,12 @@ static const uint8_t AL16 masterkey_4x_seed[0x10] = { static const uint8_t AL16 master_kek_seeds[DERIVATION_ID_MAX][0x10] = { {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, + {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, }; static const uint8_t AL16 master_devkey_seeds[DERIVATION_ID_MAX][0x10] = { {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, + {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, }; void derive_keys(void) { @@ -101,7 +103,7 @@ void derive_keys(void) { } /* Derive master kek. */ - decrypt_data_into_keyslot(0xE, 0xE, master_kek_seeds[0], 0x10); + decrypt_data_into_keyslot(0xE, 0xE, master_kek_seeds[derivation_id], 0x10); /* Derive master key, device master key. */ decrypt_data_into_keyslot(0xC, 0xE, masterkey_seed, 0x10); @@ -123,7 +125,7 @@ void derive_keys(void) { decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10); /* Derive firmware specific device key. */ - se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[0], 0x10); + se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[derivation_id], 0x10); decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10); /* Clear work buffer. */ diff --git a/sept/sept-secondary/sept_sign.py b/sept/sept-secondary/sept_sign.py index ba108c1fc..a5ca66a36 100644 --- a/sept/sept-secondary/sept_sign.py +++ b/sept/sept-secondary/sept_sign.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -import sys +import sys, os from struct import pack as pk, unpack as up from Crypto.Cipher import AES from Crypto.Hash import CMAC @@ -41,7 +41,7 @@ def get_last_block_for_desired_mac(key, data, desired_mac): return last_block -def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac): +def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac, version): # Pad with 0x20 of zeroes. code = code + bytearray(0x20) code_len = len(code) @@ -49,6 +49,9 @@ def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac): code_len &= ~0xFFF code = code + bytearray(code_len - len(code)) + # Insert version + code = code[:8] + pk(' #include -void derive_keys(void); +void derive_keys(uint32_t version); void load_keys(const uint8_t *se_state); #endif diff --git a/sept/sept-secondary/src/main.c b/sept/sept-secondary/src/main.c index 50c4f7285..b1cb458a4 100644 --- a/sept/sept-secondary/src/main.c +++ b/sept/sept-secondary/src/main.c @@ -48,7 +48,7 @@ static void set_has_rebooted(bool rebooted) { } -static void exfiltrate_keys_and_reboot_if_needed(void) { +static void exfiltrate_keys_and_reboot_if_needed(uint32_t version) { volatile tegra_pmc_t *pmc = pmc_get_regs(); uint8_t *enc_se_state = (uint8_t *)0x4003E000; uint8_t *dec_se_state = (uint8_t *)0x4003F000; @@ -59,7 +59,7 @@ static void exfiltrate_keys_and_reboot_if_needed(void) { set_has_rebooted(true); /* Derive keys. */ - derive_keys(); + derive_keys(version); reboot_to_self(); } else { @@ -135,14 +135,14 @@ static void exit_callback(int rc) { relocate_and_chainload(); } -int main(void) { +int sept_main(uint32_t version) { const char *stage2_path; stage2_args_t *stage2_args; uint32_t stage2_version = 0; ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE; /* Extract keys from the security engine, which TSEC FW locked down. */ - exfiltrate_keys_and_reboot_if_needed(); + exfiltrate_keys_and_reboot_if_needed(version); /* Override the global logging level. */ log_set_log_level(log_level); diff --git a/sept/sept-secondary/src/start.s b/sept/sept-secondary/src/start.s index b79cfce26..73cdf5b10 100644 --- a/sept/sept-secondary/src/start.s +++ b/sept/sept-secondary/src/start.s @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + .macro CLEAR_GPR_REG_ITER mov r\@, #0 .endm @@ -26,13 +26,18 @@ _start: /* Switch to system mode, mask all interrupts, clear all flags */ msr cpsr_cxsf, #0xDF + b begin_relocation_loop + _version: + .word 0x00000000 /* Version. */ + .word 0x00000000 /* Reserved. */ + begin_relocation_loop: /* Relocate ourselves if necessary */ ldr r2, =__start__ adr r3, _start cmp r2, r3 beq _relocation_loop_end - + /* If we are relocating, we are not rebooting to ourselves. Note that. */ ldr r0, =0x4003FFFC mov r1, #0x0 @@ -50,12 +55,12 @@ _start: ldr r12, =_second_relocation_start bx r12 - + _second_relocation_start: ldr r4, =__bss_start__ sub r4, r4, r2 mov r1, #0x0 - + _second_relocation_loop: ldmia r3!, {r5-r12} stmia r2!, {r5-r12} @@ -67,7 +72,7 @@ _start: bx r12 _relocation_loop_end: - + /* Set the stack pointer */ ldr sp, =__stack_top__ mov fp, #0 @@ -78,7 +83,9 @@ _start: CLEAR_GPR_REG_ITER .endr ldr lr, =__program_exit - b main + ldr r0, =_version + ldr r0, [r0] + b sept_main /* No need to include this in normal programs: */ .section .chainloader.text.start, "ax", %progbits From 493b074a9e7edc7b6a477016e3de71b58f024ea1 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 18 Jun 2019 23:54:53 -0700 Subject: [PATCH 03/15] exo: support for 8.1.0 --- Makefile | 3 +- ...F5D3090215C46F37BD079442977A85B8243BA5.ips | Bin 0 -> 27 bytes ...F609C363834471BF18CA375CB6A1DEB77755EA.ips | Bin 0 -> 27 bytes exosphere/src/masterkey.c | 3 +- exosphere/src/masterkey.h | 9 ++- exosphere/src/mc.c | 14 ++-- exosphere/src/package2.c | 13 +++- exosphere/src/package2.h | 8 +- exosphere/src/smc_api.c | 25 ++++--- exosphere/src/smc_user.c | 15 ++-- fusee/fusee-secondary/src/emummc_cfg.h | 5 +- fusee/fusee-secondary/src/ips.c | 69 +++++++++--------- sept/sept-secondary/KEYS_template.py | 1 + .../key_derivation/src/key_derivation.c | 2 +- stratosphere/libstratosphere | 2 +- 15 files changed, 96 insertions(+), 73 deletions(-) create mode 100644 common/defaults/kip_patches/default_nogc/6B09B67B29C020246DC34F5A04F5D3090215C46F37BD079442977A85B8243BA5.ips create mode 100644 common/defaults/kip_patches/default_nogc/B4CAE1F24965D92ED24EBE9E97F609C363834471BF18CA375CB6A1DEB77755EA.ips diff --git a/Makefile b/Makefile index a380a5d94..113f24aec 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,8 @@ dist: all cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin cp sept/sept-secondary/sept-secondary.bin atmosphere-$(AMSVER)/sept/sept-secondary.bin - cp sept/sept-secondary/sept-secondary.enc atmosphere-$(AMSVER)/sept/sept-secondary.enc + cp sept/sept-secondary/sept-secondary_00.enc atmosphere-$(AMSVER)/sept/sept-secondary_00.enc + cp sept/sept-secondary/sept-secondary_01.enc atmosphere-$(AMSVER)/sept/sept-secondary_01.enc cp common/defaults/BCT.ini atmosphere-$(AMSVER)/atmosphere/BCT.ini cp common/defaults/loader.ini atmosphere-$(AMSVER)/atmosphere/loader.ini cp common/defaults/system_settings.ini atmosphere-$(AMSVER)/atmosphere/system_settings.ini diff --git a/common/defaults/kip_patches/default_nogc/6B09B67B29C020246DC34F5A04F5D3090215C46F37BD079442977A85B8243BA5.ips b/common/defaults/kip_patches/default_nogc/6B09B67B29C020246DC34F5A04F5D3090215C46F37BD079442977A85B8243BA5.ips new file mode 100644 index 0000000000000000000000000000000000000000..05869a6e9febb7fd1dc549376cc45e6725373eb1 GIT binary patch literal 27 icmWG=3~}}leKVDTu|YVKfq~-zv%J;;=J;!_{%!zmjR*<= literal 0 HcmV?d00001 diff --git a/common/defaults/kip_patches/default_nogc/B4CAE1F24965D92ED24EBE9E97F609C363834471BF18CA375CB6A1DEB77755EA.ips b/common/defaults/kip_patches/default_nogc/B4CAE1F24965D92ED24EBE9E97F609C363834471BF18CA375CB6A1DEB77755EA.ips new file mode 100644 index 0000000000000000000000000000000000000000..6e66bc3bba73e7a2a407301f094e15b9ca146d31 GIT binary patch literal 27 icmWG=3~}}lTja{X*dQXefq~-zv%J;;=J;!_{%!zfoCntc literal 0 HcmV?d00001 diff --git a/exosphere/src/masterkey.c b/exosphere/src/masterkey.c index d1ef71c71..d4fbea5f6 100644 --- a/exosphere/src/masterkey.c +++ b/exosphere/src/masterkey.c @@ -42,6 +42,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] = {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. */ {0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */ }; /* Retail unit keys. */ @@ -55,6 +56,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] = {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. */ {0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */ + {0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */ }; bool check_mkey_revision(unsigned int revision, bool is_retail) { @@ -125,7 +127,6 @@ unsigned int mkey_get_keyslot(unsigned int revision) { } } - void set_old_devkey(unsigned int revision, const uint8_t *key) { if (revision < MASTERKEY_REVISION_400_410 || MASTERKEY_REVISION_MAX <= revision) { generic_panic(); diff --git a/exosphere/src/masterkey.h b/exosphere/src/masterkey.h index dab9bfbb2..90b6ec236 100644 --- a/exosphere/src/masterkey.h +++ b/exosphere/src/masterkey.h @@ -13,14 +13,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef EXOSPHERE_MASTERKEY_H #define EXOSPHERE_MASTERKEY_H /* This is glue code to enable master key support across versions. */ -/* TODO: Update to 0x9 on release of new master key. */ -#define MASTERKEY_REVISION_MAX 0x8 +/* TODO: Update to 0xA on release of new master key. */ +#define MASTERKEY_REVISION_MAX 0x9 #define MASTERKEY_REVISION_100_230 0x00 #define MASTERKEY_REVISION_300 0x01 @@ -29,7 +29,8 @@ #define MASTERKEY_REVISION_500_510 0x04 #define MASTERKEY_REVISION_600_610 0x05 #define MASTERKEY_REVISION_620 0x06 -#define MASTERKEY_REVISION_700_CURRENT 0x07 +#define MASTERKEY_REVISION_700_800 0x07 +#define MASTERKEY_REVISION_810_CURRENT 0x08 #define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410) diff --git a/exosphere/src/mc.c b/exosphere/src/mc.c index ccb6b8647..6a6ac75dc 100644 --- a/exosphere/src/mc.c +++ b/exosphere/src/mc.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include "memory_map.h" @@ -28,7 +28,7 @@ typedef struct { static saved_carveout_info_t g_saved_carveouts[2] = { {0x80060000ull, KERNEL_CARVEOUT_SIZE_MAX}, {0x00000000ull, 0x00000000ull} -}; +}; volatile security_carveout_t *get_carveout_by_id(unsigned int carveout) { if (CARVEOUT_ID_MIN <= carveout && carveout <= CARVEOUT_ID_MAX) { @@ -130,7 +130,7 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6 if (carveout_id != 4 && carveout_id != 5) { generic_panic(); } - + g_saved_carveouts[carveout_id-4].address = address; g_saved_carveouts[carveout_id-4].size = size; @@ -140,8 +140,12 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6 carveout->size_big_pages = (uint32_t)(size >> 17); carveout->client_access_0 = (BIT(CSR_PTCR) | BIT(CSR_DISPLAY0A) | BIT(CSR_DISPLAY0AB) | BIT(CSR_DISPLAY0B) | BIT(CSR_DISPLAY0BB) | BIT(CSR_DISPLAY0C) | BIT(CSR_DISPLAY0CB) | BIT(CSR_AFIR) | BIT(CSR_DISPLAYHC) | BIT(CSR_DISPLAYHCB) | BIT(CSR_HDAR) | BIT(CSR_HOST1XDMAR) | BIT(CSR_HOST1XR) | BIT(CSR_NVENCSRD) | BIT(CSR_PPCSAHBDMAR) | BIT(CSR_PPCSAHBSLVR)); carveout->client_access_1 = (BIT(CSR_MPCORER) | BIT(CSW_NVENCSWR) | BIT(CSW_AFIW) | BIT(CSW_HDAW) | BIT(CSW_HOST1XW) | BIT(CSW_MPCOREW) | BIT(CSW_PPCSAHBDMAW) | BIT(CSW_PPCSAHBSLVW)); - if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) { - carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW)); + if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_810) { + carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW)); + carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR)); + carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR)); + } else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) { + carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW)); carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR)); carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR) | BIT(CSR_TSECSRDB) | BIT(CSW_TSECSWRB)); } else { diff --git a/exosphere/src/package2.c b/exosphere/src/package2.c index 4ee7f23bf..76d3a8504 100644 --- a/exosphere/src/package2.c +++ b/exosphere/src/package2.c @@ -43,7 +43,7 @@ static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */ {0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */ {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */ - //{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ }; static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { @@ -52,7 +52,7 @@ static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */ {0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */ {0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */ - //{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ }; static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { @@ -61,7 +61,7 @@ static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS {0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.x New Device Keygen Source. */ {0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 New Device Keygen Source. */ {0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */ - //{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */ }; static void derive_new_device_keys(unsigned int keygen_keyslot) { @@ -140,6 +140,7 @@ static void setup_se(void) { case ATMOSPHERE_TARGET_FIRMWARE_620: case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_800: + case ATMOSPHERE_TARGET_FIRMWARE_810: derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY); break; } @@ -329,7 +330,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_700_CURRENT) { + if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_810_CURRENT) { return true; } @@ -454,6 +455,7 @@ static void copy_warmboot_bin_to_dram() { break; case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_800: + case ATMOSPHERE_TARGET_FIRMWARE_810: warmboot_src = (uint8_t *)0x4003E000; break; } @@ -527,6 +529,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { case ATMOSPHERE_TARGET_FIRMWARE_800: MAKE_REG32(PMC_BASE + 0x360) = 0x129; break; + case ATMOSPHERE_TARGET_FIRMWARE_810: + MAKE_REG32(PMC_BASE + 0x360) = 0x14A; + break; } } diff --git a/exosphere/src/package2.h b/exosphere/src/package2.h index 513e75d5a..900047f87 100644 --- a/exosphere/src/package2.h +++ b/exosphere/src/package2.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef EXOSPHERE_PACKAGE2_H #define EXOSPHERE_PACKAGE2_H @@ -70,7 +70,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) { #define PACKAGE2_MAXVER_500_510 0x7 #define PACKAGE2_MAXVER_600_610 0x8 #define PACKAGE2_MAXVER_620 0x9 -#define PACKAGE2_MAXVER_700_CURRENT 0xA +#define PACKAGE2_MAXVER_700_800 0xA +#define PACKAGE2_MAXVER_810_CURRENT 0xB #define PACKAGE2_MINVER_100 0x3 #define PACKAGE2_MINVER_200 0x4 @@ -80,7 +81,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) { #define PACKAGE2_MINVER_500_510 0x8 #define PACKAGE2_MINVER_600_610 0x9 #define PACKAGE2_MINVER_620 0xA -#define PACKAGE2_MINVER_700_CURRENT 0xB +#define PACKAGE2_MINVER_700_800 0xB +#define PACKAGE2_MINVER_810_CURRENT 0xC typedef struct { union { diff --git a/exosphere/src/smc_api.c b/exosphere/src/smc_api.c index 5a5d6cadc..495682b3e 100644 --- a/exosphere/src/smc_api.c +++ b/exosphere/src/smc_api.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include @@ -185,6 +185,7 @@ void set_version_specific_smcs(void) { case ATMOSPHERE_TARGET_FIRMWARE_620: case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_800: + case ATMOSPHERE_TARGET_FIRMWARE_810: /* No more LoadSecureExpModKey. */ g_smc_user_table[0xE].handler = NULL; g_smc_user_table[0xC].id = 0xC300D60C; @@ -256,7 +257,7 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) { unsigned char smc_id, call_range; unsigned int result; unsigned int (*smc_handler)(smc_args_t *args); - + /* Validate top-level handler. */ if (handler_id >= SMC_HANDLER_COUNT) { generic_panic(); @@ -288,17 +289,17 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) { if ((smc_handler = g_smc_tables[handler_id].handlers[smc_id].handler) == NULL) { generic_panic(); } - + bool is_aes_kek = handler_id == SMC_HANDLER_USER && args->X[0] == 0xC3000007; -#if DEBUG_LOG_SMCS - uint64_t num; +#if DEBUG_LOG_SMCS + uint64_t num; if (handler_id == SMC_HANDLER_USER) { num = atomic_fetch_add(&num_smcs_called, 1); *(volatile smc_args_t *)(get_iram_address_for_debug() + 0x100 + ((0x80 * num) & 0x3FFF)) = *args; } #endif - + /* Call function. */ if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_800 || (g_smc_tables[handler_id].handlers[smc_id].blacklist_mask & g_smc_blacklist_mask) == 0) { @@ -307,15 +308,15 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) { /* Call not allowed due to current boot conditions. */ args->X[0] = 6; } - -#if DEBUG_LOG_SMCS + +#if DEBUG_LOG_SMCS if (handler_id == SMC_HANDLER_USER) { *(volatile smc_args_t *)(get_iram_address_for_debug() + 0x100 + ((0x80 * num + 0x40) & 0x3FFF)) = *args; } #endif - + #if DEBUG_PANIC_ON_FAILURE - if (args->X[0] && (!is_aes_kek || args->X[3] <= ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG)) + if (args->X[0] && (!is_aes_kek || args->X[3] <= ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG)) { MAKE_REG32(get_iram_address_for_debug() + 0x4FF0) = handler_id; MAKE_REG32(get_iram_address_for_debug() + 0x4FF4) = smc_id; @@ -695,14 +696,14 @@ uint32_t smc_configure_carveout(smc_args_t *args) { if (size > KERNEL_CARVEOUT_SIZE_MAX) { return 2; } - + /* Ensure validity of carveout index. */ if (carveout_id > 1) { return 2; } /* Configuration is one-shot, and cannot be done multiple times. */ - if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_300) { + if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_300) { if (g_configured_carveouts[carveout_id]) { return 2; } diff --git a/exosphere/src/smc_user.c b/exosphere/src/smc_user.c index c8d9c12d4..cf47e9fd4 100644 --- a/exosphere/src/smc_user.c +++ b/exosphere/src/smc_user.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include #include @@ -52,6 +52,7 @@ static bool is_user_keyslot_valid(unsigned int keyslot) { case ATMOSPHERE_TARGET_FIRMWARE_620: case ATMOSPHERE_TARGET_FIRMWARE_700: case ATMOSPHERE_TARGET_FIRMWARE_800: + case ATMOSPHERE_TARGET_FIRMWARE_810: default: return keyslot <= 5; } @@ -165,7 +166,7 @@ uint32_t user_generate_aes_kek(smc_args_t *args) { bool is_personalized = (int)(packed_options & 1); bool is_recovery_boot = configitem_is_recovery_boot(); - + /* 5.0.0+ Bounds checking. */ if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) { if (is_personalized) { @@ -295,7 +296,7 @@ uint32_t crypt_aes_done_handler(void) { uint32_t user_crypt_aes(smc_args_t *args) { uint32_t keyslot = args->X[1] & 3; uint32_t mode = (args->X[1] >> 4) & 3; - + if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_600) { keyslot = args->X[1] & 7; } @@ -791,7 +792,7 @@ uint32_t user_encrypt_rsa_key_for_import(smc_args_t *args) { if (usecase > CRYPTOUSECASE_RSAIMPORT) { return 2; - } + } if (usecase == 0) { if (size < 0x31 || size > 0x240) { return 2; @@ -823,7 +824,7 @@ uint32_t user_encrypt_rsa_key_for_import(smc_args_t *args) { if (secure_copy_to_user(&page_ref, user_address, user_data, size) == 0) { return 2; - } + } return 0; } @@ -854,7 +855,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) { if (usecase > CRYPTOUSECASE_RSAIMPORT) { return 2; - } + } if (usecase == 0) { if (size < 0x31 || size > 0x240) { return 2; @@ -881,7 +882,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) { case 0: if (secure_copy_to_user(&page_ref, user_address, user_data, size) == 0) { return 2; - } + } return 0; case 1: exponent_id = 1; diff --git a/fusee/fusee-secondary/src/emummc_cfg.h b/fusee/fusee-secondary/src/emummc_cfg.h index 91d5bb515..77ab9fb8e 100644 --- a/fusee/fusee-secondary/src/emummc_cfg.h +++ b/fusee/fusee-secondary/src/emummc_cfg.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef EXOSPHERE_EMUMMC_CONFIG_H #define EXOSPHERE_EMUMMC_CONFIG_H @@ -73,6 +73,9 @@ typedef enum { FS_VER_8_0_0, FS_VER_8_0_0_EXFAT, + FS_VER_8_1_0, + FS_VER_8_1_0_EXFAT, + FS_VER_MAX, } emummc_fs_ver_t; diff --git a/fusee/fusee-secondary/src/ips.c b/fusee/fusee-secondary/src/ips.c index d94b31e5e..dedd00c67 100644 --- a/fusee/fusee-secondary/src/ips.c +++ b/fusee/fusee-secondary/src/ips.c @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include #include #include @@ -46,7 +46,7 @@ static bool should_ignore_default_patch(const char *patch_dir) { if (!g_enable_nogc_patches && strcmp(patch_dir, NOGC_PATCH_DIR) == 0) { return true; } - + return false; } @@ -64,7 +64,7 @@ static bool has_patch(const char *dir, const char *subdir, const void *hash, siz if (cur_len >= sizeof(path)) { return false; } - + FILE *f = fopen(path, "rb"); if (f != NULL) { fclose(f); @@ -77,7 +77,7 @@ static bool has_needed_default_kip_patches(uint64_t title_id, const void *hash, if (title_id == 0x0100000000000000ULL && g_enable_nogc_patches) { return has_patch("atmosphere/kip_patches", NOGC_PATCH_DIR, hash, hash_size); } - + return true; } @@ -90,7 +90,7 @@ static void apply_ips_patch(uint8_t *mem, size_t mem_size, size_t prot_size, boo } else if (!is_ips32 && memcmp(buffer, IPS_TAIL, 3) == 0) { break; } - + /* Offset of patch. */ uint32_t patch_offset; if (is_ips32) { @@ -98,27 +98,27 @@ static void apply_ips_patch(uint8_t *mem, size_t mem_size, size_t prot_size, boo } else { patch_offset = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]); } - + /* Size of patch. */ if (fread(buffer, 2, 1, f_ips) != 1) { break; } uint32_t patch_size = (buffer[0] << 8) | (buffer[1]); - + /* Check for RLE encoding. */ if (patch_size == 0) { /* Size of RLE. */ if (fread(buffer, 2, 1, f_ips) != 1) { break; } - + uint32_t rle_size = (buffer[0] << 8) | (buffer[1]); - + /* Value for RLE. */ if (fread(buffer, 1, 1, f_ips) != 1) { break; } - + if (patch_offset < prot_size) { if (patch_offset + rle_size > prot_size) { uint32_t diff = prot_size - patch_offset; @@ -187,7 +187,7 @@ static bool name_matches_hash(const char *name, size_t name_len, const void *has hash_from_name[id_ofs] |= hex_nybble_to_u8(name[name_ofs++]) << 4; hash_from_name[id_ofs] |= hex_nybble_to_u8(name[name_ofs++]); } - + return memcmp(hash, hash_from_name, hash_size) == 0; } @@ -204,11 +204,11 @@ static bool has_ips_patches(const char *dir, const void *hash, size_t hash_size) if (strcmp(pdir_ent->d_name, ".") == 0 || strcmp(pdir_ent->d_name, "..") == 0) { continue; } - + if (should_ignore_default_patch(pdir_ent->d_name)) { continue; } - + snprintf(path, sizeof(path) - 1, "%s/%s", dir, pdir_ent->d_name); DIR *patch_dir = opendir(path); struct dirent *ent; @@ -218,7 +218,7 @@ static bool has_ips_patches(const char *dir, const void *hash, size_t hash_size) if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { continue; } - + size_t name_len = strlen(ent->d_name); if ((4 < name_len && name_len <= 0x44) && ((name_len & 1) == 0) && strcmp(ent->d_name + name_len - 4, ".ips") == 0 && name_matches_hash(ent->d_name, name_len, hash, hash_size)) { snprintf(path, sizeof(path) - 1, "%s/%s/%s", dir, pdir_ent->d_name, ent->d_name); @@ -254,11 +254,11 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_ if (strcmp(pdir_ent->d_name, ".") == 0 || strcmp(pdir_ent->d_name, "..") == 0) { continue; } - + if (should_ignore_default_patch(pdir_ent->d_name)) { continue; } - + snprintf(path, sizeof(path) - 1, "%s/%s", dir, pdir_ent->d_name); DIR *patch_dir = opendir(path); struct dirent *ent; @@ -268,7 +268,7 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_ if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { continue; } - + size_t name_len = strlen(ent->d_name); if ((4 < name_len && name_len <= 0x44) && ((name_len & 1) == 0) && strcmp(ent->d_name + name_len - 4, ".ips") == 0 && name_matches_hash(ent->d_name, name_len, hash, hash_size)) { snprintf(path, sizeof(path) - 1, "%s/%s/%s", dir, pdir_ent->d_name, ent->d_name); @@ -291,7 +291,7 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_ } closedir(patches_dir); } -} +} void apply_kernel_ips_patches(void *kernel, size_t kernel_size) { uint8_t hash[0x20]; @@ -304,16 +304,16 @@ static void kip1_blz_uncompress(void *hdr_end) { uint32_t addl_size = ((u8_hdr_end[-4]) << 0) | ((u8_hdr_end[-3]) << 8) | ((u8_hdr_end[-2]) << 16) | ((u8_hdr_end[-1]) << 24); uint32_t header_size = ((u8_hdr_end[-8]) << 0) | ((u8_hdr_end[-7]) << 8) | ((u8_hdr_end[-6]) << 16) | ((u8_hdr_end[-5]) << 24); uint32_t cmp_and_hdr_size = ((u8_hdr_end[-12]) << 0) | ((u8_hdr_end[-11]) << 8) | ((u8_hdr_end[-10]) << 16) | ((u8_hdr_end[-9]) << 24); - + unsigned char *cmp_start = (unsigned char *)(((uintptr_t)hdr_end) - cmp_and_hdr_size); uint32_t cmp_ofs = cmp_and_hdr_size - header_size; uint32_t out_ofs = cmp_and_hdr_size + addl_size; - + while (out_ofs) { unsigned char control = cmp_start[--cmp_ofs]; for (unsigned int i = 0; i < 8; i++) { if (control & 0x80) { - if (cmp_ofs < 2) { + if (cmp_ofs < 2) { fatal_error("KIP1 decompression out of bounds!\n"); } cmp_ofs -= 2; @@ -325,7 +325,7 @@ static void kip1_blz_uncompress(void *hdr_end) { seg_size = out_ofs; } out_ofs -= seg_size; - + for (unsigned int j = 0; j < seg_size; j++) { cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs]; } @@ -350,15 +350,15 @@ kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) { new_header.section_headers[i].compressed_size = new_header.section_headers[i].out_size; } new_header.flags &= 0xF8; - + *size = kip1_get_size_from_header(&new_header); - + unsigned char *new_kip = calloc(1, *size); if (new_kip == NULL) { return NULL; } *((kip1_header_t *)new_kip) = new_header; - + size_t new_offset = 0x100; size_t old_offset = 0x100; for (unsigned int i = 0; i < 3; i++) { @@ -369,7 +369,7 @@ kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) { new_offset += kip->section_headers[i].out_size; old_offset += kip->section_headers[i].compressed_size; } - + return (kip1_header_t *)new_kip; } @@ -408,12 +408,15 @@ static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = { "\xB2\xF5\x17\x6B\x35\x48\x36\x4D", /* FS_VER_8_0_0 */ "\xDB\xD9\x41\xC0\xC5\x3C\x52\xCC", /* FS_VER_8_0_0_EXFAT */ + + "\x6B\x09\xB6\x7B\x29\xC0\x20\x24", /* FS_VER_8_1_0 */ + "\xB4\xCA\xE1\xF2\x49\x65\xD9\x2E", /* FS_VER_8_1_0_EXFAT */ }; kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) { uint8_t hash[0x20]; se_calculate_sha256(hash, kip, kip_size); - + if (kip->title_id == FS_TITLE_ID) { bool found = false; for (size_t i = 0; i < FS_VER_MAX; i++) { @@ -426,24 +429,24 @@ kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc fatal_error("[NXBOOT]: Failed to identify FS version..."); } } - + if (!has_needed_default_kip_patches(kip->title_id, hash, sizeof(hash))) { fatal_error("[NXBOOT]: Missing default patch for KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id); } - + if (!has_ips_patches("atmosphere/kip_patches", hash, sizeof(hash))) { return NULL; } print(SCREEN_LOG_LEVEL_MANDATORY, "[NXBOOT]: Patching KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id); - - + + size_t uncompressed_kip_size; kip1_header_t *uncompressed_kip = kip1_uncompress(kip, &uncompressed_kip_size); - if (uncompressed_kip == NULL) { + if (uncompressed_kip == NULL) { return NULL; } - + apply_ips_patches("atmosphere/kip_patches", uncompressed_kip, uncompressed_kip_size, 0x100, hash, sizeof(hash)); return uncompressed_kip; } diff --git a/sept/sept-secondary/KEYS_template.py b/sept/sept-secondary/KEYS_template.py index a3ac39639..dd3bb7b91 100644 --- a/sept/sept-secondary/KEYS_template.py +++ b/sept/sept-secondary/KEYS_template.py @@ -4,6 +4,7 @@ HOVI_ENC_KEY_PRD = [ bytearray.fromhex('00000000000000000000000000000000'), bytearray.fromhex('00000000000000000000000000000000'), ] + HOVI_SIG_KEY_PRD = [ bytearray.fromhex('00000000000000000000000000000000'), bytearray.fromhex('00000000000000000000000000000000'), diff --git a/sept/sept-secondary/key_derivation/src/key_derivation.c b/sept/sept-secondary/key_derivation/src/key_derivation.c index a94885f71..22be12e03 100644 --- a/sept/sept-secondary/key_derivation/src/key_derivation.c +++ b/sept/sept-secondary/key_derivation/src/key_derivation.c @@ -96,7 +96,7 @@ void derive_keys(void) { clear_aes_keyslot(0xE); clear_aes_keyslot(0xF); - /* Mov root key into keyslot 0xE. Clear first to wipe from IV. */ + /* Mov root key into keyslot 0xE. */ set_aes_keyslot(0xE, partial_se_state + 0x30, 0x10); for (size_t i = 0; i < 4; i++) { *((volatile uint32_t *)(partial_se_state + 0x30)) = 0xCCCCCCCC; diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index 777984476..281534d9f 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit 777984476ea7b1da56c9a3fd3f55575a8b899896 +Subproject commit 281534d9f805af7dccbdd4e0e8883d4d055581ff From 11d802143532ecea54f54955264a9ea82f188307 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 18 Jun 2019 23:58:59 -0700 Subject: [PATCH 04/15] sept: minor fix --- sept/sept-secondary/src/key_derivation.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sept/sept-secondary/src/key_derivation.c b/sept/sept-secondary/src/key_derivation.c index e81e52f38..3b87c5a98 100644 --- a/sept/sept-secondary/src/key_derivation.c +++ b/sept/sept-secondary/src/key_derivation.c @@ -52,9 +52,9 @@ void derive_keys(uint32_t version) { } void load_keys(const uint8_t *se_state) { - /* Clear keyslot 0xA. */ + /* Clear keyslots up to 0xA. */ for (size_t i = 0; i < 0xA; i++) { - clear_aes_keyslot(0xA); + clear_aes_keyslot(i); } /* Copy device keygen key out of state keyslot 0xA into keyslot 0xA. */ @@ -75,7 +75,7 @@ void load_keys(const uint8_t *se_state) { /* Copy device key out of state keyslot 0xF into keyslot 0xF. */ set_aes_keyslot(0xF, se_state + 0x30 + (0xF * 0x20), 0x10); - /* Set keyslot flags properly in preparation of derivation. */ + /* Set keyslot flags properly in preparation for secmon. */ set_aes_keyslot_flags(0xE, 0x15); set_aes_keyslot_flags(0xD, 0x15); } From 682957255624767478e2af38f0135fcd0e41244a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 00:20:42 -0700 Subject: [PATCH 05/15] sept: elide context save for safety. --- .../key_derivation/src/key_derivation.c | 60 +++---------------- 1 file changed, 7 insertions(+), 53 deletions(-) diff --git a/sept/sept-secondary/key_derivation/src/key_derivation.c b/sept/sept-secondary/key_derivation/src/key_derivation.c index 22be12e03..bb92687de 100644 --- a/sept/sept-secondary/key_derivation/src/key_derivation.c +++ b/sept/sept-secondary/key_derivation/src/key_derivation.c @@ -58,68 +58,24 @@ void derive_keys(void) { const uint32_t derivation_id = *((volatile uint32_t *)0x4003E800); if (derivation_id < DERIVATION_ID_MAX) { - uint8_t *partial_se_state = (uint8_t *)0x4000FFC0; uint8_t *enc_se_state = (uint8_t *)0x4003E000; - volatile tegra_pmc_t *pmc = pmc_get_regs(); uint32_t AL16 work_buffer[4]; - /* Save a partial context, only the keyslots we want. */ - /* We can't avoid touching memory, but save to a location that the bootrom will overwrite during init. */ - se_set_in_context_save_mode(true); - se_save_partial_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, partial_se_state); - se_set_in_context_save_mode(false); - - /* Clear the copy of the root key still inside the SE. */ - clear_aes_keyslot(0xD); - - /* Copy SRK into keyslot 0xE, clear it. */ - { - work_buffer[0] = pmc->secure_scratch4; - pmc->secure_scratch4 = 0xCCCCCCCC; - work_buffer[1] = pmc->secure_scratch5; - pmc->secure_scratch5 = 0xCCCCCCCC; - work_buffer[2] = pmc->secure_scratch6; - pmc->secure_scratch6 = 0xCCCCCCCC; - work_buffer[3] = pmc->secure_scratch7; - pmc->secure_scratch7 = 0xCCCCCCCC; - set_aes_keyslot(0xE, work_buffer, 0x10); - for (size_t i = 0; i < 4; i++) { - work_buffer[i] = 0xCCCCCCCC; - } - } - - /* Decrypt SE state. */ - se_aes_128_cbc_decrypt(0xE, partial_se_state, 0x40, partial_se_state, 0x40); - - /* Clear keyslots to wipe IVs. */ - clear_aes_keyslot(0xE); - clear_aes_keyslot(0xF); - - /* Mov root key into keyslot 0xE. */ - set_aes_keyslot(0xE, partial_se_state + 0x30, 0x10); - for (size_t i = 0; i < 4; i++) { - *((volatile uint32_t *)(partial_se_state + 0x30)) = 0xCCCCCCCC; - } + /* Derive Keyblob Key 00. */ + se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, keyblob_seed_00, 0x10); + decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10); /* Derive master kek. */ - decrypt_data_into_keyslot(0xE, 0xE, master_kek_seeds[derivation_id], 0x10); + decrypt_data_into_keyslot(0xE, 0xD, master_kek_seeds[derivation_id], 0x10); + + /* Clear the copy of the root key inside the SE. */ + clear_aes_keyslot(0xD); /* Derive master key, device master key. */ decrypt_data_into_keyslot(0xC, 0xE, masterkey_seed, 0x10); decrypt_data_into_keyslot(0xE, 0xE, masterkey_4x_seed, 0x10); - /* Derive Keyblob Key 00. */ - set_aes_keyslot(0xF, partial_se_state + 0x20, 0x10); - se_aes_ecb_decrypt_block(0xF, work_buffer, 0x10, keyblob_seed_00, 0x10); - set_aes_keyslot(0xF, partial_se_state + 0x10, 0x10); - decrypt_data_into_keyslot(0xF, 0xF, work_buffer, 0x10); - - /* Clear TSEC key + SBK. */ - for (size_t i = 0; i < 8; i++) { - *((volatile uint32_t *)(partial_se_state + 0x10)) = 0xCCCCCCCC; - } - /* Derive device keys. */ decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10); decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10); @@ -144,8 +100,6 @@ void derive_keys(void) { clear_aes_keyslot(i); } - *(volatile uint32_t *)(0x4003FFC0) = 0xCACACACA; - *mailbox = 7; while (1) { /* Wait for sept to handle the rest. */ } } From b82d8aaba9b443694f4f039c0ea09ad96f443fda Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 00:32:04 -0700 Subject: [PATCH 06/15] sept: validate ccplex reset vector --- sept/sept-secondary/src/cluster.c | 14 ++++++ sept/sept-secondary/src/main.c | 9 ++-- sept/sept-secondary/src/panic.c | 71 ++++--------------------------- sept/sept-secondary/src/panic.h | 3 +- 4 files changed, 29 insertions(+), 68 deletions(-) diff --git a/sept/sept-secondary/src/cluster.c b/sept/sept-secondary/src/cluster.c index cb29ec76b..4864ef38d 100644 --- a/sept/sept-secondary/src/cluster.c +++ b/sept/sept-secondary/src/cluster.c @@ -138,6 +138,11 @@ void cluster_boot_cpu0(uint32_t entry) MAKE_EXCP_VEC_REG(0x100) = 0; + /* Check for reset vector lock. */ + if (SB_CSR_0 & 2) { + generic_panic(); + } + /* Set reset vector. */ SB_AA64_RESET_LOW_0 = (entry | 1); SB_AA64_RESET_HIGH_0 = 0; @@ -146,6 +151,15 @@ void cluster_boot_cpu0(uint32_t entry) SB_CSR_0 = 2; (void)SB_CSR_0; + /* Validate reset vector lock + RESET_LOW/HIGH values. */ + if (!(SB_CSR_0 & 2)) { + generic_panic(); + } + + if (SB_AA64_RESET_LOW_0 != (entry | 1) || SB_AA64_RESET_HIGH_0 != 0) { + generic_panic(); + } + /* Set CPU_STRICT_TZ_APERTURE_CHECK. */ /* NOTE: [4.0.0+] This was added, but it breaks Exosphère. */ /* MAKE_MC_REG(MC_TZ_SECURITY_CTRL) = 1; */ diff --git a/sept/sept-secondary/src/main.c b/sept/sept-secondary/src/main.c index b1cb458a4..bc8f773c7 100644 --- a/sept/sept-secondary/src/main.c +++ b/sept/sept-secondary/src/main.c @@ -22,6 +22,7 @@ #include "se.h" #include "pmc.h" #include "emc.h" +#include "sysreg.h" #include "key_derivation.h" #include "timers.h" #include "fs_utils.h" @@ -96,9 +97,6 @@ static void setup_env(void) { /* Initialize hardware. */ nx_hwinit(); - /* Check for panics. */ - check_and_display_panic(); - /* Zero-fill the framebuffer and register it as printk provider. */ video_init(g_framebuffer); @@ -141,6 +139,11 @@ int sept_main(uint32_t version) { uint32_t stage2_version = 0; ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE; + /* Validate that we can safely boot the CCPLEX. */ + if (SB_CSR_0 & 2) { + generic_panic(); + } + /* Extract keys from the security engine, which TSEC FW locked down. */ exfiltrate_keys_and_reboot_if_needed(version); diff --git a/sept/sept-secondary/src/panic.c b/sept/sept-secondary/src/panic.c index cbd81bfb2..0884463d2 100644 --- a/sept/sept-secondary/src/panic.c +++ b/sept/sept-secondary/src/panic.c @@ -13,76 +13,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - +#include +#include #include "panic.h" #include "di.h" #include "pmc.h" +#include "se.h" #include "fuse.h" #include "utils.h" static uint32_t g_panic_code = 0; -void check_and_display_panic(void) { - /* We also handle our own panics. */ - /* In the case of our own panics, we assume that the display has already been initialized. */ - bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0; - uint32_t code = g_panic_code == 0 ? APBDEV_PMC_SCRATCH200_0 : g_panic_code; - - has_panic = has_panic && !(APBDEV_PMC_RST_STATUS_0 != 1 && code == PANIC_CODE_SAFEMODE); - - if (has_panic) { - uint32_t color; - - /* Check for predefined codes: */ - switch (code & MASK(20)) { - case 0x01: /* Package2 signature verification failed. */ - case 0x02: /* Package2 meta verification failed. */ - case 0x03: /* Package2 version check failed. */ - case 0x04: /* Package2 payload verification failed. */ - color = PANIC_COLOR_KERNEL; - break; - case 0x05: /* Unknown SMC. */ - case 0x06: /* Unknown Abort. */ - color = PANIC_COLOR_SECMON_GENERIC; - break; - case 0x07: /* Invalid CPU context. */ - case 0x08: /* Invalid SE state. */ - case 0x09: /* CPU is already awake (2.0.0+). */ - color = PANIC_COLOR_SECMON_DEEPSLEEP; - break; - case 0x10: /* Unknown exception. */ - color = PANIC_COLOR_SECMON_EXCEPTION; - break; - case 0x30: /* General bootloader error. */ - case 0x31: /* Invalid DRAM ID. */ - case 0x32: /* Invalid size. */ - case 0x33: /* Invalid arguement. */ - case 0x34: /* Bad GPT. */ - case 0x35: /* Failed to boot SafeMode. */ - case 0x36: /* Activity monitor fired (4.0.0+). */ - color = PANIC_COLOR_BOOTLOADER_GENERIC; - break; - case 0x40: /* Kernel panic. */ - color = PANIC_COLOR_KERNEL; - break; - default: - color = code >> 20; - color |= color << 4; - break; - } - - if (g_panic_code == 0) { - display_init(); - } - - display_color_screen(color); - wait_for_button_and_reboot(); - } else { - g_panic_code = 0; - APBDEV_PMC_SCRATCH200_0 = 0; - } -} - __attribute__ ((noreturn)) void panic(uint32_t code) { /* Set panic code. */ if (g_panic_code == 0) { @@ -90,9 +31,13 @@ __attribute__ ((noreturn)) void panic(uint32_t code) { APBDEV_PMC_SCRATCH200_0 = code; } + /* Clear all keyslots. */ + for (size_t i = 0; i < 0x10; i++) { + clear_aes_keyslot(i); + } + fuse_disable_programming(); APBDEV_PMC_CRYPTO_OP_0 = 1; /* Disable all SE operations. */ - check_and_display_panic(); while(true); } diff --git a/sept/sept-secondary/src/panic.h b/sept/sept-secondary/src/panic.h index 848a3fd81..e502a8551 100644 --- a/sept/sept-secondary/src/panic.h +++ b/sept/sept-secondary/src/panic.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef FUSEE_PANIC_H #define FUSEE_PANIC_H @@ -28,7 +28,6 @@ #define PANIC_CODE_SAFEMODE 0x00000020 -void check_and_display_panic(void); __attribute__ ((noreturn)) void panic(uint32_t code); #endif From 06e4158b938908f6ed7640249adac675a1ec72f1 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 00:42:30 -0700 Subject: [PATCH 07/15] sept: indulge paranoia, some. --- sept/sept-secondary/key_derivation/src/key_derivation.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sept/sept-secondary/key_derivation/src/key_derivation.c b/sept/sept-secondary/key_derivation/src/key_derivation.c index bb92687de..e66f836d8 100644 --- a/sept/sept-secondary/key_derivation/src/key_derivation.c +++ b/sept/sept-secondary/key_derivation/src/key_derivation.c @@ -75,14 +75,17 @@ void derive_keys(void) { /* Derive master key, device master key. */ decrypt_data_into_keyslot(0xC, 0xE, masterkey_seed, 0x10); decrypt_data_into_keyslot(0xE, 0xE, masterkey_4x_seed, 0x10); + clear_aes_keyslot(0xD); /* Derive device keys. */ decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10); decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10); + clear_aes_keyslot(0xD); /* Derive firmware specific device key. */ se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[derivation_id], 0x10); decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10); + clear_aes_keyslot(0xD); /* Clear work buffer. */ for (size_t i = 0; i < 4; i++) { From 6699fda8c94041f15819ed0a0c577aa0ae83d5b0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 11:51:30 -0700 Subject: [PATCH 08/15] loader: implement 8.1.0 changes --- sept/sept-secondary/key_derivation/src/se.c | 66 +++++++++---------- sept/sept-secondary/key_derivation/src/se.h | 2 - .../sept-secondary/key_derivation/src/utils.c | 7 ++ stratosphere/libstratosphere | 2 +- stratosphere/loader/source/ldr_npdm.hpp | 2 +- .../loader/source/ldr_process_creation.cpp | 36 +++++++++- .../loader/source/ldr_process_creation.hpp | 3 +- 7 files changed, 75 insertions(+), 43 deletions(-) diff --git a/sept/sept-secondary/key_derivation/src/se.c b/sept/sept-secondary/key_derivation/src/se.c index e7db66ab0..59ac47242 100644 --- a/sept/sept-secondary/key_derivation/src/se.c +++ b/sept/sept-secondary/key_derivation/src/se.c @@ -203,12 +203,37 @@ void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_sr generic_panic(); } + /* Write config, validate. */ se->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB); + if (se->CONFIG_REG != (ALG_AES_DEC | DST_KEYTAB)) { + generic_panic(); + } se->CRYPTO_REG = keyslot_src << 24; + if (se->CRYPTO_REG != (keyslot_src << 24)) { + generic_panic(); + } se->BLOCK_COUNT_REG = 0; + if (se->BLOCK_COUNT_REG != 0) { + generic_panic(); + } se->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8; + if (se->CRYPTO_KEYTABLE_DST_REG != (keyslot_dst << 8)) { + generic_panic(); + } + + /* Clear address context. */ + se->IN_LL_ADDR_REG = 0; + se->OUT_LL_ADDR_REG = 0; + if (se->IN_LL_ADDR_REG != 0 || se->OUT_LL_ADDR_REG != 0) { + generic_panic(); + } trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size); + + /* Validate address context. */ + if (se->IN_LL_ADDR_REG == 0 || se->OUT_LL_ADDR_REG == 0) { + generic_panic(); + } } void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) { @@ -320,6 +345,11 @@ void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const v /* Set registers for operation. */ se->ERR_STATUS_REG = se->ERR_STATUS_REG; se->INT_STATUS_REG = se->INT_STATUS_REG; + + if (se->IN_LL_ADDR_REG != (uint32_t) get_physical_address(&in_ll) || se->OUT_LL_ADDR_REG != (uint32_t) get_physical_address(&out_ll) || (se->INT_STATUS_REG & 0x10)) { + generic_panic(); + } + se->OPERATION_REG = op; while (!(se->INT_STATUS_REG & 0x10)) { /* Wait a while */ } @@ -725,39 +755,3 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void se->CONFIG_REG = 0; se_encrypt_with_srk(work_buf, 0, NULL, 0); } - -void se_save_partial_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) { - volatile tegra_se_t *se = se_get_regs(); - uint8_t _work_buf[0x80]; - uint8_t *work_buf = (uint8_t *)(((uintptr_t)_work_buf + 0x7F) & ~0x3F); - - /* Generate the SRK (context save encryption key). */ - se_generate_random_key(srkgen_keyslot, rng_keyslot); - se_generate_srk(srkgen_keyslot); - - se_generate_random(rng_keyslot, work_buf, 0x10); - - /* Save known pattern. */ - static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; - se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM); - se->BLOCK_COUNT_REG = 0; - se_encrypt_with_srk(dst + 0x00, 0x10, context_save_known_pattern, 0x10); - - /* Save specific keyslots 0xC, 0xD, 0xE. */ - se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xE << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS); - se->BLOCK_COUNT_REG = 0; - se_encrypt_with_srk(dst + 0x10, 0x10, NULL, 0); - se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xC << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS); - se->BLOCK_COUNT_REG = 0; - se_encrypt_with_srk(dst + 0x20, 0x10, NULL, 0); - se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xD << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS); - se->BLOCK_COUNT_REG = 0; - se_encrypt_with_srk(dst + 0x30, 0x10, NULL, 0); - - /* Save SRK into PMC registers. */ - se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK); - se->BLOCK_COUNT_REG = 0; - se_encrypt_with_srk(work_buf, 0, NULL, 0); - se->CONFIG_REG = 0; - se_encrypt_with_srk(work_buf, 0, NULL, 0); -} diff --git a/sept/sept-secondary/key_derivation/src/se.h b/sept/sept-secondary/key_derivation/src/se.h index d3b3c7ca1..98a6a170f 100644 --- a/sept/sept-secondary/key_derivation/src/se.h +++ b/sept/sept-secondary/key_derivation/src/se.h @@ -222,6 +222,4 @@ void se_set_in_context_save_mode(bool is_context_save_mode); void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot); void se_save_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst); -void se_save_partial_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst); - #endif diff --git a/sept/sept-secondary/key_derivation/src/utils.c b/sept/sept-secondary/key_derivation/src/utils.c index cc6cec4b7..a515fb57a 100644 --- a/sept/sept-secondary/key_derivation/src/utils.c +++ b/sept/sept-secondary/key_derivation/src/utils.c @@ -17,8 +17,15 @@ #include #include #include "utils.h" +#include "se.h" #include __attribute__ ((noreturn)) void generic_panic(void) { + /* Clear keyslots. */ + clear_aes_keyslot(0xD); + for (size_t i = 0; i < 0x10; i++) { + clear_aes_keyslot(i); + } + clear_aes_keyslot(0xD); while(1) { /* ... */ } } diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index 281534d9f..7e0ed3b38 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit 281534d9f805af7dccbdd4e0e8883d4d055581ff +Subproject commit 7e0ed3b38f437791fdd398c7058c376c9d2a6853 diff --git a/stratosphere/loader/source/ldr_npdm.hpp b/stratosphere/loader/source/ldr_npdm.hpp index b0aae5731..c8c18f76a 100644 --- a/stratosphere/loader/source/ldr_npdm.hpp +++ b/stratosphere/loader/source/ldr_npdm.hpp @@ -37,7 +37,7 @@ class NpdmUtils { u8 default_cpuid; u32 _0x10; u32 system_resource_size; - u32 process_category; + u32 version; u32 main_stack_size; char title_name[0x50]; u32 aci0_offset; diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 9a1449d4e..e76cdf20f 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -25,6 +25,35 @@ #include "ldr_npdm.hpp" #include "ldr_nso.hpp" +static inline bool IsDisallowedVersion810(const u64 title_id, const u32 version) { + return version == 0 && + (title_id == TitleId_Settings || + title_id == TitleId_Bus || + title_id == TitleId_Audio || + title_id == TitleId_NvServices || + title_id == TitleId_Ns || + title_id == TitleId_Ssl || + title_id == TitleId_Es || + title_id == TitleId_Creport || + title_id == TitleId_Ro); +} + +Result ProcessCreation::ValidateProcessVersion(u64 title_id, u32 version) { + if (GetRuntimeFirmwareVersion() < FirmwareVersion_810) { + return ResultSuccess; + } else { +#ifdef LDR_VALIDATE_PROCESS_VERSION + if (IsDisallowedVersion810(title_id, version)) { + return ResultLoaderInvalidVersion; + } else { + return ResultSuccess; + } +#else + return ResultSuccess; +#endif + } +} + Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle reslimit_h, u64 arg_flags, ProcessInfo *out_proc_info) { /* Initialize a ProcessInfo using an npdm. */ *out_proc_info = {}; @@ -36,8 +65,8 @@ Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle /* Set title id. */ out_proc_info->title_id = npdm->aci0->title_id; - /* Set process category. */ - out_proc_info->process_category = npdm->header->process_category; + /* Set version. */ + out_proc_info->version = npdm->header->version; /* Copy reslimit handle raw. */ out_proc_info->reslimit_h = reslimit_h; @@ -145,6 +174,9 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc /* Load the process's NPDM. */ R_TRY(NpdmUtils::LoadNpdmFromCache(target_process->tid_sid.title_id, &npdm_info)); + /* Validate version. */ + R_TRY(ValidateProcessVersion(target_process->tid_sid.title_id, npdm_info.header->version)); + /* Validate the title we're loading is what we expect. */ if (npdm_info.aci0->title_id < npdm_info.acid->title_id_range_min || npdm_info.aci0->title_id > npdm_info.acid->title_id_range_max) { return ResultLoaderInvalidProgramId; diff --git a/stratosphere/loader/source/ldr_process_creation.hpp b/stratosphere/loader/source/ldr_process_creation.hpp index 1914122d1..df975d063 100644 --- a/stratosphere/loader/source/ldr_process_creation.hpp +++ b/stratosphere/loader/source/ldr_process_creation.hpp @@ -27,7 +27,7 @@ class ProcessCreation { public: struct ProcessInfo { u8 name[12]; - u32 process_category; + u32 version; u64 title_id; u64 code_addr; u32 code_num_pages; @@ -35,6 +35,7 @@ class ProcessCreation { Handle reslimit_h; u32 system_resource_num_pages; }; + static Result ValidateProcessVersion(u64 title_id, u32 version); static Result InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle reslimit_h, u64 arg_flags, ProcessInfo *out_proc_info); static Result CreateProcess(Handle *out_process_h, u64 index, char *nca_path, LaunchQueue::LaunchItem *launch_item, u64 arg_flags, Handle reslimit_h); }; \ No newline at end of file From 24f7977fa6f05d34aade7c91420f8558ca1c0fb6 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 11:57:40 -0700 Subject: [PATCH 09/15] SEPT_ENC_PATH -> SEPT_00_ENC_PATH + SEPT_01_ENC_PATH --- sept/sept-secondary/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sept/sept-secondary/Makefile b/sept/sept-secondary/Makefile index b9721de5f..6bc94cd3d 100644 --- a/sept/sept-secondary/Makefile +++ b/sept/sept-secondary/Makefile @@ -124,12 +124,13 @@ check_key_derivation: @$(MAKE) -C key_derivation $(BUILD): check_rebootstub check_key_derivation -ifeq ($(strip $(SEPT_ENC_PATH)),) +ifeq ($(strip $(SEPT_ENC_00_PATH)),) @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile else @touch $(TOPDIR)/$(TARGET).bin - @cp $(SEPT_ENC_PATH) $(TOPDIR)/$(TARGET).enc + @cp $(SEPT_ENC_00_PATH) $(TOPDIR)/$(TARGET)_00.enc + @cp $(SEPT_ENC_01_PATH) $(TOPDIR)/$(TARGET)_01.enc endif #--------------------------------------------------------------------------------- From c077c75b8d826ae02b4690a5a548961d8cfcb90f Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 12:04:43 -0700 Subject: [PATCH 10/15] sept: update makefile vars to allow for presigned bin --- sept/sept-secondary/Makefile | 6 +++--- sept/sept-secondary/key_derivation/src/se.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sept/sept-secondary/Makefile b/sept/sept-secondary/Makefile index 6bc94cd3d..fbbcac1a3 100644 --- a/sept/sept-secondary/Makefile +++ b/sept/sept-secondary/Makefile @@ -124,13 +124,13 @@ check_key_derivation: @$(MAKE) -C key_derivation $(BUILD): check_rebootstub check_key_derivation -ifeq ($(strip $(SEPT_ENC_00_PATH)),) +ifeq ($(strip $(SEPT_00_ENC_PATH)),) @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile else @touch $(TOPDIR)/$(TARGET).bin - @cp $(SEPT_ENC_00_PATH) $(TOPDIR)/$(TARGET)_00.enc - @cp $(SEPT_ENC_01_PATH) $(TOPDIR)/$(TARGET)_01.enc + @cp $(SEPT_00_ENC_PATH) $(TOPDIR)/$(TARGET)_00.enc + @cp $(SEPT_01_ENC_PATH) $(TOPDIR)/$(TARGET)_01.enc endif #--------------------------------------------------------------------------------- diff --git a/sept/sept-secondary/key_derivation/src/se.c b/sept/sept-secondary/key_derivation/src/se.c index 59ac47242..ede5a05d2 100644 --- a/sept/sept-secondary/key_derivation/src/se.c +++ b/sept/sept-secondary/key_derivation/src/se.c @@ -346,7 +346,7 @@ void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const v se->ERR_STATUS_REG = se->ERR_STATUS_REG; se->INT_STATUS_REG = se->INT_STATUS_REG; - if (se->IN_LL_ADDR_REG != (uint32_t) get_physical_address(&in_ll) || se->OUT_LL_ADDR_REG != (uint32_t) get_physical_address(&out_ll) || (se->INT_STATUS_REG & 0x10)) { + if (se->IN_LL_ADDR_REG != (uint32_t) get_physical_address(&in_ll) || se->OUT_LL_ADDR_REG != (uint32_t) get_physical_address(&out_ll) || (se->FLAGS_REG & 0x3)) { generic_panic(); } From 938da08e1446cff77efef985ac95ba8827d37076 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 12:22:37 -0700 Subject: [PATCH 11/15] sept: add vector check to key derivation --- .../key_derivation/src/key_derivation.c | 23 ++++++++++++++++++- sept/sept-secondary/key_derivation/src/se.c | 2 +- .../sept-secondary/key_derivation/src/utils.c | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/sept/sept-secondary/key_derivation/src/key_derivation.c b/sept/sept-secondary/key_derivation/src/key_derivation.c index e66f836d8..349e72ada 100644 --- a/sept/sept-secondary/key_derivation/src/key_derivation.c +++ b/sept/sept-secondary/key_derivation/src/key_derivation.c @@ -14,9 +14,10 @@ * along with this program. If not, see . */ -#include +#include #include "pmc.h" #include "se.h" +#include "utils.h" #define AL16 __attribute__((aligned(16))) @@ -42,6 +43,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 zeroes[0x10] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + static const uint8_t AL16 master_kek_seeds[DERIVATION_ID_MAX][0x10] = { {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41}, @@ -52,6 +57,11 @@ static const uint8_t AL16 master_devkey_seeds[DERIVATION_ID_MAX][0x10] = { {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, }; +static const uint8_t AL16 master_devkey_vectors[DERIVATION_ID_MAX][0x10] = { + {0xD8, 0xD3, 0x67, 0x4F, 0xF3, 0xA2, 0xA4, 0x4E, 0xE4, 0x04, 0x37, 0xC2, 0xD9, 0xCF, 0x41, 0x6F}, + {0x72, 0xD0, 0xAD, 0xEB, 0xE1, 0xF6, 0x35, 0x90, 0xB4, 0x43, 0xCC, 0x4B, 0xC4, 0xDC, 0x88, 0x0A}, +}; + void derive_keys(void) { /* Set mailbox. */ volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00; @@ -87,6 +97,17 @@ void derive_keys(void) { decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10); clear_aes_keyslot(0xD); + /* Test against a vector. */ + se_aes_ecb_decrypt_block(0xE, work_buffer, 0x10, master_devkey_vectors[derivation_id], 0x10); + if (memcmp(work_buffer, zeroes, 0x10) == 0) { + clear_aes_keyslot(0xE); + clear_aes_keyslot(0xD); + clear_aes_keyslot(0xC); + clear_aes_keyslot(0xA); + clear_aes_keyslot(0xF); + generic_panic(); + } + /* Clear work buffer. */ for (size_t i = 0; i < 4; i++) { work_buffer[i] = 0xCCCCCCCC; diff --git a/sept/sept-secondary/key_derivation/src/se.c b/sept/sept-secondary/key_derivation/src/se.c index ede5a05d2..b32595c99 100644 --- a/sept/sept-secondary/key_derivation/src/se.c +++ b/sept/sept-secondary/key_derivation/src/se.c @@ -346,7 +346,7 @@ void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const v se->ERR_STATUS_REG = se->ERR_STATUS_REG; se->INT_STATUS_REG = se->INT_STATUS_REG; - if (se->IN_LL_ADDR_REG != (uint32_t) get_physical_address(&in_ll) || se->OUT_LL_ADDR_REG != (uint32_t) get_physical_address(&out_ll) || (se->FLAGS_REG & 0x3)) { + if (se->IN_LL_ADDR_REG != (uint32_t) get_physical_address(&in_ll) || se->OUT_LL_ADDR_REG != (uint32_t) get_physical_address(&out_ll) || (se->INT_STATUS_REG & 0x10) || (se->FLAGS_REG & 0x3)) { generic_panic(); } diff --git a/sept/sept-secondary/key_derivation/src/utils.c b/sept/sept-secondary/key_derivation/src/utils.c index a515fb57a..b9e7c2551 100644 --- a/sept/sept-secondary/key_derivation/src/utils.c +++ b/sept/sept-secondary/key_derivation/src/utils.c @@ -23,9 +23,11 @@ __attribute__ ((noreturn)) void generic_panic(void) { /* Clear keyslots. */ clear_aes_keyslot(0xD); + clear_aes_keyslot(0xE); for (size_t i = 0; i < 0x10; i++) { clear_aes_keyslot(i); } clear_aes_keyslot(0xD); + clear_aes_keyslot(0xE); while(1) { /* ... */ } } From 8663eb1a6ed027354a0e9cef2aa7bfbf0129dc82 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 12:26:37 -0700 Subject: [PATCH 12/15] sept: tweak vector check --- .../key_derivation/src/key_derivation.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sept/sept-secondary/key_derivation/src/key_derivation.c b/sept/sept-secondary/key_derivation/src/key_derivation.c index 349e72ada..94194bf4a 100644 --- a/sept/sept-secondary/key_derivation/src/key_derivation.c +++ b/sept/sept-secondary/key_derivation/src/key_derivation.c @@ -98,7 +98,20 @@ void derive_keys(void) { clear_aes_keyslot(0xD); /* Test against a vector. */ + for (size_t i = 0; i < 4; i++) { + work_buffer[i] = 0; + } + if (memcmp(work_buffer, zeroes, 0x10) != 0) { + clear_aes_keyslot(0xE); + clear_aes_keyslot(0xD); + clear_aes_keyslot(0xC); + clear_aes_keyslot(0xA); + clear_aes_keyslot(0xF); + generic_panic(); + } + se_aes_ecb_decrypt_block(0xE, work_buffer, 0x10, master_devkey_vectors[derivation_id], 0x10); + if (memcmp(work_buffer, zeroes, 0x10) == 0) { clear_aes_keyslot(0xE); clear_aes_keyslot(0xD); From e274d3ef37661ad3619833dada9ee24776edef64 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 12:40:39 -0700 Subject: [PATCH 13/15] sept: tweak cluster verif --- sept/sept-secondary/src/cluster.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sept/sept-secondary/src/cluster.c b/sept/sept-secondary/src/cluster.c index 4864ef38d..1ea65a699 100644 --- a/sept/sept-secondary/src/cluster.c +++ b/sept/sept-secondary/src/cluster.c @@ -156,7 +156,8 @@ void cluster_boot_cpu0(uint32_t entry) generic_panic(); } - if (SB_AA64_RESET_LOW_0 != (entry | 1) || SB_AA64_RESET_HIGH_0 != 0) { + /* TODO: Should we even bother taking as a parameter? */ + if (SB_AA64_RESET_LOW_0 != (0x4003D000 | 1) || SB_AA64_RESET_HIGH_0 != 0) { generic_panic(); } From e996acff6677c9d4517eb7fe6e20c9156632eb85 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 12:41:51 -0700 Subject: [PATCH 14/15] Latest supported version is 8.1.0 --- common/include/atmosphere/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/include/atmosphere/version.h b/common/include/atmosphere/version.h index fd07c5b20..b0afdfc7b 100644 --- a/common/include/atmosphere/version.h +++ b/common/include/atmosphere/version.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef ATMOSPHERE_VERSION_H #define ATMOSPHERE_VERSION_H @@ -22,7 +22,7 @@ #define ATMOSPHERE_RELEASE_VERSION_MICRO 0 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 8 -#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0 -#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 1 +#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1 +#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0 #endif \ No newline at end of file From 3f9d6574fbdc1e72ec7385652c12556e7697f308 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 19 Jun 2019 12:53:24 -0700 Subject: [PATCH 15/15] emummc: support for 8.1.0 --- emummc/source/FS/FS_offsets.c | 8 ++++ emummc/source/FS/FS_versions.h | 3 ++ emummc/source/FS/offsets/810.h | 58 ++++++++++++++++++++++++++++ emummc/source/FS/offsets/810_exfat.h | 58 ++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 emummc/source/FS/offsets/810.h create mode 100644 emummc/source/FS/offsets/810_exfat.h diff --git a/emummc/source/FS/FS_offsets.c b/emummc/source/FS/FS_offsets.c index 7f0cff371..1f578cd68 100644 --- a/emummc/source/FS/FS_offsets.c +++ b/emummc/source/FS/FS_offsets.c @@ -39,6 +39,8 @@ #include "offsets/700_exfat.h" #include "offsets/800.h" #include "offsets/800_exfat.h" +#include "offsets/810.h" +#include "offsets/810_exfat.h" #include "../utils/fatal.h" #define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers @@ -88,6 +90,8 @@ DEFINE_OFFSET_STRUCT(_700); DEFINE_OFFSET_STRUCT(_700_EXFAT); DEFINE_OFFSET_STRUCT(_800); DEFINE_OFFSET_STRUCT(_800_EXFAT); +DEFINE_OFFSET_STRUCT(_810); +DEFINE_OFFSET_STRUCT(_810_EXFAT); const fs_offsets_t *get_fs_offsets(enum FS_VER version) { switch (version) { @@ -137,6 +141,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) { return &(GET_OFFSET_STRUCT_NAME(_800)); case FS_VER_8_0_0_EXFAT: return &(GET_OFFSET_STRUCT_NAME(_800_EXFAT)); + case FS_VER_8_1_0: + return &(GET_OFFSET_STRUCT_NAME(_810)); + case FS_VER_8_1_0_EXFAT: + return &(GET_OFFSET_STRUCT_NAME(_810_EXFAT)); default: fatal_abort(Fatal_UnknownVersion); } diff --git a/emummc/source/FS/FS_versions.h b/emummc/source/FS/FS_versions.h index 8dd88827c..e952ee48e 100644 --- a/emummc/source/FS/FS_versions.h +++ b/emummc/source/FS/FS_versions.h @@ -56,6 +56,9 @@ enum FS_VER FS_VER_8_0_0, FS_VER_8_0_0_EXFAT, + FS_VER_8_1_0, + FS_VER_8_1_0_EXFAT, + FS_VER_MAX, }; diff --git a/emummc/source/FS/offsets/810.h b/emummc/source/FS/offsets/810.h new file mode 100644 index 000000000..02f60dcd9 --- /dev/null +++ b/emummc/source/FS/offsets/810.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019 m4xw + * Copyright (c) 2019 Atmosphere-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 __FS_810_H__ +#define __FS_810_H__ + +// Accessor vtable getters +#define FS_OFFSET_810_SDMMC_ACCESSOR_GC 0x15EA20 +#define FS_OFFSET_810_SDMMC_ACCESSOR_SD 0x15E790 +#define FS_OFFSET_810_SDMMC_ACCESSOR_NAND 0x15AC80 + +// Hooks +#define FS_OFFSET_810_SDMMC_WRAPPER_READ 0x152A80 +#define FS_OFFSET_810_SDMMC_WRAPPER_WRITE 0x152B60 +#define FS_OFFSET_810_RTLD 0x5B4 +#define FS_OFFSET_810_RTLD_DESTINATION 0x9C + +#define FS_OFFSET_810_CLKRST_SET_MIN_V_CLK_RATE 0x16F370 + +// Misc funcs +#define FS_OFFSET_810_LOCK_MUTEX 0x14B6D0 +#define FS_OFFSET_810_UNLOCK_MUTEX 0x14B720 + +// Misc Data +#define FS_OFFSET_810_SD_MUTEX 0xF1A3E8 +#define FS_OFFSET_810_NAND_MUTEX 0xF15BE8 +#define FS_OFFSET_810_ACTIVE_PARTITION 0xF15C28 +#define FS_OFFSET_810_SDMMC_DAS_HANDLE 0xE167C0 + +// NOPs +#define FS_OFFSET_810_SHUTDOWN_SD 0xBAF6C +#define FS_OFFSET_810_SD_DAS_INIT 0x87D58 + +// Nintendo Paths +#define FS_OFFSET_810_NINTENDO_PATHS \ +{ \ + {.opcode_reg = 3, .adrp_offset = 0x0007F5F0, .add_rel_offset = 4}, \ + {.opcode_reg = 3, .adrp_offset = 0x00081084, .add_rel_offset = 4}, \ + {.opcode_reg = 3, .adrp_offset = 0x00081278, .add_rel_offset = 4}, \ + {.opcode_reg = 3, .adrp_offset = 0x00081654, .add_rel_offset = 4}, \ + {.opcode_reg = 4, .adrp_offset = 0x00081818, .add_rel_offset = 4}, \ + {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \ +} + +#endif // __FS_810_H__ diff --git a/emummc/source/FS/offsets/810_exfat.h b/emummc/source/FS/offsets/810_exfat.h new file mode 100644 index 000000000..bd8240582 --- /dev/null +++ b/emummc/source/FS/offsets/810_exfat.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019 m4xw + * Copyright (c) 2019 Atmosphere-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 __FS_810_EXFAT_H__ +#define __FS_810_EXFAT_H__ + +// Accessor vtable getters +#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_GC 0x169FD0 +#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_SD 0x169D40 +#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_NAND 0x166230 + +// Hooks +#define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_READ 0x15E030 +#define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_WRITE 0x15E110 +#define FS_OFFSET_810_EXFAT_RTLD 0x5B4 +#define FS_OFFSET_810_EXFAT_RTLD_DESTINATION 0x9C + +#define FS_OFFSET_810_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x17A920 + +// Misc funcs +#define FS_OFFSET_810_EXFAT_LOCK_MUTEX 0x156C80 +#define FS_OFFSET_810_EXFAT_UNLOCK_MUTEX 0x156CD0 + +// Misc Data +#define FS_OFFSET_810_EXFAT_SD_MUTEX 0xFFE3E8 +#define FS_OFFSET_810_EXFAT_NAND_MUTEX 0xFF9BE8 +#define FS_OFFSET_810_EXFAT_ACTIVE_PARTITION 0xFF9C28 +#define FS_OFFSET_810_EXFAT_SDMMC_DAS_HANDLE 0xEFAA20 + +// NOPs +#define FS_OFFSET_810_EXFAT_SHUTDOWN_SD 0xC651C +#define FS_OFFSET_810_EXFAT_SD_DAS_INIT 0x93308 + +// Nintendo Paths +#define FS_OFFSET_810_EXFAT_NINTENDO_PATHS \ +{ \ + {.opcode_reg = 3, .adrp_offset = 0x0008ABA0, .add_rel_offset = 4}, \ + {.opcode_reg = 3, .adrp_offset = 0x0008C634, .add_rel_offset = 4}, \ + {.opcode_reg = 3, .adrp_offset = 0x0008C828, .add_rel_offset = 4}, \ + {.opcode_reg = 3, .adrp_offset = 0x0008CC04, .add_rel_offset = 4}, \ + {.opcode_reg = 4, .adrp_offset = 0x0008CDC8, .add_rel_offset = 4}, \ + {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \ +} + +#endif // __FS_810_EXFAT_H__