mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-07-17 22:22:21 +02:00
spl: extend to use virtual keyslots
This commit is contained in:
parent
daedcf5876
commit
06804ab7cf
@ -14,8 +14,8 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include "spl_api_impl.hpp"
|
#include "spl_api_impl.hpp"
|
||||||
|
|
||||||
#include "spl_ctr_drbg.hpp"
|
#include "spl_ctr_drbg.hpp"
|
||||||
|
#include "spl_key_slot_cache.hpp"
|
||||||
|
|
||||||
namespace ams::spl::impl {
|
namespace ams::spl::impl {
|
||||||
|
|
||||||
@ -34,21 +34,161 @@ namespace ams::spl::impl {
|
|||||||
|
|
||||||
constexpr size_t WorkBufferSizeMax = 0x800;
|
constexpr size_t WorkBufferSizeMax = 0x800;
|
||||||
|
|
||||||
constexpr size_t MaxAesKeyslots = 6;
|
constexpr s32 MaxPhysicalAesKeyslots = 6;
|
||||||
constexpr size_t MaxAesKeyslotsDeprecated = 4;
|
constexpr s32 MaxPhysicalAesKeyslotsDeprecated = 4;
|
||||||
|
|
||||||
/* Max Keyslots helper. */
|
constexpr s32 MaxVirtualAesKeyslots = 9;
|
||||||
inline size_t GetMaxKeyslots() {
|
|
||||||
return (hos::GetVersion() >= hos::Version_6_0_0) ? MaxAesKeyslots : MaxAesKeyslotsDeprecated;
|
/* Keyslot management. */
|
||||||
|
KeySlotCache g_keyslot_cache;
|
||||||
|
std::optional<KeySlotCacheEntry> g_keyslot_cache_entry[MaxPhysicalAesKeyslots];
|
||||||
|
|
||||||
|
inline s32 GetMaxPhysicalKeyslots() {
|
||||||
|
return (hos::GetVersion() >= hos::Version_6_0_0) ? MaxPhysicalAesKeyslots : MaxPhysicalAesKeyslotsDeprecated;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr s32 VirtualKeySlotMin = 16;
|
||||||
|
constexpr s32 VirtualKeySlotMax = VirtualKeySlotMin + MaxVirtualAesKeyslots - 1;
|
||||||
|
|
||||||
|
constexpr inline bool IsVirtualKeySlot(s32 keyslot) {
|
||||||
|
return VirtualKeySlotMin <= keyslot && keyslot <= VirtualKeySlotMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsPhysicalKeySlot(s32 keyslot) {
|
||||||
|
return keyslot < GetMaxPhysicalKeyslots();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline s32 GetVirtualKeySlotIndex(s32 keyslot) {
|
||||||
|
AMS_ASSERT(IsVirtualKeySlot(keyslot));
|
||||||
|
return keyslot - VirtualKeySlotMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline s32 MakeVirtualKeySlot(s32 index) {
|
||||||
|
const s32 virt_slot = index + VirtualKeySlotMin;
|
||||||
|
AMS_ASSERT(IsVirtualKeySlot(virt_slot));
|
||||||
|
return virt_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeKeySlotCache() {
|
||||||
|
for (s32 i = 0; i < MaxPhysicalAesKeyslots; i++) {
|
||||||
|
g_keyslot_cache_entry[i].emplace(i);
|
||||||
|
g_keyslot_cache.AddEntry(std::addressof(g_keyslot_cache_entry[i].value()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class KeySlotContentType {
|
||||||
|
None = 0,
|
||||||
|
AesKey = 1,
|
||||||
|
TitleKey = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeySlotContents {
|
||||||
|
KeySlotContentType type;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
AccessKey access_key;
|
||||||
|
KeySource key_source;
|
||||||
|
} aes_key;
|
||||||
|
struct {
|
||||||
|
AccessKey access_key;
|
||||||
|
} title_key;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const void *g_keyslot_owners[MaxVirtualAesKeyslots];
|
||||||
|
KeySlotContents g_keyslot_contents[MaxVirtualAesKeyslots];
|
||||||
|
KeySlotContents g_physical_keyslot_contents_for_backwards_compatibility[MaxPhysicalAesKeyslots];
|
||||||
|
|
||||||
|
void ClearPhysicalKeyslot(s32 keyslot) {
|
||||||
|
AMS_ASSERT(IsPhysicalKeySlot(keyslot));
|
||||||
|
|
||||||
|
AccessKey access_key = {};
|
||||||
|
KeySource key_source = {};
|
||||||
|
smc::LoadAesKey(keyslot, access_key, key_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 GetPhysicalKeySlot(s32 keyslot, bool load) {
|
||||||
|
s32 phys_slot = -1;
|
||||||
|
KeySlotContents *contents = nullptr;
|
||||||
|
|
||||||
|
if (hos::GetVersion() == hos::Version_1_0_0 && IsPhysicalKeySlot(keyslot)) {
|
||||||
|
/* On 1.0.0, we allow the use of physical keyslots. */
|
||||||
|
phys_slot = keyslot;
|
||||||
|
contents = std::addressof(g_physical_keyslot_contents_for_backwards_compatibility[phys_slot]);
|
||||||
|
|
||||||
|
/* If the physical slot is already loaded, we're good. */
|
||||||
|
if (g_keyslot_cache.FindPhysical(phys_slot)) {
|
||||||
|
return phys_slot;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* This should be a virtual keyslot. */
|
||||||
|
AMS_ASSERT(IsVirtualKeySlot(keyslot));
|
||||||
|
|
||||||
|
/* Try to find a physical slot in the cache. */
|
||||||
|
if (g_keyslot_cache.Find(std::addressof(phys_slot), keyslot)) {
|
||||||
|
return phys_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a physical slot. */
|
||||||
|
phys_slot = g_keyslot_cache.Allocate(keyslot);
|
||||||
|
contents = std::addressof(g_keyslot_contents[GetVirtualKeySlotIndex(keyslot)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the contents of the keyslot. */
|
||||||
|
if (load) {
|
||||||
|
switch (contents->type) {
|
||||||
|
case KeySlotContentType::None:
|
||||||
|
ClearPhysicalKeyslot(phys_slot);
|
||||||
|
break;
|
||||||
|
case KeySlotContentType::AesKey:
|
||||||
|
R_ABORT_UNLESS(smc::ConvertResult(smc::LoadAesKey(phys_slot, contents->aes_key.access_key, contents->aes_key.key_source)));
|
||||||
|
break;
|
||||||
|
case KeySlotContentType::TitleKey:
|
||||||
|
R_ABORT_UNLESS(smc::ConvertResult(smc::LoadTitleKey(phys_slot, contents->title_key.access_key)));
|
||||||
|
break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return phys_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LoadVirtualAesKey(s32 keyslot, const AccessKey &access_key, const KeySource &key_source) {
|
||||||
|
/* Ensure we can load into the slot. */
|
||||||
|
const s32 phys_slot = GetPhysicalKeySlot(keyslot, false);
|
||||||
|
R_TRY(smc::ConvertResult(smc::LoadAesKey(phys_slot, access_key, key_source)));
|
||||||
|
|
||||||
|
/* Update our contents. */
|
||||||
|
const s32 index = GetVirtualKeySlotIndex(keyslot);
|
||||||
|
|
||||||
|
g_keyslot_contents[index].type = KeySlotContentType::AesKey;
|
||||||
|
g_keyslot_contents[index].aes_key.access_key = access_key;
|
||||||
|
g_keyslot_contents[index].aes_key.key_source = key_source;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result LoadVirtualTitleKey(s32 keyslot, const AccessKey &access_key) {
|
||||||
|
/* Ensure we can load into the slot. */
|
||||||
|
const s32 phys_slot = GetPhysicalKeySlot(keyslot, false);
|
||||||
|
R_TRY(smc::ConvertResult(smc::LoadTitleKey(phys_slot, access_key)));
|
||||||
|
|
||||||
|
/* Update our contents. */
|
||||||
|
const s32 index = GetVirtualKeySlotIndex(keyslot);
|
||||||
|
|
||||||
|
g_keyslot_contents[index].type = KeySlotContentType::TitleKey;
|
||||||
|
g_keyslot_contents[index].title_key.access_key = access_key;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Type definitions. */
|
/* Type definitions. */
|
||||||
class ScopedAesKeyslot {
|
class ScopedAesKeyslot {
|
||||||
private:
|
private:
|
||||||
u32 slot;
|
s32 slot;
|
||||||
bool has_slot;
|
bool has_slot;
|
||||||
public:
|
public:
|
||||||
ScopedAesKeyslot() : slot(0), has_slot(false) {
|
ScopedAesKeyslot() : slot(-1), has_slot(false) {
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
~ScopedAesKeyslot() {
|
~ScopedAesKeyslot() {
|
||||||
@ -57,7 +197,7 @@ namespace ams::spl::impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetKeyslot() const {
|
u32 GetKeySlot() const {
|
||||||
return this->slot;
|
return this->slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +246,6 @@ namespace ams::spl::impl {
|
|||||||
|
|
||||||
os::Mutex g_async_op_lock(false);
|
os::Mutex g_async_op_lock(false);
|
||||||
|
|
||||||
const void *g_keyslot_owners[MaxAesKeyslots];
|
|
||||||
BootReasonValue g_boot_reason;
|
BootReasonValue g_boot_reason;
|
||||||
bool g_boot_reason_set;
|
bool g_boot_reason_set;
|
||||||
|
|
||||||
@ -201,14 +340,21 @@ namespace ams::spl::impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Internal Keyslot utility. */
|
/* Internal Keyslot utility. */
|
||||||
Result ValidateAesKeyslot(u32 keyslot, const void *owner) {
|
Result ValidateAesKeyslot(s32 keyslot, const void *owner) {
|
||||||
R_UNLESS(keyslot < GetMaxKeyslots(), spl::ResultInvalidKeyslot());
|
/* Allow the use of physical keyslots on 1.0.0. */
|
||||||
R_UNLESS((g_keyslot_owners[keyslot] == owner || hos::GetVersion() == hos::Version_1_0_0), spl::ResultInvalidKeyslot());
|
if (hos::GetVersion() == hos::Version_1_0_0) {
|
||||||
|
R_SUCCEED_IF(IsPhysicalKeySlot(keyslot));
|
||||||
|
}
|
||||||
|
|
||||||
|
R_UNLESS(IsVirtualKeySlot(keyslot), spl::ResultInvalidKeyslot());
|
||||||
|
|
||||||
|
const s32 index = GetVirtualKeySlotIndex(keyslot);
|
||||||
|
R_UNLESS(g_keyslot_owners[index] == owner, spl::ResultInvalidKeyslot());
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper to do a single AES block decryption. */
|
/* Helper to do a single AES block decryption. */
|
||||||
smc::Result DecryptAesBlock(u32 keyslot, void *dst, const void *src) {
|
smc::Result DecryptAesBlock(s32 keyslot, void *dst, const void *src) {
|
||||||
struct DecryptAesBlockLayout {
|
struct DecryptAesBlockLayout {
|
||||||
SeCryptContext crypt_ctx;
|
SeCryptContext crypt_ctx;
|
||||||
u8 in_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE)));
|
u8 in_block[AES_BLOCK_SIZE] __attribute__((aligned(AES_BLOCK_SIZE)));
|
||||||
@ -230,7 +376,7 @@ namespace ams::spl::impl {
|
|||||||
std::scoped_lock lk(g_async_op_lock);
|
std::scoped_lock lk(g_async_op_lock);
|
||||||
smc::AsyncOperationKey op_key;
|
smc::AsyncOperationKey op_key;
|
||||||
const IvCtr iv_ctr = {};
|
const IvCtr iv_ctr = {};
|
||||||
const u32 mode = smc::GetCryptAesMode(smc::CipherMode::CbcDecrypt, keyslot);
|
const u32 mode = smc::GetCryptAesMode(smc::CipherMode::CbcDecrypt, GetPhysicalKeySlot(keyslot, true));
|
||||||
const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.out);
|
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);
|
const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(DecryptAesBlockLayout, crypt_ctx.in);
|
||||||
|
|
||||||
@ -362,6 +508,8 @@ namespace ams::spl::impl {
|
|||||||
InitializeSeEvents();
|
InitializeSeEvents();
|
||||||
/* Initialize DAS for the SE. */
|
/* Initialize DAS for the SE. */
|
||||||
InitializeDeviceAddressSpace();
|
InitializeDeviceAddressSpace();
|
||||||
|
/* Initialize the keyslot cache. */
|
||||||
|
InitializeKeySlotCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* General. */
|
/* General. */
|
||||||
@ -473,14 +621,12 @@ namespace ams::spl::impl {
|
|||||||
return smc::ConvertResult(smc::GenerateAesKek(out_access_key, key_source, generation, 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) {
|
Result LoadAesKey(s32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source) {
|
||||||
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
||||||
return smc::ConvertResult(smc::LoadAesKey(keyslot, access_key, key_source));
|
return LoadVirtualAesKey(keyslot, access_key, key_source);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) {
|
Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source) {
|
||||||
smc::Result smc_rc;
|
|
||||||
|
|
||||||
static constexpr KeySource s_generate_aes_key_source = {
|
static constexpr KeySource s_generate_aes_key_source = {
|
||||||
.data = {0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}
|
.data = {0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}
|
||||||
};
|
};
|
||||||
@ -488,12 +634,9 @@ namespace ams::spl::impl {
|
|||||||
ScopedAesKeyslot keyslot_holder;
|
ScopedAesKeyslot keyslot_holder;
|
||||||
R_TRY(keyslot_holder.Allocate());
|
R_TRY(keyslot_holder.Allocate());
|
||||||
|
|
||||||
smc_rc = smc::LoadAesKey(keyslot_holder.GetKeyslot(), access_key, s_generate_aes_key_source);
|
R_TRY(LoadVirtualAesKey(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);
|
return smc::ConvertResult(DecryptAesBlock(keyslot_holder.GetKeySlot(), out_key, &key_source));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option) {
|
Result DecryptAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 option) {
|
||||||
@ -507,7 +650,7 @@ namespace ams::spl::impl {
|
|||||||
return GenerateAesKey(out_key, access_key, key_source);
|
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) {
|
Result CryptAesCtr(void *dst, size_t dst_size, s32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr) {
|
||||||
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
||||||
|
|
||||||
/* Succeed immediately if there's nothing to crypt. */
|
/* Succeed immediately if there's nothing to crypt. */
|
||||||
@ -554,7 +697,7 @@ namespace ams::spl::impl {
|
|||||||
{
|
{
|
||||||
std::scoped_lock lk(g_async_op_lock);
|
std::scoped_lock lk(g_async_op_lock);
|
||||||
smc::AsyncOperationKey op_key;
|
smc::AsyncOperationKey op_key;
|
||||||
const u32 mode = smc::GetCryptAesMode(smc::CipherMode::Ctr, keyslot);
|
const u32 mode = smc::GetCryptAesMode(smc::CipherMode::Ctr, GetPhysicalKeySlot(keyslot, true));
|
||||||
const u32 dst_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, out);
|
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);
|
const u32 src_ll_addr = g_se_mapped_work_buffer_addr + offsetof(SeCryptContext, in);
|
||||||
|
|
||||||
@ -572,26 +715,22 @@ namespace ams::spl::impl {
|
|||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size) {
|
Result ComputeCmac(Cmac *out_cmac, s32 keyslot, const void *owner, const void *data, size_t size) {
|
||||||
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
||||||
|
|
||||||
R_UNLESS(size <= WorkBufferSizeMax, spl::ResultInvalidSize());
|
R_UNLESS(size <= WorkBufferSizeMax, spl::ResultInvalidSize());
|
||||||
|
|
||||||
std::memcpy(g_work_buffer, data, size);
|
std::memcpy(g_work_buffer, data, size);
|
||||||
return smc::ConvertResult(smc::ComputeCmac(out_cmac, keyslot, g_work_buffer, size));
|
return smc::ConvertResult(smc::ComputeCmac(out_cmac, GetPhysicalKeySlot(keyslot, true), g_work_buffer, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner) {
|
Result AllocateAesKeyslot(s32 *out_keyslot, const void *owner) {
|
||||||
if (hos::GetVersion() <= hos::Version_1_0_0) {
|
/* Find a virtual keyslot. */
|
||||||
/* On 1.0.0, keyslots were kind of a wild west. */
|
for (s32 i = 0; i < MaxVirtualAesKeyslots; i++) {
|
||||||
*out_keyslot = 0;
|
if (g_keyslot_owners[i] == nullptr) {
|
||||||
return ResultSuccess();
|
g_keyslot_owners[i] = owner;
|
||||||
}
|
g_keyslot_contents[i] = { .type = KeySlotContentType::None };
|
||||||
|
*out_keyslot = MakeVirtualKeySlot(i);
|
||||||
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();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -600,22 +739,24 @@ namespace ams::spl::impl {
|
|||||||
return spl::ResultOutOfKeyslots();
|
return spl::ResultOutOfKeyslots();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FreeAesKeyslot(u32 keyslot, const void *owner) {
|
Result FreeAesKeyslot(s32 keyslot, const void *owner) {
|
||||||
if (hos::GetVersion() <= hos::Version_1_0_0) {
|
/* Only virtual keyslots can be freed. */
|
||||||
/* On 1.0.0, keyslots were kind of a wild west. */
|
R_UNLESS(IsVirtualKeySlot(keyslot), spl::ResultInvalidKeyslot());
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Ensure the keyslot is owned. */
|
||||||
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
||||||
|
|
||||||
/* Clear the keyslot. */
|
/* Clear the physical keyslot, if we're cached. */
|
||||||
{
|
s32 phys_slot;
|
||||||
AccessKey access_key = {};
|
if (g_keyslot_cache.Release(std::addressof(phys_slot), keyslot)) {
|
||||||
KeySource key_source = {};
|
ClearPhysicalKeyslot(phys_slot);
|
||||||
|
|
||||||
smc::LoadAesKey(keyslot, access_key, key_source);
|
|
||||||
}
|
}
|
||||||
g_keyslot_owners[keyslot] = nullptr;
|
|
||||||
|
/* Clear the virtual keyslot. */
|
||||||
|
const auto index = GetVirtualKeySlotIndex(keyslot);
|
||||||
|
g_keyslot_owners[index] = nullptr;
|
||||||
|
g_keyslot_contents[index].type = KeySlotContentType::None;
|
||||||
|
|
||||||
os::SignalSystemEvent(std::addressof(g_se_keyslot_available_event));
|
os::SignalSystemEvent(std::addressof(g_se_keyslot_available_event));
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
@ -701,7 +842,7 @@ namespace ams::spl::impl {
|
|||||||
return UnwrapEsRsaOaepWrappedKey(out_access_key, base, base_size, mod, mod_size, label_digest, label_digest_size, generation, smc::EsKeyType::ElicenseKey);
|
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) {
|
Result LoadElicenseKey(s32 keyslot, const void *owner, const AccessKey &access_key) {
|
||||||
/* Right now, this is just literally the same function as LoadTitleKey in N's impl. */
|
/* Right now, this is just literally the same function as LoadTitleKey in N's impl. */
|
||||||
return LoadTitleKey(keyslot, owner, access_key);
|
return LoadTitleKey(keyslot, owner, access_key);
|
||||||
}
|
}
|
||||||
@ -730,9 +871,9 @@ namespace ams::spl::impl {
|
|||||||
return smc::ConvertResult(smc::GenerateSpecificAesKey(out_key, key_source, generation, which));
|
return smc::ConvertResult(smc::GenerateSpecificAesKey(out_key, key_source, generation, which));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key) {
|
Result LoadTitleKey(s32 keyslot, const void *owner, const AccessKey &access_key) {
|
||||||
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
R_TRY(ValidateAesKeyslot(keyslot, owner));
|
||||||
return smc::ConvertResult(smc::LoadTitleKey(keyslot, access_key));
|
return LoadVirtualTitleKey(keyslot, access_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetPackage2Hash(void *dst, const size_t size) {
|
Result GetPackage2Hash(void *dst, const size_t size) {
|
||||||
@ -783,9 +924,9 @@ namespace ams::spl::impl {
|
|||||||
|
|
||||||
/* Helper. */
|
/* Helper. */
|
||||||
Result FreeAesKeyslots(const void *owner) {
|
Result FreeAesKeyslots(const void *owner) {
|
||||||
for (size_t i = 0; i < GetMaxKeyslots(); i++) {
|
for (s32 slot = VirtualKeySlotMin; slot <= VirtualKeySlotMax; ++slot) {
|
||||||
if (g_keyslot_owners[i] == owner) {
|
if (g_keyslot_owners[GetVirtualKeySlotIndex(slot)] == owner) {
|
||||||
FreeAesKeyslot(i, owner);
|
FreeAesKeyslot(slot, owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
|
@ -32,13 +32,13 @@ namespace ams::spl::impl {
|
|||||||
|
|
||||||
/* Crypto. */
|
/* Crypto. */
|
||||||
Result GenerateAesKek(AccessKey *out_access_key, const KeySource &key_source, u32 generation, u32 option);
|
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 LoadAesKey(s32 keyslot, const void *owner, const AccessKey &access_key, const KeySource &key_source);
|
||||||
Result GenerateAesKey(AesKey *out_key, const AccessKey &access_key, const KeySource &key_source);
|
Result 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 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 CryptAesCtr(void *dst, size_t dst_size, s32 keyslot, const void *owner, const void *src, size_t src_size, const IvCtr &iv_ctr);
|
||||||
Result ComputeCmac(Cmac *out_cmac, u32 keyslot, const void *owner, const void *data, size_t size);
|
Result ComputeCmac(Cmac *out_cmac, s32 keyslot, const void *owner, const void *data, size_t size);
|
||||||
Result AllocateAesKeyslot(u32 *out_keyslot, const void *owner);
|
Result AllocateAesKeyslot(s32 *out_keyslot, const void *owner);
|
||||||
Result FreeAesKeyslot(u32 keyslot, const void *owner);
|
Result FreeAesKeyslot(s32 keyslot, const void *owner);
|
||||||
|
|
||||||
/* RSA. */
|
/* 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);
|
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);
|
||||||
@ -54,13 +54,13 @@ namespace ams::spl::impl {
|
|||||||
Result ImportDrmKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source);
|
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 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 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);
|
Result LoadElicenseKey(s32 keyslot, const void *owner, const AccessKey &access_key);
|
||||||
|
|
||||||
/* FS */
|
/* FS */
|
||||||
Result ImportLotusKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option);
|
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 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 GenerateSpecificAesKey(AesKey *out_key, const KeySource &key_source, u32 generation, u32 which);
|
||||||
Result LoadTitleKey(u32 keyslot, const void *owner, const AccessKey &access_key);
|
Result LoadTitleKey(s32 keyslot, const void *owner, const AccessKey &access_key);
|
||||||
Result GetPackage2Hash(void *dst, const size_t size);
|
Result GetPackage2Hash(void *dst, const size_t size);
|
||||||
|
|
||||||
/* Manu. */
|
/* Manu. */
|
||||||
|
@ -27,7 +27,7 @@ namespace ams::spl {
|
|||||||
return impl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
return impl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CryptoService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) {
|
Result CryptoService::LoadAesKey(s32 keyslot, AccessKey access_key, KeySource key_source) {
|
||||||
return impl::LoadAesKey(keyslot, this, access_key, key_source);
|
return impl::LoadAesKey(keyslot, this, access_key, key_source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,19 +39,19 @@ namespace ams::spl {
|
|||||||
return impl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
return impl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CryptoService::CryptAesCtr(const sf::OutNonSecureBuffer &out_buf, u32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr) {
|
Result CryptoService::CryptAesCtr(const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr) {
|
||||||
return impl::CryptAesCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
return impl::CryptAesCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CryptoService::ComputeCmac(sf::Out<Cmac> out_cmac, u32 keyslot, const sf::InPointerBuffer &in_buf) {
|
Result CryptoService::ComputeCmac(sf::Out<Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf) {
|
||||||
return impl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize());
|
return impl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CryptoService::AllocateAesKeyslot(sf::Out<u32> out_keyslot) {
|
Result CryptoService::AllocateAesKeyslot(sf::Out<s32> out_keyslot) {
|
||||||
return impl::AllocateAesKeyslot(out_keyslot.GetPointer(), this);
|
return impl::AllocateAesKeyslot(out_keyslot.GetPointer(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CryptoService::FreeAesKeyslot(u32 keyslot) {
|
Result CryptoService::FreeAesKeyslot(s32 keyslot) {
|
||||||
return impl::FreeAesKeyslot(keyslot, this);
|
return impl::FreeAesKeyslot(keyslot, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,13 +25,13 @@ namespace ams::spl {
|
|||||||
protected:
|
protected:
|
||||||
/* Actual commands. */
|
/* Actual commands. */
|
||||||
virtual Result GenerateAesKek(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option);
|
virtual Result GenerateAesKek(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option);
|
||||||
virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source);
|
virtual Result LoadAesKey(s32 keyslot, AccessKey access_key, KeySource key_source);
|
||||||
virtual Result GenerateAesKey(sf::Out<AesKey> out_key, AccessKey access_key, KeySource key_source);
|
virtual Result GenerateAesKey(sf::Out<AesKey> out_key, AccessKey access_key, KeySource key_source);
|
||||||
virtual Result DecryptAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option);
|
virtual Result DecryptAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option);
|
||||||
virtual Result CryptAesCtr(const sf::OutNonSecureBuffer &out_buf, u32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr);
|
virtual Result CryptAesCtr(const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr);
|
||||||
virtual Result ComputeCmac(sf::Out<Cmac> out_cmac, u32 keyslot, const sf::InPointerBuffer &in_buf);
|
virtual Result ComputeCmac(sf::Out<Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf);
|
||||||
virtual Result AllocateAesKeyslot(sf::Out<u32> out_keyslot);
|
virtual Result AllocateAesKeyslot(sf::Out<s32> out_keyslot);
|
||||||
virtual Result FreeAesKeyslot(u32 keyslot);
|
virtual Result FreeAesKeyslot(s32 keyslot);
|
||||||
virtual void GetAesKeyslotAvailableEvent(sf::OutCopyHandle out_hnd);
|
virtual void GetAesKeyslotAvailableEvent(sf::OutCopyHandle out_hnd);
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
@ -48,9 +48,9 @@ namespace ams::spl {
|
|||||||
MAKE_SERVICE_COMMAND_META(DecryptAesKey),
|
MAKE_SERVICE_COMMAND_META(DecryptAesKey),
|
||||||
MAKE_SERVICE_COMMAND_META(CryptAesCtr),
|
MAKE_SERVICE_COMMAND_META(CryptAesCtr),
|
||||||
MAKE_SERVICE_COMMAND_META(ComputeCmac),
|
MAKE_SERVICE_COMMAND_META(ComputeCmac),
|
||||||
MAKE_SERVICE_COMMAND_META(AllocateAesKeyslot, hos::Version_2_0_0),
|
MAKE_SERVICE_COMMAND_META(AllocateAesKeyslot /* Atmosphere extension: This was added in hos::Version_2_0_0, but is allowed on older firmware by atmosphere. */),
|
||||||
MAKE_SERVICE_COMMAND_META(FreeAesKeyslot, hos::Version_2_0_0),
|
MAKE_SERVICE_COMMAND_META(FreeAesKeyslot /* Atmosphere extension: This was added in hos::Version_2_0_0, but is allowed on older firmware by atmosphere. */),
|
||||||
MAKE_SERVICE_COMMAND_META(GetAesKeyslotAvailableEvent, hos::Version_2_0_0),
|
MAKE_SERVICE_COMMAND_META(GetAesKeyslotAvailableEvent /* Atmosphere extension: This was added in hos::Version_2_0_0, but is allowed on older firmware by atmosphere. */),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ namespace ams::spl {
|
|||||||
return impl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
return impl::GenerateAesKek(out_access_key.GetPointer(), key_source, generation, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source) {
|
Result DeprecatedService::LoadAesKey(s32 keyslot, AccessKey access_key, KeySource key_source) {
|
||||||
return impl::LoadAesKey(keyslot, this, access_key, key_source);
|
return impl::LoadAesKey(keyslot, this, access_key, key_source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,15 +70,15 @@ namespace ams::spl {
|
|||||||
return impl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
return impl::DecryptAesKey(out_key.GetPointer(), key_source, generation, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::CryptAesCtrDeprecated(const sf::OutBuffer &out_buf, u32 keyslot, const sf::InBuffer &in_buf, IvCtr iv_ctr) {
|
Result DeprecatedService::CryptAesCtrDeprecated(const sf::OutBuffer &out_buf, s32 keyslot, const sf::InBuffer &in_buf, IvCtr iv_ctr) {
|
||||||
return impl::CryptAesCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
return impl::CryptAesCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::CryptAesCtr(const sf::OutNonSecureBuffer &out_buf, u32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr) {
|
Result DeprecatedService::CryptAesCtr(const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr) {
|
||||||
return impl::CryptAesCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
return impl::CryptAesCtr(out_buf.GetPointer(), out_buf.GetSize(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize(), iv_ctr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::ComputeCmac(sf::Out<Cmac> out_cmac, u32 keyslot, const sf::InPointerBuffer &in_buf) {
|
Result DeprecatedService::ComputeCmac(sf::Out<Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf) {
|
||||||
return impl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize());
|
return impl::ComputeCmac(out_cmac.GetPointer(), keyslot, this, in_buf.GetPointer(), in_buf.GetSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ namespace ams::spl {
|
|||||||
return impl::UnwrapTitleKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), generation);
|
return impl::UnwrapTitleKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::LoadTitleKey(u32 keyslot, AccessKey access_key) {
|
Result DeprecatedService::LoadTitleKey(s32 keyslot, AccessKey access_key) {
|
||||||
return impl::LoadTitleKey(keyslot, this, access_key);
|
return impl::LoadTitleKey(keyslot, this, access_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,11 +106,11 @@ namespace ams::spl {
|
|||||||
return impl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation);
|
return impl::UnwrapCommonTitleKey(out_access_key.GetPointer(), key_source, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::AllocateAesKeyslot(sf::Out<u32> out_keyslot) {
|
Result DeprecatedService::AllocateAesKeyslot(sf::Out<s32> out_keyslot) {
|
||||||
return impl::AllocateAesKeyslot(out_keyslot.GetPointer(), this);
|
return impl::AllocateAesKeyslot(out_keyslot.GetPointer(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DeprecatedService::FreeAesKeyslot(u32 keyslot) {
|
Result DeprecatedService::FreeAesKeyslot(s32 keyslot) {
|
||||||
return impl::FreeAesKeyslot(keyslot, this);
|
return impl::FreeAesKeyslot(keyslot, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ namespace ams::spl {
|
|||||||
virtual Result GetConfig(sf::Out<u64> out, u32 which);
|
virtual Result GetConfig(sf::Out<u64> out, u32 which);
|
||||||
virtual Result ExpMod(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &exp, const sf::InPointerBuffer &mod);
|
virtual Result ExpMod(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &exp, const sf::InPointerBuffer &mod);
|
||||||
virtual Result GenerateAesKek(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option);
|
virtual Result GenerateAesKek(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation, u32 option);
|
||||||
virtual Result LoadAesKey(u32 keyslot, AccessKey access_key, KeySource key_source);
|
virtual Result LoadAesKey(s32 keyslot, AccessKey access_key, KeySource key_source);
|
||||||
virtual Result GenerateAesKey(sf::Out<AesKey> out_key, AccessKey access_key, KeySource key_source);
|
virtual Result GenerateAesKey(sf::Out<AesKey> out_key, AccessKey access_key, KeySource key_source);
|
||||||
virtual Result SetConfig(u32 which, u64 value);
|
virtual Result SetConfig(u32 which, u64 value);
|
||||||
virtual Result GenerateRandomBytes(const sf::OutPointerBuffer &out);
|
virtual Result GenerateRandomBytes(const sf::OutPointerBuffer &out);
|
||||||
@ -73,17 +73,17 @@ namespace ams::spl {
|
|||||||
virtual Result GenerateSpecificAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which);
|
virtual Result GenerateSpecificAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which);
|
||||||
virtual Result DecryptRsaPrivateKey(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option);
|
virtual Result DecryptRsaPrivateKey(const sf::OutPointerBuffer &dst, const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option);
|
||||||
virtual Result DecryptAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option);
|
virtual Result DecryptAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 option);
|
||||||
virtual Result CryptAesCtrDeprecated(const sf::OutBuffer &out_buf, u32 keyslot, const sf::InBuffer &in_buf, IvCtr iv_ctr);
|
virtual Result CryptAesCtrDeprecated(const sf::OutBuffer &out_buf, s32 keyslot, const sf::InBuffer &in_buf, IvCtr iv_ctr);
|
||||||
virtual Result CryptAesCtr(const sf::OutNonSecureBuffer &out_buf, u32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr);
|
virtual Result CryptAesCtr(const sf::OutNonSecureBuffer &out_buf, s32 keyslot, const sf::InNonSecureBuffer &in_buf, IvCtr iv_ctr);
|
||||||
virtual Result ComputeCmac(sf::Out<Cmac> out_cmac, u32 keyslot, const sf::InPointerBuffer &in_buf);
|
virtual Result ComputeCmac(sf::Out<Cmac> out_cmac, s32 keyslot, const sf::InPointerBuffer &in_buf);
|
||||||
virtual Result ImportEsKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option);
|
virtual Result ImportEsKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source, u32 option);
|
||||||
virtual Result UnwrapTitleKeyDeprecated(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest);
|
virtual Result UnwrapTitleKeyDeprecated(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest);
|
||||||
virtual Result UnwrapTitleKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation);
|
virtual Result UnwrapTitleKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation);
|
||||||
virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key);
|
virtual Result LoadTitleKey(s32 keyslot, AccessKey access_key);
|
||||||
virtual Result UnwrapCommonTitleKeyDeprecated(sf::Out<AccessKey> out_access_key, KeySource key_source);
|
virtual Result UnwrapCommonTitleKeyDeprecated(sf::Out<AccessKey> out_access_key, KeySource key_source);
|
||||||
virtual Result UnwrapCommonTitleKey(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation);
|
virtual Result UnwrapCommonTitleKey(sf::Out<AccessKey> out_access_key, KeySource key_source, u32 generation);
|
||||||
virtual Result AllocateAesKeyslot(sf::Out<u32> out_keyslot);
|
virtual Result AllocateAesKeyslot(sf::Out<s32> out_keyslot);
|
||||||
virtual Result FreeAesKeyslot(u32 keyslot);
|
virtual Result FreeAesKeyslot(s32 keyslot);
|
||||||
virtual void GetAesKeyslotAvailableEvent(sf::OutCopyHandle out_hnd);
|
virtual void GetAesKeyslotAvailableEvent(sf::OutCopyHandle out_hnd);
|
||||||
virtual Result SetBootReason(BootReasonValue boot_reason);
|
virtual Result SetBootReason(BootReasonValue boot_reason);
|
||||||
virtual Result GetBootReason(sf::Out<BootReasonValue> out);
|
virtual Result GetBootReason(sf::Out<BootReasonValue> out);
|
||||||
@ -117,9 +117,9 @@ namespace ams::spl {
|
|||||||
MAKE_SERVICE_COMMAND_META(UnwrapCommonTitleKeyDeprecated, hos::Version_2_0_0, hos::Version_2_0_0),
|
MAKE_SERVICE_COMMAND_META(UnwrapCommonTitleKeyDeprecated, hos::Version_2_0_0, hos::Version_2_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(UnwrapCommonTitleKey, hos::Version_3_0_0),
|
MAKE_SERVICE_COMMAND_META(UnwrapCommonTitleKey, hos::Version_3_0_0),
|
||||||
|
|
||||||
MAKE_SERVICE_COMMAND_META(AllocateAesKeyslot, hos::Version_2_0_0),
|
MAKE_SERVICE_COMMAND_META(AllocateAesKeyslot /* Atmosphere extension: This was added in hos::Version_2_0_0, but is allowed on older firmware by atmosphere. */),
|
||||||
MAKE_SERVICE_COMMAND_META(FreeAesKeyslot, hos::Version_2_0_0),
|
MAKE_SERVICE_COMMAND_META(FreeAesKeyslot /* Atmosphere extension: This was added in hos::Version_2_0_0, but is allowed on older firmware by atmosphere. */),
|
||||||
MAKE_SERVICE_COMMAND_META(GetAesKeyslotAvailableEvent, hos::Version_2_0_0),
|
MAKE_SERVICE_COMMAND_META(GetAesKeyslotAvailableEvent /* Atmosphere extension: This was added in hos::Version_2_0_0, but is allowed on older firmware by atmosphere. */),
|
||||||
|
|
||||||
MAKE_SERVICE_COMMAND_META(SetBootReason, hos::Version_3_0_0),
|
MAKE_SERVICE_COMMAND_META(SetBootReason, hos::Version_3_0_0),
|
||||||
MAKE_SERVICE_COMMAND_META(GetBootReason, hos::Version_3_0_0),
|
MAKE_SERVICE_COMMAND_META(GetBootReason, hos::Version_3_0_0),
|
||||||
|
@ -46,7 +46,7 @@ namespace ams::spl {
|
|||||||
return impl::UnwrapElicenseKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), generation);
|
return impl::UnwrapElicenseKey(out_access_key.GetPointer(), base.GetPointer(), base.GetSize(), mod.GetPointer(), mod.GetSize(), label_digest.GetPointer(), label_digest.GetSize(), generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result EsService::LoadElicenseKey(u32 keyslot, AccessKey access_key) {
|
Result EsService::LoadElicenseKey(s32 keyslot, AccessKey access_key) {
|
||||||
return impl::LoadElicenseKey(keyslot, this, access_key);
|
return impl::LoadElicenseKey(keyslot, this, access_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ namespace ams::spl {
|
|||||||
virtual Result ImportDrmKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source);
|
virtual Result ImportDrmKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source);
|
||||||
virtual Result DrmExpMod(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod);
|
virtual Result DrmExpMod(const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod);
|
||||||
virtual Result UnwrapElicenseKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation);
|
virtual Result UnwrapElicenseKey(sf::Out<AccessKey> out_access_key, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest, u32 generation);
|
||||||
virtual Result LoadElicenseKey(u32 keyslot, AccessKey access_key);
|
virtual Result LoadElicenseKey(s32 keyslot, AccessKey access_key);
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MAKE_SERVICE_COMMAND_META(GetConfig),
|
MAKE_SERVICE_COMMAND_META(GetConfig),
|
||||||
|
@ -34,7 +34,7 @@ namespace ams::spl {
|
|||||||
return impl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
|
return impl::GenerateSpecificAesKey(out_key.GetPointer(), key_source, generation, which);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsService::LoadTitleKey(u32 keyslot, AccessKey access_key) {
|
Result FsService::LoadTitleKey(s32 keyslot, AccessKey access_key) {
|
||||||
return impl::LoadTitleKey(keyslot, this, access_key);
|
return impl::LoadTitleKey(keyslot, this, access_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace ams::spl {
|
|||||||
virtual Result ImportLotusKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source);
|
virtual Result ImportLotusKey(const sf::InPointerBuffer &src, AccessKey access_key, KeySource key_source);
|
||||||
virtual Result DecryptLotusMessage(sf::Out<u32> out_size, const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest);
|
virtual Result DecryptLotusMessage(sf::Out<u32> out_size, const sf::OutPointerBuffer &out, const sf::InPointerBuffer &base, const sf::InPointerBuffer &mod, const sf::InPointerBuffer &label_digest);
|
||||||
virtual Result GenerateSpecificAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which);
|
virtual Result GenerateSpecificAesKey(sf::Out<AesKey> out_key, KeySource key_source, u32 generation, u32 which);
|
||||||
virtual Result LoadTitleKey(u32 keyslot, AccessKey access_key);
|
virtual Result LoadTitleKey(s32 keyslot, AccessKey access_key);
|
||||||
virtual Result GetPackage2Hash(const sf::OutPointerBuffer &dst);
|
virtual Result GetPackage2Hash(const sf::OutPointerBuffer &dst);
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
|
138
stratosphere/spl/source/spl_key_slot_cache.hpp
Normal file
138
stratosphere/spl/source/spl_key_slot_cache.hpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::spl {
|
||||||
|
|
||||||
|
class KeySlotCacheEntry : public util::IntrusiveListBaseNode<KeySlotCacheEntry> {
|
||||||
|
NON_COPYABLE(KeySlotCacheEntry);
|
||||||
|
NON_MOVEABLE(KeySlotCacheEntry);
|
||||||
|
private:
|
||||||
|
friend class KeySlotCache;
|
||||||
|
public:
|
||||||
|
static constexpr size_t KeySize = crypto::AesDecryptor128::KeySize;
|
||||||
|
private:
|
||||||
|
const s32 slot_index;
|
||||||
|
s32 virtual_slot;
|
||||||
|
public:
|
||||||
|
explicit KeySlotCacheEntry(s32 idx) : slot_index(idx), virtual_slot(-1) { /* ... */ }
|
||||||
|
|
||||||
|
bool Contains(s32 virtual_slot) const {
|
||||||
|
return virtual_slot == this->virtual_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 GetPhysicalKeySlotIndex() const { return this->slot_index; }
|
||||||
|
|
||||||
|
s32 GetVirtualKeySlotIndex() const { return this->virtual_slot; }
|
||||||
|
|
||||||
|
void SetVirtualSlot(s32 virtual_slot) {
|
||||||
|
this->virtual_slot = virtual_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearVirtualSlot() {
|
||||||
|
this->virtual_slot = -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeySlotCache {
|
||||||
|
NON_COPYABLE(KeySlotCache);
|
||||||
|
NON_MOVEABLE(KeySlotCache);
|
||||||
|
private:
|
||||||
|
using KeySlotCacheEntryList = util::IntrusiveListBaseTraits<KeySlotCacheEntry>::ListType;
|
||||||
|
private:
|
||||||
|
KeySlotCacheEntryList mru_list;
|
||||||
|
public:
|
||||||
|
constexpr KeySlotCache() : mru_list() { /* ... */ }
|
||||||
|
|
||||||
|
s32 Allocate(s32 virtual_slot) {
|
||||||
|
return this->AllocateFromLru(virtual_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Find(s32 *out, s32 virtual_slot) {
|
||||||
|
for (auto it = this->mru_list.begin(); it != this->mru_list.end(); ++it) {
|
||||||
|
if (it->Contains(virtual_slot)) {
|
||||||
|
*out = it->GetPhysicalKeySlotIndex();
|
||||||
|
|
||||||
|
this->UpdateMru(it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Release(s32 *out, s32 virtual_slot) {
|
||||||
|
for (auto it = this->mru_list.begin(); it != this->mru_list.end(); ++it) {
|
||||||
|
if (it->Contains(virtual_slot)) {
|
||||||
|
*out = it->GetPhysicalKeySlotIndex();
|
||||||
|
it->ClearVirtualSlot();
|
||||||
|
|
||||||
|
this->UpdateLru(it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindPhysical(s32 physical_slot) {
|
||||||
|
for (auto it = this->mru_list.begin(); it != this->mru_list.end(); ++it) {
|
||||||
|
if (it->GetPhysicalKeySlotIndex() == physical_slot) {
|
||||||
|
this->UpdateMru(it);
|
||||||
|
|
||||||
|
if (it->GetVirtualKeySlotIndex() == physical_slot) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
it->SetVirtualSlot(physical_slot);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AMS_ABORT();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddEntry(KeySlotCacheEntry *entry) {
|
||||||
|
this->mru_list.push_front(*entry);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
s32 AllocateFromLru(s32 virtual_slot) {
|
||||||
|
AMS_ASSERT(!this->mru_list.empty());
|
||||||
|
|
||||||
|
auto it = this->mru_list.rbegin();
|
||||||
|
it->SetVirtualSlot(virtual_slot);
|
||||||
|
|
||||||
|
auto *entry = std::addressof(*it);
|
||||||
|
this->mru_list.pop_back();
|
||||||
|
this->mru_list.push_front(*entry);
|
||||||
|
|
||||||
|
return entry->GetPhysicalKeySlotIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateMru(KeySlotCacheEntryList::iterator it) {
|
||||||
|
auto *entry = std::addressof(*it);
|
||||||
|
this->mru_list.erase(it);
|
||||||
|
this->mru_list.push_front(*entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateLru(KeySlotCacheEntryList::iterator it) {
|
||||||
|
auto *entry = std::addressof(*it);
|
||||||
|
this->mru_list.erase(it);
|
||||||
|
this->mru_list.push_back(*entry);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user