|
wired
libc-free QUIC/HTTP3 SDK in C for x86_64-linux
|
RFC 9001 4 / 4.1.2, RFC 8446 4 / 4.4.4, RFC 9000 7: server-side handshake orchestrator, the symmetric peer of client. More...
#include "common/bytes/span/span.h"#include "common/platform/sys/syscall.h"#include "tls/handshake/core/sdrv/sdrv.h"#include "tls/handshake/roles/srvfin/complete.h"#include "tls/keys/kuswitch/twogen.h"#include "transport/conn/loop/crecv/collect.h"#include "transport/io/socket/io/udp.h"Go to the source code of this file.
Data Structures | |
| struct | wired_server |
| Server-side handshake orchestrator state, initialized by wired_server_init. More... | |
| struct | wired_server_init_in |
| server_priv_x25519/server_pub_x25519 are the static ECDHE pair; cert_seed is the ECDSA P-256 signing scalar (big-endian). More... | |
Macros | |
| #define | WIRED_SERVER_FLIGHT_MAX 2048 |
| Capacity of a server flight buffer in octets. | |
| #define | WIRED_SERVER_TRANSCRIPT_MAX 16384 |
| Capacity of the raw handshake transcript buffer in octets: ClientHello + ServerHello + the server Handshake flight, sized past quic-interop-runner's deliberately inflated 9-cert amplificationlimit chain (~10KB flight) with headroom. | |
| #define | WIRED_SERVER_DATAGRAM_MAX 1500 |
| Capacity of one received UDP datagram in octets. | |
Enumerations | |
| enum | { WIRED_SERVER_HS_INITIAL = 0 , WIRED_SERVER_HS_CH_RECVD , WIRED_SERVER_HS_FLIGHT_SENT , WIRED_SERVER_HS_CONFIRMED } |
| Handshake phases of the orchestrator (wired_server.phase). More... | |
Functions | |
| void | wired_server_init (wired_server *s, const wired_server_init_in *in) |
| Initialize the orchestrator with the server key material. | |
| int | wired_server_set_cids (wired_server *s, wired_span odcid, wired_span iscid) |
| RFC 9000 7.3: record the DCID of the client's first Initial (the ODCID the server echoes) and the server's source connection id (ISCID) so the EncryptedExtensions transport parameters carry the real connection ids. | |
| void | wired_server_set_limits (wired_server *s, u64 max_data, u64 max_streams_bidi, u64 max_streams_uni, u64 max_datagram_frame_size) |
| Override the advertised transport-parameter limits (RFC 9000 18.2); a zero field keeps its built-in default. | |
| void | wired_server_set_reset_token (wired_server *s, const u8 token[16]) |
| Advertise this 16-byte stateless_reset_token (RFC 9000 10.3.1/18.2) for the server's handshake SCID in the transport parameters. | |
| void | wired_server_set_keylog_path (wired_server *s, const char *path) |
| Set the NSS key log file path (SSLKEYLOGFILE format); 0 disables (the default). | |
| int | wired_server_recv_initial (wired_server *s, const u8 *ch_msg, usz ch_len) |
| RFC 8446 4.4.1: fold a received ClientHello (TLS handshake message bytes) into the transcript, recording ClientHello.random (bytes [4,36) of ch_msg: legacy_version(2) precedes it, RFC 8446 4.1.2) for later keylog lines. | |
| int | wired_server_build_hrr (wired_server *s, wired_obuf *out) |
| RFC 8446 4.1.4: emit the HelloRetryRequest a just-received ClientHello1 without a usable (x25519) key_share owes, and restart the raw transcript as message_hash(ClientHello1) || HRR (RFC 8446 4.4.1). | |
| int | wired_server_build_flight (wired_server *s, const u8 *server_random, const sdrv_flight_out *out) |
| RFC 8446 4.4 / RFC 9001 4: build the server flight (ServerHello into out->sh, EncryptedExtensions||Certificate||CertificateVerify||Finished into out->hs) and derive the Handshake key. | |
| int | wired_server_feed (wired_server *s, const u8 *crypto_payload, usz len) |
| RFC 8446 4.4.4 / RFC 9001 4.1.2: drive the handshake with one received Handshake-packet CRYPTO payload (socket-free injection). | |
| int | wired_server_handshake_done (wired_server *s, wired_obuf *out) |
| RFC 9001 4.1.2 / RFC 9000 19.20: write the HANDSHAKE_DONE frame, at most once and only after confirmation. | |
| int | wired_server_is_confirmed (const wired_server *s) |
| 1 once the client Finished verified and the handshake is confirmed. | |
| int | wired_server_early_data_used (const wired_server *s) |
| RFC 9001 4.6.1 / 9.2: whether the client's 0-RTT early data was accepted on this connection (the ticket was on its first use and its binder verified). | |
| int | wired_server_early_send_keys (wired_server *s) |
| Derive and install the server's 1-RTT send keys before the client Finished arrives (0.5-RTT, RFC 9001 4.9 / RFC 8446 7.1): the application traffic secrets depend only on the transcript through the server Finished, so they are available the moment the flight is built. | |
| int | wired_server_resumption_secret (const wired_server *s, u8 *out) |
| RFC 8446 4.6.1/7.1: resumption_master_secret = Derive-Secret(Master Secret, "res master", ClientHello..client Finished) – the secret a NewSessionTicket must actually carry (RFC 8446 4.6.1: "The ticket itself
is an opaque label... the PSK associated with the ticket is computed as...
resumption_master_secret"). | |
| int | wired_server_listen (wired_server *s, u16 port) |
| Open a UDP socket bound to port and wait for the ClientHello. | |
| int | wired_server_pump (wired_server *s) |
| One receive iteration: pull a datagram off the socket and feed it. | |
| int | wired_server_run_handshake (wired_server *s, int max_iterations) |
| Pump until confirmed or max_iterations is reached (bounded so a silent or hostile peer cannot wedge the server). | |
| void | wired_server_close (wired_server *s) |
| Close the UDP socket and wipe the key schedule's retained secrets (RFC 8446 E.1.4: the exporter_master_secret is erased at teardown). | |
RFC 9001 4 / 4.1.2, RFC 8446 4 / 4.4.4, RFC 9000 7: server-side handshake orchestrator, the symmetric peer of client.
Drives the verified parts (sdrv folds the ClientHello and emits the server flight; srvfin verifies the client Finished and, only on success, advances to Master, installs the 1-RTT key set and confirms) to handshake confirmation and HANDSHAKE_DONE.
All policy lives in those layers; the server wires them and gates 1-RTT promotion on a verified client Finished. The data path (wired_server_feed) is socket-free so it can be driven by buffer injection without a socket; only wired_server_pump enters the kernel via io/udp.
| #define WIRED_SERVER_TRANSCRIPT_MAX 16384 |
Capacity of the raw handshake transcript buffer in octets: ClientHello + ServerHello + the server Handshake flight, sized past quic-interop-runner's deliberately inflated 9-cert amplificationlimit chain (~10KB flight) with headroom.
A truncated transcript silently desyncs srv_verify_finished's hash from the client's real one, so every client Finished fails and the server goes silent (RFC 8446 4.4.1/4.4.4).
| anonymous enum |
Handshake phases of the orchestrator (wired_server.phase).
| int wired_server_build_flight | ( | wired_server * | s, |
| const u8 * | server_random, | ||
| const sdrv_flight_out * | out ) |
RFC 8446 4.4 / RFC 9001 4: build the server flight (ServerHello into out->sh, EncryptedExtensions||Certificate||CertificateVerify||Finished into out->hs) and derive the Handshake key.
Only valid after the ClientHello was received. Advances CH_RECVD -> FLIGHT_SENT.
| s | the orchestrator to advance |
| server_random | the ServerHello.random, 32 bytes |
| out | receives the ServerHello and the Handshake-level flight |
| int wired_server_build_hrr | ( | wired_server * | s, |
| wired_obuf * | out ) |
RFC 8446 4.1.4: emit the HelloRetryRequest a just-received ClientHello1 without a usable (x25519) key_share owes, and restart the raw transcript as message_hash(ClientHello1) || HRR (RFC 8446 4.4.1).
The phase stays HS_INITIAL: the retried ClientHello2 re-enters wired_server_recv_initial. Only valid while sdrv_hrr_pending; a second HRR is never produced (ClientHello2 still without a share is rejected instead).
| s | the orchestrator holding the HRR-bound ClientHello1 |
| out | receives the HelloRetryRequest handshake message bytes |
| void wired_server_close | ( | wired_server * | s | ) |
Close the UDP socket and wipe the key schedule's retained secrets (RFC 8446 E.1.4: the exporter_master_secret is erased at teardown).
| s | the orchestrator whose socket to close |
| int wired_server_early_data_used | ( | const wired_server * | s | ) |
RFC 9001 4.6.1 / 9.2: whether the client's 0-RTT early data was accepted on this connection (the ticket was on its first use and its binder verified).
Stays 1 after the 0-RTT keys are discarded at confirmation, so the application can apply its replay policy to what arrived early.
| s | the orchestrator to inspect |
| int wired_server_early_send_keys | ( | wired_server * | s | ) |
Derive and install the server's 1-RTT send keys before the client Finished arrives (0.5-RTT, RFC 9001 4.9 / RFC 8446 7.1): the application traffic secrets depend only on the transcript through the server Finished, so they are available the moment the flight is built.
Does not confirm the handshake; the confirm-time derivation over the same transcript is unaffected. Idempotent.
| s | the orchestrator whose flight has been built |
| int wired_server_feed | ( | wired_server * | s, |
| const u8 * | crypto_payload, | ||
| usz | len ) |
RFC 8446 4.4.4 / RFC 9001 4.1.2: drive the handshake with one received Handshake-packet CRYPTO payload (socket-free injection).
Reassembles the client Finished, verifies its verify_data, and ONLY on a match advances to Master, installs the 1-RTT key set and confirms (CH_RECVD/FLIGHT_SENT -> CONFIRMED). A forged Finished promotes nothing.
| s | the orchestrator to advance |
| crypto_payload | one Handshake-packet CRYPTO payload |
| len | length of crypto_payload in octets |
| int wired_server_handshake_done | ( | wired_server * | s, |
| wired_obuf * | out ) |
RFC 9001 4.1.2 / RFC 9000 19.20: write the HANDSHAKE_DONE frame, at most once and only after confirmation.
| s | the orchestrator to emit from |
| out | receives the HANDSHAKE_DONE frame |
| void wired_server_init | ( | wired_server * | s, |
| const wired_server_init_in * | in ) |
Initialize the orchestrator with the server key material.
No socket is opened.
| s | the orchestrator to initialize |
| in | the server key material |
| int wired_server_is_confirmed | ( | const wired_server * | s | ) |
1 once the client Finished verified and the handshake is confirmed.
| s | the orchestrator to inspect |
| int wired_server_listen | ( | wired_server * | s, |
| u16 | port ) |
Open a UDP socket bound to port and wait for the ClientHello.
| s | the orchestrator that will own the socket |
| port | UDP port to bind |
| int wired_server_pump | ( | wired_server * | s | ) |
One receive iteration: pull a datagram off the socket and feed it.
| s | the orchestrator to pump |
| int wired_server_recv_initial | ( | wired_server * | s, |
| const u8 * | ch_msg, | ||
| usz | ch_len ) |
RFC 8446 4.4.1: fold a received ClientHello (TLS handshake message bytes) into the transcript, recording ClientHello.random (bytes [4,36) of ch_msg: legacy_version(2) precedes it, RFC 8446 4.1.2) for later keylog lines.
Advances INITIAL -> CH_RECVD.
| s | the orchestrator to advance |
| ch_msg | the ClientHello handshake message bytes |
| ch_len | length of ch_msg in octets |
| int wired_server_resumption_secret | ( | const wired_server * | s, |
| u8 * | out ) |
RFC 8446 4.6.1/7.1: resumption_master_secret = Derive-Secret(Master Secret, "res master", ClientHello..client Finished) – the secret a NewSessionTicket must actually carry (RFC 8446 4.6.1: "The ticket itself is an opaque label... the PSK associated with the ticket is computed as... resumption_master_secret").
Only meaningful once wired_server_is_ confirmed (the client Finished must have verified first); returns 0 (leaving out untouched) before that.
| s | the confirmed orchestrator to derive from |
| out | receives the Hash.length-byte resumption_master_secret (32, or 48 under TLS_AES_256_GCM_SHA384); size it TICKET_SECRET_LEN |
| int wired_server_run_handshake | ( | wired_server * | s, |
| int | max_iterations ) |
Pump until confirmed or max_iterations is reached (bounded so a silent or hostile peer cannot wedge the server).
| s | the orchestrator to pump |
| max_iterations | upper bound on receive iterations |
| int wired_server_set_cids | ( | wired_server * | s, |
| wired_span | odcid, | ||
| wired_span | iscid ) |
RFC 9000 7.3: record the DCID of the client's first Initial (the ODCID the server echoes) and the server's source connection id (ISCID) so the EncryptedExtensions transport parameters carry the real connection ids.
Must be called before build_flight.
| s | the orchestrator to record on |
| odcid | the DCID of the client's first Initial |
| iscid | the server's source connection id |
| void wired_server_set_keylog_path | ( | wired_server * | s, |
| const char * | path ) |
Set the NSS key log file path (SSLKEYLOGFILE format); 0 disables (the default).
When set, wired_server_feed appends, once the client Finished verifies, CLIENT_EARLY_TRAFFIC_SECRET (only if 0-RTT was accepted), CLIENT_/SERVER_HANDSHAKE_TRAFFIC_SECRET, CLIENT_/SERVER_TRAFFIC_SECRET_0 and EXPORTER_SECRET lines (RFC 8446 7.1 secrets).
| s | the orchestrator to configure |
| path | NUL-terminated key log file path, or 0 to disable |
| void wired_server_set_limits | ( | wired_server * | s, |
| u64 | max_data, | ||
| u64 | max_streams_bidi, | ||
| u64 | max_streams_uni, | ||
| u64 | max_datagram_frame_size ) |
Override the advertised transport-parameter limits (RFC 9000 18.2); a zero field keeps its built-in default.
Call before the flight is built.
| s | the server |
| max_data | initial_max_data in bytes (0 = default) |
| max_streams_bidi | initial_max_streams_bidi (0 = default) |
| max_streams_uni | initial_max_streams_uni (0 = default); advertise only what the receive side's slot capacity actually backs (RFC 9000 4.6 lockstep – see stp_limits.max_streams_uni) |
| max_datagram_frame_size | max_datagram_frame_size (RFC 9221 3), 0 = not advertised (no default: opt in once DATAGRAM delivery is wired) |
| void wired_server_set_reset_token | ( | wired_server * | s, |
| const u8 | token[16] ) |
Advertise this 16-byte stateless_reset_token (RFC 9000 10.3.1/18.2) for the server's handshake SCID in the transport parameters.
Derive it from a restart-stable secret (sreset_key_derive + sreset_token) so a rebooted server can still produce it. Call before the flight is built; never calling it simply omits the TP.
| s | the server |
| token | the 16-byte token |