include/boost/corosio/tls_context.hpp

100.0% Lines (20/20) 90.5% List of functions (19/21) 100.0% Branches (3/3)
tls_context.hpp
f(x) Functions (21)
Function Calls Lines Branches Blocks
boost::corosio::verify_context::verify_context(void*, unsigned char const*, unsigned long long) :169 6x 100.0% 100.0% boost::corosio::verify_context::native_handle() const :183 1x 100.0% 100.0% boost::corosio::verify_context::certificate() const :196 4x 100.0% 100.0% boost::corosio::tls_context::tls_context(boost::corosio::tls_context const&) :290 2309x 100.0% 100.0% boost::corosio::tls_context::operator=(boost::corosio::tls_context const&) :301 1x 100.0% 100.0% boost::corosio::tls_context::tls_context(boost::corosio::tls_context&&) :310 2215x 100.0% 100.0% boost::corosio::tls_context::operator=(boost::corosio::tls_context&&) :322 1x 100.0% 100.0% boost::corosio::tls_context::~tls_context() :330 6744x 100.0% 100.0% void boost::corosio::tls_context::set_servername_callback<boost::corosio::test::testSniCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}>(boost::corosio::test::testSniCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}) :1026 1x 100.0% 100.0% 75.0% void boost::corosio::tls_context::set_servername_callback<boost::corosio::test::testSniCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#2}>(boost::corosio::test::testSniCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#2}) :1026 1x 100.0% 100.0% 75.0% void boost::corosio::tls_context::set_servername_callback<boost::corosio::test::testSniCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#3}>(boost::corosio::test::testSniCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(std::basic_string_view<char, std::char_traits<char> >)#3}) :1026 1x 100.0% 100.0% 75.0% void boost::corosio::tls_context::set_servername_callback<boost::corosio::tls_context_test::testServernameCallback()::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}>(boost::corosio::tls_context_test::testServernameCallback()::{lambda(std::basic_string_view<char, std::char_traits<char> >)#1}) :1026 1x 100.0% 100.0% 75.0% void boost::corosio::tls_context::set_password_callback<boost::corosio::test::make_encrypted_key_server_context(bool&)::{lambda(unsigned long long, boost::corosio::tls_password_purpose)#1}>(boost::corosio::test::make_encrypted_key_server_context(bool&)::{lambda(unsigned long long, boost::corosio::tls_password_purpose)#1}) :1033 1x 100.0% 100.0% 75.0% void boost::corosio::tls_context::set_password_callback<boost::corosio::tls_context_test::testPasswordCallback()::{lambda(unsigned long long, boost::corosio::tls_password_purpose)#1}>(boost::corosio::tls_context_test::testPasswordCallback()::{lambda(unsigned long long, boost::corosio::tls_password_purpose)#1}) :1033 1x 100.0% 100.0% 75.0% std::error_code boost::corosio::tls_context::set_verify_callback<boost::corosio::test::testVerifyCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory, bool)::{lambda(bool, boost::corosio::verify_context&)#1}>(boost::corosio::test::testVerifyCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory, bool)::{lambda(bool, boost::corosio::verify_context&)#1}) :1040 0 0.0% 0.0% 0.0% std::error_code boost::corosio::tls_context::set_verify_callback<boost::corosio::test::testVerifyCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory, bool)::{lambda(bool, boost::corosio::verify_context&)#2}>(boost::corosio::test::testVerifyCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory, bool)::{lambda(bool, boost::corosio::verify_context&)#2}) :1040 0 0.0% 0.0% 0.0% std::error_code boost::corosio::tls_context::set_verify_callback<boost::corosio::test::testVerifyCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory, bool)::{lambda(bool, boost::corosio::verify_context&)#3}>(boost::corosio::test::testVerifyCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory, bool)::{lambda(bool, boost::corosio::verify_context&)#3}) :1040 1x 100.0% 100.0% 77.8% std::error_code boost::corosio::tls_context::set_verify_callback<boost::corosio::test::testVerifyCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory, bool)::{lambda(bool, boost::corosio::verify_context&)#4}>(boost::corosio::test::testVerifyCallback<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory, bool)::{lambda(bool, boost::corosio::verify_context&)#4}) :1040 1x 100.0% 100.0% 77.8% std::error_code boost::corosio::tls_context::set_verify_callback<boost::corosio::test::testVerifyCallbackOnSuccess<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(bool, boost::corosio::verify_context&)#1}>(boost::corosio::test::testVerifyCallbackOnSuccess<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(bool, boost::corosio::verify_context&)#1}) :1040 1x 100.0% 100.0% 77.8% std::error_code boost::corosio::tls_context::set_verify_callback<boost::corosio::test::testVerifyCallbackOnSuccess<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(bool, boost::corosio::verify_context&)#2}>(boost::corosio::test::testVerifyCallbackOnSuccess<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(bool, boost::corosio::verify_context&)#2}) :1040 1x 100.0% 100.0% 77.8% std::error_code boost::corosio::tls_context::set_verify_callback<boost::corosio::test::testVerifyCallbackOnSuccess<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(bool, boost::corosio::verify_context&)#3}>(boost::corosio::test::testVerifyCallbackOnSuccess<boost::corosio::openssl_stream_factory>(boost::corosio::openssl_stream_factory)::{lambda(bool, boost::corosio::verify_context&)#3}) :1040 1x 100.0% 100.0% 77.8%
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco ([email protected])
3 // Copyright (c) 2026 Michael Vandeberg
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/corosio
9 //
10
11 #ifndef BOOST_COROSIO_TLS_CONTEXT_HPP
12 #define BOOST_COROSIO_TLS_CONTEXT_HPP
13
14 #include <boost/corosio/detail/config.hpp>
15
16 #include <cstddef>
17 #include <functional>
18 #include <span>
19 #include <system_error>
20 #include <memory>
21 #include <string_view>
22
23 namespace boost::corosio {
24
25 //
26 // Enumerations
27 //
28
29 /** TLS handshake role.
30
31 Specifies whether to perform the TLS handshake as a client or server.
32
33 @see stream::handshake
34 */
35 enum class tls_role
36 {
37 /// Perform handshake as the connecting client.
38 client,
39
40 /// Perform handshake as the accepting server.
41 server
42 };
43
44 /** TLS protocol version.
45
46 Specifies the minimum or maximum TLS protocol version to use
47 for connections. Only modern, secure versions are supported.
48
49 @see tls_context::set_min_protocol_version
50 @see tls_context::set_max_protocol_version
51 */
52 enum class tls_version
53 {
54 /// TLS 1.2 (RFC 5246).
55 tls_1_2,
56
57 /// TLS 1.3 (RFC 8446).
58 tls_1_3
59 };
60
61 /** Certificate and key file format.
62
63 Specifies the encoding format for certificate and key data.
64
65 @see tls_context::use_certificate
66 @see tls_context::use_private_key
67 */
68 enum class tls_file_format
69 {
70 /// PEM format (Base64-encoded with header/footer lines).
71 pem,
72
73 /// DER format (raw ASN.1 binary encoding).
74 der
75 };
76
77 /** Peer certificate verification mode.
78
79 Controls how the TLS implementation verifies the peer's
80 certificate during the handshake.
81
82 @see tls_context::set_verify_mode
83 */
84 enum class tls_verify_mode
85 {
86 /// Do not request or verify the peer certificate.
87 none,
88
89 /// Request and verify the peer certificate if presented.
90 peer,
91
92 /// Require and verify the peer certificate (fail if not presented).
93 require_peer
94 };
95
96 /** Certificate revocation checking policy.
97
98 Controls how certificate revocation status is checked during
99 verification.
100
101 @see tls_context::set_revocation_policy
102 */
103 enum class tls_revocation_policy
104 {
105 /// Do not check revocation status.
106 disabled,
107
108 /// Check revocation but allow connection if status is unknown.
109 soft_fail,
110
111 /// Require successful revocation check (fail if status is unknown).
112 hard_fail
113 };
114
115 /** Purpose for password callback invocation.
116
117 Indicates whether the password is needed for reading (decrypting)
118 or writing (encrypting) key material.
119
120 @see tls_context::set_password_callback
121 */
122 enum class tls_password_purpose
123 {
124 /// Password needed to decrypt/read protected key material.
125 for_reading,
126
127 /// Password needed to encrypt/write protected key material.
128 for_writing
129 };
130
131 class tls_context;
132
133 /** A non-owning view of certificate verification state.
134
135 An instance is passed to the callback installed via
136 tls_context::set_verify_callback during the TLS handshake. It
137 exposes the backend's native verification handle so the callback
138 can inspect the certificate and chain currently being verified.
139
140 The value returned by native_handle() is, for the OpenSSL and
141 WolfSSL backends, an `X509_STORE_CTX*`. For portable inspection that
142 works across backends (for example certificate pinning), prefer
143 certificate(), which returns the DER encoding of the certificate
144 currently being verified.
145
146 @par Lifetime
147
148 The wrapped handle and the certificate() bytes are owned by the TLS
149 backend and are valid only for the duration of a single callback
150 invocation. Do not retain them beyond the call.
151
152 @see tls_context::set_verify_callback
153 */
154 class verify_context
155 {
156 void* handle_;
157 unsigned char const* der_;
158 std::size_t der_len_;
159
160 public:
161 /** Construct from a native handle and the current certificate.
162
163 @param handle The backend verification handle (for OpenSSL and
164 WolfSSL, an `X509_STORE_CTX*`).
165 @param der Pointer to the DER encoding of the certificate under
166 verification, or `nullptr` if unavailable.
167 @param der_len Length of the DER encoding in bytes.
168 */
169 6x verify_context(
170 void* handle, unsigned char const* der, std::size_t der_len) noexcept
171 6x : handle_(handle), der_(der), der_len_(der_len)
172 {
173 6x }
174
175 /** Return the native verification handle.
176
177 Cast the result to the backend's verification context type
178 (e.g. `X509_STORE_CTX*`) to inspect the certificate chain using
179 backend-specific APIs.
180
181 @return The native handle, or `nullptr` if none is available.
182 */
183 1x void* native_handle() const noexcept { return handle_; }
184
185 /** Return the DER encoding of the certificate being verified.
186
187 This is the portable way to inspect the peer certificate from a
188 verification callback: it works identically on every backend,
189 without depending on backend-specific build options. A DER
190 certificate is an ASN.1 `SEQUENCE`, so the first byte is `0x30`.
191
192 @return A view of the certificate's DER bytes, valid only for the
193 duration of the callback. Empty if the certificate is not
194 available.
195 */
196 4x std::span<unsigned char const> certificate() const noexcept
197 {
198 4x return {der_, der_len_};
199 }
200 };
201
202 namespace detail {
203 struct tls_context_data;
204 tls_context_data const& get_tls_context_data(tls_context const&) noexcept;
205 } // namespace detail
206
207 /** A portable TLS context for certificate and settings storage.
208
209 The `tls_context` class provides a backend-agnostic interface for
210 configuring TLS connections. It stores credentials (certificates and
211 private keys), trust anchors, protocol settings, and verification
212 options that are used when establishing TLS connections.
213
214 This class is a shared handle to an opaque implementation. Copies
215 share the same underlying state. This allows contexts to be passed
216 by value and shared across multiple TLS streams.
217
218 This class abstracts the configuration phase of TLS across multiple
219 backend implementations (OpenSSL, WolfSSL, mbedTLS, Schannel, etc.),
220 allowing portable code that works regardless of which TLS library
221 is linked.
222
223 @par Modification After Stream Creation
224
225 Modifying a context after a TLS stream has been created from it
226 results in undefined behavior. The context's configuration is
227 captured when the first stream is constructed, and subsequent
228 modifications are not reflected in existing or new streams
229 sharing the context.
230
231 If different configurations are needed, create separate context
232 objects.
233
234 @par Thread Safety
235
236 Distinct objects: Safe.
237
238 Shared objects: Unsafe. A context must not be modified while
239 any thread is creating streams from it.
240
241 @par Example
242 @code
243 // Create a client context with system trust anchors
244 corosio::tls_context ctx;
245 ctx.set_default_verify_paths();
246 ctx.set_verify_mode( corosio::tls_verify_mode::peer );
247 ctx.set_hostname( "example.com" );
248
249 // Use with a TLS stream
250 corosio::openssl_stream secure( &sock, ctx );
251 co_await secure.handshake( corosio::tls_stream::client );
252 @endcode
253
254 @see tls_role
255 */
256 #ifdef _MSC_VER
257 #pragma warning(push)
258 #pragma warning(disable : 4251) // shared_ptr needs dll-interface
259 #endif
260 class BOOST_COROSIO_DECL tls_context
261 {
262 struct impl;
263 std::shared_ptr<impl> impl_;
264
265 friend detail::tls_context_data const&
266 detail::get_tls_context_data(tls_context const&) noexcept;
267
268 public:
269 /** Construct a default TLS context.
270
271 Creates a context with default settings suitable for TLS 1.2
272 and TLS 1.3 connections. No certificates or trust anchors are
273 loaded; call the appropriate methods to configure credentials
274 and verification.
275
276 @par Example
277 @code
278 corosio::tls_context ctx;
279 @endcode
280 */
281 tls_context();
282
283 /** Copy constructor.
284
285 Creates a new handle that shares ownership of the underlying
286 TLS context state with `other`.
287
288 @param other The context to copy from.
289 */
290 2309x tls_context(tls_context const& other) = default;
291
292 /** Copy assignment operator.
293
294 Releases the current context's shared ownership and acquires
295 shared ownership of `other`'s underlying state.
296
297 @param other The context to copy from.
298
299 @return Reference to this context.
300 */
301 1x tls_context& operator=(tls_context const& other) = default;
302
303 /** Move constructor.
304
305 Transfers ownership of the TLS context from another instance.
306 After the move, `other` is in a valid but empty state.
307
308 @param other The context to move from.
309 */
310 2215x tls_context(tls_context&& other) noexcept = default;
311
312 /** Move assignment operator.
313
314 Releases the current context's shared ownership and transfers
315 ownership from another instance. After the move, `other` is
316 in a valid but empty state.
317
318 @param other The context to move from.
319
320 @return Reference to this context.
321 */
322 1x tls_context& operator=(tls_context&& other) noexcept = default;
323
324 /** Destructor.
325
326 Releases this handle's shared ownership of the underlying
327 context. The context state is destroyed when the last handle
328 is released.
329 */
330 6744x ~tls_context() = default;
331
332 //
333 // Credential Loading
334 //
335
336 /** Load the entity certificate from a memory buffer.
337
338 Sets the certificate that identifies this endpoint to the peer.
339 For servers, this is the server certificate. For clients using
340 mutual TLS, this is the client certificate.
341
342 The certificate must match the private key loaded via
343 `use_private_key()` or `use_private_key_file()`.
344
345 @param certificate The certificate data.
346
347 @param format The encoding format of the certificate data.
348
349 @return Success, or an error if the certificate could not be parsed
350 or is invalid.
351
352 @see use_certificate_file
353 @see use_private_key
354 */
355 std::error_code
356 use_certificate(std::string_view certificate, tls_file_format format);
357
358 /** Load the entity certificate from a file.
359
360 Sets the certificate that identifies this endpoint to the peer.
361 For servers, this is the server certificate. For clients using
362 mutual TLS, this is the client certificate.
363
364 @param filename Path to the certificate file.
365
366 @param format The encoding format of the file.
367
368 @return Success, or an error if the file could not be read or the
369 certificate is invalid.
370
371 @par Example
372 @code
373 ctx.use_certificate_file( "server.crt", tls_file_format::pem );
374 @endcode
375
376 @see use_certificate
377 @see use_private_key_file
378 */
379 std::error_code
380 use_certificate_file(std::string_view filename, tls_file_format format);
381
382 /** Load a certificate chain from a memory buffer.
383
384 Loads the entity certificate followed by intermediate CA certificates.
385 The chain should be ordered from leaf to root (excluding the root).
386 This is the typical format for PEM certificate bundles.
387
388 @param chain The certificate chain data in PEM format (concatenated
389 certificates).
390
391 @return Success, or an error if the chain could not be parsed.
392
393 @see use_certificate_chain_file
394 */
395 std::error_code use_certificate_chain(std::string_view chain);
396
397 /** Load a certificate chain from a file.
398
399 Loads the entity certificate followed by intermediate CA certificates
400 from a PEM file. The file should contain concatenated PEM certificates
401 ordered from leaf to root (excluding the root).
402
403 @param filename Path to the certificate chain file.
404
405 @return Success, or an error if the file could not be read or parsed.
406
407 @par Example
408 @code
409 // Load certificate chain (cert + intermediates)
410 ctx.use_certificate_chain_file( "fullchain.pem" );
411 @endcode
412
413 @see use_certificate_chain
414 */
415 std::error_code use_certificate_chain_file(std::string_view filename);
416
417 /** Load the private key from a memory buffer.
418
419 Sets the private key corresponding to the entity certificate.
420 The key must match the certificate loaded via `use_certificate()`
421 or `use_certificate_chain()`.
422
423 If the key is encrypted, set a password callback via
424 `set_password_callback()` before calling this function.
425
426 @param private_key The private key data.
427
428 @param format The encoding format of the key data.
429
430 @return Success, or an error if the key could not be parsed,
431 is encrypted without a password callback, or doesn't match
432 the certificate.
433
434 @see use_private_key_file
435 @see set_password_callback
436 */
437 std::error_code
438 use_private_key(std::string_view private_key, tls_file_format format);
439
440 /** Load the private key from a file.
441
442 Sets the private key corresponding to the entity certificate.
443 The key must match the certificate loaded via `use_certificate_file()`
444 or `use_certificate_chain_file()`.
445
446 If the key file is encrypted, set a password callback via
447 `set_password_callback()` before calling this function.
448
449 @param filename Path to the private key file.
450
451 @param format The encoding format of the file.
452
453 @return Success, or an error if the file could not be read,
454 the key is invalid, or it doesn't match the certificate.
455
456 @par Example
457 @code
458 ctx.use_private_key_file( "server.key", tls_file_format::pem );
459 @endcode
460
461 @see use_private_key
462 @see set_password_callback
463 */
464 std::error_code
465 use_private_key_file(std::string_view filename, tls_file_format format);
466
467 /** Load credentials from a PKCS#12 bundle in memory.
468
469 PKCS#12 (also known as PFX) is a binary format that bundles a
470 certificate, private key, and optionally intermediate certificates
471 into a single password-protected file.
472
473 @param data The PKCS#12 bundle data.
474
475 @param passphrase The password protecting the bundle.
476
477 @return Success. The bundle is recorded and decoded into the
478 certificate, private key, and chain when the native context is
479 first built; a malformed bundle or wrong passphrase surfaces as
480 a handshake failure.
481
482 @note Intermediate certificates inside the bundle are loaded and
483 sent during the handshake on both backends.
484
485 @see use_pkcs12_file
486 */
487 std::error_code
488 use_pkcs12(std::string_view data, std::string_view passphrase);
489
490 /** Load credentials from a PKCS#12 file.
491
492 PKCS#12 (also known as PFX) is a binary format that bundles a
493 certificate, private key, and optionally intermediate certificates
494 into a single password-protected file. This is common on Windows
495 and for certificates exported from browsers.
496
497 @param filename Path to the PKCS#12 file.
498
499 @param passphrase The password protecting the file.
500
501 @return Success, or an error if the file could not be read. The
502 bundle is decoded when the native context is first built; a
503 malformed bundle or wrong passphrase surfaces as a handshake
504 failure.
505
506 @note Intermediate certificates inside the bundle are loaded and
507 sent during the handshake on both backends.
508
509 @par Example
510 @code
511 ctx.use_pkcs12_file( "credentials.pfx", "secret" );
512 @endcode
513
514 @see use_pkcs12
515 */
516 std::error_code
517 use_pkcs12_file(std::string_view filename, std::string_view passphrase);
518
519 //
520 // Trust Anchors
521 //
522
523 /** Add a certificate authority for peer verification.
524
525 Adds a single CA certificate to the trust store used for verifying
526 peer certificates. Call this multiple times to add multiple CAs,
527 or use `load_verify_file()` for a bundle.
528
529 @param ca The CA certificate data in PEM format.
530
531 @return Success, or an error if the certificate could not be parsed.
532
533 @see load_verify_file
534 @see set_default_verify_paths
535 */
536 std::error_code add_certificate_authority(std::string_view ca);
537
538 /** Load CA certificates from a file.
539
540 Loads one or more CA certificates from a PEM file. The file may
541 contain multiple concatenated PEM certificates.
542
543 @param filename Path to a PEM file containing CA certificates.
544
545 @return Success, or an error if the file could not be read or parsed.
546
547 @par Example
548 @code
549 // Load a custom CA bundle
550 ctx.load_verify_file( "/etc/ssl/certs/ca-certificates.crt" );
551 @endcode
552
553 @see add_certificate_authority
554 @see add_verify_path
555 */
556 std::error_code load_verify_file(std::string_view filename);
557
558 /** Add a directory of CA certificates for verification.
559
560 Adds a directory of CA certificates to the trust store. The
561 directory is applied when the native context is first built from
562 this context.
563
564 The expected directory layout depends on the backend. OpenSSL
565 performs on-demand lookups and requires each certificate file to
566 be named by its subject-name hash (as generated by
567 `openssl rehash` or `c_rehash`); WolfSSL loads every certificate
568 file in the directory.
569
570 @param path Path to the directory of CA certificates.
571
572 @return Success. The path is recorded and applied when the native
573 context is built; a directory that cannot be read at that time
574 is skipped rather than reported here.
575
576 @par Example
577 @code
578 ctx.add_verify_path( "/etc/ssl/certs" );
579 @endcode
580
581 @see load_verify_file
582 @see set_default_verify_paths
583 */
584 std::error_code add_verify_path(std::string_view path);
585
586 /** Use the system default CA certificate store.
587
588 Configures the context to use the operating system's default
589 trust store for peer certificate verification. This is the
590 recommended approach for HTTPS clients connecting to public
591 servers.
592
593 The system store is loaded when the native context is first built
594 from this context. For a verified-safe client, combine this with
595 `set_verify_mode( tls_verify_mode::peer )` and, when connecting by
596 name, `set_hostname()`.
597
598 @return Success. The request is recorded and applied when the
599 native context is built; if the system store cannot be loaded
600 at that time it is skipped rather than reported here, so a
601 context that must reject unverified peers should also use
602 `set_verify_mode( tls_verify_mode::peer )`.
603
604 @note The OpenSSL backend honors the `SSL_CERT_FILE` and
605 `SSL_CERT_DIR` environment variables. The WolfSSL backend
606 requires a build with `WOLFSSL_SYS_CA_CERTS`; without it the
607 system store is unavailable and this call has no effect.
608
609 @par Example
610 @code
611 // Trust the same CAs as the system
612 ctx.set_default_verify_paths();
613 ctx.set_verify_mode( tls_verify_mode::peer );
614 ctx.set_hostname( "example.com" );
615 @endcode
616
617 @see load_verify_file
618 @see add_verify_path
619 @see set_verify_mode
620 */
621 std::error_code set_default_verify_paths();
622
623 //
624 // Protocol Configuration
625 //
626
627 /** Set the minimum TLS protocol version.
628
629 Connections will reject protocol versions older than this.
630 The default allows TLS 1.2 and newer.
631
632 @param v The minimum protocol version to accept.
633
634 @return Success, or an error if the version is not supported
635 by the backend.
636
637 @par Example
638 @code
639 // Require TLS 1.3 minimum
640 ctx.set_min_protocol_version( tls_version::tls_1_3 );
641 @endcode
642
643 @see set_max_protocol_version
644 */
645 std::error_code set_min_protocol_version(tls_version v);
646
647 /** Set the maximum TLS protocol version.
648
649 Connections will not negotiate protocol versions newer than this.
650 The default allows the newest supported version.
651
652 @param v The maximum protocol version to accept.
653
654 @return Success, or an error if the version is not supported
655 by the backend.
656
657 @note On WolfSSL the ceiling is applied by selecting a
658 version-specific method (no native set-max API exists); an
659 invalid window where the minimum exceeds the maximum yields a
660 context that fails the handshake.
661
662 @see set_min_protocol_version
663 */
664 std::error_code set_max_protocol_version(tls_version v);
665
666 /** Set the allowed cipher suites.
667
668 Configures which cipher suites may be used for connections.
669 The format is backend-specific but typically follows OpenSSL
670 cipher list syntax.
671
672 @param ciphers The cipher suite specification string.
673
674 @return Success, or an error if the cipher string is invalid.
675
676 @par Example
677 @code
678 // TLS 1.2 cipher suites (OpenSSL format)
679 ctx.set_ciphersuites( "ECDHE+AESGCM:ECDHE+CHACHA20" );
680 @endcode
681
682 @note This configures cipher suites for TLS 1.2 and below. For
683 TLS 1.3, use @ref set_ciphersuites_tls13.
684 */
685 std::error_code set_ciphersuites(std::string_view ciphers);
686
687 /** Set the allowed TLS 1.3 cipher suites.
688
689 TLS 1.3 uses a distinct, fixed set of cipher suites configured
690 separately from earlier versions. The format is a colon-separated
691 list of TLS 1.3 suite names.
692
693 @param ciphers The TLS 1.3 cipher suite list.
694
695 @return Success, or an error if the cipher string is invalid.
696
697 @par Example
698 @code
699 ctx.set_ciphersuites_tls13(
700 "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" );
701 @endcode
702
703 @note On the WolfSSL backend, TLS 1.2 and TLS 1.3 suites share a
704 single cipher list; this call and @ref set_ciphersuites are
705 merged into one list.
706
707 @see set_ciphersuites
708 */
709 std::error_code set_ciphersuites_tls13(std::string_view ciphers);
710
711 /** Set the ALPN protocol list.
712
713 Configures Application-Layer Protocol Negotiation (ALPN) for
714 the connection. ALPN is used to negotiate which application
715 protocol to use over the TLS connection (e.g., "h2" for HTTP/2,
716 "http/1.1" for HTTP/1.1).
717
718 The protocols are tried in preference order (first = highest).
719
720 @param protocols Ordered list of protocol identifiers.
721
722 @return Success, or an error if ALPN configuration fails.
723
724 @note Read the negotiated protocol after the handshake via
725 @ref tls_stream::alpn_protocol. On WolfSSL, ALPN requires a
726 build with `HAVE_ALPN`; without it, offering protocols fails
727 the handshake with `std::errc::function_not_supported` rather
728 than negotiate nothing silently.
729
730 @par Example
731 @code
732 // Prefer HTTP/2, fall back to HTTP/1.1
733 ctx.set_alpn( { "h2", "http/1.1" } );
734 @endcode
735 */
736 std::error_code set_alpn(std::initializer_list<std::string_view> protocols);
737
738 //
739 // Certificate Verification
740 //
741
742 /** Set the peer certificate verification mode.
743
744 Controls whether and how peer certificates are verified during
745 the TLS handshake.
746
747 @param mode The verification mode to use.
748
749 @return Success, or an error if the mode could not be set.
750
751 @par Example
752 @code
753 // Verify peer certificate (typical for clients)
754 ctx.set_verify_mode( tls_verify_mode::peer );
755
756 // Require client certificate (server-side mTLS)
757 ctx.set_verify_mode( tls_verify_mode::require_peer );
758 @endcode
759
760 @see tls_verify_mode
761 */
762 std::error_code set_verify_mode(tls_verify_mode mode);
763
764 /** Set the maximum certificate chain verification depth.
765
766 Limits how many intermediate certificates can appear between
767 the peer certificate and a trusted root. The default is
768 typically 100, which is sufficient for most certificate chains.
769
770 @param depth Maximum number of intermediate certificates allowed.
771
772 @return Success, or an error if the depth is invalid.
773 */
774 std::error_code set_verify_depth(int depth);
775
776 /** Set a custom certificate verification callback.
777
778 Installs a callback that is invoked during certificate chain
779 verification. The callback can perform additional validation
780 beyond the standard checks and can override verification
781 results.
782
783 The callback receives the built-in verification result so far and
784 a verify_context describing the certificate being verified. Return
785 `true` to accept the certificate, `false` to reject. Inspect the
786 certificate portably via `verify_context::certificate()` (its DER
787 encoding) — for example to pin a specific certificate.
788
789 @par Backend Support
790
791 The exact set of certificates the callback sees differs by backend:
792
793 - OpenSSL: the callback runs once per certificate in the chain,
794 including certificates that passed the built-in checks. It can
795 therefore both relax verification (return `true` for a
796 certificate the library rejected) and tighten it (return `false`
797 for a certificate the library accepted, e.g. pinning).
798 - WolfSSL built with `WOLFSSL_ALWAYS_VERIFY_CB` (implied by
799 `--enable-opensslextra`): same as OpenSSL.
800 - WolfSSL without that option: the library invokes the callback
801 only on verification *failure*, so it cannot be honored on a
802 successful handshake. To avoid silently ignoring a
803 verification-tightening callback (which would fail open), a
804 context that carries a callback instead **fails the handshake**
805 with `std::errc::function_not_supported` on such a build. Rebuild
806 WolfSSL with `WOLFSSL_ALWAYS_VERIFY_CB`, or omit the callback.
807
808 @tparam Callback A callable with signature
809 `bool( bool preverified, verify_context& ctx )`.
810
811 @param callback The verification callback.
812
813 @return Success. The callback is recorded here and applied during the
814 handshake. On a WolfSSL build that cannot honor it, the handshake
815 fails with `std::errc::function_not_supported` (see Backend
816 Support).
817
818 @par Example
819 @code
820 ctx.set_verify_mode( tls_verify_mode::peer );
821 ctx.set_verify_callback(
822 []( bool preverified, verify_context& ctx ) -> bool
823 {
824 if( ! preverified )
825 return false;
826 // Pin: accept only a certificate whose DER matches.
827 auto der = ctx.certificate();
828 return der.size() == expected_pin.size() &&
829 std::equal( der.begin(), der.end(), expected_pin.begin() );
830 });
831 @endcode
832
833 @see verify_context
834 @see set_verify_mode
835 */
836 template<typename Callback>
837 std::error_code set_verify_callback(Callback callback);
838
839 /** Set the expected server hostname for verification.
840
841 For client connections, sets the hostname that the server
842 certificate must match. This enables:
843
844 1. SNI (Server Name Indication) — tells the server which
845 certificate to present (for virtual hosting)
846 2. Hostname verification — validates the certificate's
847 Subject Alternative Name or Common Name matches
848
849 @param hostname The expected server hostname.
850
851 @par Example
852 @code
853 ctx.set_hostname( "api.example.com" );
854 @endcode
855
856 @note This is typically required for HTTPS clients to ensure
857 they're connecting to the intended server.
858 */
859 void set_hostname(std::string_view hostname);
860
861 /** Set a callback for Server Name Indication (SNI).
862
863 For server connections, this callback is invoked during the TLS
864 handshake when a client sends an SNI extension. The callback
865 receives the requested hostname and can accept or reject the
866 connection.
867
868 @tparam Callback A callable with signature
869 `bool( std::string_view hostname )`.
870
871 @param callback The SNI callback. Return `true` to accept the
872 connection or `false` to reject it with an alert.
873
874 @par Example
875 @code
876 // Accept connections for specific domains only
877 ctx.set_servername_callback(
878 []( std::string_view hostname ) -> bool
879 {
880 return hostname == "api.example.com" ||
881 hostname == "www.example.com";
882 });
883 @endcode
884
885 @note For virtual hosting with different certificates per hostname,
886 create separate contexts and select the appropriate one before
887 creating the TLS stream.
888
889 @see set_hostname
890 */
891 template<typename Callback>
892 void set_servername_callback(Callback callback);
893
894 private:
895 void set_servername_callback_impl(
896 std::function<bool(std::string_view)> callback);
897
898 void set_password_callback_impl(
899 std::function<std::string(std::size_t, tls_password_purpose)> callback);
900
901 void set_verify_callback_impl(
902 std::function<bool(bool, verify_context&)> callback);
903
904 public:
905 //
906 // Revocation Checking
907 //
908
909 /** Add a Certificate Revocation List from memory.
910
911 Adds a CRL to the verification store for checking whether
912 certificates have been revoked. CRLs are typically fetched
913 from the URLs in a certificate's CRL Distribution Points
914 extension.
915
916 @param crl The CRL data in DER or PEM format.
917
918 @return Success, or an error if the CRL could not be parsed.
919
920 @note CRLs are consulted only when a revocation policy is set via
921 @ref set_revocation_policy. On WolfSSL, CRL checking requires a
922 build with `HAVE_CRL`; without it, supplying a CRL or a
923 revocation policy fails the handshake with
924 `std::errc::function_not_supported`.
925
926 @see add_crl_file
927 @see set_revocation_policy
928 */
929 std::error_code add_crl(std::string_view crl);
930
931 /** Add a Certificate Revocation List from a file.
932
933 Adds a CRL to the verification store for checking whether
934 certificates have been revoked.
935
936 @param filename Path to a CRL file (DER or PEM format).
937
938 @return Success, or an error if the file could not be read
939 or the CRL is invalid.
940
941 @note CRLs are consulted only when a revocation policy is set via
942 @ref set_revocation_policy (WolfSSL requires a `HAVE_CRL`
943 build).
944
945 @par Example
946 @code
947 ctx.add_crl_file( "issuer.crl" );
948 @endcode
949
950 @see add_crl
951 @see set_revocation_policy
952 */
953 std::error_code add_crl_file(std::string_view filename);
954
955 /** Set the certificate revocation checking policy.
956
957 Controls how certificate revocation status is checked during
958 verification via CRLs.
959
960 @param policy The revocation checking policy.
961
962 @par Example
963 @code
964 // Require successful revocation check
965 ctx.set_revocation_policy( tls_revocation_policy::hard_fail );
966
967 // Check but allow unknown status
968 ctx.set_revocation_policy( tls_revocation_policy::soft_fail );
969 @endcode
970
971 @note Revocation is checked via CRLs supplied with @ref add_crl /
972 @ref add_crl_file. `soft_fail` accepts a certificate whose
973 status cannot be determined (missing/expired CRL) but rejects
974 one that is actually revoked; `hard_fail` also rejects unknown
975 status. OCSP-based revocation is not available (see the TLS
976 guide). On WolfSSL a non-disabled policy requires a `HAVE_CRL`
977 build, else the handshake fails with
978 `std::errc::function_not_supported`.
979
980 @see tls_revocation_policy
981 @see add_crl
982 */
983 void set_revocation_policy(tls_revocation_policy policy);
984
985 //
986 // Password Handling
987 //
988
989 /** Set the password callback for encrypted keys.
990
991 Installs a callback that provides passwords for encrypted
992 private keys and PKCS#12 files. The callback is invoked when
993 loading encrypted key material.
994
995 @tparam Callback A callable with signature
996 `std::string( std::size_t max_length, password_purpose purpose )`.
997
998 @param callback The password callback. It receives the maximum
999 password length and the purpose (reading or writing), and
1000 returns the password string.
1001
1002 @par Example
1003 @code
1004 ctx.set_password_callback(
1005 []( std::size_t max_len, tls_password_purpose purpose )
1006 {
1007 // In practice, prompt user or read from secure storage
1008 return std::string( "my-key-password" );
1009 });
1010
1011 // Now load encrypted key
1012 ctx.use_private_key_file( "encrypted.key", tls_file_format::pem );
1013 @endcode
1014
1015 @see tls_password_purpose
1016 */
1017 template<typename Callback>
1018 void set_password_callback(Callback callback);
1019 };
1020 #ifdef _MSC_VER
1021 #pragma warning(pop)
1022 #endif
1023
1024 template<typename Callback>
1025 void
1026 4x tls_context::set_servername_callback(Callback callback)
1027 {
1028
1/1
✓ Branch 4 → 5 taken 4 times.
4x set_servername_callback_impl(std::move(callback));
1029 4x }
1030
1031 template<typename Callback>
1032 void
1033 2x tls_context::set_password_callback(Callback callback)
1034 {
1035
1/1
✓ Branch 4 → 5 taken 2 times.
2x set_password_callback_impl(std::move(callback));
1036 2x }
1037
1038 template<typename Callback>
1039 std::error_code
1040 5x tls_context::set_verify_callback(Callback callback)
1041 {
1042
1/1
✓ Branch 4 → 5 taken 5 times.
5x set_verify_callback_impl(std::move(callback));
1043 5x return {};
1044 }
1045
1046 } // namespace boost::corosio
1047
1048 #endif
1049