1use alloc::boxed::Box;
2
3use super::ring_like::aead;
4use crate::crypto::KeyExchangeAlgorithm;
5use crate::crypto::cipher::{
6 AeadKey, InboundOpaqueMessage, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter,
7 NONCE_LEN, Nonce, Tls12AeadAlgorithm, UnsupportedOperationError, make_tls12_aad,
8};
9use crate::crypto::tls12::PrfUsingHmac;
10use crate::enums::{CipherSuite, SignatureScheme};
11use crate::error::Error;
12use crate::msgs::fragmenter::MAX_FRAGMENT_LEN;
13use crate::msgs::message::{
14 InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload,
15};
16use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite};
17use crate::tls12::Tls12CipherSuite;
18
19pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
21 SupportedCipherSuite::Tls12(&Tls12CipherSuite {
22 common: CipherSuiteCommon {
23 suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
24 hash_provider: &super::hash::SHA256,
25 confidentiality_limit: u64::MAX,
26 },
27 kx: KeyExchangeAlgorithm::ECDHE,
28 sign: TLS12_ECDSA_SCHEMES,
29 aead_alg: &ChaCha20Poly1305,
30 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
31 });
32
33pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
35 SupportedCipherSuite::Tls12(&Tls12CipherSuite {
36 common: CipherSuiteCommon {
37 suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
38 hash_provider: &super::hash::SHA256,
39 confidentiality_limit: u64::MAX,
40 },
41 kx: KeyExchangeAlgorithm::ECDHE,
42 sign: TLS12_RSA_SCHEMES,
43 aead_alg: &ChaCha20Poly1305,
44 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
45 });
46
47pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
49 SupportedCipherSuite::Tls12(&Tls12CipherSuite {
50 common: CipherSuiteCommon {
51 suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
52 hash_provider: &super::hash::SHA256,
53 confidentiality_limit: 1 << 24,
54 },
55 kx: KeyExchangeAlgorithm::ECDHE,
56 sign: TLS12_RSA_SCHEMES,
57 aead_alg: &AES128_GCM,
58 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
59 });
60
61pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
63 SupportedCipherSuite::Tls12(&Tls12CipherSuite {
64 common: CipherSuiteCommon {
65 suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
66 hash_provider: &super::hash::SHA384,
67 confidentiality_limit: 1 << 24,
68 },
69 kx: KeyExchangeAlgorithm::ECDHE,
70 sign: TLS12_RSA_SCHEMES,
71 aead_alg: &AES256_GCM,
72 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384),
73 });
74
75pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
77 SupportedCipherSuite::Tls12(&Tls12CipherSuite {
78 common: CipherSuiteCommon {
79 suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
80 hash_provider: &super::hash::SHA256,
81 confidentiality_limit: 1 << 24,
82 },
83 kx: KeyExchangeAlgorithm::ECDHE,
84 sign: TLS12_ECDSA_SCHEMES,
85 aead_alg: &AES128_GCM,
86 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
87 });
88
89pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
91 SupportedCipherSuite::Tls12(&Tls12CipherSuite {
92 common: CipherSuiteCommon {
93 suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
94 hash_provider: &super::hash::SHA384,
95 confidentiality_limit: 1 << 24,
96 },
97 kx: KeyExchangeAlgorithm::ECDHE,
98 sign: TLS12_ECDSA_SCHEMES,
99 aead_alg: &AES256_GCM,
100 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384),
101 });
102
103static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[
104 SignatureScheme::ED25519,
105 SignatureScheme::ECDSA_NISTP521_SHA512,
106 SignatureScheme::ECDSA_NISTP384_SHA384,
107 SignatureScheme::ECDSA_NISTP256_SHA256,
108];
109
110static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[
111 SignatureScheme::RSA_PSS_SHA512,
112 SignatureScheme::RSA_PSS_SHA384,
113 SignatureScheme::RSA_PSS_SHA256,
114 SignatureScheme::RSA_PKCS1_SHA512,
115 SignatureScheme::RSA_PKCS1_SHA384,
116 SignatureScheme::RSA_PKCS1_SHA256,
117];
118
119pub(crate) static AES128_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_128_GCM);
120pub(crate) static AES256_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_256_GCM);
121
122pub(crate) struct GcmAlgorithm(&'static aead::Algorithm);
123
124impl Tls12AeadAlgorithm for GcmAlgorithm {
125 fn decrypter(&self, dec_key: AeadKey, dec_iv: &[u8]) -> Box<dyn MessageDecrypter> {
126 let dec_key =
127 aead::LessSafeKey::new(aead::UnboundKey::new(self.0, dec_key.as_ref()).unwrap());
128
129 let mut ret = GcmMessageDecrypter {
130 dec_key,
131 dec_salt: [0u8; 4],
132 };
133
134 debug_assert_eq!(dec_iv.len(), 4);
135 ret.dec_salt.copy_from_slice(dec_iv);
136 Box::new(ret)
137 }
138
139 fn encrypter(
140 &self,
141 enc_key: AeadKey,
142 write_iv: &[u8],
143 explicit: &[u8],
144 ) -> Box<dyn MessageEncrypter> {
145 let enc_key =
146 aead::LessSafeKey::new(aead::UnboundKey::new(self.0, enc_key.as_ref()).unwrap());
147 let iv = gcm_iv(write_iv, explicit);
148 Box::new(GcmMessageEncrypter { enc_key, iv })
149 }
150
151 fn key_block_shape(&self) -> KeyBlockShape {
152 KeyBlockShape {
153 enc_key_len: self.0.key_len(),
154 fixed_iv_len: 4,
155 explicit_nonce_len: 8,
156 }
157 }
158
159 fn extract_keys(
160 &self,
161 key: AeadKey,
162 write_iv: &[u8],
163 explicit: &[u8],
164 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
165 let iv = gcm_iv(write_iv, explicit);
166 Ok(match self.0.key_len() {
167 16 => ConnectionTrafficSecrets::Aes128Gcm { key, iv },
168 32 => ConnectionTrafficSecrets::Aes256Gcm { key, iv },
169 _ => unreachable!(),
170 })
171 }
172
173 fn fips(&self) -> bool {
174 super::fips()
175 }
176}
177
178pub(crate) struct ChaCha20Poly1305;
179
180impl Tls12AeadAlgorithm for ChaCha20Poly1305 {
181 fn decrypter(&self, dec_key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter> {
182 let dec_key = aead::LessSafeKey::new(
183 aead::UnboundKey::new(&aead::CHACHA20_POLY1305, dec_key.as_ref()).unwrap(),
184 );
185 Box::new(ChaCha20Poly1305MessageDecrypter {
186 dec_key,
187 dec_offset: Iv::copy(iv),
188 })
189 }
190
191 fn encrypter(&self, enc_key: AeadKey, enc_iv: &[u8], _: &[u8]) -> Box<dyn MessageEncrypter> {
192 let enc_key = aead::LessSafeKey::new(
193 aead::UnboundKey::new(&aead::CHACHA20_POLY1305, enc_key.as_ref()).unwrap(),
194 );
195 Box::new(ChaCha20Poly1305MessageEncrypter {
196 enc_key,
197 enc_offset: Iv::copy(enc_iv),
198 })
199 }
200
201 fn key_block_shape(&self) -> KeyBlockShape {
202 KeyBlockShape {
203 enc_key_len: 32,
204 fixed_iv_len: 12,
205 explicit_nonce_len: 0,
206 }
207 }
208
209 fn extract_keys(
210 &self,
211 key: AeadKey,
212 iv: &[u8],
213 _explicit: &[u8],
214 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
215 debug_assert_eq!(aead::NONCE_LEN, iv.len());
217 Ok(ConnectionTrafficSecrets::Chacha20Poly1305 {
218 key,
219 iv: Iv::new(iv[..].try_into().unwrap()),
220 })
221 }
222
223 fn fips(&self) -> bool {
224 false }
226}
227
228struct GcmMessageEncrypter {
230 enc_key: aead::LessSafeKey,
231 iv: Iv,
232}
233
234struct GcmMessageDecrypter {
236 dec_key: aead::LessSafeKey,
237 dec_salt: [u8; 4],
238}
239
240const GCM_EXPLICIT_NONCE_LEN: usize = 8;
241const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16;
242
243impl MessageDecrypter for GcmMessageDecrypter {
244 fn decrypt<'a>(
245 &mut self,
246 mut msg: InboundOpaqueMessage<'a>,
247 seq: u64,
248 ) -> Result<InboundPlainMessage<'a>, Error> {
249 let payload = &msg.payload;
250 if payload.len() < GCM_OVERHEAD {
251 return Err(Error::DecryptError);
252 }
253
254 let nonce = {
255 let mut nonce = [0u8; 12];
256 nonce[..4].copy_from_slice(&self.dec_salt);
257 nonce[4..].copy_from_slice(&payload[..8]);
258 aead::Nonce::assume_unique_for_key(nonce)
259 };
260
261 let aad = aead::Aad::from(make_tls12_aad(
262 seq,
263 msg.typ,
264 msg.version,
265 payload.len() - GCM_OVERHEAD,
266 ));
267
268 let payload = &mut msg.payload;
269 let plain_len = self
270 .dec_key
271 .open_within(nonce, aad, payload, GCM_EXPLICIT_NONCE_LEN..)
272 .map_err(|_| Error::DecryptError)?
273 .len();
274
275 if plain_len > MAX_FRAGMENT_LEN {
276 return Err(Error::PeerSentOversizedRecord);
277 }
278
279 payload.truncate(plain_len);
280 Ok(msg.into_plain_message())
281 }
282}
283
284impl MessageEncrypter for GcmMessageEncrypter {
285 fn encrypt(
286 &mut self,
287 msg: OutboundPlainMessage<'_>,
288 seq: u64,
289 ) -> Result<OutboundOpaqueMessage, Error> {
290 let total_len = self.encrypted_payload_len(msg.payload.len());
291 let mut payload = PrefixedPayload::with_capacity(total_len);
292
293 let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0);
294 let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()));
295 payload.extend_from_slice(&nonce.as_ref()[4..]);
296 payload.extend_from_chunks(&msg.payload);
297
298 self.enc_key
299 .seal_in_place_separate_tag(nonce, aad, &mut payload.as_mut()[GCM_EXPLICIT_NONCE_LEN..])
300 .map(|tag| payload.extend_from_slice(tag.as_ref()))
301 .map_err(|_| Error::EncryptError)?;
302
303 Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload))
304 }
305
306 fn encrypted_payload_len(&self, payload_len: usize) -> usize {
307 payload_len + GCM_EXPLICIT_NONCE_LEN + self.enc_key.algorithm().tag_len()
308 }
309}
310
311struct ChaCha20Poly1305MessageEncrypter {
315 enc_key: aead::LessSafeKey,
316 enc_offset: Iv,
317}
318
319struct ChaCha20Poly1305MessageDecrypter {
323 dec_key: aead::LessSafeKey,
324 dec_offset: Iv,
325}
326
327const CHACHAPOLY1305_OVERHEAD: usize = 16;
328
329impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter {
330 fn decrypt<'a>(
331 &mut self,
332 mut msg: InboundOpaqueMessage<'a>,
333 seq: u64,
334 ) -> Result<InboundPlainMessage<'a>, Error> {
335 let payload = &msg.payload;
336
337 if payload.len() < CHACHAPOLY1305_OVERHEAD {
338 return Err(Error::DecryptError);
339 }
340
341 let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.dec_offset, seq).0);
342 let aad = aead::Aad::from(make_tls12_aad(
343 seq,
344 msg.typ,
345 msg.version,
346 payload.len() - CHACHAPOLY1305_OVERHEAD,
347 ));
348
349 let payload = &mut msg.payload;
350 let plain_len = self
351 .dec_key
352 .open_in_place(nonce, aad, payload)
353 .map_err(|_| Error::DecryptError)?
354 .len();
355
356 if plain_len > MAX_FRAGMENT_LEN {
357 return Err(Error::PeerSentOversizedRecord);
358 }
359
360 payload.truncate(plain_len);
361 Ok(msg.into_plain_message())
362 }
363}
364
365impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter {
366 fn encrypt(
367 &mut self,
368 msg: OutboundPlainMessage<'_>,
369 seq: u64,
370 ) -> Result<OutboundOpaqueMessage, Error> {
371 let total_len = self.encrypted_payload_len(msg.payload.len());
372 let mut payload = PrefixedPayload::with_capacity(total_len);
373
374 let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.enc_offset, seq).0);
375 let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()));
376 payload.extend_from_chunks(&msg.payload);
377
378 self.enc_key
379 .seal_in_place_append_tag(nonce, aad, &mut payload)
380 .map_err(|_| Error::EncryptError)?;
381
382 Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload))
383 }
384
385 fn encrypted_payload_len(&self, payload_len: usize) -> usize {
386 payload_len + self.enc_key.algorithm().tag_len()
387 }
388}
389
390fn gcm_iv(write_iv: &[u8], explicit: &[u8]) -> Iv {
391 debug_assert_eq!(write_iv.len(), 4);
392 debug_assert_eq!(explicit.len(), 8);
393
394 let mut iv = [0; NONCE_LEN];
402 iv[..4].copy_from_slice(write_iv);
403 iv[4..].copy_from_slice(explicit);
404
405 Iv::new(iv)
406}