Skip to main content

rustls/
tls12.rs

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