Coverage Report

Created: 2025-10-31 06:57

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