mirror of
https://github.com/shchmue/Lockpick_RCM.git
synced 2024-12-22 15:45:30 +00:00
Use Atmosphere keygen, deprecate sept support
This commit is contained in:
parent
d84ab5796a
commit
38fff7127b
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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
|
||||||
|
|
10
Makefile
10
Makefile
|
@ -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 $@
|
||||||
|
|
|
@ -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
|
||||||
=
|
=
|
||||||
|
|
172
bdk/sec/tsec.c
172
bdk/sec/tsec.c
|
@ -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,91 +130,27 @@ 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)
|
if (!_tsec_dma_wait_idle())
|
||||||
{
|
{
|
||||||
u32 start = get_tmr_us();
|
res = -3;
|
||||||
u32 k = se[SE_CRYPTO_KEYTABLE_DATA_REG / 4];
|
goto out_free;
|
||||||
u32 key[16] = {0};
|
}
|
||||||
u32 kidx = 0;
|
u32 timeout = get_tmr_ms() + 4000;
|
||||||
|
while (!(TSEC(TSEC_CPUCTL) & TSEC_CPUCTL_KEYGEN_DONE))
|
||||||
while (*pkg11_magic_off != PKG11_MAGIC)
|
if (get_tmr_ms() > timeout)
|
||||||
{
|
{
|
||||||
smmu_flush_all();
|
res = -4;
|
||||||
|
|
||||||
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;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
if (TSEC(TSEC_STATUS) != 0xB0B0B0B0)
|
||||||
// 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())
|
res = -5;
|
||||||
{
|
goto out_free;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Fetch result.
|
||||||
|
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
|
||||||
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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] = {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
BIN
keygen/tsec_keygen
Normal file
Binary file not shown.
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
261
source/hos/fss.c
261
source/hos/fss.c
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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,
|
||||||
|
|
|
@ -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_key_set(8, keys->master_key[i], AES_128_KEY_SIZE);
|
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_crypt_block_ecb(8, 0, keys->master_key[i - 1], master_key_vectors[i]);
|
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);
|
||||||
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)) {
|
// Derive all lower master keys
|
||||||
break;
|
for (u32 i = KB_FIRMWARE_VERSION_MAX; i > 0; i--) {
|
||||||
}
|
se_aes_key_set(8, keys->master_key[i], AES_128_KEY_SIZE);
|
||||||
memcpy(keys->master_key[kb - 1], keys->master_key[kb], AES_128_KEY_SIZE);
|
se_aes_crypt_block_ecb(8, 0, keys->master_key[i - 1], master_key_vectors[i]);
|
||||||
memset(keys->master_key[kb], 0, AES_128_KEY_SIZE);
|
}
|
||||||
}
|
se_aes_key_set(8, keys->master_key[0], AES_128_KEY_SIZE);
|
||||||
if (_key_exists(keys->temp_key)) {
|
se_aes_crypt_block_ecb(8, 0, keys->temp_key, master_key_vectors[0]);
|
||||||
EPRINTFARGS("Unable to derive master key. kb = %d.", pkg1_kb);
|
|
||||||
memset(keys->master_key, 0, sizeof(keys->master_key));
|
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);
|
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() {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue