1 | use alloc::boxed::Box; |
2 | use alloc::string::ToString; |
3 | use core::fmt; |
4 | use std::error::Error as StdError; |
5 | |
6 | use crate::enums::{ContentType, ProtocolVersion}; |
7 | use crate::error::Error; |
8 | use crate::msgs::codec; |
9 | pub use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; |
10 | use crate::suites::ConnectionTrafficSecrets; |
11 | |
12 | use zeroize::Zeroize; |
13 | |
14 | /// Factory trait for building `MessageEncrypter` and `MessageDecrypter` for a TLS1.3 cipher suite. |
15 | pub trait Tls13AeadAlgorithm: Send + Sync { |
16 | /// Build a `MessageEncrypter` for the given key/iv. |
17 | fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter>; |
18 | |
19 | /// Build a `MessageDecrypter` for the given key/iv. |
20 | fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter>; |
21 | |
22 | /// The length of key in bytes required by `encrypter()` and `decrypter()`. |
23 | fn key_len(&self) -> usize; |
24 | |
25 | /// Convert the key material from `key`/`iv`, into a `ConnectionTrafficSecrets` item. |
26 | /// |
27 | /// May return [`UnsupportedOperationError`] if the AEAD algorithm is not a supported |
28 | /// variant of `ConnectionTrafficSecrets`. |
29 | fn extract_keys( |
30 | &self, |
31 | key: AeadKey, |
32 | iv: Iv, |
33 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError>; |
34 | } |
35 | |
36 | /// Factory trait for building `MessageEncrypter` and `MessageDecrypter` for a TLS1.2 cipher suite. |
37 | pub trait Tls12AeadAlgorithm: Send + Sync + 'static { |
38 | /// Build a `MessageEncrypter` for the given key/iv and extra key block (which can be used for |
39 | /// improving explicit nonce size security, if needed). |
40 | /// |
41 | /// The length of `key` is set by [`KeyBlockShape::enc_key_len`]. |
42 | /// |
43 | /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`]. |
44 | /// |
45 | /// The length of `extra` is set by [`KeyBlockShape::explicit_nonce_len`]. |
46 | fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box<dyn MessageEncrypter>; |
47 | |
48 | /// Build a `MessageDecrypter` for the given key/iv. |
49 | /// |
50 | /// The length of `key` is set by [`KeyBlockShape::enc_key_len`]. |
51 | /// |
52 | /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`]. |
53 | fn decrypter(&self, key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter>; |
54 | |
55 | /// Return a `KeyBlockShape` that defines how large the `key_block` is and how it |
56 | /// is split up prior to calling `encrypter()`, `decrypter()` and/or `extract_keys()`. |
57 | fn key_block_shape(&self) -> KeyBlockShape; |
58 | |
59 | /// Convert the key material from `key`/`iv`, into a `ConnectionTrafficSecrets` item. |
60 | /// |
61 | /// The length of `key` is set by [`KeyBlockShape::enc_key_len`]. |
62 | /// |
63 | /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`]. |
64 | /// |
65 | /// The length of `extra` is set by [`KeyBlockShape::explicit_nonce_len`]. |
66 | /// |
67 | /// May return [`UnsupportedOperationError`] if the AEAD algorithm is not a supported |
68 | /// variant of `ConnectionTrafficSecrets`. |
69 | fn extract_keys( |
70 | &self, |
71 | key: AeadKey, |
72 | iv: &[u8], |
73 | explicit: &[u8], |
74 | ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError>; |
75 | } |
76 | |
77 | /// An error indicating that the AEAD algorithm does not support the requested operation. |
78 | #[derive (Debug, Eq, PartialEq, Clone, Copy)] |
79 | pub struct UnsupportedOperationError; |
80 | |
81 | impl From<UnsupportedOperationError> for Error { |
82 | fn from(value: UnsupportedOperationError) -> Self { |
83 | Self::General(value.to_string()) |
84 | } |
85 | } |
86 | |
87 | impl fmt::Display for UnsupportedOperationError { |
88 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
89 | write!(f, "operation not supported" ) |
90 | } |
91 | } |
92 | |
93 | impl StdError for UnsupportedOperationError {} |
94 | |
95 | /// How a TLS1.2 `key_block` is partitioned. |
96 | /// |
97 | /// Note: ciphersuites with non-zero `mac_key_length` are not currently supported. |
98 | pub struct KeyBlockShape { |
99 | /// How long keys are. |
100 | /// |
101 | /// `enc_key_length` terminology is from the standard ([RFC5246 A.6]). |
102 | /// |
103 | /// [RFC5246 A.6]: <https://www.rfc-editor.org/rfc/rfc5246#appendix-A.6> |
104 | pub enc_key_len: usize, |
105 | |
106 | /// How long the fixed part of the 'IV' is. |
107 | /// |
108 | /// `fixed_iv_length` terminology is from the standard ([RFC5246 A.6]). |
109 | /// |
110 | /// This isn't usually an IV, but we continue the |
111 | /// terminology misuse to match the standard. |
112 | /// |
113 | /// [RFC5246 A.6]: <https://www.rfc-editor.org/rfc/rfc5246#appendix-A.6> |
114 | pub fixed_iv_len: usize, |
115 | |
116 | /// This is a non-standard extension which extends the |
117 | /// key block to provide an initial explicit nonce offset, |
118 | /// in a deterministic and safe way. GCM needs this, |
119 | /// chacha20poly1305 works this way by design. |
120 | pub explicit_nonce_len: usize, |
121 | } |
122 | |
123 | /// Objects with this trait can decrypt TLS messages. |
124 | pub trait MessageDecrypter: Send + Sync { |
125 | /// Decrypt the given TLS message `msg`, using the sequence number |
126 | /// `seq` which can be used to derive a unique [`Nonce`]. |
127 | fn decrypt(&mut self, msg: OpaqueMessage, seq: u64) -> Result<PlainMessage, Error>; |
128 | } |
129 | |
130 | /// Objects with this trait can encrypt TLS messages. |
131 | pub trait MessageEncrypter: Send + Sync { |
132 | /// Encrypt the given TLS message `msg`, using the sequence number |
133 | /// `seq which can be used to derive a unique [`Nonce`]. |
134 | fn encrypt(&mut self, msg: BorrowedPlainMessage, seq: u64) -> Result<OpaqueMessage, Error>; |
135 | |
136 | /// Return the length of the ciphertext that results from encrypting plaintext of |
137 | /// length `payload_len` |
138 | fn encrypted_payload_len(&self, payload_len: usize) -> usize; |
139 | } |
140 | |
141 | impl dyn MessageEncrypter { |
142 | pub(crate) fn invalid() -> Box<dyn MessageEncrypter> { |
143 | Box::new(InvalidMessageEncrypter {}) |
144 | } |
145 | } |
146 | |
147 | impl dyn MessageDecrypter { |
148 | pub(crate) fn invalid() -> Box<dyn MessageDecrypter> { |
149 | Box::new(InvalidMessageDecrypter {}) |
150 | } |
151 | } |
152 | |
153 | /// A write or read IV. |
154 | #[derive (Default)] |
155 | pub struct Iv([u8; NONCE_LEN]); |
156 | |
157 | impl Iv { |
158 | /// Create a new `Iv` from a byte array, of precisely `NONCE_LEN` bytes. |
159 | #[cfg (feature = "tls12" )] |
160 | pub fn new(value: [u8; NONCE_LEN]) -> Self { |
161 | Self(value) |
162 | } |
163 | |
164 | /// Create a new `Iv` from a byte slice, of precisely `NONCE_LEN` bytes. |
165 | #[cfg (feature = "tls12" )] |
166 | pub fn copy(value: &[u8]) -> Self { |
167 | debug_assert_eq!(value.len(), NONCE_LEN); |
168 | let mut iv: Iv = Self::new(Default::default()); |
169 | iv.0.copy_from_slice(src:value); |
170 | iv |
171 | } |
172 | } |
173 | |
174 | impl From<[u8; NONCE_LEN]> for Iv { |
175 | fn from(bytes: [u8; NONCE_LEN]) -> Self { |
176 | Self(bytes) |
177 | } |
178 | } |
179 | |
180 | impl AsRef<[u8]> for Iv { |
181 | fn as_ref(&self) -> &[u8] { |
182 | self.0.as_ref() |
183 | } |
184 | } |
185 | |
186 | /// A nonce. This is unique for all messages on a connection. |
187 | pub struct Nonce(pub [u8; NONCE_LEN]); |
188 | |
189 | impl Nonce { |
190 | /// Combine an `Iv` and sequence number to produce a unique nonce. |
191 | /// |
192 | /// This is `iv ^ seq` where `seq` is encoded as a 96-bit big-endian integer. |
193 | #[inline ] |
194 | pub fn new(iv: &Iv, seq: u64) -> Self { |
195 | let mut nonce: Nonce = Self([0u8; NONCE_LEN]); |
196 | codec::put_u64(v:seq, &mut nonce.0[4..]); |
197 | |
198 | nonceimpl Iterator |
199 | .0 |
200 | .iter_mut() |
201 | .zip(iv.0.iter()) |
202 | .for_each(|(nonce: &mut u8, iv: &u8)| { |
203 | *nonce ^= *iv; |
204 | }); |
205 | |
206 | nonce |
207 | } |
208 | } |
209 | |
210 | /// Size of TLS nonces (incorrectly termed "IV" in standard) for all supported ciphersuites |
211 | /// (AES-GCM, Chacha20Poly1305) |
212 | pub const NONCE_LEN: usize = 12; |
213 | |
214 | /// Returns a TLS1.3 `additional_data` encoding. |
215 | /// |
216 | /// See RFC8446 s5.2 for the `additional_data` definition. |
217 | #[inline ] |
218 | pub fn make_tls13_aad(payload_len: usize) -> [u8; 5] { |
219 | [ |
220 | ContentType::ApplicationData.get_u8(), |
221 | // Note: this is `legacy_record_version`, i.e. TLS1.2 even for TLS1.3. |
222 | (ProtocolVersion::TLSv1_2.get_u16() >> 8) as u8, |
223 | (ProtocolVersion::TLSv1_2.get_u16() & 0xff) as u8, |
224 | (payload_len >> 8) as u8, |
225 | (payload_len & 0xff) as u8, |
226 | ] |
227 | } |
228 | |
229 | /// Returns a TLS1.2 `additional_data` encoding. |
230 | /// |
231 | /// See RFC5246 s6.2.3.3 for the `additional_data` definition. |
232 | #[inline ] |
233 | pub fn make_tls12_aad( |
234 | seq: u64, |
235 | typ: ContentType, |
236 | vers: ProtocolVersion, |
237 | len: usize, |
238 | ) -> [u8; TLS12_AAD_SIZE] { |
239 | let mut out: [u8; 13] = [0; TLS12_AAD_SIZE]; |
240 | codec::put_u64(v:seq, &mut out[0..]); |
241 | out[8] = typ.get_u8(); |
242 | codec::put_u16(v:vers.get_u16(), &mut out[9..]); |
243 | codec::put_u16(v:len as u16, &mut out[11..]); |
244 | out |
245 | } |
246 | |
247 | const TLS12_AAD_SIZE: usize = 8 + 1 + 2 + 2; |
248 | |
249 | /// A key for an AEAD algorithm. |
250 | /// |
251 | /// This is a value type for a byte string up to `AeadKey::MAX_LEN` bytes in length. |
252 | pub struct AeadKey { |
253 | buf: [u8; Self::MAX_LEN], |
254 | used: usize, |
255 | } |
256 | |
257 | impl AeadKey { |
258 | #[cfg (feature = "tls12" )] |
259 | pub(crate) fn new(buf: &[u8]) -> Self { |
260 | debug_assert!(buf.len() <= Self::MAX_LEN); |
261 | let mut key: AeadKey = Self::from([0u8; Self::MAX_LEN]); |
262 | key.buf[..buf.len()].copy_from_slice(src:buf); |
263 | key.used = buf.len(); |
264 | key |
265 | } |
266 | |
267 | pub(crate) fn with_length(self, len: usize) -> Self { |
268 | assert!(len <= self.used); |
269 | Self { |
270 | buf: self.buf, |
271 | used: len, |
272 | } |
273 | } |
274 | |
275 | /// Largest possible AEAD key in the ciphersuites we support. |
276 | pub(crate) const MAX_LEN: usize = 32; |
277 | } |
278 | |
279 | impl Drop for AeadKey { |
280 | fn drop(&mut self) { |
281 | self.buf.zeroize(); |
282 | } |
283 | } |
284 | |
285 | impl AsRef<[u8]> for AeadKey { |
286 | fn as_ref(&self) -> &[u8] { |
287 | &self.buf[..self.used] |
288 | } |
289 | } |
290 | |
291 | impl From<[u8; Self::MAX_LEN]> for AeadKey { |
292 | fn from(bytes: [u8; Self::MAX_LEN]) -> Self { |
293 | Self { |
294 | buf: bytes, |
295 | used: Self::MAX_LEN, |
296 | } |
297 | } |
298 | } |
299 | |
300 | /// A `MessageEncrypter` which doesn't work. |
301 | struct InvalidMessageEncrypter {} |
302 | |
303 | impl MessageEncrypter for InvalidMessageEncrypter { |
304 | fn encrypt(&mut self, _m: BorrowedPlainMessage, _seq: u64) -> Result<OpaqueMessage, Error> { |
305 | Err(Error::EncryptError) |
306 | } |
307 | |
308 | fn encrypted_payload_len(&self, payload_len: usize) -> usize { |
309 | payload_len |
310 | } |
311 | } |
312 | |
313 | /// A `MessageDecrypter` which doesn't work. |
314 | struct InvalidMessageDecrypter {} |
315 | |
316 | impl MessageDecrypter for InvalidMessageDecrypter { |
317 | fn decrypt(&mut self, _m: OpaqueMessage, _seq: u64) -> Result<PlainMessage, Error> { |
318 | Err(Error::DecryptError) |
319 | } |
320 | } |
321 | |