Skip to content

Commit 76f7334

Browse files
committed
Add Visit and VisitMut patterns to iterate objects and update printer to use it
1 parent 74d3e27 commit 76f7334

File tree

5 files changed

+568
-45
lines changed

5 files changed

+568
-45
lines changed

examples/dump-der.rs

+67-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,71 @@ use der_parser::der::*;
33
use std::env;
44
use std::io;
55

6+
use nom::HexDisplay;
7+
8+
struct BerPrinter {}
9+
10+
impl BerPrinter {
11+
/// try to parse contents, constructed or not
12+
///
13+
/// Do not raise errors if object is not constructed
14+
fn try_print_encapsulated(&mut self, data: &[u8], depth: usize, ber: &BerObject) {
15+
let mut i = data;
16+
let mut first_object = true;
17+
while !i.is_empty() {
18+
match parse_ber_any_r(i, MAX_RECURSION) {
19+
Ok((rem, inner)) => {
20+
if first_object {
21+
println!("{:1$}encapsulates {{", " ", depth * 2);
22+
first_object = false;
23+
}
24+
self.run_at(&inner, depth + 1);
25+
i = rem;
26+
}
27+
Err(e) => {
28+
if ber.is_constructed() {
29+
// object was constructed, so should have been parsed correctly
30+
eprintln!(
31+
"Error while parsing constructed object at depth {}: {}",
32+
depth, e
33+
);
34+
eprintln!("tried to parse\n{}", data.to_hex(16));
35+
} else {
36+
// does not look like encapsulated data
37+
i = &[];
38+
}
39+
break;
40+
}
41+
}
42+
}
43+
if !first_object {
44+
println!("{:1$}}}", " ", depth * 2);
45+
}
46+
if !i.is_empty() {
47+
println!("WARNING: {} remaining bytes at depth {}", i.len(), depth);
48+
}
49+
}
50+
}
51+
52+
impl<'a> Visit<'a> for BerPrinter {
53+
fn visit_ber(&mut self, ber: &'a BerObject<'a>, depth: usize) {
54+
// create a printer without the recursive flag, recursion is handled by the
55+
// visitor pattern
56+
let pp = PrettyBer::new(ber, vec![PrettyPrinterFlag::ShowHeader], depth * 2, 2);
57+
println!("{:?}", pp);
58+
match ber.content {
59+
BerObjectContent::Unknown(ref any) => {
60+
self.try_print_encapsulated(any.data, depth, ber);
61+
}
62+
// Bitstring and OctetString also can encapsulate objects
63+
BerObjectContent::OctetString(data) => {
64+
self.try_print_encapsulated(data, depth, ber);
65+
}
66+
_ => (),
67+
}
68+
}
69+
}
70+
671
pub fn main() -> io::Result<()> {
772
let mut parse_as_ber = false;
873
for file_name in env::args().skip(1) {
@@ -23,7 +88,8 @@ pub fn main() -> io::Result<()> {
2388
} else {
2489
parse_der(&data).expect("could not parse DER data")
2590
};
26-
println!("{:?}", obj.as_pretty(0, 2));
91+
let mut printer = BerPrinter {};
92+
printer.run_at(&obj, 1);
2793
if !rem.is_empty() {
2894
println!("WARNING: extra bytes after BER/DER object:\n{:x?}", rem);
2995
}

src/ber/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ mod print;
5454
#[cfg(feature = "serialize")]
5555
mod serialize;
5656
mod tagged;
57+
mod visit;
58+
mod visit_mut;
5759
mod wrap_any;
5860

5961
pub use crate::ber::ber::*;
@@ -63,6 +65,8 @@ pub use crate::ber::print::*;
6365
#[cfg(feature = "serialize")]
6466
pub use crate::ber::serialize::*;
6567
pub use crate::ber::tagged::*;
68+
pub use crate::ber::visit::*;
69+
pub use crate::ber::visit_mut::*;
6670
pub use crate::ber::wrap_any::*;
6771

6872
pub mod compat;

src/ber/print.rs

+99-44
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
use crate::ber::BitStringObject;
22
use crate::ber::{BerObject, BerObjectContent};
3-
use alloc::string::String;
3+
use alloc::string::{String, ToString};
4+
use alloc::vec;
45
use alloc::vec::Vec;
5-
use asn1_rs::Tag;
6+
use asn1_rs::{Class, Header, Length, Tag};
67
use core::fmt;
78
use core::iter::FromIterator;
89
use core::str;
10+
use debug::HexSlice;
911

1012
use rusticata_macros::debug;
1113

12-
#[derive(Clone, Debug, PartialEq)]
14+
#[derive(Clone, Copy, Debug, PartialEq)]
1315
pub enum PrettyPrinterFlag {
16+
Recursive,
1417
ShowHeader,
1518
}
1619

20+
/// Pretty-print BER object
21+
///
22+
/// This method is recursive by default. To prevent that, unset the `Recursive` flag.
1723
pub struct PrettyBer<'a> {
1824
obj: &'a BerObject<'a>,
1925
indent: usize,
@@ -24,23 +30,39 @@ pub struct PrettyBer<'a> {
2430

2531
impl<'a> BerObject<'a> {
2632
pub fn as_pretty(&'a self, indent: usize, increment: usize) -> PrettyBer<'a> {
27-
PrettyBer {
28-
obj: self,
33+
PrettyBer::new(self, vec![PrettyPrinterFlag::Recursive], indent, increment)
34+
}
35+
}
36+
37+
impl<'a> PrettyBer<'a> {
38+
pub const fn new(
39+
obj: &'a BerObject<'a>,
40+
flags: Vec<PrettyPrinterFlag>,
41+
indent: usize,
42+
increment: usize,
43+
) -> Self {
44+
Self {
45+
obj,
2946
indent,
3047
inc: increment,
31-
32-
flags: Vec::new(),
48+
flags,
3349
}
3450
}
35-
}
3651

37-
impl<'a> PrettyBer<'a> {
3852
pub fn set_flag(&mut self, flag: PrettyPrinterFlag) {
3953
if !self.flags.contains(&flag) {
4054
self.flags.push(flag);
4155
}
4256
}
4357

58+
pub fn unset_flag(&mut self, flag: PrettyPrinterFlag) {
59+
self.flags.retain(|&f| f != flag);
60+
}
61+
62+
pub fn is_flag_set(&self, flag: PrettyPrinterFlag) -> bool {
63+
self.flags.contains(&flag)
64+
}
65+
4466
pub fn next_indent<'b>(&self, obj: &'b BerObject) -> PrettyBer<'b> {
4567
PrettyBer {
4668
obj,
@@ -49,6 +71,32 @@ impl<'a> PrettyBer<'a> {
4971
flags: self.flags.to_vec(),
5072
}
5173
}
74+
75+
#[inline]
76+
fn is_recursive(&self) -> bool {
77+
self.is_flag_set(PrettyPrinterFlag::Recursive)
78+
}
79+
}
80+
81+
fn dbg_header(header: &Header, f: &mut fmt::Formatter) -> fmt::Result {
82+
let s_constructed = if header.is_constructed() { "+" } else { "" };
83+
let l = match header.length() {
84+
Length::Definite(sz) => sz.to_string(),
85+
Length::Indefinite => "Indefinite".to_string(),
86+
};
87+
match header.class() {
88+
Class::Universal => {
89+
write!(f, "[{}]{} {}", header.tag(), s_constructed, l)?;
90+
}
91+
Class::ContextSpecific => {
92+
write!(f, "[{}]{} {}", header.tag().0, s_constructed, l)?;
93+
}
94+
95+
class => {
96+
write!(f, "[{} {}]{} {}", class, header.tag().0, s_constructed, l)?;
97+
}
98+
}
99+
Ok(())
52100
}
53101

54102
impl<'a> fmt::Debug for PrettyBer<'a> {
@@ -58,7 +106,8 @@ impl<'a> fmt::Debug for PrettyBer<'a> {
58106
write!(f, "{:1$}", " ", self.indent)?;
59107
};
60108
if self.flags.contains(&PrettyPrinterFlag::ShowHeader) {
61-
write!(f, "[c:{:?}, s:{}, t:{}] ", self.obj.header.class(), self.obj.header.constructed(), self.obj.header.tag())?;
109+
dbg_header(&self.obj.header, f)?;
110+
write!(f, " ")?;
62111
};
63112
fn print_utf32_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result {
64113
let chars: Option<Vec<char>> = s
@@ -72,34 +121,34 @@ impl<'a> fmt::Debug for PrettyBer<'a> {
72121
}
73122
}
74123
match self.obj.content {
75-
BerObjectContent::EndOfContent => writeln!(f, "EndOfContent"),
76-
BerObjectContent::Boolean(b) => writeln!(f, "Boolean({:?})", b),
77-
BerObjectContent::Integer(i) => writeln!(f, "Integer({:?})", debug::HexSlice(i)),
78-
BerObjectContent::Enum(i) => writeln!(f, "Enum({})", i),
79-
BerObjectContent::OID(ref v) => writeln!(f, "OID({:?})", v),
80-
BerObjectContent::RelativeOID(ref v) => writeln!(f, "RelativeOID({:?})", v),
81-
BerObjectContent::Null => writeln!(f, "Null"),
82-
BerObjectContent::OctetString(v) => writeln!(f, "OctetString({:?})", debug::HexSlice(v)),
124+
BerObjectContent::EndOfContent => write!(f, "EndOfContent"),
125+
BerObjectContent::Boolean(b) => write!(f, "Boolean({:?})", b),
126+
BerObjectContent::Integer(i) => write!(f, "Integer({:?})", HexSlice(i)),
127+
BerObjectContent::Enum(i) => write!(f, "Enum({})", i),
128+
BerObjectContent::OID(ref v) => write!(f, "OID({:?})", v),
129+
BerObjectContent::RelativeOID(ref v) => write!(f, "RelativeOID({:?})", v),
130+
BerObjectContent::Null => write!(f, "Null"),
131+
BerObjectContent::OctetString(v) => write!(f, "OctetString({:?})", HexSlice(v)),
83132
BerObjectContent::BitString(u,BitStringObject{data:v})
84-
=> writeln!(f, "BitString({},{:?})", u, debug::HexSlice(v)),
85-
BerObjectContent::GeneralizedTime(ref time) => writeln!(f, "GeneralizedTime(\"{}\")", time),
86-
BerObjectContent::UTCTime(ref time) => writeln!(f, "UTCTime(\"{}\")", time),
87-
BerObjectContent::VisibleString(s) => writeln!(f, "VisibleString(\"{}\")", s),
88-
BerObjectContent::GeneralString(s) => writeln!(f, "GeneralString(\"{}\")", s),
89-
BerObjectContent::GraphicString(s) => writeln!(f, "GraphicString(\"{}\")", s),
90-
BerObjectContent::PrintableString(s) => writeln!(f, "PrintableString(\"{}\")", s),
91-
BerObjectContent::NumericString(s) => writeln!(f, "NumericString(\"{}\")", s),
92-
BerObjectContent::UTF8String(s) => writeln!(f, "UTF8String(\"{}\")", s),
93-
BerObjectContent::IA5String(s) => writeln!(f, "IA5String(\"{}\")", s),
94-
BerObjectContent::T61String(s) => writeln!(f, "T61String({})", s),
95-
BerObjectContent::VideotexString(s) => writeln!(f, "VideotexString({})", s),
96-
BerObjectContent::ObjectDescriptor(s) => writeln!(f, "ObjectDescriptor(\"{}\")", s),
97-
BerObjectContent::BmpString(s) => writeln!(f, "BmpString(\"{}\")", s),
133+
=> write!(f, "BitString({},{:?})", u, HexSlice(v)),
134+
BerObjectContent::GeneralizedTime(ref time) => write!(f, "GeneralizedTime(\"{}\")", time),
135+
BerObjectContent::UTCTime(ref time) => write!(f, "UTCTime(\"{}\")", time),
136+
BerObjectContent::VisibleString(s) => write!(f, "VisibleString(\"{}\")", s),
137+
BerObjectContent::GeneralString(s) => write!(f, "GeneralString(\"{}\")", s),
138+
BerObjectContent::GraphicString(s) => write!(f, "GraphicString(\"{}\")", s),
139+
BerObjectContent::PrintableString(s) => write!(f, "PrintableString(\"{}\")", s),
140+
BerObjectContent::NumericString(s) => write!(f, "NumericString(\"{}\")", s),
141+
BerObjectContent::UTF8String(s) => write!(f, "UTF8String(\"{}\")", s),
142+
BerObjectContent::IA5String(s) => write!(f, "IA5String(\"{}\")", s),
143+
BerObjectContent::T61String(s) => write!(f, "T61String({})", s),
144+
BerObjectContent::VideotexString(s) => write!(f, "VideotexString({})", s),
145+
BerObjectContent::ObjectDescriptor(s) => write!(f, "ObjectDescriptor(\"{}\")", s),
146+
BerObjectContent::BmpString(s) => write!(f, "BmpString(\"{}\")", s),
98147
BerObjectContent::UniversalString(s) => print_utf32_string_with_type(f, s, "UniversalString"),
99148
BerObjectContent::Optional(ref o) => {
100149
match o {
101-
Some(obj) => writeln!(f, "OPTION {:?}", obj),
102-
None => writeln!(f, "NONE"),
150+
Some(obj) => write!(f, "OPTION {:?}", obj),
151+
None => write!(f, "NONE"),
103152
}
104153
}
105154
BerObjectContent::Tagged(class, tag, ref obj) => {
@@ -108,23 +157,29 @@ impl<'a> fmt::Debug for PrettyBer<'a> {
108157
if self.indent > 0 {
109158
write!(f, "{:1$}", " ", self.indent)?;
110159
};
111-
writeln!(f, "}}")?;
160+
write!(f, "}}")?;
112161
Ok(())
113162
},
114163
BerObjectContent::Set(ref v) |
115164
BerObjectContent::Sequence(ref v) => {
116165
let ty = if self.obj.header.tag() == Tag::Sequence { "Sequence" } else { "Set" };
117-
writeln!(f, "{}[", ty)?;
118-
for o in v {
119-
write!(f, "{:?}", self.next_indent(o))?;
120-
};
121-
if self.indent > 0 {
122-
write!(f, "{:1$}", " ", self.indent)?;
123-
};
124-
writeln!(f, "]")?;
166+
if self.is_recursive() {
167+
writeln!(f, "{}[", ty)?;
168+
for o in v {
169+
write!(f, "{:?}", self.next_indent(o))?;
170+
};
171+
if self.indent > 0 {
172+
write!(f, "{:1$}", " ", self.indent)?;
173+
};
174+
write!(f, "]")?;
175+
} else {
176+
write!(f, "{}", ty)?;
177+
}
125178
Ok(())
126179
},
127-
BerObjectContent::Unknown(ref any) => writeln!(f, "Unknown([{} {}] {:x?})", any.class(), any.tag().0, debug::HexSlice(any.data)),
180+
BerObjectContent::Unknown(ref any) => {
181+
write!(f, "Unknown {:x?}", HexSlice(any.data))
182+
},
128183
}
129184
}
130185
}

0 commit comments

Comments
 (0)