From 9ea1a2a941362cb4f1e092ce51cf0c86dae71588 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 24 Apr 2019 21:42:39 -0700 Subject: [PATCH] spl: Implement RsaService --- stratosphere/spl/source/spl_rsa_service.cpp | 24 ++++++++ stratosphere/spl/source/spl_rsa_service.hpp | 57 +++++++++++++++++++ .../spl/source/spl_secmon_wrapper.cpp | 35 ++++++++++++ .../spl/source/spl_secmon_wrapper.hpp | 3 + stratosphere/spl/source/spl_types.hpp | 14 +++++ 5 files changed, 133 insertions(+) create mode 100644 stratosphere/spl/source/spl_rsa_service.cpp create mode 100644 stratosphere/spl/source/spl_rsa_service.hpp diff --git a/stratosphere/spl/source/spl_rsa_service.cpp b/stratosphere/spl/source/spl_rsa_service.cpp new file mode 100644 index 000000000..23849b9de --- /dev/null +++ b/stratosphere/spl/source/spl_rsa_service.cpp @@ -0,0 +1,24 @@ +/* + * 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_rsa_service.hpp" + +Result RsaService::DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer 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); +} \ No newline at end of file diff --git a/stratosphere/spl/source/spl_rsa_service.hpp b/stratosphere/spl/source/spl_rsa_service.hpp new file mode 100644 index 000000000..c6d90185a --- /dev/null +++ b/stratosphere/spl/source/spl_rsa_service.hpp @@ -0,0 +1,57 @@ +/* + * 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_crypto_service.hpp" + +class RsaService : public CryptoService { + public: + RsaService(SecureMonitorWrapper *sw) : CryptoService(sw) { + /* ... */ + } + + virtual ~RsaService() { + /* ... */ + } + protected: + /* Actual commands. */ + virtual Result DecryptRsaPrivateKey(OutPointerWithClientSize dst, InPointer src, AccessKey access_key, KeySource key_source, u32 option); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + 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 fae5714a1..efc9eb6fd 100644 --- a/stratosphere/spl/source/spl_secmon_wrapper.cpp +++ b/stratosphere/spl/source/spl_secmon_wrapper.cpp @@ -29,6 +29,9 @@ constexpr u32 CryptAesInMapBase = 0x90000000u; constexpr u32 CryptAesOutMapBase = 0xC0000000u; constexpr size_t CryptAesSizeMax = static_cast(CryptAesOutMapBase - CryptAesInMapBase); +constexpr size_t RsaPrivateKeySize = 0x100; +constexpr size_t RsaPrivateKeyMetaSize = 0x30; + /* Types. */ struct SeLinkedListEntry { u32 num_entries; @@ -520,6 +523,38 @@ Result SecureMonitorWrapper::FreeAesKeyslot(u32 keyslot, const void *owner) { 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(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::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 758629485..d3285195b 100644 --- a/stratosphere/spl/source/spl_secmon_wrapper.hpp +++ b/stratosphere/spl/source/spl_secmon_wrapper.hpp @@ -72,6 +72,9 @@ 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); /* Helper. */ Result FreeAesKeyslots(const void *owner); diff --git a/stratosphere/spl/source/spl_types.hpp b/stratosphere/spl/source/spl_types.hpp index d7ee64dbe..78c984900 100644 --- a/stratosphere/spl/source/spl_types.hpp +++ b/stratosphere/spl/source/spl_types.hpp @@ -39,6 +39,20 @@ enum SmcCipherMode : u32 { SmcCipherMode_Ctr = 2, }; +enum SmcDecryptOrImportMode : u32 { + SmcDecryptOrImportMode_DecryptRsaPrivateKey = 0, + SmcDecryptOrImportMode_ImportLotusKey = 1, + SmcDecryptOrImportMode_ImportEsKey = 2, + SmcDecryptOrImportMode_ImportSslKey = 3, + SmcDecryptOrImportMode_ImportDrmKey = 4, +}; + +enum SmcSecureExpModMode : u32 { + SmcSecureExpModMode_Lotus = 0, + SmcSecureExpModMode_Ssl = 1, + SmcSecureExpModMode_Drm = 2, +}; + enum EsKeyType : u32 { EsKeyType_TitleKey = 0, EsKeyType_ElicenseKey = 1,