From 2f8979a6d21ac1d1dcf6404e6fe682d8c363e3ef Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Mon, 27 Sep 2021 08:56:35 -0700 Subject: Upgrade rust/crates/der-parser to 6.0.0 Test: make Change-Id: I511b6dca60ee1c6f3fb13b502b23ecec94bb25f1 --- .cargo_vcs_info.json | 2 +- Android.bp | 5 +- CHANGELOG.md | 36 ++- Cargo.toml | 26 +- Cargo.toml.orig | 14 +- METADATA | 8 +- README.md | 8 +- cargo2android.json | 2 +- patches/bitvec_dep.patch | 44 ---- src/ber/ber.rs | 96 +++---- src/ber/mod.rs | 5 + src/ber/parser.rs | 44 ++-- src/ber/print.rs | 15 +- src/ber/serialize.rs | 12 +- src/der/mod.rs | 4 + src/der/parser.rs | 29 +- src/error.rs | 10 +- src/lib.rs | 43 ++- src/macros.rs | 668 ----------------------------------------------- src/oid.rs | 26 +- tests/ber_parser.rs | 31 ++- tests/constructed.rs | 137 +++++----- tests/der_parser.rs | 106 ++++---- tests/macros.rs | 129 --------- tests/oid.rs | 1 + tests/primitive.rs | 27 +- 26 files changed, 364 insertions(+), 1164 deletions(-) delete mode 100644 patches/bitvec_dep.patch delete mode 100644 src/macros.rs delete mode 100644 tests/macros.rs diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index d5c766e..4eaee56 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "c8adf28076c11651618bcf414a20ecd0bd896315" + "sha1": "7b9b5b84387d7c4707b1abc7a13faba515b7c08e" } } diff --git a/Android.bp b/Android.bp index bd24618..55296a0 100644 --- a/Android.bp +++ b/Android.bp @@ -1,8 +1,6 @@ // This file is generated by cargo2android.py --config cargo2android.json. // Do not modify this file as changes will be overridden on upgrade. - - package { default_applicable_licenses: ["external_rust_crates_der-parser_license"], } @@ -43,11 +41,14 @@ rust_library { name: "libder_parser", host_supported: true, crate_name: "der_parser", + cargo_env_compat: true, + cargo_pkg_version: "6.0.0", srcs: ["src/lib.rs"], edition: "2018", features: [ "bigint", "num-bigint", + "std", ], rustlibs: [ "libnom", diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bc3295..2fa3705 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,21 +8,39 @@ ### Thanks -## 5.1.2 +## 6.0.0 -### Changed/Fixed - -- Make `BerError` Copy + Clone -- Fix clippy warnings (rustc 1.54) - -## 5.1.1 +This release has several major changes: +- upgrade to nom 7 +- add support for `no_std` +- remove all macros +- update MSRV to 1.48 ### Changed/Fixed +- Do not attempt to parse PRIVATE object contents (closes #48) - BER: raise error if using Indefinite length and not constructed +- Fix `oid!` macro to be independant of `der_parser` crate name and path (#46) +- Simplify `der-oid-macro`, do not depend on `nom` - Fix `INTEGER` signed/unsigned parsing (#49) -- Fix INTEGER signed/unsigned parsing for bigint/biguint (#49) -- Doc: clarify documentation for parsing integers (#49) +- Change `as_bigint()` and `as_uint()` to return a `Result` +- Remove deprecated functions + +### Added + +- Added support for `no_std` (#50) +- Make `BerError` Copy + Clone (#51) +- Add feature 'bitvec' for `.as_bitslice()` methods + +### Removed + +- Remove all macros + +### Thanks + +- @yoguorui for `no_std` support +- @SergioBenitez for `BerError` traits +- @lilyball for `INTEGER` parsing ## 5.1.0 diff --git a/Cargo.toml b/Cargo.toml index 9715d20..55418dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,17 +3,16 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "der-parser" -version = "5.1.2" +version = "6.0.0" authors = ["Pierre Chifflier "] include = ["LICENSE-*", "CHANGELOG.md", "README.md", "UPGRADING.md", ".gitignore", "Cargo.toml", "bench/*.rs", "src/*.rs", "src/ber/*.rs", "src/der/*.rs", "tests/*.rs", "der-oid-macro/Cargo.toml", "der-oid-macro/src/*.rs"] description = "Parser/encoder for ASN.1 BER/DER data" @@ -26,15 +25,19 @@ repository = "https://github.com/rusticata/der-parser.git" [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] +[dependencies.bitvec] +version = "0.22" +optional = true + [dependencies.cookie-factory] version = "0.3.0" optional = true [dependencies.der-oid-macro] -version = "0.4" +version = "0.5" [dependencies.nom] -version = "6.0" +version = "7.0" [dependencies.num-bigint] version = "0.4" @@ -44,7 +47,7 @@ optional = true version = "0.2" [dependencies.rusticata-macros] -version = "3.0.1" +version = "4.0" [dev-dependencies.hex-literal] version = "0.3" @@ -56,6 +59,7 @@ version = "1.0" [features] bigint = ["num-bigint"] -default = [] -serialize = ["cookie-factory"] +default = ["std"] +serialize = ["std", "cookie-factory"] +std = [] unstable = [] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index e2a6c3f..69f5242 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -5,7 +5,7 @@ keywords = ["BER","DER","ASN1","parser","nom"] homepage = "https://github.com/rusticata/der-parser" repository = "https://github.com/rusticata/der-parser.git" name = "der-parser" -version = "5.1.2" +version = "6.0.0" authors = ["Pierre Chifflier "] categories = ["parser-implementations"] readme = "README.md" @@ -32,19 +32,21 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] +bitvec = { version="0.22", optional=true } cookie-factory = { version="0.3.0", optional=true } -nom = "6.0" -rusticata-macros = "3.0.1" +nom = "7.0" +rusticata-macros = "4.0" num-traits = "0.2" num-bigint = { version = "0.4", optional = true } -der-oid-macro = { version = "0.4", path = "./der-oid-macro" } +der-oid-macro = { version = "0.5", path = "./der-oid-macro" } [features] -default = [] +default = ["std"] bigint = ["num-bigint"] -serialize = ["cookie-factory"] +serialize = ["std", "cookie-factory"] unstable = [] +std = [] [dev-dependencies] hex-literal = "0.3" diff --git a/METADATA b/METADATA index c3a9cdb..c30f813 100644 --- a/METADATA +++ b/METADATA @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/der-parser/der-parser-5.1.2.crate" + value: "https://static.crates.io/crates/der-parser/der-parser-6.0.0.crate" } - version: "5.1.2" + version: "6.0.0" license_type: NOTICE last_upgrade_date { year: 2021 - month: 8 - day: 9 + month: 9 + day: 27 } } diff --git a/README.md b/README.md index 03f33bc..42f3ee4 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ [![docs.rs](https://docs.rs/der-parser/badge.svg)](https://docs.rs/der-parser) [![crates.io](https://img.shields.io/crates/v/der-parser.svg)](https://crates.io/crates/der-parser) [![Download numbers](https://img.shields.io/crates/d/der-parser.svg)](https://crates.io/crates/der-parser) -[![dependency status](https://deps.rs/crate/der-parser/5.1.2/status.svg)](https://deps.rs/crate/der-parser/5.1.2) +[![dependency status](https://deps.rs/crate/der-parser/5.0.0/status.svg)](https://deps.rs/crate/der-parser/5.0.1) [![Github CI](https://github.com/rusticata/der-parser/workflows/Continuous%20integration/badge.svg)](https://github.com/rusticata/der-parser/actions) -[![Minimum rustc version](https://img.shields.io/badge/rustc-1.44.0+-lightgray.svg)](#rust-version-requirements) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.48.0+-lightgray.svg)](#rust-version-requirements) # BER/DER Parser @@ -174,7 +174,7 @@ let (_, object) = parse_ber_integer(data).expect("parsing failed"); assert_eq!(object.as_u64(), Ok(65537)); #[cfg(feature = "bigint")] -assert_eq!(object.as_bigint(), Some(65537.into())) +assert_eq!(object.as_bigint(), Ok(65537.into())) ``` Access to the raw value is possible using the `as_slice` method. @@ -198,7 +198,7 @@ Some parsing tools (for ex for tagged objects) are available in different forms: ## Rust version requirements -The 5.0 series of `der-parser` requires **Rustc version 1.44 or greater**, based on nom 6 +The 6.0 series of `der-parser` requires **Rustc version 1.48 or greater**, based on nom 7 dependencies. # Serialization diff --git a/cargo2android.json b/cargo2android.json index fd3c228..1a78574 100644 --- a/cargo2android.json +++ b/cargo2android.json @@ -1,6 +1,6 @@ { "device": true, - "features": "bigint", + "features": "bigint,std", "run": true } diff --git a/patches/bitvec_dep.patch b/patches/bitvec_dep.patch deleted file mode 100644 index 40bad0b..0000000 --- a/patches/bitvec_dep.patch +++ /dev/null @@ -1,44 +0,0 @@ -diff --git a/src/ber/ber.rs b/src/ber/ber.rs -index 6f6741d..e89b6c8 100644 ---- a/src/ber/ber.rs -+++ b/src/ber/ber.rs -@@ -9,6 +9,7 @@ use core::convert::From; - use crate::ber::integer::*; - use crate::error::BerError; - use crate::oid::Oid; -+#[cfg(not(any(target_os = "android", target_os = "linux")))] - use nom::bitvec::{order::Msb0, slice::BitSlice}; - use rusticata_macros::newtype_enum; - use std::convert::AsRef; -@@ -479,6 +480,7 @@ impl<'a> BerObject<'a> { - } - - /// Constructs a shared `&BitSlice` reference over the object data, if available as slice. -+ #[cfg(not(any(target_os = "android", target_os = "linux")))] - pub fn as_bitslice(&self) -> Result<&BitSlice, BerError> { - self.content.as_bitslice() - } -@@ -678,6 +680,7 @@ impl<'a> BerObjectContent<'a> { - } - - /// Constructs a shared `&BitSlice` reference over the object data, if available as slice. -+ #[cfg(not(any(target_os = "android", target_os = "linux")))] - pub fn as_bitslice(&self) -> Result<&BitSlice, BerError> { - self.as_slice() - .and_then(|s| BitSlice::::from_slice(s).ok_or(BerError::BerValueError)) -@@ -908,6 +911,7 @@ impl<'a> BitStringObject<'a> { - } - - /// Constructs a shared `&BitSlice` reference over the object data. -+ #[cfg(not(any(target_os = "android", target_os = "linux")))] - pub fn as_bitslice(&self) -> Option<&BitSlice> { - BitSlice::::from_slice(&self.data) - } -@@ -981,6 +985,7 @@ mod tests { - } - - #[test] -+ #[cfg(not(any(target_os = "android", target_os = "linux")))] - fn test_der_bitslice() { - let obj = BitStringObject { - data: &[0x0f, 0x00, 0x40], diff --git a/src/ber/ber.rs b/src/ber/ber.rs index e7bd384..47d5069 100644 --- a/src/ber/ber.rs +++ b/src/ber/ber.rs @@ -2,15 +2,17 @@ use crate::ber::bitstring_to_u64; use crate::ber::integer::*; use crate::error::BerError; use crate::oid::Oid; -#[cfg(not(any(target_os = "android", target_os = "linux")))] -use nom::bitvec::{order::Msb0, slice::BitSlice}; +use alloc::borrow::ToOwned; +use alloc::boxed::Box; +use alloc::vec::Vec; +#[cfg(feature = "bitvec")] +use bitvec::{order::Msb0, slice::BitSlice}; +use core::convert::AsRef; +use core::convert::From; +use core::convert::TryFrom; +use core::fmt; +use core::ops::Index; use rusticata_macros::newtype_enum; -use std::convert::AsRef; -use std::convert::From; -use std::convert::TryFrom; -use std::fmt; -use std::ops::Index; -use std::vec::Vec; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct BerClassFromIntError(pub(crate) ()); @@ -183,9 +185,11 @@ pub enum BerObjectContent<'a> { Optional(Option>>), /// Tagged object (EXPLICIT): class, tag and content of inner object Tagged(BerClass, BerTag, Box>), + /// Private + Private(BerObjectHeader<'a>, &'a [u8]), /// Unknown object: object tag (copied from header), and raw content - Unknown(BerTag, &'a [u8]), + Unknown(BerClass, BerTag, &'a [u8]), } impl fmt::Display for BerClass { @@ -391,15 +395,6 @@ impl<'a> BerObject<'a> { BerObject::from_obj(BerObjectContent::Set(l)) } - /// Build a BER header from this object content - #[deprecated( - since = "0.5.0", - note = "please use `obj.header` or `obj.header.clone()` instead" - )] - pub fn to_header(&self) -> BerObjectHeader { - self.header.clone() - } - /// Attempt to read a signed integer value from DER object. /// /// This can fail if the object is not an integer, or if it is too large. @@ -519,7 +514,7 @@ impl<'a> BerObject<'a> { } /// Constructs a shared `&BitSlice` reference over the object data, if available as slice. - #[cfg(not(any(target_os = "android", target_os = "linux")))] + #[cfg(feature = "bitvec")] pub fn as_bitslice(&self) -> Result<&BitSlice, BerError> { self.content.as_bitslice() } @@ -595,16 +590,6 @@ impl<'a> From> for BerObject<'a> { } } -/// Replacement function for Option.xor (>= 1.37) -#[inline] -pub(crate) fn xor_option(opta: Option, optb: Option) -> Option { - match (opta, optb) { - (Some(a), None) => Some(a), - (None, Some(b)) => Some(b), - _ => None, - } -} - /// Compare two BER headers. `len` fields are compared only if both objects have it set (same for `raw_tag`) impl<'a> PartialEq> for BerObjectHeader<'a> { fn eq(&self, other: &BerObjectHeader) -> bool { @@ -620,7 +605,7 @@ impl<'a> PartialEq> for BerObjectHeader<'a> { } && { // it tag is present for both, compare it - if xor_option(self.raw_tag, other.raw_tag).is_none() { + if self.raw_tag.xor(other.raw_tag).is_none() { self.raw_tag == other.raw_tag } else { true @@ -735,7 +720,7 @@ impl<'a> BerObjectContent<'a> { } BerObjectContent::BitString(ignored_bits, data) => { bitstring_to_u64(*ignored_bits as usize, data).and_then(|x| { - if x > u64::from(std::u32::MAX) { + if x > u64::from(core::u32::MAX) { Err(BerError::IntegerTooLarge) } else { Ok(x as u32) @@ -743,7 +728,7 @@ impl<'a> BerObjectContent<'a> { }) } BerObjectContent::Enum(i) => { - if *i > u64::from(std::u32::MAX) { + if *i > u64::from(core::u32::MAX) { Err(BerError::IntegerTooLarge) } else { Ok(*i as u32) @@ -802,10 +787,10 @@ impl<'a> BerObjectContent<'a> { } /// Constructs a shared `&BitSlice` reference over the object data, if available as slice. - #[cfg(not(any(target_os = "android", target_os = "linux")))] + #[cfg(feature = "bitvec")] pub fn as_bitslice(&self) -> Result<&BitSlice, BerError> { self.as_slice() - .and_then(|s| BitSlice::::from_slice(s).ok_or(BerError::BerValueError)) + .and_then(|s| BitSlice::::from_slice(s).map_err(|_| BerError::BerValueError)) } pub fn as_sequence(&self) -> Result<&Vec>, BerError> { @@ -842,7 +827,8 @@ impl<'a> BerObjectContent<'a> { BerObjectContent::ObjectDescriptor(s) | BerObjectContent::GraphicString(s) | BerObjectContent::GeneralString(s) | - BerObjectContent::Unknown(_,s) => Ok(s), + BerObjectContent::Unknown(_, _,s) | + BerObjectContent::Private(_,s) => Ok(s), _ => Err(BerError::BerTypeError), } } @@ -890,7 +876,8 @@ impl<'a> BerObjectContent<'a> { BerObjectContent::GraphicString(_) => BerTag::GraphicString, BerObjectContent::GeneralString(_) => BerTag::GeneralString, BerObjectContent::Tagged(_,x,_) | - BerObjectContent::Unknown(x,_) => *x, + BerObjectContent::Unknown(_, x,_) => *x, + &BerObjectContent::Private(ref hdr, _) => hdr.tag, BerObjectContent::Optional(Some(obj)) => obj.content.tag(), BerObjectContent::Optional(None) => BerTag(0x00), // XXX invalid ! } @@ -917,12 +904,12 @@ impl<'a> BerObject<'a> { /// /// let (_, object) = parse_ber_integer(data).expect("parsing failed"); /// # #[cfg(feature = "bigint")] - /// assert_eq!(object.as_bigint(), Some(65537.into())) + /// assert_eq!(object.as_bigint(), Ok(65537.into())) /// ``` - pub fn as_bigint(&self) -> Option { + pub fn as_bigint(&self) -> Result { match self.content { - BerObjectContent::Integer(s) => Some(BigInt::from_signed_bytes_be(s)), - _ => None, + BerObjectContent::Integer(s) => Ok(BigInt::from_signed_bytes_be(s)), + _ => Err(BerError::InvalidTag), } } @@ -939,17 +926,17 @@ impl<'a> BerObject<'a> { /// /// let (_, object) = parse_ber_integer(data).expect("parsing failed"); /// # #[cfg(feature = "bigint")] - /// assert_eq!(object.as_biguint(), Some(65537_u32.into())) + /// assert_eq!(object.as_biguint(), Ok(65537_u32.into())) /// ``` - pub fn as_biguint(&self) -> Option { + pub fn as_biguint(&self) -> Result { match self.content { BerObjectContent::Integer(s) => { if is_highest_bit_set(s) { - return None; + return Err(BerError::IntegerNegative); } - Some(BigUint::from_bytes_be(s)) + Ok(BigUint::from_bytes_be(s)) } - _ => None, + _ => Err(BerError::InvalidTag), } } } @@ -1066,9 +1053,9 @@ impl<'a> BitStringObject<'a> { } /// Constructs a shared `&BitSlice` reference over the object data. - #[cfg(not(any(target_os = "android", target_os = "linux")))] + #[cfg(feature = "bitvec")] pub fn as_bitslice(&self) -> Option<&BitSlice> { - BitSlice::::from_slice(self.data) + BitSlice::::from_slice(self.data).ok() } } @@ -1138,17 +1125,18 @@ mod tests { assert!(obj.is_set(17)); } + #[cfg(feature = "bitvec")] #[test] - #[cfg(not(any(target_os = "android", target_os = "linux")))] fn test_der_bitslice() { + use std::string::String; let obj = BitStringObject { data: &[0x0f, 0x00, 0x40], }; let slice = obj.as_bitslice().expect("as_bitslice"); - assert_eq!(slice.get(0), Some(&false)); - assert_eq!(slice.get(7), Some(&true)); - assert_eq!(slice.get(9), Some(&false)); - assert_eq!(slice.get(17), Some(&true)); + assert_eq!(slice.get(0).as_deref(), Some(&false)); + assert_eq!(slice.get(7).as_deref(), Some(&true)); + assert_eq!(slice.get(9).as_deref(), Some(&false)); + assert_eq!(slice.get(17).as_deref(), Some(&true)); let s = slice.iter().fold(String::with_capacity(24), |mut acc, b| { acc += if *b { "1" } else { "0" }; acc @@ -1172,7 +1160,7 @@ mod tests { let obj = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); let expected = ::num_bigint::BigInt::from(0x10001); - assert_eq!(obj.as_bigint(), Some(expected)); + assert_eq!(obj.as_bigint(), Ok(expected)); } #[cfg(feature = "bigint")] @@ -1181,6 +1169,6 @@ mod tests { let obj = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); let expected = ::num_bigint::BigUint::from(0x10001_u32); - assert_eq!(obj.as_biguint(), Some(expected)); + assert_eq!(obj.as_biguint(), Ok(expected)); } } diff --git a/src/ber/mod.rs b/src/ber/mod.rs index f2fa5f9..c674d93 100644 --- a/src/ber/mod.rs +++ b/src/ber/mod.rs @@ -62,3 +62,8 @@ pub use crate::ber::print::*; #[cfg(feature = "serialize")] pub use crate::ber::serialize::*; pub use crate::ber::tagged::*; + +use alloc::borrow::Cow; +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::convert::{Into, TryFrom}; diff --git a/src/ber/parser.rs b/src/ber/parser.rs index ace4937..81ccef8 100644 --- a/src/ber/parser.rs +++ b/src/ber/parser.rs @@ -7,8 +7,6 @@ use nom::multi::{many0, many_till}; use nom::number::streaming::be_u8; use nom::{Err, Needed, Offset}; use rusticata_macros::{combinator::parse_hex_to_u64, custom_check}; -use std::borrow::Cow; -use std::convert::{Into, TryFrom}; /// Default maximum recursion limit pub const MAX_RECURSION: usize = 50; @@ -280,7 +278,7 @@ fn ber_read_content_enum(i: &[u8], len: usize) -> BerResult { fn ber_read_content_utf8string(i: &[u8], len: usize) -> BerResult { let (i, bytes) = take(len)(i)?; - let s = std::str::from_utf8(bytes) + let s = core::str::from_utf8(bytes) .map_err(|_| Err::Error(BerError::StringInvalidCharset)) .map(|s| BerObjectContent::UTF8String(s))?; Ok((i, s)) @@ -345,7 +343,7 @@ fn ber_read_content_numericstring<'a>(i: &'a [u8], len: usize) -> BerResult(i: &'a [u8], len: usize) -> BerResult( if !bytes.iter().all(is_printable) { return Err(Err::Error(BerError::StringInvalidCharset)); } - let s = std::str::from_utf8(bytes) + let s = core::str::from_utf8(bytes) .map_err(|_| Err::Error(BerError::StringInvalidCharset)) .map(|s| BerObjectContent::PrintableString(s))?; Ok((i, s)) @@ -416,7 +414,7 @@ fn ber_read_content_ia5string<'a>(i: &'a [u8], len: usize) -> BerResult(i: &'a [u8], len: usize) -> BerResult( if !bytes.iter().all(is_visible) { return Err(Err::Error(BerError::StringInvalidCharset)); } - let s = std::str::from_utf8(bytes) + let s = core::str::from_utf8(bytes) .map_err(|_| Err::Error(BerError::StringInvalidCharset)) .map(|s| BerObjectContent::GeneralizedTime(s))?; Ok((i, s)) @@ -995,22 +993,6 @@ where }))(i) } -/// Parse an optional tagged object, applying function to get content -/// -/// This function is deprecated, use -/// [parse_ber_explicit_optional](fn.parse_ber_explicit_optional.html) instead. -#[deprecated( - since = "5.0.0", - note = "Please use `parse_ber_explicit_optional` instead" -)] -#[inline] -pub fn parse_ber_explicit(i: &[u8], tag: BerTag, f: F) -> BerResult -where - F: Fn(&[u8]) -> BerResult, -{ - parse_ber_explicit_optional(i, tag, f) -} - /// Parse an implicit tagged object, applying function to read content /// /// Note: unlike explicit tagged functions, the callback must be a *content* parsing function, @@ -1184,10 +1166,16 @@ pub fn parse_ber_recursive(i: &[u8], max_depth: usize) -> BerResult { custom_check!(i, l > MAX_OBJECT_SIZE, BerError::InvalidLength)?; } match hdr.class { - BerClass::Universal | BerClass::Private => (), + BerClass::Universal => (), + BerClass::Private => { + let (rem, content) = ber_get_object_content(rem, &hdr, max_depth)?; + let content = BerObjectContent::Private(hdr.clone(), content); + let obj = BerObject::from_header_and_content(hdr, content); + return Ok((rem, obj)); + } _ => { let (rem, content) = ber_get_object_content(rem, &hdr, max_depth)?; - let content = BerObjectContent::Unknown(hdr.tag, content); + let content = BerObjectContent::Unknown(hdr.class, hdr.tag, content); let obj = BerObject::from_header_and_content(hdr, content); return Ok((rem, obj)); } @@ -1196,7 +1184,7 @@ pub fn parse_ber_recursive(i: &[u8], max_depth: usize) -> BerResult { Ok((rem, content)) => Ok((rem, BerObject::from_header_and_content(hdr, content))), Err(Err::Error(BerError::UnknownTag)) => { let (rem, content) = ber_get_object_content(rem, &hdr, max_depth)?; - let content = BerObjectContent::Unknown(hdr.tag, content); + let content = BerObjectContent::Unknown(hdr.class, hdr.tag, content); let obj = BerObject::from_header_and_content(hdr, content); Ok((rem, obj)) } diff --git a/src/ber/print.rs b/src/ber/print.rs index b3ae221..e80eb5e 100644 --- a/src/ber/print.rs +++ b/src/ber/print.rs @@ -1,8 +1,10 @@ use crate::ber::BitStringObject; use crate::ber::{BerObject, BerObjectContent, BerTag}; -use std::fmt; -use std::iter::FromIterator; -use std::str; +use alloc::string::String; +use alloc::vec::Vec; +use core::fmt; +use core::iter::FromIterator; +use core::str; use rusticata_macros::debug; @@ -77,7 +79,7 @@ impl<'a> fmt::Debug for PrettyBer<'a> { fn print_utf32_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result { let chars: Option> = s .chunks_exact(4) - .map(|a| std::char::from_u32(u32::from_be_bytes([a[0], a[1], a[2], a[3]]))) + .map(|a| core::char::from_u32(u32::from_be_bytes([a[0], a[1], a[2], a[3]]))) .collect(); match chars { @@ -116,6 +118,9 @@ impl<'a> fmt::Debug for PrettyBer<'a> { None => writeln!(f, "NONE"), } } + BerObjectContent::Private(ref hdr, bytes) => { + writeln!(f, "Private(c:{} s:{} t:{}): {:?}", hdr.class, hdr.structured, hdr.tag.0, debug::HexSlice(bytes)) + }, BerObjectContent::Tagged(class, tag, ref obj) => { writeln!(f, "ContextSpecific [{} {}] {{", class, tag)?; write!(f, "{:?}", self.next_indent(obj))?; @@ -138,7 +143,7 @@ impl<'a> fmt::Debug for PrettyBer<'a> { writeln!(f, "]")?; Ok(()) }, - BerObjectContent::Unknown(tag,o) => writeln!(f, "Unknown({:?},{:x?})", tag, o), + BerObjectContent::Unknown(class, tag,o) => writeln!(f, "Unknown({:?},{:?},{:x?})", class, tag, o), } } } diff --git a/src/ber/serialize.rs b/src/ber/serialize.rs index 7ffedc2..8c82e29 100644 --- a/src/ber/serialize.rs +++ b/src/ber/serialize.rs @@ -1,3 +1,4 @@ +#![cfg(feature = "std")] use crate::ber::*; use crate::oid::Oid; use cookie_factory::bytes::be_u8; @@ -8,8 +9,6 @@ use cookie_factory::sequence::tuple; use cookie_factory::{GenError, SerializeFn}; use std::io::Write; -// we do not use .copied() for compatibility with 1.34 -#[allow(clippy::map_clone)] fn encode_length<'a, W: Write + 'a, Len: Into>(len: Len) -> impl SerializeFn + 'a { let l = len.into(); move |out| { @@ -23,7 +22,7 @@ fn encode_length<'a, W: Write + 'a, Len: Into>(len: Len) -> impl Serial let v: Vec = sz .to_be_bytes() .iter() - .map(|&x| x) + .cloned() .skip_while(|&b| b == 0) .collect(); let b0 = 0b1000_0000 | (v.len() as u8); @@ -108,8 +107,6 @@ pub fn ber_encode_tagged_implicit<'a, W: Write + Default + AsRef<[u8]> + 'a>( } } -// we do not use .copied() for compatibility with 1.34 -#[allow(clippy::map_clone)] fn ber_encode_object_content<'a, W: Write + Default + AsRef<[u8]> + 'a>( c: &'a BerObjectContent, ) -> impl SerializeFn + 'a { @@ -129,7 +126,7 @@ fn ber_encode_object_content<'a, W: Write + Default + AsRef<[u8]> + 'a>( let v: Vec = i .to_be_bytes() .iter() - .map(|&x| x) + .cloned() .skip_while(|&b| b == 0) .collect(); slice(v)(out) @@ -158,12 +155,13 @@ fn ber_encode_object_content<'a, W: Write + Default + AsRef<[u8]> + 'a>( None => slice(&[])(out), // XXX encode NOP ? } } + BerObjectContent::Private(_hdr, bytes) => slice(bytes)(out), BerObjectContent::Tagged(_class, _tag, inner) => { // directly encode inner object // XXX wrong, we should wrap it! ber_encode_object(inner)(out) } - BerObjectContent::Unknown(_tag, s) => slice(s)(out), + BerObjectContent::Unknown(_, _, s) => slice(s)(out), } } diff --git a/src/der/mod.rs b/src/der/mod.rs index aaa64c5..bad3f23 100644 --- a/src/der/mod.rs +++ b/src/der/mod.rs @@ -62,6 +62,10 @@ pub use crate::der::multi::*; pub use crate::der::parser::*; pub use crate::der::tagged::*; +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::convert::{Into, TryFrom}; + /// DER Object class of tag (same as `BerClass`) pub type DerClass = BerClass; diff --git a/src/der/parser.rs b/src/der/parser.rs index bb5ea0f..04b4b23 100644 --- a/src/der/parser.rs +++ b/src/der/parser.rs @@ -5,7 +5,6 @@ use nom::bytes::streaming::take; use nom::number::streaming::be_u8; use nom::{Err, Needed}; use rusticata_macros::custom_check; -use std::convert::{Into, TryFrom}; /// Parse DER object recursively /// @@ -317,22 +316,6 @@ where parse_ber_explicit_optional(i, tag, f) } -/// Parse an optional tagged object, applying function to get content -/// -/// This function is deprecated, use -/// [parse_der_explicit_optional](fn.parse_der_explicit_optional.html) instead. -#[deprecated( - since = "4.1.0", - note = "Please use `parse_der_explicit_optional` instead" -)] -#[inline] -pub fn parse_der_explicit(i: &[u8], tag: DerTag, f: F) -> BerResult -where - F: Fn(&[u8]) -> BerResult, -{ - parse_der_explicit_optional(i, tag, f) -} - /// Parse an implicit tagged object, applying function to read content /// /// Note: unlike explicit tagged functions, the callback must be a *content* parsing function, @@ -575,10 +558,16 @@ fn der_read_element_content_recursive<'a>( max_depth: usize, ) -> DerResult<'a> { match hdr.class { - DerClass::Universal | DerClass::Private => (), + BerClass::Universal => (), + BerClass::Private => { + let (rem, content) = ber_get_object_content(i, &hdr, max_depth)?; + let content = BerObjectContent::Private(hdr.clone(), content); + let obj = BerObject::from_header_and_content(hdr, content); + return Ok((rem, obj)); + } _ => { let (i, content) = ber_get_object_content(i, &hdr, max_depth)?; - let content = DerObjectContent::Unknown(hdr.tag, content); + let content = DerObjectContent::Unknown(hdr.class, hdr.tag, content); let obj = DerObject::from_header_and_content(hdr, content); return Ok((i, obj)); } @@ -587,7 +576,7 @@ fn der_read_element_content_recursive<'a>( Ok((rem, content)) => Ok((rem, DerObject::from_header_and_content(hdr, content))), Err(Err::Error(BerError::UnknownTag)) => { let (rem, content) = ber_get_object_content(i, &hdr, max_depth)?; - let content = DerObjectContent::Unknown(hdr.tag, content); + let content = DerObjectContent::Unknown(hdr.class, hdr.tag, content); let obj = DerObject::from_header_and_content(hdr, content); Ok((rem, obj)) } diff --git a/src/error.rs b/src/error.rs index 803bdee..8a496a8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,10 +2,9 @@ use crate::ber::BerObject; use crate::der::DerObject; +use alloc::fmt; use nom::error::{ErrorKind, FromExternalError, ParseError}; use nom::IResult; -use std::error::Error; -use std::fmt; /// Holds the result of parsing functions /// @@ -97,11 +96,14 @@ impl fmt::Display for BerError { } } -impl Error for BerError {} +#[cfg(feature = "std")] +impl std::error::Error for BerError {} -#[cfg(test)] +#[cfg(all(test, feature = "std"))] mod tests { use super::*; + use std::boxed::Box; + use std::error::Error; #[test] fn test_unwrap_bererror() { diff --git a/src/lib.rs b/src/lib.rs index 926a036..a5f6e2e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,9 +3,9 @@ //! [![docs.rs](https://docs.rs/der-parser/badge.svg)](https://docs.rs/der-parser) //! [![crates.io](https://img.shields.io/crates/v/der-parser.svg)](https://crates.io/crates/der-parser) //! [![Download numbers](https://img.shields.io/crates/d/der-parser.svg)](https://crates.io/crates/der-parser) -//! [![dependency status](https://deps.rs/crate/der-parser/5.1.2/status.svg)](https://deps.rs/crate/der-parser/5.1.2) +//! [![dependency status](https://deps.rs/crate/der-parser/5.0.0/status.svg)](https://deps.rs/crate/der-parser/5.0.1) //! [![Github CI](https://github.com/rusticata/der-parser/workflows/Continuous%20integration/badge.svg)](https://github.com/rusticata/der-parser/actions) -//! [![Minimum rustc version](https://img.shields.io/badge/rustc-1.44.0+-lightgray.svg)](#rust-version-requirements) +//! [![Minimum rustc version](https://img.shields.io/badge/rustc-1.48.0+-lightgray.svg)](#rust-version-requirements) //! //! # BER/DER Parser //! @@ -172,7 +172,7 @@ //! assert_eq!(object.as_u64(), Ok(65537)); //! //! #[cfg(feature = "bigint")] -//! assert_eq!(object.as_bigint(), Some(65537.into())) +//! assert_eq!(object.as_bigint(), Ok(65537.into())) //! ``` //! //! Access to the raw value is possible using the `as_slice` method. @@ -196,7 +196,7 @@ //! //! ## Rust version requirements //! -//! The 5.0 series of `der-parser` requires **Rustc version 1.44 or greater**, based on nom 6 +//! The 6.0 series of `der-parser` requires **Rustc version 1.48 or greater**, based on nom 7 //! dependencies. //! //! # Serialization @@ -237,9 +237,13 @@ no_crate_inject, attr(deny(warnings/*, rust_2018_idioms*/), allow(dead_code, unused_variables)) ))] +#![no_std] +#[cfg(any(test, feature = "std"))] #[macro_use] -mod macros; +extern crate std; + +extern crate alloc; #[allow(clippy::module_inception)] pub mod ber; @@ -259,7 +263,32 @@ pub use num_bigint; // re-exports nom macros, so this crate's macros can be used without importing nom pub use nom::IResult; #[doc(hidden)] -pub use rusticata_macros::{custom_check, flat_take}; +pub use rusticata_macros::custom_check; + +#[doc(hidden)] +pub mod exports { + pub use alloc::borrow; + pub use der_oid_macro; +} /// Procedural macro to get encoded oids, see the [oid module](oid/index.html). -pub use der_oid_macro::oid; +#[macro_export] +macro_rules! oid { + (raw $($args:tt)*) => {{ + $crate::exports::der_oid_macro::encode_oid!($($args)*) + }}; + (rel $($args:tt)*) => {{ + $crate::oid::Oid::new_relative( + $crate::exports::borrow::Cow::Borrowed(& + $crate::exports::der_oid_macro::encode_oid!(rel $($args)*) + ) + ) + }}; + ($($args:tt)*) => {{ + $crate::oid::Oid::new( + $crate::exports::borrow::Cow::Borrowed(& + $crate::exports::der_oid_macro::encode_oid!($($args)*) + ) + ) + }}; +} diff --git a/src/macros.rs b/src/macros.rs deleted file mode 100644 index 24ad59b..0000000 --- a/src/macros.rs +++ /dev/null @@ -1,668 +0,0 @@ -/// Internal parser, do not use directly -#[doc(hidden)] -#[macro_export] -macro_rules! fold_der_defined_m( - (__impl $i:expr, $acc:ident, $f:ident) => ( { - match $f($i) { - Ok((rem,res)) => { $acc.push(res); Ok((rem,$acc)) }, - Err(e) => Err(e) - } - }); - (__impl $i:expr, $acc:ident, $submac:ident!( $($args:tt)* ) ) => ( { - match $submac!($i, $($args)*) { - Ok((rem,res)) => { $acc.push(res); Ok((rem,$acc)) }, - Err(e) => Err(e) - } - }); - (__impl $i:expr, $acc:ident, $f:ident >> $($rest:tt)*) => ( - { - match $f($i) { - Ok((rem,res)) => { - $acc.push(res); - fold_der_defined_m!(__impl rem, $acc, $($rest)* ) - }, - Err(e) => Err(e) - } - } - ); - (__impl $i:expr, $acc:ident, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => ( - { - match $submac!($i, $($args)*) { - Ok((rem,res)) => { - $acc.push(res); - fold_der_defined_m!(__impl rem, $acc, $($rest)* ) - }, - Err(e) => Err(e) - } - } - ); - - ($i:expr, $($rest:tt)* ) => ( - { - let mut v = Vec::new(); - fold_der_defined_m!(__impl $i, v, $($rest)*) - } - ); -); - -/// Internal parser, do not use directly -#[doc(hidden)] -#[macro_export] -macro_rules! parse_ber_defined_m( - ($i:expr, $tag:expr, $($args:tt)*) => ( - { - use $crate::ber::parse_ber_container; - use $crate::error::BerError; - parse_ber_container(|content, hdr| { - if !hdr.is_constructed() { - return Err(nom::Err::Error(BerError::ConstructExpected.into())); - } - if hdr.tag != $tag { - return Err(nom::Err::Error(BerError::InvalidTag.into())); - } - let (rem, content) = fold_der_defined_m!(content, $($args)* )?; - Ok((rem, (hdr, content))) - })($i) - } - ); -); - -/// Parse a defined sequence of DER elements (deprecated) -/// -/// Given a list of expected parsers, apply them to build a DER sequence. -/// -/// Deprecated, use [`parse_der_sequence_defined`](macro.parse_der_sequence_defined.html) instead. -#[macro_export] -#[deprecated(since = "3.0.0", note = "Use parse_der_sequence_defined")] -macro_rules! parse_der_sequence_defined_m( - ($i:expr, $($args:tt)*) => ({ - parse_der_sequence_defined!($i, $($args)*) - }); -); - -/// Parse a defined set of DER elements (deprecated) -/// -/// Given a list of expected parsers, apply them to build a DER set. -/// -/// Deprecated, use [`parse_der_set_defined`](macro.parse_der_set_defined.html) instead. -#[macro_export] -#[deprecated(since = "3.0.0", note = "Use parse_der_set_defined")] -macro_rules! parse_der_set_defined_m( - ($i:expr, $($args:tt)*) => ({ - parse_der_set_defined!($i, $($args)*) - }); -); - -/// Internal parser, do not use directly -#[doc(hidden)] -#[macro_export] -macro_rules! fold_parsers( - ($i:expr, $($args:tt)*) => ( - { - let parsers = [ $($args)* ]; - parsers.iter().fold( - (Ok(($i,vec![]))), - |r, f| { - match r { - Ok((rem,mut v)) => { - map!(rem, f, |x| { v.push(x); v }) - } - Err(e) => Err(e) - } - } - ) - } - ); -); - -/// Internal parser, do not use directly -#[doc(hidden)] -#[macro_export] -macro_rules! parse_der_defined( - ($i:expr, $tag:expr, $($args:tt)*) => ( - { - use $crate::ber::ber_read_element_header; - let res = - do_parse!( - $i, - hdr: ber_read_element_header >> - custom_check!(hdr.class != $crate::ber::BerClass::Universal, $crate::error::BerError::InvalidClass) >> - custom_check!(hdr.structured != 0b1, $crate::error::BerError::ConstructExpected) >> - custom_check!(hdr.tag != $tag, $crate::error::BerError::InvalidTag) >> - content: take!(hdr.len) >> - (hdr,content) - ); - match res { - Ok((_rem,o)) => { - match fold_parsers!(o.1, $($args)* ) { - Ok((rem,v)) => { - if rem.len() != 0 { Err(::nom::Err::Error($crate::error::BerError::ObjectTooShort)) } - else { Ok((_rem,(o.0,v))) } - }, - Err(e) => Err(e) - } - }, - Err(e) => Err(e) - } - } - ); -); - -/// Parse a defined sequence of DER elements -/// -/// Given a list of expected parsers, apply them to build a DER sequence. -/// -/// ```rust -/// # #[macro_use] extern crate der_parser; -/// # use der_parser::ber::{parse_ber_integer, BerObject}; -/// # use der_parser::error::BerResult; -/// # -/// # fn main() { -/// fn localparse_seq(i:&[u8]) -> BerResult { -/// parse_der_sequence_defined!(i, -/// parse_ber_integer >> -/// parse_ber_integer -/// ) -/// } -/// -/// let empty = &b""[..]; -/// let bytes = [ 0x30, 0x0a, -/// 0x02, 0x03, 0x01, 0x00, 0x01, -/// 0x02, 0x03, 0x01, 0x00, 0x00, -/// ]; -/// let expected = BerObject::from_seq(vec![ -/// BerObject::from_int_slice(b"\x01\x00\x01"), -/// BerObject::from_int_slice(b"\x01\x00\x00"), -/// ]); -/// assert_eq!(localparse_seq(&bytes), Ok((empty, expected))); -/// # } -/// ``` -#[macro_export] -macro_rules! parse_der_sequence_defined( - ($i:expr, $($args:tt)*) => ({ - use nom::map; - map!( - $i, - parse_ber_defined_m!($crate::ber::BerTag::Sequence, $($args)*), - |(hdr,o)| $crate::ber::BerObject::from_header_and_content(hdr,$crate::ber::BerObjectContent::Sequence(o)) - ) - }); -); - -/// Parse a defined set of DER elements -/// -/// Given a list of expected parsers, apply them to build a DER set. -/// -/// ```rust -/// # #[macro_use] extern crate der_parser; -/// # use der_parser::ber::{parse_ber_integer, BerObject}; -/// # use der_parser::error::BerResult; -/// # -/// # fn main() { -/// fn localparse_set(i:&[u8]) -> BerResult { -/// parse_der_set_defined!(i, -/// parse_ber_integer >> -/// parse_ber_integer -/// ) -/// } -/// -/// let empty = &b""[..]; -/// let bytes = [ 0x31, 0x0a, -/// 0x02, 0x03, 0x01, 0x00, 0x01, -/// 0x02, 0x03, 0x01, 0x00, 0x00, -/// ]; -/// let expected = BerObject::from_set(vec![ -/// BerObject::from_int_slice(b"\x01\x00\x01").set_raw_tag(Some(&[0x2])), -/// BerObject::from_int_slice(b"\x01\x00\x00").set_raw_tag(Some(&[0x2])), -/// ]).set_raw_tag(Some(&[0x31])); -/// assert_eq!(localparse_set(&bytes), Ok((empty, expected))); -/// # } -/// ``` -#[macro_export] -macro_rules! parse_der_set_defined( - ($i:expr, $($args:tt)*) => ({ - use nom::map; - map!( - $i, - parse_ber_defined_m!($crate::ber::BerTag::Set, $($args)*), - |(hdr,o)| $crate::ber::BerObject::from_header_and_content(hdr,$crate::ber::BerObjectContent::Set(o)) - ) - }); -); - -/// Parse a sequence of identical DER elements -/// -/// Given a subparser for a DER type, parse a sequence of identical objects. -/// -/// ```rust -/// # #[macro_use] extern crate der_parser; -/// # use der_parser::ber::{parse_ber_integer, BerObject}; -/// # use der_parser::error::BerResult; -/// # -/// # fn main() { -/// fn parser(i:&[u8]) -> BerResult { -/// parse_der_sequence_of!(i, parse_ber_integer) -/// } -/// -/// let empty = &b""[..]; -/// let bytes = [ 0x30, 0x0a, -/// 0x02, 0x03, 0x01, 0x00, 0x01, -/// 0x02, 0x03, 0x01, 0x00, 0x00, -/// ]; -/// let expected = BerObject::from_seq(vec![ -/// BerObject::from_int_slice(b"\x01\x00\x01"), -/// BerObject::from_int_slice(b"\x01\x00\x00"), -/// ]); -/// assert_eq!(parser(&bytes), Ok((empty, expected))); -/// # } -/// ``` -#[macro_export] -macro_rules! parse_der_sequence_of( - ($i:expr, $f:ident) => ({ - use $crate::ber::parse_ber_sequence_of; - parse_ber_sequence_of($f)($i) - }) -); - -/// Parse a set of identical DER elements -/// -/// Given a subparser for a DER type, parse a set of identical objects. -/// -/// ```rust -/// # #[macro_use] extern crate der_parser; -/// # use der_parser::ber::{parse_ber_integer, BerObject}; -/// # use der_parser::error::BerResult; -/// # -/// # fn main() { -/// fn parser(i:&[u8]) -> BerResult { -/// parse_der_set_of!(i, parse_ber_integer) -/// } -/// -/// let empty = &b""[..]; -/// let bytes = [ 0x31, 0x0a, -/// 0x02, 0x03, 0x01, 0x00, 0x01, -/// 0x02, 0x03, 0x01, 0x00, 0x00, -/// ]; -/// let expected = BerObject::from_set(vec![ -/// BerObject::from_int_slice(b"\x01\x00\x01"), -/// BerObject::from_int_slice(b"\x01\x00\x00"), -/// ]); -/// assert_eq!(parser(&bytes), Ok((empty, expected))); -/// # } -/// ``` -#[macro_export] -macro_rules! parse_der_set_of( - ($i:expr, $f:ident) => ({ - use $crate::ber::parse_ber_set_of; - parse_ber_set_of($f)($i) - }) -); - -/// Parse an optional DER element -/// -/// Try to parse an optional DER element, and return it as a `ContextSpecific` item with tag 0. -/// If the parsing failed, the `ContextSpecific` object has value `None`. -/// -/// ```rust -/// # #[macro_use] extern crate der_parser; -/// # use der_parser::ber::*; -/// # use der_parser::error::BerResult; -/// # -/// # fn main() { -/// let empty = &b""[..]; -/// let bytes1 = [ 0x30, 0x0a, -/// 0x0a, 0x03, 0x00, 0x00, 0x01, -/// 0x02, 0x03, 0x01, 0x00, 0x01]; -/// let bytes2 = [ 0x30, 0x05, -/// 0x02, 0x03, 0x01, 0x00, 0x01]; -/// let expected1 = BerObject::from_seq(vec![ -/// BerObject::from_obj(BerObjectContent::Optional(Some(Box::new( -/// BerObject::from_obj(BerObjectContent::Enum(1)), -/// )))), -/// BerObject::from_int_slice(b"\x01\x00\x01"), -/// ]); -/// let expected2 = BerObject::from_seq(vec![ -/// BerObject::from_obj( -/// BerObjectContent::Optional(None), -/// ), -/// BerObject::from_int_slice(b"\x01\x00\x01"), -/// ]); -/// -/// fn parse_optional_enum(i:&[u8]) -> BerResult { -/// parse_der_optional!(i, parse_ber_enum) -/// } -/// fn parser(i:&[u8]) -> BerResult { -/// parse_der_sequence_defined!(i, -/// parse_optional_enum >> -/// parse_ber_integer -/// ) -/// } -/// -/// assert_eq!(parser(&bytes1), Ok((empty, expected1))); -/// assert_eq!(parser(&bytes2), Ok((empty, expected2))); -/// # } -/// ``` -#[macro_export] -macro_rules! parse_der_optional( - ($i:expr, $f:ident) => ( - match $f($i) { - Ok((rem, obj)) => { - let opt = - $crate::ber::BerObject::from_header_and_content( - obj.header.clone(), - $crate::ber::BerObjectContent::Optional(Some(Box::new(obj))) - ); - Ok((rem, opt)) - } - Err(_) => { - let opt = $crate::ber::BerObject::from_obj( - $crate::ber::BerObjectContent::Optional(None) - ); - Ok(($i, opt)) - } - } - // alt!( - // $i, - // complete!(do_parse!( - // content: call!($f) >> - // ( - // $crate::ber::BerObject::from_obj( - // $crate::ber::BerObjectContent::ContextSpecific($crate::ber::BerTag(0) /* XXX */,Some(Box::new(content))) - // ) - // ) - // )) | - // complete!(call!($crate::ber::parse_ber_explicit_failed,$crate::ber::BerTag(0) /* XXX */)) - // ) - ) -); - -/// Parse a constructed DER element -/// -/// Read a constructed DER element (sequence or set, typically) using the provided functions. -/// This is generally used to build a struct from a DER sequence. -/// -/// The returned object is a tuple containing a [`BerObjectHeader`](struct.BerObjectHeader.html) -/// and the object returned by the subparser. -/// -/// To ensure the subparser consumes all bytes from the constructed object, add the `eof!()` -/// subparser as the last parsing item. -/// -/// To verify the tag of the constructed element, use the `TAG` version, for ex -/// `parse_der_struct!(i, TAG DerTag::Sequence, parse_der_integer)` -/// -/// Similar to [`parse_der_sequence_defined`](macro.parse_der_sequence_defined.html), but using the -/// `do_parse` macro from nom. -/// This allows declaring variables, and running code at the end. -/// -/// # Examples -/// -/// Basic struct parsing (ignoring tag): -/// -/// ```rust -/// # #[macro_use] extern crate der_parser; -/// # use der_parser::ber::*; -/// # use der_parser::error::BerResult; -/// # use nom::eof; -/// # -/// # fn main() { -/// #[derive(Debug, PartialEq)] -/// struct MyStruct<'a>{ -/// a: BerObject<'a>, -/// b: BerObject<'a>, -/// } -/// -/// fn parse_struct01(i: &[u8]) -> BerResult { -/// parse_der_struct!( -/// i, -/// a: parse_ber_integer >> -/// b: parse_ber_integer >> -/// eof!() >> -/// ( MyStruct{ a: a, b: b } ) -/// ) -/// } -/// -/// let bytes = [ 0x30, 0x0a, -/// 0x02, 0x03, 0x01, 0x00, 0x01, -/// 0x02, 0x03, 0x01, 0x00, 0x00, -/// ]; -/// let empty = &b""[..]; -/// let expected = MyStruct { -/// a: BerObject::from_int_slice(b"\x01\x00\x01"), -/// b: BerObject::from_int_slice(b"\x01\x00\x00"), -/// }; -/// let res = parse_struct01(&bytes); -/// assert_eq!(res, Ok((empty, expected))); -/// # } -/// ``` -/// -/// To check the expected tag, use the `TAG ` variant: -/// -/// ```rust -/// # #[macro_use] extern crate der_parser; -/// # use der_parser::ber::*; -/// # use der_parser::error::BerResult; -/// # use nom::eof; -/// # -/// # fn main() { -/// struct MyStruct<'a>{ -/// a: BerObject<'a>, -/// b: BerObject<'a>, -/// } -/// -/// fn parse_struct_with_tag(i: &[u8]) -> BerResult { -/// parse_der_struct!( -/// i, -/// TAG BerTag::Sequence, -/// a: parse_ber_integer >> -/// b: parse_ber_integer >> -/// eof!() >> -/// ( MyStruct{ a, b } ) -/// ) -/// } -/// # } -/// ``` -#[macro_export] -macro_rules! parse_der_struct( - ($i:expr, TAG $tag:expr, $($rest:tt)*) => ({ - use $crate::ber::parse_ber_container; - use $crate::error::BerError; - use nom::do_parse; - parse_ber_container( - |i, hdr| { - if !hdr.is_constructed() { - return Err(nom::Err::Error(BerError::ConstructExpected.into())); - } - if hdr.tag != $tag { - return Err(nom::Err::Error(BerError::InvalidTag.into())); - } - do_parse!(i, $($rest)*) - } - )($i) - }); - ($i:expr, $($rest:tt)*) => ({ - use $crate::ber::parse_ber_container; - use $crate::error::BerError; - use nom::do_parse; - parse_ber_container( - |i, hdr| { - if !hdr.is_constructed() { - return Err(nom::Err::Error(BerError::ConstructExpected.into())); - } - do_parse!(i, $($rest)*) - } - )($i) - }); -); - -/// Parse a tagged DER element -/// -/// Read a tagged DER element using the provided function. -/// -/// The returned object is either the object returned by the subparser, or a nom error. -/// Unlike [`parse_der_explicit`](fn.parse_der_explicit.html) or -/// [`parse_der_implicit`](fn.parse_der_implicit.html), the returned values are *not* encapsulated -/// in a `BerObject` (they are directly returned, without the tag). -/// -/// To specify the kind of tag, use the EXPLICIT or IMPLICIT keyword. If no keyword is specified, -/// the parsing is EXPLICIT by default. -/// -/// When parsing IMPLICIT values, the third argument is a [`DerTag`](enum.DerTag.html) defining the -/// subtype of the object. -/// -/// # Examples -/// -/// The following parses `[2] INTEGER`: -/// -/// ```rust -/// # #[macro_use] extern crate der_parser; -/// # use der_parser::ber::{parse_ber_integer, BerObject}; -/// # use nom::map_res; -/// # use der_parser::error::BerResult; -/// # -/// # fn main() { -/// fn parse_int_explicit(i:&[u8]) -> BerResult { -/// map_res!( -/// i, -/// parse_der_tagged!(EXPLICIT 2, parse_ber_integer), -/// |x: BerObject| x.as_tagged()?.2.as_u32() -/// ) -/// } -/// -/// let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; -/// let res = parse_int_explicit(bytes); -/// match res { -/// Ok((rem,val)) => { -/// assert!(rem.is_empty()); -/// assert_eq!(val, 0x10001); -/// }, -/// Err(e) => panic!("parse_int_explicit failed: {:?}", e), -/// } -/// # } -/// ``` -/// -/// The following parses `[2] IMPLICIT INTEGER`: -/// -/// ```rust -/// # #[macro_use] extern crate der_parser; -/// # use der_parser::ber::{BerObject, BerTag}; -/// # use der_parser::error::BerResult; -/// # use nom::map_res; -/// # -/// # fn main() { -/// fn parse_int_implicit(i:&[u8]) -> BerResult { -/// map_res!( -/// i, -/// parse_der_tagged!(IMPLICIT 2, BerTag::Integer), -/// |x: BerObject| x.as_u32() -/// ) -/// } -/// -/// let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01]; -/// let res = parse_int_implicit(bytes); -/// match res { -/// Ok((rem,val)) => { -/// assert!(rem.is_empty()); -/// assert_eq!(val, 0x10001); -/// }, -/// _ => assert!(false) -/// } -/// # } -/// ``` -#[macro_export] -macro_rules! parse_der_tagged( - ($i:expr, EXPLICIT $tag:expr, $f:ident) => ({ - use $crate::ber::parse_ber_tagged_explicit; - parse_ber_tagged_explicit( - $tag, - $f - )($i) - }); - ($i:expr, EXPLICIT $tag:expr, $submac:ident!( $($args:tt)*)) => ({ - use $crate::ber::parse_ber_tagged_explicit; - parse_ber_tagged_explicit( - $tag, - |content| { - $submac!(content, $($args)*) - } - )($i) - }); - ($i:expr, IMPLICIT $tag:expr, $type:expr) => ({ - use $crate::ber::{ber_read_element_content_as, parse_ber_tagged_implicit}; - parse_ber_tagged_implicit( - $tag, - |content, hdr, max_size| { - ber_read_element_content_as(content, $type, hdr.len, hdr.is_constructed(), max_size) - } - )($i) - }); - ($i:expr, $tag:expr, $f:ident) => ( parse_der_tagged!($i, EXPLICIT $tag, $f) ); -); - -/// Parse an application DER element -/// -/// Read an application DER element using the provided functions. -/// This is generally used to build a struct from a DER sequence. -/// -/// The returned object is a tuple containing a [`BerObjectHeader`](struct.BerObjectHeader.html) -/// and the object returned by the subparser. -/// -/// To ensure the subparser consumes all bytes from the constructed object, add the `eof!()` -/// subparser as the last parsing item. -/// -/// # Examples -/// -/// The following parses `[APPLICATION 2] INTEGER`: -/// -/// ```rust -/// # #[macro_use] extern crate der_parser; -/// # use der_parser::ber::*; -/// # use der_parser::error::BerResult; -/// # use nom::{eof, map_res}; -/// # -/// # fn main() { -/// #[derive(Debug, PartialEq)] -/// struct SimpleStruct { -/// a: u32, -/// } -/// -/// fn parse_app01(i:&[u8]) -> BerResult { -/// parse_der_application!( -/// i, -/// APPLICATION 2, -/// a: map_res!(parse_ber_integer,|x: BerObject| x.as_u32()) >> -/// eof!() >> -/// ( SimpleStruct{ a:a } ) -/// ) -/// } -/// -/// let bytes = &[0x62, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; -/// let res = parse_app01(bytes); -/// match res { -/// Ok((rem, app)) => { -/// assert!(rem.is_empty()); -/// assert_eq!(app, SimpleStruct{ a:0x10001 }); -/// }, -/// _ => assert!(false) -/// } -/// # } -/// ``` -#[macro_export] -macro_rules! parse_der_application( - ($i:expr, APPLICATION $tag:expr, $($rest:tt)*) => ({ - use $crate::ber::{parse_ber_container, BerClass, BerTag}; - use $crate::error::BerError; - use nom::do_parse; - parse_ber_container( - |content, hdr| { - if hdr.class != BerClass::Application { - return Err(nom::Err::Error(BerError::InvalidClass.into())); - } - if hdr.tag != BerTag($tag) { - return Err(nom::Err::Error(BerError::BerTypeError.into())); - } - do_parse!(content, $($rest)* ) - } - )($i) - }); - ($i:expr, $tag:expr, $($rest:tt)*) => ( parse_der_application!($i, APPLICATION $tag, $($rest)*) ); -); diff --git a/src/oid.rs b/src/oid.rs index fdb17b3..618988d 100644 --- a/src/oid.rs +++ b/src/oid.rs @@ -47,17 +47,22 @@ //! ``` //! *Attention*, be aware that the latter version might not handle the case of a relative oid correctly. An //! extra check might be necessary. -use std::borrow::Cow; -use std::convert::From; -use std::fmt; -use std::iter::{ExactSizeIterator, FusedIterator, Iterator}; -use std::ops::Shl; -use std::str::FromStr; +use alloc::borrow::Cow; +use alloc::fmt; +use alloc::str::FromStr; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use core::convert::From; +use core::iter::{ExactSizeIterator, FusedIterator, Iterator}; +use core::ops::Shl; #[cfg(feature = "bigint")] use num_bigint::BigUint; use num_traits::Num; +#[cfg(not(feature = "std"))] +use alloc::format; + #[derive(Debug)] pub enum ParseError { TooShort, @@ -212,7 +217,7 @@ impl<'a> Oid<'a> { oid: self, pos: 0, first: false, - n: std::marker::PhantomData, + n: core::marker::PhantomData, } } @@ -248,7 +253,7 @@ impl<'a> Oid<'a> { oid: self, pos: 0, first: false, - n: std::marker::PhantomData, + n: core::marker::PhantomData, }) } } @@ -260,7 +265,7 @@ struct SubIdentifierIterator<'a, N: Repr> { oid: &'a Oid<'a>, pos: usize, first: bool, - n: std::marker::PhantomData<&'a N>, + n: core::marker::PhantomData<&'a N>, } impl<'a, N: Repr> Iterator for SubIdentifierIterator<'a, N> { @@ -358,6 +363,7 @@ impl<'a> FromStr for Oid<'a> { mod tests { use crate::oid::Oid; use std::borrow::Cow; + use std::borrow::ToOwned; use std::str::FromStr; #[test] @@ -437,6 +443,7 @@ mod tests { { use num_bigint::BigUint; use num_traits::FromPrimitive; + use std::vec::Vec; let oid_raw = Oid::new(Cow::Borrowed(&[0])); let ids: Vec = oid_raw.iter_bigint().collect(); @@ -444,6 +451,7 @@ mod tests { assert_eq!(oid_raw.iter_bigint().len(), 1); } { + use std::vec::Vec; let oid_raw = Oid::new(Cow::Borrowed(&[0])); let ids: Vec = oid_raw.iter().unwrap().collect(); assert_eq!(vec![0], ids); diff --git a/tests/ber_parser.rs b/tests/ber_parser.rs index 488a0c1..6f020e3 100644 --- a/tests/ber_parser.rs +++ b/tests/ber_parser.rs @@ -220,22 +220,19 @@ fn tc_ber_bigint(i: &[u8], out: Result) { } #[cfg(feature = "bigint")] -#[test_case(&hex!("02 01 01"), Ok(Some(BigUint::from(1_u8))) ; "biguint-1")] -#[test_case(&hex!("02 02 00 ff"), Ok(Some(BigUint::from(255_u8))) ; "biguint-255")] -#[test_case(&hex!("02 01 ff"), Ok(None) ; "biguint-neg1")] -#[test_case(&hex!("02 01 80"), Ok(None) ; "biguint-neg128")] -#[test_case(&hex!("02 02 ff 7f"), Ok(None) ; "biguint-neg129")] -#[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(Some(BigUint::from(0xffff_ffff_ffff_ffff_u64))) ; "biguint-long2-ok")] -#[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(Some(BigUint::from_bytes_be(&hex!("01 23 45 67 01 23 45 67 ab")))) ; "biguint-longer1")] +#[test_case(&hex!("02 01 01"), Ok(BigUint::from(1_u8)) ; "biguint-1")] +#[test_case(&hex!("02 02 00 ff"), Ok(BigUint::from(255_u8)) ; "biguint-255")] +#[test_case(&hex!("02 01 ff"), Err(BerError::IntegerNegative) ; "biguint-neg1")] +#[test_case(&hex!("02 01 80"), Err(BerError::IntegerNegative) ; "biguint-neg128")] +#[test_case(&hex!("02 02 ff 7f"), Err(BerError::IntegerNegative) ; "biguint-neg129")] +#[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(BigUint::from(0xffff_ffff_ffff_ffff_u64)) ; "biguint-long2-ok")] +#[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(BigUint::from_bytes_be(&hex!("01 23 45 67 01 23 45 67 ab"))) ; "biguint-longer1")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] -fn tc_ber_biguint(i: &[u8], out: Result, BerError>) { - let res = parse_ber_integer(i); +fn tc_ber_biguint(i: &[u8], out: Result) { + let res = parse_ber_integer(i).and_then(|(rem, ber)| Ok((rem, ber.as_biguint()?))); match out { Ok(expected) => { - let (rem, ber) = res.expect("parsing failed"); - assert!(rem.is_empty()); - let uint = ber.as_biguint(); - pretty_assertions::assert_eq!(uint, expected); + pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); @@ -543,3 +540,11 @@ fn test_parse_ber_content2() { assert_eq!(tag, BerTag::Integer); assert_eq!(content.as_u32(), Ok(0x10001)); } + +#[test] +fn parse_ber_private() { + let bytes = &hex!("c0 03 01 00 01"); + let (rem, res) = parse_ber(bytes).expect("parsing failed"); + assert!(rem.is_empty()); + assert!(matches!(res.content, BerObjectContent::Private(_, _))); +} diff --git a/tests/constructed.rs b/tests/constructed.rs index 49bc0c6..20a83a0 100644 --- a/tests/constructed.rs +++ b/tests/constructed.rs @@ -1,9 +1,12 @@ use der_parser::ber::*; +use der_parser::der::*; use der_parser::error::*; use der_parser::*; use hex_literal::hex; -use nom::combinator::map; +use nom::branch::alt; +use nom::combinator::{complete, eof, map, map_res}; use nom::error::ErrorKind; +use nom::multi::many0; use nom::sequence::tuple; use nom::*; use oid::Oid; @@ -17,44 +20,33 @@ struct MyStruct<'a> { } fn parse_struct01(i: &[u8]) -> BerResult { - parse_der_struct!( - i, - a: parse_ber_integer >> b: parse_ber_integer >> (MyStruct { a, b }) - ) + parse_der_sequence_defined_g(|i: &[u8], _| { + let (i, a) = parse_ber_integer(i)?; + let (i, b) = parse_ber_integer(i)?; + Ok((i, MyStruct { a, b })) + })(i) } fn parse_struct01_complete(i: &[u8]) -> BerResult { - parse_der_struct!( - i, - a: parse_ber_integer >> b: parse_ber_integer >> eof!() >> (MyStruct { a, b }) - ) -} - -// calling user function -#[allow(dead_code)] -fn parse_struct02(i: &[u8]) -> BerResult<()> { - parse_der_struct!(i, _a: parse_ber_integer >> _b: parse_struct01 >> (())) -} - -// embedded DER structs -#[allow(dead_code)] -fn parse_struct03(i: &[u8]) -> BerResult<()> { - parse_der_struct!( - i, - _a: parse_ber_integer >> _b: parse_der_struct!(parse_ber_integer >> (())) >> (()) - ) + parse_der_sequence_defined_g(|i: &[u8], _| { + let (i, a) = parse_ber_integer(i)?; + let (i, b) = parse_ber_integer(i)?; + eof(i)?; + Ok((i, MyStruct { a, b })) + })(i) } // verifying tag fn parse_struct04(i: &[u8], tag: BerTag) -> BerResult { - parse_der_struct!( - i, - TAG tag, - a: parse_ber_integer >> - b: parse_ber_integer >> - eof!() >> - ( MyStruct{ a, b } ) - ) + parse_der_container(|i: &[u8], hdr| { + if hdr.tag != tag { + return Err(Err::Error(BerError::InvalidTag)); + } + let (i, a) = parse_ber_integer(i)?; + let (i, b) = parse_ber_integer(i)?; + eof(i)?; + Ok((i, MyStruct { a, b })) + })(i) } #[test_case(&hex!("30 00"), Ok(&[]) ; "empty seq")] @@ -247,27 +239,33 @@ fn struct02() { ], }; fn parse_directory_string(i: &[u8]) -> BerResult { - alt!( - i, - parse_ber_utf8string | parse_ber_printablestring | parse_ber_ia5string - ) + alt(( + parse_ber_utf8string, + parse_ber_printablestring, + parse_ber_ia5string, + ))(i) } fn parse_attr_type_and_value(i: &[u8]) -> BerResult { fn clone_oid(x: BerObject) -> Result { x.as_oid().map(|o| o.clone()) } - parse_der_struct!( - i, - o: map_res!(parse_ber_oid, clone_oid) - >> s: parse_directory_string - >> (Attr { oid: o, val: s }) - ) + parse_der_sequence_defined_g(|i: &[u8], _| { + let (i, o) = map_res(parse_ber_oid, clone_oid)(i)?; + let (i, s) = parse_directory_string(i)?; + Ok((i, Attr { oid: o, val: s })) + })(i) } fn parse_rdn(i: &[u8]) -> BerResult { - parse_der_struct!(i, a: parse_attr_type_and_value >> (Rdn { a })) + parse_der_set_defined_g(|i: &[u8], _| { + let (i, a) = parse_attr_type_and_value(i)?; + Ok((i, Rdn { a })) + })(i) } fn parse_name(i: &[u8]) -> BerResult { - parse_der_struct!(i, l: many0!(complete!(parse_rdn)) >> (Name { l })) + parse_der_sequence_defined_g(|i: &[u8], _| { + let (i, l) = many0(complete(parse_rdn))(i)?; + Ok((i, Name { l })) + })(i) } let parsed = parse_name(&bytes).unwrap(); assert_eq!(parsed, (empty, expected)); @@ -337,36 +335,24 @@ fn tc_ber_tagged_explicit_g(i: &[u8], out: Result) { #[test] fn tagged_explicit() { fn parse_int_explicit(i: &[u8]) -> BerResult { - map_res!( - i, - parse_der_tagged!(EXPLICIT 2, parse_ber_integer), - |x: BerObject| x.as_tagged()?.2.as_u32() - ) - } - fn parse_int_noexplicit(i: &[u8]) -> BerResult { - map_res!( - i, - parse_der_tagged!(2, parse_ber_integer), - |x: BerObject| x.as_tagged()?.2.as_u32() - ) + map_res( + parse_der_tagged_explicit(2, parse_der_integer), + |x: BerObject| x.as_tagged()?.2.as_u32(), + )(i) } let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; // EXPLICIT tagged value parsing let (rem, val) = parse_int_explicit(bytes).expect("Could not parse explicit int"); assert!(rem.is_empty()); assert_eq!(val, 0x10001); - // omitting EXPLICIT keyword - let a = parse_int_explicit(bytes); - let b = parse_int_noexplicit(bytes); - assert_eq!(a, b); // wrong tag assert_eq!( - parse_der_tagged!(bytes as &[u8], 3, parse_ber_integer), + parse_der_tagged_explicit(3, parse_der_integer)(bytes as &[u8]), Err(Err::Error(BerError::InvalidTag)) ); // wrong type assert_eq!( - parse_der_tagged!(bytes as &[u8], 2, parse_ber_bool), + parse_der_tagged_explicit(2, parse_der_bool)(bytes as &[u8]), Err(Err::Error(BerError::InvalidTag)) ); } @@ -395,11 +381,10 @@ fn tc_ber_tagged_implicit_g(i: &[u8], out: Result) { #[test] fn tagged_implicit() { fn parse_int_implicit(i: &[u8]) -> BerResult { - map_res!( - i, - parse_der_tagged!(IMPLICIT 2, BerTag::Integer), - |x: BerObject| x.as_u32() - ) + map_res( + parse_der_tagged_implicit(2, parse_der_content(DerTag::Integer)), + |x: BerObject| x.as_u32(), + )(i) } let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01]; // IMPLICIT tagged value parsing @@ -408,7 +393,7 @@ fn tagged_implicit() { assert_eq!(val, 0x10001); // wrong tag assert_eq!( - parse_der_tagged!(bytes as &[u8], IMPLICIT 3, BerTag::Integer), + parse_der_tagged_implicit(3, parse_der_content(DerTag::Integer))(bytes as &[u8]), Err(Err::Error(BerError::InvalidTag)) ); } @@ -420,12 +405,16 @@ fn application() { a: u32, } fn parse_app01(i: &[u8]) -> BerResult { - parse_der_application!( - i, - APPLICATION 2, - a: map_res!(parse_ber_integer,|x: BerObject| x.as_u32()) >> - ( SimpleStruct{ a } ) - ) + parse_der_container(|i, hdr| { + if hdr.class != BerClass::Application { + return Err(Err::Error(BerError::InvalidClass)); + } + if hdr.tag != BerTag(2) { + return Err(Err::Error(BerError::InvalidTag)); + } + let (i, a) = map_res(parse_ber_integer, |x: BerObject| x.as_u32())(i)?; + Ok((i, SimpleStruct { a })) + })(i) } let bytes = &[0x62, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; let (rem, app) = parse_app01(bytes).expect("could not parse application"); diff --git a/tests/der_parser.rs b/tests/der_parser.rs index 9a31e5c..33665f3 100644 --- a/tests/der_parser.rs +++ b/tests/der_parser.rs @@ -6,8 +6,11 @@ use der_parser::error::*; use der_parser::oid::*; use der_parser::*; use hex_literal::hex; +use nom::branch::alt; +use nom::combinator::map; use nom::error::ErrorKind; -use nom::{alt, call, Err}; +use nom::sequence::tuple; +use nom::Err; use pretty_assertions::assert_eq; use test_case::test_case; @@ -175,7 +178,13 @@ fn test_der_seq_defined() { DerObject::from_int_slice(b"\x01\x00\x00"), ]); fn parser(i: &[u8]) -> DerResult { - parse_der_sequence_defined!(i, parse_der_integer >> parse_der_integer) + parse_der_sequence_defined( + // the nom `tuple` combinator returns a tuple, so we have to map it + // to a list + map(tuple((parse_der_integer, parse_der_integer)), |(a, b)| { + vec![a, b] + }), + )(i) } assert_eq!(parser(&bytes), Ok((empty, expected))); } @@ -191,7 +200,13 @@ fn test_der_set_defined() { DerObject::from_int_slice(b"\x01\x00\x00"), ]); fn parser(i: &[u8]) -> DerResult { - parse_der_set_defined!(i, parse_der_integer >> parse_der_integer) + parse_der_set_defined( + // the nom `tuple` combinator returns a tuple, so we have to map it + // to a list + map(tuple((parse_der_integer, parse_der_integer)), |(a, b)| { + vec![a, b] + }), + )(i) } assert_eq!(parser(&bytes), Ok((empty, expected))); } @@ -207,7 +222,7 @@ fn test_der_seq_of() { DerObject::from_int_slice(b"\x01\x00\x00"), ]); fn parser(i: &[u8]) -> DerResult { - parse_der_sequence_of!(i, parse_der_integer) + parse_der_sequence_of(parse_der_integer)(i) } assert_eq!(parser(&bytes), Ok((empty, expected.clone()))); // @@ -222,7 +237,7 @@ fn test_der_seq_of() { fn test_der_seq_of_incomplete() { let bytes = [0x30, 0x07, 0x02, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00]; fn parser(i: &[u8]) -> DerResult { - parse_der_sequence_of!(i, parse_der_integer) + parse_der_sequence_of(parse_der_integer)(i) } assert_eq!(parser(&bytes), Err(Err::Failure(BerError::InvalidTag))); // @@ -250,7 +265,7 @@ fn test_der_set_of() { DerObject::from_int_slice(b"\x01\x00\x00"), ]); fn parser(i: &[u8]) -> DerResult { - parse_der_set_of!(i, parse_der_integer) + parse_der_set_of(parse_der_integer)(i) } assert_eq!(parser(&bytes), Ok((empty, expected))); } @@ -293,13 +308,13 @@ fn test_der_contextspecific() { let expected = DerObject { header: BerObjectHeader::new(BerClass::ContextSpecific, 1, BerTag(0), 3) .with_raw_tag(Some(&[0xa0])), - content: BerObjectContent::Unknown(BerTag(0), &bytes[2..]), + content: BerObjectContent::Unknown(BerClass::ContextSpecific, BerTag(0), &bytes[2..]), }; assert_eq!(parse_der(&bytes), Ok((empty, expected))); } #[test] -fn test_der_explicit() { +fn test_der_explicit_optional() { let empty = &b""[..]; let bytes = [0xa0, 0x03, 0x02, 0x01, 0x02]; let header = BerObjectHeader::new(BerClass::ContextSpecific, 1, BerTag(0), 3) @@ -316,12 +331,12 @@ fn test_der_explicit() { )))), }; assert_eq!( - parse_der_explicit(&bytes, BerTag(0), parse_der_integer), + parse_der_explicit_optional(&bytes, BerTag(0), parse_der_integer), Ok((empty, expected)) ); let expected2 = DerObject::from_obj(BerObjectContent::Optional(None)); assert_eq!( - parse_der_explicit(&bytes, BerTag(1), parse_der_integer), + parse_der_explicit_optional(&bytes, BerTag(1), parse_der_integer), Ok((&bytes[..], expected2)) ); } @@ -396,10 +411,16 @@ fn test_der_optional() { DerObject::from_int_slice(b"\x01\x00\x01"), ]); fn parse_optional_enum(i: &[u8]) -> DerResult { - parse_der_optional!(i, parse_der_enum) + parse_ber_optional(parse_der_enum)(i) } fn parser(i: &[u8]) -> DerResult { - parse_der_sequence_defined!(i, parse_optional_enum >> parse_der_integer) + parse_der_sequence_defined( + // the nom `tuple` combinator returns a tuple, so we have to map it + // to a list + map(tuple((parse_optional_enum, parse_der_integer)), |(a, b)| { + vec![a, b] + }), + )(i) } assert_eq!(parser(&bytes1), Ok((empty, expected1))); assert_eq!(parser(&bytes2), Ok((empty, expected2))); @@ -458,66 +479,33 @@ fn test_der_seq_dn_defined() { ]); #[inline] fn parse_directory_string(i: &[u8]) -> DerResult { - alt!( - i, - parse_der_utf8string | parse_der_printablestring | parse_der_ia5string - ) + alt(( + parse_der_utf8string, + parse_der_printablestring, + parse_der_ia5string, + ))(i) } #[inline] fn parse_attr_type_and_value(i: &[u8]) -> DerResult { - parse_der_sequence_defined!(i, parse_der_oid >> parse_directory_string) + parse_der_sequence_defined( + // the nom `tuple` combinator returns a tuple, so we have to map it + // to a list + map(tuple((parse_der_oid, parse_directory_string)), |(a, b)| { + vec![a, b] + }), + )(i) } #[inline] fn parse_rdn(i: &[u8]) -> DerResult { - parse_der_set_defined!(i, parse_attr_type_and_value) + parse_der_set_of(parse_attr_type_and_value)(i) } #[inline] fn parse_name(i: &[u8]) -> DerResult { - parse_der_sequence_defined!(i, parse_rdn >> parse_rdn >> parse_rdn) + parse_der_sequence_of(parse_rdn)(i) } assert_eq!(parse_name(&bytes), Ok((empty, expected))); } -#[test] -fn test_der_defined_seq_macros() { - fn localparse_seq(i: &[u8]) -> DerResult { - parse_der_sequence_defined_m! { - i, - parse_der_integer >> - call!(parse_der_integer) - } - } - let empty = &b""[..]; - let bytes = [ - 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, - ]; - let expected = DerObject::from_seq(vec![ - DerObject::from_int_slice(b"\x01\x00\x01"), - DerObject::from_int_slice(b"\x01\x00\x00"), - ]); - assert_eq!(localparse_seq(&bytes), Ok((empty, expected))); -} - -#[test] -fn test_der_defined_set_macros() { - fn localparse_set(i: &[u8]) -> DerResult { - parse_der_set_defined_m! { - i, - parse_der_integer >> - call!(parse_der_integer) - } - } - let empty = &b""[..]; - let bytes = [ - 0x31, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, - ]; - let expected = DerObject::from_set(vec![ - DerObject::from_int_slice(b"\x01\x00\x01"), - DerObject::from_int_slice(b"\x01\x00\x00"), - ]); - assert_eq!(localparse_set(&bytes), Ok((empty, expected))); -} - #[test_case(&hex!("02 01 01"), Ok(1) ; "u32-1")] #[test_case(&hex!("02 01 ff"), Err(BerError::IntegerNegative) ; "negative integer")] #[test_case(&hex!("02 02 00 ff"), Ok(255) ; "u32-255")] diff --git a/tests/macros.rs b/tests/macros.rs deleted file mode 100644 index 361fee9..0000000 --- a/tests/macros.rs +++ /dev/null @@ -1,129 +0,0 @@ -#![allow(deprecated)] - -use der_parser::ber::{parse_ber_integer, BerObject}; -use der_parser::der::{parse_der_enum, parse_der_integer}; -use der_parser::error::{BerResult, DerResult}; -use der_parser::*; -use nom::map_res; - -// Do not import nom, to check types and re-exports - -// all following functions are declared to check if macros from -// der-parser can be used without importing nom or rusticata_macros - -#[derive(Debug, PartialEq)] -struct MyStruct<'a> { - a: BerObject<'a>, - b: BerObject<'a>, -} - -#[allow(dead_code)] -fn parse_seq_m(i: &[u8]) -> DerResult { - parse_der_sequence_defined_m! { - i, - parse_der_integer >> - parse_der_integer - } -} - -#[allow(dead_code)] -fn parse_set_m(i: &[u8]) -> DerResult { - parse_der_set_defined_m! { - i, - parse_der_integer >> - parse_der_integer - } -} - -#[allow(dead_code)] -fn parse_seq(i: &[u8]) -> DerResult { - parse_der_sequence_defined! { - i, - parse_der_integer >> - parse_der_integer - } -} - -#[allow(dead_code)] -fn parse_set(i: &[u8]) -> DerResult { - parse_der_set_defined! { - i, - parse_der_integer >> - parse_der_integer - } -} - -#[allow(dead_code)] -fn parse_seq_of_int(i: &[u8]) -> DerResult { - parse_der_sequence_of!(i, parse_der_integer) -} - -#[allow(dead_code)] -fn parse_set_of_int(i: &[u8]) -> DerResult { - parse_der_set_of!(i, parse_der_integer) -} - -#[allow(dead_code)] -fn parse_optional_enum(i: &[u8]) -> BerResult { - parse_der_optional!(i, parse_der_enum) -} - -#[allow(dead_code)] -fn parse_struct01(i: &[u8]) -> BerResult { - parse_der_struct!( - i, - a: parse_ber_integer >> b: parse_ber_integer >> (MyStruct { a, b }) - ) -} - -#[allow(dead_code)] -fn parse_tagged_int(i: &[u8]) -> BerResult { - parse_der_tagged!(i, EXPLICIT 2, parse_ber_integer) -} - -#[derive(Debug, PartialEq)] -struct SimpleStruct { - a: u32, -} - -#[allow(dead_code)] -fn parse_app_int(i: &[u8]) -> BerResult { - parse_der_application!( - i, - APPLICATION 2, - a: map_res!(parse_ber_integer,|x: BerObject| x.as_u32()) >> - ( SimpleStruct{ a } ) - ) -} - -#[rustfmt::skip::macros(oid)] -#[test] -fn oid_macro() { - let abs = oid!(1.2.44.233.0.124_982_9_348248912829838230928); - assert!(!abs.relative); - if cfg!(feature = "bigint") { - assert_eq!(abs.to_string(), "1.2.44.233.0.1249829348248912829838230928"); - } else { - assert_eq!( - abs.to_string(), - "2a 2c 81 69 00 c0 ce d6 d1 ba fd 8e c7 e5 dc ee 8b 10" - ); - } - - let rel = oid!(rel 1.2.44.233); - assert!(rel.relative); - assert_eq!(rel.to_id_string(), "1.2.44.233"); - assert_eq!(format!("{:?}", &rel), "OID(rel. 1.2.44.233)") -} - -#[test] -fn oid_macro_edge_cases() { - let undef = oid!(0); - assert_eq!(undef.bytes(), [0].as_ref()); - - let two = oid!(1.2); - assert_eq!(two.bytes(), [40 + 2].as_ref()); - - let spacing = oid!(5.2); - assert_eq!(spacing.bytes(), [5 * 40 + 2].as_ref()); -} diff --git a/tests/oid.rs b/tests/oid.rs index 7f04b53..5cffad4 100644 --- a/tests/oid.rs +++ b/tests/oid.rs @@ -1,5 +1,6 @@ //! Test the API provided to compare OIDs +extern crate alloc; use der_parser::oid; use der_parser::oid::Oid; diff --git a/tests/primitive.rs b/tests/primitive.rs index ae40317..4c07b0a 100644 --- a/tests/primitive.rs +++ b/tests/primitive.rs @@ -1,3 +1,4 @@ +extern crate alloc; use der_parser::ber::*; use der_parser::der::*; use der_parser::error::*; @@ -88,13 +89,21 @@ fn test_unknown_tag() { assert!(res.0.is_empty()); assert_eq!( res.1, - BerObject::from_obj(BerObjectContent::Unknown(BerTag(0x1d), &bytes[2..])) + BerObject::from_obj(BerObjectContent::Unknown( + BerClass::Universal, + BerTag(0x1d), + &bytes[2..] + )) ); let res = parse_der(&bytes).expect("parsing failed"); assert!(res.0.is_empty()); assert_eq!( res.1, - BerObject::from_obj(BerObjectContent::Unknown(BerTag(0x1d), &bytes[2..])) + BerObject::from_obj(BerObjectContent::Unknown( + BerClass::Universal, + BerTag(0x1d), + &bytes[2..] + )) ); } @@ -108,7 +117,7 @@ fn test_unknown_context_specific() { BerObject { header: BerObjectHeader::new(BerClass::ContextSpecific, 0, BerTag(0), 1) .with_raw_tag(Some(&[0x80])), - content: BerObjectContent::Unknown(BerTag(0x0), &bytes[2..]), + content: BerObjectContent::Unknown(BerClass::ContextSpecific, BerTag(0x0), &bytes[2..]), } ); } @@ -123,7 +132,11 @@ fn test_unknown_long_tag() { BerObject { header: BerObjectHeader::new(BerClass::ContextSpecific, 0, BerTag(0x22), 1) .with_raw_tag(Some(&[0x9f, 0x22])), - content: BerObjectContent::Unknown(BerTag(0x22), &bytes[3..]), + content: BerObjectContent::Unknown( + BerClass::ContextSpecific, + BerTag(0x22), + &bytes[3..] + ), } ); } @@ -138,7 +151,11 @@ fn test_unknown_longer_tag() { BerObject { header: BerObjectHeader::new(BerClass::ContextSpecific, 0, BerTag(0x1122), 1) .with_raw_tag(Some(&[0x9f, 0xa2, 0x22])), - content: BerObjectContent::Unknown(BerTag(0x1122), &bytes[4..]), + content: BerObjectContent::Unknown( + BerClass::ContextSpecific, + BerTag(0x1122), + &bytes[4..] + ), } ); } -- cgit v1.2.3