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