Skip to main content

ic_rustls/
suites.rs

1//! The cipher suites, assembled from the pieces in the other modules.
2
3use rustls::crypto::tls12::PrfUsingHmac;
4use rustls::crypto::tls13::HkdfUsingHmac;
5use rustls::crypto::{CipherSuiteCommon, KeyExchangeAlgorithm};
6use rustls::{CipherSuite, SignatureScheme, SupportedCipherSuite};
7
8use crate::{aead, hash, hmac, quic};
9
10/// Every suite this provider offers, strongest first.
11pub static ALL: &[SupportedCipherSuite] = &[
12    TLS13_AES_256_GCM_SHA384,
13    TLS13_AES_128_GCM_SHA256,
14    TLS13_CHACHA20_POLY1305_SHA256,
15    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
16    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
17    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
18    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
19    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
20    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
21];
22
23/// TLS 1.3 with AES-256-GCM and SHA-384.
24pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite =
25    SupportedCipherSuite::Tls13(&rustls::Tls13CipherSuite {
26        common: CipherSuiteCommon {
27            suite: CipherSuite::TLS13_AES_256_GCM_SHA384,
28            hash_provider: &hash::SHA384,
29            // RFC 8446 appendix B.4 and the AEAD limits draft: the number of
30            // records that may be protected under one key before rekeying.
31            confidentiality_limit: 1 << 24,
32        },
33        hkdf_provider: &HkdfUsingHmac(&hmac::SHA384),
34        aead_alg: &aead::TLS13_AES_256_GCM,
35        quic: Some(&quic::AES_256_GCM),
36    });
37
38/// TLS 1.3 with AES-128-GCM and SHA-256.
39pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite =
40    SupportedCipherSuite::Tls13(&rustls::Tls13CipherSuite {
41        common: CipherSuiteCommon {
42            suite: CipherSuite::TLS13_AES_128_GCM_SHA256,
43            hash_provider: &hash::SHA256,
44            confidentiality_limit: 1 << 24,
45        },
46        hkdf_provider: &HkdfUsingHmac(&hmac::SHA256),
47        aead_alg: &aead::TLS13_AES_128_GCM,
48        quic: Some(&quic::AES_128_GCM),
49    });
50
51/// TLS 1.3 with ChaCha20-Poly1305 and SHA-256.
52///
53/// Listed after the AES suites rather than before because most hardware this
54/// runs on has AES instructions, where AES-GCM is faster. On hardware without
55/// them the position in this list is what stops the connection failing
56/// outright, which is the case for offering it at all.
57pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
58    SupportedCipherSuite::Tls13(&rustls::Tls13CipherSuite {
59        common: CipherSuiteCommon {
60            suite: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
61            hash_provider: &hash::SHA256,
62            // No limit. ChaCha20-Poly1305 is not a block cipher and has no
63            // birthday bound on the ciphertext to respect, so the CFRG AEAD
64            // limits draft section 5.2.1 sets no confidentiality limit for it;
65            // rustls spells that u64::MAX, and its own provider does the same.
66            confidentiality_limit: u64::MAX,
67        },
68        hkdf_provider: &HkdfUsingHmac(&hmac::SHA256),
69        aead_alg: &aead::TLS13_CHACHA20_POLY1305,
70        quic: Some(&quic::CHACHA20_POLY1305),
71    });
72
73/// TLS 1.2 with ECDHE, ECDSA, AES-256-GCM and SHA-384.
74///
75/// ECDSA only: this provider verifies ECDSA signatures and not RSA ones, so
76/// offering an RSA suite would advertise something it cannot complete.
77pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
78    SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
79        common: CipherSuiteCommon {
80            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
81            hash_provider: &hash::SHA384,
82            confidentiality_limit: 1 << 23,
83        },
84        prf_provider: &PrfUsingHmac(&hmac::SHA384),
85        kx: KeyExchangeAlgorithm::ECDHE,
86        sign: TLS12_ECDSA_SCHEMES,
87        aead_alg: &aead::TLS12_AES_256_GCM,
88    });
89
90/// TLS 1.2 with ECDHE, ECDSA, AES-128-GCM and SHA-256.
91pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
92    SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
93        common: CipherSuiteCommon {
94            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
95            hash_provider: &hash::SHA256,
96            confidentiality_limit: 1 << 23,
97        },
98        prf_provider: &PrfUsingHmac(&hmac::SHA256),
99        kx: KeyExchangeAlgorithm::ECDHE,
100        sign: TLS12_ECDSA_SCHEMES,
101        aead_alg: &aead::TLS12_AES_128_GCM,
102    });
103
104/// TLS 1.2 with ECDHE, ECDSA, ChaCha20-Poly1305 and SHA-256.
105///
106/// RFC 7905. Note that this one is not framed like the AES-GCM suites above --
107/// it sends no explicit nonce -- which `aead` handles and tests.
108pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
109    SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
110        common: CipherSuiteCommon {
111            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
112            hash_provider: &hash::SHA256,
113            confidentiality_limit: u64::MAX,
114        },
115        prf_provider: &PrfUsingHmac(&hmac::SHA256),
116        kx: KeyExchangeAlgorithm::ECDHE,
117        sign: TLS12_ECDSA_SCHEMES,
118        aead_alg: &aead::TLS12_CHACHA20_POLY1305,
119    });
120
121/// TLS 1.2 with ECDHE, RSA, AES-256-GCM and SHA-384.
122///
123/// The RSA suites exist because most certificate chains on the public web are
124/// RSA. Without them the TLS 1.2 half of this provider can only talk to a
125/// server holding an ECDSA certificate, which is a minority of them.
126///
127/// They are listed after the ECDSA suites: where a server offers both, ECDSA is
128/// faster and smaller, and the order here is the order rustls proposes.
129pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
130    SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
131        common: CipherSuiteCommon {
132            suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
133            hash_provider: &hash::SHA384,
134            confidentiality_limit: 1 << 23,
135        },
136        prf_provider: &PrfUsingHmac(&hmac::SHA384),
137        kx: KeyExchangeAlgorithm::ECDHE,
138        sign: TLS12_RSA_SCHEMES,
139        aead_alg: &aead::TLS12_AES_256_GCM,
140    });
141
142/// TLS 1.2 with ECDHE, RSA, AES-128-GCM and SHA-256.
143pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
144    SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
145        common: CipherSuiteCommon {
146            suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
147            hash_provider: &hash::SHA256,
148            confidentiality_limit: 1 << 23,
149        },
150        prf_provider: &PrfUsingHmac(&hmac::SHA256),
151        kx: KeyExchangeAlgorithm::ECDHE,
152        sign: TLS12_RSA_SCHEMES,
153        aead_alg: &aead::TLS12_AES_128_GCM,
154    });
155
156/// TLS 1.2 with ECDHE, RSA, ChaCha20-Poly1305 and SHA-256.
157pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
158    SupportedCipherSuite::Tls12(&rustls::Tls12CipherSuite {
159        common: CipherSuiteCommon {
160            suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
161            hash_provider: &hash::SHA256,
162            confidentiality_limit: u64::MAX,
163        },
164        prf_provider: &PrfUsingHmac(&hmac::SHA256),
165        kx: KeyExchangeAlgorithm::ECDHE,
166        sign: TLS12_RSA_SCHEMES,
167        aead_alg: &aead::TLS12_CHACHA20_POLY1305,
168    });
169
170/// The signature schemes a TLS 1.2 ECDSA suite may use.
171///
172/// These are exactly the pairings [`crate::verify`] implements. Listing one
173/// that is not verifiable would let a handshake get as far as a certificate
174/// this provider then cannot check.
175/// Ed25519 belongs here rather than in a family of its own: RFC 8422 carries
176/// it in the ECDHE_ECDSA suites, so a TLS 1.2 server holding an Ed25519
177/// certificate negotiates one of these. rustls's own provider lists it first,
178/// and this follows.
179static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[
180    SignatureScheme::ED25519,
181    SignatureScheme::ECDSA_NISTP384_SHA384,
182    SignatureScheme::ECDSA_NISTP256_SHA256,
183];
184
185/// The signature schemes a TLS 1.2 RSA suite may use, strongest first.
186///
187/// PSS ahead of PKCS#1 v1.5: both are verifiable here, and the ontology records
188/// PSS as superseding v1.5. The older padding stays because a great many TLS
189/// 1.2 servers sign the key exchange with it and will not offer anything else.
190static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[
191    SignatureScheme::RSA_PSS_SHA512,
192    SignatureScheme::RSA_PSS_SHA384,
193    SignatureScheme::RSA_PSS_SHA256,
194    SignatureScheme::RSA_PKCS1_SHA512,
195    SignatureScheme::RSA_PKCS1_SHA384,
196    SignatureScheme::RSA_PKCS1_SHA256,
197];
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202
203    /// Every signature scheme a TLS 1.2 suite advertises must be one the
204    /// verifier actually implements.
205    ///
206    /// Advertising more than can be verified is worse than advertising less:
207    /// the handshake proceeds, the peer picks the scheme, and it fails at
208    /// certificate verification with no indication that the choice was ours.
209    #[test]
210    fn the_advertised_schemes_are_all_verifiable() {
211        let mapped: alloc::vec::Vec<SignatureScheme> = crate::SUPPORTED_SIG_ALGS
212            .mapping
213            .iter()
214            .map(|(scheme, _)| *scheme)
215            .collect();
216
217        let mut checked = 0;
218        for suite in ALL {
219            let SupportedCipherSuite::Tls12(t) = suite else {
220                continue;
221            };
222            for scheme in t.sign {
223                assert!(
224                    mapped.contains(scheme),
225                    "{:?} advertises {scheme:?}, which nothing here verifies",
226                    suite.suite()
227                );
228                checked += 1;
229            }
230        }
231        // Three ECDSA suites at three schemes each, three RSA suites at six.
232        assert!(checked >= 27, "only {checked} advertised schemes examined");
233    }
234
235    /// Each suite's hash must match the one its name promises, because the key
236    /// schedule and the transcript both depend on it.
237    #[test]
238    fn each_suite_uses_the_hash_it_is_named_for() {
239        use rustls::crypto::hash::HashAlgorithm;
240
241        // `common()` is crate-private in rustls, so the variant is matched to
242        // reach the public field on the concrete suite.
243        for (suite, want) in [
244            (&TLS13_AES_256_GCM_SHA384, HashAlgorithm::SHA384),
245            (&TLS13_AES_128_GCM_SHA256, HashAlgorithm::SHA256),
246            (
247                &TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
248                HashAlgorithm::SHA384,
249            ),
250            (
251                &TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
252                HashAlgorithm::SHA256,
253            ),
254            (&TLS13_CHACHA20_POLY1305_SHA256, HashAlgorithm::SHA256),
255            (
256                &TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
257                HashAlgorithm::SHA256,
258            ),
259            (
260                &TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
261                HashAlgorithm::SHA384,
262            ),
263            (
264                &TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
265                HashAlgorithm::SHA256,
266            ),
267            (
268                &TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
269                HashAlgorithm::SHA256,
270            ),
271        ] {
272            let got = match suite {
273                SupportedCipherSuite::Tls13(t) => t.common.hash_provider.algorithm(),
274                SupportedCipherSuite::Tls12(t) => t.common.hash_provider.algorithm(),
275            };
276            assert_eq!(got, want, "{:?} uses the wrong hash", suite.suite());
277        }
278    }
279
280    /// The list must be ordered strongest first, since rustls offers it in
281    /// order and the peer picks the first it accepts.
282    #[test]
283    fn the_suites_are_ordered_and_distinct() {
284        let names: alloc::vec::Vec<CipherSuite> = ALL.iter().map(|s| s.suite()).collect();
285        assert_eq!(names.len(), 9);
286        for (i, a) in names.iter().enumerate() {
287            assert!(!names[i + 1..].contains(a), "{a:?} is listed twice");
288        }
289        // TLS 1.3 before TLS 1.2, and 256 before 128 within each.
290        assert_eq!(names[0], CipherSuite::TLS13_AES_256_GCM_SHA384);
291        assert_eq!(names[1], CipherSuite::TLS13_AES_128_GCM_SHA256);
292        assert_eq!(names[2], CipherSuite::TLS13_CHACHA20_POLY1305_SHA256);
293        // Every TLS 1.3 suite before every TLS 1.2 one.
294        let first_12 = ALL
295            .iter()
296            .position(|s| matches!(s, SupportedCipherSuite::Tls12(_)))
297            .expect("there are TLS 1.2 suites");
298        assert!(
299            ALL[first_12..]
300                .iter()
301                .all(|s| matches!(s, SupportedCipherSuite::Tls12(_))),
302            "the TLS 1.3 and TLS 1.2 suites are interleaved"
303        );
304    }
305}