1use crate::error::mbedtls_err_to_rustls_error;
9use alloc::boxed::Box;
10use alloc::vec::Vec;
11use mbedtls::cipher::raw::{CipherId, CipherMode, CipherType};
12use mbedtls::cipher::{Authenticated, Cipher, Decryption, Encryption, Fresh};
13use rustls::crypto::cipher::{
14 make_tls12_aad, AeadKey, InboundOpaqueMessage, InboundPlainMessage, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter,
15 Nonce, OutboundOpaqueMessage, OutboundPlainMessage, PlainMessage, PrefixedPayload, Tls12AeadAlgorithm,
16 UnsupportedOperationError, NONCE_LEN,
17};
18use rustls::crypto::tls12::PrfUsingHmac;
19use rustls::crypto::{CipherSuiteCommon, KeyExchangeAlgorithm};
20
21use super::aead::{self, Algorithm, AES128_GCM, AES256_GCM};
22use alloc::string::String;
23use rustls::{CipherSuite, ConnectionTrafficSecrets, Error, SignatureScheme, SupportedCipherSuite, Tls12CipherSuite};
24
25pub(crate) const GCM_FIXED_IV_LEN: usize = 4;
26pub(crate) const GCM_EXPLICIT_NONCE_LEN: usize = 8;
27pub(crate) const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16;
28pub(crate) const MAX_FRAGMENT_LEN: usize = 16384;
29
30pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
32 SupportedCipherSuite::Tls12(&Tls12CipherSuite {
33 common: CipherSuiteCommon {
34 suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
35 hash_provider: &super::hash::SHA256,
36 confidentiality_limit: u64::MAX,
37 },
38 kx: KeyExchangeAlgorithm::ECDHE,
39 sign: TLS12_ECDSA_SCHEMES,
40 aead_alg: &ChaCha20Poly1305,
41 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
42 });
43
44pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls12(&Tls12CipherSuite {
46 common: CipherSuiteCommon {
47 suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
48 hash_provider: &super::hash::SHA256,
49 confidentiality_limit: u64::MAX,
50 },
51 kx: KeyExchangeAlgorithm::ECDHE,
52 sign: TLS12_RSA_SCHEMES,
53 aead_alg: &ChaCha20Poly1305,
54 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
55});
56
57pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls12(&Tls12CipherSuite {
59 common: CipherSuiteCommon {
60 suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
61 hash_provider: &super::hash::SHA256,
62 confidentiality_limit: 1 << 23,
63 },
64 kx: KeyExchangeAlgorithm::ECDHE,
65 sign: TLS12_RSA_SCHEMES,
66 aead_alg: &AES128_GCM,
67 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
68});
69
70pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = SupportedCipherSuite::Tls12(&Tls12CipherSuite {
72 common: CipherSuiteCommon {
73 suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
74 hash_provider: &super::hash::SHA384,
75 confidentiality_limit: 1 << 23,
76 },
77 kx: KeyExchangeAlgorithm::ECDHE,
78 sign: TLS12_RSA_SCHEMES,
79 aead_alg: &AES256_GCM,
80 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384),
81});
82
83pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls12(&Tls12CipherSuite {
85 common: CipherSuiteCommon {
86 suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
87 hash_provider: &super::hash::SHA256,
88 confidentiality_limit: 1 << 23,
89 },
90 kx: KeyExchangeAlgorithm::ECDHE,
91 sign: TLS12_ECDSA_SCHEMES,
92 aead_alg: &AES128_GCM,
93 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
94});
95
96pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = SupportedCipherSuite::Tls12(&Tls12CipherSuite {
98 common: CipherSuiteCommon {
99 suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
100 hash_provider: &super::hash::SHA384,
101 confidentiality_limit: 1 << 23,
102 },
103 kx: KeyExchangeAlgorithm::ECDHE,
104 sign: TLS12_ECDSA_SCHEMES,
105 aead_alg: &AES256_GCM,
106 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384),
107});
108
109pub static TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls12(&Tls12CipherSuite {
111 common: CipherSuiteCommon {
112 suite: CipherSuite::TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
113 hash_provider: &super::hash::SHA256,
114 confidentiality_limit: 1 << 23,
115 },
116 kx: KeyExchangeAlgorithm::DHE,
117 sign: TLS12_RSA_SCHEMES,
118 aead_alg: &AES128_GCM,
119 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
120});
121
122pub static TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = SupportedCipherSuite::Tls12(&Tls12CipherSuite {
124 common: CipherSuiteCommon {
125 suite: CipherSuite::TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
126 hash_provider: &super::hash::SHA384,
127 confidentiality_limit: 1 << 23,
128 },
129 kx: KeyExchangeAlgorithm::DHE,
130 sign: TLS12_RSA_SCHEMES,
131 aead_alg: &AES256_GCM,
132 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384),
133});
134
135pub static TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls12(&Tls12CipherSuite {
137 common: CipherSuiteCommon {
138 suite: CipherSuite::TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
139 hash_provider: &super::hash::SHA256,
140 confidentiality_limit: u64::MAX,
141 },
142 kx: KeyExchangeAlgorithm::DHE,
143 sign: TLS12_RSA_SCHEMES,
144 aead_alg: &ChaCha20Poly1305,
145 prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
146});
147
148static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[
149 SignatureScheme::ED25519,
150 SignatureScheme::ECDSA_NISTP521_SHA512,
151 SignatureScheme::ECDSA_NISTP384_SHA384,
152 SignatureScheme::ECDSA_NISTP256_SHA256,
153];
154
155static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[
156 SignatureScheme::RSA_PSS_SHA512,
157 SignatureScheme::RSA_PSS_SHA384,
158 SignatureScheme::RSA_PSS_SHA256,
159 SignatureScheme::RSA_PKCS1_SHA512,
160 SignatureScheme::RSA_PKCS1_SHA384,
161 SignatureScheme::RSA_PKCS1_SHA256,
162];
163
164impl Tls12AeadAlgorithm for Algorithm {
165 fn encrypter(&self, enc_key: AeadKey, iv: &[u8], extra: &[u8]) -> Box<dyn MessageEncrypter> {
166 let iv = gcm_iv(iv, extra);
167 Box::new(GcmMessageEncrypter { enc_key, iv })
168 }
169
170 fn decrypter(&self, dec_key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter> {
171 let mut ret = GcmMessageDecrypter { dec_key, dec_salt: [0u8; GCM_FIXED_IV_LEN] };
172 debug_assert_eq!(iv.len(), GCM_FIXED_IV_LEN);
173 ret.dec_salt.copy_from_slice(iv);
174 Box::new(ret)
175 }
176
177 fn key_block_shape(&self) -> KeyBlockShape {
178 KeyBlockShape {
179 enc_key_len: self.key_length,
180 fixed_iv_len: GCM_FIXED_IV_LEN,
181 explicit_nonce_len: GCM_EXPLICIT_NONCE_LEN,
182 }
183 }
184
185 fn extract_keys(
186 &self,
187 key: AeadKey,
188 iv: &[u8],
189 explicit: &[u8],
190 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
191 match self.cipher_type {
192 CipherType::Aes128Gcm => Ok(ConnectionTrafficSecrets::Aes128Gcm { key, iv: gcm_iv(iv, explicit) }),
193 CipherType::Aes256Gcm => Ok(ConnectionTrafficSecrets::Aes256Gcm { key, iv: gcm_iv(iv, explicit) }),
194 _ => Err(UnsupportedOperationError),
195 }
196 }
197}
198
199pub(crate) struct ChaCha20Poly1305;
200
201impl Tls12AeadAlgorithm for ChaCha20Poly1305 {
202 fn decrypter(&self, dec_key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter> {
203 Box::new(ChaCha20Poly1305MessageDecrypter { dec_key, dec_offset: Iv::copy(iv) })
204 }
205
206 fn encrypter(&self, enc_key: AeadKey, enc_iv: &[u8], _: &[u8]) -> Box<dyn MessageEncrypter> {
207 Box::new(ChaCha20Poly1305MessageEncrypter { enc_key, enc_offset: Iv::copy(enc_iv) })
208 }
209
210 fn key_block_shape(&self) -> KeyBlockShape {
211 KeyBlockShape { enc_key_len: 32, fixed_iv_len: 12, explicit_nonce_len: 0 }
212 }
213
214 fn extract_keys(
215 &self,
216 key: AeadKey,
217 iv: &[u8],
218 _explicit: &[u8],
219 ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
220 debug_assert_eq!(NONCE_LEN, iv.len());
222 Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv: Iv::new(iv[..].try_into().unwrap()) })
223 }
224}
225
226struct GcmMessageEncrypter {
228 enc_key: AeadKey,
229 iv: Iv,
230}
231
232struct GcmMessageDecrypter {
234 dec_key: AeadKey,
235 dec_salt: [u8; GCM_FIXED_IV_LEN],
236}
237
238impl MessageDecrypter for GcmMessageDecrypter {
239 fn decrypt<'a>(&mut self, mut msg: InboundOpaqueMessage<'a>, seq: u64) -> Result<InboundPlainMessage<'a>, Error> {
240 let payload = &mut msg.payload;
241 if payload.len() < GCM_OVERHEAD {
242 return Err(Error::DecryptError);
243 }
244 let nonce = {
245 let mut nonce = [0u8; NONCE_LEN];
246 nonce[..GCM_FIXED_IV_LEN].copy_from_slice(&self.dec_salt);
247 nonce[GCM_FIXED_IV_LEN..].copy_from_slice(&payload[..GCM_EXPLICIT_NONCE_LEN]);
248 nonce
249 };
250 let aad = make_tls12_aad(seq, msg.typ, msg.version, payload.len() - GCM_OVERHEAD);
251
252 let dec_key = self.dec_key.as_ref();
253 let cipher = Cipher::<Decryption, Authenticated, Fresh>::new(CipherId::Aes, CipherMode::GCM, (dec_key.len() * 8) as _)
254 .map_err(mbedtls_err_to_rustls_error)?;
255
256 let cipher = cipher
257 .set_key_iv(dec_key, &nonce)
258 .map_err(mbedtls_err_to_rustls_error)?;
259
260 let tag_offset = payload
261 .len()
262 .checked_sub(aead::TAG_LEN)
263 .ok_or(Error::General(String::from("Tag length overflow")))?;
264 let (remaining, tag) = payload.split_at_mut(tag_offset);
265 let (_, ciphertext) = remaining.split_at_mut(GCM_EXPLICIT_NONCE_LEN);
266 let (plain_len, _) = cipher
267 .decrypt_auth_inplace(&aad, ciphertext, tag)
268 .map_err(|err| match err {
269 mbedtls::Error::CcmAuthFailed
270 | mbedtls::Error::ChachapolyAuthFailed
271 | mbedtls::Error::CipherAuthFailed
272 | mbedtls::Error::GcmAuthFailed => Error::DecryptError,
273 _ => mbedtls_err_to_rustls_error(err),
274 })?;
275 if plain_len > MAX_FRAGMENT_LEN {
276 return Err(Error::PeerSentOversizedRecord);
277 }
278 payload.copy_within(GCM_EXPLICIT_NONCE_LEN..tag_offset, 0);
279 payload.truncate(plain_len);
280 Ok(msg.into_plain_message())
281 }
282}
283
284impl MessageEncrypter for GcmMessageEncrypter {
285 fn encrypt(&mut self, msg: OutboundPlainMessage, seq: u64) -> Result<OutboundOpaqueMessage, Error> {
286 let payload_len = msg.payload.len();
287 let total_len = self.encrypted_payload_len(payload_len);
288 let mut payload = PrefixedPayload::with_capacity(total_len);
289
290 let nonce = Nonce::new(&self.iv, seq).0;
291 payload.extend_from_slice(&nonce.as_ref()[GCM_FIXED_IV_LEN..]);
292 payload.extend_from_chunks(&msg.payload);
293
294 let aad = make_tls12_aad(seq, msg.typ, msg.version, payload_len);
295 let mut tag = [0u8; aead::TAG_LEN];
296
297 let enc_key = self.enc_key.as_ref();
298 let cipher = Cipher::<Encryption, Authenticated, Fresh>::new(CipherId::Aes, CipherMode::GCM, (enc_key.len() * 8) as _)
299 .map_err(mbedtls_err_to_rustls_error)?;
300 let cipher = cipher
301 .set_key_iv(enc_key, &nonce)
302 .map_err(mbedtls_err_to_rustls_error)?;
303
304 cipher
305 .encrypt_auth_inplace(&aad, &mut payload.as_mut()[GCM_EXPLICIT_NONCE_LEN..], &mut tag)
306 .map_err(|err| match err {
307 mbedtls::Error::CcmAuthFailed
308 | mbedtls::Error::ChachapolyAuthFailed
309 | mbedtls::Error::CipherAuthFailed
310 | mbedtls::Error::GcmAuthFailed => Error::EncryptError,
311 _ => mbedtls_err_to_rustls_error(err),
312 })?;
313 payload.extend_from_slice(&tag);
314
315 Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload))
316 }
317
318 fn encrypted_payload_len(&self, payload_len: usize) -> usize {
319 payload_len + GCM_EXPLICIT_NONCE_LEN + aead::TAG_LEN
320 }
321}
322
323struct ChaCha20Poly1305MessageEncrypter {
327 enc_key: AeadKey,
328 enc_offset: Iv,
329}
330
331struct ChaCha20Poly1305MessageDecrypter {
335 dec_key: AeadKey,
336 dec_offset: Iv,
337}
338
339const CHACHAPOLY1305_OVERHEAD: usize = 16;
340
341impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter {
342 fn decrypt<'a>(&mut self, mut msg: InboundOpaqueMessage<'a>, seq: u64) -> Result<InboundPlainMessage<'a>, Error> {
343 let payload = &mut msg.payload;
344
345 if payload.len() < CHACHAPOLY1305_OVERHEAD {
346 return Err(Error::DecryptError);
347 }
348
349 let nonce = Nonce::new(&self.dec_offset, seq).0;
350 let aad = make_tls12_aad(seq, msg.typ, msg.version, payload.len() - CHACHAPOLY1305_OVERHEAD);
351
352 let dec_key = self.dec_key.as_ref();
353 let cipher = Cipher::<Decryption, Authenticated, Fresh>::new(
354 CipherId::Chacha20,
355 CipherMode::CHACHAPOLY,
356 (dec_key.len() * 8) as _,
357 )
358 .map_err(mbedtls_err_to_rustls_error)?;
359
360 let cipher = cipher
361 .set_key_iv(dec_key, &nonce)
362 .map_err(mbedtls_err_to_rustls_error)?;
363
364 let tag_offset = payload
365 .len()
366 .checked_sub(aead::TAG_LEN)
367 .ok_or(Error::DecryptError)?;
368
369 let (ciphertext, tag) = payload.split_at_mut(tag_offset);
370
371 let (plain_len, _) = cipher
372 .decrypt_auth_inplace(&aad, ciphertext, tag)
373 .map_err(|err| match err {
374 mbedtls::Error::CcmAuthFailed
375 | mbedtls::Error::ChachapolyAuthFailed
376 | mbedtls::Error::CipherAuthFailed
377 | mbedtls::Error::GcmAuthFailed => Error::DecryptError,
378 _ => mbedtls_err_to_rustls_error(err),
379 })?;
380
381 if plain_len > MAX_FRAGMENT_LEN {
382 return Err(Error::PeerSentOversizedRecord);
383 }
384
385 payload.truncate(plain_len);
386 Ok(msg.into_plain_message())
387 }
388}
389
390impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter {
391 fn encrypt(&mut self, msg: OutboundPlainMessage, seq: u64) -> Result<OutboundOpaqueMessage, Error> {
392 let payload_len = msg.payload.len();
393 let total_len = self.encrypted_payload_len(payload_len);
394 let mut payload = PrefixedPayload::with_capacity(total_len);
395 payload.extend_from_chunks(&msg.payload);
396
397 let nonce = Nonce::new(&self.enc_offset, seq).0;
398 let aad = make_tls12_aad(seq, msg.typ, msg.version, payload_len);
399 let mut tag = [0u8; aead::TAG_LEN];
400
401 let enc_key = self.enc_key.as_ref();
402 let cipher = Cipher::<Encryption, Authenticated, Fresh>::new(
403 CipherId::Chacha20,
404 CipherMode::CHACHAPOLY,
405 (enc_key.len() * 8) as _,
406 )
407 .map_err(mbedtls_err_to_rustls_error)?;
408
409 let cipher = cipher
410 .set_key_iv(enc_key, &nonce)
411 .map_err(mbedtls_err_to_rustls_error)?;
412
413 cipher
414 .encrypt_auth_inplace(&aad, payload.as_mut(), &mut tag)
415 .map_err(|err| match err {
416 mbedtls::Error::CcmAuthFailed
417 | mbedtls::Error::ChachapolyAuthFailed
418 | mbedtls::Error::CipherAuthFailed
419 | mbedtls::Error::GcmAuthFailed => Error::EncryptError,
420 _ => mbedtls_err_to_rustls_error(err),
421 })?;
422 payload.extend_from_slice(&tag);
423
424 Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload))
425 }
426
427 fn encrypted_payload_len(&self, payload_len: usize) -> usize {
428 payload_len + aead::TAG_LEN
429 }
430}
431
432fn gcm_iv(write_iv: &[u8], explicit_nonce: &[u8]) -> Iv {
434 debug_assert_eq!(write_iv.len(), GCM_FIXED_IV_LEN);
435 debug_assert_eq!(explicit_nonce.len(), GCM_EXPLICIT_NONCE_LEN);
436
437 let mut iv = [0; NONCE_LEN];
445 iv[..GCM_FIXED_IV_LEN].copy_from_slice(write_iv);
446 iv[GCM_FIXED_IV_LEN..].copy_from_slice(explicit_nonce);
447
448 Iv::new(iv)
449}