1use alloc::boxed::Box;
2
3use super::{ActiveKeyExchange, hmac};
4use crate::error::Error;
5use crate::version::TLS12;
6
7pub struct PrfUsingHmac<'a>(pub &'a dyn hmac::Hmac);
9
10impl Prf for PrfUsingHmac<'_> {
11 fn for_key_exchange(
12 &self,
13 output: &mut [u8; 48],
14 kx: Box<dyn ActiveKeyExchange>,
15 peer_pub_key: &[u8],
16 label: &[u8],
17 seed: &[u8],
18 ) -> Result<(), Error> {
19 prf(
20 output,
21 self.0
22 .with_key(
23 kx.complete_for_tls_version(peer_pub_key, &TLS12)?
24 .secret_bytes(),
25 )
26 .as_ref(),
27 label,
28 seed,
29 );
30 Ok(())
31 }
32
33 fn for_secret(&self, output: &mut [u8], secret: &[u8], label: &[u8], seed: &[u8]) {
34 prf(output, self.0.with_key(secret).as_ref(), label, seed);
35 }
36}
37
38pub trait Prf: Send + Sync {
45 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 fn for_secret(&self, output: &mut [u8], secret: &[u8], label: &[u8], seed: &[u8]);
66
67 fn fips(&self) -> bool {
69 false
70 }
71}
72
73pub(crate) fn prf(out: &mut [u8], hmac_key: &dyn hmac::Key, label: &[u8], seed: &[u8]) {
74 let mut current_a = hmac_key.sign(&[label, seed]);
76
77 let chunk_size = hmac_key.tag_len();
78 for chunk in out.chunks_mut(chunk_size) {
79 let p_term = hmac_key.sign(&[current_a.as_ref(), label, seed]);
81 chunk.copy_from_slice(&p_term.as_ref()[..chunk.len()]);
82
83 current_a = hmac_key.sign(&[current_a.as_ref()]);
85 }
86}
87
88#[cfg(all(test, feature = "ring"))]
89mod tests {
90 use crate::crypto::hmac::Hmac;
91 use crate::crypto::ring::hmac;
94
95 #[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"))]
153mod 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}