From eb2595ed6c22804684d3cbf0aa0f689d56e604e9 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 12 May 2020 00:32:09 -0700 Subject: [PATCH] exo2: implement through boot config load/validate --- libexosphere/include/exosphere.hpp | 1 + libexosphere/include/exosphere/br.hpp | 19 +++++ .../include/exosphere/br/br_types.hpp | 30 ++++++++ .../exosphere/br/impl/br_erista_types.hpp | 21 +++++ .../exosphere/br/impl/br_mariko_types.hpp | 21 +++++ libexosphere/include/exosphere/fuse.hpp | 2 + libexosphere/include/exosphere/pkg1.hpp | 1 + .../include/exosphere/pkg1/pkg1_api.hpp | 25 ++++++ .../exosphere/pkg1/pkg1_boot_config.hpp | 6 +- libexosphere/include/exosphere/se.hpp | 1 + libexosphere/include/exosphere/se/se_hash.hpp | 30 ++++++++ libexosphere/include/exosphere/se/se_rsa.hpp | 2 + ...ecmon_configuration_context.arch.arm64.hpp | 4 + .../exosphere/secmon/secmon_memory_layout.hpp | 8 +- .../include/exosphere/tegra/tegra_sysctr0.hpp | 19 ++++- libexosphere/source/fuse/fuse_api.cpp | 26 ++++++- libexosphere/source/pkg1/pkg1_api.cpp | 40 ++++++++++ libexosphere/source/se/se_hash.cpp | 72 ++++++++++++++++++ libexosphere/source/se/se_registers.hpp | 42 ++++------ libexosphere/source/se/se_rsa.cpp | 76 ++++++++++++++++--- 20 files changed, 400 insertions(+), 46 deletions(-) create mode 100644 libexosphere/include/exosphere/br.hpp create mode 100644 libexosphere/include/exosphere/br/br_types.hpp create mode 100644 libexosphere/include/exosphere/br/impl/br_erista_types.hpp create mode 100644 libexosphere/include/exosphere/br/impl/br_mariko_types.hpp create mode 100644 libexosphere/include/exosphere/pkg1/pkg1_api.hpp create mode 100644 libexosphere/include/exosphere/se/se_hash.hpp create mode 100644 libexosphere/source/pkg1/pkg1_api.cpp create mode 100644 libexosphere/source/se/se_hash.cpp diff --git a/libexosphere/include/exosphere.hpp b/libexosphere/include/exosphere.hpp index c92a382d..b320a52e 100644 --- a/libexosphere/include/exosphere.hpp +++ b/libexosphere/include/exosphere.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/libexosphere/include/exosphere/br.hpp b/libexosphere/include/exosphere/br.hpp new file mode 100644 index 00000000..089713a0 --- /dev/null +++ b/libexosphere/include/exosphere/br.hpp @@ -0,0 +1,19 @@ +/* + * 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 diff --git a/libexosphere/include/exosphere/br/br_types.hpp b/libexosphere/include/exosphere/br/br_types.hpp new file mode 100644 index 00000000..38201075 --- /dev/null +++ b/libexosphere/include/exosphere/br/br_types.hpp @@ -0,0 +1,30 @@ +/* + * 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 +#include + +namespace ams::br { + + struct BootEcid { + u32 ecid[4]; + }; + static_assert(util::is_pod::value); + static_assert(sizeof(BootEcid) == 0x10); + +} diff --git a/libexosphere/include/exosphere/br/impl/br_erista_types.hpp b/libexosphere/include/exosphere/br/impl/br_erista_types.hpp new file mode 100644 index 00000000..ee26f5b9 --- /dev/null +++ b/libexosphere/include/exosphere/br/impl/br_erista_types.hpp @@ -0,0 +1,21 @@ +/* + * 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::br::erista { + +} diff --git a/libexosphere/include/exosphere/br/impl/br_mariko_types.hpp b/libexosphere/include/exosphere/br/impl/br_mariko_types.hpp new file mode 100644 index 00000000..8210479c --- /dev/null +++ b/libexosphere/include/exosphere/br/impl/br_mariko_types.hpp @@ -0,0 +1,21 @@ +/* + * 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::br::mariko { + +} diff --git a/libexosphere/include/exosphere/fuse.hpp b/libexosphere/include/exosphere/fuse.hpp index 3df44b8a..55efdb33 100644 --- a/libexosphere/include/exosphere/fuse.hpp +++ b/libexosphere/include/exosphere/fuse.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include #include namespace ams::fuse { @@ -45,5 +46,6 @@ namespace ams::fuse { HardwareType GetHardwareType(); HardwareState GetHardwareState(); pmic::Regulator GetRegulator(); + void GetEcid(br::BootEcid *out); } \ No newline at end of file diff --git a/libexosphere/include/exosphere/pkg1.hpp b/libexosphere/include/exosphere/pkg1.hpp index d7dbad6a..90a61cb1 100644 --- a/libexosphere/include/exosphere/pkg1.hpp +++ b/libexosphere/include/exosphere/pkg1.hpp @@ -20,3 +20,4 @@ #include #include #include +#include diff --git a/libexosphere/include/exosphere/pkg1/pkg1_api.hpp b/libexosphere/include/exosphere/pkg1/pkg1_api.hpp new file mode 100644 index 00000000..632a122a --- /dev/null +++ b/libexosphere/include/exosphere/pkg1/pkg1_api.hpp @@ -0,0 +1,25 @@ +/* + * 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::pkg1 { + + bool IsProduction(); + bool IsProductionForVersionCheck(); + bool IsProductionForPublicKey(); + +} diff --git a/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp b/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp index da73f011..8cef0c82 100644 --- a/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp +++ b/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp @@ -90,9 +90,13 @@ namespace ams::pkg1 { return static_cast(this->flags0[3]); } - bool IsTscInitialValueValid() const { + constexpr bool IsInitialTscValueValid() const { return (this->flags0[4] & (1 << 0)) != 0; } + + constexpr u64 GetInitialTscValue() const { + return this->IsInitialTscValueValid() ? this->initial_tsc_value : 0; + } }; static_assert(util::is_pod::value); static_assert(sizeof(BootConfigData) == 0x200); diff --git a/libexosphere/include/exosphere/se.hpp b/libexosphere/include/exosphere/se.hpp index ad9abd63..c4669381 100644 --- a/libexosphere/include/exosphere/se.hpp +++ b/libexosphere/include/exosphere/se.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/libexosphere/include/exosphere/se/se_hash.hpp b/libexosphere/include/exosphere/se/se_hash.hpp new file mode 100644 index 00000000..934ced60 --- /dev/null +++ b/libexosphere/include/exosphere/se/se_hash.hpp @@ -0,0 +1,30 @@ +/* + * 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::se { + + constexpr inline int Sha256HashSize = crypto::Sha256Generator::HashSize; + + union Sha256Hash { + u8 bytes[Sha256HashSize / sizeof( u8)]; + u32 words[Sha256HashSize / sizeof(u32)]; + }; + + void CalculateSha256(Sha256Hash *dst, const void *src, size_t src_size); + +} diff --git a/libexosphere/include/exosphere/se/se_rsa.hpp b/libexosphere/include/exosphere/se/se_rsa.hpp index e16b99c6..e632f67a 100644 --- a/libexosphere/include/exosphere/se/se_rsa.hpp +++ b/libexosphere/include/exosphere/se/se_rsa.hpp @@ -26,4 +26,6 @@ namespace ams::se { void SetRsaKey(int slot, const void *mod, size_t mod_size, const void *exp, size_t exp_size); + void ModularExponentiate(void *dst, size_t dst_size, int slot, const void *src, size_t src_size); + } diff --git a/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp b/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp index 7f094a14..bf851565 100644 --- a/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp +++ b/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp @@ -70,6 +70,10 @@ namespace ams::secmon { GetConfigurationContext().secmon_cfg.key_generation = generation; } + ALWAYS_INLINE pkg1::BootConfig *GetBootConfigStorage() { + return std::addressof(GetConfigurationContext().boot_config); + } + } ALWAYS_INLINE const ConfigurationContext &GetConfigurationContext() { diff --git a/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp b/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp index c40368a3..1e25108c 100644 --- a/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp +++ b/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp @@ -271,7 +271,9 @@ namespace ams::secmon { static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramL2L3PageTable)); static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramL2L3PageTable)); - constexpr inline const MemoryRegion MemoryRegionPhysicalTzramFullProgramImage = MemoryRegion(0x7C010800, 0xD800); - constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeImage = MemoryRegion(0x40032000, 0xC000); + constexpr inline const MemoryRegion MemoryRegionPhysicalTzramFullProgramImage = MemoryRegion(UINT64_C(0x7C010800), 0xD800); + constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeImage = MemoryRegion(UINT64_C(0x40032000), 0xC000); -} \ No newline at end of file + constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootConfig = MemoryRegion(UINT64_C(0x4003F800), 0x400); + +} diff --git a/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp b/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp index a191641f..d7e7fd49 100644 --- a/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp +++ b/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp @@ -16,6 +16,9 @@ #pragma once #include +#define SYSCTR0_CNTCR (0x00C) +#define SYSCTR0_CNTCV0 (0x008) +#define SYSCTR0_CNTCV1 (0x00C) #define SYSCTR0_CNTFID0 (0x020) #define SYSCTR0_CNTFID1 (0x024) @@ -33,4 +36,18 @@ #define SYSCTR0_COUNTERID10 (0xFF8) #define SYSCTR0_COUNTERID11 (0xFFC) -#define SYSCTR0_COUNTERID(n) SYSCTR0_COUNTERID##n \ No newline at end of file +#define SYSCTR0_COUNTERID(n) SYSCTR0_COUNTERID##n + +#define SYSCTR0_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (SYSCTR0, NAME) +#define SYSCTR0_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (SYSCTR0, NAME, VALUE) +#define SYSCTR0_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (SYSCTR0, NAME, ENUM) +#define SYSCTR0_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(SYSCTR0, NAME, __COND__, TRUE_ENUM, FALSE_ENUM) + +#define DEFINE_SYSCTR0_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (SYSCTR0, NAME, __OFFSET__, __WIDTH__) +#define DEFINE_SYSCTR0_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (SYSCTR0, NAME, __OFFSET__, ZERO, ONE) +#define DEFINE_SYSCTR0_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (SYSCTR0, NAME, __OFFSET__, ZERO, ONE, TWO, THREE) +#define DEFINE_SYSCTR0_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(SYSCTR0, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) +#define DEFINE_SYSCTR0_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (SYSCTR0, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) + +DEFINE_SYSCTR0_REG_BIT_ENUM(CNTCR_EN, 0, DISABLE, ENABLE); +DEFINE_SYSCTR0_REG_BIT_ENUM(CNTCR_HDBG, 1, DISABLE, ENABLE); \ No newline at end of file diff --git a/libexosphere/source/fuse/fuse_api.cpp b/libexosphere/source/fuse/fuse_api.cpp index 73f48494..32d49139 100644 --- a/libexosphere/source/fuse/fuse_api.cpp +++ b/libexosphere/source/fuse/fuse_api.cpp @@ -118,4 +118,28 @@ namespace ams::fuse { return pmic::Regulator_Erista_Max77621; } -} \ No newline at end of file + void GetEcid(br::BootEcid *out) { + /* Get the registers. */ + const volatile auto &chip = GetChipRegisters(); + + /* Read the ecid components. */ + const u32 vendor = reg::Read(chip.FUSE_OPT_VENDOR_CODE); + const u32 fab = reg::Read(chip.FUSE_OPT_FAB_CODE); + const u32 lot0 = reg::Read(chip.FUSE_OPT_LOT_CODE_0); + const u32 lot1 = reg::Read(chip.FUSE_OPT_LOT_CODE_1); + const u32 wafer = reg::Read(chip.FUSE_OPT_WAFER_ID); + const u32 x_coord = reg::Read(chip.FUSE_OPT_X_COORDINATE); + const u32 y_coord = reg::Read(chip.FUSE_OPT_Y_COORDINATE); + const u32 reserved = reg::Read(chip.FUSE_OPT_OPS_RESERVED); + + /* Clear the output. */ + util::ClearMemory(out, sizeof(*out)); + + /* Copy the component bits. */ + out->ecid[0] = static_cast((lot1 << 30) | (wafer << 24) | (x_coord << 15) | (y_coord << 6) | (reserved)); + out->ecid[1] = static_cast((lot0 << 26) | (lot1 >> 2)); + out->ecid[2] = static_cast((fab << 26) | (lot0 >> 6)); + out->ecid[3] = static_cast(vendor); + } + +} diff --git a/libexosphere/source/pkg1/pkg1_api.cpp b/libexosphere/source/pkg1/pkg1_api.cpp new file mode 100644 index 00000000..035b4d08 --- /dev/null +++ b/libexosphere/source/pkg1/pkg1_api.cpp @@ -0,0 +1,40 @@ +/* + * 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 + +namespace ams::pkg1 { + + namespace { + + bool IsProductionImpl() { + return fuse::GetHardwareState() != fuse::HardwareState_Development; + } + + } + + bool IsProduction() { + return IsProductionImpl(); + } + + bool IsProductionForVersionCheck() { + return IsProductionImpl(); + } + + bool IsProductionForPublicKey() { + return IsProductionImpl(); + } + +} diff --git a/libexosphere/source/se/se_hash.cpp b/libexosphere/source/se/se_hash.cpp new file mode 100644 index 00000000..2ef38deb --- /dev/null +++ b/libexosphere/source/se/se_hash.cpp @@ -0,0 +1,72 @@ +/* + * 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 "se_execute.hpp" + +namespace ams::se { + + namespace { + + void SetMessageSize(volatile SecurityEngineRegisters *SE, size_t src_size) { + /* Set the message size. */ + reg::Write(SE->SE_SHA_MSG_LENGTH[0], src_size * BITSIZEOF(u8)); + reg::Write(SE->SE_SHA_MSG_LENGTH[1], 0); + reg::Write(SE->SE_SHA_MSG_LENGTH[2], 0); + reg::Write(SE->SE_SHA_MSG_LENGTH[3], 0); + + /* Set the message remaining size. */ + reg::Write(SE->SE_SHA_MSG_LEFT[0], src_size * BITSIZEOF(u8)); + reg::Write(SE->SE_SHA_MSG_LEFT[1], 0); + reg::Write(SE->SE_SHA_MSG_LEFT[2], 0); + reg::Write(SE->SE_SHA_MSG_LEFT[3], 0); + } + + void GetHashResult(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size) { + /* Copy out the words. */ + const int num_words = dst_size / sizeof(u32); + for (int i = 0; i < num_words; ++i) { + const u32 word = reg::Read(SE->SE_HASH_RESULT[i]); + util::StoreBigEndian(static_cast(dst) + i, word); + } + } + + } + + void CalculateSha256(Sha256Hash *dst, const void *src, size_t src_size) { + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Configure the engine to perform SHA256 "encryption". */ + reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, SHA256), + SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128), + SE_REG_BITS_ENUM(CONFIG_ENC_ALG, SHA), + SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP), + SE_REG_BITS_ENUM(CONFIG_DST, HASH_REG)); + + /* Begin a hardware hash operation. */ + reg::Write(SE->SE_SHA_CONFIG, SE_REG_BITS_VALUE(SHA_CONFIG_HW_INIT_HASH, 1)); + + /* Set the message size. */ + SetMessageSize(SE, src_size); + + /* Execute the operation. */ + ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, src, src_size); + + /* Get the result. */ + GetHashResult(SE, dst, sizeof(*dst)); + } + +} diff --git a/libexosphere/source/se/se_registers.hpp b/libexosphere/source/se/se_registers.hpp index d76e0571..2a5e7035 100644 --- a/libexosphere/source/se/se_registers.hpp +++ b/libexosphere/source/se/se_registers.hpp @@ -133,32 +133,12 @@ namespace ams::se { DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_ERR_STAT, 16); /* SE_CONFIG */ - DEFINE_SE_REG(CONFIG_DST, 2, 3); - DEFINE_SE_REG(CONFIG_DEC_ALG, 8, 4); - DEFINE_SE_REG(CONFIG_ENC_ALG, 12, 4); DEFINE_SE_REG(CONFIG_DEC_MODE, 16, 8); DEFINE_SE_REG(CONFIG_ENC_MODE, 24, 8); - enum SE_CONFIG_DST { - SE_CONFIG_DST_MEMORY = 0, - SE_CONFIG_DST_HASH_REG = 1, - SE_CONFIG_DST_KEYTABLE = 2, - SE_CONFIG_DST_SRK = 3, - SE_CONFIG_DST_RSA_REG = 4, - }; - - enum SE_CONFIG_DEC_ALG { - SE_CONFIG_DEC_ALG_NOP = 0, - SE_CONFIG_DEC_ALG_AES_DEC = 1, - }; - - enum SE_CONFIG_ENC_ALG { - SE_CONFIG_ENC_ALG_NOP = 0, - SE_CONFIG_ENC_ALG_AES_ENC = 1, - SE_CONFIG_ENC_ALG_RNG = 2, - SE_CONFIG_ENC_ALG_SHA = 3, - SE_CONFIG_ENC_ALG_RSA = 4, - }; + DEFINE_SE_REG_THREE_BIT_ENUM(CONFIG_DST, 2, MEMORY, HASH_REG, KEYTABLE, SRK, RSA_REG, RESERVED5, RESERVED6, RESERVED7); + DEFINE_SE_REG_FOUR_BIT_ENUM(CONFIG_DEC_ALG, 8, NOP, AES_DEC, RESERVED2, RESERVED3, RESERVED4, RESERVED5, RESERVED6, RESERVED7, RESERVED8, RESERVED9, RESERVED10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15); + DEFINE_SE_REG_FOUR_BIT_ENUM(CONFIG_ENC_ALG, 12, NOP, AES_ENC, RNG, SHA, RSA, RESERVED5, RESERVED6, RESERVED7, RESERVED8, RESERVED9, RESERVED10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15); enum SE_CONFIG_DEC_MODE { SE_CONFIG_DEC_MODE_AESMODE_KEY128 = 0, @@ -171,13 +151,16 @@ namespace ams::se { SE_CONFIG_ENC_MODE_AESMODE_KEY192 = 1, SE_CONFIG_ENC_MODE_AESMODE_KEY256 = 2, - SE_CONFIG_ENC_MODE_AESMODE_SHA1 = 1, - SE_CONFIG_ENC_MODE_AESMODE_SHA224 = 4, - SE_CONFIG_ENC_MODE_AESMODE_SHA256 = 5, - SE_CONFIG_ENC_MODE_AESMODE_SHA384 = 6, - SE_CONFIG_ENC_MODE_AESMODE_SHA512 = 7, + SE_CONFIG_ENC_MODE_SHA1 = 1, + SE_CONFIG_ENC_MODE_SHA224 = 4, + SE_CONFIG_ENC_MODE_SHA256 = 5, + SE_CONFIG_ENC_MODE_SHA384 = 6, + SE_CONFIG_ENC_MODE_SHA512 = 7, }; + /* SE_SHA_CONFIG */ + DEFINE_SE_REG(SHA_CONFIG_HW_INIT_HASH, 0, 1); + /* SE_CRYPTO_KEYTABLE_ADDR */ DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_WORD, 0, 4); @@ -208,6 +191,9 @@ namespace ams::se { DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, 4, 4); + /* SE_RSA_CONFIG */ + DEFINE_SE_REG(RSA_CONFIG_KEY_SLOT, 24, 1); + /* SE_RSA_KEYTABLE_ADDR */ DEFINE_SE_REG(RSA_KEYTABLE_ADDR_WORD_ADDR, 0, 6); DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ADDR_EXPMOD_SEL, 6, EXPONENT, MODULUS); diff --git a/libexosphere/source/se/se_rsa.cpp b/libexosphere/source/se/se_rsa.cpp index d39a040d..99ec5e90 100644 --- a/libexosphere/source/se/se_rsa.cpp +++ b/libexosphere/source/se/se_rsa.cpp @@ -27,10 +27,7 @@ namespace ams::se { constinit RsaKeyInfo g_rsa_key_infos[RsaKeySlotCount] = {}; - void ClearRsaKeySlot(int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod) { - /* Get the engine. */ - auto *SE = GetRegisters(); - + void ClearRsaKeySlot(volatile SecurityEngineRegisters *SE, int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod) { constexpr int NumWords = se::RsaSize / sizeof(u32); for (int i = 0; i < NumWords; ++i) { /* Select the keyslot word. */ @@ -44,10 +41,7 @@ namespace ams::se { } } - void SetRsaKey(int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod, const void *key, size_t key_size) { - /* Get the engine. */ - auto *SE = GetRegisters(); - + void SetRsaKey(volatile SecurityEngineRegisters *SE, int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod, const void *key, size_t key_size) { const int num_words = key_size / sizeof(u32); for (int i = 0; i < num_words; ++i) { /* Select the keyslot word. */ @@ -64,6 +58,15 @@ namespace ams::se { } } + void GetRsaResult(volatile SecurityEngineRegisters *SE, void *dst, size_t size) { + /* Copy out the words. */ + const int num_words = size / sizeof(u32); + for (int i = 0; i < num_words; ++i) { + const u32 word = reg::Read(SE->SE_RSA_OUTPUT[i]); + util::StoreBigEndian(static_cast(dst) + num_words - 1 - i, word); + } + } + } void ClearRsaKeySlot(int slot) { @@ -73,11 +76,14 @@ namespace ams::se { /* Clear the info. */ g_rsa_key_infos[slot] = {}; + /* Get the engine. */ + auto *SE = GetRegisters(); + /* Clear the modulus. */ - ClearRsaKeySlot(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS); + ClearRsaKeySlot(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS); /* Clear the exponent. */ - ClearRsaKeySlot(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT); + ClearRsaKeySlot(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT); } void LockRsaKeySlot(int slot, u32 flags) { @@ -117,9 +123,55 @@ namespace ams::se { info.modulus_size_val = (mod_size / 64) - 1; info.exponent_size_val = (exp_size / 4); + /* Get the engine. */ + auto *SE = GetRegisters(); + /* Set the modulus and exponent. */ - SetRsaKey(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS, mod, mod_size); - SetRsaKey(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT, exp, exp_size); + SetRsaKey(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS, mod, mod_size); + SetRsaKey(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT, exp, exp_size); + } + + void ModularExponentiate(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) { + /* Validate the slot and sizes. */ + AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount); + AMS_ABORT_UNLESS(src_size <= RsaSize); + AMS_ABORT_UNLESS(dst_size <= RsaSize); + + /* Get the engine. */ + auto *SE = GetRegisters(); + + /* Create a work buffer. */ + u8 work[RsaSize]; + util::ClearMemory(work, sizeof(work)); + + /* Copy the input into the work buffer (reversing endianness). */ + const u8 *src_u8 = static_cast(src); + for (size_t i = 0; i < src_size; ++i) { + work[src_size - 1 - i] = src_u8[i]; + } + + /* Flush the work buffer to ensure the SE sees correct results. */ + hw::FlushDataCache(work, sizeof(work)); + hw::DataSynchronizationBarrierInnerShareable(); + + /* Configure the engine to perform RSA encryption. */ + reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128), + SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128), + SE_REG_BITS_ENUM(CONFIG_ENC_ALG, RSA), + SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP), + SE_REG_BITS_ENUM(CONFIG_DST, RSA_REG)); + + /* Configure the engine to use the keyslot and correct modulus/exp sizes. */ + const auto &info = g_rsa_key_infos[slot]; + reg::Write(SE->SE_RSA_CONFIG, SE_REG_BITS_VALUE(RSA_CONFIG_KEY_SLOT, slot)); + reg::Write(SE->SE_RSA_KEY_SIZE, info.modulus_size_val); + reg::Write(SE->SE_RSA_EXP_SIZE, info.exponent_size_val); + + /* Execute the operation. */ + ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, work, src_size); + + /* Copy out the result. */ + GetRsaResult(SE, dst, dst_size); } }