zig-tls

API reference

On this page 401

Every declaration below is extracted from zig-tls's source, with the doc comments as written there. A declaration listed without prose is public but undocumented in the source.

Root

max_ciphertext_record_len

const max_ciphertext_record_len = @import("cipher.zig").max_ciphertext_record_len

input_buffer_len

const input_buffer_len = max_ciphertext_record_len; // 16645 bytes

Buffer of this size will fit any tls ciphertext record sent by other side. To decrytp we need full record, smalled buffer will not work in general case. Bigger can be used for performance reason.

output_buffer_len

const output_buffer_len = @import("cipher.zig").max_encrypted_record_len; // 16469 bytes

Needed output buffer during handshake is the size of the tls hello message, which is (when client authentication is not used) ~1600 bytes. After handshake it limits how big tls record can be produced. This suggested value can hold max ciphertext record produced with this implementation.

Connection

const Connection = @import("connection.zig").Connection

ecdsa_p256

const ecdsa_p256 = @import("crypto/ecdsa_p256.zig")

P-256 ECDSA (CertificateVerify hot path, bench micro-benchmarks).

rsa

const rsa = @import("rsa/rsa.zig")

Low-level RSA primitives (PKCS#1 v1.5 / PSS sign+verify, public/private key parsing incl. SPKI). Exposed so consumers can do RSA outside the TLS handshake — e.g. DKIM signing/verification.

clientFromStream

inline fn clientFromStream(stream: anytype, opt: config.Client) !Connection

Upgrades existing stream to the tls connection by the client tls handshake.

client

fn client(input: *Io.Reader, output: *Io.Writer, opt: config.Client) !Connection

serverFromStream

inline fn serverFromStream(stream: anytype, opt: config.Server) !Connection

Upgrades existing stream to the tls connection by the server side tls handshake.

server

fn server(input: *Io.Reader, output: *Io.Writer, opt: config.Server) !Connection

Cipher

const Cipher = @import("cipher.zig").Cipher

Record

const Record = @import("record.zig").Record

record_header_len

const record_header_len = @import("record.zig").header_len

config

const config = struct

proto

const proto = @import("protocol.zig")

CipherSuite

const CipherSuite = @import("cipher.zig").CipherSuite

PrivateKey

const PrivateKey = @import("PrivateKey.zig")

NamedGroup

const NamedGroup = proto.NamedGroup

Version

const Version = proto.Version

ContentType

const ContentType = proto.ContentType

Record

const Record = @import("record.zig").Record

cert

const cert = common.cert

CertKeyPair

const CertKeyPair = common.CertKeyPair

W7Table

const W7Table = @import("crypto/ecdsa_p256.zig").W7Table

cipher_suites

const cipher_suites = @import("cipher.zig").cipher_suites

key_log

const key_log = @import("key_log.zig")

Client

const Client = @import("handshake_client.zig").Options

Server

const Server = @import("handshake_server.zig").Options

alpn

const alpn = @import("alpn.zig")

cipher_names

const cipher_names = @import("cipher_names.zig")

session_ticket

const session_ticket = @import("session_ticket.zig")

alpn

const alpn = @import("alpn.zig")

cipher_names

const cipher_names = @import("cipher_names.zig")

session_ticket

const session_ticket = @import("session_ticket.zig")

embed

const embed = @import("embed.zig")

ktls_linux

const ktls_linux = @import("ktls_linux.zig")

nonblock

const nonblock = struct

Non-blocking client/server handshake and connection. Handshake produces cipher used in connection to encrypt data for sending and decrypt received data.

Client

const Client = @import("handshake_client.zig").NonBlock

Server

const Server = @import("handshake_server.zig").NonBlock

Connection

const Connection = @import("connection.zig").NonBlock

Ktls

const Ktls = @import("Ktls.zig")

aes_gcm_cached

const aes_gcm_cached = @import("aes_gcm_cached.zig")

tls_hkdf

const tls_hkdf = @import("tls_hkdf.zig")

x25519_base

const x25519_base = @import("crypto/x25519_base.zig")

fuzz

const fuzz = struct

libFuzzer / audit hooks for untrusted handshake bytes (no panics).

parseClientHello

const parseClientHello = @import("handshake_server.zig").Handshake.fuzzReadClientHello

parseServerHello

const parseServerHello = @import("handshake_client.zig").Handshake.fuzzParseServerHello

max_ciphertext_record_len

encrypt_overhead_tls_12

const encrypt_overhead_tls_12: comptime_int = @max(

encrypt_overhead_tls_13

const encrypt_overhead_tls_13: comptime_int = @max(

max_cleartext_len

const max_cleartext_len = 1 << 14

max_ciphertext_len

const max_ciphertext_len = max_cleartext_len + 256

max_ciphertext_record_len

const max_ciphertext_record_len = record.header_len + max_ciphertext_len

max_certificate_msg_len

const max_certificate_msg_len = max_cleartext_len

Room for a Certificate handshake message carrying a real chain.

A single self-signed leaf fits in a few hundred bytes, which is why a small buffer survives every test that uses one. A chain issued by a public CA does not: a Let's Encrypt leaf plus its intermediate is several KB of DER, and anything with a cross-signed root is larger again. Sizing this for the convenient case makes the handshake fail against exactly the certificates people deploy, with error.OutputBufferUndersize and no hint that the certificate is the reason.

A record's cleartext limit is the natural bound: a message longer than this has to be fragmented across records regardless of buffer size.

max_handshake_flight_len

const max_handshake_flight_len = max_cleartext_len

Room for a whole server flight: EncryptedExtensions, an optional CertificateRequest, Certificate, CertificateVerify and Finished. The certificate dominates it, so this has to scale with the same bound rather than assume a small one.

max_encrypted_record_len

const max_encrypted_record_len = max_cleartext_len + @max(encrypt_overhead_tls_13, encrypt_overhead_tls_12)

Cipher

const Cipher = union(CipherSuite)

Provides initialization and common encrypt/decrypt methods for all supported ciphers. Tls 1.2 has only application cipher, tls 1.3 has separate cipher for handshake and application.

initTls12

fn initTls12(tag: CipherSuite, key_material: []const u8, side: proto.Side) !Cipher

initTls13

fn initTls13(tag: CipherSuite, secret: Transcript.Secret, side: proto.Side) !Cipher

encrypt

fn encrypt(

decrypt

fn decrypt(

decryptRecordInPlace

fn decryptRecordInPlace(c: *Cipher, record_buf: []u8) ![]const u8

TLS 1.3 application record decrypt with in-place payload (see Aead13Type.decryptRecordInPlace).

encryptApplication

fn encryptApplication(c: *Cipher, buf: []u8, cleartext_len: usize) !usize

Encrypt TLS 1.3 application data with cleartext already at buf[record.header_len..][0..cleartext_len].

transferApplication

fn transferApplication(

Encrypt then decrypt one TLS 1.3 application record (hot transfer path).

recordLen

fn recordLen(c: Cipher, cleartext_len: usize) usize

encryptOverhead

fn encryptOverhead(c: Cipher) usize

encryptSeq

fn encryptSeq(c: Cipher) u64

keyUpdateEncrypt

fn keyUpdateEncrypt(c: *Cipher) !void

keyUpdateDecrypt

fn keyUpdateDecrypt(c: *Cipher) !void

encrypt

fn encrypt(

Returns encrypted tls record in format: ----------------- buf ---------------------- header | explicit_iv | ciphertext | auth_tag

tls record header: 5 bytes explicit_iv: 8 bytes ciphertext: same length as cleartext auth_tag: 16 bytes

recordLen

fn recordLen(_: Self, cleartext_len: usize) usize

decrypt

fn decrypt(

Decrypts payload into cleartext. Returns tls record content type and cleartext. Accepts tls record header and payload: header | ----------- payload --------------- header | explicit_iv | ciphertext | auth_tag

encrypt

fn encrypt(

Returns encrypted tls record in format: ------------ buf ------------- header | ciphertext | auth_tag

tls record header: 5 bytes ciphertext: same length as cleartext auth_tag: 16 bytes

recordLen

fn recordLen(_: Self, cleartext_len: usize) usize

decrypt

fn decrypt(

Decrypts payload into cleartext. Returns tls record content type and cleartext. Accepts tls record header and payload: header | ----- payload ------- header | ciphertext | auth_tag

init

fn init(secret: Transcript.Secret, side: proto.Side) Self

refreshGcm

fn refreshGcm(self: *Self) void

keyUpdateEncrypt

fn keyUpdateEncrypt(self: *Self) void

keyUpdateDecrypt

fn keyUpdateDecrypt(self: *Self) void

encrypt

fn encrypt(

Returns encrypted tls record in format: ------------ buf ------------- header | ciphertext | auth_tag

tls record header: 5 bytes ciphertext: cleartext len + 1 byte content type auth_tag: 16 bytes

recordLen

fn recordLen(_: Self, cleartext_len: usize) usize

encryptApplication

fn encryptApplication(self: *Self, buf: []u8, cleartext_len: usize) !usize

Encrypt TLS 1.3 application data with cleartext already at buf[record.header_len..][0..cleartext_len].

decrypt

fn decrypt(

Decrypts payload into cleartext. Returns tls record content type and cleartext. Accepts tls record header and payload: header | ------- payload --------- header | ciphertext | auth_tag header | cleartext + ct | auth_tag Ciphertext after decryption contains cleartext and content type (1 byte).

decryptRecordInPlace

fn decryptRecordInPlace(self: *Self, record_buf: []u8) ![]const u8

Decrypt a full TLS 1.3 record buffer in place (header + payload).

encrypt

fn encrypt(

Returns encrypted tls record in format: ----------------- buf ----------------- header | iv | ------ ciphertext ------- header | iv | cleartext | mac | padding

tls record header: 5 bytes iv: 16 bytes ciphertext: cleartext length + mac + padding mac: 20, 32 or 48 (sha1, sha256, sha384) padding: 1-16 bytes

Max encrypt buf overhead = iv + mac + padding (1-16) aes_128_cbc_sha => 16 + 20 + 16 = 52 aes_128_cbc_sha256 => 16 + 32 + 16 = 64 aes_256_cbc_sha384 => 16 + 48 + 16 = 80

recordLen

fn recordLen(_: Self, cleartext_len: usize) usize

decrypt

fn decrypt(

Decrypts payload into cleartext. Returns tls record content type and cleartext.

additional_data_len

const additional_data_len = record.header_len + @sizeOf(u64)

cipher_suites

const cipher_suites = struct

tls12_secure

const tls12_secure = if (crypto.core.aes.has_hardware_support) [_]CipherSuite

tls12_weak

const tls12_weak = [_]CipherSuite

tls13_

const tls13_ = if (crypto.core.aes.has_hardware_support) [_]CipherSuite

tls13

const tls13 = &tls13_

tls12

const tls12 = &(tls12_secure ++ tls12_weak)

secure

const secure = &(tls13_ ++ tls12_secure)

all

const all = &(tls13_ ++ tls12_secure ++ tls12_weak)

includes

fn includes(list: []const CipherSuite, cs: CipherSuite) bool

CipherSuite

const CipherSuite = enum(u16)

validate

fn validate(cs: CipherSuite) !void

Versions

const Versions = enum

versions

fn versions(list: []const CipherSuite) !Versions

KeyExchangeAlgorithm

const KeyExchangeAlgorithm = enum

keyExchange

fn keyExchange(s: CipherSuite) KeyExchangeAlgorithm

HashTag

const HashTag = enum

hash

fn hash(cs: CipherSuite) HashTag

uniformHashTag

fn uniformHashTag(list: []const CipherSuite) ?HashTag

When every offered suite uses the same handshake hash, return it.

testCiphers

fn testCiphers() struct

Pair of ciphers based on keys from well-known key/iv pairs

Connection

Connection

const Connection = struct

enableKtls

fn enableKtls(c: *Self, fd: std.posix.socket_t) !void

Enable kernel TLS offload on fd after handshake completes. Falls back to userspace crypto on non-Linux or unsupported ciphers.

ktlsEnabled

fn ktlsEnabled(c: Self) bool

sendNewSessionTicket

fn sendNewSessionTicket(c: *Self, ticket: session_ticket.Ticket) !void

Send a TLS 1.3 NewSessionTicket post-handshake message (server only).

next

fn next(c: *Self) anyerror!?[]const u8

Returns next record of cleartext data. Null on end of stream. Can be used in iterator like loop without memcpy to another buffer: while (try client.next()) |buf| { ... }

eof

fn eof(c: *Self) bool

close

fn close(c: *Self) anyerror!void

write

fn write(c: *Self, bytes: []const u8) !usize

Encrypts cleartext and writes it to the underlying stream as single tls record. Max single tls record payload length is 1<<14 (16K) bytes.

writeAll

fn writeAll(c: *Self, bytes: []const u8) !void

Encrypts cleartext and writes it to the underlying stream. If needed splits cleartext into multiple tls record.

read

fn read(c: *Self, buffer: []u8) !usize

readAll

fn readAll(c: *Self, buffer: []u8) !usize

Returns the number of bytes read. If the number read is smaller than buffer.len, it means the stream reached the end.

readAtLeast

fn readAtLeast(c: *Self, buffer: []u8, len: usize) !usize

Returns the number of bytes read, calling the underlying read function the minimal number of times until the buffer has at least len bytes filled. If the number read is less than len it means the stream reached the end.

readv

fn readv(c: *Self, iovecs: []std.posix.iovec) !usize

Returns the number of bytes read. If the number read is less than the space provided it means the stream reached the end.

Reader

const Reader = struct

init

fn init(c: *Connection, buffer: []u8) Reader

reader

fn reader(c: *Self, buffer: []u8) Reader

There is no strict requirement on buffer size. If the buffer is big enough tls record will be decrypted directly into provided buffer. If not input buffer will be used for record decryption and than cleartext will be copied to the reader buffer when needed.

Writer

const Writer = struct

init

fn init(c: *Connection, buffer: []u8) Writer

writer

fn writer(c: *Self, buffer: []u8) Writer

VecPut

const VecPut = struct

Abstraction for sending multiple byte buffers to a slice of iovecs.

put

fn put(vp: *VecPut, bytes: []const u8) usize

Returns the amount actually put which is always equal to bytes.len unless the vectors ran out of space.

NonBlock

const NonBlock = struct

init

fn init(c: Cipher) Self

encryptedLength

fn encryptedLength(self: Self, cleartext_len: usize) usize

Required ciphertext buffer length for the given cleartext length.

encrypt

fn encrypt(

Encrypts cleartext into ciphertext. If ciphertext.len is >= encryptedLength(cleartext.len) whole cleartext will be consumed.

decrypt

fn decrypt(

Decrypts ciphertext into cleartext. NOTE: It is safe to reuses ciphertext buffer for cleartext data.

close

fn close(self: *Self, ciphertext: []u8) ![]const u8

ecdsa_p256

nistz

const nistz = nistz_base

W7Table

const W7Table = nistz_base.W7Table

TableRows

const TableRows = nistz_base.TableRows

P256

const P256 = p256.P256

EcdsaP256Sha256

const EcdsaP256Sha256 = crypto.sign.ecdsa.Ecdsa(P256, crypto.hash.sha2.Sha256)

signCertificateVerifyTls

fn signCertificateVerifyTls(

CertificateVerify sign with cached private scalar (TLS 1.3 server hot path).

signPrehashed

fn signPrehashed(

Fast TLS CertificateVerify sign: nistz mulBase, x-only affine, var-time scalar invert.

verifyPrehashed

fn verifyPrehashed(

Verify a prehashed message using Shamir double-base mul (u1G + u2Q).

signatureToDerTls

fn signatureToDerTls(sig: Signature, buf: *[Signature.der_encoded_length_max]u8) []const u8

Encode a TLS CertificateVerify ECDSA-P256 signature (fixed 72-byte layout when canonical).

signatureFromDerTls

fn signatureFromDerTls(der: []const u8) EncodingError!Signature

Parse a TLS CertificateVerify ECDSA-P256 signature without the generic DER reader.

rsa

max_modulus_bits

const max_modulus_bits = 4096

ValueError

const ValueError = error

PublicKey

const PublicKey = struct

FromBytesError

const FromBytesError = ValueError || ff.OverflowError || ff.FieldElementError || ff.InvalidModulusError || error

fromBytes

fn fromBytes(mod: []const u8, exp: []const u8) FromBytesError!PublicKey

fromDer

fn fromDer(bytes: []const u8) (der.Parser.Error || FromBytesError)!PublicKey

fromSpki

fn fromSpki(bytes: []const u8) (der.Parser.Error || FromBytesError)!PublicKey

Parse an RSA public key from a DER-encoded SubjectPublicKeyInfo (the format used by X.509 certificates, OpenSSL -pubout, and DKIM p= records). Unwraps the AlgorithmIdentifier + BIT STRING and parses the inner PKCS#1 RSAPublicKey.

encryptPkcsv1_5

fn encryptPkcsv1_5(pk: PublicKey, msg: []const u8, out: []u8) ![]const u8

Deprecated.

Encrypt a short message using RSAES-PKCS1-v1_5. The use of this scheme for encrypting an arbitrary message, as opposed to a randomly generated key, is NOT RECOMMENDED.

encryptOaep

fn encryptOaep(

Encrypt a short message using Optimal Asymmetric Encryption Padding (RSAES-OAEP).

byteLen

fn byteLen(bits: usize) usize

SecretKey

const SecretKey = struct

FromBytesError

const FromBytesError = ValueError || ff.OverflowError || ff.FieldElementError

fromBytes

fn fromBytes(n: Modulus, exp: []const u8) FromBytesError!SecretKey

KeyPair

const KeyPair = struct

FromDerError

const FromDerError = PublicKey.FromBytesError || SecretKey.FromBytesError || der.Parser.Error || error

fromDer

fn fromDer(bytes: []const u8) FromDerError!KeyPair

signPkcsv1_5

fn signPkcsv1_5(kp: KeyPair, comptime Hash: type, msg: []const u8, out: []u8) !PKCS1v1_5(Hash).Signature

Deprecated.

signerPkcsv1_5

fn signerPkcsv1_5(kp: KeyPair, comptime Hash: type) !PKCS1v1_5(Hash).Signer

Deprecated.

decryptPkcsv1_5

fn decryptPkcsv1_5(kp: KeyPair, ciphertext: []const u8, out: []u8) ![]const u8

Deprecated.

signOaep

fn signOaep(

signerOaep

fn signerOaep(kp: KeyPair, comptime Hash: type, salt: ?[]const u8) !Pss(Hash).Signer

Salt must outlive returned PSS.Signer.

decryptOaep

fn decryptOaep(

encrypt

fn encrypt(kp: KeyPair, plaintext: []const u8, out: []u8) !void

Encrypt short plaintext with secret key.

PKCS1v1_5

fn PKCS1v1_5(comptime Hash: type) type

Deprecated.

Signature Scheme with Appendix v1.5 (RSASSA-PKCS1-v1_5)

This standard has been superceded by PSS which is formally proven secure and has fewer footguns.

Signature

const Signature = struct

verifier

fn verifier(self: Self, public_key: PublicKey) !Verifier

verify

fn verify(self: Self, msg: []const u8, public_key: PublicKey) !void

Signer

const Signer = struct

update

fn update(self: *Signer, data: []const u8) void

finalize

fn finalize(self: *Signer, out: []u8) !PkcsT.Signature

Verifier

const Verifier = struct

update

fn update(self: *Verifier, data: []const u8) void

verify

fn verify(self: *Verifier) !void

Pss

fn Pss(comptime Hash: type) type

Probabilistic Signature Scheme (RSASSA-PSS)

Signature

const Signature = struct

verifier

fn verifier(self: Self, public_key: PublicKey) !Verifier

verify

fn verify(self: Self, msg: []const u8, public_key: PublicKey, salt_len: ?usize) !void

Signer

const Signer = struct

update

fn update(self: *Signer, data: []const u8) void

finalize

fn finalize(self: *Signer, out: []u8) !PssT.Signature

Verifier

const Verifier = struct

update

fn update(self: *Verifier, data: []const u8) void

verify

fn verify(self: *Verifier) !void

Record

header_len

const header_len = 5

Record

const Record = struct

init

fn init(buffer: []const u8) Record

read

fn read(rdr: *Io.Reader) Error!Record

decoder

fn decoder(rdr: *Io.Reader) !Decoder

Decoder

const Decoder = struct

init

fn init(content_type: proto.ContentType, payload: []const u8) Decoder

decode

fn decode(d: *Decoder, comptime T: type) !T

array

fn array(d: *Decoder, comptime len: usize) ![len]u8

slice

fn slice(d: *Decoder, len: usize) ![]const u8

skip

fn skip(d: *Decoder, amt: usize) !void

rest

fn rest(d: Decoder) []const u8

eof

fn eof(d: Decoder) bool

expectContentType

fn expectContentType(d: *Decoder, content_type: proto.ContentType) !void

raiseAlert

fn raiseAlert(d: *Decoder) !void

Writer

const Writer = struct

initFromIo

fn initFromIo(io_w: *Io.Writer) Writer

init

fn init(buffer: []u8) Writer

buffered

fn buffered(w: Writer) []const u8

bytesWritten

fn bytesWritten(w: Writer) usize

pos

fn pos(w: Writer) usize

byte

fn byte(w: *Writer, b: u8) !void

slice

fn slice(w: *Writer, bytes: []const u8) !void

int

fn int(w: *Writer, comptime T: type, value: anytype) !void

writableArray

fn writableArray(w: *Writer, comptime len: usize) !*[len]u8

enumValue

fn enumValue(w: *Writer, value: anytype) !void

enumList

fn enumList(w: *Writer, comptime E: type, tags: []const E) !void

extension

fn extension(w: *Writer, ex: proto.Extension, tags: anytype) !void

Default extension writer, writes extension type and list of tags

keyShare

fn keyShare(w: *Writer, named_groups: []const proto.NamedGroup, keys: []const []const u8) !void

Key share extension

serverName

fn serverName(w: *Writer, host: []const u8) !void

Server name extension

preSharedKey

fn preSharedKey(

Writes header of the pre shared key extension, without binders

preSharedKeyBinder

fn preSharedKeyBinder(w: *Writer, binder: []const u8) !void

Writes the rest of the pre shared keys extension

record

fn record(w: *Writer, content_type: proto.ContentType, payload: []const u8) !void

tls record

recordHeader

fn recordHeader(w: *Writer, content_type: proto.ContentType, payload_len: usize) !void

handshakeRecord

fn handshakeRecord(w: *Writer, handshake_type: proto.Handshake, payload: []const u8) !void

tls handshake record

handshakeRecordHeader

fn handshakeRecordHeader(w: *Writer, handshake_type: proto.Handshake, payload_len: usize) !void

unused

fn unused(w: *Writer) []u8

advance

fn advance(w: *Writer, n: usize) void

skip

fn skip(w: *Writer, n: usize) !usize

Skip n bytes from current position and return position before skip. Used with writerAt to later return to that point and write skipped bytes.

writerAt

fn writerAt(w: *Writer, p: usize) Writer

Returns writer at some previous position Parent buffer position is not changed.

writerAdvance

fn writerAdvance(w: *Writer, n: usize) !Writer

Returns new writer in unused buffer part advancing n bytes. Parent buffer position is not changed.

fn header(content_type: proto.ContentType, payload_len: usize) [header_len]u8

handshakeHeader

fn handshakeHeader(handshake_type: proto.Handshake, payload_len: usize) [4]u8

proto

Version

const Version = enum(u16)

ContentType

const ContentType = enum(u8)

Handshake

const Handshake = enum(u8)

Curve

const Curve = enum(u8)

KeyExchangeModes

const KeyExchangeModes = enum(u8)

Extension

const Extension = enum(u16)

alertFromError

fn alertFromError(err: anyerror) [2]u8

Alert

const Alert = enum(u8)

Level

const Level = enum(u8)

Error

const Error = error

toError

fn toError(alert: Alert) Error!void

fromError

fn fromError(err: anyerror) Alert

parse

fn parse(buf: [2]u8) Alert

closeNotify

fn closeNotify() [2]u8

SignatureScheme

const SignatureScheme = enum(u16)

NamedGroup

const NamedGroup = enum(u16)

KeyUpdateRequest

const KeyUpdateRequest = enum(u8)

Side

const Side = enum

PrivateKey

fromFile

fn fromFile(_: Allocator, file: std.Io.File) !PrivateKey

parsePem

fn parsePem(buf: []const u8) !PrivateKey

parseDer

fn parseDer(buf: []const u8) !PrivateKey

parseEcDer

fn parseEcDer(bytes: []const u8) !PrivateKey

key_log

label

const label = struct

client_handshake_traffic_secret

const client_handshake_traffic_secret: []const u8 = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"

server_handshake_traffic_secret

const server_handshake_traffic_secret: []const u8 = "SERVER_HANDSHAKE_TRAFFIC_SECRET"

client_traffic_secret_0

const client_traffic_secret_0: []const u8 = "CLIENT_TRAFFIC_SECRET_0"

server_traffic_secret_0

const server_traffic_secret_0: []const u8 = "SERVER_TRAFFIC_SECRET_0"

client_random

const client_random: []const u8 = "CLIENT_RANDOM"

Callback

const Callback = *const fn (label: []const u8, client_random: []const u8, secret: []const u8) void

callback

fn callback(label_: []const u8, client_random: []const u8, secret: []const u8) void

Writes tls keys to the file pointed by SSLKEYLOGFILE environment variable.

fileAppend

fn fileAppend(file_name: []const u8, label_: []const u8, client_random: []const u8, secret: []const u8) !void

formatLine

fn formatLine(buf: []u8, label_: []const u8, client_random: []const u8, secret: []const u8) ![]const u8

Client

info

fn info(comptime _: []const u8, _: anytype) void

err

fn err(comptime _: []const u8, _: anytype) void

warn

fn warn(comptime _: []const u8, _: anytype) void

debug

fn debug(comptime _: []const u8, _: anytype) void

Options

const Options = struct

Diagnostic

const Diagnostic = struct

SessionResumption

const SessionResumption = struct

Collects and stores session resumption tickets.

Ticket

const Ticket = struct

init

fn init(payload: []const u8, secret: []const u8) !Ticket

obfuscatedAge

fn obfuscatedAge(t: Ticket) u32

Obfuscated age for pre shared extension in client hello message when using this ticket.

init

fn init(allocator: mem.Allocator) Self

appendSecret

fn appendSecret(self: *Self, tag: CipherSuite.HashTag, secret: []const u8) !usize

Set resumption master secret (known at then end of the handshake) to be used by new session ticket's sent on that connection. Returns index of the appended secret in the secrets list. Connection should use that index in pushTicket to connect ticket and the secret.

pushTicket

fn pushTicket(self: *Self, data: []const u8, secret_idx: usize) !void

When new session ticket message is recived connection should push ticket.

popTicket

fn popTicket(self: *Self) ?Ticket

deinit

fn deinit(self: *Self) void

print

fn print(self: Self) !void

Handshake

const Handshake = struct

Handshake parses tls server message and creates client messages. Collects tls attributes: server random, cipher suite and so on. Client messages are created using provided buffer. Provided record reader is used to get tls record when needed.

handshake

fn handshake(h: *Self, opt: Options) !struct

Handshake exchanges messages with server to get agreement about cryptographic parameters. That upgrades existing client-server connection to TLS connection. Returns cipher used in application for encrypted message exchange.

Handles TLS 1.2 and TLS 1.3 connections. After initial client hello server chooses in its server hello which TLS version will be used.

TLS 1.2 handshake messages exchange: Client Server

ClientHello client flight 1 ---> ServerHello Certificate ServerKeyExchange CertificateRequest* <--- server flight 1 ServerHelloDone Certificate* ClientKeyExchange CertificateVerify* ChangeCipherSpec Finished client flight 2 ---> ChangeCipherSpec <--- server flight 2 Finished

TLS 1.3 handshake messages exchange: Client Server

ClientHello client flight 1 ---> ServerHello {EncryptedExtensions} {CertificateRequest*} {Certificate} {CertificateVerify} <--- server flight 1 {Finished} ChangeCipherSpec {Certificate*} {CertificateVerify*} Finished client flight 2 --->

    • optional {} - encrypted

References: https://datatracker.ietf.org/doc/html/rfc5246#section-7.3 https://datatracker.ietf.org/doc/html/rfc8446#section-2

fuzzParseServerHello

fn fuzzParseServerHello(payload: []const u8) void

Fuzz/audit entry: parse untrusted ServerHello bytes without panicking.

NonBlock

const NonBlock = struct

init

fn init(opt: Options) Self

deinit

fn deinit(self: *Self) void

Release any heap state owned by the handshake (the optional P-256 verify table allocated from opt.table_allocator). No-op when table_allocator is unset. Call once when the client is no longer needed.

reset

fn reset(self: *Self) void

Start a new handshake reusing opt and any cached certificate state.

done

fn done(self: Self) bool

True when handshake is successfully finished

run

fn run(

Runs next handshake step.

cipher

fn cipher(self: Self) ?Cipher

Cipher produced in handshake, null until successful handshake.

selectedAlpn

fn selectedAlpn(self: Self) ?alpn.Protocol

Negotiated ALPN protocol, available after handshake completes.

Server

info

fn info(comptime _: []const u8, _: anytype) void

err

fn err(comptime _: []const u8, _: anytype) void

warn

fn warn(comptime _: []const u8, _: anytype) void

debug

fn debug(comptime _: []const u8, _: anytype) void

Options

const Options = struct

SNICallback

const SNICallback = *const fn (

SessionTickets

const SessionTickets = struct

effectiveNamedGroups

fn effectiveNamedGroups(self: Options) []const proto.NamedGroup

ClientAuth

const ClientAuth = struct

Type

const Type = enum

Handshake

const Handshake = struct

earlyData

fn earlyData(h: Self) []const u8

handshake

fn handshake(h: *Self, opt_in: Options) !Cipher

selectedAlpnProtocol

fn selectedAlpnProtocol(h: Self) ?alpn.Protocol

issueSessionTicket

fn issueSessionTicket(h: *Self, opt: Options, allocator: mem.Allocator) !?session_ticket.Ticket

fuzzReadClientHello

fn fuzzReadClientHello(payload: []const u8) void

Fuzz/audit entry: parse untrusted ClientHello bytes without panicking.

NonBlock

const NonBlock = struct

init

fn init(opt: Options) Self

reset

fn reset(self: *Self) void

Start a new handshake reusing opt (bench / session resumption helpers).

done

fn done(self: Self) bool

True when handshake is successfully finished

run

fn run(

Runs next handshake step.

cipher

fn cipher(self: Self) ?Cipher

Cipher produced in handshake, null until successful handshake.

selectedAlpn

fn selectedAlpn(self: Self) ?alpn.Protocol

Negotiated ALPN protocol, available after handshake completes.

earlyData

fn earlyData(self: Self) []const u8

0-RTT early data received from the client (empty if none).

alpn

Protocol

const Protocol = []const u8

ProtocolList

const ProtocolList = []const Protocol

negotiate

fn negotiate(client_protocols: ProtocolList, server_protocols: ProtocolList) ?Protocol

Select the first client protocol that appears in the server list (RFC 7301).

Callback

const Callback = *const fn (

Per-connection ALPN picker (Node ALPNCallback semantics).

negotiateWithCallback

fn negotiateWithCallback(

parseProtocolListFixed

fn parseProtocolListFixed(

Parse ALPN extension payload into caller-provided protocol pointer array. Protocol name bytes are views into payload.

parseProtocolList

fn parseProtocolList(allocator: mem.Allocator, payload: []const u8) ![]const Protocol

Parse ALPN extension payload into a slice of protocol name views.

writeExtension

fn writeExtension(w: *record.Writer, protocols: ProtocolList) !void

Write ALPN extension to a record Writer.

makeEncryptedExtensionsBody

fn makeEncryptedExtensionsBody(buf: []u8, selected: ?Protocol) ![]const u8

Build encrypted_extensions body with optional ALPN selected protocol.

cipher_names

opensslName

fn opensslName(cs: CipherSuite) ?[]const u8

OpenSSL / IANA cipher suite name for each supported suite.

parseCipherList

fn parseCipherList(allocator: mem.Allocator, ciphers: []const u8) ![]CipherSuite

Parse an OpenSSL-style colon-separated cipher list into preference-ordered suites. Supports @SECLEVEL=n prefix (ignored for ordering; suites still filtered by grade).

fromOpensslName

fn fromOpensslName(name: []const u8) ?CipherSuite

Look up a cipher suite by OpenSSL name (case-sensitive).

validNames

fn validNames(allocator: mem.Allocator) ![]const []const u8

Return all valid OpenSSL cipher names for validation (e.g. Bun validateCiphers).

session_ticket

TicketKeys

const TicketKeys = struct

48-byte ticket keys per Node.js / OpenSSL convention: 16-byte name prefix, 16-byte HMAC key, 16-byte AES key.

fromBytes

fn fromBytes(bytes: *const [48]u8) TicketKeys

random

fn random() TicketKeys

TicketKeyRing

const TicketKeyRing = struct

Thread-safe bounded session-ticket key ring.

New tickets always use the active key at index zero. Resumption accepts the active key and at most three previous keys. Keep the ring at a stable address for as long as server configurations reference it. Rotation is serialized, does not require a listener restart, and securely clears retired material.

capacity

const capacity = 4

init

fn init(primary: TicketKeys) TicketKeyRing

rotate

fn rotate(self: *TicketKeyRing, next: TicketKeys) error

active

fn active(self: *TicketKeyRing) TicketKeys

decryptTicket

fn decryptTicket(self: *TicketKeyRing, identity: []const u8) ?SessionState

keyCount

fn keyCount(self: *TicketKeyRing) usize

containsKeyName

fn containsKeyName(self: *TicketKeyRing, name: *const [16]u8) bool

SessionState

const SessionState = struct

Serialized session state encrypted into a TLS session ticket.

Ticket

const Ticket = struct

encrypt

fn encrypt(

Encrypt session state into a ticket identity blob.

decrypt

fn decrypt(identity: []const u8, keys: TicketKeys) ?SessionState

Decrypt a ticket identity blob. Returns null if keys don't match or decryption fails.

makeNewSessionTicket

fn makeNewSessionTicket(

Build a TLS 1.3 NewSessionTicket handshake message body.

NewSessionCallback

const NewSessionCallback = *const fn (

Called when a new session is established (Node newSession callback).

ResumeSessionCallback

const ResumeSessionCallback = *const fn (

Called when client offers a ticket (Node resumeSession callback).

Manager

const Manager = struct

Server-side session ticket manager.

init

fn init(keys: TicketKeys) Manager

initKeyRing

fn initKeyRing(key_ring: *TicketKeyRing) Manager

nextNonce

fn nextNonce(self: *Manager) []const u8

issueTicket

fn issueTicket(

resumeTicket

fn resumeTicket(self: *Manager, identity: []const u8) ?SessionState

embed

Error

const Error = enum(c_int)

Mode

const Mode = enum(c_int)

Context

const Context = struct

Connection

const Connection = struct

ktls_linux

Error

const Error = error

enable

fn enable(fd: posix.socket_t, ktls: Ktls) Error!void

isSupported

fn isSupported(cipher: @import("cipher.zig").Cipher) bool

Ktls

txBytes

fn txBytes(k: *Ktls) []const u8

rxBytes

fn rxBytes(k: *Ktls) []const u8

VERSION_1_2

const VERSION_1_2 = 0x0303

VERSION_1_3

const VERSION_1_3 = 0x0304

TX

const TX = 1

RX

const RX = 2

AES_GCM_128

const AES_GCM_128 = 51

AES_GCM_256

const AES_GCM_256 = 52

CHACHA20_POLY1305

const CHACHA20_POLY1305 = 54

Info

const Info = extern struct

AesGcm128

const AesGcm128 = extern struct

AesGcm256

const AesGcm256 = extern struct

Chacha20Poly1305

const Chacha20Poly1305 = extern struct

init

fn init(cipher: Cipher) Ktls

aes_gcm_cached

CachedAesGcm

fn CachedAesGcm(comptime Aes: type) type

tag_length

const tag_length = 16

nonce_length

const nonce_length = 12

key_length

const key_length = Aes.key_bits / 8

fromKey

fn fromKey(key: [key_length]u8) @This()

encrypt

fn encrypt(

encryptTls13

fn encryptTls13(

TLS 1.3 record path: AD is always the 5-byte record header.

decrypt

fn decrypt(

decryptTls13

fn decryptTls13(

TLS 1.3 record path: AD is always the 5-byte record header.

tls_hkdf

expandLabelEmpty

fn expandLabelEmpty(

HKDF-Expand-Label with empty context (common for key/iv/finished labels).

x25519_base

recoverPublicKey

fn recoverPublicKey(seed: [32]u8) [32]u8

Compute the X25519 public key for seed (clamps internally). Equivalent to std.crypto.dh.X25519.recoverPublicKey.