Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 42 additions & 71 deletions doc/modules/ROOT/pages/3.tutorials/3d.tls-context.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,11 @@ handles:
* Configuring trust anchors for peer verification
* Setting protocol versions and cipher suites
* Configuring certificate verification behavior
* Managing revocation checking (CRL, OCSP)
* Managing revocation checking (CRLs)

Use `tls_context` to configure TLS settings once, then pass it to TLS streams
for establishing secure connections.

[WARNING]
.Not yet implemented
====
Some settings shown in this tutorial are accepted by the API but *not yet
wired up* by the backends; they are stored and silently ignored:
`set_alpn()`, `set_min_protocol_version()` / `set_max_protocol_version()`,
all revocation features (`add_crl*`, `set_ocsp_staple` /
`set_require_ocsp_staple`, `set_revocation_policy`), and `use_pkcs12*`
(returns `std::errc::function_not_supported`). `set_ciphersuites()` is
applied by OpenSSL only; WolfSSL ignores it.
====

[NOTE]
====
Two implemented features depend on how WolfSSL was built:
Expand Down Expand Up @@ -146,9 +134,10 @@ into a single password-protected file:
ctx.use_pkcs12_file( "credentials.pfx", "bundle-password" );
----

NOTE: PKCS#12 loading is not yet implemented; `use_pkcs12()` and
`use_pkcs12_file()` return `std::errc::function_not_supported`. Load the
certificate and key separately for now.
NOTE: The bundle is decoded when the first stream is created; a wrong
passphrase or malformed bundle surfaces as a handshake failure.
Intermediate certificates in the bundle are loaded and sent during the
handshake on both backends.

=== Loading from Memory

Expand Down Expand Up @@ -281,24 +270,29 @@ ctx.set_min_protocol_version( tls_version::tls_1_3 );
ctx.set_max_protocol_version( tls_version::tls_1_3 );
----

NOTE: Protocol version bounds are not yet applied by the backends. The
negotiated range is whatever the native default method provides.
NOTE: On WolfSSL the ceiling is enforced by selecting a version-specific
method (no native set-max call exists); a window whose minimum exceeds its
maximum yields a context that fails the handshake.

=== Cipher Suites

Configure allowed cipher suites using OpenSSL-style syntax:
TLS 1.2-and-below suites use an OpenSSL-style cipher list; TLS 1.3 suites
are configured separately:

[source,cpp]
----
// Strong cipher suites only
// TLS 1.2 and below
ctx.set_ciphersuites( "ECDHE+AESGCM:ECDHE+CHACHA20" );

// Disable weak ciphers
ctx.set_ciphersuites( "HIGH:!aNULL:!MD5:!RC4" );
// TLS 1.3 (distinct API and suite names)
ctx.set_ciphersuites_tls13( "TLS_AES_256_GCM_SHA384" );
----

NOTE: `set_ciphersuites()` is applied by the OpenSSL backend only; the
WolfSSL backend accepts the string but silently ignores it.
NOTE: Both backends apply these (WolfSSL merges the two into a single
list). Suite *names* differ between backends: OpenSSL uses
`TLS_AES_128_GCM_SHA256`, WolfSSL uses `TLS13-AES128-GCM-SHA256`. The
OpenSSL security level is left at the library default; include a
`@SECLEVEL=` token in the cipher string if you need a lower level.

=== ALPN (Application-Layer Protocol Negotiation)

Expand All @@ -311,13 +305,18 @@ ctx.set_alpn( { "h2", "http/1.1" } );

// gRPC
ctx.set_alpn( { "h2" } );
----

Read the negotiated protocol from the stream after the handshake:

// Custom protocol
ctx.set_alpn( { "my-protocol/1.0" } );
[source,cpp]
----
std::string_view proto = stream.alpn_protocol(); // "h2", or empty if none
----

NOTE: ALPN is not yet wired up; the protocol list is accepted but never
negotiated by either backend.
NOTE: On WolfSSL, ALPN requires a `HAVE_ALPN` build; without it, offering
protocols fails the handshake with `std::errc::function_not_supported`
rather than negotiate nothing silently.

The server selects from the client's list based on its own preferences.

Expand Down Expand Up @@ -414,31 +413,23 @@ Which certificates the callback sees depends on the backend:
== Revocation Checking

Certificate revocation checking verifies that certificates haven't been
invalidated by the issuing CA. Two mechanisms are supported: CRL and OCSP.

[WARNING]
====
None of the revocation features in this section are wired up yet.
`set_revocation_policy()`, CRLs (`add_crl()` / `add_crl_file()`), and OCSP
stapling (`set_ocsp_staple()` / `set_require_ocsp_staple()`) are all
accepted but inert. In particular, `set_require_ocsp_staple(true)` does
*not* fail the handshake when no staple is present, and `soft_fail` /
`hard_fail` do not change verification behavior.
====
invalidated by the issuing CA. Revocation is checked against Certificate
Revocation Lists (CRLs).

