Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/modules/ROOT/pages/3.tutorials/3b.http-client.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -274,16 +274,16 @@ capy::task<void> run_https_client(

// Configure the TLS context
corosio::tls_context ctx;
ctx.set_hostname(hostname);
if (auto ec = ctx.set_default_verify_paths(); ec)
throw std::system_error(ec);
if (auto ec = ctx.set_verify_mode(corosio::tls_verify_mode::peer); ec)
throw std::system_error(ec);

// Wrap the connected socket without taking ownership (pointer form)
corosio::wolfssl_stream secure(&s, ctx);
secure.set_hostname(hostname);
if (auto [ec] = co_await secure.handshake(
corosio::wolfssl_stream::client); ec)
corosio::tls_role::client); ec)
throw std::system_error(ec);

co_await do_request(secure, hostname);
Expand Down
8 changes: 4 additions & 4 deletions doc/modules/ROOT/pages/3.tutorials/3d.tls-context.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -346,11 +346,11 @@ Typical usage:

=== Hostname Verification

For clients, set the expected server hostname:
For clients, set the expected server hostname on the stream before the handshake:

[source,cpp]
----
ctx.set_hostname( "api.example.com" );
secure.set_hostname( "api.example.com" );
----

This enables:
Expand Down Expand Up @@ -570,11 +570,11 @@ tls_context make_https_client_context()

// Usage with TLS stream
tls_context ctx = make_https_client_context();
ctx.set_hostname("api.example.com"); // Set before creating stream

// Pointer form wraps the connected socket without taking ownership
corosio::wolfssl_stream secure( &sock, ctx );
co_await secure.handshake( corosio::wolfssl_stream::client );
secure.set_hostname( "api.example.com" );
co_await secure.handshake( corosio::tls_role::client );
----

=== TLS Server Context
Expand Down
34 changes: 20 additions & 14 deletions doc/modules/ROOT/pages/4.guide/4l.tls.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ and checks the hostname:
tls_context ctx;
ctx.set_default_verify_paths(); // trust the system CAs
ctx.set_verify_mode(tls_verify_mode::peer); // require + verify the peer
ctx.set_hostname("example.com"); // SNI + hostname check

corosio::tcp_socket sock(ioc);
corosio::wolfssl_stream secure(&sock, ctx);
secure.set_hostname("example.com"); // SNI + hostname check
----

Trust anchors can also be supplied explicitly with
Expand Down Expand Up @@ -80,7 +83,6 @@ The typical flow:
----
// 1. Configure a context
tls_context ctx;
ctx.set_hostname("api.example.com");
if (auto ec = ctx.set_default_verify_paths(); ec)
throw std::system_error(ec);
if (auto ec = ctx.set_verify_mode(tls_verify_mode::peer); ec)
Expand All @@ -94,7 +96,8 @@ if (auto [ec] = co_await sock.connect(endpoint); ec)

// 3. Wrap the connected socket (pointer form; does not take ownership)
corosio::wolfssl_stream secure(&sock, ctx);
if (auto [ec] = co_await secure.handshake(wolfssl_stream::client); ec)
secure.set_hostname("api.example.com");
if (auto [ec] = co_await secure.handshake(tls_role::client); ec)
throw std::system_error(ec);

// 4. Use encrypted I/O
Expand Down Expand Up @@ -301,11 +304,11 @@ For HTTPS clients, use `peer`. For servers requiring client certificates

==== Hostname Verification (SNI)

For clients, set the expected server hostname:
For clients, set the expected server hostname on the stream:

[source,cpp]
----
ctx.set_hostname("api.example.com");
secure.set_hostname("api.example.com");
----

This does two things:
Expand All @@ -314,6 +317,10 @@ This does two things:
to present (important for virtual hosting)
2. Verifies the server certificate matches this hostname

An IP literal (IPv4 or IPv6) is verified against the certificate's
iPAddress entries instead of its DNS names, and no SNI is sent
(RFC 6066 excludes literals).

==== Verification Depth

Limit the certificate chain depth:
Expand Down Expand Up @@ -401,18 +408,18 @@ the `capy::Stream` concept, so composed operations like `capy::read` and

[source,cpp]
----
enum class tls_role { client, server };

