portable_rustls/tls12/
mod.rs

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