mod connector;
mod fingerprint;
mod key_stream;
mod profile;
mod session;
use std::{
fmt::{self, Display, Formatter, Write},
future::Future,
io, ptr,
};
use bytes::Bytes;
use futures::{Sink, Stream};
use openssl::{
asn1::Asn1Time,
hash::MessageDigest,
pkey::{HasPrivate, PKeyRef},
ssl::{Ssl, SslContext, SslMethod, SslVerifyMode},
x509::{X509Ref, X509},
};
use self::connector::Connector;
pub use msf_rtp::transceiver::{RtpTransceiver, RtpTransceiverOptions, SSRC2ClockRate, SSRCMode};
pub use self::{
connector::{MuxedSrtpStream, SrtcpStream, SrtpStream},
fingerprint::{CertificateFingerprint, HashFunction, InvalidFingerprint, UnknownHashFunction},
profile::SrtpProfileId,
};
#[derive(Debug)]
pub struct Error {
inner: InternalError,
}
impl Display for Error {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(&self.inner, f)
}
}
impl std::error::Error for Error {}
impl From<openssl::error::ErrorStack> for Error {
fn from(err: openssl::error::ErrorStack) -> Self {
Self::from(InternalError::from(err))
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Self::from(InternalError::from(err))
}
}
impl From<InternalError> for Error {
fn from(err: InternalError) -> Self {
Self { inner: err }
}
}
#[derive(Debug)]
enum InternalError {
MissingProfile,
UnsupportedProfile,
InvalidPacketType,
InvalidFingerprint(InvalidFingerprint),
OpenSslError(OpenSslError),
IOError(io::Error),
}
impl Display for InternalError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::MissingProfile => f.write_str("no SRTP profile selected"),
Self::UnsupportedProfile => f.write_str("unsupported SRTP profile"),
Self::InvalidPacketType => f.write_str("invalid packet type"),
Self::InvalidFingerprint(err) => write!(f, "invalid fingerprint: {err}"),
Self::OpenSslError(err) => write!(f, "SSL error: {err}"),
Self::IOError(err) => write!(f, "IO error: {err}"),
}
}
}
impl std::error::Error for InternalError {}
impl From<InvalidFingerprint> for InternalError {
fn from(err: InvalidFingerprint) -> Self {
Self::InvalidFingerprint(err)
}
}
impl From<openssl::error::Error> for InternalError {
fn from(err: openssl::error::Error) -> Self {
Self::OpenSslError(err.into())
}
}
impl From<openssl::error::ErrorStack> for InternalError {
fn from(err: openssl::error::ErrorStack) -> Self {
Self::OpenSslError(err.into())
}
}
impl From<openssl::ssl::Error> for InternalError {
fn from(err: openssl::ssl::Error) -> Self {
Self::OpenSslError(err.into())
}
}
impl From<io::Error> for InternalError {
fn from(err: io::Error) -> Self {
Self::IOError(err)
}
}
#[derive(Debug)]
enum OpenSslError {
Error(openssl::error::Error),
ErrorStack(openssl::error::ErrorStack),
SslError(openssl::ssl::Error),
}
impl Display for OpenSslError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Error(err) => Display::fmt(err, f),
Self::ErrorStack(err) => Display::fmt(err, f),
Self::SslError(err) => Display::fmt(err, f),
}
}
}
impl std::error::Error for OpenSslError {}
impl From<openssl::error::Error> for OpenSslError {
fn from(err: openssl::error::Error) -> Self {
Self::Error(err)
}
}
impl From<openssl::error::ErrorStack> for OpenSslError {
fn from(err: openssl::error::ErrorStack) -> Self {
Self::ErrorStack(err)
}
}
impl From<openssl::ssl::Error> for OpenSslError {
fn from(err: openssl::ssl::Error) -> Self {
Self::SslError(err)
}
}
pub struct SrtpContextBuilder {
profiles: Vec<SrtpProfileId>,
}
impl SrtpContextBuilder {
fn new() -> Self {
Self {
profiles: Vec::new(),
}
}
#[inline]
pub fn profile(mut self, profile: SrtpProfileId) -> Self {
self.profiles.push(profile);
self
}
pub fn with_ssl_context(mut self, context: SslContext) -> Result<SrtpContext, Error> {
assert!(context.certificate().is_some());
assert!(context.private_key().is_some());
if self.profiles.is_empty() {
self.profiles = vec![
SrtpProfileId::SRTP_AES128_CM_SHA1_80,
SrtpProfileId::SRTP_AES128_CM_SHA1_32,
];
}
let mut profiles = String::new();
let mut iter = self.profiles.iter();
if let Some(profile) = iter.next() {
let _ = write!(profiles, "{profile}");
}
for profile in iter {
let _ = write!(profiles, ":{profile}");
}
let res = SrtpContext {
ssl_context: context,
srtp_profiles: profiles,
};
Ok(res)
}
pub fn build<T>(self, key: &PKeyRef<T>, cert: &X509Ref) -> Result<SrtpContext, Error>
where
T: HasPrivate,
{
let mut ssl_ctx_builder = SslContext::builder(SslMethod::dtls())?;
ssl_ctx_builder.set_certificate(cert)?;
ssl_ctx_builder.set_private_key(key)?;
self.with_ssl_context(ssl_ctx_builder.build())
}
pub fn self_signed<T>(self, key: &PKeyRef<T>) -> Result<SrtpContext, Error>
where
T: HasPrivate,
{
let now = unsafe { libc::time(ptr::null_mut()) };
let not_before = Asn1Time::from_unix(now)?;
let mut cert_builder = X509::builder()?;
cert_builder.set_pubkey(key)?;
cert_builder.set_not_before(¬_before)?;
cert_builder.sign(key, MessageDigest::sha256())?;
let public_cert = cert_builder.build();
self.build(key, &public_cert)
}
}
pub struct SrtpContext {
ssl_context: SslContext,
srtp_profiles: String,
}
impl SrtpContext {
#[inline]
pub fn builder() -> SrtpContextBuilder {
SrtpContextBuilder::new()
}
#[inline]
pub fn new<T>(key: &PKeyRef<T>, cert: &X509Ref) -> Result<Self, Error>
where
T: HasPrivate,
{
Self::builder().build(key, cert)
}
#[inline]
pub fn self_signed<T>(key: &PKeyRef<T>) -> Result<Self, Error>
where
T: HasPrivate,
{
Self::builder().self_signed(key)
}
#[inline]
pub fn from_ssl_context(context: SslContext) -> Result<Self, Error> {
Self::builder().with_ssl_context(context)
}
#[inline]
pub fn certificate_fingerprint(
&self,
hash_function: HashFunction,
) -> Result<CertificateFingerprint, Error> {
let cert = self.ssl_context.certificate();
CertificateFingerprint::new(cert.unwrap(), hash_function)
}
pub fn connect_srtp<S>(
&self,
stream: S,
peer_cert_fingerprint: CertificateFingerprint,
options: RtpTransceiverOptions,
) -> impl Future<Output = Result<SrtpStream<S>, Error>>
where
S: Stream<Item = io::Result<Bytes>>,
S: Sink<Bytes, Error = io::Error>,
S: Unpin,
{
let connector = self.new_connector(peer_cert_fingerprint);
async move { connector?.connect_srtp(stream, options).await }
}
pub fn connect_srtcp<S>(
&self,
stream: S,
peer_cert_fingerprint: CertificateFingerprint,
) -> impl Future<Output = Result<SrtcpStream<S>, Error>>
where
S: Stream<Item = io::Result<Bytes>>,
S: Sink<Bytes, Error = io::Error>,
S: Unpin,
{
let connector = self.new_connector(peer_cert_fingerprint);
async move { connector?.connect_srtcp(stream).await }
}
pub fn connect_muxed<S>(
&self,
stream: S,
peer_cert_fingerprint: CertificateFingerprint,
options: RtpTransceiverOptions,
) -> impl Future<Output = Result<MuxedSrtpStream<S>, Error>>
where
S: Stream<Item = io::Result<Bytes>>,
S: Sink<Bytes, Error = io::Error>,
S: Unpin,
{
let connector = self.new_connector(peer_cert_fingerprint);
async move { connector?.connect_muxed(stream, options).await }
}
pub fn accept_srtp<S>(
&self,
stream: S,
peer_cert_fingerprint: CertificateFingerprint,
options: RtpTransceiverOptions,
) -> impl Future<Output = Result<SrtpStream<S>, Error>>
where
S: Stream<Item = io::Result<Bytes>>,
S: Sink<Bytes, Error = io::Error>,
S: Unpin,
{
let connector = self.new_connector(peer_cert_fingerprint);
async move { connector?.accept_srtp(stream, options).await }
}
pub fn accept_srtcp<S>(
&self,
stream: S,
peer_cert_fingerprint: CertificateFingerprint,
) -> impl Future<Output = Result<SrtcpStream<S>, Error>>
where
S: Stream<Item = io::Result<Bytes>>,
S: Sink<Bytes, Error = io::Error>,
S: Unpin,
{
let connector = self.new_connector(peer_cert_fingerprint);
async move { connector?.accept_srtcp(stream).await }
}
pub fn accept_muxed<S>(
&self,
stream: S,
peer_cert_fingerprint: CertificateFingerprint,
options: RtpTransceiverOptions,
) -> impl Future<Output = Result<MuxedSrtpStream<S>, Error>>
where
S: Stream<Item = io::Result<Bytes>>,
S: Sink<Bytes, Error = io::Error>,
S: Unpin,
{
let connector = self.new_connector(peer_cert_fingerprint);
async move { connector?.accept_muxed(stream, options).await }
}
fn new_connector(
&self,
peer_cert_fingerprint: CertificateFingerprint,
) -> Result<Connector, InternalError> {
let mut ssl = Ssl::new(&self.ssl_context)?;
ssl.set_tlsext_use_srtp(&self.srtp_profiles)?;
let verify_mode = SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT;
ssl.set_verify_callback(verify_mode, move |_, store| {
if let Some(chain) = store.chain() {
if let Some(cert) = chain.get(0) {
if let Ok(success) = peer_cert_fingerprint.verify(cert) {
return success;
}
}
}
false
});
Ok(Connector::new(ssl))
}
}