[hle/ssl] Implement Peek(),{Get,Set}RenegotiationMode,Pending,Poll and stub miscellany (#4428)

Mainly because of Pending() as it's used in some games. May as well implement the rest.

Skyline implemented ISslContext::RegisterInternalPki which is just a success stub (for now) for JJBA:ASB

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4428
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
This commit is contained in:
lizzie
2026-09-17 05:43:59 +02:00
committed by crueter
parent 90aafeedc1
commit 8c1194474e
3 changed files with 266 additions and 250 deletions
+218 -244
View File
@@ -48,6 +48,12 @@ enum class OptionType : u32 {
EnableAlpn = 3, EnableAlpn = 3,
}; };
// This is nn::ssl::sf::RenegotiationMode
enum RenegotiationMode : u32 {
None = 0, ///< None
Secure = 1, ///< Secure
};
// This is nn::ssl::sf::SslVersion // This is nn::ssl::sf::SslVersion
struct SslVersion { struct SslVersion {
union { union {
@@ -75,34 +81,34 @@ public:
shared_data{shared_data_in}, backend{std::move(backend_in)} { shared_data{shared_data_in}, backend{std::move(backend_in)} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &ISslConnection::SetSocketDescriptor, "SetSocketDescriptor"}, {0, D<&ISslConnection::SetSocketDescriptor>, "SetSocketDescriptor"},
{1, &ISslConnection::SetHostName, "SetHostName"}, {1, D<&ISslConnection::SetHostName>, "SetHostName"},
{2, &ISslConnection::SetVerifyOption, "SetVerifyOption"}, {2, D<&ISslConnection::SetVerifyOption>, "SetVerifyOption"},
{3, &ISslConnection::SetIoMode, "SetIoMode"}, {3, D<&ISslConnection::SetIoMode>, "SetIoMode"},
{4, nullptr, "GetSocketDescriptor"}, {4, D<&ISslConnection::GetSocketDescriptor>, "GetSocketDescriptor"},
{5, nullptr, "GetHostName"}, {5, D<&ISslConnection::GetHostName>, "GetHostName"},
{6, nullptr, "GetVerifyOption"}, {6, nullptr, "GetVerifyOption"},
{7, nullptr, "GetIoMode"}, {7, D<&ISslConnection::GetIoMode>, "GetIoMode"},
{8, &ISslConnection::DoHandshake, "DoHandshake"}, {8, D<&ISslConnection::DoHandshake>, "DoHandshake"},
{9, &ISslConnection::DoHandshakeGetServerCert, "DoHandshakeGetServerCert"}, {9, &ISslConnection::DoHandshakeGetServerCert, "DoHandshakeGetServerCert"},
{10, &ISslConnection::Read, "Read"}, {10, D<&ISslConnection::Read>, "Read"},
{11, &ISslConnection::Write, "Write"}, {11, D<&ISslConnection::Write>, "Write"},
{12, &ISslConnection::Pending, "Pending"}, {12, D<&ISslConnection::Pending>, "Pending"},
{13, nullptr, "Peek"}, {13, D<&ISslConnection::Peek>, "Peek"},
{14, nullptr, "Poll"}, {14, D<&ISslConnection::Poll>, "Poll"},
{15, nullptr, "GetVerifyCertError"}, {15, D<&ISslConnection::GetVerifyCertError>, "GetVerifyCertError"},
{16, nullptr, "GetNeededServerCertBufferSize"}, {16, D<&ISslConnection::GetNeededServerCertBufferSize>, "GetNeededServerCertBufferSize"},
{17, &ISslConnection::SetSessionCacheMode, "SetSessionCacheMode"}, {17, D<&ISslConnection::SetSessionCacheMode>, "SetSessionCacheMode"},
{18, nullptr, "GetSessionCacheMode"}, {18, D<&ISslConnection::GetSessionCacheMode>, "GetSessionCacheMode"},
{19, nullptr, "FlushSessionCache"}, {19, D<&ISslConnection::FlushSessionCache>, "FlushSessionCache"},
{20, nullptr, "SetRenegotiationMode"}, {20, D<&ISslConnection::SetRenegotiationMode>, "SetRenegotiationMode"},
{21, nullptr, "GetRenegotiationMode"}, {21, D<&ISslConnection::GetRenegotiationMode>, "GetRenegotiationMode"},
{22, &ISslConnection::SetOption, "SetOption"}, {22, D<&ISslConnection::SetOption>, "SetOption"},
{23, &ISslConnection::GetOption, "GetOption"}, {23, D<&ISslConnection::GetOption>, "GetOption"},
{24, nullptr, "GetVerifyCertErrors"}, {24, nullptr, "GetVerifyCertErrors"},
{25, nullptr, "GetCipherInfo"}, {25, nullptr, "GetCipherInfo"},
{26, &ISslConnection::SetNextAlpnProto, "SetNextAlpnProto"}, {26, D<&ISslConnection::SetNextAlpnProto>, "SetNextAlpnProto"},
{27, &ISslConnection::GetNextAlpnProto, "GetNextAlpnProto"}, {27, D<&ISslConnection::GetNextAlpnProto>, "GetNextAlpnProto"},
{28, nullptr, "SetDtlsSocketDescriptor"}, {28, nullptr, "SetDtlsSocketDescriptor"},
{29, nullptr, "GetDtlsHandshakeTimeout"}, {29, nullptr, "GetDtlsHandshakeTimeout"},
{30, nullptr, "SetPrivateOption"}, {30, nullptr, "SetPrivateOption"},
@@ -141,80 +147,6 @@ public:
} }
private: private:
SslVersion ssl_version;
std::shared_ptr<SslContextSharedData> shared_data;
std::unique_ptr<SSLConnectionBackend> backend;
std::optional<int> fd_to_close;
bool do_not_close_socket = false;
bool get_server_cert_chain = false;
bool skip_default_verify = false;
bool enable_alpn = false;
std::shared_ptr<Network::SocketBase> socket;
std::vector<u8> next_alpn_proto;
bool did_handshake = false;
u32 verify_option = 0;
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
ASSERT(!did_handshake);
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
auto const res_v = bsd->DuplicateSocketImpl(fd);
if (auto *res = std::get_if<s32>(&res_v)) {
const s32 duplicated_fd = *res;
if (do_not_close_socket) {
*out_fd = duplicated_fd;
} else {
*out_fd = -1;
fd_to_close = duplicated_fd;
}
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(duplicated_fd);
if (!sock.has_value()) {
LOG_ERROR(Service_SSL, "invalid socket fd {} after duplication", duplicated_fd);
return ResultInvalidSocket;
}
socket = std::move(*sock);
backend->SetSocket(socket);
return ResultSuccess;
}
LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", fd);
return ResultInvalidSocket;
}
Result SetHostNameImpl(const std::string& hostname) {
LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
ASSERT(!did_handshake);
return backend->SetHostName(hostname);
}
Result SetVerifyOptionImpl(u32 option) {
ASSERT(!did_handshake);
LOG_DEBUG(Service_SSL, "called. option={} (forcing 0)", option);
verify_option = 0;
backend->SetVerifyOption(0);
return ResultSuccess;
}
Result SetIoModeImpl(u32 input_mode) {
auto mode = static_cast<IoMode>(input_mode);
ASSERT(mode == IoMode::Blocking || mode == IoMode::NonBlocking);
ASSERT_OR_EXECUTE(socket, { return ResultNoSocket; });
const bool non_block = mode == IoMode::NonBlocking;
const Network::Errno error = socket->SetNonBlock(non_block);
if (error != Network::Errno::SUCCESS) {
LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
}
return ResultSuccess;
}
Result SetSessionCacheModeImpl(u32 mode) {
ASSERT(!did_handshake);
LOG_WARNING(Service_SSL, "(STUBBED) called. value={}", mode);
return ResultSuccess;
}
Result DoHandshakeImpl() { Result DoHandshakeImpl() {
ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; }); ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; });
Result res = backend->DoHandshake(); Result res = backend->DoHandshake();
@@ -234,19 +166,17 @@ private:
}; };
if (!get_server_cert_chain) { if (!get_server_cert_chain) {
// Just return the first one, unencoded. // Just return the first one, unencoded.
ASSERT_OR_EXECUTE_MSG( ASSERT_OR_EXECUTE_MSG(!certs.empty(), { return {}; }, "Should be at least one server cert");
!certs.empty(), { return {}; }, "Should be at least one server cert");
return certs[0]; return certs[0];
} }
std::vector<u8> ret; std::vector<u8> ret;
Header header{0x4E4D684374726543, static_cast<u32>(certs.size()), 0}; Header header{0x4E4D684374726543, u32(certs.size()), 0};
ret.insert(ret.end(), reinterpret_cast<u8*>(&header), reinterpret_cast<u8*>(&header + 1)); ret.insert(ret.end(), reinterpret_cast<u8*>(&header), reinterpret_cast<u8*>(&header + 1));
size_t data_offset = sizeof(Header) + certs.size() * sizeof(EntryHeader); size_t data_offset = sizeof(Header) + certs.size() * sizeof(EntryHeader);
for (auto& cert : certs) { for (auto& cert : certs) {
EntryHeader entry_header{static_cast<u32>(cert.size()), static_cast<u32>(data_offset)}; EntryHeader entry_header{u32(cert.size()), u32(data_offset)};
data_offset += cert.size(); data_offset += cert.size();
ret.insert(ret.end(), reinterpret_cast<u8*>(&entry_header), ret.insert(ret.end(), reinterpret_cast<u8*>(&entry_header), reinterpret_cast<u8*>(&entry_header + 1));
reinterpret_cast<u8*>(&entry_header + 1));
} }
for (auto& cert : certs) { for (auto& cert : certs) {
ret.insert(ret.end(), cert.begin(), cert.end()); ret.insert(ret.end(), cert.begin(), cert.end());
@@ -254,65 +184,77 @@ private:
return ret; return ret;
} }
Result ReadImpl(std::vector<u8>* out_data) { Result SetSocketDescriptor(s32 in_fd, Out<s32> out_fd) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; }); LOG_DEBUG(Service_SSL, "called, fd={}", in_fd);
size_t actual_size{}; ASSERT(!did_handshake);
Result res = backend->Read(&actual_size, *out_data); auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
if (res != ResultSuccess) { ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
return res;
auto const res_v = bsd->DuplicateSocketImpl(in_fd);
if (auto *res = std::get_if<s32>(&res_v)) {
const s32 dup_fd = *res;
*out_fd = do_not_close_socket ? dup_fd : -1;
if (!do_not_close_socket)
fd_to_close = dup_fd;
auto const sock = bsd->GetSocket(dup_fd);
if (!sock.has_value()) {
LOG_ERROR(Service_SSL, "invalid socket fd {} after duplication", dup_fd);
return ResultInvalidSocket;
}
socket = std::move(*sock);
backend->SetSocket(std::move(socket));
return ResultSuccess;
} }
out_data->resize(actual_size); LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", in_fd);
return res; return ResultInvalidSocket;
} }
Result WriteImpl(size_t* out_size, std::span<const u8> data) { Result SetHostName(InBuffer<BufferAttr_HipcMapAlias> buf) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; }); auto const hostname = Common::StringFromBuffer(buf);
return backend->Write(out_size, data); LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
ASSERT(!did_handshake);
return backend->SetHostName(hostname.c_str());
} }
Result PendingImpl(s32* out_pending) { Result SetVerifyOption(u32 option) {
LOG_WARNING(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "called. option={} (forcing 0)", option);
*out_pending = 0; ASSERT(!did_handshake);
return ResultSuccess; verify_option = 0;
backend->SetVerifyOption(0);
R_SUCCEED();
} }
void SetSocketDescriptor(HLERequestContext& ctx) { Result SetIoMode(u32 input_mode) {
IPC::RequestParser rp{ctx}; auto mode = IoMode(input_mode);
const s32 in_fd = rp.Pop<s32>(); ASSERT(mode == IoMode::Blocking || mode == IoMode::NonBlocking);
s32 out_fd{-1}; R_UNLESS(socket, ResultNoSocket);
const Result res = SetSocketDescriptorImpl(&out_fd, in_fd); const bool non_block = mode == IoMode::NonBlocking;
IPC::ResponseBuilder rb{ctx, 3}; const Network::Errno error = socket->SetNonBlock(non_block);
rb.Push(res); if (error != Network::Errno::SUCCESS) {
rb.Push<s32>(out_fd); LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
}
R_SUCCEED();
} }
void SetHostName(HLERequestContext& ctx) { Result GetSocketDescriptor(Out<u32> out_fd) {
const std::string hostname = Common::StringFromBuffer(ctx.ReadBuffer()); LOG_WARNING(Service_SSL, "(STUBBED)");
const Result res = SetHostNameImpl(hostname); *out_fd = socket->GetFD();
IPC::ResponseBuilder rb{ctx, 2}; R_SUCCEED();
rb.Push(res);
} }
void SetVerifyOption(HLERequestContext& ctx) { Result GetHostName(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
IPC::RequestParser rp{ctx}; LOG_WARNING(Service_SSL, "(STUBBED)");
const u32 option = rp.Pop<u32>(); ASSERT(!did_handshake);
const Result res = SetVerifyOptionImpl(option); return backend->GetHostName(std::span<u8>{data.begin(), data.end()}, out_size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
} }
void SetIoMode(HLERequestContext& ctx) { Result GetIoMode(Out<u32> out_mode) {
IPC::RequestParser rp{ctx}; LOG_WARNING(Service_SSL, "(STUBBED)");
const u32 mode = rp.Pop<u32>(); R_SUCCEED();
const Result res = SetIoModeImpl(mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
} }
void DoHandshake(HLERequestContext& ctx) { Result DoHandshake() {
const Result res = DoHandshakeImpl(); return DoHandshakeImpl();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
} }
void DoHandshakeGetServerCert(HLERequestContext& ctx) { void DoHandshakeGetServerCert(HLERequestContext& ctx) {
@@ -351,131 +293,158 @@ private:
rb.PushRaw(out); rb.PushRaw(out);
} }
void Read(HLERequestContext& ctx) { Result Read(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
std::vector<u8> output_bytes(ctx.GetWriteBufferSize()); R_UNLESS(did_handshake, ResultInternalError);
const Result res = ReadImpl(&output_bytes); size_t tmp{};
IPC::ResponseBuilder rb{ctx, 3}; auto const res = backend->Read(&tmp, data);
rb.Push(res); *out_size = u32(tmp);
if (res == ResultSuccess) { return res;
rb.Push(static_cast<u32>(output_bytes.size()));
ctx.WriteBuffer(output_bytes);
} else {
rb.Push(static_cast<u32>(0));
}
} }
void Write(HLERequestContext& ctx) { Result Write(InBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
size_t write_size{0}; R_UNLESS(did_handshake, ResultInternalError);
const Result res = WriteImpl(&write_size, ctx.ReadBuffer()); size_t tmp{};
IPC::ResponseBuilder rb{ctx, 3}; auto const res = backend->Write(&tmp, data);
rb.Push(res); *out_size = u32(tmp);
rb.Push(static_cast<u32>(write_size)); return res;
} }
void Pending(HLERequestContext& ctx) { Result Pending(Out<s32> out_pending_size) {
s32 pending_size{0}; LOG_WARNING(Service_SSL, "(STUBBED)");
const Result res = PendingImpl(&pending_size); *out_pending_size = s32(backend->Pending());
IPC::ResponseBuilder rb{ctx, 3}; R_SUCCEED();
rb.Push(res);
rb.Push<s32>(pending_size);
} }
void SetSessionCacheMode(HLERequestContext& ctx) { Result Peek(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
IPC::RequestParser rp{ctx}; LOG_WARNING(Service_SSL, "(STUBBED)");
const u32 mode = rp.Pop<u32>(); size_t tmp{};
const Result res = SetSessionCacheModeImpl(mode); auto const res = backend->Peek(&tmp, data);
IPC::ResponseBuilder rb{ctx, 2}; *out_size = u32(tmp);
rb.Push(res); return res;
} }
void SetOption(HLERequestContext& ctx) { Result Poll(u32 in_pollevent, u32 timer, Out<u32> out_pollevent) {
struct Parameters { LOG_WARNING(Service_SSL, "(STUBBED)");
OptionType option; R_SUCCEED();
s32 value;
};
static_assert(sizeof(Parameters) == 0x8, "Parameters is an invalid size");
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
switch (parameters.option) {
case OptionType::DoNotCloseSocket:
do_not_close_socket = static_cast<bool>(parameters.value);
break;
case OptionType::GetServerCertChain:
get_server_cert_chain = static_cast<bool>(parameters.value);
break;
case OptionType::SkipDefaultVerify:
skip_default_verify = static_cast<bool>(parameters.value);
break;
case OptionType::EnableAlpn:
enable_alpn = static_cast<bool>(parameters.value);
break;
default:
LOG_WARNING(Service_SSL, "Unknown option={}, value={}", parameters.option,
parameters.value);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
} }
void GetOption(HLERequestContext& ctx) { Result GetVerifyCertError() {
IPC::RequestParser rp{ctx}; LOG_WARNING(Service_SSL, "(STUBBED)");
const auto option = rp.PopRaw<OptionType>(); R_SUCCEED();
}
u8 value = 0; Result GetNeededServerCertBufferSize(Out<u32> out_needed_buffer_size) {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_SUCCEED();
}
Result SetSessionCacheMode(u32 mode) {
LOG_WARNING(Service_SSL, "(STUBBED) called. value={}", mode);
R_UNLESS(!did_handshake, ResultInternalError);
R_SUCCEED();
}
Result GetSessionCacheMode(Out<u32> mode) {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_UNLESS(!did_handshake, ResultInternalError);
R_SUCCEED();
}
Result FlushSessionCache() {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_UNLESS(!did_handshake, ResultInternalError);
R_SUCCEED();
}
Result SetRenegotiationMode(RenegotiationMode mode) {
LOG_WARNING(Service_SSL, "(STUBBED)");
backend->SetRenegotiationMode(u32(mode));
R_SUCCEED();
}
Result GetRenegotiationMode(Out<RenegotiationMode> mode) {
LOG_WARNING(Service_SSL, "(STUBBED)");
u32 tmp{};
auto const res = backend->GetRenegotiationMode(&tmp);
*mode = RenegotiationMode(tmp);
return res;
}
Result SetOption(OptionType option, s32 value) {
switch (option) { switch (option) {
case OptionType::DoNotCloseSocket: case OptionType::DoNotCloseSocket:
value = static_cast<u8>(do_not_close_socket); do_not_close_socket = bool(value);
break; break;
case OptionType::GetServerCertChain: case OptionType::GetServerCertChain:
value = static_cast<u8>(get_server_cert_chain); get_server_cert_chain = bool(value);
break; break;
case OptionType::SkipDefaultVerify: case OptionType::SkipDefaultVerify:
value = static_cast<u8>(skip_default_verify); skip_default_verify = bool(value);
break; break;
case OptionType::EnableAlpn: case OptionType::EnableAlpn:
value = static_cast<u8>(enable_alpn); enable_alpn = bool(value);
break; break;
default: default:
LOG_WARNING(Service_SSL, "Unknown option={}", option); LOG_WARNING(Service_SSL, "Unknown option={}, value={}", option, value);
value = 0; }
R_SUCCEED();
}
Result GetOption(OptionType option, Out<u8> value) {
switch (option) {
case OptionType::DoNotCloseSocket:
*value = u8(do_not_close_socket);
break;
case OptionType::GetServerCertChain:
*value = u8(get_server_cert_chain);
break;
case OptionType::SkipDefaultVerify:
*value = u8(skip_default_verify);
break;
case OptionType::EnableAlpn:
*value = u8(enable_alpn);
break;
default:
LOG_WARNING(Service_SSL, "Unknown option={}", u32(option));
*value = 0;
break; break;
} }
LOG_DEBUG(Service_SSL, "GetOption called, option={}, ret value={}", u32(option), *value);
LOG_DEBUG(Service_SSL, "GetOption called, option={}, ret value={}", option, value); R_SUCCEED();
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(value);
} }
void SetNextAlpnProto(HLERequestContext& ctx) { Result SetNextAlpnProto(InBuffer<BufferAttr_HipcMapAlias> data) {
const auto data = ctx.ReadBuffer(0); auto const to_write = u32((std::min)(next_alpn_proto.size(), data.size()));
next_alpn_proto.assign(data.begin(), data.end()); next_alpn_proto.assign(data.begin(), data.begin() + to_write);
LOG_DEBUG(Service_SSL, "SetNextAlpnProto called, size={}", next_alpn_proto.size()); LOG_DEBUG(Service_SSL, "SetNextAlpnProto called, size={}", next_alpn_proto.size());
R_SUCCEED();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
} }
void GetNextAlpnProto(HLERequestContext& ctx) { Result GetNextAlpnProto(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> to_write) {
const size_t writable = ctx.GetWriteBufferSize(); *to_write = u32((std::min)(next_alpn_proto.size(), data.size()));
const size_t to_write = (std::min)(next_alpn_proto.size(), writable); next_alpn_proto.assign(data.begin(), data.begin() + *to_write);
LOG_DEBUG(Service_SSL, "GetNextAlpnProto called, size={}", *to_write);
if (to_write != 0) { R_SUCCEED();
ctx.WriteBuffer(std::span<const u8>(next_alpn_proto.data(), to_write));
}
LOG_DEBUG(Service_SSL, "GetNextAlpnProto called, size={}", to_write);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(to_write));
} }
Result GetVerifyCertErrors(OutBuffer<BufferAttr_HipcMapAlias> unk0, Out<u32> unk1, Out<u32> unk2) {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_SUCCEED();
}
SslVersion ssl_version;
std::shared_ptr<SslContextSharedData> shared_data;
std::unique_ptr<SSLConnectionBackend> backend;
std::optional<int> fd_to_close;
std::shared_ptr<Network::SocketBase> socket;
std::vector<u8> next_alpn_proto;
u32 verify_option = 0;
bool do_not_close_socket = false;
bool get_server_cert_chain = false;
bool skip_default_verify = false;
bool enable_alpn = false;
bool did_handshake = false;
}; };
class ISslContext final : public ServiceFramework<ISslContext> { class ISslContext final : public ServiceFramework<ISslContext> {
@@ -492,7 +461,7 @@ public:
{5, &ISslContext::ImportClientPki, "ImportClientPki"}, {5, &ISslContext::ImportClientPki, "ImportClientPki"},
{6, nullptr, "RemoveServerPki"}, {6, nullptr, "RemoveServerPki"},
{7, nullptr, "RemoveClientPki"}, {7, nullptr, "RemoveClientPki"},
{8, nullptr, "RegisterInternalPki"}, {8, D<&ISslContext::RegisterInternalPki>, "RegisterInternalPki"},
{9, nullptr, "AddPolicyOid"}, {9, nullptr, "AddPolicyOid"},
{10, nullptr, "ImportCrl"}, {10, nullptr, "ImportCrl"},
{11, nullptr, "RemoveCrl"}, {11, nullptr, "RemoveCrl"},
@@ -587,6 +556,11 @@ private:
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push(client_id); rb.Push(client_id);
} }
Result RegisterInternalPki() {
LOG_WARNING(Service_SSL, "(STUBBED) called");
R_SUCCEED();
}
}; };
class ISslService final : public ServiceFramework<ISslService> { class ISslService final : public ServiceFramework<ISslService> {
+6 -1
View File
@@ -36,12 +36,17 @@ class SSLConnectionBackend {
public: public:
virtual ~SSLConnectionBackend() {} virtual ~SSLConnectionBackend() {}
virtual void SetSocket(std::shared_ptr<Network::SocketBase> socket) = 0; virtual void SetSocket(std::shared_ptr<Network::SocketBase> socket) = 0;
virtual Result SetHostName(const std::string& hostname) = 0;
virtual void SetVerifyOption(u32 option) = 0; virtual void SetVerifyOption(u32 option) = 0;
virtual Result DoHandshake() = 0; virtual Result DoHandshake() = 0;
virtual Result Read(size_t* out_size, std::span<u8> data) = 0; virtual Result Read(size_t* out_size, std::span<u8> data) = 0;
virtual Result Peek(size_t* out_size, std::span<u8> data) = 0;
virtual Result Write(size_t* out_size, std::span<const u8> data) = 0; virtual Result Write(size_t* out_size, std::span<const u8> data) = 0;
virtual Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) = 0; virtual Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) = 0;
virtual Result SetHostName(const char* hostname) = 0;
virtual Result GetHostName(std::span<u8> hostname, u32* out_size) = 0;
virtual int Pending() = 0;
virtual Result SetRenegotiationMode(u32 mode) = 0;
virtual Result GetRenegotiationMode(u32* mode) = 0;
}; };
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend); Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend);
@@ -157,18 +157,30 @@ public:
socket = std::move(socket_in); socket = std::move(socket_in);
} }
Result SetHostName(const std::string& hostname) override { Result SetHostName(const char* hostname) override {
if (!skip_cert_verification) { if (!skip_cert_verification) {
if (!SSL_set1_host(ssl, hostname.c_str())) { if (!SSL_set1_host(ssl, hostname)) {
LOG_ERROR(Service_SSL, "SSL_set1_host({}) failed", hostname); LOG_ERROR(Service_SSL, "SSL_set1_host({}) failed", hostname);
return CheckOpenSSLErrors(); return CheckOpenSSLErrors();
} }
} }
if (!SSL_set_tlsext_host_name(ssl, hostname.c_str())) { // hostname for SNI if (!SSL_set_tlsext_host_name(ssl, hostname)) { // hostname for SNI
LOG_ERROR(Service_SSL, "SSL_set_tlsext_host_name({}) failed", hostname); LOG_ERROR(Service_SSL, "SSL_set_tlsext_host_name({}) failed", hostname);
return CheckOpenSSLErrors(); return CheckOpenSSLErrors();
} }
return ResultSuccess; R_SUCCEED();
}
Result GetHostName(std::span<u8> data, u32* out_size) override {
auto const peer_name = SSL_get0_peername(ssl);
if (peer_name == nullptr) {
LOG_ERROR(Service_SSL, "SSL_get0_peername()");
return CheckOpenSSLErrors();
}
auto const s = std::string{peer_name};
*out_size = u32(s.size());
std::memcpy(data.data(), s.data(), (std::min)(s.size(), data.size()));
R_SUCCEED();
} }
void SetVerifyOption(u32 option) override { void SetVerifyOption(u32 option) override {
@@ -213,6 +225,13 @@ public:
return HandleReturn("SSL_read_ex", out_size, ret); return HandleReturn("SSL_read_ex", out_size, ret);
} }
Result Peek(size_t* out_size, std::span<u8> data) override {
auto const n = (std::min)(data.size(), *out_size);
const int ret = SSL_peek(ssl, data.data(), int(n));
*out_size = n;
return HandleReturn("SSL_write_ex", out_size, ret);
}
Result Write(size_t* out_size, std::span<const u8> data) override { Result Write(size_t* out_size, std::span<const u8> data) override {
const int ret = SSL_write_ex(ssl, data.data(), data.size(), out_size); const int ret = SSL_write_ex(ssl, data.data(), data.size(), out_size);
return HandleReturn("SSL_write_ex", out_size, ret); return HandleReturn("SSL_write_ex", out_size, ret);
@@ -263,7 +282,25 @@ public:
out_certs->emplace_back(buf, buf + len); out_certs->emplace_back(buf, buf + len);
OPENSSL_free(buf); OPENSSL_free(buf);
} }
return ResultSuccess; R_SUCCEED();
}
int Pending() override {
return SSL_pending(ssl);
}
Result SetRenegotiationMode(u32 mode) override {
if (mode == 0) {
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_RENEGOTIATION);
} else {
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALLOW_CLIENT_RENEGOTIATION);
}
R_SUCCEED();
}
Result GetRenegotiationMode(u32* mode) override {
*mode = SSL_get_secure_renegotiation_support(ssl) ? 1 : 0;
R_SUCCEED();
} }
~SSLConnectionBackendOpenSSL() { ~SSLConnectionBackendOpenSSL() {