wired
libc-free QUIC/HTTP3 SDK in C for x86_64-linux
Loading...
Searching...
No Matches
sdrv.h File Reference

RFC 8446 4 / RFC 9001 4: server-side handshake driver. More...

#include "common/bytes/span/span.h"
#include "crypto/kdf/hkdf/hkdf.h"
#include "tls/ext/salpn/negotiate.h"
#include "tls/ext/salpn/sni_check.h"
#include "tls/ext/stp/server_tp.h"
#include "tls/handshake/core/tls/cert.h"
#include "tls/handshake/core/tls/initial.h"
#include "tls/handshake/core/tls/transcript.h"
#include "tls/keys/ticket/ticket.h"

Go to the source code of this file.

Data Structures

struct  quic_sdrv
 Server-side handshake driver state. More...
struct  quic_sdrv_init_in
 Inputs to quic_sdrv_init. More...
struct  quic_sdrv_flight_out
 Destination for quic_sdrv_build_server_flight: sh receives the ServerHello, hs the EncryptedExtensions || Certificate || CertificateVerify || Finished flight. More...

Functions

void quic_sdrv_init (quic_sdrv *s, const quic_sdrv_init_in *in)
 Hold the server key material.
int quic_sdrv_set_cids (quic_sdrv *s, quic_span odcid, quic_span iscid)
 RFC 9000 7.3: record the ODCID (the DCID of the client's first Initial) and the ISCID (the server's source connection id) to advertise in the EncryptedExtensions transport parameters.
void quic_sdrv_set_group (quic_sdrv *s, u16 group)
 RFC 8446 4.2.7: select the NamedGroup for the ECDHE key_share (QUIC_GROUP_X25519 or QUIC_GROUP_SECP256R1).
int quic_sdrv_set_cids_retried (quic_sdrv *s, quic_span odcid, quic_span iscid, quic_span true_odcid)
 RFC 9000 7.3, post-Retry accept: odcid is the Initial-key derivation input (the Retry's own SCID – the client's second Initial is keyed off it, RFC 9001 5.2), iscid the server's own source connection id as usual, and true_odcid the ORIGINAL first Initial's DCID recovered from the Retry token – advertised as original_destination_connection_id instead of odcid, which has already moved on.
int quic_sdrv_set_retry_scid (quic_sdrv *s, quic_span rscid)
 Record the Retry packet's SCID for the retry_source_connection_id transport parameter (RFC 9000 7.3) – only after a Retry actually happened; never call it on the direct-accept path.
int quic_sdrv_recv_client_hello (quic_sdrv *s, const u8 *ch_msg, usz ch_len)
 RFC 8446 4.4.1: fold the ClientHello into the transcript and take the client's x25519 key_share.
quic_salpn_sni_outcome quic_sdrv_sni_outcome (const quic_sdrv *s)
 RFC 6066 3: the outcome of checking the last ClientHello's server_name against this driver's own certificate (set by quic_sdrv_recv_client_hello via quic_salpn_sni_check).
int quic_sdrv_enforce_sni (quic_sdrv *s)
 RFC 6066 3: opt-in enforcement of the last checked SNI outcome.
int quic_sdrv_hrr_pending (const quic_sdrv *s)
 RFC 8446 4.1.4: 1 when the last quic_sdrv_recv_client_hello call found no x25519 key_share and a HelloRetryRequest must be sent before anything else – the caller must call quic_sdrv_build_hrr instead of proceeding to quic_sdrv_build_server_flight.
