1 | use alloc::boxed::Box; |
2 | |
3 | use super::ring_like::aead; |
4 | use crate::crypto::KeyExchangeAlgorithm; |
5 | use crate::crypto::cipher::{ |
6 | AeadKey, InboundOpaqueMessage, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter, |
7 | NONCE_LEN, Nonce, Tls12AeadAlgorithm, UnsupportedOperationError, make_tls12_aad, |
8 | }; |
9 | use crate::crypto::tls12::PrfUsingHmac; |
10 | use crate::enums::{CipherSuite, SignatureScheme}; |
11 | use crate::error::Error; |
12 | use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; |
13 | use crate::msgs::message::{ |
14 | InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload, |
15 | }; |
16 | use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite}; |
17 | use crate::tls12::Tls12CipherSuite; |
18 | |
19 | /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256. |
20 | pub 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 | |
33 | /// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 |
34 | pub 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 | |
47 | /// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 |
48 | pub 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 | |
61 | /// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 |
62 | pub 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 | |
75 | /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 |
76 | pub 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 | |
89 | /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 |
90 | pub 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 | |
103 | static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[ |
104 | SignatureScheme::ED25519, |
105 | SignatureScheme::ECDSA_NISTP521_SHA512, |
106 | SignatureScheme::ECDSA_NISTP384_SHA384, |
107 | SignatureScheme::ECDSA_NISTP256_SHA256, |
108 | ]; |
109 | |
110 | static 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 | |
119 | pub(crate) static AES128_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_128_GCM); |
120 | pub(crate) static AES256_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_256_GCM); |
121 | |
122 | pub(crate) struct GcmAlgorithm(&'static aead::Algorithm); |
123 | |
124 | impl 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 | |
178 | pub(crate) struct ChaCha20Poly1305; |
179 | |
180 | impl 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 | // This should always be true because KeyBlockShape and the Iv nonce len are in agreement. |
216 | 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 // not fips approved |
225 | } |
226 | } |
227 | |
228 | /// A `MessageEncrypter` for AES-GCM AEAD ciphersuites. TLS 1.2 only. |
229 | struct GcmMessageEncrypter { |
230 | enc_key: aead::LessSafeKey, |
231 | iv: Iv, |
232 | } |
233 | |
234 | /// A `MessageDecrypter` for AES-GCM AEAD ciphersuites. TLS1.2 only. |
235 | struct GcmMessageDecrypter { |
236 | dec_key: aead::LessSafeKey, |
237 | dec_salt: [u8; 4], |
238 | } |
239 | |
240 | const GCM_EXPLICIT_NONCE_LEN: usize = 8; |
241 | const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16; |
242 | |
243 | impl 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 | |
284 | impl 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 | |
311 | /// The RFC7905/RFC7539 ChaCha20Poly1305 construction. |
312 | /// This implementation does the AAD construction required in TLS1.2. |
313 | /// TLS1.3 uses `TLS13MessageEncrypter`. |
314 | struct ChaCha20Poly1305MessageEncrypter { |
315 | enc_key: aead::LessSafeKey, |
316 | enc_offset: Iv, |
317 | } |
318 | |
319 | /// The RFC7905/RFC7539 ChaCha20Poly1305 construction. |
320 | /// This implementation does the AAD construction required in TLS1.2. |
321 | /// TLS1.3 uses `TLS13MessageDecrypter`. |
322 | struct ChaCha20Poly1305MessageDecrypter { |
323 | dec_key: aead::LessSafeKey, |
324 | dec_offset: Iv, |
325 | } |
326 | |
327 | const CHACHAPOLY1305_OVERHEAD: usize = 16; |
328 | |
329 | impl 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 | |
365 | impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter { |
366 | fn encrypt( |
367 | &mut self, |
368 | msg: OutboundPlainMessage<'_>, |
369 | seq: u64, |
370 | ) -> Result<OutboundOpaqueMessage, Error> { |
371 | let total_len: usize = self.encrypted_payload_len(msg.payload.len()); |
372 | let mut payload: PrefixedPayload = PrefixedPayload::with_capacity(total_len); |
373 | |
374 | let nonce: Nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.enc_offset, seq).0); |
375 | let aad: Aad<[u8; 13]> = aead::Aad::from(make_tls12_aad(seq, msg.typ, vers: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 | |
390 | fn 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 | // The GCM nonce is constructed from a 32-bit 'salt' derived |
395 | // from the master-secret, and a 64-bit explicit part, |
396 | // with no specified construction. Thanks for that. |
397 | // |
398 | // We use the same construction as TLS1.3/ChaCha20Poly1305: |
399 | // a starting point extracted from the key block, xored with |
400 | // the sequence number. |
401 | let mut iv: [u8; 12] = [0; NONCE_LEN]; |
402 | iv[..4].copy_from_slice(src:write_iv); |
403 | iv[4..].copy_from_slice(src:explicit); |
404 | |
405 | Iv::new(iv) |
406 | } |
407 | |