1 | use super::hmac; |
2 | use super::ActiveKeyExchange; |
3 | use crate::error::Error; |
4 | |
5 | use alloc::boxed::Box; |
6 | |
7 | /// Implements [`Prf`] using a [`hmac::Hmac`]. |
8 | pub struct PrfUsingHmac<'a>(pub &'a dyn hmac::Hmac); |
9 | |
10 | impl<'a> Prf for PrfUsingHmac<'a> { |
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(peer_pub_key)? |
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 | |
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 | |
68 | pub(crate) fn prf(out: &mut [u8], hmac_key: &dyn hmac::Key, label: &[u8], seed: &[u8]) { |
69 | // A(1) |
70 | let mut current_a: Tag = hmac_key.sign(&[label, seed]); |
71 | |
72 | let chunk_size: usize = hmac_key.tag_len(); |
73 | for chunk: &mut [u8] in out.chunks_mut(chunk_size) { |
74 | // P_hash[i] = HMAC_hash(secret, A(i) + seed) |
75 | let p_term: Tag = hmac_key.sign(&[current_a.as_ref(), label, seed]); |
76 | chunk.copy_from_slice(&p_term.as_ref()[..chunk.len()]); |
77 | |
78 | // A(i+1) = HMAC_hash(secret, A(i)) |
79 | current_a = hmac_key.sign(&[current_a.as_ref()]); |
80 | } |
81 | } |
82 | |
83 | #[cfg (all(test, feature = "ring" ))] |
84 | mod tests { |
85 | use crate::crypto::hmac::Hmac; |
86 | use crate::test_provider::hmac; |
87 | |
88 | // Below known answer tests come from https://mailarchive.ietf.org/arch/msg/tls/fzVCzk-z3FShgGJ6DOXqM1ydxms/ |
89 | |
90 | #[test ] |
91 | fn check_sha256() { |
92 | let secret = b" \x9b\xbe\x43\x6b\xa9\x40\xf0\x17\xb1\x76\x52\x84\x9a\x71\xdb\x35" ; |
93 | let seed = b" \xa0\xba\x9f\x93\x6c\xda\x31\x18\x27\xa6\xf7\x96\xff\xd5\x19\x8c" ; |
94 | let label = b"test label" ; |
95 | let expect = include_bytes!("../testdata/prf-result.1.bin" ); |
96 | let mut output = [0u8; 100]; |
97 | |
98 | super::prf( |
99 | &mut output, |
100 | &*hmac::HMAC_SHA256.with_key(secret), |
101 | label, |
102 | seed, |
103 | ); |
104 | assert_eq!(expect.len(), output.len()); |
105 | assert_eq!(expect.to_vec(), output.to_vec()); |
106 | } |
107 | |
108 | #[test ] |
109 | fn check_sha512() { |
110 | let secret = b" \xb0\x32\x35\x23\xc1\x85\x35\x99\x58\x4d\x88\x56\x8b\xbb\x05\xeb" ; |
111 | let seed = b" \xd4\x64\x0e\x12\xe4\xbc\xdb\xfb\x43\x7f\x03\xe6\xae\x41\x8e\xe5" ; |
112 | let label = b"test label" ; |
113 | let expect = include_bytes!("../testdata/prf-result.2.bin" ); |
114 | let mut output = [0u8; 196]; |
115 | |
116 | super::prf( |
117 | &mut output, |
118 | &*hmac::HMAC_SHA512.with_key(secret), |
119 | label, |
120 | seed, |
121 | ); |
122 | assert_eq!(expect.len(), output.len()); |
123 | assert_eq!(expect.to_vec(), output.to_vec()); |
124 | } |
125 | |
126 | #[test ] |
127 | fn check_sha384() { |
128 | let secret = b" \xb8\x0b\x73\x3d\x6c\xee\xfc\xdc\x71\x56\x6e\xa4\x8e\x55\x67\xdf" ; |
129 | let seed = b" \xcd\x66\x5c\xf6\xa8\x44\x7d\xd6\xff\x8b\x27\x55\x5e\xdb\x74\x65" ; |
130 | let label = b"test label" ; |
131 | let expect = include_bytes!("../testdata/prf-result.3.bin" ); |
132 | let mut output = [0u8; 148]; |
133 | |
134 | super::prf( |
135 | &mut output, |
136 | &*hmac::HMAC_SHA384.with_key(secret), |
137 | label, |
138 | seed, |
139 | ); |
140 | assert_eq!(expect.len(), output.len()); |
141 | assert_eq!(expect.to_vec(), output.to_vec()); |
142 | } |
143 | } |
144 | |
145 | #[cfg (all(bench, any(feature = "ring" , feature = "aws_lc_rs" )))] |
146 | mod benchmarks { |
147 | #[bench ] |
148 | fn bench_sha256(b: &mut test::Bencher) { |
149 | use crate::crypto::hmac::Hmac; |
150 | use crate::test_provider::hmac; |
151 | |
152 | let label = &b"extended master secret" [..]; |
153 | let seed = [0u8; 32]; |
154 | let key = &b"secret" [..]; |
155 | |
156 | b.iter(|| { |
157 | let mut out = [0u8; 48]; |
158 | super::prf(&mut out, &*hmac::HMAC_SHA256.with_key(key), &label, &seed); |
159 | test::black_box(out); |
160 | }); |
161 | } |
162 | } |
163 | |