Use Atmosphere keygen, deprecate sept support

This commit is contained in:
shchmue 2021-08-24 17:44:25 -06:00
parent d84ab5796a
commit 38fff7127b
20 changed files with 141 additions and 839 deletions

1
.gitignore vendored
View File

@ -6,4 +6,5 @@ research/*
loader/payload_00.h loader/payload_00.h
loader/payload_01.h loader/payload_01.h
tools/bin2c/bin2c tools/bin2c/bin2c
keygen/tsec_keygen.h
tools/lz/lz77 tools/lz/lz77

View File

@ -16,9 +16,12 @@ include ./Versions.inc
TARGET := Lockpick_RCM TARGET := Lockpick_RCM
BUILDDIR := build BUILDDIR := build
OUTPUTDIR := output OUTPUTDIR := output
SOURCEDIR = source SOURCEDIR := source
BDKDIR := bdk BDKDIR := bdk
BDKINC := -I./$(BDKDIR) BDKINC := -I./$(BDKDIR)
KEYGENDIR := keygen
KEYGEN := tsec_keygen
KEYGENH := tsec_keygen.h
VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/)) VPATH = $(dir ./$(SOURCEDIR)/) $(dir $(wildcard ./$(SOURCEDIR)/*/)) $(dir $(wildcard ./$(SOURCEDIR)/*/*/))
VPATH += $(dir $(wildcard ./$(BDKDIR)/)) $(dir $(wildcard ./$(BDKDIR)/*/)) $(dir $(wildcard ./$(BDKDIR)/*/*/)) 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 $@ @$(CC) $(LDFLAGS) -T $(SOURCEDIR)/link.ld $^ -o $@
@echo "Lockpick_RCM was built with the following flags:\nCFLAGS: "$(CFLAGS)"\nLDFLAGS: "$(LDFLAGS) @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 $(BUILDDIR)/$(TARGET)/%.o: $(SOURCEDIR)/%.c
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
@echo Building $@ @echo Building $@

View File

