exo2: rename exosphere2 -> exosphere

This commit is contained in:
Michael Scire 2020-06-11 01:53:10 -07:00 committed by SciresM
parent 282f8f6612
commit 42f1a3bf60
136 changed files with 15 additions and 15 deletions

View file

@ -0,0 +1,42 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon::boot {
void MakePageTable();
void UnmapPhysicalIdentityMapping();
void UnmapDram();
void InitializeColdBoot();
bool VerifySignature(void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *msg, size_t msg_size);
bool VerifyHash(const void *hash, uintptr_t msg, size_t msg_size);
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);
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_boot_cache.hpp"
namespace ams::secmon::boot {
#include "../secmon_cache_impl.inc"
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon::boot {
#include "../secmon_cache.inc"
}

View file

@ -0,0 +1,34 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_boot.hpp"
namespace ams::secmon::boot {
bool VerifyBootConfigSignature(pkg1::BootConfig &bc, const void *mod, size_t mod_size) {
return VerifySignature(std::addressof(bc.signature), sizeof(bc.signature), mod, mod_size, std::addressof(bc.signed_data), sizeof(bc.signed_data));
}
bool VerifyBootConfigEcid(const pkg1::BootConfig &bc) {
/* Get the ecid. */
br::BootEcid ecid;
fuse::GetEcid(std::addressof(ecid));
/* Verify it matches. */
return crypto::IsSameBytes(std::addressof(ecid), bc.signed_data.ecid, sizeof(ecid));
}
}

View file

@ -0,0 +1,193 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_boot.hpp"
#include "secmon_boot_cache.hpp"
#include "secmon_boot_functions.hpp"
namespace ams::secmon::boot {
namespace {
constexpr inline uintptr_t SYSCTR0 = MemoryRegionVirtualDeviceSysCtr0.GetAddress();
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<void *>(dst), size, reinterpret_cast<void *>(src), size, secmon::boot::GetPackage2AesKey(), crypto::AesEncryptor128::KeySize, iv, iv_size, key_generation);
}
u32 GetChipId() {
constexpr u32 ChipIdErista = 0x210;
constexpr u32 ChipIdMariko = 0x214;
switch (GetSocType()) {
case fuse::SocType_Erista: return ChipIdErista;
case fuse::SocType_Mariko: return ChipIdMariko;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
}
void CheckVerifyResult(bool verify_result, pkg1::ErrorInfo error_info, const char *message) {
if (!verify_result) {
secmon::SetError(error_info);
AMS_ABORT(message);
}
}
void ClearIram() {
/* Clear the boot code image from where it was loaded in IRAM. */
util::ClearMemory(MemoryRegionPhysicalIramBootCodeImage.GetPointer(), MemoryRegionPhysicalIramBootCodeImage.GetSize());
}
void WaitForNxBootloader(const pkg1::SecureMonitorParameters &params, pkg1::BootloaderState state) {
/* Check NX Bootloader's state once per microsecond until it's advanced enough. */
while (params.bootloader_state < state) {
util::WaitMicroSeconds(1);
}
}
void LoadBootConfig(const void *src) {
pkg1::BootConfig * const dst = secmon::impl::GetBootConfigStorage();
if (pkg1::IsProduction()) {
std::memset(dst, 0, sizeof(*dst));
} else {
hw::FlushDataCache(src, sizeof(*dst));
hw::DataSynchronizationBarrierInnerShareable();
std::memcpy(dst, src, sizeof(*dst));
}
}
void VerifyOrClearBootConfig() {
/* On production hardware, the boot config is already cleared. */
if (pkg1::IsProduction()) {
return;
}
pkg1::BootConfig * const bc = secmon::impl::GetBootConfigStorage();
/* Determine if the bc is valid for the device. */
bool valid_for_device = false;
{
const bool valid_signature = secmon::boot::VerifyBootConfigSignature(*bc, secmon::boot::GetBootConfigRsaModulus(), se::RsaSize);
if (valid_signature) {
valid_for_device = secmon::boot::VerifyBootConfigEcid(*bc);
}
}
/* If the boot config is not valid for the device, clear its signed data. */
if (!valid_for_device) {
util::ClearMemory(std::addressof(bc->signed_data), sizeof(bc->signed_data));
}
}
void EnableTsc(u64 initial_tsc_value) {
/* Write the initial value to the CNTCV registers. */
const u32 lo = static_cast<u32>(initial_tsc_value >> 0);
const u32 hi = static_cast<u32>(initial_tsc_value >> 32);
reg::Write(SYSCTR0 + SYSCTR0_CNTCV0, lo);
reg::Write(SYSCTR0 + SYSCTR0_CNTCV1, hi);
/* Configure the system counter control register. */
reg::Write(SYSCTR0 + SYSCTR0_CNTCR, SYSCTR0_REG_BITS_ENUM(CNTCR_HDBG, ENABLE),
SYSCTR0_REG_BITS_ENUM(CNTCR_EN, ENABLE));
}
void WriteGpuCarveoutMagicNumbers() {
/* Define the magic numbers. */
constexpr u32 GpuMagicNumber = 0xC0EDBBCC;
constexpr u32 SkuInfo = 0x83;
constexpr u32 HdcpMicroCodeVersion = 0x2;
/* Get our pointers. */
u32 *gpu_magic = MemoryRegionDramGpuCarveout.GetEndPointer<u32>() - (0x004 / sizeof(*gpu_magic));
u32 *tsec_magic = MemoryRegionDramGpuCarveout.GetEndPointer<u32>() - (0x100 / sizeof(*tsec_magic));
/* Write the gpu magic number. */
gpu_magic[0] = GpuMagicNumber;
/* Write the tsec magic numbers. */
tsec_magic[0] = SkuInfo;
tsec_magic[1] = HdcpMicroCodeVersion;
tsec_magic[2] = GetChipId();
/* Flush the magic numbers. */
hw::FlushDataCache(gpu_magic, 1 * sizeof(u32));
hw::FlushDataCache(tsec_magic, 3 * sizeof(u32));
hw::DataSynchronizationBarrierInnerShareable();
}
void UpdateBootConfigForPackage2Header(const pkg2::Package2Header &header) {
/* Check for all-zeroes signature. */
bool is_decrypted = header.signature[0] == 0;
is_decrypted &= crypto::IsSameBytes(header.signature, header.signature + 1, sizeof(header.signature) - 1);
/* Check for valid magic. */
is_decrypted &= crypto::IsSameBytes(header.meta.magic, pkg2::Package2Meta::Magic::String, sizeof(header.meta.magic));
/* Set the setting in boot config. */
secmon::impl::GetBootConfigStorage()->signed_data.SetPackage2Decrypted(is_decrypted);
}
void VerifyPackage2HeaderSignature(pkg2::Package2Header &header, bool verify) {
const u8 * const mod = secmon::boot::GetPackage2RsaModulus(pkg1::IsProductionForPublicKey());
const size_t mod_size = se::RsaSize;
if (verify) {
CheckVerifyResult(secmon::boot::VerifyPackage2Signature(header, mod, mod_size), pkg1::ErrorInfo_InvalidPackage2Signature, "package2 header sign verification failed");
}
}
void DecryptPackage2Header(pkg2::Package2Meta *dst, const pkg2::Package2Meta &src, bool encrypted) {
if (encrypted) {
constexpr int IvSize = 0x10;
/* Decrypt the header. */
DecryptPackage2(dst, sizeof(*dst), std::addressof(src), sizeof(src), secmon::boot::GetPackage2AesKey(), crypto::AesEncryptor128::KeySize, std::addressof(src), IvSize, src.GetKeyGeneration());
/* Copy back the iv, which encodes encrypted metadata. */
std::memcpy(dst, std::addressof(src), IvSize);
} else {
std::memcpy(dst, std::addressof(src), sizeof(*dst));
}
}
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<void *>(dst + meta.payload_offsets[i]), reinterpret_cast<void *>(src), meta.payload_sizes[i]);
}
src += meta.payload_sizes[i];
}
}
}

