DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
tls13_kdf.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file tls13_kdf.cpp
6 * @brief TLS 1.3 key schedule (see tls13_kdf.h).
7 */
8
10
11#if (DETWS_ENABLE_HTTP3 || DETWS_ENABLE_DTLS)
12
16#include <string.h>
17
18// RFC 8446 sec 7.1 ("tls13 ") and RFC 9147 sec 5.9 ("dtls13") HKDF-Expand-Label prefixes.
19const Tls13Kdf TLS13_KDF = {"tls13 "};
20const Tls13Kdf DTLS13_KDF = {"dtls13"};
21
22namespace
23{
24// Transcript-Hash of the empty string: SHA-256(""), the context for the two "derived" steps.
25void empty_hash(uint8_t out[TLS13_SECRET_LEN])
26{
27 ssh_sha256(nullptr, 0, out);
28}
29} // namespace
30
31void tls13_kdf_expand_label(const Tls13Kdf *kdf, const uint8_t secret[TLS13_SECRET_LEN], const char *label,
32 uint8_t *out, size_t out_len)
33{
34 quic_hkdf_expand_label(secret, label, out, out_len, kdf->label_prefix);
35}
36
37void tls13_derive_secret(const Tls13Kdf *kdf, const uint8_t secret[TLS13_SECRET_LEN], const char *label,
38 const uint8_t transcript_hash[TLS13_SECRET_LEN], uint8_t out[TLS13_SECRET_LEN])
39{
40 // Derive-Secret(Secret, Label, Messages) = HKDF-Expand-Label(Secret, Label, Hash(Messages), L).
41 quic_hkdf_expand_label_ctx(secret, label, transcript_hash, TLS13_SECRET_LEN, out, TLS13_SECRET_LEN,
42 kdf->label_prefix);
43}
44
45void tls13_ks_early(const Tls13Kdf *kdf, Tls13KeySchedule *ks)
46{
47 ks->kdf = kdf;
48 // No PSK: Early Secret = HKDF-Extract(salt=0, IKM=0^Hash.length). HMAC zero-pads a short/absent
49 // key, so an empty salt and a 32-zero-byte IKM reproduce the RFC 8448 early secret exactly.
50 uint8_t zeros[TLS13_SECRET_LEN];
51 memset(zeros, 0, sizeof(zeros));
52 quic_hkdf_extract(nullptr, 0, zeros, sizeof(zeros), ks->early_secret);
53}
54
55void tls13_ks_handshake(Tls13KeySchedule *ks, const uint8_t *ecdhe, const uint8_t ch_sh_hash[TLS13_SECRET_LEN],
56 size_t ecdhe_len)
57{
58 // Handshake Secret = HKDF-Extract(Derive-Secret(Early, "derived", ""), (EC)DHE).
59 uint8_t eh[TLS13_SECRET_LEN];
60 empty_hash(eh);
61 uint8_t derived[TLS13_SECRET_LEN];
62 tls13_derive_secret(ks->kdf, ks->early_secret, "derived", eh, derived);
63 quic_hkdf_extract(derived, sizeof(derived), ecdhe, ecdhe_len, ks->handshake_secret);
64
65 tls13_derive_secret(ks->kdf, ks->handshake_secret, "c hs traffic", ch_sh_hash, ks->client_hs_traffic);
66 tls13_derive_secret(ks->kdf, ks->handshake_secret, "s hs traffic", ch_sh_hash, ks->server_hs_traffic);
67}
68
69void tls13_ks_master(Tls13KeySchedule *ks, const uint8_t ch_sfin_hash[TLS13_SECRET_LEN])
70{
71 // Master Secret = HKDF-Extract(Derive-Secret(Handshake, "derived", ""), 0^Hash.length).
72 uint8_t eh[TLS13_SECRET_LEN];
73 empty_hash(eh);
74 uint8_t derived[TLS13_SECRET_LEN];
75 tls13_derive_secret(ks->kdf, ks->handshake_secret, "derived", eh, derived);
76 uint8_t zeros[TLS13_SECRET_LEN];
77 memset(zeros, 0, sizeof(zeros));
78 quic_hkdf_extract(derived, sizeof(derived), zeros, sizeof(zeros), ks->master_secret);
79
80 tls13_derive_secret(ks->kdf, ks->master_secret, "c ap traffic", ch_sfin_hash, ks->client_ap_traffic);
81 tls13_derive_secret(ks->kdf, ks->master_secret, "s ap traffic", ch_sfin_hash, ks->server_ap_traffic);
82}
83
84void tls13_finished_mac(const Tls13Kdf *kdf, const uint8_t base_secret[TLS13_SECRET_LEN],
85 const uint8_t transcript_hash[TLS13_SECRET_LEN], uint8_t out[TLS13_SECRET_LEN])
86{
87 // finished_key = HKDF-Expand-Label(base_secret, "finished", "", L); verify_data = HMAC(fk, Hash).
88 uint8_t finished_key[TLS13_SECRET_LEN];
89 quic_hkdf_expand_label(base_secret, "finished", finished_key, sizeof(finished_key), kdf->label_prefix);
90 ssh_hmac_sha256(finished_key, sizeof(finished_key), transcript_hash, TLS13_SECRET_LEN, out);
91}
92
93#endif // DETWS_ENABLE_HTTP3 || DETWS_ENABLE_DTLS
HKDF-SHA256 (RFC 5869) and TLS 1.3 HKDF-Expand-Label (RFC 8446 sec 7.1).
void ssh_hmac_sha256(const uint8_t *key, size_t key_len, const uint8_t *data, size_t len, uint8_t mac[SSH_HMAC_SHA256_LEN])
Compute HMAC-SHA2-256 over a single contiguous buffer.
HMAC-SHA2-256 (RFC 2104 + FIPS 198-1).
void ssh_sha256(const uint8_t *data, size_t len, uint8_t digest[SSH_SHA256_DIGEST_LEN])
One-shot SHA-256: hash len bytes and write the digest.
SHA-256 (FIPS 180-4) - streaming context and one-shot API.
TLS 1.3 key schedule (RFC 8446 sec 7.1) for the QUIC handshake.