1use alloc::boxed::Box;
2use alloc::vec;
3use alloc::vec::Vec;
4use core::fmt;
5
6use zeroize::Zeroize;
7
8use crate::common_state::{CommonState, Side};
9use crate::conn::ConnectionRandoms;
10use crate::crypto;
11use crate::crypto::cipher::{AeadKey, MessageDecrypter, MessageEncrypter, Tls12AeadAlgorithm};
12use crate::crypto::hash;
13use crate::enums::{AlertDescription, SignatureScheme};
14use crate::error::{Error, InvalidMessage};
15use crate::msgs::codec::{Codec, Reader};
16use crate::msgs::handshake::{KeyExchangeAlgorithm, KxDecode};
17use crate::suites::{CipherSuiteCommon, PartiallyExtractedSecrets, SupportedCipherSuite};
18
19/// A TLS 1.2 cipher suite supported by rustls.
20pub struct Tls12CipherSuite {
21 /// Common cipher suite fields.
22 pub common: CipherSuiteCommon,
23
24 /// How to compute the TLS1.2 PRF for the suite's hash function.
25 ///
26 /// If you have a TLS1.2 PRF implementation, you should directly implement the [`crypto::tls12::Prf`] trait.
27 ///
28 /// If not, you can implement the [`crypto::hmac::Hmac`] trait (and associated), and then use
29 /// [`crypto::tls12::PrfUsingHmac`].
30 pub prf_provider: &'static dyn crypto::tls12::Prf,
31
32 /// How to exchange/agree keys.
33 ///
34 /// In TLS1.2, the key exchange method (eg, Elliptic Curve Diffie-Hellman with Ephemeral keys -- ECDHE)
35 /// is baked into the cipher suite, but the details to achieve it are negotiated separately.
36 ///
37 /// This controls how protocol messages (like the `ClientKeyExchange` message) are interpreted
38 /// once this cipher suite has been negotiated.
39 pub kx: KeyExchangeAlgorithm,
40
41 /// How to sign messages for authentication.
42 ///
43 /// This is a set of [`SignatureScheme`]s that are usable once this cipher suite has been
44 /// negotiated.
45 ///
46 /// The precise scheme used is then chosen from this set by the selected authentication key.
47 pub sign: &'static [SignatureScheme],
48
49 /// How to produce a [`MessageDecrypter`] or [`MessageEncrypter`]
50 /// from raw key material.
51 pub aead_alg: &'static dyn Tls12AeadAlgorithm,
52}
53
54impl Tls12CipherSuite {
55 /// Resolve the set of supported [`SignatureScheme`]s from the
56 /// offered signature schemes. If we return an empty
57 /// set, the handshake terminates.
58 pub fn resolve_sig_schemes(&self, offered: &[SignatureScheme]) -> Vec<SignatureScheme> {
59 self.sign
60 .iter()
61 .filter(|pref: &&SignatureScheme| offered.contains(pref))
62 .cloned()
63 .collect()
64 }
65
66 /// Return `true` if this is backed by a FIPS-approved implementation.
67 ///
68 /// This means all the constituent parts that do cryptography return `true` for `fips()`.
69 pub fn fips(&self) -> bool {
70 self.common.fips() && self.prf_provider.fips() && self.aead_alg.fips()
71 }
72}
73
74impl From<&'static Tls12CipherSuite> for SupportedCipherSuite {
75 fn from(s: &'static Tls12CipherSuite) -> Self {
76 Self::Tls12(s)
77 }
78}
79
80impl PartialEq for Tls12CipherSuite {
81 fn eq(&self, other: &Self) -> bool {
82 self.common.suite == other.common.suite
83 }
84}
85
86impl fmt::Debug for Tls12CipherSuite {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 f&mut DebugStruct<'_, '_>.debug_struct("Tls12CipherSuite")
89 .field(name:"suite", &self.common.suite)
90 .finish()
91 }
92}
93
94/// TLS1.2 per-connection keying material
95pub(crate) struct ConnectionSecrets {
96 pub(crate) randoms: ConnectionRandoms,
97 suite: &'static Tls12CipherSuite,
98 pub(crate) master_secret: [u8; 48],
99}
100
101impl ConnectionSecrets {
102 pub(crate) fn from_key_exchange(
103 kx: Box<dyn crypto::ActiveKeyExchange>,
104 peer_pub_key: &[u8],
105 ems_seed: Option<hash::Output>,
106 randoms: ConnectionRandoms,
107 suite: &'static Tls12CipherSuite,
108 ) -> Result<Self, Error> {
109 let mut ret = Self {
110 randoms,
111 suite,
112 master_secret: [0u8; 48],
113 };
114
115 let (label, seed) = match ems_seed {
116 Some(seed) => ("extended master secret", Seed::Ems(seed)),
117 None => (
118 "master secret",
119 Seed::Randoms(join_randoms(&ret.randoms.client, &ret.randoms.server)),
120 ),
121 };
122
123 // The API contract for for_key_exchange is that the caller guarantees `label` and `seed`
124 // slice parameters are non-empty.
125 // `label` is guaranteed non-empty because it's assigned from a `&str` above.
126 // `seed.as_ref()` is guaranteed non-empty by documentation on the AsRef impl.
127 ret.suite
128 .prf_provider
129 .for_key_exchange(
130 &mut ret.master_secret,
131 kx,
132 peer_pub_key,
133 label.as_bytes(),
134 seed.as_ref(),
135 )?;
136
137 Ok(ret)
138 }
139
140 pub(crate) fn new_resume(
141 randoms: ConnectionRandoms,
142 suite: &'static Tls12CipherSuite,
143 master_secret: &[u8],
144 ) -> Self {
145 let mut ret = Self {
146 randoms,
147 suite,
148 master_secret: [0u8; 48],
149 };
150 ret.master_secret
151 .copy_from_slice(master_secret);
152 ret
153 }
154
155 /// Make a `MessageCipherPair` based on the given supported ciphersuite `self.suite`,
156 /// and the session's `secrets`.
157 pub(crate) fn make_cipher_pair(&self, side: Side) -> MessageCipherPair {
158 // Make a key block, and chop it up.
159 // Note: we don't implement any ciphersuites with nonzero mac_key_len.
160 let key_block = self.make_key_block();
161 let shape = self.suite.aead_alg.key_block_shape();
162
163 let (client_write_key, key_block) = key_block.split_at(shape.enc_key_len);
164 let (server_write_key, key_block) = key_block.split_at(shape.enc_key_len);
165 let (client_write_iv, key_block) = key_block.split_at(shape.fixed_iv_len);
166 let (server_write_iv, extra) = key_block.split_at(shape.fixed_iv_len);
167
168 let (write_key, write_iv, read_key, read_iv) = match side {
169 Side::Client => (
170 client_write_key,
171 client_write_iv,
172 server_write_key,
173 server_write_iv,
174 ),
175 Side::Server => (
176 server_write_key,
177 server_write_iv,
178 client_write_key,
179 client_write_iv,
180 ),
181 };
182
183 (
184 self.suite
185 .aead_alg
186 .decrypter(AeadKey::new(read_key), read_iv),
187 self.suite
188 .aead_alg
189 .encrypter(AeadKey::new(write_key), write_iv, extra),
190 )
191 }
192
193 fn make_key_block(&self) -> Vec<u8> {
194 let shape = self.suite.aead_alg.key_block_shape();
195
196 let len = (shape.enc_key_len + shape.fixed_iv_len) * 2 + shape.explicit_nonce_len;
197
198 let mut out = vec![0u8; len];
199
200 // NOTE: opposite order to above for no good reason.
201 // Don't design security protocols on drugs, kids.
202 let randoms = join_randoms(&self.randoms.server, &self.randoms.client);
203 self.suite.prf_provider.for_secret(
204 &mut out,
205 &self.master_secret,
206 b"key expansion",
207 &randoms,
208 );
209
210 out
211 }
212
213 pub(crate) fn suite(&self) -> &'static Tls12CipherSuite {
214 self.suite
215 }
216
217 pub(crate) fn master_secret(&self) -> &[u8] {
218 &self.master_secret[..]
219 }
220
221 fn make_verify_data(&self, handshake_hash: &hash::Output, label: &[u8]) -> Vec<u8> {
222 let mut out = vec![0u8; 12];
223
224 self.suite.prf_provider.for_secret(
225 &mut out,
226 &self.master_secret,
227 label,
228 handshake_hash.as_ref(),
229 );
230
231 out
232 }
233
234 pub(crate) fn client_verify_data(&self, handshake_hash: &hash::Output) -> Vec<u8> {
235 self.make_verify_data(handshake_hash, b"client finished")
236 }
237
238 pub(crate) fn server_verify_data(&self, handshake_hash: &hash::Output) -> Vec<u8> {
239 self.make_verify_data(handshake_hash, b"server finished")
240 }
241
242 pub(crate) fn export_keying_material(
243 &self,
244 output: &mut [u8],
245 label: &[u8],
246 context: Option<&[u8]>,
247 ) {
248 let mut randoms = Vec::new();
249 randoms.extend_from_slice(&self.randoms.client);
250 randoms.extend_from_slice(&self.randoms.server);
251 if let Some(context) = context {
252 assert!(context.len() <= 0xffff);
253 (context.len() as u16).encode(&mut randoms);
254 randoms.extend_from_slice(context);
255 }
256
257 self.suite
258 .prf_provider
259 .for_secret(output, &self.master_secret, label, &randoms);
260 }
261
262 pub(crate) fn extract_secrets(&self, side: Side) -> Result<PartiallyExtractedSecrets, Error> {
263 // Make a key block, and chop it up
264 let key_block = self.make_key_block();
265 let shape = self.suite.aead_alg.key_block_shape();
266
267 let (client_key, key_block) = key_block.split_at(shape.enc_key_len);
268 let (server_key, key_block) = key_block.split_at(shape.enc_key_len);
269 let (client_iv, key_block) = key_block.split_at(shape.fixed_iv_len);
270 let (server_iv, explicit_nonce) = key_block.split_at(shape.fixed_iv_len);
271
272 let client_secrets = self.suite.aead_alg.extract_keys(
273 AeadKey::new(client_key),
274 client_iv,
275 explicit_nonce,
276 )?;
277 let server_secrets = self.suite.aead_alg.extract_keys(
278 AeadKey::new(server_key),
279 server_iv,
280 explicit_nonce,
281 )?;
282
283 let (tx, rx) = match side {
284 Side::Client => (client_secrets, server_secrets),
285 Side::Server => (server_secrets, client_secrets),
286 };
287 Ok(PartiallyExtractedSecrets { tx, rx })
288 }
289}
290
291impl Drop for ConnectionSecrets {
292 fn drop(&mut self) {
293 self.master_secret.zeroize();
294 }
295}
296
297enum Seed {
298 Ems(hash::Output),
299 Randoms([u8; 64]),
300}
301
302impl AsRef<[u8]> for Seed {
303 /// This is guaranteed to return a non-empty slice.
304 fn as_ref(&self) -> &[u8] {
305 match self {
306 // seed is a hash::Output, which is a fixed, non-zero length array.
307 Self::Ems(seed: &Output) => seed.as_ref(),
308 // randoms is a fixed, non-zero length array.
309 Self::Randoms(randoms: &[u8; 64]) => randoms.as_ref(),
310 }
311 }
312}
313
314fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] {
315 let mut randoms: [u8; 64] = [0u8; 64];
316 randoms[..32].copy_from_slice(src:first);
317 randoms[32..].copy_from_slice(src:second);
318 randoms
319}
320
321type MessageCipherPair = (Box<dyn MessageDecrypter>, Box<dyn MessageEncrypter>);
322
323pub(crate) fn decode_kx_params<'a, T: KxDecode<'a>>(
324 kx_algorithm: KeyExchangeAlgorithm,
325 common: &mut CommonState,
326 kx_params: &'a [u8],
327) -> Result<T, Error> {
328 let mut rd: Reader<'_> = Reader::init(bytes:kx_params);
329 let kx_params: T = T::decode(&mut rd, algo:kx_algorithm)?;
330 match rd.any_left() {
331 false => Ok(kx_params),
332 true => Err(common.send_fatal_alert(
333 desc:AlertDescription::DecodeError,
334 err:InvalidMessage::InvalidDhParams,
335 )),
336 }
337}
338
339pub(crate) const DOWNGRADE_SENTINEL: [u8; 8] = [0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01];
340
341#[cfg(test)]
342#[macro_rules_attribute::apply(test_for_each_provider)]
343mod tests {
344 use super::provider::kx_group::X25519;
345 use super::*;
346 use crate::common_state::{CommonState, Side};
347 use crate::msgs::handshake::{ServerEcdhParams, ServerKeyExchangeParams};
348
349 #[test]
350 fn server_ecdhe_remaining_bytes() {
351 let key = X25519.start().unwrap();
352 let server_params = ServerEcdhParams::new(&*key);
353 let mut server_buf = Vec::new();
354 server_params.encode(&mut server_buf);
355 server_buf.push(34);
356
357 let mut common = CommonState::new(Side::Client);
358 assert!(
359 decode_kx_params::<ServerKeyExchangeParams>(
360 KeyExchangeAlgorithm::ECDHE,
361 &mut common,
362 &server_buf
363 )
364 .is_err()
365 );
366 }
367
368 #[test]
369 fn client_ecdhe_invalid() {
370 let mut common = CommonState::new(Side::Server);
371 assert!(
372 decode_kx_params::<ServerKeyExchangeParams>(
373 KeyExchangeAlgorithm::ECDHE,
374 &mut common,
375 &[34],
376 )
377 .is_err()
378 );
379 }
380}
381