Silk

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 NamedGroup

One key-exchange group selected for the authenticated connection.

X25519

X25519 = 0

X25519 with a 32-byte encoded public key.

P256

P256 = 1

The 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: bool

Whether 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 ClientLimits

Inclusive local resource policy for one client connection.

Field handshakeBodyBytes

pub handshakeBodyBytes: usize

Maximum body bytes in one handshake message.

Field handshakeBytes

pub handshakeBytes: usize

Maximum total initial-handshake bytes, including four-byte headers.

Field handshakeMessages

pub handshakeMessages: usize

Maximum initial-handshake message count.

Field peerCertificates

pub peerCertificates: usize

Maximum peer certificate count, including the leaf.

Field certificateBytes

pub certificateBytes: usize

Maximum DER bytes in one peer certificate.

Field certificateTotalBytes

pub certificateTotalBytes: usize

Maximum aggregate peer DER bytes.

Field cookieBytes

pub cookieBytes: usize

Maximum echoed HelloRetryRequest cookie bytes.

Field extensionBytes

pub extensionBytes: usize

Maximum bytes in one extension vector.

Field emptyRecords

pub emptyRecords: usize

Maximum consecutive empty application or compatibility records.

Field postHandshakeControls

pub postHandshakeControls: usize

Maximum consecutive post-handshake control messages without positive application content.

Field tickets

pub tickets: usize

Maximum accepted NewSessionTicket messages.

Field ticketBytes

pub ticketBytes: usize

Maximum total encoded NewSessionTicket bytes.

Field certificateDecode

pub certificateDecode: DecodeLimits

Strict certificate decoder policy.

Field sanDecode

pub sanDecode: SanDecodeLimits

Strict SAN adapter policy.

Field identity

pub identity: IdentityLimits

HTTPS identity policy.

Field path

pub path: ValidationLimits

Certificate-path policy.

Associated function ClientLimits.defaults

pub fn defaults() -> ClientLimits

Returns the finite TLS client defaults.

Implementation Copy for ClientLimits

impl Copy for ClientLimits

ClientConfig

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: ClientLimits

Finite connection limits and nested certificate policies.

Demand

pub enum Demand

The next action or observable connection event.

NeedInput

NeedInput = 0

Supply peer transport bytes.

NeedOutput

NeedOutput = 1

Write and acknowledge the complete pending output suffix before other work.

PlaintextReady

PlaintextReady = 2

Read authenticated buffered application plaintext.

Authenticated

Authenticated = 3

Observe the one-shot authentication transition and its metadata.

PeerClosed

PeerClosed = 4

The peer receive direction closed cleanly.

Closed

Closed = 5

Both directions closed cleanly and no output remains.

Progress

pub struct Progress

Exact progress from one client driver operation.

Field consumed

pub consumed: usize

The accepted prefix of caller input or application plaintext.

Field written

pub written: usize

The bytes copied into a caller plaintext destination.

Field demand

pub demand: Demand

The next action or event under the fixed precedence rule.

ClientOperation

pub enum ClientOperation

A public operation rejected because of caller state.

FeedInput

FeedInput = 0

Transport input feed.

Progress

Progress = 1

State-machine progress without new bytes.

AckWritten

AckWritten = 2

Pending-output acknowledgment.

ReadPlaintext

ReadPlaintext = 3

Application plaintext read.

WritePlaintext

WritePlaintext = 4

Application plaintext write.

RequestKeyUpdate

RequestKeyUpdate = 5

Local traffic-key update request.

CloseWrite

CloseWrite = 6

Local write-direction close.

EndInput

EndInput = 7

Transport input end.

ProtocolReason

pub enum ProtocolReason

A protocol grammar or state-machine rule rejected from the peer.

Record

Record = 0

A record has an invalid content type, version, length, padding, or inner framing.

UnexpectedMessage

UnexpectedMessage = 1

A handshake message arrived in an invalid order.

InvalidLength

InvalidLength = 2

A handshake message or vector is truncated or has trailing bytes.

Extension

Extension = 3

An extension is duplicated, unsolicited, misplaced, or malformed.

ServerHello

ServerHello = 4

ServerHello does not select the admitted TLS 1.3 profile.

HelloRetryRequest

HelloRetryRequest = 5

HelloRetryRequest violates its single-retry and changed-ClientHello rules.

CompatibilityCcs

CompatibilityCcs = 6

Compatibility CCS is outside its window or not exactly {1}.

CertificateRequest

CertificateRequest = 7

A CertificateRequest has invalid framing, duplication, or a profile-forbidden extension.

Certificate

Certificate = 8

A peer Certificate message violates its TLS envelope.

PostHandshake

PostHandshake = 9

A NewSessionTicket or KeyUpdate message violates its TLS envelope.

InternalState

InternalState = 10

The client reached an impossible private transition.

