Skip to content

Commit bd6fcd9

Browse files
committed
der: clarify works for OctetString
1 parent 314de0c commit bd6fcd9

File tree

8 files changed

+239
-59
lines changed

8 files changed

+239
-59
lines changed

der/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ derive = ["dep:der_derive"]
4343
oid = ["dep:const-oid"]
4444
pem = ["dep:pem-rfc7468", "alloc", "zeroize"]
4545
real = []
46-
clarify = ["std", "pem", "dep:tynm", "derive"]
46+
clarify = ["std", "pem", "dep:tynm", "derive", "oid"]
4747

4848
[package.metadata.docs.rs]
4949
all-features = true

der/src/encode.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,24 @@ where
8181
/// Encode this value as ASN.1 DER using the provided [`Writer`].
8282
fn encode(&self, writer: &mut impl Writer) -> Result<()> {
8383
self.header()?.encode(writer)?;
84-
self.encode_value(writer)
84+
clarify_start_value_type::<T>(writer);
85+
let result = self.encode_value(writer);
86+
clarify_end_value_type::<T>(writer);
87+
result
88+
}
89+
}
90+
91+
fn clarify_start_value_type<T: ?Sized>(writer: &mut impl Writer) {
92+
#[cfg(feature = "clarify")]
93+
if let Some(clarifier) = writer.clarifier() {
94+
clarifier.clarify_start_value_type::<T>();
95+
}
96+
}
97+
98+
fn clarify_end_value_type<T: ?Sized>(writer: &mut impl Writer) {
99+
#[cfg(feature = "clarify")]
100+
if let Some(clarifier) = writer.clarifier() {
101+
clarifier.clarify_end_value_type::<T>();
85102
}
86103
}
87104

der/src/header.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,25 @@ impl Encode for Header {
5454
}
5555

5656
fn encode(&self, writer: &mut impl Writer) -> Result<()> {
57+
clarify_start_tag(writer, &self.tag);
5758
self.tag.encode(writer)?;
58-
self.length.encode(writer)
59+
let result = self.length.encode(writer);
60+
clarify_end_length(writer, &self.tag, self.length);
61+
result
62+
}
63+
}
64+
65+
fn clarify_start_tag(writer: &mut impl Writer, tag: &Tag) {
66+
#[cfg(feature = "clarify")]
67+
if let Some(clarifier) = writer.clarifier() {
68+
clarifier.clarify_header_start_tag(&tag);
69+
}
70+
}
71+
72+
fn clarify_end_length(writer: &mut impl Writer, tag: &Tag, length: Length) {
73+
#[cfg(feature = "clarify")]
74+
if let Some(clarifier) = writer.clarifier() {
75+
clarifier.clarify_header_end_length(Some(&tag), length);
5976
}
6077
}
6178

der/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ pub use {
400400
};
401401

402402
#[cfg(feature = "clarify")]
403-
pub use writer::clarify::ClarifySliceWriter;
403+
pub use writer::clarify::{Clarifier, ClarifyFlavor, ClarifySliceWriter, EncodeClarifyExt};
404404

405405
#[cfg(feature = "time")]
406406
pub use time;

der/src/writer/clarify.rs

Lines changed: 75 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,38 @@ pub(crate) mod commentwriter;
22
pub(crate) mod hexdisplaylines;
33

44
use crate::std::io::Write;
5+
use crate::writer::clarify::commentwriter::RustHexWriter;
56
use crate::{Encode, Error, SliceWriter};
67
use crate::{Length, Result, Tag};
78
use commentwriter::{CommentWriter, JavaCommentWriter, XmlCommentWriter};
89
use hexdisplaylines::HexDisplayLines;
910
use std::borrow::Cow;
10-
use std::println;
1111
use std::string::String;
1212
use std::{boxed::Box, vec::Vec};
1313

1414
use super::Writer;
1515

