Skip to main content

rtc_dtls/cipher_suite/
mod.rs

1pub mod cipher_suite_aes_128_ccm;
2pub mod cipher_suite_aes_128_gcm_sha256;
3pub mod cipher_suite_aes_256_cbc_sha;
4pub mod cipher_suite_chacha20_poly1305_sha256;
5pub mod cipher_suite_tls_ecdhe_ecdsa_with_aes_128_ccm;
6pub mod cipher_suite_tls_ecdhe_ecdsa_with_aes_128_ccm8;
7pub mod cipher_suite_tls_psk_with_aes_128_ccm;
8pub mod cipher_suite_tls_psk_with_aes_128_ccm8;
9pub mod cipher_suite_tls_psk_with_aes_128_gcm_sha256;
10
11use std::fmt;
12
13use super::client_certificate_type::*;
14use super::record_layer::record_layer_header::*;
15use shared::error::*;
16
17use cipher_suite_aes_128_gcm_sha256::*;
18use cipher_suite_aes_256_cbc_sha::*;
19use cipher_suite_chacha20_poly1305_sha256::*;
20use cipher_suite_tls_ecdhe_ecdsa_with_aes_128_ccm::*;
21use cipher_suite_tls_ecdhe_ecdsa_with_aes_128_ccm8::*;
22use cipher_suite_tls_psk_with_aes_128_ccm::*;
23use cipher_suite_tls_psk_with_aes_128_ccm8::*;
24use cipher_suite_tls_psk_with_aes_128_gcm_sha256::*;
25
26// CipherSuiteID is an ID for our supported CipherSuites
27// Supported Cipher Suites
28#[allow(non_camel_case_types)]
29#[derive(Copy, Clone, Debug, PartialEq, Eq)]
30pub enum CipherSuiteId {
31    // AES-128-CCM
32    Tls_Ecdhe_Ecdsa_With_Aes_128_Ccm = 0xc0ac,
33    Tls_Ecdhe_Ecdsa_With_Aes_128_Ccm_8 = 0xc0ae,
34
35    // AES-128-GCM-SHA256
36    Tls_Ecdhe_Ecdsa_With_Aes_128_Gcm_Sha256 = 0xc02b,
37    Tls_Ecdhe_Rsa_With_Aes_128_Gcm_Sha256 = 0xc02f,
38
39    // AES-256-CBC-SHA
40    Tls_Ecdhe_Ecdsa_With_Aes_256_Cbc_Sha = 0xc00a,
41    Tls_Ecdhe_Rsa_With_Aes_256_Cbc_Sha = 0xc014,
42
43    Tls_Psk_With_Aes_128_Ccm = 0xc0a4,
44    Tls_Psk_With_Aes_128_Ccm_8 = 0xc0a8,
45    Tls_Psk_With_Aes_128_Gcm_Sha256 = 0x00a8,
46
47    // CHACHA20_POLY1305_SHA256
48    Tls_Ecdhe_Rsa_With_ChaCha20_Poly1305_Sha256 = 0xcca8,
49    Tls_Ecdhe_Ecdsa_With_ChaCha20_Poly1305_Sha256 = 0xcca9,
50
51    Unsupported,
52}
53
54impl fmt::Display for CipherSuiteId {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        match *self {
57            CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Ccm => {
58                write!(f, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM")
59            }
60            CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Ccm_8 => {
61                write!(f, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8")
62            }
63            CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Gcm_Sha256 => {
64                write!(f, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256")
65            }
66            CipherSuiteId::Tls_Ecdhe_Rsa_With_Aes_128_Gcm_Sha256 => {
67                write!(f, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
68            }
69            CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_256_Cbc_Sha => {
70                write!(f, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA")
71            }
72            CipherSuiteId::Tls_Ecdhe_Rsa_With_Aes_256_Cbc_Sha => {
73                write!(f, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA")
74            }
75            CipherSuiteId::Tls_Psk_With_Aes_128_Ccm => write!(f, "TLS_PSK_WITH_AES_128_CCM"),
76            CipherSuiteId::Tls_Psk_With_Aes_128_Ccm_8 => write!(f, "TLS_PSK_WITH_AES_128_CCM_8"),
77            CipherSuiteId::Tls_Psk_With_Aes_128_Gcm_Sha256 => {
78                write!(f, "TLS_PSK_WITH_AES_128_GCM_SHA256")
79            }
80            CipherSuiteId::Tls_Ecdhe_Rsa_With_ChaCha20_Poly1305_Sha256 => {
81                write!(f, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256")
82            }
83            CipherSuiteId::Tls_Ecdhe_Ecdsa_With_ChaCha20_Poly1305_Sha256 => {
84                write!(f, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
85            }
86
87            _ => write!(f, "Unsupported CipherSuiteID"),
88        }
89    }
90}
91
92impl From<u16> for CipherSuiteId {
93    fn from(val: u16) -> Self {
94        match val {
95            // AES-128-CCM
96            0xc0ac => CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Ccm,
97            0xc0ae => CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Ccm_8,
98
99            // AES-128-GCM-SHA256
100            0xc02b => CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Gcm_Sha256,
101            0xc02f => CipherSuiteId::Tls_Ecdhe_Rsa_With_Aes_128_Gcm_Sha256,
102
103            // AES-256-CBC-SHA
104            0xc00a => CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_256_Cbc_Sha,
105            0xc014 => CipherSuiteId::Tls_Ecdhe_Rsa_With_Aes_256_Cbc_Sha,
106
107            0xc0a4 => CipherSuiteId::Tls_Psk_With_Aes_128_Ccm,
108            0xc0a8 => CipherSuiteId::Tls_Psk_With_Aes_128_Ccm_8,
109            0x00a8 => CipherSuiteId::Tls_Psk_With_Aes_128_Gcm_Sha256,
110
111            // CHACHA20_POLY1305_SHA256
112            0xcca8 => CipherSuiteId::Tls_Ecdhe_Rsa_With_ChaCha20_Poly1305_Sha256,
113            0xcca9 => CipherSuiteId::Tls_Ecdhe_Ecdsa_With_ChaCha20_Poly1305_Sha256,
114
115            _ => CipherSuiteId::Unsupported,
116        }
117    }
118}
119
120impl From<&str> for CipherSuiteId {
121    fn from(val: &str) -> Self {
122        match val {
123            "TLS_ECDHE_ECDSA_WITH_AES_128_CCM" => CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Ccm,
124            "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8" => {
125                CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Ccm_8
126            }
127            "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" => {
128                CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Gcm_Sha256
129            }
130            "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" => {
131                CipherSuiteId::Tls_Ecdhe_Rsa_With_Aes_128_Gcm_Sha256
132            }
133            "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" => {
134                CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_256_Cbc_Sha
135            }
136            "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" => {
137                CipherSuiteId::Tls_Ecdhe_Rsa_With_Aes_256_Cbc_Sha
138            }
139            "TLS_PSK_WITH_AES_128_CCM" => CipherSuiteId::Tls_Psk_With_Aes_128_Ccm,
140            "TLS_PSK_WITH_AES_128_CCM_8" => CipherSuiteId::Tls_Psk_With_Aes_128_Ccm_8,
141            "TLS_PSK_WITH_AES_128_GCM_SHA256" => CipherSuiteId::Tls_Psk_With_Aes_128_Gcm_Sha256,
142            "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" => {
143                CipherSuiteId::Tls_Ecdhe_Rsa_With_ChaCha20_Poly1305_Sha256
144            }
145            "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" => {
146                CipherSuiteId::Tls_Ecdhe_Ecdsa_With_ChaCha20_Poly1305_Sha256
147            }
148            _ => CipherSuiteId::Unsupported,
149        }
150    }
151}
152
153#[derive(Copy, Clone, Debug)]
154pub enum CipherSuiteHash {
155    Sha256,
156}
157
158impl CipherSuiteHash {
159    pub(crate) fn size(&self) -> usize {
160        match *self {
161            CipherSuiteHash::Sha256 => 32,
162        }
163    }
164}
165
166pub trait CipherSuite: Send + Sync {
167    fn to_string(&self) -> String;
168    fn id(&self) -> CipherSuiteId;
169    fn certificate_type(&self) -> ClientCertificateType;
170    fn hash_func(&self) -> CipherSuiteHash;
171    fn is_psk(&self) -> bool;
172    fn is_initialized(&self) -> bool;
173
174    // Generate the internal encryption state
175    fn init(
176        &mut self,
177        master_secret: &[u8],
178        client_random: &[u8],
179        server_random: &[u8],
180        is_client: bool,
181    ) -> Result<()>;
182
183    fn encrypt(&self, pkt_rlh: &RecordLayerHeader, raw: &[u8]) -> Result<Vec<u8>>;
184    fn decrypt(&self, input: &[u8]) -> Result<Vec<u8>>;
185}
186
187// Taken from https://www.iana.org/assignments/tls-parameters/tls-parameters.xml
188// A cipher_suite is a specific combination of key agreement, cipher and MAC
189// function.
190pub fn cipher_suite_for_id(id: CipherSuiteId) -> Result<Box<dyn CipherSuite>> {
191    match id {
192        CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Ccm => {
193            Ok(Box::new(new_cipher_suite_tls_ecdhe_ecdsa_with_aes_128_ccm()))
194        }
195        CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Ccm_8 => Ok(Box::new(
196            new_cipher_suite_tls_ecdhe_ecdsa_with_aes_128_ccm8(),
197        )),
198        CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_128_Gcm_Sha256 => {
199            Ok(Box::new(CipherSuiteAes128GcmSha256::new(false)))
200        }
201        CipherSuiteId::Tls_Ecdhe_Rsa_With_Aes_128_Gcm_Sha256 => {
202            Ok(Box::new(CipherSuiteAes128GcmSha256::new(true)))
203        }
204        CipherSuiteId::Tls_Ecdhe_Rsa_With_Aes_256_Cbc_Sha => {
205            Ok(Box::new(CipherSuiteAes256CbcSha::new(true)))
206        }
207        CipherSuiteId::Tls_Ecdhe_Ecdsa_With_Aes_256_Cbc_Sha => {
208            Ok(Box::new(CipherSuiteAes256CbcSha::new(false)))
209        }
210        CipherSuiteId::Tls_Psk_With_Aes_128_Ccm => {
211            Ok(Box::new(new_cipher_suite_tls_psk_with_aes_128_ccm()))
212        }
213        CipherSuiteId::Tls_Psk_With_Aes_128_Ccm_8 => {
214            Ok(Box::new(new_cipher_suite_tls_psk_with_aes_128_ccm8()))
215        }
216        CipherSuiteId::Tls_Psk_With_Aes_128_Gcm_Sha256 => {
217            Ok(Box::<CipherSuiteTlsPskWithAes128GcmSha256>::default())
218        }
219        CipherSuiteId::Tls_Ecdhe_Rsa_With_ChaCha20_Poly1305_Sha256 => {
220            Ok(Box::new(CipherSuiteChaCha20Poly1305Sha256::new(true)))
221        }
222        CipherSuiteId::Tls_Ecdhe_Ecdsa_With_ChaCha20_Poly1305_Sha256 => {
223            Ok(Box::new(CipherSuiteChaCha20Poly1305Sha256::new(false)))
224        }
225
226        _ => Err(Error::ErrInvalidCipherSuite),
227    }
228}
229
230// CipherSuites we support in order of preference
231pub(crate) fn default_cipher_suites() -> Vec<Box<dyn CipherSuite>> {
232    vec![
233        Box::new(CipherSuiteAes128GcmSha256::new(false)),
234        Box::new(CipherSuiteAes256CbcSha::new(false)),
235        Box::new(CipherSuiteAes128GcmSha256::new(true)),
236        Box::new(CipherSuiteAes256CbcSha::new(true)),
237        Box::new(CipherSuiteChaCha20Poly1305Sha256::new(false)),
238    ]
239}
240
241fn all_cipher_suites() -> Vec<Box<dyn CipherSuite>> {
242    vec![
243        Box::new(new_cipher_suite_tls_ecdhe_ecdsa_with_aes_128_ccm()),
244        Box::new(new_cipher_suite_tls_ecdhe_ecdsa_with_aes_128_ccm8()),
245        Box::new(CipherSuiteAes128GcmSha256::new(false)),
246        Box::new(CipherSuiteAes128GcmSha256::new(true)),
247        Box::new(CipherSuiteAes256CbcSha::new(false)),
248        Box::new(CipherSuiteAes256CbcSha::new(true)),
249        Box::new(new_cipher_suite_tls_psk_with_aes_128_ccm()),
250        Box::new(new_cipher_suite_tls_psk_with_aes_128_ccm8()),
251        Box::<CipherSuiteTlsPskWithAes128GcmSha256>::default(),
252        Box::new(CipherSuiteChaCha20Poly1305Sha256::new(false)),
253        Box::new(CipherSuiteChaCha20Poly1305Sha256::new(true)),
254    ]
255}
256
257fn cipher_suites_for_ids(ids: &[CipherSuiteId]) -> Result<Vec<Box<dyn CipherSuite>>> {
258    let mut cipher_suites = vec![];
259    for id in ids {
260        cipher_suites.push(cipher_suite_for_id(*id)?);
261    }
262    Ok(cipher_suites)
263}
264
265pub(crate) fn parse_cipher_suites(
266    user_selected_suites: &[CipherSuiteId],
267    exclude_psk: bool,
268    exclude_non_psk: bool,
269) -> Result<Vec<Box<dyn CipherSuite>>> {
270    let cipher_suites = if !user_selected_suites.is_empty() {
271        cipher_suites_for_ids(user_selected_suites)?
272    } else {
273        default_cipher_suites()
274    };
275
276    let filtered_cipher_suites: Vec<Box<dyn CipherSuite>> = cipher_suites
277        .into_iter()
278        .filter(|c| !((exclude_psk && c.is_psk()) || (exclude_non_psk && !c.is_psk())))
279        .collect();
280
281    if filtered_cipher_suites.is_empty() {
282        Err(Error::ErrNoAvailableCipherSuites)
283    } else {
284        Ok(filtered_cipher_suites)
285    }
286}