rustls_fork_shadow_tls/tls12/
mod.rs

1use crate::cipher::{MessageDecrypter, MessageEncrypter};
2use crate::conn::{CommonState, ConnectionRandoms, Side};
3use crate::enums::{CipherSuite, SignatureScheme};
4use crate::kx;
5use crate::msgs::codec::{Codec, Reader};
6use crate::msgs::enums::{AlertDescription, ContentType};
7use crate::msgs::handshake::KeyExchangeAlgorithm;
8use crate::suites::{BulkAlgorithm, CipherSuiteCommon, SupportedCipherSuite};
9#[cfg(feature = "secret_extraction")]
10use crate::suites::{ConnectionTrafficSecrets, PartiallyExtractedSecrets};
11use crate::Error;
12
13use ring::aead;
14use ring::digest::Digest;
15
16use std::fmt;
17
18mod cipher;
19pub(crate) use cipher::{AesGcm, ChaCha20Poly1305, Tls12AeadAlgorithm};
20
21mod prf;
22
23/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256.
24pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
25    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
26        common: CipherSuiteCommon {
27            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
28            bulk: BulkAlgorithm::Chacha20Poly1305,
29            aead_algorithm: &ring::aead::CHACHA20_POLY1305,
30        },
31        kx: KeyExchangeAlgorithm::ECDHE,
32        sign: TLS12_ECDSA_SCHEMES,
33        fixed_iv_len: 12,
34        explicit_nonce_len: 0,
35        aead_alg: &ChaCha20Poly1305,
36        hmac_algorithm: ring::hmac::HMAC_SHA256,
37    });
38
39/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
40pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
41    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
42        common: CipherSuiteCommon {
43            suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
44            bulk: BulkAlgorithm::Chacha20Poly1305,
45            aead_algorithm: &ring::aead::CHACHA20_POLY1305,
46        },
47        kx: KeyExchangeAlgorithm::ECDHE,
48        sign: TLS12_RSA_SCHEMES,
49        fixed_iv_len: 12,
50        explicit_nonce_len: 0,
51        aead_alg: &ChaCha20Poly1305,
52        hmac_algorithm: ring::hmac::HMAC_SHA256,
53    });
54
55/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
56pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
57    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
58        common: CipherSuiteCommon {
59            suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
60            bulk: BulkAlgorithm::Aes128Gcm,
61            aead_algorithm: &ring::aead::AES_128_GCM,
62        },
63        kx: KeyExchangeAlgorithm::ECDHE,
64        sign: TLS12_RSA_SCHEMES,
65        fixed_iv_len: 4,
66        explicit_nonce_len: 8,
67        aead_alg: &AesGcm,
68        hmac_algorithm: ring::hmac::HMAC_SHA256,
69    });
70
71/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
72pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
73    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
74        common: CipherSuiteCommon {
75            suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
76            bulk: BulkAlgorithm::Aes256Gcm,
77            aead_algorithm: &ring::aead::AES_256_GCM,
78        },
79        kx: KeyExchangeAlgorithm::ECDHE,
80        sign: TLS12_RSA_SCHEMES,
81        fixed_iv_len: 4,
82        explicit_nonce_len: 8,
83        aead_alg: &AesGcm,
84        hmac_algorithm: ring::hmac::HMAC_SHA384,
85    });
86
87/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
88pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
89    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
90        common: CipherSuiteCommon {
91            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
92            bulk: BulkAlgorithm::Aes128Gcm,
93            aead_algorithm: &ring::aead::AES_128_GCM,
94        },
95        kx: KeyExchangeAlgorithm::ECDHE,
96        sign: TLS12_ECDSA_SCHEMES,
97        fixed_iv_len: 4,
98        explicit_nonce_len: 8,
99        aead_alg: &AesGcm,
100        hmac_algorithm: ring::hmac::HMAC_SHA256,
101    });
102
103/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
104pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
105    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
106        common: CipherSuiteCommon {
107            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
108            bulk: BulkAlgorithm::Aes256Gcm,
109            aead_algorithm: &ring::aead::AES_256_GCM,
110        },
111        kx: KeyExchangeAlgorithm::ECDHE,
112        sign: TLS12_ECDSA_SCHEMES,
113        fixed_iv_len: 4,
114        explicit_nonce_len: 8,
115        aead_alg: &AesGcm,
116        hmac_algorithm: ring::hmac::HMAC_SHA384,
117    });
118
119static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[
120    SignatureScheme::ED25519,
121    SignatureScheme::ECDSA_NISTP521_SHA512,
122    SignatureScheme::ECDSA_NISTP384_SHA384,
123    SignatureScheme::ECDSA_NISTP256_SHA256,
124];
125
126static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[
127    SignatureScheme::RSA_PSS_SHA512,
128    SignatureScheme::RSA_PSS_SHA384,
129    SignatureScheme::RSA_PSS_SHA256,
130    SignatureScheme::RSA_PKCS1_SHA512,
131    SignatureScheme::RSA_PKCS1_SHA384,
132    SignatureScheme::RSA_PKCS1_SHA256,
133];
134
135/// A TLS 1.2 cipher suite supported by rustls.
136pub struct Tls12CipherSuite {
137    /// Common cipher suite fields.
138    pub common: CipherSuiteCommon,
139    pub(crate) hmac_algorithm: ring::hmac::Algorithm,
140    /// How to exchange/agree keys.
141    pub kx: KeyExchangeAlgorithm,
142
143    /// How to sign messages for authentication.
144    pub sign: &'static [SignatureScheme],
145
146    /// How long the fixed part of the 'IV' is.
147    ///
148    /// This isn't usually an IV, but we continue the
149    /// terminology misuse to match the standard.
150    pub fixed_iv_len: usize,
151
152    /// This is a non-standard extension which extends the
153    /// key block to provide an initial explicit nonce offset,
154    /// in a deterministic and safe way.  GCM needs this,
155    /// chacha20poly1305 works this way by design.
156    pub explicit_nonce_len: usize,
157
158    pub(crate) aead_alg: &'static dyn Tls12AeadAlgorithm,
159}
160
161impl Tls12CipherSuite {
162    /// Resolve the set of supported `SignatureScheme`s from the
163    /// offered `SupportedSignatureSchemes`.  If we return an empty
164    /// set, the handshake terminates.
165    pub fn resolve_sig_schemes(&self, offered: &[SignatureScheme]) -> Vec<SignatureScheme> {
166        self.sign
167            .iter()
168            .filter(|pref| offered.contains(pref))
169            .cloned()
170            .collect()
171    }
172
173    /// Which hash function to use with this suite.
174    pub fn hash_algorithm(&self) -> &'static ring::digest::Algorithm {
175        self.hmac_algorithm.digest_algorithm()
176    }
177}
178
179impl From<&'static Tls12CipherSuite> for SupportedCipherSuite {
180    fn from(s: &'static Tls12CipherSuite) -> Self {
181        Self::Tls12(s)
182    }
183}
184
185impl PartialEq for Tls12CipherSuite {
186    fn eq(&self, other: &Self) -> bool {
187        self.common.suite == other.common.suite
188    }
189}
190
191impl fmt::Debug for Tls12CipherSuite {
192    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193        f.debug_struct("Tls12CipherSuite")
194            .field("suite", &self.common.suite)
195            .field("bulk", &self.common.bulk)
196            .finish()
197    }
198}
199
200/// TLS1.2 per-connection keying material
201pub(crate) struct ConnectionSecrets {
202    pub(crate) randoms: ConnectionRandoms,
203    suite: &'static Tls12CipherSuite,
204    pub(crate) master_secret: [u8; 48],
205}
206
207impl ConnectionSecrets {
208    pub(crate) fn from_key_exchange(
209        kx: kx::KeyExchange,
210        peer_pub_key: &[u8],
211        ems_seed: Option<Digest>,
212        randoms: ConnectionRandoms,
213        suite: &'static Tls12CipherSuite,
214    ) -> Result<Self, Error> {
215        let mut ret = Self {
216            randoms,
217            suite,
218            master_secret: [0u8; 48],
219        };
220
221        let (label, seed) = match ems_seed {
222            Some(seed) => ("extended master secret", Seed::Ems(seed)),
223            None => (
224                "master secret",
225                Seed::Randoms(join_randoms(&ret.randoms.client, &ret.randoms.server)),
226            ),
227        };
228
229        kx.complete(peer_pub_key, |secret| {
230            prf::prf(
231                &mut ret.master_secret,
232                suite.hmac_algorithm,
233                secret,
234                label.as_bytes(),
235                seed.as_ref(),
236            );
237            Ok(())
238        })?;
239
240        Ok(ret)
241    }
242
243    pub(crate) fn new_resume(
244        randoms: ConnectionRandoms,
245        suite: &'static Tls12CipherSuite,
246        master_secret: &[u8],
247    ) -> Self {
248        let mut ret = Self {
249            randoms,
250            suite,
251            master_secret: [0u8; 48],
252        };
253        ret.master_secret
254            .copy_from_slice(master_secret);
255        ret
256    }
257
258    /// Make a `MessageCipherPair` based on the given supported ciphersuite `scs`,
259    /// and the session's `secrets`.
260    pub(crate) fn make_cipher_pair(&self, side: Side) -> MessageCipherPair {
261        fn split_key<'a>(
262            key_block: &'a [u8],
263            alg: &'static aead::Algorithm,
264        ) -> (aead::LessSafeKey, &'a [u8]) {
265            // Might panic if the key block is too small.
266            let (key, rest) = key_block.split_at(alg.key_len());
267            // Won't panic because its only prerequisite is that `key` is `alg.key_len()` bytes long.
268            let key = aead::UnboundKey::new(alg, key).unwrap();
269            (aead::LessSafeKey::new(key), rest)
270        }
271
272        // Make a key block, and chop it up.
273        // nb. we don't implement any ciphersuites with nonzero mac_key_len.
274        let key_block = self.make_key_block();
275
276        let suite = self.suite;
277        let scs = &suite.common;
278
279        let (client_write_key, key_block) = split_key(&key_block, scs.aead_algorithm);
280        let (server_write_key, key_block) = split_key(key_block, scs.aead_algorithm);
281        let (client_write_iv, key_block) = key_block.split_at(suite.fixed_iv_len);
282        let (server_write_iv, extra) = key_block.split_at(suite.fixed_iv_len);
283
284        let (write_key, write_iv, read_key, read_iv) = match side {
285            Side::Client => (
286                client_write_key,
287                client_write_iv,
288                server_write_key,
289                server_write_iv,
290            ),
291            Side::Server => (
292                server_write_key,
293                server_write_iv,
294                client_write_key,
295                client_write_iv,
296            ),
297        };
298
299        (
300            suite
301                .aead_alg
302                .decrypter(read_key, read_iv),
303            suite
304                .aead_alg
305                .encrypter(write_key, write_iv, extra),
306        )
307    }
308
309    fn make_key_block(&self) -> Vec<u8> {
310        let suite = &self.suite;
311        let common = &self.suite.common;
312
313        let len =
314            (common.aead_algorithm.key_len() + suite.fixed_iv_len) * 2 + suite.explicit_nonce_len;
315
316        let mut out = Vec::new();
317        out.resize(len, 0u8);
318
319        // NOTE: opposite order to above for no good reason.
320        // Don't design security protocols on drugs, kids.
321        let randoms = join_randoms(&self.randoms.server, &self.randoms.client);
322        prf::prf(
323            &mut out,
324            self.suite.hmac_algorithm,
325            &self.master_secret,
326            b"key expansion",
327            &randoms,
328        );
329
330        out
331    }
332
333    pub(crate) fn suite(&self) -> &'static Tls12CipherSuite {
334        self.suite
335    }
336
337    pub(crate) fn get_master_secret(&self) -> Vec<u8> {
338        let mut ret = Vec::new();
339        ret.extend_from_slice(&self.master_secret);
340        ret
341    }
342
343    fn make_verify_data(&self, handshake_hash: &Digest, label: &[u8]) -> Vec<u8> {
344        let mut out = Vec::new();
345        out.resize(12, 0u8);
346
347        prf::prf(
348            &mut out,
349            self.suite.hmac_algorithm,
350            &self.master_secret,
351            label,
352            handshake_hash.as_ref(),
353        );
354        out
355    }
356
357    pub(crate) fn client_verify_data(&self, handshake_hash: &Digest) -> Vec<u8> {
358        self.make_verify_data(handshake_hash, b"client finished")
359    }
360
361    pub(crate) fn server_verify_data(&self, handshake_hash: &Digest) -> Vec<u8> {
362        self.make_verify_data(handshake_hash, b"server finished")
363    }
364
365    pub(crate) fn export_keying_material(
366        &self,
367        output: &mut [u8],
368        label: &[u8],
369        context: Option<&[u8]>,
370    ) {
371        let mut randoms = Vec::new();
372        randoms.extend_from_slice(&self.randoms.client);
373        randoms.extend_from_slice(&self.randoms.server);
374        if let Some(context) = context {
375            assert!(context.len() <= 0xffff);
376            (context.len() as u16).encode(&mut randoms);
377            randoms.extend_from_slice(context);
378        }
379
380        prf::prf(
381            output,
382            self.suite.hmac_algorithm,
383            &self.master_secret,
384            label,
385            &randoms,
386        )
387    }
388
389    #[cfg(feature = "secret_extraction")]
390    pub(crate) fn extract_secrets(&self, side: Side) -> Result<PartiallyExtractedSecrets, Error> {
391        // Make a key block, and chop it up
392        let key_block = self.make_key_block();
393
394        let suite = self.suite;
395        let algo = suite.common.aead_algorithm;
396
397        let (client_key, key_block) = key_block.split_at(algo.key_len());
398        let (server_key, key_block) = key_block.split_at(algo.key_len());
399        let (client_iv, key_block) = key_block.split_at(suite.fixed_iv_len);
400        let (server_iv, extra) = key_block.split_at(suite.fixed_iv_len);
401
402        // A key/IV pair (fixed IV len is 4 for GCM, 12 for Chacha)
403        struct Pair<'a> {
404            key: &'a [u8],
405            iv: &'a [u8],
406        }
407
408        let client_pair = Pair {
409            key: client_key,
410            iv: client_iv,
411        };
412        let server_pair = Pair {
413            key: server_key,
414            iv: server_iv,
415        };
416
417        let (client_secrets, server_secrets) = if algo == &ring::aead::AES_128_GCM {
418            let extract = |pair: Pair| -> ConnectionTrafficSecrets {
419                let mut key = [0u8; 16];
420                key.copy_from_slice(pair.key);
421
422                let mut salt = [0u8; 4];
423                salt.copy_from_slice(pair.iv);
424
425                let mut iv = [0u8; 8];
426                iv.copy_from_slice(&extra[..8]);
427
428                ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv }
429            };
430
431            (extract(client_pair), extract(server_pair))
432        } else if algo == &ring::aead::AES_256_GCM {
433            let extract = |pair: Pair| -> ConnectionTrafficSecrets {
434                let mut key = [0u8; 32];
435                key.copy_from_slice(pair.key);
436
437                let mut salt = [0u8; 4];
438                salt.copy_from_slice(pair.iv);
439
440                let mut iv = [0u8; 8];
441                iv.copy_from_slice(&extra[..8]);
442
443                ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv }
444            };
445
446            (extract(client_pair), extract(server_pair))
447        } else if algo == &ring::aead::CHACHA20_POLY1305 {
448            let extract = |pair: Pair| -> ConnectionTrafficSecrets {
449                let mut key = [0u8; 32];
450                key.copy_from_slice(pair.key);
451
452                let mut iv = [0u8; 12];
453                iv.copy_from_slice(pair.iv);
454
455                ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv }
456            };
457
458            (extract(client_pair), extract(server_pair))
459        } else {
460            return Err(Error::General(format!(
461                "exporting secrets for {:?}: unimplemented",
462                algo
463            )));
464        };
465
466        let (tx, rx) = match side {
467            Side::Client => (client_secrets, server_secrets),
468            Side::Server => (server_secrets, client_secrets),
469        };
470        Ok(PartiallyExtractedSecrets { tx, rx })
471    }
472}
473
474enum Seed {
475    Ems(Digest),
476    Randoms([u8; 64]),
477}
478
479impl AsRef<[u8]> for Seed {
480    fn as_ref(&self) -> &[u8] {
481        match self {
482            Self::Ems(seed) => seed.as_ref(),
483            Self::Randoms(randoms) => randoms.as_ref(),
484        }
485    }
486}
487
488fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] {
489    let mut randoms = [0u8; 64];
490    randoms[..32].copy_from_slice(first);
491    randoms[32..].copy_from_slice(second);
492    randoms
493}
494
495type MessageCipherPair = (Box<dyn MessageDecrypter>, Box<dyn MessageEncrypter>);
496
497pub(crate) fn decode_ecdh_params<T: Codec>(
498    common: &mut CommonState,
499    kx_params: &[u8],
500) -> Result<T, Error> {
501    decode_ecdh_params_::<T>(kx_params).ok_or_else(|| {
502        common.send_fatal_alert(AlertDescription::DecodeError);
503        Error::CorruptMessagePayload(ContentType::Handshake)
504    })
505}
506
507fn decode_ecdh_params_<T: Codec>(kx_params: &[u8]) -> Option<T> {
508    let mut rd = Reader::init(kx_params);
509    let ecdh_params = T::read(&mut rd)?;
510    match rd.any_left() {
511        false => Some(ecdh_params),
512        true => None,
513    }
514}
515
516pub(crate) const DOWNGRADE_SENTINEL: [u8; 8] = [0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01];
517
518#[cfg(test)]
519mod tests {
520    use super::*;
521    use crate::msgs::handshake::{ClientECDHParams, ServerECDHParams};
522
523    #[test]
524    fn server_ecdhe_remaining_bytes() {
525        let key = kx::KeyExchange::start(&kx::X25519).unwrap();
526        let server_params = ServerECDHParams::new(key.group(), key.pubkey.as_ref());
527        let mut server_buf = Vec::new();
528        server_params.encode(&mut server_buf);
529        server_buf.push(34);
530        assert!(decode_ecdh_params_::<ServerECDHParams>(&server_buf).is_none());
531    }
532
533    #[test]
534    fn client_ecdhe_invalid() {
535        assert!(decode_ecdh_params_::<ClientECDHParams>(&[34]).is_none());
536    }
537}