1use crate::common_state::{CommonState, Side};
2use crate::conn::ConnectionRandoms;
3use crate::crypto;
4use crate::crypto::cipher::{AeadKey, MessageDecrypter, MessageEncrypter, Tls12AeadAlgorithm};
5use crate::crypto::hash;
6use crate::enums::{AlertDescription, SignatureScheme};
7use crate::error::{Error, InvalidMessage};
8use crate::msgs::codec::{Codec, Reader};
9use crate::msgs::handshake::KeyExchangeAlgorithm;
10use crate::suites::{CipherSuiteCommon, PartiallyExtractedSecrets, SupportedCipherSuite};
11
12use alloc::boxed::Box;
13use alloc::vec;
14use alloc::vec::Vec;
15use core::fmt;
16
17use zeroize::Zeroize;
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
67impl From<&'static Tls12CipherSuite> for SupportedCipherSuite {
68 fn from(s: &'static Tls12CipherSuite) -> Self {
69 Self::Tls12(s)
70 }
71}
72
73impl PartialEq for Tls12CipherSuite {
74 fn eq(&self, other: &Self) -> bool {
75 self.common.suite == other.common.suite
76 }
77}
78
79impl fmt::Debug for Tls12CipherSuite {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 f&mut DebugStruct<'_, '_>.debug_struct("Tls12CipherSuite")
82 .field(name:"suite", &self.common.suite)
83 .finish()
84 }
85}
86
87/// TLS1.2 per-connection keying material
88pub(crate) struct ConnectionSecrets {
89 pub(crate) randoms: ConnectionRandoms,
90 suite: &'static Tls12CipherSuite,
91 pub(crate) master_secret: [u8; 48],
92}
93
94impl ConnectionSecrets {
95 pub(crate) fn from_key_exchange(
96 kx: Box<dyn crypto::ActiveKeyExchange>,
97 peer_pub_key: &[u8],
98 ems_seed: Option<hash::Output>,
99 randoms: ConnectionRandoms,
100 suite: &'static Tls12CipherSuite,
101 ) -> Result<Self, Error> {
102 let mut ret = Self {
103 randoms,
104 suite,
105 master_secret: [0u8; 48],
106 };
107
108 let (label, seed) = match ems_seed {
109 Some(seed) => ("extended master secret", Seed::Ems(seed)),
110 None => (
111 "master secret",
112 Seed::Randoms(join_randoms(&ret.randoms.client, &ret.randoms.server)),
113 ),
114 };
115
116 // The API contract for for_key_exchange is that the caller guarantees `label` and `seed`
117 // slice parameters are non-empty.
118 // `label` is guaranteed non-empty because it's assigned from a `&str` above.
119 // `seed.as_ref()` is guaranteed non-empty by documentation on the AsRef impl.
120 ret.suite
121 .prf_provider
122 .for_key_exchange(
123 &mut ret.master_secret,
124 kx,
125 peer_pub_key,
126 label.as_bytes(),
127 seed.as_ref(),
128 )?;
129
130 Ok(ret)
131 }
132
133 pub(crate) fn new_resume(
134 randoms: ConnectionRandoms,
135 suite: &'static Tls12CipherSuite,
136 master_secret: &[u8],
137 ) -> Self {
138 let mut ret = Self {
139 randoms,
140 suite,
141 master_secret: [0u8; 48],
142 };
143 ret.master_secret
144 .copy_from_slice(master_secret);
145 ret
146 }
147
148 /// Make a `MessageCipherPair` based on the given supported ciphersuite `self.suite`,
149 /// and the session's `secrets`.
150 pub(crate) fn make_cipher_pair(&self, side: Side) -> MessageCipherPair {
151 // Make a key block, and chop it up.
152 // Note: we don't implement any ciphersuites with nonzero mac_key_len.
153 let key_block = self.make_key_block();
154 let shape = self.suite.aead_alg.key_block_shape();
155
156 let (client_write_key, key_block) = key_block.split_at(shape.enc_key_len);
157 let (server_write_key, key_block) = key_block.split_at(shape.enc_key_len);
158 let (client_write_iv, key_block) = key_block.split_at(shape.fixed_iv_len);
159 let (server_write_iv, extra) = key_block.split_at(shape.fixed_iv_len);
160
161 let (write_key, write_iv, read_key, read_iv) = match side {
162 Side::Client => (
163 client_write_key,
164 client_write_iv,
165 server_write_key,
166 server_write_iv,
167 ),
168 Side::Server => (
169 server_write_key,
170 server_write_iv,
171 client_write_key,
172 client_write_iv,
173 ),
174 };
175
176 (
177 self.suite
178 .aead_alg
179 .decrypter(AeadKey::new(read_key), read_iv),
180 self.suite
181 .aead_alg
182 .encrypter(AeadKey::new(write_key), write_iv, extra),
183 )
184 }
185
186 fn make_key_block(&self) -> Vec<u8> {
187 let shape = self.suite.aead_alg.key_block_shape();
188
189 let len = (shape.enc_key_len + shape.fixed_iv_len) * 2 + shape.explicit_nonce_len;
190
191 let mut out = vec![0u8; len];
192
193 // NOTE: opposite order to above for no good reason.
194 // Don't design security protocols on drugs, kids.
195 let randoms = join_randoms(&self.randoms.server, &self.randoms.client);
196 self.suite.prf_provider.for_secret(
197 &mut out,
198 &self.master_secret,
199 b"key expansion",
200 &randoms,
201 );
202
203 out
204 }
205
206 pub(crate) fn suite(&self) -> &'static Tls12CipherSuite {
207 self.suite
208 }
209
210 pub(crate) fn master_secret(&self) -> &[u8] {
211 &self.master_secret[..]
212 }
213
214 fn make_verify_data(&self, handshake_hash: &hash::Output, label: &[u8]) -> Vec<u8> {
215 let mut out = vec![0u8; 12];
216
217 self.suite.prf_provider.for_secret(
218 &mut out,
219 &self.master_secret,
220 label,
221 handshake_hash.as_ref(),
222 );
223
224 out
225 }
226
227 pub(crate) fn client_verify_data(&self, handshake_hash: &hash::Output) -> Vec<u8> {
228 self.make_verify_data(handshake_hash, b"client finished")
229 }
230
231 pub(crate) fn server_verify_data(&self, handshake_hash: &hash::Output) -> Vec<u8> {
232 self.make_verify_data(handshake_hash, b"server finished")
233 }
234
235 pub(crate) fn export_keying_material(
236 &self,
237 output: &mut [u8],
238 label: &[u8],
239 context: Option<&[u8]>,
240 ) {
241 let mut randoms = Vec::new();
242 randoms.extend_from_slice(&self.randoms.client);
243 randoms.extend_from_slice(&self.randoms.server);
244 if let Some(context) = context {
245 assert!(context.len() <= 0xffff);
246 (context.len() as u16).encode(&mut randoms);
247 randoms.extend_from_slice(context);
248 }
249
250 self.suite
251 .prf_provider
252 .for_secret(output, &self.master_secret, label, &randoms);
253 }
254
255 pub(crate) fn extract_secrets(&self, side: Side) -> Result<PartiallyExtractedSecrets, Error> {
256 // Make a key block, and chop it up
257 let key_block = self.make_key_block();
258 let shape = self.suite.aead_alg.key_block_shape();
259
260 let (client_key, key_block) = key_block.split_at(shape.enc_key_len);
261 let (server_key, key_block) = key_block.split_at(shape.enc_key_len);
262 let (client_iv, key_block) = key_block.split_at(shape.fixed_iv_len);
263 let (server_iv, explicit_nonce) = key_block.split_at(shape.fixed_iv_len);
264
265 let client_secrets = self.suite.aead_alg.extract_keys(
266 AeadKey::new(client_key),
267 client_iv,
268 explicit_nonce,
269 )?;
270 let server_secrets = self.suite.aead_alg.extract_keys(
271 AeadKey::new(server_key),
272 server_iv,
273 explicit_nonce,
274 )?;
275
276 let (tx, rx) = match side {
277 Side::Client => (client_secrets, server_secrets),
278 Side::Server => (server_secrets, client_secrets),
279 };
280 Ok(PartiallyExtractedSecrets { tx, rx })
281 }
282}
283
284impl Drop for ConnectionSecrets {
285 fn drop(&mut self) {
286 self.master_secret.zeroize();
287 }
288}
289
290enum Seed {
291 Ems(hash::Output),
292 Randoms([u8; 64]),
293}
294
295impl AsRef<[u8]> for Seed {
296 /// This is guaranteed to return a non-empty slice.
297 fn as_ref(&self) -> &[u8] {
298 match self {
299 // seed is a hash::Output, which is a fixed, non-zero length array.
300 Self::Ems(seed: &Output) => seed.as_ref(),
301 // randoms is a fixed, non-zero length array.
302 Self::Randoms(randoms: &[u8; 64]) => randoms.as_ref(),
303 }
304 }
305}
306
307fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] {
308 let mut randoms: [u8; 64] = [0u8; 64];
309 randoms[..32].copy_from_slice(src:first);
310 randoms[32..].copy_from_slice(src:second);
311 randoms
312}
313
314type MessageCipherPair = (Box<dyn MessageDecrypter>, Box<dyn MessageEncrypter>);
315
316pub(crate) fn decode_ecdh_params<T: Codec>(
317 common: &mut CommonState,
318 kx_params: &[u8],
319) -> Result<T, Error> {
320 let mut rd: Reader<'_> = Reader::init(bytes:kx_params);
321 let ecdh_params: T = T::read(&mut rd)?;
322 match rd.any_left() {
323 false => Ok(ecdh_params),
324 true => Err(common.send_fatal_alert(
325 desc:AlertDescription::DecodeError,
326 err:InvalidMessage::InvalidDhParams,
327 )),
328 }
329}
330
331pub(crate) const DOWNGRADE_SENTINEL: [u8; 8] = [0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01];
332
333#[cfg(all(test, any(feature = "ring", feature = "aws_lc_rs")))]
334mod tests {
335 use super::*;
336 use crate::common_state::{CommonState, Side};
337 use crate::msgs::handshake::{ClientEcdhParams, ServerEcdhParams};
338 use crate::test_provider::kx_group::X25519;
339
340 #[test]
341 fn server_ecdhe_remaining_bytes() {
342 let key = X25519.start().unwrap();
343 let server_params = ServerEcdhParams::new(&*key);
344 let mut server_buf = Vec::new();
345 server_params.encode(&mut server_buf);
346 server_buf.push(34);
347
348 let mut common = CommonState::new(Side::Client);
349 assert!(decode_ecdh_params::<ServerEcdhParams>(&mut common, &server_buf).is_err());
350 }
351
352 #[test]
353 fn client_ecdhe_invalid() {
354 let mut common = CommonState::new(Side::Server);
355 assert!(decode_ecdh_params::<ClientEcdhParams>(&mut common, &[34]).is_err());
356 }
357}
358