View file

@ -0,0 +1,42 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon::boot {
void ClearIram();
void WaitForNxBootloader(const pkg1::SecureMonitorParameters &params, pkg1::BootloaderState state);
void LoadBootConfig(const void *src);
void VerifyOrClearBootConfig();
void EnableTsc(u64 initial_tsc_value);
void WriteGpuCarveoutMagicNumbers();
void UpdateBootConfigForPackage2Header(const pkg2::Package2Header &header);
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);
}

View file

@ -0,0 +1,77 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
.section .volatile_keys._ZN3ams6secmon4boot15VolatileKeyDataE, "aw", %progbits
.global _ZN3ams6secmon4boot15VolatileKeyDataE
_ZN3ams6secmon4boot15VolatileKeyDataE:
/* BootConfig Rsa Modulus. */
.byte 0xB5, 0x96, 0x87, 0x31, 0x39, 0xAA, 0xBB, 0x3C, 0x28, 0xF3, 0xF0, 0x65, 0xF1, 0x50, 0x70, 0x64
.byte 0xE6, 0x6C, 0x97, 0x50, 0xCD, 0xA6, 0xEE, 0xEA, 0xC3, 0x8F, 0xE6, 0xB5, 0x81, 0x54, 0x65, 0x33
.byte 0x1B, 0x88, 0x4B, 0xCE, 0x9F, 0x53, 0xDF, 0xE4, 0xF6, 0xAD, 0xC3, 0x78, 0xD7, 0x3C, 0xD1, 0xDB
.byte 0x27, 0x21, 0xA0, 0x24, 0x30, 0x2D, 0x98, 0x41, 0xA8, 0xDF, 0x50, 0x7D, 0xAB, 0xCE, 0x00, 0xD9
.byte 0xCB, 0xAC, 0x8F, 0x37, 0xF5, 0x53, 0xE4, 0x97, 0x1F, 0x13, 0x3C, 0x19, 0xFF, 0x05, 0xA7, 0x3B
.byte 0xF6, 0xF4, 0x01, 0xDE, 0xF0, 0xC3, 0x77, 0x7B, 0x83, 0xBA, 0xAF, 0x99, 0x30, 0x94, 0x87, 0x25
.byte 0x4E, 0x54, 0x42, 0x3F, 0xAC, 0x27, 0xF9, 0xCC, 0x87, 0xDD, 0xAE, 0xF2, 0x54, 0xF3, 0x97, 0x49
.byte 0xF4, 0xB0, 0xF8, 0x6D, 0xDA, 0x60, 0xE0, 0xFD, 0x57, 0xAE, 0x55, 0xA9, 0x76, 0xEA, 0x80, 0x24
.byte 0xA0, 0x04, 0x7D, 0xBE, 0xD1, 0x81, 0xD3, 0x0C, 0x95, 0xCF, 0xB7, 0xE0, 0x2D, 0x21, 0x21, 0xFF
.byte 0x97, 0x1E, 0xB3, 0xD7, 0x9F, 0xBB, 0x33, 0x0C, 0x23, 0xC5, 0x88, 0x4A, 0x33, 0xB9, 0xC9, 0x4E
.byte 0x1E, 0x65, 0x51, 0x45, 0xDE, 0xF9, 0x64, 0x7C, 0xF0, 0xBF, 0x11, 0xB4, 0x93, 0x8D, 0x5D, 0xC6
.byte 0xAB, 0x37, 0x9E, 0xE9, 0x39, 0xC1, 0xC8, 0xDB, 0xB9, 0xFE, 0x45, 0xCE, 0x7B, 0xDD, 0x72, 0xD9
.byte 0x6F, 0x68, 0x13, 0xC0, 0x4B, 0xBA, 0x00, 0xF4, 0x1E, 0x89, 0x71, 0x91, 0x26, 0xA6, 0x46, 0x12
.byte 0xDF, 0x29, 0x6B, 0xC2, 0x5A, 0x53, 0xAF, 0xB9, 0x5B, 0xFD, 0x13, 0x9F, 0xD1, 0x8A, 0x7C, 0xB5
.byte 0x04, 0xFD, 0x69, 0xEA, 0x23, 0xB4, 0x6D, 0x16, 0x21, 0x98, 0x54, 0xB4, 0xDF, 0xE6, 0xAB, 0x93
.byte 0x36, 0xB6, 0xD2, 0x43, 0xCF, 0x2B, 0x98, 0x1D, 0x45, 0xC9, 0xBB, 0x20, 0x42, 0xB1, 0x9D, 0x1D
/* Package2 Development Rsa Modulus. */
.byte 0xB3, 0x65, 0x54, 0xFB, 0x0A, 0xB0, 0x1E, 0x85, 0xA7, 0xF6, 0xCF, 0x91, 0x8E, 0xBA, 0x96, 0x99
.byte 0x0D, 0x8B, 0x91, 0x69, 0x2A, 0xEE, 0x01, 0x20, 0x4F, 0x34, 0x5C, 0x2C, 0x4F, 0x4E, 0x37, 0xC7
.byte 0xF1, 0x0B, 0xD4, 0xCD, 0xA1, 0x7F, 0x93, 0xF1, 0x33, 0x59, 0xCE, 0xB1, 0xE9, 0xDD, 0x26, 0xE6
.byte 0xF3, 0xBB, 0x77, 0x87, 0x46, 0x7A, 0xD6, 0x4E, 0x47, 0x4A, 0xD1, 0x41, 0xB7, 0x79, 0x4A, 0x38
.byte 0x06, 0x6E, 0xCF, 0x61, 0x8F, 0xCD, 0xC1, 0x40, 0x0B, 0xFA, 0x26, 0xDC, 0xC0, 0x34, 0x51, 0x83
.byte 0xD9, 0x3B, 0x11, 0x54, 0x3B, 0x96, 0x27, 0x32, 0x9A, 0x95, 0xBE, 0x1E, 0x68, 0x11, 0x50, 0xA0
.byte 0x6B, 0x10, 0xA8, 0x83, 0x8B, 0xF5, 0xFC, 0xBC, 0x90, 0x84, 0x7A, 0x5A, 0x5C, 0x43, 0x52, 0xE6
.byte 0xC8, 0x26, 0xE9, 0xFE, 0x06, 0xA0, 0x8B, 0x53, 0x0F, 0xAF, 0x1E, 0xC4, 0x1C, 0x0B, 0xCF, 0x50
.byte 0x1A, 0xA4, 0xF3, 0x5C, 0xFB, 0xF0, 0x97, 0xE4, 0xDE, 0x32, 0x0A, 0x9F, 0xE3, 0x5A, 0xAA, 0xB7
.byte 0x44, 0x7F, 0x5C, 0x33, 0x60, 0xB9, 0x0F, 0x22, 0x2D, 0x33, 0x2A, 0xE9, 0x69, 0x79, 0x31, 0x42
.byte 0x8F, 0xE4, 0x3A, 0x13, 0x8B, 0xE7, 0x26, 0xBD, 0x08, 0x87, 0x6C, 0xA6, 0xF2, 0x73, 0xF6, 0x8E
.byte 0xA7, 0xF2, 0xFE, 0xFB, 0x6C, 0x28, 0x66, 0x0D, 0xBD, 0xD7, 0xEB, 0x42, 0xA8, 0x78, 0xE6, 0xB8
.byte 0x6B, 0xAE, 0xC7, 0xA9, 0xE2, 0x40, 0x6E, 0x89, 0x20, 0x82, 0x25, 0x8E, 0x3C, 0x6A, 0x60, 0xD7
.byte 0xF3, 0x56, 0x8E, 0xEC, 0x8D, 0x51, 0x8A, 0x63, 0x3C, 0x04, 0x78, 0x23, 0x0E, 0x90, 0x0C, 0xB4
.byte 0xE7, 0x86, 0x3B, 0x4F, 0x8E, 0x13, 0x09, 0x47, 0x32, 0x0E, 0x04, 0xB8, 0x4D, 0x5B, 0xB0, 0x46
.byte 0x71, 0xB0, 0x5C, 0xF4, 0xAD, 0x63, 0x4F, 0xC5, 0xE2, 0xAC, 0x1E, 0xC4, 0x33, 0x96, 0x09, 0x7B
/* Package2 Production Rsa Modulus. */
.byte 0x8D, 0x13, 0xA7, 0x77, 0x6A, 0xE5, 0xDC, 0xC0, 0x3B, 0x25, 0xD0, 0x58, 0xE4, 0x20, 0x69, 0x59
.byte 0x55, 0x4B, 0xAB, 0x70, 0x40, 0x08, 0x28, 0x07, 0xA8, 0xA7, 0xFD, 0x0F, 0x31, 0x2E, 0x11, 0xFE
.byte 0x47, 0xA0, 0xF9, 0x9D, 0xDF, 0x80, 0xDB, 0x86, 0x5A, 0x27, 0x89, 0xCD, 0x97, 0x6C, 0x85, 0xC5
.byte 0x6C, 0x39, 0x7F, 0x41, 0xF2, 0xFF, 0x24, 0x20, 0xC3, 0x95, 0xA6, 0xF7, 0x9D, 0x4A, 0x45, 0x74
.byte 0x8B, 0x5D, 0x28, 0x8A, 0xC6, 0x99, 0x35, 0x68, 0x85, 0xA5, 0x64, 0x32, 0x80, 0x9F, 0xD3, 0x48
.byte 0x39, 0xA2, 0x1D, 0x24, 0x67, 0x69, 0xDF, 0x75, 0xAC, 0x12, 0xB5, 0xBD, 0xC3, 0x29, 0x90, 0xBE
.byte 0x37, 0xE4, 0xA0, 0x80, 0x9A, 0xBE, 0x36, 0xBF, 0x1F, 0x2C, 0xAB, 0x2B, 0xAD, 0xF5, 0x97, 0x32
.byte 0x9A, 0x42, 0x9D, 0x09, 0x8B, 0x08, 0xF0, 0x63, 0x47, 0xA3, 0xE9, 0x1B, 0x36, 0xD8, 0x2D, 0x8A
.byte 0xD7, 0xE1, 0x54, 0x11, 0x95, 0xE4, 0x45, 0x88, 0x69, 0x8A, 0x2B, 0x35, 0xCE, 0xD0, 0xA5, 0x0B
.byte 0xD5, 0x5D, 0xAC, 0xDB, 0xAF, 0x11, 0x4D, 0xCA, 0xB8, 0x1E, 0xE7, 0x01, 0x9E, 0xF4, 0x46, 0xA3
.byte 0x8A, 0x94, 0x6D, 0x76, 0xBD, 0x8A, 0xC8, 0x3B, 0xD2, 0x31, 0x58, 0x0C, 0x79, 0xA8, 0x26, 0xE9
.byte 0xD1, 0x79, 0x9C, 0xCB, 0xD4, 0x2B, 0x6A, 0x4F, 0xC6, 0xCC, 0xCF, 0x90, 0xA7, 0xB9, 0x98, 0x47
.byte 0xFD, 0xFA, 0x4C, 0x6C, 0x6F, 0x81, 0x87, 0x3B, 0xCA, 0xB8, 0x50, 0xF6, 0x3E, 0x39, 0x5D, 0x4D
.byte 0x97, 0x3F, 0x0F, 0x35, 0x39, 0x53, 0xFB, 0xFA, 0xCD, 0xAB, 0xA8, 0x7A, 0x62, 0x9A, 0x3F, 0xF2
.byte 0x09, 0x27, 0x96, 0x3F, 0x07, 0x9A, 0x91, 0xF7, 0x16, 0xBF, 0xC6, 0x3A, 0x82, 0x5A, 0x4B, 0xCF
.byte 0x49, 0x50, 0x95, 0x8C, 0x55, 0x80, 0x7E, 0x39, 0xB1, 0x48, 0x05, 0x1E, 0x21, 0xC7, 0x24, 0x4F
/* Package2 Aes Key Source. */
.byte 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7

