diff options
author | Joel Galenson <jgalenson@google.com> | 2021-08-11 16:13:31 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-08-11 16:13:31 +0000 |
commit | 8a9d08102c0bfecc31490086c638aed5aec660c7 (patch) | |
tree | af1fe68b60da42b29f3da153cc234358a765fc17 | |
parent | dbab207c1943ec31e6a08fa561337eac4b6c5bbe (diff) | |
parent | b83de0384b622c77d95b5675b92a7725df4352ba (diff) | |
download | der-parser-8a9d08102c0bfecc31490086c638aed5aec660c7.tar.gz |
Merge "Revert "Upgrade rust/crates/der-parser to 5.1.2"" am: b83de0384b
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/der-parser/+/1792934
Change-Id: I01d7f60394dda1e6854e56edc9337249af781a29
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | CHANGELOG.md | 16 | ||||
-rw-r--r-- | Cargo.toml | 88 | ||||
-rw-r--r-- | Cargo.toml.orig | 52 | ||||
-rw-r--r-- | METADATA | 9 | ||||
-rw-r--r-- | README.md | 24 | ||||
-rw-r--r-- | benches/bench.rs | 101 | ||||
-rw-r--r-- | cargo2android.json | 2 | ||||
-rw-r--r-- | der-oid-macro/Cargo.toml | 18 | ||||
-rw-r--r-- | der-oid-macro/src/lib.rs | 139 | ||||
-rw-r--r-- | fuzz/.gitignore | 5 | ||||
-rw-r--r-- | fuzz/Cargo.toml | 30 | ||||
-rw-r--r-- | fuzz/fuzz_targets/fuzz_parse_ber.rs | 8 | ||||
-rw-r--r-- | fuzz/fuzz_targets/fuzz_parse_der.rs | 8 | ||||
-rw-r--r-- | patches/bitvec_dep.patch | 8 | ||||
-rw-r--r-- | src/ber/ber.rs | 218 | ||||
-rw-r--r-- | src/ber/integer.rs | 130 | ||||
-rw-r--r-- | src/ber/mod.rs | 6 | ||||
-rw-r--r-- | src/ber/parser.rs | 70 | ||||
-rw-r--r-- | src/ber/print.rs | 13 | ||||
-rw-r--r-- | src/ber/serialize.rs | 8 | ||||
-rw-r--r-- | src/der/mod.rs | 4 | ||||
-rw-r--r-- | src/der/parser.rs | 68 | ||||
-rw-r--r-- | src/error.rs | 14 | ||||
-rw-r--r-- | src/lib.rs | 31 | ||||
-rw-r--r-- | src/oid.rs | 30 | ||||
-rw-r--r-- | tests/ber_parser.rs | 83 | ||||
-rw-r--r-- | tests/der_parser.rs | 28 | ||||
-rw-r--r-- | tests/macros.rs | 1 | ||||
-rw-r--r-- | tests/oid.rs | 1 | ||||
-rw-r--r-- | tests/primitive.rs | 1 |
32 files changed, 540 insertions, 677 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index d5c766e..3c083e8 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "c8adf28076c11651618bcf414a20ecd0bd896315" + "sha1": "ebbea4bd6d42ad878ca2b9cdc53291f4ae19481a" } } @@ -48,6 +48,7 @@ rust_library { features: [ "bigint", "num-bigint", + "std", ], rustlibs: [ "libnom", diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bc3295..3f676f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,22 +8,6 @@ ### Thanks -## 5.1.2 - -### Changed/Fixed - -- Make `BerError` Copy + Clone -- Fix clippy warnings (rustc 1.54) - -## 5.1.1 - -### Changed/Fixed - -- BER: raise error if using Indefinite length and not constructed -- Fix `INTEGER` signed/unsigned parsing (#49) -- Fix INTEGER signed/unsigned parsing for bigint/biguint (#49) -- Doc: clarify documentation for parsing integers (#49) - ## 5.1.0 ### Changed/Fixed @@ -1,61 +1,53 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# 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 -# -# 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) - [package] -edition = "2018" -name = "der-parser" -version = "5.1.2" -authors = ["Pierre Chifflier <chifflier@wzdftpd.net>"] -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" -homepage = "https://github.com/rusticata/der-parser" -readme = "README.md" -keywords = ["BER", "DER", "ASN1", "parser", "nom"] -categories = ["parser-implementations"] license = "MIT/Apache-2.0" +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.0" +authors = ["Pierre Chifflier <chifflier@wzdftpd.net>"] +categories = ["parser-implementations"] +readme = "README.md" +edition = "2018" + +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", +] + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] -[dependencies.cookie-factory] -version = "0.3.0" -optional = true - -[dependencies.der-oid-macro] -version = "0.4" -[dependencies.nom] -version = "6.0" +[dependencies] +cookie-factory = { version="0.3.0", optional=true } +nom = "6.0" +rusticata-macros = "3.1" +num-traits = "0.2" +num-bigint = { version = "0.4", optional = true } -[dependencies.num-bigint] -version = "0.4" -optional = true - -[dependencies.num-traits] -version = "0.2" - -[dependencies.rusticata-macros] -version = "3.0.1" -[dev-dependencies.hex-literal] -version = "0.3" - -[dev-dependencies.pretty_assertions] -version = "0.7" - -[dev-dependencies.test-case] -version = "1.0" +der-oid-macro = { version = "0.4", path = "./der-oid-macro" } [features] +default = ["std"] bigint = ["num-bigint"] -default = [] -serialize = ["cookie-factory"] +serialize = ["std", "cookie-factory"] unstable = [] +std = [] + +[dev-dependencies] +hex-literal = "0.3" +pretty_assertions = "0.7" +test-case = "1.0" diff --git a/Cargo.toml.orig b/Cargo.toml.orig deleted file mode 100644 index e2a6c3f..0000000 --- a/Cargo.toml.orig +++ /dev/null @@ -1,52 +0,0 @@ -[package] -description = "Parser/encoder for ASN.1 BER/DER data" -license = "MIT/Apache-2.0" -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" -authors = ["Pierre Chifflier <chifflier@wzdftpd.net>"] -categories = ["parser-implementations"] -readme = "README.md" -edition = "2018" - -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", -] - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[dependencies] -cookie-factory = { version="0.3.0", optional=true } -nom = "6.0" -rusticata-macros = "3.0.1" -num-traits = "0.2" -num-bigint = { version = "0.4", optional = true } - -der-oid-macro = { version = "0.4", path = "./der-oid-macro" } - -[features] -default = [] -bigint = ["num-bigint"] -serialize = ["cookie-factory"] -unstable = [] - -[dev-dependencies] -hex-literal = "0.3" -pretty_assertions = "0.7" -test-case = "1.0" @@ -7,13 +7,14 @@ 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-5.1.0.crate" } - version: "5.1.2" + version: "5.1.0" + # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same. license_type: NOTICE last_upgrade_date { year: 2021 - month: 8 - day: 9 + month: 7 + day: 20 } } @@ -5,7 +5,7 @@ [![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) @@ -47,7 +47,7 @@ See the related modules for object definitions, functions, and example: ## Examples -Parse two BER integers (see [BER/DER Integers](#berder-integers)): +Parse two BER integers: ```rust use der_parser::ber::parse_ber_integer; @@ -151,19 +151,10 @@ Note that this type is also a `Result`, so usual functions (`map`, `unwrap` etc. DER integers can be of any size, so it is not possible to store them as simple integers (they are stored as raw bytes). -Note that, by default, BER/DER integers are signed. Functions are provided to request reading -unsigned values, but they will fail if the integer value is negative. - -To get the integer value for all possible integer sign and size, use -[`BerObject::as_bigint`](https://docs.rs/der-parser/latest/der_parser/ber/struct.BerObject.html#method.as_bigint)) (requires the `bigint` feature). - -To get a simple value expected to be in a known range, use methods like -[`BerObject::as_i32`](ber/struct.BerObject.html#method.as_i32)) and -[`BerObject::as_i64`](ber/struct.BerObject.html#method.as_i64) (or the unsigned versions -[`BerObject::as_u32`](ber/struct.BerObject.html#method.as_u32) and -[`BerObject::as_u64`](ber/struct.BerObject.html#method.as_u64) -), -which will return the value, or an error if the integer is too large (or is negative). +To get a simple value, use [`BerObject::as_u32`](ber/struct.BerObject.html#method.as_u32) +(knowning that this method will return an error if the integer is too large), +[`BerObject::as_u64`](ber/struct.BerObject.html#method.as_u64), or use the `bigint` feature of +this crate and use [`BerObject::as_bigint`](https://docs.rs/der-parser/latest/der_parser/ber/struct.BerObject.html#method.as_bigint). ```rust use der_parser::ber::*; @@ -172,9 +163,6 @@ let data = &[0x02, 0x03, 0x01, 0x00, 0x01]; 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())) ``` Access to the raw value is possible using the `as_slice` method. diff --git a/benches/bench.rs b/benches/bench.rs new file mode 100644 index 0000000..5a0616e --- /dev/null +++ b/benches/bench.rs @@ -0,0 +1,101 @@ +#![cfg(feature = "unstable")] +#![cfg(all(feature = "unstable", test))] +#![feature(test)] + +extern crate test; +use test::Bencher; + +use der_parser::ber::{BerClass, BerObjectHeader, BerTag}; +use der_parser::der::{ + der_read_element_header, parse_der, parse_der_integer, parse_der_u32, DerObject, +}; +use der_parser::error::DerResult; +use der_parser::*; +use hex_literal::hex; +use nom::{map, map_res}; + +#[bench] +fn bench_der_read_element_header(b: &mut Bencher) { + let bytes = hex!("0c 0a 53 6f 6d 65 2d 53 74 61 74 65"); + b.iter(|| { + let res = der_read_element_header(&bytes); + match res { + Ok((_rem, hdr)) => { + assert_eq!( + hdr, + BerObjectHeader::new(BerClass::Universal, 0, BerTag(12), 10) + .with_raw_tag(Some(&[0xc])) + ); + } + _ => assert!(false), + } + }); +} + +#[bench] +fn bench_der_map_res_integer_u32(b: &mut Bencher) { + let bytes = hex!("02 04 01 23 45 67"); + b.iter(|| { + let res = map_res!(&bytes as &[u8], parse_der_integer, |x: DerObject| x + .as_u32()); + match res { + Ok((_rem, i)) => { + assert_eq!(i, 0x0123_4567); + } + _ => assert!(false), + } + }); +} + +#[bench] +fn bench_parse_der_u32(b: &mut Bencher) { + let bytes = hex!("02 04 01 23 45 67"); + b.iter(|| { + let res = parse_der_u32(&bytes); + match res { + Ok((_rem, i)) => { + assert_eq!(i, 0x0123_4567); + } + _ => assert!(false), + } + }); +} + +#[bench] +fn bench_parse_der_seq(b: &mut Bencher) { + let bytes = hex!("30 0a 02 03 01 00 01 02 03 01 00 00"); + b.iter(|| { + let res = parse_der(&bytes); + let expected = DerObject::from_seq(vec![ + DerObject::from_int_slice(b"\x01\x00\x01"), + DerObject::from_int_slice(b"\x01\x00\x00"), + ]); + match res { + Ok((_rem, i)) => { + assert_eq!(i, expected); + } + _ => assert!(false), + } + }); +} + +#[bench] +fn bench_parse_der_seq_macros(b: &mut Bencher) { + fn localparse_seq(i: &[u8]) -> DerResult { + parse_der_sequence_defined!(i, parse_der_integer >> parse_der_integer) + } + let bytes = hex!("30 0a 02 03 01 00 01 02 03 01 00 00"); + b.iter(|| { + let res = localparse_seq(&bytes); + let expected = DerObject::from_seq(vec![ + DerObject::from_int_slice(b"\x01\x00\x01"), + DerObject::from_int_slice(b"\x01\x00\x00"), + ]); + match res { + Ok((_rem, i)) => { + assert_eq!(i, expected); + } + _ => assert!(false), + } + }); +} diff --git a/cargo2android.json b/cargo2android.json index fd3c228..323332c 100644 --- a/cargo2android.json +++ b/cargo2android.json @@ -1,6 +1,6 @@ { "device": true, - "features": "bigint", + "features": "std,bigint", "run": true } diff --git a/der-oid-macro/Cargo.toml b/der-oid-macro/Cargo.toml new file mode 100644 index 0000000..fbf8a6f --- /dev/null +++ b/der-oid-macro/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "der-oid-macro" +description = "Macro to encode DER oids at compile time" +version = "0.4.0" +edition = "2018" +license = "MIT/Apache-2.0" +homepage = "https://github.com/rusticata/der-parser" +repository = "https://github.com/rusticata/der-parser.git" +authors = ["Pierre Chifflier <chifflier@wzdftpd.net>", "Jannik Schürg <schuerg@ins.uni-bonn.de>"] + +[lib] +proc-macro = true + +[dependencies] +nom = "6.0" +num-bigint = "0.4" +num-traits = "0.2" +syn = "1.0" diff --git a/der-oid-macro/src/lib.rs b/der-oid-macro/src/lib.rs new file mode 100644 index 0000000..e12a16b --- /dev/null +++ b/der-oid-macro/src/lib.rs @@ -0,0 +1,139 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +fn parse_arg(arg: &str) -> (bool, bool, Vec<&str>) { + use nom::{ + bytes::complete::{tag, take_while}, + call, + character::complete::{char, digit1}, + combinator::{map, opt, recognize, verify}, + error::{ErrorKind, ParseError}, + exact, + multi::separated_list1, + sequence::{delimited, terminated, tuple}, + IResult, + }; + + fn uint<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> { + verify(recognize(separated_list1(char('_'), digit1)), |s: &str| { + s.len() == 1 || !s.starts_with('0') + })(i) + } + + fn ws<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> { + take_while(|c| c == ' ')(i) + } + + fn ws_dot_ws<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, char, E> { + delimited(ws, char('.'), ws)(i) + } + + fn root<'a, E: ParseError<&'a str>>( + i: &'a str, + ) -> IResult<&'a str, (bool, bool, Vec<&'a str>), E> { + tuple(( + map(opt(terminated(tag("raw "), ws)), |x| x.is_some()), + map(opt(terminated(tag("rel "), ws)), |x| x.is_some()), + separated_list1(ws_dot_ws, uint), + ))(i) + } + + exact!(arg.trim(), call!(root::<(&str, ErrorKind)>)) + .expect("could not parse oid") + .1 +} + +fn encode_components(components: &[num_bigint::BigUint], relative: bool) -> Vec<u8> { + use num_traits::cast::ToPrimitive; + + let mut enc = Vec::new(); + let mut dec = components; + if !relative { + if dec.len() < 2 { + if dec.len() == 1 && dec[0] == 0u8.into() { + return vec![0]; + } + panic!("Need at least two components for non-relative oid"); + } + if dec[0] >= 7u8.into() || dec[1] >= 40u8.into() { + panic!("First components are too big"); + } + enc.push(dec[0].to_u8().unwrap() * 40 + dec[1].to_u8().unwrap()); + dec = &dec[2..]; + } + + for int in dec.iter() { + let mut bytes = int.to_bytes_be(); + if bytes[0] == 0 { + enc.push(0u8); + continue; + } + let total_bits = (8 - bytes[0].leading_zeros()) as usize + (bytes.len() - 1) * 8; + let octects_needed = ((total_bits + 6) / 7).max(1); + enc.resize_with(enc.len() + octects_needed, Default::default); + + let mut pos = enc.len() - 1; + let mut extra = 0u8; + let mut extra_size = 0u8; + bytes.reverse(); + let mut bytes_stored = 0; + for byte in bytes.into_iter() { + if extra_size == 7 { + // there a seven bits in extra + enc[pos] = extra | (1 << 7); + bytes_stored += 1; + pos -= 1; + extra = 0; + extra_size = 0; + } + // make space for the extra bits + enc[pos] = (byte << extra_size) | extra | (1 << 7); + bytes_stored += 1; + if pos > 0 { + pos -= 1; + extra_size += 1; + extra = byte >> (8 - extra_size); + } + } + let last = enc.len() - 1; + if bytes_stored != octects_needed { + let first = last + 1 - octects_needed; + enc[first] = extra | (1 << 7); + } + enc[last] ^= 1 << 7; + } + enc +} + +#[proc_macro] +pub fn oid(item: TokenStream) -> TokenStream { + let arg = item.to_string(); + let (raw, relative, int_strings) = parse_arg(&arg); + let ints: Vec<num_bigint::BigUint> = int_strings + .into_iter() + .map(|s| s.parse().unwrap()) + .collect(); + let enc = encode_components(&ints, relative); + + let mut s = String::with_capacity(2 + 6 * enc.len()); + s.push('['); + for byte in enc.iter() { + s.insert_str(s.len(), &format!("0x{:02x}, ", byte)); + } + s.push(']'); + + let code = if raw { + format!("{{extern crate alloc; {}}}", s) + } else if relative { + format!( + "{{extern crate alloc; der_parser::oid::Oid::new_relative(alloc::borrow::Cow::Borrowed(&{}))}}", + s + ) + } else { + format!( + "{{extern crate alloc; der_parser::oid::Oid::new(alloc::borrow::Cow::Borrowed(&{}))}}", + s + ) + }; + code.parse().unwrap() +} diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..dfeb7db --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,5 @@ + +target +libfuzzer +corpus +artifacts diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..f85b6c9 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,30 @@ + +[package] +name = "der-parser-fuzz" +version = "0.0.1" +authors = ["Automatically generated"] +publish = false + +[package.metadata] +cargo-fuzz = true + +[dependencies.der-parser] +path = ".." +[dependencies.libfuzzer-sys] +git = "https://github.com/rust-fuzz/libfuzzer-sys.git" + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "fuzz_parse_der" +path = "fuzz_targets/fuzz_parse_der.rs" +test = false +doc = false + +[[bin]] +name = "fuzz_parse_ber" +path = "fuzz_targets/fuzz_parse_ber.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/fuzz_parse_ber.rs b/fuzz/fuzz_targets/fuzz_parse_ber.rs new file mode 100644 index 0000000..bd4c55c --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_parse_ber.rs @@ -0,0 +1,8 @@ +#![no_main] +extern crate libfuzzer_sys; +use libfuzzer_sys::fuzz_target; + +fuzz_target!(|data: &[u8]| { + // fuzzed code goes here + let _ = der_parser::parse_ber(data); +}); diff --git a/fuzz/fuzz_targets/fuzz_parse_der.rs b/fuzz/fuzz_targets/fuzz_parse_der.rs new file mode 100644 index 0000000..267baa5 --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_parse_der.rs @@ -0,0 +1,8 @@ +#![no_main] +extern crate libfuzzer_sys; +extern crate der_parser; +#[export_name="rust_fuzzer_test_input"] +pub extern fn go(data: &[u8]) { + // fuzzed code goes here + let _ = der_parser::parse_der(data); +} diff --git a/patches/bitvec_dep.patch b/patches/bitvec_dep.patch index 40bad0b..d38d8aa 100644 --- a/patches/bitvec_dep.patch +++ b/patches/bitvec_dep.patch @@ -3,13 +3,13 @@ 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; + use core::convert::TryFrom; + use core::fmt; + use core::ops::Index; +#[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> { } diff --git a/src/ber/ber.rs b/src/ber/ber.rs index e7bd384..e89b6c8 100644 --- a/src/ber/ber.rs +++ b/src/ber/ber.rs @@ -1,16 +1,17 @@ -use crate::ber::bitstring_to_u64; -use crate::ber::integer::*; +use crate::ber::{bitstring_to_u64, bytes_to_u64}; use crate::error::BerError; use crate::oid::Oid; +use alloc::borrow::ToOwned; +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::convert::AsRef; +use core::convert::From; +use core::convert::TryFrom; +use core::fmt; +use core::ops::Index; #[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; -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,6 +184,8 @@ pub enum BerObjectContent<'a> { Optional(Option<Box<BerObject<'a>>>), /// Tagged object (EXPLICIT): class, tag and content of inner object Tagged(BerClass, BerTag, Box<BerObject<'a>>), + /// Private + Private(BerObjectHeader<'a>, &'a [u8]), /// Unknown object: object tag (copied from header), and raw content Unknown(BerTag, &'a [u8]), @@ -400,47 +403,8 @@ impl<'a> BerObject<'a> { 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. - /// - /// # Examples - /// - /// ```rust - /// # use der_parser::ber::BerObject; - /// let der_int = BerObject::from_int_slice(b"\x80"); - /// assert_eq!( - /// der_int.as_i64(), - /// Ok(-128) - /// ); - /// ``` - pub fn as_i64(&self) -> Result<i64, BerError> { - self.content.as_i64() - } - - /// 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. - /// - /// # Examples - /// - /// ```rust - /// # use der_parser::ber::BerObject; - /// let der_int = BerObject::from_int_slice(b"\x80"); - /// assert_eq!( - /// der_int.as_i32(), - /// Ok(-128) - /// ); - /// ``` - pub fn as_i32(&self) -> Result<i32, BerError> { - self.content.as_i32() - } - /// Attempt to read integer value from DER object. - /// - /// This can fail if the object is not an unsigned integer, or if it is too large. - /// - /// # Examples + /// This can fail if the object is not an integer, or if it is too large. /// /// ```rust /// # use der_parser::ber::BerObject; @@ -455,10 +419,7 @@ impl<'a> BerObject<'a> { } /// Attempt to read integer value from DER object. - /// - /// This can fail if the object is not an unsigned integer, or if it is too large. - /// - /// # Examples + /// This can fail if the object is not an integer, or if it is too large. /// /// ```rust /// # extern crate der_parser; @@ -630,80 +591,9 @@ impl<'a> PartialEq<BerObjectHeader<'a>> for BerObjectHeader<'a> { } impl<'a> BerObjectContent<'a> { - /// Attempt to read a signed integer value from this object. - /// - /// This can fail if the object is not an integer, or if it is too large. - /// - /// # Examples - /// - /// ```rust - /// # use der_parser::ber::BerObject; - /// let der_int = BerObject::from_int_slice(b"\x80"); - /// assert_eq!( - /// der_int.as_i64(), - /// Ok(-128) - /// ); - /// ``` - pub fn as_i64(&self) -> Result<i64, BerError> { - if let BerObjectContent::Integer(bytes) = self { - let result = if is_highest_bit_set(bytes) { - <i64>::from_be_bytes(decode_array_int8(bytes)?) - } else { - <u64>::from_be_bytes(decode_array_uint8(bytes)?) as i64 - }; - Ok(result) - } else { - Err(BerError::InvalidTag) - } - } - - /// Attempt to read a signed integer value from this object. - /// - /// This can fail if the object is not an integer, or if it is too large. - /// - /// # Examples - /// - /// ```rust - /// # use der_parser::ber::BerObject; - /// let der_int = BerObject::from_int_slice(b"\x80"); - /// assert_eq!( - /// der_int.as_i32(), - /// Ok(-128) - /// ); - /// ``` - pub fn as_i32(&self) -> Result<i32, BerError> { - if let BerObjectContent::Integer(bytes) = self { - let result = if is_highest_bit_set(bytes) { - <i32>::from_be_bytes(decode_array_int4(bytes)?) - } else { - <u32>::from_be_bytes(decode_array_uint4(bytes)?) as i32 - }; - Ok(result) - } else { - Err(BerError::InvalidTag) - } - } - - /// Attempt to read integer value from this object. - /// - /// This can fail if the object is not an unsigned integer, or if it is too large. - /// - /// # Examples - /// - /// ```rust - /// # use der_parser::ber::BerObject; - /// let der_int = BerObject::from_int_slice(b"\x01\x00\x01"); - /// assert_eq!( - /// der_int.as_u64(), - /// Ok(0x10001) - /// ); - /// ``` pub fn as_u64(&self) -> Result<u64, BerError> { match self { - BerObjectContent::Integer(i) => { - let result = <u64>::from_be_bytes(decode_array_uint8(i)?); - Ok(result) - } + BerObjectContent::Integer(i) => bytes_to_u64(i), BerObjectContent::BitString(ignored_bits, data) => { bitstring_to_u64(*ignored_bits as usize, data) } @@ -712,30 +602,18 @@ impl<'a> BerObjectContent<'a> { } } - /// Attempt to read integer value from this object. - /// - /// This can fail if the object is not an unsigned integer, or if it is too large. - /// - /// # Examples - /// - /// ```rust - /// # extern crate der_parser; - /// # use der_parser::ber::{BerObject,BerObjectContent}; - /// let der_int = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); - /// assert_eq!( - /// der_int.as_u32(), - /// Ok(0x10001) - /// ); - /// ``` pub fn as_u32(&self) -> Result<u32, BerError> { match self { - BerObjectContent::Integer(i) => { - let result = <u32>::from_be_bytes(decode_array_uint4(i)?); - Ok(result) - } + BerObjectContent::Integer(i) => bytes_to_u64(i).and_then(|x| { + if x > u64::from(core::u32::MAX) { + Err(BerError::IntegerTooLarge) + } else { + Ok(x as u32) + } + }), 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 +621,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) @@ -774,7 +652,7 @@ impl<'a> BerObjectContent<'a> { pub fn as_optional(&'a self) -> Result<Option<&'_ BerObject<'a>>, BerError> { match *self { - BerObjectContent::Optional(Some(ref o)) => Ok(Some(o)), + BerObjectContent::Optional(Some(ref o)) => Ok(Some(&o)), BerObjectContent::Optional(None) => Ok(None), _ => Err(BerError::BerTypeError), } @@ -842,7 +720,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), } } @@ -891,6 +770,7 @@ impl<'a> BerObjectContent<'a> { BerObjectContent::GeneralString(_) => BerTag::GeneralString, BerObjectContent::Tagged(_,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 ! } @@ -899,56 +779,21 @@ impl<'a> BerObjectContent<'a> { #[cfg(feature = "bigint")] #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))] -use num_bigint::{BigInt, BigUint}; +use num_bigint::{BigInt, BigUint, Sign}; #[cfg(feature = "bigint")] #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))] impl<'a> BerObject<'a> { - /// Attempt to read an integer value from this object. - /// - /// This can fail if the object is not an integer. - /// - /// # Examples - /// - /// ```rust - /// use der_parser::ber::*; - /// - /// let data = &[0x02, 0x03, 0x01, 0x00, 0x01]; - /// - /// let (_, object) = parse_ber_integer(data).expect("parsing failed"); - /// # #[cfg(feature = "bigint")] - /// assert_eq!(object.as_bigint(), Some(65537.into())) - /// ``` pub fn as_bigint(&self) -> Option<BigInt> { match self.content { - BerObjectContent::Integer(s) => Some(BigInt::from_signed_bytes_be(s)), + BerObjectContent::Integer(s) => Some(BigInt::from_bytes_be(Sign::Plus, s)), _ => None, } } - /// Attempt to read a positive integer value from this object. - /// - /// This can fail if the object is not an integer, or is negative. - /// - /// # Examples - /// - /// ```rust - /// use der_parser::ber::*; - /// - /// let data = &[0x02, 0x03, 0x01, 0x00, 0x01]; - /// - /// let (_, object) = parse_ber_integer(data).expect("parsing failed"); - /// # #[cfg(feature = "bigint")] - /// assert_eq!(object.as_biguint(), Some(65537_u32.into())) - /// ``` pub fn as_biguint(&self) -> Option<BigUint> { match self.content { - BerObjectContent::Integer(s) => { - if is_highest_bit_set(s) { - return None; - } - Some(BigUint::from_bytes_be(s)) - } + BerObjectContent::Integer(s) => Some(BigUint::from_bytes_be(s)), _ => None, } } @@ -1068,7 +913,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<Msb0, u8>> { - BitSlice::<Msb0, _>::from_slice(self.data) + BitSlice::<Msb0, _>::from_slice(&self.data) } } @@ -1082,6 +927,7 @@ impl<'a> AsRef<[u8]> for BitStringObject<'a> { mod tests { use crate::ber::*; use crate::oid::*; + use std::string::String; #[test] fn test_der_as_u64() { diff --git a/src/ber/integer.rs b/src/ber/integer.rs deleted file mode 100644 index 1c05bec..0000000 --- a/src/ber/integer.rs +++ /dev/null @@ -1,130 +0,0 @@ -use crate::error::*; - -/// Decode an unsigned integer into a big endian byte slice with all leading -/// zeroes removed. -/// -/// Returns a byte array of the requested size containing a big endian integer. -fn remove_zeroes(bytes: &[u8]) -> Result<&[u8], BerError> { - // skip leading 0s - match bytes { - // [] => Err(BerError::DerConstraintFailed), - [0] => Ok(bytes), - // [0, byte, ..] if *byte < 0x80 => Err(BerError::DerConstraintFailed), - // [0, rest @ ..] => Ok(&rest), - [0, rest @ ..] => remove_zeroes(rest), - // [byte, ..] if *byte >= 0x80 => Err(BerError::IntegerTooLarge), - _ => Ok(bytes), - } -} - -// XXX const generics require rustc >= 1.51 -// /// Decode an unsigned integer into a byte array of the requested size -// /// containing a big endian integer. -// pub(crate) fn decode_array_uint<const N: usize>(bytes: &[u8]) -> Result<[u8; N], BerError> { -// // Check if MSB is set *before* leading zeroes -// if is_highest_bit_set(bytes) { -// return Err(BerError::IntegerNegative); -// } -// let input = remove_zeroes(bytes)?; - -// if input.len() > N { -// return Err(BerError::IntegerTooLarge); -// } - -// // Input has leading zeroes removed, so we need to add them back -// let mut output = [0u8; N]; -// assert!(input.len() <= N); -// output[N.saturating_sub(input.len())..].copy_from_slice(input); -// Ok(output) -// } - -pub(crate) fn decode_array_uint8(bytes: &[u8]) -> Result<[u8; 8], BerError> { - // Check if MSB is set *before* leading zeroes - if is_highest_bit_set(bytes) { - return Err(BerError::IntegerNegative); - } - let input = remove_zeroes(bytes)?; - - if input.len() > 8 { - return Err(BerError::IntegerTooLarge); - } - - // Input has leading zeroes removed, so we need to add them back - let mut output = [0u8; 8]; - assert!(input.len() <= 8); - output[8_usize.saturating_sub(input.len())..].copy_from_slice(input); - Ok(output) -} - -pub(crate) fn decode_array_uint4(bytes: &[u8]) -> Result<[u8; 4], BerError> { - // Check if MSB is set *before* leading zeroes - if is_highest_bit_set(bytes) { - return Err(BerError::IntegerNegative); - } - let input = remove_zeroes(bytes)?; - - if input.len() > 4 { - return Err(BerError::IntegerTooLarge); - } - - // Input has leading zeroes removed, so we need to add them back - let mut output = [0u8; 4]; - assert!(input.len() <= 4); - output[4_usize.saturating_sub(input.len())..].copy_from_slice(input); - Ok(output) -} - -// XXX const generics require rustc >= 1.51 -// /// Decode an unsigned integer of the specified size. -// /// -// /// Returns a byte array of the requested size containing a big endian integer. -// pub(crate) fn decode_array_int<const N: usize>(input: &[u8]) -> Result<[u8; N], BerError> { -// let input = remove_zeroes(input)?; - -// if input.len() > N { -// return Err(BerError::IntegerTooLarge); -// } - -// // any.tag().assert_eq(Tag::Integer)?; -// let mut output = [0xFFu8; N]; -// let offset = N.saturating_sub(input.len()); -// output[offset..].copy_from_slice(input); -// Ok(output) -// } - -pub(crate) fn decode_array_int8(input: &[u8]) -> Result<[u8; 8], BerError> { - let input = remove_zeroes(input)?; - - if input.len() > 8 { - return Err(BerError::IntegerTooLarge); - } - - // any.tag().assert_eq(Tag::Integer)?; - let mut output = [0xFFu8; 8]; - let offset = 8_usize.saturating_sub(input.len()); - output[offset..].copy_from_slice(input); - Ok(output) -} - -pub(crate) fn decode_array_int4(input: &[u8]) -> Result<[u8; 4], BerError> { - let input = remove_zeroes(input)?; - - if input.len() > 4 { - return Err(BerError::IntegerTooLarge); - } - - // any.tag().assert_eq(Tag::Integer)?; - let mut output = [0xFFu8; 4]; - let offset = 4_usize.saturating_sub(input.len()); - output[offset..].copy_from_slice(input); - Ok(output) -} - -/// Is the highest bit of the first byte in the slice 1? (if present) -#[inline] -pub(crate) fn is_highest_bit_set(bytes: &[u8]) -> bool { - bytes - .get(0) - .map(|byte| byte & 0b10000000 != 0) - .unwrap_or(false) -} diff --git a/src/ber/mod.rs b/src/ber/mod.rs index f2fa5f9..e479e47 100644 --- a/src/ber/mod.rs +++ b/src/ber/mod.rs @@ -47,7 +47,6 @@ //! ``` mod ber; -mod integer; mod multi; mod parser; mod print; @@ -62,3 +61,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..d5e7198 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<BerObjectContent> { fn ber_read_content_utf8string(i: &[u8], len: usize) -> BerResult<BerObjectContent> { 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<BerO if !bytes.iter().all(is_numeric) { 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::NumericString(s))?; Ok((i, s)) @@ -361,7 +359,7 @@ fn ber_read_content_visiblestring<'a>(i: &'a [u8], len: usize) -> BerResult<BerO 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::VisibleString(s))?; Ok((i, s)) @@ -395,7 +393,7 @@ fn ber_read_content_printablestring<'a>( 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<BerObjec if !bytes.iter().all(u8::is_ascii) { 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::IA5String(s))?; Ok((i, s)) @@ -432,7 +430,7 @@ fn ber_read_content_utctime<'a>(i: &'a [u8], len: usize) -> BerResult<BerObjectC 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::UTCTime(s))?; Ok((i, s)) @@ -451,7 +449,7 @@ fn ber_read_content_generalizedtime<'a>( 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)) @@ -1101,37 +1099,23 @@ where } } -/// Parse BER object and try to decode it as a 32-bits signed integer -/// -/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target -/// integer type. -#[inline] -pub fn parse_ber_i32(i: &[u8]) -> BerResult<i32> { - let (rem, ber) = parse_ber_integer(i)?; - let int = ber.as_i32().map_err(nom::Err::Error)?; - Ok((rem, int)) -} - -/// Parse BER object and try to decode it as a 64-bits signed integer -/// -/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target -/// integer type. -#[inline] -pub fn parse_ber_i64(i: &[u8]) -> BerResult<i64> { - let (rem, ber) = parse_ber_integer(i)?; - let int = ber.as_i64().map_err(nom::Err::Error)?; - Ok((rem, int)) -} - /// Parse BER object and try to decode it as a 32-bits unsigned integer /// /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. #[inline] pub fn parse_ber_u32(i: &[u8]) -> BerResult<u32> { - let (rem, ber) = parse_ber_integer(i)?; - let int = ber.as_u32().map_err(nom::Err::Error)?; - Ok((rem, int)) + parse_ber_container(|content, hdr| { + if hdr.tag != BerTag::Integer { + return Err(Err::Error(BerError::InvalidTag)); + } + let l = bytes_to_u64(content)?; + if l > 0xffff_ffff { + Err(Err::Error(BerError::IntegerTooLarge)) + } else { + Ok((&b""[..], l as u32)) + } + })(i) } /// Parse BER object and try to decode it as a 64-bits unsigned integer @@ -1140,9 +1124,13 @@ pub fn parse_ber_u32(i: &[u8]) -> BerResult<u32> { /// integer type. #[inline] pub fn parse_ber_u64(i: &[u8]) -> BerResult<u64> { - let (rem, ber) = parse_ber_integer(i)?; - let int = ber.as_u64().map_err(nom::Err::Error)?; - Ok((rem, int)) + parse_ber_container(|content, hdr| { + if hdr.tag != BerTag::Integer { + return Err(Err::Error(BerError::InvalidTag)); + } + let l = bytes_to_u64(content)?; + Ok((&b""[..], l)) + })(i) } /// Parse BER object and get content as slice @@ -1184,7 +1172,13 @@ 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); diff --git a/src/ber/print.rs b/src/ber/print.rs index b3ae221..2459d19 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<Vec<char>> = 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))?; diff --git a/src/ber/serialize.rs b/src/ber/serialize.rs index 7ffedc2..be7c187 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; @@ -79,7 +80,7 @@ pub fn ber_encode_tagged_explicit<'a, W: Write + Default + AsRef<[u8]> + 'a>( ) -> impl SerializeFn<W> + 'a { move |out| { // encode inner object - let v = gen_simple(ber_encode_object(obj), W::default())?; + let v = gen_simple(ber_encode_object(&obj), W::default())?; let len = v.as_ref().len(); // encode the application header, using the tag let hdr = BerObjectHeader::new(class, 1 /* X.690 8.14.2 */, tag, len); @@ -149,7 +150,7 @@ fn ber_encode_object_content<'a, W: Write + Default + AsRef<[u8]> + 'a>( | BerObjectContent::ObjectDescriptor(s) | BerObjectContent::GraphicString(s) | BerObjectContent::GeneralString(s) => slice(s)(out), - BerObjectContent::Sequence(v) | BerObjectContent::Set(v) => ber_encode_sequence(v)(out), + BerObjectContent::Sequence(v) | BerObjectContent::Set(v) => ber_encode_sequence(&v)(out), // best we can do is tagged-explicit, but we don't know BerObjectContent::Optional(inner) => { // directly encode inner object @@ -158,6 +159,7 @@ 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! @@ -178,7 +180,7 @@ pub fn ber_encode_object_raw<'a, 'b: 'a, 'c: 'a, W: Write + Default + AsRef<[u8] hdr: &'b BerObjectHeader, content: &'c BerObjectContent, ) -> impl SerializeFn<W> + 'a { - tuple((ber_encode_header(hdr), ber_encode_object_content(content))) + tuple((ber_encode_header(&hdr), ber_encode_object_content(&content))) } /// Encode object as BER 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..68e1a7f 100644 --- a/src/der/parser.rs +++ b/src/der/parser.rs @@ -5,7 +5,8 @@ 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}; + +use crate::ber::MAX_RECURSION; /// Parse DER object recursively /// @@ -381,36 +382,22 @@ where parse_ber_implicit(i, tag, f) } -/// Parse DER object and try to decode it as a 32-bits signed integer -/// -/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target -/// integer type. -#[inline] -pub fn parse_der_i32(i: &[u8]) -> BerResult<i32> { - let (rem, der) = parse_der_integer(i)?; - let int = der.as_i32().map_err(nom::Err::Error)?; - Ok((rem, int)) -} - -/// Parse DER object and try to decode it as a 64-bits signed integer -/// -/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target -/// integer type. -#[inline] -pub fn parse_der_i64(i: &[u8]) -> BerResult<i64> { - let (rem, der) = parse_der_integer(i)?; - let int = der.as_i64().map_err(nom::Err::Error)?; - Ok((rem, int)) -} - /// Parse DER object and try to decode it as a 32-bits unsigned integer /// /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. pub fn parse_der_u32(i: &[u8]) -> BerResult<u32> { - let (rem, der) = parse_der_integer(i)?; - let int = der.as_u32().map_err(nom::Err::Error)?; - Ok((rem, int)) + parse_der_container(|content, hdr| { + if hdr.tag != DerTag::Integer { + return Err(Err::Error(BerError::InvalidTag)); + } + let l = bytes_to_u64(content)?; + if l > 0xffff_ffff { + Err(Err::Error(BerError::IntegerTooLarge)) + } else { + Ok((&b""[..], l as u32)) + } + })(i) } /// Parse DER object and try to decode it as a 64-bits unsigned integer @@ -418,9 +405,13 @@ pub fn parse_der_u32(i: &[u8]) -> BerResult<u32> { /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. pub fn parse_der_u64(i: &[u8]) -> BerResult<u64> { - let (rem, der) = parse_der_integer(i)?; - let int = der.as_u64().map_err(nom::Err::Error)?; - Ok((rem, int)) + parse_der_container(|content, hdr| { + if hdr.tag != DerTag::Integer { + return Err(Err::Error(BerError::InvalidTag)); + } + let l = bytes_to_u64(content)?; + Ok((&b""[..], l)) + })(i) } /// Parse DER object and get content as slice @@ -527,17 +518,6 @@ pub fn der_read_element_content_as( // exception: read and verify padding bits return der_read_content_bitstring(i, l); } - DerTag::Integer => { - // verify leading zeros - match i[..l] { - [] => return Err(nom::Err::Error(BerError::DerConstraintFailed)), - [0, 0, ..] => return Err(nom::Err::Error(BerError::DerConstraintFailed)), - [0, byte, ..] if byte < 0x80 => { - return Err(nom::Err::Error(BerError::DerConstraintFailed)); - } - _ => (), - } - } DerTag::NumericString | DerTag::VisibleString | DerTag::PrintableString @@ -575,7 +555,13 @@ 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); diff --git a/src/error.rs b/src/error.rs index 803bdee..958236b 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 /// @@ -22,7 +21,7 @@ pub type BerResult<'a, O = BerObject<'a>> = IResult<&'a [u8], O, BerError>; pub type DerResult<'a> = BerResult<'a, DerObject<'a>>; /// Error for BER/DER parsers -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq)] pub enum BerError { /// BER object does not have the expected type BerTypeError, @@ -45,8 +44,6 @@ pub enum BerError { /// BER integer is too large to fit in a native type. Use `as_bigint()` IntegerTooLarge, - /// BER integer is negative, while an unsigned integer was requested - IntegerNegative, /// BER recursive parsing reached maximum depth (See /// [MAX_RECURSION](../ber/constant.MAX_RECURSION.html)) @@ -97,11 +94,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() { @@ -3,7 +3,7 @@ //! [![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) //! @@ -45,7 +45,7 @@ //! //! ## Examples //! -//! Parse two BER integers (see [BER/DER Integers](#berder-integers)): +//! Parse two BER integers: //! //! ```rust //! use der_parser::ber::parse_ber_integer; @@ -149,19 +149,10 @@ //! DER integers can be of any size, so it is not possible to store them as simple integers (they //! are stored as raw bytes). //! -//! Note that, by default, BER/DER integers are signed. Functions are provided to request reading -//! unsigned values, but they will fail if the integer value is negative. -//! -//! To get the integer value for all possible integer sign and size, use -//! [`BerObject::as_bigint`](ber/struct.BerObject.html#method.as_bigint)) (requires the `bigint` feature). -//! -//! To get a simple value expected to be in a known range, use methods like -//! [`BerObject::as_i32`](ber/struct.BerObject.html#method.as_i32)) and -//! [`BerObject::as_i64`](ber/struct.BerObject.html#method.as_i64) (or the unsigned versions -//! [`BerObject::as_u32`](ber/struct.BerObject.html#method.as_u32) and -//! [`BerObject::as_u64`](ber/struct.BerObject.html#method.as_u64) -//!), -//! which will return the value, or an error if the integer is too large (or is negative). +//! To get a simple value, use [`BerObject::as_u32`](ber/struct.BerObject.html#method.as_u32) +//! (knowning that this method will return an error if the integer is too large), +//! [`BerObject::as_u64`](ber/struct.BerObject.html#method.as_u64), or use the `bigint` feature of +//! this crate and use [`BerObject::as_bigint`](ber/struct.BerObject.html#method.as_bigint). //! //! ```rust //! use der_parser::ber::*; @@ -170,9 +161,6 @@ //! //! 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())) //! ``` //! //! Access to the raw value is possible using the `as_slice` method. @@ -237,6 +225,13 @@ no_crate_inject, attr(deny(warnings/*, rust_2018_idioms*/), allow(dead_code, unused_variables)) ))] +#![no_std] + +#[cfg(any(test, feature = "std"))] +#[macro_use] +extern crate std; + +extern crate alloc; #[macro_use] mod macros; @@ -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, @@ -209,10 +214,10 @@ impl<'a> Oid<'a> { &'_ self, ) -> impl Iterator<Item = BigUint> + FusedIterator + ExactSizeIterator + '_ { SubIdentifierIterator { - oid: self, + oid: &self, pos: 0, first: false, - n: std::marker::PhantomData, + n: core::marker::PhantomData, } } @@ -245,10 +250,10 @@ impl<'a> Oid<'a> { } Some(SubIdentifierIterator { - oid: self, + 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<BigUint> = 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<u64> = oid_raw.iter().unwrap().collect(); assert_eq!(vec![0], ids); diff --git a/tests/ber_parser.rs b/tests/ber_parser.rs index 488a0c1..e5906d7 100644 --- a/tests/ber_parser.rs +++ b/tests/ber_parser.rs @@ -6,9 +6,6 @@ use nom::Err; // use pretty_assertions::assert_eq; use test_case::test_case; -#[cfg(feature = "bigint")] -use num_bigint::{BigInt, BigUint, Sign}; - #[test_case(&hex!("01 01 00"), Some(false) ; "val true")] #[test_case(&hex!("01 01 ff"), Some(true) ; "val false")] #[test_case(&hex!("01 01 7f"), Some(true) ; "true not ff")] @@ -140,10 +137,10 @@ fn test_ber_int() { } #[test_case(&hex!("02 01 01"), Ok(1) ; "u32-1")] -#[test_case(&hex!("02 02 00 ff"), Ok(255) ; "u32-255")] +#[test_case(&hex!("02 01 ff"), Ok(255) ; "u32-255")] #[test_case(&hex!("02 02 01 23"), Ok(0x123) ; "u32-0x123")] #[test_case(&hex!("02 04 01 23 45 67"), Ok(0x0123_4567) ; "u32-long-ok")] -#[test_case(&hex!("02 05 00 ff ff ff ff"), Ok(0xffff_ffff) ; "u32-long2-ok")] +#[test_case(&hex!("02 04 ff ff ff ff"), Ok(0xffff_ffff) ; "u32-long2-ok")] #[test_case(&hex!("02 06 00 00 01 23 45 67"), Ok(0x0123_4567) ; "u32-long-leading-zeros-ok")] #[test_case(&hex!("02 05 01 23 45 67 01"), Err(BerError::IntegerTooLarge) ; "u32 too large")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Err(BerError::IntegerTooLarge) ; "u32 too large 2")] @@ -161,10 +158,10 @@ fn tc_ber_u32(i: &[u8], out: Result<u32, BerError>) { } #[test_case(&hex!("02 01 01"), Ok(1) ; "u64-1")] -#[test_case(&hex!("02 02 00 ff"), Ok(255) ; "u64-255")] +#[test_case(&hex!("02 01 ff"), Ok(255) ; "u64-255")] #[test_case(&hex!("02 02 01 23"), Ok(0x123) ; "u64-0x123")] #[test_case(&hex!("02 08 01 23 45 67 01 23 45 67"), Ok(0x0123_4567_0123_4567) ; "u64-long-ok")] -#[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(0xffff_ffff_ffff_ffff) ; "u64-long2-ok")] +#[test_case(&hex!("02 08 ff ff ff ff ff ff ff ff"), Ok(0xffff_ffff_ffff_ffff) ; "u64-long2-ok")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Err(BerError::IntegerTooLarge) ; "u64 too large")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_ber_u64(i: &[u8], out: Result<u64, BerError>) { @@ -179,70 +176,6 @@ fn tc_ber_u64(i: &[u8], out: Result<u64, BerError>) { } } -#[test_case(&hex!("02 01 01"), Ok(1) ; "i64-1")] -#[test_case(&hex!("02 01 ff"), Ok(-1) ; "i64-neg1")] -#[test_case(&hex!("02 01 80"), Ok(-128) ; "i64-neg128")] -#[test_case(&hex!("02 02 ff 7f"), Ok(-129) ; "i64-neg129")] -#[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] -fn tc_ber_i64(i: &[u8], out: Result<i64, BerError>) { - let res = parse_ber_i64(i); - match out { - Ok(expected) => { - pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); - } - Err(e) => { - pretty_assertions::assert_eq!(res, Err(Err::Error(e))); - } - } -} - -#[cfg(feature = "bigint")] -#[test_case(&hex!("02 01 01"), Ok(BigInt::from(1)) ; "bigint-1")] -#[test_case(&hex!("02 02 00 ff"), Ok(BigInt::from(255)) ; "bigint-255")] -#[test_case(&hex!("02 01 ff"), Ok(BigInt::from(-1)) ; "bigint-neg1")] -#[test_case(&hex!("02 01 80"), Ok(BigInt::from(-128)) ; "bigint-neg128")] -#[test_case(&hex!("02 02 ff 7f"), Ok(BigInt::from(-129)) ; "bigint-neg129")] -#[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(BigInt::from(0xffff_ffff_ffff_ffff_u64)) ; "bigint-long2-ok")] -#[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(BigInt::from_bytes_be(Sign::Plus, &hex!("01 23 45 67 01 23 45 67 ab"))) ; "bigint-longer1")] -fn tc_ber_bigint(i: &[u8], out: Result<BigInt, BerError>) { - let res = parse_ber_integer(i); - match out { - Ok(expected) => { - let (rem, ber) = res.expect("parsing failed"); - assert!(rem.is_empty()); - let int = ber.as_bigint().expect("failed to convert to bigint"); - pretty_assertions::assert_eq!(int, expected); - } - Err(e) => { - pretty_assertions::assert_eq!(res, Err(Err::Error(e))); - } - } -} - -#[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!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] -fn tc_ber_biguint(i: &[u8], out: Result<Option<BigUint>, BerError>) { - let res = parse_ber_integer(i); - 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); - } - Err(e) => { - pretty_assertions::assert_eq!(res, Err(Err::Error(e))); - } - } -} - #[test_case(&hex!("02 01 01"), Ok(&[1]) ; "slice 1")] #[test_case(&hex!("02 01 ff"), Ok(&[255]) ; "slice 2")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(&hex!("01 23 45 67 01 23 45 67 ab")) ; "slice 3")] @@ -543,3 +476,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/der_parser.rs b/tests/der_parser.rs index 9a31e5c..3d604b0 100644 --- a/tests/der_parser.rs +++ b/tests/der_parser.rs @@ -519,12 +519,11 @@ fn test_der_defined_set_macros() { } #[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")] +#[test_case(&hex!("02 01 ff"), Ok(255) ; "u32-255")] #[test_case(&hex!("02 02 01 23"), Ok(0x123) ; "u32-0x123")] #[test_case(&hex!("02 04 01 23 45 67"), Ok(0x0123_4567) ; "u32-long-ok")] -#[test_case(&hex!("02 04 ff ff ff ff"), Err(BerError::IntegerNegative) ; "u32-long2-neg")] -#[test_case(&hex!("02 06 00 00 01 23 45 67"), Err(BerError::DerConstraintFailed) ; "u32-long-leading-zeros")] +#[test_case(&hex!("02 04 ff ff ff ff"), Ok(0xffff_ffff) ; "u32-long2-ok")] +#[test_case(&hex!("02 06 00 00 01 23 45 67"), Ok(0x0123_4567) ; "u32-long-leading-zeros-ok")] #[test_case(&hex!("02 05 01 23 45 67 01"), Err(BerError::IntegerTooLarge) ; "u32 too large")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Err(BerError::IntegerTooLarge) ; "u32 too large 2")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] @@ -540,28 +539,11 @@ fn tc_der_u32(i: &[u8], out: Result<u32, BerError>) { } } -#[test_case(&hex!("02 01 01"), Ok(1) ; "i32-1")] -#[test_case(&hex!("02 01 ff"), Ok(-1) ; "i32-neg1")] -#[test_case(&hex!("02 01 80"), Ok(-128) ; "i32-neg128")] -#[test_case(&hex!("02 02 ff 7f"), Ok(-129) ; "i32-neg129")] -#[test_case(&hex!("02 02 00 ff"), Ok(255) ; "i32-255")] -fn tc_der_i32(i: &[u8], out: Result<i32, BerError>) { - let res = parse_der_i32(i); - match out { - Ok(expected) => { - pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); - } - Err(e) => { - pretty_assertions::assert_eq!(res, Err(Err::Error(e))); - } - } -} - #[test_case(&hex!("02 01 01"), Ok(1) ; "u64-1")] -#[test_case(&hex!("02 02 00 ff"), Ok(255) ; "u64-255")] +#[test_case(&hex!("02 01 ff"), Ok(255) ; "u64-255")] #[test_case(&hex!("02 02 01 23"), Ok(0x123) ; "u64-0x123")] #[test_case(&hex!("02 08 01 23 45 67 01 23 45 67"), Ok(0x0123_4567_0123_4567) ; "u64-long-ok")] -#[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(0xffff_ffff_ffff_ffff) ; "u64-long2-ok")] +#[test_case(&hex!("02 08 ff ff ff ff ff ff ff ff"), Ok(0xffff_ffff_ffff_ffff) ; "u64-long2-ok")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Err(BerError::IntegerTooLarge) ; "u64 too large")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_der_u64(i: &[u8], out: Result<u64, BerError>) { diff --git a/tests/macros.rs b/tests/macros.rs index 361fee9..f22c6a9 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -1,5 +1,6 @@ #![allow(deprecated)] +extern crate alloc; use der_parser::ber::{parse_ber_integer, BerObject}; use der_parser::der::{parse_der_enum, parse_der_integer}; use der_parser::error::{BerResult, DerResult}; 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..b18cf4f 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::*; |