class tls_stream
{
public:
enum handshake_type { client, server };

template<capy::MutableBufferSequence B>
auto read_some(B const& buffers); // Decrypt and read

template<capy::ConstBufferSequence B>
auto write_some(B const& buffers); // Encrypt and write

virtual capy::io_task<> handshake(handshake_type type) = 0;
virtual capy::io_task<> handshake(tls_role role) = 0;
virtual capy::io_task<> shutdown() = 0;

virtual capy::any_stream& next_layer() noexcept = 0; // Underlying stream
Expand Down Expand Up @@ -464,7 +471,7 @@ Before encrypted communication, perform the TLS handshake:

[source,cpp]
----
auto [ec] = co_await secure.handshake(tls_stream::client);
auto [ec] = co_await secure.handshake(tls_role::client);
if (ec)
{
std::cerr << "Handshake failed: " << ec.message() << "\n";
Expand All @@ -476,7 +483,7 @@ if (ec)

[source,cpp]
----
auto [ec] = co_await secure.handshake(tls_stream::server);
auto [ec] = co_await secure.handshake(tls_role::server);
----

=== Handshake Errors
Expand Down Expand Up @@ -629,15 +636,15 @@ capy::task<void> https_get(

// Configure TLS
tls_context ctx;
ctx.set_hostname(hostname);
if (auto ec = ctx.set_default_verify_paths(); ec)
throw std::system_error(ec);
if (auto ec = ctx.set_verify_mode(tls_verify_mode::peer); ec)
throw std::system_error(ec);

// Wrap the connected socket (pointer form) and handshake
corosio::wolfssl_stream secure(&sock, ctx);
if (auto [ec] = co_await secure.handshake(wolfssl_stream::client); ec)
secure.set_hostname(hostname);
if (auto [ec] = co_await secure.handshake(tls_role::client); ec)
throw std::system_error(ec);

// Send HTTP request
Expand Down Expand Up @@ -704,7 +711,7 @@ capy::task<void> handle_tls_client(
// Owning form: the handler owns the socket, so move it in
corosio::wolfssl_stream secure(std::move(sock), ctx);

auto [ec] = co_await secure.handshake(wolfssl_stream::server);
auto [ec] = co_await secure.handshake(tls_role::server);
if (ec)
co_return;

Expand Down Expand Up @@ -746,7 +753,6 @@ server's CA explicitly with `load_verify_file()` instead.
tls_context client_ctx;
client_ctx.set_default_verify_paths();
client_ctx.set_verify_mode(tls_verify_mode::peer);
client_ctx.set_hostname("server.example.com");

// Provide client certificate
client_ctx.use_certificate_file("client.crt", tls_file_format::pem);
Expand Down
4 changes: 2 additions & 2 deletions example/https-client/https_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,17 @@ run_client(

// Configure TLS context
corosio::tls_context ctx;
ctx.set_hostname(hostname);
if (auto ec = ctx.set_default_verify_paths(); ec)
throw std::system_error(ec);
if (auto ec = ctx.set_verify_mode(corosio::tls_verify_mode::peer); ec)
throw std::system_error(ec);

// Wrap socket in TLS stream
corosio::wolfssl_stream secure(&s, ctx);
secure.set_hostname(hostname);

// Perform TLS handshake
if (auto [ec] = co_await secure.handshake(corosio::wolfssl_stream::client); ec)
if (auto [ec] = co_await secure.handshake(corosio::tls_role::client); ec)
throw std::system_error(ec);

co_await do_request(secure, hostname);
Expand Down
4 changes: 0 additions & 4 deletions example/tls_context_examples.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ tls_context make_https_client()
// Verify the server certificate
must(ctx.set_verify_mode( tls_verify_mode::peer ));

// Set the hostname for SNI and certificate verification
ctx.set_hostname( "api.example.com" );

return ctx;
}

Expand All @@ -65,7 +62,6 @@ tls_context make_pinned_ca_client( std::string_view ca_pem )
must(ctx.add_certificate_authority( ca_pem ));

must(ctx.set_verify_mode( tls_verify_mode::peer ));
ctx.set_hostname( "internal.example.com" );

return ctx;
}
Expand Down
15 changes: 10 additions & 5 deletions include/boost/corosio/openssl_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ namespace boost::corosio {
@par Example
@code
tls_context ctx;
ctx.set_hostname("example.com");
ctx.set_verify_mode(tls_verify_mode::peer);

corosio::tcp_socket sock(ioc);
co_await sock.connect(endpoint);

// Reference mode - sock must outlive tls
corosio::openssl_stream tls(&sock, ctx);
auto [ec] = co_await tls.handshake(openssl_stream::client);
tls.set_hostname("example.com");
auto [ec] = co_await tls.handshake(tls_role::client);

// Or owning mode - tls owns the socket
corosio::openssl_stream tls2(std::move(sock), ctx);
Expand Down Expand Up @@ -145,11 +145,11 @@ class BOOST_COROSIO_DECL openssl_stream final : public tls_stream
The underlying stream must be connected. No other
TLS operation may be in progress on this stream.

@param type The handshake role (client or server).
@param role The handshake role, client or server.

@return An awaitable yielding `(error_code)`.
*/
capy::io_task<> handshake(handshake_type type) override;
capy::io_task<> handshake(tls_role role) override;

/** Shut down the TLS session asynchronously.

Expand All @@ -169,13 +169,18 @@ class BOOST_COROSIO_DECL openssl_stream final : public tls_stream

Clears internal buffers and session data so the stream
can perform a new handshake on the same underlying
connection.
connection. The previous session is discarded and never
resumed, so a handshake after `reset()` is always a full
handshake.

@par Preconditions
No TLS operation may be in progress on this stream.
*/
void reset() override;

/// Set the peer hostname for SNI and certificate verification.
void set_hostname(std::string_view hostname) override;

/// Return the underlying stream.
capy::any_stream& next_layer() noexcept override
{
Expand Down
46 changes: 4 additions & 42 deletions include/boost/corosio/tls_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,6 @@ namespace boost::corosio {
// Enumerations
//

/** TLS handshake role.

Specifies whether to perform the TLS handshake as a client or server.

@see stream::handshake
*/
enum class tls_role
{
/// Perform handshake as the connecting client.
client,

/// Perform handshake as the accepting server.
server
};

/** TLS protocol version.

Specifies the minimum or maximum TLS protocol version to use
Expand Down Expand Up @@ -244,11 +229,11 @@ tls_context_data const& get_tls_context_data(tls_context const&) noexcept;
corosio::tls_context ctx;
ctx.set_default_verify_paths();
ctx.set_verify_mode( corosio::tls_verify_mode::peer );
ctx.set_hostname( "example.com" );

// Use with a TLS stream
corosio::openssl_stream secure( &sock, ctx );
co_await secure.handshake( corosio::tls_stream::client );
secure.set_hostname( "example.com" );
co_await secure.handshake( corosio::tls_role::client );
@endcode

@see tls_role
Expand Down Expand Up @@ -593,7 +578,7 @@ class BOOST_COROSIO_DECL tls_context
The system store is loaded when the native context is first built
from this context. For a verified-safe client, combine this with
`set_verify_mode( tls_verify_mode::peer )` and, when connecting by
name, `set_hostname()`.
name, `tls_stream::set_hostname()`.

@return Success. The request is recorded and applied when the
native context is built; if the system store cannot be loaded
Expand All @@ -611,7 +596,6 @@ class BOOST_COROSIO_DECL tls_context
// Trust the same CAs as the system
ctx.set_default_verify_paths();
ctx.set_verify_mode( tls_verify_mode::peer );
ctx.set_hostname( "example.com" );
@endcode

@see load_verify_file
Expand Down Expand Up @@ -836,28 +820,6 @@ class BOOST_COROSIO_DECL tls_context
template<typename Callback>
std::error_code set_verify_callback(Callback callback);

/** Set the expected server hostname for verification.

For client connections, sets the hostname that the server
certificate must match. This enables:

1. SNI (Server Name Indication) — tells the server which
certificate to present (for virtual hosting)
2. Hostname verification — validates the certificate's
Subject Alternative Name or Common Name matches

@param hostname The expected server hostname.

@par Example
@code
ctx.set_hostname( "api.example.com" );
@endcode

@note This is typically required for HTTPS clients to ensure
they're connecting to the intended server.
*/
void set_hostname(std::string_view hostname);

/** Set a callback for Server Name Indication (SNI).

For server connections, this callback is invoked during the TLS
Expand Down Expand Up @@ -886,7 +848,7 @@ class BOOST_COROSIO_DECL tls_context
create separate contexts and select the appropriate one before
creating the TLS stream.

@see set_hostname
@see tls_stream::set_hostname
*/
template<typename Callback>
void set_servername_callback(Callback callback);
Expand Down
Loading
Loading