int quic_sdrv_build_hrr (quic_sdrv *s, quic_obuf *out)
 RFC 8446 4.1.4 / 4.4.1: build the HelloRetryRequest (requesting x25519, this driver's only supported group) into out, fold it into the transcript, and arm ClientHello2 handling: quic_sdrv_recv_client_hello.
u64 quic_sdrv_last_error (const quic_sdrv *s)
 RFC 9001 8.2 / RFC 9000 20.1: the CRYPTO_ERROR recorded by the last quic_sdrv_recv_client_hello call, or 0 if it succeeded.
int quic_sdrv_build_server_flight (quic_sdrv *s, const u8 *server_random, const quic_sdrv_flight_out *out)
 RFC 8446 4.4: build the full server flight into out->sh / out->hs.
int quic_sdrv_handshake_secret (const quic_sdrv *s, const u8 **secret)
 Point *secret at the derived Handshake Secret (verification aid).
int quic_sdrv_early_keys (const quic_sdrv *s, quic_initial_keys *out)
 RFC 8446 4.2.10 / RFC 9001 4.6.1: the 0-RTT packet-protection keys (client_early_traffic_secret's key/iv/hp), derived by quic_sdrv_recv_client_hello over the accepted PSK and the raw ClientHello bytes when early_data_accepted is 1.

Detailed Description

RFC 8446 4 / RFC 9001 4: server-side handshake driver.

Receives the client ClientHello and emits the real TLS bytes of the server flight (ServerHello + EncryptedExtensions + Certificate + CertificateVerify + Finished). Pure orchestration over the existing build/sign/key-schedule parts.

Function Documentation

◆ quic_sdrv_build_hrr()

int quic_sdrv_build_hrr ( quic_sdrv * s,
quic_obuf * out )

RFC 8446 4.1.4 / 4.4.1: build the HelloRetryRequest (requesting x25519, this driver's only supported group) into out, fold it into the transcript, and arm ClientHello2 handling: quic_sdrv_recv_client_hello.

Must only be called when quic_sdrv_hrr_pending is 1 (right after the ClientHello1 that triggered it, before anything else touches the transcript).

Parameters
sdriver state
outreceives the HelloRetryRequest message bytes
Returns
1 on success, 0 if out is too small.

◆ quic_sdrv_build_server_flight()

int quic_sdrv_build_server_flight ( quic_sdrv * s,
const u8 * server_random,
const quic_sdrv_flight_out * out )

RFC 8446 4.4: build the full server flight into out->sh / out->hs.

Derives the handshake secret over the real ECDHE.

Parameters
sdriver state
server_randomthe 32-byte ServerHello.random
outdestination buffers for the ServerHello and handshake flight
Returns
1 on success, 0 if a buffer is too small.

◆ quic_sdrv_early_keys()

int quic_sdrv_early_keys ( const quic_sdrv * s,
quic_initial_keys * out )

RFC 8446 4.2.10 / RFC 9001 4.6.1: the 0-RTT packet-protection keys (client_early_traffic_secret's key/iv/hp), derived by quic_sdrv_recv_client_hello over the accepted PSK and the raw ClientHello bytes when early_data_accepted is 1.

Parameters
sdriver state (quic_sdrv_recv_client_hello must have run)
outreceives the 0-RTT key/iv/hp
Returns
1 if early_data_accepted, 0 otherwise (out untouched).

◆ quic_sdrv_enforce_sni()

int quic_sdrv_enforce_sni ( quic_sdrv * s)

RFC 6066 3: opt-in enforcement of the last checked SNI outcome.

A QUIC_SALPN_SNI_MISMATCH sets s->last_error to quic_err_crypto(QUIC_TLS_ALERT_UNRECOGNIZED_NAME) and fails; MATCH and ABSENT are no-ops. Call right after a successful quic_sdrv_recv_client_hello when the caller wants unrecognized_name enforced instead of RFC 6066 3's silent-continue default.

Parameters
sdriver state
Returns
1 to continue, 0 if the caller must reject the handshake.

◆ quic_sdrv_handshake_secret()

int quic_sdrv_handshake_secret ( const quic_sdrv * s,
const u8 ** secret )

Point *secret at the derived Handshake Secret (verification aid).

Parameters
sdriver state
secretreceives a pointer to the internal Handshake Secret
Returns
1 if build_server_flight has run, 0 otherwise.

◆ quic_sdrv_hrr_pending()

int quic_sdrv_hrr_pending ( const quic_sdrv * s)

RFC 8446 4.1.4: 1 when the last quic_sdrv_recv_client_hello call found no x25519 key_share and a HelloRetryRequest must be sent before anything else – the caller must call quic_sdrv_build_hrr instead of proceeding to quic_sdrv_build_server_flight.

Parameters
sdriver state
Returns
1 if a HelloRetryRequest is pending, 0 otherwise.

◆ quic_sdrv_init()

void quic_sdrv_init ( quic_sdrv * s,
const quic_sdrv_init_in * in )

Hold the server key material.

If in->chain is NULL/empty, build the self-signed P-256 certificate from in->sign_priv; otherwise copy the chain views (leaf first) as the certificate_list to send. Init transcript/key schedule.

Parameters
sdriver state to initialize
inkey material and optional external certificate chain

◆ quic_sdrv_last_error()

u64 quic_sdrv_last_error ( const quic_sdrv * s)

RFC 9001 8.2 / RFC 9000 20.1: the CRYPTO_ERROR recorded by the last quic_sdrv_recv_client_hello call, or 0 if it succeeded.

Parameters
sdriver state
Returns
the CRYPTO_ERROR code (0x0100 | TLS alert), or 0.

◆ quic_sdrv_recv_client_hello()

int quic_sdrv_recv_client_hello ( quic_sdrv * s,
const u8 * ch_msg,
usz ch_len )

RFC 8446 4.4.1: fold the ClientHello into the transcript and take the client's x25519 key_share.

RFC 8446 4.2.11/4.2.11.2 session resumption, only when has_ticket_key: if the ClientHello carries no pre_shared_key extension, behavior is exactly the full-handshake path above (psk_accepted stays 0). If it does, this opens the offered ticket (its identity bytes) under ticket_key; a ticket that fails to open (wrong key, malformed, tampered) is a silent MAY- degrade to a full handshake (psk_accepted stays 0, no error). A ticket that opens has its PSK binder verified against the resumption secret and the truncated ClientHello; a binder mismatch instead makes this whole call fail (0) – RFC 8446 4.2.11.2 MUST abort the handshake, never fall back silently. On a verified binder, psk_accepted is set to 1 and psk_secret holds the opened ticket's resumption secret, for quic_sdrv_build_server_flight's key schedule.

RFC 9001 8.2: a ClientHello missing the quic_transport_parameters extension (0x39) is rejected before any other field is taken; s->last_error is set to the missing_extension CRYPTO_ERROR (0x016d) in that case.

Parameters
sdriver state
ch_msgthe ClientHello handshake message bytes
ch_lenlength of ch_msg in bytes
Returns
1 on success (with or without an accepted PSK), 0 if the ClientHello itself is malformed/unsupported, lacks the quic_transport_parameters extension, or a presented PSK binder fails verification.

◆ quic_sdrv_set_cids()

int quic_sdrv_set_cids ( quic_sdrv * s,
quic_span odcid,
quic_span iscid )

RFC 9000 7.3: record the ODCID (the DCID of the client's first Initial) and the ISCID (the server's source connection id) to advertise in the EncryptedExtensions transport parameters.

Must be called before build_server_flight.

Parameters
sdriver state
odcidDCID of the client's first Initial packet
iscidthe server's source connection id
Returns
1 on success, 0 if either length exceeds 20.

◆ quic_sdrv_set_cids_retried()

int quic_sdrv_set_cids_retried ( quic_sdrv * s,
quic_span odcid,
quic_span iscid,
quic_span true_odcid )

RFC 9000 7.3, post-Retry accept: odcid is the Initial-key derivation input (the Retry's own SCID – the client's second Initial is keyed off it, RFC 9001 5.2), iscid the server's own source connection id as usual, and true_odcid the ORIGINAL first Initial's DCID recovered from the Retry token – advertised as original_destination_connection_id instead of odcid, which has already moved on.

Returns
1 on success, 0 if any length exceeds 20.

◆ quic_sdrv_set_group()

void quic_sdrv_set_group ( quic_sdrv * s,
u16 group )

RFC 8446 4.2.7: select the NamedGroup for the ECDHE key_share (QUIC_GROUP_X25519 or QUIC_GROUP_SECP256R1).

quic_sdrv_init defaults to QUIC_GROUP_X25519; call this right after init, before receiving any ClientHello, to use secp256r1 instead. server_priv/server_pub must already hold the matching key pair (32-byte P-256 scalar + 65-byte SEC1 uncompressed public, in place of the x25519 pair quic_sdrv_init took).

Parameters
sdriver state
groupthe NamedGroup to require/advertise.

◆ quic_sdrv_set_retry_scid()

int quic_sdrv_set_retry_scid ( quic_sdrv * s,
quic_span rscid )

Record the Retry packet's SCID for the retry_source_connection_id transport parameter (RFC 9000 7.3) – only after a Retry actually happened; never call it on the direct-accept path.

Parameters
sthe server driver
rscidthe Retry's source connection id (at most 20 bytes)
Returns
1 on success, 0 when rscid exceeds 20 bytes

◆ quic_sdrv_sni_outcome()

quic_salpn_sni_outcome quic_sdrv_sni_outcome ( const quic_sdrv * s)

RFC 6066 3: the outcome of checking the last ClientHello's server_name against this driver's own certificate (set by quic_sdrv_recv_client_hello via quic_salpn_sni_check).

QUIC_SALPN_SNI_ABSENT if the client sent no server_name (or it was malformed) or no certificate was available yet to check against. A QUIC_SALPN_SNI_MISMATCH never fails the handshake on its own (RFC 6066 3 permits continuing); a caller that wants to enforce unrecognized_name checks this and closes with quic_err_crypto(QUIC_TLS_ALERT_UNRECOGNIZED_NAME) itself.

Parameters
sdriver state
Returns
the last checked SNI outcome.