quic_tls (quic v1.3.0)

View Source

TLS 1.3 message generation and parsing for QUIC.

This module handles TLS 1.3 handshake messages as they appear in QUIC CRYPTO frames. Messages are encoded without the TLS record layer.

TLS Messages in QUIC

QUIC uses TLS 1.3 for the cryptographic handshake, but without the TLS record layer. TLS handshake messages are sent directly in CRYPTO frames.

Summary

Functions

Build Certificate message. Certs is a list of DER-encoded certificates (server cert first).

Build a CertificateRequest message (RFC 8446 Section 4.3.2). Context is the certificate_request_context (typically empty for TLS 1.3).

Build CertificateVerify message. PrivateKey is the server's private key. TranscriptHash is the hash of all handshake messages up to (not including) CertificateVerify.

Build a CertificateVerify message for client (RFC 8446 Section 4.4.3). Uses "TLS 1.3, client CertificateVerify" context string.

Build a TLS 1.3 ClientHello message for QUIC. Options: - server_name: SNI hostname (binary) - alpn: List of ALPN protocols (list of binaries) - transport_params: QUIC transport parameters (map) - session_ticket: #session_ticket{} for resumption with PSK (optional)

Build EncryptedExtensions message. Options: - alpn: Selected ALPN protocol - transport_params: QUIC transport parameters

Build a Finished message. VerifyData should be computed using quic_crypto:compute_finished_verify/2.

Build a ServerHello message. Options: - random: Server random (32 bytes, generated if not provided) - session_id: Legacy session ID to echo - cipher_suite: Selected cipher suite - key_share: Server's public key

Decode a TLS handshake message. Returns {Type, Body, Rest} or {error, Reason}.

Decode preferred_address transport parameter (RFC 9000 Section 18.2). Format: IPv4 address: 4 bytes IPv4 port: 2 bytes IPv6 address: 16 bytes IPv6 port: 2 bytes CID length: 1 byte Connection ID: variable (0-20 bytes) Stateless reset: 16 bytes

Decode QUIC transport parameters. RFC 9000 Section 7.4: Validates against duplicate parameters and semantic constraints

Encode a TLS handshake message with type and length.

Encode preferred_address transport parameter (RFC 9000 Section 18.2).

Encode QUIC transport parameters. Params is a map with keys like: original_dcid, max_idle_timeout, max_udp_payload_size, initial_max_data, initial_max_stream_data_bidi_local, etc.

Parse Certificate message.

Parse a CertificateRequest message.

Parse CertificateVerify message.

Parse a ClientHello message. Returns a map with: - random: 32-byte client random - session_id: Legacy session ID - cipher_suites: List of cipher suites offered - extensions: Map of extensions - key_share: Client's public key for key exchange - server_name: SNI hostname (if present) - alpn_protocols: List of ALPN protocols (if present) - transport_params: QUIC transport parameters (if present)

Parse EncryptedExtensions message.

Parse Finished message.

Parse a ServerHello message. Returns server's public key and selected cipher suite.

Verify CertificateVerify signature. Role is 'client' or 'server' - determines context string.

Verify a Finished message (default SHA-256). TrafficSecret is the sender's traffic secret. TranscriptHash is the hash of all messages up to (but not including) Finished.

Verify a Finished message with cipher-specific hash.

Functions

build_certificate(Context, Certs)

-spec build_certificate(binary(), [binary()]) -> binary().

Build Certificate message. Certs is a list of DER-encoded certificates (server cert first).

build_certificate_request(Context)

-spec build_certificate_request(binary()) -> binary().

Build a CertificateRequest message (RFC 8446 Section 4.3.2). Context is the certificate_request_context (typically empty for TLS 1.3).

build_certificate_verify(SignatureAlgorithm, PrivateKey, TranscriptHash)

-spec build_certificate_verify(non_neg_integer(), crypto:key_id(), binary()) -> binary().

Build CertificateVerify message. PrivateKey is the server's private key. TranscriptHash is the hash of all handshake messages up to (not including) CertificateVerify.

build_certificate_verify_client(SignatureAlgorithm, PrivateKey, TranscriptHash)

-spec build_certificate_verify_client(non_neg_integer(), term(), binary()) -> binary().

Build a CertificateVerify message for client (RFC 8446 Section 4.4.3). Uses "TLS 1.3, client CertificateVerify" context string.

build_client_hello(Opts)

-spec build_client_hello(map()) -> {binary(), binary(), binary()}.

Build a TLS 1.3 ClientHello message for QUIC. Options: - server_name: SNI hostname (binary) - alpn: List of ALPN protocols (list of binaries) - transport_params: QUIC transport parameters (map) - session_ticket: #session_ticket{} for resumption with PSK (optional)

Returns: {ClientHelloMsg, PrivateKey, Random}

build_encrypted_extensions(Opts)

-spec build_encrypted_extensions(map()) -> binary().

Build EncryptedExtensions message. Options: - alpn: Selected ALPN protocol - transport_params: QUIC transport parameters

build_finished(VerifyData)

