23 static constexpr uint8_t TLS_ALERT_UNEXPECTED_MESSAGE = 10;
24 static constexpr uint8_t TLS_ALERT_HANDSHAKE_FAILURE = 40;
25 static constexpr uint8_t TLS_ALERT_ILLEGAL_PARAMETER = 47;
26 static constexpr uint8_t TLS_ALERT_DECODE_ERROR = 50;
27 static constexpr uint8_t TLS_ALERT_DECRYPT_ERROR = 51;
28 static constexpr uint8_t TLS_ALERT_PROTOCOL_VERSION = 70;
29 static constexpr uint8_t TLS_ALERT_INTERNAL_ERROR = 80;
30 static constexpr uint8_t TLS_ALERT_MISSING_EXTENSION = 109;
31 static constexpr uint8_t TLS_ALERT_NO_APPLICATION_PROTOCOL = 120;
37#define PC_QUIC_TLS_TP_ENC_CAP 512
41#define PC_QUIC_TLS_EE_MAX (4 + 2 + 9 + 4 + PC_QUIC_TLS_TP_ENC_CAP)
49 "PC_H3_CRYPTO_BUF (QuicTls::flight_hs) must hold a whole EncryptedExtensions: the fixed "
50 "512-byte transport-parameter buffer plus the ALPN and extension framing");
52void fail(QuicTls *qt, uint8_t alert)
54 qt->state = QtlsState::QTLS_FAILED;
66bool emit(QuicTls *qt, uint8_t *flight,
size_t cap,
size_t *plen,
size_t written)
71 if (!written || written > cap - *plen)
73 fail(qt, TlsAlert::TLS_ALERT_INTERNAL_ERROR);
86bool send_hello_retry(QuicTls *qt,
const uint8_t *msg,
size_t msg_len,
const Tls13ClientHello *ch)
97 size_t mhn = pc_tls13_build_message_hash(mh,
sizeof(mh), ch1_hash);
100 fail(qt, TlsAlert::TLS_ALERT_INTERNAL_ERROR);
105 qt->flight_initial_len = 0;
106 size_t n = pc_tls13_build_hello_retry_request(qt->flight_initial,
sizeof(qt->flight_initial), ch->session_id,
107 ch->session_id_len, TLS_GROUP_X25519MLKEM768,
nullptr, 0,
109 if (!emit(qt, qt->flight_initial,
sizeof(qt->flight_initial), &qt->flight_initial_len, n))
118bool process_client_hello(QuicTls *qt,
const uint8_t *msg,
size_t msg_len)
121 if (!pc_tls13_parse_client_hello(msg, msg_len, &ch))
123 fail(qt, TlsAlert::TLS_ALERT_DECODE_ERROR);
126 if (!ch.offers_tls13)
128 fail(qt, TlsAlert::TLS_ALERT_PROTOCOL_VERSION);
131 bool use_hybrid =
false;
134 use_hybrid = ch.has_hybrid_share && ch.offers_x25519mlkem768;
139 if (!use_hybrid && ch.offers_x25519mlkem768 && !ch.has_hybrid_share && !qt->hrr_sent)
141 return send_hello_retry(qt, msg, msg_len, &ch);
144 if (qt->hrr_sent && !use_hybrid)
146 fail(qt, TlsAlert::TLS_ALERT_HANDSHAKE_FAILURE);
150 if (!ch.offers_ed25519 || (!use_hybrid && (!ch.has_key_share || !ch.offers_x25519)))
152 fail(qt, TlsAlert::TLS_ALERT_HANDSHAKE_FAILURE);
155 if (!ch.offers_h3_alpn)
157 fail(qt, TlsAlert::TLS_ALERT_NO_APPLICATION_PROTOCOL);
162 fail(qt, TlsAlert::TLS_ALERT_MISSING_EXTENSION);
165 if (!pc_quic_tp_parse(ch.pc_quic_tp, ch.pc_quic_tp_len, &qt->peer))
167 fail(qt, TlsAlert::TLS_ALERT_ILLEGAL_PARAMETER);
170 qt->have_peer =
true;
179 uint8_t server_share[MLKEM768_CT_BYTES + 32];
183 if (!pc_mlkem768_encaps(ch.client_mlkem_ek, qt->cfg.mlkem_m, server_share, ml_ss))
185 fail(qt, TlsAlert::TLS_ALERT_HANDSHAKE_FAILURE);
189 uint8_t server_pub[32];
190 pc_x25519(x_ss, qt->cfg.ephemeral_priv, ch.client_x25519);
192 memcpy(server_share + MLKEM768_CT_BYTES, server_pub, 32);
193 memcpy(ecdhe, ml_ss, 32);
194 memcpy(ecdhe + 32, x_ss, 32);
196 share_len = MLKEM768_CT_BYTES + 32;
197 group = TLS_GROUP_X25519MLKEM768;
201 uint8_t server_share[32];
204 pc_x25519(ecdhe, qt->cfg.ephemeral_priv, ch.client_x25519);
208 group = TLS_GROUP_X25519;
218 size_t n = pc_tls13_build_server_hello(qt->flight_initial + qt->flight_initial_len,
219 sizeof(qt->flight_initial) - qt->flight_initial_len, qt->cfg.random,
220 ch.session_id, ch.session_id_len, server_share, share_len, group);
221 if (!emit(qt, qt->flight_initial,
sizeof(qt->flight_initial), &qt->flight_initial_len, n))
229 snapshot_hash(&qt->transcript, hash);
230 pc_tls13_ks_early(&TLS13_KDF, &qt->ks);
231 pc_tls13_ks_handshake(&qt->ks, ecdhe, hash, ecdhe_len);
232 pc_quic_keys_from_secret(qt->ks.client_hs_traffic, &qt->hs_client);
233 pc_quic_keys_from_secret(qt->ks.server_hs_traffic, &qt->hs_server);
234 qt->hs_keys_ready =
true;
237 qt->flight_hs_len = 0;
238 uint8_t tp_enc[PC_QUIC_TLS_TP_ENC_CAP];
239 size_t tp_len = pc_quic_tp_encode(&qt->cfg.params, tp_enc,
sizeof(tp_enc));
241 n = pc_tls13_build_encrypted_extensions(qt->flight_hs + qt->flight_hs_len,
242 sizeof(qt->flight_hs) - qt->flight_hs_len, tp_enc, tp_len);
243 if (!emit(qt, qt->flight_hs,
sizeof(qt->flight_hs), &qt->flight_hs_len, n))
249 n = pc_tls13_build_certificate(qt->flight_hs + qt->flight_hs_len,
sizeof(qt->flight_hs) - qt->flight_hs_len,
250 qt->cfg.cert_der, qt->cfg.cert_len);
251 if (!emit(qt, qt->flight_hs,
sizeof(qt->flight_hs), &qt->flight_hs_len, n))
257 snapshot_hash(&qt->transcript, hash);
258 n = pc_tls13_build_cert_verify(qt->flight_hs + qt->flight_hs_len,
sizeof(qt->flight_hs) - qt->flight_hs_len, hash,
259 qt->cfg.ed25519_seed);
260 if (!emit(qt, qt->flight_hs,
sizeof(qt->flight_hs), &qt->flight_hs_len, n))
266 snapshot_hash(&qt->transcript, hash);
268 pc_tls13_finished_mac(&TLS13_KDF, qt->ks.server_hs_traffic, hash, verify);
269 n = pc_tls13_build_finished(qt->flight_hs + qt->flight_hs_len,
sizeof(qt->flight_hs) - qt->flight_hs_len, verify);
270 if (!emit(qt, qt->flight_hs,
sizeof(qt->flight_hs), &qt->flight_hs_len, n))
277 snapshot_hash(&qt->transcript, qt->hs_finished_hash);
278 pc_tls13_ks_master(&qt->ks, qt->hs_finished_hash);
279 pc_quic_keys_from_secret(qt->ks.client_ap_traffic, &qt->ap_client);
280 pc_quic_keys_from_secret(qt->ks.server_ap_traffic, &qt->ap_server);
281 qt->ap_keys_ready =
true;
283 qt->state = QtlsState::QTLS_WAIT_FINISHED;
287bool process_client_finished(QuicTls *qt,
const uint8_t *msg,
size_t msg_len)
289 if (msg[0] != TlsHs::TLS_HS_FINISHED || msg_len != 4 + 32)
291 fail(qt, TlsAlert::TLS_ALERT_DECODE_ERROR);
294 uint8_t expected[32];
295 pc_tls13_finished_mac(&TLS13_KDF, qt->ks.client_hs_traffic, qt->hs_finished_hash, expected);
297 for (
int i = 0; i < 32; i++)
299 diff |= (uint8_t)(expected[i] ^ msg[4 + i]);
303 fail(qt, TlsAlert::TLS_ALERT_DECRYPT_ERROR);
308 qt->state = QtlsState::QTLS_DONE;
312bool process_message(QuicTls *qt,
int level,
const uint8_t *msg,
size_t msg_len)
314 if (level == QuicEnc::QUIC_ENC_INITIAL && qt->state == QtlsState::QTLS_START &&
315 msg[0] == TlsHs::TLS_HS_CLIENT_HELLO)
317 return process_client_hello(qt, msg, msg_len);
319 if (level == QuicEnc::QUIC_ENC_HANDSHAKE && qt->state == QtlsState::QTLS_WAIT_FINISHED &&
320 msg[0] == TlsHs::TLS_HS_FINISHED)
322 return process_client_finished(qt, msg, msg_len);
324 fail(qt, TlsAlert::TLS_ALERT_UNEXPECTED_MESSAGE);
329void pc_quic_tls_server_init(QuicTls *qt,
const QuicTlsConfig *cfg)
331 memset(qt, 0,
sizeof(*qt));
334 qt->state = QtlsState::QTLS_START;
337size_t pc_quic_tls_recv_crypto(QuicTls *qt,
int level,
const uint8_t *data,
size_t len)
339 if (qt->state == QtlsState::QTLS_FAILED)
344 while (off + 4 <= len)
346 uint32_t mlen = (uint32_t)((data[off + 1] << 16) | (data[off + 2] << 8) | data[off + 3]);
347 size_t total = 4 + mlen;
348 if (off + total > len)
352 if (!process_message(qt, level, data + off, total))
357 if (qt->state == QtlsState::QTLS_DONE)
365const uint8_t *pc_quic_tls_flight(
const QuicTls *qt,
int level,
size_t *len)
367 if (level == QuicEnc::QUIC_ENC_INITIAL)
369 *len = qt->flight_initial_len;
370 return qt->flight_initial;
372 if (level == QuicEnc::QUIC_ENC_HANDSHAKE)
374 *len = qt->flight_hs_len;
375 return qt->flight_hs;
381QuicPacketKeys *pc_quic_tls_keys(QuicTls *qt,
int level,
bool is_server)
383 if (level == QuicEnc::QUIC_ENC_HANDSHAKE && qt->hs_keys_ready)
385 return is_server ? &qt->hs_server : &qt->hs_client;
387 if (level == QuicEnc::QUIC_ENC_APP && qt->ap_keys_ready)
389 return is_server ? &qt->ap_server : &qt->ap_client;
394const QuicTransportParams *pc_quic_tls_peer_params(
const QuicTls *qt)
396 return qt->have_peer ? &qt->peer :
nullptr;
void pc_x25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32])
X25519 scalar multiplication: out = scalar * point (RFC 7748 §5).
void pc_x25519_base(uint8_t out[32], const uint8_t scalar[32])
X25519 with the standard base point u=9: out = scalar * G.
Curve25519 field arithmetic + X25519 (RFC 7748) for the curve25519-sha256 KEX.
ML-KEM-768 (FIPS 203): Encaps (responder) + KeyGen and Decaps (initiator).
#define PC_H3_CRYPTO_BUF
Maximum bytes of one QUIC/TLS handshake CRYPTO flight (RFC 9001).
PC_CRYPTO_HOT void pc_sha256_init(pc_sha256_ctx *ctx)
Initialize a streaming SHA-256 context (ctx must not be NULL).
void pc_sha256_final(pc_sha256_ctx *ctx, uint8_t digest[PC_SHA256_DIGEST_LEN])
Finalize the hash and write the 32-byte digest. The context is undefined afterwards; call init() agai...
void pc_sha256_update(pc_sha256_ctx *ctx, const uint8_t *data, size_t len)
Feed len bytes of data into the running hash.
Streaming SHA-256 context.