1#![forbid(unsafe_code)]
48
49use error::Error;
50use nom::{IResult, Parser};
51use tsumiki::decoder::{DecodableFrom, Decoder};
52use tsumiki::encoder::{EncodableTo, Encoder};
53use tsumiki_pem::Pem;
54
55pub mod error;
56
57#[derive(Debug, Clone, PartialEq, Eq)]
77pub struct Der {
78 elements: Vec<Tlv>,
79}
80
81impl Der {
82 pub fn elements(&self) -> &[Tlv] {
84 &self.elements
85 }
86
87 pub fn new(elements: Vec<Tlv>) -> Self {
98 Der { elements }
99 }
100}
101
102impl EncodableTo<Der> for Vec<u8> {}
103
104impl Encoder<Der, Vec<u8>> for Der {
105 type Error = Error;
106
107 fn encode(&self) -> Result<Vec<u8>, Self::Error> {
108 self.elements
109 .iter()
110 .map(|tlv| tlv.encode())
111 .collect::<Result<Vec<_>, _>>()
112 .map(|vecs| vecs.into_iter().flatten().collect())
113 }
114}
115
116impl DecodableFrom<Vec<u8>> for Der {}
117
118impl Decoder<Vec<u8>, Der> for Vec<u8> {
119 type Error = Error;
120
121 fn decode(&self) -> Result<Der, Self::Error> {
122 let mut tlvs = Vec::new();
123 let mut input = self.as_slice();
124 while !input.is_empty() {
125 let (new_input, tlv) = Tlv::parse(input).map_err(|e| match e {
126 nom::Err::Error(e) => Error::Parser(e.code),
127 nom::Err::Incomplete(e) => Error::ParserIncomplete(e),
128 nom::Err::Failure(e) => Error::Parser(e.code),
129 })?;
130 input = new_input;
131 tlvs.push(tlv);
132 }
133 Ok(Der { elements: tlvs })
134 }
135}
136
137impl DecodableFrom<&[u8]> for Der {}
138
139impl Decoder<&[u8], Der> for &[u8] {
140 type Error = Error;
141
142 fn decode(&self) -> Result<Der, Self::Error> {
143 let mut tlvs = Vec::new();
144 let mut input = *self;
145 while !input.is_empty() {
146 let (new_input, tlv) = Tlv::parse(input).map_err(|e| match e {
147 nom::Err::Error(e) => Error::Parser(e.code),
148 nom::Err::Incomplete(e) => Error::ParserIncomplete(e),
149 nom::Err::Failure(e) => Error::Parser(e.code),
150 })?;
151 input = new_input;
152 tlvs.push(tlv);
153 }
154 Ok(Der { elements: tlvs })
155 }
156}
157
158impl DecodableFrom<Pem> for Der {}
159
160impl Decoder<Pem, Der> for Pem {
161 type Error = Error;
162
163 fn decode(&self) -> Result<Der, Self::Error> {
164 let data = Decoder::<Pem, Vec<u8>>::decode(self).map_err(Error::Pem)?;
166 data.decode()
167 }
168}
169
170pub const TAG_CONSTRUCTED: u8 = 0b0010_0000;
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193pub enum Tag {
194 Primitive(PrimitiveTag, u8),
196 ContextSpecific { slot: u8, constructed: bool },
198}
199
200impl Tag {
201 pub(crate) fn is_constructed(&self) -> bool {
206 match self {
207 Tag::Primitive(_, inner) => (*inner) & TAG_CONSTRUCTED != 0,
208 Tag::ContextSpecific { constructed, .. } => *constructed,
209 }
210 }
211}
212
213impl EncodableTo<Tag> for u8 {}
214
215impl Encoder<Tag, u8> for Tag {
216 type Error = Error;
217
218 fn encode(&self) -> Result<u8, Self::Error> {
219 Ok(match self {
220 Tag::Primitive(_, value) => *value,
221 Tag::ContextSpecific { slot, constructed } => {
222 let base = 0x80; let constructed_bit = if *constructed { TAG_CONSTRUCTED } else { 0 };
224 base | constructed_bit | slot
225 }
226 })
227 }
228}
229
230impl From<u8> for Tag {
231 fn from(value: u8) -> Self {
232 let is_context_specific = value & 0b1000_0000 != 0;
233
234 if is_context_specific {
235 let constructed = value & TAG_CONSTRUCTED != 0;
238 let slot_number = value & 0b0001_1111; Tag::ContextSpecific {
240 slot: slot_number,
241 constructed,
242 }
243 } else {
244 let primitive = PrimitiveTag::from(value & 0b0001_1111);
245 Tag::Primitive(primitive, value)
246 }
247 }
248}
249
250#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
266#[repr(u8)]
267pub enum PrimitiveTag {
268 Boolean = 0x01,
270 Integer = 0x02,
272 BitString = 0x03,
274 OctetString = 0x04,
276 Null = 0x05,
278 ObjectIdentifier = 0x06,
280 UTF8String = 0x0c,
282 Sequence = 0x10,
284 Set = 0x11,
286 PrintableString = 0x13,
288 IA5String = 0x16,
290 UTCTime = 0x17,
292 GeneralizedTime = 0x18,
294 BMPString = 0x1e,
296 Unimplemented(u8),
298}
299
300impl From<u8> for PrimitiveTag {
301 fn from(value: u8) -> Self {
302 match value {
303 0x01 => Self::Boolean,
304 0x02 => Self::Integer,
305 0x03 => Self::BitString,
306 0x04 => Self::OctetString,
307 0x05 => Self::Null,
308 0x06 => Self::ObjectIdentifier,
309 0x0c => Self::UTF8String,
310 0x10 => Self::Sequence,
311 0x11 => Self::Set,
312 0x13 => Self::PrintableString,
313 0x16 => Self::IA5String,
314 0x17 => Self::UTCTime,
315 0x18 => Self::GeneralizedTime,
316 0x1e => Self::BMPString,
317 _ => PrimitiveTag::Unimplemented(value),
318 }
319 }
320}
321
322impl From<&PrimitiveTag> for u8 {
323 fn from(value: &PrimitiveTag) -> Self {
324 match value {
325 PrimitiveTag::Boolean => 0x01,
326 PrimitiveTag::Integer => 0x02,
327 PrimitiveTag::BitString => 0x03,
328 PrimitiveTag::OctetString => 0x04,
329 PrimitiveTag::Null => 0x05,
330 PrimitiveTag::ObjectIdentifier => 0x06,
331 PrimitiveTag::UTF8String => 0x0c,
332 PrimitiveTag::Sequence => 0x10,
333 PrimitiveTag::Set => 0x11,
334 PrimitiveTag::PrintableString => 0x13,
335 PrimitiveTag::IA5String => 0x16,
336 PrimitiveTag::UTCTime => 0x17,
337 PrimitiveTag::GeneralizedTime => 0x18,
338 PrimitiveTag::BMPString => 0x1e,
339 PrimitiveTag::Unimplemented(value) => *value,
340 }
341 }
342}
343
344#[derive(Debug, Clone, PartialEq, Eq)]
363pub struct Tlv {
364 tag: Tag,
365 value: Value,
367}
368
369#[derive(Debug, Clone, PartialEq, Eq)]
370enum Value {
371 Tlv(Vec<Tlv>),
372 Data(Vec<u8>),
373}
374
375impl Tlv {
376 pub fn tag(&self) -> &Tag {
378 &self.tag
379 }
380
381 pub fn new_primitive(tag: Tag, data: Vec<u8>) -> Self {
393 Tlv {
394 tag,
395 value: Value::Data(data),
396 }
397 }
398
399 pub fn new_constructed(tag: Tag, tlvs: Vec<Tlv>) -> Self {
412 Tlv {
413 tag,
414 value: Value::Tlv(tlvs),
415 }
416 }
417
418 pub fn data(&self) -> Option<&[u8]> {
422 match &self.value {
423 Value::Data(data) => Some(data),
424 Value::Tlv(_) => None,
425 }
426 }
427
428 pub fn tlvs(&self) -> Option<&[Tlv]> {
432 match &self.value {
433 Value::Tlv(tlvs) => Some(tlvs),
434 Value::Data(_) => None,
435 }
436 }
437
438 pub(crate) fn parse(input: &[u8]) -> IResult<&[u8], Tlv> {
442 let (input, tag) = parse_tag(input)?;
443 let (input, length) = parse_length(input)?;
444 let (input, data) = nom::bytes::complete::take(length).parse(input)?;
445
446 if tag.is_constructed() {
447 let mut tlvs = Vec::new();
449 let mut data = data;
450 while !data.is_empty() {
451 let (new_input, v) = Self::parse(data)?;
452 data = new_input;
453 tlvs.push(v);
454 }
455
456 return Ok((
457 input,
458 Tlv {
459 tag,
460 value: Value::Tlv(tlvs),
461 },
462 ));
463 }
464
465 Ok((
466 input,
467 Tlv {
468 tag,
469 value: Value::Data(data.to_vec()),
470 },
471 ))
472 }
473}
474
475impl EncodableTo<Tlv> for Vec<u8> {}
476
477impl Encoder<Tlv, Vec<u8>> for Tlv {
478 type Error = Error;
479
480 fn encode(&self) -> Result<Vec<u8>, Self::Error> {
481 let content = match &self.value {
483 Value::Data(data) => data.clone(),
484 Value::Tlv(tlvs) => tlvs
485 .iter()
486 .map(|tlv| tlv.encode())
487 .collect::<Result<Vec<_>, _>>()?
488 .into_iter()
489 .flatten()
490 .collect(),
491 };
492
493 let tag = self.tag.encode()?;
495 let length = encode_length(content.len());
496
497 Ok([tag].into_iter().chain(length).chain(content).collect())
498 }
499}
500
501pub(crate) fn encode_length(length: usize) -> Vec<u8> {
506 if length < 0x80 {
507 vec![length as u8]
509 } else {
510 let length_bytes: Vec<u8> = length
512 .to_be_bytes()
513 .into_iter()
514 .skip_while(|&b| b == 0) .collect();
516
517 [0x80 | length_bytes.len() as u8]
518 .into_iter()
519 .chain(length_bytes)
520 .collect()
521 }
522}
523
524pub(crate) fn parse_tag(input: &[u8]) -> IResult<&[u8], Tag> {
526 let (input, n) = nom::number::be_u8().parse(input)?;
527 Ok((input, Tag::from(n)))
528}
529
530pub(crate) fn parse_length(input: &[u8]) -> IResult<&[u8], u64> {
535 let (input, n) = nom::number::be_u8().parse(input)?;
536 if n & 0x80 == 0x80 {
537 let length = n & 0x7f;
541
542 if length > 8 {
544 return Err(nom::Err::Failure(nom::error::Error::new(
545 input,
546 nom::error::ErrorKind::TooLarge,
547 )));
548 }
549
550 let (input, bs) = nom::bytes::complete::take(length).parse(input)?;
551 let n = bs
552 .iter()
553 .enumerate()
554 .try_fold(0u64, |n, (i, &b)| {
555 let exp = (bs.len() - i - 1) as u32;
556 let base = 256_u64.checked_pow(exp)?;
557 let term = base.checked_mul(b as u64)?;
558 n.checked_add(term)
559 })
560 .ok_or_else(|| {
561 nom::Err::Failure(nom::error::Error::new(
562 input,
563 nom::error::ErrorKind::TooLarge,
564 ))
565 })?;
566 return Ok((input, n));
567 }
568 Ok((input, n as u64))
570}
571
572#[cfg(test)]
573mod tests {
574 use rstest::rstest;
575
576 use crate::{Der, PrimitiveTag, Tag, Tlv, Value, parse_length};
577 use tsumiki::decoder::Decoder;
578 use tsumiki::encoder::Encoder;
579 use tsumiki_pem::Pem;
580
581 #[rstest(
582 input,
583 expected,
584 case(vec![0x02], Tag::Primitive(PrimitiveTag::Integer, 0x02)),
585 case(vec![0x02, 0x01], Tag::Primitive(PrimitiveTag::Integer, 0x02)),
586 case(vec![0x30, 0x01], Tag::Primitive(PrimitiveTag::Sequence, 0x30)),
587 case(vec![0x0a, 0x02, 0x10], Tag::Primitive(PrimitiveTag::Unimplemented(0x0a), 0x0a)),
588 case(vec![0xa0], Tag::ContextSpecific { slot: 0x00, constructed: true }),
590 case(vec![0xa3], Tag::ContextSpecific { slot: 0x03, constructed: true }),
591 case(vec![0x80], Tag::ContextSpecific { slot: 0x00, constructed: false }),
593 case(vec![0x82], Tag::ContextSpecific { slot: 0x02, constructed: false }),
594 )]
595 fn test_parse_tag(input: Vec<u8>, expected: Tag) {
596 use crate::parse_tag;
597
598 let actual = parse_tag(&input).unwrap();
599
600 assert_eq!(expected, actual.1);
601 }
602
603 #[rstest(input, expected,
604 case(vec![0x02], 0x02),
605 case(vec![0x02, 0x01], 0x02),
606 case(vec![0x30, 0x01], 0x30),
607 case(vec![0x82, 0x02, 0x10], 256 * 0x02 + 0x10),
608 case(vec![0x83, 0x01, 0x00, 0x00], 256 * 256),
609 case(vec![0x82, 0xff, 0xff], 256 * 0xff + 0xff),
610 )]
611 fn test_parse_length(input: Vec<u8>, expected: u64) {
612 let actual = parse_length(&input).unwrap();
613
614 assert_eq!(expected, actual.1);
615 }
616
617 #[rstest(input, expected,
618 case(
619 vec![0x02, 0x01, 0x01],
620 Tlv{
621 tag: Tag::Primitive(PrimitiveTag::Integer, 0x02) ,
622 value: Value::Data(vec![0x01])
623 }
624 ),
625 case(
626 vec![0x02, 0x09, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
627 Tlv {
628 tag: Tag::Primitive(PrimitiveTag::Integer, 0x02),
629 value: Value::Data(vec![0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01])
630 }
631 ),
632 case(
633 vec![0x13, 0x02, 0x68, 0x69],
634 Tlv{
635 tag: Tag::Primitive(PrimitiveTag::PrintableString, 0x13),
636 value: Value::Data(vec![0x68, 0x69])
637 }
638 ),
639 case(
640 vec![0x16, 0x02, 0x68, 0x69],
641 Tlv{
642 tag: Tag::Primitive(PrimitiveTag::IA5String, 0x16),
643 value: Value::Data(vec![0x68, 0x69])
644 }
645 ),
646 case(
647 vec![0x0c, 0x04, 0xf0, 0x9f, 0x98, 0x8e],
648 Tlv{
649 tag: Tag::Primitive(PrimitiveTag::UTF8String, 0x0c),
650 value: Value::Data(vec![0xf0, 0x9f, 0x98, 0x8e])
651 }
652 ),
653 case(
654 vec![0x17, 0x11, 0x31, 0x39, 0x31, 0x32, 0x31, 0x35, 0x31, 0x39, 0x30, 0x32, 0x31, 0x30, 0x2d, 0x30, 0x38, 0x30, 0x30],
655 Tlv {
656 tag: Tag::Primitive(PrimitiveTag::UTCTime, 0x17),
657 value: Value::Data(vec![
658 0x31, 0x39, 0x31, 0x32, 0x31, 0x35, 0x31, 0x39, 0x30, 0x32, 0x31, 0x30, 0x2d, 0x30,
659 0x38, 0x30, 0x30,
660 ])}),
661 case(
662 vec![0x18, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x31, 0x36, 0x30, 0x33, 0x30, 0x32, 0x31, 0x30, 0x5a],
663 Tlv{
664 tag: Tag::Primitive(PrimitiveTag::GeneralizedTime, 0x18),
665 value: Value::Data(vec![0x31, 0x39, 0x31, 0x32, 0x31, 0x36, 0x30, 0x33, 0x30, 0x32, 0x31, 0x30, 0x5a])
666 }
667 ),
668 case(
669 vec![0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b],
670 Tlv {
671 tag: Tag::Primitive(PrimitiveTag::ObjectIdentifier, 0x06),
672 value: Value::Data(vec![0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b])
673 }
674 ),
675 case(
676 vec![0x05, 0x00],
677 Tlv {
678 tag: Tag::Primitive(PrimitiveTag::Null, 0x05),
679 value: Value::Data(vec![])
680 }
681 ),
682 case(
683 vec![0x04, 0x04, 0x03, 0x02, 0x06, 0xa0],
684 Tlv {
685 tag: Tag::Primitive(PrimitiveTag::OctetString, 0x04),
686 value: Value::Data(vec![0x03, 0x02, 0x06, 0xa0])
687 }
688 ),
689 case(
690 vec![0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0],
691 Tlv {
692 tag: Tag::Primitive(PrimitiveTag::BitString, 0x03),
693 value: Value::Data(vec![0x06, 0x6e, 0x5d, 0xc0])
694 }
695 )
696 )]
697 fn test_tlv_parse_primitive(input: Vec<u8>, expected: Tlv) {
698 let (_, actual) = Tlv::parse(&input).unwrap();
699 compare_primitive_tlv(&expected, &actual);
700 }
701
702 #[rstest(input, expected,
703 case(
704 vec![0x30, 0x09, 0x02, 0x01, 0x07, 0x02, 0x01, 0x08, 0x02, 0x01, 0x09],
705 Tlv {
706 tag: Tag::Primitive(PrimitiveTag::Sequence, 0x30),
707 value: Value::Tlv(
708 vec![
709 Tlv {
710 tag: Tag::Primitive(PrimitiveTag::Integer, 0x02),
711 value: Value::Data(vec![0x07])
712 },
713 Tlv {
714 tag: Tag::Primitive(PrimitiveTag::Integer, 0x02),
715 value: Value::Data(vec![0x08])
716 },
717 Tlv {
718 tag: Tag::Primitive(PrimitiveTag::Integer, 0x02),
719 value: Value::Data(vec![0x09])
720 }
721 ]
722 )
723 }
724 )
725 )]
726 fn test_tlv_parse_structured(input: Vec<u8>, expected: Tlv) {
727 let (_, actual) = Tlv::parse(&input).unwrap();
728 assert_eq!(expected.tag, actual.tag);
729 match actual.value {
730 Value::Data(_) => panic!("expected: Value::Tlv, but got Value::Data"),
731 Value::Tlv(actual_tlvs) => match expected.value {
732 Value::Data(_) => panic!("test data is invalid. required Value::Tlv"),
733 Value::Tlv(expected_tlvs) => {
734 if actual_tlvs.len() != expected_tlvs.len() {
735 panic!(
736 "expected nested TLV length is {}, but got length is {}",
737 expected_tlvs.len(),
738 actual_tlvs.len()
739 )
740 }
741 for (expected, actual) in expected_tlvs.iter().zip(actual_tlvs.iter()) {
742 compare_primitive_tlv(expected, actual);
743 }
744 }
745 },
746 }
747 }
748
749 fn compare_primitive_tlv(v1: &Tlv, v2: &Tlv) {
750 assert_eq!(v1.tag, v2.tag);
751 match &v2.value {
752 Value::Data(v2_data) => match &v1.value {
753 Value::Data(v1_data) => assert_eq!(v2_data, v1_data),
754 Value::Tlv(_) => panic!("test data is invalid. required Value::Data"),
755 },
756 Value::Tlv(tlvs) => {
757 panic!("v1: Value::Data, but got Value::Tlv({:?})", tlvs)
758 }
759 }
760 }
761
762 const TEST_PEM_CERT1: &str = r"-----BEGIN CERTIFICATE-----
763MIICLDCCAdKgAwIBAgIBADAKBggqhkjOPQQDAjB9MQswCQYDVQQGEwJCRTEPMA0G
764A1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2VydGlmaWNhdGUgYXV0aG9y
765aXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdudVRMUyBjZXJ0aWZpY2F0
766ZSBhdXRob3JpdHkwHhcNMTEwNTIzMjAzODIxWhcNMTIxMjIyMDc0MTUxWjB9MQsw
767CQYDVQQGEwJCRTEPMA0GA1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2Vy
768dGlmaWNhdGUgYXV0aG9yaXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdu
769dVRMUyBjZXJ0aWZpY2F0ZSBhdXRob3JpdHkwWTATBgcqhkjOPQIBBggqhkjOPQMB
770BwNCAARS2I0jiuNn14Y2sSALCX3IybqiIJUvxUpj+oNfzngvj/Niyv2394BWnW4X
771uQ4RTEiywK87WRcWMGgJB5kX/t2no0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1Ud
772DwEB/wQFAwMHBgAwHQYDVR0OBBYEFPC0gf6YEr+1KLlkQAPLzB9mTigDMAoGCCqG
773SM49BAMCA0gAMEUCIDGuwD1KPyG+hRf88MeyMQcqOFZD0TbVleF+UsAGQ4enAiEA
774l4wOuDwKQa+upc8GftXE2C//4mKANBC6It01gUaTIpo=
775-----END CERTIFICATE-----";
776
777 const TEST_PEM_CERT2: &str = r"-----BEGIN CERTIFICATE-----
786MIIDtTCCAp2gAwIBAgIUaFA0CT8XkKbEtG6JefcmPZp6ThowDQYJKoZIhvcNAQEL
787BQAwajELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdDaGl5
788b2RhMREwDwYDVQQKDAhUZXN0IE9yZzESMBAGA1UECwwJVGVzdCBVbml0MRIwEAYD
789VQQDDAlsb2NhbGhvc3QwHhcNMjUwNTIzMDkxMDQ3WhcNMjYwNTIzMDkxMDQ3WjBq
790MQswCQYDVQQGEwJKUDEOMAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB0NoaXlvZGEx
791ETAPBgNVBAoMCFRlc3QgT3JnMRIwEAYDVQQLDAlUZXN0IFVuaXQxEjAQBgNVBAMM
792CWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALZBodqN
793qwafTo+pEyxjMfxHdGPsMLzdHAyHbnfIoaegpaSNG+Gj3XYg8om/F4IPwe73L9wf
7942QXjrA86fW4eSumwff+AlIc70wMUOHcJTRdRLNfF3O7BHgtS1Am9P3cANsw1IVec
7950DBYB8SZG0v7kt6EZ24ygznz1ptl0noKkVp6ocEUYC8B+Kr5qsm7qz2vef9QPlli
796IEm9Za0UFs/r1jjcxfz3GwYQkburRU+bdIO61SCiFyTsqp166XRNSN5ECINwjkxC
797CB/9QjeiKjNkyHfC6u1N8Is8fJVA6kUKFyTsPlvs9dzAi3AtNlQsN8p3uRKxZ7Ks
798E2hTchypMWozHCkCAwEAAaNTMFEwHQYDVR0OBBYEFPwPDgsW4wRdDj25yLSUYFzB
799YX8LMB8GA1UdIwQYMBaAFPwPDgsW4wRdDj25yLSUYFzBYX8LMA8GA1UdEwEB/wQF
800MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJOMSkpB5GWZRw4grEmDKmT8CODNvDBT
801S/btPF+unH0fssiqjdQ/qm/Q23Ry1y8paIvXT9IaCRDF5vYhM5A1S9+ryylIM+G4
802bAvsEgXUDmLB7LHzETg+7HSYe32iyh0p3EA/LAKdr3zh12bOAdQhRXooQdVjffhc
803AKftLxa4Xx7P+w/oPqOdt/f1BQyqsSdQ9iTCnvCbuZ2q3qzFf0ehZXiebXbU5zDc
804gqAQgXRgYgyMebhkGdi+V+G75ZSYgOD0zfcoL/p1fW9hr5PPqX7SXcyh8f8Q/ZIL
805fgx5sjr+fC3fvET/buw4EnKBhR+sSxn1T70hwP3aXd6wHN0vkMgaJPM=
806-----END CERTIFICATE-----";
807
808 const TEST_PEM_PRIV_KEY1: &str = r"-----BEGIN PRIVATE KEY-----
809MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2QaHajasGn06P
810qRMsYzH8R3Rj7DC83RwMh253yKGnoKWkjRvho912IPKJvxeCD8Hu9y/cH9kF46wP
811On1uHkrpsH3/gJSHO9MDFDh3CU0XUSzXxdzuwR4LUtQJvT93ADbMNSFXnNAwWAfE
812mRtL+5LehGduMoM589abZdJ6CpFaeqHBFGAvAfiq+arJu6s9r3n/UD5ZYiBJvWWt
813FBbP69Y43MX89xsGEJG7q0VPm3SDutUgohck7Kqdeul0TUjeRAiDcI5MQggf/UI3
814oiozZMh3wurtTfCLPHyVQOpFChck7D5b7PXcwItwLTZULDfKd7kSsWeyrBNoU3Ic
815qTFqMxwpAgMBAAECggEABSbYyOE9Rtwk79mjIZuSM6Pfbd2kyQnk+5OuczNYInFf
816jUWx1pB3t5mZ0Xv10abZYARbtXiu/UQgvnN0TTMNAgsLnLfJOwNdZRZivDaml7Sj
817NFwy8QrDayWFudrAGwCGDAKqdRwJJHywh4WeaGjtj12lwM8rt20lkVHw/6Mh1bFa
818Yo2mprDvq/xxqtmqL3I9iqbWPHRg4uGbq2lRD3UAE+Ig1nlY9TmdekNOvQxDLQGV
8190yGLVEE3Yjn9QYE+zs21iyYgV7NjEDw+FLzJ3yWb4UBtSiwAzd0XeOUgWx3IYEXF
820J/pSEFgBZdRm0JviQ2+qYH/4zKaWnhjwERa4D/H/UwKBgQD3wjoHG7bVCW7BMOWw
821mSFM7wZZ6nZItuaobPZbKXQxmXlbPEWJatW6bPcb9YAaw+VUWLXJyvD52N8M9r4E
822hUvUermCLrWU0rqD+0q1+j2iLqfzAg8X0jKYAJMR2ESBmDC8p/40xNOtFxG6uhST
823cUnykNbl0SYlDbWtYTSdkf5EowKBgQC8UZ/vCPx1PnF2ycdlGqZ/2valuR1EgHXK
824ce+mZmg62l4imkAxI3oJJHJh0r99x75yyzBMRhPJKq5P80x6KpqZfH8DBMfWF4fu
82583ark/KQXe4M6RAkH+/MH2jsFWpg9c6WQleizoky8bLaDfBGZyVfHfY+FL0Z/zHj
826IXhtDyEcwwKBgQDkjs7NQ+nUedEsc5lQ4tLvkAmB5WOdDO2YLnzN+F3ya6yiV+Wm
827MWJdiqwjpMS67EChIP0C3S6UrlaGNRFyRi2AJH8B82kbk5Lwsl9npSQ6e2QAL8QQ
828q550zwLdkW8RRn6fazJ9J55GrWNzqLnWksou9SLp+5l+0TjqayQIwGealQKBgGby
829rF7tZ63kg/yvVBzWU90jY6C3MOPI4hvY62zpIOPDiqCZ+KukPEuRLCKEJoDpWBjD
830MVURHjHj7kTwuYczkS6FG54X1/MXDA259M7ZY0o+vys5ocRN3TaWmTIuhugYmGYW
831QHhVNjWuYdrIseia7Jgx9fJ8PeBfXPNQ0de05KInAoGAbbsbgtWqL5E9aWn2d0BN
832MYfyU9h1doVwVB/ZdzPtS6BuzrtfZ+Oov86tHqnEvUPs7C8Nvzx8HXbT5mdnSgea
833RJi/eAqNhqr/YHf8CvlRjMWHnNLlzqrST9aHKeZwPNr+1o/2PeEZCPShUAHZKmf9
834e8ZYGIc4gvs5McdrVUyYGUs=
835-----END PRIVATE KEY-----";
836
837 #[rstest(
838 input,
839 _expected,
840 case(TEST_PEM_CERT1, None),
841 case(TEST_PEM_CERT2, None),
842 case(TEST_PEM_PRIV_KEY1, None)
843 )]
844 fn test_decode_der_from_pem(input: &str, _expected: Option<()>) {
845 let pem = input.decode().unwrap();
846 let der: Der = pem.decode().unwrap();
848 println!("{:?}", der);
849 }
850
851 #[rstest(cert_pem, case(TEST_PEM_CERT1), case(TEST_PEM_CERT2))]
852 fn test_roundtrip_der_encode(cert_pem: &str) {
853 let pem: Pem = cert_pem.parse().expect("Failed to parse PEM");
855 let original_der: Der = pem.decode().expect("Failed to decode PEM to Der");
856
857 let encoded_bytes = original_der
858 .encode()
859 .expect("Failed to encode Der to Vec<u8>");
860 let decoded_der: Der = encoded_bytes
861 .decode()
862 .expect("Failed to decode Vec<u8> to Der");
863
864 assert_eq!(original_der, decoded_der);
865 }
866}