-spec build_finished(binary()) -> binary().

Build a Finished message. VerifyData should be computed using quic_crypto:compute_finished_verify/2.

build_server_hello(Opts)

-spec build_server_hello(map()) -> {binary(), binary()}.

Build a ServerHello message. Options: - random: Server random (32 bytes, generated if not provided) - session_id: Legacy session ID to echo - cipher_suite: Selected cipher suite - key_share: Server's public key

decode_handshake_message(_)

-spec decode_handshake_message(binary()) ->
                                  {ok, {non_neg_integer(), binary()}, binary()} | {error, term()}.

Decode a TLS handshake message. Returns {Type, Body, Rest} or {error, Reason}.

decode_preferred_address(_)

-spec decode_preferred_address(binary()) ->
                                  #preferred_address{ipv4_addr :: inet:ip4_address() | undefined,
                                                     ipv4_port :: inet:port_number() | undefined,
                                                     ipv6_addr :: inet:ip6_address() | undefined,
                                                     ipv6_port :: inet:port_number() | undefined,
                                                     cid :: binary(),
                                                     stateless_reset_token :: binary()}.

Decode preferred_address transport parameter (RFC 9000 Section 18.2). Format: IPv4 address: 4 bytes IPv4 port: 2 bytes IPv6 address: 16 bytes IPv6 port: 2 bytes CID length: 1 byte Connection ID: variable (0-20 bytes) Stateless reset: 16 bytes

decode_transport_params(Data)

-spec decode_transport_params(binary()) -> {ok, map()} | {error, term()}.

Decode QUIC transport parameters. RFC 9000 Section 7.4: Validates against duplicate parameters and semantic constraints

encode_handshake_message(Type, Body)

-spec encode_handshake_message(non_neg_integer(), binary()) -> binary().

Encode a TLS handshake message with type and length.

encode_preferred_address(Preferred_address)

-spec encode_preferred_address(#preferred_address{ipv4_addr :: inet:ip4_address() | undefined,
                                                  ipv4_port :: inet:port_number() | undefined,
                                                  ipv6_addr :: inet:ip6_address() | undefined,
                                                  ipv6_port :: inet:port_number() | undefined,
                                                  cid :: binary(),
                                                  stateless_reset_token :: binary()}) ->
                                  binary().

Encode preferred_address transport parameter (RFC 9000 Section 18.2).

encode_transport_params(Params)

-spec encode_transport_params(map()) -> binary().

Encode QUIC transport parameters. Params is a map with keys like: original_dcid, max_idle_timeout, max_udp_payload_size, initial_max_data, initial_max_stream_data_bidi_local, etc.

parse_certificate(_)

-spec parse_certificate(binary()) ->
                           {ok, #{context := binary(), certificates := [binary()]}} | {error, term()}.

Parse Certificate message.

parse_certificate_request(_)

-spec parse_certificate_request(binary()) -> {ok, map()} | {error, term()}.

Parse a CertificateRequest message.

parse_certificate_verify(_)

-spec parse_certificate_verify(binary()) ->
                                  {ok, #{algorithm := non_neg_integer(), signature := binary()}} |
                                  {error, term()}.

Parse CertificateVerify message.

parse_client_hello(Data)

-spec parse_client_hello(binary()) -> {ok, map()} | {error, term()}.

Parse a ClientHello message. Returns a map with: - random: 32-byte client random - session_id: Legacy session ID - cipher_suites: List of cipher suites offered - extensions: Map of extensions - key_share: Client's public key for key exchange - server_name: SNI hostname (if present) - alpn_protocols: List of ALPN protocols (if present) - transport_params: QUIC transport parameters (if present)

parse_encrypted_extensions(_)

-spec parse_encrypted_extensions(binary()) ->
                                    {ok, #{alpn => binary(), transport_params => map()}} |
                                    {error, term()}.

Parse EncryptedExtensions message.

parse_finished(VerifyData)

-spec parse_finished(binary()) -> {ok, binary()} | {error, term()}.

Parse Finished message.

parse_server_hello(_)

-spec parse_server_hello(binary()) ->
                            {ok, #{public_key := binary(), cipher := atom(), random := binary()}} |
                            {error, term()}.

Parse a ServerHello message. Returns server's public key and selected cipher suite.

verify_certificate_verify(Body, PeerCertDER, TranscriptHash, Role)

-spec verify_certificate_verify(binary(), binary(), binary(), client | server) -> boolean().

Verify CertificateVerify signature. Role is 'client' or 'server' - determines context string.

verify_finished(ReceivedVerifyData, TrafficSecret, TranscriptHash)

-spec verify_finished(binary(), binary(), binary()) -> boolean().

Verify a Finished message (default SHA-256). TrafficSecret is the sender's traffic secret. TranscriptHash is the hash of all messages up to (but not including) Finished.

verify_finished(ReceivedVerifyData, TrafficSecret, TranscriptHash, Cipher)

-spec verify_finished(binary(), binary(), binary(), atom()) -> boolean().

Verify a Finished message with cipher-specific hash.