mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-06-04 00:28:51 -04:00
spl: refactor for accuracy/move into libstrat
This commit is contained in:
parent
4758dfa933
commit
d8a36e39f2
40 changed files with 1898 additions and 1732 deletions
|
@ -1,944 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
#include "spl_ctr_drbg.hpp"
|
||||
#include "spl_key_slot_cache.hpp"
|
||||
|
||||
namespace ams::spl::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Convenient defines. */
|
||||
constexpr size_t DeviceAddressSpaceAlign = 0x400000;
|
||||
constexpr u32 WorkBufferMapBase = 0x80000000u;
|
||||
constexpr u32 ComputeAesInMapBase = 0x90000000u;
|
||||
constexpr u32 ComputeAesOutMapBase = 0xC0000000u;
|
||||
constexpr size_t ComputeAesSizeMax = static_cast<size_t>(ComputeAesOutMapBase - ComputeAesInMapBase);
|
||||
|
||||
constexpr size_t RsaPrivateKeySize = 0x100;
|
||||
constexpr size_t DeviceUniqueDataMetaSize = 0x30;
|
||||
constexpr size_t LabelDigestSizeMax = 0x20;
|
||||
|
||||
constexpr size_t WorkBufferSizeMax = 0x800;
|
||||
|
||||
constexpr s32 MaxPhysicalAesKeySlots = 6;
|
||||
constexpr s32 MaxPhysicalAesKeySlotsDeprecated = 4;
|
||||
|
||||
constexpr s32 MaxVirtualAesKeySlots = 9;
|
||||
|
||||
/* KeySlot management. */
|
||||
constinit KeySlotCache g_keyslot_cache;
|
||||
constinit util::optional<KeySlotCacheEntry> g_keyslot_cache_entry[MaxPhysicalAesKeySlots];
|
||||
|
||||
inline s32 GetMaxPhysicalKeySlots() {
|
||||
return (hos::GetVersion() >= hos::Version_6_0_0) ? MaxPhysicalAesKeySlots : MaxPhysicalAesKeySlotsDeprecated;
|
||||
}
|
||||
|
||||
constexpr s32 VirtualKeySlotMin = 16;
|
||||
constexpr s32 VirtualKeySlotMax = VirtualKeySlotMin + MaxVirtualAesKeySlots - 1;
|
||||
|
||||
constexpr inline bool IsVirtualKeySlot(s32 keyslot) {
|
||||
return VirtualKeySlotMin <= keyslot && keyslot <= VirtualKeySlotMax;
|
||||
}
|
||||
|
||||
inline bool IsPhysicalKeySlot(s32 keyslot) {
|
||||
return keyslot < GetMaxPhysicalKeySlots();
|
||||
}
|
||||
|
||||
constexpr inline s32 GetVirtualKeySlotIndex(s32 keyslot) {
|
||||
AMS_ASSERT(IsVirtualKeySlot(keyslot));
|
||||
return keyslot - VirtualKeySlotMin;
|
||||
}
|
||||
|
||||
constexpr inline s32 MakeVirtualKeySlot(s32 index) {
|
||||
const s32 virt_slot = index + VirtualKeySlotMin;
|
||||
AMS_ASSERT(IsVirtualKeySlot(virt_slot));
|
||||
return virt_slot;
|
||||
}
|
||||
|
||||
void InitializeKeySlotCache() {
|
||||
for (s32 i = 0; i < MaxPhysicalAesKeySlots; i++) {
|
||||
g_keyslot_cache_entry[i].emplace(i);
|
||||
g_keyslot_cache.AddEntry(std::addressof(g_keyslot_cache_entry[i].value()));
|
||||
}
|
||||
}
|
||||
|
||||
enum class KeySlotContentType {
|
||||
None = 0,
|
||||
AesKey = 1,
|
||||
PreparedKey = 2,
|
||||
};
|
||||
|
||||
struct KeySlotContents {
|
||||
KeySlotContentType type;
|
||||
union {
|
||||
struct {
|
||||
AccessKey access_key;
|
||||
KeySource key_source;
|
||||
} aes_key;
|
||||
struct {
|
||||
AccessKey access_key;
|
||||
} prepared_key;
|
||||
};
|
||||
};
|
||||
|
||||
constinit const void *g_keyslot_owners[MaxVirtualAesKeySlots];
|
||||
constinit KeySlotContents g_keyslot_contents[MaxVirtualAesKeySlots];
|
||||
constinit KeySlotContents g_physical_keyslot_contents_for_backwards_compatibility[MaxPhysicalAesKeySlots];
|
||||
|
||||
void ClearPhysicalKeySlot(s32 keyslot) {
|
||||
AMS_ASSERT(IsPhysicalKeySlot(keyslot));
|
||||
|
||||
AccessKey access_key = {};
|
||||
KeySource key_source = {};
|
||||
smc::LoadAesKey(keyslot, access_key, key_source);
|
||||
}
|
||||
|
||||
s32 GetPhysicalKeySlot(s32 keyslot, bool load) {
|
||||
s32 phys_slot = -1;
|
||||
KeySlotContents *contents = nullptr;
|
||||
|
||||
if (hos::GetVersion() == hos::Version_1_0_0 && IsPhysicalKeySlot(keyslot)) {
|
||||
/* On 1.0.0, we allow the use of physical keyslots. */
|
||||
phys_slot = keyslot;
|
||||
contents = std::addressof(g_physical_keyslot_contents_for_backwards_compatibility[phys_slot]);
|
||||
|
||||
/* If the physical slot is already loaded, we're good. */
|
||||
if (g_keyslot_cache.FindPhysical(phys_slot)) {
|
||||
return phys_slot;
|
||||
}
|
||||
} else {
|
||||
/* This should be a virtual keyslot. */
|
||||
AMS_ASSERT(IsVirtualKeySlot(keyslot));
|
||||
|
||||
/* Try to find a physical slot in the cache. */
|
||||
if (g_keyslot_cache.Find(std::addressof(phys_slot), keyslot)) {
|
||||
return phys_slot;
|
||||
}
|
||||
|
||||
/* Allocate a physical slot. */
|
||||
phys_slot = g_keyslot_cache.Allocate(keyslot);
|
||||
contents = std::addressof(g_keyslot_contents[GetVirtualKeySlotIndex(keyslot)]);
|
||||
}
|
||||
|
||||
/* Ensure the contents of the keyslot. */
|
||||
if (load) {
|
||||
switch (contents->type) {
|
||||
case KeySlotContentType::None:
|
||||
ClearPhysicalKeySlot(phys_slot);
|
||||
break;
|
||||
case KeySlotContentType::AesKey:
|
||||
R_ABORT_UNLESS(smc::ConvertResult(smc::LoadAesKey(phys_slot, contents->aes_key.access_key, contents->aes_key.key_source)));
|
||||
break;
|
||||
case KeySlotContentType::PreparedKey:
|
||||
R_ABORT_UNLESS(smc::ConvertResult(smc::LoadPreparedAesKey(phys_slot, contents->prepared_key.access_key)));
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
return phys_slot;
|
||||
}
|
||||
|
||||
Result LoadVirtualAesKey(s32 keyslot, const AccessKey &access_key, const KeySource &key_source) {
|
||||
/* Ensure we can load into the slot. */
|
||||
const s32 phys_slot = GetPhysicalKeySlot(keyslot, false);
|
||||
R_TRY(smc::ConvertResult(smc::LoadAesKey(phys_slot, access_key, key_source)));
|
||||
|
||||
/* Update our contents. */
|
||||
const s32 index = GetVirtualKeySlotIndex(keyslot);
|
||||
|
||||
g_keyslot_contents[index].type = KeySlotContentType::AesKey;
|
||||
g_keyslot_contents[index].aes_key.access_key = access_key;
|
||||
g_keyslot_contents[index].aes_key.key_source = key_source;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LoadVirtualPreparedAesKey(s32 keyslot, const AccessKey &access_key) {
|
||||
/* Ensure we can load into the slot. */
|
||||
const s32 phys_slot = GetPhysicalKeySlot(keyslot, false);
|
||||
R_TRY(smc::ConvertResult(smc::LoadPreparedAesKey(phys_slot, access_key)));
|
||||
|
||||
/* Update our contents. */
|
||||
const s32 index = GetVirtualKeySlotIndex(keyslot);
|
||||
|
||||
g_keyslot_contents[index].type = KeySlotContentType::PreparedKey;
|
||||
g_keyslot_contents[index].prepared_key.access_key = access_key;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* Type definitions. */
|
||||
class ScopedAesKeySlot {
|
||||
private:
|
||||
s32 m_slot;
|
||||
bool m_has_slot;
|
||||
public:
|
||||
ScopedAesKeySlot() : m_slot(-1), m_has_slot(false) {
|
||||
/* ... */
|
||||
}
|
||||
~ScopedAesKeySlot() {
|
||||
if (m_has_slot) {
|
||||
DeallocateAesKeySlot(m_slot, this);
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetKeySlot() const {
|
||||
return m_slot;
|
||||
}
|
||||
|
||||
Result Allocate() {
|
||||
R_TRY(AllocateAesKeySlot(std::addressof(m_slot), this));
|
||||
m_has_slot = true;
|
||||
return ResultSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
struct SeLinkedListEntry {
|
||||
u32 num_entries;
|
||||
u32 address;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct SeCryptContext {
|
||||
SeLinkedListEntry in;
|
||||
SeLinkedListEntry out;
|
||||
};
|
||||
|
||||
class DeviceAddressSpaceMapHelper {
|
||||
private:
|
||||
os::NativeHandle m_handle;
|
||||
u64 m_dst_addr;
|
||||
u64 m_src_addr;
|
||||
size_t m_size;
|
||||
svc::MemoryPermission m_perm;
|
||||
public:
|
||||
DeviceAddressSpaceMapHelper(os::NativeHandle h, u64 dst, u64 src, size_t sz, svc::MemoryPermission p) : m_handle(h), m_dst_addr(dst), m_src_addr(src), m_size(sz), m_perm(p) {
|
||||
R_ABORT_UNLESS(svc::MapDeviceAddressSpaceAligned(m_handle, dd::GetCurrentProcessHandle(), m_src_addr, m_size, m_dst_addr, m_perm));
|
||||
}
|
||||
~DeviceAddressSpaceMapHelper() {
|
||||
R_ABORT_UNLESS(svc::UnmapDeviceAddressSpace(m_handle, dd::GetCurrentProcessHandle(), m_src_addr, m_size, m_dst_addr));
|
||||
}
|
||||
};
|
||||
|
||||
/* Global variables. */
|
||||
constinit CtrDrbg g_drbg;
|
||||
constinit os::InterruptEventType g_se_event;
|
||||
constinit os::SystemEventType g_se_keyslot_available_event;
|
||||
|
||||
constinit os::NativeHandle g_se_das_hnd = os::InvalidNativeHandle;
|
||||
constinit u32 g_se_mapped_work_buffer_addr;
|
||||
alignas(os::MemoryPageSize) constinit u8 g_work_buffer[2 * WorkBufferSizeMax];
|
||||
|
||||
constinit os::SdkMutex g_async_op_lock;
|
||||
|
||||
constinit BootReasonValue g_boot_reason;
|
||||
constinit 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];
|
||||
AMS_ABORT_UNLESS(smc::GenerateRandomBytes(seed, sizeof(seed)) == smc::Result::Success);
|
||||
|
||||
g_drbg.Initialize(seed);
|
||||
}
|
||||
|
||||
void InitializeSeEvents() {
|
||||
u64 irq_num;
|
||||
AMS_ABORT_UNLESS(smc::GetConfig(std::addressof(irq_num), 1, ConfigItem::SecurityEngineInterruptNumber) == smc::Result::Success);
|
||||
os::InitializeInterruptEvent(std::addressof(g_se_event), irq_num, os::EventClearMode_AutoClear);
|
||||
|
||||
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_se_keyslot_available_event), os::EventClearMode_AutoClear, true));
|
||||
os::SignalSystemEvent(std::addressof(g_se_keyslot_available_event));
|
||||
}
|
||||
|
||||
void InitializeDeviceAddressSpace() {
|
||||
|
||||
/* Create Address Space. */
|
||||
R_ABORT_UNLESS(svc::CreateDeviceAddressSpace(std::addressof(g_se_das_hnd), 0, (1ul << 32)));
|
||||
|
||||
/* Attach it to the SE. */
|
||||
R_ABORT_UNLESS(svc::AttachDeviceAddressSpace(svc::DeviceName_Se, g_se_das_hnd));
|
||||
|
||||
const u64 work_buffer_addr = reinterpret_cast<u64>(g_work_buffer);
|
||||
g_se_mapped_work_buffer_addr = WorkBufferMapBase + (work_buffer_addr % DeviceAddressSpaceAlign);
|
||||
|
||||
/* Map the work buffer for the SE. */
|
||||
R_ABORT_UNLESS(svc::MapDeviceAddressSpaceAligned(g_se_das_hnd, dd::GetCurrentProcessHandle(), work_buffer_addr, sizeof(g_work_buffer), g_se_mapped_work_buffer_addr, svc::MemoryPermission_ReadWrite));
|
||||
}
|
||||
|
||||
/* 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() {
|
||||
os::WaitInterruptEvent(std::addressof(g_se_event));
|
||||
}
|
||||
|
||||
smc::Result WaitCheckStatus(smc::AsyncOperationKey op_key) {
|
||||
WaitSeOperationComplete();
|
||||
|
||||
smc::Result op_res;
|
||||
smc::Result res = smc::GetResult(std::addressof(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::GetResultData(std::addressof(op_res), out_buf, out_buf_size, op_key);
|
||||
if (res != smc::Result::Success) {
|
||||
return res;
|
||||
}
|
||||
|
||||
return op_res;
|
||||
}
|
||||
|
||||
/* Internal KeySlot utility. */
|
||||
Result ValidateAesKeySlot(s32 keyslot, const void *owner) {
|
||||
/* Allow the use of physical keyslots on 1.0.0. */
|
||||
if (hos::GetVersion() == hos::Version_1_0_0) {
|
||||
R_SUCCEED_IF(IsPhysicalKeySlot(keyslot));
|
||||
}
|
||||
|
||||
R_UNLESS(IsVirtualKeySlot(keyslot), spl::ResultInvalidKeySlot());
|
||||
|
||||
const s32 index = GetVirtualKeySlotIndex(keyslot);
|
||||
R_UNLESS(g_keyslot_owners[index] == owner, spl::ResultInvalidKeySlot());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* Helper to do a single AES block decryption. */
|
||||
smc::Result DecryptAesBlock(s32 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<DecryptAesBlockLayout *>(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));
|
||||
|
||||
os::FlushDataCache(layout, sizeof(*layout));
|
||||
{
|
||||
std::scoped_lock lk(g_async_op_lock);
|
||||
smc::AsyncOperationKey op_key;
|
||||
const IvCtr iv_ctr = {};
|
||||
const u32 mode = smc::GetComputeAesMode(smc::CipherMode::CbcDecrypt, GetPhysicalKeySlot(keyslot, true));
|
||||
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::ComputeAes(std::addressof(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;
|
||||
}
|
||||
}
|
||||
os::FlushDataCache(layout, sizeof(*layout));
|
||||
|
||||
std::memcpy(dst, layout->out_block, sizeof(layout->out_block));
|
||||
return smc::Result::Success;
|
||||
}
|
||||
|
||||
/* Implementation wrappers for API commands. */
|
||||
Result DecryptAndStoreDeviceUniqueKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||
struct DecryptAndStoreDeviceUniqueKeyLayout {
|
||||
u8 data[DeviceUniqueDataMetaSize + 2 * RsaPrivateKeySize + 0x10];
|
||||
};
|
||||
DecryptAndStoreDeviceUniqueKeyLayout *layout = reinterpret_cast<DecryptAndStoreDeviceUniqueKeyLayout *>(g_work_buffer);
|
||||
|
||||
/* Validate size. */
|
||||
R_UNLESS(src_size <= sizeof(DecryptAndStoreDeviceUniqueKeyLayout), spl::ResultInvalidSize());
|
||||
std::memcpy(layout, src, src_size);
|
||||
|
||||
os::FlushDataCache(layout, sizeof(*layout));
|
||||
smc::Result smc_res;
|
||||
if (hos::GetVersion() >= hos::Version_5_0_0) {
|
||||
smc_res = smc::DecryptDeviceUniqueData(layout->data, src_size, access_key, key_source, static_cast<smc::DeviceUniqueDataMode>(option));
|
||||
} else {
|
||||
smc_res = smc::DecryptAndStoreGcKey(layout->data, src_size, access_key, key_source, option);
|
||||
}
|
||||
|
||||
return smc::ConvertResult(smc_res);
|
||||
}
|
||||
|
||||
Result ModularExponentiateWithStorageKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size, smc::ModularExponentiateWithStorageKeyMode mode) {
|
||||
struct ModularExponentiateWithStorageKeyLayout {
|
||||
u8 base[0x100];
|
||||
u8 mod[0x100];
|
||||
};
|
||||
ModularExponentiateWithStorageKeyLayout *layout = reinterpret_cast<ModularExponentiateWithStorageKeyLayout *>(g_work_buffer);
|
||||
|
||||
/* Validate sizes. */
|
||||
R_UNLESS(base_size <= sizeof(layout->base), spl::ResultInvalidSize());
|
||||
R_UNLESS(mod_size <= sizeof(layout->mod), spl::ResultInvalidSize());
|
||||
R_UNLESS(out_size <= WorkBufferSizeMax, spl::ResultInvalidSize());
|
||||
|
||||
/* 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. */
|
||||
os::FlushDataCache(layout, sizeof(*layout));
|
||||
{
|
||||
std::scoped_lock lk(g_async_op_lock);
|
||||
smc::AsyncOperationKey op_key;
|
||||
|
||||
smc::Result res = smc::ModularExponentiateWithStorageKey(std::addressof(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);
|
||||
}
|
||||
}
|
||||
os::FlushDataCache(g_work_buffer, sizeof(out_size));
|
||||
|
||||
std::memcpy(out, g_work_buffer, out_size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result PrepareEsDeviceUniqueKey(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::EsCommonKeyType type) {
|
||||
struct PrepareEsDeviceUniqueKeyLayout {
|
||||
u8 base[0x100];
|
||||
u8 mod[0x100];
|
||||
};
|
||||
PrepareEsDeviceUniqueKeyLayout *layout = reinterpret_cast<PrepareEsDeviceUniqueKeyLayout *>(g_work_buffer);
|
||||
|
||||
/* Validate sizes. */
|
||||
R_UNLESS(base_size <= sizeof(layout->base), spl::ResultInvalidSize());
|
||||
R_UNLESS(mod_size <= sizeof(layout->mod), spl::ResultInvalidSize());
|
||||
R_UNLESS(label_digest_size <= LabelDigestSizeMax, spl::ResultInvalidSize());
|
||||
|
||||
/* 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. */
|
||||
os::FlushDataCache(layout, sizeof(*layout));
|
||||
{
|
||||
std::scoped_lock lk(g_async_op_lock);
|
||||
smc::AsyncOperationKey op_key;
|
||||
|
||||
smc::Result res = smc::PrepareEsDeviceUniqueKey(std::addressof(op_key), layout->base, layout->mod, label_digest, label_digest_size, smc::GetPrepareEsDeviceUniqueKeyOption(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);
|
||||
}
|
||||
}
|
||||
os::FlushDataCache(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();
|
||||
|
||||
/* Initialize the keyslot cache. */
|
||||
InitializeKeySlotCache();
|
||||
}
|
||||
|
||||
/* General. */
|
||||
Result GetConfig(u64 *out, ConfigItem which) {
|
||||
/* Nintendo explicitly blacklists package2 hash here, amusingly. */
|
||||
/* This is not blacklisted in safemode, but we're never in safe mode... */
|
||||
R_UNLESS(which != ConfigItem::Package2Hash, spl::ResultInvalidArgument());
|
||||
|
||||
smc::Result res = smc::GetConfig(out, 1, which);
|
||||
|
||||
/* Nintendo has some special handling here for hardware type/is_retail. */
|
||||
if (res == smc::Result::InvalidArgument) {
|
||||
switch (which) {
|
||||
case ConfigItem::HardwareType:
|
||||
*out = static_cast<u64>(HardwareType::Icosa);
|
||||
res = smc::Result::Success;
|
||||
break;
|
||||
case ConfigItem::HardwareState:
|
||||
*out = HardwareState_Development;
|
||||
res = smc::Result::Success;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return smc::ConvertResult(res);
|
||||
}
|
||||
|
||||
Result ModularExponentiate(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 ModularExponentiateLayout {
|
||||
u8 base[0x100];
|
||||
u8 exp[0x100];
|
||||
u8 mod[0x100];
|
||||
};
|
||||
ModularExponentiateLayout *layout = reinterpret_cast<ModularExponentiateLayout *>(g_work_buffer);
|
||||
|
||||
/* Validate sizes. */
|
||||
R_UNLESS(base_size <= sizeof(layout->base), spl::ResultInvalidSize());
|
||||
R_UNLESS(exp_size <= sizeof(layout->exp), spl::ResultInvalidSize());
|
||||
R_UNLESS(mod_size <= sizeof(layout->mod), spl::ResultInvalidSize());
|
||||
R_UNLESS(out_size <= WorkBufferSizeMax, spl::ResultInvalidSize());
|
||||
|
||||
/* 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. */
|
||||
os::FlushDataCache(layout, sizeof(*layout));
|
||||
{
|
||||
std::scoped_lock lk(g_async_op_lock);
|
||||
smc::AsyncOperationKey op_key;
|
||||
|
||||
smc::Result res = smc::ModularExponentiate(std::addressof(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);
|
||||
}
|
||||
}
|
||||
os::FlushDataCache(g_work_buffer, sizeof(out_size));
|
||||
|
||||
std::memcpy(out, g_work_buffer, out_size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SetConfig(ConfigItem which, u64 value) {
|
||||
return smc::ConvertResult(smc::SetConfig(which, std::addressof(value), 1));
|
||||
}
|
||||
|
||||
Result GenerateRandomBytes(void *out, size_t size) {
|
||||
u8 *cur_dst = reinterpret_cast<u8 *>(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 hardware_state;
|
||||
R_TRY(impl::GetConfig(std::addressof(hardware_state), ConfigItem::HardwareState));
|
||||
|
||||
*out = (hardware_state == HardwareState_Development);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SetBootReason(BootReasonValue boot_reason) {
|
||||
R_UNLESS(!IsBootReasonSet(), spl::ResultBootReasonAlreadySet());
|
||||
|
||||
g_boot_reason = boot_reason;
|
||||
g_boot_reason_set = true;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetBootReason(BootReasonValue *out) {
|
||||
R_UNLESS(IsBootReasonSet(), spl::ResultBootReasonNotSet());
|
||||
|
||||
*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(s32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source) {
|
||||
R_TRY(ValidateAesKeySlot(keyslot, owner));
|
||||
return LoadVirtualAesKey(keyslot, access_key, key_source);
|
||||
}
|
||||
|
||||
Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) {
|
||||
static constexpr 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());
|
||||
|
||||
R_TRY(LoadVirtualAesKey(keyslot_holder.GetKeySlot(), access_key, s_generate_aes_key_source));
|
||||
|
||||
return smc::ConvertResult(DecryptAesBlock(keyslot_holder.GetKeySlot(), out_key, std::addressof(key_source)));
|
||||
}
|
||||
|
||||
Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option) {
|
||||
static constexpr 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(std::addressof(access_key), s_decrypt_aes_key_source, generation, option));
|
||||
|
||||
return GenerateAesKey(out_key, access_key, key_source);
|
||||
}
|
||||
|
||||
Result ComputeCtr(void *dst, size_t dst_size, s32 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. */
|
||||
R_UNLESS(src_size <= dst_size, spl::ResultInvalidSize());
|
||||
R_UNLESS(util::IsAligned(src_size, AES_BLOCK_SIZE), spl::ResultInvalidSize());
|
||||
|
||||
/* 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<uintptr_t>(src);
|
||||
const uintptr_t dst_addr = reinterpret_cast<uintptr_t>(dst);
|
||||
const uintptr_t src_addr_page_aligned = util::AlignDown(src_addr, os::MemoryPageSize);
|
||||
const uintptr_t dst_addr_page_aligned = util::AlignDown(dst_addr, os::MemoryPageSize);
|
||||
const size_t src_size_page_aligned = util::AlignUp(src_addr + src_size, os::MemoryPageSize) - src_addr_page_aligned;
|
||||
const size_t dst_size_page_aligned = util::AlignUp(dst_addr + dst_size, os::MemoryPageSize) - dst_addr_page_aligned;
|
||||
const u32 src_se_map_addr = ComputeAesInMapBase + (src_addr_page_aligned % DeviceAddressSpaceAlign);
|
||||
const u32 dst_se_map_addr = ComputeAesOutMapBase + (dst_addr_page_aligned % DeviceAddressSpaceAlign);
|
||||
const u32 src_se_addr = ComputeAesInMapBase + (src_addr % DeviceAddressSpaceAlign);
|
||||
const u32 dst_se_addr = ComputeAesOutMapBase + (dst_addr % DeviceAddressSpaceAlign);
|
||||
|
||||
/* Validate aligned sizes. */
|
||||
R_UNLESS(src_size_page_aligned <= ComputeAesSizeMax, spl::ResultInvalidSize());
|
||||
R_UNLESS(dst_size_page_aligned <= ComputeAesSizeMax, spl::ResultInvalidSize());
|
||||
|
||||
/* Helpers for mapping/unmapping. */
|
||||
DeviceAddressSpaceMapHelper in_mapper(g_se_das_hnd, src_se_map_addr, src_addr_page_aligned, src_size_page_aligned, svc::MemoryPermission_Read);
|
||||
DeviceAddressSpaceMapHelper out_mapper(g_se_das_hnd, dst_se_map_addr, dst_addr_page_aligned, dst_size_page_aligned, svc::MemoryPermission_Write);
|
||||
|
||||
/* Setup SE linked list entries. */
|
||||
SeCryptContext *crypt_ctx = reinterpret_cast<SeCryptContext *>(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;
|
||||
|
||||
os::FlushDataCache(crypt_ctx, sizeof(*crypt_ctx));
|
||||
os::FlushDataCache(const_cast<void *>(src), src_size);
|
||||
os::FlushDataCache(dst, dst_size);
|
||||
{
|
||||
std::scoped_lock lk(g_async_op_lock);
|
||||
smc::AsyncOperationKey op_key;
|
||||
const u32 mode = smc::GetComputeAesMode(smc::CipherMode::Ctr, GetPhysicalKeySlot(keyslot, true));
|
||||
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::ComputeAes(std::addressof(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);
|
||||
}
|
||||
}
|
||||
os::FlushDataCache(dst, dst_size);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ComputeCmac(Cmac *out_cmac, s32 keyslot, const void *owner, const void *data, size_t size) {
|
||||
R_TRY(ValidateAesKeySlot(keyslot, owner));
|
||||
|
||||
R_UNLESS(size <= WorkBufferSizeMax, spl::ResultInvalidSize());
|
||||
|
||||
std::memcpy(g_work_buffer, data, size);
|
||||
return smc::ConvertResult(smc::ComputeCmac(out_cmac, GetPhysicalKeySlot(keyslot, true), g_work_buffer, size));
|
||||
}
|
||||
|
||||
Result AllocateAesKeySlot(s32 *out_keyslot, const void *owner) {
|
||||
/* Find a virtual keyslot. */
|
||||
for (s32 i = 0; i < MaxVirtualAesKeySlots; i++) {
|
||||
if (g_keyslot_owners[i] == nullptr) {
|
||||
g_keyslot_owners[i] = owner;
|
||||
g_keyslot_contents[i] = { .type = KeySlotContentType::None };
|
||||
*out_keyslot = MakeVirtualKeySlot(i);
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
os::ClearSystemEvent(std::addressof(g_se_keyslot_available_event));
|
||||
return spl::ResultOutOfKeySlots();
|
||||
}
|
||||
|
||||
Result DeallocateAesKeySlot(s32 keyslot, const void *owner) {
|
||||
/* Only virtual keyslots can be freed. */
|
||||
R_UNLESS(IsVirtualKeySlot(keyslot), spl::ResultInvalidKeySlot());
|
||||
|
||||
/* Ensure the keyslot is owned. */
|
||||
R_TRY(ValidateAesKeySlot(keyslot, owner));
|
||||
|
||||
/* Clear the physical keyslot, if we're cached. */
|
||||
s32 phys_slot;
|
||||
if (g_keyslot_cache.Release(std::addressof(phys_slot), keyslot)) {
|
||||
ClearPhysicalKeySlot(phys_slot);
|
||||
}
|
||||
|
||||
/* Clear the virtual keyslot. */
|
||||
const auto index = GetVirtualKeySlotIndex(keyslot);
|
||||
g_keyslot_owners[index] = nullptr;
|
||||
g_keyslot_contents[index].type = KeySlotContentType::None;
|
||||
|
||||
os::SignalSystemEvent(std::addressof(g_se_keyslot_available_event));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* RSA. */
|
||||
Result DecryptDeviceUniqueData(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||
struct DecryptDeviceUniqueDataLayout {
|
||||
u8 data[RsaPrivateKeySize + DeviceUniqueDataMetaSize];
|
||||
};
|
||||
DecryptDeviceUniqueDataLayout *layout = reinterpret_cast<DecryptDeviceUniqueDataLayout *>(g_work_buffer);
|
||||
|
||||
/* Validate size. */
|
||||
R_UNLESS(src_size >= DeviceUniqueDataMetaSize, spl::ResultInvalidSize());
|
||||
R_UNLESS(src_size <= sizeof(DecryptDeviceUniqueDataLayout), spl::ResultInvalidSize());
|
||||
|
||||
std::memcpy(layout->data, src, src_size);
|
||||
os::FlushDataCache(layout, sizeof(*layout));
|
||||
|
||||
smc::Result smc_res;
|
||||
size_t copy_size = 0;
|
||||
if (hos::GetVersion() >= hos::Version_5_0_0) {
|
||||
copy_size = std::min(dst_size, src_size - DeviceUniqueDataMetaSize);
|
||||
smc_res = smc::DecryptDeviceUniqueData(layout->data, src_size, access_key, key_source, static_cast<smc::DeviceUniqueDataMode>(option));
|
||||
} else {
|
||||
smc_res = smc::DecryptDeviceUniqueData(std::addressof(copy_size), layout->data, src_size, access_key, key_source, option);
|
||||
copy_size = std::min(dst_size, copy_size);
|
||||
}
|
||||
|
||||
os::FlushDataCache(layout, sizeof(*layout));
|
||||
if (smc_res == smc::Result::Success) {
|
||||
std::memcpy(dst, layout->data, copy_size);
|
||||
}
|
||||
|
||||
return smc::ConvertResult(smc_res);
|
||||
}
|
||||
|
||||
/* SSL */
|
||||
Result DecryptAndStoreSslClientCertKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) {
|
||||
return DecryptAndStoreDeviceUniqueKey(src, src_size, access_key, key_source, static_cast<u32>(smc::DeviceUniqueDataMode::DecryptAndStoreSslKey));
|
||||
}
|
||||
|
||||
Result ModularExponentiateWithSslClientCertKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) {
|
||||
return ModularExponentiateWithStorageKey(out, out_size, base, base_size, mod, mod_size, smc::ModularExponentiateWithStorageKeyMode::Ssl);
|
||||
}
|
||||
|
||||
/* ES */
|
||||
Result LoadEsDeviceKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||
if (hos::GetVersion() >= hos::Version_5_0_0) {
|
||||
return DecryptAndStoreDeviceUniqueKey(src, src_size, access_key, key_source, option);
|
||||
} else {
|
||||
struct LoadEsDeviceKeyLayout {
|
||||
u8 data[DeviceUniqueDataMetaSize + 2 * RsaPrivateKeySize + 0x10];
|
||||
};
|
||||
LoadEsDeviceKeyLayout *layout = reinterpret_cast<LoadEsDeviceKeyLayout *>(g_work_buffer);
|
||||
|
||||
/* Validate size. */
|
||||
R_UNLESS(src_size <= sizeof(LoadEsDeviceKeyLayout), spl::ResultInvalidSize());
|
||||
|
||||
std::memcpy(layout, src, src_size);
|
||||
|
||||
os::FlushDataCache(layout, sizeof(*layout));
|
||||
return smc::ConvertResult(smc::LoadEsDeviceKey(layout->data, src_size, access_key, key_source, option));
|
||||
}
|
||||
}
|
||||
|
||||
Result PrepareEsTitleKey(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 PrepareEsDeviceUniqueKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsCommonKeyType::TitleKey);
|
||||
}
|
||||
|
||||
Result PrepareCommonEsTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation) {
|
||||
return smc::ConvertResult(smc::PrepareCommonEsTitleKey(out_access_key, key_source, generation));
|
||||
}
|
||||
|
||||
Result DecryptAndStoreDrmDeviceCertKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) {
|
||||
return DecryptAndStoreDeviceUniqueKey(src, src_size, access_key, key_source, static_cast<u32>(smc::DeviceUniqueDataMode::DecryptAndStoreDrmDeviceCertKey));
|
||||
}
|
||||
|
||||
Result ModularExponentiateWithDrmDeviceCertKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) {
|
||||
return ModularExponentiateWithStorageKey(out, out_size, base, base_size, mod, mod_size, smc::ModularExponentiateWithStorageKeyMode::DrmDeviceCert);
|
||||
}
|
||||
|
||||
Result PrepareEsArchiveKey(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 PrepareEsDeviceUniqueKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsCommonKeyType::ArchiveKey);
|
||||
}
|
||||
|
||||
/* FS */
|
||||
Result DecryptAndStoreGcKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||
return DecryptAndStoreDeviceUniqueKey(src, src_size, access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result DecryptGcMessage(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. */
|
||||
R_UNLESS(dst_size <= WorkBufferSizeMax, spl::ResultInvalidSize());
|
||||
R_UNLESS(label_digest_size == LabelDigestSizeMax, spl::ResultInvalidSize());
|
||||
|
||||
/* Nintendo doesn't check this result code, but we will. */
|
||||
R_TRY(ModularExponentiateWithStorageKey(g_work_buffer, 0x100, base, base_size, mod, mod_size, smc::ModularExponentiateWithStorageKeyMode::Gc));
|
||||
|
||||
size_t data_size = crypto::DecodeRsa2048OaepSha256(dst, dst_size, label_digest, label_digest_size, g_work_buffer, 0x100);
|
||||
R_UNLESS(data_size > 0, spl::ResultDecryptionFailed());
|
||||
|
||||
*out_size = static_cast<u32>(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 LoadPreparedAesKey(s32 keyslot, const void *owner, const AccessKey &access_key) {
|
||||
R_TRY(ValidateAesKeySlot(keyslot, owner));
|
||||
return LoadVirtualPreparedAesKey(keyslot, access_key);
|
||||
}
|
||||
|
||||
Result GetPackage2Hash(void *dst, const size_t size) {
|
||||
u64 hash[4];
|
||||
R_UNLESS(size >= sizeof(hash), spl::ResultInvalidSize());
|
||||
|
||||
smc::Result smc_res;
|
||||
if ((smc_res = smc::GetConfig(hash, 4, ConfigItem::Package2Hash)) != smc::Result::Success) {
|
||||
return smc::ConvertResult(smc_res);
|
||||
}
|
||||
|
||||
std::memcpy(dst, hash, sizeof(hash));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* Manu. */
|
||||
Result ReencryptDeviceUniqueData(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 ReencryptDeviceUniqueDataLayout {
|
||||
u8 data[DeviceUniqueDataMetaSize + 2 * RsaPrivateKeySize + 0x10];
|
||||
AccessKey access_key_dec;
|
||||
KeySource source_dec;
|
||||
AccessKey access_key_enc;
|
||||
KeySource source_enc;
|
||||
};
|
||||
ReencryptDeviceUniqueDataLayout *layout = reinterpret_cast<ReencryptDeviceUniqueDataLayout *>(g_work_buffer);
|
||||
|
||||
/* Validate size. */
|
||||
R_UNLESS(src_size >= DeviceUniqueDataMetaSize, spl::ResultInvalidSize());
|
||||
R_UNLESS(src_size <= sizeof(ReencryptDeviceUniqueDataLayout), spl::ResultInvalidSize());
|
||||
|
||||
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;
|
||||
|
||||
os::FlushDataCache(layout, sizeof(*layout));
|
||||
|
||||
smc::Result smc_res = smc::ReencryptDeviceUniqueData(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);
|
||||
os::FlushDataCache(layout, copy_size);
|
||||
std::memcpy(dst, layout->data, copy_size);
|
||||
}
|
||||
|
||||
return smc::ConvertResult(smc_res);
|
||||
}
|
||||
|
||||
/* Helper. */
|
||||
Result DeallocateAllAesKeySlots(const void *owner) {
|
||||
for (s32 slot = VirtualKeySlotMin; slot <= VirtualKeySlotMax; ++slot) {
|
||||
if (g_keyslot_owners[GetVirtualKeySlotIndex(slot)] == owner) {
|
||||
DeallocateAesKeySlot(slot, owner);
|
||||
}
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
os::NativeHandle GetAesKeySlotAvailableEventHandle() {
|
||||
return os::GetReadableHandleOfSystemEvent(std::addressof(g_se_keyslot_available_event));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::spl::impl {
|
||||
|
||||
/* Initialization. */
|
||||
void Initialize();
|
||||
|
||||
/* General. */
|
||||
Result GetConfig(u64 *out, spl::ConfigItem which);
|
||||
Result ModularExponentiate(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(spl::ConfigItem 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(s32 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 ComputeCtr(void *dst, size_t dst_size, s32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr);
|
||||
Result ComputeCmac(Cmac *out_cmac, s32 keyslot, const void *owner, const void *data, size_t size);
|
||||
Result AllocateAesKeySlot(s32 *out_keyslot, const void *owner);
|
||||
Result DeallocateAesKeySlot(s32 keyslot, const void *owner);
|
||||
|
||||
/* RSA. */
|
||||
Result DecryptDeviceUniqueData(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 DecryptAndStoreSslClientCertKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
|
||||
Result ModularExponentiateWithSslClientCertKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size);
|
||||
|
||||
/* ES */
|
||||
Result LoadEsDeviceKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
||||
Result PrepareEsTitleKey(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 PrepareCommonEsTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation);
|
||||
Result DecryptAndStoreDrmDeviceCertKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
|
||||
Result ModularExponentiateWithDrmDeviceCertKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size);
|
||||
Result PrepareEsArchiveKey(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 LoadPreparedAesKey(s32 keyslot, const void *owner, const AccessKey &access_key);
|
||||
|
||||
/* FS */
|
||||
Result DecryptAndStoreGcKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
||||
Result DecryptGcMessage(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 LoadPreparedAesKey(s32 keyslot, const void *owner, const AccessKey &access_key);
|
||||
Result GetPackage2Hash(void *dst, const size_t size);
|
||||
|
||||
/* Manu. */
|
||||
Result ReencryptDeviceUniqueData(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 DeallocateAllAesKeySlots(const void *owner);
|
||||
os::NativeHandle GetAesKeySlotAvailableEventHandle();
|
||||
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
#include "spl_crypto_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
CryptoService::~CryptoService() {
|
||||
/* Free any keyslots this service is using. */
|
||||
impl::DeallocateAllAesKeySlots(this);
|
||||
}
|
||||
|
||||
Result CryptoService::GenerateAesKek(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option) {
|
||||
return impl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
||||
}
|
||||
|
||||
Result CryptoService::LoadAesKey(s32 keyslot, AccessKey access_key, KeySource key_source) {
|
||||
return impl::LoadAesKey(keyslot, this, access_key, key_source);
|
||||
}
|
||||
|
||||
Result CryptoService::GenerateAesKey(sf::Out<AesKey> out_key, AccessKey access_key, KeySource key_source) {
|
||||
return impl::GenerateAesKey(out_key.GetPointer(), access_key, key_source);
|
||||
}
|
||||
|
||||
Result CryptoService::DecryptAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option) {
|
||||
return impl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
||||
}
|
||||
|
||||
Result CryptoService::ComputeCtr(const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr) {
|
||||
return impl::ComputeCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
||||
}
|
||||
|
||||
Result CryptoService::ComputeCmac(sf::Out<Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf) {
|
||||
return impl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize());
|
||||
}
|
||||
|
||||
Result CryptoService::AllocateAesKeySlot(sf::Out<s32> out_keyslot) {
|
||||
return impl::AllocateAesKeySlot(out_keyslot.GetPointer(), this);
|
||||
}
|
||||
|
||||
Result CryptoService::DeallocateAesKeySlot(s32 keyslot) {
|
||||
return impl::DeallocateAesKeySlot(keyslot, this);
|
||||
}
|
||||
|
||||
Result CryptoService::GetAesKeySlotAvailableEvent(sf::OutCopyHandle out_hnd) {
|
||||
out_hnd.SetValue(impl::GetAesKeySlotAvailableEventHandle(), false);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
|
@ -14,24 +14,57 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_general_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class CryptoService : public GeneralService {
|
||||
public:
|
||||
virtual ~CryptoService();
|
||||
explicit CryptoService(SecureMonitorManager *manager) : GeneralService(manager) { /* ... */ }
|
||||
public:
|
||||
virtual ~CryptoService(){
|
||||
/* Free any keyslots this service is using. */
|
||||
m_manager.DeallocateAesKeySlots(this);
|
||||
}
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result GenerateAesKek(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option);
|
||||
Result LoadAesKey(s32 keyslot, AccessKey access_key, KeySource key_source);
|
||||
Result GenerateAesKey(sf::Out<AesKey> out_key, AccessKey access_key, KeySource key_source);
|
||||
Result DecryptAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option);
|
||||
Result ComputeCtr(const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr);
|
||||
Result ComputeCmac(sf::Out<Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf);
|
||||
Result AllocateAesKeySlot(sf::Out<s32> out_keyslot);
|
||||
Result DeallocateAesKeySlot(s32 keyslot);
|
||||
Result GetAesKeySlotAvailableEvent(sf::OutCopyHandle out_hnd);
|
||||
Result GenerateAesKek(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option) {
|
||||
return m_manager.GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
||||
}
|
||||
|
||||
Result LoadAesKey(s32 keyslot, AccessKey access_key, KeySource key_source) {
|
||||
return m_manager.LoadAesKey(keyslot, this, access_key, key_source);
|
||||
}
|
||||
|
||||
Result GenerateAesKey(sf::Out<AesKey> out_key, AccessKey access_key, KeySource key_source) {
|
||||
return m_manager.GenerateAesKey(out_key.GetPointer(), access_key, key_source);
|
||||
}
|
||||
|
||||
Result DecryptAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option) {
|
||||
return m_manager.DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
||||
}
|
||||
|
||||
Result ComputeCtr(const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr) {
|
||||
return m_manager.ComputeCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
||||
}
|
||||
|
||||
Result ComputeCmac(sf::Out<Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf) {
|
||||
return m_manager.ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize());
|
||||
}
|
||||
|
||||
Result AllocateAesKeySlot(sf::Out<s32> out_keyslot) {
|
||||
return m_manager.AllocateAesKeySlot(out_keyslot.GetPointer(), this);
|
||||
}
|
||||
|
||||
Result DeallocateAesKeySlot(s32 keyslot) {
|
||||
return m_manager.DeallocateAesKeySlot(keyslot, this);
|
||||
}
|
||||
|
||||
Result GetAesKeySlotAvailableEvent(sf::OutCopyHandle out_hnd) {
|
||||
out_hnd.SetValue(m_manager.GetAesKeySlotAvailableEvent()->GetReadableHandle(), false);
|
||||
return ResultSuccess();
|
||||
}
|
||||
};
|
||||
static_assert(spl::impl::IsICryptoInterface<CryptoService>);
|
||||
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_ctr_drbg.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
void CtrDrbg::Update(const void *data) {
|
||||
aes128ContextCreate(std::addressof(m_aes_ctx), m_key, true);
|
||||
for (size_t offset = 0; offset < sizeof(m_work[1]); offset += BlockSize) {
|
||||
IncrementCounter(m_counter);
|
||||
aes128EncryptBlock(std::addressof(m_aes_ctx), std::addressof(m_work[1][offset]), m_counter);
|
||||
}
|
||||
|
||||
Xor(m_work[1], data, sizeof(m_work[1]));
|
||||
|
||||
std::memcpy(m_key, std::addressof(m_work[1][0]), sizeof(m_key));
|
||||
std::memcpy(m_counter, std::addressof(m_work[1][BlockSize]), sizeof(m_key));
|
||||
}
|
||||
|
||||
void CtrDrbg::Initialize(const void *seed) {
|
||||
std::memcpy(m_work[0], seed, sizeof(m_work[0]));
|
||||
std::memset(m_key, 0, sizeof(m_key));
|
||||
std::memset(m_counter, 0, sizeof(m_counter));
|
||||
this->Update(m_work[0]);
|
||||
m_reseed_counter = 1;
|
||||
}
|
||||
|
||||
void CtrDrbg::Reseed(const void *seed) {
|
||||
std::memcpy(m_work[0], seed, sizeof(m_work[0]));
|
||||
this->Update(m_work[0]);
|
||||
m_reseed_counter = 1;
|
||||
}
|
||||
|
||||
bool CtrDrbg::GenerateRandomBytes(void *out, size_t size) {
|
||||
if (size > MaxRequestSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_reseed_counter > ReseedInterval) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aes128ContextCreate(std::addressof(m_aes_ctx), m_key, true);
|
||||
u8 *cur_dst = reinterpret_cast<u8 *>(out);
|
||||
|
||||
size_t aligned_size = (size & ~(BlockSize - 1));
|
||||
for (size_t offset = 0; offset < aligned_size; offset += BlockSize) {
|
||||
IncrementCounter(m_counter);
|
||||
aes128EncryptBlock(std::addressof(m_aes_ctx), cur_dst, m_counter);
|
||||
cur_dst += BlockSize;
|
||||
}
|
||||
|
||||
if (size > aligned_size) {
|
||||
IncrementCounter(m_counter);
|
||||
aes128EncryptBlock(std::addressof(m_aes_ctx), m_work[1], m_counter);
|
||||
std::memcpy(cur_dst, m_work[1], size - aligned_size);
|
||||
}
|
||||
|
||||
std::memset(m_work[0], 0, sizeof(m_work[0]));
|
||||
this->Update(m_work[0]);
|
||||
|
||||
m_reseed_counter++;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
/* 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 m_aes_ctx;
|
||||
u8 m_counter[BlockSize];
|
||||
u8 m_key[BlockSize];
|
||||
u8 m_work[2][SeedSize];
|
||||
u32 m_reseed_counter;
|
||||
private:
|
||||
static void Xor(void *dst, const void *src, size_t size) {
|
||||
const u8 *src_u8 = reinterpret_cast<const u8 *>(src);
|
||||
u8 *dst_u8 = reinterpret_cast<u8 *>(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<u64 *>(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);
|
||||
}
|
||||
}
|
||||
private:
|
||||
void Update(const void *data);
|
||||
public:
|
||||
void Initialize(const void *seed);
|
||||
void Reseed(const void *seed);
|
||||
bool GenerateRandomBytes(void *out, size_t size);
|
||||
};
|
||||
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
#include "spl_deprecated_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
DeprecatedService::~DeprecatedService() {
|
||||
/* Free any keyslots this service is using. */
|
||||
impl::DeallocateAllAesKeySlots(this);
|
||||
}
|
||||
|
||||
Result DeprecatedService::GetConfig(sf::Out<u64> out, u32 which) {
|
||||
return impl::GetConfig(out.GetPointer(), static_cast<spl::ConfigItem>(which));
|
||||
}
|
||||
|
||||
Result DeprecatedService::ModularExponentiate(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &exp, const sf::InPointerBuffer &mod) {
|
||||
return impl::ModularExponentiate(out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), exp.GetPointer(), exp.GetSize(), mod.GetPointer(), mod.GetSize());
|
||||
}
|
||||
|
||||
Result DeprecatedService::GenerateAesKek(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option) {
|
||||
return impl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
||||
}
|
||||
|
||||
Result DeprecatedService::LoadAesKey(s32 keyslot, AccessKey access_key, KeySource key_source) {
|
||||
return impl::LoadAesKey(keyslot, this, access_key, key_source);
|
||||
}
|
||||
|
||||
Result DeprecatedService::GenerateAesKey(sf::Out<AesKey> out_key, AccessKey access_key, KeySource key_source) {
|
||||
return impl::GenerateAesKey(out_key.GetPointer(), access_key, key_source);
|
||||
}
|
||||
|
||||
Result DeprecatedService::SetConfig(u32 which, u64 value) {
|
||||
return impl::SetConfig(static_cast<spl::ConfigItem>(which), value);
|
||||
}
|
||||
|
||||
Result DeprecatedService::GenerateRandomBytes(const sf::OutPointerBuffer &out) {
|
||||
return impl::GenerateRandomBytes(out.GetPointer(), out.GetSize());
|
||||
}
|
||||
|
||||
Result DeprecatedService::DecryptAndStoreGcKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return impl::DecryptAndStoreGcKey(src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result DeprecatedService::DecryptGcMessage(sf::Out<u32> out_size, const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest) {
|
||||
return impl::DecryptGcMessage(out_size.GetPointer(), out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize());
|
||||
}
|
||||
|
||||
Result DeprecatedService::IsDevelopment(sf::Out<bool> is_dev) {
|
||||
return impl::IsDevelopment(is_dev.GetPointer());
|
||||
}
|
||||
|
||||
Result DeprecatedService::GenerateSpecificAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which) {
|
||||
return impl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
|
||||
}
|
||||
|
||||
Result DeprecatedService::DecryptDeviceUniqueData(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return impl::DecryptDeviceUniqueData(dst.GetPointer(), dst.GetSize(), src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result DeprecatedService::DecryptAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option) {
|
||||
return impl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
||||
}
|
||||
|
||||
Result DeprecatedService::ComputeCtrDeprecated(const sf::OutBuffer &out_buf, s32 keyslot, const sf::InBuffer &in_buf, IvCtr iv_ctr) {
|
||||
return impl::ComputeCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
||||
}
|
||||
|
||||
Result DeprecatedService::ComputeCtr(const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr) {
|
||||
return impl::ComputeCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
||||
}
|
||||
|
||||
Result DeprecatedService::ComputeCmac(sf::Out<Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf) {
|
||||
return impl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize());
|
||||
}
|
||||
|
||||
Result DeprecatedService::LoadEsDeviceKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return impl::LoadEsDeviceKey(src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result DeprecatedService::PrepareEsTitleKeyDeprecated(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest) {
|
||||
return impl::PrepareEsTitleKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), 0);
|
||||
}
|
||||
|
||||
Result DeprecatedService::PrepareEsTitleKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation) {
|
||||
return impl::PrepareEsTitleKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), generation);
|
||||
}
|
||||
|
||||
Result DeprecatedService::LoadPreparedAesKey(s32 keyslot, AccessKey access_key) {
|
||||
return impl::LoadPreparedAesKey(keyslot, this, access_key);
|
||||
}
|
||||
|
||||
Result DeprecatedService::PrepareCommonEsTitleKeyDeprecated(sf::Out<AccessKey> out_access_key, KeySource key_source) {
|
||||
return impl::PrepareCommonEsTitleKey(out_access_key.GetPointer(), key_source, 0);
|
||||
}
|
||||
|
||||
Result DeprecatedService::PrepareCommonEsTitleKey(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation) {
|
||||
return impl::PrepareCommonEsTitleKey(out_access_key.GetPointer(), key_source, generation);
|
||||
}
|
||||
|
||||
Result DeprecatedService::AllocateAesKeySlot(sf::Out<s32> out_keyslot) {
|
||||
return impl::AllocateAesKeySlot(out_keyslot.GetPointer(), this);
|
||||
}
|
||||
|
||||
Result DeprecatedService::DeallocateAesKeySlot(s32 keyslot) {
|
||||
return impl::DeallocateAesKeySlot(keyslot, this);
|
||||
}
|
||||
|
||||
Result DeprecatedService::GetAesKeySlotAvailableEvent(sf::OutCopyHandle out_hnd) {
|
||||
out_hnd.SetValue(impl::GetAesKeySlotAvailableEventHandle(), false);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result DeprecatedService::SetBootReason(BootReasonValue boot_reason) {
|
||||
return impl::SetBootReason(boot_reason);
|
||||
}
|
||||
|
||||
Result DeprecatedService::GetBootReason(sf::Out<BootReasonValue> out) {
|
||||
return impl::GetBootReason(out.GetPointer());
|
||||
}
|
||||
|
||||
}
|
|
@ -15,41 +15,130 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_secure_monitor_manager.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class DeprecatedService {
|
||||
protected:
|
||||
SecureMonitorManager &m_manager;
|
||||
public:
|
||||
virtual ~DeprecatedService();
|
||||
explicit DeprecatedService(SecureMonitorManager *manager) : m_manager(*manager) { /* ... */ }
|
||||
public:
|
||||
virtual ~DeprecatedService() {
|
||||
/* Free any keyslots this service is using. */
|
||||
m_manager.DeallocateAesKeySlots(this);
|
||||
}
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result GetConfig(sf::Out<u64> out, u32 which);
|
||||
Result ModularExponentiate(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &exp, const sf::InPointerBuffer &mod);
|
||||
Result GenerateAesKek(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option);
|
||||
Result LoadAesKey(s32 keyslot, AccessKey access_key, KeySource key_source);
|
||||
Result GenerateAesKey(sf::Out<AesKey> out_key, AccessKey access_key, KeySource key_source);
|
||||
Result SetConfig(u32 which, u64 value);
|
||||
Result GenerateRandomBytes(const sf::OutPointerBuffer &out);
|
||||
Result DecryptAndStoreGcKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option);
|
||||
Result DecryptGcMessage(sf::Out<u32> out_size, const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest);
|
||||
Result IsDevelopment(sf::Out<bool> is_dev);
|
||||
Result GenerateSpecificAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which);
|
||||
Result DecryptDeviceUniqueData(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option);
|
||||
Result DecryptAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option);
|
||||
Result ComputeCtrDeprecated(const sf::OutBuffer &out_buf, s32 keyslot, const sf::InBuffer &in_buf, IvCtr iv_ctr);
|
||||
Result ComputeCtr(const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr);
|
||||
Result ComputeCmac(sf::Out<Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf);
|
||||
Result LoadEsDeviceKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option);
|
||||
Result PrepareEsTitleKeyDeprecated(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest);
|
||||
Result PrepareEsTitleKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation);
|
||||
Result LoadPreparedAesKey(s32 keyslot, AccessKey access_key);
|
||||
Result PrepareCommonEsTitleKeyDeprecated(sf::Out<AccessKey> out_access_key, KeySource key_source);
|
||||
Result PrepareCommonEsTitleKey(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation);
|
||||
Result AllocateAesKeySlot(sf::Out<s32> out_keyslot);
|
||||
Result DeallocateAesKeySlot(s32 keyslot);
|
||||
Result GetAesKeySlotAvailableEvent(sf::OutCopyHandle out_hnd);
|
||||
Result SetBootReason(BootReasonValue boot_reason);
|
||||
Result GetBootReason(sf::Out<BootReasonValue> out);
|
||||
Result GetConfig(sf::Out<u64> out, u32 which) {
|
||||
return m_manager.GetConfig(out.GetPointer(), static_cast<spl::ConfigItem>(which));
|
||||
}
|
||||
|
||||
Result ModularExponentiate(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &exp, const sf::InPointerBuffer &mod) {
|
||||
return m_manager.ModularExponentiate(out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), exp.GetPointer(), exp.GetSize(), mod.GetPointer(), mod.GetSize());
|
||||
}
|
||||
|
||||
Result GenerateAesKek(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option) {
|
||||
return m_manager.GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
||||
}
|
||||
|
||||
Result LoadAesKey(s32 keyslot, AccessKey access_key, KeySource key_source) {
|
||||
return m_manager.LoadAesKey(keyslot, this, access_key, key_source);
|
||||
}
|
||||
|
||||
Result GenerateAesKey(sf::Out<AesKey> out_key, AccessKey access_key, KeySource key_source) {
|
||||
return m_manager.GenerateAesKey(out_key.GetPointer(), access_key, key_source);
|
||||
}
|
||||
|
||||
Result SetConfig(u32 which, u64 value) {
|
||||
return m_manager.SetConfig(static_cast<spl::ConfigItem>(which), value);
|
||||
}
|
||||
|
||||
Result GenerateRandomBytes(const sf::OutPointerBuffer &out) {
|
||||
return m_manager.GenerateRandomBytes(out.GetPointer(), out.GetSize());
|
||||
}
|
||||
|
||||
Result DecryptAndStoreGcKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return m_manager.DecryptAndStoreGcKey(src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result DecryptGcMessage(sf::Out<u32> out_size, const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest) {
|
||||
return m_manager.DecryptGcMessage(out_size.GetPointer(), out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize());
|
||||
}
|
||||
|
||||
Result IsDevelopment(sf::Out<bool> is_dev) {
|
||||
return m_manager.IsDevelopment(is_dev.GetPointer());
|
||||
}
|
||||
|
||||
Result GenerateSpecificAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which) {
|
||||
return m_manager.GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
|
||||
}
|
||||
|
||||
Result DecryptDeviceUniqueData(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return m_manager.DecryptDeviceUniqueData(dst.GetPointer(), dst.GetSize(), src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result DecryptAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option) {
|
||||
return m_manager.DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
||||
}
|
||||
|
||||
Result ComputeCtrDeprecated(const sf::OutBuffer &out_buf, s32 keyslot, const sf::InBuffer &in_buf, IvCtr iv_ctr) {
|
||||
return m_manager.ComputeCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
||||
}
|
||||
|
||||
Result ComputeCtr(const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr) {
|
||||
return m_manager.ComputeCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
||||
}
|
||||
|
||||
Result ComputeCmac(sf::Out<Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf) {
|
||||
return m_manager.ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize());
|
||||
}
|
||||
|
||||
Result LoadEsDeviceKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return m_manager.LoadEsDeviceKey(src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result PrepareEsTitleKeyDeprecated(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest) {
|
||||
return m_manager.PrepareEsTitleKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), 0);
|
||||
}
|
||||
|
||||
Result PrepareEsTitleKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation) {
|
||||
return m_manager.PrepareEsTitleKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), generation);
|
||||
}
|
||||
|
||||
Result LoadPreparedAesKey(s32 keyslot, AccessKey access_key) {
|
||||
return m_manager.LoadPreparedAesKey(keyslot, this, access_key);
|
||||
}
|
||||
|
||||
Result PrepareCommonEsTitleKeyDeprecated(sf::Out<AccessKey> out_access_key, KeySource key_source) {
|
||||
return m_manager.PrepareCommonEsTitleKey(out_access_key.GetPointer(), key_source, 0);
|
||||
}
|
||||
|
||||
Result PrepareCommonEsTitleKey(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation) {
|
||||
return m_manager.PrepareCommonEsTitleKey(out_access_key.GetPointer(), key_source, generation);
|
||||
}
|
||||
|
||||
Result AllocateAesKeySlot(sf::Out<s32> out_keyslot) {
|
||||
return m_manager.AllocateAesKeySlot(out_keyslot.GetPointer(), this);
|
||||
}
|
||||
|
||||
Result DeallocateAesKeySlot(s32 keyslot) {
|
||||
return m_manager.DeallocateAesKeySlot(keyslot, this);
|
||||
}
|
||||
|
||||
Result GetAesKeySlotAvailableEvent(sf::OutCopyHandle out_hnd) {
|
||||
out_hnd.SetValue(m_manager.GetAesKeySlotAvailableEvent()->GetReadableHandle(), false);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SetBootReason(BootReasonValue boot_reason) {
|
||||
return m_manager.SetBootReason(boot_reason);
|
||||
}
|
||||
|
||||
Result GetBootReason(sf::Out<BootReasonValue> out) {
|
||||
return m_manager.GetBootReason(out.GetPointer());
|
||||
}
|
||||
};
|
||||
static_assert(spl::impl::IsIDeprecatedGeneralInterface<DeprecatedService>);
|
||||
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
#include "spl_device_unique_data_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
Result DeviceUniqueDataService::DecryptDeviceUniqueDataDeprecated(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return impl::DecryptDeviceUniqueData(dst.GetPointer(), dst.GetSize(), src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result DeviceUniqueDataService::DecryptDeviceUniqueData(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source) {
|
||||
return impl::DecryptDeviceUniqueData(dst.GetPointer(), dst.GetSize(), src.GetPointer(), src.GetSize(), access_key, key_source, static_cast<u32>(smc::DeviceUniqueDataMode::DecryptDeviceUniqueData));
|
||||
}
|
||||
|
||||
}
|
|
@ -14,15 +14,23 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_crypto_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class DeviceUniqueDataService : public CryptoService {
|
||||
public:
|
||||
explicit DeviceUniqueDataService(SecureMonitorManager *manager) : CryptoService(manager) { /* ... */ }
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result DecryptDeviceUniqueDataDeprecated(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option);
|
||||
Result DecryptDeviceUniqueData(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source);
|
||||
Result DecryptDeviceUniqueDataDeprecated(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return m_manager.DecryptDeviceUniqueData(dst.GetPointer(), dst.GetSize(), src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result DecryptDeviceUniqueData(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source) {
|
||||
return m_manager.DecryptDeviceUniqueData(dst.GetPointer(), dst.GetSize(), src.GetPointer(), src.GetSize(), access_key, key_source, static_cast<u32>(smc::DeviceUniqueDataMode::DecryptDeviceUniqueData));
|
||||
}
|
||||
};
|
||||
static_assert(spl::impl::IsIDeviceUniqueDataInterface<DeviceUniqueDataService>);
|
||||
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
#include "spl_es_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
Result EsService::LoadEsDeviceKeyDeprecated(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return impl::LoadEsDeviceKey(src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result EsService::LoadEsDeviceKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source) {
|
||||
return impl::LoadEsDeviceKey(src.GetPointer(), src.GetSize(), access_key, key_source, static_cast<u32>(smc::DeviceUniqueDataMode::DecryptAndStoreEsDeviceKey));
|
||||
}
|
||||
|
||||
Result EsService::PrepareEsTitleKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation) {
|
||||
return impl::PrepareEsTitleKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), generation);
|
||||
}
|
||||
|
||||
Result EsService::PrepareCommonEsTitleKey(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation) {
|
||||
return impl::PrepareCommonEsTitleKey(out_access_key.GetPointer(), key_source, generation);
|
||||
}
|
||||
|
||||
Result EsService::DecryptAndStoreDrmDeviceCertKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source) {
|
||||
return impl::DecryptAndStoreDrmDeviceCertKey(src.GetPointer(), src.GetSize(), access_key, key_source);
|
||||
}
|
||||
|
||||
Result EsService::ModularExponentiateWithDrmDeviceCertKey(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod) {
|
||||
return impl::ModularExponentiateWithDrmDeviceCertKey(out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize());
|
||||
}
|
||||
|
||||
Result EsService::PrepareEsArchiveKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation) {
|
||||
return impl::PrepareEsArchiveKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), generation);
|
||||
}
|
||||
|
||||
Result EsService::LoadPreparedAesKey(s32 keyslot, AccessKey access_key) {
|
||||
return impl::LoadPreparedAesKey(keyslot, this, access_key);
|
||||
}
|
||||
|
||||
}
|
|
@ -14,21 +14,47 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_device_unique_data_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class EsService : public DeviceUniqueDataService {
|
||||
public:
|
||||
explicit EsService(SecureMonitorManager *manager) : DeviceUniqueDataService(manager) { /* ... */ }
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result LoadEsDeviceKeyDeprecated(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option);
|
||||
Result LoadEsDeviceKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source);
|
||||
Result PrepareEsTitleKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation);
|
||||
Result PrepareCommonEsTitleKey(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation);
|
||||
Result DecryptAndStoreDrmDeviceCertKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source);
|
||||
Result ModularExponentiateWithDrmDeviceCertKey(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod);
|
||||
Result PrepareEsArchiveKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation);
|
||||
Result LoadPreparedAesKey(s32 keyslot, AccessKey access_key);
|
||||
Result LoadEsDeviceKeyDeprecated(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return m_manager.LoadEsDeviceKey(src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result LoadEsDeviceKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source) {
|
||||
return m_manager.LoadEsDeviceKey(src.GetPointer(), src.GetSize(), access_key, key_source, static_cast<u32>(smc::DeviceUniqueDataMode::DecryptAndStoreEsDeviceKey));
|
||||
}
|
||||
|
||||
Result PrepareEsTitleKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation) {
|
||||
return m_manager.PrepareEsTitleKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), generation);
|
||||
}
|
||||
|
||||
Result PrepareCommonEsTitleKey(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation) {
|
||||
return m_manager.PrepareCommonEsTitleKey(out_access_key.GetPointer(), key_source, generation);
|
||||
}
|
||||
|
||||
Result DecryptAndStoreDrmDeviceCertKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source) {
|
||||
return m_manager.DecryptAndStoreDrmDeviceCertKey(src.GetPointer(), src.GetSize(), access_key, key_source);
|
||||
}
|
||||
|
||||
Result ModularExponentiateWithDrmDeviceCertKey(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod) {
|
||||
return m_manager.ModularExponentiateWithDrmDeviceCertKey(out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize());
|
||||
}
|
||||
|
||||
Result PrepareEsArchiveKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation) {
|
||||
return m_manager.PrepareEsArchiveKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), generation);
|
||||
}
|
||||
|
||||
Result LoadPreparedAesKey(s32 keyslot, AccessKey access_key) {
|
||||
return m_manager.LoadPreparedAesKey(keyslot, this, access_key);
|
||||
}
|
||||
};
|
||||
static_assert(spl::impl::IsIEsInterface<EsService>);
|
||||
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
#include "spl_fs_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
Result FsService::DecryptAndStoreGcKeyDeprecated(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return impl::DecryptAndStoreGcKey(src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result FsService::DecryptAndStoreGcKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source) {
|
||||
return impl::DecryptAndStoreGcKey(src.GetPointer(), src.GetSize(), access_key, key_source, static_cast<u32>(smc::DeviceUniqueDataMode::DecryptAndStoreGcKey));
|
||||
}
|
||||
|
||||
Result FsService::DecryptGcMessage(sf::Out<u32> out_size, const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest) {
|
||||
return impl::DecryptGcMessage(out_size.GetPointer(), out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize());
|
||||
}
|
||||
|
||||
Result FsService::GenerateSpecificAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which) {
|
||||
return impl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
|
||||
}
|
||||
|
||||
Result FsService::LoadPreparedAesKey(s32 keyslot, AccessKey access_key) {
|
||||
return impl::LoadPreparedAesKey(keyslot, this, access_key);
|
||||
}
|
||||
|
||||
Result FsService::GetPackage2Hash(const sf::OutPointerBuffer &dst) {
|
||||
return impl::GetPackage2Hash(dst.GetPointer(), dst.GetSize());
|
||||
}
|
||||
|
||||
}
|
|
@ -14,19 +14,39 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_crypto_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class FsService : public CryptoService {
|
||||
public:
|
||||
explicit FsService(SecureMonitorManager *manager) : CryptoService(manager) { /* ... */ }
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result DecryptAndStoreGcKeyDeprecated(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option);
|
||||
Result DecryptAndStoreGcKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source);
|
||||
Result DecryptGcMessage(sf::Out<u32> out_size, const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest);
|
||||
Result GenerateSpecificAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which);
|
||||
Result LoadPreparedAesKey(s32 keyslot, AccessKey access_key);
|
||||
Result GetPackage2Hash(const sf::OutPointerBuffer &dst);
|
||||
Result DecryptAndStoreGcKeyDeprecated(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||
return m_manager.DecryptAndStoreGcKey(src.GetPointer(), src.GetSize(), access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result DecryptAndStoreGcKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source) {
|
||||
return m_manager.DecryptAndStoreGcKey(src.GetPointer(), src.GetSize(), access_key, key_source, static_cast<u32>(smc::DeviceUniqueDataMode::DecryptAndStoreGcKey));
|
||||
}
|
||||
|
||||
Result DecryptGcMessage(sf::Out<u32> out_size, const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest) {
|
||||
return m_manager.DecryptGcMessage(out_size.GetPointer(), out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize());
|
||||
}
|
||||
|
||||
Result GenerateSpecificAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which) {
|
||||
return m_manager.GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
|
||||
}
|
||||
|
||||
Result LoadPreparedAesKey(s32 keyslot, AccessKey access_key) {
|
||||
return m_manager.LoadPreparedAesKey(keyslot, this, access_key);
|
||||
}
|
||||
|
||||
Result GetPackage2Hash(const sf::OutPointerBuffer &dst) {
|
||||
return m_manager.GetPackage2Hash(dst.GetPointer(), dst.GetSize());
|
||||
}
|
||||
};
|
||||
static_assert(spl::impl::IsIFsInterface<FsService>);
|
||||
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
#include "spl_general_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
Result GeneralService::GetConfig(sf::Out<u64> out, u32 which) {
|
||||
return impl::GetConfig(out.GetPointer(), static_cast<spl::ConfigItem>(which));
|
||||
}
|
||||
|
||||
Result GeneralService::ModularExponentiate(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &exp, const sf::InPointerBuffer &mod) {
|
||||
return impl::ModularExponentiate(out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), exp.GetPointer(), exp.GetSize(), mod.GetPointer(), mod.GetSize());
|
||||
}
|
||||
|
||||
Result GeneralService::SetConfig(u32 which, u64 value) {
|
||||
return impl::SetConfig(static_cast<spl::ConfigItem>(which), value);
|
||||
}
|
||||
|
||||
Result GeneralService::GenerateRandomBytes(const sf::OutPointerBuffer &out) {
|
||||
return impl::GenerateRandomBytes(out.GetPointer(), out.GetSize());
|
||||
}
|
||||
|
||||
Result GeneralService::IsDevelopment(sf::Out<bool> is_dev) {
|
||||
return impl::IsDevelopment(is_dev.GetPointer());
|
||||
}
|
||||
|
||||
Result GeneralService::SetBootReason(BootReasonValue boot_reason) {
|
||||
return impl::SetBootReason(boot_reason);
|
||||
}
|
||||
|
||||
Result GeneralService::GetBootReason(sf::Out<BootReasonValue> out) {
|
||||
return impl::GetBootReason(out.GetPointer());
|
||||
}
|
||||
|
||||
}
|
|
@ -15,19 +15,44 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_secure_monitor_manager.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class GeneralService {
|
||||
protected:
|
||||
SecureMonitorManager &m_manager;
|
||||
public:
|
||||
explicit GeneralService(SecureMonitorManager *manager) : m_manager(*manager) { /* ... */ }
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result GetConfig(sf::Out<u64> out, u32 which);
|
||||
Result ModularExponentiate(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &exp, const sf::InPointerBuffer &mod);
|
||||
Result SetConfig(u32 which, u64 value);
|
||||
Result GenerateRandomBytes(const sf::OutPointerBuffer &out);
|
||||
Result IsDevelopment(sf::Out<bool> is_dev);
|
||||
Result SetBootReason(BootReasonValue boot_reason);
|
||||
Result GetBootReason(sf::Out<BootReasonValue> out);
|
||||
Result GetConfig(sf::Out<u64> out, u32 key) {
|
||||
return m_manager.GetConfig(out.GetPointer(), static_cast<spl::ConfigItem>(key));
|
||||
}
|
||||
|
||||
Result ModularExponentiate(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &exp, const sf::InPointerBuffer &mod) {
|
||||
return m_manager.ModularExponentiate(out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), exp.GetPointer(), exp.GetSize(), mod.GetPointer(), mod.GetSize());
|
||||
}
|
||||
|
||||
Result SetConfig(u32 key, u64 value) {
|
||||
return m_manager.SetConfig(static_cast<spl::ConfigItem>(key), value);
|
||||
}
|
||||
|
||||
Result GenerateRandomBytes(const sf::OutPointerBuffer &out) {
|
||||
return m_manager.GenerateRandomBytes(out.GetPointer(), out.GetSize());
|
||||
}
|
||||
|
||||
Result IsDevelopment(sf::Out<bool> is_dev) {
|
||||
return m_manager.IsDevelopment(is_dev.GetPointer());
|
||||
}
|
||||
|
||||
Result SetBootReason(BootReasonValue boot_reason) {
|
||||
return m_manager.SetBootReason(boot_reason);
|
||||
}
|
||||
|
||||
Result GetBootReason(sf::Out<BootReasonValue> out) {
|
||||
return m_manager.GetBootReason(out.GetPointer());
|
||||
}
|
||||
};
|
||||
static_assert(spl::impl::IsIGeneralInterface<GeneralService>);
|
||||
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class KeySlotCacheEntry : public util::IntrusiveListBaseNode<KeySlotCacheEntry> {
|
||||
NON_COPYABLE(KeySlotCacheEntry);
|
||||
NON_MOVEABLE(KeySlotCacheEntry);
|
||||
private:
|
||||
friend class KeySlotCache;
|
||||
public:
|
||||
static constexpr size_t KeySize = crypto::AesDecryptor128::KeySize;
|
||||
private:
|
||||
const s32 m_slot_index;
|
||||
s32 m_virtual_slot;
|
||||
public:
|
||||
explicit KeySlotCacheEntry(s32 idx) : m_slot_index(idx), m_virtual_slot(-1) { /* ... */ }
|
||||
|
||||
bool Contains(s32 virtual_slot) const {
|
||||
return virtual_slot == m_virtual_slot;
|
||||
}
|
||||
|
||||
s32 GetPhysicalKeySlotIndex() const { return m_slot_index; }
|
||||
|
||||
s32 GetVirtualKeySlotIndex() const { return m_virtual_slot; }
|
||||
|
||||
void SetVirtualSlot(s32 virtual_slot) {
|
||||
m_virtual_slot = virtual_slot;
|
||||
}
|
||||
|
||||
void ClearVirtualSlot() {
|
||||
m_virtual_slot = -1;
|
||||
}
|
||||
};
|
||||
|
||||
class KeySlotCache {
|
||||
NON_COPYABLE(KeySlotCache);
|
||||
NON_MOVEABLE(KeySlotCache);
|
||||
private:
|
||||
using KeySlotCacheEntryList = util::IntrusiveListBaseTraits<KeySlotCacheEntry>::ListType;
|
||||
private:
|
||||
KeySlotCacheEntryList m_mru_list;
|
||||
public:
|
||||
constexpr KeySlotCache() : m_mru_list() { /* ... */ }
|
||||
|
||||
s32 Allocate(s32 virtual_slot) {
|
||||
return this->AllocateFromLru(virtual_slot);
|
||||
}
|
||||
|
||||
bool Find(s32 *out, s32 virtual_slot) {
|
||||
for (auto it = m_mru_list.begin(); it != m_mru_list.end(); ++it) {
|
||||
if (it->Contains(virtual_slot)) {
|
||||
*out = it->GetPhysicalKeySlotIndex();
|
||||
|
||||
this->UpdateMru(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Release(s32 *out, s32 virtual_slot) {
|
||||
for (auto it = m_mru_list.begin(); it != m_mru_list.end(); ++it) {
|
||||
if (it->Contains(virtual_slot)) {
|
||||
*out = it->GetPhysicalKeySlotIndex();
|
||||
it->ClearVirtualSlot();
|
||||
|
||||
this->UpdateLru(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FindPhysical(s32 physical_slot) {
|
||||
for (auto it = m_mru_list.begin(); it != m_mru_list.end(); ++it) {
|
||||
if (it->GetPhysicalKeySlotIndex() == physical_slot) {
|
||||
this->UpdateMru(it);
|
||||
|
||||
if (it->GetVirtualKeySlotIndex() == physical_slot) {
|
||||
return true;
|
||||
} else {
|
||||
it->SetVirtualSlot(physical_slot);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
AMS_ABORT();
|
||||
}
|
||||
|
||||
void AddEntry(KeySlotCacheEntry *entry) {
|
||||
m_mru_list.push_front(*entry);
|
||||
}
|
||||
private:
|
||||
s32 AllocateFromLru(s32 virtual_slot) {
|
||||
AMS_ASSERT(!m_mru_list.empty());
|
||||
|
||||
auto it = m_mru_list.rbegin();
|
||||
it->SetVirtualSlot(virtual_slot);
|
||||
|
||||
auto *entry = std::addressof(*it);
|
||||
m_mru_list.pop_back();
|
||||
m_mru_list.push_front(*entry);
|
||||
|
||||
return entry->GetPhysicalKeySlotIndex();
|
||||
}
|
||||
|
||||
void UpdateMru(KeySlotCacheEntryList::iterator it) {
|
||||
auto *entry = std::addressof(*it);
|
||||
m_mru_list.erase(it);
|
||||
m_mru_list.push_front(*entry);
|
||||
}
|
||||
|
||||
void UpdateLru(KeySlotCacheEntryList::iterator it) {
|
||||
auto *entry = std::addressof(*it);
|
||||
m_mru_list.erase(it);
|
||||
m_mru_list.push_back(*entry);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -14,7 +14,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
|
||||
#include "spl_random_service.hpp"
|
||||
#include "spl_general_service.hpp"
|
||||
|
@ -79,12 +78,13 @@ namespace ams {
|
|||
class ServerManager final : public sf::hipc::ServerManager<PortIndex_Count, SplServerOptions, NumSessions> {
|
||||
private:
|
||||
sf::ExpHeapAllocator *m_allocator;
|
||||
spl::SecureMonitorManager *m_secure_monitor_manager;
|
||||
spl::GeneralService m_general_service;
|
||||
sf::UnmanagedServiceObjectByPointer<spl::impl::IGeneralInterface, spl::GeneralService> m_general_service_object;
|
||||
spl::RandomService m_random_service;
|
||||
sf::UnmanagedServiceObjectByPointer<spl::impl::IRandomInterface, spl::RandomService> m_random_service_object;
|
||||
public:
|
||||
ServerManager(sf::ExpHeapAllocator *allocator) : m_allocator(allocator), m_general_service(), m_general_service_object(std::addressof(m_general_service)), m_random_service(), m_random_service_object(std::addressof(m_random_service)) {
|
||||
ServerManager(sf::ExpHeapAllocator *allocator, spl::SecureMonitorManager *manager) : m_allocator(allocator), m_secure_monitor_manager(manager), m_general_service(manager), m_general_service_object(std::addressof(m_general_service)), m_random_service(manager), m_random_service_object(std::addressof(m_random_service)) {
|
||||
/* ... */
|
||||
}
|
||||
private:
|
||||
|
@ -96,29 +96,32 @@ namespace ams {
|
|||
|
||||
alignas(0x40) constinit u8 g_server_allocator_buffer[8_KB];
|
||||
Allocator g_server_allocator;
|
||||
constinit SecureMonitorManager g_secure_monitor_manager;
|
||||
|
||||
ServerManager g_server_manager(std::addressof(g_server_allocator));
|
||||
constinit bool g_use_new_server = false;
|
||||
|
||||
ServerManager g_server_manager(std::addressof(g_server_allocator), std::addressof(g_secure_monitor_manager));
|
||||
|
||||
ams::Result ServerManager::OnNeedsToAccept(int port_index, Server *server) {
|
||||
switch (port_index) {
|
||||
case PortIndex_General:
|
||||
if (hos::GetVersion() >= hos::Version_4_0_0) {
|
||||
if (g_use_new_server) {
|
||||
return this->AcceptImpl(server, m_general_service_object.GetShared());
|
||||
} else {
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::IDeprecatedGeneralInterface, spl::DeprecatedService>(m_allocator));
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::IDeprecatedGeneralInterface, spl::DeprecatedService>(m_allocator, m_secure_monitor_manager));
|
||||
}
|
||||
case PortIndex_Random:
|
||||
return this->AcceptImpl(server, m_random_service_object.GetShared());
|
||||
case PortIndex_Crypto:
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::ICryptoInterface, spl::CryptoService>(m_allocator));
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::ICryptoInterface, spl::CryptoService>(m_allocator, m_secure_monitor_manager));
|
||||
case PortIndex_Fs:
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::IFsInterface, spl::FsService>(m_allocator));
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::IFsInterface, spl::FsService>(m_allocator, m_secure_monitor_manager));
|
||||
case PortIndex_Ssl:
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::ISslInterface, spl::SslService>(m_allocator));
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::ISslInterface, spl::SslService>(m_allocator, m_secure_monitor_manager));
|
||||
case PortIndex_Es:
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::IEsInterface, spl::EsService>(m_allocator));
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::IEsInterface, spl::EsService>(m_allocator, m_secure_monitor_manager));
|
||||
case PortIndex_Manu:
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::IManuInterface, spl::ManuService>(m_allocator));
|
||||
return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced<spl::impl::IManuInterface, spl::ManuService>(m_allocator, m_secure_monitor_manager));
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
@ -127,8 +130,10 @@ namespace ams {
|
|||
/* Setup server allocator. */
|
||||
g_server_allocator.Attach(lmem::CreateExpHeap(g_server_allocator_buffer, sizeof(g_server_allocator_buffer), lmem::CreateOption_None));
|
||||
|
||||
/* Initialize global context. */
|
||||
spl::impl::Initialize();
|
||||
/* Initialize secure monitor manager. */
|
||||
g_secure_monitor_manager.Initialize();
|
||||
|
||||
g_use_new_server = hos::GetVersion() >= hos::Version_4_0_0;
|
||||
|
||||
/* Create services. */
|
||||
const auto fw_ver = hos::GetVersion();
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
#include "spl_manu_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
Result ManuService::ReencryptDeviceUniqueData(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option) {
|
||||
return impl::ReencryptDeviceUniqueData(out.GetPointer(), out.GetSize(), src.GetPointer(), src.GetSize(), access_key_dec, source_dec, access_key_enc, source_enc, option);
|
||||
}
|
||||
|
||||
}
|
|
@ -14,14 +14,19 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_device_unique_data_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class ManuService : public DeviceUniqueDataService {
|
||||
public:
|
||||
explicit ManuService(SecureMonitorManager *manager) : DeviceUniqueDataService(manager) { /* ... */ }
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result ReencryptDeviceUniqueData(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option);
|
||||
Result ReencryptDeviceUniqueData(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option) {
|
||||
return m_manager.ReencryptDeviceUniqueData(out.GetPointer(), out.GetSize(), src.GetPointer(), src.GetSize(), access_key_dec, source_dec, access_key_enc, source_enc, option);
|
||||
}
|
||||
};
|
||||
static_assert(spl::impl::IsIManuInterface<ManuService>);
|
||||
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
#include "spl_random_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
Result RandomService::GenerateRandomBytes(const sf::OutBuffer &out) {
|
||||
return impl::GenerateRandomBytes(out.GetPointer(), out.GetSize());
|
||||
}
|
||||
|
||||
}
|
|
@ -15,13 +15,20 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_secure_monitor_manager.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class RandomService final {
|
||||
protected:
|
||||
SecureMonitorManager &m_manager;
|
||||
public:
|
||||
explicit RandomService(SecureMonitorManager *manager) : m_manager(*manager) { /* ... */ }
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result GenerateRandomBytes(const sf::OutBuffer &out);
|
||||
Result GenerateRandomBytes(const sf::OutBuffer &out) {
|
||||
return m_manager.GenerateRandomBytes(out.GetPointer(), out.GetSize());
|
||||
}
|
||||
};
|
||||
static_assert(spl::impl::IsIRandomInterface<RandomService>);
|
||||
|
||||
|
|
190
stratosphere/spl/source/spl_secure_monitor_manager.cpp
Normal file
190
stratosphere/spl/source/spl_secure_monitor_manager.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_secure_monitor_manager.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
void SecureMonitorManager::Initialize() {
|
||||
return impl::Initialize();
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::ModularExponentiate(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) {
|
||||
return impl::ModularExponentiate(out, out_size, base, base_size, exp, exp_size, mod, mod_size);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option) {
|
||||
return impl::GenerateAesKek(out_access_key, key_source, generation, option);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::LoadAesKey(s32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source) {
|
||||
R_TRY(this->TestAesKeySlot(nullptr, keyslot, owner));
|
||||
return impl::LoadAesKey(keyslot, access_key, key_source);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) {
|
||||
return impl::GenerateAesKey(out_key, access_key, key_source);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::DecryptDeviceUniqueData(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||
return impl::DecryptDeviceUniqueData(dst, dst_size, src, src_size, access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::ReencryptDeviceUniqueData(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) {
|
||||
return impl::ReencryptDeviceUniqueData(dst, dst_size, src, src_size, access_key_dec, source_dec, access_key_enc, source_enc, option);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::GetConfig(u64 *out, spl::ConfigItem key) {
|
||||
return impl::GetConfig(out, key);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::SetConfig(spl::ConfigItem key, u64 value) {
|
||||
return impl::SetConfig(key, value);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::GetPackage2Hash(void *dst, const size_t size) {
|
||||
return impl::GetPackage2Hash(dst, size);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::GenerateRandomBytes(void *out, size_t size) {
|
||||
return impl::GenerateRandomBytes(out, size);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::DecryptAndStoreGcKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||
return impl::DecryptAndStoreGcKey(src, src_size, access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::DecryptGcMessage(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) {
|
||||
return impl::DecryptGcMessage(out_size, dst, dst_size, base, base_size, mod, mod_size, label_digest, label_digest_size);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::DecryptAndStoreSslClientCertKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) {
|
||||
return impl::DecryptAndStoreSslClientCertKey(src, src_size, access_key, key_source);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::ModularExponentiateWithSslClientCertKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) {
|
||||
return impl::ModularExponentiateWithSslClientCertKey(out, out_size, base, base_size, mod, mod_size);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::DecryptAndStoreDrmDeviceCertKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) {
|
||||
return impl::DecryptAndStoreDrmDeviceCertKey(src, src_size, access_key, key_source);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::ModularExponentiateWithDrmDeviceCertKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) {
|
||||
return impl::ModularExponentiateWithDrmDeviceCertKey(out, out_size, base, base_size, mod, mod_size);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::IsDevelopment(bool *out) {
|
||||
return impl::IsDevelopment(out);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which) {
|
||||
return impl::GenerateSpecificAesKey(out_key, key_source, generation, which);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option) {
|
||||
return impl::DecryptAesKey(out_key, key_source, generation, option);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::ComputeCtr(void *dst, size_t dst_size, s32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr) {
|
||||
R_TRY(this->TestAesKeySlot(nullptr, keyslot, owner));
|
||||
return impl::ComputeCtr(dst, dst_size, keyslot, src, src_size, iv_ctr);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::ComputeCmac(Cmac *out_cmac, s32 keyslot, const void *owner, const void *data, size_t size) {
|
||||
R_TRY(this->TestAesKeySlot(nullptr, keyslot, owner));
|
||||
return impl::ComputeCmac(out_cmac, keyslot, data, size);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::LoadEsDeviceKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||
return impl::LoadEsDeviceKey(src, src_size, access_key, key_source, option);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::PrepareEsTitleKey(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 impl::PrepareEsTitleKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::PrepareEsArchiveKey(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 impl::PrepareEsArchiveKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::PrepareCommonEsTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation) {
|
||||
return impl::PrepareCommonEsTitleKey(out_access_key, key_source, generation);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::LoadPreparedAesKey(s32 keyslot, const void *owner, const AccessKey &access_key) {
|
||||
R_TRY(this->TestAesKeySlot(nullptr, keyslot, owner));
|
||||
return impl::LoadPreparedAesKey(keyslot, access_key);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::AllocateAesKeySlot(s32 *out_keyslot, const void *owner) {
|
||||
s32 keyslot;
|
||||
R_TRY(impl::AllocateAesKeySlot(std::addressof(keyslot)));
|
||||
|
||||
s32 index;
|
||||
R_ABORT_UNLESS(impl::TestAesKeySlot(std::addressof(index), keyslot));
|
||||
|
||||
m_aes_keyslot_owners[index] = owner;
|
||||
*out_keyslot = keyslot;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::DeallocateAesKeySlot(s32 keyslot, const void *owner) {
|
||||
s32 index;
|
||||
R_TRY(this->TestAesKeySlot(std::addressof(index), keyslot, owner));
|
||||
|
||||
m_aes_keyslot_owners[index] = nullptr;
|
||||
return impl::DeallocateAesKeySlot(keyslot);
|
||||
}
|
||||
|
||||
void SecureMonitorManager::DeallocateAesKeySlots(const void *owner) {
|
||||
for (auto i = 0; i < impl::AesKeySlotCount; ++i) {
|
||||
if (m_aes_keyslot_owners[i] == owner) {
|
||||
m_aes_keyslot_owners[i] = nullptr;
|
||||
impl::DeallocateAesKeySlot(impl::AesKeySlotMin + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::SetBootReason(BootReasonValue boot_reason) {
|
||||
return impl::SetBootReason(boot_reason);
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::GetBootReason(BootReasonValue *out) {
|
||||
return impl::GetBootReason(out);
|
||||
}
|
||||
|
||||
os::SystemEvent *SecureMonitorManager::GetAesKeySlotAvailableEvent() {
|
||||
return impl::GetAesKeySlotAvailableEvent();
|
||||
}
|
||||
|
||||
Result SecureMonitorManager::TestAesKeySlot(s32 *out_index, s32 keyslot, const void *owner) {
|
||||
/* Validate the keyslot (and get the index). */
|
||||
s32 index;
|
||||
R_TRY(impl::TestAesKeySlot(std::addressof(index), keyslot));
|
||||
|
||||
/* Check that the keyslot is owned by the request maker. */
|
||||
R_UNLESS(m_aes_keyslot_owners[index] == owner, spl::ResultInvalidKeySlot());
|
||||
|
||||
/* Set output index. */
|
||||
if (out_index != nullptr) {
|
||||
*out_index = index;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
||||
}
|
66
stratosphere/spl/source/spl_secure_monitor_manager.hpp
Normal file
66
stratosphere/spl/source/spl_secure_monitor_manager.hpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class SecureMonitorManager {
|
||||
private:
|
||||
const void *m_aes_keyslot_owners[impl::AesKeySlotCount]{};
|
||||
public:
|
||||
constexpr SecureMonitorManager() = default;
|
||||
public:
|
||||
void Initialize();
|
||||
private:
|
||||
Result TestAesKeySlot(s32 *out_index, s32 keyslot, const void *owner);
|
||||
public:
|
||||
Result ModularExponentiate(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 GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option);
|
||||
Result LoadAesKey(s32 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 DecryptDeviceUniqueData(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
||||
Result ReencryptDeviceUniqueData(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);
|
||||
Result GetConfig(u64 *out, spl::ConfigItem key);
|
||||
Result SetConfig(spl::ConfigItem key, u64 value);
|
||||
Result GetPackage2Hash(void *dst, const size_t size);
|
||||
Result GenerateRandomBytes(void *out, size_t size);
|
||||
Result DecryptAndStoreGcKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
||||
Result DecryptGcMessage(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 DecryptAndStoreSslClientCertKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
|
||||
Result ModularExponentiateWithSslClientCertKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size);
|
||||
Result DecryptAndStoreDrmDeviceCertKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
|
||||
Result ModularExponentiateWithDrmDeviceCertKey(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size);
|
||||
Result IsDevelopment(bool *out);
|
||||
Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which);
|
||||
Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option);
|
||||
Result ComputeCtr(void *dst, size_t dst_size, s32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr);
|
||||
Result ComputeCmac(Cmac *out_cmac, s32 keyslot, const void *owner, const void *data, size_t size);
|
||||
Result LoadEsDeviceKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
||||
Result PrepareEsTitleKey(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 PrepareEsArchiveKey(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 PrepareCommonEsTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation);
|
||||
Result LoadPreparedAesKey(s32 keyslot, const void *owner, const AccessKey &access_key);
|
||||
Result AllocateAesKeySlot(s32 *out_keyslot, const void *owner);
|
||||
Result DeallocateAesKeySlot(s32 keyslot, const void *owner);
|
||||
void DeallocateAesKeySlots(const void *owner);
|
||||
Result SetBootReason(BootReasonValue boot_reason);
|
||||
Result GetBootReason(BootReasonValue *out);
|
||||
|
||||
os::SystemEvent *GetAesKeySlotAvailableEvent();
|
||||
};
|
||||
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_api_impl.hpp"
|
||||
#include "spl_ssl_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
Result SslService::DecryptAndStoreSslClientCertKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source) {
|
||||
return impl::DecryptAndStoreSslClientCertKey(src.GetPointer(), src.GetSize(), access_key, key_source);
|
||||
}
|
||||
|
||||
Result SslService::ModularExponentiateWithSslClientCertKey(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod) {
|
||||
return impl::ModularExponentiateWithSslClientCertKey(out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize());
|
||||
}
|
||||
|
||||
}
|
|
@ -14,15 +14,23 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "spl_device_unique_data_service.hpp"
|
||||
|
||||
namespace ams::spl {
|
||||
|
||||
class SslService : public DeviceUniqueDataService {
|
||||
public:
|
||||
explicit SslService(SecureMonitorManager *manager) : DeviceUniqueDataService(manager) { /* ... */ }
|
||||
public:
|
||||
/* Actual commands. */
|
||||
Result DecryptAndStoreSslClientCertKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source);
|
||||
Result ModularExponentiateWithSslClientCertKey(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod);
|
||||
Result DecryptAndStoreSslClientCertKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source) {
|
||||
return m_manager.DecryptAndStoreSslClientCertKey(src.GetPointer(), src.GetSize(), access_key, key_source);
|
||||
}
|
||||
|
||||
Result ModularExponentiateWithSslClientCertKey(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod) {
|
||||
return m_manager.ModularExponentiateWithSslClientCertKey(out.GetPointer(), out.GetSize(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize());
|
||||
}
|
||||
};
|
||||
static_assert(spl::impl::IsISslInterface<SslService>);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue