From f4a8124dc3afcbb3433ac1d603ab41ddce933024 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 24 Apr 2019 23:10:13 -0700 Subject: [PATCH] spl: implement SslService, some of EsService --- stratosphere/spl/source/spl_es_service.cpp | 52 +++++++++ stratosphere/spl/source/spl_es_service.hpp | 69 +++++++++++ .../spl/source/spl_secmon_wrapper.cpp | 107 ++++++++++++++++++ .../spl/source/spl_secmon_wrapper.hpp | 13 ++- stratosphere/spl/source/spl_ssl_service.cpp | 28 +++++ stratosphere/spl/source/spl_ssl_service.hpp | 60 ++++++++++ 6 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 stratosphere/spl/source/spl_es_service.cpp create mode 100644 stratosphere/spl/source/spl_es_service.hpp create mode 100644 stratosphere/spl/source/spl_ssl_service.cpp create mode 100644 stratosphere/spl/source/spl_ssl_service.hpp diff --git a/stratosphere/spl/source/spl_es_service.cpp b/stratosphere/spl/source/spl_es_service.cpp new file mode 100644 index 000000000..20c2f8d10 --- /dev/null +++ b/stratosphere/spl/source/spl_es_service.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "spl_es_service.hpp" + +Result EsService::ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option) { + return this->GetSecureMonitorWrapper()->ImportEsKey(src.pointer, src.num_elements, access_key, key_source, option); +} + +Result EsService::UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation) { + /* TODO */ + return ResultKernelConnectionClosed; +} + +Result EsService::UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation) { + /* TODO */ + return ResultKernelConnectionClosed; +} + +Result EsService::ImportDrmKey(InPointer src, AccessKey access_key, KeySource key_source) { + return this->GetSecureMonitorWrapper()->ImportDrmKey(src.pointer, src.num_elements, access_key, key_source); +} + +Result EsService::DrmExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod) { + return this->GetSecureMonitorWrapper()->DrmExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements); +} + +Result EsService::UnwrapElicenseKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation) { + /* TODO */ + return ResultKernelConnectionClosed; +} + +Result EsService::LoadElicenseKey(u32 keyslot, AccessKey access_key) { + /* TODO */ + return ResultKernelConnectionClosed; +} diff --git a/stratosphere/spl/source/spl_es_service.hpp b/stratosphere/spl/source/spl_es_service.hpp new file mode 100644 index 000000000..17f8efa0f --- /dev/null +++ b/stratosphere/spl/source/spl_es_service.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +#include "spl_types.hpp" +#include "spl_rsa_service.hpp" + +class EsService : public RsaService { + public: + EsService(SecureMonitorWrapper *sw) : RsaService(sw) { + /* ... */ + } + + virtual ~EsService() { + /* ... */ + } + protected: + /* Actual commands. */ + virtual Result ImportEsKey(InPointer src, AccessKey access_key, KeySource key_source, u32 option); + virtual Result UnwrapTitleKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation); + virtual Result UnwrapCommonTitleKey(Out out_access_key, KeySource key_source, u32 generation); + virtual Result ImportDrmKey(InPointer src, AccessKey access_key, KeySource key_source); + virtual Result DrmExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod); + virtual Result UnwrapElicenseKey(Out out_access_key, InPointer base, InPointer mod, InPointer label_digest, u32 generation); + virtual Result LoadElicenseKey(u32 keyslot, AccessKey access_key); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + }; +}; diff --git a/stratosphere/spl/source/spl_secmon_wrapper.cpp b/stratosphere/spl/source/spl_secmon_wrapper.cpp index efc9eb6fd..bcd36e479 100644 --- a/stratosphere/spl/source/spl_secmon_wrapper.cpp +++ b/stratosphere/spl/source/spl_secmon_wrapper.cpp @@ -555,6 +555,113 @@ Result SecureMonitorWrapper::DecryptRsaPrivateKey(void *dst, size_t dst_size, co 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]; + }; + ImportSecureExpModKeyLayout *layout = reinterpret_cast(g_work_buffer); + + /* Validate size. */ + if (src_size > sizeof(ImportSecureExpModKeyLayout)) { + return ResultSplInvalidSize; + } + + std::memcpy(layout, src, src_size); + + armDCacheFlush(layout, sizeof(*layout)); + SmcResult smc_res; + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { + smc_res = SmcWrapper::DecryptOrImportRsaPrivateKey(layout->data, src_size, access_key, key_source, option); + } else { + smc_res = SmcWrapper::ImportSecureExpModKey(layout->data, src_size, access_key, key_source, option); + } + + return ConvertToSplResult(smc_res); +} + +Result SecureMonitorWrapper::SecureExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size, u32 option) { + struct SecureExpModLayout { + u8 base[0x100]; + u8 mod[0x100]; + }; + SecureExpModLayout *layout = reinterpret_cast(g_work_buffer); + + /* Validate sizes. */ + if (base_size > sizeof(layout->base)) { + return ResultSplInvalidSize; + } + if (mod_size > sizeof(layout->mod)) { + return ResultSplInvalidSize; + } + if (out_size > MaxWorkBufferSize) { + return ResultSplInvalidSize; + } + + /* Copy data into work buffer. */ + const size_t base_ofs = sizeof(layout->base) - base_size; + const size_t mod_ofs = sizeof(layout->mod) - mod_size; + std::memset(layout, 0, sizeof(*layout)); + std::memcpy(layout->base + base_ofs, base, base_size); + std::memcpy(layout->mod + mod_ofs, mod, mod_size); + + /* Do exp mod operation. */ + armDCacheFlush(layout, sizeof(*layout)); + { + std::scoped_lock lk(g_async_op_lock); + AsyncOperationKey op_key; + + SmcResult res = SmcWrapper::SecureExpMod(&op_key, layout->base, layout->mod, option); + if (res != SmcResult_Success) { + return ConvertToSplResult(res); + } + + if ((res = WaitGetResult(g_work_buffer, out_size, op_key)) != SmcResult_Success) { + return ConvertToSplResult(res); + } + } + armDCacheFlush(g_work_buffer, sizeof(out_size)); + + std::memcpy(out, g_work_buffer, out_size); + return ResultSuccess; +} + +Result SecureMonitorWrapper::ImportSslKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source) { + return ImportSecureExpModKey(src, src_size, access_key, key_source, SmcDecryptOrImportMode_ImportSslKey); +} + +Result SecureMonitorWrapper::SslExpMod(void *out, size_t out_size, const void *base, size_t base_size, const void *mod, size_t mod_size) { + return SecureExpMod(out, out_size, base, base_size, mod, mod_size, SmcSecureExpModMode_Ssl); +} + +Result SecureMonitorWrapper::ImportEsKey(const void *src, size_t src_size, const AccessKey &access_key, const KeySource &key_source, u32 option) { + if (GetRuntimeFirmwareVersion() >= FirmwareVersion_500) { + return ImportSecureExpModKey(src, src_size, access_key, key_source, SmcDecryptOrImportMode_ImportEsKey); + } else { + struct ImportEsKeyLayout { + u8 data[RsaPrivateKeyMetaSize + 2 * RsaPrivateKeySize]; + }; + ImportEsKeyLayout *layout = reinterpret_cast(g_work_buffer); + + /* Validate size. */ + if (src_size > sizeof(ImportEsKeyLayout)) { + return ResultSplInvalidSize; + } + + std::memcpy(layout, src, src_size); + + armDCacheFlush(layout, sizeof(*layout)); + return ConvertToSplResult(SmcWrapper::ImportEsKey(layout->data, src_size, access_key, key_source, option)); + } +} + +Result SecureMonitorWrapper::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::FreeAesKeyslots(const void *owner) { for (size_t i = 0; i < GetMaxKeyslots(); i++) { if (this->keyslot_owners[i] == owner) { diff --git a/stratosphere/spl/source/spl_secmon_wrapper.hpp b/stratosphere/spl/source/spl_secmon_wrapper.hpp index d3285195b..4b4106139 100644 --- a/stratosphere/spl/source/spl_secmon_wrapper.hpp +++ b/stratosphere/spl/source/spl_secmon_wrapper.hpp @@ -53,6 +53,8 @@ class SecureMonitorWrapper { 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); public: /* General. */ Result GetConfig(u64 *out, SplConfigItem which); @@ -72,10 +74,19 @@ class SecureMonitorWrapper { 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 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); + /* Helper. */ Result FreeAesKeyslots(const void *owner); Handle GetAesKeyslotAvailableEventHandle(); diff --git a/stratosphere/spl/source/spl_ssl_service.cpp b/stratosphere/spl/source/spl_ssl_service.cpp new file mode 100644 index 000000000..2572968f1 --- /dev/null +++ b/stratosphere/spl/source/spl_ssl_service.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "spl_ssl_service.hpp" + +Result SslService::ImportSslKey(InPointer src, AccessKey access_key, KeySource key_source) { + return this->GetSecureMonitorWrapper()->ImportSslKey(src.pointer, src.num_elements, access_key, key_source); +} + +Result SslService::SslExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod) { + return this->GetSecureMonitorWrapper()->SslExpMod(out.pointer, out.num_elements, base.pointer, base.num_elements, mod.pointer, mod.num_elements); +} diff --git a/stratosphere/spl/source/spl_ssl_service.hpp b/stratosphere/spl/source/spl_ssl_service.hpp new file mode 100644 index 000000000..5079ba30d --- /dev/null +++ b/stratosphere/spl/source/spl_ssl_service.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +#include "spl_types.hpp" +#include "spl_rsa_service.hpp" + +class SslService : public RsaService { + public: + SslService(SecureMonitorWrapper *sw) : RsaService(sw) { + /* ... */ + } + + virtual ~SslService() { + /* ... */ + } + protected: + /* Actual commands. */ + virtual Result ImportSslKey(InPointer src, AccessKey access_key, KeySource key_source); + virtual Result SslExpMod(OutPointerWithClientSize out, InPointer base, InPointer mod); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + + }; +};