TLS Support

Configuration

TlsConfiguration groups independent optional TlsClientConfiguration and TlsServerConfiguration parts. Each part holds its own trust selection and shares an immutable identity. TlsTrustConfiguration describes profile trust; TlsSettings supplies application-wide defaults and native options. See Configuring TLS Profiles for configuring services, loading identities, and reloading profiles.

Registration and Replacement

CryptologyConfiguration::setTlsConfiguration() replaces each supplied role completely, preserving the other role already registered at that label. It validates supplied roles against the installed shared settings and does not merge fields within a role. CryptologyConfiguration::replaceTlsConfigurations() validates an entire TlsConfigurationSet before replacing its shared settings and named profiles atomically. A failed replacement leaves the installed set unchanged.

CryptologyConfiguration::hasTlsConfiguration() tests exact presence for one role. CryptologyConfiguration::clearTlsConfiguration() removes one named role, or both when no role is specified. CryptologyConfiguration::clearTlsConfigurations() preserves shared settings and built-in defaults. CryptologyConfiguration::reset() also restores shared TLS defaults. Connections retain their selected immutable profiles and effective policies across registry changes.

Label Resolution

CryptologyConfiguration::resolveTlsConfiguration() searches only the requested TlsRole at the exact label, its slash-delimited ancestors, and finally the reserved empty label. The returned TlsConfigurationResolution contains requested and matched labels, the role, the immutable configuration, and its effective certificate policy. Resolution performs no file access or native trust evaluation. An invalid selected role fails without trying an ancestor. CryptologyConfiguration::resolveTlsConfigurations() captures multiple labels from one registry state, allowing a server to select its default and SNI profiles consistently.

Both built-in defaults always exist and cannot be registered, replaced, or individually cleared. The client default has no identity and selects system trust subject to shared settings; all unresolved client labels reach it. The server default has no identity and fails synchronously when resolved. Low-level TLS connections request tls and HTTP requests http in both roles.

Named labels contain at most 16 nonempty slash-separated segments and 255 bytes, using lowercase ASCII letters, digits, and interior hyphens. At most 256 named labels may be installed; a label containing both roles counts once and defaults consume no capacity.

Trust Selection and Shared Settings

TlsTrustConfiguration::resolve() applies trust selection in this order:

  1. The profile’s explicit System Trust value.

  2. Explicit anchors in the profile, which select explicit trust.

  3. The shared System Trust value, if specified.

  4. The role default: system trust for clients, explicit trust for servers.

Profile system trust cannot be combined with explicit anchors, and intermediates require explicit anchors. Clients always require an effective trust source. Servers require one when TlsClientAuthentication is Optional or Required. Disabling shared system trust without supplying client anchors causes resolution to fail, never unverified acceptance.

The following ELCL fields belong to [TLS] and map to TlsSettings:

Field

Default

Effect

System Trust

Unspecified

Override role defaults unless the profile selects its own trust source.

Trust Allow Network

true

Allow native trust evaluation to retrieve intermediate certificates and revocation information.

Trust Bundle File

Automatic discovery

Override the Linux system CA bundle.

Identity Allow Interaction

false

Permit native identity providers to prompt during loading and signing.

A bundle override on another platform fails when a system-trust policy is evaluated. Identity interaction permission is captured at loading and remains attached to the signer. Changing that permission requires reloading the identity. See X.509 Certificates for platform trust behavior and revocation handling.

ELCL Parsing and Validation

TlsConfigurationParser::parse() parses the complete optional TLS section into an owned TlsConfigurationSet. The schema has shared [TLS] settings and optional *[TLS . Client]* and *[TLS . Server]* section lists. A label may occur once per role; matching labels across the two lists combine into one configuration. An absent TLS section returns a default set. ELCL names are case-insensitive and treat spaces and underscores equivalently.

TlsConfigurationParser::validationRules() and TlsConfigurationParser::version() expose the compiled schema and its version for a separate validation pass. Parsing always repeats schema validation, then loads certificate and identity material and checks profile trust. Validation alone does not load files or verify certificate/key matches. Password fields receive secret annotations even when supplied as ordinary ELCL text.

Relative material paths resolve from the file defining the field, including fields supplied by an included file. Absolute paths are accepted as written. Text and stream sources require absolute paths. Loading errors are reported as ConfError with the responsible source location and the underlying error as a cause where available.

TLS Identities

TlsIdentity combines a leaf-first certificate chain with a signer backed by a software key or an operating-system provider. The software-key constructor takes a move-only SigningPrivateKey. Construction rejects an empty chain, a leaf/key mismatch, or a key with no supported TLS 1.3 signature scheme. Identity chains are limited to 16 certificates and a one-MiB encoded TLS Certificate message. Mismatches and unsupported schemes report CryptologyError; empty components are caller precondition failures.

