Skip to main content

der/
bytes.rs

1//! Common handling for types backed by byte slices with enforcement of a
2//! library-level length limitation i.e. `Length::max()`.
3
4use crate::{DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, Writer};
5use core::cmp::Ordering;
6
7/// Byte slice newtype which respects the `Length::MAX` limit.
8#[derive(Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
9#[repr(transparent)]
10pub(crate) struct BytesRef([u8]);
11
12impl BytesRef {
13    /// Constant value representing an empty byte slice.
14    pub const EMPTY: &'static Self = Self::new_unchecked(&[]);
15
16    /// Create a new [`BytesRef`], ensuring that the provided `slice` value
17    /// is shorter than `Length::MAX`.
18    pub const fn new(slice: &[u8]) -> Result<&Self> {
19        match Length::new_usize(slice.len()) {
20            Ok(_) => Ok(Self::new_unchecked(slice)),
21            Err(err) => Err(err),
22        }
23    }
24
25    /// Perform a raw conversion of a byte slice to `Self` without first performing a length check.
26    pub(crate) const fn new_unchecked(slice: &[u8]) -> &Self {
27        // SAFETY: `Self` is a `repr(transparent)` newtype for `[u8]`
28        #[allow(unsafe_code)]
29        unsafe {
30            &*(core::ptr::from_ref::<[u8]>(slice) as *const Self)
31        }
32    }
33
34    /// Get a pointer to this [`BytesRef`].
35    pub(crate) const fn as_ptr(&self) -> *const BytesRef {
36        core::ptr::from_ref::<BytesRef>(self)
37    }
38
39    /// Borrow the inner byte slice
40    pub const fn as_slice(&self) -> &[u8] {
41        &self.0
42    }
43
44    /// Get the [`Length`] of this [`BytesRef`].
45    pub fn len(&self) -> Length {
46        debug_assert!(u32::try_from(self.0.len()).is_ok());
47
48        #[allow(clippy::cast_possible_truncation)] // checked by constructors
49        Length::new(self.0.len() as u32)
50    }
51
52    /// Is this [`BytesRef`] empty?
53    pub const fn is_empty(&self) -> bool {
54        self.0.is_empty()
55    }
56
57    /// Get a prefix of a [`crate::bytes_ref::BytesRef`] of the given length.
58    pub fn prefix(&self, length: Length) -> Result<&Self> {
59        let inner = self
60            .as_slice()
61            .get(..usize::try_from(length)?)
62            .ok_or_else(|| Error::incomplete(self.len()))?;
63
64        Ok(Self::new_unchecked(inner))
65    }
66}
67
68impl AsRef<[u8]> for BytesRef {
69    fn as_ref(&self) -> &[u8] {
70        self.as_slice()
71    }
72}
73
74impl<'a> DecodeValue<'a> for &'a BytesRef {
75    type Error = Error;
76
77    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
78        BytesRef::new(reader.read_slice(header.length())?)
79    }
80}
81
82impl EncodeValue for BytesRef {
83    fn value_len(&self) -> Result<Length> {
84        Ok(self.len())
85    }
86
87    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
88        writer.write(self.as_ref())
89    }
90}
91
92impl DerOrd for BytesRef {
93    fn der_cmp(&self, other: &Self) -> Result<Ordering> {
94        Ok(self.as_slice().cmp(other.as_slice()))
95    }
96}
97
98impl<'a> TryFrom<&'a [u8]> for &'a BytesRef {
99    type Error = Error;
100
101    fn try_from(slice: &'a [u8]) -> Result<Self> {
102        BytesRef::new(slice)
103    }
104}
105
106/// Implemented by hand because the derive would create invalid values.
107/// Makes sure the length and the inner.len matches.
108#[cfg(feature = "arbitrary")]
109impl<'a> arbitrary::Arbitrary<'a> for &'a BytesRef {
110    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
111        let length: Length = u.arbitrary()?;
112        Ok(BytesRef::new_unchecked(
113            u.bytes(u32::from(length) as usize)?,
114        ))
115    }
116
117    fn size_hint(depth: usize) -> (usize, Option<usize>) {
118        arbitrary::size_hint::and(Length::size_hint(depth), (0, None))
119    }
120}
121
122#[cfg(feature = "alloc")]
123pub(crate) mod allocating {
124    use super::BytesRef;
125    #[cfg(feature = "ber")]
126    use crate::{ErrorKind, length::indefinite::read_constructed_vec};
127
128    use crate::{
129        DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, Tag, Writer,
130    };
131
132    use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
133    use core::{borrow::Borrow, cmp::Ordering, ops::Deref};
134
135    /// Byte slice newtype which respects the `Length::max()` limit.
136    #[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
137    pub(crate) struct BytesOwned {
138        /// Precomputed `Length` (avoids possible panicking conversions)
139        length: Length,
140
141        /// Inner value
142        inner: Box<[u8]>,
143    }
144
145    impl BytesOwned {
146        /// Create a new [`BytesOwned`], ensuring that the provided `slice` value
147        /// is shorter than `Length::max()`.
148        pub fn new(data: impl Into<Box<[u8]>>) -> Result<Self> {
149            let inner: Box<[u8]> = data.into();
150
151            Ok(Self {
152                length: Length::try_from(inner.len())?,
153                inner,
154            })
155        }
156        /// Decodes [`BytesOwned`] as DER, or from parts, when using a BER reader.
157        pub fn decode_value_parts<'a, R: Reader<'a>>(
158            reader: &mut R,
159            header: Header,
160            inner_tag: Tag,
161        ) -> Result<Self> {
162            #[cfg(feature = "ber")]
163            if header.is_constructed() {
164                if header.length().is_indefinite() && reader.encoding_rules().is_ber() {
165                    // Reassemble indefinite length string types
166                    return Self::new(read_constructed_vec(reader, header.length(), inner_tag)?);
167                } else {
168                    // NOTE:
169                    // constructed strings with definite length unsupported
170                    // See discussion
171                    //   - https://github.com/RustCrypto/formats/issues/779#issuecomment-3049869721
172                    //
173                    // NOTE: this repositions the error to be at the end of the header
174                    // rather than at the beginning of the value
175                    return Err(Error::new(
176                        ErrorKind::Noncanonical { tag: header.tag() },
177                        reader.position().saturating_sub(Length::ONE),
178                    ));
179                }
180            }
181
182            #[cfg(not(feature = "ber"))]
183            let _ = inner_tag;
184
185            Self::decode_value(reader, header)
186        }
187    }
188
189    impl AsRef<[u8]> for BytesOwned {
190        fn as_ref(&self) -> &[u8] {
191            &self.inner
192        }
193    }
194
195    impl AsRef<BytesRef> for BytesOwned {
196        fn as_ref(&self) -> &BytesRef {
197            BytesRef::new_unchecked(&self.inner)
198        }
199    }
200
201    impl Borrow<[u8]> for BytesOwned {
202        fn borrow(&self) -> &[u8] {
203            &self.inner
204        }
205    }
206
207    impl Borrow<BytesRef> for BytesOwned {
208        fn borrow(&self) -> &BytesRef {
209            BytesRef::new_unchecked(&self.inner)
210        }
211    }
212
213    impl Deref for BytesOwned {
214        type Target = BytesRef;
215
216        fn deref(&self) -> &BytesRef {
217            self.borrow()
218        }
219    }
220
221    impl<'a> DecodeValue<'a> for BytesOwned {
222        type Error = Error;
223
224        fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
225            reader.read_vec(header.length()).and_then(Self::new)
226        }
227    }
228
229    impl EncodeValue for BytesOwned {
230        fn value_len(&self) -> Result<Length> {
231            Ok(self.length)
232        }
233
234        fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
235            writer.write(self.as_ref())
236        }
237    }
238
239    impl Default for BytesOwned {
240        fn default() -> Self {
241            Self {
242                length: Length::ZERO,
243                inner: Box::new([]),
244            }
245        }
246    }
247
248    impl DerOrd for BytesOwned {
249        fn der_cmp(&self, other: &Self) -> Result<Ordering> {
250            Ok(self.as_slice().cmp(other.as_slice()))
251        }
252    }
253
254    impl From<BytesOwned> for Box<[u8]> {
255        fn from(bytes: BytesOwned) -> Box<[u8]> {
256            bytes.inner
257        }
258    }
259
260    impl From<&BytesRef> for BytesOwned {
261        fn from(bytes: &BytesRef) -> BytesOwned {
262            BytesOwned {
263                length: bytes.len(),
264                inner: bytes.as_slice().into(),
265            }
266        }
267    }
268
269    impl TryFrom<&[u8]> for BytesOwned {
270        type Error = Error;
271
272        fn try_from(bytes: &[u8]) -> Result<Self> {
273            Self::new(bytes)
274        }
275    }
276
277    impl TryFrom<Box<[u8]>> for BytesOwned {
278        type Error = Error;
279
280        fn try_from(bytes: Box<[u8]>) -> Result<Self> {
281            Self::new(bytes)
282        }
283    }
284
285    impl TryFrom<Vec<u8>> for BytesOwned {
286        type Error = Error;
287
288        fn try_from(bytes: Vec<u8>) -> Result<Self> {
289            Self::new(bytes)
290        }
291    }
292
293    impl ToOwned for BytesRef {
294        type Owned = BytesOwned;
295
296        fn to_owned(&self) -> BytesOwned {
297            BytesOwned {
298                inner: self.as_slice().into(),
299                length: self.len(),
300            }
301        }
302    }
303
304    // Implement by hand because the derive would create invalid values.
305    // Make sure the length and the inner.len matches.
306    #[cfg(feature = "arbitrary")]
307    impl<'a> arbitrary::Arbitrary<'a> for BytesOwned {
308        fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
309            let length = u.arbitrary()?;
310            Ok(Self {
311                length,
312                inner: Box::from(u.bytes(u32::from(length) as usize)?),
313            })
314        }
315
316        fn size_hint(depth: usize) -> (usize, Option<usize>) {
317            arbitrary::size_hint::and(Length::size_hint(depth), (0, None))
318        }
319    }
320}