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 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 : verify_context(
170 : void* handle, unsigned char const* der, std::size_t der_len) noexcept
171 : : handle_(handle), der_(der), der_len_(der_len)
172 : {
173 : }
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 : 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 : std::span<unsigned char const> certificate() const noexcept
197 : {
198 : 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 HIT 1 : 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 1 : 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 1 : 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 1 : 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 34 : ~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 1 : tls_context::set_servername_callback(Callback callback)
1027 : {
1028 1 : set_servername_callback_impl(std::move(callback));
1029 1 : }
1030 :
1031 : template<typename Callback>
1032 : void
1033 1 : tls_context::set_password_callback(Callback callback)
1034 : {
1035 1 : set_password_callback_impl(std::move(callback));
1036 1 : }
1037 :
1038 : template<typename Callback>
1039 : std::error_code
1040 : tls_context::set_verify_callback(Callback callback)
1041 : {
1042 : set_verify_callback_impl(std::move(callback));
1043 : return {};
1044 : }
1045 :
1046 : } // namespace boost::corosio
1047 :
1048 : #endif
|