diff --git a/stratosphere/spl/source/spl_api.cpp b/stratosphere/spl/source/spl_api.cpp new file mode 100644 index 000000000..b43eccab9 --- /dev/null +++ b/stratosphere/spl/source/spl_api.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 "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 new file mode 100644 index 000000000..63aaaed67 --- /dev/null +++ b/stratosphere/spl/source/spl_api.hpp @@ -0,0 +1,77 @@ +/* + * 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_crypto_service.cpp b/stratosphere/spl/source/spl_crypto_service.cpp index 1e3522865..86e445eea 100644 --- a/stratosphere/spl/source/spl_crypto_service.cpp +++ b/stratosphere/spl/source/spl_crypto_service.cpp @@ -18,39 +18,49 @@ #include #include "spl_crypto_service.hpp" +#include "spl_api.hpp" -Result CryptoService::GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option) { - return this->GetSecureMonitorWrapper()->GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option); -} +namespace sts::spl { -Result CryptoService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) { - return this->GetSecureMonitorWrapper()->LoadAesKey(keyslot, this, access_key, key_source); -} + CryptoService::~CryptoService() { + /* Free any keyslots this service is using. */ + spl::FreeAesKeyslots(this); + } -Result CryptoService::GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source) { - return this->GetSecureMonitorWrapper()->GenerateAesKey(out_key.GetPointer(), access_key, key_source); -} + 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); + } -Result CryptoService::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) { - return this->GetSecureMonitorWrapper()->DecryptAesKey(out_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); + } -Result CryptoService::CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) { - return this->GetSecureMonitorWrapper()->CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr); -} + Result CryptoService::GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source) { + return spl::GenerateAesKey(out_key.GetPointer(), access_key, key_source); + } -Result CryptoService::ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf) { - return this->GetSecureMonitorWrapper()->ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements); -} + Result CryptoService::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) { + return spl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option); + } -Result CryptoService::AllocateAesKeyslot(Out out_keyslot) { - return this->GetSecureMonitorWrapper()->AllocateAesKeyslot(out_keyslot.GetPointer(), this); -} + 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); + } -Result CryptoService::FreeAesKeyslot(u32 keyslot) { - return this->GetSecureMonitorWrapper()->FreeAesKeyslot(keyslot, this); -} + 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); + } + + Result CryptoService::AllocateAesKeyslot(Out out_keyslot) { + return spl::AllocateAesKeyslot(out_keyslot.GetPointer(), this); + } + + Result CryptoService::FreeAesKeyslot(u32 keyslot) { + return spl::FreeAesKeyslot(keyslot, this); + } + + void CryptoService::GetAesKeyslotAvailableEvent(Out out_hnd) { + out_hnd.SetValue(spl::GetAesKeyslotAvailableEventHandle()); + } -void CryptoService::GetAesKeyslotAvailableEvent(Out out_hnd) { - out_hnd.SetValue(this->GetSecureMonitorWrapper()->GetAesKeyslotAvailableEventHandle()); } diff --git a/stratosphere/spl/source/spl_crypto_service.hpp b/stratosphere/spl/source/spl_crypto_service.hpp index 2f56df6ec..3acfb1f1d 100644 --- a/stratosphere/spl/source/spl_crypto_service.hpp +++ b/stratosphere/spl/source/spl_crypto_service.hpp @@ -21,44 +21,42 @@ #include "spl_types.hpp" #include "spl_general_service.hpp" -class CryptoService : public GeneralService { - public: - CryptoService(SecureMonitorWrapper *sw) : GeneralService(sw) { - /* ... */ - } +namespace sts::spl { - virtual ~CryptoService() { - this->GetSecureMonitorWrapper()->FreeAesKeyslots(this); - } - protected: - /* Actual commands. */ - virtual Result GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option); - virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source); - virtual Result GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source); - virtual Result DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option); - virtual Result CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr); - virtual Result ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf); - virtual Result AllocateAesKeyslot(Out out_keyslot); - virtual Result FreeAesKeyslot(u32 keyslot); - virtual void GetAesKeyslotAvailableEvent(Out out_hnd); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), + class CryptoService : public GeneralService { + public: + CryptoService() : GeneralService() { /* ... */ } + virtual ~CryptoService(); + protected: + /* Actual commands. */ + virtual Result GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option); + virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source); + virtual Result GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source); + virtual Result DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option); + virtual Result CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr); + virtual Result ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf); + virtual Result AllocateAesKeyslot(Out out_keyslot); + virtual Result FreeAesKeyslot(u32 keyslot); + virtual void GetAesKeyslotAvailableEvent(Out out_hnd); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + }; + }; - }; -}; +} diff --git a/stratosphere/spl/source/spl_ctr_drbg.cpp b/stratosphere/spl/source/spl_ctr_drbg.cpp index a468d2dcf..c9bc73271 100644 --- a/stratosphere/spl/source/spl_ctr_drbg.cpp +++ b/stratosphere/spl/source/spl_ctr_drbg.cpp @@ -20,62 +20,66 @@ #include "spl_types.hpp" #include "spl_ctr_drbg.hpp" -void CtrDrbg::Update(const void *data) { - aes128ContextCreate(&this->aes_ctx, this->key, true); - for (size_t offset = 0; offset < sizeof(this->work[1]); offset += BlockSize) { - IncrementCounter(this->counter); - aes128EncryptBlock(&this->aes_ctx, &this->work[1][offset], this->counter); +namespace sts::spl { + + void CtrDrbg::Update(const void *data) { + aes128ContextCreate(&this->aes_ctx, this->key, true); + for (size_t offset = 0; offset < sizeof(this->work[1]); offset += BlockSize) { + IncrementCounter(this->counter); + aes128EncryptBlock(&this->aes_ctx, &this->work[1][offset], this->counter); + } + + Xor(this->work[1], data, sizeof(this->work[1])); + + std::memcpy(this->key, &this->work[1][0], sizeof(this->key)); + std::memcpy(this->counter, &this->work[1][BlockSize], sizeof(this->key)); } - Xor(this->work[1], data, sizeof(this->work[1])); + void CtrDrbg::Initialize(const void *seed) { + std::memcpy(this->work[0], seed, sizeof(this->work[0])); + std::memset(this->key, 0, sizeof(this->key)); + std::memset(this->counter, 0, sizeof(this->counter)); + this->Update(this->work[0]); + this->reseed_counter = 1; + } + + void CtrDrbg::Reseed(const void *seed) { + std::memcpy(this->work[0], seed, sizeof(this->work[0])); + this->Update(this->work[0]); + this->reseed_counter = 1; + } + + bool CtrDrbg::GenerateRandomBytes(void *out, size_t size) { + if (size > MaxRequestSize) { + return false; + } + + if (this->reseed_counter > ReseedInterval) { + return false; + } + + aes128ContextCreate(&this->aes_ctx, this->key, true); + u8 *cur_dst = reinterpret_cast(out); + + size_t aligned_size = (size & ~(BlockSize - 1)); + for (size_t offset = 0; offset < aligned_size; offset += BlockSize) { + IncrementCounter(this->counter); + aes128EncryptBlock(&this->aes_ctx, cur_dst, this->counter); + cur_dst += BlockSize; + } + + if (size > aligned_size) { + IncrementCounter(this->counter); + aes128EncryptBlock(&this->aes_ctx, this->work[1], this->counter); + std::memcpy(cur_dst, this->work[1], size - aligned_size); + } + + std::memset(this->work[0], 0, sizeof(this->work[0])); + this->Update(this->work[0]); + + this->reseed_counter++; + return true; + + } - std::memcpy(this->key, &this->work[1][0], sizeof(this->key)); - std::memcpy(this->counter, &this->work[1][BlockSize], sizeof(this->key)); } - -void CtrDrbg::Initialize(const void *seed) { - std::memcpy(this->work[0], seed, sizeof(this->work[0])); - std::memset(this->key, 0, sizeof(this->key)); - std::memset(this->counter, 0, sizeof(this->counter)); - this->Update(this->work[0]); - this->reseed_counter = 1; -} - -void CtrDrbg::Reseed(const void *seed) { - std::memcpy(this->work[0], seed, sizeof(this->work[0])); - this->Update(this->work[0]); - this->reseed_counter = 1; -} - -bool CtrDrbg::GenerateRandomBytes(void *out, size_t size) { - if (size > MaxRequestSize) { - return false; - } - - if (this->reseed_counter > ReseedInterval) { - return false; - } - - aes128ContextCreate(&this->aes_ctx, this->key, true); - u8 *cur_dst = reinterpret_cast(out); - - size_t aligned_size = (size & ~(BlockSize - 1)); - for (size_t offset = 0; offset < aligned_size; offset += BlockSize) { - IncrementCounter(this->counter); - aes128EncryptBlock(&this->aes_ctx, cur_dst, this->counter); - cur_dst += BlockSize; - } - - if (size > aligned_size) { - IncrementCounter(this->counter); - aes128EncryptBlock(&this->aes_ctx, this->work[1], this->counter); - std::memcpy(cur_dst, this->work[1], size - aligned_size); - } - - std::memset(this->work[0], 0, sizeof(this->work[0])); - this->Update(this->work[0]); - - this->reseed_counter++; - return true; - -} \ No newline at end of file diff --git a/stratosphere/spl/source/spl_ctr_drbg.hpp b/stratosphere/spl/source/spl_ctr_drbg.hpp index 39f82ae0a..462c3c2e6 100644 --- a/stratosphere/spl/source/spl_ctr_drbg.hpp +++ b/stratosphere/spl/source/spl_ctr_drbg.hpp @@ -20,41 +20,45 @@ #include "spl_types.hpp" -/* Nintendo implements CTR_DRBG for their csrng. We will do the same. */ -class CtrDrbg { - public: - static constexpr size_t MaxRequestSize = 0x10000; - static constexpr size_t ReseedInterval = 0x7FFFFFF0; - static constexpr size_t BlockSize = AES_BLOCK_SIZE; - static constexpr size_t SeedSize = 2 * AES_BLOCK_SIZE; - private: - Aes128Context aes_ctx; - u8 counter[BlockSize]; - u8 key[BlockSize]; - u8 work[2][SeedSize]; - u32 reseed_counter; - private: - static void Xor(void *dst, const void *src, size_t size) { - const u8 *src_u8 = reinterpret_cast(src); - u8 *dst_u8 = reinterpret_cast(dst); +namespace sts::spl { - for (size_t i = 0; i < size; i++) { - dst_u8[i] ^= src_u8[i]; + /* Nintendo implements CTR_DRBG for their csrng. We will do the same. */ + class CtrDrbg { + public: + static constexpr size_t MaxRequestSize = 0x10000; + static constexpr size_t ReseedInterval = 0x7FFFFFF0; + static constexpr size_t BlockSize = AES_BLOCK_SIZE; + static constexpr size_t SeedSize = 2 * AES_BLOCK_SIZE; + private: + Aes128Context aes_ctx; + u8 counter[BlockSize]; + u8 key[BlockSize]; + u8 work[2][SeedSize]; + u32 reseed_counter; + private: + static void Xor(void *dst, const void *src, size_t size) { + const u8 *src_u8 = reinterpret_cast(src); + u8 *dst_u8 = reinterpret_cast(dst); + + for (size_t i = 0; i < size; i++) { + dst_u8[i] ^= src_u8[i]; + } } - } - static void IncrementCounter(void *ctr) { - u64 *ctr_64 = reinterpret_cast(ctr); + static void IncrementCounter(void *ctr) { + u64 *ctr_64 = reinterpret_cast(ctr); - ctr_64[1] = __builtin_bswap64(__builtin_bswap64(ctr_64[1]) + 1); - if (!ctr_64[1]) { - ctr_64[0] = __builtin_bswap64(__builtin_bswap64(ctr_64[0]) + 1); + ctr_64[1] = __builtin_bswap64(__builtin_bswap64(ctr_64[1]) + 1); + if (!ctr_64[1]) { + ctr_64[0] = __builtin_bswap64(__builtin_bswap64(ctr_64[0]) + 1); + } } - } - private: - void Update(const void *data); - public: - void Initialize(const void *seed); - void Reseed(const void *seed); - bool GenerateRandomBytes(void *out, size_t size); -}; \ No newline at end of file + private: + void Update(const void *data); + public: + void Initialize(const void *seed); + void Reseed(const void *seed); + bool GenerateRandomBytes(void *out, size_t size); + }; + +} diff --git a/stratosphere/spl/source/spl_deprecated_service.cpp b/stratosphere/spl/source/spl_deprecated_service.cpp index 12484385b..5aa7234f0 100644 --- a/stratosphere/spl/source/spl_deprecated_service.cpp +++ b/stratosphere/spl/source/spl_deprecated_service.cpp @@ -18,103 +18,108 @@ #include #include "spl_deprecated_service.hpp" +#include "spl_api.hpp" -Result DeprecatedService::GetConfig(Out out, u32 which) { - return this->GetSecureMonitorWrapper()->GetConfig(out.GetPointer(), static_cast(which)); -} +namespace sts::spl { -Result DeprecatedService::ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod) { - return this->GetSecureMonitorWrapper()->ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements); -} + Result DeprecatedService::GetConfig(Out out, u32 which) { + return spl::GetConfig(out.GetPointer(), static_cast(which)); + } -Result DeprecatedService::GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option) { - return this->GetSecureMonitorWrapper()->GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option); -} + 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); + } -Result DeprecatedService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) { - return this->GetSecureMonitorWrapper()->LoadAesKey(keyslot, this, access_key, key_source); -} + 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); + } -Result DeprecatedService::GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source) { - return this->GetSecureMonitorWrapper()->GenerateAesKey(out_key.GetPointer(), access_key, key_source); -} + Result DeprecatedService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) { + return spl::LoadAesKey(keyslot, this, access_key, key_source); + } -Result DeprecatedService::SetConfig(u32 which, u64 value) { - return this->GetSecureMonitorWrapper()->SetConfig(static_cast(which), value); -} + Result DeprecatedService::GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source) { + return spl::GenerateAesKey(out_key.GetPointer(), access_key, key_source); + } -Result DeprecatedService::GenerateRandomBytes(OutPointerWithClientSize out) { - return this->GetSecureMonitorWrapper()->GenerateRandomBytes(out.pointer, out.num_elements); -} + Result DeprecatedService::SetConfig(u32 which, u64 value) { + return spl::SetConfig(static_cast(which), value); + } -Result DeprecatedService::ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return this->GetSecureMonitorWrapper()->ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option); -} + Result DeprecatedService::GenerateRandomBytes(OutPointerWithClientSize out) { + return spl::GenerateRandomBytes(out.pointer, out.num_elements); + } -Result DeprecatedService::DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest) { - return this->GetSecureMonitorWrapper()->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::ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { + return spl::ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option); + } -Result DeprecatedService::IsDevelopment(Out is_dev) { - return this->GetSecureMonitorWrapper()->IsDevelopment(is_dev.GetPointer()); -} + 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); + } -Result DeprecatedService::GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which) { - return this->GetSecureMonitorWrapper()->GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which); -} + Result DeprecatedService::IsDevelopment(Out is_dev) { + return spl::IsDevelopment(is_dev.GetPointer()); + } -Result DeprecatedService::DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return this->GetSecureMonitorWrapper()->DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option); -} + Result DeprecatedService::GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which) { + return spl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which); + } -Result DeprecatedService::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) { - return this->GetSecureMonitorWrapper()->DecryptAesKey(out_key.GetPointer(), key_source, generation, option); -} + 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); + } -Result DeprecatedService::CryptAesCtrDeprecated(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) { - return this->GetSecureMonitorWrapper()->CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr); -} + Result DeprecatedService::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) { + return spl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option); + } -Result DeprecatedService::CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr) { - return this->GetSecureMonitorWrapper()->CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr); -} + 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); + } -Result DeprecatedService::ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf) { - return this->GetSecureMonitorWrapper()->ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements); -} + 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); + } -Result DeprecatedService::ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return this->GetSecureMonitorWrapper()->ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option); -} + 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); + } -Result DeprecatedService::UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation) { - return this->GetSecureMonitorWrapper()->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::ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { + return spl::ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option); + } -Result DeprecatedService::LoadTitleKey(u32 keyslot, AccessKey access_key) { - return this->GetSecureMonitorWrapper()->LoadTitleKey(keyslot, this, access_key); -} + 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); + } -Result DeprecatedService::UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation) { - return this->GetSecureMonitorWrapper()->UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation); -} + Result DeprecatedService::LoadTitleKey(u32 keyslot, AccessKey access_key) { + return spl::LoadTitleKey(keyslot, this, access_key); + } -Result DeprecatedService::AllocateAesKeyslot(Out out_keyslot) { - return this->GetSecureMonitorWrapper()->AllocateAesKeyslot(out_keyslot.GetPointer(), this); -} + Result DeprecatedService::UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation) { + return spl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation); + } -Result DeprecatedService::FreeAesKeyslot(u32 keyslot) { - return this->GetSecureMonitorWrapper()->FreeAesKeyslot(keyslot, this); -} + Result DeprecatedService::AllocateAesKeyslot(Out out_keyslot) { + return spl::AllocateAesKeyslot(out_keyslot.GetPointer(), this); + } -void DeprecatedService::GetAesKeyslotAvailableEvent(Out out_hnd) { - out_hnd.SetValue(this->GetSecureMonitorWrapper()->GetAesKeyslotAvailableEventHandle()); -} + Result DeprecatedService::FreeAesKeyslot(u32 keyslot) { + return spl::FreeAesKeyslot(keyslot, this); + } -Result DeprecatedService::SetBootReason(BootReasonValue boot_reason) { - return this->GetSecureMonitorWrapper()->SetBootReason(boot_reason); -} + void DeprecatedService::GetAesKeyslotAvailableEvent(Out out_hnd) { + out_hnd.SetValue(spl::GetAesKeyslotAvailableEventHandle()); + } + + Result DeprecatedService::SetBootReason(BootReasonValue boot_reason) { + return spl::SetBootReason(boot_reason); + } + + Result DeprecatedService::GetBootReason(Out out) { + return spl::GetBootReason(out.GetPointer()); + } -Result DeprecatedService::GetBootReason(Out out) { - return this->GetSecureMonitorWrapper()->GetBootReason(out.GetPointer()); } diff --git a/stratosphere/spl/source/spl_deprecated_service.hpp b/stratosphere/spl/source/spl_deprecated_service.hpp index cd52d2d0d..d78bb7282 100644 --- a/stratosphere/spl/source/spl_deprecated_service.hpp +++ b/stratosphere/spl/source/spl_deprecated_service.hpp @@ -19,74 +19,100 @@ #include #include "spl_types.hpp" -#include "spl_secmon_wrapper.hpp" -class DeprecatedService : public IServiceObject { - private: - SecureMonitorWrapper *secmon_wrapper; - public: - DeprecatedService(SecureMonitorWrapper *sw) : secmon_wrapper(sw) { - /* ... */ - } +namespace sts::spl { - virtual ~DeprecatedService() { /* ... */ } - protected: - SecureMonitorWrapper *GetSecureMonitorWrapper() const { - return this->secmon_wrapper; - } - protected: - /* Actual commands. */ - virtual Result GetConfig(Out out, u32 which); - virtual Result ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod); - virtual Result GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option); - virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source); - virtual Result GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source); - virtual Result SetConfig(u32 which, u64 value); - virtual Result GenerateRandomBytes(OutPointerWithClientSize out); - virtual Result ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option); - virtual Result DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest); - virtual Result IsDevelopment(Out is_dev); - virtual Result GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which); - virtual Result DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option); - virtual Result DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option); - virtual Result CryptAesCtrDeprecated(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr); - virtual Result CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr); - virtual Result ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf); - virtual Result ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option); - virtual Result UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation); - virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key); - virtual Result UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation); - virtual Result AllocateAesKeyslot(Out out_keyslot); - virtual Result FreeAesKeyslot(u32 keyslot); - virtual void GetAesKeyslotAvailableEvent(Out out_hnd); - virtual Result SetBootReason(BootReasonValue boot_reason); - virtual Result GetBootReason(Out out); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - }; -}; + class DeprecatedService : public IServiceObject { + protected: + enum class CommandId { + /* 1.0.0+ */ + GetConfig = 0, + ExpMod = 1, + GenerateAesKek = 2, + LoadAesKey = 3, + GenerateAesKey = 4, + SetConfig = 5, + GenerateRandomBytes = 7, + ImportLotusKey = 9, + DecryptLotusMessage = 10, + IsDevelopment = 11, + GenerateSpecificAesKey = 12, + DecryptRsaPrivateKey = 13, + DecryptAesKey = 14, + CryptAesCtr = 15, + ComputeCmac = 16, + ImportEsKey = 17, + UnwrapTitleKey = 18, + LoadTitleKey = 19, + + /* 2.0.0+ */ + UnwrapCommonTitleKey = 20, + AllocateAesKeyslot = 21, + FreeAesKeyslot = 22, + GetAesKeyslotAvailableEvent = 23, + + /* 3.0.0+ */ + SetBootReason = 24, + GetBootReason = 25, + }; + public: + DeprecatedService() { /* ... */ } + virtual ~DeprecatedService() { /* ... */ } + protected: + /* Actual commands. */ + virtual Result GetConfig(Out out, u32 which); + virtual Result ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod); + virtual Result GenerateAesKek(Out out_access_key, KeySource key_source, u32 generation, u32 option); + virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source); + virtual Result GenerateAesKey(Out out_key, AccessKey access_key, KeySource key_source); + virtual Result SetConfig(u32 which, u64 value); + virtual Result GenerateRandomBytes(OutPointerWithClientSize out); + virtual Result ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option); + virtual Result DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest); + virtual Result IsDevelopment(Out is_dev); + virtual Result GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which); + virtual Result DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option); + virtual Result DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option); + virtual Result CryptAesCtrDeprecated(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr); + virtual Result CryptAesCtr(OutBuffer out_buf, u32 keyslot, InBuffer in_buf, IvCtr iv_ctr); + virtual Result ComputeCmac(Out out_cmac, u32 keyslot, InPointer in_buf); + virtual Result ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option); + virtual Result UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation); + virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key); + virtual Result UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation); + virtual Result AllocateAesKeyslot(Out out_keyslot); + virtual Result FreeAesKeyslot(u32 keyslot); + virtual void GetAesKeyslotAvailableEvent(Out out_hnd); + virtual Result SetBootReason(BootReasonValue boot_reason); + virtual Result GetBootReason(Out out); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + }; + }; + +} diff --git a/stratosphere/spl/source/spl_es_service.cpp b/stratosphere/spl/source/spl_es_service.cpp index cb855d05e..14f4c45fc 100644 --- a/stratosphere/spl/source/spl_es_service.cpp +++ b/stratosphere/spl/source/spl_es_service.cpp @@ -18,31 +18,36 @@ #include #include "spl_es_service.hpp" +#include "spl_api.hpp" -Result EsService::ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return this->GetSecureMonitorWrapper()->ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option); -} +namespace sts::spl { -Result EsService::UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation) { - return this->GetSecureMonitorWrapper()->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::ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { + return spl::ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option); + } -Result EsService::UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation) { - return this->GetSecureMonitorWrapper()->UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation); -} + 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); + } -Result EsService::ImportDrmKey(InPointer src, AccessKey access_key, KeySource key_source) { - return this->GetSecureMonitorWrapper()->ImportDrmKey(src.pointer, src.num_elements, access_key, key_source); -} + Result EsService::UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation) { + return spl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation); + } -Result EsService::DrmExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod) { - return this->GetSecureMonitorWrapper()->DrmExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements); -} + Result EsService::ImportDrmKey(InPointer src, AccessKey access_key, KeySource key_source) { + return spl::ImportDrmKey(src.pointer, src.num_elements, access_key, key_source); + } -Result EsService::UnwrapElicenseKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation) { - return this->GetSecureMonitorWrapper()->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::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); + } + + 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); + } + + Result EsService::LoadElicenseKey(u32 keyslot, AccessKey access_key) { + return spl::LoadElicenseKey(keyslot, this, access_key); + } -Result EsService::LoadElicenseKey(u32 keyslot, AccessKey access_key) { - return this->GetSecureMonitorWrapper()->LoadElicenseKey(keyslot, this, access_key); } diff --git a/stratosphere/spl/source/spl_es_service.hpp b/stratosphere/spl/source/spl_es_service.hpp index 47c5b58ae..e9828d4af 100644 --- a/stratosphere/spl/source/spl_es_service.hpp +++ b/stratosphere/spl/source/spl_es_service.hpp @@ -21,50 +21,49 @@ #include "spl_types.hpp" #include "spl_rsa_service.hpp" -class EsService : public RsaService { - public: - EsService(SecureMonitorWrapper *sw) : RsaService(sw) { - /* ... */ - } +namespace sts::spl { - virtual ~EsService() { - /* ... */ - } - protected: - /* Actual commands. */ - virtual Result ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option); - virtual Result UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation); - virtual Result UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation); - virtual Result ImportDrmKey(InPointer src, AccessKey access_key, KeySource key_source); - virtual Result DrmExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod); - virtual Result UnwrapElicenseKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation); - virtual Result LoadElicenseKey(u32 keyslot, AccessKey access_key); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - }; -}; + class EsService : public RsaService { + public: + EsService() : RsaService() { /* ... */ } + virtual ~EsService() { /* ... */} + protected: + /* Actual commands. */ + virtual Result ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option); + virtual Result UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation); + virtual Result UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation); + virtual Result ImportDrmKey(InPointer src, AccessKey access_key, KeySource key_source); + virtual Result DrmExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod); + virtual Result UnwrapElicenseKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation); + virtual Result LoadElicenseKey(u32 keyslot, AccessKey access_key); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + }; + }; + +} diff --git a/stratosphere/spl/source/spl_fs_service.cpp b/stratosphere/spl/source/spl_fs_service.cpp index d0808e003..95d75c489 100644 --- a/stratosphere/spl/source/spl_fs_service.cpp +++ b/stratosphere/spl/source/spl_fs_service.cpp @@ -18,23 +18,28 @@ #include #include "spl_fs_service.hpp" +#include "spl_api.hpp" -Result FsService::ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return this->GetSecureMonitorWrapper()->ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option); -} +namespace sts::spl { -Result FsService::DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest) { - return this->GetSecureMonitorWrapper()->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::ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { + return spl::ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option); + } -Result FsService::GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which) { - return this->GetSecureMonitorWrapper()->GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which); -} + 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); + } -Result FsService::LoadTitleKey(u32 keyslot, AccessKey access_key) { - return this->GetSecureMonitorWrapper()->LoadTitleKey(keyslot, this, access_key); -} + Result FsService::GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which) { + return spl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which); + } + + Result FsService::LoadTitleKey(u32 keyslot, AccessKey access_key) { + return spl::LoadTitleKey(keyslot, this, access_key); + } + + Result FsService::GetPackage2Hash(OutPointerWithClientSize dst) { + return spl::GetPackage2Hash(dst.pointer, dst.num_elements); + } -Result FsService::GetPackage2Hash(OutPointerWithClientSize dst) { - return this->GetSecureMonitorWrapper()->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 7bac28934..e19d98c02 100644 --- a/stratosphere/spl/source/spl_fs_service.hpp +++ b/stratosphere/spl/source/spl_fs_service.hpp @@ -21,45 +21,43 @@ #include "spl_types.hpp" #include "spl_crypto_service.hpp" -class FsService : public CryptoService { - public: - FsService(SecureMonitorWrapper *sw) : CryptoService(sw) { - /* ... */ - } +namespace sts::spl { - virtual ~FsService() { - /* ... */ - } - protected: - /* Actual commands. */ - virtual Result ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option); - virtual Result DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest); - virtual Result GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which); - virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key); - virtual Result GetPackage2Hash(OutPointerWithClientSize dst); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), + class FsService : public CryptoService { + public: + FsService() : CryptoService() { /* ... */ } + virtual ~FsService() { /* ... */ } + protected: + /* Actual commands. */ + virtual Result ImportLotusKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option); + virtual Result DecryptLotusMessage(Out out_size, OutPointerWithClientSize out, InPointer base, InPointer mod, InPointer label_digest); + virtual Result GenerateSpecificAesKey(Out out_key, KeySource key_source, u32 generation, u32 which); + virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key); + virtual Result GetPackage2Hash(OutPointerWithClientSize dst); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + }; + }; - }; -}; +} diff --git a/stratosphere/spl/source/spl_general_service.cpp b/stratosphere/spl/source/spl_general_service.cpp index d83a5c5d2..4d1e644e5 100644 --- a/stratosphere/spl/source/spl_general_service.cpp +++ b/stratosphere/spl/source/spl_general_service.cpp @@ -18,31 +18,36 @@ #include #include "spl_general_service.hpp" +#include "spl_api.hpp" -Result GeneralService::GetConfig(Out out, u32 which) { - return this->GetSecureMonitorWrapper()->GetConfig(out.GetPointer(), static_cast(which)); -} +namespace sts::spl { -Result GeneralService::ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod) { - return this->GetSecureMonitorWrapper()->ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements); -} + Result GeneralService::GetConfig(Out out, u32 which) { + return spl::GetConfig(out.GetPointer(), static_cast(which)); + } -Result GeneralService::SetConfig(u32 which, u64 value) { - return this->GetSecureMonitorWrapper()->SetConfig(static_cast(which), value); -} + 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); + } -Result GeneralService::GenerateRandomBytes(OutPointerWithClientSize out) { - return this->GetSecureMonitorWrapper()->GenerateRandomBytes(out.pointer, out.num_elements); -} + Result GeneralService::SetConfig(u32 which, u64 value) { + return spl::SetConfig(static_cast(which), value); + } -Result GeneralService::IsDevelopment(Out is_dev) { - return this->GetSecureMonitorWrapper()->IsDevelopment(is_dev.GetPointer()); -} + Result GeneralService::GenerateRandomBytes(OutPointerWithClientSize out) { + return spl::GenerateRandomBytes(out.pointer, out.num_elements); + } -Result GeneralService::SetBootReason(BootReasonValue boot_reason) { - return this->GetSecureMonitorWrapper()->SetBootReason(boot_reason); -} + Result GeneralService::IsDevelopment(Out is_dev) { + return spl::IsDevelopment(is_dev.GetPointer()); + } + + Result GeneralService::SetBootReason(BootReasonValue boot_reason) { + return spl::SetBootReason(boot_reason); + } + + Result GeneralService::GetBootReason(Out out) { + return spl::GetBootReason(out.GetPointer()); + } -Result GeneralService::GetBootReason(Out out) { - return this->GetSecureMonitorWrapper()->GetBootReason(out.GetPointer()); } diff --git a/stratosphere/spl/source/spl_general_service.hpp b/stratosphere/spl/source/spl_general_service.hpp index 6d1879dac..a181d9127 100644 --- a/stratosphere/spl/source/spl_general_service.hpp +++ b/stratosphere/spl/source/spl_general_service.hpp @@ -19,38 +19,76 @@ #include #include "spl_types.hpp" -#include "spl_secmon_wrapper.hpp" -class GeneralService : public IServiceObject { - private: - SecureMonitorWrapper *secmon_wrapper; - public: - GeneralService(SecureMonitorWrapper *sw) : secmon_wrapper(sw) { - /* ... */ - } +namespace sts::spl { - virtual ~GeneralService() { /* ... */ } - protected: - SecureMonitorWrapper *GetSecureMonitorWrapper() const { - return this->secmon_wrapper; - } - protected: - /* Actual commands. */ - virtual Result GetConfig(Out out, u32 which); - virtual Result ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod); - virtual Result SetConfig(u32 which, u64 value); - virtual Result GenerateRandomBytes(OutPointerWithClientSize out); - virtual Result IsDevelopment(Out is_dev); - virtual Result SetBootReason(BootReasonValue boot_reason); - virtual Result GetBootReason(Out out); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - }; -}; + class GeneralService : public IServiceObject { + protected: + enum class CommandId { + /* 1.0.0+ */ + GetConfig = 0, + ExpMod = 1, + GenerateAesKek = 2, + LoadAesKey = 3, + GenerateAesKey = 4, + SetConfig = 5, + GenerateRandomBytes = 7, + ImportLotusKey = 9, + DecryptLotusMessage = 10, + IsDevelopment = 11, + GenerateSpecificAesKey = 12, + DecryptRsaPrivateKey = 13, + DecryptAesKey = 14, + CryptAesCtr = 15, + ComputeCmac = 16, + ImportEsKey = 17, + UnwrapTitleKey = 18, + LoadTitleKey = 19, + + /* 2.0.0+ */ + UnwrapCommonTitleKey = 20, + AllocateAesKeyslot = 21, + FreeAesKeyslot = 22, + GetAesKeyslotAvailableEvent = 23, + + /* 3.0.0+ */ + SetBootReason = 24, + GetBootReason = 25, + + /* 5.0.0+ */ + ImportSslKey = 26, + SslExpMod = 27, + ImportDrmKey = 28, + DrmExpMod = 29, + ReEncryptRsaPrivateKey = 30, + GetPackage2Hash = 31, + + /* 6.0.0+ */ + UnwrapElicenseKey = 31, /* re-used command id :( */ + LoadElicenseKey = 32, + }; + public: + GeneralService() { /* ... */ } + virtual ~GeneralService() { /* ... */ } + protected: + /* Actual commands. */ + virtual Result GetConfig(Out out, u32 which); + virtual Result ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod); + virtual Result SetConfig(u32 which, u64 value); + virtual Result GenerateRandomBytes(OutPointerWithClientSize out); + virtual Result IsDevelopment(Out is_dev); + virtual Result SetBootReason(BootReasonValue boot_reason); + virtual Result GetBootReason(Out out); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + }; + }; + +} diff --git a/stratosphere/spl/source/spl_main.cpp b/stratosphere/spl/source/spl_main.cpp index 863c9f3b6..bceb4cdcc 100644 --- a/stratosphere/spl/source/spl_main.cpp +++ b/stratosphere/spl/source/spl_main.cpp @@ -32,6 +32,8 @@ #include "spl_deprecated_service.hpp" +#include "spl_api.hpp" + extern "C" { extern u32 __start__; @@ -86,43 +88,27 @@ struct SplServerOptions { static constexpr size_t MaxDomainObjects = 0; }; -/* Single secure monitor wrapper singleton. */ -static SecureMonitorWrapper s_secmon_wrapper; - -/* Helpers for creating services. */ -static const auto MakeRandomService = []() { return std::make_shared(&s_secmon_wrapper); }; -static const auto MakeGeneralService = []() { return std::make_shared(&s_secmon_wrapper); }; -static const auto MakeCryptoService = []() { return std::make_shared(&s_secmon_wrapper); }; -static const auto MakeSslService = []() { return std::make_shared(&s_secmon_wrapper); }; -static const auto MakeEsService = []() { return std::make_shared(&s_secmon_wrapper); }; -static const auto MakeFsService = []() { return std::make_shared(&s_secmon_wrapper); }; -static const auto MakeManuService = []() { return std::make_shared(&s_secmon_wrapper); }; - -static const auto MakeDeprecatedService = []() { return std::make_shared(&s_secmon_wrapper); }; - int main(int argc, char **argv) { - consoleDebugInit(debugDevice_SVC); - /* Initialize global context. */ - SecureMonitorWrapper::Initialize(); + sts::spl::Initialize(); /* Create server manager. */ static auto s_server_manager = WaitableManager(1); /* Create services. */ - s_server_manager.AddWaitable(new ServiceServer("csrng", 3)); + s_server_manager.AddWaitable(new ServiceServer("csrng", 3)); if (GetRuntimeFirmwareVersion() >= FirmwareVersion_400) { - s_server_manager.AddWaitable(new ServiceServer("spl:", 9)); - s_server_manager.AddWaitable(new ServiceServer("spl:mig", 6)); - s_server_manager.AddWaitable(new ServiceServer("spl:ssl", 2)); - s_server_manager.AddWaitable(new ServiceServer("spl:es", 2)); - s_server_manager.AddWaitable(new ServiceServer("spl:fs", 2)); + s_server_manager.AddWaitable(new ServiceServer("spl:", 9)); + s_server_manager.AddWaitable(new ServiceServer("spl:mig", 6)); + s_server_manager.AddWaitable(new ServiceServer("spl:ssl", 2)); + s_server_manager.AddWaitable(new ServiceServer("spl:es", 2)); + s_server_manager.AddWaitable(new ServiceServer("spl:fs", 2)); if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { - s_server_manager.AddWaitable(new ServiceServer("spl:manu", 1)); + s_server_manager.AddWaitable(new ServiceServer("spl:manu", 1)); } } else { - s_server_manager.AddWaitable(new ServiceServer("spl:", 12)); + s_server_manager.AddWaitable(new ServiceServer("spl:", 12)); } /* Loop forever, servicing our services. */ @@ -130,4 +116,3 @@ int main(int argc, char **argv) return 0; } - diff --git a/stratosphere/spl/source/spl_manu_service.cpp b/stratosphere/spl/source/spl_manu_service.cpp index b78b7e192..d7168a6e0 100644 --- a/stratosphere/spl/source/spl_manu_service.cpp +++ b/stratosphere/spl/source/spl_manu_service.cpp @@ -18,7 +18,12 @@ #include #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); + } -Result ManuService::ReEncryptRsaPrivateKey(OutPointerWithClientSize out, InPointer src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option) { - return this->GetSecureMonitorWrapper()->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 7d78ff87c..044d8da80 100644 --- a/stratosphere/spl/source/spl_manu_service.hpp +++ b/stratosphere/spl/source/spl_manu_service.hpp @@ -21,39 +21,38 @@ #include "spl_types.hpp" #include "spl_rsa_service.hpp" -class ManuService : public RsaService { - public: - ManuService(SecureMonitorWrapper *sw) : RsaService(sw) { - /* ... */ - } +namespace sts::spl { - virtual ~ManuService() { - /* ... */ - } - protected: - /* Actual commands. */ - virtual Result ReEncryptRsaPrivateKey(OutPointerWithClientSize out, InPointer src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), + class ManuService : public RsaService { + public: + ManuService() : RsaService() { /* ... */ } - }; -}; + virtual ~ManuService() { /* ... */ } + protected: + /* Actual commands. */ + virtual Result ReEncryptRsaPrivateKey(OutPointerWithClientSize out, InPointer src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + }; + }; + +} diff --git a/stratosphere/spl/source/spl_random_service.cpp b/stratosphere/spl/source/spl_random_service.cpp index a7b0cd6d3..919112a35 100644 --- a/stratosphere/spl/source/spl_random_service.cpp +++ b/stratosphere/spl/source/spl_random_service.cpp @@ -18,7 +18,12 @@ #include #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); + } -Result RandomService::GenerateRandomBytes(OutBuffer out) { - return this->secmon_wrapper->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 66261f087..7fc3bf96b 100644 --- a/stratosphere/spl/source/spl_random_service.hpp +++ b/stratosphere/spl/source/spl_random_service.hpp @@ -19,22 +19,24 @@ #include #include "spl_types.hpp" -#include "spl_secmon_wrapper.hpp" -class RandomService final : public IServiceObject { - private: - SecureMonitorWrapper *secmon_wrapper; - public: - RandomService(SecureMonitorWrapper *sw) : secmon_wrapper(sw) { - /* ... */ - } +namespace sts::spl { - virtual ~RandomService() { /* ... */ } - private: - /* Actual commands. */ - virtual Result GenerateRandomBytes(OutBuffer out); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMeta(), - }; -}; + class RandomService final : public IServiceObject { + protected: + enum class CommandId { + GenerateRandomBytes = 0, + }; + public: + RandomService() { /* ... */ } + virtual ~RandomService() { /* ... */ } + private: + /* Actual commands. */ + virtual Result GenerateRandomBytes(OutBuffer out); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + }; + }; + +} diff --git a/stratosphere/spl/source/spl_rsa_service.cpp b/stratosphere/spl/source/spl_rsa_service.cpp index 348edae79..da81ae814 100644 --- a/stratosphere/spl/source/spl_rsa_service.cpp +++ b/stratosphere/spl/source/spl_rsa_service.cpp @@ -18,11 +18,16 @@ #include #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); + } + + 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)); + } -Result RsaService::DecryptRsaPrivateKeyDeprecated(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option) { - return this->GetSecureMonitorWrapper()->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 this->GetSecureMonitorWrapper()->DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, SmcDecryptOrImportMode_DecryptRsaPrivateKey); -} \ No newline at end of file diff --git a/stratosphere/spl/source/spl_rsa_service.hpp b/stratosphere/spl/source/spl_rsa_service.hpp index 91518bbe8..f9cd57a77 100644 --- a/stratosphere/spl/source/spl_rsa_service.hpp +++ b/stratosphere/spl/source/spl_rsa_service.hpp @@ -21,39 +21,37 @@ #include "spl_types.hpp" #include "spl_crypto_service.hpp" -class RsaService : public CryptoService { - public: - RsaService(SecureMonitorWrapper *sw) : CryptoService(sw) { - /* ... */ - } +namespace sts::spl { - virtual ~RsaService() { - /* ... */ - } - protected: - /* Actual commands. */ - virtual Result DecryptRsaPrivateKeyDeprecated(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option); - virtual Result DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), + class RsaService : public CryptoService { + public: + RsaService() : CryptoService() { /* ... */ } + virtual ~RsaService() { /* ... */ } + protected: + /* Actual commands. */ + virtual Result DecryptRsaPrivateKeyDeprecated(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option); + virtual Result DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + }; + }; - }; -}; +} diff --git a/stratosphere/spl/source/spl_secmon_wrapper.cpp b/stratosphere/spl/source/spl_secmon_wrapper.cpp deleted file mode 100644 index c816dc1cc..000000000 --- a/stratosphere/spl/source/spl_secmon_wrapper.cpp +++ /dev/null @@ -1,875 +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_secmon_wrapper.hpp" -#include "spl_smc_wrapper.hpp" -#include "spl_ctr_drbg.hpp" - -/* Convenient. */ -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; - -/* Types. */ -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)); - } -}; - -/* Globals. */ -static CtrDrbg g_drbg; -static Event g_se_event; -static IEvent *g_se_keyslot_available_event = nullptr; - -static Handle g_se_das_hnd; -static u32 g_se_mapped_work_buffer_addr; -static __attribute__((aligned(0x1000))) u8 g_work_buffer[0x1000]; -constexpr size_t MaxWorkBufferSize = sizeof(g_work_buffer) / 2; - -static HosMutex g_async_op_lock; - -void SecureMonitorWrapper::InitializeCtrDrbg() { - u8 seed[CtrDrbg::SeedSize]; - - if (SmcWrapper::GenerateRandomBytes(seed, sizeof(seed)) != SmcResult_Success) { - std::abort(); - } - - g_drbg.Initialize(seed); -} - -void SecureMonitorWrapper::InitializeSeEvents() { - u64 irq_num; - SmcWrapper::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 SecureMonitorWrapper::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)); -} - -void SecureMonitorWrapper::Initialize() { - /* Initialize the Drbg. */ - InitializeCtrDrbg(); - /* Initialize SE interrupt + keyslot events. */ - InitializeSeEvents(); - /* Initialize DAS for the SE. */ - InitializeDeviceAddressSpace(); -} - -void SecureMonitorWrapper::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 SecureMonitorWrapper::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; -} - -void SecureMonitorWrapper::WaitSeOperationComplete() { - eventWait(&g_se_event, U64_MAX); -} - -Result SecureMonitorWrapper::ConvertToSplResult(SmcResult result) { - if (result == SmcResult_Success) { - return ResultSuccess; - } - if (result < SmcResult_Max) { - return MAKERESULT(Module_Spl, static_cast(result)); - } - return ResultSplUnknownSmcResult; -} - -SmcResult SecureMonitorWrapper::WaitCheckStatus(AsyncOperationKey op_key) { - WaitSeOperationComplete(); - - SmcResult op_res; - SmcResult res = SmcWrapper::CheckStatus(&op_res, op_key); - if (res != SmcResult_Success) { - return res; - } - - return op_res; -} - -SmcResult SecureMonitorWrapper::WaitGetResult(void *out_buf, size_t out_buf_size, AsyncOperationKey op_key) { - WaitSeOperationComplete(); - - SmcResult op_res; - SmcResult res = SmcWrapper::GetResult(&op_res, out_buf, out_buf_size, op_key); - if (res != SmcResult_Success) { - return res; - } - - return op_res; -} - -SmcResult SecureMonitorWrapper::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); - AsyncOperationKey op_key; - const IvCtr iv_ctr = {}; - const u32 mode = SmcWrapper::GetCryptAesMode(SmcCipherMode_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); - - SmcResult res = SmcWrapper::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, sizeof(layout->in_block)); - if (res != SmcResult_Success) { - return res; - } - - if ((res = WaitCheckStatus(op_key)) != SmcResult_Success) { - return res; - } - } - armDCacheFlush(layout, sizeof(*layout)); - - std::memcpy(dst, layout->out_block, sizeof(layout->out_block)); - return SmcResult_Success; -} - -Result SecureMonitorWrapper::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; - } - - SmcResult res = SmcWrapper::GetConfig(out, 1, which); - - /* Nintendo has some special handling here for hardware type/is_retail. */ - if (which == SplConfigItem_HardwareType && res == SmcResult_InvalidArgument) { - *out = 0; - res = SmcResult_Success; - } - if (which == SplConfigItem_IsRetail && res == SmcResult_InvalidArgument) { - *out = 0; - res = SmcResult_Success; - } - - return ConvertToSplResult(res); -} - -Result SecureMonitorWrapper::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 > MaxWorkBufferSize) { - 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); - AsyncOperationKey op_key; - - SmcResult res = SmcWrapper::ExpMod(&op_key, layout->base, layout->exp, exp_size, layout->mod); - if (res != SmcResult_Success) { - return ConvertToSplResult(res); - } - - if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != SmcResult_Success) { - return ConvertToSplResult(res); - } - } - armDCacheFlush(g_work_buffer, sizeof(out_size)); - - std::memcpy(out, g_work_buffer, out_size); - return ResultSuccess; -} - -Result SecureMonitorWrapper::SetConfig(SplConfigItem which, u64 value) { - return ConvertToSplResult(SmcWrapper::SetConfig(which, &value, 1)); -} - -Result SecureMonitorWrapper::GenerateRandomBytesInternal(void *out, size_t size) { - if (!g_drbg.GenerateRandomBytes(out, size)) { - /* We need to reseed. */ - { - u8 seed[CtrDrbg::SeedSize]; - - SmcResult res = SmcWrapper::GenerateRandomBytes(seed, sizeof(seed)); - if (res != SmcResult_Success) { - return ConvertToSplResult(res); - } - - g_drbg.Reseed(seed); - g_drbg.GenerateRandomBytes(out, size); - } - } - - return ResultSuccess; -} - -Result SecureMonitorWrapper::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 SecureMonitorWrapper::IsDevelopment(bool *out) { - u64 is_retail; - R_TRY(this->GetConfig(&is_retail, SplConfigItem_IsRetail)); - - *out = (is_retail == 0); - return ResultSuccess; -} - -Result SecureMonitorWrapper::SetBootReason(BootReasonValue boot_reason) { - if (this->IsBootReasonSet()) { - return ResultSplBootReasonAlreadySet; - } - - this->boot_reason = boot_reason; - this->boot_reason_set = true; - return ResultSuccess; -} - -Result SecureMonitorWrapper::GetBootReason(BootReasonValue *out) { - if (!this->IsBootReasonSet()) { - return ResultSplBootReasonNotSet; - } - - *out = GetBootReason(); - return ResultSuccess; -} - -Result SecureMonitorWrapper::GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option) { - return ConvertToSplResult(SmcWrapper::GenerateAesKek(out_access_key, key_source, generation, option)); -} - -Result SecureMonitorWrapper::LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source) { - R_TRY(ValidateAesKeyslot(keyslot, owner)); - return ConvertToSplResult(SmcWrapper::LoadAesKey(keyslot, access_key, key_source)); -} - -Result SecureMonitorWrapper::GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) { - SmcResult 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(this); - R_TRY(keyslot_holder.Allocate()); - - smc_rc = SmcWrapper::LoadAesKey(keyslot_holder.GetKeyslot(), access_key, s_generate_aes_key_source); - if (smc_rc == SmcResult_Success) { - smc_rc = DecryptAesBlock(keyslot_holder.GetKeyslot(), out_key, &key_source); - } - - return ConvertToSplResult(smc_rc); -} - -Result SecureMonitorWrapper::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 SecureMonitorWrapper::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); - AsyncOperationKey op_key; - const u32 mode = SmcWrapper::GetCryptAesMode(SmcCipherMode_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); - - SmcResult res = SmcWrapper::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, src_size); - if (res != SmcResult_Success) { - return ConvertToSplResult(res); - } - - if ((res = WaitCheckStatus(op_key)) != SmcResult_Success) { - return ConvertToSplResult(res); - } - } - armDCacheFlush(dst, dst_size); - - return ResultSuccess; -} - -Result SecureMonitorWrapper::ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size) { - R_TRY(ValidateAesKeyslot(keyslot, owner)); - - if (size > MaxWorkBufferSize) { - return ResultSplInvalidSize; - } - - std::memcpy(g_work_buffer, data, size); - return ConvertToSplResult(SmcWrapper::ComputeCmac(out_cmac, keyslot, g_work_buffer, size)); -} - -Result SecureMonitorWrapper::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 (this->keyslot_owners[i] == 0) { - this->keyslot_owners[i] = owner; - *out_keyslot = static_cast(i); - return ResultSuccess; - } - } - - g_se_keyslot_available_event->Clear(); - return ResultSplOutOfKeyslots; -} - -Result SecureMonitorWrapper::ValidateAesKeyslot(u32 keyslot, const void *owner) { - if (keyslot >= GetMaxKeyslots()) { - return ResultSplInvalidKeyslot; - } - if (this->keyslot_owners[keyslot] != owner && GetRuntimeFirmwareVersion() > FirmwareVersion_100) { - return ResultSplInvalidKeyslot; - } - return ResultSuccess; -} - -Result SecureMonitorWrapper::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 = {}; - - SmcWrapper::LoadAesKey(keyslot, access_key, key_source); - } - this->keyslot_owners[keyslot] = nullptr; - g_se_keyslot_available_event->Signal(); - return ResultSuccess; -} - -Result SecureMonitorWrapper::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)); - - SmcResult smc_res; - size_t copy_size = 0; - if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { - copy_size = std::min(dst_size, src_size - RsaPrivateKeyMetaSize); - smc_res = SmcWrapper::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, SmcDecryptOrImportMode_DecryptRsaPrivateKey); - } else { - smc_res = SmcWrapper::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 == SmcResult_Success) { - std::memcpy(dst, layout->data, copy_size); - } - - return ConvertToSplResult(smc_res); -} - -Result SecureMonitorWrapper::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)); - SmcResult smc_res; - if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { - smc_res = SmcWrapper::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, option); - } else { - smc_res = SmcWrapper::ImportSecureExpModKey(layout->data, src_size, access_key, key_source, option); - } - - return ConvertToSplResult(smc_res); -} - -Result SecureMonitorWrapper::SecureExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size, u32 option) { - 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 > MaxWorkBufferSize) { - 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); - AsyncOperationKey op_key; - - SmcResult res = SmcWrapper::SecureExpMod(&op_key, layout->base, layout->mod, option); - if (res != SmcResult_Success) { - return ConvertToSplResult(res); - } - - if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != SmcResult_Success) { - return ConvertToSplResult(res); - } - } - armDCacheFlush(g_work_buffer, sizeof(out_size)); - - std::memcpy(out, g_work_buffer, out_size); - return ResultSuccess; -} - -Result SecureMonitorWrapper::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, SmcDecryptOrImportMode_ImportSslKey); -} - -Result SecureMonitorWrapper::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, SmcSecureExpModMode_Ssl); -} - -Result SecureMonitorWrapper::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, SmcDecryptOrImportMode_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 ConvertToSplResult(SmcWrapper::ImportEsKey(layout->data, src_size, access_key, key_source, option)); - } -} - -Result SecureMonitorWrapper::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, 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); - AsyncOperationKey op_key; - - SmcResult res = SmcWrapper::UnwrapTitleKey(&op_key, layout->base, layout->mod, label_digest, label_digest_size, SmcWrapper::GetUnwrapEsKeyOption(type, generation)); - if (res != SmcResult_Success) { - return ConvertToSplResult(res); - } - - if ((res = WaitGetResult(g_work_buffer, sizeof(*out_access_key), op_key)) != SmcResult_Success) { - return ConvertToSplResult(res); - } - } - armDCacheFlush(g_work_buffer, sizeof(*out_access_key)); - - std::memcpy(out_access_key, g_work_buffer, sizeof(*out_access_key)); - return ResultSuccess; -} - -Result SecureMonitorWrapper::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, EsKeyType_TitleKey); -} - -Result SecureMonitorWrapper::UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation) { - return ConvertToSplResult(SmcWrapper::UnwrapCommonTitleKey(out_access_key, key_source, generation)); -} - -Result SecureMonitorWrapper::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, SmcDecryptOrImportMode_ImportDrmKey); -} - -Result SecureMonitorWrapper::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, SmcSecureExpModMode_Drm); -} - -Result SecureMonitorWrapper::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, EsKeyType_ElicenseKey); -} - -Result SecureMonitorWrapper::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); -} - -Result SecureMonitorWrapper::ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) { - if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { - option = SmcDecryptOrImportMode_ImportLotusKey; - } - return ImportSecureExpModKey(src, src_size, access_key, key_source, option); -} - -Result SecureMonitorWrapper::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 > MaxWorkBufferSize || 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, SmcSecureExpModMode_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 SecureMonitorWrapper::GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which) { - return ConvertToSplResult(SmcWrapper::GenerateSpecificAesKey(out_key, key_source, generation, which)); -} - -Result SecureMonitorWrapper::LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key) { - R_TRY(ValidateAesKeyslot(keyslot, owner)); - return ConvertToSplResult(SmcWrapper::LoadTitleKey(keyslot, access_key)); -} - -Result SecureMonitorWrapper::GetPackage2Hash(void *dst, const size_t size) { - u64 hash[4]; - - if (size < sizeof(hash)) { - return ResultSplInvalidSize; - } - - SmcResult smc_res; - if ((smc_res = SmcWrapper::GetConfig(hash, 4, SplConfigItem_Package2Hash)) != SmcResult_Success) { - return ConvertToSplResult(smc_res); - } - - std::memcpy(dst, hash, sizeof(hash)); - return ResultSuccess; -} - -Result SecureMonitorWrapper::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)); - - SmcResult smc_res = SmcWrapper::ReEncryptRsaPrivateKey(layout->data, src_size, layout->access_key_dec, layout->source_dec, layout->access_key_enc, layout->source_enc, option); - if (smc_res == SmcResult_Success) { - size_t copy_size = std::min(dst_size, src_size); - armDCacheFlush(layout, copy_size); - std::memcpy(dst, layout->data, copy_size); - } - - return ConvertToSplResult(smc_res); - -} - -Result SecureMonitorWrapper::FreeAesKeyslots(const void *owner) { - for (size_t i = 0; i < GetMaxKeyslots(); i++) { - if (this->keyslot_owners[i] == owner) { - FreeAesKeyslot(i, owner); - } - } - return ResultSuccess; -} - -Handle SecureMonitorWrapper::GetAesKeyslotAvailableEventHandle() { - return g_se_keyslot_available_event->GetHandle(); -} \ No newline at end of file diff --git a/stratosphere/spl/source/spl_secmon_wrapper.hpp b/stratosphere/spl/source/spl_secmon_wrapper.hpp deleted file mode 100644 index c0998ac98..000000000 --- a/stratosphere/spl/source/spl_secmon_wrapper.hpp +++ /dev/null @@ -1,137 +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" - -class SecureMonitorWrapper { - public: - static constexpr size_t MaxAesKeyslots = 6; - static constexpr size_t MaxAesKeyslotsDeprecated = 4; - private: - const void *keyslot_owners[MaxAesKeyslots] = {}; - BootReasonValue boot_reason = {}; - bool boot_reason_set = false; - private: - static size_t GetMaxKeyslots() { - return (GetRuntimeFirmwareVersion() >= FirmwareVersion_600) ? MaxAesKeyslots : MaxAesKeyslotsDeprecated; - } - private: - BootReasonValue GetBootReason() const { - return this->boot_reason; - } - bool IsBootReasonSet() const { - return this->boot_reason_set; - } - static Result ConvertToSplResult(SmcResult result); - private: - static void InitializeCtrDrbg(); - static void InitializeSeEvents(); - static void InitializeDeviceAddressSpace(); - - static void CalcMgf1AndXor(void *dst, size_t dst_size, const void *src, size_t src_size); - static 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); - public: - static void Initialize(); - private: - Result GenerateRandomBytesInternal(void *out, size_t size); - void WaitSeOperationComplete(); - SmcResult WaitCheckStatus(AsyncOperationKey op_key); - SmcResult WaitGetResult(void *out_buf, size_t out_buf_size, AsyncOperationKey op_key); - Result ValidateAesKeyslot(u32 keyslot, const void *owner); - SmcResult DecryptAesBlock(u32 keyslot, void *dst, const void *src); - Result ImportSecureExpModKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option); - Result SecureExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size, u32 option); - 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, EsKeyType type); - public: - /* 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(); - private: - class ScopedAesKeyslot { - private: - SecureMonitorWrapper *secmon_wrapper; - u32 slot; - bool has_slot; - public: - ScopedAesKeyslot(SecureMonitorWrapper *sw) : secmon_wrapper(sw), slot(0), has_slot(false) { - /* ... */ - } - ~ScopedAesKeyslot() { - if (has_slot) { - this->secmon_wrapper->FreeAesKeyslot(slot, this); - } - } - - u32 GetKeyslot() const { - return this->slot; - } - - Result Allocate() { - R_TRY(this->secmon_wrapper->AllocateAesKeyslot(&this->slot, this)); - this->has_slot = true; - return ResultSuccess; - } - }; -}; diff --git a/stratosphere/spl/source/spl_smc.cpp b/stratosphere/spl/source/spl_smc.cpp new file mode 100644 index 000000000..c969afe7e --- /dev/null +++ b/stratosphere/spl/source/spl_smc.cpp @@ -0,0 +1,313 @@ +/* + * 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 new file mode 100644 index 000000000..df0af4c98 --- /dev/null +++ b/stratosphere/spl/source/spl_smc.hpp @@ -0,0 +1,58 @@ +/* + * 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_smc_wrapper.cpp b/stratosphere/spl/source/spl_smc_wrapper.cpp deleted file mode 100644 index 5845f37ce..000000000 --- a/stratosphere/spl/source/spl_smc_wrapper.cpp +++ /dev/null @@ -1,336 +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_wrapper.hpp" - -enum SmcFunctionId : u32 { - SmcFunctionId_SetConfig = 0xC3000401, - SmcFunctionId_GetConfig = 0xC3000002, - SmcFunctionId_CheckStatus = 0xC3000003, - SmcFunctionId_GetResult = 0xC3000404, - SmcFunctionId_ExpMod = 0xC3000E05, - SmcFunctionId_GenerateRandomBytes = 0xC3000006, - SmcFunctionId_GenerateAesKek = 0xC3000007, - SmcFunctionId_LoadAesKey = 0xC3000008, - SmcFunctionId_CryptAes = 0xC3000009, - SmcFunctionId_GenerateSpecificAesKey = 0xC300000A, - SmcFunctionId_ComputeCmac = 0xC300040B, - SmcFunctionId_ReEncryptRsaPrivateKey = 0xC300D60C, - SmcFunctionId_DecryptOrImportRsaPrivateKey = 0xC300100D, - - SmcFunctionId_SecureExpMod = 0xC300060F, - SmcFunctionId_UnwrapTitleKey = 0xC3000610, - SmcFunctionId_LoadTitleKey = 0xC3000011, - SmcFunctionId_UnwrapCommonTitleKey = 0xC3000012, - - /* Deprecated functions. */ - SmcFunctionId_ImportEsKey = 0xC300100C, - SmcFunctionId_DecryptRsaPrivateKey = 0xC300100D, - SmcFunctionId_ImportSecureExpModKey = 0xC300100E, -}; - -SmcResult SmcWrapper::SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::GetConfig(u64 *out, size_t num_qwords, SplConfigItem which) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::CheckStatus(SmcResult *out, AsyncOperationKey op) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_CheckStatus; - args.X[1] = op.value; - svcCallSecureMonitor(&args); - - *out = static_cast(args.X[1]); - return static_cast(args.X[0]); -} - -SmcResult SmcWrapper::GetResult(SmcResult *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::ExpMod(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::GenerateRandomBytes(void *out, size_t size) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_GenerateRandomBytes; - args.X[1] = size; - svcCallSecureMonitor(&args); - - if (args.X[0] == SmcResult_Success && (size <= sizeof(args) - sizeof(args.X[0]))) { - std::memcpy(out, &args.X[1], size); - } - return static_cast(args.X[0]); -} - -SmcResult SmcWrapper::GenerateAesKek(AccessKey *out, const KeySource &source, u32 generation, u32 option) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::LoadAesKey(u32 keyslot, const AccessKey &access_key, const KeySource &source) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::CryptAes(AsyncOperationKey *out_op, u32 mode, const IvCtr &iv_ctr, u32 dst_addr, u32 src_addr, size_t size) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::GenerateSpecificAesKey(AesKey *out_key, const KeySource &source, u32 generation, u32 which) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::ComputeCmac(Cmac *out_mac, u32 keyslot, const void *data, size_t size) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::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] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_DecryptOrImportRsaPrivateKey; - 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]); -} - -SmcResult SmcWrapper::SecureExpMod(AsyncOperationKey *out_op, const void *base, const void *mod, u32 option) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_SecureExpMod; - args.X[1] = reinterpret_cast(base); - args.X[2] = reinterpret_cast(mod); - args.X[3] = option; - svcCallSecureMonitor(&args); - - out_op->value = args.X[1]; - return static_cast(args.X[0]); -} - -SmcResult SmcWrapper::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] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::LoadTitleKey(u32 keyslot, const AccessKey &access_key) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::UnwrapCommonTitleKey(AccessKey *out, const KeySource &source, u32 generation) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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. */ -SmcResult SmcWrapper::ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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]); -} - -SmcResult SmcWrapper::ImportSecureExpModKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) { - SecmonArgs args; - - args.X[0] = SmcFunctionId_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_wrapper.hpp b/stratosphere/spl/source/spl_smc_wrapper.hpp deleted file mode 100644 index ea8798ee5..000000000 --- a/stratosphere/spl/source/spl_smc_wrapper.hpp +++ /dev/null @@ -1,54 +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" - -class SmcWrapper { - public: - static inline u32 GetCryptAesMode(SmcCipherMode mode, u32 keyslot) { - return static_cast((mode << 4) | (keyslot & 7)); - } - static inline u32 GetUnwrapEsKeyOption(EsKeyType type, u32 generation) { - return static_cast((type << 6) | (generation & 0x3F)); - } - public: - static SmcResult SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords); - static SmcResult GetConfig(u64 *out, size_t num_qwords, SplConfigItem which); - static SmcResult CheckStatus(SmcResult *out, AsyncOperationKey op); - static SmcResult GetResult(SmcResult *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op); - static SmcResult ExpMod(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod); - static SmcResult GenerateRandomBytes(void *out, size_t size); - static SmcResult GenerateAesKek(AccessKey *out, const KeySource &source, u32 generation, u32 option); - static SmcResult LoadAesKey(u32 keyslot, const AccessKey &access_key, const KeySource &source); - static SmcResult CryptAes(AsyncOperationKey *out_op, u32 mode, const IvCtr &iv_ctr, u32 dst_addr, u32 src_addr, size_t size); - static SmcResult GenerateSpecificAesKey(AesKey *out_key, const KeySource &source, u32 generation, u32 which); - static SmcResult ComputeCmac(Cmac *out_mac, u32 keyslot, const void *data, size_t size); - static SmcResult 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); - static SmcResult DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option); - static SmcResult SecureExpMod(AsyncOperationKey *out_op, const void *base, const void *mod, u32 option); - static SmcResult UnwrapTitleKey(AsyncOperationKey *out_op, const void *base, const void *mod, const void *label_digest, size_t label_digest_size, u32 option); - static SmcResult LoadTitleKey(u32 keyslot, const AccessKey &access_key); - static SmcResult UnwrapCommonTitleKey(AccessKey *out, const KeySource &source, u32 generation); - - /* Deprecated functions. */ - static SmcResult ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option); - static SmcResult DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option); - static SmcResult 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 2572968f1..d1754203f 100644 --- a/stratosphere/spl/source/spl_ssl_service.cpp +++ b/stratosphere/spl/source/spl_ssl_service.cpp @@ -18,11 +18,16 @@ #include #include "spl_ssl_service.hpp" +#include "spl_api.hpp" -Result SslService::ImportSslKey(InPointer src, AccessKey access_key, KeySource key_source) { - return this->GetSecureMonitorWrapper()->ImportSslKey(src.pointer, src.num_elements, access_key, key_source); -} +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); + } + + 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); + } -Result SslService::SslExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod) { - return this->GetSecureMonitorWrapper()->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 0bf024468..73adfeabe 100644 --- a/stratosphere/spl/source/spl_ssl_service.hpp +++ b/stratosphere/spl/source/spl_ssl_service.hpp @@ -21,41 +21,40 @@ #include "spl_types.hpp" #include "spl_rsa_service.hpp" -class SslService : public RsaService { - public: - SslService(SecureMonitorWrapper *sw) : RsaService(sw) { - /* ... */ - } +namespace sts::spl { - virtual ~SslService() { - /* ... */ - } - protected: - /* Actual commands. */ - virtual Result ImportSslKey(InPointer src, AccessKey access_key, KeySource key_source); - virtual Result SslExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), - MakeServiceCommandMetaEx(), + class SslService : public RsaService { + public: + SslService() : RsaService() { /* ... */ } + virtual ~SslService() { /* ... */ } + protected: + /* Actual commands. */ + virtual Result ImportSslKey(InPointer src, AccessKey access_key, KeySource key_source); + virtual Result SslExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), + MakeServiceCommandMetaEx(), - }; -}; + }; + }; + +} diff --git a/stratosphere/spl/source/spl_types.hpp b/stratosphere/spl/source/spl_types.hpp index dc96bc9d6..d44b8b126 100644 --- a/stratosphere/spl/source/spl_types.hpp +++ b/stratosphere/spl/source/spl_types.hpp @@ -21,141 +21,136 @@ #include #include -enum SmcResult : u32 { - SmcResult_Success = 0, - SmcResult_NotImplemented = 1, - SmcResult_InvalidArgument = 2, - SmcResult_InProgress = 3, - SmcResult_NoAsyncOperation = 4, - SmcResult_InvalidAsyncOperation = 5, - SmcResult_Blacklisted = 6, +namespace sts::spl { - SmcResult_Max = 99, -}; + namespace smc { -enum SmcCipherMode : u32 { - SmcCipherMode_CbcEncrypt = 0, - SmcCipherMode_CbcDecrypt = 1, - SmcCipherMode_Ctr = 2, -}; + 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, -enum SmcDecryptOrImportMode : u32 { - SmcDecryptOrImportMode_DecryptRsaPrivateKey = 0, - SmcDecryptOrImportMode_ImportLotusKey = 1, - SmcDecryptOrImportMode_ImportEsKey = 2, - SmcDecryptOrImportMode_ImportSslKey = 3, - SmcDecryptOrImportMode_ImportDrmKey = 4, -}; + SecureExpMod = 0xC300060F, + UnwrapTitleKey = 0xC3000610, + LoadTitleKey = 0xC3000011, + UnwrapCommonTitleKey = 0xC3000012, -enum SmcSecureExpModMode : u32 { - SmcSecureExpModMode_Lotus = 0, - SmcSecureExpModMode_Ssl = 1, - SmcSecureExpModMode_Drm = 2, -}; + /* Deprecated functions. */ + ImportEsKey = 0xC300100C, + DecryptRsaPrivateKey = 0xC300100D, + ImportSecureExpModKey = 0xC300100E, + }; -enum EsKeyType : u32 { - EsKeyType_TitleKey = 0, - EsKeyType_ElicenseKey = 1, -}; + enum class Result { + Success = 0, + NotImplemented = 1, + InvalidArgument = 2, + InProgress = 3, + NoAsyncOperation = 4, + InvalidAsyncOperation = 5, + Blacklisted = 6, -struct AsyncOperationKey { - u64 value; -}; + Max = 99, + }; -struct BootReasonValue { - u8 power_intr; - u8 rtc_intr; - u8 nv_erc; - u8 boot_reason; -}; -static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!"); + inline ::Result ConvertResult(Result result) { + if (result == Result::Success) { + return ResultSuccess; + } + if (result < Result::Max) { + return MAKERESULT(Module_Spl, static_cast(result)); + } + return ResultSplUnknownSmcResult; + } -#pragma pack(push, 1) -struct AesKey { - union { - u8 data[AES_128_KEY_SIZE]; - u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; + 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(alignof(AesKey) == alignof(u8), "AesKey definition!"); + static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!"); -struct IvCtr { - union { - u8 data[AES_128_KEY_SIZE]; - u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; + #pragma pack(push, 1) + struct AesKey { + union { + u8 data[AES_128_KEY_SIZE]; + u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; + }; }; -}; -static_assert(alignof(IvCtr) == alignof(u8), "IvCtr definition!"); + static_assert(alignof(AesKey) == alignof(u8), "AesKey definition!"); -struct Cmac { - union { - u8 data[AES_128_KEY_SIZE]; - u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; + struct IvCtr { + union { + u8 data[AES_128_KEY_SIZE]; + u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; + }; }; -}; -static_assert(alignof(Cmac) == alignof(u8), "Cmac definition!"); + static_assert(alignof(IvCtr) == alignof(u8), "IvCtr definition!"); -struct AccessKey { - union { - u8 data[AES_128_KEY_SIZE]; - u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; + struct Cmac { + union { + u8 data[AES_128_KEY_SIZE]; + u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; + }; }; -}; -static_assert(alignof(AccessKey) == alignof(u8), "AccessKey definition!"); + static_assert(alignof(Cmac) == alignof(u8), "Cmac definition!"); -struct KeySource { - union { - u8 data[AES_128_KEY_SIZE]; - u64 data64[AES_128_KEY_SIZE / sizeof(u64)]; + struct AccessKey { + 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) + static_assert(alignof(AccessKey) == alignof(u8), "AccessKey definition!"); -enum CsrngCmd { - Csrng_Cmd_GenerateRandomBytes = 0, -}; + 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) -enum SplServiceCmd { - /* 1.0.0+ */ - Spl_Cmd_GetConfig = 0, - Spl_Cmd_ExpMod = 1, - Spl_Cmd_GenerateAesKek = 2, - Spl_Cmd_LoadAesKey = 3, - Spl_Cmd_GenerateAesKey = 4, - Spl_Cmd_SetConfig = 5, - Spl_Cmd_GenerateRandomBytes = 7, - Spl_Cmd_ImportLotusKey = 9, - Spl_Cmd_DecryptLotusMessage = 10, - Spl_Cmd_IsDevelopment = 11, - Spl_Cmd_GenerateSpecificAesKey = 12, - Spl_Cmd_DecryptRsaPrivateKey = 13, - Spl_Cmd_DecryptAesKey = 14, - Spl_Cmd_CryptAesCtr = 15, - Spl_Cmd_ComputeCmac = 16, - Spl_Cmd_ImportEsKey = 17, - Spl_Cmd_UnwrapTitleKey = 18, - Spl_Cmd_LoadTitleKey = 19, - - /* 2.0.0+ */ - Spl_Cmd_UnwrapCommonTitleKey = 20, - Spl_Cmd_AllocateAesKeyslot = 21, - Spl_Cmd_FreeAesKeyslot = 22, - Spl_Cmd_GetAesKeyslotAvailableEvent = 23, - - /* 3.0.0+ */ - Spl_Cmd_SetBootReason = 24, - Spl_Cmd_GetBootReason = 25, - - /* 5.0.0+ */ - Spl_Cmd_ImportSslKey = 26, - Spl_Cmd_SslExpMod = 27, - Spl_Cmd_ImportDrmKey = 28, - Spl_Cmd_DrmExpMod = 29, - Spl_Cmd_ReEncryptRsaPrivateKey = 30, - Spl_Cmd_GetPackage2Hash = 31, - - /* 6.0.0+ */ - Spl_Cmd_UnwrapElicenseKey = 31, /* re-used command id :( */ - Spl_Cmd_LoadElicenseKey = 32, -}; +}