Coverage Report

Created: 2025-12-31 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/asn1-rs-0.6.2/src/header.rs
Line
Count
Source
1
use crate::ber::*;
2
use crate::der_constraint_fail_if;
3
use crate::error::*;
4
#[cfg(feature = "std")]
5
use crate::ToDer;
6
use crate::{BerParser, Class, DerParser, DynTagged, FromBer, FromDer, Length, Tag, ToStatic};
7
use alloc::borrow::Cow;
8
use core::convert::TryFrom;
9
use nom::bytes::streaming::take;
10
11
/// BER/DER object header (identifier and length)
12
#[derive(Clone, Debug)]
13
pub struct Header<'a> {
14
    /// Object class: universal, application, context-specific, or private
15
    pub(crate) class: Class,
16
    /// Constructed attribute: true if constructed, else false
17
    pub(crate) constructed: bool,
18
    /// Tag number
19
    pub(crate) tag: Tag,
20
    /// Object length: value if definite, or indefinite
21
    pub(crate) length: Length,
22
23
    /// Optionally, the raw encoding of the tag
24
    ///
25
    /// This is useful in some cases, where different representations of the same
26
    /// BER tags have different meanings (BER only)
27
    pub(crate) raw_tag: Option<Cow<'a, [u8]>>,
28
}
29
30
impl<'a> Header<'a> {
31
    /// Build a new BER/DER header from the provided values
32
23.6M
    pub const fn new(class: Class, constructed: bool, tag: Tag, length: Length) -> Self {
33
23.6M
        Header {
34
23.6M
            tag,
35
23.6M
            constructed,
36
23.6M
            class,
37
23.6M
            length,
38
23.6M
            raw_tag: None,
39
23.6M
        }
40
23.6M
    }
41
42
    /// Build a new BER/DER header from the provided tag, with default values for other fields
43
    #[inline]
44
0
    pub const fn new_simple(tag: Tag) -> Self {
45
0
        let constructed = matches!(tag, Tag::Sequence | Tag::Set);
46
0
        Self::new(Class::Universal, constructed, tag, Length::Definite(0))
47
0
    }
48
49
    /// Set the class of this `Header`
50
    #[inline]
51
0
    pub fn with_class(self, class: Class) -> Self {
52
0
        Self { class, ..self }
53
0
    }
54
55
    /// Set the constructed flags of this `Header`
56
    #[inline]
57
0
    pub fn with_constructed(self, constructed: bool) -> Self {
58
0
        Self {
59
0
            constructed,
60
0
            ..self
61
0
        }
62
0
    }
63
64
    /// Set the tag of this `Header`
65
    #[inline]
66
0
    pub fn with_tag(self, tag: Tag) -> Self {
67
0
        Self { tag, ..self }
68
0
    }
69
70
    /// Set the length of this `Header`
71
    #[inline]
72
0
    pub fn with_length(self, length: Length) -> Self {
73
0
        Self { length, ..self }
74
0
    }
75
76
    /// Update header to add reference to raw tag
77
    #[inline]
78
23.3M
    pub fn with_raw_tag(self, raw_tag: Option<Cow<'a, [u8]>>) -> Self {
79
23.3M
        Header { raw_tag, ..self }
80
23.3M
    }
81
82
    /// Return the class of this header.
83
    #[inline]
84
425k
    pub const fn class(&self) -> Class {
85
425k
        self.class
86
425k
    }
87
88
    /// Return true if this header has the 'constructed' flag.
89
    #[inline]
90
123k
    pub const fn constructed(&self) -> bool {
91
123k
        self.constructed
92
123k
    }
93
94
    /// Return the tag of this header.
95
    #[inline]
96
1.46M
    pub const fn tag(&self) -> Tag {
97
1.46M
        self.tag
98
1.46M
    }
99
100
    /// Return the length of this header.
101
    #[inline]
102
1.58M
    pub const fn length(&self) -> Length {
103
1.58M
        self.length
104
1.58M
    }
105
106
    /// Return the raw tag encoding, if it was stored in this object
107
    #[inline]
108
0
    pub fn raw_tag(&self) -> Option<&[u8]> {
109
0
        self.raw_tag.as_ref().map(|cow| cow.as_ref())
110
0
    }
111
112
    /// Test if object is primitive
113
    #[inline]
114
3.83M
    pub const fn is_primitive(&self) -> bool {
115
3.83M
        !self.constructed
116
3.83M
    }
117
118
    /// Test if object is constructed
119
    #[inline]
120
365k
    pub const fn is_constructed(&self) -> bool {
121
365k
        self.constructed
122
365k
    }
123
124
    /// Return error if class is not the expected class
125
    #[inline]
126
0
    pub const fn assert_class(&self, class: Class) -> Result<()> {
127
0
        self.class.assert_eq(class)
128
0
    }
129
130
    /// Return error if tag is not the expected tag
131
    #[inline]
132
484k
    pub const fn assert_tag(&self, tag: Tag) -> Result<()> {
133
484k
        self.tag.assert_eq(tag)
134
484k
    }
135
136
    /// Return error if object is not primitive
137
    #[inline]
138
2.44M
    pub const fn assert_primitive(&self) -> Result<()> {
139
2.44M
        if self.is_primitive() {
140
2.43M
            Ok(())
141
        } else {
142
2.55k
            Err(Error::ConstructUnexpected)
143
        }
144
2.44M
    }
145
146
    /// Return error if object is primitive
147
    #[inline]
148
1.39M
    pub const fn assert_constructed(&self) -> Result<()> {
149
1.39M
        if !self.is_primitive() {
150
1.31M
            Ok(())
151
        } else {
152
73.1k
            Err(Error::ConstructExpected)
153
        }
154
1.39M
    }
155
156
    /// Test if object class is Universal
157
    #[inline]
158
0
    pub const fn is_universal(&self) -> bool {
159
0
        self.class as u8 == Class::Universal as u8
160
0
    }
161
    /// Test if object class is Application
162
    #[inline]
163
739k
    pub const fn is_application(&self) -> bool {
164
739k
        self.class as u8 == Class::Application as u8
165
739k
    }
166
    /// Test if object class is Context-specific
167
    #[inline]
168
779k
    pub const fn is_contextspecific(&self) -> bool {
169
779k
        self.class as u8 == Class::ContextSpecific as u8
170
779k
    }
171
    /// Test if object class is Private
172
    #[inline]
173
0
    pub const fn is_private(&self) -> bool {
174
0
        self.class as u8 == Class::Private as u8
175
0
    }
176
177
    /// Return error if object length is definite
178
    #[inline]
179
0
    pub const fn assert_definite(&self) -> Result<()> {
180
0
        if self.length.is_definite() {
181
0
            Ok(())
182
        } else {
183
0
            Err(Error::DerConstraintFailed(DerConstraint::IndefiniteLength))
184
        }
185
0
    }
186
187
    /// Get the content following a BER header
188
    #[inline]
189
0
    pub fn parse_ber_content<'i>(&'_ self, i: &'i [u8]) -> ParseResult<'i, &'i [u8]> {
190
        // defaults to maximum depth 8
191
        // depth is used only if BER, and length is indefinite
192
0
        BerParser::get_object_content(i, self, 8)
193
0
    }
