diff --git a/exosphere2/program/source/boot/secmon_boot.hpp b/exosphere2/program/source/boot/secmon_boot.hpp index eb5138bcd..469aa8884 100644 --- a/exosphere2/program/source/boot/secmon_boot.hpp +++ b/exosphere2/program/source/boot/secmon_boot.hpp @@ -20,6 +20,7 @@ namespace ams::secmon::boot { void MakePageTable(); void UnmapPhysicalIdentityMapping(); + void UnmapDram(); void InitializeColdBoot(); @@ -29,7 +30,13 @@ namespace ams::secmon::boot { bool VerifyBootConfigSignature(pkg1::BootConfig &bc, const void *mod, size_t mod_size); bool VerifyBootConfigEcid(const pkg1::BootConfig &bc); + void CalculatePackage2Hash(se::Sha256Hash *dst, const pkg2::Package2Meta &meta, uintptr_t package2_start); + bool VerifyPackage2Signature(pkg2::Package2Header &header, const void *mod, size_t mod_size); void DecryptPackage2(void *dst, size_t dst_size, const void *src, size_t src_size, const void *key, size_t key_size, const void *iv, size_t iv_size, u8 key_generation); + bool VerifyPackage2Meta(const pkg2::Package2Meta &meta); + bool VerifyPackage2Version(const pkg2::Package2Meta &meta); + bool VerifyPackage2Payloads(const pkg2::Package2Meta &meta, uintptr_t payload_address); + } \ No newline at end of file diff --git a/exosphere2/program/source/boot/secmon_boot_functions.cpp b/exosphere2/program/source/boot/secmon_boot_functions.cpp index 1cce9cc1e..6c33be920 100644 --- a/exosphere2/program/source/boot/secmon_boot_functions.cpp +++ b/exosphere2/program/source/boot/secmon_boot_functions.cpp @@ -18,6 +18,7 @@ #include "secmon_boot.hpp" #include "secmon_boot_cache.hpp" #include "secmon_boot_functions.hpp" +#include "secmon_boot_key_data.hpp" namespace ams::secmon::boot { @@ -25,66 +26,9 @@ namespace ams::secmon::boot { constexpr inline uintptr_t SYSCTR0 = MemoryRegionVirtualDeviceSysCtr0.GetAddress(); - constinit const u8 BootConfigRsaPublicModulus[se::RsaSize] = { - 0xB5, 0x96, 0x87, 0x31, 0x39, 0xAA, 0xBB, 0x3C, 0x28, 0xF3, 0xF0, 0x65, 0xF1, 0x50, 0x70, 0x64, - 0xE6, 0x6C, 0x97, 0x50, 0xCD, 0xA6, 0xEE, 0xEA, 0xC3, 0x8F, 0xE6, 0xB5, 0x81, 0x54, 0x65, 0x33, - 0x1B, 0x88, 0x4B, 0xCE, 0x9F, 0x53, 0xDF, 0xE4, 0xF6, 0xAD, 0xC3, 0x78, 0xD7, 0x3C, 0xD1, 0xDB, - 0x27, 0x21, 0xA0, 0x24, 0x30, 0x2D, 0x98, 0x41, 0xA8, 0xDF, 0x50, 0x7D, 0xAB, 0xCE, 0x00, 0xD9, - 0xCB, 0xAC, 0x8F, 0x37, 0xF5, 0x53, 0xE4, 0x97, 0x1F, 0x13, 0x3C, 0x19, 0xFF, 0x05, 0xA7, 0x3B, - 0xF6, 0xF4, 0x01, 0xDE, 0xF0, 0xC3, 0x77, 0x7B, 0x83, 0xBA, 0xAF, 0x99, 0x30, 0x94, 0x87, 0x25, - 0x4E, 0x54, 0x42, 0x3F, 0xAC, 0x27, 0xF9, 0xCC, 0x87, 0xDD, 0xAE, 0xF2, 0x54, 0xF3, 0x97, 0x49, - 0xF4, 0xB0, 0xF8, 0x6D, 0xDA, 0x60, 0xE0, 0xFD, 0x57, 0xAE, 0x55, 0xA9, 0x76, 0xEA, 0x80, 0x24, - 0xA0, 0x04, 0x7D, 0xBE, 0xD1, 0x81, 0xD3, 0x0C, 0x95, 0xCF, 0xB7, 0xE0, 0x2D, 0x21, 0x21, 0xFF, - 0x97, 0x1E, 0xB3, 0xD7, 0x9F, 0xBB, 0x33, 0x0C, 0x23, 0xC5, 0x88, 0x4A, 0x33, 0xB9, 0xC9, 0x4E, - 0x1E, 0x65, 0x51, 0x45, 0xDE, 0xF9, 0x64, 0x7C, 0xF0, 0xBF, 0x11, 0xB4, 0x93, 0x8D, 0x5D, 0xC6, - 0xAB, 0x37, 0x9E, 0xE9, 0x39, 0xC1, 0xC8, 0xDB, 0xB9, 0xFE, 0x45, 0xCE, 0x7B, 0xDD, 0x72, 0xD9, - 0x6F, 0x68, 0x13, 0xC0, 0x4B, 0xBA, 0x00, 0xF4, 0x1E, 0x89, 0x71, 0x91, 0x26, 0xA6, 0x46, 0x12, - 0xDF, 0x29, 0x6B, 0xC2, 0x5A, 0x53, 0xAF, 0xB9, 0x5B, 0xFD, 0x13, 0x9F, 0xD1, 0x8A, 0x7C, 0xB5, - 0x04, 0xFD, 0x69, 0xEA, 0x23, 0xB4, 0x6D, 0x16, 0x21, 0x98, 0x54, 0xB4, 0xDF, 0xE6, 0xAB, 0x93, - 0x36, 0xB6, 0xD2, 0x43, 0xCF, 0x2B, 0x98, 0x1D, 0x45, 0xC9, 0xBB, 0x20, 0x42, 0xB1, 0x9D, 0x1D - }; - - constinit const u8 Package2RsaPublicModulusProduction[se::RsaSize] = { - 0x8D, 0x13, 0xA7, 0x77, 0x6A, 0xE5, 0xDC, 0xC0, 0x3B, 0x25, 0xD0, 0x58, 0xE4, 0x20, 0x69, 0x59, - 0x55, 0x4B, 0xAB, 0x70, 0x40, 0x08, 0x28, 0x07, 0xA8, 0xA7, 0xFD, 0x0F, 0x31, 0x2E, 0x11, 0xFE, - 0x47, 0xA0, 0xF9, 0x9D, 0xDF, 0x80, 0xDB, 0x86, 0x5A, 0x27, 0x89, 0xCD, 0x97, 0x6C, 0x85, 0xC5, - 0x6C, 0x39, 0x7F, 0x41, 0xF2, 0xFF, 0x24, 0x20, 0xC3, 0x95, 0xA6, 0xF7, 0x9D, 0x4A, 0x45, 0x74, - 0x8B, 0x5D, 0x28, 0x8A, 0xC6, 0x99, 0x35, 0x68, 0x85, 0xA5, 0x64, 0x32, 0x80, 0x9F, 0xD3, 0x48, - 0x39, 0xA2, 0x1D, 0x24, 0x67, 0x69, 0xDF, 0x75, 0xAC, 0x12, 0xB5, 0xBD, 0xC3, 0x29, 0x90, 0xBE, - 0x37, 0xE4, 0xA0, 0x80, 0x9A, 0xBE, 0x36, 0xBF, 0x1F, 0x2C, 0xAB, 0x2B, 0xAD, 0xF5, 0x97, 0x32, - 0x9A, 0x42, 0x9D, 0x09, 0x8B, 0x08, 0xF0, 0x63, 0x47, 0xA3, 0xE9, 0x1B, 0x36, 0xD8, 0x2D, 0x8A, - 0xD7, 0xE1, 0x54, 0x11, 0x95, 0xE4, 0x45, 0x88, 0x69, 0x8A, 0x2B, 0x35, 0xCE, 0xD0, 0xA5, 0x0B, - 0xD5, 0x5D, 0xAC, 0xDB, 0xAF, 0x11, 0x4D, 0xCA, 0xB8, 0x1E, 0xE7, 0x01, 0x9E, 0xF4, 0x46, 0xA3, - 0x8A, 0x94, 0x6D, 0x76, 0xBD, 0x8A, 0xC8, 0x3B, 0xD2, 0x31, 0x58, 0x0C, 0x79, 0xA8, 0x26, 0xE9, - 0xD1, 0x79, 0x9C, 0xCB, 0xD4, 0x2B, 0x6A, 0x4F, 0xC6, 0xCC, 0xCF, 0x90, 0xA7, 0xB9, 0x98, 0x47, - 0xFD, 0xFA, 0x4C, 0x6C, 0x6F, 0x81, 0x87, 0x3B, 0xCA, 0xB8, 0x50, 0xF6, 0x3E, 0x39, 0x5D, 0x4D, - 0x97, 0x3F, 0x0F, 0x35, 0x39, 0x53, 0xFB, 0xFA, 0xCD, 0xAB, 0xA8, 0x7A, 0x62, 0x9A, 0x3F, 0xF2, - 0x09, 0x27, 0x96, 0x3F, 0x07, 0x9A, 0x91, 0xF7, 0x16, 0xBF, 0xC6, 0x3A, 0x82, 0x5A, 0x4B, 0xCF, - 0x49, 0x50, 0x95, 0x8C, 0x55, 0x80, 0x7E, 0x39, 0xB1, 0x48, 0x05, 0x1E, 0x21, 0xC7, 0x24, 0x4F - }; - - constinit const u8 Package2RsaPublicModulusDevelopment[se::RsaSize] = { - 0xB3, 0x65, 0x54, 0xFB, 0x0A, 0xB0, 0x1E, 0x85, 0xA7, 0xF6, 0xCF, 0x91, 0x8E, 0xBA, 0x96, 0x99, - 0x0D, 0x8B, 0x91, 0x69, 0x2A, 0xEE, 0x01, 0x20, 0x4F, 0x34, 0x5C, 0x2C, 0x4F, 0x4E, 0x37, 0xC7, - 0xF1, 0x0B, 0xD4, 0xCD, 0xA1, 0x7F, 0x93, 0xF1, 0x33, 0x59, 0xCE, 0xB1, 0xE9, 0xDD, 0x26, 0xE6, - 0xF3, 0xBB, 0x77, 0x87, 0x46, 0x7A, 0xD6, 0x4E, 0x47, 0x4A, 0xD1, 0x41, 0xB7, 0x79, 0x4A, 0x38, - 0x06, 0x6E, 0xCF, 0x61, 0x8F, 0xCD, 0xC1, 0x40, 0x0B, 0xFA, 0x26, 0xDC, 0xC0, 0x34, 0x51, 0x83, - 0xD9, 0x3B, 0x11, 0x54, 0x3B, 0x96, 0x27, 0x32, 0x9A, 0x95, 0xBE, 0x1E, 0x68, 0x11, 0x50, 0xA0, - 0x6B, 0x10, 0xA8, 0x83, 0x8B, 0xF5, 0xFC, 0xBC, 0x90, 0x84, 0x7A, 0x5A, 0x5C, 0x43, 0x52, 0xE6, - 0xC8, 0x26, 0xE9, 0xFE, 0x06, 0xA0, 0x8B, 0x53, 0x0F, 0xAF, 0x1E, 0xC4, 0x1C, 0x0B, 0xCF, 0x50, - 0x1A, 0xA4, 0xF3, 0x5C, 0xFB, 0xF0, 0x97, 0xE4, 0xDE, 0x32, 0x0A, 0x9F, 0xE3, 0x5A, 0xAA, 0xB7, - 0x44, 0x7F, 0x5C, 0x33, 0x60, 0xB9, 0x0F, 0x22, 0x2D, 0x33, 0x2A, 0xE9, 0x69, 0x79, 0x31, 0x42, - 0x8F, 0xE4, 0x3A, 0x13, 0x8B, 0xE7, 0x26, 0xBD, 0x08, 0x87, 0x6C, 0xA6, 0xF2, 0x73, 0xF6, 0x8E, - 0xA7, 0xF2, 0xFE, 0xFB, 0x6C, 0x28, 0x66, 0x0D, 0xBD, 0xD7, 0xEB, 0x42, 0xA8, 0x78, 0xE6, 0xB8, - 0x6B, 0xAE, 0xC7, 0xA9, 0xE2, 0x40, 0x6E, 0x89, 0x20, 0x82, 0x25, 0x8E, 0x3C, 0x6A, 0x60, 0xD7, - 0xF3, 0x56, 0x8E, 0xEC, 0x8D, 0x51, 0x8A, 0x63, 0x3C, 0x04, 0x78, 0x23, 0x0E, 0x90, 0x0C, 0xB4, - 0xE7, 0x86, 0x3B, 0x4F, 0x8E, 0x13, 0x09, 0x47, 0x32, 0x0E, 0x04, 0xB8, 0x4D, 0x5B, 0xB0, 0x46, - 0x71, 0xB0, 0x5C, 0xF4, 0xAD, 0x63, 0x4F, 0xC5, 0xE2, 0xAC, 0x1E, 0xC4, 0x33, 0x96, 0x09, 0x7B - }; - - constinit const u8 Package2AesKey[] { - 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 - }; + NOINLINE void DecryptPayload(uintptr_t dst, uintptr_t src, size_t size, const void *iv, size_t iv_size, u8 key_generation) { + secmon::boot::DecryptPackage2(reinterpret_cast(dst), size, reinterpret_cast(src), size, Package2AesKey, util::size(Package2AesKey), iv, iv_size, key_generation); + } } @@ -215,4 +159,27 @@ namespace ams::secmon::boot { } } + void VerifyPackage2Header(const pkg2::Package2Meta &meta) { + /* Validate the metadata. */ + CheckVerifyResult(VerifyPackage2Meta(meta), pkg1::ErrorInfo_InvalidPackage2Meta, "package2 meta verification failed"); + + /* Validate the version. */ + CheckVerifyResult(VerifyPackage2Version(meta), pkg1::ErrorInfo_InvalidPackage2Version, "package2 version verification failed"); + } + + void DecryptAndLoadPackage2Payloads(uintptr_t dst, const pkg2::Package2Meta &meta, uintptr_t src, bool encrypted) { + /* Get the key generation for crypto. */ + const u8 key_generation = meta.GetKeyGeneration(); + /* Decrypt or load each payload in order. */ + for (int i = 0; i < pkg2::PayloadCount; ++i) { + if (encrypted) { + DecryptPayload(dst + meta.payload_offsets[i], src, meta.payload_sizes[i], meta.payload_ivs[i], sizeof(meta.payload_ivs[i]), key_generation); + } else { + std::memcpy(reinterpret_cast(dst + meta.payload_offsets[i]), reinterpret_cast(src), meta.payload_sizes[i]); + } + + src += meta.payload_sizes[i]; + } + } + } diff --git a/exosphere2/program/source/boot/secmon_boot_functions.hpp b/exosphere2/program/source/boot/secmon_boot_functions.hpp index 7d3d05ebc..c03a04b64 100644 --- a/exosphere2/program/source/boot/secmon_boot_functions.hpp +++ b/exosphere2/program/source/boot/secmon_boot_functions.hpp @@ -33,6 +33,10 @@ namespace ams::secmon::boot { void VerifyPackage2HeaderSignature(pkg2::Package2Header &header, bool verify); void DecryptPackage2Header(pkg2::Package2Meta *dst, const pkg2::Package2Meta &src, bool encrypted); + void VerifyPackage2Header(const pkg2::Package2Meta &meta); + + void DecryptAndLoadPackage2Payloads(uintptr_t dst, const pkg2::Package2Meta &meta, uintptr_t src, bool encrypted); + void CheckVerifyResult(bool verify_result, pkg1::ErrorInfo error_info, const char *message); } diff --git a/exosphere2/program/source/boot/secmon_boot_key_data.cpp b/exosphere2/program/source/boot/secmon_boot_key_data.cpp new file mode 100644 index 000000000..e3e74dd6e --- /dev/null +++ b/exosphere2/program/source/boot/secmon_boot_key_data.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#include +#include "secmon_boot_key_data.hpp" + +namespace ams::secmon::boot { + + constinit const u8 BootConfigRsaPublicModulus[se::RsaSize] = { + 0xB5, 0x96, 0x87, 0x31, 0x39, 0xAA, 0xBB, 0x3C, 0x28, 0xF3, 0xF0, 0x65, 0xF1, 0x50, 0x70, 0x64, + 0xE6, 0x6C, 0x97, 0x50, 0xCD, 0xA6, 0xEE, 0xEA, 0xC3, 0x8F, 0xE6, 0xB5, 0x81, 0x54, 0x65, 0x33, + 0x1B, 0x88, 0x4B, 0xCE, 0x9F, 0x53, 0xDF, 0xE4, 0xF6, 0xAD, 0xC3, 0x78, 0xD7, 0x3C, 0xD1, 0xDB, + 0x27, 0x21, 0xA0, 0x24, 0x30, 0x2D, 0x98, 0x41, 0xA8, 0xDF, 0x50, 0x7D, 0xAB, 0xCE, 0x00, 0xD9, + 0xCB, 0xAC, 0x8F, 0x37, 0xF5, 0x53, 0xE4, 0x97, 0x1F, 0x13, 0x3C, 0x19, 0xFF, 0x05, 0xA7, 0x3B, + 0xF6, 0xF4, 0x01, 0xDE, 0xF0, 0xC3, 0x77, 0x7B, 0x83, 0xBA, 0xAF, 0x99, 0x30, 0x94, 0x87, 0x25, + 0x4E, 0x54, 0x42, 0x3F, 0xAC, 0x27, 0xF9, 0xCC, 0x87, 0xDD, 0xAE, 0xF2, 0x54, 0xF3, 0x97, 0x49, + 0xF4, 0xB0, 0xF8, 0x6D, 0xDA, 0x60, 0xE0, 0xFD, 0x57, 0xAE, 0x55, 0xA9, 0x76, 0xEA, 0x80, 0x24, + 0xA0, 0x04, 0x7D, 0xBE, 0xD1, 0x81, 0xD3, 0x0C, 0x95, 0xCF, 0xB7, 0xE0, 0x2D, 0x21, 0x21, 0xFF, + 0x97, 0x1E, 0xB3, 0xD7, 0x9F, 0xBB, 0x33, 0x0C, 0x23, 0xC5, 0x88, 0x4A, 0x33, 0xB9, 0xC9, 0x4E, + 0x1E, 0x65, 0x51, 0x45, 0xDE, 0xF9, 0x64, 0x7C, 0xF0, 0xBF, 0x11, 0xB4, 0x93, 0x8D, 0x5D, 0xC6, + 0xAB, 0x37, 0x9E, 0xE9, 0x39, 0xC1, 0xC8, 0xDB, 0xB9, 0xFE, 0x45, 0xCE, 0x7B, 0xDD, 0x72, 0xD9, + 0x6F, 0x68, 0x13, 0xC0, 0x4B, 0xBA, 0x00, 0xF4, 0x1E, 0x89, 0x71, 0x91, 0x26, 0xA6, 0x46, 0x12, + 0xDF, 0x29, 0x6B, 0xC2, 0x5A, 0x53, 0xAF, 0xB9, 0x5B, 0xFD, 0x13, 0x9F, 0xD1, 0x8A, 0x7C, 0xB5, + 0x04, 0xFD, 0x69, 0xEA, 0x23, 0xB4, 0x6D, 0x16, 0x21, 0x98, 0x54, 0xB4, 0xDF, 0xE6, 0xAB, 0x93, + 0x36, 0xB6, 0xD2, 0x43, 0xCF, 0x2B, 0x98, 0x1D, 0x45, 0xC9, 0xBB, 0x20, 0x42, 0xB1, 0x9D, 0x1D + }; + + constinit const u8 Package2RsaPublicModulusProduction[se::RsaSize] = { + 0x8D, 0x13, 0xA7, 0x77, 0x6A, 0xE5, 0xDC, 0xC0, 0x3B, 0x25, 0xD0, 0x58, 0xE4, 0x20, 0x69, 0x59, + 0x55, 0x4B, 0xAB, 0x70, 0x40, 0x08, 0x28, 0x07, 0xA8, 0xA7, 0xFD, 0x0F, 0x31, 0x2E, 0x11, 0xFE, + 0x47, 0xA0, 0xF9, 0x9D, 0xDF, 0x80, 0xDB, 0x86, 0x5A, 0x27, 0x89, 0xCD, 0x97, 0x6C, 0x85, 0xC5, + 0x6C, 0x39, 0x7F, 0x41, 0xF2, 0xFF, 0x24, 0x20, 0xC3, 0x95, 0xA6, 0xF7, 0x9D, 0x4A, 0x45, 0x74, + 0x8B, 0x5D, 0x28, 0x8A, 0xC6, 0x99, 0x35, 0x68, 0x85, 0xA5, 0x64, 0x32, 0x80, 0x9F, 0xD3, 0x48, + 0x39, 0xA2, 0x1D, 0x24, 0x67, 0x69, 0xDF, 0x75, 0xAC, 0x12, 0xB5, 0xBD, 0xC3, 0x29, 0x90, 0xBE, + 0x37, 0xE4, 0xA0, 0x80, 0x9A, 0xBE, 0x36, 0xBF, 0x1F, 0x2C, 0xAB, 0x2B, 0xAD, 0xF5, 0x97, 0x32, + 0x9A, 0x42, 0x9D, 0x09, 0x8B, 0x08, 0xF0, 0x63, 0x47, 0xA3, 0xE9, 0x1B, 0x36, 0xD8, 0x2D, 0x8A, + 0xD7, 0xE1, 0x54, 0x11, 0x95, 0xE4, 0x45, 0x88, 0x69, 0x8A, 0x2B, 0x35, 0xCE, 0xD0, 0xA5, 0x0B, + 0xD5, 0x5D, 0xAC, 0xDB, 0xAF, 0x11, 0x4D, 0xCA, 0xB8, 0x1E, 0xE7, 0x01, 0x9E, 0xF4, 0x46, 0xA3, + 0x8A, 0x94, 0x6D, 0x76, 0xBD, 0x8A, 0xC8, 0x3B, 0xD2, 0x31, 0x58, 0x0C, 0x79, 0xA8, 0x26, 0xE9, + 0xD1, 0x79, 0x9C, 0xCB, 0xD4, 0x2B, 0x6A, 0x4F, 0xC6, 0xCC, 0xCF, 0x90, 0xA7, 0xB9, 0x98, 0x47, + 0xFD, 0xFA, 0x4C, 0x6C, 0x6F, 0x81, 0x87, 0x3B, 0xCA, 0xB8, 0x50, 0xF6, 0x3E, 0x39, 0x5D, 0x4D, + 0x97, 0x3F, 0x0F, 0x35, 0x39, 0x53, 0xFB, 0xFA, 0xCD, 0xAB, 0xA8, 0x7A, 0x62, 0x9A, 0x3F, 0xF2, + 0x09, 0x27, 0x96, 0x3F, 0x07, 0x9A, 0x91, 0xF7, 0x16, 0xBF, 0xC6, 0x3A, 0x82, 0x5A, 0x4B, 0xCF, + 0x49, 0x50, 0x95, 0x8C, 0x55, 0x80, 0x7E, 0x39, 0xB1, 0x48, 0x05, 0x1E, 0x21, 0xC7, 0x24, 0x4F + }; + + constinit const u8 Package2RsaPublicModulusDevelopment[se::RsaSize] = { + 0xB3, 0x65, 0x54, 0xFB, 0x0A, 0xB0, 0x1E, 0x85, 0xA7, 0xF6, 0xCF, 0x91, 0x8E, 0xBA, 0x96, 0x99, + 0x0D, 0x8B, 0x91, 0x69, 0x2A, 0xEE, 0x01, 0x20, 0x4F, 0x34, 0x5C, 0x2C, 0x4F, 0x4E, 0x37, 0xC7, + 0xF1, 0x0B, 0xD4, 0xCD, 0xA1, 0x7F, 0x93, 0xF1, 0x33, 0x59, 0xCE, 0xB1, 0xE9, 0xDD, 0x26, 0xE6, + 0xF3, 0xBB, 0x77, 0x87, 0x46, 0x7A, 0xD6, 0x4E, 0x47, 0x4A, 0xD1, 0x41, 0xB7, 0x79, 0x4A, 0x38, + 0x06, 0x6E, 0xCF, 0x61, 0x8F, 0xCD, 0xC1, 0x40, 0x0B, 0xFA, 0x26, 0xDC, 0xC0, 0x34, 0x51, 0x83, + 0xD9, 0x3B, 0x11, 0x54, 0x3B, 0x96, 0x27, 0x32, 0x9A, 0x95, 0xBE, 0x1E, 0x68, 0x11, 0x50, 0xA0, + 0x6B, 0x10, 0xA8, 0x83, 0x8B, 0xF5, 0xFC, 0xBC, 0x90, 0x84, 0x7A, 0x5A, 0x5C, 0x43, 0x52, 0xE6, + 0xC8, 0x26, 0xE9, 0xFE, 0x06, 0xA0, 0x8B, 0x53, 0x0F, 0xAF, 0x1E, 0xC4, 0x1C, 0x0B, 0xCF, 0x50, + 0x1A, 0xA4, 0xF3, 0x5C, 0xFB, 0xF0, 0x97, 0xE4, 0xDE, 0x32, 0x0A, 0x9F, 0xE3, 0x5A, 0xAA, 0xB7, + 0x44, 0x7F, 0x5C, 0x33, 0x60, 0xB9, 0x0F, 0x22, 0x2D, 0x33, 0x2A, 0xE9, 0x69, 0x79, 0x31, 0x42, + 0x8F, 0xE4, 0x3A, 0x13, 0x8B, 0xE7, 0x26, 0xBD, 0x08, 0x87, 0x6C, 0xA6, 0xF2, 0x73, 0xF6, 0x8E, + 0xA7, 0xF2, 0xFE, 0xFB, 0x6C, 0x28, 0x66, 0x0D, 0xBD, 0xD7, 0xEB, 0x42, 0xA8, 0x78, 0xE6, 0xB8, + 0x6B, 0xAE, 0xC7, 0xA9, 0xE2, 0x40, 0x6E, 0x89, 0x20, 0x82, 0x25, 0x8E, 0x3C, 0x6A, 0x60, 0xD7, + 0xF3, 0x56, 0x8E, 0xEC, 0x8D, 0x51, 0x8A, 0x63, 0x3C, 0x04, 0x78, 0x23, 0x0E, 0x90, 0x0C, 0xB4, + 0xE7, 0x86, 0x3B, 0x4F, 0x8E, 0x13, 0x09, 0x47, 0x32, 0x0E, 0x04, 0xB8, 0x4D, 0x5B, 0xB0, 0x46, + 0x71, 0xB0, 0x5C, 0xF4, 0xAD, 0x63, 0x4F, 0xC5, 0xE2, 0xAC, 0x1E, 0xC4, 0x33, 0x96, 0x09, 0x7B + }; + + constinit const u8 Package2AesKey[] { + 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 + }; + +} diff --git a/exosphere2/program/source/boot/secmon_boot_key_data.hpp b/exosphere2/program/source/boot/secmon_boot_key_data.hpp new file mode 100644 index 000000000..06513a5d3 --- /dev/null +++ b/exosphere2/program/source/boot/secmon_boot_key_data.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include + +namespace ams::secmon::boot { + + extern const u8 BootConfigRsaPublicModulus[se::RsaSize]; + extern const u8 Package2RsaPublicModulusDevelopment[se::RsaSize]; + extern const u8 Package2RsaPublicModulusProduction[se::RsaSize]; + extern const u8 Package2AesKey[se::AesBlockSize]; + +} diff --git a/exosphere2/program/source/boot/secmon_boot_setup.cpp b/exosphere2/program/source/boot/secmon_boot_setup.cpp index c9255a529..03a3be3f8 100644 --- a/exosphere2/program/source/boot/secmon_boot_setup.cpp +++ b/exosphere2/program/source/boot/secmon_boot_setup.cpp @@ -326,6 +326,11 @@ namespace ams::secmon::boot { InvalidateL1Entries(l1, MemoryRegionPhysical.GetAddress(), MemoryRegionPhysical.GetSize()); } + constexpr void UnmapDramImpl(u64 *l1, u64 *l2, u64 *l3) { + /* Unmap the L1 entry corresponding to to the Dram entries. */ + InvalidateL1Entries(l1, MemoryRegionDram.GetAddress(), MemoryRegionDram.GetSize()); + } + } void InitializeColdBoot() { @@ -366,4 +371,16 @@ namespace ams::secmon::boot { secmon::boot::EnsureMappingConsistency(); } + void UnmapDram() { + /* Get the tables. */ + u64 * const l1 = MemoryRegionPhysicalTzramL1PageTable.GetPointer(); + u64 * const l2_l3 = MemoryRegionPhysicalTzramL2L3PageTable.GetPointer(); + + /* Unmap. */ + UnmapDramImpl(l1, l2_l3, l2_l3); + + /* Ensure the mappings are consistent. */ + secmon::boot::EnsureMappingConsistency(); + } + } diff --git a/exosphere2/program/source/boot/secmon_main.cpp b/exosphere2/program/source/boot/secmon_main.cpp index 6e66c54a9..773feb347 100644 --- a/exosphere2/program/source/boot/secmon_main.cpp +++ b/exosphere2/program/source/boot/secmon_main.cpp @@ -17,11 +17,19 @@ #include "secmon_boot.hpp" #include "secmon_boot_functions.hpp" #include "../smc/secmon_random_cache.hpp" -#include "../secmon_setup.hpp" +#include "../secmon_cache.hpp" +#include "../secmon_cpu_context.hpp" #include "../secmon_misc.hpp" +#include "../secmon_setup.hpp" namespace ams::secmon { + namespace { + + constexpr inline const uintptr_t Package2LoadAddress = MemoryRegionDramPackage2Payloads.GetAddress(); + + } + void Main() { /* Set library register addresses. */ /* actmon::SetRegisterAddress(MemoryRegionVirtualDeviceActivityMonitor.GetAddress()); */ @@ -122,7 +130,7 @@ namespace ams::secmon { /* Parse and decrypt the package2 header. */ pkg2::Package2Meta pkg2_meta; - const uintptr_t pkg2_segments_start = MemoryRegionDramPackage2.GetAddress() + sizeof(pkg2::Package2Header); + const uintptr_t pkg2_payloads_start = MemoryRegionDramPackage2.GetAddress() + sizeof(pkg2::Package2Header); { /* Read the encrypred header. */ pkg2::Package2Header encrypted_header; @@ -143,8 +151,38 @@ namespace ams::secmon { secmon::boot::DecryptPackage2Header(std::addressof(pkg2_meta), encrypted_header.meta, !bc.signed_data.IsPackage2EncryptionDisabled()); } - /* TODO */ - AMS_UNUSED(pkg2_segments_start); + /* Verify the package2 header. */ + secmon::boot::VerifyPackage2Header(pkg2_meta); + + /* Save the package2 hash if in recovery boot. */ + if (secmon::IsRecoveryBoot()) { + se::Sha256Hash hash; + secmon::boot::CalculatePackage2Hash(std::addressof(hash), pkg2_meta, MemoryRegionDramPackage2.GetAddress()); + secmon::SetPackage2Hash(hash); + } + + /* Verify the package2 payloads. */ + secmon::boot::CheckVerifyResult(secmon::boot::VerifyPackage2Payloads(pkg2_meta, pkg2_payloads_start), pkg1::ErrorInfo_InvalidPackage2Payload, "package2 payload verification failed"); + + /* Decrypt/Move the package2 payloads to the right places. */ + secmon::boot::DecryptAndLoadPackage2Payloads(Package2LoadAddress, pkg2_meta, pkg2_payloads_start, !bc.signed_data.IsPackage2EncryptionDisabled()); + + /* Ensure that the CPU sees correct package2 data. */ + secmon::FlushEntireDataCache(); + secmon::EnsureInstructionConsistency(); + + /* Set the core's entrypoint and argument. */ + secmon::SetEntryContext(0, Package2LoadAddress + pkg2_meta.entrypoint, 0); + + /* Unmap DRAM. */ + secmon::boot::UnmapDram(); + + /* Wait for NX bootloader to be done. */ + secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_Done); + + /* Perform final initialization. */ + secmon::SetupSocProtections(); + secmon::SetupCpuSErrorDebug(); } -} \ No newline at end of file +} diff --git a/exosphere2/program/source/boot/secmon_package2.cpp b/exosphere2/program/source/boot/secmon_package2.cpp index 0543502ad..3a440b373 100644 --- a/exosphere2/program/source/boot/secmon_package2.cpp +++ b/exosphere2/program/source/boot/secmon_package2.cpp @@ -17,9 +17,23 @@ #include "../secmon_error.hpp" #include "../secmon_key_storage.hpp" #include "secmon_boot.hpp" +#include "secmon_boot_key_data.hpp" namespace ams::secmon::boot { + void CalculatePackage2Hash(se::Sha256Hash *dst, const pkg2::Package2Meta &meta, uintptr_t package2_start) { + /* Determine the region to hash. */ + const void *data = reinterpret_cast(package2_start); + const size_t size = meta.GetSize(); + + /* Flush to ensure the SE sees the correct data. */ + hw::FlushDataCache(data, size); + hw::DataSynchronizationBarrierInnerShareable(); + + /* Calculate the hash. */ + se::CalculateSha256(dst, data, size); + } + bool VerifyPackage2Signature(pkg2::Package2Header &header, const void *mod, size_t mod_size) { return VerifySignature(header.signature, sizeof(header.signature), mod, mod_size, std::addressof(header.meta), sizeof(header.meta)); } @@ -49,4 +63,90 @@ namespace ams::secmon::boot { hw::DataSynchronizationBarrierInnerShareable(); } + bool VerifyPackage2Meta(const pkg2::Package2Meta &meta) { + /* Get the obfuscated metadata. */ + const size_t size = meta.GetSize(); + const u8 key_generation = meta.GetKeyGeneration(); + + /* Check that size is big enough for the header. */ + if (size <= sizeof(pkg2::Package2Header)) { + return false; + } + + /* Check that the size isn't larger than what we allow. */ + if (size > pkg2::Package2SizeMax) { + return false; + } + + /* Check that the key generation is one that we can use. */ + static_assert(pkg1::KeyGeneration_Count == 11); + if (key_generation >= pkg1::KeyGeneration_Count) { + return false; + } + + /* Check the magic number. */ + if (!crypto::IsSameBytes(meta.magic, pkg2::Package2Meta::Magic::String, sizeof(meta.magic))) { + return false; + } + + /* Check the payload alignments. */ + if ((meta.entrypoint % pkg2::PayloadAlignment) != 0) { + return false; + } + + for (int i = 0; i < pkg2::PayloadCount; ++i) { + if ((meta.payload_sizes[i] % pkg2::PayloadAlignment) != 0) { + return false; + } + } + + /* Check that the sizes sum to the total. */ + if (size != sizeof(pkg2::Package2Header) + meta.payload_sizes[0] + meta.payload_sizes[1] + meta.payload_sizes[2]) { + return false; + } + + /* Check that the payloads do not overflow. */ + for (int i = 0; i < pkg2::PayloadCount; ++i) { + if (meta.payload_offsets[i] > meta.payload_offsets[i] + meta.payload_sizes[i]) { + return false; + } + } + + /* Verify that no payloads overlap. */ + for (int i = 0; i < pkg2::PayloadCount - 1; ++i) { + for (int j = i + 1; j < pkg2::PayloadCount; ++j) { + if (util::HasOverlap(meta.payload_offsets[i], meta.payload_sizes[i], meta.payload_offsets[j], meta.payload_sizes[j])) { + return false; + } + } + } + + /* Check whether any payload contains the entrypoint. */ + for (int i = 0; i < pkg2::PayloadCount; ++i) { + if (util::Contains(meta.payload_offsets[i], meta.payload_sizes[i], meta.entrypoint)) { + return true; + } + } + + /* No payload contains the entrypoint, so we're not valid. */ + return false; + } + + bool VerifyPackage2Version(const pkg2::Package2Meta &meta) { + return meta.bootloader_version <= pkg2::CurrentBootloaderVersion && meta.package2_version >= pkg2::MinimumValidDataVersion; + } + + bool VerifyPackage2Payloads(const pkg2::Package2Meta &meta, uintptr_t payload_address) { + /* Verify hashes match for all payloads. */ + for (int i = 0; i < pkg2::PayloadCount; ++i) { + if (!VerifyHash(meta.payload_hashes[i], payload_address, meta.payload_sizes[i])) { + return false; + } + + payload_address += meta.payload_sizes[i]; + } + + return true; + } + } diff --git a/exosphere2/program/source/secmon_cache.cpp b/exosphere2/program/source/secmon_cache.cpp new file mode 100644 index 000000000..02fd04383 --- /dev/null +++ b/exosphere2/program/source/secmon_cache.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#include +#include "secmon_cache.hpp" + +namespace ams::secmon { + + #include "secmon_cache_impl.inc" + +} \ No newline at end of file diff --git a/exosphere2/program/source/boot/secmon_key_data.cpp b/exosphere2/program/source/secmon_cache.hpp similarity index 90% rename from exosphere2/program/source/boot/secmon_key_data.cpp rename to exosphere2/program/source/secmon_cache.hpp index ad0649c3e..3050c38cf 100644 --- a/exosphere2/program/source/boot/secmon_key_data.cpp +++ b/exosphere2/program/source/secmon_cache.hpp @@ -13,10 +13,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#pragma once #include -namespace ams::secmon::boot { +namespace ams::secmon { - /* TODO */ + #include "secmon_cache.inc" } \ No newline at end of file diff --git a/exosphere2/program/source/secmon_cache_impl.inc b/exosphere2/program/source/secmon_cache_impl.inc index c486c8b4d..6ef2fe4bc 100644 --- a/exosphere2/program/source/secmon_cache_impl.inc +++ b/exosphere2/program/source/secmon_cache_impl.inc @@ -129,4 +129,4 @@ void EnsureInstructionConsistency() { ::ams::hw::DataSynchronizationBarrierInnerShareable(); ::ams::hw::InstructionSynchronizationBarrier(); -} \ No newline at end of file +} diff --git a/exosphere2/program/source/secmon_misc.cpp b/exosphere2/program/source/secmon_misc.cpp index 8f7a1c500..d0981d771 100644 --- a/exosphere2/program/source/secmon_misc.cpp +++ b/exosphere2/program/source/secmon_misc.cpp @@ -20,7 +20,8 @@ namespace ams::secmon { namespace { - pkg1::BctParameters g_bct_params; + constinit pkg1::BctParameters g_bct_params = {}; + constinit se::Sha256Hash g_package2_hash = {}; } @@ -43,4 +44,12 @@ namespace ams::secmon { return dbg_auth.Get() == 3; } -} \ No newline at end of file + void GetPackage2Hash(se::Sha256Hash *out) { + *out = g_package2_hash; + } + + void SetPackage2Hash(const se::Sha256Hash &hash) { + g_package2_hash = hash; + } + +} diff --git a/exosphere2/program/source/secmon_misc.hpp b/exosphere2/program/source/secmon_misc.hpp index b26641919..e8b5922ff 100644 --- a/exosphere2/program/source/secmon_misc.hpp +++ b/exosphere2/program/source/secmon_misc.hpp @@ -26,4 +26,7 @@ namespace ams::secmon { bool IsJtagEnabled(); + void GetPackage2Hash(se::Sha256Hash *out); + void SetPackage2Hash(const se::Sha256Hash &hash); + } \ No newline at end of file diff --git a/exosphere2/program/source/secmon_setup.cpp b/exosphere2/program/source/secmon_setup.cpp index 296f66d68..71c8fa190 100644 --- a/exosphere2/program/source/secmon_setup.cpp +++ b/exosphere2/program/source/secmon_setup.cpp @@ -837,7 +837,7 @@ namespace ams::secmon { } void SetupSocProtections() { - + /* TODO */ } void SetupPmcAndMcSecure() { @@ -877,7 +877,21 @@ namespace ams::secmon { } void SetupCpuSErrorDebug() { + /* Get whether we should enable SError debug. */ + const auto &bc_data = secmon::GetBootConfig().data; + const bool enabled = bc_data.IsDevelopmentFunctionEnabled() && bc_data.IsSErrorDebugEnabled(); + /* Get and set scr_el3. */ + { + util::BitPack32 scr; + HW_CPU_GET_SCR_EL3(scr); + + scr.Set(enabled ? 0 : 1); + HW_CPU_SET_SCR_EL3(scr); + } + + /* Prevent reordering instructions around this call. */ + hw::InstructionSynchronizationBarrier(); } } \ No newline at end of file diff --git a/libraries/libexosphere/include/exosphere/pkg2.hpp b/libraries/libexosphere/include/exosphere/pkg2.hpp index 8df2bc651..9fa9425d1 100644 --- a/libraries/libexosphere/include/exosphere/pkg2.hpp +++ b/libraries/libexosphere/include/exosphere/pkg2.hpp @@ -19,9 +19,9 @@ namespace ams::pkg2 { constexpr inline size_t Package2SizeMax = 8_MB - 16_KB; - constexpr inline size_t SegmentAlignment = 4; + constexpr inline size_t PayloadAlignment = 4; - constexpr inline int SegmentCount = 3; + constexpr inline int PayloadCount = 3; constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x10 in Nintendo's code. */ constexpr inline int CurrentBootloaderVersion = 0xD; @@ -32,7 +32,7 @@ namespace ams::pkg2 { u32 package2_size; u8 key_generation; u8 header_iv_remainder[11]; - u8 segment_iv[SegmentCount][0x10]; + u8 payload_ivs[PayloadCount][0x10]; u8 padding_40[0x10]; u8 magic[4]; u32 entrypoint; @@ -40,11 +40,11 @@ namespace ams::pkg2 { u8 package2_version; u8 bootloader_version; u8 padding_5E[2]; - u32 segment_sizes[SegmentCount]; + u32 payload_sizes[PayloadCount]; u8 padding_6C[4]; - u32 segment_offsets[SegmentCount]; + u32 payload_offsets[PayloadCount]; u8 padding_7C[4]; - u8 segment_hashes[SegmentCount][crypto::Sha256Generator::HashSize]; + u8 payload_hashes[PayloadCount][crypto::Sha256Generator::HashSize]; u8 padding_E0[0x20]; private: @@ -53,7 +53,7 @@ namespace ams::pkg2 { } public: ALWAYS_INLINE u8 GetKeyGeneration() const { - return std::min(0, (this->key_generation ^ this->header_iv_remainder[1] ^ this->header_iv_remainder[2]) - 1); + return static_cast(std::max(0, static_cast(this->key_generation ^ this->header_iv_remainder[1] ^ this->header_iv_remainder[2]) - 1)); } ALWAYS_INLINE u32 GetSize() const { diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp index 34e4be521..ffe9625e7 100644 --- a/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp +++ b/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp @@ -80,6 +80,9 @@ namespace ams::secmon { constexpr inline const MemoryRegion MemoryRegionDramDefaultKernelCarveout = MemoryRegion(UINT64_C(0x80060000), UINT64_C(0x1FFE0000)); static_assert(MemoryRegionDram.Contains(MemoryRegionDramDefaultKernelCarveout)); + constexpr inline const MemoryRegion MemoryRegionDramPackage2Payloads = MemoryRegion(MemoryRegionDram.GetAddress(), 8_MB); + static_assert(MemoryRegionDram.Contains(MemoryRegionDramPackage2Payloads)); + constexpr inline const MemoryRegion MemoryRegionDramPackage2 = MemoryRegion(UINT64_C(0xA9800000), UINT64_C(0x07FC0000)); static_assert(MemoryRegionDram.Contains(MemoryRegionDramPackage2)); diff --git a/libraries/libvapours/include/vapours/util.hpp b/libraries/libvapours/include/vapours/util.hpp index c10fa5d37..0d60a3ea7 100644 --- a/libraries/libvapours/include/vapours/util.hpp +++ b/libraries/libvapours/include/vapours/util.hpp @@ -36,5 +36,6 @@ #include #include #include +#include #include #include diff --git a/libraries/libvapours/include/vapours/util/util_overlap.hpp b/libraries/libvapours/include/vapours/util/util_overlap.hpp new file mode 100644 index 000000000..a1bf7d2df --- /dev/null +++ b/libraries/libvapours/include/vapours/util/util_overlap.hpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2020 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 . + */ + +#pragma once +#include +#include + +namespace ams::util { + + constexpr inline bool HasOverlap(uintptr_t addr0, size_t size0, uintptr_t addr1, size_t size1) { + if (addr0 <= addr1) { + return addr1 < addr0 + size0; + } else { + return addr0 < addr1 + size1; + } + } + + constexpr inline bool Contains(uintptr_t addr, size_t size, uintptr_t ptr) { + return (addr <= ptr) && (ptr < addr + size); + } + +}