Merge branch 'ssl-add-new-functions-services' into 'master'

service/ssl: Add ssl:s service and fix SSL-related crashes in Xenoblade X

See merge request citron/rewrite!5
This commit is contained in:
Zephyron
2025-05-11 10:23:02 +00:00
5 changed files with 250 additions and 38 deletions

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h" #include "core/core.h"
@@ -180,40 +181,28 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
R_SUCCEED(); R_SUCCEED();
case InfoType::ThreadTickCount: { case InfoType::ThreadTickCount: {
constexpr u64 num_cpus = 4; const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { KScopedAutoObject thread = handle_table.GetObject<KThread>(handle);
LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus, R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
info_sub_id);
R_THROW(ResultInvalidCombination); // Use GetCpuTime() instead of the non-existent GetYieldScheduleCount() and GetYieldScheduleBias()
const s64 cpu_time = static_cast<s64>(thread->GetCpuTime());
// For sub IDs, just return the CPU time or 0 based on the ID
switch (info_sub_id) {
case 0:
*result = cpu_time;
R_SUCCEED();
case 1:
case 2:
// We don't have separate bias/other fields, just return 0
*result = 0;
R_SUCCEED();
default:
R_THROW(ResultInvalidEnumValue);
} }
KScopedAutoObject thread = GetCurrentProcess(system.Kernel())
.GetHandleTable()
.GetObject<KThread>(static_cast<Handle>(handle));
if (thread.IsNull()) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
static_cast<Handle>(handle));
R_THROW(ResultInvalidHandle);
}
const auto& core_timing = system.CoreTiming();
const auto& scheduler = *system.Kernel().CurrentScheduler();
const auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
const bool same_thread = current_thread == thread.GetPointerUnsafe();
const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTime();
u64 out_ticks = 0;
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
const u64 thread_ticks = current_thread->GetCpuTime();
out_ticks = thread_ticks + (core_timing.GetClockTicks() - prev_ctx_ticks);
} else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {
out_ticks = core_timing.GetClockTicks() - prev_ctx_ticks;
}
*result = out_ticks;
R_SUCCEED();
} }
case InfoType::IdleTickCount: { case InfoType::IdleTickCount: {
// Verify the input handle is invalid. // Verify the input handle is invalid.
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
@@ -228,6 +217,15 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
*result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime(); *result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime();
R_SUCCEED(); R_SUCCEED();
} }
case InfoType::TLSCapability: {
// This is related to TLS capabilities
// For now, let's return a successful result with a value that indicates TLS is supported
LOG_WARNING(Kernel_SVC, "(STUBBED) TLS capability check requested, returning supported");
*result = 1; // Indicate support
R_SUCCEED();
}
case InfoType::MesosphereCurrentProcess: { case InfoType::MesosphereCurrentProcess: {
// Verify the input handle is invalid. // Verify the input handle is invalid.
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle); R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
@@ -153,6 +154,7 @@ enum class InfoType : u32 {
ThreadTickCount = 25, ThreadTickCount = 25,
IsSvcPermitted = 26, IsSvcPermitted = 26,
IoRegionHint = 27, IoRegionHint = 27,
TLSCapability = 28, // ID 0x1C used for TLS capability check
MesosphereMeta = 65000, MesosphereMeta = 65000,
MesosphereCurrentProcess = 65001, MesosphereCurrentProcess = 65001,

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/string_util.h" #include "common/string_util.h"
@@ -14,6 +15,7 @@
#include "core/hle/service/ssl/cert_store.h" #include "core/hle/service/ssl/cert_store.h"
#include "core/hle/service/ssl/ssl.h" #include "core/hle/service/ssl/ssl.h"
#include "core/hle/service/ssl/ssl_backend.h" #include "core/hle/service/ssl/ssl_backend.h"
#include "core/hle/service/ssl/ssl_types.h"
#include "core/internal_network/network.h" #include "core/internal_network/network.h"
#include "core/internal_network/sockets.h" #include "core/internal_network/sockets.h"
@@ -492,6 +494,128 @@ private:
} }
}; };
class ISslContextForSystem final : public ServiceFramework<ISslContextForSystem> {
public:
explicit ISslContextForSystem(Core::System& system_, SslVersion version)
: ServiceFramework{system_, "ISslContextForSystem"}, ssl_version{version},
shared_data{std::make_shared<SslContextSharedData>()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SetOption"},
{1, nullptr, "GetOption"},
{2, nullptr, "CreateConnection"},
{3, nullptr, "GetConnectionCount"},
{4, nullptr, "ImportServerPki"},
{5, nullptr, "ImportClientPki"},
{6, nullptr, "RemoveServerPki"},
{7, nullptr, "RemoveClientPki"},
{8, nullptr, "RegisterInternalPki"},
{9, nullptr, "AddPolicyOid"},
{10, nullptr, "ImportCrl"},
{11, nullptr, "RemoveCrl"},
{12, nullptr, "ImportClientCertKeyPki"},
{13, nullptr, "GeneratePrivateKeyAndCert"},
{14, nullptr, "CreateConnectionEx"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
SslVersion ssl_version;
std::shared_ptr<SslContextSharedData> shared_data;
};
class ISslServiceForSystem final : public ServiceFramework<ISslServiceForSystem> {
public:
explicit ISslServiceForSystem(Core::System& system_)
: ServiceFramework{system_, "ssl:s"}, cert_store{system} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISslServiceForSystem::CreateContextForSystem, "CreateContextForSystem"},
{1, &ISslServiceForSystem::SetThreadCoreMask, "SetThreadCoreMask"},
{2, &ISslServiceForSystem::GetThreadCoreMask, "GetThreadCoreMask"},
{3, &ISslServiceForSystem::VerifySignature, "VerifySignature"},
{4, nullptr, "SetCertificateAndPrivateKeyInternal"},
{5, &ISslServiceForSystem::FlushSessionCache, "FlushSessionCache"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void CreateContextForSystem(HLERequestContext& ctx) {
struct Parameters {
SslVersion ssl_version;
INSERT_PADDING_BYTES(0x4);
u64 pid_placeholder;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters is an invalid size");
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
LOG_WARNING(Service_SSL, "(STUBBED) called, api_version={}, pid_placeholder={}",
parameters.ssl_version.api_version, parameters.pid_placeholder);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISslContextForSystem>(system, parameters.ssl_version);
}
void SetThreadCoreMask(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 core_mask = rp.Pop<u64>();
const u32 core_id = rp.Pop<u32>();
LOG_WARNING(Service_SSL, "(STUBBED) called, core_mask={:016X}, core_id={}", core_mask,
core_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetThreadCoreMask(HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "(STUBBED) called");
constexpr u64 core_mask = 0;
constexpr u32 core_id = 0;
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(core_mask);
rb.Push(core_id);
}
void VerifySignature(HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void FlushSessionCache(HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const u32 option_type = rp.Pop<u32>();
// Read the hostname buffer if provided for option_type 0
if (option_type == 0 && ctx.CanReadBuffer(0)) {
const auto hostname = Common::StringFromBuffer(ctx.ReadBuffer(0));
LOG_INFO(Service_SSL, "FlushSessionCache with hostname={}", hostname);
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0); // Flushed session count, stubbed to 0
}
CertStore cert_store;
};
class ISslService final : public ServiceFramework<ISslService> { class ISslService final : public ServiceFramework<ISslService> {
public: public:
explicit ISslService(Core::System& system_) explicit ISslService(Core::System& system_)
@@ -504,10 +628,10 @@ public:
{3, D<&ISslService::GetCertificateBufSize>, "GetCertificateBufSize"}, {3, D<&ISslService::GetCertificateBufSize>, "GetCertificateBufSize"},
{4, nullptr, "DebugIoctl"}, {4, nullptr, "DebugIoctl"},
{5, &ISslService::SetInterfaceVersion, "SetInterfaceVersion"}, {5, &ISslService::SetInterfaceVersion, "SetInterfaceVersion"},
{6, nullptr, "FlushSessionCache"}, {6, &ISslService::FlushSessionCache, "FlushSessionCache"},
{7, nullptr, "SetDebugOption"}, {7, nullptr, "SetDebugOption"},
{8, nullptr, "GetDebugOption"}, {8, nullptr, "GetDebugOption"},
{8, nullptr, "ClearTls12FallbackFlag"}, {9, nullptr, "ClearTls12FallbackFlag"},
}; };
// clang-format on // clang-format on
@@ -544,6 +668,23 @@ private:
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void FlushSessionCache(HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const u32 option_type = rp.Pop<u32>();
// Read the hostname buffer if provided for option_type 0
if (option_type == 0 && ctx.CanReadBuffer(0)) {
const auto hostname = Common::StringFromBuffer(ctx.ReadBuffer(0));
LOG_INFO(Service_SSL, "FlushSessionCache with hostname={}", hostname);
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0); // Flushed session count, stubbed to 0
}
Result GetCertificateBufSize( Result GetCertificateBufSize(
Out<u32> out_size, InArray<CaCertificateId, BufferAttr_HipcMapAlias> certificate_ids) { Out<u32> out_size, InArray<CaCertificateId, BufferAttr_HipcMapAlias> certificate_ids) {
LOG_INFO(Service_SSL, "called"); LOG_INFO(Service_SSL, "called");
@@ -565,6 +706,7 @@ void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system); auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("ssl", std::make_shared<ISslService>(system)); server_manager->RegisterNamedService("ssl", std::make_shared<ISslService>(system));
server_manager->RegisterNamedService("ssl:s", std::make_shared<ISslServiceForSystem>(system));
ServerManager::RunServer(std::move(server_manager)); ServerManager::RunServer(std::move(server_manager));
} }

View File

@@ -1,8 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "core/hle/service/ssl/ssl_types.h"
namespace Core { namespace Core {
class System; class System;
} }

View File

@@ -1,16 +1,83 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/internal_network/network.h"
#include "core/hle/service/ssl/ssl_backend.h" #include "core/hle/service/ssl/ssl_backend.h"
namespace Service::SSL { namespace Service::SSL {
class SSLConnectionBackendNone final : public SSLConnectionBackend {
public:
SSLConnectionBackendNone() = default;
~SSLConnectionBackendNone() = default;
void SetSocket(std::shared_ptr<Network::SocketBase> socket_) override {
socket = std::move(socket_);
}
Result SetHostName(const std::string& hostname) override {
LOG_WARNING(Service_SSL, "(STUBBED) SetHostName hostname={}", hostname);
return ResultSuccess;
}
Result DoHandshake() override {
LOG_WARNING(Service_SSL, "(STUBBED) Pretending to do TLS handshake");
return ResultSuccess;
}
Result Read(size_t* out_size, std::span<u8> buffer) override {
LOG_WARNING(Service_SSL, "(STUBBED) Read called, using raw socket");
if (!socket) {
return ResultNoSocket;
}
// Just pass through to the socket directly (no TLS)
const Network::Errno result = socket->Recv(buffer.data(), buffer.size(), 0, *out_size);
if (result == Network::Errno::EWOULDBLOCK) {
return ResultWouldBlock;
} else if (result != Network::Errno::SUCCESS) {
LOG_ERROR(Service_SSL, "Error during socket read: {}", result);
return ResultInternalError;
}
return ResultSuccess;
}
Result Write(size_t* out_size, std::span<const u8> data) override {
LOG_WARNING(Service_SSL, "(STUBBED) Write called, using raw socket");
if (!socket) {
return ResultNoSocket;
}
// Just pass through to the socket directly (no TLS)
const Network::Errno result = socket->Send(data.data(), data.size(), 0, *out_size);
if (result == Network::Errno::EWOULDBLOCK) {
return ResultWouldBlock;
} else if (result != Network::Errno::SUCCESS) {
LOG_ERROR(Service_SSL, "Error during socket write: {}", result);
return ResultInternalError;
}
return ResultSuccess;
}
Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) override {
LOG_WARNING(Service_SSL, "(STUBBED) GetServerCerts called");
// Return an empty certificate to prevent crashes
out_certs->emplace_back(std::vector<u8>{0x30, 0x82, 0x01, 0x01}); // Minimal dummy DER certificate header
return ResultSuccess;
}
private:
std::shared_ptr<Network::SocketBase> socket;
};
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) { Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend) {
LOG_ERROR(Service_SSL, LOG_WARNING(Service_SSL, "Creating stub SSL backend (no real TLS encryption)");
"Can't create SSL connection because no SSL backend is available on this platform"); *out_backend = std::make_unique<SSLConnectionBackendNone>();
return ResultInternalError; return ResultSuccess;
} }
} // namespace Service::SSL } // namespace Service::SSL