2020-04-21 01:57:23 +04:30
|
|
|
/*
|
2021-04-23 00:43:01 +04:30
|
|
|
* Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
|
2020-04-21 01:57:23 +04:30
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-04-21 01:57:23 +04:30
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <LibTLS/TLSv12.h>
|
2021-03-12 17:29:37 +01:00
|
|
|
#include <errno.h>
|
2024-07-01 17:11:35 +02:00
|
|
|
#include <wolfssl/options.h>
|
|
|
|
|
#include <wolfssl/ssl.h>
|
2020-04-21 01:57:23 +04:30
|
|
|
|
2020-05-29 22:22:01 +02:00
|
|
|
#ifndef SOCK_NONBLOCK
|
|
|
|
|
# include <sys/ioctl.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
static Vector<ByteString> s_certificate_store_paths;
|
2023-03-21 18:48:05 +01:00
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
namespace TLS {
|
2023-03-21 18:48:05 +01:00
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
static thread_local bool g_initialized_wolfssl = false;
|
|
|
|
|
|
|
|
|
|
static int errno_to_wolfssl_error(int error)
|
|
|
|
|
{
|
|
|
|
|
switch (error) {
|
|
|
|
|
case EAGAIN:
|
|
|
|
|
return WOLFSSL_CBIO_ERR_WANT_READ;
|
|
|
|
|
case ETIMEDOUT:
|
|
|
|
|
return WOLFSSL_CBIO_ERR_TIMEOUT;
|
|
|
|
|
case ECONNRESET:
|
|
|
|
|
return WOLFSSL_CBIO_ERR_CONN_RST;
|
|
|
|
|
case EINTR:
|
|
|
|
|
return WOLFSSL_CBIO_ERR_ISR;
|
|
|
|
|
case ECONNREFUSED:
|
|
|
|
|
return WOLFSSL_CBIO_ERR_WANT_READ;
|
|
|
|
|
case ECONNABORTED:
|
|
|
|
|
return WOLFSSL_CBIO_ERR_CONN_CLOSE;
|
2020-05-05 13:24:00 +04:30
|
|
|
default:
|
2024-07-01 17:11:35 +02:00
|
|
|
return WOLFSSL_CBIO_ERR_GENERAL;
|
2020-05-05 13:24:00 +04:30
|
|
|
}
|
|
|
|
|
}
|
2020-05-18 20:16:52 +02:00
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
StringView WolfTLS::error_text(WOLFSSL* ssl, int error_code)
|
2020-10-30 11:56:31 +03:30
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
auto error = wolfSSL_get_error(ssl, error_code);
|
|
|
|
|
static char buffer[WOLFSSL_MAX_ERROR_SZ];
|
|
|
|
|
auto* ptr = wolfSSL_ERR_error_string(error, buffer);
|
|
|
|
|
return StringView { ptr, strlen(ptr) };
|
2020-10-30 11:56:31 +03:30
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
ErrorOr<NonnullOwnPtr<WolfTLS>> WolfTLS::connect(const AK::ByteString& host, u16 port)
|
2022-03-15 19:16:44 +01:00
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
if (!g_initialized_wolfssl) {
|
|
|
|
|
wolfSSL_Init();
|
|
|
|
|
g_initialized_wolfssl = true;
|
2022-02-22 16:04:07 +01:00
|
|
|
}
|
2022-03-15 19:16:44 +01:00
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
auto* context = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
|
|
|
|
|
if (!context)
|
|
|
|
|
return Error::from_string_literal("Failed to create a new TLS context");
|
2022-03-15 19:16:44 +01:00
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
if (s_certificate_store_paths.is_empty())
|
|
|
|
|
s_certificate_store_paths.append("/etc/ssl/cert.pem"); // We're just guessing this, the embedder should provide this.
|
2021-02-07 07:21:32 +03:30
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
for (auto& path : s_certificate_store_paths) {
|
|
|
|
|
if (wolfSSL_CTX_load_verify_locations(context, path.characters(), nullptr) != SSL_SUCCESS)
|
|
|
|
|
return Error::from_string_literal("Failed to load CA certificates");
|
2020-10-30 11:56:31 +03:30
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
auto ssl = wolfSSL_new(context);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
return Error::from_string_literal("Failed to create a new SSL object");
|
2020-10-30 11:56:31 +03:30
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
wolfSSL_SSLSetIOSend(ssl, [](WOLFSSL*, char* buf, int sz, void* ctx) -> int {
|
|
|
|
|
auto& self = *static_cast<WolfTLS*>(ctx);
|
|
|
|
|
auto result = self.m_underlying->write_some({ buf, static_cast<size_t>(sz) });
|
|
|
|
|
if (result.is_error() && result.error().is_errno())
|
|
|
|
|
return errno_to_wolfssl_error(result.error().code());
|
|
|
|
|
if (result.is_error())
|
|
|
|
|
return -1;
|
|
|
|
|
return static_cast<int>(result.value());
|
|
|
|
|
});
|
|
|
|
|
wolfSSL_SSLSetIORecv(ssl, [](WOLFSSL*, char* buf, int sz, void* ctx) -> int {
|
|
|
|
|
auto& self = *static_cast<WolfTLS*>(ctx);
|
|
|
|
|
auto result = self.m_underlying->read_some({ buf, static_cast<size_t>(sz) });
|
|
|
|
|
if (result.is_error() && result.error().is_errno())
|
|
|
|
|
return errno_to_wolfssl_error(result.error().code());
|
|
|
|
|
if (result.is_error())
|
|
|
|
|
return -1;
|
|
|
|
|
return static_cast<int>(result.value().size());
|
|
|
|
|
});
|
2022-02-21 22:25:34 +01:00
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
auto tcp_socket = TRY(Core::TCPSocket::connect(host, port));
|
2022-02-21 22:25:34 +01:00
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
auto object = make<WolfTLS>(context, ssl, move(tcp_socket));
|
|
|
|
|
wolfSSL_SetIOReadCtx(ssl, static_cast<void*>(object.ptr()));
|
|
|
|
|
wolfSSL_SetIOWriteCtx(ssl, static_cast<void*>(object.ptr()));
|
2022-02-21 22:25:34 +01:00
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
if (wolfSSL_CTX_UseSNI(context, WOLFSSL_SNI_HOST_NAME, host.bytes().data(), host.bytes().size()) != WOLFSSL_SUCCESS)
|
|
|
|
|
return Error::from_string_literal("Failed to set SNI hostname");
|
2022-02-21 22:25:34 +01:00
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
if (auto rc = wolfSSL_connect(ssl); rc != SSL_SUCCESS)
|
|
|
|
|
return Error::from_string_view(error_text(ssl, rc));
|
2022-02-23 17:35:05 +01:00
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
return object;
|
2022-02-21 22:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
WolfTLS::~WolfTLS()
|
2022-02-21 22:25:34 +01:00
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
close();
|
|
|
|
|
wolfSSL_free(m_ssl);
|
|
|
|
|
wolfSSL_CTX_free(m_context);
|
2020-10-30 11:56:31 +03:30
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
ErrorOr<Bytes> WolfTLS::read_some(Bytes bytes)
|
2020-10-30 11:56:31 +03:30
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
auto result = wolfSSL_read(m_ssl, bytes.data(), bytes.size());
|
|
|
|
|
if (result < 0)
|
|
|
|
|
return Error::from_string_view(error_text(m_ssl, result));
|
|
|
|
|
return Bytes { bytes.data(), static_cast<size_t>(result) };
|
2020-10-30 11:56:31 +03:30
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
ErrorOr<size_t> WolfTLS::write_some(ReadonlyBytes bytes)
|
2021-05-29 08:26:10 +02:00
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
auto result = wolfSSL_write(m_ssl, bytes.data(), bytes.size());
|
|
|
|
|
if (result < 0)
|
|
|
|
|
return Error::from_string_view(error_text(m_ssl, result));
|
|
|
|
|
return static_cast<size_t>(result);
|
2021-05-29 08:26:10 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
bool WolfTLS::is_eof() const
|
2020-05-18 20:16:52 +02:00
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
return m_underlying->is_eof() && wolfSSL_pending(m_ssl) == 0;
|
2020-05-18 20:16:52 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
bool WolfTLS::is_open() const
|
2020-08-02 05:27:42 +04:30
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
return m_underlying->is_open();
|
2020-08-02 05:27:42 +04:30
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
void WolfTLS::close()
|
2023-08-01 14:43:21 -06:00
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
wolfSSL_shutdown(m_ssl);
|
2023-08-01 14:43:21 -06:00
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
ErrorOr<size_t> WolfTLS::pending_bytes() const
|
2020-10-30 11:56:31 +03:30
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
return wolfSSL_pending(m_ssl);
|
2023-04-10 07:06:17 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
ErrorOr<bool> WolfTLS::can_read_without_blocking(int) const
|
2023-07-24 17:48:34 -06:00
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
return true;
|
2023-07-24 17:48:34 -06:00
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
ErrorOr<void> WolfTLS::set_blocking(bool)
|
2023-04-10 07:06:17 +02:00
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
return {};
|
2023-03-27 19:28:27 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-01 17:11:35 +02:00
|
|
|
void WolfTLS::install_certificate_store_paths(Vector<AK::ByteString> paths)
|
2023-03-27 19:28:27 +02:00
|
|
|
{
|
2024-07-01 17:11:35 +02:00
|
|
|
s_certificate_store_paths = move(paths);
|
2020-10-30 11:56:31 +03:30
|
|
|
}
|
2024-07-01 17:11:35 +02:00
|
|
|
|
2020-04-21 01:57:23 +04:30
|
|
|
}
|