194
195
    /// Get the content following a DER header
196
    #[inline]
197
0
    pub fn parse_der_content<'i>(&'_ self, i: &'i [u8]) -> ParseResult<'i, &'i [u8]> {
198
0
        self.assert_definite()?;
199
0
        DerParser::get_object_content(i, self, 8)
200
0
    }
201
}
202
203
impl From<Tag> for Header<'_> {
204
    #[inline]
205
0
    fn from(tag: Tag) -> Self {
206
0
        let constructed = matches!(tag, Tag::Sequence | Tag::Set);
207
0
        Self::new(Class::Universal, constructed, tag, Length::Definite(0))
208
0
    }
209
}
210
211
impl<'a> ToStatic for Header<'a> {
212
    type Owned = Header<'static>;
213
214
0
    fn to_static(&self) -> Self::Owned {
215
0
        let raw_tag: Option<Cow<'static, [u8]>> =
216
0
            self.raw_tag.as_ref().map(|b| Cow::Owned(b.to_vec()));
217
0
        Header {
218
0
            tag: self.tag,
219
0
            constructed: self.constructed,
220
0
            class: self.class,
221
0
            length: self.length,
222
0
            raw_tag,
223
0
        }
224
0
    }
225
}
226
227
impl<'a> FromBer<'a> for Header<'a> {
228
20.8M
    fn from_ber(bytes: &'a [u8]) -> ParseResult<Self> {
229
20.8M
        let (i1, el) = parse_identifier(bytes)?;
230
20.8M
        let class = match Class::try_from(el.0) {
231
20.8M
            Ok(c) => c,
232
0
            Err(_) => unreachable!(), // Cannot fail, we have read exactly 2 bits
233
        };
234
20.8M
        let (i2, len) = parse_ber_length_byte(i1)?;
235
20.8M
        let (i3, len) = match (len.0, len.1) {
236
20.1M
            (0, l1) => {
237
                // Short form: MSB is 0, the rest encodes the length (which can be 0) (8.1.3.4)
238
20.1M
                (i2, Length::Definite(usize::from(l1)))
239
            }
240
            (_, 0) => {
241
                // Indefinite form: MSB is 1, the rest is 0 (8.1.3.6)
242
                // If encoding is primitive, definite form shall be used (8.1.3.2)
243
450k
                if el.1 == 0 {
244
1.81k
                    return Err(nom::Err::Error(Error::ConstructExpected));
245
448k
                }
246
448k
                (i2, Length::Indefinite)
247
            }
248
235k
            (_, l1) => {
249
                // if len is 0xff -> error (8.1.3.5)
250
235k
                if l1 == 0b0111_1111 {
251
8.42k
                    return Err(nom::Err::Error(Error::InvalidLength));
252
227k
                }
253
227k
                let (i3, llen) = take(l1)(i2)?;
254
183k
                match bytes_to_u64(llen) {
255
180k
                    Ok(l) => {
256
180k
                        let l =
257
180k
                            usize::try_from(l).or(Err(nom::Err::Error(Error::InvalidLength)))?;
258
180k
                        (i3, Length::Definite(l))
259
                    }
260
                    Err(_) => {
261
3.06k
                        return Err(nom::Err::Error(Error::InvalidLength));
262
                    }
263
                }
264
            }
265
        };
266
20.8M
        let constructed = el.1 != 0;
267
20.8M
        let hdr = Header::new(class, constructed, Tag(el.2), len).with_raw_tag(Some(el.3.into()));
268
20.8M
        Ok((i3, hdr))
269
20.8M
    }
