Skip to main content

rtc_dtls/
config.rs

1//! Handshake configuration.
2//!
3//! [`ConfigBuilder`](crate::config::ConfigBuilder) is what a caller supplies: certificates, the client/server role, which cipher
4//! suites and curves to offer, the SRTP protection profiles to negotiate through `use_srtp`,
5//! and how strictly to require the extended master secret
6//! ([`ExtendedMasterSecretType`](crate::config::ExtendedMasterSecretType)).
7//!
8//! WebRTC authenticates peers by comparing the certificate fingerprint against the one
9//! signalled in SDP, not against a CA chain — so certificates here are normally self-signed
10//! (see [`gen_self_signed_root_cert`](crate::config::gen_self_signed_root_cert)) and the check is implemented by supplying a
11//! [`VerifyPeerCertificateFn`](crate::config::VerifyPeerCertificateFn).
12//!
13//! [`HandshakeConfig`](crate::config::HandshakeConfig) is the resolved form the handshake
14//! actually runs with, produced by [`ConfigBuilder::build`](crate::config::ConfigBuilder::build).
15
16#[cfg(test)]
17mod config_test;
18
19use crate::cipher_suite::*;
20use crate::conn::{DEFAULT_REPLAY_PROTECTION_WINDOW, INITIAL_TICKER_INTERVAL};
21use crate::crypto::*;
22use crate::extension::extension_use_srtp::SrtpProtectionProfile;
23use crate::signature_hash_algorithm::{
24    SignatureHashAlgorithm, SignatureScheme, parse_signature_schemes,
25};
26use log::warn;
27use shared::error::*;
28use std::collections::HashMap;
29use std::fmt;
30use std::net::SocketAddr;
31use std::sync::Arc;
32use std::time::Duration;
33
34use rustls::client::danger::ServerCertVerifier;
35use rustls::pki_types::CertificateDer;
36use rustls::server::danger::ClientCertVerifier;
37
38/// The rustls [`CryptoProvider`](rustls::crypto::CryptoProvider) this crate was built with.
39///
40/// rustls can infer a process-wide default from its own crate features, but only when exactly
41/// one of `ring`/`aws-lc-rs` is enabled — and it panics otherwise. Feature unification makes
42/// that easy to violate: any other crate in the graph that asks rustls for a different provider
43/// enables both, which is what happens as soon as `rtc`'s `webrtc` interop dev-dependency joins
44/// the build. Since our own `ring`/`aws-lc-rs` features already decide the answer, pass it
45/// explicitly and never consult the global default.
46///
47/// If neither feature is enabled there is no provider to name, so fall back to whatever the
48/// application installed.
49fn crypto_provider() -> Option<std::sync::Arc<rustls::crypto::CryptoProvider>> {
50    #[cfg(feature = "aws-lc-rs")]
51    {
52        Some(std::sync::Arc::new(
53            rustls::crypto::aws_lc_rs::default_provider(),
54        ))
55    }
56    #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
57    {
58        Some(std::sync::Arc::new(rustls::crypto::ring::default_provider()))
59    }
60    #[cfg(not(any(feature = "ring", feature = "aws-lc-rs")))]
61    {
62        None
63    }
64}
65
66/// Builds the default server-certificate verifier, with an explicit provider where we have one.
67///
68/// # Errors
69///
70/// Fails if the root store holds no usable trust anchors.
71fn server_cert_verifier(
72    roots: std::sync::Arc<rustls::RootCertStore>,
73) -> Result<std::sync::Arc<rustls::client::WebPkiServerVerifier>> {
74    let builder = match crypto_provider() {
75        Some(provider) => {
76            rustls::client::WebPkiServerVerifier::builder_with_provider(roots, provider)
77        }
78        None => rustls::client::WebPkiServerVerifier::builder(roots),
79    };
80    builder
81        .build()
82        .map_err(|err| Error::Other(format!("rustls server cert verifier: {err}")))
83}
84
85/// Config is used to configure a DTLS client or server.
86/// After a Config is passed to a DTLS function it must not be modified.
87#[derive(Clone)]
88pub struct ConfigBuilder {
89    certificates: Vec<Certificate>,
90    cipher_suites: Vec<CipherSuiteId>,
91    signature_schemes: Vec<SignatureScheme>,
92    srtp_protection_profiles: Vec<SrtpProtectionProfile>,
93    client_auth: ClientAuthType,
94    extended_master_secret: ExtendedMasterSecretType,
95    flight_interval: Duration,
96    psk: Option<PskCallback>,
97    psk_identity_hint: Option<Vec<u8>>,
98    insecure_skip_verify: bool,
99    insecure_hashes: bool,
100    insecure_verification: bool,
101    verify_peer_certificate: Option<VerifyPeerCertificateFn>,
102    roots_cas: rustls::RootCertStore,
103    client_cas: rustls::RootCertStore,
104    server_name: String,
105    mtu: usize,
106    replay_protection_window: usize,
107}
108
109impl Default for ConfigBuilder {
110    fn default() -> Self {
111        Self {
112            certificates: vec![],
113            cipher_suites: vec![],
114            signature_schemes: vec![],
115            srtp_protection_profiles: vec![],
116            client_auth: ClientAuthType::default(),
117            extended_master_secret: ExtendedMasterSecretType::default(),
118            flight_interval: Duration::default(),
119            psk: None,
120            psk_identity_hint: None,
121            insecure_skip_verify: false,
122            insecure_hashes: false,
123            insecure_verification: false,
124            verify_peer_certificate: None,
125            roots_cas: rustls::RootCertStore::empty(),
126            client_cas: rustls::RootCertStore::empty(),
127            server_name: String::default(),
128            mtu: 0,
129            replay_protection_window: 0,
130        }
131    }
132}
133
134impl ConfigBuilder {
135    /// certificates contains certificate chain to present to the other side of the connection.
136    /// Server MUST set this if psk is non-nil
137    /// client SHOULD sets this so CertificateRequests can be handled if psk is non-nil
138    pub fn with_certificates(mut self, certificates: Vec<Certificate>) -> Self {
139        self.certificates = certificates;
140        self
141    }
142
143    /// cipher_suites is a list of supported cipher suites.
144    /// If cipher_suites is nil, a default list is used
145    pub fn with_cipher_suites(mut self, cipher_suites: Vec<CipherSuiteId>) -> Self {
146        self.cipher_suites = cipher_suites;
147        self
148    }
149
150    /// signature_schemes contains the signature and hash schemes that the peer requests to verify.
151    pub fn with_signature_schemes(mut self, signature_schemes: Vec<SignatureScheme>) -> Self {
152        self.signature_schemes = signature_schemes;
153        self
154    }
155
156    /// srtp_protection_profiles are the supported protection profiles
157    /// Clients will send this via use_srtp and assert that the server properly responds
158    /// Servers will assert that clients send one of these profiles and will respond as needed
159    pub fn with_srtp_protection_profiles(
160        mut self,
161        srtp_protection_profiles: Vec<SrtpProtectionProfile>,
162    ) -> Self {
163        self.srtp_protection_profiles = srtp_protection_profiles;
164        self
165    }
166
167    /// client_auth determines the server's policy for
168    /// TLS Client Authentication. The default is NoClientCert.
169    pub fn with_client_auth(mut self, client_auth: ClientAuthType) -> Self {
170        self.client_auth = client_auth;
171        self
172    }
173
174    /// extended_master_secret determines if the "Extended Master Secret" extension
175    /// should be disabled, requested, or required (default requested).
176    pub fn with_extended_master_secret(
177        mut self,
178        extended_master_secret: ExtendedMasterSecretType,
179    ) -> Self {
180        self.extended_master_secret = extended_master_secret;
181        self
182    }
183
184    /// flight_interval controls how often we send outbound handshake messages
185    /// defaults to time.Second
186    pub fn with_flight_interval(mut self, flight_interval: Duration) -> Self {
187        self.flight_interval = flight_interval;
188        self
189    }
190
191    /// psk sets the pre-shared key used by this DTLS connection
192    /// If psk is non-nil only psk cipher_suites will be used
193    pub fn with_psk(mut self, psk: Option<PskCallback>) -> Self {
194        self.psk = psk;
195        self
196    }
197
198    /// psk_identity_hint sets the pre-shared key hint
199    pub fn with_psk_identity_hint(mut self, psk_identity_hint: Option<Vec<u8>>) -> Self {
200        self.psk_identity_hint = psk_identity_hint;
201        self
202    }
203
204    /// insecure_skip_verify controls whether a client verifies the
205    /// server's certificate chain and host name.
206    /// If insecure_skip_verify is true, TLS accepts any certificate
207    /// presented by the server and any host name in that certificate.
208    /// In this mode, TLS is susceptible to man-in-the-middle attacks.
209    /// This should be used only for testing.
210    pub fn with_insecure_skip_verify(mut self, insecure_skip_verify: bool) -> Self {
211        self.insecure_skip_verify = insecure_skip_verify;
212        self
213    }
214
215    /// insecure_hashes allows the use of hashing algorithms that are known
216    /// to be vulnerable.
217    pub fn with_insecure_hashes(mut self, insecure_hashes: bool) -> Self {
218        self.insecure_hashes = insecure_hashes;
219        self
220    }
221
222    /// insecure_verification allows the use of verification algorithms that are
223    /// known to be vulnerable or deprecated
224    pub fn with_insecure_verification(mut self, insecure_verification: bool) -> Self {
225        self.insecure_verification = insecure_verification;
226        self
227    }
228
229    /// VerifyPeerCertificate, if not nil, is called after normal
230    /// certificate verification by either a client or server. It
231    /// receives the certificate provided by the peer and also a flag
232    /// that tells if normal verification has succeeded. If it returns a
233    /// non-nil error, the handshake is aborted and that error results.
234    ///
235    /// If normal verification fails then the handshake will abort before
236    /// considering this callback. If normal verification is disabled by
237    /// setting insecure_skip_verify, or (for a server) when client_auth is
238    /// RequestClientCert or RequireAnyClientCert, then this callback will
239    /// be considered but the verifiedChains will always be nil.
240    pub fn with_verify_peer_certificate(
241        mut self,
242        verify_peer_certificate: Option<VerifyPeerCertificateFn>,
243    ) -> Self {
244        self.verify_peer_certificate = verify_peer_certificate;
245        self
246    }
247
248    /// roots_cas defines the set of root certificate authorities
249    /// that one peer uses when verifying the other peer's certificates.
250    /// If RootCAs is nil, TLS uses the host's root CA set.
251    /// Used by Client to verify server's certificate
252    pub fn with_roots_cas(mut self, roots_cas: rustls::RootCertStore) -> Self {
253        self.roots_cas = roots_cas;
254        self
255    }
256
257    /// client_cas defines the set of root certificate authorities
258    /// that servers use if required to verify a client certificate
259    /// by the policy in client_auth.
260    /// Used by Server to verify client's certificate
261    pub fn with_client_cas(mut self, client_cas: rustls::RootCertStore) -> Self {
262        self.client_cas = client_cas;
263        self
264    }
265
266    /// server_name is used to verify the hostname on the returned
267    /// certificates unless insecure_skip_verify is given.
268    pub fn with_server_name(mut self, server_name: String) -> Self {
269        self.server_name = server_name;
270        self
271    }
272
273    /// mtu is the length at which handshake messages will be fragmented to
274    /// fit within the maximum transmission unit (default is 1200 bytes)
275    pub fn with_mtu(mut self, mtu: usize) -> Self {
276        self.mtu = mtu;
277        self
278    }
279
280    /// replay_protection_window is the size of the replay attack protection window.
281    /// Duplication of the sequence number is checked in this window size.
282    /// Packet with sequence number older than this value compared to the latest
283    /// accepted packet will be discarded. (default is 64)
284    pub fn with_replay_protection_window(mut self, replay_protection_window: usize) -> Self {
285        self.replay_protection_window = replay_protection_window;
286        self
287    }
288}
289
290pub(crate) const DEFAULT_MTU: usize = 1200; // bytes
291
292/// PSKCallback is called once we have the remote's psk_identity_hint.
293/// If the remote provided none it will be nil
294pub(crate) type PskCallback = Arc<dyn (Fn(&[u8]) -> Result<Vec<u8>>) + Send + Sync>;
295
296/// ClientAuthType declares the policy the server will follow for
297/// TLS Client Authentication.
298#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
299pub enum ClientAuthType {
300    #[default]
301    /// `NO_CLIENT_CERT` (`0`).
302    NoClientCert = 0,
303    /// `REQUEST_CLIENT_CERT` (`1`).
304    RequestClientCert = 1,
305    /// `REQUIRE_ANY_CLIENT_CERT` (`2`).
306    RequireAnyClientCert = 2,
307    /// `VERIFY_CLIENT_CERT_IF_GIVEN` (`3`).
308    VerifyClientCertIfGiven = 3,
309    /// `REQUIRE_AND_VERIFY_CLIENT_CERT` (`4`).
310    RequireAndVerifyClientCert = 4,
311}
312
313// ExtendedMasterSecretType declares the policy the client and server
314// will follow for the Extended Master Secret extension
315#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
316/// How strictly to require the extended master secret extension ([RFC 7627]).
317pub enum ExtendedMasterSecretType {
318    #[default]
319    /// `REQUEST` (`0`).
320    Request = 0,
321    /// `REQUIRE` (`1`).
322    Require = 1,
323    /// `DISABLE` (`2`).
324    Disable = 2,
325}
326
327impl ConfigBuilder {
328    fn validate(&self, is_client: bool) -> Result<()> {
329        if is_client && self.psk.is_some() && self.psk_identity_hint.is_none() {
330            return Err(Error::ErrPskAndIdentityMustBeSetForClient);
331        }
332
333        if !is_client && self.psk.is_none() && self.certificates.is_empty() {
334            return Err(Error::ErrServerMustHaveCertificate);
335        }
336
337        if !self.certificates.is_empty() && self.psk.is_some() {
338            return Err(Error::ErrPskAndCertificate);
339        }
340
341        if self.psk_identity_hint.is_some() && self.psk.is_none() {
342            return Err(Error::ErrIdentityNoPsk);
343        }
344
345        for cert in &self.certificates {
346            match cert.private_key.kind {
347                CryptoPrivateKeyKind::Ed25519(_) => {}
348                CryptoPrivateKeyKind::Ecdsa256(_) => {}
349                CryptoPrivateKeyKind::Custom(_) => {}
350                _ => return Err(Error::ErrInvalidPrivateKey),
351            }
352        }
353
354        parse_cipher_suites(&self.cipher_suites, self.psk.is_none(), self.psk.is_some())?;
355
356        Ok(())
357    }
358
359    /// build handshake config
360    pub fn build(
361        mut self,
362        is_client: bool,
363        remote_addr: Option<SocketAddr>,
364    ) -> Result<HandshakeConfig> {
365        self.validate(is_client)?;
366
367        let local_cipher_suites: Vec<CipherSuiteId> =
368            parse_cipher_suites(&self.cipher_suites, self.psk.is_none(), self.psk.is_some())?
369                .iter()
370                .map(|cs| cs.id())
371                .collect();
372
373        let sigs: Vec<u16> = self.signature_schemes.iter().map(|x| *x as u16).collect();
374        let local_signature_schemes = parse_signature_schemes(&sigs, self.insecure_hashes)?;
375
376        let retransmit_interval = if self.flight_interval != Duration::from_secs(0) {
377            self.flight_interval
378        } else {
379            INITIAL_TICKER_INTERVAL
380        };
381
382        let maximum_transmission_unit = if self.mtu == 0 { DEFAULT_MTU } else { self.mtu };
383
384        let replay_protection_window = if self.replay_protection_window == 0 {
385            DEFAULT_REPLAY_PROTECTION_WINDOW
386        } else {
387            self.replay_protection_window
388        };
389
390        let mut server_name = self.server_name.clone();
391
392        // Use host from conn address when server_name is not provided
393        if is_client && server_name.is_empty() {
394            if let Some(remote_addr) = remote_addr {
395                server_name = remote_addr.ip().to_string();
396            } else {
397                warn!(
398                    "conn.remote_addr is empty, please set explicitly server_name in Config! Use default \"localhost\" as server_name now"
399                );
400                "localhost".clone_into(&mut server_name);
401            }
402        }
403
404        Ok(HandshakeConfig {
405            local_psk_callback: self.psk.take(),
406            local_psk_identity_hint: self.psk_identity_hint.take(),
407            local_cipher_suites,
408            local_signature_schemes,
409            extended_master_secret: self.extended_master_secret,
410            local_srtp_protection_profiles: self.srtp_protection_profiles,
411            server_name,
412            client_auth: self.client_auth,
413            local_certificates: self.certificates,
414            insecure_skip_verify: self.insecure_skip_verify,
415            insecure_verification: self.insecure_verification,
416            verify_peer_certificate: self.verify_peer_certificate.take(),
417            roots_cas: self.roots_cas,
418            server_cert_verifier: server_cert_verifier(Arc::new(gen_self_signed_root_cert()))?,
419            client_cert_verifier: None,
420            retransmit_interval,
421            initial_epoch: 0,
422            maximum_transmission_unit,
423            replay_protection_window,
424            ..Default::default()
425        })
426    }
427}
428
429/// A callback that decides whether a peer's certificate chain is acceptable.
430///
431/// WebRTC verifies the fingerprint from SDP instead of a CA chain, so this is where that check
432/// goes.
433pub type VerifyPeerCertificateFn =
434    Arc<dyn (Fn(&[Vec<u8>], &[CertificateDer<'static>]) -> Result<()>) + Send + Sync>;
435
436/// Generates a self-signed certificate, as WebRTC endpoints use.
437pub fn gen_self_signed_root_cert() -> rustls::RootCertStore {
438    let mut certs = rustls::RootCertStore::empty();
439    certs
440        .add(
441            rcgen::generate_simple_self_signed(vec![])
442                .unwrap()
443                .cert
444                .der()
445                .to_owned(),
446        )
447        .unwrap();
448    certs
449}
450
451#[derive(Clone)]
452/// The resolved configuration a handshake runs with, produced by [`ConfigBuilder::build`].
453pub struct HandshakeConfig {
454    pub(crate) local_psk_callback: Option<PskCallback>,
455    pub(crate) local_psk_identity_hint: Option<Vec<u8>>,
456    pub(crate) local_cipher_suites: Vec<CipherSuiteId>, // Available CipherSuites
457    pub(crate) local_signature_schemes: Vec<SignatureHashAlgorithm>, // Available signature schemes
458    pub(crate) extended_master_secret: ExtendedMasterSecretType, // Policy for the Extended Master Support extension
459    pub(crate) local_srtp_protection_profiles: Vec<SrtpProtectionProfile>, // Available SRTPProtectionProfiles, if empty no SRTP support
460    pub(crate) server_name: String,
461    pub(crate) client_auth: ClientAuthType, // If we are a client should we request a client certificate
462    pub(crate) local_certificates: Vec<Certificate>,
463    pub(crate) name_to_certificate: HashMap<String, Certificate>,
464    pub(crate) insecure_skip_verify: bool,
465    pub(crate) insecure_verification: bool,
466    pub(crate) verify_peer_certificate: Option<VerifyPeerCertificateFn>,
467    pub(crate) roots_cas: rustls::RootCertStore,
468    pub(crate) server_cert_verifier: Arc<dyn ServerCertVerifier>,
469    pub(crate) client_cert_verifier: Option<Arc<dyn ClientCertVerifier>>,
470    pub(crate) retransmit_interval: std::time::Duration,
471    pub(crate) initial_epoch: u16,
472    pub(crate) maximum_transmission_unit: usize,
473    pub(crate) maximum_retransmit_number: usize,
474    pub(crate) replay_protection_window: usize,
475}
476
477impl fmt::Debug for HandshakeConfig {
478    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
479        fmt.debug_struct("HandshakeConfig<T>")
480            .field("local_psk_identity_hint", &self.local_psk_identity_hint)
481            .field("local_cipher_suites", &self.local_cipher_suites)
482            .field("local_signature_schemes", &self.local_signature_schemes)
483            .field("extended_master_secret", &self.extended_master_secret)
484            .field(
485                "local_srtp_protection_profiles",
486                &self.local_srtp_protection_profiles,
487            )
488            .field("server_name", &self.server_name)
489            .field("client_auth", &self.client_auth)
490            .field("local_certificates", &self.local_certificates)
491            .field("name_to_certificate", &self.name_to_certificate)
492            .field("insecure_skip_verify", &self.insecure_skip_verify)
493            .field("insecure_verification", &self.insecure_verification)
494            .field("roots_cas", &self.roots_cas)
495            .field("retransmit_interval", &self.retransmit_interval)
496            .field("initial_epoch", &self.initial_epoch)
497            .field("maximum_transmission_unit", &self.maximum_transmission_unit)
498            .field("maximum_retransmit_number", &self.maximum_retransmit_number)
499            .field("replay_protection_window", &self.replay_protection_window)
500            .finish()
501    }
502}
503
504impl Default for HandshakeConfig {
505    fn default() -> Self {
506        HandshakeConfig {
507            local_psk_callback: None,
508            local_psk_identity_hint: None,
509            local_cipher_suites: vec![],
510            local_signature_schemes: vec![],
511            extended_master_secret: ExtendedMasterSecretType::Disable,
512            local_srtp_protection_profiles: vec![],
513            server_name: String::new(),
514            client_auth: ClientAuthType::NoClientCert,
515            local_certificates: vec![],
516            name_to_certificate: HashMap::new(),
517            insecure_skip_verify: false,
518            insecure_verification: false,
519            verify_peer_certificate: None,
520            roots_cas: rustls::RootCertStore::empty(),
521            server_cert_verifier: server_cert_verifier(Arc::new(gen_self_signed_root_cert()))
522                .expect("the built-in self-signed root is always a valid trust anchor"),
523            client_cert_verifier: None,
524            retransmit_interval: std::time::Duration::from_secs(0),
525            initial_epoch: 0,
526            maximum_transmission_unit: DEFAULT_MTU,
527            maximum_retransmit_number: 7,
528            replay_protection_window: DEFAULT_REPLAY_PROTECTION_WINDOW,
529        }
530    }
531}
532
533impl HandshakeConfig {
534    pub(crate) fn get_certificate(&self, server_name: &str) -> Result<Certificate> {
535        if self.local_certificates.is_empty() {
536            return Err(Error::ErrNoCertificates);
537        }
538
539        if self.local_certificates.len() == 1 {
540            // There's only one choice, so no point doing any work.
541            return Ok(self.local_certificates[0].clone());
542        }
543
544        if server_name.is_empty() {
545            return Ok(self.local_certificates[0].clone());
546        }
547
548        let lower = server_name.to_lowercase();
549        let name = lower.trim_end_matches('.');
550
551        if let Some(cert) = self.name_to_certificate.get(name) {
552            return Ok(cert.clone());
553        }
554
555        // try replacing labels in the name with wildcards until we get a
556        // match.
557        let mut labels: Vec<&str> = name.split_terminator('.').collect();
558        for i in 0..labels.len() {
559            labels[i] = "*";
560            let candidate = labels.join(".");
561            if let Some(cert) = self.name_to_certificate.get(&candidate) {
562                return Ok(cert.clone());
563            }
564        }
565
566        // If nothing matches, return the first certificate.
567        Ok(self.local_certificates[0].clone())
568    }
569}