asn1_rs/asn1_types/sequence.rs
1use crate::*;
2use alloc::borrow::Cow;
3#[cfg(not(feature = "std"))]
4use alloc::vec::Vec;
5use core::convert::TryFrom;
6
7mod iterator;
8mod sequence_of;
9mod vec;
10
11pub use iterator::*;
12pub use sequence_of::*;
13
14/// The `SEQUENCE` object is an ordered list of heteregeneous types.
15///
16/// Sequences can usually be of 2 types:
17/// - a list of different objects (`SEQUENCE`, usually parsed as a `struct`)
18/// - a list of similar objects (`SEQUENCE OF`, usually parsed as a `Vec<T>`)
19///
20/// The current object covers the former. For the latter, see the [`SequenceOf`] documentation.
21///
22/// The `Sequence` object contains the (*unparsed*) encoded representation of its content. It provides
23/// methods to parse and iterate contained objects, or convert the sequence to other types.
24///
25/// # Building a Sequence
26///
27/// To build a DER sequence:
28/// - if the sequence is composed of objects of the same type, the [`Sequence::from_iter_to_der`] method can be used
29/// - otherwise, the [`ToDer`] trait can be used to create content incrementally
30///
31/// ```
32/// use asn1_rs::{Integer, Sequence, SerializeResult, ToDer};
33///
34/// fn build_seq<'a>() -> SerializeResult<Sequence<'a>> {
35/// let mut v = Vec::new();
36/// // add an Integer object (construct type):
37/// let i = Integer::from_u32(4);
38/// let _ = i.write_der(&mut v)?;
39/// // some primitive objects also implement `ToDer`. A string will be mapped as `Utf8String`:
40/// let _ = "abcd".write_der(&mut v)?;
41/// // return the sequence built from the DER content
42/// Ok(Sequence::new(v.into()))
43/// }
44///
45/// let seq = build_seq().unwrap();
46///
47/// ```
48///
49/// # Examples
50///
51/// ```
52/// use asn1_rs::{Error, Sequence};
53///
54/// // build sequence
55/// let it = [2, 3, 4].iter();
56/// let seq = Sequence::from_iter_to_der(it).unwrap();
57///
58/// // `seq` now contains the serialized DER representation of the array
59///
60/// // iterate objects
61/// let mut sum = 0;
62/// for item in seq.der_iter::<u32, Error>() {
63/// // item has type `Result<u32>`, since parsing the serialized bytes could fail
64/// sum += item.expect("parsing list item failed");
65/// }
66/// assert_eq!(sum, 9);
67///
68/// ```
69///
70/// Note: the above example encodes a `SEQUENCE OF INTEGER` object, the [`SequenceOf`] object could
71/// be used to provide a simpler API.
72///
73#[derive(Clone, Debug, PartialEq, Eq)]
74pub struct Sequence<'a> {
75 /// Serialized DER representation of the sequence content
76 pub content: Cow<'a, [u8]>,
77}
78
79impl<'a> Sequence<'a> {
80 /// Build a sequence, given the provided content
81 pub const fn new(content: Cow<'a, [u8]>) -> Self {
82 Sequence { content }
83 }
84
85 /// Consume the sequence and return the content
86 #[inline]
87 pub fn into_content(self) -> Cow<'a, [u8]> {
88 self.content
89 }
90
91 /// Apply the parsing function to the sequence content, consuming the sequence
92 ///
93 /// Note: this function expects the caller to take ownership of content.
94 /// In some cases, handling the lifetime of objects is not easy (when keeping only references on
95 /// data). Other methods are provided (depending on the use case):
96 /// - [`Sequence::parse`] takes a reference on the sequence data, but does not consume it,
97 /// - [`Sequence::from_der_and_then`] does the parsing of the sequence and applying the function
98 /// in one step, ensuring there are only references (and dropping the temporary sequence).
99 pub fn and_then<U, F, E>(self, op: F) -> ParseResult<'a, U, E>
100 where
101 F: FnOnce(Cow<'a, [u8]>) -> ParseResult<U, E>,
102 {
103 op(self.content)
104 }
105
106 /// Same as [`Sequence::from_der_and_then`], but using BER encoding (no constraints).
107 pub fn from_ber_and_then<U, F, E>(bytes: &'a [u8], op: F) -> ParseResult<'a, U, E>
108 where
109 F: FnOnce(&'a [u8]) -> ParseResult<U, E>,
110 E: From<Error>,
111 {
112 let (rem, seq) = Sequence::from_ber(bytes).map_err(Err::convert)?;
113 let data = match seq.content {
114 Cow::Borrowed(b) => b,
115 // Since 'any' is built from 'bytes', it is borrowed by construction
116 Cow::Owned(_) => unreachable!(),
117 };
118 let (_, res) = op(data)?;
119 Ok((rem, res))
120 }
121
122 /// Parse a DER sequence and apply the provided parsing function to content
123 ///
124 /// After parsing, the sequence object and header are discarded.
125 ///
126 /// ```
127 /// use asn1_rs::{FromDer, ParseResult, Sequence};
128 ///
129 /// // Parse a SEQUENCE {
130 /// // a INTEGER (0..255),
131 /// // b INTEGER (0..4294967296)
132 /// // }
133 /// // and return only `(a,b)
134 /// fn parser(i: &[u8]) -> ParseResult<(u8, u32)> {
135 /// Sequence::from_der_and_then(i, |i| {
136 /// let (i, a) = u8::from_der(i)?;
137 /// let (i, b) = u32::from_der(i)?;
138 /// Ok((i, (a, b)))
139 /// }
140 /// )
141 /// }
142 /// ```
143 pub fn from_der_and_then<U, F, E>(bytes: &'a [u8], op: F) -> ParseResult<'a, U, E>
144 where
145 F: FnOnce(&'a [u8]) -> ParseResult<U, E>,
146 E: From<Error>,
147 {
148 let (rem, seq) = Sequence::from_der(bytes).map_err(Err::convert)?;
149 let data = match seq.content {
150 Cow::Borrowed(b) => b,
151 // Since 'any' is built from 'bytes', it is borrowed by construction
152 Cow::Owned(_) => unreachable!(),
153 };
154 let (_, res) = op(data)?;
155 Ok((rem, res))
156 }
157
158 /// Apply the parsing function to the sequence content (non-consuming version)
159 pub fn parse<F, T, E>(&'a self, mut f: F) -> ParseResult<'a, T, E>
160 where
161 F: FnMut(&'a [u8]) -> ParseResult<'a, T, E>,
162 {
163 let input: &[u8] = &self.content;
164 f(input)
165 }
166
167 /// Apply the parsing function to the sequence content (consuming version)
168 ///
169 /// Note: to parse and apply a parsing function in one step, use the
170 /// [`Sequence::from_der_and_then`] method.
171 ///
172 /// # Limitations
173 ///
174 /// This function fails if the sequence contains `Owned` data, because the parsing function
175 /// takes a reference on data (which is dropped).
176 pub fn parse_into<F, T, E>(self, mut f: F) -> ParseResult<'a, T, E>
177 where
178 F: FnMut(&'a [u8]) -> ParseResult<'a, T, E>,
179 E: From<Error>,
180 {
181 match self.content {
182 Cow::Borrowed(b) => f(b),
183 _ => Err(Err::Error(Error::LifetimeError.into())),
184 }
185 }
186
187 /// Return an iterator over the sequence content, attempting to decode objects as BER
188 ///
189 /// This method can be used when all objects from the sequence have the same type.
190 pub fn ber_iter<T, E>(&'a self) -> SequenceIterator<'a, T, BerParser, E>
191 where
192 T: FromBer<'a, E>,
193 {
194 SequenceIterator::new(&self.content)
195 }
196
197 /// Return an iterator over the sequence content, attempting to decode objects as DER
198 ///
199 /// This method can be used when all objects from the sequence have the same type.
200 pub fn der_iter<T, E>(&'a self) -> SequenceIterator<'a, T, DerParser, E>
201 where
202 T: FromDer<'a, E>,
203 {
204 SequenceIterator::new(&self.content)
205 }
206
207 /// Attempt to parse the sequence as a `SEQUENCE OF` items (BER), and return the parsed items as a `Vec`.
208 pub fn ber_sequence_of<T, E>(&'a self) -> Result<Vec<T>, E>
209 where
210 T: FromBer<'a, E>,
211 E: From<Error>,
212 {
213 self.ber_iter().collect()
214 }
215
216 /// Attempt to parse the sequence as a `SEQUENCE OF` items (DER), and return the parsed items as a `Vec`.
217 pub fn der_sequence_of<T, E>(&'a self) -> Result<Vec<T>, E>
218 where
219 T: FromDer<'a, E>,
220 E: From<Error>,
221 {
222 self.der_iter().collect()
223 }
224
225 /// Attempt to parse the sequence as a `SEQUENCE OF` items (BER) (consuming input),
226 /// and return the parsed items as a `Vec`.
227 ///
228 /// Note: if `Self` is an `Owned` object, the data will be duplicated (causing allocations) into separate objects.
229 pub fn into_ber_sequence_of<T, U, E>(self) -> Result<Vec<T>, E>
230 where
231 for<'b> T: FromBer<'b, E>,
232 E: From<Error>,
233 T: ToStatic<Owned = T>,
234 {
235 match self.content {
236 Cow::Borrowed(bytes) => SequenceIterator::<T, BerParser, E>::new(bytes).collect(),
237 Cow::Owned(data) => {
238 let v1 = SequenceIterator::<T, BerParser, E>::new(&data)
239 .collect::<Result<Vec<T>, E>>()?;
240 let v2 = v1.iter().map(|t| t.to_static()).collect::<Vec<_>>();
241 Ok(v2)
242 }
243 }
244 }
245
246 /// Attempt to parse the sequence as a `SEQUENCE OF` items (DER) (consuming input),
247 /// and return the parsed items as a `Vec`.
248 ///
249 /// Note: if `Self` is an `Owned` object, the data will be duplicated (causing allocations) into separate objects.
250 pub fn into_der_sequence_of<T, U, E>(self) -> Result<Vec<T>, E>
251 where
252 for<'b> T: FromDer<'b, E>,
253 E: From<Error>,
254 T: ToStatic<Owned = T>,
255 {
256 match self.content {
257 Cow::Borrowed(bytes) => SequenceIterator::<T, DerParser, E>::new(bytes).collect(),
258 Cow::Owned(data) => {
259 let v1 = SequenceIterator::<T, DerParser, E>::new(&data)
260 .collect::<Result<Vec<T>, E>>()?;
261 let v2 = v1.iter().map(|t| t.to_static()).collect::<Vec<_>>();
262 Ok(v2)
263 }
264 }
265 }
266
267 pub fn into_der_sequence_of_ref<T, E>(self) -> Result<Vec<T>, E>
268 where
269 T: FromDer<'a, E>,
270 E: From<Error>,
271 {
272 match self.content {
273 Cow::Borrowed(bytes) => SequenceIterator::<T, DerParser, E>::new(bytes).collect(),
274 Cow::Owned(_) => Err(Error::LifetimeError.into()),
275 }
276 }
277}
278
279impl<'a> ToStatic for Sequence<'a> {
280 type Owned = Sequence<'static>;
281
282 fn to_static(&self) -> Self::Owned {
283 Sequence {
284 content: Cow::Owned(self.content.to_vec()),
285 }
286 }
287}
288
289impl<T, U> ToStatic for Vec<T>
290where
291 T: ToStatic<Owned = U>,
292 U: 'static,
293{
294 type Owned = Vec<U>;
295
296 fn to_static(&self) -> Self::Owned {
297 self.iter().map(|t| t.to_static()).collect()
298 }
299}
300
301impl<'a> AsRef<[u8]> for Sequence<'a> {
302 fn as_ref(&self) -> &[u8] {
303 &self.content
304 }
305}
306
307impl<'a> TryFrom<Any<'a>> for Sequence<'a> {
308 type Error = Error;
309
310 fn try_from(any: Any<'a>) -> Result<Sequence<'a>> {
311 TryFrom::try_from(&any)
312 }
313}
314
315impl<'a, 'b> TryFrom<&'b Any<'a>> for Sequence<'a> {
316 type Error = Error;
317
318 fn try_from(any: &'b Any<'a>) -> Result<Sequence<'a>> {
319 any.tag().assert_eq(Self::TAG)?;
320 any.header.assert_constructed()?;
321 Ok(Sequence {
322 content: Cow::Borrowed(any.data),
323 })
324 }
325}
326
327impl<'a> CheckDerConstraints for Sequence<'a> {
328 fn check_constraints(_any: &Any) -> Result<()> {
329 // TODO: iterate on ANY objects and check constraints? -> this will not be exhaustive
330 // test, for ex INTEGER encoding will not be checked
331 Ok(())
332 }
333}
334
335impl<'a> DerAutoDerive for Sequence<'a> {}
336
337impl<'a> Tagged for Sequence<'a> {
338 const TAG: Tag = Tag::Sequence;
339}
340
341#[cfg(feature = "std")]
342impl ToDer for Sequence<'_> {
343 fn to_der_len(&self) -> Result<usize> {
344 let sz = self.content.len();
345 if sz < 127 {
346 // 1 (class+tag) + 1 (length) + len
347 Ok(2 + sz)
348 } else {
349 // 1 (class+tag) + n (length) + len
350 let n = Length::Definite(sz).to_der_len()?;
351 Ok(1 + n + sz)
352 }
353 }
354
355 fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
356 let header = Header::new(
357 Class::Universal,
358 true,
359 Self::TAG,
360 Length::Definite(self.content.len()),
361 );
362 header.write_der_header(writer).map_err(Into::into)
363 }
364
365 fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
366 writer.write(&self.content).map_err(Into::into)
367 }
368}
369
370#[cfg(feature = "std")]
371impl<'a> Sequence<'a> {
372 /// Attempt to create a `Sequence` from an iterator over serializable objects (to DER)
373 ///
374 /// # Examples
375 ///
376 /// ```
377 /// use asn1_rs::Sequence;
378 ///
379 /// // build sequence
380 /// let it = [2, 3, 4].iter();
381 /// let seq = Sequence::from_iter_to_der(it).unwrap();
382 /// ```
383 pub fn from_iter_to_der<T, IT>(it: IT) -> SerializeResult<Self>
384 where
385 IT: Iterator<Item = T>,
386 T: ToDer,
387 T: Tagged,
388 {
389 let mut v = Vec::new();
390 for item in it {
391 let item_v = <T as ToDer>::to_der_vec(&item)?;
392 v.extend_from_slice(&item_v);
393 }
394 Ok(Sequence {
395 content: Cow::Owned(v),
396 })
397 }
398}