1 | use alloc::boxed::Box; |
2 | |
3 | use super::ring_like::hkdf::KeyType; |
4 | use super::ring_like::{aead, hkdf, hmac}; |
5 | use crate::crypto; |
6 | use crate::crypto::cipher::{ |
7 | AeadKey, InboundOpaqueMessage, Iv, MessageDecrypter, MessageEncrypter, Nonce, |
8 | Tls13AeadAlgorithm, UnsupportedOperationError, make_tls13_aad, |
9 | }; |
10 | use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock, OutputLengthError}; |
11 | use crate::enums::{CipherSuite, ContentType, ProtocolVersion}; |
12 | use crate::error::Error; |
13 | use crate::msgs::message::{ |
14 | InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload, |
15 | }; |
16 | use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite}; |
17 | use crate::tls13::Tls13CipherSuite; |
18 | |
19 | /// The TLS1.3 ciphersuite TLS_CHACHA20_POLY1305_SHA256 |
20 | pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = |
21 | SupportedCipherSuite::Tls13(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); |
22 | |
23 | pub(crate) static TLS13_CHACHA20_POLY1305_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { |
24 | common: CipherSuiteCommon { |
25 | suite: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, |
26 | hash_provider: &super::hash::SHA256, |
27 | // ref: <https://www.ietf.org/archive/id/draft-irtf-cfrg-aead-limits-08.html#section-5.2.1> |
28 | confidentiality_limit: u64::MAX, |
29 | }, |
30 | hkdf_provider: &RingHkdf(hkdf::HKDF_SHA256, hmac::HMAC_SHA256), |
31 | aead_alg: &Chacha20Poly1305Aead(AeadAlgorithm(&aead::CHACHA20_POLY1305)), |
32 | quic: Some(&super::quic::KeyBuilder { |
33 | packet_alg: &aead::CHACHA20_POLY1305, |
34 | header_alg: &aead::quic::CHACHA20, |
35 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-6.6> |
36 | confidentiality_limit: u64::MAX, |
37 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-6.6> |
38 | integrity_limit: 1 << 36, |
39 | }), |
40 | }; |
41 | |
42 | /// The TLS1.3 ciphersuite TLS_AES_256_GCM_SHA384 |
43 | pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = |
44 | SupportedCipherSuite::Tls13(&Tls13CipherSuite { |
45 | common: CipherSuiteCommon { |
46 | suite: CipherSuite::TLS13_AES_256_GCM_SHA384, |
47 | hash_provider: &super::hash::SHA384, |
48 | confidentiality_limit: 1 << 24, |
49 | }, |
50 | hkdf_provider: &RingHkdf(hkdf::HKDF_SHA384, hmac::HMAC_SHA384), |
51 | aead_alg: &Aes256GcmAead(AeadAlgorithm(&aead::AES_256_GCM)), |
52 | quic: Some(&super::quic::KeyBuilder { |
53 | packet_alg: &aead::AES_256_GCM, |
54 | header_alg: &aead::quic::AES_256, |
55 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.1> |
56 | confidentiality_limit: 1 << 23, |
57 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.2> |
58 | integrity_limit: 1 << 52, |
59 | }), |
60 | }); |
61 | |
62 | /// The TLS1.3 ciphersuite TLS_AES_128_GCM_SHA256 |
63 | pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite = |
64 | SupportedCipherSuite::Tls13(TLS13_AES_128_GCM_SHA256_INTERNAL); |
65 | |
66 | pub(crate) static TLS13_AES_128_GCM_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { |
67 | common: CipherSuiteCommon { |
68 | suite: CipherSuite::TLS13_AES_128_GCM_SHA256, |
69 | hash_provider: &super::hash::SHA256, |
70 | confidentiality_limit: 1 << 24, |
71 | }, |
72 | hkdf_provider: &RingHkdf(hkdf::HKDF_SHA256, hmac::HMAC_SHA256), |
73 | aead_alg: &Aes128GcmAead(AeadAlgorithm(&aead::AES_128_GCM)), |
74 | quic: Some(&super::quic::KeyBuilder { |
75 | packet_alg: &aead::AES_128_GCM, |
76 | header_alg: &aead::quic::AES_128, |
77 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.1> |
78 | confidentiality_limit: 1 << 23, |
79 | // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.2> |
80 | integrity_limit: 1 << 52, |
81 | }), |
82 | }; |
83 | |
84 | struct Chacha20Poly1305Aead(AeadAlgorithm); |
85 | |
86 | impl Tls13AeadAlgorithm for Chacha20Poly1305Aead { |
87 | fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { |
88 | self.0.encrypter(key, iv) |
89 | } |
90 | |
91 | fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { |
92 | self.0.decrypter(key, iv) |
93 | } |
94 | |
95 | fn key_len(&self) -> usize { |
96 | self.0.key_len() |
97 | } |
98 | |
99 | fn extract_keys( |
100 | &self, |
101 | key: AeadKey, |
102 | iv: Iv, |
103 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { |
104 | Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv }) |
105 | } |
106 | |
107 | fn fips(&self) -> bool { |
108 | false // chacha20poly1305 not FIPS approved |
109 | } |
110 | } |
111 | |
112 | struct Aes256GcmAead(AeadAlgorithm); |
113 | |
114 | impl Tls13AeadAlgorithm for Aes256GcmAead { |
115 | fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { |
116 | self.0.encrypter(key, iv) |
117 | } |
118 | |
119 | fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { |
120 | self.0.decrypter(key, iv) |
121 | } |
122 | |
123 | fn key_len(&self) -> usize { |
124 | self.0.key_len() |
125 | } |
126 | |
127 | fn extract_keys( |
128 | &self, |
129 | key: AeadKey, |
130 | iv: Iv, |
131 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { |
132 | Ok(ConnectionTrafficSecrets::Aes256Gcm { key, iv }) |
133 | } |
134 | |
135 | fn fips(&self) -> bool { |
136 | super::fips() |
137 | } |
138 | } |
139 | |
140 | struct Aes128GcmAead(AeadAlgorithm); |
141 | |
142 | impl Tls13AeadAlgorithm for Aes128GcmAead { |
143 | fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { |
144 | self.0.encrypter(key, iv) |
145 | } |
146 | |
147 | fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { |
148 | self.0.decrypter(key, iv) |
149 | } |
150 | |
151 | fn key_len(&self) -> usize { |
152 | self.0.key_len() |
153 | } |
154 | |
155 | fn extract_keys( |
156 | &self, |
157 | key: AeadKey, |
158 | iv: Iv, |
159 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { |
160 | Ok(ConnectionTrafficSecrets::Aes128Gcm { key, iv }) |
161 | } |
162 | |
163 | fn fips(&self) -> bool { |
164 | super::fips() |
165 | } |
166 | } |
167 | |
168 | // common encrypter/decrypter/key_len items for above Tls13AeadAlgorithm impls |
169 | struct AeadAlgorithm(&'static aead::Algorithm); |
170 | |
171 | impl AeadAlgorithm { |
172 | fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { |
173 | // safety: the caller arranges that `key` is `key_len()` in bytes, so this unwrap is safe. |
174 | Box::new(Tls13MessageEncrypter { |
175 | enc_key: aead::LessSafeKey::new(key:aead::UnboundKey::new(self.0, key.as_ref()).unwrap()), |
176 | iv, |
177 | }) |
178 | } |
179 | |
180 | fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { |
181 | // safety: the caller arranges that `key` is `key_len()` in bytes, so this unwrap is safe. |
182 | Box::new(Tls13MessageDecrypter { |
183 | dec_key: aead::LessSafeKey::new(key:aead::UnboundKey::new(self.0, key.as_ref()).unwrap()), |
184 | iv, |
185 | }) |
186 | } |
187 | |
188 | fn key_len(&self) -> usize { |
189 | self.0.key_len() |
190 | } |
191 | } |
192 | |
193 | struct Tls13MessageEncrypter { |
194 | enc_key: aead::LessSafeKey, |
195 | iv: Iv, |
196 | } |
197 | |
198 | struct Tls13MessageDecrypter { |
199 | dec_key: aead::LessSafeKey, |
200 | iv: Iv, |
201 | } |
202 | |
203 | impl MessageEncrypter for Tls13MessageEncrypter { |
204 | fn encrypt( |
205 | &mut self, |
206 | msg: OutboundPlainMessage<'_>, |
207 | seq: u64, |
208 | ) -> Result<OutboundOpaqueMessage, Error> { |
209 | let total_len = self.encrypted_payload_len(msg.payload.len()); |
210 | let mut payload = PrefixedPayload::with_capacity(total_len); |
211 | |
212 | let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); |
213 | let aad = aead::Aad::from(make_tls13_aad(total_len)); |
214 | payload.extend_from_chunks(&msg.payload); |
215 | payload.extend_from_slice(&msg.typ.to_array()); |
216 | |
217 | self.enc_key |
218 | .seal_in_place_append_tag(nonce, aad, &mut payload) |
219 | .map_err(|_| Error::EncryptError)?; |
220 | |
221 | Ok(OutboundOpaqueMessage::new( |
222 | ContentType::ApplicationData, |
223 | // Note: all TLS 1.3 application data records use TLSv1_2 (0x0303) as the legacy record |
224 | // protocol version, see https://www.rfc-editor.org/rfc/rfc8446#section-5.1 |
225 | ProtocolVersion::TLSv1_2, |
226 | payload, |
227 | )) |
228 | } |
229 | |
230 | fn encrypted_payload_len(&self, payload_len: usize) -> usize { |
231 | payload_len + 1 + self.enc_key.algorithm().tag_len() |
232 | } |
233 | } |
234 | |
235 | impl MessageDecrypter for Tls13MessageDecrypter { |
236 | fn decrypt<'a>( |
237 | &mut self, |
238 | mut msg: InboundOpaqueMessage<'a>, |
239 | seq: u64, |
240 | ) -> Result<InboundPlainMessage<'a>, Error> { |
241 | let payload: &mut BorrowedPayload<'a> = &mut msg.payload; |
242 | if payload.len() < self.dec_key.algorithm().tag_len() { |
243 | return Err(Error::DecryptError); |
244 | } |
245 | |
246 | let nonce: Nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); |
247 | let aad: Aad<[u8; 5]> = aead::Aad::from(make_tls13_aad(payload.len())); |
248 | let plain_len: usize = self |
249 | .dec_key |
250 | .open_in_place(nonce, aad, payload) |
251 | .map_err(|_| Error::DecryptError)? |
252 | .len(); |
253 | |
254 | payload.truncate(plain_len); |
255 | msg.into_tls13_unpadded_message() |
256 | } |
257 | } |
258 | |
259 | struct RingHkdf(hkdf::Algorithm, hmac::Algorithm); |
260 | |
261 | impl Hkdf for RingHkdf { |
262 | fn extract_from_zero_ikm(&self, salt: Option<&[u8]>) -> Box<dyn HkdfExpander> { |
263 | let zeroes = [0u8; OkmBlock::MAX_LEN]; |
264 | let salt = match salt { |
265 | Some(salt) => salt, |
266 | None => &zeroes[..self.0.len()], |
267 | }; |
268 | Box::new(RingHkdfExpander { |
269 | alg: self.0, |
270 | prk: hkdf::Salt::new(self.0, salt).extract(&zeroes[..self.0.len()]), |
271 | }) |
272 | } |
273 | |
274 | fn extract_from_secret(&self, salt: Option<&[u8]>, secret: &[u8]) -> Box<dyn HkdfExpander> { |
275 | let zeroes = [0u8; OkmBlock::MAX_LEN]; |
276 | let salt = match salt { |
277 | Some(salt) => salt, |
278 | None => &zeroes[..self.0.len()], |
279 | }; |
280 | Box::new(RingHkdfExpander { |
281 | alg: self.0, |
282 | prk: hkdf::Salt::new(self.0, salt).extract(secret), |
283 | }) |
284 | } |
285 | |
286 | fn expander_for_okm(&self, okm: &OkmBlock) -> Box<dyn HkdfExpander> { |
287 | Box::new(RingHkdfExpander { |
288 | alg: self.0, |
289 | prk: hkdf::Prk::new_less_safe(self.0, okm.as_ref()), |
290 | }) |
291 | } |
292 | |
293 | fn hmac_sign(&self, key: &OkmBlock, message: &[u8]) -> crypto::hmac::Tag { |
294 | crypto::hmac::Tag::new(hmac::sign(&hmac::Key::new(self.1, key.as_ref()), message).as_ref()) |
295 | } |
296 | |
297 | fn fips(&self) -> bool { |
298 | super::fips() |
299 | } |
300 | } |
301 | |
302 | struct RingHkdfExpander { |
303 | alg: hkdf::Algorithm, |
304 | prk: hkdf::Prk, |
305 | } |
306 | |
307 | impl HkdfExpander for RingHkdfExpander { |
308 | fn expand_slice(&self, info: &[&[u8]], output: &mut [u8]) -> Result<(), OutputLengthError> { |
309 | self.prk |
310 | .expand(info, Len(output.len())) |
311 | .and_then(|okm| okm.fill(output)) |
312 | .map_err(|_| OutputLengthError) |
313 | } |
314 | |
315 | fn expand_block(&self, info: &[&[u8]]) -> OkmBlock { |
316 | let mut buf: [u8; 64] = [0u8; OkmBlock::MAX_LEN]; |
317 | let output: &mut [u8] = &mut buf[..self.hash_len()]; |
318 | self.prk |
319 | .expand(info, Len(output.len())) |
320 | .and_then(|okm: Okm<'_, Len>| okm.fill(out:output)) |
321 | .unwrap(); |
322 | OkmBlock::new(bytes:output) |
323 | } |
324 | |
325 | fn hash_len(&self) -> usize { |
326 | self.alg.len() |
327 | } |
328 | } |
329 | |
330 | struct Len(usize); |
331 | |
332 | impl KeyType for Len { |
333 | fn len(&self) -> usize { |
334 | self.0 |
335 | } |
336 | } |
337 | |