Revise sept key generation methodology.

This commit is contained in:
Michael Scire 2019-06-18 22:22:40 -07:00
parent 63a9c856fc
commit c96ae0148e
21 changed files with 2533 additions and 198 deletions

View file

@ -13,7 +13,7 @@
* 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 <stdbool.h>
#include <stdint.h>
#include <string.h>
@ -83,7 +83,7 @@ void mkey_detect_revision(void) {
if (g_determined_mkey_revision) {
generic_panic();
}
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
if (check_mkey_revision(rev, configitem_is_retail())) {
g_determined_mkey_revision = true;
@ -91,7 +91,7 @@ void mkey_detect_revision(void) {
break;
}
}
/* We must have determined the master key, or we're not running on a Switch. */
if (!g_determined_mkey_revision) {
/* Panic in bright red. */
@ -135,23 +135,17 @@ void set_old_devkey(unsigned int revision, const uint8_t *key) {
}
unsigned int devkey_get_keyslot(unsigned int revision) {
if (!g_determined_mkey_revision || revision >= MASTERKEY_REVISION_MAX) {
if (!g_determined_mkey_revision || revision > g_mkey_revision) {
generic_panic();
}
if (revision > g_mkey_revision) {
generic_panic();
}
if (revision >= 1) {
if (revision == MASTERKEY_REVISION_MAX) {
return KEYSLOT_SWITCH_DEVICEKEY;
} else {
/* Load into a temp keyslot. */
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
return KEYSLOT_SWITCH_TEMPKEY;
}
} else {
if (revision < MASTERKEY_REVISION_400_410) {
return KEYSLOT_SWITCH_4XOLDDEVICEKEY;
} else if (revision < g_mkey_revision) {
/* Load into a temp keyslot. */
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
return KEYSLOT_SWITCH_TEMPKEY;
} else {
return KEYSLOT_SWITCH_DEVICEKEY;
}
}
}

View file

@ -13,7 +13,7 @@
* 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 "utils.h"
@ -43,6 +43,7 @@ static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10]
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */
//{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
};
static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
@ -51,6 +52,7 @@ static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
//{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
};
static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
@ -58,45 +60,28 @@ static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS
{0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.x New Device Keygen Source. */
{0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.x New Device Keygen Source. */
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 New Device Keygen Source. */
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 6.2.0 New Device Keygen Source. */
};
static const uint8_t new_master_kek_sources[MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_600_610][0x10] = {
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, /* 6.2.0 Master Kek Source. */
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* 7.0.0 Master Kek Source. */
};
static const uint8_t keyblob_key_seed_00[0x10] = {
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
};
static const uint8_t devicekey_seed[0x10] = {
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
};
static const uint8_t devicekey_4x_seed[0x10] = {
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
};
static const uint8_t masterkey_seed[0x10] = {
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
};
static const uint8_t devicekek_4x_seed[0x10] = {
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */
//{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
};
static void derive_new_device_keys(unsigned int keygen_keyslot) {
uint8_t work_buffer[0x10];
bool is_retail = configitem_is_retail();
for (unsigned int revision = 0; revision < MASTERKEY_NUM_NEW_DEVICE_KEYS; revision++) {
const unsigned int relative_revision = revision + MASTERKEY_REVISION_400_410;
se_aes_ecb_decrypt_block(keygen_keyslot, work_buffer, 0x10, new_device_key_sources[revision], 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, mkey_get_keyslot(0), is_retail ? new_device_keygen_sources[revision] : new_device_keygen_sources_dev[revision], 0x10);
if (revision < MASTERKEY_NUM_NEW_DEVICE_KEYS - 1) {
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10);
set_old_devkey(revision + MASTERKEY_REVISION_400_410, work_buffer);
if (relative_revision > mkey_get_revision()) {
break;
} else if (relative_revision == mkey_get_revision()) {
/* On 7.0.0, sept will have derived this key for us already. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_700) {
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
}
} else {
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10);
set_old_devkey(relative_revision, work_buffer);
}
}
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
@ -118,7 +103,8 @@ static void setup_se(void) {
se->_0x0 &= 0xFFFEFFFF; /* Clear bit 16. */
(void)(se->FLAGS_REG);
__dsb_sy();
/* NOTE: On 8.1.0+, Nintendo does not make keyslots 0-5 unreadable. */
se->_0x4 = 0;
se->AES_KEY_READ_DISABLE_REG = 0;
se->RSA_KEY_READ_DISABLE_REG = 0;
@ -136,33 +122,6 @@ static void setup_se(void) {
for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) {
set_rsa_keyslot_flags(i, 0x41);
}
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_620 && exosphere_should_perform_620_keygen()) {
unsigned int master_kek_source_ind;
switch (exosphere_get_target_firmware()) {
case ATMOSPHERE_TARGET_FIRMWARE_620:
master_kek_source_ind = MASTERKEY_REVISION_620 - MASTERKEY_REVISION_620;
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
master_kek_source_ind = MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_620;
break;
default:
generic_panic();
break;
}
/* Start by generating device keys. */
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_6XTSECKEY, work_buffer, 0x10, keyblob_key_seed_00, 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, KEYSLOT_SWITCH_6XSBK, work_buffer, 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY, KEYSLOT_SWITCH_4XOLDDEVICEKEY, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, KEYSLOT_SWITCH_4XOLDDEVICEKEY, devicekey_seed, 0x10);
/* Next, generate the master kek, and from there master key/device kek. We use different keyslots than Nintendo, here. */
decrypt_data_into_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, new_master_kek_sources[master_kek_source_ind], 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_MASTERKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, masterkey_seed, 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, devicekek_4x_seed, 0x10);
clear_aes_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY);
}
/* Detect Master Key revision. */
mkey_detect_revision();
@ -198,7 +157,7 @@ static void setup_se(void) {
set_aes_keyslot_flags(KEYSLOT_SWITCH_SESSIONKEY, 0xFF);
/* Generate test vector for our keys. */
se_generate_stored_vector();
se_generate_stored_vector();
}
static void setup_boot_config(void) {
@ -287,7 +246,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
if (metadata->magic != MAGIC_PK21) {
return false;
}
/* Package2 size, version number is stored XORed in header CTR. */
/* Nintendo, what the fuck? */
@ -500,16 +459,16 @@ static void copy_warmboot_bin_to_dram() {
}
uint8_t *warmboot_dst = (uint8_t *)0x8000D000;
const size_t warmboot_size = 0x2000;
/* Flush cache, to ensure warmboot is where we need it to be. */
flush_dcache_range(warmboot_src, warmboot_src + warmboot_size);
__dsb_sy();
/* Copy warmboot. */
for (size_t i = 0; i < warmboot_size; i += sizeof(uint32_t)) {
write32le(warmboot_dst, i, read32le(warmboot_src, i));
}
/* Flush cache, to ensure warmboot is where we need it to be. */
flush_dcache_range(warmboot_dst, warmboot_dst + warmboot_size);
__dsb_sy();
@ -544,12 +503,12 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Setup the Security Engine. */
setup_se();
/* Perform initial PMC register writes, if relevant. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
MAKE_REG32(PMC_BASE + 0x334) |= 0x10;
switch (exosphere_get_target_firmware()) {
case ATMOSPHERE_TARGET_FIRMWARE_400:
@ -585,7 +544,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* memclear the initial copy of Exosphere running in IRAM (relocated to TZRAM by earlier code). */
/* memset((void *)reloc_list->reloc_base, 0, reloc_list->loaded_bin_size); */
/* Let NX Bootloader know that we're running. */
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(exosphere_get_target_firmware()) = 1;
@ -597,7 +556,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Load Boot Config into global. */
setup_boot_config();
/* Set sysctr0 registers based on bootconfig. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
uint64_t sysctr0_val = bootconfig_get_value_for_sysctr0();
@ -620,7 +579,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Make PMC (2.x+), MC (4.x+) registers secure-only */
secure_additional_devices();
/* Remove the identity mapping for iRAM-C+D & TZRAM */
/* For our crt0 to work, this doesn't actually unmap TZRAM */
identity_unmap_iram_cd_tzram();
@ -630,7 +589,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
flush_dcache_range((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, (uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(header));
memcpy(&header, NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, sizeof(header));
flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header));
/* Perform signature checks. */
/* Special exosphere patching enable: All-zeroes signature + decrypted header implies unsigned and decrypted package2. */
if (header.signature[0] == 0 && memcmp(header.signature, header.signature + 1, sizeof(header.signature) - 1) == 0 && header.metadata.magic == MAGIC_PK21) {
@ -641,7 +600,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Decrypt header, get key revision required. */
uint32_t package2_mkey_rev = decrypt_and_validate_header(&header);
/* Copy hash, if necessary. */
if (bootconfig_is_recovery_boot()) {
bootconfig_set_package2_hash_for_recovery(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, get_package2_size(&header.metadata));
@ -649,7 +608,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Load Package2 Sections. */
load_package2_sections(&header.metadata, package2_mkey_rev);
/* Clean up cache. */
flush_dcache_all();
invalidate_icache_all(); /* non-broadcasting */
@ -660,7 +619,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Remove the DRAM identity mapping. */
if (0) {
identity_unmap_dram();
}
}
/* Synchronize with NX BOOTLOADER. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {

View file

@ -77,14 +77,15 @@ export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
$(AMS)/exosphere/rebootstub
$(AMS)/exosphere/rebootstub \
$(TOPDIR)/key_derivation
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin key_derivation.bin
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
@ -111,15 +112,18 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all check_rebootstub
.PHONY: $(BUILD) clean all check_rebootstub check_key_derivation
#---------------------------------------------------------------------------------
all: check_rebootstub $(BUILD)
all: check_rebootstub check_key_derivation $(BUILD)
check_rebootstub:
@$(MAKE) -C $(AMS)/exosphere/rebootstub all
$(BUILD):
check_key_derivation:
@$(MAKE) -C key_derivation
$(BUILD): check_rebootstub check_key_derivation
ifeq ($(strip $(SEPT_ENC_PATH)),)
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
@ -132,6 +136,7 @@ endif
clean:
@echo clean ...
@$(MAKE) -C $(AMS)/exosphere/rebootstub clean
@$(MAKE) -C key_derivation clean
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).enc $(TARGET).elf

View file

@ -0,0 +1,154 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/devkitA64/base_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := src
DATA := data
INCLUDES := include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a -mtune=cortex-a57 -mgeneral-regs-only #<- important
CFLAGS := \
-g \
-Os \
-ffunction-sections \
-fdata-sections \
-fomit-frame-pointer \
-fno-inline \
-std=gnu11 \
-Werror \
-Wall \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(TOPDIR)/linker.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT).bin
$(OUTPUT).bin : $(OUTPUT).elf
$(OBJCOPY) -S -O binary $< $@
@echo built ... $(notdir $@)
$(OUTPUT).elf : $(OFILES)
%.elf: $(OFILES)
@echo linking $(notdir $@)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
@$(NM) -CSn $@ > $(notdir $*.lst)
$(OFILES_SRC) : $(HFILES_BIN)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View file

@ -0,0 +1,17 @@
OUTPUT_ARCH(aarch64)
ENTRY(_start)
SECTIONS
{
. = 0x4003D000;
__start__ = ABSOLUTE(.);
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
.bss : ALIGN(8) { __bss_start__ = .; *(.bss* COMMON); . = ALIGN(8); __bss_end__ = .; }
. = ALIGN(4);
__end__ = ABSOLUTE(.);
}

View file

@ -0,0 +1,7 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
*startfile:
crti%O%s crtbegin%O%s

View file

@ -0,0 +1,149 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "pmc.h"
#include "se.h"
#define AL16 __attribute__((aligned(16)))
#define DERIVATION_ID_MAX 1
static const uint8_t AL16 keyblob_seed_00[0x10] = {
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
};
static const uint8_t AL16 masterkey_seed[0x10] = {
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
};
static const uint8_t AL16 devicekey_seed[0x10] = {
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
};
static const uint8_t AL16 devicekey_4x_seed[0x10] = {
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
};
static const uint8_t AL16 masterkey_4x_seed[0x10] = {
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
};
static const uint8_t AL16 master_kek_seeds[DERIVATION_ID_MAX][0x10] = {
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C},
};
static const uint8_t AL16 master_devkey_seeds[DERIVATION_ID_MAX][0x10] = {
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D},
};
void derive_keys(void) {
/* Set mailbox. */
volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00;
const uint32_t derivation_id = *((volatile uint32_t *)0x4003E800);
if (derivation_id < DERIVATION_ID_MAX) {
uint8_t *partial_se_state = (uint8_t *)0x4000FFC0;
uint8_t *enc_se_state = (uint8_t *)0x4003E000;
volatile tegra_pmc_t *pmc = pmc_get_regs();
uint32_t AL16 work_buffer[4];
/* Save a partial context, only the keyslots we want. */
/* We can't avoid touching memory, but save to a location that the bootrom will overwrite during init. */
se_set_in_context_save_mode(true);
se_save_partial_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, partial_se_state);
se_set_in_context_save_mode(false);
/* Clear the copy of the root key still inside the SE. */
clear_aes_keyslot(0xD);
/* Copy SRK into keyslot 0xE, clear it. */
{
work_buffer[0] = pmc->secure_scratch4;
pmc->secure_scratch4 = 0xCCCCCCCC;
work_buffer[1] = pmc->secure_scratch5;
pmc->secure_scratch5 = 0xCCCCCCCC;
work_buffer[2] = pmc->secure_scratch6;
pmc->secure_scratch6 = 0xCCCCCCCC;
work_buffer[3] = pmc->secure_scratch7;
pmc->secure_scratch7 = 0xCCCCCCCC;
set_aes_keyslot(0xE, work_buffer, 0x10);
for (size_t i = 0; i < 4; i++) {
work_buffer[i] = 0xCCCCCCCC;
}
}
/* Decrypt SE state. */
se_aes_128_cbc_decrypt(0xE, partial_se_state, 0x40, partial_se_state, 0x40);
/* Clear keyslots to wipe IVs. */
clear_aes_keyslot(0xE);
clear_aes_keyslot(0xF);
/* Mov root key into keyslot 0xE. Clear first to wipe from IV. */
set_aes_keyslot(0xE, partial_se_state + 0x30, 0x10);
for (size_t i = 0; i < 4; i++) {
*((volatile uint32_t *)(partial_se_state + 0x30)) = 0xCCCCCCCC;
}
/* Derive master kek. */
decrypt_data_into_keyslot(0xE, 0xE, master_kek_seeds[0], 0x10);
/* Derive master key, device master key. */
decrypt_data_into_keyslot(0xC, 0xE, masterkey_seed, 0x10);
decrypt_data_into_keyslot(0xE, 0xE, masterkey_4x_seed, 0x10);
/* Derive Keyblob Key 00. */
set_aes_keyslot(0xF, partial_se_state + 0x20, 0x10);
se_aes_ecb_decrypt_block(0xF, work_buffer, 0x10, keyblob_seed_00, 0x10);
set_aes_keyslot(0xF, partial_se_state + 0x10, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, work_buffer, 0x10);
/* Clear TSEC key + SBK. */
for (size_t i = 0; i < 8; i++) {
*((volatile uint32_t *)(partial_se_state + 0x10)) = 0xCCCCCCCC;
}
/* Derive device keys. */
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
/* Derive firmware specific device key. */
se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[0], 0x10);
decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10);
/* Clear work buffer. */
for (size_t i = 0; i < 4; i++) {
work_buffer[i] = 0xCCCCCCCC;
}
/* Save context for real. */
se_set_in_context_save_mode(true);
se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, enc_se_state);
se_set_in_context_save_mode(false);
}
/* Clear all keyslots. */
for (size_t i = 0; i < 0x10; i++) {
clear_aes_keyslot(i);
}
*(volatile uint32_t *)(0x4003FFC0) = 0xCACACACA;
*mailbox = 7;
while (1) { /* Wait for sept to handle the rest. */ }
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SEPT_KEYDERIVATION_H
#define SEPT_KEYDERIVATION_H
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
void derive_keys(void);
#endif

