LCOV - code coverage report
Current view: top level - corosio - tls_stream.hpp (source / functions) Coverage Total Missed
Test: coverage_remapped.info Lines: 0.0 % 4 4
Test Date: 2026-08-03 19:53:42 Functions: 0.0 % 4 4

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
       3                 : // Copyright (c) 2026 Michael Vandeberg
       4                 : // Copyright (c) 2026 Steve Gerbino
       5                 : //
       6                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       7                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       8                 : //
       9                 : // Official repository: https://github.com/cppalliance/corosio
      10                 : //
      11                 : 
      12                 : #ifndef BOOST_COROSIO_TLS_STREAM_HPP
      13                 : #define BOOST_COROSIO_TLS_STREAM_HPP
      14                 : 
      15                 : #include <boost/corosio/detail/config.hpp>
      16                 : #include <boost/capy/buffers.hpp>
      17                 : #include <boost/capy/detail/buffer_array.hpp>
      18                 : #include <boost/capy/io/any_stream.hpp>
      19                 : #include <boost/capy/io_task.hpp>
      20                 : 
      21                 : #include <cstddef>
      22                 : #include <string_view>
      23                 : 
      24                 : namespace boost::corosio {
      25                 : 
      26                 : /** TLS handshake role.
      27                 : 
      28                 :     Specifies whether to perform the TLS handshake as a client or server.
      29                 : 
      30                 :     @see tls_stream::handshake
      31                 : */
      32                 : enum class tls_role
      33                 : {
      34                 :     /// Perform handshake as the connecting client.
      35                 :     client,
      36                 : 
      37                 :     /// Perform handshake as the accepting server.
      38                 :     server
      39                 : };
      40                 : 
      41                 : /** Abstract base class for TLS streams.
      42                 : 
      43                 :     This class provides a runtime-polymorphic interface for TLS
      44                 :     implementations. Derived classes (openssl_stream, wolfssl_stream)
      45                 :     implement the virtual functions to provide backend-specific
      46                 :     TLS functionality.
      47                 : 
      48                 :     Unlike @ref io_stream which represents OS-level I/O completed
      49                 :     by the kernel, TLS streams are coroutine-based: their operations
      50                 :     are implemented as coroutines that orchestrate sub-operations
      51                 :     on the underlying stream.
      52                 : 
      53                 :     The non-virtual template wrappers (`read_some`, `write_some`)
      54                 :     satisfy the `capy::Stream` concept, enabling TLS streams to
      55                 :     be used anywhere a Stream is expected.
      56                 : 
      57                 :     @par Thread Safety
      58                 :     Distinct objects: Safe.@n
      59                 :     Shared objects: Unsafe, with one exception: one read operation and
      60                 :     one write operation may be in flight simultaneously. `shutdown()`
      61                 :     may overlap a pending read. When the execution context runs on
      62                 :     multiple threads, all operations on one stream must be performed
      63                 :     within the same `capy::strand` (or otherwise never run
      64                 :     concurrently); a single-threaded context needs no strand.
      65                 : 
      66                 :     @see openssl_stream, wolfssl_stream
      67                 : */
      68                 : class BOOST_COROSIO_DECL tls_stream
      69                 : {
      70                 : public:
      71                 :     /// Destroy the TLS stream.
      72                 :     virtual ~tls_stream() = default;
      73                 : 
      74                 :     tls_stream(tls_stream const&)            = delete;
      75                 :     tls_stream& operator=(tls_stream const&) = delete;
      76                 : 
      77                 :     /** Initiate an asynchronous read operation.
      78                 : 
      79                 :         Reads decrypted data into the provided buffer sequence. The
      80                 :         operation completes when at least one byte has been read,
      81                 :         or an error occurs.
      82                 : 
      83                 :         This non-virtual template wrapper satisfies the `capy::Stream`
      84                 :         concept by delegating to the virtual `do_read_some`.
      85                 : 
      86                 :         @par Thread Safety
      87                 :         May run concurrently with one operation in the other
      88                 :         direction, subject to the class-level threading contract.
      89                 :         Two concurrent operations in the same direction are
      90                 :         undefined.
      91                 : 
      92                 :         @param buffers The buffer sequence to read data into.
      93                 : 
      94                 :         @return An awaitable yielding `(error_code,std::size_t)`.
      95                 :     */
      96                 :     template<capy::MutableBufferSequence Buffers>
      97 MIS           0 :     auto read_some(Buffers const& buffers)
      98                 :     {
      99               0 :         return do_read_some(buffers);
     100                 :     }
     101                 : 
     102                 :     /** Initiate an asynchronous write operation.
     103                 : 
     104                 :         Encrypts and writes data from the provided buffer sequence.
     105                 :         The operation completes when at least one byte has been
     106                 :         written, or an error occurs.
     107                 : 
     108                 :         This non-virtual template wrapper satisfies the `capy::Stream`
     109                 :         concept by delegating to the virtual `do_write_some`.
     110                 : 
     111                 :         @par Thread Safety
     112                 :         May run concurrently with one operation in the other
     113                 :         direction, subject to the class-level threading contract.
     114                 :         Two concurrent operations in the same direction are
     115                 :         undefined.
     116                 : 
     117                 :         @param buffers The buffer sequence containing data to write.
     118                 : 
     119                 :         @return An awaitable yielding `(error_code,std::size_t)`.
     120                 :     */
     121                 :     template<capy::ConstBufferSequence Buffers>
     122               0 :     auto write_some(Buffers const& buffers)
     123                 :     {
     124               0 :         return do_write_some(buffers);
     125                 :     }
     126                 : 
     127                 :     /** Asynchronously perform the TLS handshake.
     128                 : 
     129                 :         Initiates the TLS handshake process. For client connections,
     130                 :         this sends the ClientHello and processes the server's response.
     131                 :         For server connections, this waits for the ClientHello and
     132                 :         sends the server's response.
     133                 : 
     134                 :         A handshake attempt, successful or not, consumes the stream
     135                 :         state: a subsequent call behaves as if `reset()` had been
     136                 :         called first and performs a fresh handshake using the
     137                 :         current configuration.
     138                 : 
     139                 :         @par Preconditions
     140                 :         The underlying stream must be connected. No other TLS
     141                 :         operation may be in progress on this stream.
     142                 : 
     143                 :         @param role The handshake role, client or server.
     144                 : 
     145                 :         @return An awaitable yielding `(error_code)`.
     146                 :     */
     147                 :     virtual capy::io_task<> handshake(tls_role role) = 0;
     148                 : 
     149                 :     /** Asynchronously perform a graceful TLS shutdown.
     150                 : 
     151                 :         Initiates the TLS shutdown sequence by sending a close_notify
     152                 :         alert and waiting for the peer's close_notify response.
     153                 : 
     154                 :         @par Preconditions
     155                 :         A handshake must have completed successfully. May overlap
     156                 :         a pending read. No concurrent write may be in progress.
     157                 : 
     158                 :         @par Postconditions
     159                 :         If the transport ends before the peer's close_notify is
     160                 :         received, the result is `capy::error::stream_truncated`, not
     161                 :         success: an unannounced close is indistinguishable from a
     162                 :         truncation attack and must not be reported as a clean
     163                 :         shutdown. A shutdown stopped mid-flight reports canceled;
     164                 :         any other transport error propagates unchanged.
     165                 : 
     166                 :         @return An awaitable yielding `(error_code)`.
     167                 :     */
     168                 :     virtual capy::io_task<> shutdown() = 0;
     169                 : 
     170                 :     /** Reset TLS session state for reuse.
     171                 : 
     172                 :         Releases TLS session state including session keys and peer
     173                 :         certificates, returning the stream to a state where
     174                 :         `handshake()` can be called again. Internal memory
     175                 :         allocations (I/O buffers) are preserved.
     176                 : 
     177                 :         Calling `handshake()` on a previously-used stream
     178                 :         implicitly performs a reset first, so explicit calls
     179                 :         are only needed to eagerly release session state.
     180                 : 
     181                 :         @par Preconditions
     182                 :         No TLS operation (handshake, read, write, shutdown) is
     183                 :         in progress.
     184                 : 
     185                 :         @par Thread Safety
     186                 :         Not thread safe. The caller must ensure no concurrent
     187                 :         operations are in progress on this stream.
     188                 : 
     189                 :         @note If called mid-session before `shutdown()`, pending
     190                 :             TLS data is discarded and the peer will observe a
     191                 :             truncated stream.
     192                 :     */
     193                 :     virtual void reset() = 0;
     194                 : 
     195                 :     /** Set the peer hostname for SNI and certificate verification.
     196                 : 
     197                 :         Configures the hostname sent in the TLS Server Name
     198                 :         Indication extension and matched against the peer
     199                 :         certificate during verification. The value takes effect
     200                 :         at the next `handshake()`; an established session is not
     201                 :         affected. It persists across `reset()`, so a stream reused
     202                 :         to reach a different host must set the new name before
     203                 :         handshaking again.
     204                 : 
     205                 :         An empty hostname (the default) disables SNI and hostname
     206                 :         verification.
     207                 : 
     208                 :         If `hostname` is an IP literal (IPv4 or IPv6), it is matched
     209                 :         against the certificate's iPAddress entries instead of its
     210                 :         DNS names, and no SNI is sent (RFC 6066 excludes literals).
     211                 :         A backend build that cannot match iPAddress entries fails the
     212                 :         handshake with `std::errc::function_not_supported` rather
     213                 :         than skip verification.
     214                 : 
     215                 :         @par Postconditions
     216                 :         The next `handshake()` uses `hostname` for SNI and
     217                 :         certificate verification, or neither if it is empty.
     218                 : 
     219                 :         @note The hostname is used for client handshakes only;
     220                 :         it is ignored when handshaking as a server.
     221                 : 
     222                 :         @param hostname The peer hostname, or empty to disable.
     223                 :     */
     224                 :     virtual void set_hostname(std::string_view hostname) = 0;
     225                 : 
     226                 :     /** Return a reference to the underlying stream.
     227                 : 
     228                 :         Provides access to the type-erased underlying stream for
     229                 :         operations like cancellation or accessing native handles.
     230                 : 
     231                 :         @warning Do not reseat (assign to) the returned reference.
     232                 :             The TLS implementation holds internal state bound to
     233                 :             the original stream. Replacing it causes undefined
     234                 :             behavior.
     235                 : 
     236                 :         @return Reference to the wrapped stream.
     237                 :     */
     238                 :     virtual capy::any_stream& next_layer() noexcept = 0;
     239                 : 
     240                 :     /** Return a const reference to the underlying stream.
     241                 : 
     242                 :         @return Const reference to the wrapped stream.
     243                 :     */
     244                 :     virtual capy::any_stream const& next_layer() const noexcept = 0;
     245                 : 
     246                 :     /** Return the name of the TLS backend.
     247                 : 
     248                 :         @return A string identifying the TLS implementation,
     249                 :             such as "openssl" or "wolfssl".
     250                 :     */
     251                 :     virtual std::string_view name() const noexcept = 0;
     252                 : 
     253                 :     /** Return the ALPN protocol negotiated during the handshake.
     254                 : 
     255                 :         Application-Layer Protocol Negotiation selects a single
     256                 :         application protocol (for example `"h2"` or `"http/1.1"`)
     257                 :         during the TLS handshake, from the list supplied via
     258                 :         @ref tls_context::set_alpn.
     259                 : 
     260                 :         @return The negotiated protocol, or an empty view if no
     261                 :             protocol was negotiated, ALPN was not offered, the
     262                 :             handshake has not completed, or the backend/build does
     263                 :             not support ALPN.
     264                 : 
     265                 :         @par Thread Safety
     266                 :         Safe to call after the handshake completes; not safe to call
     267                 :         concurrently with a handshake or reset.
     268                 :     */
     269                 :     virtual std::string_view alpn_protocol() const noexcept { return {}; }
     270                 : 
     271                 : protected:
     272                 :     tls_stream() = default;
     273                 : 
     274                 :     /** Virtual read implementation.
     275                 : 
     276                 :         Derived classes override this to perform TLS decryption
     277                 :         and read operations.
     278                 : 
     279                 :         @param buffers Buffer sequence to read into.
     280                 : 
     281                 :         @return An awaitable yielding `(error_code,std::size_t)`.
     282                 :     */
     283                 :     virtual capy::io_task<std::size_t> do_read_some(
     284                 :         capy::detail::mutable_buffer_array<capy::detail::max_iovec_> buffers) = 0;
     285                 : 
     286                 :     /** Virtual write implementation.
     287                 : 
     288                 :         Derived classes override this to perform TLS encryption
     289                 :         and write operations.
     290                 : 
     291                 :         @param buffers Buffer sequence to write from.
     292                 : 
     293                 :         @return An awaitable yielding `(error_code,std::size_t)`.
     294                 :     */
     295                 :     virtual capy::io_task<std::size_t> do_write_some(
     296                 :         capy::detail::const_buffer_array<capy::detail::max_iovec_> buffers) = 0;
     297                 : };
     298                 : 
     299                 : } // namespace boost::corosio
     300                 : 
     301                 : #endif
        

Generated by: LCOV version 2.3