1use core::fmt::Debug;
29
30use crate::digest::{match_digest_type, AlgorithmID};
31use crate::error::Unspecified;
32use crate::fips::indicator_check;
33use core::ptr::null;
34
35use crate::aws_lc::CRYPTO_tls1_prf;
36
37pub struct Algorithm(AlgorithmID);
39
40impl Debug for Algorithm {
41 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42 Debug::fmt(&self.0, f)
43 }
44}
45
46pub const P_SHA256: Algorithm = Algorithm(AlgorithmID::SHA256);
48
49pub const P_SHA384: Algorithm = Algorithm(AlgorithmID::SHA384);
51
52pub const P_SHA512: Algorithm = Algorithm(AlgorithmID::SHA512);
54
55pub struct Secret {
57 algorithm: &'static Algorithm,
58 secret: Box<[u8]>,
59}
60
61impl Secret {
62 pub fn new(algorithm: &'static Algorithm, secret: &[u8]) -> Result<Self, Unspecified> {
67 if secret.is_empty() {
68 return Err(Unspecified);
69 }
70
71 let secret = Vec::from(secret).into_boxed_slice();
72
73 Ok(Self { algorithm, secret })
74 }
75
76 pub fn derive(self, label: &[u8], seed: &[u8], output: usize) -> Result<Secret, Unspecified> {
82 prf(self.algorithm, &self.secret, label, seed, None, output)
83 }
84
85 pub fn derive_with_seed_concatination(
94 self,
95 label: &[u8],
96 seed1: &[u8],
97 seed2: &[u8],
98 len: usize,
99 ) -> Result<Secret, Unspecified> {
100 prf(self.algorithm, &self.secret, label, seed1, Some(seed2), len)
101 }
102}
103
104impl Drop for Secret {
105 fn drop(&mut self) {
106 use zeroize::Zeroize;
107 self.secret.zeroize();
108 }
109}
110
111impl AsRef<[u8]> for Secret {
112 fn as_ref(&self) -> &[u8] {
113 &self.secret
114 }
115}
116
117impl<const L: usize> TryFrom<Secret> for [u8; L] {
118 type Error = Unspecified;
119
120 fn try_from(value: Secret) -> Result<Self, Self::Error> {
121 if value.secret.len() != L {
122 return Err(Unspecified);
123 }
124
125 let mut ret = [0u8; L];
126 ret.copy_from_slice(&value.secret);
127
128 Ok(ret)
129 }
130}
131
132#[allow(clippy::missing_fields_in_debug)]
133impl Debug for Secret {
134 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
135 f.debug_struct("Secret")
136 .field("algorithm", &self.algorithm)
137 .finish()
138 }
139}
140
141fn prf(
142 algorithm: &'static Algorithm,
143 secret: &[u8],
144 label: &[u8],
145 seed1: &[u8],
146 seed2: Option<&[u8]>,
147 output: usize,
148) -> Result<Secret, Unspecified> {
149 if output == 0 {
150 return Err(Unspecified);
151 }
152
153 let mut output = vec![0u8; output];
154
155 let digest = match_digest_type(&algorithm.0);
156
157 let (seed2, seed2_len) = if let Some(seed2) = seed2 {
158 (seed2.as_ptr(), seed2.len())
159 } else {
160 (null(), 0usize)
161 };
162
163 if 1 != indicator_check!(unsafe {
164 CRYPTO_tls1_prf(
165 *digest,
166 output.as_mut_ptr(),
167 output.len(),
168 secret.as_ptr(),
169 secret.len(),
170 label.as_ptr().cast(),
171 label.len(),
172 seed1.as_ptr(),
173 seed1.len(),
174 seed2,
175 seed2_len,
176 )
177 }) {
178 return Err(Unspecified);
179 }
180
181 Ok(Secret {
182 algorithm,
183 secret: output.into_boxed_slice(),
184 })
185}
186
187#[cfg(test)]
188mod tests {
189 use alloc::ffi::CString;
190
191 use super::{Secret, P_SHA256, P_SHA384, P_SHA512};
192
193 #[cfg(feature = "fips")]
194 mod fips;
195
196 #[test]
197 fn aws_lc_kat() {
198 const TLS_SECRET: &[u8; 32] = &[
200 0xab, 0xc3, 0x65, 0x7b, 0x09, 0x4c, 0x76, 0x28, 0xa0, 0xb2, 0x82, 0x99, 0x6f, 0xe7,
201 0x5a, 0x75, 0xf4, 0x98, 0x4f, 0xd9, 0x4d, 0x4e, 0xcc, 0x2f, 0xcf, 0x53, 0xa2, 0xc4,
202 0x69, 0xa3, 0xf7, 0x31,
203 ];
204
205 const TLS_LABEL: &str = "FIPS self test";
206
207 const TLS_SEED1: &[u8; 16] = &[
208 0x8f, 0x0d, 0xe8, 0xb6, 0x90, 0x8f, 0xb1, 0xd2, 0x6d, 0x51, 0xf4, 0x79, 0x18, 0x63,
209 0x51, 0x65,
210 ];
211
212 const TLS_SEED2: &[u8; 16] = &[
213 0x7d, 0x24, 0x1a, 0x9d, 0x3c, 0x59, 0xbf, 0x3c, 0x31, 0x1e, 0x2b, 0x21, 0x41, 0x8d,
214 0x32, 0x81,
215 ];
216
217 const TLS_OUTPUT_P_SHA256: &[u8; 32] = &[
218 0xe2, 0x1d, 0xd6, 0xc2, 0x68, 0xc7, 0x57, 0x03, 0x2c, 0x2c, 0xeb, 0xbb, 0xb8, 0xa9,
219 0x7d, 0xe9, 0xee, 0xe6, 0xc9, 0x47, 0x83, 0x0a, 0xbd, 0x11, 0x60, 0x5d, 0xd5, 0x2c,
220 0x47, 0xb6, 0x05, 0x88,
221 ];
222
223 let secret = Secret::new(&P_SHA256, TLS_SECRET).expect("secret created");
224
225 let label = CString::new(TLS_LABEL).expect("failed to create CString");
227
228 let output = secret
229 .derive_with_seed_concatination(
230 label.as_bytes_with_nul(),
231 TLS_SEED1,
232 TLS_SEED2,
233 TLS_OUTPUT_P_SHA256.len(),
234 )
235 .unwrap();
236
237 assert_eq!(TLS_OUTPUT_P_SHA256, output.as_ref());
238
239 let mut seed = Vec::<u8>::with_capacity(TLS_SEED1.len() + TLS_SEED2.len());
240 seed.extend(TLS_SEED1);
241 seed.extend(TLS_SEED2);
242
243 let secret = Secret::new(&P_SHA256, TLS_SECRET).expect("secret created");
244 let output = secret
245 .derive(label.as_bytes_with_nul(), &seed, TLS_OUTPUT_P_SHA256.len())
246 .unwrap();
247
248 assert_eq!(TLS_OUTPUT_P_SHA256, output.as_ref());
249 }
250
251 #[test]
252 fn sha256() {
253 const SECRET: &[u8] = &[
256 0xf8, 0x93, 0x8e, 0xcc, 0x9e, 0xde, 0xbc, 0x50, 0x30, 0xc0, 0xc6, 0xa4, 0x41, 0xe2,
257 0x13, 0xcd, 0x24, 0xe6, 0xf7, 0x70, 0xa5, 0x0d, 0xda, 0x07, 0x87, 0x6f, 0x8d, 0x55,
258 0xda, 0x06, 0x2b, 0xca, 0xdb, 0x38, 0x6b, 0x41, 0x1f, 0xd4, 0xfe, 0x43, 0x13, 0xa6,
259 0x04, 0xfc, 0xe6, 0xc1, 0x7f, 0xbc,
260 ];
261 const LABEL: &[u8] = b"master secret";
262 const SEED1: &[u8] = &[
263 0x36, 0xc1, 0x29, 0xd0, 0x1a, 0x32, 0x00, 0x89, 0x4b, 0x91, 0x79, 0xfa, 0xac, 0x58,
264 0x9d, 0x98, 0x35, 0xd5, 0x87, 0x75, 0xf9, 0xb5, 0xea, 0x35, 0x87, 0xcb, 0x8f, 0xd0,
265 0x36, 0x4c, 0xae, 0x8c,
266 ];
267 const SEED2: &[u8] = &[
268 0xf6, 0xc9, 0x57, 0x5e, 0xd7, 0xdd, 0xd7, 0x3e, 0x1f, 0x7d, 0x16, 0xec, 0xa1, 0x15,
269 0x41, 0x58, 0x12, 0xa4, 0x3c, 0x2b, 0x74, 0x7d, 0xaa, 0xaa, 0xe0, 0x43, 0xab, 0xfb,
270 0x50, 0x05, 0x3f, 0xce,
271 ];
272 const EXPECT: &[u8] = &[
273 0x20, 0x2c, 0x88, 0xc0, 0x0f, 0x84, 0xa1, 0x7a, 0x20, 0x02, 0x70, 0x79, 0x60, 0x47,
274 0x87, 0x46, 0x11, 0x76, 0x45, 0x55, 0x39, 0xe7, 0x05, 0xbe, 0x73, 0x08, 0x90, 0x60,
275 0x2c, 0x28, 0x9a, 0x50, 0x01, 0xe3, 0x4e, 0xeb, 0x3a, 0x04, 0x3e, 0x5d, 0x52, 0xa6,
276 0x5e, 0x66, 0x12, 0x51, 0x88, 0xbf,
277 ];
278
279 let secret = Secret::new(&P_SHA256, SECRET).expect("secret created");
280
281 let output = secret
282 .derive_with_seed_concatination(LABEL, SEED1, SEED2, EXPECT.len())
283 .expect("derive successful");
284
285 assert_eq!(EXPECT, output.as_ref());
286 }
287
288 #[test]
289 fn sha384() {
290 const SECRET: &[u8] = &[
293 0xa5, 0xe2, 0x64, 0x26, 0x33, 0xf5, 0xb8, 0xc8, 0x1a, 0xd3, 0xfe, 0x0c, 0x2f, 0xe3,
294 0xa8, 0xe5, 0xef, 0x80, 0x6b, 0x06, 0x12, 0x1d, 0xd1, 0x0d, 0xf4, 0xbb, 0x0f, 0xe8,
295 0x57, 0xbf, 0xdc, 0xf5, 0x22, 0x55, 0x8e, 0x05, 0xd2, 0x68, 0x2c, 0x9a, 0x80, 0xc7,
296 0x41, 0xa3, 0xaa, 0xb1, 0x71, 0x6f,
297 ];
298 const LABEL: &[u8] = b"master secret";
299 const SEED1: &[u8] = &[
300 0xab, 0xe4, 0xbf, 0x55, 0x27, 0x42, 0x9a, 0xc8, 0xeb, 0x13, 0x57, 0x4d, 0x27, 0x09,
301 0xe8, 0x01, 0x2b, 0xd1, 0xa1, 0x13, 0xc6, 0xd3, 0xb1, 0xd3, 0xaa, 0x2c, 0x38, 0x40,
302 0x51, 0x87, 0x78, 0xac,
303 ];
304 const SEED2: &[u8] = &[
305 0xcb, 0x6e, 0x0b, 0x3e, 0xb0, 0x29, 0x76, 0xb6, 0x46, 0x6d, 0xfa, 0x96, 0x51, 0xc2,
306 0x91, 0x94, 0x14, 0xf1, 0x64, 0x8f, 0xd3, 0xa7, 0x83, 0x8d, 0x02, 0x15, 0x3e, 0x5b,
307 0xd3, 0x95, 0x35, 0xb6,
308 ];
309 const EXPECT: &[u8] = &[
310 0xb4, 0xd4, 0x9b, 0xfa, 0x87, 0x74, 0x7f, 0xe8, 0x15, 0x45, 0x7b, 0xc3, 0xda, 0x15,
311 0x07, 0x3d, 0x6a, 0xc7, 0x33, 0x89, 0xe7, 0x03, 0x07, 0x9a, 0x35, 0x03, 0xc0, 0x9e,
312 0x14, 0xbd, 0x55, 0x9a, 0x5b, 0x3c, 0x7c, 0x60, 0x1c, 0x73, 0x65, 0xf6, 0xea, 0x8c,
313 0x68, 0xd3, 0xd9, 0x59, 0x68, 0x27,
314 ];
315
316 let secret = Secret::new(&P_SHA384, SECRET).expect("secret created");
317
318 let output = secret
319 .derive_with_seed_concatination(LABEL, SEED1, SEED2, EXPECT.len())
320 .expect("derive successful");
321
322 assert_eq!(EXPECT, output.as_ref());
323 }
324
325 #[test]
326 fn sha512() {
327 const SECRET: &[u8] = &[
330 0xdf, 0xef, 0x39, 0xaf, 0x25, 0xc1, 0x26, 0x63, 0xa9, 0x1e, 0xe5, 0xd2, 0x70, 0x42,
331 0xb9, 0x64, 0x4a, 0x16, 0xef, 0x55, 0xb8, 0x10, 0x55, 0xd1, 0xbd, 0x7d, 0xcb, 0x0b,
332 0x8f, 0x06, 0xeb, 0x00, 0x17, 0x08, 0xcd, 0xef, 0xcf, 0x82, 0x59, 0x1d, 0xef, 0xca,
333 0x1a, 0x6f, 0x1a, 0xc6, 0x93, 0xab,
334 ];
335 const LABEL: &[u8] = b"master secret";
336 const SEED1: &[u8] = &[
337 0x78, 0xbc, 0x52, 0x98, 0xdf, 0xe9, 0xcf, 0x8e, 0xd3, 0x36, 0xc2, 0xe2, 0xf0, 0xf6,
338 0xb4, 0x6e, 0x24, 0x56, 0xf3, 0x9f, 0x35, 0xf1, 0x14, 0x3c, 0xd2, 0x1e, 0xaa, 0x16,
339 0x27, 0x70, 0x25, 0xb2,
340 ];
341 const SEED2: &[u8] = &[
342 0xe2, 0x33, 0x9a, 0x6c, 0x68, 0x1e, 0xb3, 0x08, 0x08, 0x88, 0x39, 0x71, 0xb1, 0xce,
343 0x5b, 0x9b, 0x1e, 0xce, 0x0f, 0x3d, 0x01, 0x1a, 0x96, 0xa7, 0xff, 0xf1, 0xf5, 0xf9,
344 0xd8, 0x0f, 0xfd, 0x4b,
345 ];
346 const EXPECT: &[u8] = &[
347 0xa7, 0x0c, 0x5f, 0xe8, 0xd3, 0x4b, 0x64, 0x5a, 0x20, 0xce, 0x98, 0x96, 0x9b, 0xd3,
348 0x08, 0x58, 0xe7, 0x29, 0xc7, 0x7c, 0x8a, 0x5f, 0x05, 0xd3, 0xe2, 0x89, 0x21, 0x9d,
349 0x6b, 0x57, 0x52, 0xb7, 0x5b, 0x75, 0xe1, 0xca, 0x00, 0xd3, 0x32, 0x96, 0x58, 0xd7,
350 0xf1, 0x88, 0xed, 0x1a, 0xb7, 0xe0,
351 ];
352
353 let secret = Secret::new(&P_SHA512, SECRET).expect("secret created");
354
355 let output = secret
356 .derive_with_seed_concatination(LABEL, SEED1, SEED2, EXPECT.len())
357 .expect("derive successful");
358
359 assert_eq!(EXPECT, output.as_ref());
360 }
361
362 #[test]
363 fn try_into_array() {
364 let secret = Secret::new(&P_SHA256, &[42u8; 32]).expect("secret creation to succeed");
365
366 let secret = secret
367 .derive("master secret".as_bytes(), &[7u8; 3], 7)
368 .expect("derive to succeed");
369
370 let _secret: [u8; 7] = secret.try_into().expect("try_into to succeed");
371 }
372}