Skip to content

Commit fb8db96

Browse files
authored
der: add EncodingRules enum (#1321)
Adds an enum with `Ber` and `Der` (default) variants which can be used to selectively allow a limited number of BER productions when decoding certain BER-based security-oriented formats, e.g. CMS, PKCS#8. Currently this doesn't actually do anything, however the goal is to address #779, where we can't decode CMS generated by Apple tooling. PR #810 is an example of how the rules could be relaxed to support `IndefiniteLength`s.
1 parent e97d077 commit fb8db96

File tree

6 files changed

+50
-7
lines changed

6 files changed

+50
-7
lines changed

der/src/encoding_rules.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// ASN.1 encoding rules.
2+
///
3+
/// This enum identifies the specific encoding rules which are applied at the time a given document
4+
/// is decoded from a byte/octet serialization.
5+
///
6+
/// In addition to the Distinguished Encoding Rules (DER), this crate also supports a strict subset
7+
/// of the Basic Encoding Rules (BER) which supports the minimum amount of additional productions
8+
/// beyond DER needed to interoperate with other implementations of cryptography-oriented formats
9+
/// which utilize BER, e.g. CMS, PKCS#8.
10+
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
11+
pub enum EncodingRules {
12+
/// Basic Encoding Rules.
13+
Ber,
14+
15+
/// Distinguished Encoding Rules.
16+
#[default]
17+
Der,
18+
}

der/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ mod datetime;
337337
mod decode;
338338
mod encode;
339339
mod encode_ref;
340+
mod encoding_rules;
340341
mod error;
341342
mod header;
342343
mod length;
@@ -359,6 +360,7 @@ pub use crate::{
359360
decode::{Decode, DecodeOwned, DecodeValue},
360361
encode::{Encode, EncodeValue},
361362
encode_ref::{EncodeRef, EncodeValueRef},
363+
encoding_rules::EncodingRules,
362364
error::{Error, ErrorKind, Result},
363365
header::Header,
364366
length::{IndefiniteLength, Length},

der/src/reader.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,18 @@ pub(crate) mod slice;
88
pub(crate) use nested::NestedReader;
99

1010
use crate::{
11-
asn1::ContextSpecific, Decode, DecodeValue, Encode, Error, ErrorKind, FixedTag, Header, Length,
12-
Result, Tag, TagMode, TagNumber,
11+
asn1::ContextSpecific, Decode, DecodeValue, Encode, EncodingRules, Error, ErrorKind, FixedTag,
12+
Header, Length, Result, Tag, TagMode, TagNumber,
1313
};
1414

1515
#[cfg(feature = "alloc")]
1616
use alloc::vec::Vec;
1717

1818
/// Reader trait which reads DER-encoded input.
1919
pub trait Reader<'r>: Sized {
20+
/// Get the [`EncodingRules`] which should be applied when decoding the input.
21+
fn encoding_rules(&self) -> EncodingRules;
22+
2023
/// Get the length of the input.
2124
fn input_len(&self) -> Length;
2225

der/src/reader/nested.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Reader type for consuming nested TLV records within a DER document.
22
3-
use crate::{reader::Reader, Error, ErrorKind, Header, Length, Result};
3+
use crate::{reader::Reader, EncodingRules, Error, ErrorKind, Header, Length, Result};
44

55
/// Reader type used by [`Reader::read_nested`].
66
pub struct NestedReader<'i, R> {
@@ -51,6 +51,10 @@ impl<'i, 'r, R: Reader<'r>> NestedReader<'i, R> {
5151
}
5252

5353
impl<'i, 'r, R: Reader<'r>> Reader<'r> for NestedReader<'i, R> {
54+
fn encoding_rules(&self) -> EncodingRules {
55+
self.inner.encoding_rules()
56+
}
57+
5458
fn input_len(&self) -> Length {
5559
self.input_len
5660
}

der/src/reader/pem.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Streaming PEM reader.
22
33
use super::Reader;
4-
use crate::{Decode, Error, ErrorKind, Header, Length, Result};
4+
use crate::{Decode, EncodingRules, Error, ErrorKind, Header, Length, Result};
55
use core::cell::RefCell;
66

77
#[allow(clippy::arithmetic_side_effects)]
@@ -86,9 +86,7 @@ mod utils {
8686
fn as_slice(&self) -> &[u8] {
8787
&self.buf[self.pos..self.cap]
8888
}
89-
}
9089

91-
impl<'i> BufReader<'i> {
9290
pub fn peek_byte(&self) -> Option<u8> {
9391
let s = self.as_slice();
9492
s.first().copied()
@@ -130,6 +128,9 @@ pub struct PemReader<'i> {
130128
/// Inner PEM decoder wrapped in a BufReader.
131129
reader: RefCell<utils::BufReader<'i>>,
132130

131+
/// Encoding rules to apply when decoding the input.
132+
encoding_rules: EncodingRules,
133+
133134
/// Input length (in bytes after Base64 decoding).
134135
input_len: Length,
135136

@@ -148,6 +149,7 @@ impl<'i> PemReader<'i> {
148149

149150
Ok(Self {
150151
reader: RefCell::new(reader),
152+
encoding_rules: EncodingRules::default(),
151153
input_len,
152154
position: Length::ZERO,
153155
})
@@ -162,6 +164,10 @@ impl<'i> PemReader<'i> {
162164

163165
#[cfg(feature = "pem")]
164166
impl<'i> Reader<'i> for PemReader<'i> {
167+
fn encoding_rules(&self) -> EncodingRules {
168+
self.encoding_rules
169+
}
170+
165171
fn input_len(&self) -> Length {
166172
self.input_len
167173
}

der/src/reader/slice.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
//! Slice reader.
22
3-
use crate::{BytesRef, Decode, Error, ErrorKind, Header, Length, Reader, Result, Tag};
3+
use crate::{
4+
BytesRef, Decode, EncodingRules, Error, ErrorKind, Header, Length, Reader, Result, Tag,
5+
};
46

57
/// [`Reader`] which consumes an input byte slice.
68
#[derive(Clone, Debug)]
79
pub struct SliceReader<'a> {
810
/// Byte slice being decoded.
911
bytes: BytesRef<'a>,
1012

13+
/// Encoding rules to apply when decoding the input.
14+
encoding_rules: EncodingRules,
15+
1116
/// Did the decoding operation fail?
1217
failed: bool,
1318

@@ -20,6 +25,7 @@ impl<'a> SliceReader<'a> {
2025
pub fn new(bytes: &'a [u8]) -> Result<Self> {
2126
Ok(Self {
2227
bytes: BytesRef::new(bytes)?,
28+
encoding_rules: EncodingRules::default(),
2329
failed: false,
2430
position: Length::ZERO,
2531
})
@@ -57,6 +63,10 @@ impl<'a> SliceReader<'a> {
5763
}
5864

5965
impl<'a> Reader<'a> for SliceReader<'a> {
66+
fn encoding_rules(&self) -> EncodingRules {
67+
self.encoding_rules
68+
}
69+
6070
fn input_len(&self) -> Length {
6171
self.bytes.len()
6272
}

0 commit comments

Comments
 (0)