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/suitehash.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  sdrv
 Server-side handshake driver state. More...
struct  sdrv_pref_addr
 Inputs to sdrv_set_preferred_address: both addresses in network byte order, the CID the migrating client will use (sequence 1), and its stateless reset token (RFC 9000 9.6/18.2). More...
struct  sdrv_init_in
 Inputs to sdrv_init. More...
struct  sdrv_flight_out
 Destination for sdrv_build_server_flight: sh receives the ServerHello, hs the EncryptedExtensions || Certificate || CertificateVerify || Finished flight. More...

Functions

void sdrv_set_preferred_address (sdrv *s, const sdrv_pref_addr *p)
 RFC 9000 9.6: arm the preferred_address transport parameter for this connection's flight.
void sdrv_set_raw_alpns (sdrv *s, const char *raw_alpns)
 RFC 7301 3.2: also select the raw-QUIC application ids in raw_alpns (see wired_srvboot_id.raw_alpns's doc; 0, the sdrv_init default, selects only h3 and hq-interop).
void sdrv_init (sdrv *s, const sdrv_init_in *in)
 Hold the server key material.
int sdrv_set_cids (sdrv *s, wired_span odcid, wired_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 sdrv_set_group (sdrv *s, u16 group)
 RFC 8446 4.2.7: select the NamedGroup for the ECDHE key_share (GROUP_X25519 or GROUP_SECP256R1).
int sdrv_set_cids_retried (sdrv *s, wired_span odcid, wired_span iscid, wired_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 sdrv_set_retry_scid (sdrv *s, wired_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.
void sdrv_set_ticket_key_prev (sdrv *s, const u8 *prev)
 Key rotation: also open presented tickets under prev (TICKET_KEY_LEN bytes, copied), the previous generation of the ticket key.
int sdrv_recv_client_hello (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.
salpn_sni_outcome sdrv_sni_outcome (const sdrv *s)
 RFC 6066 3: the outcome of checking the last ClientHello's server_name against this driver's own certificate (set by sdrv_recv_client_hello via salpn_sni_check).
int sdrv_enforce_sni (sdrv *s)
 RFC 6066 3: opt-in enforcement of the last checked SNI outcome.
void sdrv_set_client_version (sdrv *s, u32 version)
 RFC 9368 2.2: record the QUIC version the client's Initial arrived in, so sdrv_recv_client_hello can validate the version_information parameter's Chosen Version against it (RFC 9368 4) and sdrv_wire_version can fall back to it while nothing better was negotiated.
u32 sdrv_wire_version (const sdrv *s)
 RFC 9368 2.3: the QUIC version every packet of this server's flight (and everything after it) must be sent and read in – the negotiated compatible version once sdrv_recv_client_hello selected one from the client's version_information, else the client's own Initial version (VERSION_1 when that was never recorded either).
int sdrv_hrr_pending (const sdrv *s)
 RFC 8446 4.1.4: 1 when the last sdrv_recv_client_hello call found no x25519 key_share and a HelloRetryRequest must be sent before anything else – the caller must call sdrv_build_hrr instead of proceeding to sdrv_build_server_flight.
int sdrv_early_allowed (const sdrv *s)
 0-RTT is ever admitted under the negotiated ALPN: never on a raw-QUIC id (draft-ietf-moq-transport-18 3.3.1 / -22 6.3.1 let a relay refuse it).
int sdrv_build_hrr (sdrv *s, wired_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: sdrv_recv_client_hello.
u64 sdrv_last_error (const sdrv *s)
 RFC 9001 8.2 / RFC 9000 20.1: the CRYPTO_ERROR recorded by the last sdrv_recv_client_hello call, or 0 if it succeeded.
int sdrv_build_server_flight (sdrv *s, const u8 *server_random, const sdrv_flight_out *out)
 RFC 8446 4.4: build the full server flight into out->sh / out->hs.
int sdrv_handshake_secret (const sdrv *s, const u8 **secret)
 Point *secret at the derived Handshake Secret (verification aid).
int sdrv_early_keys (const sdrv *s, 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 sdrv_recv_client_hello over the accepted PSK and the raw ClientHello bytes when early_data_accepted is 1.
void sdrv_discard_early_keys (sdrv *s)
 RFC 9001 4.9.3: zero the cached 0-RTT keys and mark them unusable once the connection has switched to 1-RTT keys; sdrv_early_keys returns 0 afterwards while early_data_accepted keeps recording that 0-RTT was used.

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

◆ sdrv_build_hrr()

int sdrv_build_hrr ( sdrv * s,
wired_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: sdrv_recv_client_hello.

Must only be called when 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.

◆ sdrv_build_server_flight()

int sdrv_build_server_flight ( sdrv * s,
const u8 * server_random,
const 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.

◆ sdrv_discard_early_keys()

void sdrv_discard_early_keys ( sdrv * s)

RFC 9001 4.9.3: zero the cached 0-RTT keys and mark them unusable once the connection has switched to 1-RTT keys; sdrv_early_keys returns 0 afterwards while early_data_accepted keeps recording that 0-RTT was used.

Idempotent.

Parameters
sdriver state

◆ sdrv_early_allowed()

int sdrv_early_allowed ( const sdrv * s)

0-RTT is ever admitted under the negotiated ALPN: never on a raw-QUIC id (draft-ietf-moq-transport-18 3.3.1 / -22 6.3.1 let a relay refuse it).

A session ticket issued here advertises early data only when this holds (RFC 8446 4.2.10).

Parameters
sdriver state
Returns
1 if 0-RTT may be accepted, 0 otherwise.

◆ sdrv_early_keys()

int sdrv_early_keys ( const sdrv * s,
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 sdrv_recv_client_hello over the accepted PSK and the raw ClientHello bytes when early_data_accepted is 1.

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

◆ sdrv_enforce_sni()

int sdrv_enforce_sni ( sdrv * s)

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

A SALPN_SNI_MISMATCH sets s->last_error to err_crypto(TLS_ALERT_UNRECOGNIZED_NAME) and fails; MATCH and ABSENT are no-ops. Call right after a successful 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.

◆ sdrv_handshake_secret()

int sdrv_handshake_secret ( const 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.

◆ sdrv_hrr_pending()

int sdrv_hrr_pending ( const sdrv * s)

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

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

◆ sdrv_init()

void sdrv_init ( sdrv * s,
const 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

◆ sdrv_last_error()

u64 sdrv_last_error ( const sdrv * s)

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

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

◆ sdrv_recv_client_hello()

int sdrv_recv_client_hello ( 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 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.

◆ sdrv_set_cids()

int sdrv_set_cids ( sdrv * s,
wired_span odcid,
wired_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.

◆ sdrv_set_cids_retried()

int sdrv_set_cids_retried ( sdrv * s,
wired_span odcid,
wired_span iscid,
wired_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.

◆ sdrv_set_client_version()

void sdrv_set_client_version ( sdrv * s,
u32 version )

RFC 9368 2.2: record the QUIC version the client's Initial arrived in, so sdrv_recv_client_hello can validate the version_information parameter's Chosen Version against it (RFC 9368 4) and sdrv_wire_version can fall back to it while nothing better was negotiated.

Call after sdrv_init, before sdrv_recv_client_hello.

Parameters
sdriver state
versionthe client Initial's long-header Version field.

◆ sdrv_set_group()

void sdrv_set_group ( sdrv * s,
u16 group )

RFC 8446 4.2.7: select the NamedGroup for the ECDHE key_share (GROUP_X25519 or GROUP_SECP256R1).

sdrv_init defaults to 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 sdrv_init took).

Parameters
sdriver state
groupthe NamedGroup to require/advertise.

◆ sdrv_set_preferred_address()

void sdrv_set_preferred_address ( sdrv * s,
const sdrv_pref_addr * p )

RFC 9000 9.6: arm the preferred_address transport parameter for this connection's flight.

Call after sdrv_init, before the flight is built.

Parameters
sdriver state
pthe addresses, CID and token to advertise.

◆ sdrv_set_raw_alpns()

void sdrv_set_raw_alpns ( sdrv * s,
const char * raw_alpns )

RFC 7301 3.2: also select the raw-QUIC application ids in raw_alpns (see wired_srvboot_id.raw_alpns's doc; 0, the sdrv_init default, selects only h3 and hq-interop).

Call after sdrv_init, before the ClientHello. raw_alpns must outlive the connection: alpn_tok views into it.

Parameters
sdriver state
raw_alpnsspace-separated protocol ids, or 0

◆ sdrv_set_retry_scid()

int sdrv_set_retry_scid ( sdrv * s,
wired_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

◆ sdrv_set_ticket_key_prev()

void sdrv_set_ticket_key_prev ( sdrv * s,
const u8 * prev )

Key rotation: also open presented tickets under prev (TICKET_KEY_LEN bytes, copied), the previous generation of the ticket key.

Call after sdrv_init, before sdrv_recv_client_hello.

Parameters
sdriver state
prevthe previous ticket key

◆ sdrv_sni_outcome()

salpn_sni_outcome sdrv_sni_outcome ( const sdrv * s)

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

SALPN_SNI_ABSENT if the client sent no server_name (or it was malformed) or no certificate was available yet to check against. A 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 err_crypto(TLS_ALERT_UNRECOGNIZED_NAME) itself.

Parameters
sdriver state
Returns
the last checked SNI outcome.

◆ sdrv_wire_version()

u32 sdrv_wire_version ( const sdrv * s)

RFC 9368 2.3: the QUIC version every packet of this server's flight (and everything after it) must be sent and read in – the negotiated compatible version once sdrv_recv_client_hello selected one from the client's version_information, else the client's own Initial version (VERSION_1 when that was never recorded either).

Parameters
sdriver state
Returns
the connection's wire version (never 0).