TlsConfiguration::setServer() and setClient() configure independent role parts. Their identities use immutable shared ownership. Configuration copies and connection snapshots share the identity without copying private key material. Replacing or clearing a registry entry does not invalidate existing snapshots. selectSignatureScheme() examines the peer’s offered schemes in order and returns the first compatible value.

Client Certificate Authentication

A client identity is sent only in response to an initial CertificateRequest, after the server’s certificate, CertificateVerify, and Finished messages have authenticated it. The identity must satisfy certificate validity, digital-signature key usage, client-authentication purpose, requested issuer names, and signature-scheme requirements. Unsupported nonempty OID filters suppress identity disclosure. An absent or unsuitable identity produces an empty certificate list; the connection never searches a store for another identity. TlsServerConfiguration::setClientAuthentication() selects whether the server requests a client certificate during the initial handshake:

Mode

Behavior

Disabled

Send no certificate request. This is the default.

Optional

Request a certificate and accept an empty certificate list as anonymous.

Required

Request a certificate and reject an empty certificate list with certificate_required.

Both enabled modes reject invalid presented certificates or proofs of private-key possession. CertificateRequest uses an empty context and supported signature algorithms without CA-name hints or OID filters. Client path validation, CertificateVerify, and Finished must all succeed before authenticated peer metadata is published. See Network Connections for server connection metadata and its lifetime. Post-handshake authentication, PSK/resumption, and early data are not supported.

Native Identity Stores

SystemIdentityStore::list() returns public SystemIdentityInfo metadata. load() selects an identity by its exact 32-byte SHA-256 leaf-certificate fingerprint and returns a TlsIdentity that retains the native signer without exporting the private key. Public intermediate certificates are collected from locally available material, within the identity chain limit. Enumeration is limited to 4,096 entries.

macOS uses identities from the current user’s Keychain. Windows uses the current-user personal certificate store with CNG private keys; legacy CAPI keys and machine stores are not supported. isSupported() reports whether a native provider is available; Linux applications can use file-based identities. Provisioning certificates and private keys remains a deployment task.

Store enumeration and identity loading are synchronous, so perform them during setup or on an appropriate worker. Connection-triggered signing runs on background workers as described in Network Connections. SystemIdentityStore{true} permits provider authorization dialogs; the default is silent access. On macOS, Keychain interaction policy is process-wide. The library serializes its own Keychain calls and restores the previous policy after each call; applications making independent Security.framework calls must coordinate their use of that policy.

See Configuring TLS Profiles for configuring file-based and native identities in ELCL.

TLS 1.3 Record Protection

The record-protection API implements the authenticated TLS 1.3 record transformations from RFC 8446. A TlsRecordEncryptor and TlsRecordDecryptor each retain one independent traffic-secret generation and sequence number. They operate on complete records so the exact wire header used as authenticated data cannot diverge from the header returned to or received from the network layer.

Cipher Suites and Traffic Secrets

TlsCipherSuite represents exactly TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, and TLS_CHACHA20_POLY1305_SHA256. It maps each RFC 8446 wire value to its registry name, HKDF hash, and symmetric construction. All supported constructions use a 96-bit nonce and a 128-bit authentication tag.

Create a move-only TlsTrafficSecret from exact SHA-256- or SHA-384-sized bytes. The consuming factory erases its input allocation after copying the secret into ProtectedByteBlock. An incorrect input length reports OutOfRangeError. There is intentionally no plaintext accessor. Record state resolves the secret only inside an erased callback while deriving a key, IV, or next-generation secret.

One Direction per Object

Construct a separate TlsRecordEncryptor and TlsRecordDecryptor for each protocol direction. protect() returns one complete header-plus-ciphertext record. unprotect() accepts exactly one complete record and returns a move-only TlsRecordPlaintext only after authentication and inner-plaintext validation succeed.

Callers choose the inner content type and an explicit padding length. This API deliberately defines no automatic padding policy. Empty application data is supported; empty Alert and Handshake content is rejected. Stream buffering, alert serialization, the record_size_limit extension, automatic padding strategies, and other optional record extensions remain in the network protocol layer.

Failures and Terminal State

TlsRecordErrorCategory distinguishes decode errors, unexpected messages, authentication failure, record overflow, and exhausted key usage. This lets a network implementation select an alert without parsing diagnostic text.

A local protect() parameter error occurs before key or sequence use and leaves the encryptor usable. Any failure after protection begins erases the sending generation so an uncertain nonce cannot be reused. Every peer-record rejection or backend failure permanently erases the decryptor. Authentication failure therefore exposes no plaintext and cannot be followed by another attempt with the same receiving object.

Bounds and Key Usage

The implementation limits TLSInnerPlaintext to \(2^{14} + 1\) bytes and rejects an outer TLSCiphertext length above \(2^{14} + 256\) bytes. Supported records have the tighter construction bound of inner length plus the fixed 16-byte tag.

