mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-27 03:12:02 +00:00
[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:
+218
-244
@@ -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> {
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user