270
}
271
272
impl<'a> FromDer<'a> for Header<'a> {
273
2.80M
    fn from_der(bytes: &'a [u8]) -> ParseResult<Self> {
274
2.80M
        let (i1, el) = parse_identifier(bytes)?;
275
2.61M
        let class = match Class::try_from(el.0) {
276
2.61M
            Ok(c) => c,
277
0
            Err(_) => unreachable!(), // Cannot fail, we have read exactly 2 bits
278
        };
279
2.61M
        let (i2, len) = parse_ber_length_byte(i1)?;
280
2.58M
        let (i3, len) = match (len.0, len.1) {
281
2.43M
            (0, l1) => {
282
                // Short form: MSB is 0, the rest encodes the length (which can be 0) (8.1.3.4)
283
2.43M
                (i2, Length::Definite(usize::from(l1)))
284
            }
285
            (_, 0) => {
286
                // Indefinite form is not allowed in DER (10.1)
287
3.85k
                return Err(nom::Err::Error(Error::DerConstraintFailed(
288
3.85k
                    DerConstraint::IndefiniteLength,
289
3.85k
                )));
290
            }
291
150k
            (_, l1) => {
292
                // if len is 0xff -> error (8.1.3.5)
293
150k
                if l1 == 0b0111_1111 {
294
10.7k
                    return Err(nom::Err::Error(Error::InvalidLength));
295
139k
                }
296
                // DER(9.1) if len is 0 (indefinite form), obj must be constructed
297
0
                der_constraint_fail_if!(
298
                    &i[1..],
299
139k
                    len.1 == 0 && el.1 != 1,
300
0
                    DerConstraint::NotConstructed
301
                );
302
139k
                let (i3, llen) = take(l1)(i2)?;
303
120k
                match bytes_to_u64(llen) {
304
113k
                    Ok(l) => {
305
                        // DER: should have been encoded in short form (< 127)
306
                        // XXX der_constraint_fail_if!(i, l < 127);
307
113k
                        let l =
308
113k
                            usize::try_from(l).or(Err(nom::Err::Error(Error::InvalidLength)))?;
309
113k
                        (i3, Length::Definite(l))
310
                    }
311
                    Err(_) => {
312
6.75k
                        return Err(nom::Err::Error(Error::InvalidLength));
313
                    }
314
                }
315
            }
316
        };
317
2.54M
        let constructed = el.1 != 0;
318
2.54M
        let hdr = Header::new(class, constructed, Tag(el.2), len).with_raw_tag(Some(el.3.into()));
319
2.54M
        Ok((i3, hdr))
320
2.80M
    }
