msf_srtp/
lib.rs

1//! This crate implements DTLS-SRTP as defined in RFC 5764. The RFC is built on
2//! top of:
3//! * RFC 3711 (SRTP)
4//! * RFC 4347 (DTLS)
5//! * RFC 8122 (TLS in SDP)
6//!
7//! # Usage example
8//! ```ignore
9//! use openssl::{pkey::PKey, rsa::Rsa};
10//!
11//! // a UDP stream + sink
12//! let stream = ...;
13//!
14//! // peer certificate fingerprint from SDP
15//! let cert_fingerprint = "...";
16//!
17//! // peer setup attribute from SDP
18//! let setup = "...";
19//!
20//! let connect = match setup {
21//!     "active" | "actpass" => true,
22//!     "passive" => false,
23//!     _ => panic!("unsupported setup"),
24//! };
25//!
26//! // generate a private key (can be application-wide)
27//! let rsa = Rsa::generate(2048)?;
28//! let key = PKey::from_rsa(rsa)?;
29//!
30//! let context = SrtpContext::self_signed(&key)?;
31//!
32//! let stream = if connect {
33//!     context.connect_muxed(stream, cert_fingerprint).await?
34//! } else {
35//!     context.accept_muxed(stream, cert_fingerprint).await?
36//! };
37//! ```
38
39mod connector;
40mod fingerprint;
41mod key_stream;
42mod profile;
43mod session;
44
45use std::{
46    fmt::{self, Display, Formatter, Write},
47    future::Future,
48    io, ptr,
49};
50
51use bytes::Bytes;
52use futures::{Sink, Stream};
53use openssl::{
54    asn1::Asn1Time,
55    hash::MessageDigest,
56    pkey::{HasPrivate, PKeyRef},
57    ssl::{Ssl, SslContext, SslMethod, SslVerifyMode},
58    x509::{X509Ref, X509},
59};
60
61use self::connector::Connector;
62
63pub use msf_rtp::transceiver::{RtpTransceiver, RtpTransceiverOptions, SSRC2ClockRate, SSRCMode};
64
65pub use self::{
66    connector::{MuxedSrtpStream, SrtcpStream, SrtpStream},
67    fingerprint::{CertificateFingerprint, HashFunction, InvalidFingerprint, UnknownHashFunction},
68    profile::SrtpProfileId,
69};
70
71/// SRTP error.
72#[derive(Debug)]
73pub struct Error {
74    inner: InternalError,
75}
76
77impl Display for Error {
78    #[inline]
79    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
80        Display::fmt(&self.inner, f)
81    }
82}
83
84impl std::error::Error for Error {}
85
86impl From<openssl::error::ErrorStack> for Error {
87    fn from(err: openssl::error::ErrorStack) -> Self {
88        Self::from(InternalError::from(err))
89    }
90}
91
92impl From<io::Error> for Error {
93    fn from(err: io::Error) -> Self {
94        Self::from(InternalError::from(err))
95    }
96}
97
98impl From<InternalError> for Error {
99    fn from(err: InternalError) -> Self {
100        Self { inner: err }
101    }
102}
103
104/// Internal error.
105#[derive(Debug)]
106enum InternalError {
107    MissingProfile,
108    UnsupportedProfile,
109    InvalidPacketType,
110    InvalidFingerprint(InvalidFingerprint),
111    OpenSslError(OpenSslError),
112    IOError(io::Error),
113}
114
115impl Display for InternalError {
116    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
117        match self {
118            Self::MissingProfile => f.write_str("no SRTP profile selected"),
119            Self::UnsupportedProfile => f.write_str("unsupported SRTP profile"),
120            Self::InvalidPacketType => f.write_str("invalid packet type"),
121            Self::InvalidFingerprint(err) => write!(f, "invalid fingerprint: {err}"),
122            Self::OpenSslError(err) => write!(f, "SSL error: {err}"),
123            Self::IOError(err) => write!(f, "IO error: {err}"),
124        }
125    }
126}
127
128impl std::error::Error for InternalError {}
129
130impl From<InvalidFingerprint> for InternalError {
131    fn from(err: InvalidFingerprint) -> Self {
132        Self::InvalidFingerprint(err)
133    }
134}
135
136impl From<openssl::error::Error> for InternalError {
137    fn from(err: openssl::error::Error) -> Self {
138        Self::OpenSslError(err.into())
139    }
140}
141
142impl From<openssl::error::ErrorStack> for InternalError {
143    fn from(err: openssl::error::ErrorStack) -> Self {
144        Self::OpenSslError(err.into())
145    }
146}
147
148impl From<openssl::ssl::Error> for InternalError {
149    fn from(err: openssl::ssl::Error) -> Self {
150        Self::OpenSslError(err.into())
151    }
152}
153
154impl From<io::Error> for InternalError {
155    fn from(err: io::Error) -> Self {
156        Self::IOError(err)
157    }
158}
159
160/// OpenSSL error.
161#[derive(Debug)]
162enum OpenSslError {
163    Error(openssl::error::Error),
164    ErrorStack(openssl::error::ErrorStack),
165    SslError(openssl::ssl::Error),
166}
167
168impl Display for OpenSslError {
169    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
170        match self {
171            Self::Error(err) => Display::fmt(err, f),
172            Self::ErrorStack(err) => Display::fmt(err, f),
173            Self::SslError(err) => Display::fmt(err, f),
174        }
175    }
176}
177
178impl std::error::Error for OpenSslError {}
179
180impl From<openssl::error::Error> for OpenSslError {
181    fn from(err: openssl::error::Error) -> Self {
182        Self::Error(err)
183    }
184}
185
186impl From<openssl::error::ErrorStack> for OpenSslError {
187    fn from(err: openssl::error::ErrorStack) -> Self {
188        Self::ErrorStack(err)
189    }
190}
191
192impl From<openssl::ssl::Error> for OpenSslError {
193    fn from(err: openssl::ssl::Error) -> Self {
194        Self::SslError(err)
195    }
196}
197
198/// SRTP context builder.
199pub struct SrtpContextBuilder {
200    profiles: Vec<SrtpProfileId>,
201}
202
203impl SrtpContextBuilder {
204    /// Create a new builder.
205    fn new() -> Self {
206        Self {
207            profiles: Vec::new(),
208        }
209    }
210
211    /// Enable a given SRTP profile.
212    ///
213    /// Multiple SRTP profiles can be enabled by calling this method multiple
214    /// times. The order in which you enable SRTP profiles matters. The first
215    /// enabled profile will have the highest priority when negotiating session
216    /// parameters with a remote peer.
217    ///
218    /// If you don't enable any profiles, the default profiles will be enabled:
219    /// * `SRTP_AES128_CM_SHA1_80`
220    /// * `SRTP_AES128_CM_SHA1_32`
221    #[inline]
222    pub fn profile(mut self, profile: SrtpProfileId) -> Self {
223        self.profiles.push(profile);
224        self
225    }
226
227    /// Create a new SRTP context from a given SSL context.
228    ///
229    /// # Panics
230    /// This methods panics if the given SSL context does not contain any
231    /// private key or certificate.
232    pub fn with_ssl_context(mut self, context: SslContext) -> Result<SrtpContext, Error> {
233        assert!(context.certificate().is_some());
234        assert!(context.private_key().is_some());
235
236        if self.profiles.is_empty() {
237            self.profiles = vec![
238                SrtpProfileId::SRTP_AES128_CM_SHA1_80,
239                SrtpProfileId::SRTP_AES128_CM_SHA1_32,
240            ];
241        }
242
243        let mut profiles = String::new();
244
245        let mut iter = self.profiles.iter();
246
247        if let Some(profile) = iter.next() {
248            let _ = write!(profiles, "{profile}");
249        }
250
251        for profile in iter {
252            let _ = write!(profiles, ":{profile}");
253        }
254
255        let res = SrtpContext {
256            ssl_context: context,
257            srtp_profiles: profiles,
258        };
259
260        Ok(res)
261    }
262
263    /// Create a new SRTP context from a given private key and a corresponding
264    /// certificate.
265    pub fn build<T>(self, key: &PKeyRef<T>, cert: &X509Ref) -> Result<SrtpContext, Error>
266    where
267        T: HasPrivate,
268    {
269        let mut ssl_ctx_builder = SslContext::builder(SslMethod::dtls())?;
270
271        ssl_ctx_builder.set_certificate(cert)?;
272        ssl_ctx_builder.set_private_key(key)?;
273
274        self.with_ssl_context(ssl_ctx_builder.build())
275    }
276
277    /// Create a new SRTP context with a self-signed certificate from a given
278    /// private key.
279    pub fn self_signed<T>(self, key: &PKeyRef<T>) -> Result<SrtpContext, Error>
280    where
281        T: HasPrivate,
282    {
283        let now = unsafe { libc::time(ptr::null_mut()) };
284
285        let not_before = Asn1Time::from_unix(now)?;
286
287        let mut cert_builder = X509::builder()?;
288
289        cert_builder.set_pubkey(key)?;
290        cert_builder.set_not_before(&not_before)?;
291        cert_builder.sign(key, MessageDigest::sha256())?;
292
293        let public_cert = cert_builder.build();
294
295        self.build(key, &public_cert)
296    }
297}
298
299/// SRTP context.
300pub struct SrtpContext {
301    ssl_context: SslContext,
302    srtp_profiles: String,
303}
304
305impl SrtpContext {
306    /// Get an SRTP context builder.
307    #[inline]
308    pub fn builder() -> SrtpContextBuilder {
309        SrtpContextBuilder::new()
310    }
311
312    /// Create a new SRTP context builder that will use a given private key,
313    /// certificate and default parameters.
314    #[inline]
315    pub fn new<T>(key: &PKeyRef<T>, cert: &X509Ref) -> Result<Self, Error>
316    where
317        T: HasPrivate,
318    {
319        Self::builder().build(key, cert)
320    }
321
322    /// Create a new SRTP context with self signed certificate from a given key
323    /// and use default parameters.
324    #[inline]
325    pub fn self_signed<T>(key: &PKeyRef<T>) -> Result<Self, Error>
326    where
327        T: HasPrivate,
328    {
329        Self::builder().self_signed(key)
330    }
331
332    /// Create a new SRTP context from a given SSL context and use default
333    /// parameters.
334    ///
335    /// # Panics
336    /// The method panics if the given context does not contain any private key
337    /// or a certificate.
338    #[inline]
339    pub fn from_ssl_context(context: SslContext) -> Result<Self, Error> {
340        Self::builder().with_ssl_context(context)
341    }
342
343    /// Get a certificate fingerprint.
344    #[inline]
345    pub fn certificate_fingerprint(
346        &self,
347        hash_function: HashFunction,
348    ) -> Result<CertificateFingerprint, Error> {
349        let cert = self.ssl_context.certificate();
350
351        CertificateFingerprint::new(cert.unwrap(), hash_function)
352    }
353
354    /// Connect to a given SRTP "server" and check that the peer certificate
355    /// matches a given fingerprint.
356    pub fn connect_srtp<S>(
357        &self,
358        stream: S,
359        peer_cert_fingerprint: CertificateFingerprint,
360        options: RtpTransceiverOptions,
361    ) -> impl Future<Output = Result<SrtpStream<S>, Error>>
362    where
363        S: Stream<Item = io::Result<Bytes>>,
364        S: Sink<Bytes, Error = io::Error>,
365        S: Unpin,
366    {
367        let connector = self.new_connector(peer_cert_fingerprint);
368
369        async move { connector?.connect_srtp(stream, options).await }
370    }
371
372    /// Connect to a given SRTCP "server" and check that the peer certificate
373    /// matches a given fingerprint.
374    pub fn connect_srtcp<S>(
375        &self,
376        stream: S,
377        peer_cert_fingerprint: CertificateFingerprint,
378    ) -> impl Future<Output = Result<SrtcpStream<S>, Error>>
379    where
380        S: Stream<Item = io::Result<Bytes>>,
381        S: Sink<Bytes, Error = io::Error>,
382        S: Unpin,
383    {
384        let connector = self.new_connector(peer_cert_fingerprint);
385
386        async move { connector?.connect_srtcp(stream).await }
387    }
388
389    /// Connect to a given muxed SRTP-SRTCP "server" and check that the peer
390    /// certificate matches a given fingerprint.
391    pub fn connect_muxed<S>(
392        &self,
393        stream: S,
394        peer_cert_fingerprint: CertificateFingerprint,
395        options: RtpTransceiverOptions,
396    ) -> impl Future<Output = Result<MuxedSrtpStream<S>, Error>>
397    where
398        S: Stream<Item = io::Result<Bytes>>,
399        S: Sink<Bytes, Error = io::Error>,
400        S: Unpin,
401    {
402        let connector = self.new_connector(peer_cert_fingerprint);
403
404        async move { connector?.connect_muxed(stream, options).await }
405    }
406
407    /// Accept connection from a given SRTP "client" and check that the peer
408    /// certificate matches a given fingerprint.
409    pub fn accept_srtp<S>(
410        &self,
411        stream: S,
412        peer_cert_fingerprint: CertificateFingerprint,
413        options: RtpTransceiverOptions,
414    ) -> impl Future<Output = Result<SrtpStream<S>, Error>>
415    where
416        S: Stream<Item = io::Result<Bytes>>,
417        S: Sink<Bytes, Error = io::Error>,
418        S: Unpin,
419    {
420        let connector = self.new_connector(peer_cert_fingerprint);
421
422        async move { connector?.accept_srtp(stream, options).await }
423    }
424
425    /// Accept connection from a given SRTCP "client" and check that the peer
426    /// certificate matches a given fingerprint.
427    pub fn accept_srtcp<S>(
428        &self,
429        stream: S,
430        peer_cert_fingerprint: CertificateFingerprint,
431    ) -> impl Future<Output = Result<SrtcpStream<S>, Error>>
432    where
433        S: Stream<Item = io::Result<Bytes>>,
434        S: Sink<Bytes, Error = io::Error>,
435        S: Unpin,
436    {
437        let connector = self.new_connector(peer_cert_fingerprint);
438
439        async move { connector?.accept_srtcp(stream).await }
440    }
441
442    /// Accept connection from a given muxed SRTP-SRTCP "client" and check that
443    /// the peer certificate matches a given fingerprint.
444    pub fn accept_muxed<S>(
445        &self,
446        stream: S,
447        peer_cert_fingerprint: CertificateFingerprint,
448        options: RtpTransceiverOptions,
449    ) -> impl Future<Output = Result<MuxedSrtpStream<S>, Error>>
450    where
451        S: Stream<Item = io::Result<Bytes>>,
452        S: Sink<Bytes, Error = io::Error>,
453        S: Unpin,
454    {
455        let connector = self.new_connector(peer_cert_fingerprint);
456
457        async move { connector?.accept_muxed(stream, options).await }
458    }
459
460    /// Create a new connector.
461    fn new_connector(
462        &self,
463        peer_cert_fingerprint: CertificateFingerprint,
464    ) -> Result<Connector, InternalError> {
465        let mut ssl = Ssl::new(&self.ssl_context)?;
466
467        ssl.set_tlsext_use_srtp(&self.srtp_profiles)?;
468
469        let verify_mode = SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT;
470
471        ssl.set_verify_callback(verify_mode, move |_, store| {
472            if let Some(chain) = store.chain() {
473                if let Some(cert) = chain.get(0) {
474                    if let Ok(success) = peer_cert_fingerprint.verify(cert) {
475                        return success;
476                    }
477                }
478            }
479
480            false
481        });
482
483        Ok(Connector::new(ssl))
484    }
485}