=== Revocation Policy

Set the overall revocation checking behavior:
Set the overall revocation checking behavior. CRLs are consulted only when
the policy is not `disabled`:

[source,cpp]
----
// Don't check revocation (default)
ctx.set_revocation_policy( tls_revocation_policy::disabled );

// Check but allow if status is unknown (lenient)
// Accept unknown status, reject a listed (revoked) certificate
ctx.set_revocation_policy( tls_revocation_policy::soft_fail );

// Require successful revocation check (strict)
// Also reject when status can't be determined (strict)
ctx.set_revocation_policy( tls_revocation_policy::hard_fail );
----

Expand All @@ -454,33 +445,15 @@ ctx.add_crl_file( "/path/to/issuer.crl" );
// From memory (e.g., fetched via HTTP)
std::string crl_data = fetch_crl_from_url( crl_url );
ctx.add_crl( crl_data );
----

CRLs must be refreshed periodically as they expire.

=== OCSP Stapling

OCSP provides per-certificate revocation status without downloading
large CRLs.

**Server-side** (provide pre-fetched OCSP response):

[source,cpp]
----
// Fetch OCSP response for your certificate
std::string ocsp_response = fetch_ocsp_response();

// Provide to clients during handshake
ctx.set_ocsp_staple( ocsp_response );
ctx.set_revocation_policy( tls_revocation_policy::hard_fail );
----

**Client-side** (require server to staple):
CRLs must be refreshed periodically as they expire.

[source,cpp]
----
// Fail if server doesn't provide OCSP staple
ctx.set_require_ocsp_staple( true );
----
NOTE: On WolfSSL, CRL checking requires a `HAVE_CRL` build; without it,
supplying a CRL or a non-disabled policy fails the handshake with
`std::errc::function_not_supported`.

=== Bootstrap vs. Hardened Connections

Expand All @@ -489,10 +462,9 @@ A common pattern uses two context configurations:
[NOTE]
====
Both contexts below verify the peer via `set_default_verify_paths()` and
`set_verify_mode( tls_verify_mode::peer )`. The revocation hardening on the
"hardened" path (`add_crl_file()` / `set_revocation_policy()`) is *not yet
applied* by the backends, so that context currently offers the same
verification as the bootstrap one.
`set_verify_mode( tls_verify_mode::peer )`. The "hardened" path adds CRL
checking (`add_crl_file()` / `set_revocation_policy( hard_fail )`), which
is applied on OpenSSL and on WolfSSL builds with `HAVE_CRL`.
====

[source,cpp]
Expand Down Expand Up @@ -576,8 +548,7 @@ scenarios.
NOTE: This example trusts public CAs via `set_default_verify_paths()`. On
WolfSSL builds without `WOLFSSL_SYS_CA_CERTS`, load an explicit CA bundle
instead, for example
`ctx.load_verify_file( "/etc/ssl/certs/ca-certificates.crt" );`. The
`set_min_protocol_version()` call is inert in this release.
`ctx.load_verify_file( "/etc/ssl/certs/ca-certificates.crt" );`.

[source,cpp]
----
Expand Down
108 changes: 42 additions & 66 deletions doc/modules/ROOT/pages/4.guide/4l.tls.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,12 @@ Trust anchors can also be supplied explicitly with
`add_certificate_authority()`, `load_verify_file()`, or `add_verify_path()`,
and `set_verify_callback()` installs a custom verification hook.

[WARNING]
.Not yet implemented
====
Several other `tls_context` settings are accepted by the API but are *not
yet wired up* by the OpenSSL or WolfSSL backends in this release. They are
stored and silently ignored:

* `set_alpn()` — ALPN is never negotiated.
* `set_min_protocol_version()` / `set_max_protocol_version()` — version
bounds are never applied; the range is the native default.
* `add_crl()` / `add_crl_file()`, `set_ocsp_staple()` /
`set_require_ocsp_staple()`, `set_revocation_policy()` — all
revocation checking is inert.
* `use_pkcs12()` / `use_pkcs12_file()` — return
`std::errc::function_not_supported`.
* `set_ciphersuites()` — applied by OpenSSL only; WolfSSL ignores it.
====
Protocol version bounds (`set_min_protocol_version()` /
`set_max_protocol_version()`), cipher suites (`set_ciphersuites()` and
`set_ciphersuites_tls13()`), ALPN (`set_alpn()`, read back with
`alpn_protocol()`), PKCS#12 credentials (`use_pkcs12()` /
`use_pkcs12_file()`), and CRL-based revocation (`add_crl()` /
`add_crl_file()` with `set_revocation_policy()`) are all supported.

[NOTE]
====
Expand Down Expand Up @@ -183,9 +172,10 @@ PKCS#12 (`.pfx` or `.p12`) files bundle certificate, key, and chain together:
ctx.use_pkcs12_file("credentials.pfx", "bundle-password");
----

