From bfa84e27c13da8b1e6f84565bf613b0f0ef649f0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 24 Apr 2019 21:00:39 -0700 Subject: [PATCH] spl: implement CryptoService. --- .../spl/source/spl_crypto_service.cpp | 56 +++ .../spl/source/spl_crypto_service.hpp | 64 ++++ stratosphere/spl/source/spl_ctr_drbg.cpp | 18 +- stratosphere/spl/source/spl_ctr_drbg.hpp | 4 +- .../spl/source/spl_general_service.cpp | 14 +- .../spl/source/spl_general_service.hpp | 8 +- stratosphere/spl/source/spl_main.cpp | 5 +- .../spl/source/spl_secmon_wrapper.cpp | 327 ++++++++++++++++-- .../spl/source/spl_secmon_wrapper.hpp | 49 ++- stratosphere/spl/source/spl_smc_wrapper.cpp | 66 ++-- stratosphere/spl/source/spl_smc_wrapper.hpp | 28 +- stratosphere/spl/source/spl_types.hpp | 21 +- 12 files changed, 558 insertions(+), 102 deletions(-) create mode 100644 stratosphere/spl/source/spl_crypto_service.cpp create mode 100644 stratosphere/spl/source/spl_crypto_service.hpp diff --git a/stratosphere/spl/source/spl_crypto_service.cpp b/stratosphere/spl/source/spl_crypto_service.cpp new file mode 100644 index 000000000..53c47242f --- /dev/null +++ b/stratosphere/spl/source/spl_crypto_service.cpp @@ -0,0 +1,56 @@ +/* + * 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_crypto_service.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); +} + +Result CryptoService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) { + return this->GetSecureMonitorWrapper()->LoadAesKey(keyslot, this, access_key, key_source); +} + +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::DecryptAesKey(Out out_key, KeySource key_source, u32 generation, u32 option) { + return this->GetSecureMonitorWrapper()->DecryptAesKey(out_key.GetPointer(), key_source, generation, option); +} + +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::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::AllocateAesKeyslot(Out out_keyslot) { + return this->GetSecureMonitorWrapper()->AllocateAesKeyslot(out_keyslot.GetPointer(), this); +} + +Result CryptoService::FreeAesKeyslot(u32 keyslot) { + return this->GetSecureMonitorWrapper()->FreeAesKeyslot(keyslot, this); +} + +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 new file mode 100644 index 000000000..b5e025b17 --- /dev/null +++ b/stratosphere/spl/source/spl_crypto_service.hpp @@ -0,0 +1,64 @@ +/* + * 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" +#include "spl_general_service.hpp" + +class CryptoService : public GeneralService { + public: + CryptoService(SecureMonitorWrapper *sw) : GeneralService(sw) { + /* ... */ + } + + 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 { + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + + }; +}; diff --git a/stratosphere/spl/source/spl_ctr_drbg.cpp b/stratosphere/spl/source/spl_ctr_drbg.cpp index 1eadb7e4e..a468d2dcf 100644 --- a/stratosphere/spl/source/spl_ctr_drbg.cpp +++ b/stratosphere/spl/source/spl_ctr_drbg.cpp @@ -26,9 +26,9 @@ void CtrDrbg::Update(const void *data) { 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)); } @@ -51,31 +51,31 @@ 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 71564b582..448a22eab 100644 --- a/stratosphere/spl/source/spl_ctr_drbg.hpp +++ b/stratosphere/spl/source/spl_ctr_drbg.hpp @@ -42,10 +42,10 @@ class CtrDrbg { dst_u8[i] = src_u8[i]; } } - + 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); diff --git a/stratosphere/spl/source/spl_general_service.cpp b/stratosphere/spl/source/spl_general_service.cpp index ae0c9bf92..d83a5c5d2 100644 --- a/stratosphere/spl/source/spl_general_service.cpp +++ b/stratosphere/spl/source/spl_general_service.cpp @@ -20,29 +20,29 @@ #include "spl_general_service.hpp" Result GeneralService::GetConfig(Out out, u32 which) { - return this->secmon_wrapper->GetConfig(out.GetPointer(), static_cast(which)); + return this->GetSecureMonitorWrapper()->GetConfig(out.GetPointer(), static_cast(which)); } Result GeneralService::ExpMod(OutPointerWithClientSize out, InPointer base, InPointer exp, InPointer mod) { - return this->secmon_wrapper->ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements); + 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::SetConfig(u32 which, u64 value) { - return this->secmon_wrapper->SetConfig(static_cast(which), value); + return this->GetSecureMonitorWrapper()->SetConfig(static_cast(which), value); } Result GeneralService::GenerateRandomBytes(OutPointerWithClientSize out) { - return this->secmon_wrapper->GenerateRandomBytes(out.pointer, out.num_elements); + return this->GetSecureMonitorWrapper()->GenerateRandomBytes(out.pointer, out.num_elements); } Result GeneralService::IsDevelopment(Out is_dev) { - return this->secmon_wrapper->IsDevelopment(is_dev.GetPointer()); + return this->GetSecureMonitorWrapper()->IsDevelopment(is_dev.GetPointer()); } Result GeneralService::SetBootReason(BootReasonValue boot_reason) { - return this->secmon_wrapper->SetBootReason(boot_reason); + return this->GetSecureMonitorWrapper()->SetBootReason(boot_reason); } Result GeneralService::GetBootReason(Out out) { - return this->secmon_wrapper->GetBootReason(out.GetPointer()); + 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 9f785ee74..6d1879dac 100644 --- a/stratosphere/spl/source/spl_general_service.hpp +++ b/stratosphere/spl/source/spl_general_service.hpp @@ -21,7 +21,7 @@ #include "spl_types.hpp" #include "spl_secmon_wrapper.hpp" -class GeneralService final : public IServiceObject { +class GeneralService : public IServiceObject { private: SecureMonitorWrapper *secmon_wrapper; public: @@ -30,7 +30,11 @@ class GeneralService final : public IServiceObject { } virtual ~GeneralService() { /* ... */ } - private: + 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); diff --git a/stratosphere/spl/source/spl_main.cpp b/stratosphere/spl/source/spl_main.cpp index a644814fb..d87872bfc 100644 --- a/stratosphere/spl/source/spl_main.cpp +++ b/stratosphere/spl/source/spl_main.cpp @@ -24,6 +24,7 @@ #include "spl_random_service.hpp" #include "spl_general_service.hpp" +#include "spl_crypto_service.hpp" extern "C" { extern u32 __start__; @@ -83,8 +84,9 @@ struct SplServerOptions { static SecureMonitorWrapper s_secmon_wrapper; /* Helpers for creating services. */ -static const auto MakeRandomService = []() { return std::make_shared(&s_secmon_wrapper); }; +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); }; int main(int argc, char **argv) { @@ -100,6 +102,7 @@ int main(int argc, char **argv) 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)); /* TODO: Other services. */ } else { /* TODO, DeprecatedGeneralService */ diff --git a/stratosphere/spl/source/spl_secmon_wrapper.cpp b/stratosphere/spl/source/spl_secmon_wrapper.cpp index a52c49535..fae5714a1 100644 --- a/stratosphere/spl/source/spl_secmon_wrapper.cpp +++ b/stratosphere/spl/source/spl_secmon_wrapper.cpp @@ -24,29 +24,66 @@ /* Convenient. */ constexpr size_t DeviceAddressSpaceAlignSize = 0x400000; constexpr size_t DeviceAddressSpaceAlignMask = DeviceAddressSpaceAlignSize - 1; -constexpr u32 DeviceMapBase = 0x80000000u; +constexpr u32 WorkBufferMapBase = 0x80000000u; +constexpr u32 CryptAesInMapBase = 0x90000000u; +constexpr u32 CryptAesOutMapBase = 0xC0000000u; +constexpr size_t CryptAesSizeMax = static_cast(CryptAesOutMapBase - CryptAesInMapBase); + +/* 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) { + if (R_FAILED(svcMapDeviceAddressSpaceAligned(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr, this->perm))) { + std::abort(); + } + } + ~DeviceAddressSpaceMapHelper() { + if (R_FAILED(svcUnmapDeviceAddressSpace(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr))) { + std::abort(); + } + } +}; /* 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_se_lock; +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::InitializeSeInterruptEvent() { +void SecureMonitorWrapper::InitializeSeEvents() { u64 irq_num; SmcWrapper::GetConfig(&irq_num, 1, SplConfigItem_SecurityEngineIrqNumber); Handle hnd; @@ -54,6 +91,9 @@ void SecureMonitorWrapper::InitializeSeInterruptEvent() { std::abort(); } eventLoadRemote(&g_se_event, hnd, true); + + g_se_keyslot_available_event = CreateWriteOnlySystemEvent(); + g_se_keyslot_available_event->Signal(); } void SecureMonitorWrapper::InitializeDeviceAddressSpace() { @@ -67,10 +107,10 @@ void SecureMonitorWrapper::InitializeDeviceAddressSpace() { if (R_FAILED(svcAttachDeviceAddressSpace(DeviceName_SE, g_se_das_hnd))) { std::abort(); } - + const u64 work_buffer_addr = reinterpret_cast(g_work_buffer); - g_se_mapped_work_buffer_addr = 0x80000000u + (work_buffer_addr & DeviceAddressSpaceAlignMask); - + g_se_mapped_work_buffer_addr = WorkBufferMapBase + (work_buffer_addr & DeviceAddressSpaceAlignMask); + /* Map the work buffer for the SE. */ if (R_FAILED(svcMapDeviceAddressSpaceAligned(g_se_das_hnd, CUR_PROCESS_HANDLE, work_buffer_addr, sizeof(g_work_buffer), g_se_mapped_work_buffer_addr, 3))) { std::abort(); @@ -80,8 +120,8 @@ void SecureMonitorWrapper::InitializeDeviceAddressSpace() { void SecureMonitorWrapper::Initialize() { /* Initialize the Drbg. */ InitializeCtrDrbg(); - /* Initialize SE interrupt event. */ - InitializeSeInterruptEvent(); + /* Initialize SE interrupt + keyslot events. */ + InitializeSeEvents(); /* Initialize DAS for the SE. */ InitializeDeviceAddressSpace(); } @@ -102,37 +142,78 @@ Result SecureMonitorWrapper::ConvertToSplResult(SmcResult result) { 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; @@ -142,7 +223,7 @@ Result SecureMonitorWrapper::GetConfig(u64 *out, SplConfigItem which) { *out = 0; res = SmcResult_Success; } - + return ConvertToSplResult(res); } @@ -153,7 +234,7 @@ Result SecureMonitorWrapper::ExpMod(void *out, size_t out_size, const void *base u8 mod[0x100]; }; ExpModLayout *layout = reinterpret_cast(g_work_buffer); - + /* Validate sizes. */ if (base_size > sizeof(layout->base)) { return ResultSplInvalidSize; @@ -164,10 +245,10 @@ Result SecureMonitorWrapper::ExpMod(void *out, size_t out_size, const void *base if (mod_size > sizeof(layout->mod)) { return ResultSplInvalidSize; } - if (out_size > sizeof(g_work_buffer) / 2) { + 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; @@ -175,22 +256,24 @@ Result SecureMonitorWrapper::ExpMod(void *out, size_t out_size, const void *base 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_se_lock); + 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; } @@ -204,17 +287,17 @@ Result SecureMonitorWrapper::GenerateRandomBytesInternal(void *out, size_t 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; } @@ -223,7 +306,7 @@ Result SecureMonitorWrapper::GenerateRandomBytes(void *out, size_t size) { for (size_t ofs = 0; ofs < size; ofs += CtrDrbg::MaxRequestSize) { const size_t cur_size = std::min(size - ofs, CtrDrbg::MaxRequestSize); - + Result rc = GenerateRandomBytesInternal(cur_dst, size); if (R_FAILED(rc)) { return rc; @@ -262,4 +345,190 @@ Result SecureMonitorWrapper::GetBootReason(BootReasonValue *out) { *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) { + Result rc = ValidateAesKeyslot(keyslot, owner); + if (R_FAILED(rc)) { + return rc; + } + return ConvertToSplResult(SmcWrapper::LoadAesKey(keyslot, access_key, key_source)); +} + +Result SecureMonitorWrapper::GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) { + Result rc; + 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); + if (R_FAILED((rc = keyslot_holder.Allocate()))) { + return rc; + } + + 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) { + Result rc; + + 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; + if (R_FAILED((rc = GenerateAesKek(&access_key, s_decrypt_aes_key_source, generation, option)))) { + return rc; + } + + 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) { + Result rc = ValidateAesKeyslot(keyslot, owner); + if (R_FAILED(rc)) { + return rc; + } + + /* 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 = CryptAesInMapBase + (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) { + Result rc = ValidateAesKeyslot(keyslot, owner); + if (R_FAILED(rc)) { + return rc; + } + + 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) { + 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) { + return ResultSplInvalidKeyslot; + } + return ResultSuccess; +} + +Result SecureMonitorWrapper::FreeAesKeyslot(u32 keyslot, const void *owner) { + Result rc = ValidateAesKeyslot(keyslot, owner); + if (R_FAILED(rc)) { + return rc; + } + + /* 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::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 index cfaf123ca..758629485 100644 --- a/stratosphere/spl/source/spl_secmon_wrapper.hpp +++ b/stratosphere/spl/source/spl_secmon_wrapper.hpp @@ -25,7 +25,7 @@ class SecureMonitorWrapper { static constexpr size_t MaxAesKeyslots = 6; static constexpr size_t MaxAesKeyslotsDeprecated = 4; private: - uintptr_t keyslot_owners[MaxAesKeyslots] = {}; + const void *keyslot_owners[MaxAesKeyslots] = {}; BootReasonValue boot_reason = {}; bool boot_reason_set = false; private: @@ -42,7 +42,7 @@ class SecureMonitorWrapper { static Result ConvertToSplResult(SmcResult result); private: static void InitializeCtrDrbg(); - static void InitializeSeInterruptEvent(); + static void InitializeSeEvents(); static void InitializeDeviceAddressSpace(); public: static void Initialize(); @@ -51,7 +51,10 @@ class SecureMonitorWrapper { 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); 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); @@ -59,4 +62,46 @@ class SecureMonitorWrapper { 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); + + /* 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() { + Result rc = this->secmon_wrapper->AllocateAesKeyslot(&this->slot, this); + if (R_SUCCEEDED(rc)) { + this->has_slot = true; + } + return rc; + } + }; }; diff --git a/stratosphere/spl/source/spl_smc_wrapper.cpp b/stratosphere/spl/source/spl_smc_wrapper.cpp index 97e39afc5..8f39e87ec 100644 --- a/stratosphere/spl/source/spl_smc_wrapper.cpp +++ b/stratosphere/spl/source/spl_smc_wrapper.cpp @@ -123,12 +123,12 @@ SmcResult SmcWrapper::GenerateRandomBytes(void *out, size_t size) { return static_cast(args.X[0]); } -SmcResult SmcWrapper::GenerateAesKek(AccessKey *out, const u64 *source, u32 generation, u32 option) { +SmcResult SmcWrapper::GenerateAesKek(AccessKey *out, const KeySource &source, u32 generation, u32 option) { SecmonArgs args; args.X[0] = SmcFunctionId_GenerateAesKek; - args.X[1] = source[0]; - args.X[2] = source[1]; + args.X[1] = source.data64[0]; + args.X[2] = source.data64[1]; args.X[3] = generation; args.X[4] = option; svcCallSecureMonitor(&args); @@ -138,27 +138,27 @@ SmcResult SmcWrapper::GenerateAesKek(AccessKey *out, const u64 *source, u32 gene return static_cast(args.X[0]); } -SmcResult SmcWrapper::LoadAesKey(u32 keyslot, const AccessKey &access_key, const u64 *source) { +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[0]; - args.X[5] = source[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 u64 *iv_ctr, u32 dst_addr, u32 src_addr, size_t size) { +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[0]; - args.X[3] = iv_ctr[1]; + 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; @@ -168,12 +168,12 @@ SmcResult SmcWrapper::CryptAes(AsyncOperationKey *out_op, u32 mode, const u64 *i return static_cast(args.X[0]); } -SmcResult SmcWrapper::GenerateSpecificAesKey(u64 *out, const u64 *source, u32 generation, u32 which) { +SmcResult SmcWrapper::GenerateSpecificAesKey(u64 *out, const KeySource &source, u32 generation, u32 which) { SecmonArgs args; args.X[0] = SmcFunctionId_GenerateSpecificAesKey; - args.X[1] = source[0]; - args.X[2] = source[1]; + args.X[1] = source.data64[0]; + args.X[2] = source.data64[1]; args.X[3] = generation; args.X[4] = which; svcCallSecureMonitor(&args); @@ -181,7 +181,7 @@ SmcResult SmcWrapper::GenerateSpecificAesKey(u64 *out, const u64 *source, u32 ge return static_cast(args.X[0]); } -SmcResult SmcWrapper::ComputeCmac(Cmac &out_mac, u32 keyslot, const void *data, size_t size) { +SmcResult SmcWrapper::ComputeCmac(Cmac *out_mac, u32 keyslot, const void *data, size_t size) { SecmonArgs args; args.X[0] = SmcFunctionId_ComputeCmac; @@ -190,12 +190,12 @@ SmcResult SmcWrapper::ComputeCmac(Cmac &out_mac, u32 keyslot, const void *data, args.X[3] = size; svcCallSecureMonitor(&args); - out_mac.data64[0] = args.X[1]; - out_mac.data64[1] = args.X[2]; + 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 u64 *source_dec, const AccessKey &access_key_enc, const u64 *source_enc, u32 option) { +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; @@ -204,14 +204,14 @@ SmcResult SmcWrapper::ReEncryptRsaPrivateKey(void *data, size_t size, const Acce 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); + 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 u64 *source, u32 option) { +SmcResult SmcWrapper::DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) { SecmonArgs args; args.X[0] = SmcFunctionId_DecryptOrImportRsaPrivateKey; @@ -220,8 +220,8 @@ SmcResult SmcWrapper::DecryptOrImportRsaPrivateKey(void *data, size_t size, cons args.X[3] = option; args.X[4] = reinterpret_cast(data); args.X[5] = size; - args.X[6] = source[0]; - args.X[7] = source[1]; + args.X[6] = source.data64[0]; + args.X[7] = source.data64[1]; svcCallSecureMonitor(&args); return static_cast(args.X[0]); @@ -267,12 +267,12 @@ SmcResult SmcWrapper::LoadTitleKey(u32 keyslot, const AccessKey &access_key) { return static_cast(args.X[0]); } -SmcResult SmcWrapper::UnwrapCommonTitleKey(AccessKey *out, const u64 *source, u32 generation) { +SmcResult SmcWrapper::UnwrapCommonTitleKey(AccessKey *out, const KeySource &source, u32 generation) { SecmonArgs args; args.X[0] = SmcFunctionId_UnwrapCommonTitleKey; - args.X[1] = source[0]; - args.X[2] = source[1]; + args.X[1] = source.data64[0]; + args.X[2] = source.data64[1]; args.X[3] = generation; svcCallSecureMonitor(&args); @@ -283,7 +283,7 @@ SmcResult SmcWrapper::UnwrapCommonTitleKey(AccessKey *out, const u64 *source, u3 /* Deprecated functions. */ -SmcResult SmcWrapper::ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option) { +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; @@ -292,14 +292,14 @@ SmcResult SmcWrapper::ImportEsKey(const void *data, size_t size, const AccessKey args.X[3] = option; args.X[4] = reinterpret_cast(data); args.X[5] = size; - args.X[6] = source[0]; - args.X[7] = source[1]; + 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 u64 *source, u32 option) { +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; @@ -308,15 +308,15 @@ SmcResult SmcWrapper::DecryptRsaPrivateKey(size_t *out_size, void *data, size_t args.X[3] = option; args.X[4] = reinterpret_cast(data); args.X[5] = size; - args.X[6] = source[0]; - args.X[7] = source[1]; + 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 u64 *source, u32 option) { +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; @@ -325,8 +325,8 @@ SmcResult SmcWrapper::ImportSecureExpModKey(const void *data, size_t size, const args.X[3] = option; args.X[4] = reinterpret_cast(data); args.X[5] = size; - args.X[6] = source[0]; - args.X[7] = source[1]; + 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 index 41a97cf40..427b4c7c7 100644 --- a/stratosphere/spl/source/spl_smc_wrapper.hpp +++ b/stratosphere/spl/source/spl_smc_wrapper.hpp @@ -21,6 +21,10 @@ #include "spl_types.hpp" class SmcWrapper { + public: + static inline u32 GetCryptAesMode(SmcCipherMode mode, u32 keyslot) { + return static_cast((mode << 4) | (keyslot & 7)); + } public: static SmcResult SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords); static SmcResult GetConfig(u64 *out, size_t num_qwords, SplConfigItem which); @@ -28,20 +32,20 @@ class SmcWrapper { 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 u64 *source, u32 generation, u32 option); - static SmcResult LoadAesKey(u32 keyslot, const AccessKey &access_key, const u64 *source); - static SmcResult CryptAes(AsyncOperationKey *out_op, u32 mode, const u64 *iv_ctr, u32 dst_addr, u32 src_addr, size_t size); - static SmcResult GenerateSpecificAesKey(u64 *out, const u64 *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 u64 *source_dec, const AccessKey &access_key_enc, const u64 *source_enc, u32 option); - static SmcResult DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option); + 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(u64 *out, 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 u64 *source, u32 generation); - + 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 u64 *source, u32 option); - static SmcResult DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option); - static SmcResult ImportSecureExpModKey(const void *data, size_t size, const AccessKey &access_key, const u64 *source, u32 option); + 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_types.hpp b/stratosphere/spl/source/spl_types.hpp index 8d8317a48..d7ee64dbe 100644 --- a/stratosphere/spl/source/spl_types.hpp +++ b/stratosphere/spl/source/spl_types.hpp @@ -37,7 +37,6 @@ enum SmcCipherMode : u32 { SmcCipherMode_CbcEncrypt = 0, SmcCipherMode_CbcDecrypt = 1, SmcCipherMode_Ctr = 2, - SmcCipherMode_Cmac = 3, }; enum EsKeyType : u32 { @@ -58,12 +57,20 @@ struct BootReasonValue { static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!"); struct AesKey { - u8 data[AES_128_KEY_SIZE]; + union { + u8 data[AES_128_KEY_SIZE]; + u8 data64[AES_128_KEY_SIZE / sizeof(u64)]; + }; }; +static_assert(alignof(AesKey) == alignof(u8), "AesKey definition!"); struct IvCtr { - u8 data[AES_128_KEY_SIZE]; + union { + u8 data[AES_128_KEY_SIZE]; + u8 data64[AES_128_KEY_SIZE / sizeof(u64)]; + }; }; +static_assert(alignof(IvCtr) == alignof(u8), "IvCtr definition!"); struct Cmac { union { @@ -82,8 +89,12 @@ struct AccessKey { static_assert(alignof(AccessKey) == alignof(u8), "AccessKey definition!"); struct KeySource { - u8 data[AES_128_KEY_SIZE]; + union { + u8 data[AES_128_KEY_SIZE]; + u8 data64[AES_128_KEY_SIZE / sizeof(u64)]; + }; }; +static_assert(alignof(AccessKey) == alignof(u8), "KeySource definition!"); enum SplServiceCmd { /* 1.0.0+ */ @@ -110,7 +121,7 @@ enum SplServiceCmd { Spl_Cmd_UnwrapCommonTitleKey = 20, Spl_Cmd_AllocateAesKeyslot = 21, Spl_Cmd_FreeAesKeyslot = 22, - Spl_Cmd_GetAesKeyslotEvent = 23, + Spl_Cmd_GetAesKeyslotAvailableEvent = 23, /* 3.0.0+ */ Spl_Cmd_SetBootReason = 24,