View file

@ -0,0 +1,159 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_boot.hpp"
namespace ams::secmon::boot {
namespace {
constinit const u8 RsaPublicKeyExponent[] = {
0x00, 0x01, 0x00, 0x01,
};
constexpr inline u8 TailMagic = 0xBC;
bool VerifyRsaPssSha256(const u8 *sig, const void *msg, size_t msg_size) {
/* Define constants. */
constexpr int EmBits = 2047;
constexpr int EmLen = util::DivideUp(EmBits, BITSIZEOF(u8));
constexpr int SaltLen = 0x20;
constexpr int HashLen = se::Sha256HashSize;
/* Define a work buffer. */
u8 work[EmLen];
ON_SCOPE_EXIT { util::ClearMemory(work, sizeof(work)); };
/* Calculate the message hash, first flushing cache to ensure SE sees correct data. */
se::Sha256Hash msg_hash;
hw::FlushDataCache(msg, msg_size);
hw::DataSynchronizationBarrierInnerShareable();
se::CalculateSha256(std::addressof(msg_hash), msg, msg_size);
/* Verify the tail magic. */
bool is_valid = sig[EmLen - 1] == TailMagic;
/* Determine extents of masked db and h. */
const u8 *masked_db = std::addressof(sig[0]);
const u8 *h = std::addressof(sig[EmLen - HashLen - 1]);
/* Verify the extra bits are zero. */
is_valid &= (masked_db[0] >> (BITSIZEOF(u8) - (BITSIZEOF(u8) * EmLen - EmBits))) == 0;
/* Calculate the db mask. */
{
constexpr int MaskLen = EmLen - HashLen - 1;
constexpr int HashIters = util::DivideUp(MaskLen, HashLen);
u8 mgf1_buf[sizeof(u32) + HashLen];
std::memcpy(std::addressof(mgf1_buf[0]), h, HashLen);
std::memset(std::addressof(mgf1_buf[HashLen]), 0, sizeof(u32));
for (int i = 0; i < HashIters; ++i) {
/* Set the counter for this iteration. */
mgf1_buf[sizeof(mgf1_buf) - 1] = i;
/* Calculate the sha256 to the appropriate place in the work buffer. */
auto *mgf1_dst = reinterpret_cast<se::Sha256Hash *>(std::addressof(work[HashLen * i]));
hw::FlushDataCache(mgf1_buf, sizeof(mgf1_buf));
hw::DataSynchronizationBarrierInnerShareable();
se::CalculateSha256(mgf1_dst, mgf1_buf, sizeof(mgf1_buf));
}
}
/* Decrypt masked db using the mask we just generated. */
for (int i = 0; i < EmLen - HashLen - 1; ++i) {
work[i] ^= masked_db[i];
}
/* Mask out the top bits. */
u8 *db = work;
db[0] &= 0xFF >> (BITSIZEOF(u8) * EmLen - EmBits);
/* Verify that DB is of the form 0000...0001 */
constexpr int DbLen = EmLen - HashLen - 1;
int salt_ofs = 0;
{
int looking_for_one = 1;
int invalid_db_padding = 0;
int is_zero;
int is_one;
for (size_t i = 0; i < DbLen; /* ... */) {
is_zero = (db[i] == 0);
is_one = (db[i] == 1);
salt_ofs += (looking_for_one & is_one) * (static_cast<s32>(++i));
looking_for_one &= ~is_one;
invalid_db_padding |= (looking_for_one & ~is_zero);
}
is_valid &= (invalid_db_padding == 0);
}
/* Verify salt. */
is_valid &= (DbLen - salt_ofs) == SaltLen;
/* Setup the message to verify. */
const u8 *salt = std::addressof(db[DbLen - SaltLen]);
u8 verif_msg[8 + HashLen + SaltLen];
ON_SCOPE_EXIT { util::ClearMemory(verif_msg, sizeof(verif_msg)); };
util::ClearMemory(std::addressof(verif_msg[0]), 8);
std::memcpy(std::addressof(verif_msg[8]), std::addressof(msg_hash), HashLen);
std::memcpy(std::addressof(verif_msg[8 + HashLen]), salt, SaltLen);
/* Verify the final hash. */
return VerifyHash(h, reinterpret_cast<uintptr_t>(std::addressof(verif_msg[0])), sizeof(verif_msg));
}
bool VerifyRsaPssSha256(int slot, void *sig, size_t sig_size, const void *msg, size_t msg_size) {
/* Exponentiate the signature, using the signature as the destination buffer. */
se::ModularExponentiate(sig, sig_size, slot, sig, sig_size);
/* Verify the pss padding. */
return VerifyRsaPssSha256(static_cast<const u8 *>(sig), msg, msg_size);
}
}
bool VerifySignature(void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *msg, size_t msg_size) {
/* Load the public key into a temporary keyslot. */
const int slot = pkg1::RsaKeySlot_Temporary;
se::SetRsaKey(slot, mod, mod_size, RsaPublicKeyExponent, util::size(RsaPublicKeyExponent));
return VerifyRsaPssSha256(slot, sig, sig_size, msg, msg_size);
}
bool VerifyHash(const void *hash, uintptr_t msg, size_t msg_size) {
/* Zero-sized messages are always valid. */
if (msg_size == 0) {
return true;
}
/* Ensure that the SE sees correct data for the message. */
hw::FlushDataCache(reinterpret_cast<void *>(msg), msg_size);
hw::DataSynchronizationBarrierInnerShareable();
/* Calculate the hash. */
se::Sha256Hash calc_hash;
se::CalculateSha256(std::addressof(calc_hash), reinterpret_cast<void *>(msg), msg_size);
/* Verify the result. */
return crypto::IsSameBytes(std::addressof(calc_hash), hash, sizeof(calc_hash));
}
}

