nquic_tls_client (nquic v1.0.0)

View Source

Client-side TLS 1.3 handshake flow for QUIC per RFC 9001.

Builds ClientHello (full and PSK-resumption variants), processes ServerHello, drives the post-ServerHello handshake (EncryptedExtensions, Certificate, CertificateVerify, Finished) for both fresh and PSK handshakes, and emits the client Finished. Certificate-chain validation against a trust store lives here too because only the client validates server certificates today. Codec helpers shared with the server live in nquic_tls; the binder / NewSessionTicket helpers remain there because they straddle both roles.

Summary

Functions

Construct the client Finished message and derive application keys.

Construct a TLS 1.3 ClientHello message with the default cipher suites.

Construct a TLS 1.3 ClientHello message with an explicit cipher suite list. undefined advertises all three RFC 8446 TLS 1.3 suites.

Build a ClientHello with PSK extensions for session resumption, using the default cipher suites.

Build a ClientHello with PSK extensions for session resumption. TicketData is the map received from a prior NewSessionTicket message. PSK is the pre-shared key derived from the resumption master secret. The pre_shared_key extension MUST be the last extension (RFC 8446 S4.2.11). CipherSuites controls which suites are advertised; undefined keeps the default of all three RFC 8446 TLS 1.3 suites.

Process handshake messages (EncryptedExtensions, Certificate, CertificateVerify, Finished).

Process PSK handshake messages (EncryptedExtensions + Finished only). No Certificate or CertificateVerify in PSK mode (RFC 8446 S2.3).

Process a ServerHello, extract the key share, and derive handshake secrets.

Functions

compute_ticket_age(TicketData)

-spec compute_ticket_age(map()) -> non_neg_integer().

encode_early_data_extension()

-spec encode_early_data_extension() -> binary().

encode_psk_identity(Identity, ObfuscatedAge)

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

encode_psk_ke_modes_extension()

-spec encode_psk_ke_modes_extension() -> binary().

find_message/2

-spec find_message(non_neg_integer(), [binary()]) -> binary() | undefined.

make_client_finished(HandshakeSecret, Keys)

-spec make_client_finished(binary(), map()) ->
                              {ok, binary(), map(), map()} | {error, nquic_error:any_reason()}.

Construct the client Finished message and derive application keys.

make_client_hello(TransportParams, ALPNProtos, Hostname)

-spec make_client_hello(nquic_transport:params(),
                        [binary()] | undefined,
                        string() | binary() | undefined) ->
                           {ok, binary(), map()} | {error, term()}.

Construct a TLS 1.3 ClientHello message with the default cipher suites.

make_client_hello(TransportParams, ALPNProtos, Hostname, CipherSuites)

-spec make_client_hello(nquic_transport:params(),
                        [binary()] | undefined,
                        string() | binary() | undefined,
                        [aes_128_gcm | aes_256_gcm | chacha20_poly1305] | undefined) ->
                           {ok, binary(), map()} | {error, term()}.

Construct a TLS 1.3 ClientHello message with an explicit cipher suite list. undefined advertises all three RFC 8446 TLS 1.3 suites.

make_client_hello_psk(TransportParams, ALPNProtos, Hostname, PSKInfo)

-spec make_client_hello_psk(nquic_transport:params(),
                            [binary()] | undefined,
                            string() | binary() | undefined,
                            #{psk := binary(), ticket := map(), cipher := atom()}) ->
                               {ok, binary(), map()} | {error, term()}.

Build a ClientHello with PSK extensions for session resumption, using the default cipher suites.

make_client_hello_psk(TransportParams, ALPNProtos, Hostname, PSKInfo, CipherSuites)

-spec make_client_hello_psk(nquic_transport:params(),
                            [binary()] | undefined,
                            string() | binary() | undefined,
                            #{psk := binary(), ticket := map(), cipher := atom()},
                            [aes_128_gcm | aes_256_gcm | chacha20_poly1305] | undefined) ->
                               {ok, binary(), map()} | {error, term()}.

Build a ClientHello with PSK extensions for session resumption. TicketData is the map received from a prior NewSessionTicket message. PSK is the pre-shared key derived from the resumption master secret. The pre_shared_key extension MUST be the last extension (RFC 8446 S4.2.11). CipherSuites controls which suites are advertised; undefined keeps the default of all three RFC 8446 TLS 1.3 suites.

parse_cert_entries/1

-spec parse_cert_entries(binary()) -> {binary(), [binary()]}.

parse_remaining_cert_entries/1

-spec parse_remaining_cert_entries(binary()) -> [binary()].

process_handshake_messages(Data, HandshakeSecret, State)

-spec process_handshake_messages(binary(), binary(), map()) ->
                                    {ok, map()} | {error, nquic_error:any_reason()}.

Process handshake messages (EncryptedExtensions, Certificate, CertificateVerify, Finished).

process_handshake_messages_psk(Data, HandshakeSecret, State)

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

Process PSK handshake messages (EncryptedExtensions + Finished only). No Certificate or CertificateVerify in PSK mode (RFC 8446 S2.3).

process_server_hello(ServerHelloBin, ClientHelloBin, State)

-spec process_server_hello(binary(), binary(), map()) -> {ok, map()} | {error, nquic_error:any_reason()}.

Process a ServerHello, extract the key share, and derive handshake secrets.

take_through_type(Type, Messages)

-spec take_through_type(non_neg_integer(), [binary()]) -> [binary()].

update_transcript_ctx(Ctx, Messages)

-spec update_transcript_ctx(crypto:hash_state(), [binary()]) -> crypto:hash_state().