Skip to main content

der/asn1/
octet_string.rs

1//! ASN.1 `OCTET STRING` support.
2
3use crate::{
4    BytesRef, Decode, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader,
5    Tag, Writer, asn1::AnyRef, ord::OrdIsValueOrd,
6};
7
8/// ASN.1 `OCTET STRING` type: borrowed form.
9///
10/// Octet strings represent contiguous sequences of octets, a.k.a. bytes.
11///
12/// This is a zero-copy reference type which borrows from the input data.
13#[derive(Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
14#[repr(transparent)]
15pub struct OctetStringRef {
16    /// Inner value
17    inner: BytesRef,
18}
19
20impl OctetStringRef {
21    /// Create a new ASN.1 `OCTET STRING` from a byte slice.
22    ///
23    /// # Errors
24    /// Returns [`Error`] with [`ErrorKind::Length`] in the event `slice` is too long.
25    pub fn new(slice: &[u8]) -> Result<&Self, Error> {
26        BytesRef::new(slice)
27            .map(Self::from_bytes_ref)
28            .map_err(|_| ErrorKind::Length { tag: Self::TAG }.into())
29    }
30
31    /// Create an [`OctetStringRef`] from a [`BytesRef`].
32    ///
33    /// Implemented as an inherent method to keep [`BytesRef`] out of the public API.
34    fn from_bytes_ref(bytes_ref: &BytesRef) -> &Self {
35        // SAFETY: `Self` is a `repr(transparent)` newtype for `BytesRef`
36        #[allow(unsafe_code)]
37        unsafe {
38            &*(bytes_ref.as_ptr() as *const Self)
39        }
40    }
41
42    /// Borrow the inner byte slice.
43    #[must_use]
44    pub fn as_bytes(&self) -> &[u8] {
45        self.inner.as_slice()
46    }
47
48    /// Get the length of the inner byte slice.
49    #[must_use]
50    pub fn len(&self) -> Length {
51        self.inner.len()
52    }
53
54    /// Is the inner byte slice empty?
55    #[must_use]
56    pub fn is_empty(&self) -> bool {
57        self.inner.is_empty()
58    }
59
60    /// Parse `T` from this `OCTET STRING`'s contents.
61    ///
62    /// # Errors
63    /// Returns `T::Error` in the event a decoding error occurred.
64    pub fn decode_into<'a, T: Decode<'a>>(&'a self) -> Result<T, T::Error> {
65        Decode::from_der(self.as_bytes())
66    }
67}
68
69impl_any_conversions!(&'a OctetStringRef, 'a);
70
71impl AsRef<[u8]> for OctetStringRef {
72    fn as_ref(&self) -> &[u8] {
73        self.as_bytes()
74    }
75}
76
77impl<'a> DecodeValue<'a> for &'a OctetStringRef {
78    type Error = Error;
79
80    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Error> {
81        <&'a BytesRef>::decode_value(reader, header).map(OctetStringRef::from_bytes_ref)
82    }
83}
84
85impl EncodeValue for &OctetStringRef {
86    fn value_len(&self) -> Result<Length, Error> {
87        self.inner.value_len()
88    }
89
90    fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
91        self.inner.encode_value(writer)
92    }
93}
94
95impl FixedTag for OctetStringRef {
96    const TAG: Tag = Tag::OctetString;
97}
98impl FixedTag for &OctetStringRef {
99    const TAG: Tag = Tag::OctetString;
100}
101
102impl OrdIsValueOrd for &OctetStringRef {}
103
104impl<'a> From<&'a OctetStringRef> for AnyRef<'a> {
105    fn from(octet_string: &'a OctetStringRef) -> AnyRef<'a> {
106        AnyRef::from_tag_and_value(Tag::OctetString, &octet_string.inner)
107    }
108}
109
110impl<'a> From<&'a OctetStringRef> for &'a [u8] {
111    fn from(octet_string: &'a OctetStringRef) -> &'a [u8] {
112        octet_string.as_bytes()
113    }
114}
115
116impl<'a> TryFrom<&'a [u8]> for &'a OctetStringRef {
117    type Error = Error;
118
119    fn try_from(byte_slice: &'a [u8]) -> Result<Self, Error> {
120        OctetStringRef::new(byte_slice)
121    }
122}
123
124/// Hack for simplifying the custom derive use case.
125impl<'a> TryFrom<&&'a [u8]> for &'a OctetStringRef {
126    type Error = Error;
127
128    fn try_from(byte_slice: &&'a [u8]) -> Result<Self, Error> {
129        OctetStringRef::new(byte_slice)
130    }
131}
132
133impl<'a, const N: usize> TryFrom<&'a [u8; N]> for &'a OctetStringRef {
134    type Error = Error;
135
136    fn try_from(byte_slice: &'a [u8; N]) -> Result<Self, Error> {
137        OctetStringRef::new(byte_slice)
138    }
139}
140
141impl<'a, const N: usize> TryFrom<&'a OctetStringRef> for [u8; N] {
142    type Error = Error;
143
144    fn try_from(octet_string: &'a OctetStringRef) -> Result<Self, Self::Error> {
145        octet_string
146            .as_bytes()
147            .try_into()
148            .map_err(|_| Tag::OctetString.length_error().into())
149    }
150}
151
152#[cfg(feature = "heapless")]
153impl<const N: usize> TryFrom<&OctetStringRef> for heapless::Vec<u8, N> {
154    type Error = Error;
155
156    fn try_from(octet_string: &OctetStringRef) -> Result<Self, Self::Error> {
157        octet_string
158            .as_bytes()
159            .try_into()
160            .map_err(|_| Tag::OctetString.length_error().into())
161    }
162}
163
164#[cfg(feature = "heapless")]
165impl<'a, const N: usize> TryFrom<&'a heapless::Vec<u8, N>> for &'a OctetStringRef {
166    type Error = Error;
167
168    fn try_from(byte_vec: &'a heapless::Vec<u8, N>) -> Result<Self, Error> {
169        OctetStringRef::new(byte_vec)
170    }
171}
172
173#[cfg(feature = "alloc")]
174pub use self::allocating::OctetString;
175
176#[cfg(feature = "alloc")]
177mod allocating {
178    use super::*;
179    use crate::BytesOwned;
180    use alloc::{
181        borrow::{Borrow, Cow, ToOwned},
182        boxed::Box,
183        vec::Vec,
184    };
185
186    /// ASN.1 `OCTET STRING` type: owned form.
187    ///
188    /// Octet strings represent contiguous sequences of octets, a.k.a. bytes.
189    ///
190    /// This type provides the same functionality as [`OctetStringRef`] but owns
191    /// the backing data.
192    #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
193    pub struct OctetString {
194        /// Inner bytestring type.
195        pub(super) inner: BytesOwned,
196    }
197
198    impl OctetString {
199        /// Create a new ASN.1 `OCTET STRING`.
200        ///
201        /// # Errors
202        /// If `bytes` is too long.
203        pub fn new(bytes: impl Into<Box<[u8]>>) -> Result<Self, Error> {
204            let inner = BytesOwned::new(bytes)?;
205
206            // Ensure the bytes parse successfully as an `OctetStringRef`
207            OctetStringRef::new(inner.as_slice())?;
208
209            Ok(Self { inner })
210        }
211
212        /// Borrow the inner byte slice.
213        #[must_use]
214        pub fn as_bytes(&self) -> &[u8] {
215            self.inner.as_slice()
216        }
217
218        /// Take ownership of the octet string.
219        #[must_use]
220        pub fn into_bytes(self) -> Box<[u8]> {
221            self.inner.into()
222        }
223
224        /// Get the length of the inner byte slice.
225        #[must_use]
226        pub fn len(&self) -> Length {
227            self.inner.len()
228        }
229
230        /// Is the inner byte slice empty?
231        #[must_use]
232        pub fn is_empty(&self) -> bool {
233            self.inner.is_empty()
234        }
235    }
236
237    impl_any_conversions!(OctetString);
238
239    impl AsRef<[u8]> for OctetString {
240        fn as_ref(&self) -> &[u8] {
241            self.as_bytes()
242        }
243    }
244
245    impl Borrow<OctetStringRef> for OctetString {
246        fn borrow(&self) -> &OctetStringRef {
247            OctetStringRef::from_bytes_ref(self.inner.as_ref())
248        }
249    }
250
251    impl<'a> DecodeValue<'a> for OctetString {
252        type Error = Error;
253
254        fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Error> {
255            let inner = BytesOwned::decode_value_parts(reader, header, Self::TAG)?;
256            Ok(Self { inner })
257        }
258    }
259
260    impl EncodeValue for OctetString {
261        fn value_len(&self) -> Result<Length, Error> {
262            self.inner.value_len()
263        }
264
265        fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
266            self.inner.encode_value(writer)
267        }
268    }
269
270    impl FixedTag for OctetString {
271        const TAG: Tag = Tag::OctetString;
272    }
273
274    impl OrdIsValueOrd for OctetString {}
275
276    impl<'a> From<&'a OctetString> for &'a OctetStringRef {
277        fn from(octet_string: &'a OctetString) -> &'a OctetStringRef {
278            OctetStringRef::from_bytes_ref(octet_string.inner.as_ref())
279        }
280    }
281
282    impl From<&OctetStringRef> for OctetString {
283        fn from(octet_string_ref: &OctetStringRef) -> OctetString {
284            Self {
285                inner: octet_string_ref.inner.to_owned(),
286            }
287        }
288    }
289
290    impl From<&OctetStringRef> for Vec<u8> {
291        fn from(octet_string: &OctetStringRef) -> Vec<u8> {
292            Vec::from(octet_string.as_bytes())
293        }
294    }
295
296    /// Hack for simplifying the custom derive use case.
297    impl<'a> TryFrom<&'a Vec<u8>> for &'a OctetStringRef {
298        type Error = Error;
299
300        fn try_from(byte_vec: &'a Vec<u8>) -> Result<Self, Error> {
301            OctetStringRef::new(byte_vec)
302        }
303    }
304
305    impl From<OctetString> for Vec<u8> {
306        fn from(octet_string: OctetString) -> Vec<u8> {
307            octet_string.into_bytes().into()
308        }
309    }
310
311    impl ToOwned for OctetStringRef {
312        type Owned = OctetString;
313
314        fn to_owned(&self) -> OctetString {
315            self.into()
316        }
317    }
318
319    impl<'a> TryFrom<&'a Cow<'a, [u8]>> for &'a OctetStringRef {
320        type Error = Error;
321
322        fn try_from(byte_slice: &'a Cow<'a, [u8]>) -> Result<Self, Error> {
323            OctetStringRef::new(byte_slice)
324        }
325    }
326
327    impl<'a> TryFrom<&'a OctetStringRef> for Cow<'a, [u8]> {
328        type Error = Error;
329
330        fn try_from(octet_string: &'a OctetStringRef) -> Result<Self, Self::Error> {
331            Ok(Cow::Borrowed(octet_string.as_bytes()))
332        }
333    }
334
335    // Implement by hand because the derive would create invalid values.
336    // Use the constructor to create a valid value.
337    #[cfg(feature = "arbitrary")]
338    impl<'a> arbitrary::Arbitrary<'a> for OctetString {
339        fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
340            Self::new(Vec::arbitrary(u)?).map_err(|_| arbitrary::Error::IncorrectFormat)
341        }
342
343        fn size_hint(depth: usize) -> (usize, Option<usize>) {
344            arbitrary::size_hint::and(u8::size_hint(depth), Vec::<u8>::size_hint(depth))
345        }
346    }
347}
348
349#[cfg(feature = "bytes")]
350mod bytes {
351    use super::{OctetString, OctetStringRef};
352    use crate::{
353        DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag, Writer,
354    };
355    use alloc::vec::Vec;
356    use bytes::Bytes;
357
358    impl<'a> DecodeValue<'a> for Bytes {
359        type Error = Error;
360
361        fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
362            OctetString::decode_value(reader, header).map(Into::into)
363        }
364    }
365
366    impl EncodeValue for Bytes {
367        fn value_len(&self) -> Result<Length> {
368            self.len().try_into()
369        }
370
371        fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
372            writer.write(self.as_ref())
373        }
374    }
375
376    impl FixedTag for Bytes {
377        const TAG: Tag = Tag::OctetString;
378    }
379
380    impl From<&OctetStringRef> for Bytes {
381        fn from(octet_string: &OctetStringRef) -> Bytes {
382            Vec::from(octet_string).into()
383        }
384    }
385
386    impl From<OctetString> for Bytes {
387        fn from(octet_string: OctetString) -> Bytes {
388            Vec::from(octet_string).into()
389        }
390    }
391}
392
393#[cfg(test)]
394#[allow(clippy::unwrap_used)]
395mod tests {
396    use crate::{
397        Decode,
398        asn1::{OctetStringRef, PrintableStringRef},
399    };
400    use hex_literal::hex;
401
402    #[cfg(feature = "alloc")]
403    use {crate::Encode, alloc::borrow::Cow};
404
405    #[test]
406    fn octet_string_decode() {
407        // PrintableString "hi"
408        const EXAMPLE: &[u8] = &hex!(
409            "040c" // primitive definite length OCTET STRING
410            "48656c6c6f2c20776f726c64" // "Hello, world"
411        );
412
413        let decoded = <&OctetStringRef>::from_der(EXAMPLE).unwrap();
414        assert_eq!(decoded.as_bytes(), b"Hello, world");
415    }
416
417    #[test]
418    fn octet_string_decode_into() {
419        // PrintableString "hi"
420        let der = b"\x13\x02\x68\x69";
421        let oct = OctetStringRef::new(der).unwrap();
422
423        let res = oct.decode_into::<PrintableStringRef<'_>>().unwrap();
424        assert_eq!(AsRef::<str>::as_ref(&res), "hi");
425    }
426
427    #[cfg(feature = "alloc")]
428    #[test]
429    fn cow_octet_string_decode_and_encode() {
430        // PrintableString "hi"
431        const EXAMPLE: &[u8] = &hex!(
432            "040c" // primitive definite length OCTET STRING
433            "48656c6c6f2c20776f726c64" // "Hello, world"
434        );
435
436        let decoded = Cow::<OctetStringRef>::from_der(EXAMPLE).unwrap();
437        assert_eq!(decoded.as_bytes(), b"Hello, world");
438
439        let encoded = decoded.to_der().unwrap();
440        assert_eq!(EXAMPLE, encoded);
441    }
442
443    #[test]
444    #[cfg(all(feature = "alloc", feature = "ber"))]
445    fn decode_ber_primitive_definite() {
446        use crate::{Decode, asn1::OctetString};
447        use hex_literal::hex;
448
449        const EXAMPLE: &[u8] = &hex!(
450            "040c" // primitive definite length OCTET STRING
451            "48656c6c6f2c20776f726c64" // "Hello, world"
452        );
453
454        let decoded = OctetString::from_ber(EXAMPLE).unwrap();
455        assert_eq!(decoded.as_bytes(), b"Hello, world");
456
457        let decoded = OctetString::from_der(EXAMPLE).unwrap();
458        assert_eq!(decoded.as_bytes(), b"Hello, world");
459    }
460
461    #[test]
462    #[cfg(all(feature = "alloc", feature = "ber"))]
463    fn decode_ber_constructed_indefinite() {
464        use crate::{Decode, asn1::OctetString};
465        use hex_literal::hex;
466
467        const EXAMPLE_BER: &[u8] = &hex!(
468            "2480" // Constructed indefinite length OCTET STRING
469            "040648656c6c6f2c" // Segment containing "Hello,"
470            "040620776f726c64" // Segment containing " world"
471            "0000" // End-of-contents marker
472        );
473
474        let decoded = OctetString::from_ber(EXAMPLE_BER).unwrap();
475        assert_eq!(decoded.as_bytes(), b"Hello, world");
476    }
477
478    #[test]
479    #[cfg(all(feature = "alloc", feature = "ber"))]
480    fn decode_ber_constructed_definite() {
481        use crate::{Decode, Error, ErrorKind, Length, Tag, asn1::OctetString};
482        use hex_literal::hex;
483
484        const EXAMPLE_BER: &[u8] = &hex!(
485            "2410" // Constructed definite length OCTET STRING
486            "040648656c6c6f2c" // Segment containing "Hello,"
487            "040620776f726c64" // Segment containing " world"
488        );
489
490        let err = OctetString::from_ber(EXAMPLE_BER).err().unwrap();
491        let expected = Error::new(
492            ErrorKind::Noncanonical {
493                tag: Tag::OctetString,
494            },
495            Length::new(1),
496        );
497        assert_eq!(expected, err);
498    }
499
500    #[test]
501    #[cfg(all(feature = "alloc", feature = "ber"))]
502    fn decode_context_specific_ber_explicit() {
503        use crate::{
504            EncodingRules, SliceReader, TagNumber,
505            asn1::{ContextSpecific, OctetString},
506        };
507        use hex_literal::hex;
508
509        let tag_number = TagNumber(0);
510
511        const EXAMPLE_BER: &[u8] = &hex!(
512            "A080" // indefinite length explicit tag
513            "2480" // Constructed indefinite length OCTET STRING
514            "040648656c6c6f2c" // Segment containing "Hello,"
515            "040620776f726c64" // Segment containing " world"
516            "0000" // End-of-contents marker
517            "0000" // End-of-contents marker
518        );
519
520        let mut reader =
521            SliceReader::new_with_encoding_rules(EXAMPLE_BER, EncodingRules::Ber).unwrap();
522
523        let decoded = ContextSpecific::<OctetString>::decode_explicit(&mut reader, tag_number)
524            .unwrap()
525            .unwrap()
526            .value;
527
528        assert_eq!(decoded.as_bytes(), b"Hello, world");
529    }
530
531    #[test]
532    #[cfg(all(feature = "alloc", feature = "ber"))]
533    fn decode_context_specific_ber_implicit() {
534        use crate::{
535            EncodingRules, SliceReader, TagNumber,
536            asn1::{ContextSpecific, OctetString},
537        };
538        use hex_literal::hex;
539
540        let tag_number = TagNumber(0);
541
542        const EXAMPLE_BER: &[u8] = &hex!(
543            "A080" // implicit tag, constructed indefinite length OCTET STRING
544            "040648656c6c6f2c" // Segment containing "Hello,"
545            "040620776f726c64" // Segment containing " world"
546            "0000" // End-of-contents marker
547        );
548
549        let mut reader =
550            SliceReader::new_with_encoding_rules(EXAMPLE_BER, EncodingRules::Ber).unwrap();
551
552        let decoded = ContextSpecific::<OctetString>::decode_implicit(&mut reader, tag_number)
553            .unwrap()
554            .unwrap()
555            .value;
556
557        assert_eq!(decoded.as_bytes(), b"Hello, world");
558    }
559
560    #[test]
561    #[cfg(all(feature = "alloc", feature = "ber"))]
562    fn decode_ber_recursive_unsupported() {
563        use crate::{Decode, Error, ErrorKind, Length, asn1::OctetString};
564        use hex_literal::hex;
565
566        const EXAMPLE_BER: &[u8] = &hex!(
567            "2480" // Constructed indefinite length OCTET STRING
568                "2480" // Constructed indefinite length OCTET STRING
569                    "040648656c6c6f2c" // Segment containing "Hello,"
570                    "040620776f726c64" // Segment containing " world"
571                "0000" // End-of-contents marker
572                "040620776f726c64" // Segment containing " world"
573            "0000" // End-of-contents marker
574        );
575
576        let err = OctetString::from_ber(EXAMPLE_BER).err().unwrap();
577        let expected = Error::new(ErrorKind::IndefiniteLength, Length::new(4));
578        assert_eq!(expected, err);
579    }
580}