1
0
Fork 0
mirror of https://github.com/Atmosphere-NX/Atmosphere.git synced 2024-12-18 00:12:03 +00:00

Fix PK2LDR bugs, Fix SE bugs

This commit is contained in:
Michael Scire 2018-03-01 03:24:45 -08:00
parent 7850d3fd57
commit 205d3b8b80
2 changed files with 47 additions and 13 deletions

View file

@ -10,6 +10,7 @@
#include "interrupt.h" #include "interrupt.h"
#include "masterkey.h" #include "masterkey.h"
#include "arm.h" #include "arm.h"
#include "pmc.h"
#include "randomcache.h" #include "randomcache.h"
#include "timers.h" #include "timers.h"
@ -30,6 +31,8 @@ static void setup_se(void) {
p_security_engine->RSA_KEY_READ_DISABLE_REG = 0; p_security_engine->RSA_KEY_READ_DISABLE_REG = 0;
p_security_engine->_0x0 &= 0xFFFFFFFB; p_security_engine->_0x0 &= 0xFFFFFFFB;
/* Currently unknown what each flag does. */ /* Currently unknown what each flag does. */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) { for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
set_aes_keyslot_flags(i, 0x15); set_aes_keyslot_flags(i, 0x15);
@ -45,7 +48,7 @@ static void setup_se(void) {
/* Detect Master Key revision. */ /* Detect Master Key revision. */
mkey_detect_revision(); mkey_detect_revision();
/* Setup new device key, if necessary. */ /* Setup new device key, if necessary. */
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) { if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
const uint8_t new_devicekey_source_4x[0x10] = {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}; const uint8_t new_devicekey_source_4x[0x10] = {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D};
@ -140,7 +143,7 @@ static void verify_header_signature(package2_header_t *header) {
/* This is normally only allowed on dev units, but we'll allow it anywhere. */ /* This is normally only allowed on dev units, but we'll allow it anywhere. */
if (bootconfig_is_package2_unsigned() == 0 && se_rsa2048_pss_verify(header->signature, 0x100, modulus, 0x100, header->encrypted_header, 0x100) == 0) { if (bootconfig_is_package2_unsigned() == 0 && se_rsa2048_pss_verify(header->signature, 0x100, modulus, 0x100, header->encrypted_header, 0x100) == 0) {
generic_panic(); panic(0xF0000001); /* Invalid PK21 signature. */
} }
} }
@ -177,6 +180,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
bool entrypoint_found = false; bool entrypoint_found = false;
/* Header has space for 4 sections, but only 3 are validated/potentially loaded on hardware. */ /* Header has space for 4 sections, but only 3 are validated/potentially loaded on hardware. */
size_t cur_section_offset = 0;
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) { for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
/* Validate section size alignment. */ /* Validate section size alignment. */
if (metadata->section_sizes[section] & 3) { if (metadata->section_sizes[section] & 3) {
@ -203,12 +207,17 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
} }
/* Validate section hashes. */ /* Validate section hashes. */
void *section_data = (void *)((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(package2_header_t) + metadata->section_offsets[section]); if (metadata->section_sizes[section]) {
uint8_t calculated_hash[0x20]; void *section_data = (void *)((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(package2_header_t) + cur_section_offset);
se_calculate_sha256(calculated_hash, section_data, metadata->section_sizes[section]); uint8_t calculated_hash[0x20];
if (memcmp(calculated_hash, metadata->section_hashes[section], sizeof(metadata->section_hashes[section])) != 0) { flush_dcache_range((uint8_t *)section_data, (uint8_t *)section_data + metadata->section_sizes[section]);
return false; se_calculate_sha256(calculated_hash, section_data, metadata->section_sizes[section]);
if (memcmp(calculated_hash, metadata->section_hashes[section], sizeof(metadata->section_hashes[section])) != 0) {
return false;
}
cur_section_offset += metadata->section_sizes[section];
} }
} }
/* Ensure that entrypoint is present in one of our sections. */ /* Ensure that entrypoint is present in one of our sections. */
@ -219,10 +228,10 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
/* Perform version checks. */ /* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */ /* We will be compatible with all package2s released before current, but not newer ones. */
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_400_CURRENT) { if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_400_CURRENT) {
return false; return true;
} }
return true; return false;
} }
/* Decrypts package2 header, and returns the master key revision required. */ /* Decrypts package2 header, and returns the master key revision required. */
@ -233,7 +242,7 @@ static uint32_t decrypt_and_validate_header(package2_header_t *header) {
uint32_t mkey_rev; uint32_t mkey_rev;
/* Try to decrypt for all possible master keys. */ /* Try to decrypt for all possible master keys. */
for (mkey_rev = 0; mkey_rev < MASTERKEY_REVISION_MAX; mkey_rev++) { for (mkey_rev = 0; mkey_rev <= mkey_get_revision(); mkey_rev++) {
package2_crypt_ctr(mkey_rev, &metadata, sizeof(package2_meta_t), &header->metadata, sizeof(package2_meta_t), header->metadata.ctr, sizeof(header->metadata.ctr)); package2_crypt_ctr(mkey_rev, &metadata, sizeof(package2_meta_t), &header->metadata, sizeof(package2_meta_t), header->metadata.ctr, sizeof(header->metadata.ctr));
/* Copy the ctr (which stores information) into the decrypted metadata. */ /* Copy the ctr (which stores information) into the decrypted metadata. */
memcpy(metadata.ctr, header->metadata.ctr, sizeof(header->metadata.ctr)); memcpy(metadata.ctr, header->metadata.ctr, sizeof(header->metadata.ctr));
@ -245,7 +254,9 @@ static uint32_t decrypt_and_validate_header(package2_header_t *header) {
} }
/* Ensure we successfully decrypted the header. */ /* Ensure we successfully decrypted the header. */
generic_panic(); if (mkey_rev > mkey_get_revision()) {
panic(0xFAF00003);
}
} }
return 0; return 0;
} }
@ -296,7 +307,8 @@ static void load_package2_sections(package2_meta_t *metadata, uint32_t master_ke
memset(load_buf, 0, PACKAGE2_SIZE_MAX); memset(load_buf, 0, PACKAGE2_SIZE_MAX);
load_buf = (void *)potential_base_start; load_buf = (void *)potential_base_start;
} }
size_t cur_section_offset = 0;
/* Copy each section to its appropriate location, decrypting if necessary. */ /* Copy each section to its appropriate location, decrypting if necessary. */
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) { for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
if (metadata->section_sizes[section] == 0) { if (metadata->section_sizes[section] == 0) {
@ -304,7 +316,7 @@ static void load_package2_sections(package2_meta_t *metadata, uint32_t master_ke
} }
void *dst_start = (void *)(DRAM_BASE_PHYSICAL + (uint64_t)metadata->section_offsets[section]); void *dst_start = (void *)(DRAM_BASE_PHYSICAL + (uint64_t)metadata->section_offsets[section]);
void *src_start = load_buf + sizeof(package2_header_t) + metadata->section_offsets[section]; void *src_start = load_buf + sizeof(package2_header_t) + cur_section_offset;
size_t size = (size_t)metadata->section_sizes[section]; size_t size = (size_t)metadata->section_sizes[section];
if (bootconfig_is_package2_plaintext()) { if (bootconfig_is_package2_plaintext()) {
@ -312,6 +324,7 @@ static void load_package2_sections(package2_meta_t *metadata, uint32_t master_ke
} else { } else {
package2_crypt_ctr(master_key_rev, dst_start, size, src_start, size, metadata->section_ctrs[section], 0x10); package2_crypt_ctr(master_key_rev, dst_start, size, src_start, size, metadata->section_ctrs[section], 0x10);
} }
cur_section_offset += size;
} }
/* Clear the encrypted package2 from memory. */ /* Clear the encrypted package2 from memory. */
@ -325,6 +338,7 @@ uintptr_t get_pk2ldr_stack_address(void) {
/* This function is called during coldboot init, and validates a package2. */ /* This function is called during coldboot init, and validates a package2. */
/* This package2 is read into memory by a concurrent BPMP bootloader. */ /* This package2 is read into memory by a concurrent BPMP bootloader. */
void load_package2(void) { void load_package2(void) {
/* Setup the Security Engine. */ /* Setup the Security Engine. */
setup_se(); setup_se();
@ -346,6 +360,9 @@ void load_package2(void) {
/* Let NX Bootloader know that we're running. */ /* Let NX Bootloader know that we're running. */
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 1; MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 1;
/* Wait for 1 second, to allow time for NX_BOOTLOADER to draw to the screen. This is useful for debugging. */
wait(1000000);
/* Synchronize with NX BOOTLOADER. */ /* Synchronize with NX BOOTLOADER. */
if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_INIT) { if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_INIT) {
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG) { while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG) {
@ -353,6 +370,7 @@ void load_package2(void) {
} }
} }
/* Load Boot Config into global. */ /* Load Boot Config into global. */
setup_boot_config(); setup_boot_config();
@ -369,15 +387,20 @@ void load_package2(void) {
memcpy(&header, 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)); flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header));
/* Perform signature checks. */ /* Perform signature checks. */
verify_header_signature(&header); verify_header_signature(&header);
/* Decrypt header, get key revision required. */ /* Decrypt header, get key revision required. */
uint32_t package2_mkey_rev = decrypt_and_validate_header(&header); uint32_t package2_mkey_rev = decrypt_and_validate_header(&header);
/* Load Package2 Sections. */ /* Load Package2 Sections. */
load_package2_sections(&header.metadata, package2_mkey_rev); load_package2_sections(&header.metadata, package2_mkey_rev);
/* Clean up cache. */ /* Clean up cache. */
flush_dcache_all(); flush_dcache_all();
invalidate_icache_all_inner_shareable(); invalidate_icache_all_inner_shareable();

View file

@ -460,6 +460,13 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
generic_panic(); generic_panic();
} }
if (src_size) {
flush_dcache_range((uint8_t *)src, (uint8_t *)src + src_size);
}
if (dst_size) {
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
}
unsigned int num_blocks = src_size >> 4; unsigned int num_blocks = src_size >> 4;
/* Unknown what this write does, but official code writes it for CTR mode. */ /* Unknown what this write does, but official code writes it for CTR mode. */
@ -483,6 +490,10 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
} }
se_perform_aes_block_operation(dst + aligned_size, last_block_size, (uint8_t *)src + aligned_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);
} }
if (dst_size) {
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_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) { 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) {