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(),
+
+ };
+};