Skip to content

Commit bd84063

Browse files
authored
der: add ber feature (#1948)
1 parent 8396437 commit bd84063

File tree

11 files changed

+72
-27
lines changed

11 files changed

+72
-27
lines changed

cms/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ rust-version = "1.85"
1616

1717
[dependencies]
1818
const-oid = { version = "0.10", features = ["db"] }
19-
der = { version = "0.8.0-rc.7", features = ["alloc", "derive", "oid"] }
19+
der = { version = "0.8.0-rc.7", features = ["ber", "derive", "oid"] }
2020
spki = "0.8.0-rc.4"
2121
x509-cert = { version = "0.3.0-rc.0", default-features = false }
2222

der/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ derive = ["dep:der_derive"]
4141
oid = ["dep:const-oid"]
4242
pem = ["dep:pem-rfc7468", "alloc", "zeroize"]
4343
real = []
44+
ber = ["alloc"]
4445

4546
[package.metadata.docs.rs]
4647
all-features = true

der/src/asn1/octet_string.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ mod tests {
374374
}
375375

376376
#[test]
377-
#[cfg(feature = "alloc")]
377+
#[cfg(feature = "ber")]
378378
fn decode_ber() {
379379
use crate::{Decode, asn1::OctetString};
380380
use hex_literal::hex;
@@ -391,7 +391,7 @@ mod tests {
391391
}
392392

393393
#[test]
394-
#[cfg(feature = "alloc")]
394+
#[cfg(feature = "ber")]
395395
fn decode_context_specific_ber_explicit() {
396396
use crate::{
397397
EncodingRules, SliceReader, TagNumber,
@@ -422,7 +422,7 @@ mod tests {
422422
}
423423

424424
#[test]
425-
#[cfg(feature = "alloc")]
425+
#[cfg(feature = "ber")]
426426
fn decode_context_specific_ber_implicit() {
427427
use crate::{
428428
EncodingRules, SliceReader, TagNumber,

der/src/bytes.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,13 @@ impl<'a> arbitrary::Arbitrary<'a> for &'a BytesRef {
117117
#[cfg(feature = "alloc")]
118118
pub(crate) mod allocating {
119119
use super::BytesRef;
120+
#[cfg(feature = "ber")]
121+
use crate::{EncodingRules, length::indefinite::read_constructed_vec};
122+
120123
use crate::{
121-
DecodeValue, DerOrd, EncodeValue, EncodingRules, Error, Header, Length, Reader, Result,
122-
Tag, Writer, length::indefinite::read_constructed_vec,
124+
DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, Tag, Writer,
123125
};
126+
124127
use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
125128
use core::{borrow::Borrow, cmp::Ordering, ops::Deref};
126129

@@ -152,13 +155,17 @@ pub(crate) mod allocating {
152155
inner_tag: Tag,
153156
) -> Result<Self> {
154157
// Reassemble indefinite length string types
158+
#[cfg(feature = "ber")]
155159
if reader.encoding_rules() == EncodingRules::Ber
156160
&& header.length.is_indefinite()
157161
&& !inner_tag.is_constructed()
158162
{
159163
return Self::new(read_constructed_vec(reader, header.length, inner_tag)?);
160164
}
161165

166+
#[cfg(not(feature = "ber"))]
167+
let _ = inner_tag;
168+
162169
Self::decode_value(reader, header)
163170
}
164171
}

der/src/decode.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Trait definition for [`Decode`].
22
3-
use crate::{EncodingRules, Error, FixedTag, Header, Reader, SliceReader, reader::read_value};
3+
use crate::{Error, FixedTag, Header, Reader, SliceReader, reader::read_value};
4+
45
use core::marker::PhantomData;
56

67
#[cfg(feature = "pem")]
@@ -12,6 +13,9 @@ use crate::{ErrorKind, Length, Tag};
1213
#[cfg(feature = "alloc")]
1314
use alloc::boxed::Box;
1415

16+
#[cfg(feature = "ber")]
17+
use crate::EncodingRules;
18+
1519
/// Decoding trait.
1620
///
1721
/// This trait provides the core abstraction upon which all decoding operations
@@ -30,6 +34,7 @@ pub trait Decode<'a>: Sized + 'a {
3034
///
3135
/// Note that most usages should probably use [`Decode::from_der`]. This method allows some
3236
/// BER productions which are not allowed under DER.
37+
#[cfg(feature = "ber")]
3338
fn from_ber(bytes: &'a [u8]) -> Result<Self, Self::Error> {
3439
let mut reader = SliceReader::new_with_encoding_rules(bytes, EncodingRules::Ber)?;
3540
let result = Self::decode(&mut reader)?;

der/src/encoding_rules.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use core::{fmt, str::FromStr};
1313
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
1414
pub enum EncodingRules {
1515
/// Basic Encoding Rules.
16+
#[cfg(feature = "ber")]
1617
Ber,
1718

1819
/// Distinguished Encoding Rules.
@@ -25,6 +26,7 @@ impl FromStr for EncodingRules {
2526

2627
fn from_str(s: &str) -> Result<Self, Error> {
2728
match s {
29+
#[cfg(feature = "ber")]
2830
"ber" | "BER" => Ok(EncodingRules::Ber),
2931
"der" | "DER" => Ok(EncodingRules::Der),
3032
_ => Err(ErrorKind::EncodingRules.into()),
@@ -35,6 +37,7 @@ impl FromStr for EncodingRules {
3537
impl fmt::Display for EncodingRules {
3638
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3739
f.write_str(match self {
40+
#[cfg(feature = "ber")]
3841
Self::Ber => "BER",
3942
Self::Der => "DER",
4043
})
@@ -50,13 +53,16 @@ mod tests {
5053
#[test]
5154
fn display() {
5255
use alloc::string::ToString;
56+
#[cfg(feature = "ber")]
5357
assert_eq!(EncodingRules::Ber.to_string(), "BER");
5458
assert_eq!(EncodingRules::Der.to_string(), "DER");
5559
}
5660

5761
#[test]
5862
fn parse() {
63+
#[cfg(feature = "ber")]
5964
assert_eq!(EncodingRules::Ber, "ber".parse().unwrap());
65+
#[cfg(feature = "ber")]
6066
assert_eq!(EncodingRules::Ber, "BER".parse().unwrap());
6167
assert_eq!(EncodingRules::Der, "der".parse().unwrap());
6268
assert_eq!(EncodingRules::Der, "DER".parse().unwrap());

der/src/header.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//! ASN.1 DER headers.
22
3-
use crate::{
4-
Decode, DerOrd, Encode, EncodingRules, Error, ErrorKind, Length, Reader, Result, Tag, Writer,
5-
};
3+
#[cfg(feature = "ber")]
4+
use crate::EncodingRules;
5+
use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Tag, Writer};
6+
67
use core::cmp::Ordering;
78

89
/// ASN.1 DER headers: tag + length component of TLV-encoded values
@@ -46,11 +47,15 @@ impl<'a> Decode<'a> for Header {
4647
}
4748
})?;
4849

50+
#[cfg(feature = "ber")]
4951
if length.is_indefinite() && !is_constructed {
5052
debug_assert_eq!(reader.encoding_rules(), EncodingRules::Ber);
5153
return Err(reader.error(ErrorKind::IndefiniteLength));
5254
}
5355

56+
#[cfg(not(feature = "ber"))]
57+
debug_assert_eq!(is_constructed, tag.is_constructed());
58+
5459
Ok(Self { tag, length })
5560
}
5661
}

der/src/length.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
//! Length calculations for encoded ASN.1 DER values
22
3+
#[cfg(feature = "ber")]
34
pub(crate) mod indefinite;
45

5-
use self::indefinite::INDEFINITE_LENGTH_OCTET;
6+
/// Octet identifying an indefinite length as described in X.690 Section
7+
/// 8.1.3.6.1:
8+
///
9+
/// > The single octet shall have bit 8 set to one, and bits 7 to
10+
/// > 1 set to zero.
11+
pub(super) const INDEFINITE_LENGTH_OCTET: u8 = 0b10000000; // 0x80
12+
613
use crate::{Decode, DerOrd, Encode, EncodingRules, Error, ErrorKind, Reader, Result, Tag, Writer};
714
use core::{
815
cmp::Ordering,
@@ -20,6 +27,7 @@ pub struct Length {
2027
/// Flag bit which specifies whether the length was indeterminate when decoding ASN.1 BER.
2128
///
2229
/// This should always be false when working with DER.
30+
#[cfg(feature = "ber")]
2331
indefinite: bool,
2432
}
2533

@@ -34,6 +42,7 @@ impl Length {
3442
pub const MAX: Self = Self::new(u32::MAX);
3543

3644
/// Length of end-of-content octets (i.e. `00 00`).
45+
#[cfg(feature = "ber")]
3746
pub(crate) const EOC_LEN: Self = Self::new(2);
3847

3948
/// Maximum number of octets in a DER encoding of a [`Length`] using the
@@ -46,6 +55,8 @@ impl Length {
4655
pub const fn new(value: u32) -> Self {
4756
Self {
4857
inner: value,
58+
59+
#[cfg(feature = "ber")]
4960
indefinite: false,
5061
}
5162
}
@@ -68,6 +79,7 @@ impl Length {
6879
}
6980

7081
/// Was this length decoded from an indefinite length when decoding BER?
82+
#[cfg(feature = "ber")]
7183
pub(crate) const fn is_indefinite(self) -> bool {
7284
self.indefinite
7385
}
@@ -94,6 +106,7 @@ impl Length {
94106
/// Otherwise (as should always be the case with DER), the length is unchanged.
95107
///
96108
/// This method notably preserves the `indefinite` flag when performing arithmetic.
109+
#[cfg(feature = "ber")]
97110
pub(crate) fn sans_eoc(self) -> Self {
98111
if self.indefinite {
99112
// We expect EOC to be present when this is called.
@@ -104,6 +117,7 @@ impl Length {
104117
indefinite: true,
105118
}
106119
} else {
120+
// Return DER length
107121
self
108122
}
109123
}
@@ -250,6 +264,7 @@ impl<'a> Decode<'a> for Length {
250264
// Note: per X.690 Section 8.1.3.6.1 the byte 0x80 encodes indefinite lengths
251265
INDEFINITE_LENGTH_OCTET => match reader.encoding_rules() {
252266
// Indefinite lengths are allowed when decoding BER
267+
#[cfg(feature = "ber")]
253268
EncodingRules::Ber => indefinite::decode_indefinite_length(&mut reader.clone()),
254269
// Indefinite lengths are disallowed when decoding DER
255270
EncodingRules::Der => Err(reader.error(ErrorKind::IndefiniteLength)),
@@ -333,11 +348,12 @@ impl DerOrd for Length {
333348

334349
impl fmt::Debug for Length {
335350
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351+
#[cfg(feature = "ber")]
336352
if self.indefinite {
337-
write!(f, "Length({self} [indefinite])")
338-
} else {
339-
f.debug_tuple("Length").field(&self.inner).finish()
353+
return write!(f, "Length([indefinite])");
340354
}
355+
356+
f.debug_tuple("Length").field(&self.inner).finish()
341357
}
342358
}
343359

der/src/length/indefinite.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,6 @@ use crate::Tag;
2727
#[cfg(feature = "alloc")]
2828
use alloc::vec::Vec;
2929

30-
/// Octet identifying an indefinite length as described in X.690 Section
31-
/// 8.1.3.6.1:
32-
///
33-
/// > The single octet shall have bit 8 set to one, and bits 7 to
34-
/// > 1 set to zero.
35-
pub(super) const INDEFINITE_LENGTH_OCTET: u8 = 0b10000000; // 0x80
36-
3730
/// The end-of-contents octets can be considered as the encoding of a value whose tag is
3831
/// universal class, whose form is primitive, whose number of the tag is zero, and whose
3932
/// contents are absent.

der/src/reader.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ mod position;
99

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

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

18+
#[cfg(feature = "ber")]
19+
use crate::length::indefinite::read_eoc;
20+
1821
/// Reader trait which reads DER-encoded input.
1922
pub trait Reader<'r>: Clone {
2023
/// Get the [`EncodingRules`] which should be applied when decoding the input.
@@ -207,16 +210,22 @@ pub trait Reader<'r>: Clone {
207210
///
208211
/// This calls the provided function `f` with a nested reader created using
209212
/// [`Reader::read_nested`].
210-
pub(crate) fn read_value<'r, R, T, F, E>(reader: &mut R, mut header: Header, f: F) -> Result<T, E>
213+
pub(crate) fn read_value<'r, R, T, F, E>(reader: &mut R, header: Header, f: F) -> Result<T, E>
211214
where
212215
R: Reader<'r>,
213216
E: From<Error>,
214217
F: FnOnce(&mut R, Header) -> Result<T, E>,
215218
{
216-
header.length = header.length.sans_eoc();
219+
#[cfg(feature = "ber")]
220+
let header = Header {
221+
length: header.length.sans_eoc(),
222+
tag: header.tag,
223+
};
224+
217225
let ret = reader.read_nested(header.length, |r| f(r, header))?;
218226

219227
// Consume EOC marker if the length is indefinite.
228+
#[cfg(feature = "ber")]
220229
if header.length.is_indefinite() {
221230
read_eoc(reader)?;
222231
}

0 commit comments

Comments
 (0)