Skip to main content

tls2/
key_schedule.rs

1use crate::{CipherSuite, CryptoProvider, Hash, errors::Error};
2
3/// HKDF-Expand-Label as defined in RFC 8446 §7.1.
4///
5/// Derives keying material from a secret using a labeled context.
6/// `out` must be sized to the desired output length.
7pub fn hkdf_expand_label(
8    provider: &impl CryptoProvider,
9    suite: CipherSuite,
10    secret: &Hash,
11    label: &[u8],
12    context: &[u8],
13    out: &mut [u8],
14) -> Result<(), Error> {
15    provider.hkdf_expand_label(out, suite, secret, label, context)
16}
17
18/// Derive-Secret as defined in RFC 8446 §7.1.
19///
20/// Derive-Secret(Secret, Label, Messages) =
21///     HKDF-Expand-Label(Secret, Label, Transcript-Hash(Messages), Hash.length)
22pub fn derive_secret(
23    provider: &impl CryptoProvider,
24    suite: CipherSuite,
25    secret: &Hash,
26    label: &[u8],
27    transcript_hash: &Hash,
28) -> Result<Hash, Error> {
29    let hash_size = suite.hash_size();
30    let mut out = Hash::new_zeroed(hash_size as u8);
31    hkdf_expand_label(provider, suite, secret, label, transcript_hash, &mut *out)?;
32    Ok(out)
33}
34
35/// Derive handshake traffic keys from a traffic secret.
36///
37/// Derives key = HKDF-Expand-Label(secret, "key", "", Nkey)
38/// Derives iv  = HKDF-Expand-Label(secret, "iv", "", 12)
39/// Returns the AEAD key and IV directly.
40pub fn derive_traffic_keys<C: CryptoProvider + ?Sized>(
41    provider: &C,
42    suite: CipherSuite,
43    traffic_secret: &Hash,
44) -> Result<(C::AeadKey, [u8; 12]), Error> {
45    let key_size = suite.key_size();
46    let mut key_out = [0u8; 32];
47    let mut iv_out = [0u8; 12];
48    hkdf_expand_label(provider, suite, traffic_secret, b"key", b"", &mut key_out[..key_size])?;
49    hkdf_expand_label(provider, suite, traffic_secret, b"iv", b"", &mut iv_out)?;
50    let key = provider.new_aead_key(suite, &key_out[..key_size]);
51    Ok((key, iv_out))
52}
53
54/// Derive the Finished key from a traffic secret.
55///
56/// finished_key = HKDF-Expand-Label(traffic_secret, "finished", "", Hash.length)
57pub fn derive_finished_key(
58    provider: &impl CryptoProvider,
59    suite: CipherSuite,
60    traffic_secret: &Hash,
61) -> Result<Hash, Error> {
62    let hash_size = suite.hash_size();
63    let mut out = Hash::new_zeroed(hash_size as u8);
64    hkdf_expand_label(provider, suite, traffic_secret, b"finished", b"", &mut *out)?;
65    Ok(out)
66}
67
68/// Compute the TLS 1.3 Finished verify_data.
69///
70/// verify_data = HMAC(finished_key, transcript_hash)
71pub fn compute_finished(
72    provider: &impl CryptoProvider,
73    suite: CipherSuite,
74    finished_key: &Hash,
75    transcript_hash: &Hash,
76) -> Result<Hash, Error> {
77    provider.hmac(suite, finished_key, transcript_hash)
78}
79
80/// Derive the PSK for a NewSessionTicket.
81///
82/// PSK = HKDF-Expand-Label(resumption_secret, "resumption", ticket_nonce, Hash.length)
83pub fn derive_ticket_psk(
84    provider: &impl CryptoProvider,
85    suite: CipherSuite,
86    resumption_secret: &Hash,
87    ticket_nonce: &[u8],
88) -> Result<Hash, Error> {
89    let hash_size = suite.hash_size();
90    let mut out = Hash::new_zeroed(hash_size as u8);
91    hkdf_expand_label(provider, suite, resumption_secret, b"resumption", ticket_nonce, &mut *out)?;
92    Ok(out)
93}
94
95/// KeyUpdate: new_secret = HKDF-Expand-Label(old_traffic_secret, "traffic upd", "", Hash.length)
96pub fn key_update_secret(provider: &impl CryptoProvider, suite: CipherSuite, old_secret: &Hash) -> Result<Hash, Error> {
97    let hash_size = suite.hash_size();
98    let mut out = Hash::new_zeroed(hash_size as u8);
99    hkdf_expand_label(provider, suite, old_secret, b"traffic upd", b"", &mut *out)?;
100    Ok(out)
101}
102
103/// Compute the transcript hash of an empty string: Hash("").
104pub fn compute_empty_hash(provider: &impl CryptoProvider, suite: CipherSuite) -> Result<Hash, Error> {
105    provider.hash(suite, &[])
106}