we (web engine): Experimental web browser project to understand the limits of Claude
1//! ASN.1 DER (Distinguished Encoding Rules) parser.
2//!
3//! Parses TLV (Tag-Length-Value) structures from DER-encoded byte slices.
4//! Supports all types needed for X.509 certificate and PKCS#1 key parsing.
5
6use core::fmt;
7
8// ---------------------------------------------------------------------------
9// Error type
10// ---------------------------------------------------------------------------
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum Asn1Error {
14 /// Not enough data to read the tag/length/value.
15 Truncated,
16 /// Indefinite-length encoding is forbidden in DER.
17 IndefiniteLength,
18 /// Length encoding is not minimal (DER violation).
19 NonMinimalLength,
20 /// Integer encoding is not minimal (leading zero or negative without sign byte).
21 NonMinimalInteger,
22 /// Unexpected tag encountered.
23 UnexpectedTag { expected: u8, got: u8 },
24 /// Trailing data after a complete parse.
25 TrailingData,
26 /// Invalid OID encoding.
27 InvalidOid,
28 /// Invalid boolean value in DER (must be 0x00 or 0xFF).
29 InvalidBoolean,
30 /// Invalid UTF-8 in string value.
31 InvalidUtf8,
32 /// Invalid time string format.
33 InvalidTime,
34 /// Bit string unused bits > 7 or non-zero unused bits with empty content.
35 InvalidBitString,
36 /// Content length exceeds available data.
37 LengthOverflow,
38}
39
40impl fmt::Display for Asn1Error {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 match self {
43 Self::Truncated => write!(f, "truncated data"),
44 Self::IndefiniteLength => write!(f, "indefinite length not allowed in DER"),
45 Self::NonMinimalLength => write!(f, "non-minimal length encoding"),
46 Self::NonMinimalInteger => write!(f, "non-minimal integer encoding"),
47 Self::UnexpectedTag { expected, got } => {
48 write!(
49 f,
50 "unexpected tag: expected 0x{expected:02x}, got 0x{got:02x}"
51 )
52 }
53 Self::TrailingData => write!(f, "trailing data after value"),
54 Self::InvalidOid => write!(f, "invalid OID encoding"),
55 Self::InvalidBoolean => write!(f, "invalid DER boolean"),
56 Self::InvalidUtf8 => write!(f, "invalid UTF-8"),
57 Self::InvalidTime => write!(f, "invalid time string"),
58 Self::InvalidBitString => write!(f, "invalid bit string"),
59 Self::LengthOverflow => write!(f, "length overflow"),
60 }
61 }
62}
63
64pub type Result<T> = core::result::Result<T, Asn1Error>;
65
66// ---------------------------------------------------------------------------
67// Tag constants
68// ---------------------------------------------------------------------------
69
70// Tag class bits (bits 7-6)
71pub const TAG_CLASS_UNIVERSAL: u8 = 0x00;
72pub const TAG_CLASS_APPLICATION: u8 = 0x40;
73pub const TAG_CLASS_CONTEXT: u8 = 0x80;
74pub const TAG_CLASS_PRIVATE: u8 = 0xC0;
75
76// Constructed bit (bit 5)
77pub const TAG_CONSTRUCTED: u8 = 0x20;
78
79// Universal type tags
80pub const TAG_BOOLEAN: u8 = 0x01;
81pub const TAG_INTEGER: u8 = 0x02;
82pub const TAG_BIT_STRING: u8 = 0x03;
83pub const TAG_OCTET_STRING: u8 = 0x04;
84pub const TAG_NULL: u8 = 0x05;
85pub const TAG_OID: u8 = 0x06;
86pub const TAG_UTF8_STRING: u8 = 0x0C;
87pub const TAG_SEQUENCE: u8 = 0x30; // constructed
88pub const TAG_SET: u8 = 0x31; // constructed
89pub const TAG_PRINTABLE_STRING: u8 = 0x13;
90pub const TAG_IA5_STRING: u8 = 0x16;
91pub const TAG_UTC_TIME: u8 = 0x17;
92pub const TAG_GENERALIZED_TIME: u8 = 0x18;
93
94// ---------------------------------------------------------------------------
95// OID — Object Identifier
96// ---------------------------------------------------------------------------
97
98/// An ASN.1 Object Identifier, stored as raw DER-encoded bytes.
99#[derive(Clone, PartialEq, Eq)]
100pub struct Oid<'a> {
101 /// The raw DER-encoded OID value bytes (without tag and length).
102 bytes: &'a [u8],
103}
104
105impl<'a> Oid<'a> {
106 /// Create an OID from raw DER-encoded bytes.
107 pub fn from_der_bytes(bytes: &'a [u8]) -> Self {
108 Self { bytes }
109 }
110
111 /// Return the raw DER-encoded bytes.
112 pub fn as_bytes(&self) -> &[u8] {
113 self.bytes
114 }
115
116 /// Decode to a vector of arc components (e.g., [1, 2, 840, 113549, ...]).
117 pub fn components(&self) -> Result<Vec<u32>> {
118 if self.bytes.is_empty() {
119 return Err(Asn1Error::InvalidOid);
120 }
121
122 let mut out = Vec::new();
123 let first = self.bytes[0];
124 out.push((first / 40) as u32);
125 out.push((first % 40) as u32);
126
127 let mut i = 1;
128 while i < self.bytes.len() {
129 let mut value: u32 = 0;
130 loop {
131 if i >= self.bytes.len() {
132 return Err(Asn1Error::InvalidOid);
133 }
134 let byte = self.bytes[i];
135 i += 1;
136 value = value
137 .checked_shl(7)
138 .and_then(|v| v.checked_add((byte & 0x7F) as u32))
139 .ok_or(Asn1Error::InvalidOid)?;
140 if byte & 0x80 == 0 {
141 break;
142 }
143 }
144 out.push(value);
145 }
146
147 Ok(out)
148 }
149
150 /// Encode from dotted-notation components.
151 pub fn encode_components(components: &[u32]) -> Result<Vec<u8>> {
152 if components.len() < 2 {
153 return Err(Asn1Error::InvalidOid);
154 }
155 if components[0] > 2 || (components[0] < 2 && components[1] >= 40) {
156 return Err(Asn1Error::InvalidOid);
157 }
158
159 let mut out = Vec::new();
160 let first = (components[0] * 40 + components[1]) as u8;
161 out.push(first);
162
163 for &c in &components[2..] {
164 encode_base128(&mut out, c);
165 }
166
167 Ok(out)
168 }
169
170 /// Compare against a known OID given as a byte slice of DER-encoded value.
171 pub fn matches(&self, other: &[u8]) -> bool {
172 self.bytes == other
173 }
174}
175
176impl fmt::Debug for Oid<'_> {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 match self.components() {
179 Ok(comps) => {
180 let s: Vec<String> = comps.iter().map(|c| c.to_string()).collect();
181 write!(f, "OID({})", s.join("."))
182 }
183 Err(_) => write!(f, "OID(<invalid>)"),
184 }
185 }
186}
187
188impl fmt::Display for Oid<'_> {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 match self.components() {
191 Ok(comps) => {
192 let s: Vec<String> = comps.iter().map(|c| c.to_string()).collect();
193 write!(f, "{}", s.join("."))
194 }
195 Err(_) => write!(f, "<invalid OID>"),
196 }
197 }
198}
199
200fn encode_base128(out: &mut Vec<u8>, mut value: u32) {
201 if value == 0 {
202 out.push(0);
203 return;
204 }
205 // Find out how many bytes we need
206 let mut tmp = Vec::new();
207 while value > 0 {
208 tmp.push((value & 0x7F) as u8);
209 value >>= 7;
210 }
211 tmp.reverse();
212 for (i, byte) in tmp.iter().enumerate() {
213 if i < tmp.len() - 1 {
214 out.push(byte | 0x80);
215 } else {
216 out.push(*byte);
217 }
218 }
219}
220
221// ---------------------------------------------------------------------------
222// Well-known OIDs (DER-encoded value bytes)
223// ---------------------------------------------------------------------------
224
225/// sha256WithRSAEncryption (1.2.840.113549.1.1.11)
226pub const OID_SHA256_WITH_RSA: &[u8] = &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B];
227
228/// sha384WithRSAEncryption (1.2.840.113549.1.1.12)
229pub const OID_SHA384_WITH_RSA: &[u8] = &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C];
230
231/// sha512WithRSAEncryption (1.2.840.113549.1.1.13)
232pub const OID_SHA512_WITH_RSA: &[u8] = &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D];
233
234/// rsaEncryption (1.2.840.113549.1.1.1)
235pub const OID_RSA_ENCRYPTION: &[u8] = &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01];
236
237/// ecPublicKey (1.2.840.10045.2.1)
238pub const OID_EC_PUBLIC_KEY: &[u8] = &[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01];
239
240/// prime256v1 / secp256r1 (1.2.840.10045.3.1.7)
241pub const OID_PRIME256V1: &[u8] = &[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07];
242
243/// secp384r1 (1.3.132.0.34)
244pub const OID_SECP384R1: &[u8] = &[0x2B, 0x81, 0x04, 0x00, 0x22];
245
246/// ecdsaWithSHA256 (1.2.840.10045.4.3.2)
247pub const OID_ECDSA_WITH_SHA256: &[u8] = &[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02];
248
249/// ecdsaWithSHA384 (1.2.840.10045.4.3.3)
250pub const OID_ECDSA_WITH_SHA384: &[u8] = &[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03];
251
252/// sha256 (2.16.840.1.101.3.4.2.1)
253pub const OID_SHA256: &[u8] = &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01];
254
255/// sha384 (2.16.840.1.101.3.4.2.2)
256pub const OID_SHA384: &[u8] = &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02];
257
258/// sha512 (2.16.840.1.101.3.4.2.3)
259pub const OID_SHA512: &[u8] = &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03];
260
261/// id-ce-subjectKeyIdentifier (2.5.29.14)
262pub const OID_SUBJECT_KEY_IDENTIFIER: &[u8] = &[0x55, 0x1D, 0x0E];
263
264/// id-ce-keyUsage (2.5.29.15)
265pub const OID_KEY_USAGE: &[u8] = &[0x55, 0x1D, 0x0F];
266
267/// id-ce-subjectAltName (2.5.29.17)
268pub const OID_SUBJECT_ALT_NAME: &[u8] = &[0x55, 0x1D, 0x11];
269
270/// id-ce-basicConstraints (2.5.29.19)
271pub const OID_BASIC_CONSTRAINTS: &[u8] = &[0x55, 0x1D, 0x13];
272
273/// id-ce-authorityKeyIdentifier (2.5.29.35)
274pub const OID_AUTHORITY_KEY_IDENTIFIER: &[u8] = &[0x55, 0x1D, 0x23];
275
276/// id-at-commonName (2.5.4.3)
277pub const OID_COMMON_NAME: &[u8] = &[0x55, 0x04, 0x03];
278
279/// id-at-countryName (2.5.4.6)
280pub const OID_COUNTRY_NAME: &[u8] = &[0x55, 0x04, 0x06];
281
282/// id-at-organizationName (2.5.4.10)
283pub const OID_ORGANIZATION_NAME: &[u8] = &[0x55, 0x04, 0x0A];
284
285/// id-at-organizationalUnitName (2.5.4.11)
286pub const OID_ORGANIZATIONAL_UNIT_NAME: &[u8] = &[0x55, 0x04, 0x0B];
287
288// ---------------------------------------------------------------------------
289// TLV item — a parsed tag-length-value triple
290// ---------------------------------------------------------------------------
291
292/// A single parsed TLV (Tag-Length-Value) item.
293#[derive(Debug, Clone)]
294pub struct Tlv<'a> {
295 /// The raw tag byte.
296 pub tag: u8,
297 /// The value bytes (not including tag and length encoding).
298 pub value: &'a [u8],
299 /// The full TLV encoding (tag + length + value). Useful for signature verification.
300 pub raw: &'a [u8],
301}
302
303impl<'a> Tlv<'a> {
304 /// True if this is a constructed (SEQUENCE, SET, context-specific constructed) type.
305 pub fn is_constructed(&self) -> bool {
306 self.tag & TAG_CONSTRUCTED != 0
307 }
308
309 /// Return the tag class (UNIVERSAL, APPLICATION, CONTEXT, PRIVATE).
310 pub fn tag_class(&self) -> u8 {
311 self.tag & 0xC0
312 }
313
314 /// Return the tag number (bits 4-0).
315 pub fn tag_number(&self) -> u8 {
316 self.tag & 0x1F
317 }
318
319 /// True if this is a context-specific tag (class bits = 10).
320 pub fn is_context_specific(&self) -> bool {
321 self.tag_class() == TAG_CLASS_CONTEXT
322 }
323
324 /// Return context-specific tag number, or None if not context-specific.
325 pub fn context_tag(&self) -> Option<u8> {
326 if self.is_context_specific() {
327 Some(self.tag_number())
328 } else {
329 None
330 }
331 }
332
333 /// Parse the value as a SEQUENCE of TLV items.
334 pub fn sequence_items(&self) -> Result<Vec<Tlv<'a>>> {
335 let mut parser = DerParser::new(self.value);
336 let mut items = Vec::new();
337 while parser.has_more() {
338 items.push(parser.read_tlv()?);
339 }
340 Ok(items)
341 }
342
343 /// Parse the value as a DER INTEGER and return the bytes (may have leading zero for sign).
344 pub fn as_integer(&self) -> Result<&'a [u8]> {
345 if self.tag != TAG_INTEGER {
346 return Err(Asn1Error::UnexpectedTag {
347 expected: TAG_INTEGER,
348 got: self.tag,
349 });
350 }
351 validate_der_integer(self.value)?;
352 Ok(self.value)
353 }
354
355 /// Parse the value as a positive DER INTEGER, stripping any leading zero byte.
356 pub fn as_positive_integer(&self) -> Result<&'a [u8]> {
357 let bytes = self.as_integer()?;
358 if bytes.first() == Some(&0) && bytes.len() > 1 {
359 Ok(&bytes[1..])
360 } else {
361 Ok(bytes)
362 }
363 }
364
365 /// Parse the value as a BOOLEAN.
366 pub fn as_boolean(&self) -> Result<bool> {
367 if self.tag != TAG_BOOLEAN {
368 return Err(Asn1Error::UnexpectedTag {
369 expected: TAG_BOOLEAN,
370 got: self.tag,
371 });
372 }
373 if self.value.len() != 1 {
374 return Err(Asn1Error::InvalidBoolean);
375 }
376 match self.value[0] {
377 0x00 => Ok(false),
378 0xFF => Ok(true),
379 _ => Err(Asn1Error::InvalidBoolean),
380 }
381 }
382
383 /// Parse the value as a NULL (must be empty).
384 pub fn as_null(&self) -> Result<()> {
385 if self.tag != TAG_NULL {
386 return Err(Asn1Error::UnexpectedTag {
387 expected: TAG_NULL,
388 got: self.tag,
389 });
390 }
391 if !self.value.is_empty() {
392 return Err(Asn1Error::TrailingData);
393 }
394 Ok(())
395 }
396
397 /// Parse the value as an OID.
398 pub fn as_oid(&self) -> Result<Oid<'a>> {
399 if self.tag != TAG_OID {
400 return Err(Asn1Error::UnexpectedTag {
401 expected: TAG_OID,
402 got: self.tag,
403 });
404 }
405 if self.value.is_empty() {
406 return Err(Asn1Error::InvalidOid);
407 }
408 Ok(Oid::from_der_bytes(self.value))
409 }
410
411 /// Parse the value as a BIT STRING. Returns (unused_bits, data).
412 pub fn as_bit_string(&self) -> Result<(u8, &'a [u8])> {
413 if self.tag != TAG_BIT_STRING {
414 return Err(Asn1Error::UnexpectedTag {
415 expected: TAG_BIT_STRING,
416 got: self.tag,
417 });
418 }
419 if self.value.is_empty() {
420 return Err(Asn1Error::InvalidBitString);
421 }
422 let unused = self.value[0];
423 if unused > 7 {
424 return Err(Asn1Error::InvalidBitString);
425 }
426 let data = &self.value[1..];
427 if data.is_empty() && unused != 0 {
428 return Err(Asn1Error::InvalidBitString);
429 }
430 // DER: unused bits in the last byte must be zero
431 if unused > 0 && !data.is_empty() {
432 let mask = (1u8 << unused) - 1;
433 if data[data.len() - 1] & mask != 0 {
434 return Err(Asn1Error::InvalidBitString);
435 }
436 }
437 Ok((unused, data))
438 }
439
440 /// Parse the value as an OCTET STRING.
441 pub fn as_octet_string(&self) -> Result<&'a [u8]> {
442 if self.tag != TAG_OCTET_STRING {
443 return Err(Asn1Error::UnexpectedTag {
444 expected: TAG_OCTET_STRING,
445 got: self.tag,
446 });
447 }
448 Ok(self.value)
449 }
450
451 /// Parse the value as a UTF8String.
452 pub fn as_utf8_string(&self) -> Result<&'a str> {
453 if self.tag != TAG_UTF8_STRING {
454 return Err(Asn1Error::UnexpectedTag {
455 expected: TAG_UTF8_STRING,
456 got: self.tag,
457 });
458 }
459 core::str::from_utf8(self.value).map_err(|_| Asn1Error::InvalidUtf8)
460 }
461
462 /// Parse the value as a PrintableString (ASCII subset).
463 pub fn as_printable_string(&self) -> Result<&'a str> {
464 if self.tag != TAG_PRINTABLE_STRING {
465 return Err(Asn1Error::UnexpectedTag {
466 expected: TAG_PRINTABLE_STRING,
467 got: self.tag,
468 });
469 }
470 core::str::from_utf8(self.value).map_err(|_| Asn1Error::InvalidUtf8)
471 }
472
473 /// Parse the value as an IA5String (ASCII).
474 pub fn as_ia5_string(&self) -> Result<&'a str> {
475 if self.tag != TAG_IA5_STRING {
476 return Err(Asn1Error::UnexpectedTag {
477 expected: TAG_IA5_STRING,
478 got: self.tag,
479 });
480 }
481 core::str::from_utf8(self.value).map_err(|_| Asn1Error::InvalidUtf8)
482 }
483
484 /// Parse as any string type (UTF8String, PrintableString, IA5String).
485 pub fn as_string(&self) -> Result<&'a str> {
486 match self.tag {
487 TAG_UTF8_STRING | TAG_PRINTABLE_STRING | TAG_IA5_STRING => {
488 core::str::from_utf8(self.value).map_err(|_| Asn1Error::InvalidUtf8)
489 }
490 _ => Err(Asn1Error::UnexpectedTag {
491 expected: TAG_UTF8_STRING,
492 got: self.tag,
493 }),
494 }
495 }
496
497 /// Parse the value as UTCTime (YYMMDDHHMMSSZ).
498 pub fn as_utc_time(&self) -> Result<&'a str> {
499 if self.tag != TAG_UTC_TIME {
500 return Err(Asn1Error::UnexpectedTag {
501 expected: TAG_UTC_TIME,
502 got: self.tag,
503 });
504 }
505 let s = core::str::from_utf8(self.value).map_err(|_| Asn1Error::InvalidTime)?;
506 // Basic validation: should be 13 chars ending in 'Z' (YYMMDDHHMMSSZ)
507 if s.len() != 13 || !s.ends_with('Z') {
508 return Err(Asn1Error::InvalidTime);
509 }
510 Ok(s)
511 }
512
513 /// Parse the value as GeneralizedTime (YYYYMMDDHHMMSSZ).
514 pub fn as_generalized_time(&self) -> Result<&'a str> {
515 if self.tag != TAG_GENERALIZED_TIME {
516 return Err(Asn1Error::UnexpectedTag {
517 expected: TAG_GENERALIZED_TIME,
518 got: self.tag,
519 });
520 }
521 let s = core::str::from_utf8(self.value).map_err(|_| Asn1Error::InvalidTime)?;
522 // Basic validation: should be 15 chars ending in 'Z' (YYYYMMDDHHMMSSZ)
523 if s.len() != 15 || !s.ends_with('Z') {
524 return Err(Asn1Error::InvalidTime);
525 }
526 Ok(s)
527 }
528}
529
530// ---------------------------------------------------------------------------
531// DER integer validation
532// ---------------------------------------------------------------------------
533
534fn validate_der_integer(bytes: &[u8]) -> Result<()> {
535 if bytes.is_empty() {
536 return Err(Asn1Error::NonMinimalInteger);
537 }
538 // Check for non-minimal positive: leading 0x00 followed by a byte < 0x80
539 if bytes.len() > 1 && bytes[0] == 0x00 && bytes[1] & 0x80 == 0 {
540 return Err(Asn1Error::NonMinimalInteger);
541 }
542 // Check for non-minimal negative: leading 0xFF followed by a byte >= 0x80
543 if bytes.len() > 1 && bytes[0] == 0xFF && bytes[1] & 0x80 != 0 {
544 return Err(Asn1Error::NonMinimalInteger);
545 }
546 Ok(())
547}
548
549// ---------------------------------------------------------------------------
550// DER parser
551// ---------------------------------------------------------------------------
552
553/// A streaming DER parser over a byte slice.
554pub struct DerParser<'a> {
555 data: &'a [u8],
556 pos: usize,
557}
558
559impl<'a> DerParser<'a> {
560 /// Create a new parser over the given data.
561 pub fn new(data: &'a [u8]) -> Self {
562 Self { data, pos: 0 }
563 }
564
565 /// True if there is more data to parse.
566 pub fn has_more(&self) -> bool {
567 self.pos < self.data.len()
568 }
569
570 /// Remaining unparsed bytes.
571 pub fn remaining(&self) -> &'a [u8] {
572 &self.data[self.pos..]
573 }
574
575 /// Current position in the input.
576 pub fn position(&self) -> usize {
577 self.pos
578 }
579
580 /// Read the next TLV item.
581 pub fn read_tlv(&mut self) -> Result<Tlv<'a>> {
582 let start = self.pos;
583
584 // Read tag
585 let tag = self.read_byte()?;
586
587 // We only support single-byte tags (tag number < 31).
588 // Multi-byte tags (tag number == 0x1F) are rare in X.509.
589 if tag & 0x1F == 0x1F {
590 // Long-form tag — skip continuation bytes
591 // For simplicity, we don't decode these but we need to consume them.
592 while self.pos < self.data.len() {
593 let b = self.read_byte()?;
594 if b & 0x80 == 0 {
595 break;
596 }
597 }
598 // This is a simplification; we store the first tag byte only.
599 }
600
601 // Read length
602 let length = self.read_length()?;
603
604 // Read value
605 if self.pos + length > self.data.len() {
606 return Err(Asn1Error::Truncated);
607 }
608 let value = &self.data[self.pos..self.pos + length];
609 self.pos += length;
610 let raw = &self.data[start..self.pos];
611
612 Ok(Tlv { tag, value, raw })
613 }
614
615 /// Read a TLV and expect a specific tag.
616 pub fn read_expect(&mut self, expected_tag: u8) -> Result<Tlv<'a>> {
617 let tlv = self.read_tlv()?;
618 if tlv.tag != expected_tag {
619 return Err(Asn1Error::UnexpectedTag {
620 expected: expected_tag,
621 got: tlv.tag,
622 });
623 }
624 Ok(tlv)
625 }
626
627 /// Read an optional context-specific tagged value. Returns None if the next
628 /// tag doesn't match.
629 pub fn read_optional_context(
630 &mut self,
631 tag_number: u8,
632 constructed: bool,
633 ) -> Result<Option<Tlv<'a>>> {
634 if !self.has_more() {
635 return Ok(None);
636 }
637 let expected =
638 TAG_CLASS_CONTEXT | if constructed { TAG_CONSTRUCTED } else { 0 } | tag_number;
639 if self.peek_tag()? != expected {
640 return Ok(None);
641 }
642 Ok(Some(self.read_tlv()?))
643 }
644
645 /// Peek at the next tag byte without consuming it.
646 pub fn peek_tag(&self) -> Result<u8> {
647 if self.pos >= self.data.len() {
648 return Err(Asn1Error::Truncated);
649 }
650 Ok(self.data[self.pos])
651 }
652
653 /// Skip the next TLV item.
654 pub fn skip(&mut self) -> Result<()> {
655 self.read_tlv()?;
656 Ok(())
657 }
658
659 /// Read all remaining TLV items.
660 pub fn read_all(&mut self) -> Result<Vec<Tlv<'a>>> {
661 let mut items = Vec::new();
662 while self.has_more() {
663 items.push(self.read_tlv()?);
664 }
665 Ok(items)
666 }
667
668 // --- Internal helpers ---
669
670 fn read_byte(&mut self) -> Result<u8> {
671 if self.pos >= self.data.len() {
672 return Err(Asn1Error::Truncated);
673 }
674 let b = self.data[self.pos];
675 self.pos += 1;
676 Ok(b)
677 }
678
679 fn read_length(&mut self) -> Result<usize> {
680 let first = self.read_byte()?;
681 if first == 0x80 {
682 // Indefinite length — forbidden in DER
683 return Err(Asn1Error::IndefiniteLength);
684 }
685 if first & 0x80 == 0 {
686 // Short form: length is the byte itself
687 return Ok(first as usize);
688 }
689
690 // Long form: first byte tells how many length bytes follow
691 let num_bytes = (first & 0x7F) as usize;
692 if num_bytes == 0 {
693 return Err(Asn1Error::IndefiniteLength);
694 }
695 if num_bytes > 4 {
696 // We don't support lengths > 4 bytes (4 GB should be more than enough)
697 return Err(Asn1Error::LengthOverflow);
698 }
699
700 let mut length: usize = 0;
701 for i in 0..num_bytes {
702 let b = self.read_byte()? as usize;
703 // DER minimality: first byte must not be 0 in multi-byte encoding
704 if i == 0 && b == 0 {
705 return Err(Asn1Error::NonMinimalLength);
706 }
707 length = length
708 .checked_shl(8)
709 .and_then(|v| v.checked_add(b))
710 .ok_or(Asn1Error::LengthOverflow)?;
711 }
712
713 // DER minimality: if the length fits in short form (< 128), must use short form
714 if length < 128 {
715 return Err(Asn1Error::NonMinimalLength);
716 }
717 // DER minimality: if the length fits in fewer bytes, must use fewer bytes
718 if num_bytes > 1 {
719 let min_bytes = if length < 0x100 {
720 1
721 } else if length < 0x10000 {
722 2
723 } else if length < 0x1000000 {
724 3
725 } else {
726 4
727 };
728 if num_bytes > min_bytes {
729 return Err(Asn1Error::NonMinimalLength);
730 }
731 }
732
733 Ok(length)
734 }
735}
736
737// ---------------------------------------------------------------------------
738// Convenience: parse a single top-level TLV from a byte slice
739// ---------------------------------------------------------------------------
740
741/// Parse a single DER-encoded TLV from the data, returning an error if there
742/// is trailing data.
743pub fn parse_one(data: &[u8]) -> Result<Tlv<'_>> {
744 let mut parser = DerParser::new(data);
745 let tlv = parser.read_tlv()?;
746 if parser.has_more() {
747 return Err(Asn1Error::TrailingData);
748 }
749 Ok(tlv)
750}
751
752/// Parse a DER-encoded SEQUENCE and return its inner TLV items.
753pub fn parse_sequence(data: &[u8]) -> Result<Vec<Tlv<'_>>> {
754 let outer = parse_one(data)?;
755 if outer.tag != TAG_SEQUENCE {
756 return Err(Asn1Error::UnexpectedTag {
757 expected: TAG_SEQUENCE,
758 got: outer.tag,
759 });
760 }
761 outer.sequence_items()
762}
763
764// ---------------------------------------------------------------------------
765// Tests
766// ---------------------------------------------------------------------------
767
768#[cfg(test)]
769mod tests {
770 use super::*;
771
772 // --- Basic TLV parsing ---
773
774 #[test]
775 fn parse_null() {
776 let data = [0x05, 0x00]; // NULL
777 let tlv = parse_one(&data).unwrap();
778 assert_eq!(tlv.tag, TAG_NULL);
779 assert!(tlv.value.is_empty());
780 tlv.as_null().unwrap();
781 }
782
783 #[test]
784 fn parse_boolean_true() {
785 let data = [0x01, 0x01, 0xFF]; // BOOLEAN TRUE
786 let tlv = parse_one(&data).unwrap();
787 assert!(tlv.as_boolean().unwrap());
788 }
789
790 #[test]
791 fn parse_boolean_false() {
792 let data = [0x01, 0x01, 0x00]; // BOOLEAN FALSE
793 let tlv = parse_one(&data).unwrap();
794 assert!(!tlv.as_boolean().unwrap());
795 }
796
797 #[test]
798 fn reject_invalid_boolean() {
799 let data = [0x01, 0x01, 0x01]; // Not 0x00 or 0xFF
800 let tlv = parse_one(&data).unwrap();
801 assert_eq!(tlv.as_boolean().unwrap_err(), Asn1Error::InvalidBoolean);
802 }
803
804 #[test]
805 fn parse_integer_positive() {
806 // INTEGER 127
807 let data = [0x02, 0x01, 0x7F];
808 let tlv = parse_one(&data).unwrap();
809 assert_eq!(tlv.as_integer().unwrap(), &[0x7F]);
810 }
811
812 #[test]
813 fn parse_integer_with_leading_zero() {
814 // INTEGER 128 (needs leading 0x00 to stay positive)
815 let data = [0x02, 0x02, 0x00, 0x80];
816 let tlv = parse_one(&data).unwrap();
817 assert_eq!(tlv.as_integer().unwrap(), &[0x00, 0x80]);
818 assert_eq!(tlv.as_positive_integer().unwrap(), &[0x80]);
819 }
820
821 #[test]
822 fn reject_non_minimal_integer() {
823 // Non-minimal: leading 0x00 before a byte < 0x80
824 let data = [0x02, 0x02, 0x00, 0x7F];
825 let tlv = parse_one(&data).unwrap();
826 assert_eq!(tlv.as_integer().unwrap_err(), Asn1Error::NonMinimalInteger);
827 }
828
829 #[test]
830 fn parse_octet_string() {
831 let data = [0x04, 0x03, 0x01, 0x02, 0x03];
832 let tlv = parse_one(&data).unwrap();
833 assert_eq!(tlv.as_octet_string().unwrap(), &[0x01, 0x02, 0x03]);
834 }
835
836 #[test]
837 fn parse_bit_string() {
838 // BIT STRING: 0 unused bits, data = [0xAB, 0xCD]
839 let data = [0x03, 0x03, 0x00, 0xAB, 0xCD];
840 let tlv = parse_one(&data).unwrap();
841 let (unused, bits) = tlv.as_bit_string().unwrap();
842 assert_eq!(unused, 0);
843 assert_eq!(bits, &[0xAB, 0xCD]);
844 }
845
846 #[test]
847 fn parse_bit_string_with_unused_bits() {
848 // BIT STRING: 4 unused bits, last byte has low 4 bits = 0
849 let data = [0x03, 0x02, 0x04, 0xF0];
850 let tlv = parse_one(&data).unwrap();
851 let (unused, bits) = tlv.as_bit_string().unwrap();
852 assert_eq!(unused, 4);
853 assert_eq!(bits, &[0xF0]);
854 }
855
856 #[test]
857 fn reject_invalid_bit_string_nonzero_unused() {
858 // BIT STRING: 4 unused bits but low 4 bits are non-zero
859 let data = [0x03, 0x02, 0x04, 0xF1];
860 let tlv = parse_one(&data).unwrap();
861 assert_eq!(
862 tlv.as_bit_string().unwrap_err(),
863 Asn1Error::InvalidBitString
864 );
865 }
866
867 // --- OID tests ---
868
869 #[test]
870 fn parse_oid_rsa_encryption() {
871 // OID 1.2.840.113549.1.1.1 (rsaEncryption)
872 let data = [
873 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
874 ];
875 let tlv = parse_one(&data).unwrap();
876 let oid = tlv.as_oid().unwrap();
877 assert!(oid.matches(OID_RSA_ENCRYPTION));
878 let comps = oid.components().unwrap();
879 assert_eq!(comps, vec![1, 2, 840, 113549, 1, 1, 1]);
880 }
881
882 #[test]
883 fn parse_oid_sha256_with_rsa() {
884 let data = [
885 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
886 ];
887 let tlv = parse_one(&data).unwrap();
888 let oid = tlv.as_oid().unwrap();
889 assert!(oid.matches(OID_SHA256_WITH_RSA));
890 assert_eq!(oid.components().unwrap(), vec![1, 2, 840, 113549, 1, 1, 11]);
891 }
892
893 #[test]
894 fn parse_oid_prime256v1() {
895 let data = [0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07];
896 let tlv = parse_one(&data).unwrap();
897 let oid = tlv.as_oid().unwrap();
898 assert!(oid.matches(OID_PRIME256V1));
899 assert_eq!(oid.components().unwrap(), vec![1, 2, 840, 10045, 3, 1, 7]);
900 }
901
902 #[test]
903 fn oid_display() {
904 let oid = Oid::from_der_bytes(OID_RSA_ENCRYPTION);
905 assert_eq!(format!("{}", oid), "1.2.840.113549.1.1.1");
906 }
907
908 #[test]
909 fn oid_encode_decode_roundtrip() {
910 let components = [1u32, 2, 840, 113549, 1, 1, 1];
911 let encoded = Oid::encode_components(&components).unwrap();
912 assert_eq!(encoded.as_slice(), OID_RSA_ENCRYPTION);
913 let oid = Oid::from_der_bytes(&encoded);
914 assert_eq!(oid.components().unwrap(), components);
915 }
916
917 #[test]
918 fn oid_encode_simple() {
919 // 2.5.4.3 (id-at-commonName)
920 let components = [2u32, 5, 4, 3];
921 let encoded = Oid::encode_components(&components).unwrap();
922 assert_eq!(encoded.as_slice(), OID_COMMON_NAME);
923 }
924
925 // --- String tests ---
926
927 #[test]
928 fn parse_utf8_string() {
929 let data = [0x0C, 0x05, b'H', b'e', b'l', b'l', b'o'];
930 let tlv = parse_one(&data).unwrap();
931 assert_eq!(tlv.as_utf8_string().unwrap(), "Hello");
932 }
933
934 #[test]
935 fn parse_printable_string() {
936 let data = [0x13, 0x02, b'U', b'S'];
937 let tlv = parse_one(&data).unwrap();
938 assert_eq!(tlv.as_printable_string().unwrap(), "US");
939 }
940
941 #[test]
942 fn parse_ia5_string() {
943 let data = [0x16, 0x03, b'c', b'o', b'm'];
944 let tlv = parse_one(&data).unwrap();
945 assert_eq!(tlv.as_ia5_string().unwrap(), "com");
946 }
947
948 // --- Time tests ---
949
950 #[test]
951 fn parse_utc_time() {
952 // "230101120000Z"
953 let time_str = b"230101120000Z";
954 let mut data = vec![TAG_UTC_TIME, time_str.len() as u8];
955 data.extend_from_slice(time_str);
956 let tlv = parse_one(&data).unwrap();
957 assert_eq!(tlv.as_utc_time().unwrap(), "230101120000Z");
958 }
959
960 #[test]
961 fn parse_generalized_time() {
962 // "20230101120000Z"
963 let time_str = b"20230101120000Z";
964 let mut data = vec![TAG_GENERALIZED_TIME, time_str.len() as u8];
965 data.extend_from_slice(time_str);
966 let tlv = parse_one(&data).unwrap();
967 assert_eq!(tlv.as_generalized_time().unwrap(), "20230101120000Z");
968 }
969
970 // --- SEQUENCE tests ---
971
972 #[test]
973 fn parse_sequence_of_integers() {
974 // SEQUENCE { INTEGER 1, INTEGER 2 }
975 #[rustfmt::skip]
976 let data = [
977 0x30, 0x06, // SEQUENCE, length 6
978 0x02, 0x01, 0x01, // INTEGER 1
979 0x02, 0x01, 0x02, // INTEGER 2
980 ];
981 let items = parse_sequence(&data).unwrap();
982 assert_eq!(items.len(), 2);
983 assert_eq!(items[0].as_integer().unwrap(), &[0x01]);
984 assert_eq!(items[1].as_integer().unwrap(), &[0x02]);
985 }
986
987 #[test]
988 fn parse_nested_sequence() {
989 // SEQUENCE { SEQUENCE { INTEGER 42 } }
990 #[rustfmt::skip]
991 let data = [
992 0x30, 0x05, // outer SEQUENCE
993 0x30, 0x03, // inner SEQUENCE
994 0x02, 0x01, 0x2A, // INTEGER 42
995 ];
996 let outer = parse_sequence(&data).unwrap();
997 assert_eq!(outer.len(), 1);
998 let inner = outer[0].sequence_items().unwrap();
999 assert_eq!(inner.len(), 1);
1000 assert_eq!(inner[0].as_integer().unwrap(), &[0x2A]);
1001 }
1002
1003 // --- Context-specific tags ---
1004
1005 #[test]
1006 fn parse_context_specific_explicit() {
1007 // [0] EXPLICIT { INTEGER 3 }
1008 #[rustfmt::skip]
1009 let data = [
1010 0xA0, 0x03, // context-specific [0] constructed
1011 0x02, 0x01, 0x03, // INTEGER 3
1012 ];
1013 let tlv = parse_one(&data).unwrap();
1014 assert!(tlv.is_context_specific());
1015 assert_eq!(tlv.context_tag(), Some(0));
1016 assert!(tlv.is_constructed());
1017
1018 // Parse inner content
1019 let mut inner = DerParser::new(tlv.value);
1020 let int_tlv = inner.read_tlv().unwrap();
1021 assert_eq!(int_tlv.as_integer().unwrap(), &[0x03]);
1022 }
1023
1024 #[test]
1025 fn parse_context_specific_implicit() {
1026 // [1] IMPLICIT OCTET STRING (primitive)
1027 let data = [0x81, 0x02, 0xAB, 0xCD];
1028 let tlv = parse_one(&data).unwrap();
1029 assert!(tlv.is_context_specific());
1030 assert_eq!(tlv.context_tag(), Some(1));
1031 assert!(!tlv.is_constructed());
1032 assert_eq!(tlv.value, &[0xAB, 0xCD]);
1033 }
1034
1035 #[test]
1036 fn read_optional_context_present() {
1037 #[rustfmt::skip]
1038 let data = [
1039 0xA0, 0x03, // [0] constructed
1040 0x02, 0x01, 0x03, // INTEGER 3
1041 ];
1042 let mut parser = DerParser::new(&data);
1043 let opt = parser.read_optional_context(0, true).unwrap();
1044 assert!(opt.is_some());
1045 assert_eq!(opt.unwrap().context_tag(), Some(0));
1046 }
1047
1048 #[test]
1049 fn read_optional_context_absent() {
1050 let data = [0x02, 0x01, 0x42]; // INTEGER, not [0]
1051 let mut parser = DerParser::new(&data);
1052 let opt = parser.read_optional_context(0, true).unwrap();
1053 assert!(opt.is_none());
1054 // Parser should not have advanced
1055 assert_eq!(parser.position(), 0);
1056 }
1057
1058 // --- Long-form length ---
1059
1060 #[test]
1061 fn parse_long_form_length() {
1062 // OCTET STRING with 200 bytes (needs 2-byte length encoding: 0x81, 0xC8)
1063 let mut data = vec![0x04, 0x81, 0xC8];
1064 data.extend_from_slice(&[0xAA; 200]);
1065 let tlv = parse_one(&data).unwrap();
1066 assert_eq!(tlv.value.len(), 200);
1067 }
1068
1069 #[test]
1070 fn parse_two_byte_long_form_length() {
1071 // OCTET STRING with 256 bytes (needs: 0x82, 0x01, 0x00)
1072 let mut data = vec![0x04, 0x82, 0x01, 0x00];
1073 data.extend_from_slice(&[0xBB; 256]);
1074 let tlv = parse_one(&data).unwrap();
1075 assert_eq!(tlv.value.len(), 256);
1076 }
1077
1078 // --- DER violation rejection ---
1079
1080 #[test]
1081 fn reject_indefinite_length() {
1082 let data = [0x30, 0x80, 0x00, 0x00]; // SEQUENCE with indefinite length
1083 assert_eq!(parse_one(&data).unwrap_err(), Asn1Error::IndefiniteLength);
1084 }
1085
1086 #[test]
1087 fn reject_non_minimal_length() {
1088 // OCTET STRING, length 5 encoded as 0x81, 0x05 (should be just 0x05)
1089 let data = [0x04, 0x81, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05];
1090 assert_eq!(parse_one(&data).unwrap_err(), Asn1Error::NonMinimalLength);
1091 }
1092
1093 #[test]
1094 fn reject_trailing_data() {
1095 let data = [0x05, 0x00, 0xFF]; // NULL + trailing byte
1096 assert_eq!(parse_one(&data).unwrap_err(), Asn1Error::TrailingData);
1097 }
1098
1099 #[test]
1100 fn reject_truncated() {
1101 let data = [0x04, 0x05, 0x01, 0x02]; // OCTET STRING claims 5 bytes but only 2 given
1102 assert_eq!(parse_one(&data).unwrap_err(), Asn1Error::Truncated);
1103 }
1104
1105 // --- Real certificate fragment ---
1106
1107 #[test]
1108 fn parse_algorithm_identifier() {
1109 // AlgorithmIdentifier { algorithm: sha256WithRSA, parameters: NULL }
1110 #[rustfmt::skip]
1111 let data = [
1112 0x30, 0x0D, // SEQUENCE
1113 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, // OID
1114 0x05, 0x00, // NULL
1115 ];
1116 let items = parse_sequence(&data).unwrap();
1117 assert_eq!(items.len(), 2);
1118 let oid = items[0].as_oid().unwrap();
1119 assert!(oid.matches(OID_SHA256_WITH_RSA));
1120 items[1].as_null().unwrap();
1121 }
1122
1123 #[test]
1124 fn parse_rdn_sequence_fragment() {
1125 // A single RelativeDistinguishedName: CN = "Test"
1126 #[rustfmt::skip]
1127 let data = [
1128 0x30, 0x13, // SEQUENCE (Name)
1129 0x31, 0x11, // SET (RDN)
1130 0x30, 0x0F, // SEQUENCE (AttributeTypeAndValue)
1131 0x06, 0x03, 0x55, 0x04, 0x03, // OID: id-at-commonName
1132 0x0C, 0x08, b'T', b'e', b's', b't', b' ', b'C', b'A', b'0', // UTF8String "Test CA0"
1133 ];
1134 let name_items = parse_sequence(&data).unwrap();
1135 assert_eq!(name_items.len(), 1); // One RDN
1136
1137 let rdn = name_items[0].sequence_items().unwrap();
1138 assert_eq!(rdn.len(), 1); // One attribute
1139
1140 let atv = rdn[0].sequence_items().unwrap();
1141 assert_eq!(atv.len(), 2);
1142
1143 let oid = atv[0].as_oid().unwrap();
1144 assert!(oid.matches(OID_COMMON_NAME));
1145 assert_eq!(atv[1].as_utf8_string().unwrap(), "Test CA0");
1146 }
1147
1148 // --- Raw field access ---
1149
1150 #[test]
1151 fn raw_includes_full_encoding() {
1152 let data = [0x02, 0x01, 0x42]; // INTEGER 66
1153 let tlv = parse_one(&data).unwrap();
1154 assert_eq!(tlv.raw, &data);
1155 assert_eq!(tlv.value, &[0x42]);
1156 }
1157
1158 // --- DerParser sequential reads ---
1159
1160 #[test]
1161 fn parser_sequential_reads() {
1162 #[rustfmt::skip]
1163 let data = [
1164 0x02, 0x01, 0x01, // INTEGER 1
1165 0x02, 0x01, 0x02, // INTEGER 2
1166 0x05, 0x00, // NULL
1167 ];
1168 let mut parser = DerParser::new(&data);
1169 let a = parser.read_expect(TAG_INTEGER).unwrap();
1170 assert_eq!(a.as_integer().unwrap(), &[0x01]);
1171 let b = parser.read_expect(TAG_INTEGER).unwrap();
1172 assert_eq!(b.as_integer().unwrap(), &[0x02]);
1173 let c = parser.read_expect(TAG_NULL).unwrap();
1174 c.as_null().unwrap();
1175 assert!(!parser.has_more());
1176 }
1177
1178 #[test]
1179 fn parser_read_expect_wrong_tag() {
1180 let data = [0x05, 0x00]; // NULL
1181 let mut parser = DerParser::new(&data);
1182 let err = parser.read_expect(TAG_INTEGER).unwrap_err();
1183 assert_eq!(
1184 err,
1185 Asn1Error::UnexpectedTag {
1186 expected: TAG_INTEGER,
1187 got: TAG_NULL,
1188 }
1189 );
1190 }
1191
1192 // --- X.509 version field (context-specific [0] EXPLICIT INTEGER) ---
1193
1194 #[test]
1195 fn parse_x509_version_field() {
1196 // [0] EXPLICIT { INTEGER 2 } — X.509 v3
1197 #[rustfmt::skip]
1198 let data = [
1199 0xA0, 0x03, // [0] constructed
1200 0x02, 0x01, 0x02, // INTEGER 2
1201 ];
1202 let tlv = parse_one(&data).unwrap();
1203 assert!(tlv.is_context_specific());
1204 assert!(tlv.is_constructed());
1205 assert_eq!(tlv.context_tag(), Some(0));
1206
1207 let mut inner = DerParser::new(tlv.value);
1208 let version = inner.read_expect(TAG_INTEGER).unwrap();
1209 assert_eq!(version.as_integer().unwrap(), &[0x02]);
1210 }
1211
1212 // --- BasicConstraints extension value ---
1213
1214 #[test]
1215 fn parse_basic_constraints() {
1216 // SEQUENCE { BOOLEAN TRUE, INTEGER 0 }
1217 #[rustfmt::skip]
1218 let data = [
1219 0x30, 0x06, // SEQUENCE
1220 0x01, 0x01, 0xFF, // BOOLEAN TRUE (cA)
1221 0x02, 0x01, 0x00, // INTEGER 0 (pathLenConstraint)
1222 ];
1223 let items = parse_sequence(&data).unwrap();
1224 assert_eq!(items.len(), 2);
1225 assert!(items[0].as_boolean().unwrap());
1226 assert_eq!(items[1].as_integer().unwrap(), &[0x00]);
1227 }
1228
1229 // --- Large OID component values ---
1230
1231 #[test]
1232 fn parse_oid_large_components() {
1233 // 2.16.840.1.101.3.4.2.1 (sha256)
1234 let data = [
1235 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
1236 ];
1237 let tlv = parse_one(&data).unwrap();
1238 let oid = tlv.as_oid().unwrap();
1239 assert!(oid.matches(OID_SHA256));
1240 assert_eq!(
1241 oid.components().unwrap(),
1242 vec![2, 16, 840, 1, 101, 3, 4, 2, 1]
1243 );
1244 }
1245
1246 // --- SET tag ---
1247
1248 #[test]
1249 fn parse_set() {
1250 // SET { INTEGER 1, INTEGER 2 }
1251 #[rustfmt::skip]
1252 let data = [
1253 0x31, 0x06, // SET
1254 0x02, 0x01, 0x01, // INTEGER 1
1255 0x02, 0x01, 0x02, // INTEGER 2
1256 ];
1257 let tlv = parse_one(&data).unwrap();
1258 assert_eq!(tlv.tag, TAG_SET);
1259 assert!(tlv.is_constructed());
1260 let items = tlv.sequence_items().unwrap();
1261 assert_eq!(items.len(), 2);
1262 }
1263
1264 // --- read_all ---
1265
1266 #[test]
1267 fn read_all_items() {
1268 #[rustfmt::skip]
1269 let data = [
1270 0x02, 0x01, 0x01,
1271 0x02, 0x01, 0x02,
1272 0x02, 0x01, 0x03,
1273 ];
1274 let mut parser = DerParser::new(&data);
1275 let items = parser.read_all().unwrap();
1276 assert_eq!(items.len(), 3);
1277 }
1278
1279 // --- Empty data ---
1280
1281 #[test]
1282 fn empty_data_returns_truncated() {
1283 assert_eq!(parse_one(&[]).unwrap_err(), Asn1Error::Truncated);
1284 }
1285}