include/boost/corosio/tls_context.hpp

100.0% Lines (6/6) 100.0% Functions (5/5) 50.0% Branches (2/4)
include/boost/corosio/tls_context.hpp
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco ([email protected])
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/corosio
8 //
9
10 #ifndef BOOST_COROSIO_TLS_CONTEXT_HPP
11 #define BOOST_COROSIO_TLS_CONTEXT_HPP
12
13 #include <boost/corosio/detail/config.hpp>
14
15 #include <functional>
16 #include <system_error>
17 #include <memory>
18 #include <string_view>
19
20 namespace boost::corosio {
21
22 //
23 // Enumerations
24 //
25
26 /** TLS handshake role.
27
28 Specifies whether to perform the TLS handshake as a client or server.
29
30 @see stream::handshake
31 */
32 enum class tls_role
33 {
34 /// Perform handshake as the connecting client.
35 client,
36
37 /// Perform handshake as the accepting server.
38 server
39 };
40
41 /** TLS protocol version.
42
43 Specifies the minimum or maximum TLS protocol version to use
44 for connections. Only modern, secure versions are supported.
45
46 @see tls_context::set_min_protocol_version
47 @see tls_context::set_max_protocol_version
48 */
49 enum class tls_version
50 {
51 /// TLS 1.2 (RFC 5246).
52 tls_1_2,
53
54 /// TLS 1.3 (RFC 8446).
55 tls_1_3
56 };
57
58 /** Certificate and key file format.
59
60 Specifies the encoding format for certificate and key data.
61
62 @see tls_context::use_certificate
63 @see tls_context::use_private_key
64 */
65 enum class tls_file_format
66 {
67 /// PEM format (Base64-encoded with header/footer lines).
68 pem,
69
70 /// DER format (raw ASN.1 binary encoding).
71 der
72 };
73
74 /** Peer certificate verification mode.
75
76 Controls how the TLS implementation verifies the peer's
77 certificate during the handshake.
78
79 @see tls_context::set_verify_mode
80 */
81 enum class tls_verify_mode
82 {
83 /// Do not request or verify the peer certificate.
84 none,
85
86 /// Request and verify the peer certificate if presented.
87 peer,
88
89 /// Require and verify the peer certificate (fail if not presented).
90 require_peer
91 };
92
93 /** Certificate revocation checking policy.
94
95 Controls how certificate revocation status is checked during
96 verification.
97
98 @see tls_context::set_revocation_policy
99 */
100 enum class tls_revocation_policy
101 {
102 /// Do not check revocation status.
103 disabled,
104
105 /// Check revocation but allow connection if status is unknown.
106 soft_fail,
107
108 /// Require successful revocation check (fail if status is unknown).
109 hard_fail
110 };
111
112 /** Purpose for password callback invocation.
113
114 Indicates whether the password is needed for reading (decrypting)
115 or writing (encrypting) key material.
116
117 @see tls_context::set_password_callback
118 */
119 enum class tls_password_purpose
120 {
121 /// Password needed to decrypt/read protected key material.
122 for_reading,
123
124 /// Password needed to encrypt/write protected key material.
125 for_writing
126 };
127
128 class tls_context;
129
130 namespace detail {
131 struct tls_context_data;
132 tls_context_data const& get_tls_context_data(tls_context const&) noexcept;
133 } // namespace detail
134
135 /** A portable TLS context for certificate and settings storage.
136
137 The `tls_context` class provides a backend-agnostic interface for
138 configuring TLS connections. It stores credentials (certificates and
139 private keys), trust anchors, protocol settings, and verification
140 options that are used when establishing TLS connections.
141
142 This class is a shared handle to an opaque implementation. Copies
143 share the same underlying state. This allows contexts to be passed
144 by value and shared across multiple TLS streams.
145
146 This class abstracts the configuration phase of TLS across multiple
147 backend implementations (OpenSSL, WolfSSL, mbedTLS, Schannel, etc.),
148 allowing portable code that works regardless of which TLS library
149 is linked.
150
151 @par Modification After Stream Creation
152
153 Modifying a context after a TLS stream has been created from it
154 results in undefined behavior. The context's configuration is
155 captured when the first stream is constructed, and subsequent
156 modifications are not reflected in existing or new streams
157 sharing the context.
158
159 If different configurations are needed, create separate context
160 objects.
161
162 @par Thread Safety
163
164 Distinct objects: Safe.
165
166 Shared objects: Unsafe. A context must not be modified while
167 any thread is creating streams from it.
168
169 @par Example
170 @code
171 // Create a client context with system trust anchors
172 corosio::tls_context ctx;
173 ctx.set_default_verify_paths();
174 ctx.set_verify_mode( corosio::tls_verify_mode::peer );
175 ctx.set_hostname( "example.com" );
176
177 // Use with a TLS stream
178 corosio::openssl_stream secure( sock, ctx );
179 co_await secure.handshake( corosio::tls_stream::client );
180 @endcode
181
182 @see tls_role
183 */
184 #ifdef _MSC_VER
185 #pragma warning(push)
186 #pragma warning(disable : 4251) // shared_ptr needs dll-interface
187 #endif
188 class BOOST_COROSIO_DECL tls_context
189 {
190 struct impl;
191 std::shared_ptr<impl> impl_;
192
193 friend detail::tls_context_data const&
194 detail::get_tls_context_data(tls_context const&) noexcept;
195
196 public:
197 /** Construct a default TLS context.
198
199 Creates a context with default settings suitable for TLS 1.2
200 and TLS 1.3 connections. No certificates or trust anchors are
201 loaded; call the appropriate methods to configure credentials
202 and verification.
203
204 @par Example
205 @code
206 corosio::tls_context ctx;
207 @endcode
208 */
209 tls_context();
210
211 /** Copy constructor.
212
213 Creates a new handle that shares ownership of the underlying
214 TLS context state with `other`.
215
216 @param other The context to copy from.
217 */
218 10840 tls_context(tls_context const& other) = default;
219
220 /** Copy assignment operator.
221
222 Releases the current context's shared ownership and acquires
223 shared ownership of `other`'s underlying state.
224
225 @param other The context to copy from.
226
227 @return Reference to this context.
228 */
229 tls_context& operator=(tls_context const& other) = default;
230
231 /** Move constructor.
232
233 Transfers ownership of the TLS context from another instance.
234 After the move, `other` is in a valid but empty state.
235
236 @param other The context to move from.
237 */
238 3606 tls_context(tls_context&& other) noexcept = default;
239
240 /** Move assignment operator.
241
242 Releases the current context's shared ownership and transfers
243 ownership from another instance. After the move, `other` is
244 in a valid but empty state.
245
246 @param other The context to move from.
247
248 @return Reference to this context.
249 */
250 tls_context& operator=(tls_context&& other) noexcept = default;
251
252 /** Destructor.
253
254 Releases this handle's shared ownership of the underlying
255 context. The context state is destroyed when the last handle
256 is released.
257 */
258 18010 ~tls_context() = default;
259
260 //
261 // Credential Loading
262 //
263
264 /** Load the entity certificate from a memory buffer.
265
266 Sets the certificate that identifies this endpoint to the peer.
267 For servers, this is the server certificate. For clients using
268 mutual TLS, this is the client certificate.
269
270 The certificate must match the private key loaded via
271 `use_private_key()` or `use_private_key_file()`.
272
273 @param certificate The certificate data.
274
275 @param format The encoding format of the certificate data.
276
277 @return Success, or an error if the certificate could not be parsed
278 or is invalid.
279
280 @see use_certificate_file
281 @see use_private_key
282 */
283 std::error_code
284 use_certificate(std::string_view certificate, tls_file_format format);
285
286 /** Load the entity certificate from a file.
287
288 Sets the certificate that identifies this endpoint to the peer.
289 For servers, this is the server certificate. For clients using
290 mutual TLS, this is the client certificate.
291
292 @param filename Path to the certificate file.
293
294 @param format The encoding format of the file.
295
296 @return Success, or an error if the file could not be read or the
297 certificate is invalid.
298
299 @par Example
300 @code
301 ctx.use_certificate_file( "server.crt", tls_file_format::pem );
302 @endcode
303
304 @see use_certificate
305 @see use_private_key_file
306 */
307 std::error_code
308 use_certificate_file(std::string_view filename, tls_file_format format);
309
310 /** Load a certificate chain from a memory buffer.
311
312 Loads the entity certificate followed by intermediate CA certificates.
313 The chain should be ordered from leaf to root (excluding the root).
314 This is the typical format for PEM certificate bundles.
315
316 @param chain The certificate chain data in PEM format (concatenated
317 certificates).
318
319 @return Success, or an error if the chain could not be parsed.
320
321 @see use_certificate_chain_file
322 */
323 std::error_code use_certificate_chain(std::string_view chain);
324
325 /** Load a certificate chain from a file.
326
327 Loads the entity certificate followed by intermediate CA certificates
328 from a PEM file. The file should contain concatenated PEM certificates
329 ordered from leaf to root (excluding the root).
330
331 @param filename Path to the certificate chain file.
332
333 @return Success, or an error if the file could not be read or parsed.
334
335 @par Example
336 @code
337 // Load certificate chain (cert + intermediates)
338 ctx.use_certificate_chain_file( "fullchain.pem" );
339 @endcode
340
341 @see use_certificate_chain
342 */
343 std::error_code use_certificate_chain_file(std::string_view filename);
344
345 /** Load the private key from a memory buffer.
346
347 Sets the private key corresponding to the entity certificate.
348 The key must match the certificate loaded via `use_certificate()`
349 or `use_certificate_chain()`.
350
351 If the key is encrypted, set a password callback via
352 `set_password_callback()` before calling this function.
353
354 @param private_key The private key data.
355
356 @param format The encoding format of the key data.
357
358 @return Success, or an error if the key could not be parsed,
359 is encrypted without a password callback, or doesn't match
360 the certificate.
361
362 @see use_private_key_file
363 @see set_password_callback
364 */
365 std::error_code
366 use_private_key(std::string_view private_key, tls_file_format format);
367
368 /** Load the private key from a file.
369
370 Sets the private key corresponding to the entity certificate.
371 The key must match the certificate loaded via `use_certificate_file()`
372 or `use_certificate_chain_file()`.
373
374 If the key file is encrypted, set a password callback via
375 `set_password_callback()` before calling this function.
376
377 @param filename Path to the private key file.
378
379 @param format The encoding format of the file.
380
381 @return Success, or an error if the file could not be read,
382 the key is invalid, or it doesn't match the certificate.
383
384 @par Example
385 @code
386 ctx.use_private_key_file( "server.key", tls_file_format::pem );
387 @endcode
388
389 @see use_private_key
390 @see set_password_callback
391 */
392 std::error_code
393 use_private_key_file(std::string_view filename, tls_file_format format);
394
395 /** Load credentials from a PKCS#12 bundle in memory.
396
397 PKCS#12 (also known as PFX) is a binary format that bundles a
398 certificate, private key, and optionally intermediate certificates
399 into a single password-protected file.
400
401 @param data The PKCS#12 bundle data.
402
403 @param passphrase The password protecting the bundle.
404
405 @return Success, or an error if the bundle could not be parsed
406 or the passphrase is incorrect.
407
408 @see use_pkcs12_file
409 */
410 std::error_code
411 use_pkcs12(std::string_view data, std::string_view passphrase);
412
413 /** Load credentials from a PKCS#12 file.
414
415 PKCS#12 (also known as PFX) is a binary format that bundles a
416 certificate, private key, and optionally intermediate certificates
417 into a single password-protected file. This is common on Windows
418 and for certificates exported from browsers.
419
420 @param filename Path to the PKCS#12 file.
421
422 @param passphrase The password protecting the file.
423
424 @return Success, or an error if the file could not be read,
425 parsed, or the passphrase is incorrect.
426
427 @par Example
428 @code
429 ctx.use_pkcs12_file( "credentials.pfx", "secret" );
430 @endcode
431
432 @see use_pkcs12
433 */
434 std::error_code
435 use_pkcs12_file(std::string_view filename, std::string_view passphrase);
436
437 //
438 // Trust Anchors
439 //
440
441 /** Add a certificate authority for peer verification.
442
443 Adds a single CA certificate to the trust store used for verifying
444 peer certificates. Call this multiple times to add multiple CAs,
445 or use `load_verify_file()` for a bundle.
446
447 @param ca The CA certificate data in PEM format.
448
449 @return Success, or an error if the certificate could not be parsed.
450
451 @see load_verify_file
452 @see set_default_verify_paths
453 */
454 std::error_code add_certificate_authority(std::string_view ca);
455
456 /** Load CA certificates from a file.
457
458 Loads one or more CA certificates from a PEM file. The file may
459 contain multiple concatenated PEM certificates.
460
461 @param filename Path to a PEM file containing CA certificates.
462
463 @return Success, or an error if the file could not be read or parsed.
464
465 @par Example
466 @code
467 // Load a custom CA bundle
468 ctx.load_verify_file( "/etc/ssl/certs/ca-certificates.crt" );
469 @endcode
470
471 @see add_certificate_authority
472 @see add_verify_path
473 */
474 std::error_code load_verify_file(std::string_view filename);
475
476 /** Add a directory of CA certificates for verification.
477
478 Adds a directory containing CA certificate files. Each file must
479 contain a single certificate in PEM format, named using the
480 subject name hash (as generated by `openssl rehash` or
481 `c_rehash`).
482
483 @param path Path to the directory containing hashed CA certificates.
484
485 @return Success, or an error if the directory is invalid.
486
487 @par Example
488 @code
489 ctx.add_verify_path( "/etc/ssl/certs" );
490 @endcode
491
492 @see load_verify_file
493 @see set_default_verify_paths
494 */
495 std::error_code add_verify_path(std::string_view path);
496
497 /** Use the system default CA certificate store.
498
499 Configures the context to use the operating system's default
500 trust store for peer certificate verification. This is the
501 recommended approach for HTTPS clients connecting to public
502 servers.
503
504 On different platforms this uses:
505 - Linux: `/etc/ssl/certs` or distribution-specific paths
506 - macOS: System Keychain
507 - Windows: Windows Certificate Store
508
509 @return Success, or an error if the system store could not be loaded.
510
511 @par Example
512 @code
513 // Trust the same CAs as the system
514 ctx.set_default_verify_paths();
515 @endcode
516
517 @see load_verify_file
518 @see add_verify_path
519 */
520 std::error_code set_default_verify_paths();
521
522 //
523 // Protocol Configuration
524 //
525
526 /** Set the minimum TLS protocol version.
527
528 Connections will reject protocol versions older than this.
529 The default allows TLS 1.2 and newer.
530
531 @param v The minimum protocol version to accept.
532
533 @return Success, or an error if the version is not supported
534 by the backend.
535
536 @par Example
537 @code
538 // Require TLS 1.3 minimum
539 ctx.set_min_protocol_version( tls_version::tls_1_3 );
540 @endcode
541
542 @see set_max_protocol_version
543 */
544 std::error_code set_min_protocol_version(tls_version v);
545
546 /** Set the maximum TLS protocol version.
547
548 Connections will not negotiate protocol versions newer than this.
549 The default allows the newest supported version.
550
551 @param v The maximum protocol version to accept.
552
553 @return Success, or an error if the version is not supported
554 by the backend.
555
556 @see set_min_protocol_version
557 */
558 std::error_code set_max_protocol_version(tls_version v);
559
560 /** Set the allowed cipher suites.
561
562 Configures which cipher suites may be used for connections.
563 The format is backend-specific but typically follows OpenSSL
564 cipher list syntax.
565
566 @param ciphers The cipher suite specification string.
567
568 @return Success, or an error if the cipher string is invalid.
569
570 @par Example
571 @code
572 // TLS 1.2 cipher suites (OpenSSL format)
573 ctx.set_ciphersuites( "ECDHE+AESGCM:ECDHE+CHACHA20" );
574 @endcode
575
576 @note For TLS 1.3, use `set_ciphersuites_tls13()` on backends
577 that distinguish between TLS 1.2 and 1.3 cipher configuration.
578 */
579 std::error_code set_ciphersuites(std::string_view ciphers);
580
581 /** Set the ALPN protocol list.
582
583 Configures Application-Layer Protocol Negotiation (ALPN) for
584 the connection. ALPN is used to negotiate which application
585 protocol to use over the TLS connection (e.g., "h2" for HTTP/2,
586 "http/1.1" for HTTP/1.1).
587
588 The protocols are tried in preference order (first = highest).
589
590 @param protocols Ordered list of protocol identifiers.
591
592 @return Success, or an error if ALPN configuration fails.
593
594 @par Example
595 @code
596 // Prefer HTTP/2, fall back to HTTP/1.1
597 ctx.set_alpn( { "h2", "http/1.1" } );
598 @endcode
599 */
600 std::error_code set_alpn(std::initializer_list<std::string_view> protocols);
601
602 //
603 // Certificate Verification
604 //
605
606 /** Set the peer certificate verification mode.
607
608 Controls whether and how peer certificates are verified during
609 the TLS handshake.
610
611 @param mode The verification mode to use.
612
613 @return Success, or an error if the mode could not be set.
614
615 @par Example
616 @code
617 // Verify peer certificate (typical for clients)
618 ctx.set_verify_mode( tls_verify_mode::peer );
619
620 // Require client certificate (server-side mTLS)
621 ctx.set_verify_mode( tls_verify_mode::require_peer );
622 @endcode
623
624 @see tls_verify_mode
625 */
626 std::error_code set_verify_mode(tls_verify_mode mode);
627
628 /** Set the maximum certificate chain verification depth.
629
630 Limits how many intermediate certificates can appear between
631 the peer certificate and a trusted root. The default is
632 typically 100, which is sufficient for most certificate chains.
633
634 @param depth Maximum number of intermediate certificates allowed.
635
636 @return Success, or an error if the depth is invalid.
637 */
638 std::error_code set_verify_depth(int depth);
639
640 /** Set a custom certificate verification callback.
641
642 Installs a callback that is invoked during certificate chain
643 verification. The callback can perform additional validation
644 beyond the standard checks and can override verification
645 results.
646
647 The callback receives the verification result so far and
648 information about the certificate being verified. Return
649 `true` to accept the certificate, `false` to reject.
650
651 @tparam Callback A callable with signature
652 `bool( bool preverified, verify_context& ctx )`.
653
654 @param callback The verification callback.
655
656 @return Success, or an error if the callback could not be set.
657
658 @note The `verify_context` type provides access to the
659 certificate and chain information. Its exact interface
660 depends on the TLS backend.
661 */
662 template<typename Callback>
663 std::error_code set_verify_callback(Callback callback);
664
665 /** Set the expected server hostname for verification.
666
667 For client connections, sets the hostname that the server
668 certificate must match. This enables:
669
670 1. SNI (Server Name Indication) — tells the server which
671 certificate to present (for virtual hosting)
672 2. Hostname verification — validates the certificate's
673 Subject Alternative Name or Common Name matches
674
675 @param hostname The expected server hostname.
676
677 @par Example
678 @code
679 ctx.set_hostname( "api.example.com" );
680 @endcode
681
682 @note This is typically required for HTTPS clients to ensure
683 they're connecting to the intended server.
684 */
685 void set_hostname(std::string_view hostname);
686
687 /** Set a callback for Server Name Indication (SNI).
688
689 For server connections, this callback is invoked during the TLS
690 handshake when a client sends an SNI extension. The callback
691 receives the requested hostname and can accept or reject the
692 connection.
693
694 @tparam Callback A callable with signature
695 `bool( std::string_view hostname )`.
696
697 @param callback The SNI callback. Return `true` to accept the
698 connection or `false` to reject it with an alert.
699
700 @par Example
701 @code
702 // Accept connections for specific domains only
703 ctx.set_servername_callback(
704 []( std::string_view hostname ) -> bool
705 {
706 return hostname == "api.example.com" ||
707 hostname == "www.example.com";
708 });
709 @endcode
710
711 @note For virtual hosting with different certificates per hostname,
712 create separate contexts and select the appropriate one before
713 creating the TLS stream.
714
715 @see set_hostname
716 */
717 template<typename Callback>
718 void set_servername_callback(Callback callback);
719
720 private:
721 void set_servername_callback_impl(
722 std::function<bool(std::string_view)> callback);
723
724 void set_password_callback_impl(
725 std::function<std::string(std::size_t, tls_password_purpose)> callback);
726
727 public:
728 //
729 // Revocation Checking
730 //
731
732 /** Add a Certificate Revocation List from memory.
733
734 Adds a CRL to the verification store for checking whether
735 certificates have been revoked. CRLs are typically fetched
736 from the URLs in a certificate's CRL Distribution Points
737 extension.
738
739 @param crl The CRL data in DER or PEM format.
740
741 @return Success, or an error if the CRL could not be parsed.
742
743 @see add_crl_file
744 @see set_revocation_policy
745 */
746 std::error_code add_crl(std::string_view crl);
747
748 /** Add a Certificate Revocation List from a file.
749
750 Adds a CRL to the verification store for checking whether
751 certificates have been revoked.
752
753 @param filename Path to a CRL file (DER or PEM format).
754
755 @return Success, or an error if the file could not be read
756 or the CRL is invalid.
757
758 @par Example
759 @code
760 ctx.add_crl_file( "issuer.crl" );
761 @endcode
762
763 @see add_crl
764 @see set_revocation_policy
765 */
766 std::error_code add_crl_file(std::string_view filename);
767
768 /** Set the OCSP staple response for server-side stapling.
769
770 For servers, provides a pre-fetched OCSP response to send
771 to clients during the handshake. This proves the server's
772 certificate hasn't been revoked without requiring the client
773 to contact the OCSP responder.
774
775 The OCSP response must be periodically refreshed (typically
776 every few hours to days) before it expires.
777
778 @param response The DER-encoded OCSP response.
779
780 @return Success, or an error if the response is invalid.
781
782 @note This is a server-side operation. Clients use
783 `set_require_ocsp_staple()` to require stapled responses.
784 */
785 std::error_code set_ocsp_staple(std::string_view response);
786
787 /** Require OCSP stapling from the server.
788
789 For clients, requires the server to provide a stapled OCSP
790 response proving its certificate hasn't been revoked. If
791 the server doesn't provide a stapled response, the handshake
792 fails.
793
794 @param require Whether to require OCSP stapling.
795
796 @note Not all servers support OCSP stapling. Enable this only
797 when connecting to servers known to support it.
798 */
799 void set_require_ocsp_staple(bool require);
800
801 /** Set the certificate revocation checking policy.
802
803 Controls how certificate revocation status is checked during
804 verification. This affects both CRL and OCSP checking.
805
806 @param policy The revocation checking policy.
807
808 @par Example
809 @code
810 // Require successful revocation check
811 ctx.set_revocation_policy( tls_revocation_policy::hard_fail );
812
813 // Check but allow unknown status
814 ctx.set_revocation_policy( tls_revocation_policy::soft_fail );
815 @endcode
816
817 @see tls_revocation_policy
818 @see add_crl
819 */
820 void set_revocation_policy(tls_revocation_policy policy);
821
822 //
823 // Password Handling
824 //
825
826 /** Set the password callback for encrypted keys.
827
828 Installs a callback that provides passwords for encrypted
829 private keys and PKCS#12 files. The callback is invoked when
830 loading encrypted key material.
831
832 @tparam Callback A callable with signature
833 `std::string( std::size_t max_length, password_purpose purpose )`.
834
835 @param callback The password callback. It receives the maximum
836 password length and the purpose (reading or writing), and
837 returns the password string.
838
839 @par Example
840 @code
841 ctx.set_password_callback(
842 []( std::size_t max_len, tls_password_purpose purpose )
843 {
844 // In practice, prompt user or read from secure storage
845 return std::string( "my-key-password" );
846 });
847
848 // Now load encrypted key
849 ctx.use_private_key_file( "encrypted.key", tls_file_format::pem );
850 @endcode
851
852 @see tls_password_purpose
853 */
854 template<typename Callback>
855 void set_password_callback(Callback callback);
856 };
857 #ifdef _MSC_VER
858 #pragma warning(pop)
859 #endif
860
861 template<typename Callback>
862 void
863 2 tls_context::set_servername_callback(Callback callback)
864 {
865
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
2 set_servername_callback_impl(std::move(callback));
866 2 }
867
868 template<typename Callback>
869 void
870 tls_context::set_password_callback(Callback callback)
871 {
872 set_password_callback_impl(std::move(callback));
873 }
874
875 } // namespace boost::corosio
876
877 #endif
878