1 | use crate::crypto::cipher::{ |
2 | make_tls12_aad, AeadKey, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter, Nonce, |
3 | Tls12AeadAlgorithm, UnsupportedOperationError, NONCE_LEN, |
4 | }; |
5 | use crate::crypto::tls12::PrfUsingHmac; |
6 | use crate::crypto::KeyExchangeAlgorithm; |
7 | use crate::enums::{CipherSuite, SignatureScheme}; |
8 | use crate::error::Error; |
9 | use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; |
10 | use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; |
11 | use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite}; |
12 | use crate::tls12::Tls12CipherSuite; |
13 | |
14 | use alloc::boxed::Box; |
15 | use alloc::vec::Vec; |
16 | |
17 | use super::ring_like::aead; |
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 | integrity_limit: 1 << 36, |
27 | }, |
28 | kx: KeyExchangeAlgorithm::ECDHE, |
29 | sign: TLS12_ECDSA_SCHEMES, |
30 | aead_alg: &ChaCha20Poly1305, |
31 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), |
32 | }); |
33 | |
34 | /// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 |
35 | pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = |
36 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
37 | common: CipherSuiteCommon { |
38 | suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, |
39 | hash_provider: &super::hash::SHA256, |
40 | confidentiality_limit: u64::MAX, |
41 | integrity_limit: 1 << 36, |
42 | }, |
43 | kx: KeyExchangeAlgorithm::ECDHE, |
44 | sign: TLS12_RSA_SCHEMES, |
45 | aead_alg: &ChaCha20Poly1305, |
46 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), |
47 | }); |
48 | |
49 | /// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 |
50 | pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = |
51 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
52 | common: CipherSuiteCommon { |
53 | suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
54 | hash_provider: &super::hash::SHA256, |
55 | confidentiality_limit: 1 << 23, |
56 | integrity_limit: 1 << 52, |
57 | }, |
58 | kx: KeyExchangeAlgorithm::ECDHE, |
59 | sign: TLS12_RSA_SCHEMES, |
60 | aead_alg: &AES128_GCM, |
61 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), |
62 | }); |
63 | |
64 | /// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 |
65 | pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = |
66 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
67 | common: CipherSuiteCommon { |
68 | suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, |
69 | hash_provider: &super::hash::SHA384, |
70 | confidentiality_limit: 1 << 23, |
71 | integrity_limit: 1 << 52, |
72 | }, |
73 | kx: KeyExchangeAlgorithm::ECDHE, |
74 | sign: TLS12_RSA_SCHEMES, |
75 | aead_alg: &AES256_GCM, |
76 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384), |
77 | }); |
78 | |
79 | /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 |
80 | pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = |
81 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
82 | common: CipherSuiteCommon { |
83 | suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
84 | hash_provider: &super::hash::SHA256, |
85 | confidentiality_limit: 1 << 23, |
86 | integrity_limit: 1 << 52, |
87 | }, |
88 | kx: KeyExchangeAlgorithm::ECDHE, |
89 | sign: TLS12_ECDSA_SCHEMES, |
90 | aead_alg: &AES128_GCM, |
91 | prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), |
92 | }); |
93 | |
94 | /// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 |
95 | pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = |
96 | SupportedCipherSuite::Tls12(&Tls12CipherSuite { |
97 | common: CipherSuiteCommon { |
98 | suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, |
99 | hash_provider: &super::hash::SHA384, |
100 | confidentiality_limit: 1 << 23, |
101 | integrity_limit: 1 << 52, |
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 | |
109 | static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[ |
110 | SignatureScheme::ED25519, |
111 | SignatureScheme::ECDSA_NISTP521_SHA512, |
112 | SignatureScheme::ECDSA_NISTP384_SHA384, |
113 | SignatureScheme::ECDSA_NISTP256_SHA256, |
114 | ]; |
115 | |
116 | static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[ |
117 | SignatureScheme::RSA_PSS_SHA512, |
118 | SignatureScheme::RSA_PSS_SHA384, |
119 | SignatureScheme::RSA_PSS_SHA256, |
120 | SignatureScheme::RSA_PKCS1_SHA512, |
121 | SignatureScheme::RSA_PKCS1_SHA384, |
122 | SignatureScheme::RSA_PKCS1_SHA256, |
123 | ]; |
124 | |
125 | pub(crate) static AES128_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_128_GCM); |
126 | pub(crate) static AES256_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_256_GCM); |
127 | |
128 | pub(crate) struct GcmAlgorithm(&'static aead::Algorithm); |
129 | |
130 | impl Tls12AeadAlgorithm for GcmAlgorithm { |
131 | fn decrypter(&self, dec_key: AeadKey, dec_iv: &[u8]) -> Box<dyn MessageDecrypter> { |
132 | let dec_key = |
133 | aead::LessSafeKey::new(aead::UnboundKey::new(self.0, dec_key.as_ref()).unwrap()); |
134 | |
135 | let mut ret = GcmMessageDecrypter { |
136 | dec_key, |
137 | dec_salt: [0u8; 4], |
138 | }; |
139 | |
140 | debug_assert_eq!(dec_iv.len(), 4); |
141 | ret.dec_salt.copy_from_slice(dec_iv); |
142 | Box::new(ret) |
143 | } |
144 | |
145 | fn encrypter( |
146 | &self, |
147 | enc_key: AeadKey, |
148 | write_iv: &[u8], |
149 | explicit: &[u8], |
150 | ) -> Box<dyn MessageEncrypter> { |
151 | let enc_key = |
152 | aead::LessSafeKey::new(aead::UnboundKey::new(self.0, enc_key.as_ref()).unwrap()); |
153 | let iv = gcm_iv(write_iv, explicit); |
154 | Box::new(GcmMessageEncrypter { enc_key, iv }) |
155 | } |
156 | |
157 | fn key_block_shape(&self) -> KeyBlockShape { |
158 | KeyBlockShape { |
159 | enc_key_len: self.0.key_len(), |
160 | fixed_iv_len: 4, |
161 | explicit_nonce_len: 8, |
162 | } |
163 | } |
164 | |
165 | fn extract_keys( |
166 | &self, |
167 | key: AeadKey, |
168 | write_iv: &[u8], |
169 | explicit: &[u8], |
170 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { |
171 | Ok(ConnectionTrafficSecrets::Aes128Gcm { |
172 | key, |
173 | iv: gcm_iv(write_iv, explicit), |
174 | }) |
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 | |
224 | /// A `MessageEncrypter` for AES-GCM AEAD ciphersuites. TLS 1.2 only. |
225 | struct GcmMessageEncrypter { |
226 | enc_key: aead::LessSafeKey, |
227 | iv: Iv, |
228 | } |
229 | |
230 | /// A `MessageDecrypter` for AES-GCM AEAD ciphersuites. TLS1.2 only. |
231 | struct GcmMessageDecrypter { |
232 | dec_key: aead::LessSafeKey, |
233 | dec_salt: [u8; 4], |
234 | } |
235 | |
236 | const GCM_EXPLICIT_NONCE_LEN: usize = 8; |
237 | const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16; |
238 | |
239 | impl MessageDecrypter for GcmMessageDecrypter { |
240 | fn decrypt(&mut self, mut msg: OpaqueMessage, seq: u64) -> Result<PlainMessage, Error> { |
241 | let payload = msg.payload(); |
242 | if payload.len() < GCM_OVERHEAD { |
243 | return Err(Error::DecryptError); |
244 | } |
245 | |
246 | let nonce = { |
247 | let mut nonce = [0u8; 12]; |
248 | nonce[..4].copy_from_slice(&self.dec_salt); |
249 | nonce[4..].copy_from_slice(&payload[..8]); |
250 | aead::Nonce::assume_unique_for_key(nonce) |
251 | }; |
252 | |
253 | let aad = aead::Aad::from(make_tls12_aad( |
254 | seq, |
255 | msg.typ, |
256 | msg.version, |
257 | payload.len() - GCM_OVERHEAD, |
258 | )); |
259 | |
260 | let payload = msg.payload_mut(); |
261 | let plain_len = self |
262 | .dec_key |
263 | .open_within(nonce, aad, payload, GCM_EXPLICIT_NONCE_LEN..) |
264 | .map_err(|_| Error::DecryptError)? |
265 | .len(); |
266 | |
267 | if plain_len > MAX_FRAGMENT_LEN { |
268 | return Err(Error::PeerSentOversizedRecord); |
269 | } |
270 | |
271 | payload.truncate(plain_len); |
272 | Ok(msg.into_plain_message()) |
273 | } |
274 | } |
275 | |
276 | impl MessageEncrypter for GcmMessageEncrypter { |
277 | fn encrypt(&mut self, msg: BorrowedPlainMessage, seq: u64) -> Result<OpaqueMessage, Error> { |
278 | let nonce: Nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); |
279 | let aad: Aad<[u8; 13]> = aead::Aad::from(aad:make_tls12_aad(seq, msg.typ, vers:msg.version, msg.payload.len())); |
280 | |
281 | let total_len: usize = self.encrypted_payload_len(msg.payload.len()); |
282 | let mut payload: Vec = Vec::with_capacity(total_len); |
283 | payload.extend_from_slice(&nonce.as_ref()[4..]); |
284 | payload.extend_from_slice(msg.payload); |
285 | |
286 | self.enc_key |
287 | .seal_in_place_separate_tag(nonce, aad, &mut payload[GCM_EXPLICIT_NONCE_LEN..]) |
288 | .map(|tag| payload.extend(tag.as_ref())) |
289 | .map_err(|_| Error::EncryptError)?; |
290 | |
291 | Ok(OpaqueMessage::new(msg.typ, msg.version, body:payload)) |
292 | } |
293 | |
294 | fn encrypted_payload_len(&self, payload_len: usize) -> usize { |
295 | payload_len + GCM_EXPLICIT_NONCE_LEN + self.enc_key.algorithm().tag_len() |
296 | } |
297 | } |
298 | |
299 | /// The RFC7905/RFC7539 ChaCha20Poly1305 construction. |
300 | /// This implementation does the AAD construction required in TLS1.2. |
301 | /// TLS1.3 uses `TLS13MessageEncrypter`. |
302 | struct ChaCha20Poly1305MessageEncrypter { |
303 | enc_key: aead::LessSafeKey, |
304 | enc_offset: Iv, |
305 | } |
306 | |
307 | /// The RFC7905/RFC7539 ChaCha20Poly1305 construction. |
308 | /// This implementation does the AAD construction required in TLS1.2. |
309 | /// TLS1.3 uses `TLS13MessageDecrypter`. |
310 | struct ChaCha20Poly1305MessageDecrypter { |
311 | dec_key: aead::LessSafeKey, |
312 | dec_offset: Iv, |
313 | } |
314 | |
315 | const CHACHAPOLY1305_OVERHEAD: usize = 16; |
316 | |
317 | impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter { |
318 | fn decrypt(&mut self, mut msg: OpaqueMessage, seq: u64) -> Result<PlainMessage, Error> { |
319 | let payload = msg.payload(); |
320 | |
321 | if payload.len() < CHACHAPOLY1305_OVERHEAD { |
322 | return Err(Error::DecryptError); |
323 | } |
324 | |
325 | let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.dec_offset, seq).0); |
326 | let aad = aead::Aad::from(make_tls12_aad( |
327 | seq, |
328 | msg.typ, |
329 | msg.version, |
330 | payload.len() - CHACHAPOLY1305_OVERHEAD, |
331 | )); |
332 | |
333 | let payload = msg.payload_mut(); |
334 | let plain_len = self |
335 | .dec_key |
336 | .open_in_place(nonce, aad, payload) |
337 | .map_err(|_| Error::DecryptError)? |
338 | .len(); |
339 | |
340 | if plain_len > MAX_FRAGMENT_LEN { |
341 | return Err(Error::PeerSentOversizedRecord); |
342 | } |
343 | |
344 | payload.truncate(plain_len); |
345 | Ok(msg.into_plain_message()) |
346 | } |
347 | } |
348 | |
349 | impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter { |
350 | fn encrypt(&mut self, msg: BorrowedPlainMessage, seq: u64) -> Result<OpaqueMessage, Error> { |
351 | let nonce: Nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.enc_offset, seq).0); |
352 | let aad: Aad<[u8; 13]> = aead::Aad::from(aad:make_tls12_aad(seq, msg.typ, vers:msg.version, msg.payload.len())); |
353 | |
354 | let total_len: usize = self.encrypted_payload_len(msg.payload.len()); |
355 | let mut buf: Vec = Vec::with_capacity(total_len); |
356 | buf.extend_from_slice(msg.payload); |
357 | |
358 | self.enc_key |
359 | .seal_in_place_append_tag(nonce, aad, &mut buf) |
360 | .map_err(|_| Error::EncryptError)?; |
361 | |
362 | Ok(OpaqueMessage::new(msg.typ, msg.version, body:buf)) |
363 | } |
364 | |
365 | fn encrypted_payload_len(&self, payload_len: usize) -> usize { |
366 | payload_len + self.enc_key.algorithm().tag_len() |
367 | } |
368 | } |
369 | |
370 | fn gcm_iv(write_iv: &[u8], explicit: &[u8]) -> Iv { |
371 | debug_assert_eq!(write_iv.len(), 4); |
372 | debug_assert_eq!(explicit.len(), 8); |
373 | |
374 | // The GCM nonce is constructed from a 32-bit 'salt' derived |
375 | // from the master-secret, and a 64-bit explicit part, |
376 | // with no specified construction. Thanks for that. |
377 | // |
378 | // We use the same construction as TLS1.3/ChaCha20Poly1305: |
379 | // a starting point extracted from the key block, xored with |
380 | // the sequence number. |
381 | let mut iv: [u8; 12] = [0; NONCE_LEN]; |
382 | iv[..4].copy_from_slice(src:write_iv); |
383 | iv[4..].copy_from_slice(src:explicit); |
384 | |
385 | Iv::new(iv) |
386 | } |
387 | |