View file

@ -0,0 +1,626 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FUSEE_PMC_H
#define FUSEE_PMC_H
#include <stdint.h>
#define PMC_BASE 0x7000E400
#define MAKE_PMC_REG(n) MAKE_REG32(PMC_BASE + n)
#define PMC_CONTROL_SDMMC1 (1 << 12)
#define PMC_CONTROL_SDMMC3 (1 << 13)
#define PMC_CONTROL_SDMMC4 (1 << 14)
#define APBDEV_PMC_CONTROL MAKE_PMC_REG(0x00)
#define APBDEV_PM_0 MAKE_PMC_REG(0x14)
#define APBDEV_PMC_DPD_ENABLE_0 MAKE_PMC_REG(0x24)
#define APBDEV_PMC_PWRGATE_TOGGLE_0 MAKE_PMC_REG(0x30)
#define APBDEV_PMC_PWRGATE_STATUS_0 MAKE_PMC_REG(0x38)
#define APBDEV_PMC_NO_IOPOWER_0 MAKE_PMC_REG(0x44)
#define APBDEV_PMC_SCRATCH0_0 MAKE_PMC_REG(0x50)
#define APBDEV_PMC_SCRATCH1_0 MAKE_PMC_REG(0x54)
#define APBDEV_PMC_SCRATCH20_0 MAKE_PMC_REG(0xA0)
#define APBDEV_PMC_PWR_DET_VAL_0 MAKE_PMC_REG(0xE4)
#define APBDEV_PMC_DDR_PWR_0 MAKE_PMC_REG(0xE8)
#define APBDEV_PMC_CRYPTO_OP_0 MAKE_PMC_REG(0xF4)
#define APBDEV_PMC_WAKE2_STATUS_0 MAKE_PMC_REG(0x168)
#define APBDEV_PMC_OSC_EDPD_OVER_0 MAKE_PMC_REG(0x1A4)
#define APBDEV_PMC_RST_STATUS_0 MAKE_PMC_REG(0x1B4)
#define APBDEV_PMC_IO_DPD_REQ_0 MAKE_PMC_REG(0x1B8)
#define APBDEV_PMC_IO_DPD2_REQ_0 MAKE_PMC_REG(0x1C0)
#define APBDEV_PMC_VDDP_SEL_0 MAKE_PMC_REG(0x1CC)
#define APBDEV_PMC_SCRATCH49_0 MAKE_PMC_REG(0x244)
#define APBDEV_PMC_TSC_MULT_0 MAKE_PMC_REG(0x2B4)
#define APBDEV_PMC_REG_SHORT_0 MAKE_PMC_REG(0x2CC)
#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8)
#define APBDEV_PMC_SECURE_SCRATCH21_0 MAKE_PMC_REG(0x334)
#define APBDEV_PMC_SECURE_SCRATCH32_0 MAKE_PMC_REG(0x360)
#define APBDEV_PMC_SECURE_SCRATCH49_0 MAKE_PMC_REG(0x3A4)
#define APBDEV_PMC_CNTRL2_0 MAKE_PMC_REG(0x440)
#define APBDEV_PMC_IO_DPD4_REQ_0 MAKE_PMC_REG(0x464)
#define APBDEV_PMC_UTMIP_PAD_CFG1_0 MAKE_PMC_REG(0x4C4)
#define APBDEV_PMC_UTMIP_PAD_CFG3_0 MAKE_PMC_REG(0x4CC)
#define APBDEV_PMC_DDR_CNTRL_0 MAKE_PMC_REG(0x4E4)
#define APBDEV_PMC_SCRATCH43_0 MAKE_PMC_REG(0x22C)
#define APBDEV_PMC_SCRATCH188_0 MAKE_PMC_REG(0x810)
#define APBDEV_PMC_SCRATCH190_0 MAKE_PMC_REG(0x818)
#define APBDEV_PMC_SCRATCH200_0 MAKE_PMC_REG(0x840)
#define APBDEV_PMC_SCRATCH45_0 MAKE_PMC_REG(0x234)
#define APBDEV_PMC_SCRATCH46_0 MAKE_PMC_REG(0x238)
#define APBDEV_PMC_SCRATCH33_0 MAKE_PMC_REG(0x120)
#define APBDEV_PMC_SCRATCH40_0 MAKE_PMC_REG(0x13C)
typedef struct {
uint32_t cntrl;
uint32_t sec_disable;
uint32_t pmc_swrst;
uint32_t wake_mask;
uint32_t wake_lvl;
uint32_t wake_status;
uint32_t sw_wake_status;
uint32_t dpd_pads_oride;
uint32_t dpd_sample;
uint32_t dpd_enable;
uint32_t pwrgate_timer_off;
uint32_t clamp_status;
uint32_t pwrgate_toggle;
uint32_t remove_clamping;
uint32_t pwrgate_status;
uint32_t pwrgood_timer;
uint32_t blink_timer;
uint32_t no_iopower;
uint32_t pwr_det;
uint32_t pwr_det_latch;
uint32_t scratch0;
uint32_t scratch1;
uint32_t scratch2;
uint32_t scratch3;
uint32_t scratch4;
uint32_t scratch5;
uint32_t scratch6;
uint32_t scratch7;
uint32_t scratch8;
uint32_t scratch9;
uint32_t scratch10;
uint32_t scratch11;
uint32_t scratch12;
uint32_t scratch13;
uint32_t scratch14;
uint32_t scratch15;
uint32_t scratch16;
uint32_t scratch17;
uint32_t scratch18;
uint32_t scratch19;
uint32_t scratch20;
uint32_t scratch21;
uint32_t scratch22;
uint32_t scratch23;
uint32_t secure_scratch0;
uint32_t secure_scratch1;
uint32_t secure_scratch2;
uint32_t secure_scratch3;
uint32_t secure_scratch4;
uint32_t secure_scratch5;
uint32_t cpupwrgood_timer;
uint32_t cpupwroff_timer;
uint32_t pg_mask;
uint32_t pg_mask_1;
uint32_t auto_wake_lvl;
uint32_t auto_wake_lvl_mask;
uint32_t wake_delay;
uint32_t pwr_det_val;
uint32_t ddr_pwr;
uint32_t usb_debounce_del;
uint32_t usb_ao;
uint32_t crypto_op;
uint32_t pllp_wb0_override;
uint32_t scratch24;
uint32_t scratch25;
uint32_t scratch26;
uint32_t scratch27;
uint32_t scratch28;
uint32_t scratch29;
uint32_t scratch30;
uint32_t scratch31;
uint32_t scratch32;
uint32_t scratch33;
uint32_t scratch34;
uint32_t scratch35;
uint32_t scratch36;
uint32_t scratch37;
uint32_t scratch38;
uint32_t scratch39;
uint32_t scratch40;
uint32_t scratch41;
uint32_t scratch42;
uint32_t bo_mirror0;
uint32_t bo_mirror1;
uint32_t bo_mirror2;
uint32_t sys_33v_en;
uint32_t bo_mirror_access;
uint32_t gate;
uint32_t wake2_mask;
uint32_t wake2_lvl;
uint32_t wake2_stat;
uint32_t sw_wake2_stat;
uint32_t auto_wake2_lvl_mask;
uint32_t pg_mask2;
uint32_t pg_mask_ce1;
uint32_t pg_mask_ce2;
uint32_t pg_mask_ce3;
uint32_t pwrgate_timer_ce0;
uint32_t pwrgate_timer_ce1;
uint32_t pwrgate_timer_ce2;
uint32_t pwrgate_timer_ce3;
uint32_t pwrgate_timer_ce4;
uint32_t pwrgate_timer_ce5;
uint32_t pwrgate_timer_ce6;
uint32_t pcx_edpd_cntrl;
uint32_t osc_edpd_over;
uint32_t clk_out_cntrl;
uint32_t sata_pwrgate;
uint32_t sensor_ctrl;
uint32_t reset_status;
uint32_t io_dpd_req;
uint32_t io_dpd_stat;
uint32_t io_dpd2_req;
uint32_t io_dpd2_stat;
uint32_t sel_dpd_tim;
uint32_t vddp_sel;
uint32_t ddr_cfg;
uint32_t e_no_vttgen;
uint32_t _reserved0;
uint32_t pllm_wb0_ovrride_frq;
uint32_t test_pwrgate;
uint32_t pwrgate_timer_mult;
uint32_t dsi_sel_dpd;
uint32_t utmip_uhsic_triggers;
uint32_t utmip_uhsic_saved_st;
uint32_t utmip_pad_cfg;
uint32_t utmip_term_pad_cfg;
uint32_t utmip_uhsic_sleep_cfg;
uint32_t utmip_uhsic_sleepwalk_cfg;
uint32_t utmip_sleepwalk_p[3];
uint32_t uhsic_sleepwalk_p0;
uint32_t utmip_uhsic_status;
uint32_t utmip_uhsic_fake;
uint32_t bo_mirror3[2];
uint32_t secure_scratch6;
uint32_t secure_scratch7;
uint32_t scratch43;
uint32_t scratch44;
uint32_t scratch45;
uint32_t scratch46;
uint32_t scratch47;
uint32_t scratch48;
uint32_t scratch49;
uint32_t scratch50;
uint32_t scratch51;
uint32_t scratch52;
uint32_t scratch53;
uint32_t scratch54;
uint32_t scratch55;
uint32_t scratch0_eco;
uint32_t por_dpd_ctrl;
uint32_t scratch2_eco;
uint32_t utmip_uhsic_line_wakeup;
uint32_t utmip_bias_master_cntrl;
uint32_t utmip_master_config;
uint32_t td_pwrgate_inter_part_timer;
uint32_t utmip_uhsic2_triggers;
uint32_t utmip_uhsic2_saved_state;
uint32_t utmip_uhsic2_sleep_cfg;
uint32_t utmip_uhsic2_sleepwalk_cfg;
uint32_t uhsic2_sleepwalk_p1;
uint32_t utmip_uhsic2_status;
uint32_t utmip_uhsic2_fake;
uint32_t utmip_uhsic2_line_wakeup;
uint32_t utmip_master2_config;
uint32_t utmip_uhsic_rpd_cfg;
uint32_t pg_mask_ce0;
uint32_t pg_mask3[2];
uint32_t pllm_wb0_override2;
uint32_t tsc_mult;
uint32_t cpu_vsense_override;
uint32_t glb_amap_cfg;
uint32_t sticky_bits;
uint32_t sec_disable2;
uint32_t weak_bias;
uint32_t reg_short;
uint32_t pg_mask_andor;
uint32_t _reserved1[11];
uint32_t secure_scratch8;
uint32_t secure_scratch9;
uint32_t secure_scratch10;
uint32_t secure_scratch11;
uint32_t secure_scratch12;
uint32_t secure_scratch13;
uint32_t secure_scratch14;
uint32_t secure_scratch15;
uint32_t secure_scratch16;
uint32_t secure_scratch17;
uint32_t secure_scratch18;
uint32_t secure_scratch19;
uint32_t secure_scratch20;
uint32_t secure_scratch21;
uint32_t secure_scratch22;
uint32_t secure_scratch23;
uint32_t secure_scratch24;
uint32_t secure_scratch25;
uint32_t secure_scratch26;
uint32_t secure_scratch27;
uint32_t secure_scratch28;
uint32_t secure_scratch29;
uint32_t secure_scratch30;
uint32_t secure_scratch31;
uint32_t secure_scratch32;
uint32_t secure_scratch33;
uint32_t secure_scratch34;
uint32_t secure_scratch35;
uint32_t secure_scratch36;
uint32_t secure_scratch37;
uint32_t secure_scratch38;
uint32_t secure_scratch39;
uint32_t secure_scratch40;
uint32_t secure_scratch41;
uint32_t secure_scratch42;
uint32_t secure_scratch43;
uint32_t secure_scratch44;
uint32_t secure_scratch45;
uint32_t secure_scratch46;
uint32_t secure_scratch47;
uint32_t secure_scratch48;
uint32_t secure_scratch49;
uint32_t secure_scratch50;
uint32_t secure_scratch51;
uint32_t secure_scratch52;
uint32_t secure_scratch53;
uint32_t secure_scratch54;
uint32_t secure_scratch55;
uint32_t secure_scratch56;
uint32_t secure_scratch57;
uint32_t secure_scratch58;
uint32_t secure_scratch59;
uint32_t secure_scratch60;
uint32_t secure_scratch61;
uint32_t secure_scratch62;
uint32_t secure_scratch63;
uint32_t secure_scratch64;
uint32_t secure_scratch65;
uint32_t secure_scratch66;
uint32_t secure_scratch67;
uint32_t secure_scratch68;
uint32_t secure_scratch69;
uint32_t secure_scratch70;
uint32_t secure_scratch71;
uint32_t secure_scratch72;
uint32_t secure_scratch73;
uint32_t secure_scratch74;
uint32_t secure_scratch75;
uint32_t secure_scratch76;
uint32_t secure_scratch77;
uint32_t secure_scratch78;
uint32_t secure_scratch79;
uint32_t _reserved2[8];
uint32_t cntrl2;
uint32_t _reserved3[2];
uint32_t event_counter;
uint32_t fuse_control;
uint32_t scratch1_eco;
uint32_t _reserved4;
uint32_t io_dpd3_req;
uint32_t io_dpd3_status;
uint32_t io_dpd4_req;
uint32_t io_dpd4_status;
uint32_t _reserved5[30];
uint32_t ddr_cntrl;
uint32_t _reserved6[70];
uint32_t scratch56;
uint32_t scratch57;
uint32_t scratch58;
uint32_t scratch59;
uint32_t scratch60;
uint32_t scratch61;
uint32_t scratch62;
uint32_t scratch63;
uint32_t scratch64;
uint32_t scratch65;
uint32_t scratch66;
uint32_t scratch67;
uint32_t scratch68;
uint32_t scratch69;
uint32_t scratch70;
uint32_t scratch71;
uint32_t scratch72;
uint32_t scratch73;
uint32_t scratch74;
uint32_t scratch75;
uint32_t scratch76;
uint32_t scratch77;
uint32_t scratch78;
uint32_t scratch79;
uint32_t scratch80;
uint32_t scratch81;
uint32_t scratch82;
uint32_t scratch83;
uint32_t scratch84;
uint32_t scratch85;
uint32_t scratch86;
uint32_t scratch87;
uint32_t scratch88;
uint32_t scratch89;
uint32_t scratch90;
uint32_t scratch91;
uint32_t scratch92;
uint32_t scratch93;
uint32_t scratch94;
uint32_t scratch95;
uint32_t scratch96;
uint32_t scratch97;
uint32_t scratch98;
uint32_t scratch99;
uint32_t scratch100;
uint32_t scratch101;
uint32_t scratch102;
uint32_t scratch103;
uint32_t scratch104;
uint32_t scratch105;
uint32_t scratch106;
uint32_t scratch107;
uint32_t scratch108;
uint32_t scratch109;
uint32_t scratch110;
uint32_t scratch111;
uint32_t scratch112;
uint32_t scratch113;
uint32_t scratch114;
uint32_t scratch115;
uint32_t scratch116;
uint32_t scratch117;
uint32_t scratch118;
uint32_t scratch119;
uint32_t scratch120;
uint32_t scratch121;
uint32_t scratch122;
uint32_t scratch123;
uint32_t scratch124;
uint32_t scratch125;
uint32_t scratch126;
uint32_t scratch127;
uint32_t scratch128;
uint32_t scratch129;
uint32_t scratch130;
uint32_t scratch131;
uint32_t scratch132;
uint32_t scratch133;
uint32_t scratch134;
uint32_t scratch135;
uint32_t scratch136;
uint32_t scratch137;
uint32_t scratch138;
uint32_t scratch139;
uint32_t scratch140;
uint32_t scratch141;
uint32_t scratch142;
uint32_t scratch143;
uint32_t scratch144;
uint32_t scratch145;
uint32_t scratch146;
uint32_t scratch147;
uint32_t scratch148;
uint32_t scratch149;
uint32_t scratch150;
uint32_t scratch151;
uint32_t scratch152;
uint32_t scratch153;
uint32_t scratch154;
uint32_t scratch155;
uint32_t scratch156;
uint32_t scratch157;
uint32_t scratch158;
uint32_t scratch159;
uint32_t scratch160;
uint32_t scratch161;
uint32_t scratch162;
uint32_t scratch163;
uint32_t scratch164;
uint32_t scratch165;
uint32_t scratch166;
uint32_t scratch167;
uint32_t scratch168;
uint32_t scratch169;
uint32_t scratch170;
uint32_t scratch171;
uint32_t scratch172;
uint32_t scratch173;
uint32_t scratch174;
uint32_t scratch175;
uint32_t scratch176;
uint32_t scratch177;
uint32_t scratch178;
uint32_t scratch179;
uint32_t scratch180;
uint32_t scratch181;
uint32_t scratch182;
uint32_t scratch183;
uint32_t scratch184;
uint32_t scratch185;
uint32_t scratch186;
uint32_t scratch187;
uint32_t scratch188;
uint32_t scratch189;
uint32_t scratch190;
uint32_t scratch191;
uint32_t scratch192;
uint32_t scratch193;
uint32_t scratch194;
uint32_t scratch195;
uint32_t scratch196;
uint32_t scratch197;
uint32_t scratch198;
uint32_t scratch199;
uint32_t scratch200;
uint32_t scratch201;
uint32_t scratch202;
uint32_t scratch203;
uint32_t scratch204;
uint32_t scratch205;
uint32_t scratch206;
uint32_t scratch207;
uint32_t scratch208;
uint32_t scratch209;
uint32_t scratch210;
uint32_t scratch211;
uint32_t scratch212;
uint32_t scratch213;
uint32_t scratch214;
uint32_t scratch215;
uint32_t scratch216;
uint32_t scratch217;
uint32_t scratch218;
uint32_t scratch219;
uint32_t scratch220;
uint32_t scratch221;
uint32_t scratch222;
uint32_t scratch223;
uint32_t scratch224;
uint32_t scratch225;
uint32_t scratch226;
uint32_t scratch227;
uint32_t scratch228;
uint32_t scratch229;
uint32_t scratch230;
uint32_t scratch231;
uint32_t scratch232;
uint32_t scratch233;
uint32_t scratch234;
uint32_t scratch235;
uint32_t scratch236;
uint32_t scratch237;
uint32_t scratch238;
uint32_t scratch239;
uint32_t scratch240;
uint32_t scratch241;
uint32_t scratch242;
uint32_t scratch243;
uint32_t scratch244;
uint32_t scratch245;
uint32_t scratch246;
uint32_t scratch247;
uint32_t scratch248;
uint32_t scratch249;
uint32_t scratch250;
uint32_t scratch251;
uint32_t scratch252;
uint32_t scratch253;
uint32_t scratch254;
uint32_t scratch255;
uint32_t scratch256;
uint32_t scratch257;
uint32_t scratch258;
uint32_t scratch259;
uint32_t scratch260;
uint32_t scratch261;
uint32_t scratch262;
uint32_t scratch263;
uint32_t scratch264;
uint32_t scratch265;
uint32_t scratch266;
uint32_t scratch267;
uint32_t scratch268;
uint32_t scratch269;
uint32_t scratch270;
uint32_t scratch271;
uint32_t scratch272;
uint32_t scratch273;
uint32_t scratch274;
uint32_t scratch275;
uint32_t scratch276;
uint32_t scratch277;
uint32_t scratch278;
uint32_t scratch279;
uint32_t scratch280;
uint32_t scratch281;
uint32_t scratch282;
uint32_t scratch283;
uint32_t scratch284;
uint32_t scratch285;
uint32_t scratch286;
uint32_t scratch287;
uint32_t scratch288;
uint32_t scratch289;
uint32_t scratch290;
uint32_t scratch291;
uint32_t scratch292;
uint32_t scratch293;
uint32_t scratch294;
uint32_t scratch295;
uint32_t scratch296;
uint32_t scratch297;
uint32_t scratch298;
uint32_t scratch299;
uint32_t _reserved7[50];
uint32_t secure_scratch80;
uint32_t secure_scratch81;
uint32_t secure_scratch82;
uint32_t secure_scratch83;
uint32_t secure_scratch84;
uint32_t secure_scratch85;
uint32_t secure_scratch86;
uint32_t secure_scratch87;
uint32_t secure_scratch88;
uint32_t secure_scratch89;
uint32_t secure_scratch90;
uint32_t secure_scratch91;
uint32_t secure_scratch92;
uint32_t secure_scratch93;
uint32_t secure_scratch94;
uint32_t secure_scratch95;
uint32_t secure_scratch96;
uint32_t secure_scratch97;
uint32_t secure_scratch98;
uint32_t secure_scratch99;
uint32_t secure_scratch100;
uint32_t secure_scratch101;
uint32_t secure_scratch102;
uint32_t secure_scratch103;
uint32_t secure_scratch104;
uint32_t secure_scratch105;
uint32_t secure_scratch106;
uint32_t secure_scratch107;
uint32_t secure_scratch108;
uint32_t secure_scratch109;
uint32_t secure_scratch110;
uint32_t secure_scratch111;
uint32_t secure_scratch112;
uint32_t secure_scratch113;
uint32_t secure_scratch114;
uint32_t secure_scratch115;
uint32_t secure_scratch116;
uint32_t secure_scratch117;
uint32_t secure_scratch118;
uint32_t secure_scratch119;
} tegra_pmc_t;
static inline volatile tegra_pmc_t *pmc_get_regs(void)
{
return (volatile tegra_pmc_t *)PMC_BASE;
}
#endif

