#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::sync::Arc;
#[cfg(feature = "std")]
use std::sync::Arc;
use crate::asn1::Frame;
use crate::cms::enveloped_data::EncryptedContentInfo;
use crate::der::{Choice, Decode, Encode, EncodeValue, Tag, Tagged};
use crate::policy::TransitStatus;
#[cfg(feature = "x509")]
mod x509 {
pub use crate::cms::enveloped_data::EnvelopedData;
pub use crate::cms::signed_data::SignedData;
}
#[cfg(feature = "derive")]
use crate::Beamable;
#[cfg(not(feature = "derive"))]
use crate::{Message, Version};
#[cfg(feature = "x509")]
use x509::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RequestPackage {
pub(crate) message: Arc<Frame>,
}
impl RequestPackage {
pub fn new(message: Frame) -> Self {
Self { message: Arc::new(message) }
}
}
impl EncodeValue for RequestPackage {
fn value_len(&self) -> crate::der::Result<crate::der::Length> {
self.message.as_ref().encoded_len()
}
fn encode_value(&self, writer: &mut impl crate::der::Writer) -> crate::der::Result<()> {
self.message.as_ref().encode(writer)
}
}
impl Tagged for RequestPackage {
fn tag(&self) -> Tag {
Tag::Sequence
}
}
impl<'a> Decode<'a> for RequestPackage {
fn decode<R: crate::der::Reader<'a>>(reader: &mut R) -> crate::der::Result<Self> {
reader.sequence(|reader| {
let frame = Frame::decode(reader)?;
Ok(Self { message: Arc::new(frame) })
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ResponsePackage {
pub(crate) status: TransitStatus,
pub(crate) message: Option<Arc<Frame>>,
}
impl ResponsePackage {
pub fn new(status: TransitStatus, message: Option<Frame>) -> Self {
Self { status, message: message.map(Arc::new) }
}
pub fn status(&self) -> TransitStatus {
self.status
}
pub fn message(&self) -> Option<&Arc<Frame>> {
self.message.as_ref()
}
}
impl EncodeValue for ResponsePackage {
fn value_len(&self) -> crate::der::Result<crate::der::Length> {
let message_len = match &self.message {
Some(arc) => arc.as_ref().encoded_len()?,
None => crate::der::Length::ZERO,
};
[self.status.encoded_len()?, message_len]
.into_iter()
.try_fold(crate::der::Length::ZERO, |acc, len| acc + len)
}
fn encode_value(&self, writer: &mut impl crate::der::Writer) -> crate::der::Result<()> {
self.status.encode(writer)?;
if let Some(arc) = &self.message {
arc.as_ref().encode(writer)?;
}
Ok(())
}
}
impl Tagged for ResponsePackage {
fn tag(&self) -> Tag {
Tag::Sequence
}
}
impl<'a> Decode<'a> for ResponsePackage {
fn decode<R: crate::der::Reader<'a>>(reader: &mut R) -> crate::der::Result<Self> {
reader.sequence(|reader| {
let status = TransitStatus::decode(reader)?;
let message: Option<Frame> = Option::<Frame>::decode(reader)?;
Ok(Self { status, message: message.map(Arc::new) })
})
}
}
#[cfg_attr(feature = "derive", derive(Beamable))]
#[derive(Choice, Clone, Debug, PartialEq)]
pub enum TransportEnvelope {
#[asn1(context_specific = "0", constructed = "true")]
Request(RequestPackage),
#[asn1(context_specific = "1", constructed = "true")]
Response(ResponsePackage),
#[cfg(feature = "x509")]
#[asn1(context_specific = "2", constructed = "true")]
EnvelopedData(EnvelopedData),
#[cfg(feature = "x509")]
#[asn1(context_specific = "3", constructed = "true")]
SignedData(SignedData),
}
#[derive(Choice, Clone, Debug, PartialEq)]
#[allow(clippy::large_enum_variant)]
pub enum WireEnvelope {
#[asn1(context_specific = "0", constructed = "true")]
Cleartext(TransportEnvelope),
#[asn1(context_specific = "1", constructed = "true")]
Encrypted(EncryptedContentInfo),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WireMode {
Cleartext,
Encrypted,
}
#[cfg(not(feature = "derive"))]
impl Message for TransportEnvelope {
const MUST_BE_NON_REPUDIABLE: bool = false;
const MUST_BE_CONFIDENTIAL: bool = false;
const MUST_BE_COMPRESSED: bool = false;
const MUST_BE_PRIORITIZED: bool = false;
const MIN_VERSION: Version = Version::V0;
}
impl From<ResponsePackage> for TransportEnvelope {
fn from(pkg: ResponsePackage) -> Self {
Self::Response(pkg)
}
}
impl From<Frame> for TransportEnvelope {
fn from(msg: Frame) -> Self {
Self::Request(RequestPackage { message: Arc::new(msg) })
}
}
impl TransportEnvelope {
pub fn new_request(msg: Frame) -> Self {
Self::Request(RequestPackage { message: Arc::new(msg) })
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testing::create_v0_tightbeam;
struct PackageTestCase {
message_value: &'static str,
expected_status: TransitStatus,
should_have_message: bool,
}
impl PackageTestCase {
fn create_request(&self) -> RequestPackage {
RequestPackage::new(create_v0_tightbeam(Some(self.message_value), None))
}
fn create_response(&self) -> ResponsePackage {
ResponsePackage {
status: self.expected_status,
message: if self.should_have_message {
Some(Arc::new(create_v0_tightbeam(Some(self.message_value), None)))
} else {
None
},
}
}
}
fn as_test_cases() -> Vec<PackageTestCase> {
vec![
PackageTestCase {
message_value: "Hi",
expected_status: TransitStatus::Accepted,
should_have_message: true,
},
PackageTestCase {
message_value: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
expected_status: TransitStatus::Accepted,
should_have_message: true,
},
PackageTestCase {
message_value: "",
expected_status: TransitStatus::Accepted,
should_have_message: true,
},
PackageTestCase {
message_value: "Busy",
expected_status: TransitStatus::Busy,
should_have_message: false,
},
PackageTestCase {
message_value: "Unauthorized",
expected_status: TransitStatus::Unauthorized,
should_have_message: false,
},
]
}
#[test]
fn test_request_package_encode_decode() -> Result<(), Box<dyn std::error::Error>> {
for test_case in as_test_cases() {
let original = test_case.create_request();
let encoded = original.to_der()?;
let decoded = RequestPackage::from_der(&encoded)?;
assert_eq!(original, decoded);
}
Ok(())
}
#[test]
fn test_response_package_encode_decode() -> Result<(), Box<dyn std::error::Error>> {
for test_case in as_test_cases() {
let original = test_case.create_response();
let encoded = original.to_der()?;
let decoded = ResponsePackage::from_der(&encoded)?;
assert_eq!(original.status, decoded.status);
assert_eq!(original.message, decoded.message);
}
Ok(())
}
#[test]
fn test_length_validation_request() -> Result<(), Box<dyn std::error::Error>> {
let original = RequestPackage::new(create_v0_tightbeam(None, None));
let mut encoded = original.to_der()?;
if encoded.len() > 10 {
let corrupt_pos = 5;
encoded[corrupt_pos] = encoded[corrupt_pos].wrapping_add(1);
let result = RequestPackage::from_der(&encoded);
assert!(result.is_err(), "Should fail with corrupted length");
}
Ok(())
}
#[test]
fn test_length_validation_response() -> Result<(), Box<dyn std::error::Error>> {
let original = ResponsePackage {
status: TransitStatus::Accepted,
message: Some(Arc::new(create_v0_tightbeam(None, None))),
};
let mut encoded = original.to_der()?;
if encoded.len() > 10 {
let corrupt_pos = 8;
encoded[corrupt_pos] = encoded[corrupt_pos].wrapping_add(1);
let result = ResponsePackage::from_der(&encoded);
assert!(result.is_err(), "Should fail with corrupted length");
}
Ok(())
}
#[test]
fn test_response_empty_message() -> Result<(), Box<dyn std::error::Error>> {
let original = ResponsePackage { status: TransitStatus::Busy, message: None };
let encoded = original.to_der()?;
let decoded = ResponsePackage::from_der(&encoded)?;
assert_eq!(original.status, decoded.status);
assert_eq!(original.message, decoded.message);
Ok(())
}
}