NOTE: PKCS#12 loading is not yet implemented; `use_pkcs12()` and
`use_pkcs12_file()` return `std::errc::function_not_supported`. Load the
certificate and key separately for now.
NOTE: The bundle is decoded when the first stream is created; a malformed
bundle or wrong passphrase surfaces as a handshake failure. Intermediate
certificates in the bundle are loaded and sent during the handshake on
both backends.

=== Trust Anchors

Expand Down Expand Up @@ -238,8 +228,9 @@ ctx.set_min_protocol_version(tls_version::tls_1_3);
ctx.set_max_protocol_version(tls_version::tls_1_2);
----

NOTE: Protocol version bounds are not yet applied by the backends. The
negotiated range is whatever the native default method provides.
NOTE: On WolfSSL the ceiling is applied by selecting a version-specific
method (there is no native set-max call); a window whose minimum exceeds
its maximum yields a context that fails the handshake.

Available versions:

Expand All @@ -258,25 +249,36 @@ Available versions:

[source,cpp]
----
// OpenSSL-style cipher string
// TLS 1.2-and-below cipher list (OpenSSL syntax)
ctx.set_ciphersuites("ECDHE+AESGCM:ECDHE+CHACHA20");
// TLS 1.3 cipher suites (configured separately)
ctx.set_ciphersuites_tls13("TLS_AES_256_GCM_SHA384");
----

NOTE: `set_ciphersuites()` is applied by the OpenSSL backend only; the
WolfSSL backend accepts the string but silently ignores it.
NOTE: `set_ciphersuites()` covers TLS 1.2 and below; TLS 1.3 suites use
`set_ciphersuites_tls13()`. Both backends apply them (WolfSSL merges the
two into one list). Suite *names* differ between backends (OpenSSL
`TLS_AES_128_GCM_SHA256` vs WolfSSL `TLS13-AES128-GCM-SHA256`). The OpenSSL
security level is left at the library default; express a lower level
explicitly with a `@SECLEVEL=` token if required.

==== ALPN

Application-Layer Protocol Negotiation selects the application protocol:
Application-Layer Protocol Negotiation selects the application protocol.
Read the negotiated protocol after the handshake with
`stream.alpn_protocol()`:

[source,cpp]
----
// Prefer HTTP/2, fall back to HTTP/1.1
ctx.set_alpn({"h2", "http/1.1"});
// ... after handshake:
std::string_view proto = stream.alpn_protocol(); // e.g. "h2", or empty
----

NOTE: ALPN is not yet wired up; the protocol list is accepted but never
negotiated by either backend.
NOTE: On WolfSSL, ALPN requires a `HAVE_ALPN` build; without it, offering
protocols fails the handshake with `std::errc::function_not_supported`
rather than negotiate nothing silently.

=== Certificate Verification

Expand Down Expand Up @@ -361,53 +363,27 @@ Which certificates the callback sees depends on the backend:

=== Revocation Checking

WARNING: None of the revocation features below are wired up yet. CRLs
(`add_crl()` / `add_crl_file()`), OCSP stapling (`set_ocsp_staple()` /
`set_require_ocsp_staple()`), and `set_revocation_policy()` are all accepted
but inert. In particular, `set_require_ocsp_staple(true)` does *not* fail the
handshake when no staple is present, and `soft_fail` / `hard_fail` do not
change verification behavior.

==== Certificate Revocation Lists
Revocation is checked against Certificate Revocation Lists (CRLs). CRLs
are consulted only when a revocation policy other than `disabled` is set.

[source,cpp]
----
// Load CRL from file
// Load a CRL (PEM or DER), from file or memory
ctx.add_crl_file("issuer.crl");

// Load CRL from memory
ctx.add_crl(crl_data);
----

==== OCSP Stapling

For servers, provide a stapled OCSP response:

[source,cpp]
----
ctx.set_ocsp_staple(ocsp_response_data);
----

For clients, require the server to staple:

[source,cpp]
----
ctx.set_require_ocsp_staple(true);
----

==== Revocation Policy

[source,cpp]
// Choose how strict to be
ctx.set_revocation_policy(tls_revocation_policy::hard_fail);
----
// Don't check revocation (default)
ctx.set_revocation_policy(tls_revocation_policy::disabled);

// Check but allow if status unknown
ctx.set_revocation_policy(tls_revocation_policy::soft_fail);
Under `soft_fail`, a certificate whose status cannot be determined
(missing or expired CRL) is accepted, but one that is actually listed as
revoked is rejected. Under `hard_fail`, an undeterminable status is also
rejected. `disabled` (the default) skips revocation entirely.

// Fail if revocation status can't be determined
ctx.set_revocation_policy(tls_revocation_policy::hard_fail);
----
NOTE: On WolfSSL, CRL checking requires a `HAVE_CRL` build; without it,
supplying a CRL or a non-disabled policy fails the handshake with
`std::errc::function_not_supported` rather than skip the check silently.

== TLS Streams

Expand Down
Loading
Loading