1use alloc::boxed::Box;
2
3use aws_lc_rs::{aead, tls_prf};
4use zeroize::Zeroizing;
5
6use crate::crypto::cipher::{
7 AeadKey, InboundOpaqueMessage, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter,
8 NONCE_LEN, Nonce, Tls12AeadAlgorithm, UnsupportedOperationError, make_tls12_aad,
9};
10use crate::crypto::tls12::{Prf, PrfSecret};
11use crate::crypto::{ActiveKeyExchange, KeyExchangeAlgorithm, SharedSecret};
12use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme};
13use crate::error::Error;
14use crate::msgs::fragmenter::MAX_FRAGMENT_LEN;
15use crate::msgs::message::{
16 InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload,
17};
18use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets};
19use crate::tls12::Tls12CipherSuite;
20use crate::version::TLS12_VERSION;
21
22pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: &Tls12CipherSuite = &Tls12CipherSuite {
24 common: CipherSuiteCommon {
25 suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
26 hash_provider: &super::hash::SHA256,
27 confidentiality_limit: u64::MAX,
28 },
29 protocol_version: TLS12_VERSION,
30 kx: KeyExchangeAlgorithm::ECDHE,
31 sign: TLS12_ECDSA_SCHEMES,
32 aead_alg: &ChaCha20Poly1305,
33 prf_provider: &Tls12Prf(&tls_prf::P_SHA256),
34};
35
36pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: &Tls12CipherSuite = &Tls12CipherSuite {
38 common: CipherSuiteCommon {
39 suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
40 hash_provider: &super::hash::SHA256,
41 confidentiality_limit: u64::MAX,
42 },
43 protocol_version: TLS12_VERSION,
44 kx: KeyExchangeAlgorithm::ECDHE,
45 sign: TLS12_RSA_SCHEMES,
46 aead_alg: &ChaCha20Poly1305,
47 prf_provider: &Tls12Prf(&tls_prf::P_SHA256),
48};
49
50pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: &Tls12CipherSuite = &Tls12CipherSuite {
52 common: CipherSuiteCommon {
53 suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
54 hash_provider: &super::hash::SHA256,
55 confidentiality_limit: 1 << 24,
56 },
57 protocol_version: TLS12_VERSION,
58 kx: KeyExchangeAlgorithm::ECDHE,
59 sign: TLS12_RSA_SCHEMES,
60 aead_alg: &AES128_GCM,
61 prf_provider: &Tls12Prf(&tls_prf::P_SHA256),
62};
63
64pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: &Tls12CipherSuite = &Tls12CipherSuite {
66 common: CipherSuiteCommon {
67 suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
68 hash_provider: &super::hash::SHA384,
69 confidentiality_limit: 1 << 24,
70 },
71 protocol_version: TLS12_VERSION,
72 kx: KeyExchangeAlgorithm::ECDHE,
73 sign: TLS12_RSA_SCHEMES,
74 aead_alg: &AES256_GCM,
75 prf_provider: &Tls12Prf(&tls_prf::P_SHA384),
76};
77
78pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: &Tls12CipherSuite = &Tls12CipherSuite {
80 common: CipherSuiteCommon {
81 suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
82 hash_provider: &super::hash::SHA256,
83 confidentiality_limit: 1 << 24,
84 },
85 protocol_version: TLS12_VERSION,
86 kx: KeyExchangeAlgorithm::ECDHE,
87 sign: TLS12_ECDSA_SCHEMES,
88 aead_alg: &AES128_GCM,
89 prf_provider: &Tls12Prf(&tls_prf::P_SHA256),
90};
91
92pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: &Tls12CipherSuite = &Tls12CipherSuite {
94 common: CipherSuiteCommon {
95 suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
96 hash_provider: &super::hash::SHA384,
97 confidentiality_limit: 1 << 24,
98 },
99 protocol_version: TLS12_VERSION,
100 kx: KeyExchangeAlgorithm::ECDHE,
101 sign: TLS12_ECDSA_SCHEMES,
102 aead_alg: &AES256_GCM,
103 prf_provider: &Tls12Prf(&tls_prf::P_SHA384),
104};
105
106static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[
107 SignatureScheme::ED25519,
108 SignatureScheme::ECDSA_NISTP521_SHA512,
109 SignatureScheme::ECDSA_NISTP384_SHA384,
110 SignatureScheme::ECDSA_NISTP256_SHA256,
111];
112
113static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[
114 SignatureScheme::RSA_PSS_SHA512,
115 SignatureScheme::RSA_PSS_SHA384,
116 SignatureScheme::RSA_PSS_SHA256,
117 SignatureScheme::RSA_PKCS1_SHA512,
118 SignatureScheme::RSA_PKCS1_SHA384,
119 SignatureScheme::RSA_PKCS1_SHA256,
120];
121
122pub(crate) static AES128_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_128_GCM);
123pub(crate) static AES256_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_256_GCM);
124
125pub(crate) struct GcmAlgorithm(&'static aead::Algorithm);
126
127impl Tls12AeadAlgorithm for GcmAlgorithm {
128 fn decrypter(&self, dec_key: AeadKey, dec_iv: &[u8]) -> Box<dyn MessageDecrypter> {
129 let dec_key =
131 aead::TlsRecordOpeningKey::new(self.0, aead::TlsProtocolId::TLS12, dec_key.as_ref())
132 .unwrap();
133
134 let mut ret = GcmMessageDecrypter {
135 dec_key,
136 dec_salt: [0u8; 4],
137 };
138
139 debug_assert_eq!(dec_iv.len(), 4);
140 ret.dec_salt.copy_from_slice(dec_iv);
141 Box::new(ret)
142 }
143
144 fn encrypter(
145 &self,
146 enc_key: AeadKey,
147 write_iv: &[u8],
148 explicit: &[u8],
149 ) -> Box<dyn MessageEncrypter> {
150 let enc_key =
163 aead::TlsRecordSealingKey::new(self.0, aead::TlsProtocolId::TLS13, enc_key.as_ref())
164 .unwrap();
165 let iv = gcm_iv(write_iv, explicit);
166 Box::new(GcmMessageEncrypter { enc_key, iv })
167 }
168
169 fn key_block_shape(&self) -> KeyBlockShape {
170 KeyBlockShape {
171 enc_key_len: self.0.key_len(),
172 fixed_iv_len: 4,
173 explicit_nonce_len: 8,
174 }
175 }
176
177 fn extract_keys(
178 &self,
179 key: AeadKey,
180 write_iv: &[u8],
181 explicit: &[u8],
182 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
183 let iv = gcm_iv(write_iv, explicit);
184 Ok(match self.0.key_len() {
185 16 => ConnectionTrafficSecrets::Aes128Gcm { key, iv },
186 32 => ConnectionTrafficSecrets::Aes256Gcm { key, iv },
187 _ => unreachable!(),
188 })
189 }
190
191 fn fips(&self) -> bool {
192 super::fips()
193 }
194}
195
196pub(crate) struct ChaCha20Poly1305;
197
198impl Tls12AeadAlgorithm for ChaCha20Poly1305 {
199 fn decrypter(&self, dec_key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter> {
200 let dec_key = aead::LessSafeKey::new(
201 aead::UnboundKey::new(&aead::CHACHA20_POLY1305, dec_key.as_ref()).unwrap(),
202 );
203 Box::new(ChaCha20Poly1305MessageDecrypter {
204 dec_key,
205 dec_offset: Iv::copy(iv),
206 })
207 }
208
209 fn encrypter(&self, enc_key: AeadKey, enc_iv: &[u8], _: &[u8]) -> Box<dyn MessageEncrypter> {
210 let enc_key = aead::LessSafeKey::new(
211 aead::UnboundKey::new(&aead::CHACHA20_POLY1305, enc_key.as_ref()).unwrap(),
212 );
213 Box::new(ChaCha20Poly1305MessageEncrypter {
214 enc_key,
215 enc_offset: Iv::copy(enc_iv),
216 })
217 }
218
219 fn key_block_shape(&self) -> KeyBlockShape {
220 KeyBlockShape {
221 enc_key_len: 32,
222 fixed_iv_len: 12,
223 explicit_nonce_len: 0,
224 }
225 }
226
227 fn extract_keys(
228 &self,
229 key: AeadKey,
230 iv: &[u8],
231 _explicit: &[u8],
232 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
233 debug_assert_eq!(aead::NONCE_LEN, iv.len());
235 Ok(ConnectionTrafficSecrets::Chacha20Poly1305 {
236 key,
237 iv: Iv::new(iv[..].try_into().unwrap()),
238 })
239 }
240
241 fn fips(&self) -> bool {
242 false }
244}
245
246struct GcmMessageEncrypter {
248 enc_key: aead::TlsRecordSealingKey,
249 iv: Iv,
250}
251
252struct GcmMessageDecrypter {
254 dec_key: aead::TlsRecordOpeningKey,
255 dec_salt: [u8; 4],
256}
257
258const GCM_EXPLICIT_NONCE_LEN: usize = 8;
259const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16;
260
261impl MessageDecrypter for GcmMessageDecrypter {
262 fn decrypt<'a>(
263 &mut self,
264 mut msg: InboundOpaqueMessage<'a>,
265 seq: u64,
266 ) -> Result<InboundPlainMessage<'a>, Error> {
267 let payload = &msg.payload;
268 if payload.len() < GCM_OVERHEAD {
269 return Err(Error::DecryptError);
270 }
271
272 let nonce = {
273 let mut nonce = [0u8; 12];
274 nonce[..4].copy_from_slice(&self.dec_salt);
275 nonce[4..].copy_from_slice(&payload[..8]);
276 aead::Nonce::assume_unique_for_key(nonce)
277 };
278
279 let aad = aead::Aad::from(make_tls12_aad(
280 seq,
281 msg.typ,
282 msg.version,
283 payload.len() - GCM_OVERHEAD,
284 ));
285
286 let payload = &mut msg.payload;
287 let plain_len = self
288 .dec_key
289 .open_in_place(nonce, aad, &mut payload[GCM_EXPLICIT_NONCE_LEN..])
290 .map_err(|_| Error::DecryptError)?
291 .len();
292
293 if plain_len > MAX_FRAGMENT_LEN {
294 return Err(Error::PeerSentOversizedRecord);
295 }
296
297 Ok(
298 msg.into_plain_message_range(
299 GCM_EXPLICIT_NONCE_LEN..GCM_EXPLICIT_NONCE_LEN + plain_len,
300 ),
301 )
302 }
303}
304
305impl MessageEncrypter for GcmMessageEncrypter {
306 fn encrypt(
307 &mut self,
308 msg: OutboundPlainMessage<'_>,
309 seq: u64,
310 ) -> Result<OutboundOpaqueMessage, Error> {
311 let total_len = self.encrypted_payload_len(msg.payload.len());
312 let mut payload = PrefixedPayload::with_capacity(total_len);
313
314 let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0);
315 let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()));
316 payload.extend_from_slice(&nonce.as_ref()[4..]);
317 payload.extend_from_chunks(&msg.payload);
318
319 self.enc_key
320 .seal_in_place_separate_tag(nonce, aad, &mut payload.as_mut()[GCM_EXPLICIT_NONCE_LEN..])
321 .map(|tag| payload.extend_from_slice(tag.as_ref()))
322 .map_err(|_| Error::EncryptError)?;
323
324 Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload))
325 }
326
327 fn encrypted_payload_len(&self, payload_len: usize) -> usize {
328 payload_len + GCM_EXPLICIT_NONCE_LEN + self.enc_key.algorithm().tag_len()
329 }
330}
331
332struct ChaCha20Poly1305MessageEncrypter {
336 enc_key: aead::LessSafeKey,
337 enc_offset: Iv,
338}
339
340struct ChaCha20Poly1305MessageDecrypter {
344 dec_key: aead::LessSafeKey,
345 dec_offset: Iv,
346}
347
348const CHACHAPOLY1305_OVERHEAD: usize = 16;
349
350impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter {
351 fn decrypt<'a>(
352 &mut self,
353 mut msg: InboundOpaqueMessage<'a>,
354 seq: u64,
355 ) -> Result<InboundPlainMessage<'a>, Error> {
356 let payload = &msg.payload;
357
358 if payload.len() < CHACHAPOLY1305_OVERHEAD {
359 return Err(Error::DecryptError);
360 }
361
362 let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.dec_offset, seq).0);
363 let aad = aead::Aad::from(make_tls12_aad(
364 seq,
365 msg.typ,
366 msg.version,
367 payload.len() - CHACHAPOLY1305_OVERHEAD,
368 ));
369
370 let payload = &mut msg.payload;
371 let plain_len = self
372 .dec_key
373 .open_in_place(nonce, aad, payload)
374 .map_err(|_| Error::DecryptError)?
375 .len();
376
377 if plain_len > MAX_FRAGMENT_LEN {
378 return Err(Error::PeerSentOversizedRecord);
379 }
380
381 payload.truncate(plain_len);
382 Ok(msg.into_plain_message())
383 }
384}
385
386impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter {
387 fn encrypt(
388 &mut self,
389 msg: OutboundPlainMessage<'_>,
390 seq: u64,
391 ) -> Result<OutboundOpaqueMessage, Error> {
392 let total_len = self.encrypted_payload_len(msg.payload.len());
393 let mut payload = PrefixedPayload::with_capacity(total_len);
394
395 let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.enc_offset, seq).0);
396 let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()));
397 payload.extend_from_chunks(&msg.payload);
398
399 self.enc_key
400 .seal_in_place_append_tag(nonce, aad, &mut payload)
401 .map_err(|_| Error::EncryptError)?;
402
403 Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload))
404 }
405
406 fn encrypted_payload_len(&self, payload_len: usize) -> usize {
407 payload_len + self.enc_key.algorithm().tag_len()
408 }
409}
410
411fn gcm_iv(write_iv: &[u8], explicit: &[u8]) -> Iv {
412 debug_assert_eq!(write_iv.len(), 4);
413 debug_assert_eq!(explicit.len(), 8);
414
415 let mut iv = [0; NONCE_LEN];
423 iv[..4].copy_from_slice(write_iv);
424 iv[4..].copy_from_slice(explicit);
425
426 Iv::new(iv)
427}
428
429struct Tls12Prf(&'static tls_prf::Algorithm);
430
431impl Prf for Tls12Prf {
432 fn for_key_exchange(
433 &self,
434 output: &mut [u8; 48],
435 kx: Box<dyn ActiveKeyExchange>,
436 peer_pub_key: &[u8],
437 label: &[u8],
438 seed: &[u8],
439 ) -> Result<(), Error> {
440 Tls12PrfSecret {
441 alg: self.0,
442 secret: Secret::KeyExchange(
443 kx.complete_for_tls_version(peer_pub_key, ProtocolVersion::TLSv1_2)?,
444 ),
445 }
446 .prf(output, label, seed);
447 Ok(())
448 }
449
450 fn new_secret(&self, secret: &[u8; 48]) -> Box<dyn PrfSecret> {
451 Box::new(Tls12PrfSecret {
452 alg: self.0,
453 secret: Secret::Master(Zeroizing::new(*secret)),
454 })
455 }
456
457 fn fips(&self) -> bool {
458 super::fips()
459 }
460}
461
462struct Tls12PrfSecret {
465 alg: &'static tls_prf::Algorithm,
466 secret: Secret,
467}
468
469impl PrfSecret for Tls12PrfSecret {
470 fn prf(&self, output: &mut [u8], label: &[u8], seed: &[u8]) {
471 let derived = tls_prf::Secret::new(self.alg, self.secret.as_ref())
477 .unwrap() .derive(label, seed, output.len())
479 .unwrap(); output.copy_from_slice(derived.as_ref());
481 }
482}
483
484enum Secret {
485 Master(Zeroizing<[u8; 48]>),
486 KeyExchange(SharedSecret),
487}
488
489impl AsRef<[u8]> for Secret {
490 fn as_ref(&self) -> &[u8] {
491 match self {
492 Self::Master(ms) => ms.as_ref(),
493 Self::KeyExchange(kx) => kx.secret_bytes(),
494 }
495 }
496}