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        // Gates future private key kinds from being automatically allowed.
346        for cert in &self.certificates {
347            match cert.private_key.kind {
348                CryptoPrivateKeyKind::Ed25519(_) => {}
349                CryptoPrivateKeyKind::Ecdsa256(_) => {}
350                CryptoPrivateKeyKind::Rsa256(_) => {}
351                CryptoPrivateKeyKind::Custom(_) => {}
352            }
353        }
354
355        parse_cipher_suites(&self.cipher_suites, self.psk.is_none(), self.psk.is_some())?;
356
357        Ok(())
358    }
359
360    /// build handshake config
361    pub fn build(
362        mut self,
363        is_client: bool,
364        remote_addr: Option<SocketAddr>,
365    ) -> Result<HandshakeConfig> {
366        self.validate(is_client)?;
367
368        let local_cipher_suites: Vec<CipherSuiteId> =
369            parse_cipher_suites(&self.cipher_suites, self.psk.is_none(), self.psk.is_some())?
370                .iter()
371                .map(|cs| cs.id())
372                .collect();
373
374        let sigs: Vec<u16> = self.signature_schemes.iter().map(|x| *x as u16).collect();
375        let local_signature_schemes = parse_signature_schemes(&sigs, self.insecure_hashes)?;
376
377        let retransmit_interval = if self.flight_interval != Duration::from_secs(0) {
378            self.flight_interval
379        } else {
380            INITIAL_TICKER_INTERVAL
381        };
382
383        let maximum_transmission_unit = if self.mtu == 0 { DEFAULT_MTU } else { self.mtu };
384
385        let replay_protection_window = if self.replay_protection_window == 0 {
386            DEFAULT_REPLAY_PROTECTION_WINDOW
387        } else {
388            self.replay_protection_window
389        };
390
391        let mut server_name = self.server_name.clone();
392
393        // Use host from conn address when server_name is not provided
394        if is_client && server_name.is_empty() {
395            if let Some(remote_addr) = remote_addr {
396                server_name = remote_addr.ip().to_string();
397            } else {
398                warn!(
399                    "conn.remote_addr is empty, please set explicitly server_name in Config! Use default \"localhost\" as server_name now"
400                );
401                "localhost".clone_into(&mut server_name);
402            }
403        }
404
405        Ok(HandshakeConfig {
406            local_psk_callback: self.psk.take(),
407            local_psk_identity_hint: self.psk_identity_hint.take(),
408            local_cipher_suites,
409            local_signature_schemes,
410            extended_master_secret: self.extended_master_secret,
411            local_srtp_protection_profiles: self.srtp_protection_profiles,
412            server_name,
413            client_auth: self.client_auth,
414            local_certificates: self.certificates,
415            insecure_skip_verify: self.insecure_skip_verify,
416            insecure_verification: self.insecure_verification,
417            verify_peer_certificate: self.verify_peer_certificate.take(),
418            roots_cas: self.roots_cas,
419            server_cert_verifier: server_cert_verifier(Arc::new(gen_self_signed_root_cert()))?,
420            client_cert_verifier: None,
421            retransmit_interval,
422            initial_epoch: 0,
423            maximum_transmission_unit,
424            replay_protection_window,
425            ..Default::default()
426        })
427    }
428}
429
430/// A callback that decides whether a peer's certificate chain is acceptable.
431///
432/// WebRTC verifies the fingerprint from SDP instead of a CA chain, so this is where that check
433/// goes.
434pub type VerifyPeerCertificateFn =
435    Arc<dyn (Fn(&[Vec<u8>], &[CertificateDer<'static>]) -> Result<()>) + Send + Sync>;
436
437/// Generates a self-signed certificate, as WebRTC endpoints use.
438pub fn gen_self_signed_root_cert() -> rustls::RootCertStore {
439    let mut certs = rustls::RootCertStore::empty();
440    certs
441        .add(
442            rcgen::generate_simple_self_signed(vec![])
443                .unwrap()
444                .cert
445                .der()
446                .to_owned(),
447        )
448        .unwrap();
449    certs
450}
451
452#[derive(Clone)]
453/// The resolved configuration a handshake runs with, produced by [`ConfigBuilder::build`].
454pub struct HandshakeConfig {
455    pub(crate) local_psk_callback: Option<PskCallback>,
456    pub(crate) local_psk_identity_hint: Option<Vec<u8>>,
457    pub(crate) local_cipher_suites: Vec<CipherSuiteId>, // Available CipherSuites
458    pub(crate) local_signature_schemes: Vec<SignatureHashAlgorithm>, // Available signature schemes
459    pub(crate) extended_master_secret: ExtendedMasterSecretType, // Policy for the Extended Master Support extension
460    pub(crate) local_srtp_protection_profiles: Vec<SrtpProtectionProfile>, // Available SRTPProtectionProfiles, if empty no SRTP support
461    pub(crate) server_name: String,
462    pub(crate) client_auth: ClientAuthType, // If we are a client should we request a client certificate
463    pub(crate) local_certificates: Vec<Certificate>,
464    pub(crate) name_to_certificate: HashMap<String, Certificate>,
465    pub(crate) insecure_skip_verify: bool,
466    pub(crate) insecure_verification: bool,
467    pub(crate) verify_peer_certificate: Option<VerifyPeerCertificateFn>,
468    pub(crate) roots_cas: rustls::RootCertStore,
469    pub(crate) server_cert_verifier: Arc<dyn ServerCertVerifier>,
470    pub(crate) client_cert_verifier: Option<Arc<dyn ClientCertVerifier>>,
471    pub(crate) retransmit_interval: std::time::Duration,
472    pub(crate) initial_epoch: u16,
473    pub(crate) maximum_transmission_unit: usize,
474    pub(crate) maximum_retransmit_number: usize,
475    pub(crate) replay_protection_window: usize,
476}
477
478impl fmt::Debug for HandshakeConfig {
479    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
480        fmt.debug_struct("HandshakeConfig<T>")
481            .field("local_psk_identity_hint", &self.local_psk_identity_hint)
482            .field("local_cipher_suites", &self.local_cipher_suites)
483            .field("local_signature_schemes", &self.local_signature_schemes)
484            .field("extended_master_secret", &self.extended_master_secret)
485            .field(
486                "local_srtp_protection_profiles",
487                &self.local_srtp_protection_profiles,
488            )
489            .field("server_name", &self.server_name)
490            .field("client_auth", &self.client_auth)
491            .field("local_certificates", &self.local_certificates)
492            .field("name_to_certificate", &self.name_to_certificate)
493            .field("insecure_skip_verify", &self.insecure_skip_verify)
494            .field("insecure_verification", &self.insecure_verification)
495            .field("roots_cas", &self.roots_cas)
496            .field("retransmit_interval", &self.retransmit_interval)
497            .field("initial_epoch", &self.initial_epoch)
498            .field("maximum_transmission_unit", &self.maximum_transmission_unit)
499            .field("maximum_retransmit_number", &self.maximum_retransmit_number)
500            .field("replay_protection_window", &self.replay_protection_window)
501            .finish()
502    }
503}
504
505impl Default for HandshakeConfig {
506    fn default() -> Self {
507        HandshakeConfig {
508            local_psk_callback: None,
509            local_psk_identity_hint: None,
510            local_cipher_suites: vec![],
511            local_signature_schemes: vec![],
512            extended_master_secret: ExtendedMasterSecretType::Disable,
513            local_srtp_protection_profiles: vec![],
514            server_name: String::new(),
515            client_auth: ClientAuthType::NoClientCert,
516            local_certificates: vec![],
517            name_to_certificate: HashMap::new(),
518            insecure_skip_verify: false,
519            insecure_verification: false,
520            verify_peer_certificate: None,
521            roots_cas: rustls::RootCertStore::empty(),
522            server_cert_verifier: server_cert_verifier(Arc::new(gen_self_signed_root_cert()))
523                .expect("the built-in self-signed root is always a valid trust anchor"),
524            client_cert_verifier: None,
525            retransmit_interval: std::time::Duration::from_secs(0),
526            initial_epoch: 0,
527            maximum_transmission_unit: DEFAULT_MTU,
528            maximum_retransmit_number: 7,
529            replay_protection_window: DEFAULT_REPLAY_PROTECTION_WINDOW,
530        }
531    }
532}
533
534impl HandshakeConfig {
535    pub(crate) fn get_certificate(&self, server_name: &str) -> Result<Certificate> {
536        if self.local_certificates.is_empty() {
537            return Err(Error::ErrNoCertificates);
538        }
539
540        if self.local_certificates.len() == 1 {
541            // There's only one choice, so no point doing any work.
542            return Ok(self.local_certificates[0].clone());
543        }
544
545        if server_name.is_empty() {
546            return Ok(self.local_certificates[0].clone());
547        }
548
549        let lower = server_name.to_lowercase();
550        let name = lower.trim_end_matches('.');
551
552        if let Some(cert) = self.name_to_certificate.get(name) {
553            return Ok(cert.clone());
554        }
555
556        // try replacing labels in the name with wildcards until we get a
557        // match.
558        let mut labels: Vec<&str> = name.split_terminator('.').collect();
559        for i in 0..labels.len() {
560            labels[i] = "*";
561            let candidate = labels.join(".");
562            if let Some(cert) = self.name_to_certificate.get(&candidate) {
563                return Ok(cert.clone());
564            }
565        }
566
567        // If nothing matches, return the first certificate.
568        Ok(self.local_certificates[0].clone())
569    }
570}