For AES-GCM, isKeyUpdateRequired() becomes true after \(2^{24}\) successful records. Protection and deprotection refuse record number 23,726,566, the floor of \(2^{24.5}\). For ChaCha20-Poly1305 the signal becomes true while one old-key record remains, and processing refuses before advancing a 64-bit sequence would wrap.

updateApplicationTrafficKeys() performs only the caller-directed cryptographic transition from RFC 8446 Sections 4.6.3 and 7.2. Message parsing, serialization, and transition timing remain handshake responsibilities. The method fully derives the next traffic secret, key, and IV before replacement, immediately erases the old generation, and resets sequence and record counters to zero.

RFC 8446 Specification Mapping

The implementation follows the defining operations in review order:

  • Section 7.1 encodes HkdfLabel as the requested network-order length, "tls13 "-prefixed label, and empty context before HKDF expansion.

  • Section 7.3 derives write_key and the 96-bit write_iv from Secret with the "key" and "iv" labels.

  • Section 5.3 encodes the 64-bit sequence in network byte order, left-pads it to 12 bytes, and XORs all 12 bytes with write_iv to form the nonce.

  • Sections 5.2 and 5.4 encode content, the nonzero inner type, and explicit zero padding as TLSInnerPlaintext.

  • Section 5.2 encodes outer type 23, legacy version 0x0303, and ciphertext length. Those exact five bytes are additional_data for AEAD.

  • Section 5.2 performs AEAD protection or deprotection through the symmetric API. Tentative decryption storage remains sensitive and guarded until tag verification succeeds.

  • Section 5.4 reverse-scans authenticated plaintext over zero padding and validates the recovered inner type before copying content into its returned sensitive allocation.

  • Section 5.5 checks record and sequence usage before processing and advances counters exactly once after success.

  • Sections 4.6.3 and 7.2 derive "traffic upd", construct a complete replacement generation, erase the old secret, key, and IV, then reset the sequence.

Validation

Focused tests include the RFC 8448 Section 3 AES-128-GCM application record and key derivation, plus pinned AES-256-GCM and ChaCha20-Poly1305 composition vectors independently generated with Node.js 24.4.1 and OpenSSL 3.5.0. Boundary tests cover sequences, content types, explicit padding, empty application data, maximum lengths, malformed framing, header and ciphertext tampering, terminal erasure, usage ceilings, and KeyUpdate. A bounded ASan/UBSan libFuzzer target seeds valid, malformed, oversized, and authentication-tampered records.

Specifications

Programmatic TLS profile registration and resolution raise CryptologyError for unusable profiles, conflicting trust settings, duplicate roles, or registry capacity exhaustion. Invalid label syntax and role values are caller precondition failures. Linux trust-bundle discovery and unstable snapshots also raise CryptologyError; file access and certificate parsing retain their documented path, stream, and parse errors.

Interface

struct SystemIdentityInfo

Public metadata identifying one current-user certificate without exposing a native handle.

Public Members

mem::ByteBlock fingerprint

Exact SHA-256 of the leaf certificate DER, used for unambiguous selection.

X509Certificate certificate

Public leaf certificate; listing does not sign or export a private key.

class SystemIdentityStore

Explicit access to current-user OS certificate identities; Linux has no native provider.

See: TLS Support

Public Functions

explicit SystemIdentityStore(bool allowInteraction = false)

Create a store with explicit authorization-UI policy; no hidden worker threads are created.

Parameters:

allowInteraction – Whether provider authorization UI is permitted.

bool isSupported() const noexcept

Test whether this platform implements native identities.

util::List<SystemIdentityInfo> list() const

List public certificate metadata from the current-user identity store.

Throws:

CryptologyError – If native access fails or this platform is unsupported.

Returns:

Available public identities, without selecting one for a connection.

TlsIdentity load(const mem::ByteBlock &fingerprint) const

Load exactly one identity by SHA-256 certificate fingerprint, retaining private keys in their provider.

Parameters:

fingerprint – Exactly 32 fingerprint bytes.

Throws:

CryptologyError – If no exact usable identity exists, access is denied, or interaction is required.

Returns:

The identity and its available chain, ready for explicit TLS configuration.

class TlsCipherSuite

A supported TLS 1.3 cipher suite from RFC 8446 section 9.1.

The suite binds one AEAD construction to the hash used by HKDF and the handshake transcript. Only the three cipher suites defined by RFC 8446 are represented.

See: TLS Support

Public Types

enum Value

Supported RFC 8446 cipher-suite values.

Values:

enumerator Aes128GcmSha256

TLS_AES_128_GCM_SHA256.

enumerator Aes256GcmSha384

TLS_AES_256_GCM_SHA384.

enumerator ChaCha20Poly1305Sha256

TLS_CHACHA20_POLY1305_SHA256.

Public Functions

