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