Skip to main content

josekit/util/der/
der_reader.rs

1#![allow(unused)]
2
3use std::io::{Bytes, Read};
4
5use crate::util::der::{DerClass, DerError, DerType};
6use crate::util::oid::ObjectIdentifier;
7
8struct DerStackItem {
9    len: Option<usize>,
10    parsed_len: usize,
11}
12
13pub struct DerReader<R: Read> {
14    input: Bytes<R>,
15    stack: Vec<DerStackItem>,
16    der_type: DerType,
17    constructed: bool,
18    contents: Option<Vec<u8>>,
19    read_count: usize,
20}
21
22impl<'a> DerReader<&'a [u8]> {
23    pub fn from_bytes(input: &'a impl AsRef<[u8]>) -> Self {
24        Self::from_reader(input.as_ref())
25    }
26}
27
28impl<R: Read> DerReader<R> {
29    pub fn from_reader(input: R) -> Self {
30        Self {
31            input: input.bytes(),
32            stack: Vec::new(),
33            der_type: DerType::EndOfContents,
34            constructed: false,
35            contents: None,
36            read_count: 0,
37        }
38    }
39
40    pub fn next(&mut self) -> Result<Option<DerType>, DerError> {
41        let mut depth = self.stack.len();
42        let mut is_indefinite_parent = false;
43        if depth > 0 {
44            match self.stack[depth - 1].len {
45                Some(val) => {
46                    if val == self.stack[depth - 1].parsed_len {
47                        self.stack.pop();
48
49                        depth = self.stack.len();
50                        if depth > 0 {
51                            self.stack[depth - 1].parsed_len += val;
52                        }
53
54                        return Ok(Some(DerType::EndOfContents));
55                    }
56                }
57                None => {
58                    is_indefinite_parent = true;
59                }
60            }
61        }
62
63        let start_read_count = self.read_count;
64
65        match self.get_tag()? {
66            None => return Ok(None),
67            Some((DerType::EndOfContents, constructed)) => {
68                if !is_indefinite_parent {
69                    return Err(DerError::InvalidTag(format!(
70                        "End of contents type is not allowed here."
71                    )));
72                }
73
74                if constructed {
75                    return Err(DerError::InvalidTag(format!(
76                        "End of contents type cannot be constructed."
77                    )));
78                }
79
80                match self.get_length()? {
81                    Some(0) => {}
82                    Some(val) => {
83                        return Err(DerError::InvalidLength(format!(
84                            "End of contents content length must be 0: {}",
85                            val
86                        )));
87                    }
88                    None => {
89                        return Err(DerError::InvalidLength(format!(
90                            "End of contents content length must be 0: indefinite"
91                        )));
92                    }
93                }
94
95                self.stack.pop();
96
97                self.der_type = DerType::EndOfContents;
98                self.constructed = constructed;
99                self.contents = None;
100            }
101            Some((der_type, true)) => {
102                if !der_type.can_constructed() {
103                    return Err(DerError::InvalidTag(format!(
104                        "{} type cannot be constructed.",
105                        der_type
106                    )));
107                }
108
109                let olength = self.get_length()?;
110                let offset = self.read_count - start_read_count;
111                self.stack.push(DerStackItem {
112                    len: olength.map(|val| val + offset),
113                    parsed_len: offset,
114                });
115
116                self.der_type = der_type;
117                self.constructed = true;
118                self.contents = None;
119            }
120            Some((der_type, false)) => {
121                if !der_type.can_primitive() {
122                    return Err(DerError::InvalidTag(format!(
123                        "{} type cannot be primitive.",
124                        der_type
125                    )));
126                }
127
128                let length = match self.get_length()? {
129                    Some(val) => val,
130                    None => {
131                        return Err(DerError::InvalidLength(format!(
132                            "Primitive type content length cannot be indefinite."
133                        )));
134                    }
135                };
136
137                let mut contents = Vec::with_capacity(length);
138                for _ in 0..length {
139                    match self.get()? {
140                        Some(val) => contents.push(val),
141                        None => return Err(DerError::UnexpectedEndOfInput),
142                    }
143                }
144
145                if depth > 0 {
146                    let offset = self.read_count - start_read_count;
147                    self.stack[depth - 1].parsed_len += offset;
148                }
149
150                self.der_type = der_type;
151                self.constructed = false;
152                self.contents = Some(contents);
153            }
154        }
155
156        Ok(Some(self.der_type))
157    }
158
159    pub fn skip_contents(&mut self) -> Result<(), DerError> {
160        if self.constructed {
161            let mut depth = 1;
162            loop {
163                match self.next()? {
164                    Some(DerType::EndOfContents) => {
165                        depth -= 1;
166                        if depth == 0 {
167                            break;
168                        }
169                    }
170                    Some(_) => {
171                        if self.constructed {
172                            depth += 1;
173                        }
174                    }
175                    None => break,
176                }
177            }
178        }
179
180        Ok(())
181    }
182
183    pub fn is_constructed(&self) -> bool {
184        self.constructed
185    }
186
187    pub fn is_primitive(&self) -> bool {
188        !self.constructed
189    }
190
191    pub fn contents(&self) -> Option<&[u8]> {
192        match &self.contents {
193            Some(val) => Some(val),
194            None => None,
195        }
196    }
197
198    pub fn to_null(&self) -> Result<(), DerError> {
199        if let DerType::Null = self.der_type {
200            if let Some(contents) = &self.contents {
201                if contents.len() != 0 {
202                    return Err(DerError::InvalidLength(format!(
203                        "Null content length must be 0: {}",
204                        contents.len()
205                    )));
206                }
207
208                Ok(())
209            } else {
210                unreachable!();
211            }
212        } else {
213            panic!(
214                "{} type is not supported to convert to null.",
215                self.der_type
216            );
217        }
218    }
219
220    pub fn to_boolean(&self) -> Result<bool, DerError> {
221        if let DerType::Boolean = self.der_type {
222            if let Some(contents) = &self.contents {
223                if contents.len() != 1 {
224                    return Err(DerError::InvalidLength(format!(
225                        "Boolean content length must be 1: {}",
226                        contents.len()
227                    )));
228                }
229
230                let value = contents[0] != 0;
231                Ok(value)
232            } else {
233                unreachable!();
234            }
235        } else {
236            panic!(
237                "{} type is not supported to convert to bool.",
238                self.der_type
239            );
240        }
241    }
242
243    pub fn to_u8(&self) -> Result<u8, DerError> {
244        if let DerType::Integer | DerType::Enumerated = self.der_type {
245            if let Some(contents) = &self.contents {
246                if contents.len() == 0 {
247                    return Err(DerError::InvalidLength(format!(
248                        "{} content length must be 1 or more.",
249                        self.der_type
250                    )));
251                }
252
253                if contents.len() > 1 {
254                    return Err(DerError::Overflow);
255                }
256
257                Ok(contents[0])
258            } else {
259                unreachable!();
260            }
261        } else {
262            panic!("{} type is not supported to convert to u8.", self.der_type);
263        }
264    }
265
266    pub fn to_u64(&self) -> Result<u64, DerError> {
267        if let DerType::Integer | DerType::Enumerated = self.der_type {
268            if let Some(contents) = &self.contents {
269                if contents.len() == 0 {
270                    return Err(DerError::InvalidLength(format!(
271                        "{} content length must be 1 or more.",
272                        self.der_type
273                    )));
274                }
275
276                let mut value = 0u64;
277                let mut shift_count = 0u8;
278                for i in 0..contents.len() {
279                    let b = contents[i];
280                    shift_count += 8;
281                    if shift_count > 64 {
282                        return Err(DerError::Overflow);
283                    }
284                    value = (value << 8) | b as u64;
285                }
286                Ok(value)
287            } else {
288                unreachable!();
289            }
290        } else {
291            panic!("{} type is not supported to convert to u64.", self.der_type);
292        }
293    }
294
295    pub fn to_be_bytes(&self, sign: bool, min_len: usize) -> Vec<u8> {
296        if let DerType::Integer = self.der_type {
297            if let Some(contents) = &self.contents {
298                if contents.len() < min_len {
299                    let mut vec = Vec::with_capacity(min_len);
300                    if sign && contents.len() > 0 && (contents[0] & 0b10000000) != 0 {
301                        vec.push(0b10000000);
302                        for _ in 0..(min_len - contents.len() - 1) {
303                            vec.push(0);
304                        }
305                        vec.push(contents[0] & 0b01111111);
306                        vec.extend_from_slice(&contents[1..]);
307                    } else {
308                        for _ in 0..(min_len - contents.len()) {
309                            vec.push(0);
310                        }
311                        vec.extend_from_slice(contents);
312                    }
313                    vec
314                } else if contents.len() - 1 >= min_len
315                    && !sign
316                    && contents.len() > 0
317                    && contents[0] == 0
318                {
319                    contents[1..].to_vec()
320                } else {
321                    contents.to_vec()
322                }
323            } else {
324                unreachable!();
325            }
326        } else {
327            panic!(
328                "{} type is not supported to convert to BitVec",
329                self.der_type
330            );
331        }
332    }
333
334    pub fn to_vec(&self) -> Result<Vec<u8>, DerError> {
335        if let DerType::OctetString = self.der_type {
336            if let Some(contents) = &self.contents {
337                Ok(contents.to_vec())
338            } else {
339                unreachable!();
340            }
341        } else {
342            panic!(
343                "{} type is not supported to convert to OctetString",
344                self.der_type
345            );
346        }
347    }
348
349    pub fn to_bit_vec(&self) -> Result<(Vec<u8>, u8), DerError> {
350        if let DerType::BitString = self.der_type {
351            if let Some(contents) = &self.contents {
352                if contents.len() < 2 {
353                    return Err(DerError::InvalidLength(format!(
354                        "Bit String content length must be 2 or more."
355                    )));
356                }
357
358                let unused_bits = contents[0];
359                if unused_bits > 7 {
360                    return Err(DerError::InvalidContents(format!(
361                        "Unused bit count of Bit String must be from 0 to 7."
362                    )));
363                }
364
365                Ok((contents[1..contents.len()].to_vec(), unused_bits))
366            } else {
367                unreachable!();
368            }
369        } else {
370            panic!(
371                "{} type is not supported to convert to BitVec",
372                self.der_type
373            );
374        }
375    }
376
377    pub fn to_string(&self) -> Result<String, DerError> {
378        if let DerType::Utf8String = self.der_type {
379            if let Some(contents) = &self.contents {
380                let value = String::from_utf8(contents.to_vec()).map_err(|_| {
381                    DerError::InvalidContents("Invalid UTF-8 sequence found".to_string())
382                })?;
383                Ok(value)
384            } else {
385                unreachable!();
386            }
387        } else {
388            panic!(
389                "{} type is not supported to convert to String.",
390                self.der_type
391            );
392        }
393    }
394
395    pub fn to_object_identifier(&self) -> Result<ObjectIdentifier, DerError> {
396        if let DerType::ObjectIdentifier = self.der_type {
397            if let Some(contents) = &self.contents {
398                let mut oid = Vec::<u64>::new();
399                if contents.len() > 0 {
400                    let b0 = contents[0];
401                    oid.push((b0 / 40) as u64);
402                    oid.push((b0 % 40) as u64);
403
404                    let mut buf = 0u64;
405                    let mut shift_count = 0u8;
406                    for i in 1..contents.len() {
407                        let b = contents[i];
408                        shift_count += 7;
409                        if shift_count > 64 {
410                            return Err(DerError::Overflow);
411                        }
412                        buf = (buf << 7) | (b & 0x7F) as u64;
413                        if b & 0x80 == 0 {
414                            oid.push(buf);
415                            buf = 0u64;
416                            shift_count = 0;
417                        }
418                    }
419                }
420                return Ok(ObjectIdentifier::from_slice(&oid));
421            } else {
422                unreachable!();
423            }
424        }
425        panic!(
426            "{} type is not supported to convert to ObjectIdentifier.",
427            self.der_type
428        );
429    }
430
431    fn get_tag(&mut self) -> Result<Option<(DerType, bool)>, DerError> {
432        let result = match self.get()? {
433            Some(val) => {
434                let der_class = Self::lookup_der_class(val >> 6);
435                let constructed = ((val >> 5) & 0x01) != 0;
436                let tag_no = if (val & 0x1F) > 30 {
437                    let mut buf = 0u64;
438                    let mut shift_count = 0u8;
439                    loop {
440                        match self.get()? {
441                            Some(val) => {
442                                shift_count += 7;
443                                if shift_count > 64 {
444                                    return Err(DerError::Overflow);
445                                }
446                                buf = (buf << 7) | (val & 0x7F) as u64;
447                                if val & 0x80 == 0 {
448                                    break;
449                                }
450                            }
451                            None => return Err(DerError::UnexpectedEndOfInput),
452                        }
453                    }
454                    buf
455                } else {
456                    (val & 0x1F) as u64
457                };
458
459                Some((Self::lookup_der_type(der_class, tag_no), constructed))
460            }
461            None => None,
462        };
463        Ok(result)
464    }
465
466    fn lookup_der_class(class_no: u8) -> DerClass {
467        match class_no {
468            0b00 => DerClass::Universal,
469            0b01 => DerClass::Application,
470            0b10 => DerClass::ContextSpecific,
471            0b11 => DerClass::Private,
472            _ => unreachable!(),
473        }
474    }
475
476    fn lookup_der_type(class: DerClass, tag_no: u64) -> DerType {
477        match (class, tag_no) {
478            (DerClass::Universal, 0) => DerType::EndOfContents,
479            (DerClass::Universal, 1) => DerType::Boolean,
480            (DerClass::Universal, 2) => DerType::Integer,
481            (DerClass::Universal, 3) => DerType::BitString,
482            (DerClass::Universal, 4) => DerType::OctetString,
483            (DerClass::Universal, 5) => DerType::Null,
484            (DerClass::Universal, 6) => DerType::ObjectIdentifier,
485            (DerClass::Universal, 7) => DerType::ObjectDescriptor,
486            (DerClass::Universal, 8) => DerType::External,
487            (DerClass::Universal, 9) => DerType::Real,
488            (DerClass::Universal, 10) => DerType::Enumerated,
489            (DerClass::Universal, 11) => DerType::EmbeddedPdv,
490            (DerClass::Universal, 12) => DerType::Utf8String,
491            (DerClass::Universal, 13) => DerType::RelativeOid,
492            (DerClass::Universal, 14) => DerType::Time,
493            (DerClass::Universal, 16) => DerType::Sequence,
494            (DerClass::Universal, 17) => DerType::Set,
495            (DerClass::Universal, 18) => DerType::NumericString,
496            (DerClass::Universal, 19) => DerType::PrintableString,
497            (DerClass::Universal, 20) => DerType::TeletexString,
498            (DerClass::Universal, 21) => DerType::VideotexString,
499            (DerClass::Universal, 22) => DerType::Ia5String,
500            (DerClass::Universal, 23) => DerType::UtcTime,
501            (DerClass::Universal, 24) => DerType::GeneralizedTime,
502            (DerClass::Universal, 25) => DerType::GraphicString,
503            (DerClass::Universal, 26) => DerType::VisibleString,
504            (DerClass::Universal, 27) => DerType::GeneralString,
505            (DerClass::Universal, 28) => DerType::UniversalString,
506            (DerClass::Universal, 29) => DerType::CharacterString,
507            (DerClass::Universal, 30) => DerType::BmpString,
508            (DerClass::Universal, 31) => DerType::Date,
509            (DerClass::Universal, 32) => DerType::TimeOfDay,
510            (DerClass::Universal, 33) => DerType::DateTime,
511            (DerClass::Universal, 34) => DerType::Duration,
512            _ => DerType::Other(class, tag_no),
513        }
514    }
515
516    fn get_length(&mut self) -> Result<Option<usize>, DerError> {
517        let result = match self.get()? {
518            Some(val) if val == 0xFF => {
519                return Err(DerError::InvalidLength(format!(
520                    "Length 0x{:X} is reserved for possible future extension.",
521                    val
522                )));
523            }
524            Some(val) if val == 0x80 => None,
525            Some(val) if val < 0x80 => Some(val as usize),
526            Some(val) => {
527                let len_size = (val & 0x7F) as usize;
528                if len_size > std::mem::size_of::<usize>() {
529                    return Err(DerError::Overflow);
530                }
531                let mut num = 0usize;
532                for _ in 0..len_size {
533                    match self.get()? {
534                        Some(val) => {
535                            num = num << 8 | val as usize;
536                        }
537                        None => return Err(DerError::UnexpectedEndOfInput),
538                    }
539                }
540                Some(num)
541            }
542            None => return Err(DerError::UnexpectedEndOfInput),
543        };
544        Ok(result)
545    }
546
547    fn get(&mut self) -> Result<Option<u8>, DerError> {
548        let result = match self.input.next() {
549            Some(Ok(val)) => {
550                self.read_count += 1;
551                Some(val)
552            }
553            Some(Err(err)) => return Err(DerError::ReadFailure(err)),
554            None => None,
555        };
556        Ok(result)
557    }
558}
559
560#[cfg(test)]
561mod tests {
562    use super::*;
563
564    use anyhow::Result;
565    use std::fs::File;
566    use std::path::PathBuf;
567
568    use crate::util::der::DerBuilder;
569
570    #[test]
571    fn parse_der() -> Result<()> {
572        let bytes = load_file("der/RSA_2048bit_raw_public.der")?;
573
574        let mut parser = DerReader::from_reader(bytes);
575        assert!(matches!(parser.next()?, Some(DerType::Sequence)));
576        assert!(matches!(parser.next()?, Some(DerType::Integer)));
577        assert!(matches!(parser.next()?, Some(DerType::Integer)));
578        assert!(matches!(parser.next()?, Some(DerType::EndOfContents)));
579        Ok(())
580    }
581
582    #[test]
583    fn parse_der_2() -> Result<()> {
584        let mut vec = Vec::new();
585        let _ = load_file("der/RSA_2048bit_raw_public.der")?.read_to_end(&mut vec)?;
586
587        let mut parser = DerReader::from_bytes(&vec);
588        assert!(matches!(parser.next()?, Some(DerType::Sequence)));
589        assert!(matches!(parser.next()?, Some(DerType::Integer)));
590        assert!(matches!(parser.next()?, Some(DerType::Integer)));
591        assert!(matches!(parser.next()?, Some(DerType::EndOfContents)));
592        Ok(())
593    }
594
595    #[test]
596    fn parse_der_3() -> Result<()> {
597        let mut builder = DerBuilder::new();
598        builder.begin(DerType::Sequence);
599        {
600            builder.begin(DerType::Sequence);
601            {
602                builder.append_integer_from_u8(1);
603            }
604            builder.end();
605        }
606        builder.end();
607
608        let input = builder.build();
609        let mut parser = DerReader::from_bytes(&input);
610        assert!(matches!(parser.next()?, Some(DerType::Sequence)));
611        assert!(matches!(parser.next()?, Some(DerType::Sequence)));
612        assert!(matches!(parser.next()?, Some(DerType::Integer)));
613        assert!(matches!(parser.next()?, Some(DerType::EndOfContents)));
614        assert!(matches!(parser.next()?, Some(DerType::EndOfContents)));
615
616        Ok(())
617    }
618
619    fn load_file(path: &str) -> Result<File> {
620        let mut pb = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
621        pb.push("data");
622        pb.push(path);
623
624        let file = File::open(&pb)?;
625        Ok(file)
626    }
627}