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 "masterkey.h"
#include "arm.h"
#include "pmc.h"
#include "randomcache.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->_0x0 &= 0xFFFFFFFB;
/* Currently unknown what each flag does. */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
set_aes_keyslot_flags(i, 0x15);
@ -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. */
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;
/* 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++) {
/* Validate section size alignment. */
if (metadata->section_sizes[section] & 3) {
@ -203,12 +207,17 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
}
/* Validate section hashes. */
void *section_data = (void *)((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(package2_header_t) + metadata->section_offsets[section]);
uint8_t calculated_hash[0x20];
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;
if (metadata->section_sizes[section]) {
void *section_data = (void *)((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(package2_header_t) + cur_section_offset);
uint8_t calculated_hash[0x20];
flush_dcache_range((uint8_t *)section_data, (uint8_t *)section_data + metadata->section_sizes[section]);
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. */
@ -219,10 +228,10 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
/* Perform version checks. */
/* 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) {
return false;
return true;
}
return true;
return false;
}
/* 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;
/* 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));
/* Copy the ctr (which stores information) into the decrypted metadata. */
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. */
generic_panic();
if (mkey_rev > mkey_get_revision()) {
panic(0xFAF00003);
}
}
return 0;
}
@ -297,6 +308,7 @@ static void load_package2_sections(package2_meta_t *metadata, uint32_t master_ke
load_buf = (void *)potential_base_start;
}
size_t cur_section_offset = 0;
/* Copy each section to its appropriate location, decrypting if necessary. */
for (unsigned int section = 0; section < PACKAGE2_SECTION_MAX; section++) {
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 *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];
if (bootconfig_is_package2_plaintext()) {
@ -312,6 +324,7 @@ static void load_package2_sections(package2_meta_t *metadata, uint32_t master_ke
} else {
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. */
@ -325,6 +338,7 @@ uintptr_t get_pk2ldr_stack_address(void) {
/* This function is called during coldboot init, and validates a package2. */
/* This package2 is read into memory by a concurrent BPMP bootloader. */
void load_package2(void) {
/* Setup the Security Engine. */
setup_se();
@ -346,6 +360,9 @@ void load_package2(void) {
/* Let NX Bootloader know that we're running. */
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. */
if (MAILBOX_NX_BOOTLOADER_SETUP_STATE == NX_BOOTLOADER_STATE_INIT) {
while (MAILBOX_NX_BOOTLOADER_SETUP_STATE < NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG) {
@ -353,6 +370,7 @@ void load_package2(void) {
}
}
/* Load Boot Config into global. */
setup_boot_config();
@ -369,15 +387,20 @@ void load_package2(void) {
memcpy(&header, NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, sizeof(header));
flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header));
/* Perform signature checks. */
verify_header_signature(&header);
/* Decrypt header, get key revision required. */
uint32_t package2_mkey_rev = decrypt_and_validate_header(&header);
/* Load Package2 Sections. */
load_package2_sections(&header.metadata, package2_mkey_rev);
/* Clean up cache. */
flush_dcache_all();
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();
}
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;
/* 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);
}
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) {