mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-25 11:00:18 +00:00
spl: refactor into sts namespace
This commit is contained in:
parent
1671c04e24
commit
f9b48f06a3
30 changed files with 2230 additions and 2152 deletions
937
stratosphere/spl/source/spl_api.cpp
Normal file
937
stratosphere/spl/source/spl_api.cpp
Normal file
|
@ -0,0 +1,937 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
#include "spl_smc.hpp"
|
||||||
|
|
||||||
|
#include "spl_ctr_drbg.hpp"
|
||||||
|
|
||||||
|
namespace sts::spl {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/* Convenient defines. */
|
||||||
|
constexpr size_t DeviceAddressSpaceAlignSize = 0x400000;
|
||||||
|
constexpr size_t DeviceAddressSpaceAlignMask = DeviceAddressSpaceAlignSize - 1;
|
||||||
|
constexpr u32 WorkBufferMapBase = 0x80000000u;
|
||||||
|
constexpr u32 CryptAesInMapBase = 0x90000000u;
|
||||||
|
constexpr u32 CryptAesOutMapBase = 0xC0000000u;
|
||||||
|
constexpr size_t CryptAesSizeMax = static_cast<size_t>(CryptAesOutMapBase - CryptAesInMapBase);
|
||||||
|
|
||||||
|
constexpr size_t RsaPrivateKeySize = 0x100;
|
||||||
|
constexpr size_t RsaPrivateKeyMetaSize = 0x30;
|
||||||
|
constexpr size_t LabelDigestSizeMax = 0x20;
|
||||||
|
|
||||||
|
constexpr size_t WorkBufferSizeMax = 0x800;
|
||||||
|
|
||||||
|
constexpr size_t MaxAesKeyslots = 6;
|
||||||
|
constexpr size_t MaxAesKeyslotsDeprecated = 4;
|
||||||
|
|
||||||
|
/* Max Keyslots helper. */
|
||||||
|
inline size_t GetMaxKeyslots() {
|
||||||
|
return (GetRuntimeFirmwareVersion() >= FirmwareVersion_600) ? MaxAesKeyslots : MaxAesKeyslotsDeprecated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Type definitions. */
|
||||||
|
class ScopedAesKeyslot {
|
||||||
|
private:
|
||||||
|
u32 slot;
|
||||||
|
bool has_slot;
|
||||||
|
public:
|
||||||
|
ScopedAesKeyslot() : slot(0), has_slot(false) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
~ScopedAesKeyslot() {
|
||||||
|
if (has_slot) {
|
||||||
|
spl::FreeAesKeyslot(slot, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetKeyslot() const {
|
||||||
|
return this->slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Allocate() {
|
||||||
|
R_TRY(spl::AllocateAesKeyslot(&this->slot, this));
|
||||||
|
this->has_slot = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SeLinkedListEntry {
|
||||||
|
u32 num_entries;
|
||||||
|
u32 address;
|
||||||
|
u32 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SeCryptContext {
|
||||||
|
SeLinkedListEntry in;
|
||||||
|
SeLinkedListEntry out;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeviceAddressSpaceMapHelper {
|
||||||
|
private:
|
||||||
|
Handle das_hnd;
|
||||||
|
u64 dst_addr;
|
||||||
|
u64 src_addr;
|
||||||
|
size_t size;
|
||||||
|
u32 perm;
|
||||||
|
public:
|
||||||
|
DeviceAddressSpaceMapHelper(Handle h, u64 dst, u64 src, size_t sz, u32 p) : das_hnd(h), dst_addr(dst), src_addr(src), size(sz), perm(p) {
|
||||||
|
R_ASSERT(svcMapDeviceAddressSpaceAligned(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr, this->perm));
|
||||||
|
}
|
||||||
|
~DeviceAddressSpaceMapHelper() {
|
||||||
|
R_ASSERT(svcUnmapDeviceAddressSpace(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Global variables. */
|
||||||
|
CtrDrbg g_drbg;
|
||||||
|
Event g_se_event;
|
||||||
|
IEvent *g_se_keyslot_available_event;
|
||||||
|
|
||||||
|
Handle g_se_das_hnd;
|
||||||
|
u32 g_se_mapped_work_buffer_addr;
|
||||||
|
u8 __attribute__((aligned(0x1000))) g_work_buffer[2 * WorkBufferSizeMax];
|
||||||
|
|
||||||
|
HosMutex g_async_op_lock;
|
||||||
|
|
||||||
|
const void *g_keyslot_owners[MaxAesKeyslots];
|
||||||
|
BootReasonValue g_boot_reason;
|
||||||
|
bool g_boot_reason_set;
|
||||||
|
|
||||||
|
/* Boot Reason accessors. */
|
||||||
|
BootReasonValue GetBootReason() {
|
||||||
|
return g_boot_reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsBootReasonSet() {
|
||||||
|
return g_boot_reason_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialization functionality. */
|
||||||
|
void InitializeCtrDrbg() {
|
||||||
|
u8 seed[CtrDrbg::SeedSize];
|
||||||
|
|
||||||
|
if (smc::GenerateRandomBytes(seed, sizeof(seed)) != smc::Result::Success) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
g_drbg.Initialize(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeSeEvents() {
|
||||||
|
u64 irq_num;
|
||||||
|
smc::GetConfig(&irq_num, 1, SplConfigItem_SecurityEngineIrqNumber);
|
||||||
|
Handle hnd;
|
||||||
|
R_ASSERT(svcCreateInterruptEvent(&hnd, irq_num, 1));
|
||||||
|
eventLoadRemote(&g_se_event, hnd, true);
|
||||||
|
|
||||||
|
g_se_keyslot_available_event = CreateWriteOnlySystemEvent();
|
||||||
|
g_se_keyslot_available_event->Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeDeviceAddressSpace() {
|
||||||
|
constexpr u64 DeviceName_SE = 29;
|
||||||
|
|
||||||
|
/* Create Address Space. */
|
||||||
|
R_ASSERT(svcCreateDeviceAddressSpace(&g_se_das_hnd, 0, (1ul << 32)));
|
||||||
|
|
||||||
|
/* Attach it to the SE. */
|
||||||
|
R_ASSERT(svcAttachDeviceAddressSpace(DeviceName_SE, g_se_das_hnd));
|
||||||
|
|
||||||
|
const u64 work_buffer_addr = reinterpret_cast<u64>(g_work_buffer);
|
||||||
|
g_se_mapped_work_buffer_addr = WorkBufferMapBase + (work_buffer_addr & DeviceAddressSpaceAlignMask);
|
||||||
|
|
||||||
|
/* Map the work buffer for the SE. */
|
||||||
|
R_ASSERT(svcMapDeviceAddressSpaceAligned(g_se_das_hnd, CUR_PROCESS_HANDLE, work_buffer_addr, sizeof(g_work_buffer), g_se_mapped_work_buffer_addr, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RSA OAEP implementation helpers. */
|
||||||
|
void CalcMgf1AndXor(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||||
|
uint8_t *dst_u8 = reinterpret_cast<u8 *>(dst);
|
||||||
|
|
||||||
|
u32 ctr = 0;
|
||||||
|
while (dst_size > 0) {
|
||||||
|
size_t cur_size = SHA256_HASH_SIZE;
|
||||||
|
if (cur_size > dst_size) {
|
||||||
|
cur_size = dst_size;
|
||||||
|
}
|
||||||
|
dst_size -= cur_size;
|
||||||
|
|
||||||
|
u32 ctr_be = __builtin_bswap32(ctr++);
|
||||||
|
u8 hash[SHA256_HASH_SIZE];
|
||||||
|
{
|
||||||
|
Sha256Context ctx;
|
||||||
|
sha256ContextCreate(&ctx);
|
||||||
|
sha256ContextUpdate(&ctx, src, src_size);
|
||||||
|
sha256ContextUpdate(&ctx, &ctr_be, sizeof(ctr_be));
|
||||||
|
sha256ContextGetHash(&ctx, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < cur_size; i++) {
|
||||||
|
*(dst_u8++) ^= hash[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DecodeRsaOaep(void *dst, size_t dst_size, const void *label_digest, size_t label_digest_size, const void *src, size_t src_size) {
|
||||||
|
/* Very basic validation. */
|
||||||
|
if (dst_size == 0 || src_size != 0x100 || label_digest_size != SHA256_HASH_SIZE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 block[0x100];
|
||||||
|
std::memcpy(block, src, sizeof(block));
|
||||||
|
|
||||||
|
/* First, validate byte 0 == 0, and unmask DB. */
|
||||||
|
int invalid = block[0];
|
||||||
|
u8 *salt = block + 1;
|
||||||
|
u8 *db = salt + SHA256_HASH_SIZE;
|
||||||
|
CalcMgf1AndXor(salt, SHA256_HASH_SIZE, db, src_size - (1 + SHA256_HASH_SIZE));
|
||||||
|
CalcMgf1AndXor(db, src_size - (1 + SHA256_HASH_SIZE), salt, SHA256_HASH_SIZE);
|
||||||
|
|
||||||
|
/* Validate label digest. */
|
||||||
|
for (size_t i = 0; i < SHA256_HASH_SIZE; i++) {
|
||||||
|
invalid |= db[i] ^ reinterpret_cast<const u8 *>(label_digest)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Locate message after 00...0001 padding. */
|
||||||
|
const u8 *padded_msg = db + SHA256_HASH_SIZE;
|
||||||
|
size_t padded_msg_size = src_size - (1 + 2 * SHA256_HASH_SIZE);
|
||||||
|
size_t msg_ind = 0;
|
||||||
|
int not_found = 1;
|
||||||
|
int wrong_padding = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < padded_msg_size) {
|
||||||
|
int zero = (padded_msg[i] == 0);
|
||||||
|
int one = (padded_msg[i] == 1);
|
||||||
|
msg_ind += static_cast<size_t>(not_found & one) * (++i);
|
||||||
|
not_found &= ~one;
|
||||||
|
wrong_padding |= (not_found & ~zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalid | not_found | wrong_padding) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy message out. */
|
||||||
|
size_t msg_size = padded_msg_size - msg_ind;
|
||||||
|
if (msg_size > dst_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
std::memcpy(dst, padded_msg + msg_ind, msg_size);
|
||||||
|
return msg_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal RNG functionality. */
|
||||||
|
Result GenerateRandomBytesInternal(void *out, size_t size) {
|
||||||
|
if (!g_drbg.GenerateRandomBytes(out, size)) {
|
||||||
|
/* We need to reseed. */
|
||||||
|
{
|
||||||
|
u8 seed[CtrDrbg::SeedSize];
|
||||||
|
|
||||||
|
smc::Result res = smc::GenerateRandomBytes(seed, sizeof(seed));
|
||||||
|
if (res != smc::Result::Success) {
|
||||||
|
return smc::ConvertResult(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_drbg.Reseed(seed);
|
||||||
|
g_drbg.GenerateRandomBytes(out, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal async implementation functionality. */
|
||||||
|
void WaitSeOperationComplete() {
|
||||||
|
eventWait(&g_se_event, U64_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
smc::Result WaitCheckStatus(smc::AsyncOperationKey op_key) {
|
||||||
|
WaitSeOperationComplete();
|
||||||
|
|
||||||
|
smc::Result op_res;
|
||||||
|
smc::Result res = smc::CheckStatus(&op_res, op_key);
|
||||||
|
if (res != smc::Result::Success) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return op_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
smc::Result WaitGetResult(void *out_buf, size_t out_buf_size, smc::AsyncOperationKey op_key) {
|
||||||
|
WaitSeOperationComplete();
|
||||||
|
|
||||||
|
smc::Result op_res;
|
||||||
|
smc::Result res = smc::GetResult(&op_res, out_buf, out_buf_size, op_key);
|
||||||
|
if (res != smc::Result::Success) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return op_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal Keyslot utility. */
|
||||||
|
Result ValidateAesKeyslot(u32 keyslot, const void *owner) {
|
||||||
|
if (keyslot >= GetMaxKeyslots()) {
|
||||||
|
return ResultSplInvalidKeyslot;
|
||||||
|
}
|
||||||
|
if (g_keyslot_owners[keyslot] != owner && GetRuntimeFirmwareVersion() > FirmwareVersion_100) {
|
||||||
|
return ResultSplInvalidKeyslot;
|
||||||
|
}
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper to do a single AES block decryption. */
|
||||||
|
smc::Result DecryptAesBlock(u32 keyslot, void *dst, const void *src) {
|
||||||
|
struct DecryptAesBlockLayout {
|
||||||
|
SeCryptContext crypt_ctx;
|
||||||
|
u8 in_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE)));
|
||||||
|
u8 out_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE)));
|
||||||
|
};
|
||||||
|
DecryptAesBlockLayout *layout = reinterpret_cast<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));
|
||||||
|
|
||||||
|
armDCacheFlush(layout, sizeof(*layout));
|
||||||
|
{
|
||||||
|
std::scoped_lock<HosMutex> lk(g_async_op_lock);
|
||||||
|
smc::AsyncOperationKey op_key;
|
||||||
|
const IvCtr iv_ctr = {};
|
||||||
|
const u32 mode = smc::GetCryptAesMode(smc::CipherMode::CbcDecrypt, keyslot);
|
||||||
|
const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.out);
|
||||||
|
const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.in);
|
||||||
|
|
||||||
|
smc::Result res = smc::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, sizeof(layout->in_block));
|
||||||
|
if (res != smc::Result::Success) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = WaitCheckStatus(op_key)) != smc::Result::Success) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
armDCacheFlush(layout, sizeof(*layout));
|
||||||
|
|
||||||
|
std::memcpy(dst, layout->out_block, sizeof(layout->out_block));
|
||||||
|
return smc::Result::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implementation wrappers for API commands. */
|
||||||
|
Result ImportSecureExpModKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||||
|
struct ImportSecureExpModKeyLayout {
|
||||||
|
u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10];
|
||||||
|
};
|
||||||
|
ImportSecureExpModKeyLayout *layout = reinterpret_cast<ImportSecureExpModKeyLayout *>(g_work_buffer);
|
||||||
|
|
||||||
|
/* Validate size. */
|
||||||
|
if (src_size > sizeof(ImportSecureExpModKeyLayout)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(layout, src, src_size);
|
||||||
|
|
||||||
|
armDCacheFlush(layout, sizeof(*layout));
|
||||||
|
smc::Result smc_res;
|
||||||
|
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
|
||||||
|
smc_res = smc::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, static_cast<smc::DecryptOrImportMode>(option));
|
||||||
|
} else {
|
||||||
|
smc_res = smc::ImportSecureExpModKey(layout->data, src_size, access_key, key_source, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
return smc::ConvertResult(smc_res);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SecureExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size, smc::SecureExpModMode mode) {
|
||||||
|
struct SecureExpModLayout {
|
||||||
|
u8 base[0x100];
|
||||||
|
u8 mod[0x100];
|
||||||
|
};
|
||||||
|
SecureExpModLayout *layout = reinterpret_cast<SecureExpModLayout *>(g_work_buffer);
|
||||||
|
|
||||||
|
/* Validate sizes. */
|
||||||
|
if (base_size > sizeof(layout->base)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
if (mod_size > sizeof(layout->mod)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
if (out_size > WorkBufferSizeMax) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy data into work buffer. */
|
||||||
|
const size_t base_ofs = sizeof(layout->base) - base_size;
|
||||||
|
const size_t mod_ofs = sizeof(layout->mod) - mod_size;
|
||||||
|
std::memset(layout, 0, sizeof(*layout));
|
||||||
|
std::memcpy(layout->base + base_ofs, base, base_size);
|
||||||
|
std::memcpy(layout->mod + mod_ofs, mod, mod_size);
|
||||||
|
|
||||||
|
/* Do exp mod operation. */
|
||||||
|
armDCacheFlush(layout, sizeof(*layout));
|
||||||
|
{
|
||||||
|
std::scoped_lock<HosMutex> lk(g_async_op_lock);
|
||||||
|
smc::AsyncOperationKey op_key;
|
||||||
|
|
||||||
|
smc::Result res = smc::SecureExpMod(&op_key, layout->base, layout->mod, mode);
|
||||||
|
if (res != smc::Result::Success) {
|
||||||
|
return smc::ConvertResult(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != smc::Result::Success) {
|
||||||
|
return smc::ConvertResult(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
armDCacheFlush(g_work_buffer, sizeof(out_size));
|
||||||
|
|
||||||
|
std::memcpy(out, g_work_buffer, out_size);
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnwrapEsRsaOaepWrappedKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation, smc::EsKeyType type) {
|
||||||
|
struct UnwrapEsKeyLayout {
|
||||||
|
u8 base[0x100];
|
||||||
|
u8 mod[0x100];
|
||||||
|
};
|
||||||
|
UnwrapEsKeyLayout *layout = reinterpret_cast<UnwrapEsKeyLayout *>(g_work_buffer);
|
||||||
|
|
||||||
|
/* Validate sizes. */
|
||||||
|
if (base_size > sizeof(layout->base)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
if (mod_size > sizeof(layout->mod)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
if (label_digest_size > LabelDigestSizeMax) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy data into work buffer. */
|
||||||
|
const size_t base_ofs = sizeof(layout->base) - base_size;
|
||||||
|
const size_t mod_ofs = sizeof(layout->mod) - mod_size;
|
||||||
|
std::memset(layout, 0, sizeof(*layout));
|
||||||
|
std::memcpy(layout->base + base_ofs, base, base_size);
|
||||||
|
std::memcpy(layout->mod + mod_ofs, mod, mod_size);
|
||||||
|
|
||||||
|
/* Do exp mod operation. */
|
||||||
|
armDCacheFlush(layout, sizeof(*layout));
|
||||||
|
{
|
||||||
|
std::scoped_lock<HosMutex> lk(g_async_op_lock);
|
||||||
|
smc::AsyncOperationKey op_key;
|
||||||
|
|
||||||
|
smc::Result res = smc::UnwrapTitleKey(&op_key, layout->base, layout->mod, label_digest, label_digest_size, smc::GetUnwrapEsKeyOption(type, generation));
|
||||||
|
if (res != smc::Result::Success) {
|
||||||
|
return smc::ConvertResult(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = WaitGetResult(g_work_buffer, sizeof(*out_access_key), op_key)) != smc::Result::Success) {
|
||||||
|
return smc::ConvertResult(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
armDCacheFlush(g_work_buffer, sizeof(*out_access_key));
|
||||||
|
|
||||||
|
std::memcpy(out_access_key, g_work_buffer, sizeof(*out_access_key));
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialization. */
|
||||||
|
void Initialize() {
|
||||||
|
/* Initialize the Drbg. */
|
||||||
|
InitializeCtrDrbg();
|
||||||
|
/* Initialize SE interrupt + keyslot events. */
|
||||||
|
InitializeSeEvents();
|
||||||
|
/* Initialize DAS for the SE. */
|
||||||
|
InitializeDeviceAddressSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* General. */
|
||||||
|
Result GetConfig(u64 *out, SplConfigItem which) {
|
||||||
|
/* Nintendo explicitly blacklists package2 hash here, amusingly. */
|
||||||
|
/* This is not blacklisted in safemode, but we're never in safe mode... */
|
||||||
|
if (which == SplConfigItem_Package2Hash) {
|
||||||
|
return ResultSplInvalidArgument;
|
||||||
|
}
|
||||||
|
|
||||||
|
smc::Result res = smc::GetConfig(out, 1, which);
|
||||||
|
|
||||||
|
/* Nintendo has some special handling here for hardware type/is_retail. */
|
||||||
|
if (which == SplConfigItem_HardwareType && res == smc::Result::InvalidArgument) {
|
||||||
|
*out = 0;
|
||||||
|
res = smc::Result::Success;
|
||||||
|
}
|
||||||
|
if (which == SplConfigItem_IsRetail && res == smc::Result::InvalidArgument) {
|
||||||
|
*out = 0;
|
||||||
|
res = smc::Result::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return smc::ConvertResult(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size) {
|
||||||
|
struct ExpModLayout {
|
||||||
|
u8 base[0x100];
|
||||||
|
u8 exp[0x100];
|
||||||
|
u8 mod[0x100];
|
||||||
|
};
|
||||||
|
ExpModLayout *layout = reinterpret_cast<ExpModLayout *>(g_work_buffer);
|
||||||
|
|
||||||
|
/* Validate sizes. */
|
||||||
|
if (base_size > sizeof(layout->base)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
if (exp_size > sizeof(layout->exp)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
if (mod_size > sizeof(layout->mod)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
if (out_size > WorkBufferSizeMax) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy data into work buffer. */
|
||||||
|
const size_t base_ofs = sizeof(layout->base) - base_size;
|
||||||
|
const size_t mod_ofs = sizeof(layout->mod) - mod_size;
|
||||||
|
std::memset(layout, 0, sizeof(*layout));
|
||||||
|
std::memcpy(layout->base + base_ofs, base, base_size);
|
||||||
|
std::memcpy(layout->exp, exp, exp_size);
|
||||||
|
std::memcpy(layout->mod + mod_ofs, mod, mod_size);
|
||||||
|
|
||||||
|
/* Do exp mod operation. */
|
||||||
|
armDCacheFlush(layout, sizeof(*layout));
|
||||||
|
{
|
||||||
|
std::scoped_lock<HosMutex> lk(g_async_op_lock);
|
||||||
|
smc::AsyncOperationKey op_key;
|
||||||
|
|
||||||
|
smc::Result res = smc::ExpMod(&op_key, layout->base, layout->exp, exp_size, layout->mod);
|
||||||
|
if (res != smc::Result::Success) {
|
||||||
|
return smc::ConvertResult(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != smc::Result::Success) {
|
||||||
|
return smc::ConvertResult(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
armDCacheFlush(g_work_buffer, sizeof(out_size));
|
||||||
|
|
||||||
|
std::memcpy(out, g_work_buffer, out_size);
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetConfig(SplConfigItem which, u64 value) {
|
||||||
|
return smc::ConvertResult(smc::SetConfig(which, &value, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GenerateRandomBytes(void *out, size_t size) {
|
||||||
|
u8 *cur_dst = reinterpret_cast<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 is_retail;
|
||||||
|
R_TRY(GetConfig(&is_retail, SplConfigItem_IsRetail));
|
||||||
|
|
||||||
|
*out = (is_retail == 0);
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SetBootReason(BootReasonValue boot_reason) {
|
||||||
|
if (IsBootReasonSet()) {
|
||||||
|
return ResultSplBootReasonAlreadySet;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_boot_reason = boot_reason;
|
||||||
|
g_boot_reason_set = true;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetBootReason(BootReasonValue *out) {
|
||||||
|
if (!IsBootReasonSet()) {
|
||||||
|
return ResultSplBootReasonNotSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = GetBootReason();
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Crypto. */
|
||||||
|
Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option) {
|
||||||
|
return smc::ConvertResult(smc::GenerateAesKek(out_access_key, key_source, generation, option));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source) {
|
||||||
|
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
||||||
|
return smc::ConvertResult(smc::LoadAesKey(keyslot, access_key, key_source));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) {
|
||||||
|
smc::Result smc_rc;
|
||||||
|
|
||||||
|
static const KeySource s_generate_aes_key_source = {
|
||||||
|
.data = {0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}
|
||||||
|
};
|
||||||
|
|
||||||
|
ScopedAesKeyslot keyslot_holder;
|
||||||
|
R_TRY(keyslot_holder.Allocate());
|
||||||
|
|
||||||
|
smc_rc = smc::LoadAesKey(keyslot_holder.GetKeyslot(), access_key, s_generate_aes_key_source);
|
||||||
|
if (smc_rc == smc::Result::Success) {
|
||||||
|
smc_rc = DecryptAesBlock(keyslot_holder.GetKeyslot(), out_key, &key_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
return smc::ConvertResult(smc_rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option) {
|
||||||
|
static const KeySource s_decrypt_aes_key_source = {
|
||||||
|
.data = {0x11, 0x70, 0x24, 0x2B, 0x48, 0x69, 0x11, 0xF1, 0x11, 0xB0, 0x0C, 0x47, 0x7C, 0xC3, 0xEF, 0x7E}
|
||||||
|
};
|
||||||
|
|
||||||
|
AccessKey access_key;
|
||||||
|
R_TRY(GenerateAesKek(&access_key, s_decrypt_aes_key_source, generation, option));
|
||||||
|
|
||||||
|
return GenerateAesKey(out_key, access_key, key_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CryptAesCtr(void *dst, size_t dst_size, u32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr) {
|
||||||
|
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
||||||
|
|
||||||
|
/* Succeed immediately if there's nothing to crypt. */
|
||||||
|
if (src_size == 0) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate sizes. */
|
||||||
|
if (src_size > dst_size || src_size % AES_BLOCK_SIZE != 0) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We can only map 0x400000 aligned buffers for the SE. With that in mind, we have some math to do. */
|
||||||
|
const uintptr_t src_addr = reinterpret_cast<uintptr_t>(src);
|
||||||
|
const uintptr_t dst_addr = reinterpret_cast<uintptr_t>(dst);
|
||||||
|
const uintptr_t src_addr_page_aligned = src_addr & ~0xFFFul;
|
||||||
|
const uintptr_t dst_addr_page_aligned = dst_addr & ~0xFFFul;
|
||||||
|
const size_t src_size_page_aligned = ((src_addr + src_size + 0xFFFul) & ~0xFFFul) - src_addr_page_aligned;
|
||||||
|
const size_t dst_size_page_aligned = ((dst_addr + dst_size + 0xFFFul) & ~0xFFFul) - dst_addr_page_aligned;
|
||||||
|
const u32 src_se_map_addr = CryptAesInMapBase + (src_addr_page_aligned & DeviceAddressSpaceAlignMask);
|
||||||
|
const u32 dst_se_map_addr = CryptAesOutMapBase + (dst_addr_page_aligned & DeviceAddressSpaceAlignMask);
|
||||||
|
const u32 src_se_addr = CryptAesInMapBase + (src_addr & DeviceAddressSpaceAlignMask);
|
||||||
|
const u32 dst_se_addr = CryptAesOutMapBase + (dst_addr & DeviceAddressSpaceAlignMask);
|
||||||
|
|
||||||
|
/* Validate aligned sizes. */
|
||||||
|
if (src_size_page_aligned > CryptAesSizeMax || dst_size_page_aligned > CryptAesSizeMax) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helpers for mapping/unmapping. */
|
||||||
|
DeviceAddressSpaceMapHelper in_mapper(g_se_das_hnd, src_se_map_addr, src_addr_page_aligned, src_size_page_aligned, 1);
|
||||||
|
DeviceAddressSpaceMapHelper out_mapper(g_se_das_hnd, dst_se_map_addr, dst_addr_page_aligned, dst_size_page_aligned, 2);
|
||||||
|
|
||||||
|
/* Setup SE linked list entries. */
|
||||||
|
SeCryptContext *crypt_ctx = reinterpret_cast<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;
|
||||||
|
|
||||||
|
armDCacheFlush(crypt_ctx, sizeof(*crypt_ctx));
|
||||||
|
armDCacheFlush(const_cast<void *>(src), src_size);
|
||||||
|
armDCacheFlush(dst, dst_size);
|
||||||
|
{
|
||||||
|
std::scoped_lock<HosMutex> lk(g_async_op_lock);
|
||||||
|
smc::AsyncOperationKey op_key;
|
||||||
|
const u32 mode = smc::GetCryptAesMode(smc::CipherMode::Ctr, keyslot);
|
||||||
|
const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, out);
|
||||||
|
const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, in);
|
||||||
|
|
||||||
|
smc::Result res = smc::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, src_size);
|
||||||
|
if (res != smc::Result::Success) {
|
||||||
|
return smc::ConvertResult(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = WaitCheckStatus(op_key)) != smc::Result::Success) {
|
||||||
|
return smc::ConvertResult(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
armDCacheFlush(dst, dst_size);
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size) {
|
||||||
|
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
||||||
|
|
||||||
|
if (size > WorkBufferSizeMax) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(g_work_buffer, data, size);
|
||||||
|
return smc::ConvertResult(smc::ComputeCmac(out_cmac, keyslot, g_work_buffer, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner) {
|
||||||
|
if (GetRuntimeFirmwareVersion() <= FirmwareVersion_100) {
|
||||||
|
/* On 1.0.0, keyslots were kind of a wild west. */
|
||||||
|
*out_keyslot = 0;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < GetMaxKeyslots(); i++) {
|
||||||
|
if (g_keyslot_owners[i] == 0) {
|
||||||
|
g_keyslot_owners[i] = owner;
|
||||||
|
*out_keyslot = static_cast<u32>(i);
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_se_keyslot_available_event->Clear();
|
||||||
|
return ResultSplOutOfKeyslots;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FreeAesKeyslot(u32 keyslot, const void *owner) {
|
||||||
|
if (GetRuntimeFirmwareVersion() <= FirmwareVersion_100) {
|
||||||
|
/* On 1.0.0, keyslots were kind of a wild west. */
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
||||||
|
|
||||||
|
/* Clear the keyslot. */
|
||||||
|
{
|
||||||
|
AccessKey access_key = {};
|
||||||
|
KeySource key_source = {};
|
||||||
|
|
||||||
|
smc::LoadAesKey(keyslot, access_key, key_source);
|
||||||
|
}
|
||||||
|
g_keyslot_owners[keyslot] = nullptr;
|
||||||
|
g_se_keyslot_available_event->Signal();
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RSA. */
|
||||||
|
Result DecryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||||
|
struct DecryptRsaPrivateKeyLayout {
|
||||||
|
u8 data[RsaPrivateKeySize + RsaPrivateKeyMetaSize];
|
||||||
|
};
|
||||||
|
DecryptRsaPrivateKeyLayout *layout = reinterpret_cast<DecryptRsaPrivateKeyLayout *>(g_work_buffer);
|
||||||
|
|
||||||
|
/* Validate size. */
|
||||||
|
if (src_size < RsaPrivateKeyMetaSize || src_size > sizeof(DecryptRsaPrivateKeyLayout)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(layout->data, src, src_size);
|
||||||
|
armDCacheFlush(layout, sizeof(*layout));
|
||||||
|
|
||||||
|
smc::Result smc_res;
|
||||||
|
size_t copy_size = 0;
|
||||||
|
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
|
||||||
|
copy_size = std::min(dst_size, src_size - RsaPrivateKeyMetaSize);
|
||||||
|
smc_res = smc::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, smc::DecryptOrImportMode::DecryptRsaPrivateKey);
|
||||||
|
} else {
|
||||||
|
smc_res = smc::DecryptRsaPrivateKey(©_size, layout->data, src_size, access_key, key_source, option);
|
||||||
|
copy_size = std::min(dst_size, copy_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
armDCacheFlush(layout, sizeof(*layout));
|
||||||
|
if (smc_res == smc::Result::Success) {
|
||||||
|
std::memcpy(dst, layout->data, copy_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return smc::ConvertResult(smc_res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SSL */
|
||||||
|
Result ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) {
|
||||||
|
return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast<u32>(smc::DecryptOrImportMode::ImportSslKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) {
|
||||||
|
return SecureExpMod(out, out_size, base, base_size, mod, mod_size, smc::SecureExpModMode::Ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ES */
|
||||||
|
Result ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||||
|
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
|
||||||
|
return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast<u32>(smc::DecryptOrImportMode::ImportEsKey));
|
||||||
|
} else {
|
||||||
|
struct ImportEsKeyLayout {
|
||||||
|
u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10];
|
||||||
|
};
|
||||||
|
ImportEsKeyLayout *layout = reinterpret_cast<ImportEsKeyLayout *>(g_work_buffer);
|
||||||
|
|
||||||
|
/* Validate size. */
|
||||||
|
if (src_size > sizeof(ImportEsKeyLayout)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(layout, src, src_size);
|
||||||
|
|
||||||
|
armDCacheFlush(layout, sizeof(*layout));
|
||||||
|
return smc::ConvertResult(smc::ImportEsKey(layout->data, src_size, access_key, key_source, option));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnwrapTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation) {
|
||||||
|
return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsKeyType::TitleKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation) {
|
||||||
|
return smc::ConvertResult(smc::UnwrapCommonTitleKey(out_access_key, key_source, generation));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) {
|
||||||
|
return ImportSecureExpModKey(src, src_size, access_key, key_source, static_cast<u32>(smc::DecryptOrImportMode::ImportDrmKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DrmExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) {
|
||||||
|
return SecureExpMod(out, out_size, base, base_size, mod, mod_size, smc::SecureExpModMode::Drm);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnwrapElicenseKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation) {
|
||||||
|
return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsKeyType::ElicenseKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LoadElicenseKey(u32 keyslot, const void *owner, const AccessKey &access_key) {
|
||||||
|
/* Right now, this is just literally the same function as LoadTitleKey in N's impl. */
|
||||||
|
return LoadTitleKey(keyslot, owner, access_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FS */
|
||||||
|
Result ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
||||||
|
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
|
||||||
|
option = static_cast<u32>(smc::DecryptOrImportMode::ImportLotusKey);
|
||||||
|
}
|
||||||
|
return ImportSecureExpModKey(src, src_size, access_key, key_source, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DecryptLotusMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size) {
|
||||||
|
/* Validate sizes. */
|
||||||
|
if (dst_size > WorkBufferSizeMax || label_digest_size != LabelDigestSizeMax) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nintendo doesn't check this result code, but we will. */
|
||||||
|
R_TRY(SecureExpMod(g_work_buffer, 0x100, base, base_size, mod, mod_size, smc::SecureExpModMode::Lotus));
|
||||||
|
|
||||||
|
size_t data_size = DecodeRsaOaep(dst, dst_size, label_digest, label_digest_size, g_work_buffer, 0x100);
|
||||||
|
if (data_size == 0) {
|
||||||
|
return ResultSplDecryptionFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_size = static_cast<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 LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key) {
|
||||||
|
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
||||||
|
return smc::ConvertResult(smc::LoadTitleKey(keyslot, access_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetPackage2Hash(void *dst, const size_t size) {
|
||||||
|
u64 hash[4];
|
||||||
|
|
||||||
|
if (size < sizeof(hash)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
smc::Result smc_res;
|
||||||
|
if ((smc_res = smc::GetConfig(hash, 4, SplConfigItem_Package2Hash)) != smc::Result::Success) {
|
||||||
|
return smc::ConvertResult(smc_res);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(dst, hash, sizeof(hash));
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Manu. */
|
||||||
|
Result ReEncryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option) {
|
||||||
|
struct ReEncryptRsaPrivateKeyLayout {
|
||||||
|
u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10];
|
||||||
|
AccessKey access_key_dec;
|
||||||
|
KeySource source_dec;
|
||||||
|
AccessKey access_key_enc;
|
||||||
|
KeySource source_enc;
|
||||||
|
};
|
||||||
|
ReEncryptRsaPrivateKeyLayout *layout = reinterpret_cast<ReEncryptRsaPrivateKeyLayout *>(g_work_buffer);
|
||||||
|
|
||||||
|
/* Validate size. */
|
||||||
|
if (src_size < RsaPrivateKeyMetaSize || src_size > sizeof(ReEncryptRsaPrivateKeyLayout)) {
|
||||||
|
return ResultSplInvalidSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(layout, src, src_size);
|
||||||
|
layout->access_key_dec = access_key_dec;
|
||||||
|
layout->source_dec = source_dec;
|
||||||
|
layout->access_key_enc = access_key_enc;
|
||||||
|
layout->source_enc = source_enc;
|
||||||
|
|
||||||
|
armDCacheFlush(layout, sizeof(*layout));
|
||||||
|
|
||||||
|
smc::Result smc_res = smc::ReEncryptRsaPrivateKey(layout->data, src_size, layout->access_key_dec, layout->source_dec, layout->access_key_enc, layout->source_enc, option);
|
||||||
|
if (smc_res == smc::Result::Success) {
|
||||||
|
size_t copy_size = std::min(dst_size, src_size);
|
||||||
|
armDCacheFlush(layout, copy_size);
|
||||||
|
std::memcpy(dst, layout->data, copy_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return smc::ConvertResult(smc_res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper. */
|
||||||
|
Result FreeAesKeyslots(const void *owner) {
|
||||||
|
for (size_t i = 0; i < GetMaxKeyslots(); i++) {
|
||||||
|
if (g_keyslot_owners[i] == owner) {
|
||||||
|
FreeAesKeyslot(i, owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle GetAesKeyslotAvailableEventHandle() {
|
||||||
|
return g_se_keyslot_available_event->GetHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
77
stratosphere/spl/source/spl_api.hpp
Normal file
77
stratosphere/spl/source/spl_api.hpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "spl_types.hpp"
|
||||||
|
|
||||||
|
namespace sts::spl {
|
||||||
|
|
||||||
|
/* Initialization. */
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
|
/* General. */
|
||||||
|
Result GetConfig(u64 *out, SplConfigItem which);
|
||||||
|
Result ExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size);
|
||||||
|
Result SetConfig(SplConfigItem which, u64 value);
|
||||||
|
Result GenerateRandomBytes(void *out, size_t size);
|
||||||
|
Result IsDevelopment(bool *out);
|
||||||
|
Result SetBootReason(BootReasonValue boot_reason);
|
||||||
|
Result GetBootReason(BootReasonValue *out);
|
||||||
|
|
||||||
|
/* Crypto. */
|
||||||
|
Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option);
|
||||||
|
Result LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source);
|
||||||
|
Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source);
|
||||||
|
Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option);
|
||||||
|
Result CryptAesCtr(void *dst, size_t dst_size, u32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr);
|
||||||
|
Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size);
|
||||||
|
Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner);
|
||||||
|
Result FreeAesKeyslot(u32 keyslot, const void *owner);
|
||||||
|
|
||||||
|
/* RSA. */
|
||||||
|
Result DecryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
||||||
|
|
||||||
|
/* SSL */
|
||||||
|
Result ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
|
||||||
|
Result SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size);
|
||||||
|
|
||||||
|
/* ES */
|
||||||
|
Result ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
||||||
|
Result UnwrapTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation);
|
||||||
|
Result UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation);
|
||||||
|
Result ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
|
||||||
|
Result DrmExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size);
|
||||||
|
Result UnwrapElicenseKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation);
|
||||||
|
Result LoadElicenseKey(u32 keyslot, const void *owner, const AccessKey &access_key);
|
||||||
|
|
||||||
|
/* FS */
|
||||||
|
Result ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
||||||
|
Result DecryptLotusMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size);
|
||||||
|
Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which);
|
||||||
|
Result LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key);
|
||||||
|
Result GetPackage2Hash(void *dst, const size_t size);
|
||||||
|
|
||||||
|
/* Manu. */
|
||||||
|
Result ReEncryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option);
|
||||||
|
|
||||||
|
/* Helper. */
|
||||||
|
Result FreeAesKeyslots(const void *owner);
|
||||||
|
Handle GetAesKeyslotAvailableEventHandle();
|
||||||
|
|
||||||
|
}
|
|
@ -18,39 +18,49 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_crypto_service.hpp"
|
#include "spl_crypto_service.hpp"
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
|
||||||
Result CryptoService::GenerateAesKek(Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option) {
|
namespace sts::spl {
|
||||||
return this->GetSecureMonitorWrapper()->GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result CryptoService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) {
|
CryptoService::~CryptoService() {
|
||||||
return this->GetSecureMonitorWrapper()->LoadAesKey(keyslot, this, access_key, key_source);
|
/* Free any keyslots this service is using. */
|
||||||
}
|
spl::FreeAesKeyslots(this);
|
||||||
|
}
|
||||||
|
|
||||||
Result CryptoService::GenerateAesKey(Out<AesKey> out_key, AccessKey access_key, KeySource key_source) {
|
Result CryptoService::GenerateAesKek(Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option) {
|
||||||
return this->GetSecureMonitorWrapper()->GenerateAesKey(out_key.GetPointer(), access_key, key_source);
|
return spl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CryptoService::DecryptAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option) {
|
Result CryptoService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) {
|
||||||
return this->GetSecureMonitorWrapper()->DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
return spl::LoadAesKey(keyslot, this, access_key, key_source);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CryptoService::CryptAesCtr(OutBuffer<u8, BufferType_Type1> out_buf, u32 keyslot, InBuffer<u8, BufferType_Type1> in_buf, IvCtr iv_ctr) {
|
Result CryptoService::GenerateAesKey(Out<AesKey> out_key, AccessKey access_key, KeySource key_source) {
|
||||||
return this->GetSecureMonitorWrapper()->CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
|
return spl::GenerateAesKey(out_key.GetPointer(), access_key, key_source);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CryptoService::ComputeCmac(Out<Cmac> out_cmac, u32 keyslot, InPointer<u8> in_buf) {
|
Result CryptoService::DecryptAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option) {
|
||||||
return this->GetSecureMonitorWrapper()->ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements);
|
return spl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CryptoService::AllocateAesKeyslot(Out<u32> out_keyslot) {
|
Result CryptoService::CryptAesCtr(OutBuffer<u8, BufferType_Type1> out_buf, u32 keyslot, InBuffer<u8, BufferType_Type1> in_buf, IvCtr iv_ctr) {
|
||||||
return this->GetSecureMonitorWrapper()->AllocateAesKeyslot(out_keyslot.GetPointer(), this);
|
return spl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CryptoService::FreeAesKeyslot(u32 keyslot) {
|
Result CryptoService::ComputeCmac(Out<Cmac> out_cmac, u32 keyslot, InPointer<u8> in_buf) {
|
||||||
return this->GetSecureMonitorWrapper()->FreeAesKeyslot(keyslot, this);
|
return spl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result CryptoService::AllocateAesKeyslot(Out<u32> out_keyslot) {
|
||||||
|
return spl::AllocateAesKeyslot(out_keyslot.GetPointer(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CryptoService::FreeAesKeyslot(u32 keyslot) {
|
||||||
|
return spl::FreeAesKeyslot(keyslot, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CryptoService::GetAesKeyslotAvailableEvent(Out<CopiedHandle> out_hnd) {
|
||||||
|
out_hnd.SetValue(spl::GetAesKeyslotAvailableEventHandle());
|
||||||
|
}
|
||||||
|
|
||||||
void CryptoService::GetAesKeyslotAvailableEvent(Out<CopiedHandle> out_hnd) {
|
|
||||||
out_hnd.SetValue(this->GetSecureMonitorWrapper()->GetAesKeyslotAvailableEventHandle());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,44 +21,42 @@
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
#include "spl_general_service.hpp"
|
#include "spl_general_service.hpp"
|
||||||
|
|
||||||
class CryptoService : public GeneralService {
|
namespace sts::spl {
|
||||||
public:
|
|
||||||
CryptoService(SecureMonitorWrapper *sw) : GeneralService(sw) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~CryptoService() {
|
class CryptoService : public GeneralService {
|
||||||
this->GetSecureMonitorWrapper()->FreeAesKeyslots(this);
|
public:
|
||||||
}
|
CryptoService() : GeneralService() { /* ... */ }
|
||||||
protected:
|
virtual ~CryptoService();
|
||||||
/* Actual commands. */
|
protected:
|
||||||
virtual Result GenerateAesKek(Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option);
|
/* Actual commands. */
|
||||||
virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source);
|
virtual Result GenerateAesKek(Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option);
|
||||||
virtual Result GenerateAesKey(Out<AesKey> out_key, AccessKey access_key, KeySource key_source);
|
virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source);
|
||||||
virtual Result DecryptAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option);
|
virtual Result GenerateAesKey(Out<AesKey> out_key, AccessKey access_key, KeySource key_source);
|
||||||
virtual Result CryptAesCtr(OutBuffer<u8, BufferType_Type1> out_buf, u32 keyslot, InBuffer<u8, BufferType_Type1> in_buf, IvCtr iv_ctr);
|
virtual Result DecryptAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option);
|
||||||
virtual Result ComputeCmac(Out<Cmac> out_cmac, u32 keyslot, InPointer<u8> in_buf);
|
virtual Result CryptAesCtr(OutBuffer<u8, BufferType_Type1> out_buf, u32 keyslot, InBuffer<u8, BufferType_Type1> in_buf, IvCtr iv_ctr);
|
||||||
virtual Result AllocateAesKeyslot(Out<u32> out_keyslot);
|
virtual Result ComputeCmac(Out<Cmac> out_cmac, u32 keyslot, InPointer<u8> in_buf);
|
||||||
virtual Result FreeAesKeyslot(u32 keyslot);
|
virtual Result AllocateAesKeyslot(Out<u32> out_keyslot);
|
||||||
virtual void GetAesKeyslotAvailableEvent(Out<CopiedHandle> out_hnd);
|
virtual Result FreeAesKeyslot(u32 keyslot);
|
||||||
public:
|
virtual void GetAesKeyslotAvailableEvent(Out<CopiedHandle> out_hnd);
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
public:
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetConfig, &CryptoService::GetConfig, CryptoService>(),
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ExpMod, &CryptoService::ExpMod, CryptoService>(),
|
MakeServiceCommandMetaEx<CommandId::GetConfig, &CryptoService::GetConfig, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetConfig, &CryptoService::SetConfig, CryptoService>(),
|
MakeServiceCommandMetaEx<CommandId::ExpMod, &CryptoService::ExpMod, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateRandomBytes, &CryptoService::GenerateRandomBytes, CryptoService>(),
|
MakeServiceCommandMetaEx<CommandId::SetConfig, &CryptoService::SetConfig, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_IsDevelopment, &CryptoService::IsDevelopment, CryptoService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateRandomBytes, &CryptoService::GenerateRandomBytes, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetBootReason, &CryptoService::SetBootReason, CryptoService, FirmwareVersion_300>(),
|
MakeServiceCommandMetaEx<CommandId::IsDevelopment, &CryptoService::IsDevelopment, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetBootReason, &CryptoService::GetBootReason, CryptoService, FirmwareVersion_300>(),
|
MakeServiceCommandMetaEx<CommandId::SetBootReason, &CryptoService::SetBootReason, CryptoService, FirmwareVersion_300>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKek, &CryptoService::GenerateAesKek, CryptoService>(),
|
MakeServiceCommandMetaEx<CommandId::GetBootReason, &CryptoService::GetBootReason, CryptoService, FirmwareVersion_300>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_LoadAesKey, &CryptoService::LoadAesKey, CryptoService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKek, &CryptoService::GenerateAesKek, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKey, &CryptoService::GenerateAesKey, CryptoService>(),
|
MakeServiceCommandMetaEx<CommandId::LoadAesKey, &CryptoService::LoadAesKey, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptAesKey, &CryptoService::DecryptAesKey, CryptoService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKey, &CryptoService::GenerateAesKey, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_CryptAesCtr, &CryptoService::CryptAesCtr, CryptoService>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptAesKey, &CryptoService::DecryptAesKey, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ComputeCmac, &CryptoService::ComputeCmac, CryptoService>(),
|
MakeServiceCommandMetaEx<CommandId::CryptAesCtr, &CryptoService::CryptAesCtr, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_AllocateAesKeyslot, &CryptoService::AllocateAesKeyslot, CryptoService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::ComputeCmac, &CryptoService::ComputeCmac, CryptoService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_FreeAesKeyslot, &CryptoService::FreeAesKeyslot, CryptoService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::AllocateAesKeyslot, &CryptoService::AllocateAesKeyslot, CryptoService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetAesKeyslotAvailableEvent, &CryptoService::GetAesKeyslotAvailableEvent, CryptoService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::FreeAesKeyslot, &CryptoService::FreeAesKeyslot, CryptoService, FirmwareVersion_200>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::GetAesKeyslotAvailableEvent, &CryptoService::GetAesKeyslotAvailableEvent, CryptoService, FirmwareVersion_200>(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
}
|
||||||
};
|
|
||||||
|
|
|
@ -20,62 +20,66 @@
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
#include "spl_ctr_drbg.hpp"
|
#include "spl_ctr_drbg.hpp"
|
||||||
|
|
||||||
void CtrDrbg::Update(const void *data) {
|
namespace sts::spl {
|
||||||
aes128ContextCreate(&this->aes_ctx, this->key, true);
|
|
||||||
for (size_t offset = 0; offset < sizeof(this->work[1]); offset += BlockSize) {
|
void CtrDrbg::Update(const void *data) {
|
||||||
IncrementCounter(this->counter);
|
aes128ContextCreate(&this->aes_ctx, this->key, true);
|
||||||
aes128EncryptBlock(&this->aes_ctx, &this->work[1][offset], this->counter);
|
for (size_t offset = 0; offset < sizeof(this->work[1]); offset += BlockSize) {
|
||||||
|
IncrementCounter(this->counter);
|
||||||
|
aes128EncryptBlock(&this->aes_ctx, &this->work[1][offset], this->counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
Xor(this->work[1], data, sizeof(this->work[1]));
|
||||||
|
|
||||||
|
std::memcpy(this->key, &this->work[1][0], sizeof(this->key));
|
||||||
|
std::memcpy(this->counter, &this->work[1][BlockSize], sizeof(this->key));
|
||||||
}
|
}
|
||||||
|
|
||||||
Xor(this->work[1], data, sizeof(this->work[1]));
|
void CtrDrbg::Initialize(const void *seed) {
|
||||||
|
std::memcpy(this->work[0], seed, sizeof(this->work[0]));
|
||||||
|
std::memset(this->key, 0, sizeof(this->key));
|
||||||
|
std::memset(this->counter, 0, sizeof(this->counter));
|
||||||
|
this->Update(this->work[0]);
|
||||||
|
this->reseed_counter = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CtrDrbg::Reseed(const void *seed) {
|
||||||
|
std::memcpy(this->work[0], seed, sizeof(this->work[0]));
|
||||||
|
this->Update(this->work[0]);
|
||||||
|
this->reseed_counter = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CtrDrbg::GenerateRandomBytes(void *out, size_t size) {
|
||||||
|
if (size > MaxRequestSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->reseed_counter > ReseedInterval) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
aes128ContextCreate(&this->aes_ctx, this->key, true);
|
||||||
|
u8 *cur_dst = reinterpret_cast<u8 *>(out);
|
||||||
|
|
||||||
|
size_t aligned_size = (size & ~(BlockSize - 1));
|
||||||
|
for (size_t offset = 0; offset < aligned_size; offset += BlockSize) {
|
||||||
|
IncrementCounter(this->counter);
|
||||||
|
aes128EncryptBlock(&this->aes_ctx, cur_dst, this->counter);
|
||||||
|
cur_dst += BlockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > aligned_size) {
|
||||||
|
IncrementCounter(this->counter);
|
||||||
|
aes128EncryptBlock(&this->aes_ctx, this->work[1], this->counter);
|
||||||
|
std::memcpy(cur_dst, this->work[1], size - aligned_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memset(this->work[0], 0, sizeof(this->work[0]));
|
||||||
|
this->Update(this->work[0]);
|
||||||
|
|
||||||
|
this->reseed_counter++;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
std::memcpy(this->key, &this->work[1][0], sizeof(this->key));
|
|
||||||
std::memcpy(this->counter, &this->work[1][BlockSize], sizeof(this->key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CtrDrbg::Initialize(const void *seed) {
|
|
||||||
std::memcpy(this->work[0], seed, sizeof(this->work[0]));
|
|
||||||
std::memset(this->key, 0, sizeof(this->key));
|
|
||||||
std::memset(this->counter, 0, sizeof(this->counter));
|
|
||||||
this->Update(this->work[0]);
|
|
||||||
this->reseed_counter = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CtrDrbg::Reseed(const void *seed) {
|
|
||||||
std::memcpy(this->work[0], seed, sizeof(this->work[0]));
|
|
||||||
this->Update(this->work[0]);
|
|
||||||
this->reseed_counter = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CtrDrbg::GenerateRandomBytes(void *out, size_t size) {
|
|
||||||
if (size > MaxRequestSize) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->reseed_counter > ReseedInterval) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
aes128ContextCreate(&this->aes_ctx, this->key, true);
|
|
||||||
u8 *cur_dst = reinterpret_cast<u8 *>(out);
|
|
||||||
|
|
||||||
size_t aligned_size = (size & ~(BlockSize - 1));
|
|
||||||
for (size_t offset = 0; offset < aligned_size; offset += BlockSize) {
|
|
||||||
IncrementCounter(this->counter);
|
|
||||||
aes128EncryptBlock(&this->aes_ctx, cur_dst, this->counter);
|
|
||||||
cur_dst += BlockSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size > aligned_size) {
|
|
||||||
IncrementCounter(this->counter);
|
|
||||||
aes128EncryptBlock(&this->aes_ctx, this->work[1], this->counter);
|
|
||||||
std::memcpy(cur_dst, this->work[1], size - aligned_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memset(this->work[0], 0, sizeof(this->work[0]));
|
|
||||||
this->Update(this->work[0]);
|
|
||||||
|
|
||||||
this->reseed_counter++;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
|
@ -20,41 +20,45 @@
|
||||||
|
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
|
|
||||||
/* Nintendo implements CTR_DRBG for their csrng. We will do the same. */
|
namespace sts::spl {
|
||||||
class CtrDrbg {
|
|
||||||
public:
|
|
||||||
static constexpr size_t MaxRequestSize = 0x10000;
|
|
||||||
static constexpr size_t ReseedInterval = 0x7FFFFFF0;
|
|
||||||
static constexpr size_t BlockSize = AES_BLOCK_SIZE;
|
|
||||||
static constexpr size_t SeedSize = 2 * AES_BLOCK_SIZE;
|
|
||||||
private:
|
|
||||||
Aes128Context aes_ctx;
|
|
||||||
u8 counter[BlockSize];
|
|
||||||
u8 key[BlockSize];
|
|
||||||
u8 work[2][SeedSize];
|
|
||||||
u32 reseed_counter;
|
|
||||||
private:
|
|
||||||
static void Xor(void *dst, const void *src, size_t size) {
|
|
||||||
const u8 *src_u8 = reinterpret_cast<const u8 *>(src);
|
|
||||||
u8 *dst_u8 = reinterpret_cast<u8 *>(dst);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
/* Nintendo implements CTR_DRBG for their csrng. We will do the same. */
|
||||||
dst_u8[i] ^= src_u8[i];
|
class CtrDrbg {
|
||||||
|
public:
|
||||||
|
static constexpr size_t MaxRequestSize = 0x10000;
|
||||||
|
static constexpr size_t ReseedInterval = 0x7FFFFFF0;
|
||||||
|
static constexpr size_t BlockSize = AES_BLOCK_SIZE;
|
||||||
|
static constexpr size_t SeedSize = 2 * AES_BLOCK_SIZE;
|
||||||
|
private:
|
||||||
|
Aes128Context aes_ctx;
|
||||||
|
u8 counter[BlockSize];
|
||||||
|
u8 key[BlockSize];
|
||||||
|
u8 work[2][SeedSize];
|
||||||
|
u32 reseed_counter;
|
||||||
|
private:
|
||||||
|
static void Xor(void *dst, const void *src, size_t size) {
|
||||||
|
const u8 *src_u8 = reinterpret_cast<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) {
|
static void IncrementCounter(void *ctr) {
|
||||||
u64 *ctr_64 = reinterpret_cast<u64 *>(ctr);
|
u64 *ctr_64 = reinterpret_cast<u64 *>(ctr);
|
||||||
|
|
||||||
ctr_64[1] = __builtin_bswap64(__builtin_bswap64(ctr_64[1]) + 1);
|
ctr_64[1] = __builtin_bswap64(__builtin_bswap64(ctr_64[1]) + 1);
|
||||||
if (!ctr_64[1]) {
|
if (!ctr_64[1]) {
|
||||||
ctr_64[0] = __builtin_bswap64(__builtin_bswap64(ctr_64[0]) + 1);
|
ctr_64[0] = __builtin_bswap64(__builtin_bswap64(ctr_64[0]) + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
private:
|
||||||
private:
|
void Update(const void *data);
|
||||||
void Update(const void *data);
|
public:
|
||||||
public:
|
void Initialize(const void *seed);
|
||||||
void Initialize(const void *seed);
|
void Reseed(const void *seed);
|
||||||
void Reseed(const void *seed);
|
bool GenerateRandomBytes(void *out, size_t size);
|
||||||
bool GenerateRandomBytes(void *out, size_t size);
|
};
|
||||||
};
|
|
||||||
|
}
|
||||||
|
|
|
@ -18,103 +18,108 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_deprecated_service.hpp"
|
#include "spl_deprecated_service.hpp"
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
|
||||||
Result DeprecatedService::GetConfig(Out<u64> out, u32 which) {
|
namespace sts::spl {
|
||||||
return this->GetSecureMonitorWrapper()->GetConfig(out.GetPointer(), static_cast<SplConfigItem>(which));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result DeprecatedService::ExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> exp, InPointer<u8> mod) {
|
Result DeprecatedService::GetConfig(Out<u64> out, u32 which) {
|
||||||
return this->GetSecureMonitorWrapper()->ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements);
|
return spl::GetConfig(out.GetPointer(), static_cast<SplConfigItem>(which));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::GenerateAesKek(Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option) {
|
Result DeprecatedService::ExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> exp, InPointer<u8> mod) {
|
||||||
return this->GetSecureMonitorWrapper()->GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
return spl::ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) {
|
Result DeprecatedService::GenerateAesKek(Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option) {
|
||||||
return this->GetSecureMonitorWrapper()->LoadAesKey(keyslot, this, access_key, key_source);
|
return spl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::GenerateAesKey(Out<AesKey> out_key, AccessKey access_key, KeySource key_source) {
|
Result DeprecatedService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) {
|
||||||
return this->GetSecureMonitorWrapper()->GenerateAesKey(out_key.GetPointer(), access_key, key_source);
|
return spl::LoadAesKey(keyslot, this, access_key, key_source);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::SetConfig(u32 which, u64 value) {
|
Result DeprecatedService::GenerateAesKey(Out<AesKey> out_key, AccessKey access_key, KeySource key_source) {
|
||||||
return this->GetSecureMonitorWrapper()->SetConfig(static_cast<SplConfigItem>(which), value);
|
return spl::GenerateAesKey(out_key.GetPointer(), access_key, key_source);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::GenerateRandomBytes(OutPointerWithClientSize<u8> out) {
|
Result DeprecatedService::SetConfig(u32 which, u64 value) {
|
||||||
return this->GetSecureMonitorWrapper()->GenerateRandomBytes(out.pointer, out.num_elements);
|
return spl::SetConfig(static_cast<SplConfigItem>(which), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::ImportLotusKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
Result DeprecatedService::GenerateRandomBytes(OutPointerWithClientSize<u8> out) {
|
||||||
return this->GetSecureMonitorWrapper()->ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option);
|
return spl::GenerateRandomBytes(out.pointer, out.num_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::DecryptLotusMessage(Out<u32> out_size, OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest) {
|
Result DeprecatedService::ImportLotusKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||||
return this->GetSecureMonitorWrapper()->DecryptLotusMessage(out_size.GetPointer(), out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements);
|
return spl::ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::IsDevelopment(Out<bool> is_dev) {
|
Result DeprecatedService::DecryptLotusMessage(Out<u32> out_size, OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest) {
|
||||||
return this->GetSecureMonitorWrapper()->IsDevelopment(is_dev.GetPointer());
|
return spl::DecryptLotusMessage(out_size.GetPointer(), out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::GenerateSpecificAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which) {
|
Result DeprecatedService::IsDevelopment(Out<bool> is_dev) {
|
||||||
return this->GetSecureMonitorWrapper()->GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
|
return spl::IsDevelopment(is_dev.GetPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::DecryptRsaPrivateKey(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
Result DeprecatedService::GenerateSpecificAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which) {
|
||||||
return this->GetSecureMonitorWrapper()->DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option);
|
return spl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::DecryptAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option) {
|
Result DeprecatedService::DecryptRsaPrivateKey(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||||
return this->GetSecureMonitorWrapper()->DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
return spl::DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::CryptAesCtrDeprecated(OutBuffer<u8> out_buf, u32 keyslot, InBuffer<u8> in_buf, IvCtr iv_ctr) {
|
Result DeprecatedService::DecryptAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option) {
|
||||||
return this->GetSecureMonitorWrapper()->CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
|
return spl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::CryptAesCtr(OutBuffer<u8, BufferType_Type1> out_buf, u32 keyslot, InBuffer<u8, BufferType_Type1> in_buf, IvCtr iv_ctr) {
|
Result DeprecatedService::CryptAesCtrDeprecated(OutBuffer<u8> out_buf, u32 keyslot, InBuffer<u8> in_buf, IvCtr iv_ctr) {
|
||||||
return this->GetSecureMonitorWrapper()->CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
|
return spl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::ComputeCmac(Out<Cmac> out_cmac, u32 keyslot, InPointer<u8> in_buf) {
|
Result DeprecatedService::CryptAesCtr(OutBuffer<u8, BufferType_Type1> out_buf, u32 keyslot, InBuffer<u8, BufferType_Type1> in_buf, IvCtr iv_ctr) {
|
||||||
return this->GetSecureMonitorWrapper()->ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements);
|
return spl::CryptAesCtr(out_buf.buffer, out_buf.num_elements, keyslot, this, in_buf.buffer, in_buf.num_elements, iv_ctr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::ImportEsKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
Result DeprecatedService::ComputeCmac(Out<Cmac> out_cmac, u32 keyslot, InPointer<u8> in_buf) {
|
||||||
return this->GetSecureMonitorWrapper()->ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option);
|
return spl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.pointer, in_buf.num_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::UnwrapTitleKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation) {
|
Result DeprecatedService::ImportEsKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||||
return this->GetSecureMonitorWrapper()->UnwrapTitleKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation);
|
return spl::ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::LoadTitleKey(u32 keyslot, AccessKey access_key) {
|
Result DeprecatedService::UnwrapTitleKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation) {
|
||||||
return this->GetSecureMonitorWrapper()->LoadTitleKey(keyslot, this, access_key);
|
return spl::UnwrapTitleKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::UnwrapCommonTitleKey(Out<AccessKey> out_access_key, KeySource key_source, u32 generation) {
|
Result DeprecatedService::LoadTitleKey(u32 keyslot, AccessKey access_key) {
|
||||||
return this->GetSecureMonitorWrapper()->UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation);
|
return spl::LoadTitleKey(keyslot, this, access_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::AllocateAesKeyslot(Out<u32> out_keyslot) {
|
Result DeprecatedService::UnwrapCommonTitleKey(Out<AccessKey> out_access_key, KeySource key_source, u32 generation) {
|
||||||
return this->GetSecureMonitorWrapper()->AllocateAesKeyslot(out_keyslot.GetPointer(), this);
|
return spl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::FreeAesKeyslot(u32 keyslot) {
|
Result DeprecatedService::AllocateAesKeyslot(Out<u32> out_keyslot) {
|
||||||
return this->GetSecureMonitorWrapper()->FreeAesKeyslot(keyslot, this);
|
return spl::AllocateAesKeyslot(out_keyslot.GetPointer(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeprecatedService::GetAesKeyslotAvailableEvent(Out<CopiedHandle> out_hnd) {
|
Result DeprecatedService::FreeAesKeyslot(u32 keyslot) {
|
||||||
out_hnd.SetValue(this->GetSecureMonitorWrapper()->GetAesKeyslotAvailableEventHandle());
|
return spl::FreeAesKeyslot(keyslot, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::SetBootReason(BootReasonValue boot_reason) {
|
void DeprecatedService::GetAesKeyslotAvailableEvent(Out<CopiedHandle> out_hnd) {
|
||||||
return this->GetSecureMonitorWrapper()->SetBootReason(boot_reason);
|
out_hnd.SetValue(spl::GetAesKeyslotAvailableEventHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result DeprecatedService::SetBootReason(BootReasonValue boot_reason) {
|
||||||
|
return spl::SetBootReason(boot_reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DeprecatedService::GetBootReason(Out<BootReasonValue> out) {
|
||||||
|
return spl::GetBootReason(out.GetPointer());
|
||||||
|
}
|
||||||
|
|
||||||
Result DeprecatedService::GetBootReason(Out<BootReasonValue> out) {
|
|
||||||
return this->GetSecureMonitorWrapper()->GetBootReason(out.GetPointer());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,74 +19,100 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
#include "spl_secmon_wrapper.hpp"
|
|
||||||
|
|
||||||
class DeprecatedService : public IServiceObject {
|
namespace sts::spl {
|
||||||
private:
|
|
||||||
SecureMonitorWrapper *secmon_wrapper;
|
|
||||||
public:
|
|
||||||
DeprecatedService(SecureMonitorWrapper *sw) : secmon_wrapper(sw) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~DeprecatedService() { /* ... */ }
|
class DeprecatedService : public IServiceObject {
|
||||||
protected:
|
protected:
|
||||||
SecureMonitorWrapper *GetSecureMonitorWrapper() const {
|
enum class CommandId {
|
||||||
return this->secmon_wrapper;
|
/* 1.0.0+ */
|
||||||
}
|
GetConfig = 0,
|
||||||
protected:
|
ExpMod = 1,
|
||||||
/* Actual commands. */
|
GenerateAesKek = 2,
|
||||||
virtual Result GetConfig(Out<u64> out, u32 which);
|
LoadAesKey = 3,
|
||||||
virtual Result ExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> exp, InPointer<u8> mod);
|
GenerateAesKey = 4,
|
||||||
virtual Result GenerateAesKek(Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option);
|
SetConfig = 5,
|
||||||
virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source);
|
GenerateRandomBytes = 7,
|
||||||
virtual Result GenerateAesKey(Out<AesKey> out_key, AccessKey access_key, KeySource key_source);
|
ImportLotusKey = 9,
|
||||||
virtual Result SetConfig(u32 which, u64 value);
|
DecryptLotusMessage = 10,
|
||||||
virtual Result GenerateRandomBytes(OutPointerWithClientSize<u8> out);
|
IsDevelopment = 11,
|
||||||
virtual Result ImportLotusKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
GenerateSpecificAesKey = 12,
|
||||||
virtual Result DecryptLotusMessage(Out<u32> out_size, OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest);
|
DecryptRsaPrivateKey = 13,
|
||||||
virtual Result IsDevelopment(Out<bool> is_dev);
|
DecryptAesKey = 14,
|
||||||
virtual Result GenerateSpecificAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which);
|
CryptAesCtr = 15,
|
||||||
virtual Result DecryptRsaPrivateKey(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
ComputeCmac = 16,
|
||||||
virtual Result DecryptAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option);
|
ImportEsKey = 17,
|
||||||
virtual Result CryptAesCtrDeprecated(OutBuffer<u8> out_buf, u32 keyslot, InBuffer<u8> in_buf, IvCtr iv_ctr);
|
UnwrapTitleKey = 18,
|
||||||
virtual Result CryptAesCtr(OutBuffer<u8, BufferType_Type1> out_buf, u32 keyslot, InBuffer<u8, BufferType_Type1> in_buf, IvCtr iv_ctr);
|
LoadTitleKey = 19,
|
||||||
virtual Result ComputeCmac(Out<Cmac> out_cmac, u32 keyslot, InPointer<u8> in_buf);
|
|
||||||
virtual Result ImportEsKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
/* 2.0.0+ */
|
||||||
virtual Result UnwrapTitleKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation);
|
UnwrapCommonTitleKey = 20,
|
||||||
virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key);
|
AllocateAesKeyslot = 21,
|
||||||
virtual Result UnwrapCommonTitleKey(Out<AccessKey> out_access_key, KeySource key_source, u32 generation);
|
FreeAesKeyslot = 22,
|
||||||
virtual Result AllocateAesKeyslot(Out<u32> out_keyslot);
|
GetAesKeyslotAvailableEvent = 23,
|
||||||
virtual Result FreeAesKeyslot(u32 keyslot);
|
|
||||||
virtual void GetAesKeyslotAvailableEvent(Out<CopiedHandle> out_hnd);
|
/* 3.0.0+ */
|
||||||
virtual Result SetBootReason(BootReasonValue boot_reason);
|
SetBootReason = 24,
|
||||||
virtual Result GetBootReason(Out<BootReasonValue> out);
|
GetBootReason = 25,
|
||||||
public:
|
};
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
public:
|
||||||
MakeServiceCommandMeta<Spl_Cmd_GetConfig, &DeprecatedService::GetConfig>(),
|
DeprecatedService() { /* ... */ }
|
||||||
MakeServiceCommandMeta<Spl_Cmd_ExpMod, &DeprecatedService::ExpMod>(),
|
virtual ~DeprecatedService() { /* ... */ }
|
||||||
MakeServiceCommandMeta<Spl_Cmd_GenerateAesKek, &DeprecatedService::GenerateAesKek>(),
|
protected:
|
||||||
MakeServiceCommandMeta<Spl_Cmd_LoadAesKey, &DeprecatedService::LoadAesKey>(),
|
/* Actual commands. */
|
||||||
MakeServiceCommandMeta<Spl_Cmd_GenerateAesKey, &DeprecatedService::GenerateAesKey>(),
|
virtual Result GetConfig(Out<u64> out, u32 which);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_SetConfig, &DeprecatedService::SetConfig>(),
|
virtual Result ExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> exp, InPointer<u8> mod);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_GenerateRandomBytes, &DeprecatedService::GenerateRandomBytes>(),
|
virtual Result GenerateAesKek(Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_ImportLotusKey, &DeprecatedService::ImportLotusKey>(),
|
virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_DecryptLotusMessage, &DeprecatedService::DecryptLotusMessage>(),
|
virtual Result GenerateAesKey(Out<AesKey> out_key, AccessKey access_key, KeySource key_source);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_IsDevelopment, &DeprecatedService::IsDevelopment>(),
|
virtual Result SetConfig(u32 which, u64 value);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_GenerateSpecificAesKey, &DeprecatedService::GenerateSpecificAesKey>(),
|
virtual Result GenerateRandomBytes(OutPointerWithClientSize<u8> out);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_DecryptRsaPrivateKey, &DeprecatedService::DecryptRsaPrivateKey>(),
|
virtual Result ImportLotusKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_DecryptAesKey, &DeprecatedService::DecryptAesKey>(),
|
virtual Result DecryptLotusMessage(Out<u32> out_size, OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_CryptAesCtr, &DeprecatedService::CryptAesCtrDeprecated, FirmwareVersion_100, FirmwareVersion_100>(),
|
virtual Result IsDevelopment(Out<bool> is_dev);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_CryptAesCtr, &DeprecatedService::CryptAesCtr, FirmwareVersion_200>(),
|
virtual Result GenerateSpecificAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_ComputeCmac, &DeprecatedService::ComputeCmac>(),
|
virtual Result DecryptRsaPrivateKey(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_ImportEsKey, &DeprecatedService::ImportEsKey>(),
|
virtual Result DecryptAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_UnwrapTitleKey, &DeprecatedService::UnwrapTitleKey>(),
|
virtual Result CryptAesCtrDeprecated(OutBuffer<u8> out_buf, u32 keyslot, InBuffer<u8> in_buf, IvCtr iv_ctr);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_LoadTitleKey, &DeprecatedService::LoadTitleKey>(),
|
virtual Result CryptAesCtr(OutBuffer<u8, BufferType_Type1> out_buf, u32 keyslot, InBuffer<u8, BufferType_Type1> in_buf, IvCtr iv_ctr);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_UnwrapCommonTitleKey, &DeprecatedService::UnwrapCommonTitleKey, FirmwareVersion_200>(),
|
virtual Result ComputeCmac(Out<Cmac> out_cmac, u32 keyslot, InPointer<u8> in_buf);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_AllocateAesKeyslot, &DeprecatedService::AllocateAesKeyslot, FirmwareVersion_200>(),
|
virtual Result ImportEsKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_FreeAesKeyslot, &DeprecatedService::FreeAesKeyslot, FirmwareVersion_200>(),
|
virtual Result UnwrapTitleKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_GetAesKeyslotAvailableEvent, &DeprecatedService::GetAesKeyslotAvailableEvent, FirmwareVersion_200>(),
|
virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_SetBootReason, &DeprecatedService::SetBootReason, FirmwareVersion_300>(),
|
virtual Result UnwrapCommonTitleKey(Out<AccessKey> out_access_key, KeySource key_source, u32 generation);
|
||||||
MakeServiceCommandMeta<Spl_Cmd_GetBootReason, &DeprecatedService::GetBootReason, FirmwareVersion_300>(),
|
virtual Result AllocateAesKeyslot(Out<u32> out_keyslot);
|
||||||
};
|
virtual Result FreeAesKeyslot(u32 keyslot);
|
||||||
};
|
virtual void GetAesKeyslotAvailableEvent(Out<CopiedHandle> out_hnd);
|
||||||
|
virtual Result SetBootReason(BootReasonValue boot_reason);
|
||||||
|
virtual Result GetBootReason(Out<BootReasonValue> out);
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MakeServiceCommandMeta<CommandId::GetConfig, &DeprecatedService::GetConfig>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::ExpMod, &DeprecatedService::ExpMod>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::GenerateAesKek, &DeprecatedService::GenerateAesKek>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::LoadAesKey, &DeprecatedService::LoadAesKey>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::GenerateAesKey, &DeprecatedService::GenerateAesKey>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::SetConfig, &DeprecatedService::SetConfig>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::GenerateRandomBytes, &DeprecatedService::GenerateRandomBytes>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::ImportLotusKey, &DeprecatedService::ImportLotusKey>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::DecryptLotusMessage, &DeprecatedService::DecryptLotusMessage>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::IsDevelopment, &DeprecatedService::IsDevelopment>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::GenerateSpecificAesKey, &DeprecatedService::GenerateSpecificAesKey>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::DecryptRsaPrivateKey, &DeprecatedService::DecryptRsaPrivateKey>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::DecryptAesKey, &DeprecatedService::DecryptAesKey>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::CryptAesCtr, &DeprecatedService::CryptAesCtrDeprecated, FirmwareVersion_100, FirmwareVersion_100>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::CryptAesCtr, &DeprecatedService::CryptAesCtr, FirmwareVersion_200>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::ComputeCmac, &DeprecatedService::ComputeCmac>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::ImportEsKey, &DeprecatedService::ImportEsKey>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::UnwrapTitleKey, &DeprecatedService::UnwrapTitleKey>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::LoadTitleKey, &DeprecatedService::LoadTitleKey>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::UnwrapCommonTitleKey, &DeprecatedService::UnwrapCommonTitleKey, FirmwareVersion_200>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::AllocateAesKeyslot, &DeprecatedService::AllocateAesKeyslot, FirmwareVersion_200>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::FreeAesKeyslot, &DeprecatedService::FreeAesKeyslot, FirmwareVersion_200>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::GetAesKeyslotAvailableEvent, &DeprecatedService::GetAesKeyslotAvailableEvent, FirmwareVersion_200>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::SetBootReason, &DeprecatedService::SetBootReason, FirmwareVersion_300>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::GetBootReason, &DeprecatedService::GetBootReason, FirmwareVersion_300>(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -18,31 +18,36 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_es_service.hpp"
|
#include "spl_es_service.hpp"
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
|
||||||
Result EsService::ImportEsKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
namespace sts::spl {
|
||||||
return this->GetSecureMonitorWrapper()->ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result EsService::UnwrapTitleKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation) {
|
Result EsService::ImportEsKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||||
return this->GetSecureMonitorWrapper()->UnwrapTitleKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation);
|
return spl::ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result EsService::UnwrapCommonTitleKey(Out<AccessKey> out_access_key, KeySource key_source, u32 generation) {
|
Result EsService::UnwrapTitleKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation) {
|
||||||
return this->GetSecureMonitorWrapper()->UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation);
|
return spl::UnwrapTitleKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result EsService::ImportDrmKey(InPointer<u8> src, AccessKey access_key, KeySource key_source) {
|
Result EsService::UnwrapCommonTitleKey(Out<AccessKey> out_access_key, KeySource key_source, u32 generation) {
|
||||||
return this->GetSecureMonitorWrapper()->ImportDrmKey(src.pointer, src.num_elements, access_key, key_source);
|
return spl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result EsService::DrmExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod) {
|
Result EsService::ImportDrmKey(InPointer<u8> src, AccessKey access_key, KeySource key_source) {
|
||||||
return this->GetSecureMonitorWrapper()->DrmExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements);
|
return spl::ImportDrmKey(src.pointer, src.num_elements, access_key, key_source);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result EsService::UnwrapElicenseKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation) {
|
Result EsService::DrmExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod) {
|
||||||
return this->GetSecureMonitorWrapper()->UnwrapElicenseKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation);
|
return spl::DrmExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result EsService::UnwrapElicenseKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation) {
|
||||||
|
return spl::UnwrapElicenseKey(out_access_key.GetPointer(), base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements, generation);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result EsService::LoadElicenseKey(u32 keyslot, AccessKey access_key) {
|
||||||
|
return spl::LoadElicenseKey(keyslot, this, access_key);
|
||||||
|
}
|
||||||
|
|
||||||
Result EsService::LoadElicenseKey(u32 keyslot, AccessKey access_key) {
|
|
||||||
return this->GetSecureMonitorWrapper()->LoadElicenseKey(keyslot, this, access_key);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,50 +21,49 @@
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
#include "spl_rsa_service.hpp"
|
#include "spl_rsa_service.hpp"
|
||||||
|
|
||||||
class EsService : public RsaService {
|
namespace sts::spl {
|
||||||
public:
|
|
||||||
EsService(SecureMonitorWrapper *sw) : RsaService(sw) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~EsService() {
|
class EsService : public RsaService {
|
||||||
/* ... */
|
public:
|
||||||
}
|
EsService() : RsaService() { /* ... */ }
|
||||||
protected:
|
virtual ~EsService() { /* ... */}
|
||||||
/* Actual commands. */
|
protected:
|
||||||
virtual Result ImportEsKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
/* Actual commands. */
|
||||||
virtual Result UnwrapTitleKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation);
|
virtual Result ImportEsKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
||||||
virtual Result UnwrapCommonTitleKey(Out<AccessKey> out_access_key, KeySource key_source, u32 generation);
|
virtual Result UnwrapTitleKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation);
|
||||||
virtual Result ImportDrmKey(InPointer<u8> src, AccessKey access_key, KeySource key_source);
|
virtual Result UnwrapCommonTitleKey(Out<AccessKey> out_access_key, KeySource key_source, u32 generation);
|
||||||
virtual Result DrmExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod);
|
virtual Result ImportDrmKey(InPointer<u8> src, AccessKey access_key, KeySource key_source);
|
||||||
virtual Result UnwrapElicenseKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation);
|
virtual Result DrmExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod);
|
||||||
virtual Result LoadElicenseKey(u32 keyslot, AccessKey access_key);
|
virtual Result UnwrapElicenseKey(Out<AccessKey> out_access_key, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest, u32 generation);
|
||||||
public:
|
virtual Result LoadElicenseKey(u32 keyslot, AccessKey access_key);
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
public:
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetConfig, &EsService::GetConfig, EsService>(),
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ExpMod, &EsService::ExpMod, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::GetConfig, &EsService::GetConfig, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetConfig, &EsService::SetConfig, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::ExpMod, &EsService::ExpMod, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateRandomBytes, &EsService::GenerateRandomBytes, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::SetConfig, &EsService::SetConfig, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_IsDevelopment, &EsService::IsDevelopment, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateRandomBytes, &EsService::GenerateRandomBytes, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetBootReason, &EsService::SetBootReason, EsService, FirmwareVersion_300>(),
|
MakeServiceCommandMetaEx<CommandId::IsDevelopment, &EsService::IsDevelopment, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetBootReason, &EsService::GetBootReason, EsService, FirmwareVersion_300>(),
|
MakeServiceCommandMetaEx<CommandId::SetBootReason, &EsService::SetBootReason, EsService, FirmwareVersion_300>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKek, &EsService::GenerateAesKek, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::GetBootReason, &EsService::GetBootReason, EsService, FirmwareVersion_300>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_LoadAesKey, &EsService::LoadAesKey, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKek, &EsService::GenerateAesKek, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKey, &EsService::GenerateAesKey, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::LoadAesKey, &EsService::LoadAesKey, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptAesKey, &EsService::DecryptAesKey, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKey, &EsService::GenerateAesKey, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_CryptAesCtr, &EsService::CryptAesCtr, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptAesKey, &EsService::DecryptAesKey, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ComputeCmac, &EsService::ComputeCmac, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::CryptAesCtr, &EsService::CryptAesCtr, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_AllocateAesKeyslot, &EsService::AllocateAesKeyslot, EsService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::ComputeCmac, &EsService::ComputeCmac, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_FreeAesKeyslot, &EsService::FreeAesKeyslot, EsService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::AllocateAesKeyslot, &EsService::AllocateAesKeyslot, EsService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetAesKeyslotAvailableEvent, &EsService::GetAesKeyslotAvailableEvent, EsService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::FreeAesKeyslot, &EsService::FreeAesKeyslot, EsService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptRsaPrivateKey, &EsService::DecryptRsaPrivateKeyDeprecated, EsService, FirmwareVersion_400, FirmwareVersion_400>(),
|
MakeServiceCommandMetaEx<CommandId::GetAesKeyslotAvailableEvent, &EsService::GetAesKeyslotAvailableEvent, EsService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptRsaPrivateKey, &EsService::DecryptRsaPrivateKey, EsService, FirmwareVersion_500>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptRsaPrivateKey, &EsService::DecryptRsaPrivateKeyDeprecated, EsService, FirmwareVersion_400, FirmwareVersion_400>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ImportEsKey, &EsService::ImportEsKey, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptRsaPrivateKey, &EsService::DecryptRsaPrivateKey, EsService, FirmwareVersion_500>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_UnwrapTitleKey, &EsService::UnwrapTitleKey, EsService>(),
|
MakeServiceCommandMetaEx<CommandId::ImportEsKey, &EsService::ImportEsKey, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_UnwrapCommonTitleKey, &EsService::UnwrapCommonTitleKey, EsService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::UnwrapTitleKey, &EsService::UnwrapTitleKey, EsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ImportDrmKey, &EsService::ImportDrmKey, EsService, FirmwareVersion_500>(),
|
MakeServiceCommandMetaEx<CommandId::UnwrapCommonTitleKey, &EsService::UnwrapCommonTitleKey, EsService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DrmExpMod, &EsService::DrmExpMod, EsService, FirmwareVersion_500>(),
|
MakeServiceCommandMetaEx<CommandId::ImportDrmKey, &EsService::ImportDrmKey, EsService, FirmwareVersion_500>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_UnwrapElicenseKey, &EsService::UnwrapElicenseKey, EsService, FirmwareVersion_600>(),
|
MakeServiceCommandMetaEx<CommandId::DrmExpMod, &EsService::DrmExpMod, EsService, FirmwareVersion_500>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_LoadElicenseKey, &EsService::LoadElicenseKey, EsService, FirmwareVersion_600>(),
|
MakeServiceCommandMetaEx<CommandId::UnwrapElicenseKey, &EsService::UnwrapElicenseKey, EsService, FirmwareVersion_600>(),
|
||||||
};
|
MakeServiceCommandMetaEx<CommandId::LoadElicenseKey, &EsService::LoadElicenseKey, EsService, FirmwareVersion_600>(),
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -18,23 +18,28 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_fs_service.hpp"
|
#include "spl_fs_service.hpp"
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
|
||||||
Result FsService::ImportLotusKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
namespace sts::spl {
|
||||||
return this->GetSecureMonitorWrapper()->ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result FsService::DecryptLotusMessage(Out<u32> out_size, OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest) {
|
Result FsService::ImportLotusKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||||
return this->GetSecureMonitorWrapper()->DecryptLotusMessage(out_size.GetPointer(), out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements);
|
return spl::ImportLotusKey(src.pointer, src.num_elements, access_key, key_source, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsService::GenerateSpecificAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which) {
|
Result FsService::DecryptLotusMessage(Out<u32> out_size, OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest) {
|
||||||
return this->GetSecureMonitorWrapper()->GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
|
return spl::DecryptLotusMessage(out_size.GetPointer(), out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements, label_digest.pointer, label_digest.num_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsService::LoadTitleKey(u32 keyslot, AccessKey access_key) {
|
Result FsService::GenerateSpecificAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which) {
|
||||||
return this->GetSecureMonitorWrapper()->LoadTitleKey(keyslot, this, access_key);
|
return spl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result FsService::LoadTitleKey(u32 keyslot, AccessKey access_key) {
|
||||||
|
return spl::LoadTitleKey(keyslot, this, access_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FsService::GetPackage2Hash(OutPointerWithClientSize<u8> dst) {
|
||||||
|
return spl::GetPackage2Hash(dst.pointer, dst.num_elements);
|
||||||
|
}
|
||||||
|
|
||||||
Result FsService::GetPackage2Hash(OutPointerWithClientSize<u8> dst) {
|
|
||||||
return this->GetSecureMonitorWrapper()->GetPackage2Hash(dst.pointer, dst.num_elements);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,45 +21,43 @@
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
#include "spl_crypto_service.hpp"
|
#include "spl_crypto_service.hpp"
|
||||||
|
|
||||||
class FsService : public CryptoService {
|
namespace sts::spl {
|
||||||
public:
|
|
||||||
FsService(SecureMonitorWrapper *sw) : CryptoService(sw) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~FsService() {
|
class FsService : public CryptoService {
|
||||||
/* ... */
|
public:
|
||||||
}
|
FsService() : CryptoService() { /* ... */ }
|
||||||
protected:
|
virtual ~FsService() { /* ... */ }
|
||||||
/* Actual commands. */
|
protected:
|
||||||
virtual Result ImportLotusKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
/* Actual commands. */
|
||||||
virtual Result DecryptLotusMessage(Out<u32> out_size, OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest);
|
virtual Result ImportLotusKey(InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
||||||
virtual Result GenerateSpecificAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which);
|
virtual Result DecryptLotusMessage(Out<u32> out_size, OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod, InPointer<u8> label_digest);
|
||||||
virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key);
|
virtual Result GenerateSpecificAesKey(Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which);
|
||||||
virtual Result GetPackage2Hash(OutPointerWithClientSize<u8> dst);
|
virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key);
|
||||||
public:
|
virtual Result GetPackage2Hash(OutPointerWithClientSize<u8> dst);
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
public:
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetConfig, &FsService::GetConfig, FsService>(),
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ExpMod, &FsService::ExpMod, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::GetConfig, &FsService::GetConfig, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetConfig, &FsService::SetConfig, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::ExpMod, &FsService::ExpMod, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateRandomBytes, &FsService::GenerateRandomBytes, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::SetConfig, &FsService::SetConfig, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_IsDevelopment, &FsService::IsDevelopment, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateRandomBytes, &FsService::GenerateRandomBytes, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetBootReason, &FsService::SetBootReason, FsService, FirmwareVersion_300>(),
|
MakeServiceCommandMetaEx<CommandId::IsDevelopment, &FsService::IsDevelopment, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetBootReason, &FsService::GetBootReason, FsService, FirmwareVersion_300>(),
|
MakeServiceCommandMetaEx<CommandId::SetBootReason, &FsService::SetBootReason, FsService, FirmwareVersion_300>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKek, &FsService::GenerateAesKek, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::GetBootReason, &FsService::GetBootReason, FsService, FirmwareVersion_300>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_LoadAesKey, &FsService::LoadAesKey, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKek, &FsService::GenerateAesKek, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKey, &FsService::GenerateAesKey, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::LoadAesKey, &FsService::LoadAesKey, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptAesKey, &FsService::DecryptAesKey, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKey, &FsService::GenerateAesKey, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_CryptAesCtr, &FsService::CryptAesCtr, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptAesKey, &FsService::DecryptAesKey, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ComputeCmac, &FsService::ComputeCmac, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::CryptAesCtr, &FsService::CryptAesCtr, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_AllocateAesKeyslot, &FsService::AllocateAesKeyslot, FsService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::ComputeCmac, &FsService::ComputeCmac, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_FreeAesKeyslot, &FsService::FreeAesKeyslot, FsService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::AllocateAesKeyslot, &FsService::AllocateAesKeyslot, FsService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetAesKeyslotAvailableEvent, &FsService::GetAesKeyslotAvailableEvent, FsService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::FreeAesKeyslot, &FsService::FreeAesKeyslot, FsService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ImportLotusKey, &FsService::ImportLotusKey, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::GetAesKeyslotAvailableEvent, &FsService::GetAesKeyslotAvailableEvent, FsService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptLotusMessage, &FsService::DecryptLotusMessage, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::ImportLotusKey, &FsService::ImportLotusKey, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateSpecificAesKey, &FsService::GenerateSpecificAesKey, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptLotusMessage, &FsService::DecryptLotusMessage, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_LoadTitleKey, &FsService::LoadTitleKey, FsService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateSpecificAesKey, &FsService::GenerateSpecificAesKey, FsService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetPackage2Hash, &FsService::GetPackage2Hash, FsService, FirmwareVersion_500>(),
|
MakeServiceCommandMetaEx<CommandId::LoadTitleKey, &FsService::LoadTitleKey, FsService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::GetPackage2Hash, &FsService::GetPackage2Hash, FsService, FirmwareVersion_500>(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
}
|
||||||
};
|
|
||||||
|
|
|
@ -18,31 +18,36 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_general_service.hpp"
|
#include "spl_general_service.hpp"
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
|
||||||
Result GeneralService::GetConfig(Out<u64> out, u32 which) {
|
namespace sts::spl {
|
||||||
return this->GetSecureMonitorWrapper()->GetConfig(out.GetPointer(), static_cast<SplConfigItem>(which));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result GeneralService::ExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> exp, InPointer<u8> mod) {
|
Result GeneralService::GetConfig(Out<u64> out, u32 which) {
|
||||||
return this->GetSecureMonitorWrapper()->ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements);
|
return spl::GetConfig(out.GetPointer(), static_cast<SplConfigItem>(which));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GeneralService::SetConfig(u32 which, u64 value) {
|
Result GeneralService::ExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> exp, InPointer<u8> mod) {
|
||||||
return this->GetSecureMonitorWrapper()->SetConfig(static_cast<SplConfigItem>(which), value);
|
return spl::ExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, exp.pointer, exp.num_elements, mod.pointer, mod.num_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GeneralService::GenerateRandomBytes(OutPointerWithClientSize<u8> out) {
|
Result GeneralService::SetConfig(u32 which, u64 value) {
|
||||||
return this->GetSecureMonitorWrapper()->GenerateRandomBytes(out.pointer, out.num_elements);
|
return spl::SetConfig(static_cast<SplConfigItem>(which), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GeneralService::IsDevelopment(Out<bool> is_dev) {
|
Result GeneralService::GenerateRandomBytes(OutPointerWithClientSize<u8> out) {
|
||||||
return this->GetSecureMonitorWrapper()->IsDevelopment(is_dev.GetPointer());
|
return spl::GenerateRandomBytes(out.pointer, out.num_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GeneralService::SetBootReason(BootReasonValue boot_reason) {
|
Result GeneralService::IsDevelopment(Out<bool> is_dev) {
|
||||||
return this->GetSecureMonitorWrapper()->SetBootReason(boot_reason);
|
return spl::IsDevelopment(is_dev.GetPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GeneralService::SetBootReason(BootReasonValue boot_reason) {
|
||||||
|
return spl::SetBootReason(boot_reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GeneralService::GetBootReason(Out<BootReasonValue> out) {
|
||||||
|
return spl::GetBootReason(out.GetPointer());
|
||||||
|
}
|
||||||
|
|
||||||
Result GeneralService::GetBootReason(Out<BootReasonValue> out) {
|
|
||||||
return this->GetSecureMonitorWrapper()->GetBootReason(out.GetPointer());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,38 +19,76 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
#include "spl_secmon_wrapper.hpp"
|
|
||||||
|
|
||||||
class GeneralService : public IServiceObject {
|
namespace sts::spl {
|
||||||
private:
|
|
||||||
SecureMonitorWrapper *secmon_wrapper;
|
|
||||||
public:
|
|
||||||
GeneralService(SecureMonitorWrapper *sw) : secmon_wrapper(sw) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~GeneralService() { /* ... */ }
|
class GeneralService : public IServiceObject {
|
||||||
protected:
|
protected:
|
||||||
SecureMonitorWrapper *GetSecureMonitorWrapper() const {
|
enum class CommandId {
|
||||||
return this->secmon_wrapper;
|
/* 1.0.0+ */
|
||||||
}
|
GetConfig = 0,
|
||||||
protected:
|
ExpMod = 1,
|
||||||
/* Actual commands. */
|
GenerateAesKek = 2,
|
||||||
virtual Result GetConfig(Out<u64> out, u32 which);
|
LoadAesKey = 3,
|
||||||
virtual Result ExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> exp, InPointer<u8> mod);
|
GenerateAesKey = 4,
|
||||||
virtual Result SetConfig(u32 which, u64 value);
|
SetConfig = 5,
|
||||||
virtual Result GenerateRandomBytes(OutPointerWithClientSize<u8> out);
|
GenerateRandomBytes = 7,
|
||||||
virtual Result IsDevelopment(Out<bool> is_dev);
|
ImportLotusKey = 9,
|
||||||
virtual Result SetBootReason(BootReasonValue boot_reason);
|
DecryptLotusMessage = 10,
|
||||||
virtual Result GetBootReason(Out<BootReasonValue> out);
|
IsDevelopment = 11,
|
||||||
public:
|
GenerateSpecificAesKey = 12,
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DecryptRsaPrivateKey = 13,
|
||||||
MakeServiceCommandMeta<Spl_Cmd_GetConfig, &GeneralService::GetConfig>(),
|
DecryptAesKey = 14,
|
||||||
MakeServiceCommandMeta<Spl_Cmd_ExpMod, &GeneralService::ExpMod>(),
|
CryptAesCtr = 15,
|
||||||
MakeServiceCommandMeta<Spl_Cmd_SetConfig, &GeneralService::SetConfig>(),
|
ComputeCmac = 16,
|
||||||
MakeServiceCommandMeta<Spl_Cmd_GenerateRandomBytes, &GeneralService::GenerateRandomBytes>(),
|
ImportEsKey = 17,
|
||||||
MakeServiceCommandMeta<Spl_Cmd_IsDevelopment, &GeneralService::IsDevelopment>(),
|
UnwrapTitleKey = 18,
|
||||||
MakeServiceCommandMeta<Spl_Cmd_SetBootReason, &GeneralService::SetBootReason, FirmwareVersion_300>(),
|
LoadTitleKey = 19,
|
||||||
MakeServiceCommandMeta<Spl_Cmd_GetBootReason, &GeneralService::GetBootReason, FirmwareVersion_300>(),
|
|
||||||
};
|
/* 2.0.0+ */
|
||||||
};
|
UnwrapCommonTitleKey = 20,
|
||||||
|
AllocateAesKeyslot = 21,
|
||||||
|
FreeAesKeyslot = 22,
|
||||||
|
GetAesKeyslotAvailableEvent = 23,
|
||||||
|
|
||||||
|
/* 3.0.0+ */
|
||||||
|
SetBootReason = 24,
|
||||||
|
GetBootReason = 25,
|
||||||
|
|
||||||
|
/* 5.0.0+ */
|
||||||
|
ImportSslKey = 26,
|
||||||
|
SslExpMod = 27,
|
||||||
|
ImportDrmKey = 28,
|
||||||
|
DrmExpMod = 29,
|
||||||
|
ReEncryptRsaPrivateKey = 30,
|
||||||
|
GetPackage2Hash = 31,
|
||||||
|
|
||||||
|
/* 6.0.0+ */
|
||||||
|
UnwrapElicenseKey = 31, /* re-used command id :( */
|
||||||
|
LoadElicenseKey = 32,
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
GeneralService() { /* ... */ }
|
||||||
|
virtual ~GeneralService() { /* ... */ }
|
||||||
|
protected:
|
||||||
|
/* Actual commands. */
|
||||||
|
virtual Result GetConfig(Out<u64> out, u32 which);
|
||||||
|
virtual Result ExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> exp, InPointer<u8> mod);
|
||||||
|
virtual Result SetConfig(u32 which, u64 value);
|
||||||
|
virtual Result GenerateRandomBytes(OutPointerWithClientSize<u8> out);
|
||||||
|
virtual Result IsDevelopment(Out<bool> is_dev);
|
||||||
|
virtual Result SetBootReason(BootReasonValue boot_reason);
|
||||||
|
virtual Result GetBootReason(Out<BootReasonValue> out);
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MakeServiceCommandMeta<CommandId::GetConfig, &GeneralService::GetConfig>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::ExpMod, &GeneralService::ExpMod>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::SetConfig, &GeneralService::SetConfig>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::GenerateRandomBytes, &GeneralService::GenerateRandomBytes>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::IsDevelopment, &GeneralService::IsDevelopment>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::SetBootReason, &GeneralService::SetBootReason, FirmwareVersion_300>(),
|
||||||
|
MakeServiceCommandMeta<CommandId::GetBootReason, &GeneralService::GetBootReason, FirmwareVersion_300>(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
|
|
||||||
#include "spl_deprecated_service.hpp"
|
#include "spl_deprecated_service.hpp"
|
||||||
|
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
extern u32 __start__;
|
extern u32 __start__;
|
||||||
|
|
||||||
|
@ -86,43 +88,27 @@ struct SplServerOptions {
|
||||||
static constexpr size_t MaxDomainObjects = 0;
|
static constexpr size_t MaxDomainObjects = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Single secure monitor wrapper singleton. */
|
|
||||||
static SecureMonitorWrapper s_secmon_wrapper;
|
|
||||||
|
|
||||||
/* Helpers for creating services. */
|
|
||||||
static const auto MakeRandomService = []() { return std::make_shared<RandomService>(&s_secmon_wrapper); };
|
|
||||||
static const auto MakeGeneralService = []() { return std::make_shared<GeneralService>(&s_secmon_wrapper); };
|
|
||||||
static const auto MakeCryptoService = []() { return std::make_shared<CryptoService>(&s_secmon_wrapper); };
|
|
||||||
static const auto MakeSslService = []() { return std::make_shared<SslService>(&s_secmon_wrapper); };
|
|
||||||
static const auto MakeEsService = []() { return std::make_shared<EsService>(&s_secmon_wrapper); };
|
|
||||||
static const auto MakeFsService = []() { return std::make_shared<FsService>(&s_secmon_wrapper); };
|
|
||||||
static const auto MakeManuService = []() { return std::make_shared<ManuService>(&s_secmon_wrapper); };
|
|
||||||
|
|
||||||
static const auto MakeDeprecatedService = []() { return std::make_shared<DeprecatedService>(&s_secmon_wrapper); };
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
consoleDebugInit(debugDevice_SVC);
|
|
||||||
|
|
||||||
/* Initialize global context. */
|
/* Initialize global context. */
|
||||||
SecureMonitorWrapper::Initialize();
|
sts::spl::Initialize();
|
||||||
|
|
||||||
/* Create server manager. */
|
/* Create server manager. */
|
||||||
static auto s_server_manager = WaitableManager<SplServerOptions>(1);
|
static auto s_server_manager = WaitableManager<SplServerOptions>(1);
|
||||||
|
|
||||||
/* Create services. */
|
/* Create services. */
|
||||||
s_server_manager.AddWaitable(new ServiceServer<RandomService, +MakeRandomService>("csrng", 3));
|
s_server_manager.AddWaitable(new ServiceServer<sts::spl::RandomService>("csrng", 3));
|
||||||
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_400) {
|
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_400) {
|
||||||
s_server_manager.AddWaitable(new ServiceServer<GeneralService, +MakeGeneralService>("spl:", 9));
|
s_server_manager.AddWaitable(new ServiceServer<sts::spl::GeneralService>("spl:", 9));
|
||||||
s_server_manager.AddWaitable(new ServiceServer<CryptoService, +MakeCryptoService>("spl:mig", 6));
|
s_server_manager.AddWaitable(new ServiceServer<sts::spl::CryptoService>("spl:mig", 6));
|
||||||
s_server_manager.AddWaitable(new ServiceServer<SslService, +MakeSslService>("spl:ssl", 2));
|
s_server_manager.AddWaitable(new ServiceServer<sts::spl::SslService>("spl:ssl", 2));
|
||||||
s_server_manager.AddWaitable(new ServiceServer<EsService, +MakeEsService>("spl:es", 2));
|
s_server_manager.AddWaitable(new ServiceServer<sts::spl::EsService>("spl:es", 2));
|
||||||
s_server_manager.AddWaitable(new ServiceServer<FsService, +MakeFsService>("spl:fs", 2));
|
s_server_manager.AddWaitable(new ServiceServer<sts::spl::FsService>("spl:fs", 2));
|
||||||
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
|
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
|
||||||
s_server_manager.AddWaitable(new ServiceServer<ManuService, +MakeManuService>("spl:manu", 1));
|
s_server_manager.AddWaitable(new ServiceServer<sts::spl::ManuService>("spl:manu", 1));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s_server_manager.AddWaitable(new ServiceServer<DeprecatedService, +MakeDeprecatedService>("spl:", 12));
|
s_server_manager.AddWaitable(new ServiceServer<sts::spl::DeprecatedService>("spl:", 12));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop forever, servicing our services. */
|
/* Loop forever, servicing our services. */
|
||||||
|
@ -130,4 +116,3 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,12 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_manu_service.hpp"
|
#include "spl_manu_service.hpp"
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
|
||||||
|
namespace sts::spl {
|
||||||
|
|
||||||
|
Result ManuService::ReEncryptRsaPrivateKey(OutPointerWithClientSize<u8> out, InPointer<u8> src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option) {
|
||||||
|
return spl::ReEncryptRsaPrivateKey(out.pointer, out.num_elements, src.pointer, src.num_elements, access_key_dec, source_dec, access_key_enc, source_enc, option);
|
||||||
|
}
|
||||||
|
|
||||||
Result ManuService::ReEncryptRsaPrivateKey(OutPointerWithClientSize<u8> out, InPointer<u8> src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option) {
|
|
||||||
return this->GetSecureMonitorWrapper()->ReEncryptRsaPrivateKey(out.pointer, out.num_elements, src.pointer, src.num_elements, access_key_dec, source_dec, access_key_enc, source_enc, option);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,39 +21,38 @@
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
#include "spl_rsa_service.hpp"
|
#include "spl_rsa_service.hpp"
|
||||||
|
|
||||||
class ManuService : public RsaService {
|
namespace sts::spl {
|
||||||
public:
|
|
||||||
ManuService(SecureMonitorWrapper *sw) : RsaService(sw) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~ManuService() {
|
class ManuService : public RsaService {
|
||||||
/* ... */
|
public:
|
||||||
}
|
ManuService() : RsaService() { /* ... */ }
|
||||||
protected:
|
|
||||||
/* Actual commands. */
|
|
||||||
virtual Result ReEncryptRsaPrivateKey(OutPointerWithClientSize<u8> out, InPointer<u8> src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option);
|
|
||||||
public:
|
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetConfig, &ManuService::GetConfig, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ExpMod, &ManuService::ExpMod, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetConfig, &ManuService::SetConfig, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateRandomBytes, &ManuService::GenerateRandomBytes, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_IsDevelopment, &ManuService::IsDevelopment, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetBootReason, &ManuService::SetBootReason, ManuService, FirmwareVersion_300>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetBootReason, &ManuService::GetBootReason, ManuService, FirmwareVersion_300>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKek, &ManuService::GenerateAesKek, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_LoadAesKey, &ManuService::LoadAesKey, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKey, &ManuService::GenerateAesKey, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptAesKey, &ManuService::DecryptAesKey, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_CryptAesCtr, &ManuService::CryptAesCtr, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ComputeCmac, &ManuService::ComputeCmac, ManuService>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_AllocateAesKeyslot, &ManuService::AllocateAesKeyslot, ManuService, FirmwareVersion_200>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_FreeAesKeyslot, &ManuService::FreeAesKeyslot, ManuService, FirmwareVersion_200>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetAesKeyslotAvailableEvent, &ManuService::GetAesKeyslotAvailableEvent, ManuService, FirmwareVersion_200>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptRsaPrivateKey, &ManuService::DecryptRsaPrivateKeyDeprecated, ManuService, FirmwareVersion_400, FirmwareVersion_400>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptRsaPrivateKey, &ManuService::DecryptRsaPrivateKey, ManuService, FirmwareVersion_500>(),
|
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ReEncryptRsaPrivateKey, &ManuService::ReEncryptRsaPrivateKey, ManuService, FirmwareVersion_500>(),
|
|
||||||
|
|
||||||
};
|
virtual ~ManuService() { /* ... */ }
|
||||||
};
|
protected:
|
||||||
|
/* Actual commands. */
|
||||||
|
virtual Result ReEncryptRsaPrivateKey(OutPointerWithClientSize<u8> out, InPointer<u8> src, AccessKey access_key_dec, KeySource source_dec, AccessKey access_key_enc, KeySource source_enc, u32 option);
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MakeServiceCommandMetaEx<CommandId::GetConfig, &ManuService::GetConfig, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::ExpMod, &ManuService::ExpMod, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::SetConfig, &ManuService::SetConfig, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::GenerateRandomBytes, &ManuService::GenerateRandomBytes, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::IsDevelopment, &ManuService::IsDevelopment, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::SetBootReason, &ManuService::SetBootReason, ManuService, FirmwareVersion_300>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::GetBootReason, &ManuService::GetBootReason, ManuService, FirmwareVersion_300>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKek, &ManuService::GenerateAesKek, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::LoadAesKey, &ManuService::LoadAesKey, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKey, &ManuService::GenerateAesKey, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::DecryptAesKey, &ManuService::DecryptAesKey, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::CryptAesCtr, &ManuService::CryptAesCtr, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::ComputeCmac, &ManuService::ComputeCmac, ManuService>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::AllocateAesKeyslot, &ManuService::AllocateAesKeyslot, ManuService, FirmwareVersion_200>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::FreeAesKeyslot, &ManuService::FreeAesKeyslot, ManuService, FirmwareVersion_200>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::GetAesKeyslotAvailableEvent, &ManuService::GetAesKeyslotAvailableEvent, ManuService, FirmwareVersion_200>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::DecryptRsaPrivateKey, &ManuService::DecryptRsaPrivateKeyDeprecated, ManuService, FirmwareVersion_400, FirmwareVersion_400>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::DecryptRsaPrivateKey, &ManuService::DecryptRsaPrivateKey, ManuService, FirmwareVersion_500>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::ReEncryptRsaPrivateKey, &ManuService::ReEncryptRsaPrivateKey, ManuService, FirmwareVersion_500>(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -18,7 +18,12 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_random_service.hpp"
|
#include "spl_random_service.hpp"
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
|
||||||
|
namespace sts::spl {
|
||||||
|
|
||||||
|
Result RandomService::GenerateRandomBytes(OutBuffer<u8> out) {
|
||||||
|
return spl::GenerateRandomBytes(out.buffer, out.num_elements);
|
||||||
|
}
|
||||||
|
|
||||||
Result RandomService::GenerateRandomBytes(OutBuffer<u8> out) {
|
|
||||||
return this->secmon_wrapper->GenerateRandomBytes(out.buffer, out.num_elements);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,22 +19,24 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
#include "spl_secmon_wrapper.hpp"
|
|
||||||
|
|
||||||
class RandomService final : public IServiceObject {
|
namespace sts::spl {
|
||||||
private:
|
|
||||||
SecureMonitorWrapper *secmon_wrapper;
|
|
||||||
public:
|
|
||||||
RandomService(SecureMonitorWrapper *sw) : secmon_wrapper(sw) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~RandomService() { /* ... */ }
|
class RandomService final : public IServiceObject {
|
||||||
private:
|
protected:
|
||||||
/* Actual commands. */
|
enum class CommandId {
|
||||||
virtual Result GenerateRandomBytes(OutBuffer<u8> out);
|
GenerateRandomBytes = 0,
|
||||||
public:
|
};
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
public:
|
||||||
MakeServiceCommandMeta<Csrng_Cmd_GenerateRandomBytes, &RandomService::GenerateRandomBytes>(),
|
RandomService() { /* ... */ }
|
||||||
};
|
virtual ~RandomService() { /* ... */ }
|
||||||
};
|
private:
|
||||||
|
/* Actual commands. */
|
||||||
|
virtual Result GenerateRandomBytes(OutBuffer<u8> out);
|
||||||
|
public:
|
||||||
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
MakeServiceCommandMeta<CommandId::GenerateRandomBytes, &RandomService::GenerateRandomBytes>(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -18,11 +18,16 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_rsa_service.hpp"
|
#include "spl_rsa_service.hpp"
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
|
||||||
|
namespace sts::spl {
|
||||||
|
|
||||||
|
Result RsaService::DecryptRsaPrivateKeyDeprecated(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
||||||
|
return spl::DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result RsaService::DecryptRsaPrivateKey(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source) {
|
||||||
|
return spl::DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, static_cast<u32>(smc::DecryptOrImportMode::DecryptRsaPrivateKey));
|
||||||
|
}
|
||||||
|
|
||||||
Result RsaService::DecryptRsaPrivateKeyDeprecated(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option) {
|
|
||||||
return this->GetSecureMonitorWrapper()->DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, option);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result RsaService::DecryptRsaPrivateKey(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source) {
|
|
||||||
return this->GetSecureMonitorWrapper()->DecryptRsaPrivateKey(dst.pointer, dst.num_elements, src.pointer, src.num_elements, access_key, key_source, SmcDecryptOrImportMode_DecryptRsaPrivateKey);
|
|
||||||
}
|
|
|
@ -21,39 +21,37 @@
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
#include "spl_crypto_service.hpp"
|
#include "spl_crypto_service.hpp"
|
||||||
|
|
||||||
class RsaService : public CryptoService {
|
namespace sts::spl {
|
||||||
public:
|
|
||||||
RsaService(SecureMonitorWrapper *sw) : CryptoService(sw) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~RsaService() {
|
class RsaService : public CryptoService {
|
||||||
/* ... */
|
public:
|
||||||
}
|
RsaService() : CryptoService() { /* ... */ }
|
||||||
protected:
|
virtual ~RsaService() { /* ... */ }
|
||||||
/* Actual commands. */
|
protected:
|
||||||
virtual Result DecryptRsaPrivateKeyDeprecated(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
/* Actual commands. */
|
||||||
virtual Result DecryptRsaPrivateKey(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source);
|
virtual Result DecryptRsaPrivateKeyDeprecated(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source, u32 option);
|
||||||
public:
|
virtual Result DecryptRsaPrivateKey(OutPointerWithClientSize<u8> dst, InPointer<u8> src, AccessKey access_key, KeySource key_source);
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
public:
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetConfig, &RsaService::GetConfig, RsaService>(),
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ExpMod, &RsaService::ExpMod, RsaService>(),
|
MakeServiceCommandMetaEx<CommandId::GetConfig, &RsaService::GetConfig, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetConfig, &RsaService::SetConfig, RsaService>(),
|
MakeServiceCommandMetaEx<CommandId::ExpMod, &RsaService::ExpMod, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateRandomBytes, &RsaService::GenerateRandomBytes, RsaService>(),
|
MakeServiceCommandMetaEx<CommandId::SetConfig, &RsaService::SetConfig, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_IsDevelopment, &RsaService::IsDevelopment, RsaService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateRandomBytes, &RsaService::GenerateRandomBytes, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetBootReason, &RsaService::SetBootReason, RsaService, FirmwareVersion_300>(),
|
MakeServiceCommandMetaEx<CommandId::IsDevelopment, &RsaService::IsDevelopment, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetBootReason, &RsaService::GetBootReason, RsaService, FirmwareVersion_300>(),
|
MakeServiceCommandMetaEx<CommandId::SetBootReason, &RsaService::SetBootReason, RsaService, FirmwareVersion_300>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKek, &RsaService::GenerateAesKek, RsaService>(),
|
MakeServiceCommandMetaEx<CommandId::GetBootReason, &RsaService::GetBootReason, RsaService, FirmwareVersion_300>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_LoadAesKey, &RsaService::LoadAesKey, RsaService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKek, &RsaService::GenerateAesKek, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKey, &RsaService::GenerateAesKey, RsaService>(),
|
MakeServiceCommandMetaEx<CommandId::LoadAesKey, &RsaService::LoadAesKey, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptAesKey, &RsaService::DecryptAesKey, RsaService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKey, &RsaService::GenerateAesKey, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_CryptAesCtr, &RsaService::CryptAesCtr, RsaService>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptAesKey, &RsaService::DecryptAesKey, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ComputeCmac, &RsaService::ComputeCmac, RsaService>(),
|
MakeServiceCommandMetaEx<CommandId::CryptAesCtr, &RsaService::CryptAesCtr, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_AllocateAesKeyslot, &RsaService::AllocateAesKeyslot, RsaService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::ComputeCmac, &RsaService::ComputeCmac, RsaService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_FreeAesKeyslot, &RsaService::FreeAesKeyslot, RsaService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::AllocateAesKeyslot, &RsaService::AllocateAesKeyslot, RsaService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetAesKeyslotAvailableEvent, &RsaService::GetAesKeyslotAvailableEvent, RsaService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::FreeAesKeyslot, &RsaService::FreeAesKeyslot, RsaService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptRsaPrivateKey, &RsaService::DecryptRsaPrivateKeyDeprecated, RsaService, FirmwareVersion_400, FirmwareVersion_400>(),
|
MakeServiceCommandMetaEx<CommandId::GetAesKeyslotAvailableEvent, &RsaService::GetAesKeyslotAvailableEvent, RsaService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptRsaPrivateKey, &RsaService::DecryptRsaPrivateKey, RsaService, FirmwareVersion_500>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptRsaPrivateKey, &RsaService::DecryptRsaPrivateKeyDeprecated, RsaService, FirmwareVersion_400, FirmwareVersion_400>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::DecryptRsaPrivateKey, &RsaService::DecryptRsaPrivateKey, RsaService, FirmwareVersion_500>(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
}
|
||||||
};
|
|
||||||
|
|
|
@ -1,875 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <switch.h>
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
|
|
||||||
#include "spl_secmon_wrapper.hpp"
|
|
||||||
#include "spl_smc_wrapper.hpp"
|
|
||||||
#include "spl_ctr_drbg.hpp"
|
|
||||||
|
|
||||||
/* Convenient. */
|
|
||||||
constexpr size_t DeviceAddressSpaceAlignSize = 0x400000;
|
|
||||||
constexpr size_t DeviceAddressSpaceAlignMask = DeviceAddressSpaceAlignSize - 1;
|
|
||||||
constexpr u32 WorkBufferMapBase = 0x80000000u;
|
|
||||||
constexpr u32 CryptAesInMapBase = 0x90000000u;
|
|
||||||
constexpr u32 CryptAesOutMapBase = 0xC0000000u;
|
|
||||||
constexpr size_t CryptAesSizeMax = static_cast<size_t>(CryptAesOutMapBase - CryptAesInMapBase);
|
|
||||||
|
|
||||||
constexpr size_t RsaPrivateKeySize = 0x100;
|
|
||||||
constexpr size_t RsaPrivateKeyMetaSize = 0x30;
|
|
||||||
constexpr size_t LabelDigestSizeMax = 0x20;
|
|
||||||
|
|
||||||
/* Types. */
|
|
||||||
struct SeLinkedListEntry {
|
|
||||||
u32 num_entries;
|
|
||||||
u32 address;
|
|
||||||
u32 size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SeCryptContext {
|
|
||||||
SeLinkedListEntry in;
|
|
||||||
SeLinkedListEntry out;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DeviceAddressSpaceMapHelper {
|
|
||||||
private:
|
|
||||||
Handle das_hnd;
|
|
||||||
u64 dst_addr;
|
|
||||||
u64 src_addr;
|
|
||||||
size_t size;
|
|
||||||
u32 perm;
|
|
||||||
public:
|
|
||||||
DeviceAddressSpaceMapHelper(Handle h, u64 dst, u64 src, size_t sz, u32 p) : das_hnd(h), dst_addr(dst), src_addr(src), size(sz), perm(p) {
|
|
||||||
R_ASSERT(svcMapDeviceAddressSpaceAligned(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr, this->perm));
|
|
||||||
}
|
|
||||||
~DeviceAddressSpaceMapHelper() {
|
|
||||||
R_ASSERT(svcUnmapDeviceAddressSpace(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Globals. */
|
|
||||||
static CtrDrbg g_drbg;
|
|
||||||
static Event g_se_event;
|
|
||||||
static IEvent *g_se_keyslot_available_event = nullptr;
|
|
||||||
|
|
||||||
static Handle g_se_das_hnd;
|
|
||||||
static u32 g_se_mapped_work_buffer_addr;
|
|
||||||
static __attribute__((aligned(0x1000))) u8 g_work_buffer[0x1000];
|
|
||||||
constexpr size_t MaxWorkBufferSize = sizeof(g_work_buffer) / 2;
|
|
||||||
|
|
||||||
static HosMutex g_async_op_lock;
|
|
||||||
|
|
||||||
void SecureMonitorWrapper::InitializeCtrDrbg() {
|
|
||||||
u8 seed[CtrDrbg::SeedSize];
|
|
||||||
|
|
||||||
if (SmcWrapper::GenerateRandomBytes(seed, sizeof(seed)) != SmcResult_Success) {
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
g_drbg.Initialize(seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecureMonitorWrapper::InitializeSeEvents() {
|
|
||||||
u64 irq_num;
|
|
||||||
SmcWrapper::GetConfig(&irq_num, 1, SplConfigItem_SecurityEngineIrqNumber);
|
|
||||||
Handle hnd;
|
|
||||||
R_ASSERT(svcCreateInterruptEvent(&hnd, irq_num, 1));
|
|
||||||
eventLoadRemote(&g_se_event, hnd, true);
|
|
||||||
|
|
||||||
g_se_keyslot_available_event = CreateWriteOnlySystemEvent();
|
|
||||||
g_se_keyslot_available_event->Signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecureMonitorWrapper::InitializeDeviceAddressSpace() {
|
|
||||||
constexpr u64 DeviceName_SE = 29;
|
|
||||||
|
|
||||||
/* Create Address Space. */
|
|
||||||
R_ASSERT(svcCreateDeviceAddressSpace(&g_se_das_hnd, 0, (1ul << 32)));
|
|
||||||
|
|
||||||
/* Attach it to the SE. */
|
|
||||||
R_ASSERT(svcAttachDeviceAddressSpace(DeviceName_SE, g_se_das_hnd));
|
|
||||||
|
|
||||||
const u64 work_buffer_addr = reinterpret_cast<u64>(g_work_buffer);
|
|
||||||
g_se_mapped_work_buffer_addr = WorkBufferMapBase + (work_buffer_addr & DeviceAddressSpaceAlignMask);
|
|
||||||
|
|
||||||
/* Map the work buffer for the SE. */
|
|
||||||
R_ASSERT(svcMapDeviceAddressSpaceAligned(g_se_das_hnd, CUR_PROCESS_HANDLE, work_buffer_addr, sizeof(g_work_buffer), g_se_mapped_work_buffer_addr, 3));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecureMonitorWrapper::Initialize() {
|
|
||||||
/* Initialize the Drbg. */
|
|
||||||
InitializeCtrDrbg();
|
|
||||||
/* Initialize SE interrupt + keyslot events. */
|
|
||||||
InitializeSeEvents();
|
|
||||||
/* Initialize DAS for the SE. */
|
|
||||||
InitializeDeviceAddressSpace();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecureMonitorWrapper::CalcMgf1AndXor(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
|
||||||
uint8_t *dst_u8 = reinterpret_cast<u8 *>(dst);
|
|
||||||
|
|
||||||
u32 ctr = 0;
|
|
||||||
while (dst_size > 0) {
|
|
||||||
size_t cur_size = SHA256_HASH_SIZE;
|
|
||||||
if (cur_size > dst_size) {
|
|
||||||
cur_size = dst_size;
|
|
||||||
}
|
|
||||||
dst_size -= cur_size;
|
|
||||||
|
|
||||||
u32 ctr_be = __builtin_bswap32(ctr++);
|
|
||||||
u8 hash[SHA256_HASH_SIZE];
|
|
||||||
{
|
|
||||||
Sha256Context ctx;
|
|
||||||
sha256ContextCreate(&ctx);
|
|
||||||
sha256ContextUpdate(&ctx, src, src_size);
|
|
||||||
sha256ContextUpdate(&ctx, &ctr_be, sizeof(ctr_be));
|
|
||||||
sha256ContextGetHash(&ctx, hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < cur_size; i++) {
|
|
||||||
*(dst_u8++) ^= hash[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SecureMonitorWrapper::DecodeRsaOaep(void *dst, size_t dst_size, const void *label_digest, size_t label_digest_size, const void *src, size_t src_size) {
|
|
||||||
/* Very basic validation. */
|
|
||||||
if (dst_size == 0 || src_size != 0x100 || label_digest_size != SHA256_HASH_SIZE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 block[0x100];
|
|
||||||
std::memcpy(block, src, sizeof(block));
|
|
||||||
|
|
||||||
/* First, validate byte 0 == 0, and unmask DB. */
|
|
||||||
int invalid = block[0];
|
|
||||||
u8 *salt = block + 1;
|
|
||||||
u8 *db = salt + SHA256_HASH_SIZE;
|
|
||||||
CalcMgf1AndXor(salt, SHA256_HASH_SIZE, db, src_size - (1 + SHA256_HASH_SIZE));
|
|
||||||
CalcMgf1AndXor(db, src_size - (1 + SHA256_HASH_SIZE), salt, SHA256_HASH_SIZE);
|
|
||||||
|
|
||||||
/* Validate label digest. */
|
|
||||||
for (size_t i = 0; i < SHA256_HASH_SIZE; i++) {
|
|
||||||
invalid |= db[i] ^ reinterpret_cast<const u8 *>(label_digest)[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Locate message after 00...0001 padding. */
|
|
||||||
const u8 *padded_msg = db + SHA256_HASH_SIZE;
|
|
||||||
size_t padded_msg_size = src_size - (1 + 2 * SHA256_HASH_SIZE);
|
|
||||||
size_t msg_ind = 0;
|
|
||||||
int not_found = 1;
|
|
||||||
int wrong_padding = 0;
|
|
||||||
size_t i = 0;
|
|
||||||
while (i < padded_msg_size) {
|
|
||||||
int zero = (padded_msg[i] == 0);
|
|
||||||
int one = (padded_msg[i] == 1);
|
|
||||||
msg_ind += static_cast<size_t>(not_found & one) * (++i);
|
|
||||||
not_found &= ~one;
|
|
||||||
wrong_padding |= (not_found & ~zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (invalid | not_found | wrong_padding) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy message out. */
|
|
||||||
size_t msg_size = padded_msg_size - msg_ind;
|
|
||||||
if (msg_size > dst_size) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
std::memcpy(dst, padded_msg + msg_ind, msg_size);
|
|
||||||
return msg_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SecureMonitorWrapper::WaitSeOperationComplete() {
|
|
||||||
eventWait(&g_se_event, U64_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::ConvertToSplResult(SmcResult result) {
|
|
||||||
if (result == SmcResult_Success) {
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
if (result < SmcResult_Max) {
|
|
||||||
return MAKERESULT(Module_Spl, static_cast<u32>(result));
|
|
||||||
}
|
|
||||||
return ResultSplUnknownSmcResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SecureMonitorWrapper::WaitCheckStatus(AsyncOperationKey op_key) {
|
|
||||||
WaitSeOperationComplete();
|
|
||||||
|
|
||||||
SmcResult op_res;
|
|
||||||
SmcResult res = SmcWrapper::CheckStatus(&op_res, op_key);
|
|
||||||
if (res != SmcResult_Success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return op_res;
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SecureMonitorWrapper::WaitGetResult(void *out_buf, size_t out_buf_size, AsyncOperationKey op_key) {
|
|
||||||
WaitSeOperationComplete();
|
|
||||||
|
|
||||||
SmcResult op_res;
|
|
||||||
SmcResult res = SmcWrapper::GetResult(&op_res, out_buf, out_buf_size, op_key);
|
|
||||||
if (res != SmcResult_Success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return op_res;
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SecureMonitorWrapper::DecryptAesBlock(u32 keyslot, void *dst, const void *src) {
|
|
||||||
struct DecryptAesBlockLayout {
|
|
||||||
SeCryptContext crypt_ctx;
|
|
||||||
u8 in_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE)));
|
|
||||||
u8 out_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE)));
|
|
||||||
};
|
|
||||||
DecryptAesBlockLayout *layout = reinterpret_cast<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));
|
|
||||||
|
|
||||||
armDCacheFlush(layout, sizeof(*layout));
|
|
||||||
{
|
|
||||||
std::scoped_lock<HosMutex> lk(g_async_op_lock);
|
|
||||||
AsyncOperationKey op_key;
|
|
||||||
const IvCtr iv_ctr = {};
|
|
||||||
const u32 mode = SmcWrapper::GetCryptAesMode(SmcCipherMode_CbcDecrypt, keyslot);
|
|
||||||
const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.out);
|
|
||||||
const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.in);
|
|
||||||
|
|
||||||
SmcResult res = SmcWrapper::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, sizeof(layout->in_block));
|
|
||||||
if (res != SmcResult_Success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((res = WaitCheckStatus(op_key)) != SmcResult_Success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
armDCacheFlush(layout, sizeof(*layout));
|
|
||||||
|
|
||||||
std::memcpy(dst, layout->out_block, sizeof(layout->out_block));
|
|
||||||
return SmcResult_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::GetConfig(u64 *out, SplConfigItem which) {
|
|
||||||
/* Nintendo explicitly blacklists package2 hash here, amusingly. */
|
|
||||||
/* This is not blacklisted in safemode, but we're never in safe mode... */
|
|
||||||
if (which == SplConfigItem_Package2Hash) {
|
|
||||||
return ResultSplInvalidArgument;
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult res = SmcWrapper::GetConfig(out, 1, which);
|
|
||||||
|
|
||||||
/* Nintendo has some special handling here for hardware type/is_retail. */
|
|
||||||
if (which == SplConfigItem_HardwareType && res == SmcResult_InvalidArgument) {
|
|
||||||
*out = 0;
|
|
||||||
res = SmcResult_Success;
|
|
||||||
}
|
|
||||||
if (which == SplConfigItem_IsRetail && res == SmcResult_InvalidArgument) {
|
|
||||||
*out = 0;
|
|
||||||
res = SmcResult_Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConvertToSplResult(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::ExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size) {
|
|
||||||
struct ExpModLayout {
|
|
||||||
u8 base[0x100];
|
|
||||||
u8 exp[0x100];
|
|
||||||
u8 mod[0x100];
|
|
||||||
};
|
|
||||||
ExpModLayout *layout = reinterpret_cast<ExpModLayout *>(g_work_buffer);
|
|
||||||
|
|
||||||
/* Validate sizes. */
|
|
||||||
if (base_size > sizeof(layout->base)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
if (exp_size > sizeof(layout->exp)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
if (mod_size > sizeof(layout->mod)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
if (out_size > MaxWorkBufferSize) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy data into work buffer. */
|
|
||||||
const size_t base_ofs = sizeof(layout->base) - base_size;
|
|
||||||
const size_t mod_ofs = sizeof(layout->mod) - mod_size;
|
|
||||||
std::memset(layout, 0, sizeof(*layout));
|
|
||||||
std::memcpy(layout->base + base_ofs, base, base_size);
|
|
||||||
std::memcpy(layout->exp, exp, exp_size);
|
|
||||||
std::memcpy(layout->mod + mod_ofs, mod, mod_size);
|
|
||||||
|
|
||||||
/* Do exp mod operation. */
|
|
||||||
armDCacheFlush(layout, sizeof(*layout));
|
|
||||||
{
|
|
||||||
std::scoped_lock<HosMutex> lk(g_async_op_lock);
|
|
||||||
AsyncOperationKey op_key;
|
|
||||||
|
|
||||||
SmcResult res = SmcWrapper::ExpMod(&op_key, layout->base, layout->exp, exp_size, layout->mod);
|
|
||||||
if (res != SmcResult_Success) {
|
|
||||||
return ConvertToSplResult(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != SmcResult_Success) {
|
|
||||||
return ConvertToSplResult(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
armDCacheFlush(g_work_buffer, sizeof(out_size));
|
|
||||||
|
|
||||||
std::memcpy(out, g_work_buffer, out_size);
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::SetConfig(SplConfigItem which, u64 value) {
|
|
||||||
return ConvertToSplResult(SmcWrapper::SetConfig(which, &value, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::GenerateRandomBytesInternal(void *out, size_t size) {
|
|
||||||
if (!g_drbg.GenerateRandomBytes(out, size)) {
|
|
||||||
/* We need to reseed. */
|
|
||||||
{
|
|
||||||
u8 seed[CtrDrbg::SeedSize];
|
|
||||||
|
|
||||||
SmcResult res = SmcWrapper::GenerateRandomBytes(seed, sizeof(seed));
|
|
||||||
if (res != SmcResult_Success) {
|
|
||||||
return ConvertToSplResult(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_drbg.Reseed(seed);
|
|
||||||
g_drbg.GenerateRandomBytes(out, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::GenerateRandomBytes(void *out, size_t size) {
|
|
||||||
u8 *cur_dst = reinterpret_cast<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 SecureMonitorWrapper::IsDevelopment(bool *out) {
|
|
||||||
u64 is_retail;
|
|
||||||
R_TRY(this->GetConfig(&is_retail, SplConfigItem_IsRetail));
|
|
||||||
|
|
||||||
*out = (is_retail == 0);
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::SetBootReason(BootReasonValue boot_reason) {
|
|
||||||
if (this->IsBootReasonSet()) {
|
|
||||||
return ResultSplBootReasonAlreadySet;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->boot_reason = boot_reason;
|
|
||||||
this->boot_reason_set = true;
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::GetBootReason(BootReasonValue *out) {
|
|
||||||
if (!this->IsBootReasonSet()) {
|
|
||||||
return ResultSplBootReasonNotSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out = GetBootReason();
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option) {
|
|
||||||
return ConvertToSplResult(SmcWrapper::GenerateAesKek(out_access_key, key_source, generation, option));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source) {
|
|
||||||
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
|
||||||
return ConvertToSplResult(SmcWrapper::LoadAesKey(keyslot, access_key, key_source));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) {
|
|
||||||
SmcResult smc_rc;
|
|
||||||
|
|
||||||
static const KeySource s_generate_aes_key_source = {
|
|
||||||
.data = {0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}
|
|
||||||
};
|
|
||||||
|
|
||||||
ScopedAesKeyslot keyslot_holder(this);
|
|
||||||
R_TRY(keyslot_holder.Allocate());
|
|
||||||
|
|
||||||
smc_rc = SmcWrapper::LoadAesKey(keyslot_holder.GetKeyslot(), access_key, s_generate_aes_key_source);
|
|
||||||
if (smc_rc == SmcResult_Success) {
|
|
||||||
smc_rc = DecryptAesBlock(keyslot_holder.GetKeyslot(), out_key, &key_source);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConvertToSplResult(smc_rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option) {
|
|
||||||
static const KeySource s_decrypt_aes_key_source = {
|
|
||||||
.data = {0x11, 0x70, 0x24, 0x2B, 0x48, 0x69, 0x11, 0xF1, 0x11, 0xB0, 0x0C, 0x47, 0x7C, 0xC3, 0xEF, 0x7E}
|
|
||||||
};
|
|
||||||
|
|
||||||
AccessKey access_key;
|
|
||||||
R_TRY(GenerateAesKek(&access_key, s_decrypt_aes_key_source, generation, option));
|
|
||||||
|
|
||||||
return GenerateAesKey(out_key, access_key, key_source);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::CryptAesCtr(void *dst, size_t dst_size, u32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr) {
|
|
||||||
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
|
||||||
|
|
||||||
/* Succeed immediately if there's nothing to crypt. */
|
|
||||||
if (src_size == 0) {
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Validate sizes. */
|
|
||||||
if (src_size > dst_size || src_size % AES_BLOCK_SIZE != 0) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We can only map 0x400000 aligned buffers for the SE. With that in mind, we have some math to do. */
|
|
||||||
const uintptr_t src_addr = reinterpret_cast<uintptr_t>(src);
|
|
||||||
const uintptr_t dst_addr = reinterpret_cast<uintptr_t>(dst);
|
|
||||||
const uintptr_t src_addr_page_aligned = src_addr & ~0xFFFul;
|
|
||||||
const uintptr_t dst_addr_page_aligned = dst_addr & ~0xFFFul;
|
|
||||||
const size_t src_size_page_aligned = ((src_addr + src_size + 0xFFFul) & ~0xFFFul) - src_addr_page_aligned;
|
|
||||||
const size_t dst_size_page_aligned = ((dst_addr + dst_size + 0xFFFul) & ~0xFFFul) - dst_addr_page_aligned;
|
|
||||||
const u32 src_se_map_addr = CryptAesInMapBase + (src_addr_page_aligned & DeviceAddressSpaceAlignMask);
|
|
||||||
const u32 dst_se_map_addr = CryptAesOutMapBase + (dst_addr_page_aligned & DeviceAddressSpaceAlignMask);
|
|
||||||
const u32 src_se_addr = CryptAesInMapBase + (src_addr & DeviceAddressSpaceAlignMask);
|
|
||||||
const u32 dst_se_addr = CryptAesOutMapBase + (dst_addr & DeviceAddressSpaceAlignMask);
|
|
||||||
|
|
||||||
/* Validate aligned sizes. */
|
|
||||||
if (src_size_page_aligned > CryptAesSizeMax || dst_size_page_aligned > CryptAesSizeMax) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Helpers for mapping/unmapping. */
|
|
||||||
DeviceAddressSpaceMapHelper in_mapper(g_se_das_hnd, src_se_map_addr, src_addr_page_aligned, src_size_page_aligned, 1);
|
|
||||||
DeviceAddressSpaceMapHelper out_mapper(g_se_das_hnd, dst_se_map_addr, dst_addr_page_aligned, dst_size_page_aligned, 2);
|
|
||||||
|
|
||||||
/* Setup SE linked list entries. */
|
|
||||||
SeCryptContext *crypt_ctx = reinterpret_cast<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;
|
|
||||||
|
|
||||||
armDCacheFlush(crypt_ctx, sizeof(*crypt_ctx));
|
|
||||||
armDCacheFlush(const_cast<void *>(src), src_size);
|
|
||||||
armDCacheFlush(dst, dst_size);
|
|
||||||
{
|
|
||||||
std::scoped_lock<HosMutex> lk(g_async_op_lock);
|
|
||||||
AsyncOperationKey op_key;
|
|
||||||
const u32 mode = SmcWrapper::GetCryptAesMode(SmcCipherMode_Ctr, keyslot);
|
|
||||||
const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, out);
|
|
||||||
const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, in);
|
|
||||||
|
|
||||||
SmcResult res = SmcWrapper::CryptAes(&op_key, mode, iv_ctr, dst_ll_addr, src_ll_addr, src_size);
|
|
||||||
if (res != SmcResult_Success) {
|
|
||||||
return ConvertToSplResult(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((res = WaitCheckStatus(op_key)) != SmcResult_Success) {
|
|
||||||
return ConvertToSplResult(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
armDCacheFlush(dst, dst_size);
|
|
||||||
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size) {
|
|
||||||
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
|
||||||
|
|
||||||
if (size > MaxWorkBufferSize) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(g_work_buffer, data, size);
|
|
||||||
return ConvertToSplResult(SmcWrapper::ComputeCmac(out_cmac, keyslot, g_work_buffer, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::AllocateAesKeyslot(u32 *out_keyslot, const void *owner) {
|
|
||||||
if (GetRuntimeFirmwareVersion() <= FirmwareVersion_100) {
|
|
||||||
/* On 1.0.0, keyslots were kind of a wild west. */
|
|
||||||
*out_keyslot = 0;
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < GetMaxKeyslots(); i++) {
|
|
||||||
if (this->keyslot_owners[i] == 0) {
|
|
||||||
this->keyslot_owners[i] = owner;
|
|
||||||
*out_keyslot = static_cast<u32>(i);
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_se_keyslot_available_event->Clear();
|
|
||||||
return ResultSplOutOfKeyslots;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::ValidateAesKeyslot(u32 keyslot, const void *owner) {
|
|
||||||
if (keyslot >= GetMaxKeyslots()) {
|
|
||||||
return ResultSplInvalidKeyslot;
|
|
||||||
}
|
|
||||||
if (this->keyslot_owners[keyslot] != owner && GetRuntimeFirmwareVersion() > FirmwareVersion_100) {
|
|
||||||
return ResultSplInvalidKeyslot;
|
|
||||||
}
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::FreeAesKeyslot(u32 keyslot, const void *owner) {
|
|
||||||
if (GetRuntimeFirmwareVersion() <= FirmwareVersion_100) {
|
|
||||||
/* On 1.0.0, keyslots were kind of a wild west. */
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
|
||||||
|
|
||||||
/* Clear the keyslot. */
|
|
||||||
{
|
|
||||||
AccessKey access_key = {};
|
|
||||||
KeySource key_source = {};
|
|
||||||
|
|
||||||
SmcWrapper::LoadAesKey(keyslot, access_key, key_source);
|
|
||||||
}
|
|
||||||
this->keyslot_owners[keyslot] = nullptr;
|
|
||||||
g_se_keyslot_available_event->Signal();
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::DecryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
|
||||||
struct DecryptRsaPrivateKeyLayout {
|
|
||||||
u8 data[RsaPrivateKeySize + RsaPrivateKeyMetaSize];
|
|
||||||
};
|
|
||||||
DecryptRsaPrivateKeyLayout *layout = reinterpret_cast<DecryptRsaPrivateKeyLayout *>(g_work_buffer);
|
|
||||||
|
|
||||||
/* Validate size. */
|
|
||||||
if (src_size < RsaPrivateKeyMetaSize || src_size > sizeof(DecryptRsaPrivateKeyLayout)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(layout->data, src, src_size);
|
|
||||||
armDCacheFlush(layout, sizeof(*layout));
|
|
||||||
|
|
||||||
SmcResult smc_res;
|
|
||||||
size_t copy_size = 0;
|
|
||||||
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
|
|
||||||
copy_size = std::min(dst_size, src_size - RsaPrivateKeyMetaSize);
|
|
||||||
smc_res = SmcWrapper::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, SmcDecryptOrImportMode_DecryptRsaPrivateKey);
|
|
||||||
} else {
|
|
||||||
smc_res = SmcWrapper::DecryptRsaPrivateKey(©_size, layout->data, src_size, access_key, key_source, option);
|
|
||||||
copy_size = std::min(dst_size, copy_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
armDCacheFlush(layout, sizeof(*layout));
|
|
||||||
if (smc_res == SmcResult_Success) {
|
|
||||||
std::memcpy(dst, layout->data, copy_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConvertToSplResult(smc_res);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::ImportSecureExpModKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
|
||||||
struct ImportSecureExpModKeyLayout {
|
|
||||||
u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10];
|
|
||||||
};
|
|
||||||
ImportSecureExpModKeyLayout *layout = reinterpret_cast<ImportSecureExpModKeyLayout *>(g_work_buffer);
|
|
||||||
|
|
||||||
/* Validate size. */
|
|
||||||
if (src_size > sizeof(ImportSecureExpModKeyLayout)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(layout, src, src_size);
|
|
||||||
|
|
||||||
armDCacheFlush(layout, sizeof(*layout));
|
|
||||||
SmcResult smc_res;
|
|
||||||
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
|
|
||||||
smc_res = SmcWrapper::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, option);
|
|
||||||
} else {
|
|
||||||
smc_res = SmcWrapper::ImportSecureExpModKey(layout->data, src_size, access_key, key_source, option);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConvertToSplResult(smc_res);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::SecureExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size, u32 option) {
|
|
||||||
struct SecureExpModLayout {
|
|
||||||
u8 base[0x100];
|
|
||||||
u8 mod[0x100];
|
|
||||||
};
|
|
||||||
SecureExpModLayout *layout = reinterpret_cast<SecureExpModLayout *>(g_work_buffer);
|
|
||||||
|
|
||||||
/* Validate sizes. */
|
|
||||||
if (base_size > sizeof(layout->base)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
if (mod_size > sizeof(layout->mod)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
if (out_size > MaxWorkBufferSize) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy data into work buffer. */
|
|
||||||
const size_t base_ofs = sizeof(layout->base) - base_size;
|
|
||||||
const size_t mod_ofs = sizeof(layout->mod) - mod_size;
|
|
||||||
std::memset(layout, 0, sizeof(*layout));
|
|
||||||
std::memcpy(layout->base + base_ofs, base, base_size);
|
|
||||||
std::memcpy(layout->mod + mod_ofs, mod, mod_size);
|
|
||||||
|
|
||||||
/* Do exp mod operation. */
|
|
||||||
armDCacheFlush(layout, sizeof(*layout));
|
|
||||||
{
|
|
||||||
std::scoped_lock<HosMutex> lk(g_async_op_lock);
|
|
||||||
AsyncOperationKey op_key;
|
|
||||||
|
|
||||||
SmcResult res = SmcWrapper::SecureExpMod(&op_key, layout->base, layout->mod, option);
|
|
||||||
if (res != SmcResult_Success) {
|
|
||||||
return ConvertToSplResult(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != SmcResult_Success) {
|
|
||||||
return ConvertToSplResult(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
armDCacheFlush(g_work_buffer, sizeof(out_size));
|
|
||||||
|
|
||||||
std::memcpy(out, g_work_buffer, out_size);
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) {
|
|
||||||
return ImportSecureExpModKey(src, src_size, access_key, key_source, SmcDecryptOrImportMode_ImportSslKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) {
|
|
||||||
return SecureExpMod(out, out_size, base, base_size, mod, mod_size, SmcSecureExpModMode_Ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
|
||||||
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
|
|
||||||
return ImportSecureExpModKey(src, src_size, access_key, key_source, SmcDecryptOrImportMode_ImportEsKey);
|
|
||||||
} else {
|
|
||||||
struct ImportEsKeyLayout {
|
|
||||||
u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10];
|
|
||||||
};
|
|
||||||
ImportEsKeyLayout *layout = reinterpret_cast<ImportEsKeyLayout *>(g_work_buffer);
|
|
||||||
|
|
||||||
/* Validate size. */
|
|
||||||
if (src_size > sizeof(ImportEsKeyLayout)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(layout, src, src_size);
|
|
||||||
|
|
||||||
armDCacheFlush(layout, sizeof(*layout));
|
|
||||||
return ConvertToSplResult(SmcWrapper::ImportEsKey(layout->data, src_size, access_key, key_source, option));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::UnwrapEsRsaOaepWrappedKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation, EsKeyType type) {
|
|
||||||
struct UnwrapEsKeyLayout {
|
|
||||||
u8 base[0x100];
|
|
||||||
u8 mod[0x100];
|
|
||||||
};
|
|
||||||
UnwrapEsKeyLayout *layout = reinterpret_cast<UnwrapEsKeyLayout *>(g_work_buffer);
|
|
||||||
|
|
||||||
/* Validate sizes. */
|
|
||||||
if (base_size > sizeof(layout->base)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
if (mod_size > sizeof(layout->mod)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
if (label_digest_size > LabelDigestSizeMax) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy data into work buffer. */
|
|
||||||
const size_t base_ofs = sizeof(layout->base) - base_size;
|
|
||||||
const size_t mod_ofs = sizeof(layout->mod) - mod_size;
|
|
||||||
std::memset(layout, 0, sizeof(*layout));
|
|
||||||
std::memcpy(layout->base + base_ofs, base, base_size);
|
|
||||||
std::memcpy(layout->mod + mod_ofs, mod, mod_size);
|
|
||||||
|
|
||||||
/* Do exp mod operation. */
|
|
||||||
armDCacheFlush(layout, sizeof(*layout));
|
|
||||||
{
|
|
||||||
std::scoped_lock<HosMutex> lk(g_async_op_lock);
|
|
||||||
AsyncOperationKey op_key;
|
|
||||||
|
|
||||||
SmcResult res = SmcWrapper::UnwrapTitleKey(&op_key, layout->base, layout->mod, label_digest, label_digest_size, SmcWrapper::GetUnwrapEsKeyOption(type, generation));
|
|
||||||
if (res != SmcResult_Success) {
|
|
||||||
return ConvertToSplResult(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((res = WaitGetResult(g_work_buffer, sizeof(*out_access_key), op_key)) != SmcResult_Success) {
|
|
||||||
return ConvertToSplResult(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
armDCacheFlush(g_work_buffer, sizeof(*out_access_key));
|
|
||||||
|
|
||||||
std::memcpy(out_access_key, g_work_buffer, sizeof(*out_access_key));
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::UnwrapTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation) {
|
|
||||||
return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, EsKeyType_TitleKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation) {
|
|
||||||
return ConvertToSplResult(SmcWrapper::UnwrapCommonTitleKey(out_access_key, key_source, generation));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) {
|
|
||||||
return ImportSecureExpModKey(src, src_size, access_key, key_source, SmcDecryptOrImportMode_ImportDrmKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::DrmExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) {
|
|
||||||
return SecureExpMod(out, out_size, base, base_size, mod, mod_size, SmcSecureExpModMode_Drm);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::UnwrapElicenseKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation) {
|
|
||||||
return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, EsKeyType_ElicenseKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::LoadElicenseKey(u32 keyslot, const void *owner, const AccessKey &access_key) {
|
|
||||||
/* Right now, this is just literally the same function as LoadTitleKey in N's impl. */
|
|
||||||
return LoadTitleKey(keyslot, owner, access_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) {
|
|
||||||
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) {
|
|
||||||
option = SmcDecryptOrImportMode_ImportLotusKey;
|
|
||||||
}
|
|
||||||
return ImportSecureExpModKey(src, src_size, access_key, key_source, option);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::DecryptLotusMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size) {
|
|
||||||
/* Validate sizes. */
|
|
||||||
if (dst_size > MaxWorkBufferSize || label_digest_size != LabelDigestSizeMax) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nintendo doesn't check this result code, but we will. */
|
|
||||||
R_TRY(SecureExpMod(g_work_buffer, 0x100, base, base_size, mod, mod_size, SmcSecureExpModMode_Lotus));
|
|
||||||
|
|
||||||
size_t data_size = DecodeRsaOaep(dst, dst_size, label_digest, label_digest_size, g_work_buffer, 0x100);
|
|
||||||
if (data_size == 0) {
|
|
||||||
return ResultSplDecryptionFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_size = static_cast<u32>(data_size);
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which) {
|
|
||||||
return ConvertToSplResult(SmcWrapper::GenerateSpecificAesKey(out_key, key_source, generation, which));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key) {
|
|
||||||
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
|
||||||
return ConvertToSplResult(SmcWrapper::LoadTitleKey(keyslot, access_key));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::GetPackage2Hash(void *dst, const size_t size) {
|
|
||||||
u64 hash[4];
|
|
||||||
|
|
||||||
if (size < sizeof(hash)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult smc_res;
|
|
||||||
if ((smc_res = SmcWrapper::GetConfig(hash, 4, SplConfigItem_Package2Hash)) != SmcResult_Success) {
|
|
||||||
return ConvertToSplResult(smc_res);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(dst, hash, sizeof(hash));
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::ReEncryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option) {
|
|
||||||
struct ReEncryptRsaPrivateKeyLayout {
|
|
||||||
u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize + 0x10];
|
|
||||||
AccessKey access_key_dec;
|
|
||||||
KeySource source_dec;
|
|
||||||
AccessKey access_key_enc;
|
|
||||||
KeySource source_enc;
|
|
||||||
};
|
|
||||||
ReEncryptRsaPrivateKeyLayout *layout = reinterpret_cast<ReEncryptRsaPrivateKeyLayout *>(g_work_buffer);
|
|
||||||
|
|
||||||
/* Validate size. */
|
|
||||||
if (src_size < RsaPrivateKeyMetaSize || src_size > sizeof(ReEncryptRsaPrivateKeyLayout)) {
|
|
||||||
return ResultSplInvalidSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(layout, src, src_size);
|
|
||||||
layout->access_key_dec = access_key_dec;
|
|
||||||
layout->source_dec = source_dec;
|
|
||||||
layout->access_key_enc = access_key_enc;
|
|
||||||
layout->source_enc = source_enc;
|
|
||||||
|
|
||||||
armDCacheFlush(layout, sizeof(*layout));
|
|
||||||
|
|
||||||
SmcResult smc_res = SmcWrapper::ReEncryptRsaPrivateKey(layout->data, src_size, layout->access_key_dec, layout->source_dec, layout->access_key_enc, layout->source_enc, option);
|
|
||||||
if (smc_res == SmcResult_Success) {
|
|
||||||
size_t copy_size = std::min(dst_size, src_size);
|
|
||||||
armDCacheFlush(layout, copy_size);
|
|
||||||
std::memcpy(dst, layout->data, copy_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConvertToSplResult(smc_res);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SecureMonitorWrapper::FreeAesKeyslots(const void *owner) {
|
|
||||||
for (size_t i = 0; i < GetMaxKeyslots(); i++) {
|
|
||||||
if (this->keyslot_owners[i] == owner) {
|
|
||||||
FreeAesKeyslot(i, owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle SecureMonitorWrapper::GetAesKeyslotAvailableEventHandle() {
|
|
||||||
return g_se_keyslot_available_event->GetHandle();
|
|
||||||
}
|
|
|
@ -1,137 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <switch.h>
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
|
|
||||||
#include "spl_types.hpp"
|
|
||||||
|
|
||||||
class SecureMonitorWrapper {
|
|
||||||
public:
|
|
||||||
static constexpr size_t MaxAesKeyslots = 6;
|
|
||||||
static constexpr size_t MaxAesKeyslotsDeprecated = 4;
|
|
||||||
private:
|
|
||||||
const void *keyslot_owners[MaxAesKeyslots] = {};
|
|
||||||
BootReasonValue boot_reason = {};
|
|
||||||
bool boot_reason_set = false;
|
|
||||||
private:
|
|
||||||
static size_t GetMaxKeyslots() {
|
|
||||||
return (GetRuntimeFirmwareVersion() >= FirmwareVersion_600) ? MaxAesKeyslots : MaxAesKeyslotsDeprecated;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
BootReasonValue GetBootReason() const {
|
|
||||||
return this->boot_reason;
|
|
||||||
}
|
|
||||||
bool IsBootReasonSet() const {
|
|
||||||
return this->boot_reason_set;
|
|
||||||
}
|
|
||||||
static Result ConvertToSplResult(SmcResult result);
|
|
||||||
private:
|
|
||||||
static void InitializeCtrDrbg();
|
|
||||||
static void InitializeSeEvents();
|
|
||||||
static void InitializeDeviceAddressSpace();
|
|
||||||
|
|
||||||
static void CalcMgf1AndXor(void *dst, size_t dst_size, const void *src, size_t src_size);
|
|
||||||
static size_t DecodeRsaOaep(void *dst, size_t dst_size, const void *label_digest, size_t label_digest_size, const void *src, size_t src_size);
|
|
||||||
public:
|
|
||||||
static void Initialize();
|
|
||||||
private:
|
|
||||||
Result GenerateRandomBytesInternal(void *out, size_t size);
|
|
||||||
void WaitSeOperationComplete();
|
|
||||||
SmcResult WaitCheckStatus(AsyncOperationKey op_key);
|
|
||||||
SmcResult WaitGetResult(void *out_buf, size_t out_buf_size, AsyncOperationKey op_key);
|
|
||||||
Result ValidateAesKeyslot(u32 keyslot, const void *owner);
|
|
||||||
SmcResult DecryptAesBlock(u32 keyslot, void *dst, const void *src);
|
|
||||||
Result ImportSecureExpModKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
|
||||||
Result SecureExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size, u32 option);
|
|
||||||
Result UnwrapEsRsaOaepWrappedKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation, EsKeyType type);
|
|
||||||
public:
|
|
||||||
/* General. */
|
|
||||||
Result GetConfig(u64 *out, SplConfigItem which);
|
|
||||||
Result ExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *exp, size_t exp_size, const void *mod, size_t mod_size);
|
|
||||||
Result SetConfig(SplConfigItem which, u64 value);
|
|
||||||
Result GenerateRandomBytes(void *out, size_t size);
|
|
||||||
Result IsDevelopment(bool *out);
|
|
||||||
Result SetBootReason(BootReasonValue boot_reason);
|
|
||||||
Result GetBootReason(BootReasonValue *out);
|
|
||||||
|
|
||||||
/* Crypto. */
|
|
||||||
Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option);
|
|
||||||
Result LoadAesKey(u32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source);
|
|
||||||
Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source);
|
|
||||||
Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option);
|
|
||||||
Result CryptAesCtr(void *dst, size_t dst_size, u32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr);
|
|
||||||
Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size);
|
|
||||||
Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner);
|
|
||||||
Result FreeAesKeyslot(u32 keyslot, const void *owner);
|
|
||||||
|
|
||||||
/* RSA. */
|
|
||||||
Result DecryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
|
||||||
|
|
||||||
/* SSL */
|
|
||||||
Result ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
|
|
||||||
Result SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size);
|
|
||||||
|
|
||||||
/* ES */
|
|
||||||
Result ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
|
||||||
Result UnwrapTitleKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation);
|
|
||||||
Result UnwrapCommonTitleKey(AccessKey *out_access_key, const KeySource &key_source, u32 generation);
|
|
||||||
Result ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
|
|
||||||
Result DrmExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size);
|
|
||||||
Result UnwrapElicenseKey(AccessKey *out_access_key, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size, u32 generation);
|
|
||||||
Result LoadElicenseKey(u32 keyslot, const void *owner, const AccessKey &access_key);
|
|
||||||
|
|
||||||
/* FS */
|
|
||||||
Result ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
|
||||||
Result DecryptLotusMessage(u32 *out_size, void *dst, size_t dst_size, const void *base, size_t base_size, const void *mod, size_t mod_size, const void *label_digest, size_t label_digest_size);
|
|
||||||
Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which);
|
|
||||||
Result LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key);
|
|
||||||
Result GetPackage2Hash(void *dst, const size_t size);
|
|
||||||
|
|
||||||
/* Manu. */
|
|
||||||
Result ReEncryptRsaPrivateKey(void *dst, size_t dst_size, const void *src, size_t src_size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option);
|
|
||||||
|
|
||||||
/* Helper. */
|
|
||||||
Result FreeAesKeyslots(const void *owner);
|
|
||||||
Handle GetAesKeyslotAvailableEventHandle();
|
|
||||||
private:
|
|
||||||
class ScopedAesKeyslot {
|
|
||||||
private:
|
|
||||||
SecureMonitorWrapper *secmon_wrapper;
|
|
||||||
u32 slot;
|
|
||||||
bool has_slot;
|
|
||||||
public:
|
|
||||||
ScopedAesKeyslot(SecureMonitorWrapper *sw) : secmon_wrapper(sw), slot(0), has_slot(false) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
~ScopedAesKeyslot() {
|
|
||||||
if (has_slot) {
|
|
||||||
this->secmon_wrapper->FreeAesKeyslot(slot, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetKeyslot() const {
|
|
||||||
return this->slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result Allocate() {
|
|
||||||
R_TRY(this->secmon_wrapper->AllocateAesKeyslot(&this->slot, this));
|
|
||||||
this->has_slot = true;
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
313
stratosphere/spl/source/spl_smc.cpp
Normal file
313
stratosphere/spl/source/spl_smc.cpp
Normal file
|
@ -0,0 +1,313 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "spl_smc.hpp"
|
||||||
|
|
||||||
|
namespace sts::spl::smc {
|
||||||
|
|
||||||
|
Result SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::SetConfig);
|
||||||
|
args.X[1] = which;
|
||||||
|
args.X[2] = 0;
|
||||||
|
for (size_t i = 0; i < std::min(size_t(4), num_qwords); i++) {
|
||||||
|
args.X[3 + i] = value[i];
|
||||||
|
}
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetConfig(u64 *out, size_t num_qwords, SplConfigItem which) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::GetConfig);
|
||||||
|
args.X[1] = which;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < std::min(size_t(4), num_qwords); i++) {
|
||||||
|
out[i] = args.X[1 + i];
|
||||||
|
}
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CheckStatus(Result *out, AsyncOperationKey op) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::CheckStatus);
|
||||||
|
args.X[1] = op.value;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
*out = static_cast<Result>(args.X[1]);
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetResult(Result *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::GetResult);
|
||||||
|
args.X[1] = op.value;
|
||||||
|
args.X[2] = reinterpret_cast<u64>(out_buf);
|
||||||
|
args.X[3] = out_buf_size;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
*out = static_cast<Result>(args.X[1]);
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ExpMod(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::ExpMod);
|
||||||
|
args.X[1] = reinterpret_cast<u64>(base);
|
||||||
|
args.X[2] = reinterpret_cast<u64>(exp);
|
||||||
|
args.X[3] = reinterpret_cast<u64>(mod);
|
||||||
|
args.X[4] = exp_size;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
out_op->value = args.X[1];
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GenerateRandomBytes(void *out, size_t size) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::GenerateRandomBytes);
|
||||||
|
args.X[1] = size;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
if (args.X[0] == static_cast<u64>(Result::Success) && (size <= sizeof(args) - sizeof(args.X[0]))) {
|
||||||
|
std::memcpy(out, &args.X[1], size);
|
||||||
|
}
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GenerateAesKek(AccessKey *out, const KeySource &source, u32 generation, u32 option) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::GenerateAesKek);
|
||||||
|
args.X[1] = source.data64[0];
|
||||||
|
args.X[2] = source.data64[1];
|
||||||
|
args.X[3] = generation;
|
||||||
|
args.X[4] = option;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
out->data64[0] = args.X[1];
|
||||||
|
out->data64[1] = args.X[2];
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LoadAesKey(u32 keyslot, const AccessKey &access_key, const KeySource &source) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::LoadAesKey);
|
||||||
|
args.X[1] = keyslot;
|
||||||
|
args.X[2] = access_key.data64[0];
|
||||||
|
args.X[3] = access_key.data64[1];
|
||||||
|
args.X[4] = source.data64[0];
|
||||||
|
args.X[5] = source.data64[1];
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CryptAes(AsyncOperationKey *out_op, u32 mode, const IvCtr &iv_ctr, u32 dst_addr, u32 src_addr, size_t size) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::CryptAes);
|
||||||
|
args.X[1] = mode;
|
||||||
|
args.X[2] = iv_ctr.data64[0];
|
||||||
|
args.X[3] = iv_ctr.data64[1];
|
||||||
|
args.X[4] = src_addr;
|
||||||
|
args.X[5] = dst_addr;
|
||||||
|
args.X[6] = size;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
out_op->value = args.X[1];
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &source, u32 generation, u32 which) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::GenerateSpecificAesKey);
|
||||||
|
args.X[1] = source.data64[0];
|
||||||
|
args.X[2] = source.data64[1];
|
||||||
|
args.X[3] = generation;
|
||||||
|
args.X[4] = which;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
out_key->data64[0] = args.X[1];
|
||||||
|
out_key->data64[1] = args.X[2];
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ComputeCmac(Cmac *out_mac, u32 keyslot, const void *data, size_t size) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::ComputeCmac);
|
||||||
|
args.X[1] = keyslot;
|
||||||
|
args.X[2] = reinterpret_cast<u64>(data);
|
||||||
|
args.X[3] = size;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
out_mac->data64[0] = args.X[1];
|
||||||
|
out_mac->data64[1] = args.X[2];
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ReEncryptRsaPrivateKey(void *data, size_t size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::ReEncryptRsaPrivateKey);
|
||||||
|
args.X[1] = reinterpret_cast<u64>(&access_key_dec);
|
||||||
|
args.X[2] = reinterpret_cast<u64>(&access_key_enc);
|
||||||
|
args.X[3] = option;
|
||||||
|
args.X[4] = reinterpret_cast<u64>(data);
|
||||||
|
args.X[5] = size;
|
||||||
|
args.X[6] = reinterpret_cast<u64>(&source_dec);
|
||||||
|
args.X[7] = reinterpret_cast<u64>(&source_enc);
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const KeySource &source, DecryptOrImportMode mode) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::DecryptOrImportRsaPrivateKey);
|
||||||
|
args.X[1] = access_key.data64[0];
|
||||||
|
args.X[2] = access_key.data64[1];
|
||||||
|
args.X[3] = static_cast<u32>(mode);
|
||||||
|
args.X[4] = reinterpret_cast<u64>(data);
|
||||||
|
args.X[5] = size;
|
||||||
|
args.X[6] = source.data64[0];
|
||||||
|
args.X[7] = source.data64[1];
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SecureExpMod(AsyncOperationKey *out_op, const void *base, const void *mod, SecureExpModMode mode) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::SecureExpMod);
|
||||||
|
args.X[1] = reinterpret_cast<u64>(base);
|
||||||
|
args.X[2] = reinterpret_cast<u64>(mod);
|
||||||
|
args.X[3] = static_cast<u32>(mode);
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
out_op->value = args.X[1];
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnwrapTitleKey(AsyncOperationKey *out_op, const void *base, const void *mod, const void *label_digest, size_t label_digest_size, u32 option) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::UnwrapTitleKey);
|
||||||
|
args.X[1] = reinterpret_cast<u64>(base);
|
||||||
|
args.X[2] = reinterpret_cast<u64>(mod);
|
||||||
|
std::memset(&args.X[3], 0, 4 * sizeof(args.X[3]));
|
||||||
|
std::memcpy(&args.X[3], label_digest, std::min(size_t(4 * sizeof(args.X[3])), label_digest_size));
|
||||||
|
args.X[7] = option;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
out_op->value = args.X[1];
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LoadTitleKey(u32 keyslot, const AccessKey &access_key) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::LoadTitleKey);
|
||||||
|
args.X[1] = keyslot;
|
||||||
|
args.X[2] = access_key.data64[0];
|
||||||
|
args.X[3] = access_key.data64[1];
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnwrapCommonTitleKey(AccessKey *out, const KeySource &source, u32 generation) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::UnwrapCommonTitleKey);
|
||||||
|
args.X[1] = source.data64[0];
|
||||||
|
args.X[2] = source.data64[1];
|
||||||
|
args.X[3] = generation;
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
out->data64[0] = args.X[1];
|
||||||
|
out->data64[1] = args.X[2];
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Deprecated functions. */
|
||||||
|
Result ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::ImportEsKey);
|
||||||
|
args.X[1] = access_key.data64[0];
|
||||||
|
args.X[2] = access_key.data64[1];
|
||||||
|
args.X[3] = option;
|
||||||
|
args.X[4] = reinterpret_cast<u64>(data);
|
||||||
|
args.X[5] = size;
|
||||||
|
args.X[6] = source.data64[0];
|
||||||
|
args.X[7] = source.data64[1];
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::DecryptRsaPrivateKey);
|
||||||
|
args.X[1] = access_key.data64[0];
|
||||||
|
args.X[2] = access_key.data64[1];
|
||||||
|
args.X[3] = option;
|
||||||
|
args.X[4] = reinterpret_cast<u64>(data);
|
||||||
|
args.X[5] = size;
|
||||||
|
args.X[6] = source.data64[0];
|
||||||
|
args.X[7] = source.data64[1];
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
*out_size = static_cast<size_t>(args.X[1]);
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ImportSecureExpModKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) {
|
||||||
|
SecmonArgs args;
|
||||||
|
|
||||||
|
args.X[0] = static_cast<u64>(FunctionId::ImportSecureExpModKey);
|
||||||
|
args.X[1] = access_key.data64[0];
|
||||||
|
args.X[2] = access_key.data64[1];
|
||||||
|
args.X[3] = option;
|
||||||
|
args.X[4] = reinterpret_cast<u64>(data);
|
||||||
|
args.X[5] = size;
|
||||||
|
args.X[6] = source.data64[0];
|
||||||
|
args.X[7] = source.data64[1];
|
||||||
|
svcCallSecureMonitor(&args);
|
||||||
|
|
||||||
|
return static_cast<Result>(args.X[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
58
stratosphere/spl/source/spl_smc.hpp
Normal file
58
stratosphere/spl/source/spl_smc.hpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
#include "spl_types.hpp"
|
||||||
|
|
||||||
|
namespace sts::spl::smc {
|
||||||
|
|
||||||
|
/* Helpers for converting arguments. */
|
||||||
|
inline u32 GetCryptAesMode(CipherMode mode, u32 keyslot) {
|
||||||
|
return static_cast<u32>((static_cast<u32>(mode) << 4) | (keyslot & 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 GetUnwrapEsKeyOption(EsKeyType type, u32 generation) {
|
||||||
|
return static_cast<u32>((static_cast<u32>(type) << 6) | (generation & 0x3F));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Functions. */
|
||||||
|
Result SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords);
|
||||||
|
Result GetConfig(u64 *out, size_t num_qwords, SplConfigItem which);
|
||||||
|
Result CheckStatus(Result *out, AsyncOperationKey op);
|
||||||
|
Result GetResult(Result *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op);
|
||||||
|
Result ExpMod(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod);
|
||||||
|
Result GenerateRandomBytes(void *out, size_t size);
|
||||||
|
Result GenerateAesKek(AccessKey *out, const KeySource &source, u32 generation, u32 option);
|
||||||
|
Result LoadAesKey(u32 keyslot, const AccessKey &access_key, const KeySource &source);
|
||||||
|
Result CryptAes(AsyncOperationKey *out_op, u32 mode, const IvCtr &iv_ctr, u32 dst_addr, u32 src_addr, size_t size);
|
||||||
|
Result GenerateSpecificAesKey(AesKey *out_key, const KeySource &source, u32 generation, u32 which);
|
||||||
|
Result ComputeCmac(Cmac *out_mac, u32 keyslot, const void *data, size_t size);
|
||||||
|
Result ReEncryptRsaPrivateKey(void *data, size_t size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option);
|
||||||
|
Result DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const KeySource &source, DecryptOrImportMode mode);
|
||||||
|
Result SecureExpMod(AsyncOperationKey *out_op, const void *base, const void *mod, SecureExpModMode mode);
|
||||||
|
Result UnwrapTitleKey(AsyncOperationKey *out_op, const void *base, const void *mod, const void *label_digest, size_t label_digest_size, u32 option);
|
||||||
|
Result LoadTitleKey(u32 keyslot, const AccessKey &access_key);
|
||||||
|
Result UnwrapCommonTitleKey(AccessKey *out, const KeySource &source, u32 generation);
|
||||||
|
|
||||||
|
/* Deprecated functions. */
|
||||||
|
Result ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option);
|
||||||
|
Result DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option);
|
||||||
|
Result ImportSecureExpModKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option);
|
||||||
|
|
||||||
|
}
|
|
@ -1,336 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <switch.h>
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
|
|
||||||
#include "spl_smc_wrapper.hpp"
|
|
||||||
|
|
||||||
enum SmcFunctionId : u32 {
|
|
||||||
SmcFunctionId_SetConfig = 0xC3000401,
|
|
||||||
SmcFunctionId_GetConfig = 0xC3000002,
|
|
||||||
SmcFunctionId_CheckStatus = 0xC3000003,
|
|
||||||
SmcFunctionId_GetResult = 0xC3000404,
|
|
||||||
SmcFunctionId_ExpMod = 0xC3000E05,
|
|
||||||
SmcFunctionId_GenerateRandomBytes = 0xC3000006,
|
|
||||||
SmcFunctionId_GenerateAesKek = 0xC3000007,
|
|
||||||
SmcFunctionId_LoadAesKey = 0xC3000008,
|
|
||||||
SmcFunctionId_CryptAes = 0xC3000009,
|
|
||||||
SmcFunctionId_GenerateSpecificAesKey = 0xC300000A,
|
|
||||||
SmcFunctionId_ComputeCmac = 0xC300040B,
|
|
||||||
SmcFunctionId_ReEncryptRsaPrivateKey = 0xC300D60C,
|
|
||||||
SmcFunctionId_DecryptOrImportRsaPrivateKey = 0xC300100D,
|
|
||||||
|
|
||||||
SmcFunctionId_SecureExpMod = 0xC300060F,
|
|
||||||
SmcFunctionId_UnwrapTitleKey = 0xC3000610,
|
|
||||||
SmcFunctionId_LoadTitleKey = 0xC3000011,
|
|
||||||
SmcFunctionId_UnwrapCommonTitleKey = 0xC3000012,
|
|
||||||
|
|
||||||
/* Deprecated functions. */
|
|
||||||
SmcFunctionId_ImportEsKey = 0xC300100C,
|
|
||||||
SmcFunctionId_DecryptRsaPrivateKey = 0xC300100D,
|
|
||||||
SmcFunctionId_ImportSecureExpModKey = 0xC300100E,
|
|
||||||
};
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_SetConfig;
|
|
||||||
args.X[1] = which;
|
|
||||||
args.X[2] = 0;
|
|
||||||
for (size_t i = 0; i < std::min(size_t(4), num_qwords); i++) {
|
|
||||||
args.X[3 + i] = value[i];
|
|
||||||
}
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::GetConfig(u64 *out, size_t num_qwords, SplConfigItem which) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_GetConfig;
|
|
||||||
args.X[1] = which;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < std::min(size_t(4), num_qwords); i++) {
|
|
||||||
out[i] = args.X[1 + i];
|
|
||||||
}
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::CheckStatus(SmcResult *out, AsyncOperationKey op) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_CheckStatus;
|
|
||||||
args.X[1] = op.value;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
*out = static_cast<SmcResult>(args.X[1]);
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::GetResult(SmcResult *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_GetResult;
|
|
||||||
args.X[1] = op.value;
|
|
||||||
args.X[2] = reinterpret_cast<u64>(out_buf);
|
|
||||||
args.X[3] = out_buf_size;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
*out = static_cast<SmcResult>(args.X[1]);
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::ExpMod(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_ExpMod;
|
|
||||||
args.X[1] = reinterpret_cast<u64>(base);
|
|
||||||
args.X[2] = reinterpret_cast<u64>(exp);
|
|
||||||
args.X[3] = reinterpret_cast<u64>(mod);
|
|
||||||
args.X[4] = exp_size;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
out_op->value = args.X[1];
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::GenerateRandomBytes(void *out, size_t size) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_GenerateRandomBytes;
|
|
||||||
args.X[1] = size;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
if (args.X[0] == SmcResult_Success && (size <= sizeof(args) - sizeof(args.X[0]))) {
|
|
||||||
std::memcpy(out, &args.X[1], size);
|
|
||||||
}
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::GenerateAesKek(AccessKey *out, const KeySource &source, u32 generation, u32 option) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_GenerateAesKek;
|
|
||||||
args.X[1] = source.data64[0];
|
|
||||||
args.X[2] = source.data64[1];
|
|
||||||
args.X[3] = generation;
|
|
||||||
args.X[4] = option;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
out->data64[0] = args.X[1];
|
|
||||||
out->data64[1] = args.X[2];
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::LoadAesKey(u32 keyslot, const AccessKey &access_key, const KeySource &source) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_LoadAesKey;
|
|
||||||
args.X[1] = keyslot;
|
|
||||||
args.X[2] = access_key.data64[0];
|
|
||||||
args.X[3] = access_key.data64[1];
|
|
||||||
args.X[4] = source.data64[0];
|
|
||||||
args.X[5] = source.data64[1];
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::CryptAes(AsyncOperationKey *out_op, u32 mode, const IvCtr &iv_ctr, u32 dst_addr, u32 src_addr, size_t size) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_CryptAes;
|
|
||||||
args.X[1] = mode;
|
|
||||||
args.X[2] = iv_ctr.data64[0];
|
|
||||||
args.X[3] = iv_ctr.data64[1];
|
|
||||||
args.X[4] = src_addr;
|
|
||||||
args.X[5] = dst_addr;
|
|
||||||
args.X[6] = size;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
out_op->value = args.X[1];
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::GenerateSpecificAesKey(AesKey *out_key, const KeySource &source, u32 generation, u32 which) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_GenerateSpecificAesKey;
|
|
||||||
args.X[1] = source.data64[0];
|
|
||||||
args.X[2] = source.data64[1];
|
|
||||||
args.X[3] = generation;
|
|
||||||
args.X[4] = which;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
out_key->data64[0] = args.X[1];
|
|
||||||
out_key->data64[1] = args.X[2];
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::ComputeCmac(Cmac *out_mac, u32 keyslot, const void *data, size_t size) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_ComputeCmac;
|
|
||||||
args.X[1] = keyslot;
|
|
||||||
args.X[2] = reinterpret_cast<u64>(data);
|
|
||||||
args.X[3] = size;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
out_mac->data64[0] = args.X[1];
|
|
||||||
out_mac->data64[1] = args.X[2];
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::ReEncryptRsaPrivateKey(void *data, size_t size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_ReEncryptRsaPrivateKey;
|
|
||||||
args.X[1] = reinterpret_cast<u64>(&access_key_dec);
|
|
||||||
args.X[2] = reinterpret_cast<u64>(&access_key_enc);
|
|
||||||
args.X[3] = option;
|
|
||||||
args.X[4] = reinterpret_cast<u64>(data);
|
|
||||||
args.X[5] = size;
|
|
||||||
args.X[6] = reinterpret_cast<u64>(&source_dec);
|
|
||||||
args.X[7] = reinterpret_cast<u64>(&source_enc);
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_DecryptOrImportRsaPrivateKey;
|
|
||||||
args.X[1] = access_key.data64[0];
|
|
||||||
args.X[2] = access_key.data64[1];
|
|
||||||
args.X[3] = option;
|
|
||||||
args.X[4] = reinterpret_cast<u64>(data);
|
|
||||||
args.X[5] = size;
|
|
||||||
args.X[6] = source.data64[0];
|
|
||||||
args.X[7] = source.data64[1];
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::SecureExpMod(AsyncOperationKey *out_op, const void *base, const void *mod, u32 option) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_SecureExpMod;
|
|
||||||
args.X[1] = reinterpret_cast<u64>(base);
|
|
||||||
args.X[2] = reinterpret_cast<u64>(mod);
|
|
||||||
args.X[3] = option;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
out_op->value = args.X[1];
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::UnwrapTitleKey(AsyncOperationKey *out_op, const void *base, const void *mod, const void *label_digest, size_t label_digest_size, u32 option) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_UnwrapTitleKey;
|
|
||||||
args.X[1] = reinterpret_cast<u64>(base);
|
|
||||||
args.X[2] = reinterpret_cast<u64>(mod);
|
|
||||||
std::memset(&args.X[3], 0, 4 * sizeof(args.X[3]));
|
|
||||||
std::memcpy(&args.X[3], label_digest, std::min(size_t(4 * sizeof(args.X[3])), label_digest_size));
|
|
||||||
args.X[7] = option;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
out_op->value = args.X[1];
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::LoadTitleKey(u32 keyslot, const AccessKey &access_key) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_LoadTitleKey;
|
|
||||||
args.X[1] = keyslot;
|
|
||||||
args.X[2] = access_key.data64[0];
|
|
||||||
args.X[3] = access_key.data64[1];
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::UnwrapCommonTitleKey(AccessKey *out, const KeySource &source, u32 generation) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_UnwrapCommonTitleKey;
|
|
||||||
args.X[1] = source.data64[0];
|
|
||||||
args.X[2] = source.data64[1];
|
|
||||||
args.X[3] = generation;
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
out->data64[0] = args.X[1];
|
|
||||||
out->data64[1] = args.X[2];
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Deprecated functions. */
|
|
||||||
SmcResult SmcWrapper::ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_ImportEsKey;
|
|
||||||
args.X[1] = access_key.data64[0];
|
|
||||||
args.X[2] = access_key.data64[1];
|
|
||||||
args.X[3] = option;
|
|
||||||
args.X[4] = reinterpret_cast<u64>(data);
|
|
||||||
args.X[5] = size;
|
|
||||||
args.X[6] = source.data64[0];
|
|
||||||
args.X[7] = source.data64[1];
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_DecryptRsaPrivateKey;
|
|
||||||
args.X[1] = access_key.data64[0];
|
|
||||||
args.X[2] = access_key.data64[1];
|
|
||||||
args.X[3] = option;
|
|
||||||
args.X[4] = reinterpret_cast<u64>(data);
|
|
||||||
args.X[5] = size;
|
|
||||||
args.X[6] = source.data64[0];
|
|
||||||
args.X[7] = source.data64[1];
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
*out_size = static_cast<size_t>(args.X[1]);
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SmcResult SmcWrapper::ImportSecureExpModKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option) {
|
|
||||||
SecmonArgs args;
|
|
||||||
|
|
||||||
args.X[0] = SmcFunctionId_ImportSecureExpModKey;
|
|
||||||
args.X[1] = access_key.data64[0];
|
|
||||||
args.X[2] = access_key.data64[1];
|
|
||||||
args.X[3] = option;
|
|
||||||
args.X[4] = reinterpret_cast<u64>(data);
|
|
||||||
args.X[5] = size;
|
|
||||||
args.X[6] = source.data64[0];
|
|
||||||
args.X[7] = source.data64[1];
|
|
||||||
svcCallSecureMonitor(&args);
|
|
||||||
|
|
||||||
return static_cast<SmcResult>(args.X[0]);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <switch.h>
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
|
|
||||||
#include "spl_types.hpp"
|
|
||||||
|
|
||||||
class SmcWrapper {
|
|
||||||
public:
|
|
||||||
static inline u32 GetCryptAesMode(SmcCipherMode mode, u32 keyslot) {
|
|
||||||
return static_cast<u32>((mode << 4) | (keyslot & 7));
|
|
||||||
}
|
|
||||||
static inline u32 GetUnwrapEsKeyOption(EsKeyType type, u32 generation) {
|
|
||||||
return static_cast<u32>((type << 6) | (generation & 0x3F));
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
static SmcResult SetConfig(SplConfigItem which, const u64 *value, size_t num_qwords);
|
|
||||||
static SmcResult GetConfig(u64 *out, size_t num_qwords, SplConfigItem which);
|
|
||||||
static SmcResult CheckStatus(SmcResult *out, AsyncOperationKey op);
|
|
||||||
static SmcResult GetResult(SmcResult *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op);
|
|
||||||
static SmcResult ExpMod(AsyncOperationKey *out_op, const void *base, const void *exp, size_t exp_size, const void *mod);
|
|
||||||
static SmcResult GenerateRandomBytes(void *out, size_t size);
|
|
||||||
static SmcResult GenerateAesKek(AccessKey *out, const KeySource &source, u32 generation, u32 option);
|
|
||||||
static SmcResult LoadAesKey(u32 keyslot, const AccessKey &access_key, const KeySource &source);
|
|
||||||
static SmcResult CryptAes(AsyncOperationKey *out_op, u32 mode, const IvCtr &iv_ctr, u32 dst_addr, u32 src_addr, size_t size);
|
|
||||||
static SmcResult GenerateSpecificAesKey(AesKey *out_key, const KeySource &source, u32 generation, u32 which);
|
|
||||||
static SmcResult ComputeCmac(Cmac *out_mac, u32 keyslot, const void *data, size_t size);
|
|
||||||
static SmcResult ReEncryptRsaPrivateKey(void *data, size_t size, const AccessKey &access_key_dec, const KeySource &source_dec, const AccessKey &access_key_enc, const KeySource &source_enc, u32 option);
|
|
||||||
static SmcResult DecryptOrImportRsaPrivateKey(void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option);
|
|
||||||
static SmcResult SecureExpMod(AsyncOperationKey *out_op, const void *base, const void *mod, u32 option);
|
|
||||||
static SmcResult UnwrapTitleKey(AsyncOperationKey *out_op, const void *base, const void *mod, const void *label_digest, size_t label_digest_size, u32 option);
|
|
||||||
static SmcResult LoadTitleKey(u32 keyslot, const AccessKey &access_key);
|
|
||||||
static SmcResult UnwrapCommonTitleKey(AccessKey *out, const KeySource &source, u32 generation);
|
|
||||||
|
|
||||||
/* Deprecated functions. */
|
|
||||||
static SmcResult ImportEsKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option);
|
|
||||||
static SmcResult DecryptRsaPrivateKey(size_t *out_size, void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option);
|
|
||||||
static SmcResult ImportSecureExpModKey(const void *data, size_t size, const AccessKey &access_key, const KeySource &source, u32 option);
|
|
||||||
};
|
|
|
@ -18,11 +18,16 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "spl_ssl_service.hpp"
|
#include "spl_ssl_service.hpp"
|
||||||
|
#include "spl_api.hpp"
|
||||||
|
|
||||||
Result SslService::ImportSslKey(InPointer<u8> src, AccessKey access_key, KeySource key_source) {
|
namespace sts::spl {
|
||||||
return this->GetSecureMonitorWrapper()->ImportSslKey(src.pointer, src.num_elements, access_key, key_source);
|
|
||||||
}
|
Result SslService::ImportSslKey(InPointer<u8> src, AccessKey access_key, KeySource key_source) {
|
||||||
|
return spl::ImportSslKey(src.pointer, src.num_elements, access_key, key_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result SslService::SslExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod) {
|
||||||
|
return spl::SslExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements);
|
||||||
|
}
|
||||||
|
|
||||||
Result SslService::SslExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod) {
|
|
||||||
return this->GetSecureMonitorWrapper()->SslExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,41 +21,40 @@
|
||||||
#include "spl_types.hpp"
|
#include "spl_types.hpp"
|
||||||
#include "spl_rsa_service.hpp"
|
#include "spl_rsa_service.hpp"
|
||||||
|
|
||||||
class SslService : public RsaService {
|
namespace sts::spl {
|
||||||
public:
|
|
||||||
SslService(SecureMonitorWrapper *sw) : RsaService(sw) {
|
|
||||||
/* ... */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~SslService() {
|
class SslService : public RsaService {
|
||||||
/* ... */
|
public:
|
||||||
}
|
SslService() : RsaService() { /* ... */ }
|
||||||
protected:
|
virtual ~SslService() { /* ... */ }
|
||||||
/* Actual commands. */
|
protected:
|
||||||
virtual Result ImportSslKey(InPointer<u8> src, AccessKey access_key, KeySource key_source);
|
/* Actual commands. */
|
||||||
virtual Result SslExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod);
|
virtual Result ImportSslKey(InPointer<u8> src, AccessKey access_key, KeySource key_source);
|
||||||
public:
|
virtual Result SslExpMod(OutPointerWithClientSize<u8> out, InPointer<u8> base, InPointer<u8> mod);
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
public:
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetConfig, &SslService::GetConfig, SslService>(),
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ExpMod, &SslService::ExpMod, SslService>(),
|
MakeServiceCommandMetaEx<CommandId::GetConfig, &SslService::GetConfig, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetConfig, &SslService::SetConfig, SslService>(),
|
MakeServiceCommandMetaEx<CommandId::ExpMod, &SslService::ExpMod, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateRandomBytes, &SslService::GenerateRandomBytes, SslService>(),
|
MakeServiceCommandMetaEx<CommandId::SetConfig, &SslService::SetConfig, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_IsDevelopment, &SslService::IsDevelopment, SslService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateRandomBytes, &SslService::GenerateRandomBytes, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SetBootReason, &SslService::SetBootReason, SslService, FirmwareVersion_300>(),
|
MakeServiceCommandMetaEx<CommandId::IsDevelopment, &SslService::IsDevelopment, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetBootReason, &SslService::GetBootReason, SslService, FirmwareVersion_300>(),
|
MakeServiceCommandMetaEx<CommandId::SetBootReason, &SslService::SetBootReason, SslService, FirmwareVersion_300>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKek, &SslService::GenerateAesKek, SslService>(),
|
MakeServiceCommandMetaEx<CommandId::GetBootReason, &SslService::GetBootReason, SslService, FirmwareVersion_300>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_LoadAesKey, &SslService::LoadAesKey, SslService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKek, &SslService::GenerateAesKek, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GenerateAesKey, &SslService::GenerateAesKey, SslService>(),
|
MakeServiceCommandMetaEx<CommandId::LoadAesKey, &SslService::LoadAesKey, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptAesKey, &SslService::DecryptAesKey, SslService>(),
|
MakeServiceCommandMetaEx<CommandId::GenerateAesKey, &SslService::GenerateAesKey, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_CryptAesCtr, &SslService::CryptAesCtr, SslService>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptAesKey, &SslService::DecryptAesKey, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ComputeCmac, &SslService::ComputeCmac, SslService>(),
|
MakeServiceCommandMetaEx<CommandId::CryptAesCtr, &SslService::CryptAesCtr, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_AllocateAesKeyslot, &SslService::AllocateAesKeyslot, SslService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::ComputeCmac, &SslService::ComputeCmac, SslService>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_FreeAesKeyslot, &SslService::FreeAesKeyslot, SslService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::AllocateAesKeyslot, &SslService::AllocateAesKeyslot, SslService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_GetAesKeyslotAvailableEvent, &SslService::GetAesKeyslotAvailableEvent, SslService, FirmwareVersion_200>(),
|
MakeServiceCommandMetaEx<CommandId::FreeAesKeyslot, &SslService::FreeAesKeyslot, SslService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptRsaPrivateKey, &SslService::DecryptRsaPrivateKeyDeprecated, SslService, FirmwareVersion_400, FirmwareVersion_400>(),
|
MakeServiceCommandMetaEx<CommandId::GetAesKeyslotAvailableEvent, &SslService::GetAesKeyslotAvailableEvent, SslService, FirmwareVersion_200>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_DecryptRsaPrivateKey, &SslService::DecryptRsaPrivateKey, SslService, FirmwareVersion_500>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptRsaPrivateKey, &SslService::DecryptRsaPrivateKeyDeprecated, SslService, FirmwareVersion_400, FirmwareVersion_400>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_ImportSslKey, &SslService::ImportSslKey, SslService, FirmwareVersion_500>(),
|
MakeServiceCommandMetaEx<CommandId::DecryptRsaPrivateKey, &SslService::DecryptRsaPrivateKey, SslService, FirmwareVersion_500>(),
|
||||||
MakeServiceCommandMetaEx<Spl_Cmd_SslExpMod, &SslService::SslExpMod, SslService, FirmwareVersion_500>(),
|
MakeServiceCommandMetaEx<CommandId::ImportSslKey, &SslService::ImportSslKey, SslService, FirmwareVersion_500>(),
|
||||||
|
MakeServiceCommandMetaEx<CommandId::SslExpMod, &SslService::SslExpMod, SslService, FirmwareVersion_500>(),
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -21,141 +21,136 @@
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
enum SmcResult : u32 {
|
namespace sts::spl {
|
||||||
SmcResult_Success = 0,
|
|
||||||
SmcResult_NotImplemented = 1,
|
|
||||||
SmcResult_InvalidArgument = 2,
|
|
||||||
SmcResult_InProgress = 3,
|
|
||||||
SmcResult_NoAsyncOperation = 4,
|
|
||||||
SmcResult_InvalidAsyncOperation = 5,
|
|
||||||
SmcResult_Blacklisted = 6,
|
|
||||||
|
|
||||||
SmcResult_Max = 99,
|
namespace smc {
|
||||||
};
|
|
||||||
|
|
||||||
enum SmcCipherMode : u32 {
|
enum class FunctionId : u32 {
|
||||||
SmcCipherMode_CbcEncrypt = 0,
|
SetConfig = 0xC3000401,
|
||||||
SmcCipherMode_CbcDecrypt = 1,
|
GetConfig = 0xC3000002,
|
||||||
SmcCipherMode_Ctr = 2,
|
CheckStatus = 0xC3000003,
|
||||||
};
|
GetResult = 0xC3000404,
|
||||||
|
ExpMod = 0xC3000E05,
|
||||||
|
GenerateRandomBytes = 0xC3000006,
|
||||||
|
GenerateAesKek = 0xC3000007,
|
||||||
|
LoadAesKey = 0xC3000008,
|
||||||
|
CryptAes = 0xC3000009,
|
||||||
|
GenerateSpecificAesKey = 0xC300000A,
|
||||||
|
ComputeCmac = 0xC300040B,
|
||||||
|
ReEncryptRsaPrivateKey = 0xC300D60C,
|
||||||
|
DecryptOrImportRsaPrivateKey = 0xC300100D,
|
||||||
|
|
||||||
enum SmcDecryptOrImportMode : u32 {
|
SecureExpMod = 0xC300060F,
|
||||||
SmcDecryptOrImportMode_DecryptRsaPrivateKey = 0,
|
UnwrapTitleKey = 0xC3000610,
|
||||||
SmcDecryptOrImportMode_ImportLotusKey = 1,
|
LoadTitleKey = 0xC3000011,
|
||||||
SmcDecryptOrImportMode_ImportEsKey = 2,
|
UnwrapCommonTitleKey = 0xC3000012,
|
||||||
SmcDecryptOrImportMode_ImportSslKey = 3,
|
|
||||||
SmcDecryptOrImportMode_ImportDrmKey = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SmcSecureExpModMode : u32 {
|
/* Deprecated functions. */
|
||||||
SmcSecureExpModMode_Lotus = 0,
|
ImportEsKey = 0xC300100C,
|
||||||
SmcSecureExpModMode_Ssl = 1,
|
DecryptRsaPrivateKey = 0xC300100D,
|
||||||
SmcSecureExpModMode_Drm = 2,
|
ImportSecureExpModKey = 0xC300100E,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EsKeyType : u32 {
|
enum class Result {
|
||||||
EsKeyType_TitleKey = 0,
|
Success = 0,
|
||||||
EsKeyType_ElicenseKey = 1,
|
NotImplemented = 1,
|
||||||
};
|
InvalidArgument = 2,
|
||||||
|
InProgress = 3,
|
||||||
|
NoAsyncOperation = 4,
|
||||||
|
InvalidAsyncOperation = 5,
|
||||||
|
Blacklisted = 6,
|
||||||
|
|
||||||
struct AsyncOperationKey {
|
Max = 99,
|
||||||
u64 value;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
struct BootReasonValue {
|
inline ::Result ConvertResult(Result result) {
|
||||||
u8 power_intr;
|
if (result == Result::Success) {
|
||||||
u8 rtc_intr;
|
return ResultSuccess;
|
||||||
u8 nv_erc;
|
}
|
||||||
u8 boot_reason;
|
if (result < Result::Max) {
|
||||||
};
|
return MAKERESULT(Module_Spl, static_cast<u32>(result));
|
||||||
static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!");
|
}
|
||||||
|
return ResultSplUnknownSmcResult;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
enum class CipherMode {
|
||||||
struct AesKey {
|
CbcEncrypt = 0,
|
||||||
union {
|
CbcDecrypt = 1,
|
||||||
u8 data[AES_128_KEY_SIZE];
|
Ctr = 2,
|
||||||
u64 data64[AES_128_KEY_SIZE / sizeof(u64)];
|
};
|
||||||
|
|
||||||
|
enum class DecryptOrImportMode {
|
||||||
|
DecryptRsaPrivateKey = 0,
|
||||||
|
ImportLotusKey = 1,
|
||||||
|
ImportEsKey = 2,
|
||||||
|
ImportSslKey = 3,
|
||||||
|
ImportDrmKey = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SecureExpModMode {
|
||||||
|
Lotus = 0,
|
||||||
|
Ssl = 1,
|
||||||
|
Drm = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class EsKeyType {
|
||||||
|
TitleKey = 0,
|
||||||
|
ElicenseKey = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AsyncOperationKey {
|
||||||
|
u64 value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BootReasonValue {
|
||||||
|
u8 power_intr;
|
||||||
|
u8 rtc_intr;
|
||||||
|
u8 nv_erc;
|
||||||
|
u8 boot_reason;
|
||||||
};
|
};
|
||||||
};
|
static_assert(sizeof(BootReasonValue) == sizeof(u32), "BootReasonValue definition!");
|
||||||
static_assert(alignof(AesKey) == alignof(u8), "AesKey definition!");
|
|
||||||
|
|
||||||
struct IvCtr {
|
#pragma pack(push, 1)
|
||||||
union {
|
struct AesKey {
|
||||||
u8 data[AES_128_KEY_SIZE];
|
union {
|
||||||
u64 data64[AES_128_KEY_SIZE / sizeof(u64)];
|
u8 data[AES_128_KEY_SIZE];
|
||||||
|
u64 data64[AES_128_KEY_SIZE / sizeof(u64)];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
static_assert(alignof(AesKey) == alignof(u8), "AesKey definition!");
|
||||||
static_assert(alignof(IvCtr) == alignof(u8), "IvCtr definition!");
|
|
||||||
|
|
||||||
struct Cmac {
|
struct IvCtr {
|
||||||
union {
|
union {
|
||||||
u8 data[AES_128_KEY_SIZE];
|
u8 data[AES_128_KEY_SIZE];
|
||||||
u64 data64[AES_128_KEY_SIZE / sizeof(u64)];
|
u64 data64[AES_128_KEY_SIZE / sizeof(u64)];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
static_assert(alignof(IvCtr) == alignof(u8), "IvCtr definition!");
|
||||||
static_assert(alignof(Cmac) == alignof(u8), "Cmac definition!");
|
|
||||||
|
|
||||||
struct AccessKey {
|
struct Cmac {
|
||||||
union {
|
union {
|
||||||
u8 data[AES_128_KEY_SIZE];
|
u8 data[AES_128_KEY_SIZE];
|
||||||
u64 data64[AES_128_KEY_SIZE / sizeof(u64)];
|
u64 data64[AES_128_KEY_SIZE / sizeof(u64)];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
static_assert(alignof(Cmac) == alignof(u8), "Cmac definition!");
|
||||||
static_assert(alignof(AccessKey) == alignof(u8), "AccessKey definition!");
|
|
||||||
|
|
||||||
struct KeySource {
|
struct AccessKey {
|
||||||
union {
|
union {
|
||||||
u8 data[AES_128_KEY_SIZE];
|
u8 data[AES_128_KEY_SIZE];
|
||||||
u64 data64[AES_128_KEY_SIZE / sizeof(u64)];
|
u64 data64[AES_128_KEY_SIZE / sizeof(u64)];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
static_assert(alignof(AccessKey) == alignof(u8), "AccessKey definition!");
|
||||||
static_assert(alignof(AccessKey) == alignof(u8), "KeySource definition!");
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
enum CsrngCmd {
|
struct KeySource {
|
||||||
Csrng_Cmd_GenerateRandomBytes = 0,
|
union {
|
||||||
};
|
u8 data[AES_128_KEY_SIZE];
|
||||||
|
u64 data64[AES_128_KEY_SIZE / sizeof(u64)];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(alignof(AccessKey) == alignof(u8), "KeySource definition!");
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
enum SplServiceCmd {
|
}
|
||||||
/* 1.0.0+ */
|
|
||||||
Spl_Cmd_GetConfig = 0,
|
|
||||||
Spl_Cmd_ExpMod = 1,
|
|
||||||
Spl_Cmd_GenerateAesKek = 2,
|
|
||||||
Spl_Cmd_LoadAesKey = 3,
|
|
||||||
Spl_Cmd_GenerateAesKey = 4,
|
|
||||||
Spl_Cmd_SetConfig = 5,
|
|
||||||
Spl_Cmd_GenerateRandomBytes = 7,
|
|
||||||
Spl_Cmd_ImportLotusKey = 9,
|
|
||||||
Spl_Cmd_DecryptLotusMessage = 10,
|
|
||||||
Spl_Cmd_IsDevelopment = 11,
|
|
||||||
Spl_Cmd_GenerateSpecificAesKey = 12,
|
|
||||||
Spl_Cmd_DecryptRsaPrivateKey = 13,
|
|
||||||
Spl_Cmd_DecryptAesKey = 14,
|
|
||||||
Spl_Cmd_CryptAesCtr = 15,
|
|
||||||
Spl_Cmd_ComputeCmac = 16,
|
|
||||||
Spl_Cmd_ImportEsKey = 17,
|
|
||||||
Spl_Cmd_UnwrapTitleKey = 18,
|
|
||||||
Spl_Cmd_LoadTitleKey = 19,
|
|
||||||
|
|
||||||
/* 2.0.0+ */
|
|
||||||
Spl_Cmd_UnwrapCommonTitleKey = 20,
|
|
||||||
Spl_Cmd_AllocateAesKeyslot = 21,
|
|
||||||
Spl_Cmd_FreeAesKeyslot = 22,
|
|
||||||
Spl_Cmd_GetAesKeyslotAvailableEvent = 23,
|
|
||||||
|
|
||||||
/* 3.0.0+ */
|
|
||||||
Spl_Cmd_SetBootReason = 24,
|
|
||||||
Spl_Cmd_GetBootReason = 25,
|
|
||||||
|
|
||||||
/* 5.0.0+ */
|
|
||||||
Spl_Cmd_ImportSslKey = 26,
|
|
||||||
Spl_Cmd_SslExpMod = 27,
|
|
||||||
Spl_Cmd_ImportDrmKey = 28,
|
|
||||||
Spl_Cmd_DrmExpMod = 29,
|
|
||||||
Spl_Cmd_ReEncryptRsaPrivateKey = 30,
|
|
||||||
Spl_Cmd_GetPackage2Hash = 31,
|
|
||||||
|
|
||||||
/* 6.0.0+ */
|
|
||||||
Spl_Cmd_UnwrapElicenseKey = 31, /* re-used command id :( */
|
|
||||||
Spl_Cmd_LoadElicenseKey = 32,
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in a new issue