View file

@ -0,0 +1,763 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "utils.h"
#include "se.h"
void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size);
/* Globals for driver. */
static unsigned int g_se_modulus_sizes[KEYSLOT_RSA_MAX];
static unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX];
/* Initialize a SE linked list. */
void NOINLINE ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
ll->num_entries = 0; /* 1 Entry. */
if (buffer != NULL) {
ll->addr_info.address = (uint32_t) get_physical_address(buffer);
ll->addr_info.size = (uint32_t) size;
} else {
ll->addr_info.address = 0;
ll->addr_info.size = 0;
}
}
void se_check_error_status_reg(void) {
if (se_get_regs()->ERR_STATUS_REG) {
generic_panic();
}
}
void se_check_for_error(void) {
volatile tegra_se_t *se = se_get_regs();
if (se->INT_STATUS_REG & 0x10000 || se->FLAGS_REG & 3 || se->ERR_STATUS_REG) {
generic_panic();
}
}
void se_verify_flags_cleared(void) {
if (se_get_regs()->FLAGS_REG & 3) {
generic_panic();
}
}
/* Set the flags for an AES keyslot. */
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
/* Misc flags. */
if (flags & ~0x80) {
se->AES_KEYSLOT_FLAGS[keyslot] = ~flags;
}
/* Disable keyslot reads. */
if (flags & 0x80) {
se->AES_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
}
}
/* Set the flags for an RSA keyslot. */
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic();
}
/* Misc flags. */
if (flags & ~0x80) {
/* TODO: Why are flags assigned this way? */
se->RSA_KEYSLOT_FLAGS[keyslot] = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
}
/* Disable keyslot reads. */
if (flags & 0x80) {
se->RSA_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
}
}
void clear_aes_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
/* Zero out the whole keyslot and IV. */
for (unsigned int i = 0; i < 0x10; i++) {
se->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
se->AES_KEYTABLE_DATA = 0;
}
}
void clear_rsa_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic();
}
/* Zero out the whole keyslot. */
for (unsigned int i = 0; i < 0x40; i++) {
/* Select Keyslot Modulus[i] */
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i | 0x40;
se->RSA_KEYTABLE_DATA = 0;
}
for (unsigned int i = 0; i < 0x40; i++) {
/* Select Keyslot Expontent[i] */
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
se->RSA_KEYTABLE_DATA = 0;
}
}
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
generic_panic();
}
for (size_t i = 0; i < (key_size >> 2); i++) {
se->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
se->AES_KEYTABLE_DATA = read32le(key, 4 * i);
}
}
void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
generic_panic();
}
for (size_t i = 0; i < (modulus_size >> 2); i++) {
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | 0x40 | i;
se->RSA_KEYTABLE_DATA = read32be(modulus, (4 * (modulus_size >> 2)) - (4 * i) - 4);
}
for (size_t i = 0; i < (exp_size >> 2); i++) {
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
se->RSA_KEYTABLE_DATA = read32be(exponent, (4 * (exp_size >> 2)) - (4 * i) - 4);
}
g_se_modulus_sizes[keyslot] = modulus_size;
g_se_exp_sizes[keyslot] = exp_size;
}
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
generic_panic();
}
for (size_t i = 0; i < (iv_size >> 2); i++) {
se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
se->AES_KEYTABLE_DATA = read32le(iv, 4 * i);
}
}
void clear_aes_keyslot_iv(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
for (size_t i = 0; i < (0x10 >> 2); i++) {
se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
se->AES_KEYTABLE_DATA = 0;
}
}
void set_se_ctr(const void *ctr) {
for (unsigned int i = 0; i < 4; i++) {
se_get_regs()->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
}
}
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSLOT_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
generic_panic();
}
se->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB);
se->CRYPTO_REG = keyslot_src << 24;
se->BLOCK_COUNT_REG = 0;
se->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8;
trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size);
}
void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
uint8_t ALIGN(16) stack_buf[KEYSIZE_RSA_MAX];
if (keyslot >= KEYSLOT_RSA_MAX || src_size > KEYSIZE_RSA_MAX || dst_size > KEYSIZE_RSA_MAX) {
generic_panic();
}
/* Endian swap the input. */
for (size_t i = 0; i < src_size; i++) {
stack_buf[i] = *((uint8_t *)src + src_size - i - 1);
}
se->CONFIG_REG = (ALG_RSA | DST_RSAREG);
se->RSA_CONFIG = keyslot << 24;
se->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1;
se->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2;
trigger_se_blocking_op(OP_START, NULL, 0, stack_buf, src_size);
se_get_exp_mod_output(dst, dst_size);
}
void se_get_exp_mod_output(void *buf, size_t size) {
size_t num_dwords = (size >> 2);
if (num_dwords < 1) {
return;
}
uint32_t *p_out = ((uint32_t *)buf) + num_dwords - 1;
uint32_t offset = 0;
/* Copy endian swapped output. */
while (num_dwords) {
*p_out = read32be(se_get_regs()->RSA_OUTPUT, offset);
offset += 4;
p_out--;
num_dwords--;
}
}
bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size) {
uint8_t message[RSA_2048_BYTES];
uint8_t h_buf[0x24];
/* Hardcode RSA with keyslot 0. */
const uint8_t public_exponent[4] = {0x00, 0x01, 0x00, 0x01};
set_rsa_keyslot(0, modulus, modulus_size, public_exponent, sizeof(public_exponent));
se_synchronous_exp_mod(0, message, sizeof(message), signature, signature_size);
/* Validate sanity byte. */
if (message[RSA_2048_BYTES - 1] != 0xBC) {
return false;
}
/* Copy Salt into MGF1 Hash Buffer. */
memset(h_buf, 0, sizeof(h_buf));
memcpy(h_buf, message + RSA_2048_BYTES - 0x20 - 0x1, 0x20);
/* Decrypt maskedDB (via inline MGF1). */
uint8_t seed = 0;
uint8_t mgf1_buf[0x20];
for (unsigned int ofs = 0; ofs < RSA_2048_BYTES - 0x20 - 1; ofs += 0x20) {
h_buf[sizeof(h_buf) - 1] = seed++;
se_calculate_sha256(mgf1_buf, h_buf, sizeof(h_buf));
for (unsigned int i = ofs; i < ofs + 0x20 && i < RSA_2048_BYTES - 0x20 - 1; i++) {
message[i] ^= mgf1_buf[i - ofs];
}
}
/* Constant lmask for rsa-2048-pss. */
message[0] &= 0x7F;
/* Validate DB is of the form 0000...0001. */
for (unsigned int i = 0; i < RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1; i++) {
if (message[i] != 0) {
return false;
}
}
if (message[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) {
return false;
}
/* Check hash correctness. */
uint8_t validate_buf[8 + 0x20 + 0x20];
uint8_t validate_hash[0x20];
memset(validate_buf, 0, sizeof(validate_buf));
se_calculate_sha256(&validate_buf[8], data, data_size);
memcpy(&validate_buf[0x28], &message[RSA_2048_BYTES - 0x20 - 0x20 - 1], 0x20);
se_calculate_sha256(validate_hash, validate_buf, sizeof(validate_buf));
return memcmp(h_buf, validate_hash, 0x20) == 0;
}
void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
se_ll_t in_ll;
se_ll_t out_ll;
ll_init(&in_ll, (void *)src, src_size);
ll_init(&out_ll, dst, dst_size);
/* Set the LLs. */
se->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll);
se->OUT_LL_ADDR_REG = (uint32_t) get_physical_address(&out_ll);
/* Set registers for operation. */
se->ERR_STATUS_REG = se->ERR_STATUS_REG;
se->INT_STATUS_REG = se->INT_STATUS_REG;
se->OPERATION_REG = op;
while (!(se->INT_STATUS_REG & 0x10)) { /* Wait a while */ }
se_check_for_error();
}
/* Secure AES Functionality. */
void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src, size_t src_size) {
uint8_t block[0x10] = {0};
if (src_size > sizeof(block) || dst_size > sizeof(block)) {
generic_panic();
}
/* Load src data into block. */
if (src_size != 0) {
memcpy(block, src, src_size);
}
/* Trigger AES operation. */
se_get_regs()->BLOCK_COUNT_REG = 0;
trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block));
/* Copy output data into dst. */
if (dst_size != 0) {
memcpy(dst, block, dst_size);
}
}
void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
generic_panic();
}
unsigned int num_blocks = src_size >> 4;
/* Unknown what this write does, but official code writes it for CTR mode. */
se->SPARE_0 = 1;
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
se->CRYPTO_REG = (keyslot << 24) | 0x91E;
set_se_ctr(ctr);
/* Handle any aligned blocks. */
size_t aligned_size = (size_t)num_blocks << 4;
if (aligned_size) {
se->BLOCK_COUNT_REG = num_blocks - 1;
trigger_se_blocking_op(OP_START, dst, dst_size, src, aligned_size);
}
/* Handle final, unaligned block. */
if (aligned_size < dst_size && aligned_size < src_size) {
size_t last_block_size = dst_size - aligned_size;
if (src_size < dst_size) {
last_block_size = src_size - aligned_size;
}
se_perform_aes_block_operation(dst + aligned_size, last_block_size, (uint8_t *)src + aligned_size, src_size - aligned_size);
}
}
void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic();
}
/* Set configuration high (256-bit vs 128-bit) based on parameter. */
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (config_high << 16);
se->CRYPTO_REG = keyslot << 24 | 0x100;
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
}
void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0);
}
void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0x202);
}
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic();
}
se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY);
se->CRYPTO_REG = keyslot << 24;
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
}
void shift_left_xor_rb(uint8_t *key) {
uint8_t prev_high_bit = 0;
for (unsigned int i = 0; i < 0x10; i++) {
uint8_t cur_byte = key[0xF - i];
key[0xF - i] = (cur_byte << 1) | (prev_high_bit);
prev_high_bit = cur_byte >> 7;
}
if (prev_high_bit) {
key[0xF] ^= 0x87;
}
}
void shift_left_xor_rb_le(uint8_t *key) {
uint8_t prev_high_bit = 0;
for (unsigned int i = 0; i < 0x10; i++) {
uint8_t cur_byte = key[i];
key[i] = (cur_byte << 1) | (prev_high_bit);
prev_high_bit = cur_byte >> 7;
}
if (prev_high_bit) {
key[0x0] ^= 0x87;
}
}
void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
/* Generate the derived key, to be XOR'd with final output block. */
uint8_t ALIGN(16) derived_key[0x10] = {0};
se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high);
shift_left_xor_rb(derived_key);
if (data_size & 0xF) {
shift_left_xor_rb(derived_key);
}
se->CONFIG_REG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
se->CRYPTO_REG = (keyslot << 24) | (0x145);
clear_aes_keyslot_iv(keyslot);
unsigned int num_blocks = (data_size + 0xF) >> 4;
/* Handle aligned blocks. */
if (num_blocks > 1) {
se->BLOCK_COUNT_REG = num_blocks - 2;
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
se->CRYPTO_REG |= 0x80;
}
/* Create final block. */
uint8_t ALIGN(16) last_block[0x10] = {0};
if (data_size & 0xF) {
memcpy(last_block, data + (data_size & ~0xF), data_size & 0xF);
last_block[data_size & 0xF] = 0x80; /* Last block = data || 100...0 */
} else if (data_size >= 0x10) {
memcpy(last_block, data + data_size - 0x10, 0x10);
}
for (unsigned int i = 0; i < 0x10; i++) {
last_block[i] ^= derived_key[i];
}
/* Perform last operation. */
se->BLOCK_COUNT_REG = 0;
trigger_se_blocking_op(OP_START, NULL, 0, last_block, sizeof(last_block));
/* Copy output CMAC. */
for (unsigned int i = 0; i < (cmac_size >> 2); i++) {
((uint32_t *)cmac)[i] = read32le(se->HASH_RESULT_REG, i << 2);
}
}
void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0);
}
void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0x202);
}
void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
generic_panic();
}
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
se->CRYPTO_REG = (keyslot << 24) | 0x144;
set_aes_keyslot_iv(keyslot, iv, 0x10);
se->BLOCK_COUNT_REG = (src_size >> 4) - 1;
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
}
void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
generic_panic();
}
se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY) | (0x000 << 16);
se->CRYPTO_REG = (keyslot << 24) | 0x66;
clear_aes_keyslot_iv(keyslot);
se->BLOCK_COUNT_REG = (src_size >> 4) - 1;
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
}
/* SHA256 Implementation. */
void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
/* Setup config for SHA256, size = BITS(src_size) */
se->CONFIG_REG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
se->SHA_CONFIG_REG = 1;
se->SHA_MSG_LENGTH_REG = (uint32_t)(src_size << 3);
se->_0x208 = 0;
se->_0x20C = 0;
se->_0x210 = 0;
se->SHA_MSG_LEFT_REG = (uint32_t)(src_size << 3);
se->_0x218 = 0;
se->_0x21C = 0;
se->_0x220 = 0;
/* Trigger the operation. */
trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);
/* Copy output hash. */
for (unsigned int i = 0; i < (0x20 >> 2); i++) {
((uint32_t *)dst)[i] = read32be(se->HASH_RESULT_REG, i << 2);
}
}
/* RNG API */
void se_initialize_rng(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
/* To initialize the RNG, we'll perform an RNG operation into an output buffer. */
/* This will be discarded, when done. */
uint8_t ALIGN(16) output_buf[0x10];
se->RNG_SRC_CONFIG_REG = 3; /* Entropy enable + Entropy lock enable */
se->RNG_RESEED_INTERVAL_REG = 70001;
se->CONFIG_REG = (ALG_RNG | DST_MEMORY);
se->CRYPTO_REG = (keyslot << 24) | 0x108;
se->RNG_CONFIG_REG = 5;
se->BLOCK_COUNT_REG = 0;
trigger_se_blocking_op(OP_START, output_buf, 0x10, NULL, 0);
}
void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
uint32_t num_blocks = size >> 4;
size_t aligned_size = num_blocks << 4;
se->CONFIG_REG = (ALG_RNG | DST_MEMORY);
se->CRYPTO_REG = (keyslot << 24) | 0x108;
se->RNG_CONFIG_REG = 4;
if (num_blocks >= 1) {
se->BLOCK_COUNT_REG = num_blocks - 1;
trigger_se_blocking_op(OP_START, dst, aligned_size, NULL, 0);
}
if (size > aligned_size) {
se_perform_aes_block_operation(dst + aligned_size, size - aligned_size, NULL, 0);
}
}
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
/* Setup Config. */
se->CONFIG_REG = (ALG_RNG | DST_KEYTAB);
se->CRYPTO_REG = (rng_keyslot << 24) | 0x108;
se->RNG_CONFIG_REG = 4;
se->BLOCK_COUNT_REG = 0;
/* Generate low part of key. */
se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8);
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
/* Generate high part of key. */
se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8) | 1;
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
}
/* SE context save API. */
void se_set_in_context_save_mode(bool is_context_save_mode) {
volatile tegra_se_t *se = se_get_regs();
uint32_t val = se->_0x0;
if (is_context_save_mode) {
val |= 0x10000;
} else {
val &= 0xFFFEFFFF;
}
se->_0x0 = val;
/* Perform a useless read from flags reg. */
(void)(se->FLAGS_REG);
}
void se_generate_srk(unsigned int srkgen_keyslot) {
volatile tegra_se_t *se = se_get_regs();
se->CONFIG_REG = (ALG_RNG | DST_SRK);
se->CRYPTO_REG = (srkgen_keyslot << 24) | 0x108;
se->RNG_CONFIG_REG = 6;
se->BLOCK_COUNT_REG = 0;
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
}
void se_encrypt_with_srk(void *dst, size_t dst_size, const void *src, size_t src_size) {
uint8_t output[0x80];
uint8_t *aligned_out = (uint8_t *)(((uintptr_t)output + 0x7F) & ~0x3F);
if (dst_size > 0x10) {
generic_panic();
}
if (dst_size) {
trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, dst_size, src, src_size);
memcpy(dst, aligned_out, dst_size);
} else {
trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, 0, src, src_size);
}
}
void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) {
volatile tegra_se_t *se = se_get_regs();
uint8_t _work_buf[0x80];
uint8_t *work_buf = (uint8_t *)(((uintptr_t)_work_buf + 0x7F) & ~0x3F);
/* Generate the SRK (context save encryption key). */
se_generate_random_key(srkgen_keyslot, rng_keyslot);
se_generate_srk(srkgen_keyslot);
se_generate_random(rng_keyslot, work_buf, 0x10);
/* Save random initial block. */
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst, 0x10, work_buf, 0x10);
/* Save Sticky Bits. */
for (unsigned int i = 0; i < 0x2; i++) {
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0);
}
/* Save AES Key Table. */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x30 + (i * 0x20), 0x10, NULL, 0);
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_HIGH_BITS);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0);
}
/* Save AES Original IVs. */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_ORIGINAL_IV);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0);
}
/* Save AES Updated IVs */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_UPDATED_IV);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0);
}
/* Save RSA Keytable. */
uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430;
for (unsigned int rsa_key = 0; rsa_key < KEYSLOT_RSA_MAX; rsa_key++) {
for (unsigned int mod_exp = 0; mod_exp < 2; mod_exp++) {
for (unsigned int sub_block = 0; sub_block < 0x10; sub_block++) {
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_RSA) | ((2 * rsa_key + (1 - mod_exp)) << CTX_SAVE_RSA_KEY_INDEX_SHIFT) | (sub_block << CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(rsa_ctx_out, 0x10, NULL, 0);
rsa_ctx_out += 0x10;
}
}
}
/* Save "Known Pattern. " */
static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10);
/* Save SRK into PMC registers. */
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(work_buf, 0, NULL, 0);
se->CONFIG_REG = 0;
se_encrypt_with_srk(work_buf, 0, NULL, 0);
}
void se_save_partial_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) {
volatile tegra_se_t *se = se_get_regs();
uint8_t _work_buf[0x80];
uint8_t *work_buf = (uint8_t *)(((uintptr_t)_work_buf + 0x7F) & ~0x3F);
/* Generate the SRK (context save encryption key). */
se_generate_random_key(srkgen_keyslot, rng_keyslot);
se_generate_srk(srkgen_keyslot);
se_generate_random(rng_keyslot, work_buf, 0x10);
/* Save known pattern. */
static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x00, 0x10, context_save_known_pattern, 0x10);
/* Save specific keyslots 0xC, 0xD, 0xE. */
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xE << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x10, 0x10, NULL, 0);
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xC << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x20, 0x10, NULL, 0);
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xD << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x30, 0x10, NULL, 0);
/* Save SRK into PMC registers. */
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(work_buf, 0, NULL, 0);
se->CONFIG_REG = 0;
se_encrypt_with_srk(work_buf, 0, NULL, 0);
}

View file

@ -0,0 +1,227 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#ifndef FUSEE_SE_H
#define FUSEE_SE_H
#define SE_BASE 0x70012000
#define MAKE_SE_REG(n) MAKE_REG32(SE_BASE + n)
#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x2
#define KEYSLOT_SWITCH_SRKGENKEY 0x8
#define KEYSLOT_SWITCH_PACKAGE2KEY 0x8
#define KEYSLOT_SWITCH_TEMPKEY 0x9
#define KEYSLOT_SWITCH_SESSIONKEY 0xA
#define KEYSLOT_SWITCH_RNGKEY 0xB
#define KEYSLOT_SWITCH_MASTERKEY 0xC
#define KEYSLOT_SWITCH_DEVICEKEY 0xD
/* This keyslot was added in 4.0.0. */
#define KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY 0xD
#define KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY 0xE
#define KEYSLOT_SWITCH_4XOLDDEVICEKEY 0xF
/* This keyslot was added in 5.0.0. */
#define KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY 0xA
#define KEYSLOT_AES_MAX 0x10
#define KEYSLOT_RSA_MAX 0x2
#define KEYSIZE_AES_MAX 0x20
#define KEYSIZE_RSA_MAX 0x100
#define ALG_SHIFT (12)
#define ALG_DEC_SHIFT (8)
#define ALG_NOP (0 << ALG_SHIFT)
#define ALG_AES_ENC (1 << ALG_SHIFT)
#define ALG_AES_DEC ((1 << ALG_DEC_SHIFT) | ALG_NOP)
#define ALG_RNG (2 << ALG_SHIFT)
#define ALG_SHA (3 << ALG_SHIFT)
#define ALG_RSA (4 << ALG_SHIFT)
#define DST_SHIFT (2)
#define DST_MEMORY (0 << DST_SHIFT)
#define DST_HASHREG (1 << DST_SHIFT)
#define DST_KEYTAB (2 << DST_SHIFT)
#define DST_SRK (3 << DST_SHIFT)
#define DST_RSAREG (4 << DST_SHIFT)
#define ENCMODE_SHIFT (24)
#define DECMODE_SHIFT (16)
#define ENCMODE_SHA256 (5 << ENCMODE_SHIFT)
#define HASH_DISABLE (0x0)
#define HASH_ENABLE (0x1)
#define OP_ABORT 0
#define OP_START 1
#define OP_RESTART 2
#define OP_CTX_SAVE 3
#define OP_RESTART_IN 4
#define CTX_SAVE_SRC_SHIFT 29
#define CTX_SAVE_SRC_STICKY_BITS (0 << CTX_SAVE_SRC_SHIFT)
#define CTX_SAVE_SRC_KEYTABLE_AES (2 << CTX_SAVE_SRC_SHIFT)
#define CTX_SAVE_SRC_KEYTABLE_RSA (1 << CTX_SAVE_SRC_SHIFT)
#define CTX_SAVE_SRC_MEM (4 << CTX_SAVE_SRC_SHIFT)
#define CTX_SAVE_SRC_SRK (6 << CTX_SAVE_SRC_SHIFT)
#define CTX_SAVE_KEY_LOW_BITS 0
#define CTX_SAVE_KEY_HIGH_BITS 1
#define CTX_SAVE_KEY_ORIGINAL_IV 2
#define CTX_SAVE_KEY_UPDATED_IV 3
#define CTX_SAVE_STICKY_BIT_INDEX_SHIFT 24
#define CTX_SAVE_KEY_INDEX_SHIFT 8
#define CTX_SAVE_RSA_KEY_INDEX_SHIFT 16
#define CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT 12
#define RSA_2048_BYTES 0x100
typedef struct {
uint32_t _0x0;
uint32_t _0x4;
uint32_t OPERATION_REG;
uint32_t INT_ENABLE_REG;
uint32_t INT_STATUS_REG;
uint32_t CONFIG_REG;
uint32_t IN_LL_ADDR_REG;
uint32_t _0x1C;
uint32_t _0x20;
uint32_t OUT_LL_ADDR_REG;
uint32_t _0x28;
uint32_t _0x2C;
uint8_t HASH_RESULT_REG[0x20];
uint8_t _0x50[0x20];
uint32_t CONTEXT_SAVE_CONFIG_REG;
uint8_t _0x74[0x18C];
uint32_t SHA_CONFIG_REG;
uint32_t SHA_MSG_LENGTH_REG;
uint32_t _0x208;
uint32_t _0x20C;
uint32_t _0x210;
uint32_t SHA_MSG_LEFT_REG;
uint32_t _0x218;
uint32_t _0x21C;
uint32_t _0x220;
uint32_t _0x224;
uint8_t _0x228[0x58];
uint32_t AES_KEY_READ_DISABLE_REG;
uint32_t AES_KEYSLOT_FLAGS[0x10];
uint8_t _0x2C4[0x3C];
uint32_t _0x300;
uint32_t CRYPTO_REG;
uint32_t CRYPTO_CTR_REG[4];
uint32_t BLOCK_COUNT_REG;
uint32_t AES_KEYTABLE_ADDR;
uint32_t AES_KEYTABLE_DATA;
uint32_t _0x324;
uint32_t _0x328;
uint32_t _0x32C;
uint32_t CRYPTO_KEYTABLE_DST_REG;
uint8_t _0x334[0xC];
uint32_t RNG_CONFIG_REG;
uint32_t RNG_SRC_CONFIG_REG;
uint32_t RNG_RESEED_INTERVAL_REG;
uint8_t _0x34C[0xB4];
uint32_t RSA_CONFIG;
uint32_t RSA_KEY_SIZE_REG;
uint32_t RSA_EXP_SIZE_REG;
uint32_t RSA_KEY_READ_DISABLE_REG;
uint32_t RSA_KEYSLOT_FLAGS[2];
uint32_t _0x418;
uint32_t _0x41C;
uint32_t RSA_KEYTABLE_ADDR;
uint32_t RSA_KEYTABLE_DATA;
uint8_t RSA_OUTPUT[0x100];
uint8_t _0x528[0x2D8];
uint32_t FLAGS_REG;
uint32_t ERR_STATUS_REG;
uint32_t _0x808;
uint32_t SPARE_0;
uint32_t _0x810;
uint32_t _0x814;
uint32_t _0x818;
uint32_t _0x81C;
uint8_t _0x820[0x17E0];
} tegra_se_t;
typedef struct {
uint32_t address;
uint32_t size;
} se_addr_info_t;
typedef struct {
uint32_t num_entries; /* Set to total entries - 1 */
se_addr_info_t addr_info; /* This should really be an array...but for our use case it works. */
} se_ll_t;
static inline volatile tegra_se_t *se_get_regs(void) {
return (volatile tegra_se_t *)SE_BASE;
}
void se_check_error_status_reg(void);
void se_check_for_error(void);
void se_trigger_interrupt(void);
void se_validate_stored_vector(void);
void se_generate_stored_vector(void);
void se_verify_flags_cleared(void);
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags);
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags);
void clear_aes_keyslot(unsigned int keyslot);
void clear_rsa_keyslot(unsigned int keyslot);
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size);
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size);
void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size);
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size);
void set_se_ctr(const void *ctr);
/* Secure AES API */
void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size);
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv);
void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
/* Hash API */
void se_calculate_sha256(void *dst, const void *src, size_t src_size);
/* RSA API */
void se_get_exp_mod_output(void *buf, size_t size);
void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size);
/* RNG API */
void se_initialize_rng(unsigned int keyslot);
void se_generate_random(unsigned int keyslot, void *dst, size_t size);
/* SE context save API. */
void se_generate_srk(unsigned int srkgen_keyslot);
void se_set_in_context_save_mode(bool is_context_save_mode);
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot);
void se_save_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst);
void se_save_partial_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst);
#endif

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
#define cpuactlr_el1 s3_1_c15_c2_0
#define cpuectlr_el1 s3_1_c15_c2_1
.macro RESET_CORE
mov x0, #(1 << 63)
msr cpuactlr_el1, x0 /* disable regional clock gating */
isb
mov x0, #3
msr rmr_el3, x0
isb
dsb sy
/* Nintendo forgot to copy-paste the branch instruction below. */
1:
wfi
b 1b
.endm
.macro ERRATUM_INVALIDATE_BTB_AT_BOOT
/* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* The following comments are mine. */
/* mask all interrupts */
msr daifset, 0b1111
/*
Enable invalidates of branch target buffer, then flush
the entire instruction cache at the local level, and
with the reg change, the branch target buffer, then disable
invalidates of the branch target buffer again.
*/
mrs x0, cpuactlr_el1
orr x0, x0, #1
msr cpuactlr_el1, x0
dsb sy
isb
ic iallu
dsb sy
isb
mrs x0, cpuactlr_el1
bic x0, x0, #1
msr cpuactlr_el1, x0
.rept 7
nop /* wait long enough for the write to cpuactlr_el1 to have completed */
.endr
/* if the OS lock is set, disable it and request a warm reset */
mrs x0, oslsr_el1
ands x0, x0, #2
b.eq 2f
mov x0, xzr
msr oslar_el1, x0
RESET_CORE
.rept 65
nop /* guard against speculative excecution */
.endr
2:
/* set the OS lock */
mov x0, #1
msr oslar_el1, x0
.endm
.section .text.start
.align 4
.global _start
_start:
ERRATUM_INVALIDATE_BTB_AT_BOOT
msr spsel, #0
ldr x0, =__start__
mov sp, x0
mov fp, #0x0
bl derive_keys

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdarg.h>
#include "utils.h"
#include <inttypes.h>
__attribute__ ((noreturn)) void generic_panic(void) {
while(1) { /* ... */ }
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FUSEE_UTILS_H
#define FUSEE_UTILS_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define BIT(n) (1u << (n))
#define BITL(n) (1ull << (n))
#define MASK(n) (BIT(n) - 1)
#define MASKL(n) (BITL(n) - 1)
#define MASK2(a,b) (MASK(a) & ~MASK(b))
#define MASK2L(a,b) (MASKL(a) & ~MASKL(b))
#define MAKE_REG32(a) (*(volatile uint32_t *)(a))
#define ALIGN(m) __attribute__((aligned(m)))
#define PACKED __attribute__((packed))
#define ALINLINE __attribute__((always_inline))
#define NOINLINE __attribute__((noinline))
#define SET_SYSREG(reg, val) do { temp_reg = (val); __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false)
static inline uintptr_t get_physical_address(const void *addr) {
return (uintptr_t)addr;
}
static inline uint32_t read32le(const volatile void *dword, size_t offset) {
uintptr_t addr = (uintptr_t)dword + offset;
volatile uint32_t *target = (uint32_t *)addr;
return *target;
}
static inline uint32_t read32be(const volatile void *dword, size_t offset) {
return __builtin_bswap32(read32le(dword, offset));
}
static inline uint64_t read64le(const volatile void *qword, size_t offset) {
uintptr_t addr = (uintptr_t)qword + offset;
volatile uint64_t *target = (uint64_t *)addr;
return *target;
}
static inline uint64_t read64be(const volatile void *qword, size_t offset) {
return __builtin_bswap64(read64le(qword, offset));
}
static inline void write32le(volatile void *dword, size_t offset, uint32_t value) {
uintptr_t addr = (uintptr_t)dword + offset;
volatile uint32_t *target = (uint32_t *)addr;
*target = value;
}
static inline void write32be(volatile void *dword, size_t offset, uint32_t value) {
write32le(dword, offset, __builtin_bswap32(value));
}
static inline void write64le(volatile void *qword, size_t offset, uint64_t value) {
uintptr_t addr = (uintptr_t)qword + offset;
volatile uint64_t *target = (uint64_t *)addr;
*target = value;
}
static inline void write64be(volatile void *qword, size_t offset, uint64_t value) {
write64le(qword, offset, __builtin_bswap64(value));
}
static inline bool check_32bit_additive_overflow(uint32_t a, uint32_t b) {
return __builtin_add_overflow_p(a, b, (uint32_t)0);
}
static inline bool check_32bit_address_loadable(uintptr_t addr) {
/* FWIW the bootROM forbids loading anything between 0x40000000 and 0x40010000, using it for itself... */
return (addr >= 0x40010000u && addr < 0x40040000u) || addr >= 0x80000000u;
}
static inline bool check_32bit_address_range_loadable(uintptr_t addr, size_t size) {
return
!__builtin_add_overflow_p(addr, size, (uintptr_t)0) && /* the range doesn't overflow */
check_32bit_address_loadable(addr) && check_32bit_address_loadable(addr + size) && /* bounds are valid */
!(addr >= 0x40010000u && addr < 0x40040000u && addr + size >= 0x40040000u) /* the range doesn't cross MMIO */
;
}
bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be);
static inline bool overlaps_a(const void *as, const void *ae, const void *bs, const void *be) {
return overlaps((uint64_t)(uintptr_t)as, (uint64_t)(uintptr_t)ae, (uint64_t)(uintptr_t)bs, (uint64_t)(uintptr_t)be);
}
static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t size) {
extern uint8_t __chainloader_start__[], __chainloader_end__[];
extern uint8_t __stack_bottom__[], __stack_top__[];
extern uint8_t __start__[], __end__[];
uint8_t *start = (uint8_t *)addr, *end = start + size;
return overlaps_a(start, end, __chainloader_start__, __chainloader_end__) ||
overlaps_a(start, end, __stack_bottom__, __stack_top__) ||
overlaps_a(start, end, (void *)0xC0000000, (void *)0xC03C0000) || /* framebuffer */
overlaps_a(start, end, __start__, __end__);
}
__attribute__((noreturn)) void generic_panic(void);
#endif

