Coverage Report

Created: 2026-04-29 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-0.23.40/src/crypto/tls12.rs
Line
Count
Source
1
use alloc::boxed::Box;
2
3
use super::{ActiveKeyExchange, hmac};
4
use crate::error::Error;
5
use crate::version::TLS12;
6
7
/// Implements [`Prf`] using a [`hmac::Hmac`].
8
pub struct PrfUsingHmac<'a>(pub &'a dyn hmac::Hmac);
9
10
impl Prf for PrfUsingHmac<'_> {
11
0
    fn for_key_exchange(
12
0
        &self,
13
0
        output: &mut [u8; 48],
14
0
        kx: Box<dyn ActiveKeyExchange>,
15
0
        peer_pub_key: &[u8],
16
0
        label: &[u8],
17
0
        seed: &[u8],
18
0
    ) -> Result<(), Error> {
19
0
        prf(
20
0
            output,
21
0
            self.0
22
0
                .with_key(
23
0
                    kx.complete_for_tls_version(peer_pub_key, &TLS12)?
24
0
                        .secret_bytes(),
25
                )
26
0
                .as_ref(),
27
0
            label,
28
0
            seed,
29
        );
30
0
        Ok(())
31
0
    }
32
33
0
    fn for_secret(&self, output: &mut [u8], secret: &[u8], label: &[u8], seed: &[u8]) {
34
0
        prf(output, self.0.with_key(secret).as_ref(), label, seed);
35
0
    }
36
}
37
38
/// An instantiation of the TLS1.2 PRF with a specific, implicit hash function.
39
///
40
/// See the definition in [RFC5246 section 5](https://www.rfc-editor.org/rfc/rfc5246#section-5).
41
///
42
/// See [`PrfUsingHmac`] as a route to implementing this trait with just
43
/// an implementation of [`hmac::Hmac`].
44
pub trait Prf: Send + Sync {
45
    /// Computes `PRF(secret, label, seed)` using the secret from a completed key exchange.
46
    ///
47
    /// Completes the given key exchange, and then uses the resulting shared secret
48
    /// to compute the PRF, writing the result into `output`.
49
    ///
50
    /// The caller guarantees that `label`, `seed` are non-empty. The caller makes no
51
    /// guarantees about the contents of `peer_pub_key`. It must be validated by
52
    /// [`ActiveKeyExchange::complete`].
53
    fn for_key_exchange(
54
        &self,
55
        output: &mut [u8; 48],
56
        kx: Box<dyn ActiveKeyExchange>,
57
        peer_pub_key: &[u8],
58
        label: &[u8],
59
        seed: &[u8],
60
    ) -> Result<(), Error>;
61
62
    /// Computes `PRF(secret, label, seed)`, writing the result into `output`.
63
    ///
64
    /// The caller guarantees that `secret`, `label`, and `seed` are non-empty.
65
    fn for_secret(&self, output: &mut [u8], secret: &[u8], label: &[u8], seed: &[u8]);
66
67
    /// Return `true` if this is backed by a FIPS-approved implementation.
68
0
    fn fips(&self) -> bool {
69
0
        false
70
0
    }
71
}
72
73
0
pub(crate) fn prf(out: &mut [u8], hmac_key: &dyn hmac::Key, label: &[u8], seed: &[u8]) {
74
    // A(1)
75
0
    let mut current_a = hmac_key.sign(&[label, seed]);
76
77
0
    let chunk_size = hmac_key.tag_len();
78
0
    for chunk in out.chunks_mut(chunk_size) {
79
0
        // P_hash[i] = HMAC_hash(secret, A(i) + seed)
80
0
        let p_term = hmac_key.sign(&[current_a.as_ref(), label, seed]);
81
0
        chunk.copy_from_slice(&p_term.as_ref()[..chunk.len()]);
82
0
83
0
        // A(i+1) = HMAC_hash(secret, A(i))
84
0
        current_a = hmac_key.sign(&[current_a.as_ref()]);
85
0
    }
86
0
}
87
88
#[cfg(all(test, feature = "ring"))]
89
mod tests {
90
    use crate::crypto::hmac::Hmac;
91
    // nb: crypto::aws_lc_rs provider doesn't provide (or need) hmac,
92
    // so cannot be used for this test.
93
    use crate::crypto::ring::hmac;
94
95
    // Below known answer tests come from https://mailarchive.ietf.org/arch/msg/tls/fzVCzk-z3FShgGJ6DOXqM1ydxms/
96
97
    #[test]
98
    fn check_sha256() {
99
        let secret = b"\x9b\xbe\x43\x6b\xa9\x40\xf0\x17\xb1\x76\x52\x84\x9a\x71\xdb\x35";
100
        let seed = b"\xa0\xba\x9f\x93\x6c\xda\x31\x18\x27\xa6\xf7\x96\xff\xd5\x19\x8c";
101
        let label = b"test label";
102
        let expect = include_bytes!("../testdata/prf-result.1.bin");
103
        let mut output = [0u8; 100];
104
105
        super::prf(
106
            &mut output,
107
            &*hmac::HMAC_SHA256.with_key(secret),
108
            label,
109
            seed,
110
        );
111
        assert_eq!(expect.len(), output.len());
112
        assert_eq!(expect.to_vec(), output.to_vec());
113
    }
114
115
    #[test]
116
    fn check_sha512() {
117
        let secret = b"\xb0\x32\x35\x23\xc1\x85\x35\x99\x58\x4d\x88\x56\x8b\xbb\x05\xeb";
118
        let seed = b"\xd4\x64\x0e\x12\xe4\xbc\xdb\xfb\x43\x7f\x03\xe6\xae\x41\x8e\xe5";
119
        let label = b"test label";
120
        let expect = include_bytes!("../testdata/prf-result.2.bin");
121
        let mut output = [0u8; 196];
122
123
        super::prf(
124
            &mut output,
125
            &*hmac::HMAC_SHA512.with_key(secret),
126
            label,
127
            seed,
128
        );
129
        assert_eq!(expect.len(), output.len());
130
        assert_eq!(expect.to_vec(), output.to_vec());
131
    }
132
133
    #[test]
134
    fn check_sha384() {
135
        let secret = b"\xb8\x0b\x73\x3d\x6c\xee\xfc\xdc\x71\x56\x6e\xa4\x8e\x55\x67\xdf";
136
        let seed = b"\xcd\x66\x5c\xf6\xa8\x44\x7d\xd6\xff\x8b\x27\x55\x5e\xdb\x74\x65";
137
        let label = b"test label";
138
        let expect = include_bytes!("../testdata/prf-result.3.bin");
139
        let mut output = [0u8; 148];
140
141
        super::prf(
142
            &mut output,
143
            &*hmac::HMAC_SHA384.with_key(secret),
144
            label,
145
            seed,
146
        );
147
        assert_eq!(expect.len(), output.len());
148
        assert_eq!(expect.to_vec(), output.to_vec());
149
    }
150
}
151
152
#[cfg(all(bench, feature = "ring"))]
153
mod benchmarks {
154
    #[bench]
155
    fn bench_sha256(b: &mut test::Bencher) {
156
        use crate::crypto::hmac::Hmac;
157
        use crate::crypto::ring::hmac;
158
159
        let label = &b"extended master secret"[..];
160
        let seed = [0u8; 32];
161
        let key = &b"secret"[..];
162
163
        b.iter(|| {
164
            let mut out = [0u8; 48];
165
            super::prf(&mut out, &*hmac::HMAC_SHA256.with_key(key), &label, &seed);
166
            test::black_box(out);
167
        });
168
    }
169
}