we (web engine): Experimental web browser project to understand the limits of Claude
at float-layout 1285 lines 42 kB view raw
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}