View file

@ -20,8 +20,8 @@ MEMORY
SECTIONS
{
PROVIDE(__start__ = 0x40010000);
PROVIDE(__stack_top__ = 0x40010000);
PROVIDE(__stack_bottom__ = 0x4000C000);
PROVIDE(__stack_top__ = 0x4003C000);
PROVIDE(__stack_bottom__ = 0x40038000);
PROVIDE(__heap_start__ = 0);
PROVIDE(__heap_end__ = 0);

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include "cluster.h"
#include "flow.h"
#include "sysreg.h"
#include "i2c.h"
#include "car.h"
#include "mc.h"
#include "timers.h"
#include "pmc.h"
#include "max77620.h"
void _cluster_enable_power()
{
/* Reboot I2C5. */
clkrst_reboot(CARDEVICE_I2C5);
i2c_init(I2C_5);
uint8_t val = 0;
i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_AME_GPIO, &val, 1);
val &= 0xDF;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_AME_GPIO, &val, 1);
val = 0x09;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_GPIO5, &val, 1);
/* Enable power. */
val = 0x20;
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x02, &val, 1);
val = 0x8D;
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x03, &val, 1);
val = 0xB7;
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x00, &val, 1);
val = 0xB7;
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x01, &val, 1);
}
int _cluster_pmc_enable_partition(uint32_t part, uint32_t toggle)
{
volatile tegra_pmc_t *pmc = pmc_get_regs();
/* Check if the partition has already been turned on. */
if (pmc->pwrgate_status & part)
return 1;
uint32_t i = 5001;
while (pmc->pwrgate_toggle & 0x100)
{
udelay(1);
i--;
if (i < 1)
return 0;
}
pmc->pwrgate_toggle = (toggle | 0x100);
i = 5001;
while (i > 0)
{
if (pmc->pwrgate_status & part)
break;
udelay(1);
i--;
}
return 1;
}
void cluster_boot_cpu0(uint32_t entry)
{
volatile tegra_car_t *car = car_get_regs();
/* Set ACTIVE_CLUSER to FAST. */
FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 &= 0xFFFFFFFE;
_cluster_enable_power();
if (!(car->pllx_base & 0x40000000))
{
car->pllx_misc3 &= 0xFFFFFFF7;
udelay(2);
car->pllx_base = 0x80404E02;
car->pllx_base = 0x404E02;
car->pllx_misc = ((car->pllx_misc & 0xFFFBFFFF) | 0x40000);
car->pllx_base = 0x40404E02;
}
while (!(car->pllx_base & 0x8000000)) {
/* Wait. */
}
/* Configure MSELECT source and enable clock. */
car->clk_source_mselect = ((car->clk_source_mselect & 0x1FFFFF00) | 6);
car->clk_out_enb_v = ((car->clk_out_enb_v & 0xFFFFFFF7) | 8);
/* Configure initial CPU clock frequency and enable clock. */
car->cclk_brst_pol = 0x20008888;
car->super_cclk_div = 0x80000000;
car->clk_enb_v_set = 1;
clkrst_reboot(CARDEVICE_CORESIGHT);
/* CAR2PMC_CPU_ACK_WIDTH should be set to 0. */
car->cpu_softrst_ctrl2 &= 0xFFFFF000;
/* Enable CPU rail. */
_cluster_pmc_enable_partition(1, 0);
/* Enable cluster 0 non-CPU. */
_cluster_pmc_enable_partition(0x8000, 15);
/* Enable CE0. */
_cluster_pmc_enable_partition(0x4000, 14);
/* Request and wait for RAM repair. */
FLOW_CTLR_RAM_REPAIR_0 = 1;
while (!(FLOW_CTLR_RAM_REPAIR_0 & 2)) {
/* Wait. */
}
MAKE_EXCP_VEC_REG(0x100) = 0;
/* Set reset vector. */
SB_AA64_RESET_LOW_0 = (entry | 1);
SB_AA64_RESET_HIGH_0 = 0;
/* Non-secure reset vector write disable. */
SB_CSR_0 = 2;
(void)SB_CSR_0;
/* Set CPU_STRICT_TZ_APERTURE_CHECK. */
/* NOTE: [4.0.0+] This was added, but it breaks Exosphère. */
/* MAKE_MC_REG(MC_TZ_SECURITY_CTRL) = 1; */
/* Clear MSELECT reset. */
car->rst_dev_v &= 0xFFFFFFF7;
/* Clear NONCPU reset. */
car->rst_cpug_cmplx_clr = 0x20000000;
/* Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.*/
/* NOTE: [5.0.0+] This was changed so only CPU0 reset is cleared. */
/* car->rst_cpug_cmplx_clr = 0x411F000F; */
car->rst_cpug_cmplx_clr = 0x41010001;
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FUSEE_CLUSTER_H_
#define FUSEE_CLUSTER_H_
void cluster_boot_cpu0(uint32_t entry);
#endif

View file

@ -17,64 +17,65 @@
#include <stdio.h>
#include "key_derivation.h"
#include "se.h"
#include "cluster.h"
#include "timers.h"
#include "fuse.h"
#include "utils.h"
#define AL16 ALIGN(16)
#define u8 uint8_t
#define u32 uint32_t
#include "key_derivation_bin.h"
#undef u8
#undef u32
static const uint8_t AL16 keyblob_seed_00[0x10] = {
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
};
static const uint8_t AL16 masterkey_seed[0x10] = {
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
};
void derive_keys(void) {
/* Clear mailbox. */
volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00;
while (*mailbox != 0) {
*mailbox = 0;
}
static const uint8_t AL16 devicekey_seed[0x10] = {
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
};
/* Set derivation id. */
*((volatile uint32_t *)0x4003E800) = 0x0;
static const uint8_t AL16 devicekey_4x_seed[0x10] = {
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
};
/* Copy key derivation stub into IRAM high. */
for (size_t i = 0; i < key_derivation_bin_size; i += sizeof(uint32_t)) {
write32le((void *)0x4003D000, i, read32le(key_derivation_bin, i));
}
static const uint8_t AL16 masterkey_4x_seed[0x10] = {
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
};
cluster_boot_cpu0(0x4003D000);
static const uint8_t AL16 new_master_kek_seed_7x[0x10] = {
0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C
};
while (*mailbox != 7) {
/* Wait until keys have been derived. */
}
}
void derive_7x_keys(const void *tsec_key, void *tsec_root_key) {
uint8_t AL16 work_buffer[0x10];
void load_keys(const uint8_t *se_state) {
/* Clear keyslot 0xA. */
for (size_t i = 0; i < 0xA; i++) {
clear_aes_keyslot(0xA);
}
/* Copy device keygen key out of state keyslot 0xA into keyslot 0xA. */
set_aes_keyslot(0xA, se_state + 0x30 + (0xA * 0x20), 0x10);
/* Clear keyslot 0xB. */
clear_aes_keyslot(0xB);
/* Copy master key out of state keyslot 0xC into keyslot 0xC. */
set_aes_keyslot(0xC, se_state + 0x30 + (0xC * 0x20), 0x10);
/* Copy firmware device key out of state keyslot 0xE into keyslot 0xD. */
set_aes_keyslot(0xD, se_state + 0x30 + (0xE * 0x20), 0x10);
/* Clear keyslot 0xE. */
clear_aes_keyslot(0xE);
/* Copy device key out of state keyslot 0xF into keyslot 0xF. */
set_aes_keyslot(0xF, se_state + 0x30 + (0xF * 0x20), 0x10);
/* Set keyslot flags properly in preparation of derivation. */
set_aes_keyslot_flags(0xE, 0x15);
set_aes_keyslot_flags(0xD, 0x15);
/* Set the TSEC key. */
set_aes_keyslot(0xD, tsec_key, 0x10);
/* Derive keyblob key 0. */
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seed_00, 0x10);
decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10);
/* Clear the SBK. */
clear_aes_keyslot(0xE);
/* Derive the master kek. */
set_aes_keyslot(0xC, tsec_root_key, 0x10);
decrypt_data_into_keyslot(0xC, 0xC, new_master_kek_seed_7x, 0x10);
/* Derive keys for exosphere. */
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10);
/* Clear master kek from memory. */
for (size_t i = 0; i < sizeof(work_buffer); i++) {
work_buffer[i] = 0xCC;
}
}