@ -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` * 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 * 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 * 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 Mariko-Specific Keys
= =

View File

@ -66,8 +66,6 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
{ {
int res = 0; int res = 0;
u8 *fwbuf = NULL; u8 *fwbuf = NULL;
u32 *pdir, *car, *fuse, *pmc, *flowctrl, *se, *mc, *iram, *evec;
u32 *pkg11_magic_off;
bpmp_mmu_disable(); bpmp_mmu_disable();
bpmp_freq_t prev_fid = bpmp_clk_rate_set(BPMP_CLK_NORMAL); 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. //Execute firmware.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA; HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
TSEC(TSEC_STATUS) = 0; TSEC(TSEC_STATUS) = 0;
@ -187,65 +130,13 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
TSEC(TSEC_BOOTVEC) = 0; TSEC(TSEC_BOOTVEC) = 0;
TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU; TSEC(TSEC_CPUCTL) = TSEC_CPUCTL_STARTCPU;
if (kb == KB_TSEC_FW_EMU_COMPAT)
{
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)
{
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();
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_dma_wait_idle()) if (!_tsec_dma_wait_idle())
{ {
res = -3; res = -3;
goto out_free; goto out_free;
} }
u32 timeout = get_tmr_ms() + 2000; u32 timeout = get_tmr_ms() + 4000;
while (!TSEC(TSEC_STATUS)) while (!(TSEC(TSEC_CPUCTL) & TSEC_CPUCTL_KEYGEN_DONE))
if (get_tmr_ms() > timeout) if (get_tmr_ms() > timeout)
{ {
res = -4; res = -4;
@ -259,18 +150,6 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
//Fetch result. //Fetch result.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0; 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);
}
out_free:; out_free:;
free(fwbuf); free(fwbuf);
@ -288,3 +167,26 @@ out:;
return res; 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;
}

View File

@ -24,7 +24,7 @@
typedef struct _tsec_ctxt_t typedef struct _tsec_ctxt_t
{ {
void *fw; const void *fw;
u32 size; u32 size;
void *pkg1; void *pkg1;
} tsec_ctxt_t; } tsec_ctxt_t;
@ -47,5 +47,6 @@ typedef struct _tsec_key_data_t
} tsec_key_data_t; } tsec_key_data_t;
int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt); int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt);
int tsec_run_fw(tsec_ctxt_t *tsec_ctxt);
#endif #endif

View File

@ -37,6 +37,7 @@
#define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8) #define TSEC_IRQDEST_EXT(val) (((val) & 0xFF) << 8)
#define TSEC_CPUCTL 0x1100 #define TSEC_CPUCTL 0x1100
#define TSEC_CPUCTL_STARTCPU BIT(1) #define TSEC_CPUCTL_STARTCPU BIT(1)
#define TSEC_CPUCTL_KEYGEN_DONE BIT(4)
#define TSEC_BOOTVEC 0x1104 #define TSEC_BOOTVEC 0x1104
#define TSEC_DMACTL 0x110C #define TSEC_DMACTL 0x110C
#define TSEC_DMATRFBASE 0x1110 #define TSEC_DMATRFBASE 0x1110

View File

@ -253,9 +253,8 @@ static void _config_se_brom()
// Enable fuse clock. // Enable fuse clock.
clock_enable_fuse(true); clock_enable_fuse(true);
// Skip SBK/SSK if sept was run. // Skip SBK/SSK if running on patched Erista.
bool sbk_skip = b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN || FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF; if (!(FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF))
if (!sbk_skip)
{ {
// Bootrom part we skipped. // Bootrom part we skipped.
u32 sbk[4] = { u32 sbk[4] = {

View File

@ -281,7 +281,6 @@
/*! Special registers. */ /*! Special registers. */
#define EMC_SCRATCH0 0x324 #define EMC_SCRATCH0 0x324
#define EMC_HEKA_UPD BIT(30) #define EMC_HEKA_UPD BIT(30)
#define EMC_SEPT_RUN BIT(31)
/*! Flow controller registers. */ /*! Flow controller registers. */
#define FLOW_CTLR_HALT_COP_EVENTS 0x4 #define FLOW_CTLR_HALT_COP_EVENTS 0x4

View File

@ -83,7 +83,6 @@ typedef int bool;
#define BOOT_CFG_FROM_LAUNCH BIT(1) #define BOOT_CFG_FROM_LAUNCH BIT(1)
#define BOOT_CFG_FROM_ID BIT(2) #define BOOT_CFG_FROM_ID BIT(2)
#define BOOT_CFG_TO_EMUMMC BIT(3) #define BOOT_CFG_TO_EMUMMC BIT(3)
#define BOOT_CFG_SEPT_RUN BIT(7)
#define EXTRA_CFG_DUMP_EMUMMC BIT(0) #define EXTRA_CFG_DUMP_EMUMMC BIT(0)

BIN
keygen/tsec_keygen Normal file

Binary file not shown.

View File

@ -46,7 +46,6 @@ void set_default_configuration()
h_cfg.bootprotect = 0; h_cfg.bootprotect = 0;
h_cfg.errors = 0; h_cfg.errors = 0;
h_cfg.eks = NULL; h_cfg.eks = NULL;
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
h_cfg.aes_slots_new = false; h_cfg.aes_slots_new = false;
h_cfg.rcm_patched = fuse_check_patched_rcm(); h_cfg.rcm_patched = fuse_check_patched_rcm();
h_cfg.sbk_set = FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF; h_cfg.sbk_set = FUSE(FUSE_PRIVATE_KEY0) == 0xFFFFFFFF;

View File

@ -34,7 +34,6 @@ typedef struct _hekate_config
// Global temporary config. // Global temporary config.
bool t210b01; bool t210b01;
bool se_keygen_done; bool se_keygen_done;
bool sept_run;
bool aes_slots_new; bool aes_slots_new;
bool emummc_force_disable; bool emummc_force_disable;
bool rcm_patched; bool rcm_patched;

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "fss.h"
#include "hos.h"
#include "../config.h"
#include <libs/fatfs/ff.h>
#include <mem/heap.h>
#include "../storage/emummc.h"
#include <storage/nx_sd.h>
#include <gfx_utils.h>
#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;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "hos.h"
#include "fss.h"
#include "sept.h"
#include "../config.h"
#include <utils/ini.h>
#include <display/di.h>
#include <libs/fatfs/ff.h>
#include <mem/heap.h>
#include <soc/hw_init.h>
#include <soc/pmc.h>
#include <soc/t210.h>
#include "../storage/nx_emmc.h"
#include <storage/nx_sd.h>
#include <storage/sdmmc.h>
#include <utils/btn.h>
#include <utils/list.h>
#include <utils/types.h>
#include <gfx_utils.h>
#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;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef _SEPT_H_
#define _SEPT_H_
#include <utils/types.h>
int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb);
#endif

View File

@ -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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * 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, 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}; 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 {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 {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 {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 // from FS
static const u8 bis_kek_source[0x10] __attribute__((aligned(4))) = { 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}; 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, {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}, 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, {0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F,

View File

@ -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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@ -16,17 +16,17 @@
#include "keys.h" #include "keys.h"
#include "../../keygen/tsec_keygen.h"
#include "../config.h" #include "../config.h"
#include <display/di.h> #include <display/di.h>
#include <gfx_utils.h> #include <gfx_utils.h>
#include "../gfx/tui.h" #include "../gfx/tui.h"
#include "../hos/pkg1.h" #include "../hos/pkg1.h"
#include "../hos/pkg2.h" #include "../hos/pkg2.h"
#include "../hos/sept.h"
#include <libs/fatfs/ff.h> #include <libs/fatfs/ff.h>
#include <libs/nx_savedata/save.h> #include <libs/nx_savedata/save.h>
#include <mem/heap.h> #include <mem/heap.h>
#include <mem/mc.h>
#include <mem/minerva.h> #include <mem/minerva.h>
#include <mem/sdram.h> #include <mem/sdram.h>
#include <sec/se.h> #include <sec/se.h>
@ -122,108 +122,6 @@ static u8 *_read_pkg1(const pkg1_id_t **pkg1_id) {
return pkg1; 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) { static void _derive_master_key_mariko(key_derivation_ctx_t *keys) {
// Relies on the SBK being properly set in slot 14 // 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); 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); 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) { static int _run_ams_keygen(key_derivation_ctx_t *keys) {
// on firmware 6.2.0 only, the tsec_root_key is available tsec_ctxt_t tsec_ctxt;
if (pkg1_kb == KB_FIRMWARE_VERSION_620 && _key_exists(keys->tsec_keys + AES_128_KEY_SIZE)) { tsec_ctxt.fw = tsec_keygen;
se_aes_key_set(8, keys->tsec_keys + AES_128_KEY_SIZE, AES_128_KEY_SIZE); // mkek6 = unwrap(mkeks6, tsecroot) tsec_ctxt.size = sizeof(tsec_keygen);
se_aes_crypt_block_ecb(8, 0, keys->master_kek[6], master_kek_sources[0]); int res = tsec_run_fw(&tsec_ctxt);
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); if (res) {
EPRINTFARGS("ERROR %d running keygen.\n", res);
} }
if (pkg1_kb >= KB_FIRMWARE_VERSION_620) { return res;
// 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--) { static void _derive_master_keys_from_latest_key(key_derivation_ctx_t *keys) {
for (u32 i = kb; i > 0; i--) { 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_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_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_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]); 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)) { if (_key_exists(keys->temp_key)) {
EPRINTFARGS("Unable to derive master key. kb = %d.", pkg1_kb); EPRINTF("Unable to derive master key.");
memset(keys->master_key, 0, sizeof(keys->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); u8 *keyblob_block = (u8 *)calloc(KB_FIRMWARE_VERSION_600 + 1, NX_EMMC_BLOCKSIZE);
encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block; encrypted_keyblob_t *current_keyblob = (encrypted_keyblob_t *)keyblob_block;
u32 keyblob_mac[AES_128_KEY_SIZE / 4] = {0}; 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); 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)) { if (!emummc_storage_read(KEYBLOB_OFFSET / NX_EMMC_BLOCKSIZE, KB_FIRMWARE_VERSION_600 + 1, keyblob_block)) {
EPRINTF("Unable to read keyblobs."); EPRINTF("Unable to read keyblobs.");
} }
for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) { for (u32 i = 0; i <= KB_FIRMWARE_VERSION_600; i++, current_keyblob++) {
minerva_periodic_training(); 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_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_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) 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]); _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_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_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] + 0x00, bis_key_sources[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] + 0x10, bis_key_sources[0] + 0x10);
// kek = generate_kek(bkeks, devkey, aeskek, aeskey) // kek = generate_kek(bkeks, devkey, aeskek, aeskey)
_generate_kek(8, bis_kek_source, keys->temp_key, aes_kek_generation_source, aes_key_generation_source); _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] + 0x00, bis_key_sources[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[1] + 0x10, bis_key_sources[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] + 0x00, bis_key_sources[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[2] + 0x10, bis_key_sources[2] + 0x10);
memcpy(keys->bis_key[3], keys->bis_key[2], 0x20); 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])) { 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); _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); 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); se_aes_crypt_block_ecb(8, 0, keys->save_mac_key, save_mac_key_source);
} }
if (_key_exists(keys->master_key[*derivable_key_count])) { for (u32 i = 0; i < KB_FIRMWARE_VERSION_MAX + 1; i++) {
*derivable_key_count = KB_FIRMWARE_VERSION_MAX + 1;
}
for (u32 i = 0; i < *derivable_key_count; i++) {
if (!_key_exists(keys->master_key[i])) if (!_key_exists(keys->master_key[i]))
continue; continue;
for (u32 j = 0; j < 3; j++) { 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; 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."); 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); 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; char *text_buffer = NULL;
if (!sd_mount()) { if (!sd_mount()) {
EPRINTF("Unable to mount SD."); 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(aes_key_generation_source);
SAVE_KEY(bis_kek_source); SAVE_KEY(bis_kek_source);
SAVE_KEY_FAMILY_VAR(bis_key, keys->bis_key, 0); 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, keys->device_key);
SAVE_KEY_VAR(device_key_4x, keys->device_key_4x); SAVE_KEY_VAR(device_key_4x, keys->device_key_4x);
SAVE_KEY_VAR(eticket_rsa_kek, keys->eticket_rsa_kek); 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_VAR(key_area_key_system_source, key_area_key_sources[2]);
SAVE_KEY_FAMILY_VAR(keyblob, keys->keyblob, 0); SAVE_KEY_FAMILY_VAR(keyblob, keys->keyblob, 0);
SAVE_KEY_FAMILY_VAR(keyblob_key, keys->keyblob_key, 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_FAMILY_VAR(keyblob_mac_key, keys->keyblob_mac_key, 0);
SAVE_KEY(keyblob_mac_key_source); SAVE_KEY(keyblob_mac_key_source);
SAVE_KEY_FAMILY_VAR(master_kek, keys->master_kek, 0); 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(ssl_rsa_kek_source_y);
SAVE_KEY_FAMILY_VAR(titlekek, keys->titlekek, 0); SAVE_KEY_FAMILY_VAR(titlekek, keys->titlekek, 0);
SAVE_KEY(titlekek_source); SAVE_KEY(titlekek_source);
_save_key("tsec_key", keys->tsec_keys, AES_128_KEY_SIZE, text_buffer); SAVE_KEY_VAR(tsec_key, keys->tsec_key);
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); 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(); end_time = get_tmr_us();
gfx_printf("\n%k Found %d keys.\n\n", colors[(color_idx++) % 6], _key_count); 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("%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"); f_mkdir("sd:/switch");
char keyfile_path[30] = "sd:/switch/prod.keys"; 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"); s_printf(&keyfile_path[11], "dev.keys");
FILINFO fno; FILINFO fno;
@ -902,28 +805,30 @@ static void _derive_keys() {
if (!pkg1) { if (!pkg1) {
return; 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); free(pkg1);
if (res == false) {
return; key_derivation_ctx_t __attribute__((aligned(4))) keys = {0};
}
// Master key derivation // Master key derivation
if (h_cfg.t210b01) { if (h_cfg.t210b01) {
_derive_master_key_mariko(&keys); _derive_master_key_mariko(&keys);
_derive_master_keys_post_620(KB_FIRMWARE_VERSION_MAX, &keys); _derive_master_keys_from_latest_key(&keys);
} else { } else {
_derive_master_keys_post_620(pkg1_id->kb, &keys); int res = _run_ams_keygen(&keys);
_derive_master_keys_from_keyblobs(&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]); TPRINTFARGS("%kMaster keys... ", colors[(color_idx++) % 6]);
@ -932,7 +837,7 @@ static void _derive_keys() {
TPRINTFARGS("%kBIS keys... ", colors[(color_idx++) % 6]); 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; 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."); 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() { void dump_keys() {

View File

@ -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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * 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], master_key[KB_FIRMWARE_VERSION_MAX + 1][AES_128_KEY_SIZE],
package2_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], 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]; u32 sbk[4];
keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1]; keyblob_t keyblob[KB_FIRMWARE_VERSION_600 + 1];
} key_derivation_ctx_t; } key_derivation_ctx_t;
@ -137,9 +139,9 @@ typedef struct {
// save key with different name than variable // save key with different name than variable
#define SAVE_KEY_VAR(name, varname) _save_key(#name, varname, sizeof(varname), text_buffer) #define SAVE_KEY_VAR(name, varname) _save_key(#name, varname, sizeof(varname), text_buffer)
// save key family wrapper // 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 // 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(); void dump_keys();

View File

@ -395,15 +395,6 @@ void ipl_main()
h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path; h_cfg.emummc_force_disable = emu_cfg.sector == 0 && !emu_cfg.path;
emu_cfg.enabled = !h_cfg.emummc_force_disable; 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. // Grey out emummc option if not present.
if (h_cfg.emummc_force_disable) if (h_cfg.emummc_force_disable)
{ {