constexpr TlsCipherSuite() noexcept = default

Create the mandatory-to-implement TLS_AES_128_GCM_SHA256 suite.

inline constexpr TlsCipherSuite(const Value value) noexcept

Create a suite from a supported raw value.

inline constexpr uint16_t toRawValue() const noexcept

Get the exact unsigned 16-bit TLS wire value.

HashAlgorithm hashAlgorithm() const noexcept

Get the suite’s HKDF and transcript hash.

SymmetricEncryptionType encryptionType() const noexcept

Get the suite’s AEAD construction.

text::String toString() const

Convert the suite to its exact TLS registry name.

Public Static Functions

static std::optional<TlsCipherSuite> fromRawValue(uint16_t value) noexcept

Parse one supported unsigned 16-bit TLS wire value.

static TlsCipherSuite fromRawValueOrThrow(uint16_t value)

Parse one supported unsigned 16-bit TLS wire value.

Throws:

err::ParseError – If the value is not supported.

static std::span<const TlsCipherSuite> all() noexcept

Get all supported TLS 1.3 cipher suites in preference order.

enum class erbsland::cryptology::TlsClientAuthentication : uint8_t

Whether a TLS server requests and requires a client certificate.

Values:

enumerator Disabled

Do not request a certificate.

enumerator Optional

Accept absence, but verify every presented certificate.

enumerator Required

Require a verified certificate and proof of key possession.

class TlsClientConfiguration

The independent client part of an application TLS profile.

Public Functions

TlsClientConfiguration() = default

Create a client configuration inheriting trust defaults and without an identity.

inline explicit TlsClientConfiguration(TlsTrustConfiguration trust, TlsIdentityConstPtr identity = {})

Create a client configuration with explicit trust settings and optional identity.

Parameters:
  • trust – Profile trust settings.

  • identity – Optional immutable client identity.

inline explicit TlsClientConfiguration(TlsIdentity identity)

Create a client configuration with an identity and inherited trust.

Parameters:

identity – The explicitly selected client identity.

inline const TlsTrustConfiguration &trust() const noexcept

Get profile trust settings.

inline void setTrust(TlsTrustConfiguration value)

Replace profile trust settings.

inline const TlsIdentityConstPtr &identity() const noexcept

Get the explicitly selected certificate identity, or null when absent.

inline void setIdentity(TlsIdentity value)

Set the certificate identity.

inline void setIdentity(TlsIdentityConstPtr value)

Share an immutable certificate identity.

class TlsConfiguration

Independent client and server parts sharing one application profile label.

Public Functions

TlsConfiguration() = default

Create a profile without either role.

inline explicit TlsConfiguration(TlsClientConfiguration client)

Create a client-only profile.

Parameters:

client – Complete client configuration.

inline explicit TlsConfiguration(TlsServerConfiguration server)

Create a server-only profile.

Parameters:

server – Complete server configuration.

inline const std::optional<TlsClientConfiguration> &client() const noexcept

Get the optional client part.

inline void setClient(TlsClientConfiguration value)

Replace the client part without modifying the server part.

inline const std::optional<TlsServerConfiguration> &server() const noexcept

Get the optional server part.

inline void setServer(TlsServerConfiguration value)

Replace the server part without modifying the client part.

inline bool hasRole(TlsRole role) const

Test whether this profile contains the requested local role.

Parameters:

role – A valid local TLS role.

Returns:

Whether that role is present.

inline void clearRole(TlsRole role)

Remove one role without modifying the other.

Parameters:

role – A valid local TLS role.

inline void merge(const TlsConfiguration &value)

Replace only the role parts supplied by another profile.

Parameters:

value – The supplied replacement parts.

Public Static Functions

static inline void validateRole(TlsRole role)

Validate a local role.

Parameters:

role – The role to check.

class TlsConfigurationEntry

One labeled TLS configuration parsed from an external representation.

See: Configuring TLS Profiles

Public Functions

inline TlsConfigurationEntry(text::String label, TlsConfiguration configuration) noexcept

Create one labeled TLS configuration entry.

Parameters:
  • label – The validated registry label.

  • configuration – The complete TLS configuration.

inline const text::String &label() const noexcept

Get the registry label.

inline const TlsConfiguration &configuration() const noexcept

Get the parsed TLS configuration.

inline TlsConfiguration takeConfiguration() noexcept

Move the parsed TLS configuration out of this entry.

class TlsConfigurationParser

Parse shared TLS settings and role-specific profile lists.

See: Configuring TLS Profiles

Public Functions

TlsConfigurationSet parse(const conf::ValuePtr &sectionValue) const

Validate and load a complete TLS section without modifying the application registry.

Parameters:

sectionValue – The optional TLS section; null produces the default empty configuration set.

Throws:

conf::ConfError – If validation or referenced-material loading fails.

Returns:

Owned shared settings and grouped role profiles.

