use crate::SrtpProfile;
use crate::buffer::Buf;
use arrayvec::ArrayVec;
use nom::bytes::complete::take;
use nom::error::{Error, ErrorKind};
use nom::number::complete::{be_u8, be_u16};
use nom::{Err, IResult};
pub type SrtpProfileVec = ArrayVec<SrtpProfileId, { SrtpProfileId::supported().len() }>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[allow(non_camel_case_types)]
pub enum SrtpProfileId {
#[default]
SRTP_AES128_CM_SHA1_80 = 0x0001,
SRTP_AEAD_AES_128_GCM = 0x0007,
SRTP_AEAD_AES_256_GCM = 0x0008,
}
impl SrtpProfileId {
pub fn parse(input: &[u8]) -> IResult<&[u8], SrtpProfileId> {
let (input, value) = be_u16(input)?;
let profile = match value {
0x0001 => SrtpProfileId::SRTP_AES128_CM_SHA1_80,
0x0007 => SrtpProfileId::SRTP_AEAD_AES_128_GCM,
0x0008 => SrtpProfileId::SRTP_AEAD_AES_256_GCM,
_ => {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Switch,
)));
}
};
Ok((input, profile))
}
pub fn as_u16(&self) -> u16 {
*self as u16
}
pub const fn all() -> &'static [SrtpProfileId; 3] {
&[
SrtpProfileId::SRTP_AES128_CM_SHA1_80,
SrtpProfileId::SRTP_AEAD_AES_128_GCM,
SrtpProfileId::SRTP_AEAD_AES_256_GCM,
]
}
pub const fn supported() -> &'static [SrtpProfileId; 3] {
Self::all()
}
}
impl From<SrtpProfile> for SrtpProfileId {
fn from(profile: SrtpProfile) -> Self {
match profile {
SrtpProfile::AES128_CM_SHA1_80 => SrtpProfileId::SRTP_AES128_CM_SHA1_80,
SrtpProfile::AEAD_AES_128_GCM => SrtpProfileId::SRTP_AEAD_AES_128_GCM,
SrtpProfile::AEAD_AES_256_GCM => SrtpProfileId::SRTP_AEAD_AES_256_GCM,
}
}
}
impl From<SrtpProfileId> for SrtpProfile {
fn from(profile: SrtpProfileId) -> Self {
match profile {
SrtpProfileId::SRTP_AES128_CM_SHA1_80 => SrtpProfile::AES128_CM_SHA1_80,
SrtpProfileId::SRTP_AEAD_AES_128_GCM => SrtpProfile::AEAD_AES_128_GCM,
SrtpProfileId::SRTP_AEAD_AES_256_GCM => SrtpProfile::AEAD_AES_256_GCM,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UseSrtpExtension {
pub profiles: SrtpProfileVec,
pub mki: ArrayVec<u8, 255>, }
impl UseSrtpExtension {
pub fn new(profiles: SrtpProfileVec, mki: ArrayVec<u8, 255>) -> Self {
UseSrtpExtension { profiles, mki }
}
pub fn default() -> Self {
let mut profiles = SrtpProfileVec::new();
profiles.push(SrtpProfileId::SRTP_AEAD_AES_256_GCM);
profiles.push(SrtpProfileId::SRTP_AEAD_AES_128_GCM);
profiles.push(SrtpProfileId::SRTP_AES128_CM_SHA1_80);
UseSrtpExtension {
profiles,
mki: ArrayVec::new(),
}
}
pub fn parse(input: &[u8]) -> IResult<&[u8], UseSrtpExtension> {
let (input, profiles_length) = be_u16(input)?;
let (input, profiles_data) = take(profiles_length)(input)?;
let mut profiles = SrtpProfileVec::new();
let mut profiles_rest = profiles_data;
while profiles_rest.len() >= 2 {
let profile_input = profiles_rest;
let (rest, value) = be_u16(profile_input)?;
profiles_rest = rest;
match value {
0x0001 => profiles
.try_push(SrtpProfileId::SRTP_AES128_CM_SHA1_80)
.map_err(|_| Err::Failure(Error::new(profile_input, ErrorKind::LengthValue)))?,
0x0007 => profiles
.try_push(SrtpProfileId::SRTP_AEAD_AES_128_GCM)
.map_err(|_| Err::Failure(Error::new(profile_input, ErrorKind::LengthValue)))?,
0x0008 => profiles
.try_push(SrtpProfileId::SRTP_AEAD_AES_256_GCM)
.map_err(|_| Err::Failure(Error::new(profile_input, ErrorKind::LengthValue)))?,
_ => {
}
}
}
if !profiles_rest.is_empty() {
return Err(Err::Failure(Error::new(
profiles_rest,
ErrorKind::LengthValue,
)));
}
let (input, mki_length) = be_u8(input)?;
let (input, mki) = take(mki_length)(input)?;
if !input.is_empty() {
return Err(Err::Failure(Error::new(input, ErrorKind::LengthValue)));
}
Ok((
input,
UseSrtpExtension {
profiles,
mki: ArrayVec::try_from(mki).unwrap_or_default(),
},
))
}
pub fn serialize(&self, output: &mut Buf) {
output.extend_from_slice(&((self.profiles.len() * 2) as u16).to_be_bytes());
for profile in &self.profiles {
output.extend_from_slice(&profile.as_u16().to_be_bytes());
}
output.push(self.mki.len() as u8);
output.extend_from_slice(&self.mki);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::buffer::Buf;
#[test]
fn test_use_srtp_extension() {
let mut profiles = SrtpProfileVec::new();
profiles.push(SrtpProfileId::SRTP_AEAD_AES_256_GCM);
profiles.push(SrtpProfileId::SRTP_AEAD_AES_128_GCM);
profiles.push(SrtpProfileId::SRTP_AES128_CM_SHA1_80);
let mut mki = ArrayVec::new();
mki.push(1);
mki.push(2);
mki.push(3);
let ext = UseSrtpExtension::new(profiles, mki.clone());
let mut serialized = Buf::new();
ext.serialize(&mut serialized);
let expected = [
0x00, 0x06, 0x00, 0x08, 0x00, 0x07, 0x00, 0x01, 0x03, 0x01, 0x02, 0x03, ];
assert_eq!(&*serialized, expected);
let (_, parsed) = UseSrtpExtension::parse(&serialized).unwrap();
assert_eq!(parsed.profiles.as_slice(), ext.profiles.as_slice());
assert_eq!(parsed.mki, mki);
}
#[test]
fn test_use_srtp_parse_provided_bytes() {
let bytes = [0, 8, 0, 7, 0, 8, 0, 1, 0, 2, 0];
let (_, parsed) = UseSrtpExtension::parse(&bytes).expect("parse UseSrtpExtension");
assert_eq!(
parsed.profiles.as_slice(),
&[
SrtpProfileId::SRTP_AEAD_AES_128_GCM,
SrtpProfileId::SRTP_AEAD_AES_256_GCM,
SrtpProfileId::SRTP_AES128_CM_SHA1_80
]
);
assert_eq!(parsed.mki, ArrayVec::<u8, 255>::new());
}
#[test]
fn too_many_supported_srtp_profiles_are_rejected() {
let bytes = [
0x00, 0x08, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, ];
let err = UseSrtpExtension::parse(&bytes).unwrap_err();
assert!(matches!(
err,
Err::Failure(Error {
code: ErrorKind::LengthValue,
..
})
));
}
#[test]
fn odd_srtp_profile_vector_is_rejected() {
let bytes = [
0x00, 0x03, 0x00, 0x01, 0x00, 0x00, ];
let err = UseSrtpExtension::parse(&bytes).unwrap_err();
assert!(matches!(
err,
Err::Failure(Error {
code: ErrorKind::LengthValue,
..
})
));
}
#[test]
fn trailing_mki_bytes_are_rejected() {
let bytes = [
0x00, 0x02, 0x00, 0x01, 0x00, 0xFF, ];
let err = UseSrtpExtension::parse(&bytes).unwrap_err();
assert!(matches!(
err,
Err::Failure(Error {
code: ErrorKind::LengthValue,
..
})
));
}
}