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