rustls/tls12/
mod.rs

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| 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.debug_struct("Tls12CipherSuite")
82            .field("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) => seed.as_ref(),
301            // randoms is a fixed, non-zero length array.
302            Self::Randoms(randoms) => randoms.as_ref(),
303        }
304    }
305}
306
307fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] {
308    let mut randoms = [0u8; 64];
309    randoms[..32].copy_from_slice(first);
310    randoms[32..].copy_from_slice(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::init(kx_params);
321    let ecdh_params = T::read(&mut rd)?;
322    match rd.any_left() {
323        false => Ok(ecdh_params),
324        true => Err(common.send_fatal_alert(
325            AlertDescription::DecodeError,
326            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::msgs::handshake::{ClientEcdhParams, ServerEcdhParams};
337    use crate::test_provider::kx_group::X25519;
338
339    #[test]
340    fn server_ecdhe_remaining_bytes() {
341        let key = X25519.start().unwrap();
342        let server_params = ServerEcdhParams::new(&*key);
343        let mut server_buf = Vec::new();
344        server_params.encode(&mut server_buf);
345        server_buf.push(34);
346
347        let mut common = CommonState::new(Side::Client);
348        assert!(decode_ecdh_params::<ServerEcdhParams>(&mut common, &server_buf).is_err());
349    }
350
351    #[test]
352    fn client_ecdhe_invalid() {
353        let mut common = CommonState::new(Side::Server);
354        assert!(decode_ecdh_params::<ClientEcdhParams>(&mut common, &[34]).is_err());
355    }
356}