diff --git a/stratosphere/boot/source/boot_boot_reason.cpp b/stratosphere/boot/source/boot_boot_reason.cpp index fdad4f0..d78ef8a 100644 --- a/stratosphere/boot/source/boot_boot_reason.cpp +++ b/stratosphere/boot/source/boot_boot_reason.cpp @@ -14,10 +14,11 @@ * along with this program. If not, see . */ +#include + #include "boot_boot_reason.hpp" #include "boot_pmic_driver.hpp" #include "boot_rtc_driver.hpp" -#include "boot_spl_utils.hpp" namespace sts::boot { diff --git a/stratosphere/boot/source/boot_display.cpp b/stratosphere/boot/source/boot_display.cpp index eb3994f..45bd128 100644 --- a/stratosphere/boot/source/boot_display.cpp +++ b/stratosphere/boot/source/boot_display.cpp @@ -15,11 +15,11 @@ */ #include +#include #include "boot_display.hpp" #include "boot_i2c_utils.hpp" #include "boot_pmc_wrapper.hpp" -#include "boot_spl_utils.hpp" #include "boot_registers_clkrst.hpp" #include "boot_registers_di.hpp" diff --git a/stratosphere/boot/source/boot_fan_enable.cpp b/stratosphere/boot/source/boot_fan_enable.cpp index 190c0b6..d235cc5 100644 --- a/stratosphere/boot/source/boot_fan_enable.cpp +++ b/stratosphere/boot/source/boot_fan_enable.cpp @@ -14,8 +14,9 @@ * along with this program. If not, see . */ +#include + #include "boot_fan_enable.hpp" -#include "boot_spl_utils.hpp" #include "gpio/gpio_utils.hpp" diff --git a/stratosphere/boot/source/boot_main.cpp b/stratosphere/boot/source/boot_main.cpp index a28b72a..f7b120c 100644 --- a/stratosphere/boot/source/boot_main.cpp +++ b/stratosphere/boot/source/boot_main.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "boot_boot_reason.hpp" #include "boot_change_voltage.hpp" @@ -37,7 +38,6 @@ #include "pinmux/pinmux_initial_configuration.hpp" #include "boot_power_utils.hpp" -#include "boot_spl_utils.hpp" using namespace sts; diff --git a/stratosphere/boot/source/boot_repair_boot_images.cpp b/stratosphere/boot/source/boot_repair_boot_images.cpp index 78fd8fa..e2ae290 100644 --- a/stratosphere/boot/source/boot_repair_boot_images.cpp +++ b/stratosphere/boot/source/boot_repair_boot_images.cpp @@ -14,9 +14,10 @@ * along with this program. If not, see . */ +#include + #include "boot_power_utils.hpp" #include "boot_repair_boot_images.hpp" -#include "boot_spl_utils.hpp" #include "updater/updater_api.hpp" diff --git a/stratosphere/boot/source/boot_spl_utils.cpp b/stratosphere/boot/source/boot_spl_utils.cpp deleted file mode 100644 index d5e60e1..0000000 --- a/stratosphere/boot/source/boot_spl_utils.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018-2019 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 "boot_spl_utils.hpp" - -namespace sts::spl { - - spl::HardwareType GetHardwareType() { - u64 out_val = 0; - R_ASSERT(splGetConfig(SplConfigItem_HardwareType, &out_val)); - return static_cast(out_val); - } - - bool IsRecoveryBoot() { - u64 val = 0; - R_ASSERT(splGetConfig(SplConfigItem_IsRecoveryBoot, &val)); - return val != 0; - } - - bool IsMariko() { - const auto hw_type = GetHardwareType(); - switch (hw_type) { - case spl::HardwareType::Icosa: - case spl::HardwareType::Copper: - return false; - case spl::HardwareType::Hoag: - case spl::HardwareType::Iowa: - return true; - default: - std::abort(); - } - } - -} diff --git a/stratosphere/boot/source/boot_spl_utils.hpp b/stratosphere/boot/source/boot_spl_utils.hpp deleted file mode 100644 index a12171f..0000000 --- a/stratosphere/boot/source/boot_spl_utils.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018-2019 Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once -#include -#include - -namespace sts::spl { - - enum class HardwareType { - Icosa = 0, - Copper = 1, - Hoag = 2, - Iowa = 3, - }; - - /* SPL Utilities. */ - HardwareType GetHardwareType(); - bool IsRecoveryBoot(); - bool IsMariko(); - -} \ No newline at end of file diff --git a/stratosphere/boot/source/boot_wake_pins.cpp b/stratosphere/boot/source/boot_wake_pins.cpp index 9df434f..c32c2d1 100644 --- a/stratosphere/boot/source/boot_wake_pins.cpp +++ b/stratosphere/boot/source/boot_wake_pins.cpp @@ -14,8 +14,9 @@ * along with this program. If not, see . */ +#include + #include "boot_pmc_wrapper.hpp" -#include "boot_spl_utils.hpp" #include "boot_wake_pins.hpp" #include "boot_registers_pmc.hpp" diff --git a/stratosphere/boot/source/gpio/gpio_initial_configuration.cpp b/stratosphere/boot/source/gpio/gpio_initial_configuration.cpp index c516be8..d16e580 100644 --- a/stratosphere/boot/source/gpio/gpio_initial_configuration.cpp +++ b/stratosphere/boot/source/gpio/gpio_initial_configuration.cpp @@ -14,12 +14,11 @@ * along with this program. If not, see . */ +#include + #include "gpio_initial_configuration.hpp" #include "gpio_utils.hpp" -/* TODO: Better way? */ -#include "../boot_spl_utils.hpp" - namespace sts::gpio { namespace { diff --git a/stratosphere/boot/source/pinmux/pinmux_initial_configuration.cpp b/stratosphere/boot/source/pinmux/pinmux_initial_configuration.cpp index 091c55f..5076932 100644 --- a/stratosphere/boot/source/pinmux/pinmux_initial_configuration.cpp +++ b/stratosphere/boot/source/pinmux/pinmux_initial_configuration.cpp @@ -14,13 +14,11 @@ * along with this program. If not, see . */ +#include #include "pinmux_initial_configuration.hpp" #include "pinmux_utils.hpp" -/* TODO: Better way? */ -#include "../boot_spl_utils.hpp" - namespace sts::pinmux { namespace { diff --git a/stratosphere/boot/source/updater/updater_api.hpp b/stratosphere/boot/source/updater/updater_api.hpp index fcca1da..1baa7e9 100644 --- a/stratosphere/boot/source/updater/updater_api.hpp +++ b/stratosphere/boot/source/updater/updater_api.hpp @@ -17,6 +17,7 @@ #pragma once #include #include +#include #include "updater_types.hpp" diff --git a/stratosphere/boot/source/updater/updater_types.hpp b/stratosphere/boot/source/updater/updater_types.hpp index 5c3f9c0..6abd7cd 100644 --- a/stratosphere/boot/source/updater/updater_types.hpp +++ b/stratosphere/boot/source/updater/updater_types.hpp @@ -18,9 +18,6 @@ #include #include -/* TODO: Better way to do this? */ -#include "../boot_spl_utils.hpp" - namespace sts::updater { /* Types. */ diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index 13e3f51..ca344e1 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit 13e3f517cb5db1053e01fb21ec189728d5b9d6db +Subproject commit ca344e1d19267779a59b6a212683792538bb76af diff --git a/stratosphere/spl/source/spl_api.cpp b/stratosphere/spl/source/spl_api.cpp deleted file mode 100644 index b43ecca..0000000 --- a/stratosphere/spl/source/spl_api.cpp +++ /dev/null @@ -1,937 +0,0 @@ -/* - * Copyright (c) 2018-2019 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 - -#include "spl_api.hpp" -#include "spl_smc.hpp" - -#include "spl_ctr_drbg.hpp" - -namespace sts::spl { - - namespace { - - /* Convenient defines. */ - constexpr size_t DeviceAddressSpaceAlignSize = 0x400000; - constexpr size_t DeviceAddressSpaceAlignMask = DeviceAddressSpaceAlignSize - 1; - constexpr u32 WorkBufferMapBase = 0x80000000u; - constexpr u32 CryptAesInMapBase = 0x90000000u; - constexpr u32 CryptAesOutMapBase = 0xC0000000u; - constexpr size_t CryptAesSizeMax = static_cast(CryptAesOutMapBase - CryptAesInMapBase); - - constexpr size_t RsaPrivateKeySize = 0x100; - constexpr size_t RsaPrivateKeyMetaSize = 0x30; - constexpr size_t LabelDigestSizeMax = 0x20; - - constexpr size_t WorkBufferSizeMax = 0x800; - - constexpr size_t MaxAesKeyslots = 6; - constexpr size_t MaxAesKeyslotsDeprecated = 4; - - /* Max Keyslots helper. */ - inline size_t GetMaxKeyslots() { - return (GetRuntimeFirmwareVersion() >= FirmwareVersion_600) ? MaxAesKeyslots : MaxAesKeyslotsDeprecated; - } - - /* Type definitions. */ - class ScopedAesKeyslot { - private: - u32 slot; - bool has_slot; - public: - ScopedAesKeyslot() : slot(0), has_slot(false) { - /* ... */ - } - ~ScopedAesKeyslot() { - if (has_slot) { - spl::FreeAesKeyslot(slot, this); - } - } - - u32 GetKeyslot() const { - return this->slot; - } - - Result Allocate() { - R_TRY(spl::AllocateAesKeyslot(&this->slot, this)); - this->has_slot = true; - return ResultSuccess; - } - }; - - struct SeLinkedListEntry { - u32 num_entries; - u32 address; - u32 size; - }; - - struct SeCryptContext { - SeLinkedListEntry in; - SeLinkedListEntry out; - }; - - class DeviceAddressSpaceMapHelper { - private: - Handle das_hnd; - u64 dst_addr; - u64 src_addr; - size_t size; - u32 perm; - public: - DeviceAddressSpaceMapHelper(Handle h, u64 dst, u64 src, size_t sz, u32 p) : das_hnd(h), dst_addr(dst), src_addr(src), size(sz), perm(p) { - R_ASSERT(svcMapDeviceAddressSpaceAligned(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr, this->perm)); - } - ~DeviceAddressSpaceMapHelper() { - R_ASSERT(svcUnmapDeviceAddressSpace(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr)); - } - }; - - /* Global variables. */ - CtrDrbg g_drbg; - Event g_se_event; - IEvent *g_se_keyslot_available_event; - - Handle g_se_das_hnd; - u32 g_se_mapped_work_buffer_addr; - u8 __attribute__((aligned(0x1000))) g_work_buffer[2 * WorkBufferSizeMax]; - - HosMutex g_async_op_lock; - - const void *g_keyslot_owners[MaxAesKeyslots]; - BootReasonValue g_boot_reason; - bool g_boot_reason_set; - - /* Boot Reason accessors. */ - BootReasonValue GetBootReason() { - return g_boot_reason; - } - - bool IsBootReasonSet() { - return g_boot_reason_set; - } - - /* Initialization functionality. */ - void InitializeCtrDrbg() { - u8 seed[CtrDrbg::SeedSize]; - - if (smc::GenerateRandomBytes(seed, sizeof(seed)) != smc::Result::Success) { - std::abort(); - } - - g_drbg.Initialize(seed); - } - - void InitializeSeEvents() { - u64 irq_num; - smc::GetConfig(&irq_num, 1, SplConfigItem_SecurityEngineIrqNumber); - Handle hnd; - R_ASSERT(svcCreateInterruptEvent(&hnd, irq_num, 1)); - eventLoadRemote(&g_se_event, hnd, true); - - g_se_keyslot_available_event = CreateWriteOnlySystemEvent(); - g_se_keyslot_available_event->Signal(); - } - - void InitializeDeviceAddressSpace() { - constexpr u64 DeviceName_SE = 29; - - /* Create Address Space. */ - R_ASSERT(svcCreateDeviceAddressSpace(&g_se_das_hnd, 0, (1ul << 32))); - - /* Attach it to the SE. */ - R_ASSERT(svcAttachDeviceAddressSpace(DeviceName_SE, g_se_das_hnd)); - - const u64 work_buffer_addr = reinterpret_cast(g_work_buffer); - g_se_mapped_work_buffer_addr = WorkBufferMapBase + (work_buffer_addr & DeviceAddressSpaceAlignMask); - - /* Map the work buffer for the SE. */ - R_ASSERT(svcMapDeviceAddressSpaceAligned(g_se_das_hnd, CUR_PROCESS_HANDLE, work_buffer_addr, sizeof(g_work_buffer), g_se_mapped_work_buffer_addr, 3)); - } - - /* RSA OAEP implementation helpers. */ - void CalcMgf1AndXor(void *dst, size_t dst_size, const void *src, size_t src_size) { - uint8_t *dst_u8 = reinterpret_cast(dst); - - u32 ctr = 0; - while (dst_size > 0) { - size_t cur_size = SHA256_HASH_SIZE; - if (cur_size > dst_size) { - cur_size = dst_size; - } - dst_size -= cur_size; - - u32 ctr_be = __builtin_bswap32(ctr++); - u8 hash[SHA256_HASH_SIZE]; - { - Sha256Context ctx; - sha256ContextCreate(&ctx); - sha256ContextUpdate(&ctx, src, src_size); - sha256ContextUpdate(&ctx, &ctr_be, sizeof(ctr_be)); - sha256ContextGetHash(&ctx, hash); - } - - for (size_t i = 0; i < cur_size; i++) { - *(dst_u8++) ^= hash[i]; - } - } - } - - size_t DecodeRsaOaep(void *dst, size_t dst_size, const void *label_digest, size_t label_digest_size, const void *src, size_t src_size) { - /* Very basic validation. */ - if (dst_size == 0 || src_size != 0x100 || label_digest_size != SHA256_HASH_SIZE) { - return 0; - } - - u8 block[0x100]; - std::memcpy(block, src, sizeof(block)); - - /* First, validate byte 0 == 0, and unmask DB. */ - int invalid = block[0]; - u8 *salt = block + 1; - u8 *db = salt + SHA256_HASH_SIZE; - CalcMgf1AndXor(salt, SHA256_HASH_SIZE, db, src_size - (1 + SHA256_HASH_SIZE)); - CalcMgf1AndXor(db, src_size - (1 + SHA256_HASH_SIZE), salt, SHA256_HASH_SIZE); - - /* Validate label digest. */ - for (size_t i = 0; i < SHA256_HASH_SIZE; i++) { - invalid |= db[i] ^ reinterpret_cast(label_digest)[i]; - } - - /* Locate message after 00...0001 padding. */ - const u8 *padded_msg = db + SHA256_HASH_SIZE; - size_t padded_msg_size = src_size - (1 + 2 * SHA256_HASH_SIZE); - size_t msg_ind = 0; - int not_found = 1; - int wrong_padding = 0; - size_t i = 0; - while (i < padded_msg_size) { - int zero = (padded_msg[i] == 0); - int one = (padded_msg[i] == 1); - msg_ind += static_cast(not_found & one) * (++i); - not_found &= ~one; - wrong_padding |= (not_found & ~zero); - } - - if (invalid | not_found | wrong_padding) { - return 0; - } - - /* Copy message out. */ - size_t msg_size = padded_msg_size - msg_ind; - if (msg_size > dst_size) { - return 0; - } - std::memcpy(dst, padded_msg + msg_ind, msg_size); - return msg_size; - } - - /* Internal RNG functionality. */ - Result GenerateRandomBytesInternal(void *out, size_t size) { - if (!g_drbg.GenerateRandomBytes(out, size)) { - /* We need to reseed. */ - { - u8 seed[CtrDrbg::SeedSize]; - - smc::Result res = smc::GenerateRandomBytes(seed, sizeof(seed)); - if (res != smc::Result::Success) { - return smc::ConvertResult(res); - } - - g_drbg.Reseed(seed); - g_drbg.GenerateRandomBytes(out, size); - } - } - - return ResultSuccess; - } - - /* Internal async implementation functionality. */ - void WaitSeOperationComplete() { - eventWait(&g_se_event, U64_MAX); - } - - smc::Result WaitCheckStatus(smc::AsyncOperationKey op_key) { - WaitSeOperationComplete(); - - smc::Result op_res; - smc::Result res = smc::CheckStatus(&op_res, op_key); - if (res != smc::Result::Success) { - return res; - } - - return op_res; - } - - smc::Result WaitGetResult(void *out_buf, size_t out_buf_size, smc::AsyncOperationKey op_key) { - WaitSeOperationComplete(); - - smc::Result op_res; - smc::Result res = smc::GetResult(&op_res, out_buf, out_buf_size, op_key); - if (res != smc::Result::Success) { - return res; - } - - return op_res; - } - - /* Internal Keyslot utility. */ - Result ValidateAesKeyslot(u32 keyslot, const void *owner) { - if (keyslot >= GetMaxKeyslots()) { - return ResultSplInvalidKeyslot; - } - if (g_keyslot_owners[keyslot] != owner && GetRuntimeFirmwareVersion() > FirmwareVersion_100) { - return ResultSplInvalidKeyslot; - } - return ResultSuccess; - } - - /* Helper to do a single AES block decryption. */ - smc::Result DecryptAesBlock(u32 keyslot, void *dst, const void *src) { - struct DecryptAesBlockLayout { - SeCryptContext crypt_ctx; - u8 in_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE))); - u8 out_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE))); - }; - DecryptAesBlockLayout *layout = reinterpret_cast(g_work_buffer); - - layout->crypt_ctx.in.num_entries = 0; - layout->crypt_ctx.in.address = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, in_block); - layout->crypt_ctx.in.size = sizeof(layout->in_block); - layout->crypt_ctx.out.num_entries = 0; - layout->crypt_ctx.out.address = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, out_block); - layout->crypt_ctx.out.size = sizeof(layout->out_block); - - std::memcpy(layout->in_block, src, sizeof(layout->in_block)); - - armDCacheFlush(layout, sizeof(*layout)); - { - std::scoped_lock lk(g_async_op_lock); - smc::AsyncOperationKey op_key; - const IvCtr iv_ctr = {}; - const u32 mode = smc::GetCryptAesMode(smc::CipherMode::CbcDecrypt, keyslot); - const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.out); - const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.in); - - smc::Result res = smc::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, sizeof(layout->in_block)); - if (res != smc::Result::Success) { - return res; - } - - if ((res = WaitCheckStatus(op_key)) != smc::Result::Success) { - return res; - } - } - armDCacheFlush(layout, sizeof(*layout)); - - std::memcpy(dst, layout->out_block, sizeof(layout->out_block)); - return smc::Result::Success; - } - - /* Implementation wrappers for API commands. */ - Result ImportSecureExpModKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) { - struct ImportSecureExpModKeyLayout { - u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10]; - }; - ImportSecureExpModKeyLayout *layout = reinterpret_cast(g_work_buffer); - - /* Validate size. */ - if (src_size > sizeof(ImportSecureExpModKeyLayout)) { - return ResultSplInvalidSize; - } - - std::memcpy(layout, src, src_size); - - armDCacheFlush(layout, sizeof(*layout)); - smc::Result smc_res; - if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { - smc_res = smc::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, static_cast(option)); - } else { - smc_res = smc::ImportSecureExpModKey(layout->data, src_size, access_key, key_source, option); - } - - return smc::ConvertResult(smc_res); - } - - Result SecureExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size, smc::SecureExpModMode mode) { - struct SecureExpModLayout { - u8 base[0x100]; - u8 mod[0x100]; - }; - SecureExpModLayout *layout = reinterpret_cast(g_work_buffer); - - /* Validate sizes. */ - if (base_size > sizeof(layout->base)) { - return ResultSplInvalidSize; - } - if (mod_size > sizeof(layout->mod)) { - return ResultSplInvalidSize; - } - if (out_size > WorkBufferSizeMax) { - return ResultSplInvalidSize; - } - - /* Copy data into work buffer. */ - const size_t base_ofs = sizeof(layout->base) - base_size; - const size_t mod_ofs = sizeof(layout->mod) - mod_size; - std::memset(layout, 0, sizeof(*layout)); - std::memcpy(layout->base + base_ofs, base, base_size); - std::memcpy(layout->mod + mod_ofs, mod, mod_size); - - /* Do exp mod operation. */ - armDCacheFlush(layout, sizeof(*layout)); - { - std::scoped_lock lk(g_async_op_lock); - smc::AsyncOperationKey op_key; - - smc::Result res = smc::SecureExpMod(&op_key, layout->base, layout->mod, mode); - if (res != smc::Result::Success) { - return smc::ConvertResult(res); - } - - if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != smc::Result::Success) { - return smc::ConvertResult(res); - } - } - armDCacheFlush(g_work_buffer, sizeof(out_size)); - - std::memcpy(out, g_work_buffer, out_size); - return ResultSuccess; - } - - Result UnwrapEsRsaOaepWrappedKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation, smc::EsKeyType type) { - struct UnwrapEsKeyLayout { - u8 base[0x100]; - u8 mod[0x100]; - }; - UnwrapEsKeyLayout *layout = reinterpret_cast(g_work_buffer); - - /* Validate sizes. */ - if (base_size > sizeof(layout->base)) { - return ResultSplInvalidSize; - } - if (mod_size > sizeof(layout->mod)) { - return ResultSplInvalidSize; - } - if (label_digest_size > LabelDigestSizeMax) { - return ResultSplInvalidSize; - } - - /* Copy data into work buffer. */ - const size_t base_ofs = sizeof(layout->base) - base_size; - const size_t mod_ofs = sizeof(layout->mod) - mod_size; - std::memset(layout, 0, sizeof(*layout)); - std::memcpy(layout->base + base_ofs, base, base_size); - std::memcpy(layout->mod + mod_ofs, mod, mod_size); - - /* Do exp mod operation. */ - armDCacheFlush(layout, sizeof(*layout)); - { - std::scoped_lock lk(g_async_op_lock); - smc::AsyncOperationKey op_key; - - smc::Result res = smc::UnwrapTitleKey(&op_key, layout->base, layout->mod, label_digest, label_digest_size, smc::GetUnwrapEsKeyOption(type, generation)); - if (res != smc::Result::Success) { - return smc::ConvertResult(res); - } - - if ((res = WaitGetResult(g_work_buffer, sizeof(*out_access_key), op_key)) != smc::Result::Success) { - return smc::ConvertResult(res); - } - } - armDCacheFlush(g_work_buffer, sizeof(*out_access_key)); - - std::memcpy(out_access_key, g_work_buffer, sizeof(*out_access_key)); - return ResultSuccess; - } - - - } - - /* Initialization. */ - void Initialize() { - /* Initialize the Drbg. */ - InitializeCtrDrbg(); - /* Initialize SE interrupt + keyslot events. */ - InitializeSeEvents(); - /* Initialize DAS for the SE. */ - InitializeDeviceAddressSpace(); - } - - /* General. */ - Result GetConfig(u64 *out, SplConfigItem which) { - /* Nintendo explicitly blacklists package2 hash here, amusingly. */ - /* This is not blacklisted in safemode, but we're never in safe mode... */ - if (which == SplConfigItem_Package2Hash) { - return ResultSplInvalidArgument; - } - - smc::Result res = smc::GetConfig(out, 1, which); - - /* Nintendo has some special handling here for hardware type/is_retail. */ - if (which == SplConfigItem_HardwareType && res == smc::Result::InvalidArgument) { - *out = 0; - res = smc::Result::Success; - } - if (which == SplConfigItem_IsRetail && res == smc::Result::InvalidArgument) { - *out = 0; - res = smc::Result::Success; - } - - return smc::ConvertResult(res); - } - - Result ExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size) { - struct ExpModLayout { - u8 base[0x100]; - u8 exp[0x100]; - u8 mod[0x100]; - }; - ExpModLayout *layout = reinterpret_cast(g_work_buffer); - - /* Validate sizes. */ - if (base_size > sizeof(layout->base)) { - return ResultSplInvalidSize; - } - if (exp_size > sizeof(layout->exp)) { - return ResultSplInvalidSize; - } - if (mod_size > sizeof(layout->mod)) { - return ResultSplInvalidSize; - } - if (out_size > WorkBufferSizeMax) { - return ResultSplInvalidSize; - } - - /* Copy data into work buffer. */ - const size_t base_ofs = sizeof(layout->base) - base_size; - const size_t mod_ofs = sizeof(layout->mod) - mod_size; - std::memset(layout, 0, sizeof(*layout)); - std::memcpy(layout->base + base_ofs, base, base_size); - std::memcpy(layout->exp, exp, exp_size); - std::memcpy(layout->mod + mod_ofs, mod, mod_size); - - /* Do exp mod operation. */ - armDCacheFlush(layout, sizeof(*layout)); - { - std::scoped_lock lk(g_async_op_lock); - smc::AsyncOperationKey op_key; - - smc::Result res = smc::ExpMod(&op_key, layout->base, layout->exp, exp_size, layout->mod); - if (res != smc::Result::Success) { - return smc::ConvertResult(res); - } - - if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != smc::Result::Success) { - return smc::ConvertResult(res); - } - } - armDCacheFlush(g_work_buffer, sizeof(out_size)); - - std::memcpy(out, g_work_buffer, out_size); - return ResultSuccess; - } - - Result SetConfig(SplConfigItem which, u64 value) { - return smc::ConvertResult(smc::SetConfig(which, &value, 1)); - } - - Result GenerateRandomBytes(void *out, size_t size) { - u8 *cur_dst = reinterpret_cast(out); - - for (size_t ofs = 0; ofs < size; ofs += CtrDrbg::MaxRequestSize) { - const size_t cur_size = std::min(size - ofs, CtrDrbg::MaxRequestSize); - - R_TRY(GenerateRandomBytesInternal(cur_dst, size)); - cur_dst += cur_size; - } - - return ResultSuccess; - } - - Result IsDevelopment(bool *out) { - u64 is_retail; - R_TRY(GetConfig(&is_retail, SplConfigItem_IsRetail)); - - *out = (is_retail == 0); - return ResultSuccess; - } - - Result SetBootReason(BootReasonValue boot_reason) { - if (IsBootReasonSet()) { - return ResultSplBootReasonAlreadySet; - } - - g_boot_reason = boot_reason; - g_boot_reason_set = true; - return ResultSuccess; - } - - Result GetBootReason(BootReasonValue *out) { - if (!IsBootReasonSet()) { - return ResultSplBootReasonNotSet; - } - - *out = GetBootReason(); - return ResultSuccess; - } - - /* Crypto. */ - Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option) { - return smc::ConvertResult(smc::GenerateAesKek(out_access_key, key_source, generation, option)); - } - - Result LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source) { - R_TRY(ValidateAesKeyslot(keyslot, owner)); - return smc::ConvertResult(smc::LoadAesKey(keyslot, access_key, key_source)); - } - - Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) { - smc::Result smc_rc; - - static const KeySource s_generate_aes_key_source = { - .data = {0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8} - }; - - ScopedAesKeyslot keyslot_holder; - R_TRY(keyslot_holder.Allocate()); - - smc_rc = smc::LoadAesKey(keyslot_holder.GetKeyslot(), access_key, s_generate_aes_key_source); - if (smc_rc == smc::Result::Success) { - smc_rc = DecryptAesBlock(keyslot_holder.GetKeyslot(), out_key, &key_source); - } - - return smc::ConvertResult(smc_rc); - } - - Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option) { - static const KeySource s_decrypt_aes_key_source = { - .data = {0x11, 0x70, 0x24, 0x2B, 0x48, 0x69, 0x11, 0xF1, 0x11, 0xB0, 0x0C, 0x47, 0x7C, 0xC3, 0xEF, 0x7E} - }; - - AccessKey access_key; - R_TRY(GenerateAesKek(&access_key, s_decrypt_aes_key_source, generation, option)); - - return GenerateAesKey(out_key, access_key, key_source); - } - - Result CryptAesCtr(void *dst, size_t dst_size, u32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr) { - R_TRY(ValidateAesKeyslot(keyslot, owner)); - - /* Succeed immediately if there's nothing to crypt. */ - if (src_size == 0) { - return ResultSuccess; - } - - /* Validate sizes. */ - if (src_size > dst_size || src_size % AES_BLOCK_SIZE != 0) { - return ResultSplInvalidSize; - } - - /* We can only map 0x400000 aligned buffers for the SE. With that in mind, we have some math to do. */ - const uintptr_t src_addr = reinterpret_cast(src); - const uintptr_t dst_addr = reinterpret_cast(dst); - const uintptr_t src_addr_page_aligned = src_addr & ~0xFFFul; - const uintptr_t dst_addr_page_aligned = dst_addr & ~0xFFFul; - const size_t src_size_page_aligned = ((src_addr + src_size + 0xFFFul) & ~0xFFFul) - src_addr_page_aligned; - const size_t dst_size_page_aligned = ((dst_addr + dst_size + 0xFFFul) & ~0xFFFul) - dst_addr_page_aligned; - const u32 src_se_map_addr = CryptAesInMapBase + (src_addr_page_aligned & DeviceAddressSpaceAlignMask); - const u32 dst_se_map_addr = CryptAesOutMapBase + (dst_addr_page_aligned & DeviceAddressSpaceAlignMask); - const u32 src_se_addr = CryptAesInMapBase + (src_addr & DeviceAddressSpaceAlignMask); - const u32 dst_se_addr = CryptAesOutMapBase + (dst_addr & DeviceAddressSpaceAlignMask); - - /* Validate aligned sizes. */ - if (src_size_page_aligned > CryptAesSizeMax || dst_size_page_aligned > CryptAesSizeMax) { - return ResultSplInvalidSize; - } - - /* Helpers for mapping/unmapping. */ - DeviceAddressSpaceMapHelper in_mapper(g_se_das_hnd, src_se_map_addr, src_addr_page_aligned, src_size_page_aligned, 1); - DeviceAddressSpaceMapHelper out_mapper(g_se_das_hnd, dst_se_map_addr, dst_addr_page_aligned, dst_size_page_aligned, 2); - - /* Setup SE linked list entries. */ - SeCryptContext *crypt_ctx = reinterpret_cast(g_work_buffer); - crypt_ctx->in.num_entries = 0; - crypt_ctx->in.address = src_se_addr; - crypt_ctx->in.size = src_size; - crypt_ctx->out.num_entries = 0; - crypt_ctx->out.address = dst_se_addr; - crypt_ctx->out.size = dst_size; - - armDCacheFlush(crypt_ctx, sizeof(*crypt_ctx)); - armDCacheFlush(const_cast(src), src_size); - armDCacheFlush(dst, dst_size); - { - std::scoped_lock lk(g_async_op_lock); - smc::AsyncOperationKey op_key; - const u32 mode = smc::GetCryptAesMode(smc::CipherMode::Ctr, keyslot); - const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, out); - const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, in); - - smc::Result res = smc::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, src_size); - if (res != smc::Result::Success) { - return smc::ConvertResult(res); - } - - if ((res = WaitCheckStatus(op_key)) != smc::Result::Success) { - return smc::ConvertResult(res); - } - } - armDCacheFlush(dst, dst_size); - - return ResultSuccess; - } - - Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size) { - R_TRY(ValidateAesKeyslot(keyslot, owner)); - - if (size > WorkBufferSizeMax) { - return ResultSplInvalidSize; - } - - std::memcpy(g_work_buffer, data, size); - return smc::ConvertResult(smc::ComputeCmac(out_cmac, keyslot, g_work_buffer, size)); - } - - Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner) { - if (GetRuntimeFirmwareVersion() <= FirmwareVersion_100) { - /* On 1.0.0, keyslots were kind of a wild west. */ - *out_keyslot = 0; - return ResultSuccess; - } - - for (size_t i = 0; i < GetMaxKeyslots(); i++) { - if (g_keyslot_owners[i] == 0) { - g_keyslot_owners[i] = owner; - *out_keyslot = static_cast(i); - return ResultSuccess; - } - } - - g_se_keyslot_available_event->Clear(); - return ResultSplOutOfKeyslots; - } - - Result FreeAesKeyslot(u32 keyslot, const void *owner) { - if (GetRuntimeFirmwareVersion() <= FirmwareVersion_100) { - /* On 1.0.0, keyslots were kind of a wild west. */ - return ResultSuccess; - } - - R_TRY(ValidateAesKeyslot(keyslot, owner)); - - /* Clear the keyslot. */ - { - AccessKey access_key = {}; - KeySource key_source = {}; - - smc::LoadAesKey(keyslot, access_key, key_source); - } - g_keyslot_owners[keyslot] = nullptr; - g_se_keyslot_available_event->Signal(); - return ResultSuccess; - } - - /* RSA. */ - Result DecryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) { - struct DecryptRsaPrivateKeyLayout { - u8 data[RsaPrivateKeySize + RsaPrivateKeyMetaSize]; - }; - DecryptRsaPrivateKeyLayout *layout = reinterpret_cast(g_work_buffer); - - /* Validate size. */ - if (src_size < RsaPrivateKeyMetaSize || src_size > sizeof(DecryptRsaPrivateKeyLayout)) { - return ResultSplInvalidSize; - } - - std::memcpy(layout->data, src, src_size); - armDCacheFlush(layout, sizeof(*layout)); - - smc::Result smc_res; - size_t copy_size = 0; - if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { - copy_size = std::min(dst_size, src_size - RsaPrivateKeyMetaSize); - smc_res = smc::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, smc::DecryptOrImportMode::DecryptRsaPrivateKey); - } else { - smc_res = smc::DecryptRsaPrivateKey(©_size, layout->data, src_size, access_key, key_source, option); - copy_size = std::min(dst_size, copy_size); - } - - armDCacheFlush(layout, sizeof(*layout)); - if (smc_res == smc::Result::Success) { - std::memcpy(dst, layout->data, copy_size); - } - - return smc::ConvertResult(smc_res); - } - - /* SSL */ - Result ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) { - return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast(smc::DecryptOrImportMode::ImportSslKey)); - } - - Result SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) { - return SecureExpMod(out, out_size, base, base_size, mod, mod_size, smc::SecureExpModMode::Ssl); - } - - /* ES */ - Result ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) { - if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { - return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast(smc::DecryptOrImportMode::ImportEsKey)); - } else { - struct ImportEsKeyLayout { - u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10]; - }; - ImportEsKeyLayout *layout = reinterpret_cast(g_work_buffer); - - /* Validate size. */ - if (src_size > sizeof(ImportEsKeyLayout)) { - return ResultSplInvalidSize; - } - - std::memcpy(layout, src, src_size); - - armDCacheFlush(layout, sizeof(*layout)); - return smc::ConvertResult(smc::ImportEsKey(layout->data, src_size, access_key, key_source, option)); - } - } - - Result UnwrapTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation) { - return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsKeyType::TitleKey); - } - - Result UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation) { - return smc::ConvertResult(smc::UnwrapCommonTitleKey(out_access_key, key_source, generation)); - } - - Result ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) { - return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast(smc::DecryptOrImportMode::ImportDrmKey)); - } - - Result DrmExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) { - return SecureExpMod(out, out_size, base, base_size, mod, mod_size, smc::SecureExpModMode::Drm); - } - - Result UnwrapElicenseKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation) { - return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsKeyType::ElicenseKey); - } - - Result LoadElicenseKey(u32 keyslot, const void *owner, const AccessKey &access_key) { - /* Right now, this is just literally the same function as LoadTitleKey in N's impl. */ - return LoadTitleKey(keyslot, owner, access_key); - } - - /* FS */ - Result ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) { - if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { - option = static_cast(smc::DecryptOrImportMode::ImportLotusKey); - } - return ImportSecureExpModKey(src, src_size, access_key, key_source, option); - } - - Result DecryptLotusMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size) { - /* Validate sizes. */ - if (dst_size > WorkBufferSizeMax || label_digest_size != LabelDigestSizeMax) { - return ResultSplInvalidSize; - } - - /* Nintendo doesn't check this result code, but we will. */ - R_TRY(SecureExpMod(g_work_buffer, 0x100, base, base_size, mod, mod_size, smc::SecureExpModMode::Lotus)); - - size_t data_size = DecodeRsaOaep(dst, dst_size, label_digest, label_digest_size, g_work_buffer, 0x100); - if (data_size == 0) { - return ResultSplDecryptionFailed; - } - - *out_size = static_cast(data_size); - return ResultSuccess; - } - - Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which) { - return smc::ConvertResult(smc::GenerateSpecificAesKey(out_key, key_source, generation, which)); - } - - Result LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key) { - R_TRY(ValidateAesKeyslot(keyslot, owner)); - return smc::ConvertResult(smc::LoadTitleKey(keyslot, access_key)); - } - - Result GetPackage2Hash(void *dst, const size_t size) { - u64 hash[4]; - - if (size < sizeof(hash)) { - return ResultSplInvalidSize; - } - - smc::Result smc_res; - if ((smc_res = smc::GetConfig(hash, 4, SplConfigItem_Package2Hash)) != smc::Result::Success) { - return smc::ConvertResult(smc_res); - } - - std::memcpy(dst, hash, sizeof(hash)); - return ResultSuccess; - } - - /* Manu. */ - Result ReEncryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option) { - struct ReEncryptRsaPrivateKeyLayout { - u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10]; - AccessKey access_key_dec; - KeySource source_dec; - AccessKey access_key_enc; - KeySource source_enc; - }; - ReEncryptRsaPrivateKeyLayout *layout = reinterpret_cast(g_work_buffer); - - /* Validate size. */ - if (src_size < RsaPrivateKeyMetaSize || src_size > sizeof(ReEncryptRsaPrivateKeyLayout)) { - return ResultSplInvalidSize; - } - - std::memcpy(layout, src, src_size); - layout->access_key_dec = access_key_dec; - layout->source_dec = source_dec; - layout->access_key_enc = access_key_enc; - layout->source_enc = source_enc; - - armDCacheFlush(layout, sizeof(*layout)); - - smc::Result smc_res = smc::ReEncryptRsaPrivateKey(layout->data, src_size, layout->access_key_dec, layout->source_dec, layout->access_key_enc, layout->source_enc, option); - if (smc_res == smc::Result::Success) { - size_t copy_size = std::min(dst_size, src_size); - armDCacheFlush(layout, copy_size); - std::memcpy(dst, layout->data, copy_size); - } - - return smc::ConvertResult(smc_res); - } - - /* Helper. */ - Result FreeAesKeyslots(const void *owner) { - for (size_t i = 0; i < GetMaxKeyslots(); i++) { - if (g_keyslot_owners[i] == owner) { - FreeAesKeyslot(i, owner); - } - } - return ResultSuccess; - } - - Handle GetAesKeyslotAvailableEventHandle() { - return g_se_keyslot_available_event->GetHandle(); - } - -} diff --git a/stratosphere/spl/source/spl_api.hpp b/stratosphere/spl/source/spl_api.hpp deleted file mode 100644 index 63aaaed..0000000 --- a/stratosphere/spl/source/spl_api.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2018-2019 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 "spl_types.hpp" - -namespace sts::spl { - - /* Initialization. */ - void Initialize(); - - /* General. */ - Result GetConfig(u64 *out, SplConfigItem which); - Result ExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size); - Result SetConfig(SplConfigItem which, u64 value); - Result GenerateRandomBytes(void *out, size_t size); - Result IsDevelopment(bool *out); - Result SetBootReason(BootReasonValue boot_reason); - Result GetBootReason(BootReasonValue *out); - - /* Crypto. */ - Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option); - Result LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source); - Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source); - Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option); - Result CryptAesCtr(void *dst, size_t dst_size, u32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr); - Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size); - Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner); - Result FreeAesKeyslot(u32 keyslot, const void *owner); - - /* RSA. */ - Result DecryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option); - - /* SSL */ - Result ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source); - Result SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size); - - /* ES */ - Result ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option); - Result UnwrapTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation); - Result UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation); - Result ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source); - Result DrmExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size); - Result UnwrapElicenseKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation); - Result LoadElicenseKey(u32 keyslot, const void *owner, const AccessKey &access_key); - - /* FS */ - Result ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option); - Result DecryptLotusMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size); - Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which); - Result LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key); - Result GetPackage2Hash(void *dst, const size_t size); - - /* Manu. */ - Result ReEncryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option); - - /* Helper. */ - Result FreeAesKeyslots(const void *owner); - Handle GetAesKeyslotAvailableEventHandle(); - -} diff --git a/stratosphere/spl/source/spl_api_impl.cpp b/stratosphere/spl/source/spl_api_impl.cpp new file mode 100644 index 0000000..e6f67a5 --- /dev/null +++ b/stratosphere/spl/source/spl_api_impl.cpp @@ -0,0 +1,937 @@ +/* + * Copyright (c) 2018-2019 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 +#include + +#include "spl_api_impl.hpp" + +#include "spl_ctr_drbg.hpp" + +namespace sts::spl::impl { + + namespace { + + /* Convenient defines. */ + constexpr size_t DeviceAddressSpaceAlignSize = 0x400000; + constexpr size_t DeviceAddressSpaceAlignMask = DeviceAddressSpaceAlignSize - 1; + constexpr u32 WorkBufferMapBase = 0x80000000u; + constexpr u32 CryptAesInMapBase = 0x90000000u; + constexpr u32 CryptAesOutMapBase = 0xC0000000u; + constexpr size_t CryptAesSizeMax = static_cast(CryptAesOutMapBase - CryptAesInMapBase); + + constexpr size_t RsaPrivateKeySize = 0x100; + constexpr size_t RsaPrivateKeyMetaSize = 0x30; + constexpr size_t LabelDigestSizeMax = 0x20; + + constexpr size_t WorkBufferSizeMax = 0x800; + + constexpr size_t MaxAesKeyslots = 6; + constexpr size_t MaxAesKeyslotsDeprecated = 4; + + /* Max Keyslots helper. */ + inline size_t GetMaxKeyslots() { + return (GetRuntimeFirmwareVersion() >= FirmwareVersion_600) ? MaxAesKeyslots : MaxAesKeyslotsDeprecated; + } + + /* Type definitions. */ + class ScopedAesKeyslot { + private: + u32 slot; + bool has_slot; + public: + ScopedAesKeyslot() : slot(0), has_slot(false) { + /* ... */ + } + ~ScopedAesKeyslot() { + if (has_slot) { + FreeAesKeyslot(slot, this); + } + } + + u32 GetKeyslot() const { + return this->slot; + } + + Result Allocate() { + R_TRY(AllocateAesKeyslot(&this->slot, this)); + this->has_slot = true; + return ResultSuccess; + } + }; + + struct SeLinkedListEntry { + u32 num_entries; + u32 address; + u32 size; + }; + + struct SeCryptContext { + SeLinkedListEntry in; + SeLinkedListEntry out; + }; + + class DeviceAddressSpaceMapHelper { + private: + Handle das_hnd; + u64 dst_addr; + u64 src_addr; + size_t size; + u32 perm; + public: + DeviceAddressSpaceMapHelper(Handle h, u64 dst, u64 src, size_t sz, u32 p) : das_hnd(h), dst_addr(dst), src_addr(src), size(sz), perm(p) { + R_ASSERT(svcMapDeviceAddressSpaceAligned(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr, this->perm)); + } + ~DeviceAddressSpaceMapHelper() { + R_ASSERT(svcUnmapDeviceAddressSpace(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr)); + } + }; + + /* Global variables. */ + CtrDrbg g_drbg; + Event g_se_event; + IEvent *g_se_keyslot_available_event; + + Handle g_se_das_hnd; + u32 g_se_mapped_work_buffer_addr; + u8 __attribute__((aligned(0x1000))) g_work_buffer[2 * WorkBufferSizeMax]; + + HosMutex g_async_op_lock; + + const void *g_keyslot_owners[MaxAesKeyslots]; + BootReasonValue g_boot_reason; + bool g_boot_reason_set; + + /* Boot Reason accessors. */ + BootReasonValue GetBootReason() { + return g_boot_reason; + } + + bool IsBootReasonSet() { + return g_boot_reason_set; + } + + /* Initialization functionality. */ + void InitializeCtrDrbg() { + u8 seed[CtrDrbg::SeedSize]; + + if (smc::GenerateRandomBytes(seed, sizeof(seed)) != smc::Result::Success) { + std::abort(); + } + + g_drbg.Initialize(seed); + } + + void InitializeSeEvents() { + u64 irq_num; + smc::GetConfig(&irq_num, 1, SplConfigItem_SecurityEngineIrqNumber); + Handle hnd; + R_ASSERT(svcCreateInterruptEvent(&hnd, irq_num, 1)); + eventLoadRemote(&g_se_event, hnd, true); + + g_se_keyslot_available_event = CreateWriteOnlySystemEvent(); + g_se_keyslot_available_event->Signal(); + } + + void InitializeDeviceAddressSpace() { + constexpr u64 DeviceName_SE = 29; + + /* Create Address Space. */ + R_ASSERT(svcCreateDeviceAddressSpace(&g_se_das_hnd, 0, (1ul << 32))); + + /* Attach it to the SE. */ + R_ASSERT(svcAttachDeviceAddressSpace(DeviceName_SE, g_se_das_hnd)); + + const u64 work_buffer_addr = reinterpret_cast(g_work_buffer); + g_se_mapped_work_buffer_addr = WorkBufferMapBase + (work_buffer_addr & DeviceAddressSpaceAlignMask); + + /* Map the work buffer for the SE. */ + R_ASSERT(svcMapDeviceAddressSpaceAligned(g_se_das_hnd, CUR_PROCESS_HANDLE, work_buffer_addr, sizeof(g_work_buffer), g_se_mapped_work_buffer_addr, 3)); + } + + /* RSA OAEP implementation helpers. */ + void CalcMgf1AndXor(void *dst, size_t dst_size, const void *src, size_t src_size) { + uint8_t *dst_u8 = reinterpret_cast(dst); + + u32 ctr = 0; + while (dst_size > 0) { + size_t cur_size = SHA256_HASH_SIZE; + if (cur_size > dst_size) { + cur_size = dst_size; + } + dst_size -= cur_size; + + u32 ctr_be = __builtin_bswap32(ctr++); + u8 hash[SHA256_HASH_SIZE]; + { + Sha256Context ctx; + sha256ContextCreate(&ctx); + sha256ContextUpdate(&ctx, src, src_size); + sha256ContextUpdate(&ctx, &ctr_be, sizeof(ctr_be)); + sha256ContextGetHash(&ctx, hash); + } + + for (size_t i = 0; i < cur_size; i++) { + *(dst_u8++) ^= hash[i]; + } + } + } + + size_t DecodeRsaOaep(void *dst, size_t dst_size, const void *label_digest, size_t label_digest_size, const void *src, size_t src_size) { + /* Very basic validation. */ + if (dst_size == 0 || src_size != 0x100 || label_digest_size != SHA256_HASH_SIZE) { + return 0; + } + + u8 block[0x100]; + std::memcpy(block, src, sizeof(block)); + + /* First, validate byte 0 == 0, and unmask DB. */ + int invalid = block[0]; + u8 *salt = block + 1; + u8 *db = salt + SHA256_HASH_SIZE; + CalcMgf1AndXor(salt, SHA256_HASH_SIZE, db, src_size - (1 + SHA256_HASH_SIZE)); + CalcMgf1AndXor(db, src_size - (1 + SHA256_HASH_SIZE), salt, SHA256_HASH_SIZE); + + /* Validate label digest. */ + for (size_t i = 0; i < SHA256_HASH_SIZE; i++) { + invalid |= db[i] ^ reinterpret_cast(label_digest)[i]; + } + + /* Locate message after 00...0001 padding. */ + const u8 *padded_msg = db + SHA256_HASH_SIZE; + size_t padded_msg_size = src_size - (1 + 2 * SHA256_HASH_SIZE); + size_t msg_ind = 0; + int not_found = 1; + int wrong_padding = 0; + size_t i = 0; + while (i < padded_msg_size) { + int zero = (padded_msg[i] == 0); + int one = (padded_msg[i] == 1); + msg_ind += static_cast(not_found & one) * (++i); + not_found &= ~one; + wrong_padding |= (not_found & ~zero); + } + + if (invalid | not_found | wrong_padding) { + return 0; + } + + /* Copy message out. */ + size_t msg_size = padded_msg_size - msg_ind; + if (msg_size > dst_size) { + return 0; + } + std::memcpy(dst, padded_msg + msg_ind, msg_size); + return msg_size; + } + + /* Internal RNG functionality. */ + Result GenerateRandomBytesInternal(void *out, size_t size) { + if (!g_drbg.GenerateRandomBytes(out, size)) { + /* We need to reseed. */ + { + u8 seed[CtrDrbg::SeedSize]; + + smc::Result res = smc::GenerateRandomBytes(seed, sizeof(seed)); + if (res != smc::Result::Success) { + return smc::ConvertResult(res); + } + + g_drbg.Reseed(seed); + g_drbg.GenerateRandomBytes(out, size); + } + } + + return ResultSuccess; + } + + /* Internal async implementation functionality. */ + void WaitSeOperationComplete() { + eventWait(&g_se_event, U64_MAX); + } + + smc::Result WaitCheckStatus(smc::AsyncOperationKey op_key) { + WaitSeOperationComplete(); + + smc::Result op_res; + smc::Result res = smc::CheckStatus(&op_res, op_key); + if (res != smc::Result::Success) { + return res; + } + + return op_res; + } + + smc::Result WaitGetResult(void *out_buf, size_t out_buf_size, smc::AsyncOperationKey op_key) { + WaitSeOperationComplete(); + + smc::Result op_res; + smc::Result res = smc::GetResult(&op_res, out_buf, out_buf_size, op_key); + if (res != smc::Result::Success) { + return res; + } + + return op_res; + } + + /* Internal Keyslot utility. */ + Result ValidateAesKeyslot(u32 keyslot, const void *owner) { + if (keyslot >= GetMaxKeyslots()) { + return ResultSplInvalidKeyslot; + } + if (g_keyslot_owners[keyslot] != owner && GetRuntimeFirmwareVersion() > FirmwareVersion_100) { + return ResultSplInvalidKeyslot; + } + return ResultSuccess; + } + + /* Helper to do a single AES block decryption. */ + smc::Result DecryptAesBlock(u32 keyslot, void *dst, const void *src) { + struct DecryptAesBlockLayout { + SeCryptContext crypt_ctx; + u8 in_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE))); + u8 out_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE))); + }; + DecryptAesBlockLayout *layout = reinterpret_cast(g_work_buffer); + + layout->crypt_ctx.in.num_entries = 0; + layout->crypt_ctx.in.address = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, in_block); + layout->crypt_ctx.in.size = sizeof(layout->in_block); + layout->crypt_ctx.out.num_entries = 0; + layout->crypt_ctx.out.address = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, out_block); + layout->crypt_ctx.out.size = sizeof(layout->out_block); + + std::memcpy(layout->in_block, src, sizeof(layout->in_block)); + + armDCacheFlush(layout, sizeof(*layout)); + { + std::scoped_lock lk(g_async_op_lock); + smc::AsyncOperationKey op_key; + const IvCtr iv_ctr = {}; + const u32 mode = smc::GetCryptAesMode(smc::CipherMode::CbcDecrypt, keyslot); + const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.out); + const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.in); + + smc::Result res = smc::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, sizeof(layout->in_block)); + if (res != smc::Result::Success) { + return res; + } + + if ((res = WaitCheckStatus(op_key)) != smc::Result::Success) { + return res; + } + } + armDCacheFlush(layout, sizeof(*layout)); + + std::memcpy(dst, layout->out_block, sizeof(layout->out_block)); + return smc::Result::Success; + } + + /* Implementation wrappers for API commands. */ + Result ImportSecureExpModKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) { + struct ImportSecureExpModKeyLayout { + u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10]; + }; + ImportSecureExpModKeyLayout *layout = reinterpret_cast(g_work_buffer); + + /* Validate size. */ + if (src_size > sizeof(ImportSecureExpModKeyLayout)) { + return ResultSplInvalidSize; + } + + std::memcpy(layout, src, src_size); + + armDCacheFlush(layout, sizeof(*layout)); + smc::Result smc_res; + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { + smc_res = smc::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, static_cast(option)); + } else { + smc_res = smc::ImportSecureExpModKey(layout->data, src_size, access_key, key_source, option); + } + + return smc::ConvertResult(smc_res); + } + + Result SecureExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size, smc::SecureExpModMode mode) { + struct SecureExpModLayout { + u8 base[0x100]; + u8 mod[0x100]; + }; + SecureExpModLayout *layout = reinterpret_cast(g_work_buffer); + + /* Validate sizes. */ + if (base_size > sizeof(layout->base)) { + return ResultSplInvalidSize; + } + if (mod_size > sizeof(layout->mod)) { + return ResultSplInvalidSize; + } + if (out_size > WorkBufferSizeMax) { + return ResultSplInvalidSize; + } + + /* Copy data into work buffer. */ + const size_t base_ofs = sizeof(layout->base) - base_size; + const size_t mod_ofs = sizeof(layout->mod) - mod_size; + std::memset(layout, 0, sizeof(*layout)); + std::memcpy(layout->base + base_ofs, base, base_size); + std::memcpy(layout->mod + mod_ofs, mod, mod_size); + + /* Do exp mod operation. */ + armDCacheFlush(layout, sizeof(*layout)); + { + std::scoped_lock lk(g_async_op_lock); + smc::AsyncOperationKey op_key; + + smc::Result res = smc::SecureExpMod(&op_key, layout->base, layout->mod, mode); + if (res != smc::Result::Success) { + return smc::ConvertResult(res); + } + + if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != smc::Result::Success) { + return smc::ConvertResult(res); + } + } + armDCacheFlush(g_work_buffer, sizeof(out_size)); + + std::memcpy(out, g_work_buffer, out_size); + return ResultSuccess; + } + + Result UnwrapEsRsaOaepWrappedKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation, smc::EsKeyType type) { + struct UnwrapEsKeyLayout { + u8 base[0x100]; + u8 mod[0x100]; + }; + UnwrapEsKeyLayout *layout = reinterpret_cast(g_work_buffer); + + /* Validate sizes. */ + if (base_size > sizeof(layout->base)) { + return ResultSplInvalidSize; + } + if (mod_size > sizeof(layout->mod)) { + return ResultSplInvalidSize; + } + if (label_digest_size > LabelDigestSizeMax) { + return ResultSplInvalidSize; + } + + /* Copy data into work buffer. */ + const size_t base_ofs = sizeof(layout->base) - base_size; + const size_t mod_ofs = sizeof(layout->mod) - mod_size; + std::memset(layout, 0, sizeof(*layout)); + std::memcpy(layout->base + base_ofs, base, base_size); + std::memcpy(layout->mod + mod_ofs, mod, mod_size); + + /* Do exp mod operation. */ + armDCacheFlush(layout, sizeof(*layout)); + { + std::scoped_lock lk(g_async_op_lock); + smc::AsyncOperationKey op_key; + + smc::Result res = smc::UnwrapTitleKey(&op_key, layout->base, layout->mod, label_digest, label_digest_size, smc::GetUnwrapEsKeyOption(type, generation)); + if (res != smc::Result::Success) { + return smc::ConvertResult(res); + } + + if ((res = WaitGetResult(g_work_buffer, sizeof(*out_access_key), op_key)) != smc::Result::Success) { + return smc::ConvertResult(res); + } + } + armDCacheFlush(g_work_buffer, sizeof(*out_access_key)); + + std::memcpy(out_access_key, g_work_buffer, sizeof(*out_access_key)); + return ResultSuccess; + } + + + } + + /* Initialization. */ + void Initialize() { + /* Initialize the Drbg. */ + InitializeCtrDrbg(); + /* Initialize SE interrupt + keyslot events. */ + InitializeSeEvents(); + /* Initialize DAS for the SE. */ + InitializeDeviceAddressSpace(); + } + + /* General. */ + Result GetConfig(u64 *out, SplConfigItem which) { + /* Nintendo explicitly blacklists package2 hash here, amusingly. */ + /* This is not blacklisted in safemode, but we're never in safe mode... */ + if (which == SplConfigItem_Package2Hash) { + return ResultSplInvalidArgument; + } + + smc::Result res = smc::GetConfig(out, 1, which); + + /* Nintendo has some special handling here for hardware type/is_retail. */ + if (which == SplConfigItem_HardwareType && res == smc::Result::InvalidArgument) { + *out = 0; + res = smc::Result::Success; + } + if (which == SplConfigItem_IsRetail && res == smc::Result::InvalidArgument) { + *out = 0; + res = smc::Result::Success; + } + + return smc::ConvertResult(res); + } + + Result ExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size) { + struct ExpModLayout { + u8 base[0x100]; + u8 exp[0x100]; + u8 mod[0x100]; + }; + ExpModLayout *layout = reinterpret_cast(g_work_buffer); + + /* Validate sizes. */ + if (base_size > sizeof(layout->base)) { + return ResultSplInvalidSize; + } + if (exp_size > sizeof(layout->exp)) { + return ResultSplInvalidSize; + } + if (mod_size > sizeof(layout->mod)) { + return ResultSplInvalidSize; + } + if (out_size > WorkBufferSizeMax) { + return ResultSplInvalidSize; + } + + /* Copy data into work buffer. */ + const size_t base_ofs = sizeof(layout->base) - base_size; + const size_t mod_ofs = sizeof(layout->mod) - mod_size; + std::memset(layout, 0, sizeof(*layout)); + std::memcpy(layout->base + base_ofs, base, base_size); + std::memcpy(layout->exp, exp, exp_size); + std::memcpy(layout->mod + mod_ofs, mod, mod_size); + + /* Do exp mod operation. */ + armDCacheFlush(layout, sizeof(*layout)); + { + std::scoped_lock lk(g_async_op_lock); + smc::AsyncOperationKey op_key; + + smc::Result res = smc::ExpMod(&op_key, layout->base, layout->exp, exp_size, layout->mod); + if (res != smc::Result::Success) { + return smc::ConvertResult(res); + } + + if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != smc::Result::Success) { + return smc::ConvertResult(res); + } + } + armDCacheFlush(g_work_buffer, sizeof(out_size)); + + std::memcpy(out, g_work_buffer, out_size); + return ResultSuccess; + } + + Result SetConfig(SplConfigItem which, u64 value) { + return smc::ConvertResult(smc::SetConfig(which, &value, 1)); + } + + Result GenerateRandomBytes(void *out, size_t size) { + u8 *cur_dst = reinterpret_cast(out); + + for (size_t ofs = 0; ofs < size; ofs += CtrDrbg::MaxRequestSize) { + const size_t cur_size = std::min(size - ofs, CtrDrbg::MaxRequestSize); + + R_TRY(GenerateRandomBytesInternal(cur_dst, size)); + cur_dst += cur_size; + } + + return ResultSuccess; + } + + Result IsDevelopment(bool *out) { + u64 is_retail; + R_TRY(GetConfig(&is_retail, SplConfigItem_IsRetail)); + + *out = (is_retail == 0); + return ResultSuccess; + } + + Result SetBootReason(BootReasonValue boot_reason) { + if (IsBootReasonSet()) { + return ResultSplBootReasonAlreadySet; + } + + g_boot_reason = boot_reason; + g_boot_reason_set = true; + return ResultSuccess; + } + + Result GetBootReason(BootReasonValue *out) { + if (!IsBootReasonSet()) { + return ResultSplBootReasonNotSet; + } + + *out = GetBootReason(); + return ResultSuccess; + } + + /* Crypto. */ + Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option) { + return smc::ConvertResult(smc::GenerateAesKek(out_access_key, key_source, generation, option)); + } + + Result LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source) { + R_TRY(ValidateAesKeyslot(keyslot, owner)); + return smc::ConvertResult(smc::LoadAesKey(keyslot, access_key, key_source)); + } + + Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) { + smc::Result smc_rc; + + static const KeySource s_generate_aes_key_source = { + .data = {0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8} + }; + + ScopedAesKeyslot keyslot_holder; + R_TRY(keyslot_holder.Allocate()); + + smc_rc = smc::LoadAesKey(keyslot_holder.GetKeyslot(), access_key, s_generate_aes_key_source); + if (smc_rc == smc::Result::Success) { + smc_rc = DecryptAesBlock(keyslot_holder.GetKeyslot(), out_key, &key_source); + } + + return smc::ConvertResult(smc_rc); + } + + Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option) { + static const KeySource s_decrypt_aes_key_source = { + .data = {0x11, 0x70, 0x24, 0x2B, 0x48, 0x69, 0x11, 0xF1, 0x11, 0xB0, 0x0C, 0x47, 0x7C, 0xC3, 0xEF, 0x7E} + }; + + AccessKey access_key; + R_TRY(GenerateAesKek(&access_key, s_decrypt_aes_key_source, generation, option)); + + return GenerateAesKey(out_key, access_key, key_source); + } + + Result CryptAesCtr(void *dst, size_t dst_size, u32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr) { + R_TRY(ValidateAesKeyslot(keyslot, owner)); + + /* Succeed immediately if there's nothing to crypt. */ + if (src_size == 0) { + return ResultSuccess; + } + + /* Validate sizes. */ + if (src_size > dst_size || src_size % AES_BLOCK_SIZE != 0) { + return ResultSplInvalidSize; + } + + /* We can only map 0x400000 aligned buffers for the SE. With that in mind, we have some math to do. */ + const uintptr_t src_addr = reinterpret_cast(src); + const uintptr_t dst_addr = reinterpret_cast(dst); + const uintptr_t src_addr_page_aligned = src_addr & ~0xFFFul; + const uintptr_t dst_addr_page_aligned = dst_addr & ~0xFFFul; + const size_t src_size_page_aligned = ((src_addr + src_size + 0xFFFul) & ~0xFFFul) - src_addr_page_aligned; + const size_t dst_size_page_aligned = ((dst_addr + dst_size + 0xFFFul) & ~0xFFFul) - dst_addr_page_aligned; + const u32 src_se_map_addr = CryptAesInMapBase + (src_addr_page_aligned & DeviceAddressSpaceAlignMask); + const u32 dst_se_map_addr = CryptAesOutMapBase + (dst_addr_page_aligned & DeviceAddressSpaceAlignMask); + const u32 src_se_addr = CryptAesInMapBase + (src_addr & DeviceAddressSpaceAlignMask); + const u32 dst_se_addr = CryptAesOutMapBase + (dst_addr & DeviceAddressSpaceAlignMask); + + /* Validate aligned sizes. */ + if (src_size_page_aligned > CryptAesSizeMax || dst_size_page_aligned > CryptAesSizeMax) { + return ResultSplInvalidSize; + } + + /* Helpers for mapping/unmapping. */ + DeviceAddressSpaceMapHelper in_mapper(g_se_das_hnd, src_se_map_addr, src_addr_page_aligned, src_size_page_aligned, 1); + DeviceAddressSpaceMapHelper out_mapper(g_se_das_hnd, dst_se_map_addr, dst_addr_page_aligned, dst_size_page_aligned, 2); + + /* Setup SE linked list entries. */ + SeCryptContext *crypt_ctx = reinterpret_cast(g_work_buffer); + crypt_ctx->in.num_entries = 0; + crypt_ctx->in.address = src_se_addr; + crypt_ctx->in.size = src_size; + crypt_ctx->out.num_entries = 0; + crypt_ctx->out.address = dst_se_addr; + crypt_ctx->out.size = dst_size; + + armDCacheFlush(crypt_ctx, sizeof(*crypt_ctx)); + armDCacheFlush(const_cast(src), src_size); + armDCacheFlush(dst, dst_size); + { + std::scoped_lock lk(g_async_op_lock); + smc::AsyncOperationKey op_key; + const u32 mode = smc::GetCryptAesMode(smc::CipherMode::Ctr, keyslot); + const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, out); + const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, in); + + smc::Result res = smc::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, src_size); + if (res != smc::Result::Success) { + return smc::ConvertResult(res); + } + + if ((res = WaitCheckStatus(op_key)) != smc::Result::Success) { + return smc::ConvertResult(res); + } + } + armDCacheFlush(dst, dst_size); + + return ResultSuccess; + } + + Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size) { + R_TRY(ValidateAesKeyslot(keyslot, owner)); + + if (size > WorkBufferSizeMax) { + return ResultSplInvalidSize; + } + + std::memcpy(g_work_buffer, data, size); + return smc::ConvertResult(smc::ComputeCmac(out_cmac, keyslot, g_work_buffer, size)); + } + + Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner) { + if (GetRuntimeFirmwareVersion() <= FirmwareVersion_100) { + /* On 1.0.0, keyslots were kind of a wild west. */ + *out_keyslot = 0; + return ResultSuccess; + } + + for (size_t i = 0; i < GetMaxKeyslots(); i++) { + if (g_keyslot_owners[i] == 0) { + g_keyslot_owners[i] = owner; + *out_keyslot = static_cast(i); + return ResultSuccess; + } + } + + g_se_keyslot_available_event->Clear(); + return ResultSplOutOfKeyslots; + } + + Result FreeAesKeyslot(u32 keyslot, const void *owner) { + if (GetRuntimeFirmwareVersion() <= FirmwareVersion_100) { + /* On 1.0.0, keyslots were kind of a wild west. */ + return ResultSuccess; + } + + R_TRY(ValidateAesKeyslot(keyslot, owner)); + + /* Clear the keyslot. */ + { + AccessKey access_key = {}; + KeySource key_source = {}; + + smc::LoadAesKey(keyslot, access_key, key_source); + } + g_keyslot_owners[keyslot] = nullptr; + g_se_keyslot_available_event->Signal(); + return ResultSuccess; + } + + /* RSA. */ + Result DecryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) { + struct DecryptRsaPrivateKeyLayout { + u8 data[RsaPrivateKeySize + RsaPrivateKeyMetaSize]; + }; + DecryptRsaPrivateKeyLayout *layout = reinterpret_cast(g_work_buffer); + + /* Validate size. */ + if (src_size < RsaPrivateKeyMetaSize || src_size > sizeof(DecryptRsaPrivateKeyLayout)) { + return ResultSplInvalidSize; + } + + std::memcpy(layout->data, src, src_size); + armDCacheFlush(layout, sizeof(*layout)); + + smc::Result smc_res; + size_t copy_size = 0; + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { + copy_size = std::min(dst_size, src_size - RsaPrivateKeyMetaSize); + smc_res = smc::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, smc::DecryptOrImportMode::DecryptRsaPrivateKey); + } else { + smc_res = smc::DecryptRsaPrivateKey(©_size, layout->data, src_size, access_key, key_source, option); + copy_size = std::min(dst_size, copy_size); + } + + armDCacheFlush(layout, sizeof(*layout)); + if (smc_res == smc::Result::Success) { + std::memcpy(dst, layout->data, copy_size); + } + + return smc::ConvertResult(smc_res); + } + + /* SSL */ + Result ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) { + return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast(smc::DecryptOrImportMode::ImportSslKey)); + } + + Result SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) { + return SecureExpMod(out, out_size, base, base_size, mod, mod_size, smc::SecureExpModMode::Ssl); + } + + /* ES */ + Result ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) { + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { + return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast(smc::DecryptOrImportMode::ImportEsKey)); + } else { + struct ImportEsKeyLayout { + u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10]; + }; + ImportEsKeyLayout *layout = reinterpret_cast(g_work_buffer); + + /* Validate size. */ + if (src_size > sizeof(ImportEsKeyLayout)) { + return ResultSplInvalidSize; + } + + std::memcpy(layout, src, src_size); + + armDCacheFlush(layout, sizeof(*layout)); + return smc::ConvertResult(smc::ImportEsKey(layout->data, src_size, access_key, key_source, option)); + } + } + + Result UnwrapTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation) { + return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsKeyType::TitleKey); + } + + Result UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation) { + return smc::ConvertResult(smc::UnwrapCommonTitleKey(out_access_key, key_source, generation)); + } + + Result ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) { + return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast(smc::DecryptOrImportMode::ImportDrmKey)); + } + + Result DrmExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) { + return SecureExpMod(out, out_size, base, base_size, mod, mod_size, smc::SecureExpModMode::Drm); + } + + Result UnwrapElicenseKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation) { + return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsKeyType::ElicenseKey); + } + + Result LoadElicenseKey(u32 keyslot, const void *owner, const AccessKey &access_key) { + /* Right now, this is just literally the same function as LoadTitleKey in N's impl. */ + return LoadTitleKey(keyslot, owner, access_key); + } + + /* FS */ + Result ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) { + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { + option = static_cast(smc::DecryptOrImportMode::ImportLotusKey); + } + return ImportSecureExpModKey(src, src_size, access_key, key_source, option); + } + + Result DecryptLotusMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size) { + /* Validate sizes. */ + if (dst_size > WorkBufferSizeMax || label_digest_size != LabelDigestSizeMax) { + return ResultSplInvalidSize; + } + + /* Nintendo doesn't check this result code, but we will. */ + R_TRY(SecureExpMod(g_work_buffer, 0x100, base, base_size, mod, mod_size, smc::SecureExpModMode::Lotus)); + + size_t data_size = DecodeRsaOaep(dst, dst_size, label_digest, label_digest_size, g_work_buffer, 0x100); + if (data_size == 0) { + return ResultSplDecryptionFailed; + } + + *out_size = static_cast(data_size); + return ResultSuccess; + } + + Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which) { + return smc::ConvertResult(smc::GenerateSpecificAesKey(out_key, key_source, generation, which)); + } + + Result LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key) { + R_TRY(ValidateAesKeyslot(keyslot, owner)); + return smc::ConvertResult(smc::LoadTitleKey(keyslot, access_key)); + } + + Result GetPackage2Hash(void *dst, const size_t size) { + u64 hash[4]; + + if (size < sizeof(hash)) { + return ResultSplInvalidSize; + } + + smc::Result smc_res; + if ((smc_res = smc::GetConfig(hash, 4, SplConfigItem_Package2Hash)) != smc::Result::Success) { + return smc::ConvertResult(smc_res); + } + + std::memcpy(dst, hash, sizeof(hash)); + return ResultSuccess; + } + + /* Manu. */ + Result ReEncryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option) { + struct ReEncryptRsaPrivateKeyLayout { + u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10]; + AccessKey access_key_dec; + KeySource source_dec; + AccessKey access_key_enc; + KeySource source_enc; + }; + ReEncryptRsaPrivateKeyLayout *layout = reinterpret_cast(g_work_buffer); + + /* Validate size. */ + if (src_size < RsaPrivateKeyMetaSize || src_size > sizeof(ReEncryptRsaPrivateKeyLayout)) { + return ResultSplInvalidSize; + } + + std::memcpy(layout, src, src_size); + layout->access_key_dec = access_key_dec; + layout->source_dec = source_dec; + layout->access_key_enc = access_key_enc; + layout->source_enc = source_enc; + + armDCacheFlush(layout, sizeof(*layout)); + + smc::Result smc_res = smc::ReEncryptRsaPrivateKey(layout->data, src_size, layout->access_key_dec, layout->source_dec, layout->access_key_enc, layout->source_enc, option); + if (smc_res == smc::Result::Success) { + size_t copy_size = std::min(dst_size, src_size); + armDCacheFlush(layout, copy_size); + std::memcpy(dst, layout->data, copy_size); + } + + return smc::ConvertResult(smc_res); + } + + /* Helper. */ + Result FreeAesKeyslots(const void *owner) { + for (size_t i = 0; i < GetMaxKeyslots(); i++) { + if (g_keyslot_owners[i] == owner) { + FreeAesKeyslot(i, owner); + } + } + return ResultSuccess; + } + + Handle GetAesKeyslotAvailableEventHandle() { + return g_se_keyslot_available_event->GetHandle(); + } + +} diff --git a/stratosphere/spl/source/spl_api_impl.hpp b/stratosphere/spl/source/spl_api_impl.hpp new file mode 100644 index 0000000..8ef033f --- /dev/null +++ b/stratosphere/spl/source/spl_api_impl.hpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018-2019 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 sts::spl::impl { + + /* Initialization. */ + void Initialize(); + + /* General. */ + Result GetConfig(u64 *out, SplConfigItem which); + Result ExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size); + Result SetConfig(SplConfigItem which, u64 value); + Result GenerateRandomBytes(void *out, size_t size); + Result IsDevelopment(bool *out); + Result SetBootReason(BootReasonValue boot_reason); + Result GetBootReason(BootReasonValue *out); + + /* Crypto. */ + Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option); + Result LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source); + Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source); + Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option); + Result CryptAesCtr(void *dst, size_t dst_size, u32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr); + Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size); + Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner); + Result FreeAesKeyslot(u32 keyslot, const void *owner); + + /* RSA. */ + Result DecryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option); + + /* SSL */ + Result ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source); + Result SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size); + + /* ES */ + Result ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option); + Result UnwrapTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation); + Result UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation); + Result ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source); + Result DrmExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size); + Result UnwrapElicenseKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation); + Result LoadElicenseKey(u32 keyslot, const void *owner, const AccessKey &access_key); + + /* FS */ + Result ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option); + Result DecryptLotusMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size); + Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which); + Result LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key); + Result GetPackage2Hash(void *dst, const size_t size); + + /* Manu. */ + Result ReEncryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option); + + /* Helper. */ + Result FreeAesKeyslots(const void *owner); + Handle GetAesKeyslotAvailableEventHandle(); + +} diff --git a/stratosphere/spl/source/spl_crypto_service.cpp b/stratosphere/spl/source/spl_crypto_service.cpp index 86e445e..8dacd4b 100644 --- a/stratosphere/spl/source/spl_crypto_service.cpp +++ b/stratosphere/spl/source/spl_crypto_service.cpp @@ -17,50 +17,50 @@ #include #include +#include "spl_api_impl.hpp" #include "spl_crypto_service.hpp" -#include "spl_api.hpp" namespace sts::spl { CryptoService::~CryptoService() { /* Free any keyslots this service is using. */ - spl::FreeAesKeyslots(this); + impl::FreeAesKeyslots(this); } Result CryptoService::GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option) { - return spl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option); + return impl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option); } Result CryptoService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) { - return spl::LoadAesKey(keyslot, this, access_key, key_source); + return impl::LoadAesKey(keyslot, this, access_key, key_source); } Result CryptoService::GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source) { - return spl::GenerateAesKey(out_key.GetPointer(), access_key, key_source); + return impl::GenerateAesKey(out_key.GetPointer(), access_key, key_source); } Result CryptoService::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) { - return spl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option); + return impl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option); } Result CryptoService::CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) { - return spl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr); + return impl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr); } Result CryptoService::ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf) { - return spl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements); + return impl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements); } Result CryptoService::AllocateAesKeyslot(Out out_keyslot) { - return spl::AllocateAesKeyslot(out_keyslot.GetPointer(), this); + return impl::AllocateAesKeyslot(out_keyslot.GetPointer(), this); } Result CryptoService::FreeAesKeyslot(u32 keyslot) { - return spl::FreeAesKeyslot(keyslot, this); + return impl::FreeAesKeyslot(keyslot, this); } void CryptoService::GetAesKeyslotAvailableEvent(Out out_hnd) { - out_hnd.SetValue(spl::GetAesKeyslotAvailableEventHandle()); + out_hnd.SetValue(impl::GetAesKeyslotAvailableEventHandle()); } } diff --git a/stratosphere/spl/source/spl_crypto_service.hpp b/stratosphere/spl/source/spl_crypto_service.hpp index 3acfb1f..c5ad23b 100644 --- a/stratosphere/spl/source/spl_crypto_service.hpp +++ b/stratosphere/spl/source/spl_crypto_service.hpp @@ -17,8 +17,8 @@ #pragma once #include #include +#include -#include "spl_types.hpp" #include "spl_general_service.hpp" namespace sts::spl { diff --git a/stratosphere/spl/source/spl_ctr_drbg.cpp b/stratosphere/spl/source/spl_ctr_drbg.cpp index c9bc732..72ad9f7 100644 --- a/stratosphere/spl/source/spl_ctr_drbg.cpp +++ b/stratosphere/spl/source/spl_ctr_drbg.cpp @@ -16,8 +16,8 @@ #include #include +#include -#include "spl_types.hpp" #include "spl_ctr_drbg.hpp" namespace sts::spl { diff --git a/stratosphere/spl/source/spl_ctr_drbg.hpp b/stratosphere/spl/source/spl_ctr_drbg.hpp index 462c3c2..2bbff9d 100644 --- a/stratosphere/spl/source/spl_ctr_drbg.hpp +++ b/stratosphere/spl/source/spl_ctr_drbg.hpp @@ -17,8 +17,7 @@ #pragma once #include #include - -#include "spl_types.hpp" +#include namespace sts::spl { diff --git a/stratosphere/spl/source/spl_deprecated_service.cpp b/stratosphere/spl/source/spl_deprecated_service.cpp index 5aa7234..21bcff2 100644 --- a/stratosphere/spl/source/spl_deprecated_service.cpp +++ b/stratosphere/spl/source/spl_deprecated_service.cpp @@ -17,109 +17,109 @@ #include #include +#include "spl_api_impl.hpp" #include "spl_deprecated_service.hpp" -#include "spl_api.hpp" namespace sts::spl { Result DeprecatedService::GetConfig(Out out, u32 which) { - return spl::GetConfig(out.GetPointer(), static_cast(which)); + return impl::GetConfig(out.GetPointer(), static_cast(which)); } Result DeprecatedService::ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod) { - return spl::ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements); + return impl::ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements); } Result DeprecatedService::GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option) { - return spl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option); + return impl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option); } Result DeprecatedService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) { - return spl::LoadAesKey(keyslot, this, access_key, key_source); + return impl::LoadAesKey(keyslot, this, access_key, key_source); } Result DeprecatedService::GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source) { - return spl::GenerateAesKey(out_key.GetPointer(), access_key, key_source); + return impl::GenerateAesKey(out_key.GetPointer(), access_key, key_source); } Result DeprecatedService::SetConfig(u32 which, u64 value) { - return spl::SetConfig(static_cast(which), value); + return impl::SetConfig(static_cast(which), value); } Result DeprecatedService::GenerateRandomBytes(OutPointerWithClientSize out) { - return spl::GenerateRandomBytes(out.pointer, out.num_elements); + return impl::GenerateRandomBytes(out.pointer, out.num_elements); } Result DeprecatedService::ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return spl::ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option); + return impl::ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option); } Result DeprecatedService::DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest) { - return spl::DecryptLotusMessage(out_size.GetPointer(), out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements); + return impl::DecryptLotusMessage(out_size.GetPointer(), out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements); } Result DeprecatedService::IsDevelopment(Out is_dev) { - return spl::IsDevelopment(is_dev.GetPointer()); + return impl::IsDevelopment(is_dev.GetPointer()); } Result DeprecatedService::GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which) { - return spl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which); + return impl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which); } Result DeprecatedService::DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return spl::DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option); + return impl::DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option); } Result DeprecatedService::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) { - return spl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option); + return impl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option); } Result DeprecatedService::CryptAesCtrDeprecated(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) { - return spl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr); + return impl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr); } Result DeprecatedService::CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) { - return spl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr); + return impl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr); } Result DeprecatedService::ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf) { - return spl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements); + return impl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements); } Result DeprecatedService::ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return spl::ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option); + return impl::ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option); } Result DeprecatedService::UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation) { - return spl::UnwrapTitleKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation); + return impl::UnwrapTitleKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation); } Result DeprecatedService::LoadTitleKey(u32 keyslot, AccessKey access_key) { - return spl::LoadTitleKey(keyslot, this, access_key); + return impl::LoadTitleKey(keyslot, this, access_key); } Result DeprecatedService::UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation) { - return spl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation); + return impl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation); } Result DeprecatedService::AllocateAesKeyslot(Out out_keyslot) { - return spl::AllocateAesKeyslot(out_keyslot.GetPointer(), this); + return impl::AllocateAesKeyslot(out_keyslot.GetPointer(), this); } Result DeprecatedService::FreeAesKeyslot(u32 keyslot) { - return spl::FreeAesKeyslot(keyslot, this); + return impl::FreeAesKeyslot(keyslot, this); } void DeprecatedService::GetAesKeyslotAvailableEvent(Out out_hnd) { - out_hnd.SetValue(spl::GetAesKeyslotAvailableEventHandle()); + out_hnd.SetValue(impl::GetAesKeyslotAvailableEventHandle()); } Result DeprecatedService::SetBootReason(BootReasonValue boot_reason) { - return spl::SetBootReason(boot_reason); + return impl::SetBootReason(boot_reason); } Result DeprecatedService::GetBootReason(Out out) { - return spl::GetBootReason(out.GetPointer()); + return impl::GetBootReason(out.GetPointer()); } } diff --git a/stratosphere/spl/source/spl_deprecated_service.hpp b/stratosphere/spl/source/spl_deprecated_service.hpp index d78bb72..ee5e469 100644 --- a/stratosphere/spl/source/spl_deprecated_service.hpp +++ b/stratosphere/spl/source/spl_deprecated_service.hpp @@ -17,8 +17,7 @@ #pragma once #include #include - -#include "spl_types.hpp" +#include namespace sts::spl { diff --git a/stratosphere/spl/source/spl_es_service.cpp b/stratosphere/spl/source/spl_es_service.cpp index 14f4c45..96aa8a1 100644 --- a/stratosphere/spl/source/spl_es_service.cpp +++ b/stratosphere/spl/source/spl_es_service.cpp @@ -17,37 +17,37 @@ #include #include +#include "spl_api_impl.hpp" #include "spl_es_service.hpp" -#include "spl_api.hpp" namespace sts::spl { Result EsService::ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return spl::ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option); + return impl::ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option); } Result EsService::UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation) { - return spl::UnwrapTitleKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation); + return impl::UnwrapTitleKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation); } Result EsService::UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation) { - return spl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation); + return impl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation); } Result EsService::ImportDrmKey(InPointer src, AccessKey access_key, KeySource key_source) { - return spl::ImportDrmKey(src.pointer, src.num_elements, access_key, key_source); + return impl::ImportDrmKey(src.pointer, src.num_elements, access_key, key_source); } Result EsService::DrmExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod) { - return spl::DrmExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements); + return impl::DrmExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements); } Result EsService::UnwrapElicenseKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation) { - return spl::UnwrapElicenseKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation); + return impl::UnwrapElicenseKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation); } Result EsService::LoadElicenseKey(u32 keyslot, AccessKey access_key) { - return spl::LoadElicenseKey(keyslot, this, access_key); + return impl::LoadElicenseKey(keyslot, this, access_key); } } diff --git a/stratosphere/spl/source/spl_es_service.hpp b/stratosphere/spl/source/spl_es_service.hpp index e9828d4..34564c3 100644 --- a/stratosphere/spl/source/spl_es_service.hpp +++ b/stratosphere/spl/source/spl_es_service.hpp @@ -17,8 +17,8 @@ #pragma once #include #include +#include -#include "spl_types.hpp" #include "spl_rsa_service.hpp" namespace sts::spl { diff --git a/stratosphere/spl/source/spl_fs_service.cpp b/stratosphere/spl/source/spl_fs_service.cpp index 95d75c4..a550bdf 100644 --- a/stratosphere/spl/source/spl_fs_service.cpp +++ b/stratosphere/spl/source/spl_fs_service.cpp @@ -17,29 +17,29 @@ #include #include +#include "spl_api_impl.hpp" #include "spl_fs_service.hpp" -#include "spl_api.hpp" namespace sts::spl { Result FsService::ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return spl::ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option); + return impl::ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option); } Result FsService::DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest) { - return spl::DecryptLotusMessage(out_size.GetPointer(), out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements); + return impl::DecryptLotusMessage(out_size.GetPointer(), out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements); } Result FsService::GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which) { - return spl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which); + return impl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which); } Result FsService::LoadTitleKey(u32 keyslot, AccessKey access_key) { - return spl::LoadTitleKey(keyslot, this, access_key); + return impl::LoadTitleKey(keyslot, this, access_key); } Result FsService::GetPackage2Hash(OutPointerWithClientSize dst) { - return spl::GetPackage2Hash(dst.pointer, dst.num_elements); + return impl::GetPackage2Hash(dst.pointer, dst.num_elements); } } diff --git a/stratosphere/spl/source/spl_fs_service.hpp b/stratosphere/spl/source/spl_fs_service.hpp index e19d98c..11ce445 100644 --- a/stratosphere/spl/source/spl_fs_service.hpp +++ b/stratosphere/spl/source/spl_fs_service.hpp @@ -17,8 +17,8 @@ #pragma once #include #include +#include -#include "spl_types.hpp" #include "spl_crypto_service.hpp" namespace sts::spl { diff --git a/stratosphere/spl/source/spl_general_service.cpp b/stratosphere/spl/source/spl_general_service.cpp index 4d1e644..fc70c7a 100644 --- a/stratosphere/spl/source/spl_general_service.cpp +++ b/stratosphere/spl/source/spl_general_service.cpp @@ -17,37 +17,37 @@ #include #include +#include "spl_api_impl.hpp" #include "spl_general_service.hpp" -#include "spl_api.hpp" namespace sts::spl { Result GeneralService::GetConfig(Out out, u32 which) { - return spl::GetConfig(out.GetPointer(), static_cast(which)); + return impl::GetConfig(out.GetPointer(), static_cast(which)); } Result GeneralService::ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod) { - return spl::ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements); + return impl::ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements); } Result GeneralService::SetConfig(u32 which, u64 value) { - return spl::SetConfig(static_cast(which), value); + return impl::SetConfig(static_cast(which), value); } Result GeneralService::GenerateRandomBytes(OutPointerWithClientSize out) { - return spl::GenerateRandomBytes(out.pointer, out.num_elements); + return impl::GenerateRandomBytes(out.pointer, out.num_elements); } Result GeneralService::IsDevelopment(Out is_dev) { - return spl::IsDevelopment(is_dev.GetPointer()); + return impl::IsDevelopment(is_dev.GetPointer()); } Result GeneralService::SetBootReason(BootReasonValue boot_reason) { - return spl::SetBootReason(boot_reason); + return impl::SetBootReason(boot_reason); } Result GeneralService::GetBootReason(Out out) { - return spl::GetBootReason(out.GetPointer()); + return impl::GetBootReason(out.GetPointer()); } } diff --git a/stratosphere/spl/source/spl_general_service.hpp b/stratosphere/spl/source/spl_general_service.hpp index a181d91..d6c2f0a 100644 --- a/stratosphere/spl/source/spl_general_service.hpp +++ b/stratosphere/spl/source/spl_general_service.hpp @@ -17,8 +17,7 @@ #pragma once #include #include - -#include "spl_types.hpp" +#include namespace sts::spl { diff --git a/stratosphere/spl/source/spl_main.cpp b/stratosphere/spl/source/spl_main.cpp index bceb4cd..93973d8 100644 --- a/stratosphere/spl/source/spl_main.cpp +++ b/stratosphere/spl/source/spl_main.cpp @@ -22,6 +22,8 @@ #include #include +#include "spl_api_impl.hpp" + #include "spl_random_service.hpp" #include "spl_general_service.hpp" #include "spl_crypto_service.hpp" @@ -32,8 +34,6 @@ #include "spl_deprecated_service.hpp" -#include "spl_api.hpp" - extern "C" { extern u32 __start__; @@ -91,7 +91,7 @@ int main(int argc, char **argv) { /* Initialize global context. */ - sts::spl::Initialize(); + sts::spl::impl::Initialize(); /* Create server manager. */ static auto s_server_manager = WaitableManager(1); diff --git a/stratosphere/spl/source/spl_manu_service.cpp b/stratosphere/spl/source/spl_manu_service.cpp index d7168a6..1ee4bfc 100644 --- a/stratosphere/spl/source/spl_manu_service.cpp +++ b/stratosphere/spl/source/spl_manu_service.cpp @@ -17,13 +17,13 @@ #include #include +#include "spl_api_impl.hpp" #include "spl_manu_service.hpp" -#include "spl_api.hpp" namespace sts::spl { Result ManuService::ReEncryptRsaPrivateKey(OutPointerWithClientSize out, InPointer src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option) { - return spl::ReEncryptRsaPrivateKey(out.pointer, out.num_elements, src.pointer, src.num_elements, access_key_dec, source_dec, access_key_enc, source_enc, option); + return impl::ReEncryptRsaPrivateKey(out.pointer, out.num_elements, src.pointer, src.num_elements, access_key_dec, source_dec, access_key_enc, source_enc, option); } } diff --git a/stratosphere/spl/source/spl_manu_service.hpp b/stratosphere/spl/source/spl_manu_service.hpp index 044d8da..3c1c6f9 100644 --- a/stratosphere/spl/source/spl_manu_service.hpp +++ b/stratosphere/spl/source/spl_manu_service.hpp @@ -17,8 +17,8 @@ #pragma once #include #include +#include -#include "spl_types.hpp" #include "spl_rsa_service.hpp" namespace sts::spl { diff --git a/stratosphere/spl/source/spl_random_service.cpp b/stratosphere/spl/source/spl_random_service.cpp index 919112a..9127209 100644 --- a/stratosphere/spl/source/spl_random_service.cpp +++ b/stratosphere/spl/source/spl_random_service.cpp @@ -17,13 +17,13 @@ #include #include +#include "spl_api_impl.hpp" #include "spl_random_service.hpp" -#include "spl_api.hpp" namespace sts::spl { Result RandomService::GenerateRandomBytes(OutBuffer out) { - return spl::GenerateRandomBytes(out.buffer, out.num_elements); + return impl::GenerateRandomBytes(out.buffer, out.num_elements); } } diff --git a/stratosphere/spl/source/spl_random_service.hpp b/stratosphere/spl/source/spl_random_service.hpp index 7fc3bf9..e89e92b 100644 --- a/stratosphere/spl/source/spl_random_service.hpp +++ b/stratosphere/spl/source/spl_random_service.hpp @@ -17,8 +17,7 @@ #pragma once #include #include - -#include "spl_types.hpp" +#include namespace sts::spl { diff --git a/stratosphere/spl/source/spl_rsa_service.cpp b/stratosphere/spl/source/spl_rsa_service.cpp index da81ae8..e075fa7 100644 --- a/stratosphere/spl/source/spl_rsa_service.cpp +++ b/stratosphere/spl/source/spl_rsa_service.cpp @@ -17,17 +17,17 @@ #include #include +#include "spl_api_impl.hpp" #include "spl_rsa_service.hpp" -#include "spl_api.hpp" namespace sts::spl { Result RsaService::DecryptRsaPrivateKeyDeprecated(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return spl::DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option); + return impl::DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option); } Result RsaService::DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source) { - return spl::DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, static_cast(smc::DecryptOrImportMode::DecryptRsaPrivateKey)); + return impl::DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, static_cast(smc::DecryptOrImportMode::DecryptRsaPrivateKey)); } } diff --git a/stratosphere/spl/source/spl_rsa_service.hpp b/stratosphere/spl/source/spl_rsa_service.hpp index f9cd57a..7b0933a 100644 --- a/stratosphere/spl/source/spl_rsa_service.hpp +++ b/stratosphere/spl/source/spl_rsa_service.hpp @@ -17,8 +17,8 @@ #pragma once #include #include +#include -#include "spl_types.hpp" #include "spl_crypto_service.hpp" namespace sts::spl { diff --git a/stratosphere/spl/source/spl_smc.cpp b/stratosphere/spl/source/spl_smc.cpp deleted file mode 100644 index c969afe..0000000 --- a/stratosphere/spl/source/spl_smc.cpp +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2018-2019 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 - -#include "spl_smc.hpp" - -namespace sts::spl::smc { - - Result SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::SetConfig); - args.X[1] = which; - args.X[2] = 0; - for (size_t i = 0; i < std::min(size_t(4), num_qwords); i++) { - args.X[3 + i] = value[i]; - } - svcCallSecureMonitor(&args); - - return static_cast(args.X[0]); - } - - Result GetConfig(u64 *out, size_t num_qwords, SplConfigItem which) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::GetConfig); - args.X[1] = which; - svcCallSecureMonitor(&args); - - for (size_t i = 0; i < std::min(size_t(4), num_qwords); i++) { - out[i] = args.X[1 + i]; - } - return static_cast(args.X[0]); - } - - Result CheckStatus(Result *out, AsyncOperationKey op) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::CheckStatus); - args.X[1] = op.value; - svcCallSecureMonitor(&args); - - *out = static_cast(args.X[1]); - return static_cast(args.X[0]); - } - - Result GetResult(Result *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::GetResult); - args.X[1] = op.value; - args.X[2] = reinterpret_cast(out_buf); - args.X[3] = out_buf_size; - svcCallSecureMonitor(&args); - - *out = static_cast(args.X[1]); - return static_cast(args.X[0]); - } - - Result ExpMod(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::ExpMod); - args.X[1] = reinterpret_cast(base); - args.X[2] = reinterpret_cast(exp); - args.X[3] = reinterpret_cast(mod); - args.X[4] = exp_size; - svcCallSecureMonitor(&args); - - out_op->value = args.X[1]; - return static_cast(args.X[0]); - } - - Result GenerateRandomBytes(void *out, size_t size) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::GenerateRandomBytes); - args.X[1] = size; - svcCallSecureMonitor(&args); - - if (args.X[0] == static_cast(Result::Success) && (size <= sizeof(args) - sizeof(args.X[0]))) { - std::memcpy(out, &args.X[1], size); - } - return static_cast(args.X[0]); - } - - Result GenerateAesKek(AccessKey *out, const KeySource &source, u32 generation, u32 option) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::GenerateAesKek); - args.X[1] = source.data64[0]; - args.X[2] = source.data64[1]; - args.X[3] = generation; - args.X[4] = option; - svcCallSecureMonitor(&args); - - out->data64[0] = args.X[1]; - out->data64[1] = args.X[2]; - return static_cast(args.X[0]); - } - - Result LoadAesKey(u32 keyslot, const AccessKey &access_key, const KeySource &source) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::LoadAesKey); - args.X[1] = keyslot; - args.X[2] = access_key.data64[0]; - args.X[3] = access_key.data64[1]; - args.X[4] = source.data64[0]; - args.X[5] = source.data64[1]; - svcCallSecureMonitor(&args); - - return static_cast(args.X[0]); - } - - Result CryptAes(AsyncOperationKey *out_op, u32 mode, const IvCtr &iv_ctr, u32 dst_addr, u32 src_addr, size_t size) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::CryptAes); - args.X[1] = mode; - args.X[2] = iv_ctr.data64[0]; - args.X[3] = iv_ctr.data64[1]; - args.X[4] = src_addr; - args.X[5] = dst_addr; - args.X[6] = size; - svcCallSecureMonitor(&args); - - out_op->value = args.X[1]; - return static_cast(args.X[0]); - } - - Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &source, u32 generation, u32 which) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::GenerateSpecificAesKey); - args.X[1] = source.data64[0]; - args.X[2] = source.data64[1]; - args.X[3] = generation; - args.X[4] = which; - svcCallSecureMonitor(&args); - - out_key->data64[0] = args.X[1]; - out_key->data64[1] = args.X[2]; - return static_cast(args.X[0]); - } - - Result ComputeCmac(Cmac *out_mac, u32 keyslot, const void *data, size_t size) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::ComputeCmac); - args.X[1] = keyslot; - args.X[2] = reinterpret_cast(data); - args.X[3] = size; - svcCallSecureMonitor(&args); - - out_mac->data64[0] = args.X[1]; - out_mac->data64[1] = args.X[2]; - return static_cast(args.X[0]); - } - - Result ReEncryptRsaPrivateKey(void *data, size_t size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::ReEncryptRsaPrivateKey); - args.X[1] = reinterpret_cast(&access_key_dec); - args.X[2] = reinterpret_cast(&access_key_enc); - args.X[3] = option; - args.X[4] = reinterpret_cast(data); - args.X[5] = size; - args.X[6] = reinterpret_cast(&source_dec); - args.X[7] = reinterpret_cast(&source_enc); - svcCallSecureMonitor(&args); - - return static_cast(args.X[0]); - } - - Result DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const KeySource &source, DecryptOrImportMode mode) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::DecryptOrImportRsaPrivateKey); - args.X[1] = access_key.data64[0]; - args.X[2] = access_key.data64[1]; - args.X[3] = static_cast(mode); - args.X[4] = reinterpret_cast(data); - args.X[5] = size; - args.X[6] = source.data64[0]; - args.X[7] = source.data64[1]; - svcCallSecureMonitor(&args); - - return static_cast(args.X[0]); - } - - Result SecureExpMod(AsyncOperationKey *out_op, const void *base, const void *mod, SecureExpModMode mode) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::SecureExpMod); - args.X[1] = reinterpret_cast(base); - args.X[2] = reinterpret_cast(mod); - args.X[3] = static_cast(mode); - svcCallSecureMonitor(&args); - - out_op->value = args.X[1]; - return static_cast(args.X[0]); - } - - Result UnwrapTitleKey(AsyncOperationKey *out_op, const void *base, const void *mod, const void *label_digest, size_t label_digest_size, u32 option) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::UnwrapTitleKey); - args.X[1] = reinterpret_cast(base); - args.X[2] = reinterpret_cast(mod); - std::memset(&args.X[3], 0, 4 * sizeof(args.X[3])); - std::memcpy(&args.X[3], label_digest, std::min(size_t(4 * sizeof(args.X[3])), label_digest_size)); - args.X[7] = option; - svcCallSecureMonitor(&args); - - out_op->value = args.X[1]; - return static_cast(args.X[0]); - } - - Result LoadTitleKey(u32 keyslot, const AccessKey &access_key) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::LoadTitleKey); - args.X[1] = keyslot; - args.X[2] = access_key.data64[0]; - args.X[3] = access_key.data64[1]; - svcCallSecureMonitor(&args); - - return static_cast(args.X[0]); - } - - Result UnwrapCommonTitleKey(AccessKey *out, const KeySource &source, u32 generation) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::UnwrapCommonTitleKey); - args.X[1] = source.data64[0]; - args.X[2] = source.data64[1]; - args.X[3] = generation; - svcCallSecureMonitor(&args); - - out->data64[0] = args.X[1]; - out->data64[1] = args.X[2]; - return static_cast(args.X[0]); - } - - - /* Deprecated functions. */ - Result ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::ImportEsKey); - args.X[1] = access_key.data64[0]; - args.X[2] = access_key.data64[1]; - args.X[3] = option; - args.X[4] = reinterpret_cast(data); - args.X[5] = size; - args.X[6] = source.data64[0]; - args.X[7] = source.data64[1]; - svcCallSecureMonitor(&args); - - return static_cast(args.X[0]); - } - - Result DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::DecryptRsaPrivateKey); - args.X[1] = access_key.data64[0]; - args.X[2] = access_key.data64[1]; - args.X[3] = option; - args.X[4] = reinterpret_cast(data); - args.X[5] = size; - args.X[6] = source.data64[0]; - args.X[7] = source.data64[1]; - svcCallSecureMonitor(&args); - - *out_size = static_cast(args.X[1]); - return static_cast(args.X[0]); - } - - Result ImportSecureExpModKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) { - SecmonArgs args; - - args.X[0] = static_cast(FunctionId::ImportSecureExpModKey); - args.X[1] = access_key.data64[0]; - args.X[2] = access_key.data64[1]; - args.X[3] = option; - args.X[4] = reinterpret_cast(data); - args.X[5] = size; - args.X[6] = source.data64[0]; - args.X[7] = source.data64[1]; - svcCallSecureMonitor(&args); - - return static_cast(args.X[0]); - } - -} diff --git a/stratosphere/spl/source/spl_smc.hpp b/stratosphere/spl/source/spl_smc.hpp deleted file mode 100644 index df0af4c..0000000 --- a/stratosphere/spl/source/spl_smc.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2018-2019 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 "spl_types.hpp" - -namespace sts::spl::smc { - - /* Helpers for converting arguments. */ - inline u32 GetCryptAesMode(CipherMode mode, u32 keyslot) { - return static_cast((static_cast(mode) << 4) | (keyslot & 7)); - } - - inline u32 GetUnwrapEsKeyOption(EsKeyType type, u32 generation) { - return static_cast((static_cast(type) << 6) | (generation & 0x3F)); - } - - /* Functions. */ - Result SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords); - Result GetConfig(u64 *out, size_t num_qwords, SplConfigItem which); - Result CheckStatus(Result *out, AsyncOperationKey op); - Result GetResult(Result *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op); - Result ExpMod(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod); - Result GenerateRandomBytes(void *out, size_t size); - Result GenerateAesKek(AccessKey *out, const KeySource &source, u32 generation, u32 option); - Result LoadAesKey(u32 keyslot, const AccessKey &access_key, const KeySource &source); - Result CryptAes(AsyncOperationKey *out_op, u32 mode, const IvCtr &iv_ctr, u32 dst_addr, u32 src_addr, size_t size); - Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &source, u32 generation, u32 which); - Result ComputeCmac(Cmac *out_mac, u32 keyslot, const void *data, size_t size); - Result ReEncryptRsaPrivateKey(void *data, size_t size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option); - Result DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const KeySource &source, DecryptOrImportMode mode); - Result SecureExpMod(AsyncOperationKey *out_op, const void *base, const void *mod, SecureExpModMode mode); - Result UnwrapTitleKey(AsyncOperationKey *out_op, const void *base, const void *mod, const void *label_digest, size_t label_digest_size, u32 option); - Result LoadTitleKey(u32 keyslot, const AccessKey &access_key); - Result UnwrapCommonTitleKey(AccessKey *out, const KeySource &source, u32 generation); - - /* Deprecated functions. */ - Result ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option); - Result DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option); - Result ImportSecureExpModKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option); - -} diff --git a/stratosphere/spl/source/spl_ssl_service.cpp b/stratosphere/spl/source/spl_ssl_service.cpp index d175420..3c6d1a3 100644 --- a/stratosphere/spl/source/spl_ssl_service.cpp +++ b/stratosphere/spl/source/spl_ssl_service.cpp @@ -17,17 +17,17 @@ #include #include +#include "spl_api_impl.hpp" #include "spl_ssl_service.hpp" -#include "spl_api.hpp" namespace sts::spl { Result SslService::ImportSslKey(InPointer src, AccessKey access_key, KeySource key_source) { - return spl::ImportSslKey(src.pointer, src.num_elements, access_key, key_source); + return impl::ImportSslKey(src.pointer, src.num_elements, access_key, key_source); } Result SslService::SslExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod) { - return spl::SslExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements); + return impl::SslExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements); } } diff --git a/stratosphere/spl/source/spl_ssl_service.hpp b/stratosphere/spl/source/spl_ssl_service.hpp index 73adfea..2a2fbf6 100644 --- a/stratosphere/spl/source/spl_ssl_service.hpp +++ b/stratosphere/spl/source/spl_ssl_service.hpp @@ -17,8 +17,8 @@ #pragma once #include #include +#include -#include "spl_types.hpp" #include "spl_rsa_service.hpp" namespace sts::spl { diff --git a/stratosphere/spl/source/spl_types.hpp b/stratosphere/spl/source/spl_types.hpp deleted file mode 100644 index d44b8b1..0000000 --- a/stratosphere/spl/source/spl_types.hpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2018-2019 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 -#include -#include - -namespace sts::spl { - - namespace smc { - - enum class FunctionId : u32 { - SetConfig = 0xC3000401, - GetConfig = 0xC3000002, - CheckStatus = 0xC3000003, - GetResult = 0xC3000404, - ExpMod = 0xC3000E05, - GenerateRandomBytes = 0xC3000006, - GenerateAesKek = 0xC3000007, - LoadAesKey = 0xC3000008, - CryptAes = 0xC3000009, - GenerateSpecificAesKey = 0xC300000A, - ComputeCmac = 0xC300040B, - ReEncryptRsaPrivateKey = 0xC300D60C, - DecryptOrImportRsaPrivateKey = 0xC300100D, - - SecureExpMod = 0xC300060F, - UnwrapTitleKey = 0xC3000610, - LoadTitleKey = 0xC3000011, - UnwrapCommonTitleKey = 0xC3000012, - - /* Deprecated functions. */ - ImportEsKey = 0xC300100C, - DecryptRsaPrivateKey = 0xC300100D, - ImportSecureExpModKey = 0xC300100E, - }; - - enum class Result { - Success = 0, - NotImplemented = 1, - InvalidArgument = 2, - InProgress = 3, - NoAsyncOperation = 4, - InvalidAsyncOperation = 5, - Blacklisted = 6, - - Max = 99, - }; - - inline ::Result ConvertResult(Result result) { - if (result == Result::Success) { - return ResultSuccess; - } - if (result < Result::Max) { - return MAKERESULT(Module_Spl, static_cast(result)); - } - return ResultSplUnknownSmcResult; - } - - enum class CipherMode { - CbcEncrypt = 0, - CbcDecrypt = 1, - Ctr = 2, - }; - - enum class DecryptOrImportMode { - DecryptRsaPrivateKey = 0, - ImportLotusKey = 1, - ImportEsKey = 2, - ImportSslKey = 3, - ImportDrmKey = 4, - }; - - enum class SecureExpModMode { - Lotus = 0, - Ssl = 1, - Drm = 2, - }; - - enum class EsKeyType { - TitleKey = 0, - ElicenseKey = 1, - }; - - struct AsyncOperationKey { - u64 value; - }; - } - - struct BootReasonValue { - u8 power_intr; - u8 rtc_intr; - u8 nv_erc; - u8 boot_reason; - }; - static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!"); - - #pragma pack(push, 1) - struct AesKey { - union { - u8 data[AES_128_KEY_SIZE]; - u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; - }; - }; - static_assert(alignof(AesKey) == alignof(u8), "AesKey definition!"); - - struct IvCtr { - union { - u8 data[AES_128_KEY_SIZE]; - u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; - }; - }; - static_assert(alignof(IvCtr) == alignof(u8), "IvCtr definition!"); - - struct Cmac { - union { - u8 data[AES_128_KEY_SIZE]; - u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; - }; - }; - static_assert(alignof(Cmac) == alignof(u8), "Cmac definition!"); - - struct AccessKey { - union { - u8 data[AES_128_KEY_SIZE]; - u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; - }; - }; - static_assert(alignof(AccessKey) == alignof(u8), "AccessKey definition!"); - - struct KeySource { - union { - u8 data[AES_128_KEY_SIZE]; - u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; - }; - }; - static_assert(alignof(AccessKey) == alignof(u8), "KeySource definition!"); - #pragma pack(pop) - -}