|
wired
libc-free QUIC/HTTP3 SDK in C for x86_64-linux
|
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. | |
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.
| 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).
| s | driver state |
| out | receives the HelloRetryRequest message bytes |
| 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.
| s | driver state |
| server_random | the 32-byte ServerHello.random |
| out | destination buffers for the ServerHello and handshake flight |
| 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.
| s | driver state |
| 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).
| s | driver state |
| 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.
| s | driver state (sdrv_recv_client_hello must have run) |
| out | receives the 0-RTT key/iv/hp |
| 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.
| s | driver state |
Point *secret at the derived Handshake Secret (verification aid).
| s | driver state |
| secret | receives a pointer to the internal Handshake Secret |
| 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.
| s | driver state |
| 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.
| s | driver state to initialize |
| in | key material and optional external certificate chain |
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.
| s | driver state |
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.
| s | driver state |
| ch_msg | the ClientHello handshake message bytes |
| ch_len | length of ch_msg in bytes |
| 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.
| s | driver state |
| odcid | DCID of the client's first Initial packet |
| iscid | the server's source connection id |
| 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.
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.
| s | driver state |
| version | the client Initial's long-header Version field. |
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).
| s | driver state |
| group | the NamedGroup to require/advertise. |
| 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.
| s | driver state |
| p | the addresses, CID and token to advertise. |
| 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.
| s | driver state |
| raw_alpns | space-separated protocol ids, or 0 |
| 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.
| s | the server driver |
| rscid | the Retry's source connection id (at most 20 bytes) |
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.
| s | driver state |
| prev | the previous ticket key |
| 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.
| s | driver state |
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).
| s | driver state |