Public Static Functions

static const conf::vr::RulesPtr &validationRules()

Access the compiled validation rules shared by all parser instances.

Returns:

The immutable compiled rules for the complete TLS section.

static conf::Integer version()

Get the current version of the TLS configuration format.

class TlsConfigurationResolution

One coherently resolved immutable TLS configuration.

Public Functions

TlsConfigurationResolution() = default

Create an empty resolution.

inline TlsConfigurationResolution(text::String requestedLabel, text::String matchedLabel, TlsConfigurationConstPtr configuration, TlsRole role, std::optional<X509TlsCertificatePolicy> policy) noexcept

Create a successful resolution.

Parameters:
  • requestedLabel – The label originally requested.

  • matchedLabel – The exact profile or built-in default selected by fallback.

  • role – The selected local role.

  • policy – The effective certificate policy.

  • configuration – The immutable configuration snapshot.

inline const text::String &requestedLabel() const noexcept

Get the label originally requested by the caller.

inline const text::String &matchedLabel() const noexcept

Get the exact profile label or empty built-in default label selected by fallback resolution.

inline const TlsConfigurationConstPtr &configuration() const noexcept

Get the immutable configuration snapshot.

inline TlsRole role() const noexcept

Get the selected local TLS role.

inline const std::optional<X509TlsCertificatePolicy> &certificatePolicy() const noexcept

Get the effective certificate policy, absent when client authentication is disabled.

class TlsConfigurationSet

Owned shared settings and named profiles published as one TLS registry update.

Public Functions

inline const TlsSettings &settings() const noexcept

Get shared settings.

inline void setSettings(TlsSettings value)

Replace shared settings.

inline const std::vector<TlsConfigurationEntry> &entries() const noexcept

Get the named profiles.

inline void add(text::String label, TlsConfiguration configuration)

Append a named profile; publication validates labels, duplicates, and roles.

Parameters:
  • label – Nonempty application label.

  • configuration – The supplied role parts.

class TlsIdentity

One immutable role-neutral TLS certificate chain and opaque software or native signer.

Matching follows RFC 8410 for Ed25519, RFC 5480 for P-256, and RFC 3279/RFC 4055 for RSA. Signature-scheme selection follows RFC 8446 section 4.2.3 in the peer-provided order and never permits certificate-only PKCS#1 schemes. The identity owns the move-only key; configurations share it only through a pointer to const.

See: TLS Support

Public Functions

TlsIdentity(X509CertificateBundle certificateChain, SigningPrivateKey signingKey)

Create a validated software identity usable in either TLS role.

Parameters:
  • certificateChain – The leaf-first certificate chain. Must not be empty, and its leaf public key must match signingKey.

  • signingKey – The matching private key. Must not be empty and must support a usable TLS 1.3 signature scheme.

Throws:

CryptologyError – If the certificate and key do not match or support no TLS 1.3 signature scheme.

auto selectSignatureScheme(const util::List<TlsSignatureScheme> &offeredSchemes) const noexcept -> std::optional<TlsSignatureScheme>

Select the first peer-offered scheme compatible with this identity.

Parameters:

offeredSchemes – ClientHello or CertificateRequest signature_algorithms values in wire order.

Returns:

The first compatible TLS 1.3 CertificateVerify scheme, or no value.

inline const X509CertificateBundle &certificateChain() const noexcept

Get the leaf-first certificate chain.

bool isNative() const noexcept

Test whether the private key remains in a native provider.

auto signTlsCertificateVerify(TlsSignatureScheme scheme, mem::ConstByteSpan message) const -> mem::ByteBlock

Sign RFC 8446 section 4.4.3 content using the owned provider; native operations may block.

Parameters:
  • scheme – A compatible TLS CertificateVerify scheme.

  • message – Complete CertificateVerify content.

Throws:

CryptologyError – If signing, provider access, or the signature fault check fails.

Returns:

The verified signature, without exposing private key material.

enum class erbsland::cryptology::TlsRole : uint8_t

The local role used to select a TLS profile.

Values:

enumerator Client

Initiate a connection and authenticate a server.

enumerator Server

Accept a connection and optionally authenticate a client.

class TlsServerConfiguration

The independent server part of an application TLS profile.

Public Functions

TlsServerConfiguration() = default

Create an incomplete server configuration requiring an identity before registration.

inline explicit TlsServerConfiguration(TlsIdentity identity)

Create a server configuration with client authentication disabled.

Parameters:

identity – The explicitly selected server identity.

inline const TlsTrustConfiguration &trust() const noexcept

Get profile trust settings.

inline void setTrust(TlsTrustConfiguration value)

Replace profile trust settings.

inline const TlsIdentityConstPtr &identity() const noexcept

Get the explicitly selected certificate identity, or null when absent.

inline void setIdentity(TlsIdentity value)