TlsLimitKind

pub enum TlsLimitKind

A named finite resource exhausted by peer input or configuration.

HandshakeBodyBytes

HandshakeBodyBytes = 0

One handshake body.

HandshakeBytes

HandshakeBytes = 1

Aggregate initial-handshake headers and bodies.

HandshakeMessages

HandshakeMessages = 2

Initial-handshake message count.

PeerCertificates

PeerCertificates = 3

Peer certificate count.

CertificateBytes

CertificateBytes = 4

DER bytes in one peer certificate.

CertificateTotalBytes

CertificateTotalBytes = 5

Aggregate peer certificate DER bytes.

CookieBytes

CookieBytes = 6

HelloRetryRequest cookie bytes.

ExtensionBytes

ExtensionBytes = 7

One extension vector.

EmptyRecords

EmptyRecords = 8

Consecutive empty application or compatibility records.

PostHandshakeControls

PostHandshakeControls = 9

Consecutive post-handshake control messages.

Tickets

Tickets = 10

NewSessionTicket count.

TicketBytes

TicketBytes = 11

Aggregate encoded NewSessionTicket bytes.

Arithmetic

Arithmetic = 12

Checked size arithmetic.

Alpn

Alpn = 13

One ALPN protocol or list.

CertificateDecode

CertificateDecode = 14

The configured certificate-decoder policy.

CertificateSanDecode

CertificateSanDecode = 15

The configured certificate-SAN decoder policy.

CertificateIdentity

CertificateIdentity = 16

The configured HTTPS identity policy.

CertificatePath

CertificatePath = 17

The configured certificate-path search policy.

CertificateProfile

CertificateProfile = 18

The configured semantic certificate-profile policy.

CertificateIdentityFailure

pub union CertificateIdentityFailure

A certificate identity failure that preserves its originating actor.

Decode

CertificateIdentityFailure.Decode { error: SanDecodeError }: CertificateIdentityFailure

The certificate SAN adapter rejected structure or a resource bound.

Field error

pub error: SanDecodeError

The complete SAN adapter failure.

Match

CertificateIdentityFailure.Match { error: IdentityError }: CertificateIdentityFailure

The HTTPS reference matcher rejected the complete decoded identity set.

Field error

pub error: IdentityError

The complete HTTPS identity failure.

CertificateVerifyFailure

pub union CertificateVerifyFailure

A server CertificateVerify failure with its selected signature implementation.

Ecdsa

CertificateVerifyFailure.Ecdsa { error: P256SignatureError }: CertificateVerifyFailure

ECDSA-P256/SHA-256 verification failed.

Field error

pub error: P256SignatureError

The exact primitive failure.

Rsa

CertificateVerifyFailure.Rsa { error: RsaError }: CertificateVerifyFailure

RSA-PSS-RSAE/SHA-256 verification failed.

Field error

pub error: RsaError

The exact primitive failure.

TlsError

pub union TlsError

A typed TLS client failure.

PeerAlert

TlsError.PeerAlert { code: u8 }: TlsError

The peer sent a fatal alert with this wire description.

Field code

pub code: u8

The alert description byte.

BadRecordMac

TlsError.BadRecordMac: TlsError

Protected record authentication failed.

ProtocolViolation

TlsError.ProtocolViolation { reason: ProtocolReason }: TlsError

Peer syntax, ordering, or negotiation violated the selected TLS profile.

Field reason

pub reason: ProtocolReason

The rejected rule.

CertificateDecode

TlsError.CertificateDecode { error: DecodeError }: TlsError

A peer certificate did not decode.

Field error

pub error: DecodeError

The complete strict decoder failure.

CertificatePath

TlsError.CertificatePath { error: ValidationError }: TlsError

Certificate-path construction or validation failed.

Field error

pub error: ValidationError

The complete bounded path failure.

CertificateIdentity

TlsError.CertificateIdentity { error: CertificateIdentityFailure }: TlsError

SAN decoding or HTTPS reference matching failed.

Field error

pub error: CertificateIdentityFailure

The exact nested identity failure.

CertificateVerify

TlsError.CertificateVerify { error: CertificateVerifyFailure }: TlsError

Server CertificateVerify did not authenticate the transcript with the selected leaf key.

Field error

pub error: CertificateVerifyFailure

The exact selected primitive failure.

Finished

TlsError.Finished: TlsError

Server Finished did not authenticate the transcript.

UnsupportedProfile

TlsError.UnsupportedProfile: TlsError

A server-selected suite, group, signature, or extension shape is outside the selected profile.

LimitExceeded

TlsError.LimitExceeded { kind: TlsLimitKind, limit: usize }: TlsError

A finite resource budget was exceeded.

Field kind

pub kind: TlsLimitKind

The exhausted resource category.

Field limit

pub limit: usize

The inclusive configured limit.

