silk/tls_client
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc.
An authenticated bounded TLS 1.3 client for caller-driven byte transports.
When to use
Use Client.make when an application has an explicit HTTPS identity, trust snapshot,
validation instant, cryptographic random provider, allocator, and byte transport. Use the
driver operations to move exact input and output prefixes without retaining caller buffers.
Details
The client supports the selected ChaCha20-Poly1305, AES-128-GCM, and AES-256-GCM TLS 1.3 suites with X25519 or P-256. It publishes plaintext only after path, identity, CertificateVerify, and Finished authentication and acknowledgment of the client Finished. Configuration, trust, handshake bytes, traffic state, and result evidence have one affine owner. Resource limits are finite and inclusive.
Gotchas
This module does not acquire trust, time, entropy, or a transport. It implements a selected
TLS 1.3 profile, not complete Web PKI. Logical state invalidation does not guarantee physical
secret erasure. Drop releases storage but does not send close_notify.
Examples
Queue and acknowledge a ClientHello with explicit dependencies
The client copies the HTTPS identity and consumes the trust snapshot. Transport writes are explicit: borrow the current suffix, write that exact prefix, then acknowledge only those bytes.
import silk.allocator as Allocators {Allocator, OutOfMemoryError}
import silk.effect as Effects {Effect}
import silk.https_identity as Identities {HttpsIdentity, IdentityError, OriginHost, ReferenceIdentity}
import silk.random as Randomness {Random}
import silk.result as Results {Result}
import silk.system_clock as Clocks {SystemClock}
import silk.tls_client as TlsClients {AlpnConfig, Client, ClientConfig, ClientLimits, TlsError}
import silk.trust_anchor as TrustAnchors {TrustAnchor}
import silk.trust_snapshot as TrustSnapshots {SnapshotLimits, TrustSnapshot, TrustSourceError}
import silk.u8
import silk.usize
import silk.vector as Vectors {Vector}
struct ExampleRandom { next: usize }
impl Random for ExampleRandom {
effect fn fillBytes(self: &mut Self, output: &mut [u8]) -> () {
let mut index = usize.ZERO
while index < output.length {
output[index] = usize.toU8((self.next + index) % 251 + usize.ONE)
index = index + usize.ONE
}
self.next = self.next + output.length
return ()
}
}
effect fn program<'name>(name: &'name [u8]) -> i32 ! OutOfMemoryError {
let admitted = HttpsIdentity.reference(OriginHost<'name>.Dns {bytes: name})
let reference = match move admitted {
Result<ReferenceIdentity<'name>, IdentityError>.Success {value} => value
Result<ReferenceIdentity<'name>, IdentityError>.Failure {error} => { return 0 }
}
let snapshot = TrustSnapshot.fromAnchors(
Vector.make<TrustAnchor>(),
SnapshotLimits {anchors: 0, encodedBytes: 0},
)
let trust = match move snapshot {
Result<TrustSnapshot, TrustSourceError>.Success {value} => move value
Result<TrustSnapshot, TrustSourceError>.Failure {error} => { return 0 }
}
let config = ClientConfig {
reference: reference,
alpn: AlpnConfig.defaults(),
limits: ClientLimits.defaults(),
}
let mut allocator = Allocator.systemAllocatorProvider()
let mut random = ExampleRandom {next: usize.ONE}
let made = run Client.make(&config, move trust, SystemClock.make(1789156800, 0))
|> Effect.provideMut<Random>(&mut random)
|> Effect.provideMut<Allocator>(&mut allocator)
let mut client = match move made {
Result<Client, TlsError>.Success {value} => move value
Result<Client, TlsError>.Failure {error} => { return 0 }
}
let pending = client.pendingOutput()
let length = pending.length
drop pending
if length == 0 { return 0 }
drop client.ackWritten(length)
return 42
}
effect fn recover(error: OutOfMemoryError) -> i32 { return 0 }
pub fn main() -> i32 { return run Effect.catchAll(program(b"example.com"), recover) }Import as Client with import silk.tls_client { Client }.
Public declarations: 15.
NamedGroup
pub enum NamedGroupOne key-exchange group selected for the authenticated connection.
X25519
X25519 = 0X25519 with a 32-byte encoded public key.
P256
P256 = 1The NIST P-256 curve with a 65-byte uncompressed encoded point.
AlpnProtocol
pub struct AlpnProtocol<'a>One borrowed opaque ALPN protocol offered in caller order.
Field bytes
pub bytes: &'a [u8]The nonempty protocol bytes, without a length prefix.
AlpnConfig
pub union AlpnConfig<'a>Borrowed ALPN policy copied by Client.make.
Disabled
AlpnConfig<'a>.Disabled: AlpnConfig<'a>Sends no ALPN extension and accepts no server selection.
Offered
AlpnConfig<'a>.Offered { protocols: &'a [silk/tls_client.AlpnProtocol<'a>], required: bool }: AlpnConfig<'a>Sends one ordered, nonempty, duplicate-free protocol list.
Field protocols
pub protocols: &'a [silk/tls_client.AlpnProtocol<'a>]The protocols in preference order.
Field required
pub required: boolWhether absence of a server selection is a failure.
Associated function AlpnConfig.defaults
pub fn defaults<'a>() -> silk/tls_client.AlpnConfig<'a>Returns the default policy, which sends no ALPN extension.
Implementation Copy for silk/tls_client.AlpnProtocol<'a>
impl Copy for silk/tls_client.AlpnProtocol<'a>Implementation Copy for silk/tls_client.AlpnConfig<'a>
impl Copy for silk/tls_client.AlpnConfig<'a>ClientLimits
pub struct ClientLimitsInclusive local resource policy for one client connection.
Field handshakeBodyBytes
pub handshakeBodyBytes: usizeMaximum body bytes in one handshake message.
Field handshakeBytes
pub handshakeBytes: usizeMaximum total initial-handshake bytes, including four-byte headers.
Field handshakeMessages
pub handshakeMessages: usizeMaximum initial-handshake message count.
Field peerCertificates
pub peerCertificates: usizeMaximum peer certificate count, including the leaf.
Field certificateBytes
pub certificateBytes: usizeMaximum DER bytes in one peer certificate.
Field certificateTotalBytes
pub certificateTotalBytes: usizeMaximum aggregate peer DER bytes.
Field cookieBytes
pub cookieBytes: usizeMaximum echoed HelloRetryRequest cookie bytes.
Field extensionBytes
pub extensionBytes: usizeMaximum bytes in one extension vector.
Field emptyRecords
pub emptyRecords: usizeMaximum consecutive empty application or compatibility records.
Field postHandshakeControls
pub postHandshakeControls: usizeMaximum consecutive post-handshake control messages without positive application content.
Field tickets
pub tickets: usizeMaximum accepted NewSessionTicket messages.
Field ticketBytes
pub ticketBytes: usizeMaximum total encoded NewSessionTicket bytes.
Field certificateDecode
pub certificateDecode: DecodeLimitsStrict certificate decoder policy.
Field sanDecode
pub sanDecode: SanDecodeLimitsStrict SAN adapter policy.
Field identity
pub identity: IdentityLimitsHTTPS identity policy.
Field path
pub path: ValidationLimitsCertificate-path policy.
Associated function ClientLimits.defaults
pub fn defaults() -> ClientLimitsReturns the finite TLS client defaults.
Implementation Copy for ClientLimits
impl Copy for ClientLimitsClientConfig
pub struct ClientConfig<'a>Borrowed client configuration that construction copies into owned storage.
Field reference
pub reference: silk/https_identity.ReferenceIdentity<'a>A reference already admitted by HttpsIdentity.reference; construction revalidates it.
Field alpn
pub alpn: silk/tls_client.AlpnConfig<'a>ALPN policy, with opaque protocols in caller preference order.
Field limits
pub limits: ClientLimitsFinite connection limits and nested certificate policies.
Demand
pub enum DemandThe next action or observable connection event.
NeedInput
NeedInput = 0Supply peer transport bytes.
NeedOutput
NeedOutput = 1Write and acknowledge the complete pending output suffix before other work.
PlaintextReady
PlaintextReady = 2Read authenticated buffered application plaintext.
Authenticated
Authenticated = 3Observe the one-shot authentication transition and its metadata.
PeerClosed
PeerClosed = 4The peer receive direction closed cleanly.
Closed
Closed = 5Both directions closed cleanly and no output remains.
Progress
pub struct ProgressExact progress from one client driver operation.
Field consumed
pub consumed: usizeThe accepted prefix of caller input or application plaintext.
Field written
pub written: usizeThe bytes copied into a caller plaintext destination.
Field demand
pub demand: DemandThe next action or event under the fixed precedence rule.
ClientOperation
pub enum ClientOperationA public operation rejected because of caller state.
FeedInput
FeedInput = 0Transport input feed.
Progress
Progress = 1State-machine progress without new bytes.
AckWritten
AckWritten = 2Pending-output acknowledgment.
ReadPlaintext
ReadPlaintext = 3Application plaintext read.
WritePlaintext
WritePlaintext = 4Application plaintext write.
RequestKeyUpdate
RequestKeyUpdate = 5Local traffic-key update request.
CloseWrite
CloseWrite = 6Local write-direction close.
EndInput
EndInput = 7Transport input end.
ProtocolReason
pub enum ProtocolReasonA protocol grammar or state-machine rule rejected from the peer.
Record
Record = 0A record has an invalid content type, version, length, padding, or inner framing.
UnexpectedMessage
UnexpectedMessage = 1A handshake message arrived in an invalid order.
InvalidLength
InvalidLength = 2A handshake message or vector is truncated or has trailing bytes.
Extension
Extension = 3An extension is duplicated, unsolicited, misplaced, or malformed.
ServerHello
ServerHello = 4ServerHello does not select the admitted TLS 1.3 profile.
HelloRetryRequest
HelloRetryRequest = 5HelloRetryRequest violates its single-retry and changed-ClientHello rules.
CompatibilityCcs
CompatibilityCcs = 6Compatibility CCS is outside its window or not exactly {1}.
CertificateRequest
CertificateRequest = 7A CertificateRequest has invalid framing, duplication, or a profile-forbidden extension.
Certificate
Certificate = 8A peer Certificate message violates its TLS envelope.
PostHandshake
PostHandshake = 9A NewSessionTicket or KeyUpdate message violates its TLS envelope.
InternalState
InternalState = 10The client reached an impossible private transition.
TlsLimitKind
pub enum TlsLimitKindA named finite resource exhausted by peer input or configuration.
HandshakeBodyBytes
HandshakeBodyBytes = 0One handshake body.
HandshakeBytes
HandshakeBytes = 1Aggregate initial-handshake headers and bodies.
HandshakeMessages
HandshakeMessages = 2Initial-handshake message count.
PeerCertificates
PeerCertificates = 3Peer certificate count.
CertificateBytes
CertificateBytes = 4DER bytes in one peer certificate.
CertificateTotalBytes
CertificateTotalBytes = 5Aggregate peer certificate DER bytes.
CookieBytes
CookieBytes = 6HelloRetryRequest cookie bytes.
ExtensionBytes
ExtensionBytes = 7One extension vector.
EmptyRecords
EmptyRecords = 8Consecutive empty application or compatibility records.
PostHandshakeControls
PostHandshakeControls = 9Consecutive post-handshake control messages.
Tickets
Tickets = 10NewSessionTicket count.
TicketBytes
TicketBytes = 11Aggregate encoded NewSessionTicket bytes.
Arithmetic
Arithmetic = 12Checked size arithmetic.
Alpn
Alpn = 13One ALPN protocol or list.
CertificateDecode
CertificateDecode = 14The configured certificate-decoder policy.
CertificateSanDecode
CertificateSanDecode = 15The configured certificate-SAN decoder policy.
CertificateIdentity
CertificateIdentity = 16The configured HTTPS identity policy.
CertificatePath
CertificatePath = 17The configured certificate-path search policy.
CertificateProfile
CertificateProfile = 18The configured semantic certificate-profile policy.
CertificateIdentityFailure
pub union CertificateIdentityFailureA certificate identity failure that preserves its originating actor.
Decode
CertificateIdentityFailure.Decode { error: SanDecodeError }: CertificateIdentityFailureThe certificate SAN adapter rejected structure or a resource bound.
Field error
pub error: SanDecodeErrorThe complete SAN adapter failure.
Match
CertificateIdentityFailure.Match { error: IdentityError }: CertificateIdentityFailureThe HTTPS reference matcher rejected the complete decoded identity set.
Field error
pub error: IdentityErrorThe complete HTTPS identity failure.
CertificateVerifyFailure
pub union CertificateVerifyFailureA server CertificateVerify failure with its selected signature implementation.
Ecdsa
CertificateVerifyFailure.Ecdsa { error: P256SignatureError }: CertificateVerifyFailureECDSA-P256/SHA-256 verification failed.
Field error
pub error: P256SignatureErrorThe exact primitive failure.
Rsa
CertificateVerifyFailure.Rsa { error: RsaError }: CertificateVerifyFailureRSA-PSS-RSAE/SHA-256 verification failed.
Field error
pub error: RsaErrorThe exact primitive failure.
TlsError
pub union TlsErrorA typed TLS client failure.
PeerAlert
TlsError.PeerAlert { code: u8 }: TlsErrorThe peer sent a fatal alert with this wire description.
Field code
pub code: u8The alert description byte.
BadRecordMac
TlsError.BadRecordMac: TlsErrorProtected record authentication failed.
ProtocolViolation
TlsError.ProtocolViolation { reason: ProtocolReason }: TlsErrorPeer syntax, ordering, or negotiation violated the selected TLS profile.
Field reason
pub reason: ProtocolReasonThe rejected rule.
CertificateDecode
TlsError.CertificateDecode { error: DecodeError }: TlsErrorA peer certificate did not decode.
Field error
pub error: DecodeErrorThe complete strict decoder failure.
CertificatePath
TlsError.CertificatePath { error: ValidationError }: TlsErrorCertificate-path construction or validation failed.
Field error
pub error: ValidationErrorThe complete bounded path failure.
CertificateIdentity
TlsError.CertificateIdentity { error: CertificateIdentityFailure }: TlsErrorSAN decoding or HTTPS reference matching failed.
Field error
pub error: CertificateIdentityFailureThe exact nested identity failure.
CertificateVerify
TlsError.CertificateVerify { error: CertificateVerifyFailure }: TlsErrorServer CertificateVerify did not authenticate the transcript with the selected leaf key.
Field error
pub error: CertificateVerifyFailureThe exact selected primitive failure.
Finished
TlsError.Finished: TlsErrorServer Finished did not authenticate the transcript.
UnsupportedProfile
TlsError.UnsupportedProfile: TlsErrorA server-selected suite, group, signature, or extension shape is outside the selected profile.
LimitExceeded
TlsError.LimitExceeded { kind: TlsLimitKind, limit: usize }: TlsErrorA finite resource budget was exceeded.
Field kind
pub kind: TlsLimitKindThe exhausted resource category.
Field limit
pub limit: usizeThe inclusive configured limit.
InvalidState
TlsError.InvalidState { operation: ClientOperation }: TlsErrorA caller operation is invalid in the current state.
Field operation
pub operation: ClientOperationThe rejected operation.
EmptyBuffer
TlsError.EmptyBuffer: TlsErrorA caller supplied an empty plaintext output buffer.
HandshakeTruncated
TlsError.HandshakeTruncated: TlsErrorTransport input ended before authentication and peer closure.
Truncated
TlsError.Truncated: TlsErrorTransport input ended after authentication without peer close_notify.
NoApplicationProtocol
TlsError.NoApplicationProtocol: TlsErrorThe server omits a required ALPN selection or selects a protocol that was not offered.
Implementation Copy for CertificateVerifyFailure
impl Copy for CertificateVerifyFailureAuthentication
pub struct Authentication<'a>Authenticated result metadata borrowed from one client owner.
Method Authentication.suite
pub fn suite<'a, 'life1>(self: &'life1 Authentication<'a>) -> CipherSuiteReturns the negotiated TLS 1.3 cipher suite.
Method Authentication.group
pub fn group<'a, 'life1>(self: &'life1 Authentication<'a>) -> NamedGroupReturns the negotiated ephemeral key-exchange group.
Method Authentication.selectedAlpn
pub fn selectedAlpn<'a, 'life1>(self: &'life1 Authentication<'a>) -> silk/option.Option<&'a [u8]>Returns the selected offered ALPN protocol, or None when ALPN was disabled or optional.
Method Authentication.leafDer
pub fn leafDer<'a, 'life1>(self: &'life1 Authentication<'a>) -> &'a [u8]Borrows the exact DER of the leaf used for path, identity, and signature authentication.
Method Authentication.intermediateIndices
pub fn intermediateIndices<'a, 'life1>(self: &'life1 Authentication<'a>) -> &'a [usize]Borrows selected intermediate indices in leaf-to-anchor order.
Method Authentication.anchorIndex
pub fn anchorIndex<'a, 'life1>(self: &'life1 Authentication<'a>) -> usizeReturns the selected explicit trust-anchor index.
Method Authentication.validationTime
pub fn validationTime<'a, 'life1>(self: &'life1 Authentication<'a>) -> InstantReturns the exact caller-supplied validation instant, including nanoseconds.
Method Authentication.revocationStatus
pub fn revocationStatus<'a, 'life1>(self: &'life1 Authentication<'a>) -> RevocationStatusReturns the revocation evidence produced by certificate-path validation.
Method Authentication.sanIndex
pub fn sanIndex<'a, 'life1>(self: &'life1 Authentication<'a>) -> usizeReturns the matching SAN's original certificate index.
Client
pub struct ClientOne affine authenticated TLS 1.3 client state machine.
Associated function Client.make
pub effect<'env> fn make<'a: 'env, 'life1: 'env, 'env>(config: &'life1 silk/tls_client.ClientConfig<'a>, trust: TrustSnapshot, validationTime: Instant) -> silk/result.Result<silk/tls_client.Client, silk/tls_client.TlsError> ! OutOfMemoryError ? &mut Allocator | &mut RandomCreates a client, consumes explicit trust, copies validated configuration, and queues ClientHello.
Details
The operation validates all caller-controlled limits, identity, time, and ALPN data before allocation. It samples no clock and loads no trust. DNS bytes become one owned lowercase A-label used for both SNI and certificate identity. IP references send no SNI.
Gotchas
The caller must supply a trustworthy validation instant and providers. Random-provider
failure remains fatal. Allocation refusal is an OutOfMemoryError Effect failure.
Method Client.pendingOutput
pub fn pendingOutput<'a>(self: &'a Client) -> &'a [u8]Borrows the exact unacknowledged TLS output suffix.
Method Client.authentication
pub fn authentication<'a>(self: &'a Client) -> silk/option.Option<silk/tls_client.Authentication<'a>>Returns authenticated metadata only after the one-shot authentication event becomes visible.
Method Client.feedInput
pub effect<'env> fn feedInput<'life0: 'env, 'life1: 'env, 'env>(self: &'life0 mut Client, input: &'life1 [u8]) -> silk/result.Result<silk/tls_client.Progress, silk/tls_client.TlsError> ! OutOfMemoryError ? &mut Allocator | &mut RandomFeeds a peer-ciphertext prefix without retaining the caller slice.
Details
The returned consumed count identifies the exact accepted prefix. A clean peer close
consumes and ignores all later transport bytes as required by TLS 1.3. Before requesting
more input, the client drains every complete handshake message exposed by the accepted
record and schedules mandatory response output.
Method Client.progress
pub effect<'life0> fn progress<'life0>(self: &'life0 mut Client) -> silk/result.Result<silk/tls_client.Progress, silk/tls_client.TlsError> ! OutOfMemoryError ? &mut Allocator | &mut RandomDrains complete buffered handshake work and schedules mandatory control output without input.
Method Client.ackWritten
pub fn ackWritten<'life0>(self: &'life0 mut Client, count: usize) -> silk/result.Result<silk/tls_client.Progress, silk/tls_client.TlsError>Acknowledges one transmitted prefix without acknowledging bytes implicitly.
Method Client.readPlaintext
pub fn readPlaintext<'life0, 'life1>(self: &'life0 mut Client, output: &'life1 mut [u8]) -> silk/result.Result<silk/tls_client.Progress, silk/tls_client.TlsError>Copies authenticated application plaintext or reports pending input, closure, or truncation.
Gotchas
A zero-length destination returns EmptyBuffer; it is never clean EOF.
Method Client.writePlaintext
pub fn writePlaintext<'life0, 'life1>(self: &'life0 mut Client, input: &'life1 [u8]) -> silk/result.Result<silk/tls_client.Progress, silk/tls_client.TlsError>Accepts at most one 16384-byte application fragment after authentication.
Details
Mandatory control output has priority and accepts no plaintext. A positive accepted prefix is encrypted once and must not be resubmitted after partial transport writes.
Method Client.requestKeyUpdate
pub fn requestKeyUpdate<'life0>(self: &'life0 mut Client) -> silk/result.Result<silk/tls_client.Progress, silk/tls_client.TlsError>Schedules one coalesced local KeyUpdate before the next application write.
Method Client.closeWrite
pub fn closeWrite<'life0>(self: &'life0 mut Client) -> silk/result.Result<silk/tls_client.Progress, silk/tls_client.TlsError>Idempotently schedules one local close_notify after accepted output.
Method Client.endInput
pub fn endInput<'life0>(self: &'life0 mut Client) -> silk/result.Result<silk/tls_client.Progress, silk/tls_client.TlsError>Marks transport input EOF without acknowledging pending output.