use crate::{
BytesRef, Decode, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader,
Tag, Writer, asn1::AnyRef, ord::OrdIsValueOrd,
};
#[derive(Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct OctetStringRef {
inner: BytesRef,
}
impl OctetStringRef {
pub fn new(slice: &[u8]) -> Result<&Self, Error> {
BytesRef::new(slice)
.map(Self::from_bytes_ref)
.map_err(|_| ErrorKind::Length { tag: Self::TAG }.into())
}
fn from_bytes_ref(bytes_ref: &BytesRef) -> &Self {
#[allow(unsafe_code)]
unsafe {
&*(bytes_ref.as_ptr() as *const Self)
}
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
self.inner.as_slice()
}
#[must_use]
pub fn len(&self) -> Length {
self.inner.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn decode_into<'a, T: Decode<'a>>(&'a self) -> Result<T, T::Error> {
Decode::from_der(self.as_bytes())
}
}
impl_any_conversions!(&'a OctetStringRef, 'a);
impl AsRef<[u8]> for OctetStringRef {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<'a> DecodeValue<'a> for &'a OctetStringRef {
type Error = Error;
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Error> {
<&'a BytesRef>::decode_value(reader, header).map(OctetStringRef::from_bytes_ref)
}
}
impl EncodeValue for &OctetStringRef {
fn value_len(&self) -> Result<Length, Error> {
self.inner.value_len()
}
fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
self.inner.encode_value(writer)
}
}
impl FixedTag for OctetStringRef {
const TAG: Tag = Tag::OctetString;
}
impl FixedTag for &OctetStringRef {
const TAG: Tag = Tag::OctetString;
}
impl OrdIsValueOrd for &OctetStringRef {}
impl<'a> From<&'a OctetStringRef> for AnyRef<'a> {
fn from(octet_string: &'a OctetStringRef) -> AnyRef<'a> {
AnyRef::from_tag_and_value(Tag::OctetString, &octet_string.inner)
}
}
impl<'a> From<&'a OctetStringRef> for &'a [u8] {
fn from(octet_string: &'a OctetStringRef) -> &'a [u8] {
octet_string.as_bytes()
}
}
impl<'a> TryFrom<&'a [u8]> for &'a OctetStringRef {
type Error = Error;
fn try_from(byte_slice: &'a [u8]) -> Result<Self, Error> {
OctetStringRef::new(byte_slice)
}
}
impl<'a> TryFrom<&&'a [u8]> for &'a OctetStringRef {
type Error = Error;
fn try_from(byte_slice: &&'a [u8]) -> Result<Self, Error> {
OctetStringRef::new(byte_slice)
}
}
impl<'a, const N: usize> TryFrom<&'a [u8; N]> for &'a OctetStringRef {
type Error = Error;
fn try_from(byte_slice: &'a [u8; N]) -> Result<Self, Error> {
OctetStringRef::new(byte_slice)
}
}
impl<'a, const N: usize> TryFrom<&'a OctetStringRef> for [u8; N] {
type Error = Error;
fn try_from(octet_string: &'a OctetStringRef) -> Result<Self, Self::Error> {
octet_string
.as_bytes()
.try_into()
.map_err(|_| Tag::OctetString.length_error().into())
}
}
#[cfg(feature = "heapless")]
impl<const N: usize> TryFrom<&OctetStringRef> for heapless::Vec<u8, N> {
type Error = Error;
fn try_from(octet_string: &OctetStringRef) -> Result<Self, Self::Error> {
octet_string
.as_bytes()
.try_into()
.map_err(|_| Tag::OctetString.length_error().into())
}
}
#[cfg(feature = "heapless")]
impl<'a, const N: usize> TryFrom<&'a heapless::Vec<u8, N>> for &'a OctetStringRef {
type Error = Error;
fn try_from(byte_vec: &'a heapless::Vec<u8, N>) -> Result<Self, Error> {
OctetStringRef::new(byte_vec)
}
}
#[cfg(feature = "alloc")]
pub use self::allocating::OctetString;
#[cfg(feature = "alloc")]
mod allocating {
use super::*;
use crate::BytesOwned;
use alloc::{
borrow::{Borrow, Cow, ToOwned},
boxed::Box,
vec::Vec,
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct OctetString {
pub(super) inner: BytesOwned,
}
impl OctetString {
pub fn new(bytes: impl Into<Box<[u8]>>) -> Result<Self, Error> {
let inner = BytesOwned::new(bytes)?;
OctetStringRef::new(inner.as_slice())?;
Ok(Self { inner })
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
self.inner.as_slice()
}
#[must_use]
pub fn into_bytes(self) -> Box<[u8]> {
self.inner.into()
}
#[must_use]
pub fn len(&self) -> Length {
self.inner.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}
impl_any_conversions!(OctetString);
impl AsRef<[u8]> for OctetString {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl Borrow<OctetStringRef> for OctetString {
fn borrow(&self) -> &OctetStringRef {
OctetStringRef::from_bytes_ref(self.inner.as_ref())
}
}
impl<'a> DecodeValue<'a> for OctetString {
type Error = Error;
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Error> {
let inner = BytesOwned::decode_value_parts(reader, header, Self::TAG)?;
Ok(Self { inner })
}
}
impl EncodeValue for OctetString {
fn value_len(&self) -> Result<Length, Error> {
self.inner.value_len()
}
fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
self.inner.encode_value(writer)
}
}
impl FixedTag for OctetString {
const TAG: Tag = Tag::OctetString;
}
impl OrdIsValueOrd for OctetString {}
impl<'a> From<&'a OctetString> for &'a OctetStringRef {
fn from(octet_string: &'a OctetString) -> &'a OctetStringRef {
OctetStringRef::from_bytes_ref(octet_string.inner.as_ref())
}
}
impl From<&OctetStringRef> for OctetString {
fn from(octet_string_ref: &OctetStringRef) -> OctetString {
Self {
inner: octet_string_ref.inner.to_owned(),
}
}
}
impl From<&OctetStringRef> for Vec<u8> {
fn from(octet_string: &OctetStringRef) -> Vec<u8> {
Vec::from(octet_string.as_bytes())
}
}
impl<'a> TryFrom<&'a Vec<u8>> for &'a OctetStringRef {
type Error = Error;
fn try_from(byte_vec: &'a Vec<u8>) -> Result<Self, Error> {
OctetStringRef::new(byte_vec)
}
}
impl From<OctetString> for Vec<u8> {
fn from(octet_string: OctetString) -> Vec<u8> {
octet_string.into_bytes().into()
}
}
impl ToOwned for OctetStringRef {
type Owned = OctetString;
fn to_owned(&self) -> OctetString {
self.into()
}
}
impl<'a> TryFrom<&'a Cow<'a, [u8]>> for &'a OctetStringRef {
type Error = Error;
fn try_from(byte_slice: &'a Cow<'a, [u8]>) -> Result<Self, Error> {
OctetStringRef::new(byte_slice)
}
}
impl<'a> TryFrom<&'a OctetStringRef> for Cow<'a, [u8]> {
type Error = Error;
fn try_from(octet_string: &'a OctetStringRef) -> Result<Self, Self::Error> {
Ok(Cow::Borrowed(octet_string.as_bytes()))
}
}
#[cfg(feature = "arbitrary")]
impl<'a> arbitrary::Arbitrary<'a> for OctetString {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
Self::new(Vec::arbitrary(u)?).map_err(|_| arbitrary::Error::IncorrectFormat)
}
fn size_hint(depth: usize) -> (usize, Option<usize>) {
arbitrary::size_hint::and(u8::size_hint(depth), Vec::<u8>::size_hint(depth))
}
}
}
#[cfg(feature = "bytes")]
mod bytes {
use super::{OctetString, OctetStringRef};
use crate::{
DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag, Writer,
};
use alloc::vec::Vec;
use bytes::Bytes;
impl<'a> DecodeValue<'a> for Bytes {
type Error = Error;
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
OctetString::decode_value(reader, header).map(Into::into)
}
}
impl EncodeValue for Bytes {
fn value_len(&self) -> Result<Length> {
self.len().try_into()
}
fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
writer.write(self.as_ref())
}
}
impl FixedTag for Bytes {
const TAG: Tag = Tag::OctetString;
}
impl From<&OctetStringRef> for Bytes {
fn from(octet_string: &OctetStringRef) -> Bytes {
Vec::from(octet_string).into()
}
}
impl From<OctetString> for Bytes {
fn from(octet_string: OctetString) -> Bytes {
Vec::from(octet_string).into()
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use crate::{
Decode,
asn1::{OctetStringRef, PrintableStringRef},
};
use hex_literal::hex;
#[cfg(feature = "alloc")]
use {crate::Encode, alloc::borrow::Cow};
#[test]
fn octet_string_decode() {
const EXAMPLE: &[u8] = &hex!(
"040c" "48656c6c6f2c20776f726c64" );
let decoded = <&OctetStringRef>::from_der(EXAMPLE).unwrap();
assert_eq!(decoded.as_bytes(), b"Hello, world");
}
#[test]
fn octet_string_decode_into() {
let der = b"\x13\x02\x68\x69";
let oct = OctetStringRef::new(der).unwrap();
let res = oct.decode_into::<PrintableStringRef<'_>>().unwrap();
assert_eq!(AsRef::<str>::as_ref(&res), "hi");
}
#[cfg(feature = "alloc")]
#[test]
fn cow_octet_string_decode_and_encode() {
const EXAMPLE: &[u8] = &hex!(
"040c" "48656c6c6f2c20776f726c64" );
let decoded = Cow::<OctetStringRef>::from_der(EXAMPLE).unwrap();
assert_eq!(decoded.as_bytes(), b"Hello, world");
let encoded = decoded.to_der().unwrap();
assert_eq!(EXAMPLE, encoded);
}
#[test]
#[cfg(all(feature = "alloc", feature = "ber"))]
fn decode_ber_primitive_definite() {
use crate::{Decode, asn1::OctetString};
use hex_literal::hex;
const EXAMPLE: &[u8] = &hex!(
"040c" "48656c6c6f2c20776f726c64" );
let decoded = OctetString::from_ber(EXAMPLE).unwrap();
assert_eq!(decoded.as_bytes(), b"Hello, world");
let decoded = OctetString::from_der(EXAMPLE).unwrap();
assert_eq!(decoded.as_bytes(), b"Hello, world");
}
#[test]
#[cfg(all(feature = "alloc", feature = "ber"))]
fn decode_ber_constructed_indefinite() {
use crate::{Decode, asn1::OctetString};
use hex_literal::hex;
const EXAMPLE_BER: &[u8] = &hex!(
"2480" "040648656c6c6f2c" "040620776f726c64" "0000" );
let decoded = OctetString::from_ber(EXAMPLE_BER).unwrap();
assert_eq!(decoded.as_bytes(), b"Hello, world");
}
#[test]
#[cfg(all(feature = "alloc", feature = "ber"))]
fn decode_ber_constructed_definite() {
use crate::{Decode, Error, ErrorKind, Length, Tag, asn1::OctetString};
use hex_literal::hex;
const EXAMPLE_BER: &[u8] = &hex!(
"2410" "040648656c6c6f2c" "040620776f726c64" );
let err = OctetString::from_ber(EXAMPLE_BER).err().unwrap();
let expected = Error::new(
ErrorKind::Noncanonical {
tag: Tag::OctetString,
},
Length::new(1),
);
assert_eq!(expected, err);
}
#[test]
#[cfg(all(feature = "alloc", feature = "ber"))]
fn decode_context_specific_ber_explicit() {
use crate::{
EncodingRules, SliceReader, TagNumber,
asn1::{ContextSpecific, OctetString},
};
use hex_literal::hex;
let tag_number = TagNumber(0);
const EXAMPLE_BER: &[u8] = &hex!(
"A080" "2480" "040648656c6c6f2c" "040620776f726c64" "0000" "0000" );
let mut reader =
SliceReader::new_with_encoding_rules(EXAMPLE_BER, EncodingRules::Ber).unwrap();
let decoded = ContextSpecific::<OctetString>::decode_explicit(&mut reader, tag_number)
.unwrap()
.unwrap()
.value;
assert_eq!(decoded.as_bytes(), b"Hello, world");
}
#[test]
#[cfg(all(feature = "alloc", feature = "ber"))]
fn decode_context_specific_ber_implicit() {
use crate::{
EncodingRules, SliceReader, TagNumber,
asn1::{ContextSpecific, OctetString},
};
use hex_literal::hex;
let tag_number = TagNumber(0);
const EXAMPLE_BER: &[u8] = &hex!(
"A080" "040648656c6c6f2c" "040620776f726c64" "0000" );
let mut reader =
SliceReader::new_with_encoding_rules(EXAMPLE_BER, EncodingRules::Ber).unwrap();
let decoded = ContextSpecific::<OctetString>::decode_implicit(&mut reader, tag_number)
.unwrap()
.unwrap()
.value;
assert_eq!(decoded.as_bytes(), b"Hello, world");
}
#[test]
#[cfg(all(feature = "alloc", feature = "ber"))]
fn decode_ber_recursive_unsupported() {
use crate::{Decode, Error, ErrorKind, Length, asn1::OctetString};
use hex_literal::hex;
const EXAMPLE_BER: &[u8] = &hex!(
"2480" "2480" "040648656c6c6f2c" "040620776f726c64" "0000" "040620776f726c64" "0000" );
let err = OctetString::from_ber(EXAMPLE_BER).err().unwrap();
let expected = Error::new(ErrorKind::IndefiniteLength, Length::new(4));
assert_eq!(expected, err);
}
}