321
}
322
323
impl DynTagged for (Class, bool, Tag) {
324
0
    fn tag(&self) -> Tag {
325
0
        self.2
326
0
    }
327
}
328
329
#[cfg(feature = "std")]
330
impl ToDer for (Class, bool, Tag) {
331
0
    fn to_der_len(&self) -> Result<usize> {
332
0
        let (_, _, tag) = self;
333
0
        match tag.0 {
334
0
            0..=30 => Ok(1),
335
0
            t => {
336
0
                let mut sz = 1;
337
0
                let mut val = t;
338
                loop {
339
0
                    if val <= 127 {
340
0
                        return Ok(sz + 1);
341
0
                    } else {
342
0
                        val >>= 7;
343
0
                        sz += 1;
344
0
                    }
345
                }
346
            }
347
        }
348
0
    }
349
350
0
    fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
351
0
        let (class, constructed, tag) = self;
352
0
        let b0 = (*class as u8) << 6;
353
0
        let b0 = b0 | if *constructed { 0b10_0000 } else { 0 };
354
0
        if tag.0 > 30 {
355
0
            let mut val = tag.0;
356
357
            const BUF_SZ: usize = 8;
358
0
            let mut buffer = [0u8; BUF_SZ];
359
0
            let mut current_index = BUF_SZ - 1;
360
361
            // first byte: class+constructed+0x1f
362
0
            let b0 = b0 | 0b1_1111;
363
0
            let mut sz = writer.write(&[b0])?;
364
365
            // now write bytes from right (last) to left
366
367
            // last encoded byte
368
0
            buffer[current_index] = (val & 0x7f) as u8;
369
0
            val >>= 7;
370
371
0
            while val > 0 {
372
0
                current_index -= 1;
373
0
                if current_index == 0 {
374
0
                    return Err(SerializeError::InvalidLength);
375
0
                }
376
0
                buffer[current_index] = (val & 0x7f) as u8 | 0x80;
377
0
                val >>= 7;
378
            }
379
380
0
            sz += writer.write(&buffer[current_index..])?;
381
0
            Ok(sz)
382
        } else {
383
0
            let b0 = b0 | (tag.0 as u8);
384
0
            let sz = writer.write(&[b0])?;
385
0
            Ok(sz)
386
        }
387
0
    }
388
389
0
    fn write_der_content(&self, _writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
390
0
        Ok(0)
391
0
    }
392
}
393
394
impl DynTagged for Header<'_> {
395
0
    fn tag(&self) -> Tag {
396
0
        self.tag
397
0
    }
