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