Set the certificate identity.

inline void setIdentity(TlsIdentityConstPtr value)

Share an immutable certificate identity.

inline TlsClientAuthentication clientAuthentication() const noexcept

Get the client certificate authentication requirement.

inline void setClientAuthentication(TlsClientAuthentication value) noexcept

Set the client certificate authentication requirement.

class TlsSettings

Shared settings captured with an application TLS configuration set.

Public Functions

inline std::optional<bool> systemTrust() const noexcept

Get the shared trust selection, or no value for role defaults.

inline void setSystemTrust(std::optional<bool> value) noexcept

Set the shared trust selection; no value restores role defaults.

inline bool allowsTrustNetwork() const noexcept

Test whether native trust evaluation may retrieve certificates and revocation information.

inline void setTrustAllowNetwork(bool value) noexcept

Set native trust retrieval permission.

inline const path::Path &trustBundlePath() const noexcept

Get the Linux system trust bundle override.

inline void setTrustBundlePath(path::Path value)

Set the Linux system trust bundle override.

inline bool allowsIdentityInteraction() const noexcept

Test whether loading and using native identities may display authorization dialogs.

inline void setIdentityAllowInteraction(bool value) noexcept

Set permission captured when native identities are loaded.

class TlsSignatureScheme

A supported TLS 1.3 signature scheme.

Code points and their permitted uses follow RFC 8446 section 4.2.3. The PKCS#1 v1.5 schemes are retained only for signatures appearing in certificates and are never allowed for TLS 1.3 CertificateVerify messages. All values describe public verification inputs; this type creates and retains no secret state requiring erasure.

See: X.509 Certificates

Public Types

enum Value

The supported RFC 8446 SignatureScheme values.

Values:

enumerator RsaPkcs1Sha256

Certificate-only RSASSA-PKCS1-v1_5 with SHA-256.

enumerator RsaPkcs1Sha384

Certificate-only RSASSA-PKCS1-v1_5 with SHA-384.

enumerator RsaPkcs1Sha512

Certificate-only RSASSA-PKCS1-v1_5 with SHA-512.

enumerator EcdsaSecp256r1Sha256

ECDSA with P-256 and SHA-256.

enumerator EcdsaSecp384r1Sha384

ECDSA with P-384 and SHA-384.

enumerator RsaPssRsaeSha256

RSASSA-PSS/SHA-256 with an rsaEncryption public key.

enumerator RsaPssRsaeSha384

RSASSA-PSS/SHA-384 with an rsaEncryption public key.

enumerator RsaPssRsaeSha512

RSASSA-PSS/SHA-512 with an rsaEncryption public key.

enumerator Ed25519

Pure Ed25519.

enumerator RsaPssPssSha256

RSASSA-PSS/SHA-256 with an id-RSASSA-PSS public key.

enumerator RsaPssPssSha384

RSASSA-PSS/SHA-384 with an id-RSASSA-PSS public key.

enumerator RsaPssPssSha512

RSASSA-PSS/SHA-512 with an id-RSASSA-PSS public key.

Public Functions

constexpr TlsSignatureScheme() noexcept = default

Create the mandatory-to-implement RSA-PSS-RSAE/SHA-256 scheme.

inline constexpr TlsSignatureScheme(const Value value) noexcept

Create a scheme from its supported raw value.

Parameters:

value – The supported raw scheme value.

bool isAllowedForCertificateVerify() const noexcept

Test whether this scheme may verify a TLS 1.3 CertificateVerify signature.

bool isAllowedForCertificateSignature() const noexcept

Test whether this scheme may describe a signature appearing in an X.509 certificate.

inline constexpr uint16_t toRawValue() const noexcept

Get the exact unsigned 16-bit TLS wire value.

text::String toString() const

Convert the scheme to its stable TLS registry name.

X509AlgorithmIdentifier signatureAlgorithmIdentifier() const

Map this scheme to the complete X.509 signature AlgorithmIdentifier.

Public Static Functions

static std::optional<TlsSignatureScheme> fromRawValue(uint16_t value) noexcept

Parse one supported unsigned 16-bit TLS wire value.

Parameters:

value – The raw wire value.

Returns:

The matching scheme, or no value when unsupported.

static TlsSignatureScheme fromRawValueOrThrow(uint16_t value)

Parse one supported unsigned 16-bit TLS wire value.

Parameters:

value – The raw wire value.

Throws:

err::ParseError – If the value is not supported.

Returns:

The matching scheme.

class TlsTrustConfiguration

A profile trust selection resolved against shared TLS settings.

Public Functions

TlsTrustConfiguration() = default

Create a trust configuration inheriting application and role defaults.

inline explicit TlsTrustConfiguration(X509CertificateBundle anchors, X509CertificateBundle intermediates = {})

Create an explicit-anchor trust configuration.

