rustls/tls12/
mod.rs

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