rustls/
tls12.rs

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