Parameters:
  • anchors – Trusted root or directly trusted leaf certificates.

  • intermediates – Untrusted issuer candidates.

inline std::optional<bool> systemTrust() const noexcept

Get the profile override, or no value for inherited selection.

inline void setSystemTrust(std::optional<bool> value) noexcept

Set the profile override.

inline const X509CertificateBundle &trustAnchors() const noexcept

Get explicit anchors.

inline void setTrustAnchors(X509CertificateBundle value)

Set explicit anchors, implicitly selecting explicit trust unless overridden.

inline const X509CertificateBundle &intermediates() const noexcept

Get additional untrusted intermediate certificates.

inline void setIntermediates(X509CertificateBundle value)

Set additional untrusted intermediate certificates.

inline auto resolve(const TlsSettings &settings, TlsRole role, bool required = true) const -> std::optional<X509TlsCertificatePolicy>

Resolve a complete policy without native work or file access.

Parameters:
  • settings – Shared application settings.

  • role – Local connection role.

  • required – Whether a usable trust source is required.

Throws:

CryptologyError – If trust settings conflict or required trust is missing.

Returns:

The effective policy, or no policy when verification is disabled.

enum class erbsland::cryptology::TlsRecordContentType : uint8_t

An authenticated TLS 1.3 inner-plaintext content type from RFC 8446 sections 5.1 and 5.2.

Values:

enumerator Alert

One TLS alert message.

enumerator Handshake

One or more TLS handshake-message fragments.

enumerator ApplicationData

Opaque application data.

class TlsRecordDecryptor

A move-only TLS 1.3 record decryptor implementing RFC 8446 sections 5.2&#8212;5.5 and 7.2&#8212;7.3.

It authenticates one complete TLSCiphertext record before returning sensitive plaintext. Any malformed record, authentication failure, overflow, or exhausted key makes this state terminal and erases all retained secrets.

See: TLS Support

Public Functions

TlsRecordDecryptor() noexcept

Create an empty record-decryptor placeholder.

TlsRecordDecryptor(TlsCipherSuite suite, TlsTrafficSecret &&trafficSecret)

Create RFC 8446 Sections 5.3 and 7.3 receiving state by consuming a matching traffic secret.

Parameters:
  • trafficSecret – The traffic secret to consume. Its hash algorithm must match the cipher suite.

  • suite – The selected TLS cipher suite.

Throws:

CryptologyError – If key derivation or protected storage fails.

~TlsRecordDecryptor()

Securely erase record-protection state.

TlsRecordPlaintext unprotect(mem::ConstByteSpan record)

Authenticate and deprotect one exact complete TLS 1.3 record under RFC 8446 Sections 5.2&#8212;5.5.

Parameters:

record – The complete five-byte header and encrypted body.

Throws:
  • TlsRecordError – For malformed, unauthenticated, overflowing, or exhausted input.

  • CryptologyError – If the cryptographic backend fails independently of peer authentication.

Returns:

Authenticated sensitive content and its inner content type.

void updateApplicationTrafficKeys()

Derive and install the next application traffic-secret generation under RFC 8446 Sections 4.6.3 and 7.2.

The caller must invoke this only after authenticating the RFC 8446 section 4.6.3 KeyUpdate message.

void secureErase() noexcept

Securely erase all retained secret state and restore the empty state.

inline bool isEmpty() const noexcept

Test whether no record-protection state is retained.

bool isKeyUpdateRequired() const noexcept

Test the RFC 8446 Section 5.5 signal that the peer should update before more application data.

TlsCipherSuite suite() const

Get the configured cipher suite.

This decryptor must not be empty.

class TlsRecordEncryptor

A move-only TLS 1.3 record encryptor implementing RFC 8446 sections 5.2&#8212;5.5 and 7.2&#8212;7.3.

It constructs complete TLSCiphertext records, maintains one sending sequence, enforces key-usage limits, and keeps traffic secrets protected outside scoped derivation. Padding length is explicit; no padding policy is implied.

See: TLS Support

Public Functions

TlsRecordEncryptor() noexcept

Create an empty record-encryptor placeholder.

TlsRecordEncryptor(TlsCipherSuite suite, TlsTrafficSecret &&trafficSecret)

Create RFC 8446 Sections 5.3 and 7.3 sending state by consuming a matching traffic secret.

Parameters:
  • trafficSecret – The traffic secret to consume. Its hash algorithm must match the cipher suite.

  • suite – The selected TLS cipher suite.

Throws:

CryptologyError – If key derivation or protected storage fails.

~TlsRecordEncryptor()

Securely erase record-protection state.

auto protect(TlsRecordContentType type, mem::ConstByteSpan content, unit::ByteCount paddingLength = unit::ByteCount::zero()) -> mem::ByteBlock

Protect one complete TLS 1.3 record under RFC 8446 Sections 5.2&#8212;5.5.