InvalidState

TlsError.InvalidState { operation: ClientOperation }: TlsError

A caller operation is invalid in the current state.

Field operation

pub operation: ClientOperation

The rejected operation.

EmptyBuffer

TlsError.EmptyBuffer: TlsError

A caller supplied an empty plaintext output buffer.

HandshakeTruncated

TlsError.HandshakeTruncated: TlsError

Transport input ended before authentication and peer closure.

Truncated

TlsError.Truncated: TlsError

Transport input ended after authentication without peer close_notify.

NoApplicationProtocol

TlsError.NoApplicationProtocol: TlsError

The server omits a required ALPN selection or selects a protocol that was not offered.

Implementation Copy for CertificateVerifyFailure

impl Copy for CertificateVerifyFailure

Authentication

pub struct Authentication<'a>

Authenticated result metadata borrowed from one client owner.

Method Authentication.suite

pub fn suite<'a, 'life1>(self: &'life1 Authentication<'a>) -> CipherSuite

Returns the negotiated TLS 1.3 cipher suite.

Method Authentication.group

pub fn group<'a, 'life1>(self: &'life1 Authentication<'a>) -> NamedGroup

Returns 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>) -> usize

Returns the selected explicit trust-anchor index.

Method Authentication.validationTime

pub fn validationTime<'a, 'life1>(self: &'life1 Authentication<'a>) -> Instant

Returns the exact caller-supplied validation instant, including nanoseconds.

Method Authentication.revocationStatus

pub fn revocationStatus<'a, 'life1>(self: &'life1 Authentication<'a>) -> RevocationStatus

Returns the revocation evidence produced by certificate-path validation.

Method Authentication.sanIndex

pub fn sanIndex<'a, 'life1>(self: &'life1 Authentication<'a>) -> usize

Returns the matching SAN's original certificate index.

Client

pub struct Client

One 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 Random

Creates 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 Random

Feeds 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 Random

Drains 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.

On this page

When to useDetailsGotchasExamplesQueue and acknowledge a ClientHello with explicit dependenciesNamedGroupX25519P256AlpnProtocolField bytesAlpnConfigDisabledOfferedField protocolsField requiredAssociated function AlpnConfig.defaultsImplementation Copy for silk/tls_client.AlpnProtocol<'a>Implementation Copy for silk/tls_client.AlpnConfig<'a>ClientLimitsField handshakeBodyBytesField handshakeBytesField handshakeMessagesField peerCertificatesField certificateBytesField certificateTotalBytesField cookieBytesField extensionBytesField emptyRecordsField postHandshakeControlsField ticketsField ticketBytesField certificateDecodeField sanDecodeField identityField pathAssociated function ClientLimits.defaultsImplementation Copy for ClientLimitsClientConfigField referenceField alpnField limitsDemandNeedInputNeedOutputPlaintextReadyAuthenticatedPeerClosedClosedProgressField consumedField writtenField demandClientOperationFeedInputProgressAckWrittenReadPlaintextWritePlaintextRequestKeyUpdateCloseWriteEndInputProtocolReasonRecordUnexpectedMessageInvalidLengthExtensionServerHelloHelloRetryRequestCompatibilityCcsCertificateRequestCertificatePostHandshakeInternalStateTlsLimitKindHandshakeBodyBytesHandshakeBytesHandshakeMessagesPeerCertificatesCertificateBytesCertificateTotalBytesCookieBytesExtensionBytesEmptyRecordsPostHandshakeControlsTicketsTicketBytesArithmeticAlpnCertificateDecodeCertificateSanDecodeCertificateIdentityCertificatePathCertificateProfileCertificateIdentityFailureDecodeField errorMatchField errorCertificateVerifyFailureEcdsaField errorRsaField errorTlsErrorPeerAlertField codeBadRecordMacProtocolViolationField reasonCertificateDecodeField errorCertificatePathField errorCertificateIdentityField errorCertificateVerifyField errorFinishedUnsupportedProfileLimitExceededField kindField limitInvalidStateField operationEmptyBufferHandshakeTruncatedTruncatedNoApplicationProtocolImplementation Copy for CertificateVerifyFailureAuthenticationMethod Authentication.suiteMethod Authentication.groupMethod Authentication.selectedAlpnMethod Authentication.leafDerMethod Authentication.intermediateIndicesMethod Authentication.anchorIndexMethod Authentication.validationTimeMethod Authentication.revocationStatusMethod Authentication.sanIndexClientAssociated function Client.makeDetailsGotchasMethod Client.pendingOutputMethod Client.authenticationMethod Client.feedInputDetailsMethod Client.progressMethod Client.ackWrittenMethod Client.readPlaintextGotchasMethod Client.writePlaintextDetailsMethod Client.requestKeyUpdateMethod Client.closeWriteMethod Client.endInput