View file

@ -13,7 +13,7 @@
* 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_KEYDERIVATION_H
#define SEPT_KEYDERIVATION_H
@ -21,6 +21,7 @@
#include <stdbool.h>
#include <stdint.h>
void derive_7x_keys(const void *tsec_key, void *tsec_root_key);
void derive_keys(void);
void load_keys(const uint8_t *se_state);
#endif

View file

@ -13,7 +13,7 @@
* 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 "utils.h"
#include "exception_handlers.h"
#include "panic.h"
@ -39,9 +39,6 @@ extern void (*__program_exit_callback)(int rc);
static void *g_framebuffer;
static uint32_t g_tsec_root_key[0x4] = {0};
static uint32_t g_tsec_key[0x4] = {0};
static bool has_rebooted(void) {
return MAKE_REG32(0x4003FFFC) == 0xFAFAFAFA;
}
@ -55,23 +52,15 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
volatile tegra_pmc_t *pmc = pmc_get_regs();
uint8_t *enc_se_state = (uint8_t *)0x4003E000;
uint8_t *dec_se_state = (uint8_t *)0x4003F000;
if (!has_rebooted()) {
/* Prepare for a reboot before doing anything else. */
prepare_for_reboot_to_self();
set_has_rebooted(true);
/* Save the security engine context. */
se_get_regs()->_0x4 = 0x0;
se_set_in_context_save_mode(true);
se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, enc_se_state);
se_set_in_context_save_mode(false);
/* Clear all keyslots. */
for (size_t k = 0; k < 0x10; k++) {
clear_aes_keyslot(k);
}
/* Derive keys. */
derive_keys();
reboot_to_self();
} else {
/* Decrypt the security engine state. */
@ -82,13 +71,10 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
context_key[3] = pmc->secure_scratch7;
set_aes_keyslot(0xC, context_key, sizeof(context_key));
se_aes_128_cbc_decrypt(0xC, dec_se_state, 0x840, enc_se_state, 0x840);
/* Copy out tsec key + tsec root key. */
for (size_t i = 0; i < 0x10; i += 4) {
g_tsec_key[i/4] = MAKE_REG32((uintptr_t)(dec_se_state) + 0x1B0 + i);
g_tsec_root_key[i/4] = MAKE_REG32((uintptr_t)(dec_se_state) + 0x1D0 + i);
}
/* Load keys in from decrypted state. */
load_keys(dec_se_state);
/* Clear the security engine state. */
for (size_t i = 0; i < 0x840; i += 4) {
MAKE_REG32((uintptr_t)(enc_se_state) + i) = 0xCCCCCCCC;
@ -101,11 +87,6 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
pmc->secure_scratch5 = 0xCCCCCCCC;
pmc->secure_scratch6 = 0xCCCCCCCC;
pmc->secure_scratch7 = 0xCCCCCCCC;
/* Clear all keyslots except for SBK/SSK. */
for (size_t k = 0; k < 0xE; k++) {
clear_aes_keyslot(k);
}
}
}
@ -126,7 +107,7 @@ static void setup_env(void) {
/* Set the framebuffer. */
display_init_framebuffer(g_framebuffer);
/* Draw splash. */
draw_splash((volatile uint32_t *)g_framebuffer);
@ -136,7 +117,7 @@ static void setup_env(void) {
/* Set up the exception handlers. */
setup_exception_handlers();
/* Mount the SD card. */
mount_sd();
}
@ -159,28 +140,19 @@ int main(void) {
stage2_args_t *stage2_args;
uint32_t stage2_version = 0;
ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE;
/* Extract keys from the security engine, which TSEC FW locked down. */
exfiltrate_keys_and_reboot_if_needed();
/* Override the global logging level. */
log_set_log_level(log_level);
/* Initialize the display, console, etc. */
setup_env();
/* Derive keys. */
derive_7x_keys(g_tsec_key, g_tsec_root_key);
/* Cleanup keys in memory. */
for (size_t i = 0; i < 0x10; i += 4) {
g_tsec_root_key[i/4] = 0xCCCCCCCC;
g_tsec_key[i/4] = 0xCCCCCCCC;
}
/* Mark EMC scratch to say that sept has run. */
MAKE_EMC_REG(EMC_SCRATCH0) |= 0x80000000;
/* Load the loader payload into DRAM. */
load_stage2();
@ -194,10 +166,10 @@ int main(void) {
stage2_args->display_initialized = false;
strcpy(stage2_args->bct0, "");
g_chainloader_argc = 2;
/* Wait a while. */
mdelay(1500);
/* Deinitialize the display, console, etc. */
cleanup_env();

View file

@ -13,7 +13,7 @@
* 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 <stdbool.h>
#include <stdarg.h>
#include "utils.h"
@ -66,13 +66,16 @@ __attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) {
}
void prepare_for_reboot_to_self(void) {
/* Write warmboot to scratch0. */
APBDEV_PMC_SCRATCH0_0 = 0x00000001;
/* Patch SDRAM init to perform an SVC immediately after second write */
APBDEV_PMC_SCRATCH45_0 = 0x2E38DFFF;
APBDEV_PMC_SCRATCH46_0 = 0x6001DC28;
/* Set SVC handler to jump to reboot stub in IRAM. */
APBDEV_PMC_SCRATCH33_0 = 0x4003F000;
APBDEV_PMC_SCRATCH40_0 = 0x6000F208;
/* Copy reboot stub into IRAM high. */
for (size_t i = 0; i < rebootstub_bin_size; i += sizeof(uint32_t)) {
write32le((void *)0x4003F000, i, read32le(rebootstub_bin, i));
@ -82,7 +85,7 @@ void prepare_for_reboot_to_self(void) {
__attribute__((noreturn)) void reboot_to_self(void) {
/* Prep IRAM for reboot. */
prepare_for_reboot_to_self();
/* Trigger warm reboot. */
pmc_reboot(1 << 0);
}