Parameters:
  • type – The authenticated inner content type. Must be Alert, Handshake, or ApplicationData.

  • content – The exact content bytes. Must contain at most 16,384 bytes; only ApplicationData may be empty.

  • paddingLength – The number of zero padding octets. Content plus padding must contain at most 16,384 bytes.

Throws:
Returns:

A complete TLSCiphertext header and encrypted body.

void updateApplicationTrafficKeys()

Derive and install the next application traffic-secret generation under RFC 8446 Sections 4.6.3 and 7.2.

The caller must invoke this only at the RFC 8446 section 4.6.3 protocol transition.

void secureErase() noexcept

Securely erase all retained secret state and restore the empty state.

inline bool isEmpty() const noexcept

Test whether no record-protection state is retained.

bool isKeyUpdateRequired() const noexcept

Test the RFC 8446 Section 5.5 signal for sending KeyUpdate before more application data.

TlsCipherSuite suite() const

Get the configured cipher suite.

This encryptor must not be empty.

class TlsRecordError : public erbsland::err::RuntimeError

A categorized failure from TLS 1.3 record protection or deprotection.

Categories preserve the RFC 8446 alert distinction required by sections 5 and 6 without coupling cryptology to network alert serialization.

See: TLS Support

Public Functions

TlsRecordError(TlsRecordErrorCategory category, text::String reason) noexcept

Create a categorized record error.

inline TlsRecordErrorCategory category() const noexcept

Get the stable failure category.

enum class erbsland::cryptology::TlsRecordErrorCategory : uint8_t

A stable TLS 1.3 record-protection failure category.

Values:

enumerator DecodeError

The complete record framing or encoded length is malformed.

enumerator UnexpectedMessage

The outer or authenticated inner record semantics are invalid.

enumerator BadRecordMac

AEAD authentication or decryption failed.

enumerator RecordOverflow

A ciphertext or authenticated plaintext exceeds its RFC bound.

enumerator KeyUsageExhausted

The sequence number or cipher-specific record limit is exhausted.

class TlsRecordPlaintext

Authenticated content recovered from one TLS 1.3 record.

The content type is the final nonzero TLSInnerPlaintext octet from RFC 8446 section 5.2. Content is retained in sensitive storage and is never constructed until AEAD authentication succeeds.

See: TLS Support

Public Functions

TlsRecordPlaintext(TlsRecordContentType type, mem::ByteBlock content) noexcept

Create authenticated record content.

~TlsRecordPlaintext()

Securely erase retained plaintext.

void secureErase() noexcept

Securely erase content and restore an empty payload.

mem::ByteBlock takeContent() noexcept

Transfer the authenticated content to the caller.

inline bool isEmpty() const noexcept

Test whether the authenticated content is empty.

inline TlsRecordContentType type() const noexcept

Get the authenticated inner content type.

inline const mem::ByteBlock &content() const noexcept

Borrow the authenticated content.

class TlsTrafficSecret

A move-only TLS 1.3 traffic secret retained in application-protected storage.

The secret length is the selected SHA-256 or SHA-384 digest length required by RFC 8446 sections 7.1&#8212;7.3. There is no public plaintext accessor; record protection resolves the secret only for scoped derivation and erasure.

See: TLS Support

Public Functions

TlsTrafficSecret() noexcept = default

Create an empty traffic-secret placeholder.

~TlsTrafficSecret()

Securely erase the protected envelope.

void secureErase() noexcept

Securely erase the protected envelope and restore the empty state.

inline bool isEmpty() const noexcept

Test whether no traffic secret is stored.

inline HashAlgorithm hashAlgorithm() const noexcept

Get the traffic-secret hash algorithm.

inline unit::ByteCount byteLength() const noexcept

Get the plaintext secret length without resolving it.

Public Static Functions

static TlsTrafficSecret fromBytes(HashAlgorithm algorithm, mem::ConstByteSpan data)

Protect a copy of RFC 8446 Sections 7.1&#8212;7.3 exact digest-sized traffic-secret bytes.

The caller retains ownership and erasure responsibility for the borrowed bytes.

Parameters:
  • algorithm – The traffic-secret hash algorithm. Must be SHA-256 or SHA-384.

  • data – The traffic-secret bytes. Length must equal the selected hash digest size.

Throws:

err::OutOfRangeError – If the secret length does not match the selected hash digest size.

static TlsTrafficSecret fromBytes(HashAlgorithm algorithm, mem::ByteBlock &&data)

Protect and then erase an owning RFC 8446 Sections 7.1&#8212;7.3 exact digest-sized traffic-secret block.

Parameters:
  • algorithm – The traffic-secret hash algorithm. Must be SHA-256 or SHA-384.

  • data – The traffic-secret block to erase after protection. Length must equal the selected hash digest size.

Throws:

err::OutOfRangeError – If the secret length does not match the selected hash digest size.