diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-04-11 05:36:22 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-04-11 05:36:22 +0800 |
| commit | 4ef9c771444943008bb990343127a7d659fd6df2 (patch) | |
| tree | 560b1c93f1950ddc5540999eae9b8d446e384470 /src/net/ssl_socket.cc | |
| parent | 5efb7400b96fa112c38009b18e2a48620f328148 (diff) | |
| download | rwebbrowser-4ef9c771444943008bb990343127a7d659fd6df2.tar.gz rwebbrowser-4ef9c771444943008bb990343127a7d659fd6df2.tar.xz | |
feat: implement SSLSocket for encrypted connections and add terminal size detection utility
Diffstat (limited to 'src/net/ssl_socket.cc')
| -rw-r--r-- | src/net/ssl_socket.cc | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/src/net/ssl_socket.cc b/src/net/ssl_socket.cc new file mode 100644 index 0000000..a31b564 --- /dev/null +++ b/src/net/ssl_socket.cc @@ -0,0 +1,118 @@ +/* + * Ricochet - A minimalist CLI web browser for fast, distraction-free navigation. + * Copyright (C) 2026 Richard Qin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "ricochet/net/ssl_socket.hh" +#include <iostream> +#include <openssl/err.h> +#include <openssl/ssl.h> +#include <stdexcept> + +namespace ricochet::net { + +// --- RAII Deleters --- + +void SslCtxDeleter::operator()( SSL_CTX* ptr ) const +{ + if ( ptr != nullptr ) { + SSL_CTX_free( ptr ); + } +} + +void SslDeleter::operator()( SSL* ptr ) const +{ + if ( ptr != nullptr ) { + SSL_free( ptr ); + } +} + +// SSLSocket Implementation + +SSLSocket::SSLSocket() +{ + const SSL_METHOD* method = TLS_client_method(); + ctx_.reset( SSL_CTX_new( method ) ); + if ( !ctx_ ) { + throw std::runtime_error( "Failed to create SSL_CTX" ); + } + + if ( SSL_CTX_set_default_verify_paths( ctx_.get() ) != 1 ) { + throw std::runtime_error( "Failed to load default CA certificates" ); + } +} + +void SSLSocket::connect( const Address& address, const std::string& hostname ) +{ + // TCP Connect + underlying_socket_.connect( address ); + + ssl_.reset( SSL_new( ctx_.get() ) ); + if ( !ssl_ ) { + throw std::runtime_error( "Failed to create SSL object" ); + } + + // Setup SNI (Server Name Indication) + if ( SSL_set_tlsext_host_name( ssl_.get(), hostname.c_str() ) != 1 ) { + // Some old servers do not support SNI, here we can ignore the error or throw an exception, depending on the + // requirements + std::cerr << "Warning: Failed to set SNI" << '\n'; + } + + SSL_set_fd( ssl_.get(), underlying_socket_.fd_num() ); + + if ( SSL_connect( ssl_.get() ) != 1 ) { + throw std::runtime_error( "TLS Handshake failed!" ); + } +} + +std::size_t SSLSocket::write( std::string_view data ) +{ + if ( !ssl_ ) { + return 0; + } + + const int bytes_written = SSL_write( ssl_.get(), data.data(), static_cast<int>( data.size() ) ); + if ( bytes_written <= 0 ) { + throw std::runtime_error( "SSL write failed" ); + } + return static_cast<std::size_t>( bytes_written ); +} + +void SSLSocket::read( std::string& buffer ) +{ + if ( !ssl_ ) { + return; + } + + std::array<char, 4096> buf {}; + // Read decrypted data from the encrypted channel + const int bytes_read = SSL_read( ssl_.get(), buf.data(), static_cast<int>( buf.size() ) ); + + if ( bytes_read > 0 ) { + buffer.append( buf.data(), static_cast<std::size_t>( bytes_read ) ); + } else { + // Read 0 or negative, representing the server closed the connection (EOF) + eof_ = true; + } +} + +bool SSLSocket::eof() const +{ + return eof_; +} + +} // namespace ricochet::net
\ No newline at end of file |