View file

@ -0,0 +1,386 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_boot.hpp"
#include "secmon_boot_cache.hpp"
#include "../secmon_setup.hpp"
#include "../secmon_key_storage.hpp"
namespace ams::secmon::boot {
namespace {
void ValidateSystemCounters() {
const uintptr_t sysctr0 = MemoryRegionVirtualDeviceSysCtr0.GetAddress();
/* Validate the system counter frequency is as expected. */
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_CNTFID0) == 19'200'000u);
/* Validate the system counters are as expected. */
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 0)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 1)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 2)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 3)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 4)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 5)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 6)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 7)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 8)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 9)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID(10)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID(11)) == 0);
}
void SetupPmcRegisters() {
const auto pmc = MemoryRegionVirtualDevicePmc.GetAddress();
/* Set the physical address of the warmboot binary to scratch 1. */
reg::Write(pmc + APBDEV_PMC_SCRATCH1, static_cast<u32>(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress()));
/* Configure logging by setting bits 18-19 of scratch 20. */
reg::ReadWrite(pmc + APBDEV_PMC_SCRATCH20, REG_BITS_VALUE(18, 2, 0));
/* Clear the wdt reset flag. */
reg::ReadWrite(pmc + APBDEV_PMC_SCRATCH190, REG_BITS_VALUE(0, 1, 0));
/* Configure warmboot to set Set FUSE_PRIVATEKEYDISABLE to KEY_INVISIBLE. */
reg::ReadWrite(pmc + APBDEV_PMC_SECURE_SCRATCH21, REG_BITS_VALUE(4, 1, 1));
/* Write the warmboot key. */
/* TODO */
}
/* This function derives the master kek and device keys using the tsec root key. */
/* NOTE: Exosphere does not use this in practice, and expects the bootloader to set up keys already. */
/* NOTE: This function is currently not implemented. If implemented, it will only be a reference implementation. */
[[maybe_unused]]
void DeriveMasterKekAndDeviceKey() {
/* TODO: Decide whether to implement this. */
}
void SetupRandomKey(int slot, se::KeySlotLockFlags flags) {
/* Create an aligned buffer to hold the key. */
constexpr size_t KeySize = se::AesBlockSize;
util::AlignedBuffer<hw::DataCacheLineSize, KeySize> key;
/* Ensure data is consistent before triggering the SE. */
hw::FlushDataCache(key, KeySize);
hw::DataSynchronizationBarrierInnerShareable();
/* Generate random bytes into the key. */
se::GenerateRandomBytes(key, KeySize);
/* Ensure that the CPU sees consistent data. */
hw::DataSynchronizationBarrierInnerShareable();
hw::FlushDataCache(key, KeySize);
hw::DataSynchronizationBarrierInnerShareable();
/* Use the random bytes as a key source. */
se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_DeviceMaster, key, KeySize);
/* Lock the keyslot. */
se::LockAesKeySlot(slot, flags);
}
constinit const u8 MasterKeyVectorsDev[pkg1::OldMasterKeyCount + 1][se::AesBlockSize] = {
{0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE}, /* Zeroes encrypted with Master Key 00. */
{0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23}, /* Master key 00 encrypted with Master key 01. */
{0x97, 0x29, 0xB0, 0x32, 0x43, 0x14, 0x8C, 0xA6, 0x85, 0xE9, 0x5A, 0x94, 0x99, 0x39, 0xAC, 0x5D}, /* Master key 01 encrypted with Master key 02. */
{0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3}, /* Master key 02 encrypted with Master key 03. */
{0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA}, /* Master key 03 encrypted with Master key 04. */
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
{0xEC, 0xE1, 0x46, 0x89, 0x37, 0xFD, 0xD2, 0x15, 0x8C, 0x3F, 0x24, 0x82, 0xEF, 0x49, 0x68, 0x04}, /* Master key 07 encrypted with Master key 08. */
{0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE}, /* Master key 08 encrypted with Master key 09. */
{0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4}, /* Master key 09 encrypted with Master key 0A. */
};
constinit const u8 MasterKeyVectorsProd[pkg1::OldMasterKeyCount + 1][se::AesBlockSize] = {
{0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */
{0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */
{0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */
{0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */
{0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
{0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */
{0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */
};
bool TestKeyGeneration(int generation, bool is_prod) {
/* Decrypt the vector chain from generation to start. */
int slot = pkg1::AesKeySlot_Master;
for (int i = generation; i > 0; --i) {
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, slot, is_prod ? MasterKeyVectorsProd[i] : MasterKeyVectorsDev[i], se::AesBlockSize);
slot = pkg1::AesKeySlot_Temporary;
}
/* Decrypt the final vector. */
u8 test_vector[se::AesBlockSize];
se::DecryptAes128(test_vector, se::AesBlockSize, slot, is_prod ? MasterKeyVectorsProd[0] : MasterKeyVectorsDev[0], se::AesBlockSize);
constexpr u8 ZeroBlock[se::AesBlockSize] = {};
return crypto::IsSameBytes(ZeroBlock, test_vector, se::AesBlockSize);
}
int DetermineKeyGeneration(bool is_prod) {
/* Test each generation in order. */
for (int generation = 0; generation < pkg1::KeyGeneration_Count; ++generation) {
if (TestKeyGeneration(generation, is_prod)) {
return generation;
}
}
/* We must have found a correct key generation. */
AMS_ABORT();
}
void DeriveAllMasterKeys(bool is_prod, u8 * const work_block) {
/* Determine the generation. */
const int generation = DetermineKeyGeneration(is_prod);
/* Set the global generation. */
::ams::secmon::impl::SetKeyGeneration(generation);
/* Derive all old keys. */
int slot = pkg1::AesKeySlot_Master;
for (int i = generation; i > 0; --i) {
/* Decrypt the old master key. */
se::DecryptAes128(work_block, se::AesBlockSize, slot, is_prod ? MasterKeyVectorsProd[i] : MasterKeyVectorsDev[i], se::AesBlockSize);
/* Set the old master key. */
SetMasterKey(i - 1, work_block, se::AesBlockSize);
/* Set the old master key into a temporary keyslot. */
se::SetAesKey(pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize);
/* Perform the next decryption with the older master key. */
slot = pkg1::AesKeySlot_Temporary;
}
}
constinit const u8 DeviceMasterKeySourceSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.0.0 Device Master Key Source Source. */
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.0.0 Device Master Key Source Source. */
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 Device Master Key Source Source. */
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 Device Master Key Source Source. */
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 Device Master Key Source Source. */
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */
{0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */
};
constinit const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
{0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.0.0 Device Master Kek Source. */
{0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.0.0 Device Master Kek Source. */
{0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.0.0 Device Master Kek Source. */
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 Device Master Kek Source. */
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 Device Master Kek Source. */
{0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 Device Master Kek Source. */
{0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 Device Master Kek Source. */
{0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */
};
constinit const u8 DeviceMasterKekSourcesProd[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.0.0 Device Master Kek Source. */
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.0.0 Device Master Kek Source. */
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 Device Master Kek Source. */
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 Device Master Kek Source. */
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 Device Master Kek Source. */
{0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */
{0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */
};
void DeriveAllDeviceMasterKeys(bool is_prod, u8 * const work_block) {
/* Get the current key generation. */
const int current_generation = secmon::GetKeyGeneration();
/* Iterate for all generations. */
for (int i = 0; i < pkg1::OldDeviceMasterKeyCount; ++i) {
const int generation = pkg1::KeyGeneration_4_0_0 + i;
/* Load the first master key into the temporary keyslot keyslot. */
LoadMasterKey(pkg1::AesKeySlot_Temporary, pkg1::KeyGeneration_1_0_0);
/* Decrypt the device master kek for the generation. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, pkg1::AesKeySlot_Temporary, is_prod ? DeviceMasterKekSourcesProd[i] : DeviceMasterKekSourcesDev[i], se::AesBlockSize);
/* Decrypt the device master key source into the work block. */
se::DecryptAes128(work_block, se::AesBlockSize, pkg1::AesKeySlot_DeviceMasterKeySourceKek, DeviceMasterKeySourceSources[i], se::AesBlockSize);
/* If we're decrypting the current device master key, decrypt into the keyslot. */
if (generation == current_generation) {
se::SetEncryptedAesKey128(pkg1::AesKeySlot_DeviceMaster, pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize);
} else {
/* Otherwise, decrypt the work block into itself and set the old device master key. */
se::DecryptAes128(work_block, se::AesBlockSize, pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize);
/* Set the device master key. */
SetDeviceMasterKey(generation, work_block, se::AesBlockSize);
}
}
/* Clear and lock the Device Master Key Source Kek. */
se::ClearAesKeySlot(pkg1::AesKeySlot_DeviceMasterKeySourceKek);
se::LockAesKeySlot(pkg1::AesKeySlot_DeviceMasterKeySourceKek, se::KeySlotLockFlags_AllLockKek);
}
void DeriveAllKeys() {
/* Determine whether we're prod. */
const bool is_prod = IsProduction();
/* Get the ephemeral work block. */
u8 * const work_block = se::GetEphemeralWorkBlock();
ON_SCOPE_EXIT { util::ClearMemory(work_block, se::AesBlockSize); };
/* Lock the master key as a key. */
se::LockAesKeySlot(pkg1::AesKeySlot_Master, se::KeySlotLockFlags_AllLockKey);
/* Setup a random key to protect the old master and device master keys. */
SetupRandomKey(pkg1::AesKeySlot_RandomForKeyStorageWrap, se::KeySlotLockFlags_AllLockKey);
/* Derive the master keys. */
DeriveAllMasterKeys(is_prod, work_block);
/* Derive the device master keys. */
DeriveAllDeviceMasterKeys(is_prod, work_block);
/* Lock the device master key as a kek. */
se::LockAesKeySlot(pkg1::AesKeySlot_DeviceMaster, se::KeySlotLockFlags_AllLockKek);
/* Setup a random key to protect user keys. */
SetupRandomKey(pkg1::AesKeySlot_RandomForUserWrap, se::KeySlotLockFlags_AllLockKek);
}
void InitializeKeys() {
/* Read lock all aes keys. */
for (int i = 0; i < se::AesKeySlotCount; ++i) {
se::LockAesKeySlot(i, se::KeySlotLockFlags_AllReadLock);
}
/* Lock the secure monitor aes keys to be secmon only and non-readable. */
for (int i = pkg1::AesKeySlot_SecmonStart; i < pkg1::AesKeySlot_SecmonEnd; ++i) {
se::LockAesKeySlot(i, se::KeySlotLockFlags_KeyUse | se::KeySlotLockFlags_PerKey);
}
/* Lock the unused keyslots entirely. */
static_assert(pkg1::AesKeySlot_UserEnd <= pkg1::AesKeySlot_SecmonStart);
for (int i = pkg1::AesKeySlot_UserEnd; i < pkg1::AesKeySlot_SecmonStart; ++i) {
se::LockAesKeySlot(i, se::KeySlotLockFlags_AllLockKek);
}
/* Read lock all rsa keys. */
for (int i = 0; i < se::RsaKeySlotCount; ++i) {
se::LockRsaKeySlot(i, se::KeySlotLockFlags_KeyUse | se::KeySlotLockFlags_PerKey | se::KeySlotLockFlags_KeyRead);
}
/* Initialize the rng. */
se::InitializeRandom();
/* Derive the master kek and device key. */
if constexpr (false) {
DeriveMasterKekAndDeviceKey();
}
/* Lock the device key as only usable as a kek. */
se::LockAesKeySlot(pkg1::AesKeySlot_Device, se::KeySlotLockFlags_AllLockKek);
/* Derive all keys. */
DeriveAllKeys();
}
}
namespace {
using namespace ams::mmu;
constexpr void UnmapPhysicalIdentityMappingImpl(u64 *l1, u64 *l2, u64 *l3) {
/* Invalidate the L3 entries for the tzram and iram boot code regions. */
InvalidateL3Entries(l3, MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize());
InvalidateL3Entries(l3, MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetSize());
/* Unmap the L2 entries corresponding to those L3 entries. */
InvalidateL2Entries(l2, MemoryRegionPhysicalIramL2.GetAddress(), MemoryRegionPhysicalIramL2.GetSize());
InvalidateL2Entries(l2, MemoryRegionPhysicalTzramL2.GetAddress(), MemoryRegionPhysicalTzramL2.GetSize());
/* Unmap the L1 entry corresponding to to those L2 entries. */
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() {
/* Ensure that the system counters are valid. */
ValidateSystemCounters();
/* Set the security engine to Tzram Secure. */
se::SetTzramSecure();
/* Set the security engine to Per Key Secure. */
se::SetPerKeySecure();
/* Setup the PMC registers. */
SetupPmcRegisters();
/* Lockout the scratch that we've just written. */
/* pmc::LockSecureRegisters(1); */
/* Generate a random srk. */
se::GenerateSrk();
/* Initialize the SE keyslots. */
InitializeKeys();
/* Save a test vector for the SE keyslots. */
SaveSecurityEngineAesKeySlotTestVector();
}
void UnmapPhysicalIdentityMapping() {
/* Get the tables. */
u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>();
u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>();
/* Unmap. */
UnmapPhysicalIdentityMappingImpl(l1, l2_l3, l2_l3);
/* Ensure the mappings are consistent. */
secmon::boot::EnsureMappingConsistency();
}
void UnmapDram() {
/* Get the tables. */
u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>();
u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>();
/* Unmap. */
UnmapDramImpl(l1, l2_l3, l2_l3);
/* Ensure the mappings are consistent. */
secmon::boot::EnsureMappingConsistency();
}
}

View file

@ -0,0 +1,37 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
.section .crt0.text.start, "ax", %progbits
.align 6
.global _start
_start:
/* mask all interrupts */
msr daifset, #0xF
/* Set the stack pointer to a temporary location. */
ldr x20, =0x7C010800
mov sp, x20
/* Initialize all memory to expected state. */
ldr x0, =__bss_start__
ldr x1, =__bss_end__
ldr x2, =__boot_bss_start__
ldr x3, =__boot_bss_end__
bl _ZN3ams6secmon4boot10InitializeEmmmm
/* Jump to the first bit of virtual code. */
ldr x16, =_ZN3ams6secmon5StartEv
br x16

View file

@ -0,0 +1,46 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_boot.hpp"
#include "../secmon_setup.hpp"
extern "C" void __libc_init_array();
namespace ams::secmon::boot {
void Initialize(uintptr_t bss_start, size_t bss_end, uintptr_t boot_bss_start, uintptr_t boot_bss_end) {
/* Set our start time. */
auto &secmon_params = *MemoryRegionPhysicalDeviceBootloaderParams.GetPointer<pkg1::SecureMonitorParameters>();
secmon_params.secmon_start_time = *reinterpret_cast<volatile u32 *>(MemoryRegionPhysicalDeviceTimer.GetAddress() + 0x10);
/* Setup DMA controllers. */
SetupSocDmaControllers();
/* Make the page table. */
MakePageTable();
/* Setup memory controllers the MMU. */
SetupCpuMemoryControllersEnableMmu();
/* Clear bss. */
std::memset(reinterpret_cast<void *>(bss_start), 0, bss_end - bss_start);
std::memset(reinterpret_cast<void *>(boot_bss_start), 0, boot_bss_end - boot_bss_start);
/* Call init array. */
__libc_init_array();
}
}

View file

@ -0,0 +1,185 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_boot.hpp"
#include "secmon_boot_functions.hpp"
#include "../smc/secmon_random_cache.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());
clkrst::SetRegisterAddress(MemoryRegionVirtualDeviceClkRst.GetAddress());
flow::SetRegisterAddress(MemoryRegionVirtualDeviceFlowController.GetAddress());
fuse::SetRegisterAddress(MemoryRegionVirtualDeviceFuses.GetAddress());
gic::SetRegisterAddress(MemoryRegionVirtualDeviceGicDistributor.GetAddress(), MemoryRegionVirtualDeviceGicCpuInterface.GetAddress());
i2c::SetRegisterAddress(i2c::Port_1, MemoryRegionVirtualDeviceI2c1.GetAddress());
i2c::SetRegisterAddress(i2c::Port_5, MemoryRegionVirtualDeviceI2c5.GetAddress());
pinmux::SetRegisterAddress(MemoryRegionVirtualDeviceApbMisc.GetAddress(), MemoryRegionVirtualDeviceGpio.GetAddress());
pmc::SetRegisterAddress(MemoryRegionVirtualDevicePmc.GetAddress());
se::SetRegisterAddress(MemoryRegionVirtualDeviceSecurityEngine.GetAddress());
uart::SetRegisterAddress(MemoryRegionVirtualDeviceUart.GetAddress());
wdt::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
util::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
/* Get the secure monitor parameters. */
auto &secmon_params = *reinterpret_cast<pkg1::SecureMonitorParameters *>(MemoryRegionVirtualDeviceBootloaderParams.GetAddress());
/* Perform initialization. */
{
/* Perform initial setup. */
/* This checks the security engine's validity, and configures common interrupts in the GIC. */
/* This also initializes the global configuration context. */
secmon::Setup1();
/* Save the boot info. */
secmon::SaveBootInfo(secmon_params);
/* Perform cold-boot specific init. */
secmon::boot::InitializeColdBoot();
/* Setup the SoC security measures. */
secmon::SetupSocSecurity();
/* Setup the Cpu core context. */
secmon::SetupCpuCoreContext();
/* Clear the crt0 code that was present in iram. */
secmon::boot::ClearIram();
/* Alert the bootloader that we're initialized. */
secmon_params.secmon_state = pkg1::SecureMonitorState_Initialized;
}
/* Wait for NX Bootloader to finish loading the BootConfig. */
secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_LoadedBootConfig);
hw::DataSynchronizationBarrierInnerShareable();
/* Load the bootconfig. */
secmon::boot::LoadBootConfig(MemoryRegionPhysicalIramBootConfig.GetPointer());
/* Verify or clear the boot config. */
secmon::boot::VerifyOrClearBootConfig();
/* Get the boot config. */
const auto &bc = secmon::GetBootConfig();
/* Set the tsc value by the boot config. */
{
constexpr u64 TscMask = (static_cast<u64>(1) << 55) - 1;
secmon::boot::EnableTsc(bc.data.GetInitialTscValue() & TscMask);
}
/* Wait for NX Bootloader to initialize DRAM. */
secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_InitializedDram);
/* Secure the PMC and MC. */
secmon::SetupPmcAndMcSecure();
/* Copy warmboot to dram. */
{
/* Define warmboot extents. */
const void * const src = MemoryRegionPhysicalIramWarmbootBin.GetPointer();
void * const dst = MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware.GetPointer();
const size_t size = MemoryRegionPhysicalIramWarmbootBin.GetSize();
/* Ensure we copy the correct data. */
hw::FlushDataCache(src, size);
hw::DataSynchronizationBarrierInnerShareable();
/* Copy warmboot.bin to its secure dram location. */
std::memcpy(dst, src, size);
}
/* Unmap the identity mapping. */
secmon::boot::UnmapPhysicalIdentityMapping();
/* Setup the GPU carveout's magic numbers. */
secmon::boot::WriteGpuCarveoutMagicNumbers();
/* Wait for NX bootloader to load Package2. */
secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_LoadedPackage2);
/* Parse and decrypt the package2 header. */
pkg2::Package2Meta &pkg2_meta = secmon::boot::GetEphemeralPackage2Meta();
const uintptr_t pkg2_payloads_start = MemoryRegionDramPackage2.GetAddress() + sizeof(pkg2::Package2Header);
{
/* Read the encrypred header. */
pkg2::Package2Header encrypted_header;
const auto *dram_header = MemoryRegionDramPackage2.GetPointer<pkg2::Package2Header>();
hw::FlushDataCache(dram_header, sizeof(*dram_header));
hw::DataSynchronizationBarrierInnerShareable();
std::memcpy(std::addressof(encrypted_header), dram_header, sizeof(encrypted_header));
/* Atmosphere extension: support plaintext package2, identified by all-zeroes signature and decrypted header. */
secmon::boot::UpdateBootConfigForPackage2Header(encrypted_header);
/* Verify the package2 header's signature. */
secmon::boot::VerifyPackage2HeaderSignature(encrypted_header, !bc.signed_data.IsPackage2SignatureVerificationDisabled());
/* Decrypt the package2 header. */
secmon::boot::DecryptPackage2Header(std::addressof(pkg2_meta), encrypted_header.meta, !bc.signed_data.IsPackage2EncryptionDisabled());
}
/* 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();
}
}

View file

@ -0,0 +1,152 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_setup.hpp"
#include "secmon_boot.hpp"
namespace ams::secmon::boot {
namespace {
using namespace ams::mmu;
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRoCode = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRoCode, MemoryAttributeIndexNormal);
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRwCode = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwCode, MemoryAttributeIndexNormal);
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRoData = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRoData, MemoryAttributeIndexNormal);
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRwData = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwData, MemoryAttributeIndexNormal);
constexpr inline PageTableMappingAttribute MappingAttributesEl3NonSecureRwData = AddMappingAttributeIndex(PageTableMappingAttributes_El3NonSecureRwData, MemoryAttributeIndexNormal);
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureDevice = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwData, MemoryAttributeIndexDevice);
constexpr inline PageTableMappingAttribute MappingAttributesEl3NonSecureDevice = AddMappingAttributeIndex(PageTableMappingAttributes_El3NonSecureRwData, MemoryAttributeIndexDevice);
constexpr void ClearMemory(volatile u64 *start, size_t size) {
volatile u64 * const end = start + (size / sizeof(u64));
for (volatile u64 *cur = start; cur < end; ++cur) {
*cur = 0;
}
}
constexpr void MakePageTablesImpl(u64 *l1, u64 *l2, u64 *l3) {
/* Setup the L1 table. */
{
ClearMemory(l1, MemoryRegionPhysicalTzramL1PageTable.GetSize());
/* Create an L1 table entry for the physical region. */
SetL1TableEntry(l1, MemoryRegionPhysical.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
static_assert(GetL1EntryIndex(MemoryRegionPhysical.GetAddress()) == 1);
/* Create an L1 mapping entry for dram. */
SetL1BlockEntry(l1, MemoryRegionDram.GetAddress(), MemoryRegionDram.GetAddress(), MemoryRegionDram.GetSize(), MappingAttributesEl3NonSecureRwData);
/* Create an L1 table entry for the virtual region. */
SetL1TableEntry(l1, MemoryRegionVirtual.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
}
/* Setup the L2 table. */
{
ClearMemory(l2, MemoryRegionPhysicalTzramL2L3PageTable.GetSize());
/* Create an L2 table entry for the virtual region. */
SetL2TableEntry(l2, MemoryRegionVirtualL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
/* Create an L2 table entry for the physical iram region. */
SetL2TableEntry(l2, MemoryRegionPhysicalIramL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
/* Create an L2 table entry for the physical tzram region. */
SetL2TableEntry(l2, MemoryRegionPhysicalTzramL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
}
/* Setup the L3 table. */
{
/* L2 and L3 share a page table. */
if (l2 != l3) {
ClearMemory(l3, MemoryRegionPhysicalTzramL2L3PageTable.GetSize());
}
/* Identity-map TZRAM as rwx. */
SetL3BlockEntry(l3, MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize(), MappingAttributesEl3SecureRwCode);
/* Identity-map IRAM boot code as rwx. */
SetL3BlockEntry(l3, MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetSize(), MappingAttributesEl3SecureRwCode);
/* Map all devices. */
{
#define MAP_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \
SetL3BlockEntry(l3, MemoryRegionVirtualDevice##_NAME_.GetAddress(), MemoryRegionPhysicalDevice##_NAME_.GetAddress(), MemoryRegionVirtualDevice##_NAME_.GetSize(), _SECURE_ ? MappingAttributesEl3SecureDevice : MappingAttributesEl3NonSecureDevice);
AMS_SECMON_FOREACH_DEVICE_REGION(MAP_DEVICE_REGION);
#undef MAP_DEVICE_REGION
}
/* Map the IRAM SC7 work region. */
SetL3BlockEntry(l3, MemoryRegionVirtualIramSc7Work.GetAddress(), MemoryRegionPhysicalIramSc7Work.GetAddress(), MemoryRegionVirtualIramSc7Work.GetSize(), MappingAttributesEl3NonSecureDevice);
/* Map the IRAM SC7 firmware region. */
SetL3BlockEntry(l3, MemoryRegionVirtualIramSc7Firmware.GetAddress(), MemoryRegionPhysicalIramSc7Firmware.GetAddress(), MemoryRegionVirtualIramSc7Firmware.GetSize(), MappingAttributesEl3NonSecureDevice);
/* Map the Debug region. */
/* NOTE: This region is reserved for debug. By default it will be the last 0x8000 bytes of IRAM, but this is subject to change. */
/* If you are doing development work for exosphere, feel free to locally change this to whatever is useful. */
SetL3BlockEntry(l3, MemoryRegionVirtualDebug.GetAddress(), MemoryRegionPhysicalIram.GetEndAddress() - 0x8000, 0x8000, MappingAttributesEl3SecureDevice);
/* Map the TZRAM ro alias region. */
SetL3BlockEntry(l3, MemoryRegionVirtualTzramReadOnlyAlias.GetAddress(), MemoryRegionPhysicalTzramReadOnlyAlias.GetAddress(), MemoryRegionVirtualTzramReadOnlyAlias.GetSize(), MappingAttributesEl3SecureRoData);
/* Map the DRAM secure data store region. */
SetL3BlockEntry(l3, MemoryRegionVirtualDramSecureDataStore.GetAddress(), MemoryRegionPhysicalDramSecureDataStore.GetAddress(), MemoryRegionVirtualDramSecureDataStore.GetSize(), MappingAttributesEl3NonSecureDevice);
/* Map the program region as rwx. */
SetL3BlockEntry(l3, MemoryRegionVirtualTzramProgram.GetAddress(), MemoryRegionPhysicalTzramProgram.GetAddress(), MemoryRegionVirtualTzramProgram.GetSize(), MappingAttributesEl3SecureRwCode);
/* Map the boot code region. */
SetL3BlockEntry(l3, MemoryRegionVirtualTzramBootCode.GetAddress(), MemoryRegionPhysicalTzramBootCode.GetAddress(), MemoryRegionVirtualTzramBootCode.GetSize(), MappingAttributesEl3SecureRwCode);
/* Map the volatile data regions regions. */
SetL3BlockEntry(l3, MemoryRegionVirtualTzramVolatileData.GetAddress(), MemoryRegionPhysicalTzramVolatileData.GetAddress(), MemoryRegionVirtualTzramVolatileData.GetSize(), MappingAttributesEl3SecureRwData);
SetL3BlockEntry(l3, MemoryRegionVirtualTzramVolatileStack.GetAddress(), MemoryRegionPhysicalTzramVolatileStack.GetAddress(), MemoryRegionVirtualTzramVolatileStack.GetSize(), MappingAttributesEl3SecureRwData);
/* Map the configuration data. */
SetL3BlockEntry(l3, MemoryRegionVirtualTzramConfigurationData.GetAddress(), MemoryRegionPhysicalTzramConfigurationData.GetAddress(), MemoryRegionVirtualTzramConfigurationData.GetSize(), MappingAttributesEl3SecureRwData);
/* Map the page tables. */
SetL3BlockEntry(l3, util::AlignDown(MemoryRegionVirtualTzramL1PageTable.GetAddress(), PageSize), util::AlignDown(MemoryRegionPhysicalTzramL1PageTable.GetAddress(), PageSize), PageSize, MappingAttributesEl3SecureRwData);
SetL3BlockEntry(l3, MemoryRegionVirtualTzramL2L3PageTable.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), MemoryRegionVirtualTzramL2L3PageTable.GetSize(), MappingAttributesEl3SecureRwData);
}
}
constexpr bool ValidateTzramPageTables() {
u64 l1_table[MemoryRegionPhysicalTzramL1PageTable.GetSize() / sizeof(u64)] = {};
u64 l2_l3_table[MemoryRegionPhysicalTzramL2L3PageTable.GetSize() / sizeof(u64)] = {};
MakePageTablesImpl(l1_table, l2_l3_table, l2_l3_table);
return true;
}
static_assert(ValidateTzramPageTables());
}
void MakePageTable() {
u64 * const l1 = MemoryRegionPhysicalTzramL1PageTable.GetPointer<u64>();
u64 * const l2_l3 = MemoryRegionPhysicalTzramL2L3PageTable.GetPointer<u64>();
MakePageTablesImpl(l1, l2_l3, l2_l3);
}
}

View file

@ -0,0 +1,151 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "../secmon_key_storage.hpp"
#include "secmon_boot.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<const void *>(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));
}
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) {
/* Ensure that the SE sees consistent data. */
hw::FlushDataCache(key, key_size);
hw::FlushDataCache(src, src_size);
hw::FlushDataCache(dst, dst_size);
hw::DataSynchronizationBarrierInnerShareable();
/* Load the needed master key into the temporary keyslot. */
secmon::LoadMasterKey(pkg1::AesKeySlot_Temporary, key_generation);
/* Load the package2 key into the temporary keyslot. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, pkg1::AesKeySlot_Temporary, key, key_size);
/* Decrypt the data. */
se::ComputeAes128Ctr(dst, dst_size, pkg1::AesKeySlot_Temporary, src, src_size, iv, iv_size);
/* Clear the keyslot we just used. */
se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary);
/* Ensure that the cpu sees consistent data. */
hw::DataSynchronizationBarrierInnerShareable();
hw::FlushDataCache(dst, dst_size);
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;
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
.section .metadata.sizes, "ax", %progbits
.align 6
.global __metadata__sizes
__metadata__sizes:
.quad 0xAAAAAAAAAAAAAAAA, 0xBBBBBBBBBBBBBBBB
.quad __glob_start__
.quad __bootcode_start__
.quad __bootcode_end__
.quad __program_start__
.quad 0xCCCCCCCCCCCCCCCC, 0xDDDDDDDDDDDDDDDD