From a504069938ea47a3288ce15f540f9e0d96dbd8e5 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 14 Sep 2026 17:06:28 +0000 Subject: [PATCH] 2026-09-14 17:06:28 Signed-off-by: lizzie --- src/core/hle/service/ssl/ssl.cpp | 449 ++++++++---------- src/core/hle/service/ssl/ssl_backend.h | 7 +- .../hle/service/ssl/ssl_backend_openssl.cpp | 47 +- 3 files changed, 257 insertions(+), 246 deletions(-) diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index 750a7de236..494f1121c9 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp @@ -48,6 +48,12 @@ enum class OptionType : u32 { EnableAlpn = 3, }; +// This is nn::ssl::sf::RenegotiationMode +enum RenegotiationMode : u32 { + None = 0, ///< None + Secure = 1, ///< Secure +}; + // This is nn::ssl::sf::SslVersion struct SslVersion { union { @@ -75,34 +81,34 @@ public: shared_data{shared_data_in}, backend{std::move(backend_in)} { // clang-format off static const FunctionInfo functions[] = { - {0, &ISslConnection::SetSocketDescriptor, "SetSocketDescriptor"}, - {1, &ISslConnection::SetHostName, "SetHostName"}, - {2, &ISslConnection::SetVerifyOption, "SetVerifyOption"}, - {3, &ISslConnection::SetIoMode, "SetIoMode"}, - {4, nullptr, "GetSocketDescriptor"}, - {5, nullptr, "GetHostName"}, + {0, D<&ISslConnection::SetSocketDescriptor>, "SetSocketDescriptor"}, + {1, D<&ISslConnection::SetHostName>, "SetHostName"}, + {2, D<&ISslConnection::SetVerifyOption>, "SetVerifyOption"}, + {3, D<&ISslConnection::SetIoMode>, "SetIoMode"}, + {4, D<&ISslConnection::GetSocketDescriptor>, "GetSocketDescriptor"}, + {5, D<&ISslConnection::GetHostName>, "GetHostName"}, {6, nullptr, "GetVerifyOption"}, - {7, nullptr, "GetIoMode"}, - {8, &ISslConnection::DoHandshake, "DoHandshake"}, + {7, D<&ISslConnection::GetIoMode>, "GetIoMode"}, + {8, D<&ISslConnection::DoHandshake>, "DoHandshake"}, {9, &ISslConnection::DoHandshakeGetServerCert, "DoHandshakeGetServerCert"}, - {10, &ISslConnection::Read, "Read"}, - {11, &ISslConnection::Write, "Write"}, - {12, &ISslConnection::Pending, "Pending"}, - {13, nullptr, "Peek"}, - {14, nullptr, "Poll"}, - {15, nullptr, "GetVerifyCertError"}, - {16, nullptr, "GetNeededServerCertBufferSize"}, - {17, &ISslConnection::SetSessionCacheMode, "SetSessionCacheMode"}, - {18, nullptr, "GetSessionCacheMode"}, - {19, nullptr, "FlushSessionCache"}, - {20, nullptr, "SetRenegotiationMode"}, - {21, nullptr, "GetRenegotiationMode"}, - {22, &ISslConnection::SetOption, "SetOption"}, - {23, &ISslConnection::GetOption, "GetOption"}, + {10, D<&ISslConnection::Read>, "Read"}, + {11, D<&ISslConnection::Write>, "Write"}, + {12, D<&ISslConnection::Pending>, "Pending"}, + {13, D<&ISslConnection::Peek>, "Peek"}, + {14, D<&ISslConnection::Poll>, "Poll"}, + {15, D<&ISslConnection::GetVerifyCertError>, "GetVerifyCertError"}, + {16, D<&ISslConnection::GetNeededServerCertBufferSize>, "GetNeededServerCertBufferSize"}, + {17, D<&ISslConnection::SetSessionCacheMode>, "SetSessionCacheMode"}, + {18, D<&ISslConnection::GetSessionCacheMode>, "GetSessionCacheMode"}, + {19, D<&ISslConnection::FlushSessionCache>, "FlushSessionCache"}, + {20, D<&ISslConnection::SetRenegotiationMode>, "SetRenegotiationMode"}, + {21, D<&ISslConnection::GetRenegotiationMode>, "GetRenegotiationMode"}, + {22, D<&ISslConnection::SetOption>, "SetOption"}, + {23, D<&ISslConnection::GetOption>, "GetOption"}, {24, nullptr, "GetVerifyCertErrors"}, {25, nullptr, "GetCipherInfo"}, - {26, &ISslConnection::SetNextAlpnProto, "SetNextAlpnProto"}, - {27, &ISslConnection::GetNextAlpnProto, "GetNextAlpnProto"}, + {26, D<&ISslConnection::SetNextAlpnProto>, "SetNextAlpnProto"}, + {27, D<&ISslConnection::GetNextAlpnProto>, "GetNextAlpnProto"}, {28, nullptr, "SetDtlsSocketDescriptor"}, {29, nullptr, "GetDtlsHandshakeTimeout"}, {30, nullptr, "SetPrivateOption"}, @@ -141,80 +147,6 @@ public: } private: - SslVersion ssl_version; - std::shared_ptr shared_data; - std::unique_ptr backend; - std::optional 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 socket; - std::vector 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("bsd:u"); - ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; }); - - auto const res_v = bsd->DuplicateSocketImpl(fd); - if (auto *res = std::get_if(&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> 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(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() { ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; }); Result res = backend->DoHandshake(); @@ -234,19 +166,17 @@ private: }; if (!get_server_cert_chain) { // Just return the first one, unencoded. - ASSERT_OR_EXECUTE_MSG( - !certs.empty(), { return {}; }, "Should be at least one server cert"); + ASSERT_OR_EXECUTE_MSG(!certs.empty(), { return {}; }, "Should be at least one server cert"); return certs[0]; } std::vector ret; - Header header{0x4E4D684374726543, static_cast(certs.size()), 0}; + Header header{0x4E4D684374726543, u32(certs.size()), 0}; ret.insert(ret.end(), reinterpret_cast(&header), reinterpret_cast(&header + 1)); size_t data_offset = sizeof(Header) + certs.size() * sizeof(EntryHeader); for (auto& cert : certs) { - EntryHeader entry_header{static_cast(cert.size()), static_cast(data_offset)}; + EntryHeader entry_header{u32(cert.size()), u32(data_offset)}; data_offset += cert.size(); - ret.insert(ret.end(), reinterpret_cast(&entry_header), - reinterpret_cast(&entry_header + 1)); + ret.insert(ret.end(), reinterpret_cast(&entry_header), reinterpret_cast(&entry_header + 1)); } for (auto& cert : certs) { ret.insert(ret.end(), cert.begin(), cert.end()); @@ -254,65 +184,77 @@ private: return ret; } - Result ReadImpl(std::vector* out_data) { - ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; }); - size_t actual_size{}; - Result res = backend->Read(&actual_size, *out_data); - if (res != ResultSuccess) { - return res; + Result SetSocketDescriptor(s32 in_fd, Out out_fd) { + LOG_DEBUG(Service_SSL, "called, fd={}", in_fd); + ASSERT(!did_handshake); + auto bsd = system.ServiceManager().GetService("bsd:u"); + ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; }); + + auto const res_v = bsd->DuplicateSocketImpl(in_fd); + if (auto *res = std::get_if(&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); - return res; + LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", in_fd); + return ResultInvalidSocket; } - Result WriteImpl(size_t* out_size, std::span data) { - ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; }); - return backend->Write(out_size, data); + Result SetHostName(InBuffer buf) { + auto const hostname = Common::StringFromBuffer(buf); + LOG_DEBUG(Service_SSL, "called. hostname={}", hostname); + ASSERT(!did_handshake); + return backend->SetHostName(hostname.c_str()); } - Result PendingImpl(s32* out_pending) { - LOG_WARNING(Service_SSL, "(STUBBED) called."); - *out_pending = 0; - return ResultSuccess; + Result SetVerifyOption(u32 option) { + LOG_DEBUG(Service_SSL, "called. option={} (forcing 0)", option); + ASSERT(!did_handshake); + verify_option = 0; + backend->SetVerifyOption(0); + R_SUCCEED(); } - void SetSocketDescriptor(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const s32 in_fd = rp.Pop(); - s32 out_fd{-1}; - const Result res = SetSocketDescriptorImpl(&out_fd, in_fd); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(res); - rb.Push(out_fd); + Result SetIoMode(u32 input_mode) { + auto mode = IoMode(input_mode); + ASSERT(mode == IoMode::Blocking || mode == IoMode::NonBlocking); + R_UNLESS(socket, 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); + } + R_SUCCEED(); } - void SetHostName(HLERequestContext& ctx) { - const std::string hostname = Common::StringFromBuffer(ctx.ReadBuffer()); - const Result res = SetHostNameImpl(hostname); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); + Result GetSocketDescriptor(Out out_fd) { + LOG_WARNING(Service_SSL, "(STUBBED)"); + *out_fd = socket->GetFD(); + R_SUCCEED(); } - void SetVerifyOption(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u32 option = rp.Pop(); - const Result res = SetVerifyOptionImpl(option); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); + Result GetHostName(OutBuffer data, Out out_size) { + LOG_WARNING(Service_SSL, "(STUBBED)"); + ASSERT(!did_handshake); + return backend->GetHostName(std::span{data.begin(), data.end()}, out_size); } - void SetIoMode(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u32 mode = rp.Pop(); - const Result res = SetIoModeImpl(mode); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); + Result GetIoMode(Out out_mode) { + LOG_WARNING(Service_SSL, "(STUBBED)"); + R_SUCCEED(); } - void DoHandshake(HLERequestContext& ctx) { - const Result res = DoHandshakeImpl(); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); + Result DoHandshake() { + return DoHandshakeImpl(); } void DoHandshakeGetServerCert(HLERequestContext& ctx) { @@ -351,131 +293,158 @@ private: rb.PushRaw(out); } - void Read(HLERequestContext& ctx) { - std::vector output_bytes(ctx.GetWriteBufferSize()); - const Result res = ReadImpl(&output_bytes); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(res); - if (res == ResultSuccess) { - rb.Push(static_cast(output_bytes.size())); - ctx.WriteBuffer(output_bytes); - } else { - rb.Push(static_cast(0)); - } + Result Read(OutBuffer data, Out out_size) { + R_UNLESS(did_handshake, ResultInternalError); + size_t tmp{}; + auto const res = backend->Read(&tmp, data); + *out_size = u32(tmp); + return res; } - void Write(HLERequestContext& ctx) { - size_t write_size{0}; - const Result res = WriteImpl(&write_size, ctx.ReadBuffer()); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(res); - rb.Push(static_cast(write_size)); + Result Write(InBuffer data, Out out_size) { + R_UNLESS(did_handshake, ResultInternalError); + size_t tmp{}; + auto const res = backend->Write(&tmp, data); + *out_size = u32(tmp); + return res; } - void Pending(HLERequestContext& ctx) { - s32 pending_size{0}; - const Result res = PendingImpl(&pending_size); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(res); - rb.Push(pending_size); + Result Pending(Out out_pending_size) { + LOG_WARNING(Service_SSL, "(STUBBED)"); + *out_pending_size = s32(backend->Pending()); + R_SUCCEED(); } - void SetSessionCacheMode(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u32 mode = rp.Pop(); - const Result res = SetSessionCacheModeImpl(mode); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); + Result Peek(OutBuffer data, Out out_size) { + LOG_WARNING(Service_SSL, "(STUBBED)"); + size_t tmp{}; + auto const res = backend->Peek(&tmp, data); + *out_size = u32(tmp); + return res; } - void SetOption(HLERequestContext& ctx) { - struct Parameters { - OptionType option; - s32 value; - }; - static_assert(sizeof(Parameters) == 0x8, "Parameters is an invalid size"); - - IPC::RequestParser rp{ctx}; - const auto parameters = rp.PopRaw(); - - switch (parameters.option) { - case OptionType::DoNotCloseSocket: - do_not_close_socket = static_cast(parameters.value); - break; - case OptionType::GetServerCertChain: - get_server_cert_chain = static_cast(parameters.value); - break; - case OptionType::SkipDefaultVerify: - skip_default_verify = static_cast(parameters.value); - break; - case OptionType::EnableAlpn: - enable_alpn = static_cast(parameters.value); - break; - default: - LOG_WARNING(Service_SSL, "Unknown option={}, value={}", parameters.option, - parameters.value); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + Result Poll(u32 in_pollevent, u32 timer, Out out_pollevent) { + LOG_WARNING(Service_SSL, "(STUBBED)"); + R_SUCCEED(); } - void GetOption(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto option = rp.PopRaw(); + Result GetVerifyCertError() { + LOG_WARNING(Service_SSL, "(STUBBED)"); + R_SUCCEED(); + } - u8 value = 0; + Result GetNeededServerCertBufferSize(Out 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 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 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) { case OptionType::DoNotCloseSocket: - value = static_cast(do_not_close_socket); + do_not_close_socket = bool(value); break; case OptionType::GetServerCertChain: - value = static_cast(get_server_cert_chain); + get_server_cert_chain = bool(value); break; case OptionType::SkipDefaultVerify: - value = static_cast(skip_default_verify); + skip_default_verify = bool(value); break; case OptionType::EnableAlpn: - value = static_cast(enable_alpn); + enable_alpn = bool(value); + break; + default: + LOG_WARNING(Service_SSL, "Unknown option={}, value={}", option, value); + } + R_SUCCEED(); + } + + Result GetOption(OptionType option, Out 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={}", option); - value = 0; + *value = 0; break; } - LOG_DEBUG(Service_SSL, "GetOption called, option={}, ret value={}", option, value); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(value); + R_SUCCEED(); } - void SetNextAlpnProto(HLERequestContext& ctx) { - const auto data = ctx.ReadBuffer(0); - next_alpn_proto.assign(data.begin(), data.end()); - + Result SetNextAlpnProto(InBuffer data) { + auto const to_write = u32((std::min)(next_alpn_proto.size(), data.size())); + next_alpn_proto.assign(data.begin(), data.begin() + to_write); LOG_DEBUG(Service_SSL, "SetNextAlpnProto called, size={}", next_alpn_proto.size()); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + R_SUCCEED(); } - void GetNextAlpnProto(HLERequestContext& ctx) { - const size_t writable = ctx.GetWriteBufferSize(); - const size_t to_write = (std::min)(next_alpn_proto.size(), writable); - - if (to_write != 0) { - ctx.WriteBuffer(std::span(next_alpn_proto.data(), to_write)); - } - + Result GetNextAlpnProto(OutBuffer data, Out to_write) { + *to_write = u32((std::min)(next_alpn_proto.size(), data.size())); + next_alpn_proto.assign(data.begin(), data.begin() + *to_write); LOG_DEBUG(Service_SSL, "GetNextAlpnProto called, size={}", to_write); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast(to_write)); + R_SUCCEED(); } + + Result GetVerifyCertErrors(OutBuffer unk0, Out unk1, Out unk2) { + LOG_WARNING(Service_SSL, "(STUBBED)"); + R_SUCCEED(); + } + + SslVersion ssl_version; + std::shared_ptr shared_data; + std::unique_ptr backend; + std::optional fd_to_close; + std::shared_ptr socket; + std::vector 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 { diff --git a/src/core/hle/service/ssl/ssl_backend.h b/src/core/hle/service/ssl/ssl_backend.h index a3127342a2..ef6bf8f9de 100644 --- a/src/core/hle/service/ssl/ssl_backend.h +++ b/src/core/hle/service/ssl/ssl_backend.h @@ -36,12 +36,17 @@ class SSLConnectionBackend { public: virtual ~SSLConnectionBackend() {} virtual void SetSocket(std::shared_ptr socket) = 0; - virtual Result SetHostName(const std::string& hostname) = 0; virtual void SetVerifyOption(u32 option) = 0; virtual Result DoHandshake() = 0; virtual Result Read(size_t* out_size, std::span data) = 0; + virtual Result Peek(size_t* out_size, std::span data) = 0; virtual Result Write(size_t* out_size, std::span data) = 0; virtual Result GetServerCerts(std::vector>* out_certs) = 0; + virtual Result SetHostName(const char* hostname) = 0; + virtual Result GetHostName(std::span 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* out_backend); diff --git a/src/core/hle/service/ssl/ssl_backend_openssl.cpp b/src/core/hle/service/ssl/ssl_backend_openssl.cpp index f0e05266ba..435ada845d 100644 --- a/src/core/hle/service/ssl/ssl_backend_openssl.cpp +++ b/src/core/hle/service/ssl/ssl_backend_openssl.cpp @@ -157,18 +157,30 @@ public: socket = std::move(socket_in); } - Result SetHostName(const std::string& hostname) override { + Result SetHostName(const char* hostname) override { 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); 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); return CheckOpenSSLErrors(); } - return ResultSuccess; + R_SUCCEED(); + } + + Result GetHostName(std::span 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 { @@ -213,6 +225,13 @@ public: return HandleReturn("SSL_read_ex", out_size, ret); } + Result Peek(size_t* out_size, std::span 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 data) override { const int ret = SSL_write_ex(ssl, data.data(), data.size(), out_size); return HandleReturn("SSL_write_ex", out_size, ret); @@ -263,7 +282,25 @@ public: out_certs->emplace_back(buf, buf + len); 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() {