398
}
399
400
#[cfg(feature = "std")]
401
impl ToDer for Header<'_> {
402
0
    fn to_der_len(&self) -> Result<usize> {
403
0
        let tag_len = (self.class, self.constructed, self.tag).to_der_len()?;
404
0
        let len_len = self.length.to_der_len()?;
405
0
        Ok(tag_len + len_len)
406
0
    }
407
408
0
    fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
409
0
        let sz = (self.class, self.constructed, self.tag).write_der_header(writer)?;
410
0
        let sz = sz + self.length.write_der_header(writer)?;
411
0
        Ok(sz)
412
0
    }
413
414
0
    fn write_der_content(&self, _writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
415
0
        Ok(0)
416
0
    }
417
418
0
    fn write_der_raw(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
419
        // use raw_tag if present
420
0
        let sz = match &self.raw_tag {
421
0
            Some(t) => writer.write(t)?,
422
0
            None => (self.class, self.constructed, self.tag).write_der_header(writer)?,
423
        };
424
0
        let sz = sz + self.length.write_der_header(writer)?;
425
0
        Ok(sz)
426
0
    }
427
}
428
429
/// Compare two BER headers. `len` fields are compared only if both objects have it set (same for `raw_tag`)
430
impl<'a> PartialEq<Header<'a>> for Header<'a> {
431
0
    fn eq(&self, other: &Header) -> bool {
432
0
        self.class == other.class
433
0
            && self.tag == other.tag
434
0
            && self.constructed == other.constructed
435
            && {
436
0
                if self.length.is_null() && other.length.is_null() {
437
0
                    self.length == other.length
438
                } else {
439
0
                    true
440
                }
441
            }
442
            && {
443
                // it tag is present for both, compare it
444
0
                if self.raw_tag.as_ref().xor(other.raw_tag.as_ref()).is_none() {
445
0
                    self.raw_tag == other.raw_tag
446
                } else {
447
0
                    true
448
                }
449
            }
450
0
    }
451
}
452
453
impl Eq for Header<'_> {}
454
455
#[cfg(test)]
456
mod tests {
457
    use crate::*;
458
    use hex_literal::hex;
459
460
    /// Generic tests on methods, and coverage tests
461
    #[test]
462
    fn methods_header() {
463
        // Getters
464
        let input = &hex! {"02 01 00"};
465
        let (rem, header) = Header::from_ber(input).expect("parsing header failed");
466
        assert_eq!(header.class(), Class::Universal);
467
        assert_eq!(header.tag(), Tag::Integer);
468
        assert!(header.assert_primitive().is_ok());
469
        assert!(header.assert_constructed().is_err());
470
        assert!(header.is_universal());
471
        assert!(!header.is_application());
472
        assert!(!header.is_private());
473
        assert_eq!(rem, &input[2..]);
474
475
        // test PartialEq
476
        let hdr2 = Header::new_simple(Tag::Integer);
477
        assert_eq!(header, hdr2);
478
479
        // builder methods
480
        let hdr3 = hdr2
481
            .with_class(Class::ContextSpecific)
482
            .with_constructed(true)
483
            .with_length(Length::Definite(1));
484
        assert!(hdr3.constructed());
485
        assert!(hdr3.is_constructed());
486
        assert!(hdr3.assert_constructed().is_ok());
487
        assert!(hdr3.is_contextspecific());
488
        let xx = hdr3.to_der_vec().expect("serialize failed");
489
        assert_eq!(&xx, &[0xa2, 0x01]);
490
491
        // indefinite length
492
        let hdr4 = hdr3.with_length(Length::Indefinite);
493
        assert!(hdr4.assert_definite().is_err());
494
        let xx = hdr4.to_der_vec().expect("serialize failed");
495
        assert_eq!(&xx, &[0xa2, 0x80]);
496
497
        // parse_*_content
498
        let hdr = Header::new_simple(Tag(2)).with_length(Length::Definite(1));
499
        let (_, r) = hdr.parse_ber_content(&input[2..]).unwrap();
500
        assert_eq!(r, &input[2..]);
501
        let (_, r) = hdr.parse_der_content(&input[2..]).unwrap();
502
        assert_eq!(r, &input[2..]);
503
    }
504
}