diff --git a/.gitignore b/.gitignore index 7592fed..dfb2a80 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ research/* loader/payload_00.h loader/payload_01.h tools/bin2c/bin2c +keygen/tsec_keygen.h tools/lz/lz77 diff --git a/Makefile b/Makefile index 94d81f3..1fdc863 100644 --- a/Makefile +++ b/Makefile @@ -16,9 +16,12 @@ include ./Versions.inc TARGET := Lockpick_RCM BUILDDIR := build OUTPUTDIR := output -SOURCEDIR = source +SOURCEDIR := source BDKDIR := bdk BDKINC := -I./$(BDKDIR) +KEYGENDIR := keygen +KEYGEN := tsec_keygen +KEYGENH := tsec_keygen.h VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) VPATH += $(dir $(wildcard ./$(BDKDIR)/)) $(dir $(wildcard ./$(BDKDIR)/*/)) $(dir $(wildcard ./$(BDKDIR)/*/*/)) @@ -100,6 +103,11 @@ $(BUILDDIR)/$(TARGET)/$(TARGET).elf: $(OBJS) @$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@ @echo "Lockpick_RCM was built with the following flags:\nCFLAGS: "$(CFLAGS)"\nLDFLAGS: "$(LDFLAGS) +$(OBJS): | $(KEYGENDIR) + +$(KEYGENDIR): $(TOOLS) + @cd $(KEYGENDIR) && ../$(TOOLSB2C)/bin2c $(KEYGEN) > $(KEYGENH) + $(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c @mkdir -p "$(@D)" @echo Building $@ diff --git a/README.md b/README.md index fcdd5ef..8c8d4bd 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Usage * It is highly recommended, but not required, to place Minerva on SD from the latest [Hekate](https://github.com/CTCaer/hekate/releases) for best performance, especially while dumping titlekeys - the file and path is `/bootloader/sys/libsys_minerva.bso` * Launch Lockpick_RCM.bin using your favorite payload injector or chainloader * Upon completion, keys will be saved to `/switch/prod.keys` and titlekeys to `/switch/title.keys` on SD -* If the console has Firmware 7.x or higher, the `/sept/` folder from [Atmosphère](https://github.com/Atmosphere-NX/Atmosphere/releases) or [Kosmos](https://github.com/AtlasNX/Kosmos/releases) release zip must be present on SD or else only keyblob master key derivation is possible (ie. up to `master_key_05` only) +* This release bundles the Falcon keygen from [Atmosphère-NX](https://github.com/Atmosphere-NX/Atmosphere) Mariko-Specific Keys = diff --git a/bdk/sec/tsec.c b/bdk/sec/tsec.c index adf5ac2..c154062 100644 --- a/bdk/sec/tsec.c +++ b/bdk/sec/tsec.c @@ -66,8 +66,6 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) { int res = 0; u8 *fwbuf = NULL; - u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec; - u32 *pkg11_magic_off; bpmp_mmu_disable(); bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL); @@ -125,61 +123,6 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) } } - if (kb == KB_TSEC_FW_EMU_COMPAT) - { - // Init SMMU translation for TSEC. - pdir = smmu_init_for_tsec(); - smmu_init(0x4002B000); - // Enable SMMU - if (!smmu_is_used()) - smmu_enable(); - - // Clock reset controller. - car = page_alloc(1); - memcpy(car, (void *)CLOCK_BASE, 0x1000); - car[CLK_RST_CONTROLLER_CLK_SOURCE_TSEC / 4] = 2; - smmu_map(pdir, CLOCK_BASE, (u32)car, 1, _WRITABLE | _READABLE | _NONSECURE); - - // Fuse driver. - fuse = page_alloc(1); - memcpy((void *)&fuse[0x800/4], (void *)FUSE_BASE, 0x400); - fuse[0x82C / 4] = 0; - fuse[0x9E0 / 4] = (1 << (kb + 2)) - 1; - fuse[0x9E4 / 4] = (1 << (kb + 2)) - 1; - smmu_map(pdir, (FUSE_BASE - 0x800), (u32)fuse, 1, _READABLE | _NONSECURE); - - // Power management controller. - pmc = page_alloc(1); - smmu_map(pdir, RTC_BASE, (u32)pmc, 1, _READABLE | _NONSECURE); - - // Flow control. - flowctrl = page_alloc(1); - smmu_map(pdir, FLOW_CTLR_BASE, (u32)flowctrl, 1, _WRITABLE | _NONSECURE); - - // Security engine. - se = page_alloc(1); - memcpy(se, (void *)SE_BASE, 0x1000); - smmu_map(pdir, SE_BASE, (u32)se, 1, _READABLE | _WRITABLE | _NONSECURE); - - // Memory controller. - mc = page_alloc(1); - memcpy(mc, (void *)MC_BASE, 0x1000); - mc[MC_IRAM_BOM / 4] = 0; - mc[MC_IRAM_TOM / 4] = 0x80000000; - smmu_map(pdir, MC_BASE, (u32)mc, 1, _READABLE | _NONSECURE); - - // IRAM - iram = page_alloc(0x30); - memcpy(iram, tsec_ctxt->pkg1, 0x30000); - // PKG1.1 magic offset. - pkg11_magic_off = (u32 *)(iram + (0x7000 / 4)); - smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE); - - // Exception vectors - evec = page_alloc(1); - smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE); - } - //Execute firmware. HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; TSEC(TSEC_STATUS) = 0; @@ -187,91 +130,27 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt) TSEC(TSEC_BOOTVEC) = 0; TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU; - if (kb == KB_TSEC_FW_EMU_COMPAT) + if (!_tsec_dma_wait_idle()) { - u32 start = get_tmr_us(); - u32 k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]; - u32 key[16] = {0}; - u32 kidx = 0; - - while (*pkg11_magic_off != PKG11_MAGIC) + res = -3; + goto out_free; + } + u32 timeout = get_tmr_ms() + 4000; + while (!(TSEC(TSEC_CPUCTL) & TSEC_CPUCTL_KEYGEN_DONE)) + if (get_tmr_ms() > timeout) { - smmu_flush_all(); - - if (k != se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]) - { - k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4]; - key[kidx++] = k; - } - - // Failsafe. - if ((u32)get_tmr_us() - start > 125000) - break; - } - - if (kidx != 8) - { - res = -6; - smmu_deinit_for_tsec(); - + res = -4; goto out_free; } - - // Give some extra time to make sure PKG1.1 is decrypted. - msleep(50); - - memcpy(tsec_keys, &key, 0x20); - memcpy(tsec_ctxt->pkg1, iram, 0x30000); - - smmu_deinit_for_tsec(); - - // for (int i = 0; i < kidx; i++) - // gfx_printf("key %08X\n", key[i]); - - // gfx_printf("cpuctl (%08X) mbox (%08X)\n", TSEC(TSEC_CPUCTL), TSEC(TSEC_STATUS)); - - // u32 errst = MC(MC_ERR_STATUS); - // gfx_printf(" MC %08X %08X %08X\n", MC(MC_INTSTATUS), errst, MC(MC_ERR_ADR)); - // gfx_printf(" type: %02X\n", errst >> 28); - // gfx_printf(" smmu: %02X\n", (errst >> 25) & 3); - // gfx_printf(" dir: %s\n", (errst >> 16) & 1 ? "W" : "R"); - // gfx_printf(" cid: %02x\n", errst & 0xFF); - } - else + if (TSEC(TSEC_STATUS) != 0xB0B0B0B0) { - if (!_tsec_dma_wait_idle()) - { - res = -3; - goto out_free; - } - u32 timeout = get_tmr_ms() + 2000; - while (!TSEC(TSEC_STATUS)) - if (get_tmr_ms() > timeout) - { - res = -4; - goto out_free; - } - if (TSEC(TSEC_STATUS) != 0xB0B0B0B0) - { - res = -5; - goto out_free; - } - - //Fetch result. - HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; - u32 buf[4]; - buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB); - buf[1] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB); - buf[2] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB); - buf[3] = SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB); - SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_BKSV_LSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_MSB) = 0; - SOR1(SOR_NV_PDISP_SOR_TMDS_HDCP_CN_LSB) = 0; - - memcpy(tsec_keys, &buf, SE_KEY_128_SIZE); + res = -5; + goto out_free; } + //Fetch result. + HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; + out_free:; free(fwbuf); @@ -288,3 +167,26 @@ out:; return res; } + +int tsec_run_fw(tsec_ctxt_t *tsec_ctxt) +{ + /* Ensure that the ahb redirect is enabled. */ + mc_enable_ahb_redirect(); + + /* Get bom/tom */ + u32 bom = MC(MC_IRAM_BOM); + u32 tom = MC(MC_IRAM_TOM); + + /* Override the ahb redirect extents. */ + MC(MC_IRAM_BOM) = 0x40000000; + MC(MC_IRAM_TOM) = 0x80000000; + + /* Run the fw. */ + int res = tsec_query(NULL, 0, tsec_ctxt); + + /* Reset the ahb redirect extents. */ + MC(MC_IRAM_BOM) = bom; + MC(MC_IRAM_TOM) = tom; + + return res; +} diff --git a/bdk/sec/tsec.h b/bdk/sec/tsec.h index 274b6e7..47c9f45 100644 --- a/bdk/sec/tsec.h +++ b/bdk/sec/tsec.h @@ -24,7 +24,7 @@ typedef struct _tsec_ctxt_t { - void *fw; + const void *fw; u32 size; void *pkg1; } tsec_ctxt_t; @@ -47,5 +47,6 @@ typedef struct _tsec_key_data_t } tsec_key_data_t; int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt); +int tsec_run_fw(tsec_ctxt_t *tsec_ctxt); #endif diff --git a/bdk/sec/tsec_t210.h b/bdk/sec/tsec_t210.h index 889d0d4..9d473cb 100644 --- a/bdk/sec/tsec_t210.h +++ b/bdk/sec/tsec_t210.h @@ -37,6 +37,7 @@ #define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8) #define TSEC_CPUCTL 0x1100 #define TSEC_CPUCTL_STARTCPU BIT(1) +#define TSEC_CPUCTL_KEYGEN_DONE BIT(4) #define TSEC_BOOTVEC 0x1104 #define TSEC_DMACTL 0x110C #define TSEC_DMATRFBASE 0x1110 diff --git a/bdk/soc/hw_init.c b/bdk/soc/hw_init.c index 1da102f..afde017 100644 --- a/bdk/soc/hw_init.c +++ b/bdk/soc/hw_init.c @@ -253,9 +253,8 @@ static void _config_se_brom() // Enable fuse clock. clock_enable_fuse(true); - // Skip SBK/SSK if sept was run. - bool sbk_skip = b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN || FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF; - if (!sbk_skip) + // Skip SBK/SSK if running on patched Erista. + if (!(FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF)) { // Bootrom part we skipped. u32 sbk[4] = { diff --git a/bdk/soc/t210.h b/bdk/soc/t210.h index e48f53a..ac703ef 100644 --- a/bdk/soc/t210.h +++ b/bdk/soc/t210.h @@ -281,7 +281,6 @@ /*! Special registers. */ #define EMC_SCRATCH0 0x324 #define EMC_HEKA_UPD BIT(30) -#define EMC_SEPT_RUN BIT(31) /*! Flow controller registers. */ #define FLOW_CTLR_HALT_COP_EVENTS 0x4 diff --git a/bdk/utils/types.h b/bdk/utils/types.h index afa6853..57fb509 100644 --- a/bdk/utils/types.h +++ b/bdk/utils/types.h @@ -83,7 +83,6 @@ typedef int bool; #define BOOT_CFG_FROM_LAUNCH BIT(1) #define BOOT_CFG_FROM_ID BIT(2) #define BOOT_CFG_TO_EMUMMC BIT(3) -#define BOOT_CFG_SEPT_RUN BIT(7) #define EXTRA_CFG_DUMP_EMUMMC BIT(0) diff --git a/keygen/tsec_keygen b/keygen/tsec_keygen new file mode 100644 index 0000000..b27cdaf Binary files /dev/null and b/keygen/tsec_keygen differ diff --git a/source/config.c b/source/config.c index 55bd64e..526eb55 100644 --- a/source/config.c +++ b/source/config.c @@ -46,7 +46,6 @@ void set_default_configuration() h_cfg.bootprotect = 0; h_cfg.errors = 0; h_cfg.eks = NULL; - h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; h_cfg.aes_slots_new = false; h_cfg.rcm_patched = fuse_check_patched_rcm(); h_cfg.sbk_set = FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF; diff --git a/source/config.h b/source/config.h index 9a69d19..bfb0b3b 100644 --- a/source/config.h +++ b/source/config.h @@ -34,7 +34,6 @@ typedef struct _hekate_config // Global temporary config. bool t210b01; bool se_keygen_done; - bool sept_run; bool aes_slots_new; bool emummc_force_disable; bool rcm_patched; diff --git a/source/hos/fss.c b/source/hos/fss.c deleted file mode 100644 index 1521d82..0000000 --- a/source/hos/fss.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Atmosphère Fusée Secondary Storage parser. - * - * Copyright (c) 2019-2020 CTCaer - * - * 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 "fss.h" -#include "hos.h" -#include "../config.h" -#include -#include -#include "../storage/emummc.h" -#include - -#include -#define DPRINTF(...) - -extern hekate_config h_cfg; - -extern bool is_ipl_updated(void *buf, char *path, bool force); - -// FSS0 Magic and Meta header offset. -#define FSS0_MAGIC 0x30535346 -#define FSS0_META_OFFSET 0x4 -#define FSS0_VERSION_0_17_0 0x110000 - -// FSS0 Content Types. -#define CNT_TYPE_FSP 0 -#define CNT_TYPE_EXO 1 // Exosphere (Secure Monitor). -#define CNT_TYPE_WBT 2 // Warmboot (SC7Exit fw). -#define CNT_TYPE_RBT 3 // Rebootstub (Warmboot based reboot fw). -#define CNT_TYPE_SP1 4 // Sept Primary (TSEC and Sept Secondary loader). -#define CNT_TYPE_SP2 5 // Sept Secondary (Acts as pkg11 and derives keys). -#define CNT_TYPE_KIP 6 // KIP1 (Used for replacement or addition). -#define CNT_TYPE_BMP 7 -#define CNT_TYPE_EMC 8 -#define CNT_TYPE_KLD 9 // Kernel Loader. -#define CNT_TYPE_KRN 10 // Kernel. -#define CNT_TYPE_EXF 11 // Exosphere Mariko fatal payload. - -// FSS0 Content Flags. -#define CNT_FLAG0_EXPERIMENTAL BIT(0) - -// FSS0 Meta Header. -typedef struct _fss_meta_t -{ - u32 magic; - u32 size; - u32 crt0_off; - u32 cnt_off; - u32 cnt_count; - u32 hos_ver; - u32 version; - u32 git_rev; -} fss_meta_t; - -// FSS0 Content Header. -typedef struct _fss_content_t -{ - u32 offset; - u32 size; - u8 type; - u8 flags0; - u8 flags1; - u8 flags2; - u32 rsvd1; - char name[0x10]; -} fss_content_t; - -int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt) -{ - FIL fp; - - bool stock = false; - int sept_used = 0; - - // Skip if stock and Exosphere and warmboot are not needed. - if (!sept_ctxt) - { - bool pkg1_old = ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620; - bool emummc_disabled = !emu_cfg.enabled || h_cfg.emummc_force_disable; - - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link) - { - if (!strcmp("stock", kv->key)) - if (kv->val[0] == '1') - stock = true; - } - -#ifdef HOS_MARIKO_STOCK_SECMON - if (stock && emummc_disabled && (pkg1_old || h_cfg.t210b01)) -#else - if (stock && emummc_disabled && pkg1_old) -#endif - return 1; - } - - if (f_open(&fp, path, FA_READ) != FR_OK) - return 0; - - void *fss = malloc(f_size(&fp)); - - // Read first 1024 bytes of the fss file. - f_read(&fp, fss, 1024, NULL); - - // Get FSS0 Meta header offset. - u32 fss_meta_addr = *(u32 *)(fss + FSS0_META_OFFSET); - fss_meta_t *fss_meta = (fss_meta_t *)(fss + fss_meta_addr); - - // Check if valid FSS0 and parse it. - if (fss_meta->magic == FSS0_MAGIC) - { - bool mariko_not_supported = false; - if (h_cfg.t210b01 && (fss_meta->version < FSS0_VERSION_0_17_0)) - { - gfx_con.mute = false; - mariko_not_supported = true; - } - - gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n" - "Max HOS supported: %d.%d.%d\n" - "Unpacking and loading components.. ", - fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev, - fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF); - - if (mariko_not_supported) - { - EPRINTF("\nMariko not supported on < 0.17.0!"); - goto fail; - } - - if (!sept_ctxt) - { - ctxt->atmosphere = true; - ctxt->fss0_hosver = fss_meta->hos_ver; - } - - // Parse FSS0 contents. - fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off); - void *content; - for (u32 i = 0; i < fss_meta->cnt_count; i++) - { - content = (void *)(fss + curr_fss_cnt[i].offset); - - // Check if offset is inside limits. - if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size) - continue; - - // If content is experimental and experimental flag is not enabled, skip it. - if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_experimental) - continue; - - // Parse content. - if (!sept_ctxt) - { - // Prepare content context. - switch (curr_fss_cnt[i].type) - { - case CNT_TYPE_KIP: - if (stock) - continue; - merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t)); - mkip1->kip1 = content; - list_append(&ctxt->kip1_list, &mkip1->link); - DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size); - break; - - case CNT_TYPE_KRN: - if (stock) - continue; - ctxt->kernel_size = curr_fss_cnt[i].size; - ctxt->kernel = content; - break; - - case CNT_TYPE_EXO: - ctxt->secmon_size = curr_fss_cnt[i].size; - ctxt->secmon = content; - break; - - case CNT_TYPE_EXF: - ctxt->exofatal_size = curr_fss_cnt[i].size; - ctxt->exofatal = content; - break; - - case CNT_TYPE_WBT: - if (h_cfg.t210b01) - continue; - ctxt->warmboot_size = curr_fss_cnt[i].size; - ctxt->warmboot = content; - break; - - default: - continue; - } - - // Load content to launch context. - f_lseek(&fp, curr_fss_cnt[i].offset); - f_read(&fp, content, curr_fss_cnt[i].size, NULL); - } - else - { - // Load sept content directly to launch context. - switch (curr_fss_cnt[i].type) - { - case CNT_TYPE_SP1: - f_lseek(&fp, curr_fss_cnt[i].offset); - f_read(&fp, sept_ctxt->sept_primary, curr_fss_cnt[i].size, NULL); - break; - case CNT_TYPE_SP2: - if (!memcmp(curr_fss_cnt[i].name, (sept_ctxt->kb < KB_FIRMWARE_VERSION_810) ? "septsecondary00" : "septsecondary01", 15)) - { - f_lseek(&fp, curr_fss_cnt[i].offset); - f_read(&fp, sept_ctxt->sept_secondary, curr_fss_cnt[i].size, NULL); - sept_used = 1; - goto out; - } - break; - default: - break; - } - } - } - -out: - gfx_printf("Done!\n"); - f_close(&fp); - - return (!sept_ctxt ? 1 : sept_used); - } - -fail: - f_close(&fp); - free(fss); - - return 0; -} - -int load_sept_from_ffs0(fss0_sept_t *sept_ctxt) -{ - LIST_FOREACH_ENTRY(ini_kv_t, kv, &sept_ctxt->cfg_sec->kvs, link) - { - if (!strcmp("fss0", kv->key)) - return parse_fss(NULL, kv->val, sept_ctxt); - } - - return 0; -} diff --git a/source/hos/fss.h b/source/hos/fss.h deleted file mode 100644 index 3f56d7c..0000000 --- a/source/hos/fss.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019 CTCaer - * - * 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 _FSS_H_ -#define _FSS_H_ - -#include "hos.h" - -typedef struct _fss0_sept_t -{ - u32 kb; - ini_sec_t *cfg_sec; - void *sept_primary; - void *sept_secondary; - -} fss0_sept_t; - -int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt); -int load_sept_from_ffs0(fss0_sept_t *sept_ctxt); - -#endif diff --git a/source/hos/sept.c b/source/hos/sept.c deleted file mode 100644 index 873b7ab..0000000 --- a/source/hos/sept.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2019 CTCaer - * - * 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 "hos.h" -#include "fss.h" -#include "sept.h" -#include "../config.h" -#include -#include -#include -#include -#include -#include -#include -#include "../storage/nx_emmc.h" -#include -#include -#include -#include -#include - -#include - -#define PATCHED_RELOC_SZ 0x94 - -#define WB_RST_ADDR 0x40010ED0 -#define WB_RST_SIZE 0x30 - -u8 warmboot_reboot[] = { - 0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450 - 0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1 - 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400 - 0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10 - 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] - 0xFE, 0xFF, 0xFF, 0xEA, // LOOP - 0x50, 0xE4, 0x00, 0x70, // #0x7000E450 - 0x00, 0xE4, 0x00, 0x70 // #0x7000E400 -}; - -#define SEPT_PRI_ADDR 0x4003F000 - -#define SEPT_PK1T_ADDR 0xC0400000 -#define SEPT_PK1T_STACK 0x40008000 -#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4) -#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100) -#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) -#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) - -extern u32 color_idx; -extern boot_cfg_t b_cfg; -extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); - -int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb) -{ - FIL fp; - bool fss0_sept_used = false; - - // Copy warmboot reboot code and TSEC fw. - memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); - memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size); - *(vu32 *)SEPT_TCSZ_ADDR = tsec_size; - - LIST_INIT(ini_sections); - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) - { - bool found = false; - LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) - { - // Only parse non config sections. - if (ini_sec->type == INI_CHOICE && strcmp(ini_sec->name, "config")) - { - LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) - { - if (!strcmp("fss0", kv->key)) - { - fss0_sept_t sept_ctxt; - sept_ctxt.kb = kb; - sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR; - sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR; - fss0_sept_used = parse_fss(NULL, kv->val, &sept_ctxt); - - found = true; - break; - } - } - } - if (found) - break; - } - } - - if (!fss0_sept_used) - { - // Copy sept-primary. - if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ)) - goto error; - - if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; - } - f_close(&fp); - - // Copy sept-secondary. - if (kb < KB_FIRMWARE_VERSION_810) - { - if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ)) - if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. - goto error; - } - else - { - if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ)) - goto error; - } - - if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) - { - f_close(&fp); - goto error; - } - f_close(&fp); - } - - // Save auto boot config to sept payload, if any. - boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); - memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t)); - - tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN; - - if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) - { - free(tmp_cfg); - goto error; - } - - f_lseek(&fp, PATCHED_RELOC_SZ); - f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); - - f_close(&fp); - - sd_unmount(); - - u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); - - void (*sept)() = (void *)pk1t_sept; - - reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ); - - // Patch SDRAM init to perform an SVC immediately after second write. - PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF; - PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28; - // Set SVC handler to jump to sept-primary in IRAM. - PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR; - PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208; - - hw_reinit_workaround(false, 0); - - (*sept)(); - -error: - EPRINTF("\nSept files not found in sd:/sept!\nPlace appropriate files and try again."); - display_backlight_brightness(100, 1000); - - btn_wait(); - - return 0; -} \ No newline at end of file diff --git a/source/hos/sept.h b/source/hos/sept.h deleted file mode 100644 index 086d50d..0000000 --- a/source/hos/sept.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2019 CTCaer - * - * 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_H_ -#define _SEPT_H_ - -#include - -int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb); - -#endif diff --git a/source/keys/key_sources.inl b/source/keys/key_sources.inl index 2dd52c2..dab8a4b 100644 --- a/source/keys/key_sources.inl +++ b/source/keys/key_sources.inl @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -19,7 +19,7 @@ static const u8 null_hash[0x20] __attribute__((aligned(4))) = { 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; -static const u8 keyblob_key_source[][0x10] __attribute__((aligned(4))) = { +static const u8 keyblob_key_sources[][0x10] __attribute__((aligned(4))) = { {0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3}, //1.0.0 {0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC}, //3.0.0 {0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B}, //3.0.1 @@ -146,7 +146,7 @@ static const u8 aes_key_generation_source[0x10] __attribute__((aligned(4))) = { // from FS static const u8 bis_kek_source[0x10] __attribute__((aligned(4))) = { 0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}; -static const u8 bis_key_source[3][0x20] __attribute__((aligned(4))) = { +static const u8 bis_key_sources[3][0x20] __attribute__((aligned(4))) = { {0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48, 0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}, {0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F, diff --git a/source/keys/keys.c b/source/keys/keys.c index 4bc24d7..765ac5a 100644 --- a/source/keys/keys.c +++ b/source/keys/keys.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,17 +16,17 @@ #include "keys.h" +#include "../../keygen/tsec_keygen.h" + #include "../config.h" #include #include #include "../gfx/tui.h" #include "../hos/pkg1.h" #include "../hos/pkg2.h" -#include "../hos/sept.h" #include #include #include -#include #include #include #include @@ -122,108 +122,6 @@ static u8 *_read_pkg1(const pkg1_id_t **pkg1_id) { return pkg1; } -#define RELOC_META_OFF 0x7C - -static bool _handle_sept(void *tsec_fw, u32 tsec_size, u32 kb, void *out_key) { - sd_mount(); - if (!f_stat("sd:/sept/payload.bak", NULL)) { - f_unlink("sd:/sept/payload.bin"); - f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin"); - } - - if (!h_cfg.sept_run) { - // bundle lp0 fw for sept instead of loading it from SD as hekate does - sdram_lp0_save_params(sdram_get_params_patched()); - - FIL fp; - if (f_stat("sd:/sept", NULL)) { - EPRINTF("On firmware 7.x+ but Sept missing.\nSkipping new key derivation..."); - return true; - } - // backup post-reboot payload - if (!f_stat("sd:/sept/payload.bin", NULL)) { - if (f_rename("sd:/sept/payload.bin", "sd:/sept/payload.bak")) { - EPRINTF("Unable to backup payload.bin."); - return false; - } - } - // write self to payload.bin to run again when sept finishes - volatile reloc_meta_t *relocator = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF); - u32 payload_size = relocator->end - IPL_LOAD_ADDR; - if (f_open(&fp, "sd:/sept/payload.bin", FA_CREATE_NEW | FA_WRITE)) { - EPRINTF("Unable to write self to /sept/payload.bin."); - return false; - } - gfx_printf("%kWrite self to /sept/payload.bin...", colors[(color_idx++) % 6]); - if (f_write(&fp, (u8 *)IPL_LOAD_ADDR, payload_size, NULL)) { - EPRINTF("Unable to write self to /sept/payload.bin."); - f_close(&fp); - return false; - } - gfx_printf(" done"); - f_close(&fp); - gfx_printf("%k\nRebooting to sept...\n\n", colors[(color_idx++) % 6]); - sdmmc_storage_end(&emmc_storage); - if (!reboot_to_sept((u8 *)tsec_fw, tsec_size, kb)) { - return false; - } - } else { - se_aes_key_get(se_key_acc_ctrl_get(12) == 0x6A ? 13 : 12, out_key, AES_128_KEY_SIZE); - } - - return true; -} - -static bool _derive_tsec_keys(tsec_ctxt_t *tsec_ctxt, u32 kb, key_derivation_ctx_t *keys) { - tsec_ctxt->fw = _find_tsec_fw(tsec_ctxt->pkg1); - if (!tsec_ctxt->fw) { - EPRINTF("Unable to locate TSEC firmware."); - return false; - } - - minerva_periodic_training(); - - tsec_ctxt->size = _get_tsec_fw_size((tsec_key_data_t *)(tsec_ctxt->fw + TSEC_KEY_DATA_OFFSET)); - if (tsec_ctxt->size > PKG1_MAX_SIZE) { - EPRINTF("Unexpected TSEC firmware size."); - return false; - } - - if (kb >= KB_FIRMWARE_VERSION_700) { - if (!_handle_sept(tsec_ctxt->fw, tsec_ctxt->size, kb, keys->master_key[KB_FIRMWARE_VERSION_MAX])) { - return false; - } - } else if (kb == KB_FIRMWARE_VERSION_620) { - u8 *tsec_paged = (u8 *)page_alloc(3); - memcpy(tsec_paged, tsec_ctxt->fw, tsec_ctxt->size); - tsec_ctxt->fw = tsec_paged; - } - - int res = 0; - u32 retries = 0; - - // mc_disable_ahb_redirect(); - - while (tsec_query(keys->tsec_keys, kb, tsec_ctxt) < 0) { - memset(keys->tsec_keys, 0, sizeof(keys->tsec_keys)); - retries++; - if (retries > 15) { - res = -1; - break; - } - } - - // mc_enable_ahb_redirect(); - - if (res < 0) { - EPRINTFARGS("ERROR %x dumping TSEC.\n", res); - return false; - } - - TPRINTFARGS("%kTSEC key(s)... ", colors[(color_idx++) % 6]); - return true; -} - static void _derive_master_key_mariko(key_derivation_ctx_t *keys) { // Relies on the SBK being properly set in slot 14 se_aes_crypt_block_ecb(14, 0, keys->device_key_4x, device_master_key_source_kek_source); @@ -232,39 +130,41 @@ static void _derive_master_key_mariko(key_derivation_ctx_t *keys) { se_aes_crypt_block_ecb(8, 0, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source); } -static void _derive_master_keys_post_620(u32 pkg1_kb, key_derivation_ctx_t *keys) { - // on firmware 6.2.0 only, the tsec_root_key is available - if (pkg1_kb == KB_FIRMWARE_VERSION_620 && _key_exists(keys->tsec_keys + AES_128_KEY_SIZE)) { - se_aes_key_set(8, keys->tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE); // mkek6 = unwrap(mkeks6, tsecroot) - se_aes_crypt_block_ecb(8, 0, keys->master_kek[6], master_kek_sources[0]); - se_aes_key_set(8, keys->master_kek[6], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mks) - se_aes_crypt_block_ecb(8, 0, keys->master_key[6], master_key_source); +static int _run_ams_keygen(key_derivation_ctx_t *keys) { + tsec_ctxt_t tsec_ctxt; + tsec_ctxt.fw = tsec_keygen; + tsec_ctxt.size = sizeof(tsec_keygen); + int res = tsec_run_fw(&tsec_ctxt); + + if (res) { + EPRINTFARGS("ERROR %d running keygen.\n", res); } - if (pkg1_kb >= KB_FIRMWARE_VERSION_620) { - // derive all lower master keys in case keyblobs are bad - // handle sept version differences - for (u32 kb = pkg1_kb == KB_FIRMWARE_VERSION_620 ? KB_FIRMWARE_VERSION_620 : KB_FIRMWARE_VERSION_MAX; kb >= KB_FIRMWARE_VERSION_620; kb--) { - for (u32 i = kb; i > 0; i--) { - se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], master_key_vectors[i]); - } - se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE); - se_aes_crypt_block_ecb(8, 0, keys->temp_key, master_key_vectors[0]); - if (!_key_exists(keys->temp_key)) { - break; - } - memcpy(keys->master_key[kb - 1], keys->master_key[kb], AES_128_KEY_SIZE); - memset(keys->master_key[kb], 0, AES_128_KEY_SIZE); - } - if (_key_exists(keys->temp_key)) { - EPRINTFARGS("Unable to derive master key. kb = %d.", pkg1_kb); - memset(keys->master_key, 0, sizeof(keys->master_key)); - } + return res; +} + +static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys) { + if (!h_cfg.t210b01) { + se_aes_crypt_block_ecb(13, 0, keys->master_kek[KB_FIRMWARE_VERSION_MAX], master_kek_sources[KB_FIRMWARE_VERSION_MAX - KB_FIRMWARE_VERSION_620]); // mkek = unwrap(tsec_root, mkeks) + se_aes_key_set(8, keys->master_kek[KB_FIRMWARE_VERSION_MAX], AES_128_KEY_SIZE); // mkey = unwrap(mkek, mkeys) + se_aes_crypt_block_ecb(8, 0, keys->master_key[KB_FIRMWARE_VERSION_MAX], master_key_source); + } + + // Derive all lower master keys + for (u32 i = KB_FIRMWARE_VERSION_MAX; i > 0; i--) { + se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE); + se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], master_key_vectors[i]); + } + se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE); + se_aes_crypt_block_ecb(8, 0, keys->temp_key, master_key_vectors[0]); + + if (_key_exists(keys->temp_key)) { + EPRINTF("Unable to derive master key."); + memset(keys->master_key, 0, sizeof(keys->master_key)); } } -static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { +static void _derive_keyblob_keys(key_derivation_ctx_t *keys) { u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE); encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; u32 keyblob_mac[AES_128_KEY_SIZE / 4] = {0}; @@ -281,15 +181,13 @@ static void _derive_master_keys_from_keyblobs(key_derivation_ctx_t *keys) { keys->sbk[3] = FUSE(FUSE_PRIVATE_KEY3); } - se_aes_key_set(8, keys->tsec_keys, sizeof(keys->tsec_keys) / 2); - if (!emummc_storage_read(KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) { EPRINTF("Unable to read keyblobs."); } for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { minerva_periodic_training(); - se_aes_crypt_block_ecb(8, 0, keys->keyblob_key[i], keyblob_key_source[i]); // temp = unwrap(kbks, tsec) + se_aes_crypt_block_ecb(12, 0, keys->keyblob_key[i], keyblob_key_sources[i]); // temp = unwrap(kbks, tsec) se_aes_crypt_block_ecb(14, 0, keys->keyblob_key[i], keys->keyblob_key[i]); // kbk = unwrap(temp, sbk) se_aes_key_set(7, keys->keyblob_key[i], sizeof(keys->keyblob_key[i])); se_aes_crypt_block_ecb(7, 0, keys->keyblob_mac_key[i], keyblob_mac_key_source); // kbm = unwrap(kbms, kbk) @@ -335,18 +233,18 @@ static void _derive_bis_keys(key_derivation_ctx_t *keys) { _get_device_key(8, keys->temp_key, key_generation, keys->device_key, keys->device_key_4x, keys->master_key[0]); se_aes_key_set(8, keys->temp_key, AES_128_KEY_SIZE); se_aes_unwrap_key(8, 8, retail_specific_aes_key_source); // kek = unwrap(rsaks, devkey) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x00, bis_key_source[0] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x10, bis_key_source[0] + 0x10); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x00, bis_key_sources[0] + 0x00); // bkey = unwrap(bkeys, kek) + se_aes_crypt_block_ecb(8, 0, keys->bis_key[0] + 0x10, bis_key_sources[0] + 0x10); // kek = generate_kek(bkeks, devkey, aeskek, aeskey) _generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x00, bis_key_source[1] + 0x00); // bkey = unwrap(bkeys, kek) - se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x10, bis_key_source[1] + 0x10); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x00, bis_key_source[2] + 0x00); - se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x10, bis_key_source[2] + 0x10); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x00, bis_key_sources[1] + 0x00); // bkey = unwrap(bkeys, kek) + se_aes_crypt_block_ecb(8, 0, keys->bis_key[1] + 0x10, bis_key_sources[1] + 0x10); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x00, bis_key_sources[2] + 0x00); + se_aes_crypt_block_ecb(8, 0, keys->bis_key[2] + 0x10, bis_key_sources[2] + 0x10); memcpy(keys->bis_key[3], keys->bis_key[2], 0x20); } -static void _derive_misc_keys(key_derivation_ctx_t *keys, u32 *derivable_key_count) { +static void _derive_misc_keys(key_derivation_ctx_t *keys) { if (_key_exists(keys->master_key[0])) { _generate_kek(8, header_kek_source, keys->master_key[0], aes_kek_generation_source, aes_key_generation_source); se_aes_crypt_block_ecb(8, 0, keys->header_key + 0x00, header_key_source + 0x00); @@ -359,10 +257,7 @@ static void _derive_misc_keys(key_derivation_ctx_t *keys, u32 *derivable_key_cou se_aes_crypt_block_ecb(8, 0, keys->save_mac_key, save_mac_key_source); } - if (_key_exists(keys->master_key[*derivable_key_count])) { - *derivable_key_count = KB_FIRMWARE_VERSION_MAX + 1; - } - for (u32 i = 0; i < *derivable_key_count; i++) { + for (u32 i = 0; i < KB_FIRMWARE_VERSION_MAX + 1; i++) { if (!_key_exists(keys->master_key[i])) continue; for (u32 j = 0; j < 3; j++) { @@ -666,7 +561,9 @@ static bool _derive_emmc_keys(key_derivation_ctx_t *keys, titlekey_buffer_t *tit return false; } - if (!_derive_sd_seed(keys)) { + if (!sd_mount()) { + EPRINTF("Unable to mount SD."); + } else if (!_derive_sd_seed(keys)) { EPRINTF("Unable to get SD seed."); } @@ -757,7 +654,7 @@ static void _save_mariko_partial_keys(u32 start, u32 count, bool append) { free(text_buffer); } -static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time, u32 derivable_key_count) { +static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titlekey_buffer, const pkg1_id_t *pkg1_id, u32 start_whole_operation_time) { char *text_buffer = NULL; if (!sd_mount()) { EPRINTF("Unable to mount SD."); @@ -771,7 +668,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(aes_key_generation_source); SAVE_KEY(bis_kek_source); SAVE_KEY_FAMILY_VAR(bis_key, keys->bis_key, 0); - SAVE_KEY_FAMILY(bis_key_source, 0); + SAVE_KEY_FAMILY(bis_key_sources, 0); SAVE_KEY_VAR(device_key, keys->device_key); SAVE_KEY_VAR(device_key_4x, keys->device_key_4x); SAVE_KEY_VAR(eticket_rsa_kek, keys->eticket_rsa_kek); @@ -789,7 +686,7 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY_VAR(key_area_key_system_source, key_area_key_sources[2]); SAVE_KEY_FAMILY_VAR(keyblob, keys->keyblob, 0); SAVE_KEY_FAMILY_VAR(keyblob_key, keys->keyblob_key, 0); - SAVE_KEY_FAMILY(keyblob_key_source, 0); + SAVE_KEY_FAMILY(keyblob_key_sources, 0); SAVE_KEY_FAMILY_VAR(keyblob_mac_key, keys->keyblob_mac_key, 0); SAVE_KEY(keyblob_mac_key_source); SAVE_KEY_FAMILY_VAR(master_kek, keys->master_kek, 0); @@ -823,18 +720,24 @@ static void _save_keys_to_sd(key_derivation_ctx_t *keys, titlekey_buffer_t *titl SAVE_KEY(ssl_rsa_kek_source_y); SAVE_KEY_FAMILY_VAR(titlekek, keys->titlekek, 0); SAVE_KEY(titlekek_source); - _save_key("tsec_key", keys->tsec_keys, AES_128_KEY_SIZE, text_buffer); - if (pkg1_id->kb == KB_FIRMWARE_VERSION_620) - _save_key("tsec_root_key", keys->tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE, text_buffer); + SAVE_KEY_VAR(tsec_key, keys->tsec_key); + + const u32 root_key_ver = 2; + char root_key_name[21] = "tsec_root_key_00"; + s_printf(root_key_name + 14, "%02x", root_key_ver); + _save_key(root_key_name, keys->tsec_root_key, AES_128_KEY_SIZE, text_buffer); + + s_printf(root_key_name + 14, "dev_%02x", root_key_ver); + _save_key(root_key_name, keys->tsec_root_key_dev, AES_128_KEY_SIZE, text_buffer); end_time = get_tmr_us(); gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); gfx_printf("%kLockpick totally done in %d us\n\n", colors[(color_idx++) % 6], end_time - start_whole_operation_time); - gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], derivable_key_count - 1); + gfx_printf("%kFound through master_key_%02x.\n\n", colors[(color_idx++) % 6], KB_FIRMWARE_VERSION_MAX); f_mkdir("sd:/switch"); char keyfile_path[30] = "sd:/switch/prod.keys"; - if (fuse_read_odm(4) & 3) + if (fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV) s_printf(&keyfile_path[11], "dev.keys"); FILINFO fno; @@ -902,28 +805,30 @@ static void _derive_keys() { if (!pkg1) { return; } - - u32 derivable_key_count = pkg1_id->kb >= KB_FIRMWARE_VERSION_620 ? pkg1_id->kb + 1 : 6; - bool res = true; - key_derivation_ctx_t __attribute__((aligned(4))) keys = {0}; - - if (!h_cfg.t210b01) { - tsec_ctxt_t tsec_ctxt; - tsec_ctxt.pkg1 = pkg1; - res =_derive_tsec_keys(&tsec_ctxt, pkg1_id->kb, &keys); - } free(pkg1); - if (res == false) { - return; - } + + key_derivation_ctx_t __attribute__((aligned(4))) keys = {0}; // Master key derivation if (h_cfg.t210b01) { _derive_master_key_mariko(&keys); - _derive_master_keys_post_620(KB_FIRMWARE_VERSION_MAX, &keys); + _derive_master_keys_from_latest_key(&keys); } else { - _derive_master_keys_post_620(pkg1_id->kb, &keys); - _derive_master_keys_from_keyblobs(&keys); + int res = _run_ams_keygen(&keys); + if (res) { + EPRINTF("Unable to run keygen."); + return; + } + + u8 *aes_keys = (u8 *)calloc(0x1000, 1); + se_get_aes_keys(aes_keys + 0x800, aes_keys, AES_128_KEY_SIZE); + memcpy(&keys.tsec_root_key_dev, aes_keys + 11 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(&keys.tsec_key, aes_keys + 12 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + memcpy(&keys.tsec_root_key, aes_keys + 13 * AES_128_KEY_SIZE, AES_128_KEY_SIZE); + free(aes_keys); + + _derive_master_keys_from_latest_key(&keys); + _derive_keyblob_keys(&keys); } TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]); @@ -932,7 +837,7 @@ static void _derive_keys() { TPRINTFARGS("%kBIS keys... ", colors[(color_idx++) % 6]); - _derive_misc_keys(&keys, &derivable_key_count); + _derive_misc_keys(&keys); titlekey_buffer_t *titlekey_buffer = (titlekey_buffer_t *)TITLEKEY_BUF_ADR; @@ -943,7 +848,7 @@ static void _derive_keys() { EPRINTF("Missing needed BIS keys.\nSkipping SD seed and titlekeys."); } - _save_keys_to_sd(&keys, titlekey_buffer, pkg1_id, start_whole_operation_time, derivable_key_count); + _save_keys_to_sd(&keys, titlekey_buffer, pkg1_id, start_whole_operation_time); } void dump_keys() { diff --git a/source/keys/keys.h b/source/keys/keys.h index b3018a5..32d7fb6 100644 --- a/source/keys/keys.h +++ b/source/keys/keys.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 shchmue + * Copyright (c) 2019-2021 shchmue * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -108,7 +108,9 @@ typedef struct { master_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], package2_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], titlekek[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE], - tsec_keys[AES_128_KEY_SIZE * 2]; + tsec_key[AES_128_KEY_SIZE], + tsec_root_key[AES_128_KEY_SIZE], + tsec_root_key_dev[AES_128_KEY_SIZE]; u32 sbk[4]; keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; } key_derivation_ctx_t; @@ -137,9 +139,9 @@ typedef struct { // save key with different name than variable #define SAVE_KEY_VAR(name, varname) _save_key(#name, varname, sizeof(varname), text_buffer) // save key family wrapper -#define SAVE_KEY_FAMILY(name, start) _save_key_family(#name, name, start, sizeof(name) / sizeof(name[0]), sizeof(name[0]), text_buffer) +#define SAVE_KEY_FAMILY(name, start) _save_key_family(#name, name, start, ARRAY_SIZE(name), sizeof(*(name)), text_buffer) // save key family with different name than variable -#define SAVE_KEY_FAMILY_VAR(name, varname, start) _save_key_family(#name, varname, start, sizeof(varname) / sizeof(varname[0]), sizeof(varname[0]), text_buffer) +#define SAVE_KEY_FAMILY_VAR(name, varname, start) _save_key_family(#name, varname, start, ARRAY_SIZE(varname), sizeof(*(varname)), text_buffer) void dump_keys(); diff --git a/source/main.c b/source/main.c index deee446..1eea1fb 100644 --- a/source/main.c +++ b/source/main.c @@ -395,15 +395,6 @@ void ipl_main() h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; emu_cfg.enabled = !h_cfg.emummc_force_disable; - if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN) - { - if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC)) { - h_cfg.emummc_force_disable = true; - emu_cfg.enabled = false; - } - dump_keys(); - } - // Grey out emummc option if not present. if (h_cfg.emummc_force_disable) {