16+
/// Extension trait, auto-implemented on [`Encode`]
1617
pub trait EncodeClarifyExt: Encode {
1718
/// Encode this type as pretty-printed hex DER, with comments.
1819
fn to_der_clarify(&self, flavor: ClarifyFlavor) -> Result<String> {
19-
let outputs = self.to_der_clarify_ignorant(flavor);
20+
let outputs = self.to_der_clarify_err_ignorant(flavor);
2021
// Propagate encode and finish errors
2122
outputs.raw?;
2223
Ok(String::from_utf8(outputs.clarify_buf).expect("clarified output to be utf-8"))
2324
}
2425

2526
/// Encode this type as pretty-printed hex DER, with comments.
2627
/// Ignores any errors that occur during [`Encode::encode`].
27-
fn to_der_clarify_ignorant(&self, flavor: ClarifyFlavor) -> ClarifyOutputs<'static> {
28+
fn to_der_clarify_err_ignorant(&self, flavor: ClarifyFlavor) -> ClarifyOutputs<'static> {
2829
let len = match self.encoded_len() {
2930
Ok(len) => len,
3031
Err(err) => return ClarifyOutputs::from_err(err),
3132
};
3233

33-
let mut buf = Vec::with_capacity(u32::from(len) as usize);
34+
let mut buf: Vec<u8> = Vec::new();
35+
buf.resize(u32::from(len) as usize, 0u8);
36+
3437
let mut writer = ClarifySliceWriter::new(&mut buf, Vec::new(), flavor);
3538
let result = self.encode(&mut writer);
3639

@@ -104,14 +107,19 @@ impl<'a> ClarifyOutputs<'a> {
104107
// }
105108
}
106109

110+
/// Determines how comments will look like
107111
#[derive(Copy, Clone, Debug)]
108112
pub enum ClarifyFlavor {
113+
/// `01 02 <!-- comment -->`
109114
XmlComments,
115+
/// `01 02 // comment`
110116
JavaComments,
117+
/// `"01 02" // comment`
111118
RustHex,
112119
}
113120

114121
impl Clarifier {
122+
/// Creates new Clarifier with buffer, that accumulates comments and hex bytes.
115123
pub fn new(clarify_buf: Vec<u8>, flavor: ClarifyFlavor) -> Self {
116124
Self {
117125
clarify_buf,
@@ -123,7 +131,7 @@ impl Clarifier {
123131
comment_writer: match flavor {
124132
ClarifyFlavor::XmlComments => Box::new(XmlCommentWriter::default()),
125133
ClarifyFlavor::JavaComments => Box::new(JavaCommentWriter::default()),
126-
ClarifyFlavor::RustHex => todo!(),
134+
ClarifyFlavor::RustHex => Box::new(RustHexWriter::default()),
127135
},
128136
}
129137
}
@@ -162,7 +170,9 @@ impl<'a> ClarifySliceWriter<'a> {
162170

163171
/// Finish encoding to the buffer, returning a slice containing the data
164172
/// written to the buffer.
165-
pub fn finish(self) -> ClarifyOutputs<'a> {
173+
pub fn finish(mut self) -> ClarifyOutputs<'a> {
174+
self.clarifier.flush_line();
175+
166176
ClarifyOutputs {
167177
raw: self.writer.finish().map(|raw| Cow::Borrowed(raw)),
168178
clarify_buf: self.clarifier.clarify_buf,
@@ -219,34 +229,48 @@ impl Clarifier {
219229
&INDENT_STR[..ilen]
220230
}
221231

232+
/// Writes indent if it is currently enabled
222233
pub fn write_clarify_indent_if_enabled(&mut self) {
223234
if self.indent_enabled {
224235
self.write_clarify_indent();
225236
}
226237
}
227238

239+
fn flush_line(&mut self) {
240+
// if current line ends in space
241+
if self
242+
.clarify_buf
243+
.last()
244+
.map(|last| *last == b' ')
245+
.unwrap_or_default()
246+
{
247+
// remove space
248+
self.clarify_buf.pop();
249+
}
250+
// write comment after hex
251+
self.comment_writer.before_new_line(&mut self.clarify_buf);
252+
}
253+
228254
/// Writes indentation to debug output, for example "\n\t" for depth == 1
229255
pub fn write_clarify_indent(&mut self) {
256+
self.flush_line();
257+
230258
let indent = self.indent_str();
231-
{
232-
self.comment_writer.before_new_line(&mut self.clarify_buf);
233-
write!(&mut self.clarify_buf, "\n{}", indent).unwrap();
234-
}
259+
write!(&mut self.clarify_buf, "\n{}", indent).ok();
260+
261+
// write e.g. '"' before hex
262+
self.comment_writer.start_new_line(&mut self.clarify_buf);
235263
}
236264

237265
/// Writes hex bytes to debug output, for example "30 04 "
238266
pub fn write_clarify_hex(&mut self, slice: &[u8]) {
239267
let indent = self.indent_str();
240-
{
241-
write!(&mut self.clarify_buf, "{}", HexDisplayLines(&slice, indent)).unwrap();
242-
}
268+
write!(&mut self.clarify_buf, "{}", HexDisplayLines(&slice, indent)).ok();
243269
}
244270

245271
/// Writes string to debug output, for example a comment "// SEQUENCE"
246272
pub fn write_clarify_str(&mut self, s: &str) {
247-
{
248-
write!(&mut self.clarify_buf, "{}", s).unwrap();
249-
}
273+
write!(&mut self.clarify_buf, "{}", s).unwrap();
250274
}
251275
/// Writes string to debug output, for example a comment: `// SEQUENCE: name`
252276
pub fn write_clarify_type_str(&mut self, start_end: &str, type_name: &str) {
@@ -291,7 +315,7 @@ impl Clarifier {
291315
match (writer_pos, last_pos) {
292316
(Some(writer_pos), Some(last_pos)) => {
293317
let diff = writer_pos - last_pos;
294-
if diff < 16 {
318+
if diff < 15 {
295319
// ignore short runs
296320
return;
297321
}
@@ -304,9 +328,16 @@ impl Clarifier {
304328
self.write_clarify_type_str("end", type_name.as_ref());
305329
}
306330

331+
// /// for better tag-length pretty-printing inline
332+
// pub fn clarify_end_tag(&mut self, _tag: &Tag) {
333+
// // just to print a single length byte without indent
334+
// self.indent_enabled = false;
335+
// }
336+
307337
/// for better tag-length pretty-printing inline
308-
pub fn clarify_end_tag(&mut self, _tag: &Tag) {
309-
// just to print a single length byte without indent
338+
pub fn clarify_header_start_tag(&mut self, _tag: &Tag) {
339+
self.write_clarify_indent();
340+
// just to print header bytes without indent
310341
self.indent_enabled = false;
311342
}
312343

@@ -318,27 +349,36 @@ impl Clarifier {
318349
// self.indent_enabled = enabled;
319350
// }
320351

352+
/// Writes field name, i.e. field: `public_key`
353+
///
354+
/// when used on Sequence field:
355+
/// ```text
356+
/// public_key: Option<&'a [u8]>
357+
/// ```
321358
pub fn clarify_field_name(&mut self, field_name: &str) {
322359
self.write_clarify_indent();
323360
self.write_clarify_type_str("field", field_name);
324361
}
325362

326-
pub fn clarify_start_value_type<T>(&mut self) {
363+
/// Writes e.g. `// type: OctetString`
364+
pub fn clarify_start_value_type<T: ?Sized>(&mut self) {
327365
self.clarify_start_value_type_str(Some(self.last_position), &tynm::type_name::<T>());
328366
}
329-
pub fn clarify_end_value_type<T>(&mut self) {
367+
/// Writes e.g. `// end: OctetString`
368+
pub fn clarify_end_value_type<T: ?Sized>(&mut self) {
330369
self.clarify_end_value_type_str(Some(self.last_position), &tynm::type_name::<T>());
331370
}
332371

333-
// fn clarify_end_length(&mut self, tag: Option<&Tag>, length: Length) {
334-
// self.indent_enabled = true;
335-
// if let Some(tag) = tag {
336-
// self.write_debug_type_str("tag", &format!("{}", tag));
337-
// }
338-
// if u32::from(length) >= 10 {
339-
// self.write_debug_type_str("len", &format!("{}", length));
340-
// }
341-
// }
372+
/// Writes e.g. `// tag: OCTET STRING len: 17`
373+
pub fn clarify_header_end_length(&mut self, tag: Option<&Tag>, length: Length) {
374+
self.indent_enabled = true;
375+
if let Some(tag) = tag {
376+
self.write_clarify_type_str("tag", &format!("{}", tag));
377+
}
378+
if u32::from(length) >= 10 {
379+
self.write_clarify_type_str("len", &format!("{}", length));
380+
}
381+
}
342382

343383
// fn clarify_value_quote(&mut self, _type_name: &str, tag_name: &[u8]) {
344384
// //self.write_debug_value_quote(type_name, tag_name);
@@ -349,6 +389,7 @@ impl Clarifier {
349389
// self.write_debug_int(value);
350390
// }
351391

392+
/// Writes pretty-printed `CHOICE name`
352393
pub fn clarify_choice(&mut self, choice_name: &[u8]) {
353394
self.write_clarify_indent();
354395
if let Ok(choice_name) = std::str::from_utf8(choice_name) {
@@ -359,7 +400,6 @@ impl Clarifier {
359400

360401
impl<'a> Writer for ClarifySliceWriter<'a> {
361402
fn write(&mut self, slice: &[u8]) -> Result<()> {
362-
println!("writing {slice:?}");
363403
self.reserve(slice.len())?.copy_from_slice(slice);
364404
self.clarifier.last_position += slice.len() as u32;
365405

@@ -368,6 +408,10 @@ impl<'a> Writer for ClarifySliceWriter<'a> {
368408

369409
Ok(())
370410
}
411+
412+
fn clarifier(&mut self) -> Option<&mut Clarifier> {
413+
Some(&mut self.clarifier)
414+
}
371415
}
372416

373417
/// Strips wrappers, such as `EncodeValueRef`, which is commonly used and is completely transparent
@@ -390,24 +434,3 @@ fn strip_transparent_types(mut type_name: &str) -> Cow<'_, str> {
390434

391435
Cow::Borrowed(type_name)
392436
}
393-
394-
#[cfg(test)]
395-
pub mod test {
396-
use std::{println, vec::Vec};
397-
398-
use crate::{
399-
asn1::OctetString,
400-
writer::clarify::{ClarifyFlavor, EncodeClarifyExt},
401-
};
402-
403-
#[test]
404-
fn clarify_simple_octetstring() {
405-
let obj = OctetString::new(&[0xAA, 0xBB, 0xCC]).unwrap();
406-
407-
let clarified = obj
408-
.to_der_clarify(ClarifyFlavor::XmlComments)
409-
.expect("encoded DER");
410-
411-
println!("clarified: {clarified}");
412-
}
413-
}

der/src/writer/clarify/commentwriter.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ pub trait CommentWriter {
44
fn comment(&mut self, s: &str);
55

66
fn before_new_line(&mut self, w: &mut dyn Write);
7+
8+
fn start_new_line(&mut self, _w: &mut dyn Write) {}
79
}
810

911
#[derive(Default)]
@@ -20,7 +22,7 @@ impl CommentWriter for JavaCommentWriter {
2022
if self.buf.len() == 0 {
2123
return;
2224
}
23-
let _ = w.write_all(b"// ");
25+
let _ = w.write_all(b" // ");
2426
let _ = w.write_all(&self.buf);
2527
self.buf.clear();
2628
}
@@ -40,9 +42,38 @@ impl CommentWriter for XmlCommentWriter {
4042
if self.buf.len() == 0 {
4143
return;
4244
}
43-
let _ = w.write_all(b"<!-- ");
45+
let _ = w.write_all(b" <!-- ");
4446
let _ = w.write_all(&self.buf);
4547
let _ = w.write_all(b"-->");
4648
self.buf.clear();
4749
}
4850
}
51+
52+
#[derive(Default)]
53+
pub struct RustHexWriter {
54+
pub started_newline: bool,
55+
pub buf: Vec<u8>,
56+
}
57+
58+
impl CommentWriter for RustHexWriter {
59+
fn comment(&mut self, s: &str) {
60+
self.buf.extend_from_slice(s.as_bytes());
61+
}
62+
63+
fn before_new_line(&mut self, w: &mut dyn Write) {
64+
if self.started_newline {
65+
w.write_all(b"\"").ok();
66+
}
67+
if self.buf.len() == 0 {
68+
return;
69+
}
70+
w.write_all(b" // ").ok();
71+
w.write_all(&self.buf).ok();
72+
self.buf.clear();
73+
self.started_newline = false;
74+
}
75+
fn start_new_line(&mut self, w: &mut dyn Write) {
76+
self.started_newline = true;
77+
w.write_all(b"\"").ok();
78+
}
79+
}

0 commit comments

Comments
 (0)