der-parser-3.0.3/Cargo.toml.orig010064400017500001750000000016601356716424100147050ustar0000000000000000[package] description = "Parser for BER/DER encoded 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 = "3.0.3" authors = ["Pierre Chifflier "] categories = ["parser-implementations"] readme = "README.md" edition = "2018" include = [ "LICENSE-*", "README.md", ".gitignore", ".travis.yml", "Cargo.toml", "bench/*.rs", "src/*.rs", "src/ber/*.rs", "src/der/*.rs", "tests/*.rs" ] [package.metadata.docs.rs] features = [ "bigint" ] all-features = true [dependencies] nom = "5.0" rusticata-macros = "2.0.2" num-bigint = { version = "0.2", optional = true } [features] default = [] bigint = ["num-bigint"] [dev-dependencies] hex-literal = "0.2" pretty_assertions = "0.6" [badges] travis-ci = { repository = "rusticata/der-parser" } der-parser-3.0.3/Cargo.toml0000644000000027530000000000000111470ustar00# 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 = "3.0.3" authors = ["Pierre Chifflier "] include = ["LICENSE-*", "README.md", ".gitignore", ".travis.yml", "Cargo.toml", "bench/*.rs", "src/*.rs", "src/ber/*.rs", "src/der/*.rs", "tests/*.rs"] description = "Parser for BER/DER encoded 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" repository = "https://github.com/rusticata/der-parser.git" [package.metadata.docs.rs] all-features = true features = ["bigint"] [dependencies.nom] version = "5.0" [dependencies.num-bigint] version = "0.2" optional = true [dependencies.rusticata-macros] version = "2.0.2" [dev-dependencies.hex-literal] version = "0.2" [dev-dependencies.pretty_assertions] version = "0.6" [features] bigint = ["num-bigint"] default = [] [badges.travis-ci] repository = "rusticata/der-parser" der-parser-3.0.3/LICENSE-APACHE010064400017500001750000000251371322757230200137410ustar0000000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. der-parser-3.0.3/LICENSE-MIT010064400017500001750000000020441322757230200134410ustar0000000000000000Copyright (c) 2017 Pierre Chifflier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. der-parser-3.0.3/README.md010064400017500001750000000160511356716442300132770ustar0000000000000000# der-parser [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE-MIT) [![Apache License 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE-APACHE) [![Build Status](https://travis-ci.org/rusticata/der-parser.svg?branch=master)](https://travis-ci.org/rusticata/der-parser) [![Crates.io Version](https://img.shields.io/crates/v/der-parser.svg)](https://crates.io/crates/der-parser) # BER/DER Parser A parser for Basic Encoding Rules (BER [[X.690]]) and Distinguished Encoding Rules(DER [[X.690]]), implemented with the [nom](https://github.com/Geal/nom) parser combinator framework. The code is available on [Github](https://github.com/rusticata/der-parser) and is part of the [Rusticata](https://github.com/rusticata) project. # DER parser design There are two different approaches for parsing DER objects: reading the objects recursively as long as the tags are known, or specifying a description of the expected objects (generally from the [ASN.1][X.680] description). The first parsing method can be done using the [`parse_ber`](ber/fn.parse_ber.html) and [`parse_der`](der/fn.parse_der.html) methods. However, it cannot fully parse all objects, especially those containing IMPLICIT, OPTIONAL, or DEFINED BY items. ```rust use der_parser::parse_der; let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let parsed = parse_der(&bytes); ``` The second (and preferred) parsing method is to specify the expected objects recursively. The following macros can be used: [`parse_der_sequence_defined`](macro.parse_der_sequence_defined.html) and similar functions, [`parse_der_struct`](macro.parse_der_struct.html), etc. For example, to read a sequence containing two integers: ```rust use der_parser::ber::*; use der_parser::error::BerResult; fn localparse_seq(i:&[u8]) -> BerResult { parse_der_sequence_defined!(i, parse_ber_integer >> parse_ber_integer ) } let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let parsed = localparse_seq(&bytes); ``` All functions return a [`BerResult`](error/type.BerResult.html) object: the parsed [`BerObject`](ber/struct.BerObject.html), an `Incomplete` value, or an error. Note that this type is also a `Result`, so usual functions (`map`, `unwrap` etc.) are available. # Notes - The DER constraints are verified if using `parse_der`. - `BerObject` and `DerObject` are the same objects (type alias). The only difference is the verification of constraints *during parsing*. - DER integers can be of any size, so it is not possible to store them as simple integers (they are stored as raw bytes). 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). # References - [[X.680]] Abstract Syntax Notation One (ASN.1): Specification of basic notation. - [[X.690]] ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER). [X.680]: http://www.itu.int/rec/T-REC-X.680/en "Abstract Syntax Notation One (ASN.1): Specification of basic notation." [X.690]: https://www.itu.int/rec/T-REC-X.690/en "ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)." ## Changes ### 3.0.3 - Make the pretty-printer function public - Fix DER datestring sanity check - CI - add rusfmt check - add cargo clippy ### 3.0.2 - Add `parse_ber_u32` and `parse_ber_u64` functions - Fix typo in description ### 3.0.1 - Add crate `BerResult` and `DerResult` types - Use crate result types, remove uneeded imports - Crates using `der-parser` do not need to import `nom` or `rusticata-macros` anymore - Result types are aliases, so API is unchanged ### 3.0.0 - Upgrade to nom 5 (breaks API) - New error types, now all functions use `BerError` ### 2.1.0 - Handle BER/DER tags that are longer than one byte. - Set edition to 2018 ### 2.0.2 - Revert 2.0.1 release, breaks API ### 2.0.1 - Handle BER/DER tags that are longer than one byte. ### 2.0.0 - Refactor code, split BER and DER, check DER constraints - Add recursion limit for sequences and sets - Rustfmt - Documentation - Remove unused function `ber_read_element_content` ### 1.1.1 - Fix OID parsing, and add support for relative OIDs - Add FromStr trait for Oid ### 1.1.0 - Use num-bigint over num and upgrade to 0.2 ### 1.0.0 - Upgrade to nom 4 ### 0.5.5 - Add functions `parse_der_u32` and `parse_der_u64` to quickly parse integers - Remove `Oid::from_vec`, `Oid::from` does the same - Enforce constraints on DER booleans ### 0.5.4 - Add `BitStringObject` to wrap BitString objects - Mark constructed BitStrings as unsupported - Do not try to parse application-specific data in `parse_der` ### 0.5.3 - Add function `DerObject::as_u64` - Add function `DerObject::as_oid_val` - Add `parse_der_struct!` variant to check tag ### 0.5.2 - Add functions to test object class and primitive/constructed state - Add macro `parse_der_application!` - Add macro `parse_der_tagged!` to parse `[x] EXPLICIT` or `[x] IMPLICIT` tagged values ### 0.5.1 - Add type GeneralString - Add macro `parse_der_struct!` ### 0.5.0 - Allow use of crate without extra use statements - Use constants for u32 errors instead of magical numbers - Rename `tag_of_der_content()` to `DerObjectContent::tag` - Rename DerElementxxx structs to have a consistent naming scheme - Add documentation for parsing DER sequences and sets, and fix wrong return type for sets - Fix a lot of clippy warnings - QA: add pragma rules (disable unsafe code, unstable features etc.) - More documentation - Switch license to MIT + APLv2 ### 0.4.4 - Add macro parse_der_defined_m, to parse a defined sequence or set This macro differs from `parse_der_defined` because it allows using macros - Rename `DerObject::new_int` to `DerObject::from_int_slice` - Rename `Oid::to_hex` to `Oid::to_string` - Document more functions ### 0.4.1 - Add new feature 'bigint' to export DER integers - OID is now a specific type - Add new types T61String and BmpString - Fix wrong expected tag in parse_der_set_of ### 0.4.0 - Der Integers are now represented as slices (byte arrays) since they can be larger than u64. ## License Licensed under either of * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ## Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. der-parser-3.0.3/src/ber/ber.rs010064400017500001750000000476461356716373500145200ustar0000000000000000use crate::ber::bytes_to_u64; use crate::error::BerError; use crate::oid::Oid; use std::convert::AsRef; use std::convert::From; use std::ops::Index; use std::vec::Vec; /// Defined in X.680 section 8.4 /// X.690 doesn't specify the maxmimum tag size so we're assuming that people /// aren't going to need anything more than a u32. #[derive(Clone, Copy, PartialEq, Eq)] pub struct BerTag(pub u32); newtype_enum! { impl debug BerTag { EndOfContent = 0x0, Boolean = 0x1, Integer = 0x2, BitString = 0x3, OctetString = 0x4, Null = 0x05, Oid = 0x06, ObjDescriptor = 0x07, External = 0x08, RealType = 0x09, Enumerated = 0xa, EmbeddedPdv = 0xb, Utf8String = 0xc, RelativeOid = 0xd, Sequence = 0x10, Set = 0x11, NumericString = 0x12, PrintableString = 0x13, T61String = 0x14, Ia5String = 0x16, UtcTime = 0x17, GeneralizedTime = 0x18, GeneralString = 27, // 0x1b BmpString = 0x1e, Invalid = 0xff, } } /// Representation of a DER-encoded (X.690) object #[derive(Debug, Clone, PartialEq)] pub struct BerObject<'a> { pub class: u8, pub structured: u8, pub tag: BerTag, pub content: BerObjectContent<'a>, } #[derive(Clone, Copy, Debug, PartialEq)] pub struct BerObjectHeader { pub class: u8, pub structured: u8, pub tag: BerTag, pub len: u64, } #[derive(Debug, Clone, PartialEq)] pub enum BerObjectContent<'a> { EndOfContent, Boolean(bool), Integer(&'a [u8]), BitString(u8, BitStringObject<'a>), OctetString(&'a [u8]), Null, Enum(u64), OID(Oid), RelativeOID(Oid), NumericString(&'a [u8]), PrintableString(&'a [u8]), IA5String(&'a [u8]), UTF8String(&'a [u8]), T61String(&'a [u8]), BmpString(&'a [u8]), Sequence(Vec>), Set(Vec>), UTCTime(&'a [u8]), GeneralizedTime(&'a [u8]), GeneralString(&'a [u8]), ContextSpecific(BerTag, Option>>), Unknown(BerTag, &'a [u8]), } impl BerObjectHeader { /// Test if object class is Universal #[inline] pub fn is_universal(&self) -> bool { self.class == 0 } /// Test if object class is Application #[inline] pub fn is_application(&self) -> bool { self.class == 0b01 } /// Test if object class is Context-specific #[inline] pub fn is_contextspecific(&self) -> bool { self.class == 0b10 } /// Test if object class is Private #[inline] pub fn is_private(&self) -> bool { self.class == 0b11 } /// Test if object is primitive #[inline] pub fn is_primitive(&self) -> bool { self.structured == 0 } /// Test if object is constructed #[inline] pub fn is_constructed(&self) -> bool { self.structured == 1 } } impl<'a> BerObject<'a> { /// Build a BerObject from a header and content. /// Note: values are not checked, so the tag can be different from the real content, or flags /// can be invalid. pub fn from_header_and_content(hdr: BerObjectHeader, c: BerObjectContent) -> BerObject { BerObject { class: hdr.class, structured: hdr.structured, tag: hdr.tag, content: c, } } /// Build a BerObject from its content, using default flags (no class, correct tag, /// and structured flag set only for Set and Sequence) pub fn from_obj(c: BerObjectContent) -> BerObject { let class = 0; let tag = c.tag(); let structured = match tag { BerTag::Sequence | BerTag::Set => 1, _ => 0, }; BerObject { class, structured, tag, content: c, } } /// Build a DER integer object from a slice containing an encoded integer pub fn from_int_slice(i: &'a [u8]) -> BerObject<'a> { BerObject { class: 0, structured: 0, tag: BerTag::Integer, content: BerObjectContent::Integer(i), } } /// Build a DER sequence object from a vector of DER objects pub fn from_seq(l: Vec) -> BerObject { BerObject::from_obj(BerObjectContent::Sequence(l)) } /// Build a DER set object from a vector of DER objects pub fn from_set(l: Vec) -> BerObject { BerObject::from_obj(BerObjectContent::Set(l)) } /// Attempt to read integer value from DER object. /// This can fail if the object is not an integer, or if it is too large. /// /// ```rust /// # extern crate der_parser; /// # use der_parser::ber::{BerObject,BerObjectContent}; /// # fn main() { /// 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 { self.content.as_u64() } /// Attempt to read integer value from DER object. /// This can fail if the object is not an integer, or if it is too large. /// /// ```rust /// # extern crate der_parser; /// # use der_parser::ber::{BerObject,BerObjectContent}; /// # fn main() { /// 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 { self.content.as_u32() } /// Attempt to read integer value from DER object. /// This can fail if the object is not a boolean. pub fn as_bool(&self) -> Result { self.content.as_bool() } /// Attempt to read an OID value from DER object. /// This can fail if the object is not an OID. /// /// Note that this function returns a reference to the OID. To get an owned value, /// use [`as_oid_val`](struct.BerObject.html#method.as_oid_val) pub fn as_oid(&self) -> Result<&Oid, BerError> { self.content.as_oid() } /// Attempt to read an OID value from DER object. /// This can fail if the object is not an OID. pub fn as_oid_val(&self) -> Result { self.content.as_oid_val() } /// Attempt to read the content from a context-specific DER object. /// This can fail if the object is not context-specific. /// /// Note: the object is cloned. pub fn as_context_specific(&self) -> Result<(BerTag, Option>>), BerError> { self.content.as_context_specific() } /// Attempt to read a reference to a BitString value from DER object. /// This can fail if the object is not an BitString. /// /// Note that this function returns a reference to the BitString. To get an owned value, /// use [`as_bitstring`](struct.BerObject.html#method.as_bitstring) pub fn as_bitstring_ref(&self) -> Result<&BitStringObject, BerError> { self.content.as_bitstring_ref() } /// Attempt to read a BitString value from DER object. /// This can fail if the object is not an BitString. pub fn as_bitstring(&'a self) -> Result, BerError> { self.content.as_bitstring() } /// Attempt to extract the list of objects from a DER sequence. /// This can fail if the object is not a sequence. pub fn as_sequence(&self) -> Result<&Vec>, BerError> { self.content.as_sequence() } /// Attempt to extract the list of objects from a DER set. /// This can fail if the object is not a set. pub fn as_set(&self) -> Result<&Vec>, BerError> { self.content.as_set() } /// Attempt to get the content from a DER object, as a slice. /// This can fail if the object does not contain a type directly equivalent to a slice (e.g a /// sequence). /// This function mostly concerns string types, integers, or unknown DER objects. pub fn as_slice(&self) -> Result<&'a [u8], BerError> { self.content.as_slice() } /// Test if object class is Universal pub fn is_universal(&self) -> bool { self.class == 0 } /// Test if object class is Application pub fn is_application(&self) -> bool { self.class == 0b01 } /// Test if object class is Context-specific pub fn is_contextspecific(&self) -> bool { self.class == 0b10 } /// Test if object class is Private pub fn is_private(&self) -> bool { self.class == 0b11 } /// Test if object is primitive pub fn is_primitive(&self) -> bool { self.structured == 0 } /// Test if object is constructed pub fn is_constructed(&self) -> bool { self.structured == 1 } } /// Build a DER object from an OID. impl<'a> From for BerObject<'a> { fn from(oid: Oid) -> BerObject<'a> { BerObject::from_obj(BerObjectContent::OID(oid)) } } /// Build a DER object from a BerObjectContent. impl<'a> From> for BerObject<'a> { fn from(obj: BerObjectContent<'a>) -> BerObject<'a> { BerObject::from_obj(obj) } } impl<'a> BerObjectContent<'a> { pub fn as_u64(&self) -> Result { match *self { BerObjectContent::Integer(i) => bytes_to_u64(i), BerObjectContent::Enum(i) => Ok(i as u64), _ => Err(BerError::BerTypeError), } } pub fn as_u32(&self) -> Result { match *self { BerObjectContent::Integer(i) => bytes_to_u64(i).and_then(|x| { if x > u64::from(std::u32::MAX) { Err(BerError::IntegerTooLarge) } else { Ok(x as u32) } }), BerObjectContent::Enum(i) => { if i > u64::from(std::u32::MAX) { Err(BerError::IntegerTooLarge) } else { Ok(i as u32) } } _ => Err(BerError::BerTypeError), } } pub fn as_bool(&self) -> Result { match *self { BerObjectContent::Boolean(b) => Ok(b), _ => Err(BerError::BerTypeError), } } pub fn as_oid(&self) -> Result<&Oid, BerError> { match *self { BerObjectContent::OID(ref o) => Ok(o), BerObjectContent::RelativeOID(ref o) => Ok(o), _ => Err(BerError::BerTypeError), } } pub fn as_oid_val(&self) -> Result { match *self { BerObjectContent::OID(ref o) => Ok(o.to_owned()), BerObjectContent::RelativeOID(ref o) => Ok(o.to_owned()), _ => Err(BerError::BerTypeError), } } pub fn as_context_specific(&self) -> Result<(BerTag, Option>>), BerError> { match *self { BerObjectContent::ContextSpecific(u, ref o) => Ok((u, o.clone())), _ => Err(BerError::BerTypeError), } } pub fn as_bitstring_ref(&self) -> Result<&BitStringObject, BerError> { match *self { BerObjectContent::BitString(_, ref b) => Ok(b), _ => Err(BerError::BerTypeError), } } pub fn as_bitstring(&'a self) -> Result, BerError> { match *self { BerObjectContent::BitString(_, ref b) => Ok(b.to_owned()), _ => Err(BerError::BerTypeError), } } pub fn as_sequence(&self) -> Result<&Vec>, BerError> { match *self { BerObjectContent::Sequence(ref s) => Ok(s), _ => Err(BerError::BerTypeError), } } pub fn as_set(&self) -> Result<&Vec>, BerError> { match *self { BerObjectContent::Set(ref s) => Ok(s), _ => Err(BerError::BerTypeError), } } #[rustfmt::skip] pub fn as_slice(&self) -> Result<&'a [u8],BerError> { match *self { BerObjectContent::Integer(s) | BerObjectContent::BitString(_,BitStringObject{data:s}) | BerObjectContent::OctetString(s) | BerObjectContent::NumericString(s) | BerObjectContent::PrintableString(s) | BerObjectContent::IA5String(s) | BerObjectContent::UTF8String(s) | BerObjectContent::T61String(s) | BerObjectContent::BmpString(s) | BerObjectContent::GeneralString(s) | BerObjectContent::Unknown(_,s) => Ok(s), _ => Err(BerError::BerTypeError), } } #[rustfmt::skip] pub fn tag(&self) -> BerTag { match *self { BerObjectContent::EndOfContent => BerTag::EndOfContent, BerObjectContent::Boolean(_) => BerTag::Boolean, BerObjectContent::Integer(_) => BerTag::Integer, BerObjectContent::BitString(_,_) => BerTag::BitString, BerObjectContent::OctetString(_) => BerTag::OctetString, BerObjectContent::Null => BerTag::Null, BerObjectContent::Enum(_) => BerTag::Enumerated, BerObjectContent::OID(_) => BerTag::Oid, BerObjectContent::NumericString(_) => BerTag::NumericString, BerObjectContent::PrintableString(_) => BerTag::PrintableString, BerObjectContent::IA5String(_) => BerTag::Ia5String, BerObjectContent::UTF8String(_) => BerTag::Utf8String, BerObjectContent::RelativeOID(_) => BerTag::RelativeOid, BerObjectContent::T61String(_) => BerTag::T61String, BerObjectContent::BmpString(_) => BerTag::BmpString, BerObjectContent::Sequence(_) => BerTag::Sequence, BerObjectContent::Set(_) => BerTag::Set, BerObjectContent::UTCTime(_) => BerTag::UtcTime, BerObjectContent::GeneralizedTime(_) => BerTag::GeneralizedTime, BerObjectContent::GeneralString(_) => BerTag::GeneralString, BerObjectContent::ContextSpecific(x,_) | BerObjectContent::Unknown(x,_) => x, } } } #[cfg(feature = "bigint")] mod bigint { use super::{BerObject, BerObjectContent}; use num_bigint::{BigInt, BigUint, Sign}; impl<'a> BerObject<'a> { pub fn as_bigint(&self) -> Option { match self.content { BerObjectContent::Integer(s) => Some(BigInt::from_bytes_be(Sign::Plus, s)), _ => None, } } pub fn as_biguint(&self) -> Option { match self.content { BerObjectContent::Integer(s) => Some(BigUint::from_bytes_be(s)), _ => None, } } } } // This is a consuming iterator impl<'a> IntoIterator for BerObject<'a> { type Item = BerObject<'a>; type IntoIter = BerObjectIntoIterator<'a>; fn into_iter(self) -> Self::IntoIter { // match self { // BerObjectContent::Sequence(ref v) => (), // _ => (), // }; BerObjectIntoIterator { val: self, idx: 0 } } } pub struct BerObjectIntoIterator<'a> { val: BerObject<'a>, idx: usize, } impl<'a> Iterator for BerObjectIntoIterator<'a> { type Item = BerObject<'a>; fn next(&mut self) -> Option> { // let result = if self.idx < self.vec.len() { // Some(self.vec[self.idx].clone()) // } else { // None // }; let res = match self.val.content { BerObjectContent::Sequence(ref v) if self.idx < v.len() => Some(v[self.idx].clone()), BerObjectContent::Set(ref v) if self.idx < v.len() => Some(v[self.idx].clone()), _ => { if self.idx == 0 { Some(self.val.clone()) } else { None } } }; self.idx += 1; res } } // impl<'a> Iterator for BerObjectContent<'a> { // type Item = BerObjectContent<'a>; // // fn next(&mut self) -> Option> { // None // } // } pub struct BerObjectRefIterator<'a> { obj: &'a BerObject<'a>, idx: usize, } impl<'a> Iterator for BerObjectRefIterator<'a> { type Item = &'a BerObject<'a>; fn next(&mut self) -> Option<&'a BerObject<'a>> { let res = match (*self.obj).content { BerObjectContent::Sequence(ref v) if self.idx < v.len() => Some(&v[self.idx]), BerObjectContent::Set(ref v) if self.idx < v.len() => Some(&v[self.idx]), _ => None, }; self.idx += 1; res } } impl<'a> BerObject<'a> { pub fn ref_iter(&'a self) -> BerObjectRefIterator<'a> { BerObjectRefIterator { obj: self, idx: 0 } } } impl<'a> Index for BerObject<'a> { type Output = BerObject<'a>; fn index(&self, idx: usize) -> &BerObject<'a> { match (*self).content { BerObjectContent::Sequence(ref v) if idx < v.len() => &v[idx], BerObjectContent::Set(ref v) if idx < v.len() => &v[idx], _ => panic!("Try to index BerObjectContent which is not structured"), } // XXX the following // self.ref_iter().nth(idx).unwrap() // fails with: // error: cannot infer an appropriate lifetime for autoref due to conflicting requirements [E0495] // self.ref_iter().nth(idx).unwrap() } } /// BitString wrapper #[derive(Clone, Debug, PartialEq)] pub struct BitStringObject<'a> { pub data: &'a [u8], } impl<'a> BitStringObject<'a> { /// Test if bit `bitnum` is set pub fn is_set(&self, bitnum: usize) -> bool { let byte_pos = bitnum / 8; if byte_pos >= self.data.len() { return false; } let b = 7 - (bitnum % 8); (self.data[byte_pos] & (1 << b)) != 0 } } impl<'a> AsRef<[u8]> for BitStringObject<'a> { fn as_ref(&self) -> &[u8] { self.data } } #[cfg(test)] mod tests { use crate::ber::*; use crate::oid::*; #[test] fn test_der_as_u64() { let der_obj = BerObject::from_int_slice(b"\x01\x00\x02"); assert_eq!(der_obj.as_u64(), Ok(0x10002)); } #[test] fn test_der_seq_iter() { let der_obj = BerObject::from_obj(BerObjectContent::Sequence(vec![ BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_int_slice(b"\x01\x00\x00"), ])); let expected_values = vec![ BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_int_slice(b"\x01\x00\x00"), ]; for (idx, v) in der_obj.ref_iter().enumerate() { // println!("v: {:?}", v); assert_eq!((*v), expected_values[idx]); } } #[test] fn test_der_from_oid() { let obj: BerObject = Oid::from(&[1, 2]).into(); let expected = BerObject::from_obj(BerObjectContent::OID(Oid::from(&[1, 2]))); assert_eq!(obj, expected); } #[test] fn test_der_bistringobject() { let obj = BitStringObject { data: &[0x0f, 0x00, 0x40], }; assert!(!obj.is_set(0)); assert!(obj.is_set(7)); assert!(!obj.is_set(9)); assert!(obj.is_set(17)); } #[test] fn test_der_bistringobject_asref() { fn assert_equal>(s: T, b: &[u8]) { assert_eq!(s.as_ref(), b); } let b: &[u8] = &[0x0f, 0x00, 0x40]; let obj = BitStringObject { data: b }; assert_equal(obj, b); } #[cfg(feature = "bigint")] #[test] fn test_der_to_bigint() { 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)); } #[cfg(feature = "bigint")] #[test] fn test_der_to_biguint() { let obj = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); let expected = ::num_bigint::BigUint::from(0x10001 as u32); assert_eq!(obj.as_biguint(), Some(expected)); } } der-parser-3.0.3/src/ber/mod.rs010064400017500001750000000002551356716373500145100ustar0000000000000000//! Basic Encoding Rules (BER) objects and parser mod ber; mod parser; mod print; pub use crate::ber::ber::*; pub use crate::ber::parser::*; pub use crate::ber::print::*; der-parser-3.0.3/src/ber/parser.rs010064400017500001750000000527411356716373500152340ustar0000000000000000use crate::ber::*; use crate::error::*; use crate::oid::*; use nom::combinator::map_res; use nom::error::ErrorKind; use nom::number::streaming::be_u8; use nom::{Err, Needed}; /// Maximum recursion limit pub const MAX_RECURSION: usize = 50; /// Try to parse input bytes as u64 pub(crate) fn bytes_to_u64(s: &[u8]) -> Result { let mut u: u64 = 0; for &c in s { if u & 0xff00_0000_0000_0000 != 0 { return Err(BerError::IntegerTooLarge); } u <<= 8; u |= u64::from(c); } Ok(u) } pub(crate) fn parse_identifier(i: &[u8]) -> BerResult<(u8, u8, u32)> { if i.is_empty() { Err(Err::Incomplete(Needed::Size(1))) } else { let a = i[0] >> 6; let b = if i[0] & 0b0010_0000 != 0 { 1 } else { 0 }; let mut c = u32::from(i[0] & 0b0001_1111); let mut tag_byte_count = 1; if c == 0x1f { c = 0; loop { // Make sure we don't read past the end of our data. custom_check!(i, tag_byte_count >= i.len(), BerError::InvalidTag)?; // With tag defined as u32 the most we can fit in is four tag bytes. // (X.690 doesn't actually specify maximum tag width.) custom_check!(i, tag_byte_count > 5, BerError::InvalidTag)?; c = (c << 7) | (u32::from(i[tag_byte_count]) & 0x7f); let done = i[tag_byte_count] & 0x80 == 0; tag_byte_count += 1; if done { break; } } } Ok((&i[tag_byte_count..], (a, b, c))) } } pub(crate) fn parse_ber_length_byte(i: &[u8]) -> BerResult<(u8, u8)> { if i.is_empty() { Err(Err::Incomplete(Needed::Size(1))) } else { let a = i[0] >> 7; let b = i[0] & 0b0111_1111; Ok((&i[1..], (a, b))) } } fn ber_read_relative_oid(i: &[u8]) -> Result, u64> { let mut oid = Vec::new(); let mut acc: u64; if i.is_empty() { return Ok(oid); }; acc = 0; for &c in &i[0..] { acc = (acc << 7) | u64::from(c & 0b0111_1111); if (c & (1 << 7)) == 0 { oid.push(acc); acc = 0; } } match acc { 0 => Ok(oid), _ => Err(acc), } } fn ber_read_oid(i: &[u8]) -> Result, u64> { let mut oid = Vec::new(); let mut index = 0; if i.is_empty() { return Err(0); }; /* first element = X*40 + Y (See 8.19.4) */ let acc = u64::from(i[0]); if acc < 128 { oid.push(acc / 40); oid.push(acc % 40); index = 1; } let rel_oid = ber_read_relative_oid(&i[index..])?; oid.extend(&rel_oid); Ok(oid) } /// Read an object header pub fn ber_read_element_header(i: &[u8]) -> BerResult { do_parse! { i, el: parse_identifier >> len: parse_ber_length_byte >> llen: cond!(len.0 == 1, take!(len.1)) >> ( { let len : u64 = match len.0 { 0 => u64::from(len.1), _ => { // if len is 0xff -> error (8.1.3.5) if len.1 == 0b0111_1111 { return Err(::nom::Err::Error(BerError::InvalidTag)); } // XXX llen: test if 0 (indefinite form), if len is 0xff -> error match bytes_to_u64(llen.unwrap()) { Ok(l) => l, Err(_) => { return Err(::nom::Err::Error(BerError::InvalidTag)); }, } }, }; BerObjectHeader { class: el.0, structured: el.1, tag: BerTag(el.2), len, } } ) } } #[inline] pub(crate) fn ber_read_content_eoc(i: &[u8]) -> BerResult { Ok((i, BerObjectContent::EndOfContent)) } #[inline] pub(crate) fn ber_read_content_bool(i: &[u8]) -> BerResult { match be_u8(i) { Ok((rem, 0)) => Ok((rem, BerObjectContent::Boolean(false))), Ok((rem, _)) => Ok((rem, BerObjectContent::Boolean(true))), Err(e) => Err(e), } } #[inline] pub(crate) fn ber_read_content_integer(i: &[u8], len: usize) -> BerResult { map!(i, take!(len), |i| { BerObjectContent::Integer(i) }) } // XXX check if constructed (8.6.3) #[inline] pub(crate) fn ber_read_content_bitstring(i: &[u8], len: usize) -> BerResult { do_parse! { i, ignored_bits: be_u8 >> custom_check!(len == 0, BerError::InvalidLength) >> s: take!(len - 1) >> ( BerObjectContent::BitString(ignored_bits,BitStringObject{ data:s }) ) } } // XXX check if constructed (8.7) #[inline] pub(crate) fn ber_read_content_octetstring(i: &[u8], len: usize) -> BerResult { map!(i, take!(len), |s| BerObjectContent::OctetString(s)) } #[inline] pub(crate) fn ber_read_content_null(i: &[u8]) -> BerResult { Ok((i, BerObjectContent::Null)) } // XXX check if primitive (8.19.1) #[inline] pub(crate) fn ber_read_content_oid(i: &[u8], len: usize) -> BerResult { do_parse! { i, error_if!(len == 0, ErrorKind::LengthValue) >> oid: map_res!(take!(len),ber_read_oid) >> ( BerObjectContent::OID(Oid::from(&oid)) ) } } // XXX check if primitive (8.4) #[inline] pub(crate) fn ber_read_content_enum(i: &[u8], len: usize) -> BerResult { parse_hex_to_u64!(i, len).map(|(rem, i)| (rem, BerObjectContent::Enum(i))) } // XXX check if constructed, or indefinite length (8.21) #[inline] pub(crate) fn ber_read_content_utf8string(i: &[u8], len: usize) -> BerResult { map!(i, take!(len), |s| BerObjectContent::UTF8String(s)) } #[inline] pub(crate) fn ber_read_content_relativeoid(i: &[u8], len: usize) -> BerResult { do_parse! { i, custom_check!(len == 0, BerError::InvalidLength) >> oid: map_res!(take!(len), ber_read_relative_oid) >> ( BerObjectContent::RelativeOID(Oid::from(&oid)) ) } } #[inline] pub(crate) fn ber_read_content_sequence( i: &[u8], len: usize, depth: usize, ) -> BerResult { if len == 0 { // indefinite form // read until end-of-content map!( i, many_till!( call!(parse_ber_recursive, depth + 1), parse_ber_endofcontent ), |(l, _)| { BerObjectContent::Sequence(l) } ) } else { map!( i, flat_take!( len, many0!(complete!(call!(parse_ber_recursive, depth + 1))) ), |l| { BerObjectContent::Sequence(l) } ) } } #[inline] pub(crate) fn ber_read_content_set( i: &[u8], len: usize, depth: usize, ) -> BerResult { if len == 0 { // indefinite form // read until end-of-content map!( i, many_till!( call!(parse_ber_recursive, depth + 1), parse_ber_endofcontent ), |(l, _)| { BerObjectContent::Set(l) } ) } else { map!( i, flat_take!( len, many0!(complete!(call!(parse_ber_recursive, depth + 1))) ), |l| { BerObjectContent::Set(l) } ) } } // XXX check if constructed, or indefinite length (8.21) #[inline] pub(crate) fn ber_read_content_numericstring(i: &[u8], len: usize) -> BerResult { map!(i, take!(len), |s| BerObjectContent::NumericString(s)) } // XXX check if constructed, or indefinite length (8.21) #[inline] pub(crate) fn ber_read_content_printablestring( i: &[u8], len: usize, ) -> BerResult { map!(i, take!(len), |s| BerObjectContent::PrintableString(s)) } // XXX check if constructed, or indefinite length (8.21) #[inline] pub(crate) fn ber_read_content_t61string(i: &[u8], len: usize) -> BerResult { map!(i, take!(len), |s| BerObjectContent::T61String(s)) } // XXX check if constructed, or indefinite length (8.21) #[inline] pub(crate) fn ber_read_content_ia5string(i: &[u8], len: usize) -> BerResult { map!(i, take!(len), |s| BerObjectContent::IA5String(s)) } #[inline] pub(crate) fn ber_read_content_utctime(i: &[u8], len: usize) -> BerResult { map!(i, take!(len), |s| BerObjectContent::UTCTime(s)) } #[inline] pub(crate) fn ber_read_content_generalizedtime( i: &[u8], len: usize, ) -> BerResult { map!(i, take!(len), |s| BerObjectContent::GeneralizedTime(s)) } // XXX check if constructed, or indefinite length (8.21) #[inline] pub(crate) fn ber_read_content_generalstring(i: &[u8], len: usize) -> BerResult { map!(i, take!(len), |s| BerObjectContent::GeneralString(s)) } // XXX check if constructed, or indefinite length (8.21) #[inline] pub(crate) fn ber_read_content_bmpstring(i: &[u8], len: usize) -> BerResult { map!(i, take!(len), |s| BerObjectContent::BmpString(s)) } /// Parse the next bytes as the content of a BER object. /// /// Content type is *not* checked, caller is reponsible of providing the correct tag pub fn ber_read_element_content_as( i: &[u8], tag: BerTag, len: usize, constructed: bool, depth: usize, ) -> BerResult { if i.len() < len { return Err(Err::Incomplete(Needed::Size(len))); } match tag { // 0x00 end-of-content BerTag::EndOfContent => { custom_check!(i, len != 0, BerError::InvalidLength)?; ber_read_content_eoc(i) } // 0x01 bool BerTag::Boolean => { custom_check!(i, len != 1, BerError::InvalidLength)?; ber_read_content_bool(i) } // 0x02 BerTag::Integer => { custom_check!(i, constructed, BerError::ConstructUnexpected)?; ber_read_content_integer(i, len) } // 0x03: bitstring BerTag::BitString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER ber_read_content_bitstring(i, len) } // 0x04: octetstring BerTag::OctetString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER ber_read_content_octetstring(i, len) } // 0x05: null BerTag::Null => { custom_check!(i, constructed, BerError::ConstructUnexpected)?; custom_check!(i, len != 0, BerError::InvalidLength)?; ber_read_content_null(i) } // 0x06: object identified BerTag::Oid => { custom_check!(i, constructed, BerError::ConstructUnexpected)?; ber_read_content_oid(i, len) } // 0x0a: enumerated BerTag::Enumerated => { custom_check!(i, constructed, BerError::ConstructUnexpected)?; ber_read_content_enum(i, len) } // 0x0c: UTF8String BerTag::Utf8String => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER ber_read_content_utf8string(i, len) } // 0x0d: relative object identified BerTag::RelativeOid => { custom_check!(i, constructed, BerError::ConstructUnexpected)?; ber_read_content_relativeoid(i, len) } // 0x10: sequence BerTag::Sequence => { custom_check!(i, !constructed, BerError::ConstructExpected)?; ber_read_content_sequence(i, len, depth) } // 0x11: set BerTag::Set => { custom_check!(i, !constructed, BerError::ConstructExpected)?; ber_read_content_set(i, len, depth) } // 0x12: numericstring BerTag::NumericString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER ber_read_content_numericstring(i, len) } // 0x13: printablestring BerTag::PrintableString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER ber_read_content_printablestring(i, len) } // 0x14: t61string BerTag::T61String => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER ber_read_content_t61string(i, len) } // 0x16: ia5string BerTag::Ia5String => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER ber_read_content_ia5string(i, len) } // 0x17: utctime BerTag::UtcTime => ber_read_content_utctime(i, len), // 0x18: generalizedtime BerTag::GeneralizedTime => ber_read_content_generalizedtime(i, len), // 0x1b: generalstring BerTag::GeneralString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER ber_read_content_generalstring(i, len) } // 0x1e: bmpstring BerTag::BmpString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER ber_read_content_bmpstring(i, len) } // all unknown values _ => Err(Err::Error(BerError::UnknownTag)), } } // /// Parse a BER object, expecting a value with specificed tag pub fn parse_ber_with_tag(i: &[u8], tag: BerTag) -> BerResult { do_parse! { i, hdr: ber_read_element_header >> custom_check!(hdr.tag != tag, BerError::InvalidTag) >> o: call!(ber_read_element_content_as, hdr.tag, hdr.len as usize, hdr.is_constructed(), 0) >> ( BerObject::from_header_and_content(hdr, o) ) } } /// Read end of content marker #[inline] pub fn parse_ber_endofcontent(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::EndOfContent) } /// Read a boolean value /// /// The encoding of a boolean value shall be primitive. The contents octets shall consist of a /// single octet. /// /// If the boolean value is FALSE, the octet shall be zero. /// If the boolean value is TRUE, the octet shall be one byte, and have all bits set to one (0xff). #[inline] pub fn parse_ber_bool(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::Boolean) } /// Read an integer value /// /// The encoding of a boolean value shall be primitive. The contents octets shall consist of one or /// more octets. /// /// To access the content, use the [`as_u64`](struct.BerObject.html#method.as_u64), /// [`as_u32`](struct.BerObject.html#method.as_u32), /// [`as_biguint`](struct.BerObject.html#method.as_biguint) or /// [`as_bigint`](struct.BerObject.html#method.as_bigint) methods. /// Remember that a BER integer has unlimited size, so these methods return `Result` or `Option` /// objects. /// /// # Examples /// /// ```rust /// # #[macro_use] extern crate der_parser; /// # extern crate nom; /// # use der_parser::ber::parse_ber_integer; /// # use der_parser::ber::{BerObject,BerObjectContent}; /// # fn main() { /// let empty = &b""[..]; /// let bytes = [0x02, 0x03, 0x01, 0x00, 0x01]; /// let expected = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); /// assert_eq!( /// parse_ber_integer(&bytes), /// Ok((empty, expected)) /// ); /// # } /// ``` #[inline] pub fn parse_ber_integer(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::Integer) } /// Read an bitstring value #[inline] pub fn parse_ber_bitstring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::BitString) } /// Read an octetstring value #[inline] pub fn parse_ber_octetstring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::OctetString) } /// Read a null value #[inline] pub fn parse_ber_null(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::Null) } /// Read an object identifier value #[inline] pub fn parse_ber_oid(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::Oid) } /// Read an enumerated value #[inline] pub fn parse_ber_enum(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::Enumerated) } /// Read a UTF-8 string value #[inline] pub fn parse_ber_utf8string(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::Utf8String) } /// Read a relative object identifier value #[inline] pub fn parse_ber_relative_oid(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::RelativeOid) } /// Parse a sequence of BER elements /// /// Read a sequence of BER objects, without any constraint on the types. /// Sequence is parsed recursively, so if structured elements are found, they are parsed using the /// same function. /// /// To read a specific sequence of objects (giving the expected types), use the /// [`parse_ber_sequence_defined`](macro.parse_ber_sequence_defined.html) macro. #[inline] pub fn parse_ber_sequence(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::Sequence) } /// Parse a set of BER elements /// /// Read a set of BER objects, without any constraint on the types. /// Set is parsed recursively, so if structured elements are found, they are parsed using the /// same function. /// /// To read a specific set of objects (giving the expected types), use the /// [`parse_ber_set_defined`](macro.parse_ber_set_defined.html) macro. #[inline] pub fn parse_ber_set(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::Set) } /// Read a numeric string value #[inline] pub fn parse_ber_numericstring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::NumericString) } /// Read a printable string value #[inline] pub fn parse_ber_printablestring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::PrintableString) } /// Read a T61 string value #[inline] pub fn parse_ber_t61string(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::T61String) } /// Read an IA5 string value #[inline] pub fn parse_ber_ia5string(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::Ia5String) } /// Read an UTC time value #[inline] pub fn parse_ber_utctime(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::UtcTime) } /// Read a Generalized time value #[inline] pub fn parse_ber_generalizedtime(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::GeneralizedTime) } /// Read a GeneralString value #[inline] pub fn parse_ber_generalstring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::GeneralString) } /// Read a BmpString value #[inline] pub fn parse_ber_bmpstring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::BmpString) } pub fn parse_ber_explicit_failed(i: &[u8], tag: BerTag) -> BerResult { Ok(( i, BerObject::from_obj(BerObjectContent::ContextSpecific(tag, None)), )) } pub fn parse_ber_explicit(i: &[u8], tag: BerTag, f: F) -> BerResult where F: Fn(&[u8]) -> BerResult, { alt! { i, complete!(do_parse!( hdr: ber_read_element_header >> custom_check!(hdr.tag != tag, BerError::InvalidTag) >> content: f >> ( BerObject::from_header_and_content( hdr, BerObjectContent::ContextSpecific(tag,Some(Box::new(content))) ) ) )) | complete!(call!(parse_ber_explicit_failed, tag)) } } /// call der *content* parsing function pub fn parse_ber_implicit(i: &[u8], tag: BerTag, f: F) -> BerResult where F: Fn(&[u8], BerTag, usize) -> BerResult, { alt! { i, complete!(do_parse!( hdr: ber_read_element_header >> custom_check!(hdr.tag != tag, BerError::InvalidTag) >> content: call!(f, tag, hdr.len as usize) >> ( BerObject::from_header_and_content( hdr, BerObjectContent::ContextSpecific(tag,Some(Box::new(BerObject::from_obj(content)))) ) ) )) | complete!(call!(parse_ber_explicit_failed, tag)) } } /// Parse BER object and try to decode it as a 32-bits unsigned integer #[inline] pub fn parse_ber_u32(i: &[u8]) -> BerResult { map_res(parse_ber_integer, |o| o.as_u32())(i) } /// Parse BER object and try to decode it as a 64-bits unsigned integer #[inline] pub fn parse_ber_u64(i: &[u8]) -> BerResult { map_res(parse_ber_integer, |o| o.as_u64())(i) } fn parse_ber_recursive(i: &[u8], depth: usize) -> BerResult { custom_check!(i, depth > MAX_RECURSION, BerError::BerMaxDepth)?; let (rem, hdr) = ber_read_element_header(i)?; custom_check!( i, hdr.len as usize > i.len() || hdr.len > u64::from(::std::u32::MAX), BerError::InvalidLength )?; match hdr.class { // universal 0b00 | // private 0b11 => (), // application 0b01 | // context-specific 0b10 => return map!( rem, take!(hdr.len), |b| { BerObject::from_header_and_content(hdr,BerObjectContent::Unknown(hdr.tag, b)) } ), _ => { return Err(Err::Error(BerError::InvalidClass)); }, } match ber_read_element_content_as(rem, hdr.tag, hdr.len as usize, hdr.is_constructed(), depth) { Ok((rem, content)) => Ok((rem, BerObject::from_header_and_content(hdr, content))), Err(Err::Error(BerError::UnknownTag)) => map!(rem, take!(hdr.len), |b| { BerObject::from_header_and_content(hdr, BerObjectContent::Unknown(hdr.tag, b)) }), Err(e) => Err(e), } } /// Parse BER object #[inline] pub fn parse_ber(i: &[u8]) -> BerResult { parse_ber_recursive(i, 0) } der-parser-3.0.3/src/ber/print.rs010064400017500001750000000126161354435704100150570ustar0000000000000000use crate::ber::BitStringObject; use crate::ber::{BerObject, BerObjectContent, BerTag}; use std::fmt; use std::str; use rusticata_macros::debug; #[derive(Clone, PartialEq)] pub enum PrettyPrinterFlag { ShowHeader, } pub struct PrettyBer<'a> { obj: &'a BerObject<'a>, indent: usize, inc: usize, flags: Vec, } impl<'a> BerObject<'a> { pub fn as_pretty(&'a self, indent: usize, increment: usize) -> PrettyBer<'a> { PrettyBer { obj: self, indent, inc: increment, flags: Vec::new(), } } } impl<'a> PrettyBer<'a> { pub fn set_flag(&mut self, flag: PrettyPrinterFlag) { if !self.flags.contains(&flag) { self.flags.push(flag); } } pub fn next_indent<'b>(&self, obj: &'b BerObject) -> PrettyBer<'b> { PrettyBer { obj, indent: self.indent + self.inc, inc: self.inc, flags: self.flags.to_vec(), } } } impl<'a> fmt::Debug for PrettyBer<'a> { #[rustfmt::skip] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.indent > 0 { write!(f, "{:1$}", " ", self.indent)?; }; if self.flags.contains(&PrettyPrinterFlag::ShowHeader) { write!(f, "[c:{}, s:{}, t:{}] ", self.obj.class, self.obj.structured, self.obj.tag)?; }; fn print_utf8_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result { match str::from_utf8(s) { Ok(b) => writeln!(f, "{}(\"{}\")", ty, b), Err(e) => writeln!(f, "{}({:?}) ", ty, s, e), } } match self.obj.content { BerObjectContent::EndOfContent => writeln!(f, "EndOfContent"), BerObjectContent::Boolean(b) => writeln!(f, "Boolean({:?})", b), BerObjectContent::Integer(i) => writeln!(f, "Integer({:?})", debug::HexSlice(i)), BerObjectContent::Enum(i) => writeln!(f, "Enum({})", i), BerObjectContent::OID(ref v) => writeln!(f, "OID({:?})", v), BerObjectContent::RelativeOID(ref v) => writeln!(f, "RelativeOID({:?})", v), BerObjectContent::Null => writeln!(f, "Null"), BerObjectContent::OctetString(v) => writeln!(f, "OctetString({:?})", debug::HexSlice(v)), BerObjectContent::BitString(u,BitStringObject{data:v}) => writeln!(f, "BitString({},{:?})", u, debug::HexSlice(v)), BerObjectContent::GeneralizedTime(s) => print_utf8_string_with_type(f, s, "GeneralizedTime"), BerObjectContent::UTCTime(s) => print_utf8_string_with_type(f, s, "UTCTime"), BerObjectContent::PrintableString(s) => print_utf8_string_with_type(f, s, "PrintableString"), BerObjectContent::NumericString(s) => print_utf8_string_with_type(f, s, "NumericString"), BerObjectContent::UTF8String(s) => print_utf8_string_with_type(f, s, "UTF8String"), BerObjectContent::IA5String(s) => print_utf8_string_with_type(f, s, "IA5String"), BerObjectContent::T61String(s) => print_utf8_string_with_type(f, s, "T61String"), BerObjectContent::BmpString(s) => print_utf8_string_with_type(f, s, "BmpString"), BerObjectContent::GeneralString(s) => print_utf8_string_with_type(f, s, "GeneralString"), BerObjectContent::ContextSpecific(n,ref o) => { let new_indent = self.indent + self.inc; writeln!(f, "ContextSpecific [{}] {{", n)?; match *o { Some(ref obj) => write!(f, "{:?}", self.next_indent(obj))?, None => writeln!(f, "{:1$}None", " ", new_indent)?, }; if self.indent > 0 { write!(f, "{:1$}", " ", self.indent)?; }; writeln!(f, "}}")?; Ok(()) }, BerObjectContent::Set(ref v) | BerObjectContent::Sequence(ref v) => { let ty = if self.obj.tag == BerTag::Sequence { "Sequence" } else { "Set" }; writeln!(f, "{}[", ty)?; for o in v { write!(f, "{:?}", self.next_indent(o))?; }; if self.indent > 0 { write!(f, "{:1$}", " ", self.indent)?; }; writeln!(f, "]")?; Ok(()) }, BerObjectContent::Unknown(tag,o) => writeln!(f, "Unknown({:?},{:x?})", tag, o), } } } #[cfg(test)] mod tests { use super::PrettyPrinterFlag; use crate::ber::*; #[test] fn test_pretty_print() { let d = BerObject::from_obj(BerObjectContent::Sequence(vec![ BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_obj(BerObjectContent::Set(vec![ BerObject::from_int_slice(b"\x01"), BerObject::from_int_slice(b"\x02"), ])), ])); println!("{:?}", d.as_pretty(0, 2)); let mut pp = d.as_pretty(0, 4); pp.set_flag(PrettyPrinterFlag::ShowHeader); println!("{:?}", pp); } } der-parser-3.0.3/src/der/mod.rs010064400017500001750000000005531351626226700145050ustar0000000000000000//! Basic Encoding Rules (BER) objects and parser use crate::ber::{BerObject, BerTag}; mod parser; pub use crate::der::parser::*; /// DER tag (same as BER tag) pub type DerTag = BerTag; /// Representation of a DER-encoded (X.690) object /// /// Note that a DER object is just a BER object, with additional constraints. pub type DerObject<'a> = BerObject<'a>; der-parser-3.0.3/src/der/parser.rs010064400017500001750000000315011354434243200152110ustar0000000000000000use crate::ber::*; use crate::der::DerObject; use crate::error::*; use nom::number::streaming::be_u8; use nom::{Err, Needed}; /// Parse DER object pub fn parse_der(i: &[u8]) -> DerResult { do_parse! { i, hdr: der_read_element_header >> // XXX safety check: length cannot be more than 2^32 bytes custom_check!(hdr.len > u64::from(::std::u32::MAX), BerError::InvalidLength) >> content: call!(der_read_element_content,hdr) >> ( content ) } } #[doc(hidden)] #[macro_export] macro_rules! der_constraint_fail_if( ($slice:expr, $cond:expr) => ( { if $cond { return Err(::nom::Err::Error(BerError::DerConstraintFailed)); } } ); ); /// Parse a DER object, expecting a value with specificed tag pub fn parse_der_with_tag(i: &[u8], tag: BerTag) -> DerResult { do_parse! { i, hdr: der_read_element_header >> custom_check!(hdr.tag != tag, BerError::InvalidTag) >> o: call!(der_read_element_content_as, hdr.tag, hdr.len as usize, hdr.is_constructed(), 0) >> ( BerObject::from_header_and_content(hdr, o) ) } } /// Read end of content marker #[inline] pub fn parse_der_endofcontent(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::EndOfContent) } /// Read a boolean value /// /// The encoding of a boolean value shall be primitive. The contents octets shall consist of a /// single octet. /// /// If the boolean value is FALSE, the octet shall be zero. /// If the boolean value is TRUE, the octet shall be one byte, and have all bits set to one (0xff). #[inline] pub fn parse_der_bool(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::Boolean) } /// Read an integer value /// /// The encoding of a boolean value shall be primitive. The contents octets shall consist of one or /// more octets. /// /// To access the content, use the [`as_u64`](struct.BerObject.html#method.as_u64), /// [`as_u32`](struct.BerObject.html#method.as_u32), /// [`as_biguint`](struct.BerObject.html#method.as_biguint) or /// [`as_bigint`](struct.BerObject.html#method.as_bigint) methods. /// Remember that a BER integer has unlimited size, so these methods return `Result` or `Option` /// objects. /// /// # Examples /// /// ```rust /// # #[macro_use] extern crate der_parser; /// # extern crate nom; /// # use der_parser::der::{parse_der_integer, DerObject}; /// # use der_parser::ber::BerObjectContent; /// # fn main() { /// let empty = &b""[..]; /// let bytes = [0x02, 0x03, 0x01, 0x00, 0x01]; /// let expected = DerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); /// assert_eq!( /// parse_der_integer(&bytes), /// Ok((empty, expected)) /// ); /// # } /// ``` #[inline] pub fn parse_der_integer(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::Integer) } /// Read an bitstring value pub fn parse_der_bitstring(i: &[u8]) -> DerResult { do_parse! { i, hdr: der_read_element_header >> custom_check!(hdr.tag != BerTag::BitString, BerError::InvalidTag) >> custom_check!(hdr.is_constructed(), BerError::DerConstraintFailed) >> b: call!(der_read_content_bitstring, hdr.len as usize) >> ( DerObject::from_header_and_content(hdr, b) ) } } /// Read an octetstring value #[inline] pub fn parse_der_octetstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::OctetString) } /// Read a null value #[inline] pub fn parse_der_null(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::Null) } /// Read an object identifier value #[inline] pub fn parse_der_oid(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::Oid) } /// Read an enumerated value #[inline] pub fn parse_der_enum(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::Enumerated) } /// Read a UTF-8 string value #[inline] pub fn parse_der_utf8string(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::Utf8String) } /// Read a relative object identifier value #[inline] pub fn parse_der_relative_oid(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::RelativeOid) } /// Parse a sequence of DER elements /// /// Read a sequence of DER objects, without any constraint on the types. /// Sequence is parsed recursively, so if structured elements are found, they are parsed using the /// same function. /// /// To read a specific sequence of objects (giving the expected types), use the /// [`parse_ber_sequence_defined`](macro.parse_ber_sequence_defined.html) macro. #[inline] pub fn parse_der_sequence(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::Sequence) } /// Parse a set of DER elements /// /// Read a set of DER objects, without any constraint on the types. /// Set is parsed recursively, so if structured elements are found, they are parsed using the /// same function. /// /// To read a specific set of objects (giving the expected types), use the /// [`parse_ber_set_defined`](macro.parse_ber_set_defined.html) macro. #[inline] pub fn parse_der_set(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::Set) } /// Read a numeric string value #[inline] pub fn parse_der_numericstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::NumericString) } /// Read a printable string value #[inline] pub fn parse_der_printablestring(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::PrintableString) } /// Read a T61 string value #[inline] pub fn parse_der_t61string(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::T61String) } /// Read an IA5 string value #[inline] pub fn parse_der_ia5string(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::Ia5String) } /// Read an UTC time value #[inline] pub fn parse_der_utctime(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::UtcTime) } /// Read a Generalized time value #[inline] pub fn parse_der_generalizedtime(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::GeneralizedTime) } /// Read a GeneralString value #[inline] pub fn parse_der_generalstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::GeneralString) } /// Read a BmpString value #[inline] pub fn parse_der_bmpstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, BerTag::BmpString) } #[inline] pub fn parse_der_explicit(i: &[u8], tag: BerTag, f: F) -> DerResult where F: Fn(&[u8]) -> DerResult, { parse_ber_explicit(i, tag, f) } #[inline] pub fn parse_der_implicit(i: &[u8], tag: BerTag, f: F) -> DerResult where F: Fn(&[u8], BerTag, usize) -> BerResult, { parse_ber_implicit(i, tag, f) } /// Parse DER object and try to decode it as a 32-bits unsigned integer pub fn parse_der_u32(i: &[u8]) -> BerResult { match parse_ber_integer(i) { Ok((rem, ref obj)) => match obj.content { BerObjectContent::Integer(i) => match i.len() { 1 => Ok((rem, u32::from(i[0]))), 2 => Ok((rem, u32::from(i[0]) << 8 | u32::from(i[1]))), 3 => Ok(( rem, u32::from(i[0]) << 16 | u32::from(i[1]) << 8 | u32::from(i[2]), )), 4 => Ok(( rem, u32::from(i[0]) << 24 | u32::from(i[1]) << 16 | u32::from(i[2]) << 8 | u32::from(i[3]), )), _ => Err(Err::Error(BerError::IntegerTooLarge)), }, _ => Err(Err::Error(BerError::InvalidTag)), }, Err(e) => Err(e), } } /// Parse DER object and try to decode it as a 64-bits unsigned integer pub fn parse_der_u64(i: &[u8]) -> BerResult { match parse_ber_integer(i) { Ok((rem, ref obj)) => match obj.content { BerObjectContent::Integer(i) => match bytes_to_u64(i) { Ok(l) => Ok((rem, l)), Err(_) => Err(Err::Error(BerError::IntegerTooLarge)), }, _ => Err(Err::Error(BerError::InvalidTag)), }, Err(e) => Err(e), } } // --------- end of parse_der_xxx functions ---------- /// Parse the next bytes as the content of a DER object. /// /// Content type is *not* checked, caller is reponsible of providing the correct tag pub fn der_read_element_content_as( i: &[u8], tag: BerTag, len: usize, constructed: bool, depth: usize, ) -> BerResult { if i.len() < len { return Err(Err::Incomplete(Needed::Size(len))); } match tag { BerTag::Boolean => { custom_check!(i, len != 1, BerError::InvalidLength)?; der_constraint_fail_if!(i, i[0] != 0 && i[0] != 0xff); } BerTag::BitString => { der_constraint_fail_if!(i, constructed); // exception: read and verify padding bits return der_read_content_bitstring(i, len); } BerTag::NumericString | BerTag::PrintableString | BerTag::Ia5String | BerTag::Utf8String | BerTag::T61String | BerTag::BmpString | BerTag::GeneralString => { der_constraint_fail_if!(i, constructed); } BerTag::UtcTime | BerTag::GeneralizedTime => { if len == 0 || i.get(len - 1).copied() != Some(b'Z') { return Err(Err::Error(BerError::DerConstraintFailed)); } } _ => (), } ber_read_element_content_as(i, tag, len, constructed, depth) } pub fn der_read_element_content(i: &[u8], hdr: BerObjectHeader) -> DerResult { match hdr.class { // universal 0b00 | // private 0b11 => (), // application 0b01 | // context-specific 0b10 => return map!( i, take!(hdr.len), |b| { DerObject::from_header_and_content(hdr,BerObjectContent::Unknown(hdr.tag, b)) } ), _ => { return Err(Err::Error(BerError::InvalidClass)); }, } match der_read_element_content_as(i, hdr.tag, hdr.len as usize, hdr.is_constructed(), 0) { Ok((rem, content)) => Ok((rem, DerObject::from_header_and_content(hdr, content))), Err(Err::Error(BerError::UnknownTag)) => map!(i, take!(hdr.len), |b| { DerObject::from_header_and_content(hdr, BerObjectContent::Unknown(hdr.tag, b)) }), Err(e) => Err(e), } } #[inline] fn der_read_content_bitstring(i: &[u8], len: usize) -> BerResult { do_parse! { i, ignored_bits: be_u8 >> custom_check!(ignored_bits > 7, BerError::DerConstraintFailed) >> custom_check!(len == 0, BerError::InvalidLength) >> s: take!(len - 1) >> call!(|input| { if len > 1 { let mut last_byte = s[len-2]; for _ in 0..ignored_bits as usize { der_constraint_fail_if!(i, last_byte & 1 != 0); last_byte >>= 1; } } Ok((input,())) }) >> ( BerObjectContent::BitString(ignored_bits,BitStringObject{ data:s }) ) } } /// Read an object header (DER) pub fn der_read_element_header(i: &[u8]) -> BerResult { do_parse! { i, el: parse_identifier >> len: parse_ber_length_byte >> llen: cond!(len.0 == 1, take!(len.1)) >> ( { let len : u64 = match len.0 { 0 => u64::from(len.1), _ => { // if len is 0xff -> error (8.1.3.5) custom_check!(&i[1..], len.1 == 0b0111_1111, BerError::InvalidLength)?; // if len.1 == 0b0111_1111 { // return Err(::nom::Err::Error(error_position!(&i[1..], ErrorKind::Custom(BER_INVALID_LENGTH)))); // } // DER(9.1) if len is 0 (indefinite form), obj must be constructed der_constraint_fail_if!(&i[1..], len.1 == 0 && el.1 != 1); // if len.1 == 0 && el.1 != 1 { // return Err(::nom::Err::Error(error_position!(&i[1..], ErrorKind::Custom(BER_INVALID_LENGTH)))); // } let llen = llen.unwrap(); // safe because we tested len.0 != 0 match bytes_to_u64(llen) { Ok(l) => { // DER: should have been encoded in short form (< 127) der_constraint_fail_if!(i, l < 127); l }, Err(_) => { return Err(::nom::Err::Error(BerError::InvalidTag)); }, } }, }; BerObjectHeader { class: el.0, structured: el.1, tag: BerTag(el.2), len, } } ) } } der-parser-3.0.3/src/error.rs010064400017500001750000000041031352717524600143020ustar0000000000000000//! Error type for BER/DER parsers use crate::ber::BerObject; use crate::der::DerObject; use nom::error::{ErrorKind, ParseError}; /// Holds the result of parsing functions /// /// `O` is the output type, and defaults to a `BerObject`. /// /// Note that this type is also a `Result`, so usual functions (`map`, `unwrap` etc.) are available. /// /// This type is a wrapper around nom's IResult type pub type BerResult<'a, O = BerObject<'a>> = ::nom::IResult<&'a [u8], O, BerError>; /// Holds the result of parsing functions (DER) /// /// Note that this type is also a `Result`, so usual functions (`map`, `unwrap` etc.) are available. pub type DerResult<'a> = BerResult<'a, DerObject<'a>>; /// Error for BER/DER parsers #[derive(Debug, PartialEq)] pub enum BerError { /// BER object does not have the expected type BerTypeError, /// BER object does not have the expected value BerValueError, InvalidTag, InvalidClass, InvalidLength, /// DER object was expected to be constructed (and found to be primitive) ConstructExpected, /// DER object was expected to be primitive (and found to be constructed) ConstructUnexpected, /// BER integer is too large to fit in a native type. Use `as_bigint()` IntegerTooLarge, /// BER recursive parsing reached maximum depth (See /// [MAX_RECURSION](../ber/constant.MAX_RECURSION.html)) BerMaxDepth, /// When parsing a defined sequence, some items could not be found ObjectTooShort, /// A DER constraint failed (object may be using BER encoding?) DerConstraintFailed, UnknownTag, /// Feature is not yet implemented Unsupported, /// Custom error type left for parsers on top of this crate, so they can handle their custom /// errors Custom(u32), /// Error raised by the underlying nom parser NomError(ErrorKind), } impl ParseError for BerError { fn from_error_kind(_input: I, kind: ErrorKind) -> Self { BerError::NomError(kind) } fn append(_input: I, kind: ErrorKind, _other: Self) -> Self { BerError::NomError(kind) } } der-parser-3.0.3/src/lib.rs010064400017500001750000000104561356716373500137330ustar0000000000000000//! # BER/DER Parser //! //! A parser for Basic Encoding Rules (BER [[X.690]]) and Distinguished Encoding Rules(DER //! [[X.690]]), implemented with the [nom](https://github.com/Geal/nom) parser combinator //! framework. //! //! The code is available on [Github](https://github.com/rusticata/der-parser) //! and is part of the [Rusticata](https://github.com/rusticata) project. //! //! # DER parser design //! //! There are two different approaches for parsing DER objects: reading the objects recursively as //! long as the tags are known, or specifying a description of the expected objects (generally from //! the [ASN.1][X.680] description). //! //! The first parsing method can be done using the [`parse_ber`](ber/fn.parse_ber.html) and //! [`parse_der`](der/fn.parse_der.html) methods. //! However, it cannot fully parse all objects, especially those containing IMPLICIT, OPTIONAL, or //! DEFINED BY items. //! //! ```rust //! # #[macro_use] extern crate der_parser; //! use der_parser::parse_der; //! //! # fn main() { //! let bytes = [ 0x30, 0x0a, //! 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x02, 0x03, 0x01, 0x00, 0x00, //! ]; //! //! let parsed = parse_der(&bytes); //! # } //! ``` //! //! The second (and preferred) parsing method is to specify the expected objects recursively. The //! following macros can be used: //! [`parse_der_sequence_defined`](macro.parse_der_sequence_defined.html) and similar functions, //! [`parse_der_struct`](macro.parse_der_struct.html), etc. //! //! For example, to read a sequence containing two integers: //! //! ```rust //! # #[macro_use] extern crate der_parser; //! use der_parser::ber::*; //! 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 bytes = [ 0x30, 0x0a, //! 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x02, 0x03, 0x01, 0x00, 0x00, //! ]; //! let parsed = localparse_seq(&bytes); //! # } //! ``` //! //! All functions return a [`BerResult`](error/type.BerResult.html) object: the parsed //! [`BerObject`](ber/struct.BerObject.html), an `Incomplete` value, or an error. //! //! Note that this type is also a `Result`, so usual functions (`map`, `unwrap` etc.) are available. //! //! # Notes //! //! - The DER constraints are verified if using `parse_der`. //! - `BerObject` and `DerObject` are the same objects (type alias). The only difference is the //! verification of constraints *during parsing*. //! - DER integers can be of any size, so it is not possible to store them as simple integers (they //! are stored as raw bytes). 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). //! //! # References //! //! - [[X.680]] Abstract Syntax Notation One (ASN.1): Specification of basic notation. //! - [[X.690]] ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical //! Encoding Rules (CER) and Distinguished Encoding Rules (DER). //! //! [X.680]: http://www.itu.int/rec/T-REC-X.680/en "Abstract Syntax Notation One (ASN.1): //! Specification of basic notation." //! [X.690]: https://www.itu.int/rec/T-REC-X.690/en "ASN.1 encoding rules: Specification of //! Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules //! (DER)." #![deny(/*missing_docs,*/unsafe_code, unstable_features, unused_import_braces, unused_qualifications)] #[macro_use] extern crate nom; #[macro_use] extern crate rusticata_macros; #[macro_use] mod macros; #[allow(clippy::module_inception)] pub mod ber; pub mod der; pub mod error; pub mod oid; // compatibility: re-export at crate root pub use ber::parse_ber; pub use der::parse_der; // re-exports nom macros, so this crate's macros can be used without importing nom #[doc(hidden)] pub use nom::{alt, call, complete, do_parse, eof, many0, map, map_res, verify}; #[doc(hidden)] pub use rusticata_macros::{custom_check, flat_take}; #[cfg(feature = "bigint")] extern crate num_bigint; der-parser-3.0.3/src/macros.rs010064400017500001750000000562451352722415200144420ustar0000000000000000/// 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::ber_read_element_header; use $crate::fold_der_defined_m; do_parse!( $i, hdr: ber_read_element_header >> custom_check!(hdr.class != 0b00, $crate::error::BerError::InvalidClass) >> custom_check!(hdr.structured != 0b1, $crate::error::BerError::ConstructExpected) >> custom_check!(hdr.tag != $tag, $crate::error::BerError::InvalidTag) >> content: flat_take!(hdr.len as usize, fold_der_defined_m!( $($args)* )) >> (hdr,content) ) } ); ); /// Parse a defined sequence of DER elements (macro version) /// /// 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_m!(i, /// parse_ber_integer >> /// // macros can also be called /// call!(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] #[deprecated(since = "3.0.0", note = "Use parse_der_sequence_defined")] macro_rules! parse_der_sequence_defined_m( ($i:expr, $($args:tt)*) => ({ 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_m!(i, /// parse_ber_integer >> /// // macros can also be called /// call!(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!(localparse_set(&bytes), Ok((empty, expected))); /// # } /// ``` #[macro_export] #[deprecated(since = "3.0.0", note = "Use parse_der_set_defined")] macro_rules! parse_der_set_defined_m( ($i:expr, $($args:tt)*) => ({ 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)) ) }); ); /// 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 != 0b00, $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)*) => ({ 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)) ) }); ); // macro_rules! parse_der_sequence_defined( // ($i:expr, $($args:tt)*) => ({ // map!( // $i, // parse_der_defined!($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"), /// BerObject::from_int_slice(b"\x01\x00\x00"), /// ]); /// assert_eq!(localparse_set(&bytes), Ok((empty, expected))); /// # } /// ``` #[macro_export] macro_rules! parse_der_set_defined( ($i:expr, $($args:tt)*) => ({ 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)) ) }); ); // #[macro_export] // macro_rules! parse_der_set_defined( // ($i:expr, $($args:tt)*) => ( // map!( // $i, // parse_der_defined!($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::ber_read_element_header; do_parse!( $i, hdr: ber_read_element_header >> custom_check!(hdr.tag != $crate::ber::BerTag::Sequence, $crate::error::BerError::InvalidTag) >> content: flat_take!(hdr.len as usize, do_parse!( r: many0!(complete!($f)) >> eof!() >> ( r ) ) ) >> ( $crate::ber::BerObject::from_header_and_content(hdr, $crate::ber::BerObjectContent::Sequence(content)) ) ) }) ); /// 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::ber_read_element_header; do_parse!( $i, hdr: ber_read_element_header >> custom_check!(hdr.tag != $crate::ber::BerTag::Set, $crate::error::BerError::InvalidTag) >> content: flat_take!(hdr.len as usize, do_parse!( r: many0!(complete!($f)) >> eof!() >> ( r ) ) ) >> ( $crate::ber::BerObject::from_header_and_content(hdr, $crate::ber::BerObjectContent::Set(content)) ) ) }) ); /// 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::ContextSpecific(BerTag(0), /// 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::ContextSpecific(BerTag(0), 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_m!(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) => ( 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; /// # /// # fn main() { /// #[derive(Debug, PartialEq)] /// struct MyStruct<'a>{ /// a: BerObject<'a>, /// b: BerObject<'a>, /// } /// /// fn parse_struct01(i: &[u8]) -> BerResult<(BerObjectHeader,MyStruct)> { /// 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 = ( /// BerObjectHeader{ /// class: 0, /// structured: 1, /// tag: BerTag::Sequence, /// len: 0xa, /// }, /// 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; /// # /// # fn main() { /// struct MyStruct<'a>{ /// a: BerObject<'a>, /// b: BerObject<'a>, /// } /// /// fn parse_struct_with_tag(i: &[u8]) -> BerResult<(BerObjectHeader,MyStruct)> { /// parse_der_struct!( /// i, /// TAG BerTag::Sequence, /// a: parse_ber_integer >> /// b: parse_ber_integer >> /// eof!() >> /// ( MyStruct{ a: a, b: b } ) /// ) /// } /// # } /// ``` #[macro_export] macro_rules! parse_der_struct( ($i:expr, TAG $tag:expr, $($rest:tt)*) => ({ use $crate::ber::{BerObjectHeader,ber_read_element_header}; do_parse!( $i, hdr: verify!(ber_read_element_header, |hdr: &BerObjectHeader| hdr.structured == 1 && hdr.tag == $tag) >> res: flat_take!(hdr.len as usize, do_parse!( $($rest)* )) >> (hdr,res) ) }); ($i:expr, $($rest:tt)*) => ({ use $crate::ber::{BerObjectHeader,ber_read_element_header}; do_parse!( $i, hdr: verify!(ber_read_element_header, |hdr: &BerObjectHeader| hdr.structured == 1) >> res: flat_take!(hdr.len as usize, do_parse!( $($rest)* )) >> (hdr,res) ) }); ); /// 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 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_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); /// }, /// _ => assert!(false) /// } /// # } /// ``` /// /// The following parses `[2] IMPLICIT INTEGER`: /// /// ```rust /// # #[macro_use] extern crate der_parser; /// # use der_parser::ber::{parse_ber_integer, BerObject, BerTag}; /// # use der_parser::error::BerResult; /// # /// # 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::{BerObjectHeader,ber_read_element_header}; do_parse!( $i, hdr: verify!(ber_read_element_header, |hdr: &BerObjectHeader| hdr.tag.0 == $tag) >> res: flat_take!(hdr.len as usize, call!( $f )) >> (res) ) }); ($i:expr, EXPLICIT $tag:expr, $submac:ident!( $($args:tt)*)) => ({ use $crate::ber::{BerObjectHeader,ber_read_element_header}; do_parse!( $i, hdr: verify!(ber_read_element_header, |hdr: &BerObjectHeader| hdr.tag.0 == $tag) >> res: flat_take!(hdr.len as usize, $submac!( $($args)* )) >> (res) ) }); ($i:expr, IMPLICIT $tag:expr, $type:expr) => ({ use $crate::ber::{BerObjectHeader,ber_read_element_header,ber_read_element_content_as}; do_parse!( $i, hdr: verify!(ber_read_element_header, |hdr: &BerObjectHeader| hdr.tag.0 == $tag) >> res: call!(ber_read_element_content_as, $type, hdr.len as usize, hdr.is_constructed(), 0) >> (BerObject::from_obj(res)) ) }); ($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; /// # /// # fn main() { /// #[derive(Debug, PartialEq)] /// struct SimpleStruct { /// a: u32, /// }; /// /// fn parse_app01(i:&[u8]) -> BerResult<(BerObjectHeader,SimpleStruct)> { /// 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,(hdr,app))) => { /// assert!(rem.is_empty()); /// assert_eq!(hdr.tag, BerTag::Integer); /// assert!(hdr.is_application()); /// assert_eq!(hdr.structured, 1); /// 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::{BerObjectHeader,ber_read_element_header}; do_parse!( $i, hdr: verify!(ber_read_element_header, |hdr: &BerObjectHeader| hdr.class == 0b01 && hdr.tag.0 == $tag) >> res: flat_take!(hdr.len as usize, do_parse!( $($rest)* )) >> (hdr,res) ) }); ($i:expr, $tag:expr, $($rest:tt)*) => ( parse_der_application!($i, $tag, $($rest)*) ); ); der-parser-3.0.3/src/oid.rs010064400017500001750000000034621356716373500137370ustar0000000000000000//! Object ID (OID) representation use std::fmt; use std::slice; use std::num::ParseIntError; use std::str::FromStr; /// Object ID (OID) representation #[derive(PartialEq, Eq, Clone)] pub struct Oid(Vec); impl Oid { /// Build an OID from an array of `u64` integers pub fn from(s: &[u64]) -> Oid { Oid(s.to_owned()) } /// Return an iterator on every ID pub fn iter(&self) -> slice::Iter { self.0.iter() } } impl fmt::Display for Oid { /// Convert the OID to a string representation. /// The string contains the IDs separated by dots, for ex: "1.2.840.113549.1.1.5" fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.0.is_empty() { return Ok(()); } write!(f, "{}", self.0[0])?; for it in self.0.iter().skip(1) { write!(f, ".{}", it)?; } Ok(()) } } impl fmt::Debug for Oid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&format!("OID({})", self.to_string())) } } impl FromStr for Oid { type Err = ParseIntError; fn from_str(s: &str) -> Result { let v: Result, ParseIntError> = s.split('.').map(|c| c.parse::()).collect(); v.map(Oid) } } #[cfg(test)] mod tests { use crate::oid::Oid; use std::str::FromStr; #[test] fn test_oid_fmt() { let oid = Oid::from(&[1, 2, 840, 113_549, 1, 1, 5]); assert_eq!(format!("{}", oid), "1.2.840.113549.1.1.5".to_owned()); assert_eq!(format!("{:?}", oid), "OID(1.2.840.113549.1.1.5)".to_owned()); } #[test] fn test_oid_from_str() { let oid_ref = Oid::from(&[1, 2, 840, 113_549, 1, 1, 5]); let oid = Oid::from_str("1.2.840.113549.1.1.5").unwrap(); assert_eq!(oid_ref, oid); } } der-parser-3.0.3/tests/ber_parser.rs010064400017500001750000000125161356716373500156630ustar0000000000000000#[macro_use] extern crate pretty_assertions; #[macro_use] extern crate hex_literal; extern crate der_parser; extern crate nom; use der_parser::ber::*; use der_parser::error::*; use der_parser::oid::*; use nom::Err; #[test] fn test_ber_bool() { let empty = &b""[..]; let b_true = BerObject::from_obj(BerObjectContent::Boolean(true)); let b_false = BerObject::from_obj(BerObjectContent::Boolean(false)); assert_eq!(parse_ber_bool(&[0x01, 0x01, 0x00]), Ok((empty, b_false))); assert_eq!( parse_ber_bool(&[0x01, 0x01, 0xff]), Ok((empty, b_true.clone())) ); assert_eq!(parse_ber_bool(&[0x01, 0x01, 0x7f]), Ok((empty, b_true))); assert_eq!( parse_ber_bool(&[0x01, 0x02, 0x12, 0x34]), Err(Err::Error(BerError::InvalidLength)) ); } #[test] fn test_seq_indefinite_length() { let data = hex!("30 80 04 03 56 78 90 00 00 02 01 01"); let res = parse_ber(&data); assert_eq!( res, Ok(( &data[9..], BerObject::from_seq(vec![BerObject::from_obj(BerObjectContent::OctetString( &data[4..=6] )),]) )) ); let res = parse_ber_sequence(&data); assert_eq!( res, Ok(( &data[9..], BerObject::from_seq(vec![BerObject::from_obj(BerObjectContent::OctetString( &data[4..=6] )),]) )) ); } #[test] fn test_set_indefinite_length() { let data = hex!("31 80 04 03 56 78 90 00 00"); let res = parse_ber(&data); assert_eq!( res, Ok(( &data[9..], BerObject::from_set(vec![BerObject::from_obj(BerObjectContent::OctetString( &data[4..=6] )),]) )) ); let res = parse_ber_set(&data); assert_eq!( res, Ok(( &data[9..], BerObject::from_set(vec![BerObject::from_obj(BerObjectContent::OctetString( &data[4..=6] )),]) )) ); } #[test] fn test_ber_int() { let empty = &b""[..]; let bytes = [0x02, 0x03, 0x01, 0x00, 0x01]; let expected = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); assert_eq!(parse_ber_integer(&bytes), Ok((empty, expected))); } #[test] fn test_ber_bitstring_primitive() { let empty = &b""[..]; let bytes = &[0x03, 0x07, 0x04, 0x0a, 0x3b, 0x5f, 0x29, 0x1c, 0xd0]; let expected = BerObject::from_obj(BerObjectContent::BitString( 4, BitStringObject { data: &bytes[3..] }, )); assert_eq!(parse_ber_bitstring(bytes), Ok((empty, expected))); // // correct encoding, padding bits not all set to 0 // let bytes = &[0x03, 0x04, 0x06, 0x6e, 0x5d, 0xe0]; let expected = BerObject::from_obj(BerObjectContent::BitString( 6, BitStringObject { data: &bytes[3..] }, )); assert_eq!(parse_ber_bitstring(bytes), Ok((empty, expected))); // // long form of length // let bytes = &[0x03, 0x81, 0x04, 0x06, 0x6e, 0x5d, 0xc0]; let expected = BerObject::from_obj(BerObjectContent::BitString( 6, BitStringObject { data: &bytes[4..] }, )); assert_eq!(parse_ber_bitstring(bytes), Ok((empty, expected))); } #[test] fn test_ber_bitstring_constructed() { let bytes = &[ 0x23, 0x80, 0x03, 0x03, 0x00, 0x0a, 0x3b, 0x03, 0x05, 0x04, 0x5f, 0x29, 0x1c, 0xd0, 0x00, 0x00, ]; assert_eq!( parse_ber_bitstring(bytes), Err(Err::Error(BerError::Unsupported)) ); // XXX valid encoding } #[test] fn test_ber_octetstring_primitive() { let empty = &b""[..]; let bytes = [0x04, 0x05, 0x41, 0x41, 0x41, 0x41, 0x41]; let expected = BerObject::from_obj(BerObjectContent::OctetString(b"AAAAA")); assert_eq!(parse_ber_octetstring(&bytes), Ok((empty, expected))); } #[test] fn test_ber_null() { let empty = &b""[..]; let expected = BerObject::from_obj(BerObjectContent::Null); assert_eq!(parse_ber_null(&[0x05, 0x00]), Ok((empty, expected))); } #[test] fn test_ber_oid() { let empty = &b""[..]; let bytes = [ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, ]; let expected = BerObject::from_obj(BerObjectContent::OID(Oid::from(&[ 1, 2, 840, 113549, 1, 1, 5, ]))); assert_eq!(parse_ber_oid(&bytes), Ok((empty, expected))); } #[test] fn test_ber_enum() { let empty = &b""[..]; let expected = BerObject::from_obj(BerObjectContent::Enum(2)); assert_eq!(parse_ber_enum(&[0x0a, 0x01, 0x02]), Ok((empty, expected))); } #[test] fn test_ber_utf8string() { let empty = &b""[..]; let bytes = [ 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, ]; let expected = BerObject::from_obj(BerObjectContent::UTF8String(b"Some-State")); assert_eq!(parse_ber_utf8string(&bytes), Ok((empty, expected))); } #[test] fn test_ber_relativeoid() { let empty = &b""[..]; let bytes = hex!("0d 04 c2 7b 03 02"); let expected = BerObject::from_obj(BerObjectContent::RelativeOID(Oid::from(&[8571, 3, 2]))); assert_eq!(parse_ber_relative_oid(&bytes), Ok((empty, expected))); } #[test] fn test_ber_bmpstring() { let empty = &b""[..]; let bytes = hex!("1e 08 00 55 00 73 00 65 00 72"); let expected = BerObject::from_obj(BerObjectContent::BmpString(b"\x00U\x00s\x00e\x00r")); assert_eq!(parse_ber_bmpstring(&bytes), Ok((empty, expected))); } der-parser-3.0.3/tests/constructed.rs010064400017500001750000000211721356716373500160720ustar0000000000000000#[macro_use] extern crate pretty_assertions; extern crate der_parser; #[macro_use] extern crate nom; use der_parser::ber::*; use der_parser::error::*; use der_parser::*; use nom::error::ErrorKind; use nom::Err; use oid::Oid; #[derive(Debug, PartialEq)] struct MyStruct<'a> { a: BerObject<'a>, b: BerObject<'a>, } fn parse_struct01(i: &[u8]) -> BerResult<(BerObjectHeader, MyStruct)> { parse_der_struct!( i, a: parse_ber_integer >> b: parse_ber_integer >> (MyStruct { a: a, b: b }) ) } fn parse_struct01_complete(i: &[u8]) -> BerResult<(BerObjectHeader, MyStruct)> { parse_der_struct!( i, a: parse_ber_integer >> b: parse_ber_integer >> eof!() >> (MyStruct { a: a, b: b }) ) } // calling user function #[allow(dead_code)] fn parse_struct02(i: &[u8]) -> BerResult<(BerObjectHeader, ())> { parse_der_struct!(i, _a: parse_ber_integer >> _b: parse_struct01 >> (())) } // embedded DER structs #[allow(dead_code)] fn parse_struct03(i: &[u8]) -> BerResult<(BerObjectHeader, ())> { parse_der_struct!( i, _a: parse_ber_integer >> _b: parse_der_struct!(parse_ber_integer >> (())) >> (()) ) } // verifying tag fn parse_struct04(i: &[u8], tag: BerTag) -> BerResult<(BerObjectHeader, MyStruct)> { parse_der_struct!( i, TAG tag, a: parse_ber_integer >> b: parse_ber_integer >> eof!() >> ( MyStruct{ a: a, b: b } ) ) } #[test] fn struct01() { let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let empty = &b""[..]; let expected = ( BerObjectHeader { class: 0, structured: 1, tag: BerTag::Sequence, len: 0xa, }, 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))); } #[test] fn struct02() { let empty = &b""[..]; let bytes = [ 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x46, 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, ]; #[derive(Debug, PartialEq)] struct Attr<'a> { oid: Oid, val: BerObject<'a>, }; #[derive(Debug, PartialEq)] struct Rdn<'a> { a: Attr<'a>, } #[derive(Debug, PartialEq)] struct Name<'a> { l: Vec>, } let expected = Name { l: vec![ Rdn { a: Attr { oid: Oid::from(&[2, 5, 4, 6]), // countryName val: BerObject::from_obj(BerObjectContent::PrintableString(b"FR")), }, }, Rdn { a: Attr { oid: Oid::from(&[2, 5, 4, 8]), // stateOrProvinceName val: BerObject::from_obj(BerObjectContent::UTF8String(b"Some-State")), }, }, Rdn { a: Attr { oid: Oid::from(&[2, 5, 4, 10]), // organizationName val: BerObject::from_obj(BerObjectContent::UTF8String( b"Internet Widgits Pty Ltd", )), }, }, ], }; fn parse_directory_string(i: &[u8]) -> BerResult { alt!( i, parse_ber_utf8string | parse_ber_printablestring | parse_ber_ia5string ) } fn parse_attr_type_and_value(i: &[u8]) -> BerResult { parse_der_struct!( i, o: map_res!(parse_ber_oid, |x: BerObject| x.as_oid().map(|o| o.clone())) >> s: parse_directory_string >> (Attr { oid: o, val: s }) ) .map(|(rem, x)| (rem, x.1)) }; fn parse_rdn(i: &[u8]) -> BerResult { parse_der_struct!(i, a: parse_attr_type_and_value >> (Rdn { a: a })) .map(|(rem, x)| (rem, x.1)) } fn parse_name(i: &[u8]) -> BerResult { parse_der_struct!(i, l: many0!(complete!(parse_rdn)) >> (Name { l: l })) .map(|(rem, x)| (rem, x.1)) } assert_eq!(parse_name(&bytes), Ok((empty, expected))); } #[test] fn struct_with_garbage() { let bytes = [ 0x30, 0x0c, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, 0xff, 0xff, ]; let empty = &b""[..]; let expected = ( BerObjectHeader { class: 0, structured: 1, tag: BerTag::Sequence, len: 0xc, }, MyStruct { a: BerObject::from_int_slice(b"\x01\x00\x01"), b: BerObject::from_int_slice(b"\x01\x00\x00"), }, ); assert_eq!(parse_struct01(&bytes), Ok((empty, expected))); assert_eq!( parse_struct01_complete(&bytes), Err(Err::Error(error_position!(&bytes[12..], ErrorKind::Eof))) ); } #[test] fn struct_verify_tag() { let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let empty = &b""[..]; let expected = ( BerObjectHeader { class: 0, structured: 1, tag: BerTag::Sequence, len: 0xa, }, MyStruct { a: BerObject::from_int_slice(b"\x01\x00\x01"), b: BerObject::from_int_slice(b"\x01\x00\x00"), }, ); let res = parse_struct04(&bytes, BerTag::Sequence); assert_eq!(res, Ok((empty, expected))); let res = parse_struct04(&bytes, BerTag::Set); assert_eq!( res, Err(Err::Error(error_position!(&bytes[..], ErrorKind::Verify))) ); } #[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_u32() ) } fn parse_int_noexplicit(i: &[u8]) -> BerResult { map_res!( i, parse_der_tagged!(2, parse_ber_integer), |x: BerObject| x.as_u32() ) } let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; // EXPLICIT tagged value parsing let res = parse_int_explicit(bytes); match res { Ok((rem, val)) => { assert!(rem.is_empty()); assert_eq!(val, 0x10001); } _ => assert!(false), } // 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), Err(Err::Error(error_position!( bytes as &[u8], ErrorKind::Verify ))) ); // wrong type assert_eq!( parse_der_tagged!(bytes as &[u8], 2, parse_ber_bool), Err(Err::Error(BerError::InvalidTag)) ); } #[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() ) } let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01]; // IMPLICIT tagged value parsing let res = parse_int_implicit(bytes); match res { Ok((rem, val)) => { assert!(rem.is_empty()); assert_eq!(val, 0x10001); } _ => assert!(false), } // wrong tag assert_eq!( parse_der_tagged!(bytes as &[u8],IMPLICIT 3,BerTag::Integer), Err(Err::Error(error_position!( bytes as &[u8], ErrorKind::Verify ))) ); } #[test] fn application() { #[derive(Debug, PartialEq)] struct SimpleStruct { a: u32, }; fn parse_app01(i: &[u8]) -> BerResult<(BerObjectHeader, SimpleStruct)> { parse_der_application!( i, APPLICATION 2, a: map_res!(parse_ber_integer,|x: BerObject| x.as_u32()) >> ( SimpleStruct{ a } ) ) } let bytes = &[0x62, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; let res = parse_app01(bytes); match res { Ok((rem, (hdr, app))) => { assert!(rem.is_empty()); assert_eq!(hdr.tag, BerTag::Integer); assert!(hdr.is_application()); assert_eq!(hdr.structured, 1); assert_eq!(app, SimpleStruct { a: 0x10001 }); } _ => assert!(false), } } der-parser-3.0.3/tests/der_parser.rs010064400017500001750000000451271356716373500156710ustar0000000000000000#[macro_use] extern crate pretty_assertions; #[macro_use] extern crate nom; #[macro_use] extern crate der_parser; #[macro_use] extern crate hex_literal; use der_parser::ber::{ber_read_element_content_as, BerObjectContent, BerTag, BitStringObject}; use der_parser::der::*; use der_parser::error::*; use der_parser::oid::*; use nom::error::ErrorKind; use nom::Err; #[test] fn test_der_bool() { let empty = &b""[..]; let b_true = DerObject::from_obj(BerObjectContent::Boolean(true)); let b_false = DerObject::from_obj(BerObjectContent::Boolean(false)); assert_eq!(parse_der_bool(&[0x01, 0x01, 0x00]), Ok((empty, b_false))); assert_eq!(parse_der_bool(&[0x01, 0x01, 0xff]), Ok((empty, b_true))); assert_eq!( parse_der_bool(&[0x01, 0x01, 0x7f]), Err(Err::Error(BerError::DerConstraintFailed)) ); } #[test] fn test_der_int() { let empty = &b""[..]; let bytes = hex!("02 03 01 00 01"); let expected = DerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); assert_eq!(parse_der_integer(&bytes), Ok((empty, expected))); let res = parse_der_u64(&bytes); assert_eq!(res.expect("integer").1, 0x10001); // wrong tag let bytes = hex!("04 03 41 41 41"); let res = parse_der_integer(&bytes); assert!(res.is_err()); let res = parse_der_u64(&bytes); assert!(res.is_err()); // very long integer let bytes = hex!("02 0b 40 41 02 03 04 05 06 07 08 09 0a"); let res = parse_der_integer(&bytes); assert!(res.is_ok()); let res = parse_der_u64(&bytes); assert!(res.is_err()); } #[test] fn test_der_bitstring_primitive() { let empty = &b""[..]; // // correct DER encoding // let bytes = &[0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0]; let expected = DerObject::from_obj(BerObjectContent::BitString( 6, BitStringObject { data: &bytes[3..] }, )); assert_eq!(parse_der_bitstring(bytes), Ok((empty, expected))); // // correct encoding, but wrong padding bits (not all set to 0) // let bytes = &[0x03, 0x04, 0x06, 0x6e, 0x5d, 0xe0]; assert_eq!( parse_der_bitstring(bytes), Err(Err::Error(BerError::DerConstraintFailed)) ); // // long form of length (invalid, < 127) // let bytes = &[0x03, 0x81, 0x04, 0x06, 0x6e, 0x5d, 0xc0]; assert_eq!( parse_der_bitstring(bytes), Err(Err::Error(BerError::DerConstraintFailed)) ); } #[test] fn test_der_bitstring_constructed() { let bytes = &[ 0x23, 0x80, 0x03, 0x03, 0x00, 0x0a, 0x3b, 0x03, 0x05, 0x04, 0x5f, 0x29, 0x1c, 0xd0, 0x00, 0x00, ]; assert_eq!( parse_der_bitstring(bytes), Err(Err::Error(BerError::DerConstraintFailed)) ); } #[test] fn test_der_octetstring_primitive() { let empty = &b""[..]; let bytes = [0x04, 0x05, 0x41, 0x41, 0x41, 0x41, 0x41]; let expected = DerObject::from_obj(BerObjectContent::OctetString(b"AAAAA")); assert_eq!(parse_der_octetstring(&bytes), Ok((empty, expected))); } #[test] fn test_der_null() { let empty = &b""[..]; let expected = DerObject::from_obj(BerObjectContent::Null); assert_eq!(parse_der_null(&[0x05, 0x00]), Ok((empty, expected))); } #[test] fn test_der_oid() { let empty = &b""[..]; let bytes = [ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, ]; let expected = DerObject::from_obj(BerObjectContent::OID(Oid::from(&[ 1, 2, 840, 113549, 1, 1, 5, ]))); assert_eq!(parse_der_oid(&bytes), Ok((empty, expected))); } #[test] fn test_der_enum() { let empty = &b""[..]; let expected = DerObject::from_obj(BerObjectContent::Enum(2)); assert_eq!(parse_der_enum(&[0x0a, 0x01, 0x02]), Ok((empty, expected))); } #[test] fn test_der_utf8string() { let empty = &b""[..]; let bytes = [ 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, ]; let expected = DerObject::from_obj(BerObjectContent::UTF8String(b"Some-State")); assert_eq!(parse_der_utf8string(&bytes), Ok((empty, expected))); } #[test] fn test_der_relativeoid() { let empty = &b""[..]; let bytes = [0x0d, 0x04, 0xc2, 0x7b, 0x03, 0x02]; let expected = DerObject::from_obj(BerObjectContent::RelativeOID(Oid::from(&[8571, 3, 2]))); assert_eq!(parse_der_relative_oid(&bytes), Ok((empty, expected))); } #[test] fn test_der_seq() { let empty = &b""[..]; let bytes = [0x30, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; let expected = DerObject::from_seq(vec![DerObject::from_int_slice(b"\x01\x00\x01")]); assert_eq!(parse_der_sequence(&bytes), Ok((empty, expected))); } #[test] fn test_der_set() { let empty = &b""[..]; let bytes = [0x31, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; let expected = DerObject::from_set(vec![DerObject::from_int_slice(b"\x01\x00\x01")]); assert_eq!(parse_der_set(&bytes), Ok((empty, expected))); } #[test] fn test_der_seq_defined() { 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"), ]); fn parser(i: &[u8]) -> DerResult { parse_der_sequence_defined!(i, parse_der_integer >> parse_der_integer) }; assert_eq!(parser(&bytes), Ok((empty, expected))); } #[test] fn test_der_set_defined() { 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"), ]); fn parser(i: &[u8]) -> DerResult { parse_der_set_defined!(i, parse_der_integer >> parse_der_integer) }; assert_eq!(parser(&bytes), Ok((empty, expected))); } #[test] fn test_der_seq_of() { 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"), ]); fn parser(i: &[u8]) -> DerResult { parse_der_sequence_of!(i, parse_der_integer) }; assert_eq!(parser(&bytes), Ok((empty, expected))); } #[test] 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) }; assert_eq!( parser(&bytes), Err(Err::Error(error_position!(&bytes[7..], ErrorKind::Eof))) ); } #[test] fn test_der_set_of() { 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"), ]); fn parser(i: &[u8]) -> DerResult { parse_der_set_of!(i, parse_der_integer) }; assert_eq!(parser(&bytes), Ok((empty, expected))); } #[test] fn test_der_utctime() { let empty = &b""[..]; let bytes = hex!("17 0D 30 32 31 32 31 33 31 34 32 39 32 33 5A FF"); let expected = DerObject::from_obj(BerObjectContent::UTCTime(&bytes[2..(2 + 0x0d)])); assert_eq!(parse_der_utctime(&bytes), Ok((&[0xff][..], expected))); let bytes = hex!("17 0c 30 32 31 32 31 33 31 34 32 39 32 33"); parse_der_utctime(&bytes).err().expect("expected error"); } #[test] fn test_der_generalizedtime() { let empty = &b""[..]; let bytes = [ 0x18, 0x0D, 0x30, 0x32, 0x31, 0x32, 0x31, 0x33, 0x31, 0x34, 0x32, 0x39, 0x32, 0x33, 0x5A, ]; let expected = DerObject::from_obj(BerObjectContent::GeneralizedTime(&bytes[2..])); assert_eq!(parse_der_generalizedtime(&bytes), Ok((empty, expected))); } #[test] fn test_der_generalstring() { let empty = &b""[..]; let bytes = [0x1b, 0x04, 0x63, 0x69, 0x66, 0x73]; let expected = DerObject::from_obj(BerObjectContent::GeneralString(b"cifs")); assert_eq!(parse_der_generalstring(&bytes), Ok((empty, expected))); } #[test] fn test_der_contextspecific() { let bytes = [0xa0, 0x03, 0x02, 0x01, 0x02]; let empty = &b""[..]; let expected = DerObject { class: 2, structured: 1, tag: BerTag(0), content: BerObjectContent::Unknown(BerTag(0), &bytes[2..]), }; assert_eq!(parse_der(&bytes), Ok((empty, expected))); } #[test] fn test_der_explicit() { let empty = &b""[..]; let bytes = [0xa0, 0x03, 0x02, 0x01, 0x02]; let expected = DerObject { class: 2, structured: 1, tag: BerTag(0), content: BerObjectContent::ContextSpecific( BerTag(0), Some(Box::new(DerObject::from_int_slice(b"\x02"))), ), }; assert_eq!( parse_der_explicit(&bytes, BerTag(0), parse_der_integer), Ok((empty, expected)) ); let expected2 = DerObject::from_obj(BerObjectContent::ContextSpecific(BerTag(1), None)); assert_eq!( parse_der_explicit(&bytes, BerTag(1), parse_der_integer), Ok((&bytes[..], expected2)) ); } #[test] fn test_der_implicit() { let empty = &b""[..]; let bytes = [0x81, 0x04, 0x70, 0x61, 0x73, 0x73]; let pass = DerObject::from_obj(BerObjectContent::IA5String(b"pass")); let expected = DerObject { class: 2, structured: 0, tag: BerTag(1), content: BerObjectContent::ContextSpecific(BerTag(1), Some(Box::new(pass))), }; fn der_read_ia5string_content( i: &[u8], _tag: BerTag, len: usize, ) -> BerResult { ber_read_element_content_as(i, DerTag::Ia5String, len, false, 0) } assert_eq!( parse_der_implicit(&bytes, BerTag(1), der_read_ia5string_content), Ok((empty, expected)) ); let expected2 = DerObject::from_obj(BerObjectContent::ContextSpecific(BerTag(2), None)); assert_eq!( parse_der_implicit(&bytes, BerTag(2), der_read_ia5string_content), Ok((&bytes[..], expected2)) ); } #[test] fn test_der_implicit_long_tag() { let empty = &b""[..]; let bytes = [0x5f, 0x52, 0x04, 0x70, 0x61, 0x73, 0x73]; let pass = DerObject::from_obj(BerObjectContent::IA5String(b"pass")); let expected = DerObject { class: 1, structured: 0, tag: BerTag(0x52), content: BerObjectContent::ContextSpecific(BerTag(0x52), Some(Box::new(pass))), }; fn der_read_ia5string_content( i: &[u8], _tag: BerTag, len: usize, ) -> BerResult { ber_read_element_content_as(i, DerTag::Ia5String, len, false, 0) } assert_eq!( parse_der_implicit(&bytes, BerTag(0x52), der_read_ia5string_content), Ok((empty, expected)) ); let expected2 = DerObject::from_obj(BerObjectContent::ContextSpecific(BerTag(2), None)); assert_eq!( parse_der_implicit(&bytes, BerTag(2), der_read_ia5string_content), Ok((&bytes[..], expected2)) ); } #[test] fn test_der_optional() { 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 = DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::ContextSpecific( BerTag(0), Some(Box::new(DerObject::from_obj(BerObjectContent::Enum(1)))), )), DerObject::from_int_slice(b"\x01\x00\x01"), ]); let expected2 = DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::ContextSpecific(BerTag(0), None)), DerObject::from_int_slice(b"\x01\x00\x01"), ]); fn parse_optional_enum(i: &[u8]) -> DerResult { parse_der_optional!(i, parse_der_enum) } fn parser(i: &[u8]) -> DerResult { parse_der_sequence_defined!(i, parse_optional_enum >> parse_der_integer) }; assert_eq!(parser(&bytes1), Ok((empty, expected1))); assert_eq!(parser(&bytes2), Ok((empty, expected2))); } #[test] fn test_der_seq_dn() { let empty = &b""[..]; let bytes = [ 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x46, 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, ]; let expected = DerObject::from_seq(vec![ DerObject::from_set(vec![DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::OID(Oid::from(&[2, 5, 4, 6]))), // countryName DerObject::from_obj(BerObjectContent::PrintableString(b"FR")), ])]), DerObject::from_set(vec![DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::OID(Oid::from(&[2, 5, 4, 8]))), // stateOrProvinceName DerObject::from_obj(BerObjectContent::UTF8String(b"Some-State")), ])]), DerObject::from_set(vec![DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::OID(Oid::from(&[2, 5, 4, 10]))), // organizationName DerObject::from_obj(BerObjectContent::UTF8String(b"Internet Widgits Pty Ltd")), ])]), ]); assert_eq!(parse_der(&bytes), Ok((empty, expected))); } #[test] fn test_der_seq_dn_defined() { let empty = &b""[..]; let bytes = [ 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x46, 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, ]; let expected = DerObject::from_seq(vec![ DerObject::from_set(vec![DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::OID(Oid::from(&[2, 5, 4, 6]))), // countryName DerObject::from_obj(BerObjectContent::PrintableString(b"FR")), ])]), DerObject::from_set(vec![DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::OID(Oid::from(&[2, 5, 4, 8]))), // stateOrProvinceName DerObject::from_obj(BerObjectContent::UTF8String(b"Some-State")), ])]), DerObject::from_set(vec![DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::OID(Oid::from(&[2, 5, 4, 10]))), // organizationName DerObject::from_obj(BerObjectContent::UTF8String(b"Internet Widgits Pty Ltd")), ])]), ]); #[inline] fn parse_directory_string(i: &[u8]) -> DerResult { alt!( i, parse_der_utf8string | parse_der_printablestring | parse_der_ia5string ) } #[inline] fn parse_attr_type_and_value(i: &[u8]) -> DerResult { parse_der_sequence_defined!(i, parse_der_oid >> parse_directory_string) }; #[inline] fn parse_rdn(i: &[u8]) -> DerResult { parse_der_set_defined!(i, parse_attr_type_and_value) } #[inline] fn parse_name(i: &[u8]) -> DerResult { parse_der_sequence_defined!(i, parse_rdn >> parse_rdn >> parse_rdn) } 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] fn test_parse_u32() { let empty = &b""[..]; assert_eq!(parse_der_u32(&[0x02, 0x01, 0x01]), Ok((empty, 1))); assert_eq!(parse_der_u32(&[0x02, 0x01, 0xff]), Ok((empty, 255))); assert_eq!(parse_der_u32(&[0x02, 0x02, 0x01, 0x23]), Ok((empty, 0x123))); assert_eq!( parse_der_u32(&[0x02, 0x02, 0xff, 0xff]), Ok((empty, 0xffff)) ); assert_eq!( parse_der_u32(&[0x02, 0x03, 0x01, 0x23, 0x45]), Ok((empty, 0x12345)) ); assert_eq!( parse_der_u32(&[0x02, 0x03, 0xff, 0xff, 0xff]), Ok((empty, 0xffffff)) ); assert_eq!( parse_der_u32(&[0x02, 0x04, 0x01, 0x23, 0x45, 0x67]), Ok((empty, 0x1234567)) ); assert_eq!( parse_der_u32(&[0x02, 0x04, 0xff, 0xff, 0xff, 0xff]), Ok((empty, 0xffffffff)) ); let s = &[0x02, 0x05, 0x01, 0x23, 0x45, 0x67, 0x89]; assert_eq!(parse_der_u32(s), Err(Err::Error(BerError::IntegerTooLarge))); let s = &[0x01, 0x01, 0xff]; assert_eq!(parse_der_u32(s), Err(Err::Error(BerError::InvalidTag))); } #[test] fn test_parse_u64() { let empty = &b""[..]; assert_eq!(parse_der_u64(&[0x02, 0x01, 0x01]), Ok((empty, 1))); assert_eq!(parse_der_u64(&[0x02, 0x01, 0xff]), Ok((empty, 255))); assert_eq!(parse_der_u64(&[0x02, 0x02, 0x01, 0x23]), Ok((empty, 0x123))); assert_eq!( parse_der_u64(&[0x02, 0x02, 0xff, 0xff]), Ok((empty, 0xffff)) ); assert_eq!( parse_der_u64(&[0x02, 0x03, 0x01, 0x23, 0x45]), Ok((empty, 0x12345)) ); assert_eq!( parse_der_u64(&[0x02, 0x03, 0xff, 0xff, 0xff]), Ok((empty, 0xffffff)) ); assert_eq!( parse_der_u64(&[0x02, 0x04, 0x01, 0x23, 0x45, 0x67]), Ok((empty, 0x1234567)) ); assert_eq!( parse_der_u64(&[0x02, 0x04, 0xff, 0xff, 0xff, 0xff]), Ok((empty, 0xffffffff)) ); assert_eq!( parse_der_u64(&[0x02, 0x05, 0x01, 0x23, 0x45, 0x67, 0x89]), Ok((empty, 0x123456789)) ); let s = &[0x01, 0x01, 0xff]; assert_eq!(parse_der_u64(s), Err(Err::Error(BerError::InvalidTag))); } der-parser-3.0.3/tests/fuzz01.rs010064400017500001750000000004471352005746400146640ustar0000000000000000extern crate der_parser; #[test] fn test01() { let data = b"\x03\x00\x00kk\x00\x00\x00\x00\x00\x00\x00.\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff;\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00\xff\x0a\xff"; let _ = der_parser::parse_der(data); } der-parser-3.0.3/tests/fuzz02.rs010064400017500001750000000014431351626274500146670ustar0000000000000000extern crate der_parser; #[test] fn test02() { let data = b"\x06\x00\x01\x00\x00\x2a"; let _ = der_parser::parse_der(data); } #[test] fn test03() { let data = b"\x06\x0a*\xf1\x0a*\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe"; let _ = der_parser::parse_der(data); } #[test] fn test04() { let data = &[ 0x50, 0x2a, 0xa, 0x8d, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa, 0x0, 0xb, 0x22, 0x56, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf1, 0xa, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ]; let _ = der_parser::parse_der(data); } der-parser-3.0.3/tests/macros.rs010064400017500001750000000042301356716373500150150ustar0000000000000000#[macro_use] extern crate der_parser; use der_parser::ber::{parse_ber_integer, BerObject, BerObjectHeader}; use der_parser::der::{parse_der_enum, parse_der_integer}; use der_parser::error::{BerResult, DerResult}; // 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]) -> DerResult { parse_der_optional!(i, parse_der_enum) } #[allow(dead_code)] fn parse_struct01(i: &[u8]) -> BerResult<(BerObjectHeader, MyStruct)> { parse_der_struct!( i, a: parse_ber_integer >> b: parse_ber_integer >> (MyStruct { a: a, b: 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<(BerObjectHeader, SimpleStruct)> { parse_der_application!( i, APPLICATION 2, a: map_res!(parse_ber_integer,|x: BerObject| x.as_u32()) >> ( SimpleStruct{ a } ) ) } #[test] fn macros() {} der-parser-3.0.3/tests/primitive.rs010064400017500001750000000132661356716373500155520ustar0000000000000000#[macro_use] extern crate pretty_assertions; #[macro_use] extern crate hex_literal; extern crate der_parser; extern crate nom; use der_parser::ber::*; use der_parser::der::*; use der_parser::error::*; use der_parser::oid::Oid; use nom::{Err, Needed}; #[test] fn test_flat_take() { let empty = &b""[..]; assert_eq!( parse_ber_bool(&[0x01, 0x01, 0xff]), Ok((empty, BerObject::from_obj(BerObjectContent::Boolean(true)))) ); assert_eq!( parse_ber_bool(&[0x01, 0x01, 0x00]), Ok((empty, BerObject::from_obj(BerObjectContent::Boolean(false)))) ); assert_eq!( ber_read_element_content_as(&[0xff], BerTag::Boolean, 0x01, false, 0), Ok((empty, BerObjectContent::Boolean(true))) ); assert_eq!( ber_read_element_content_as(&[0x00], BerTag::Boolean, 0x01, false, 0), Ok((empty, BerObjectContent::Boolean(false))) ); } #[test] fn test_oid() { let empty = &b""[..]; assert_eq!( parse_der(&[0x06, 0x06, 42, 129, 122, 1, 16, 9]), Ok(( empty, BerObject::from_obj(BerObjectContent::OID(Oid::from(&[1, 2, 250, 1, 16, 9]))) )) ); // Dubuisson 433 assert_eq!( parse_der(&[0x06, 0x05, 129, 122, 1, 16, 9]), Ok(( empty, BerObject::from_obj(BerObjectContent::OID(Oid::from(&[250, 1, 16, 9]))) )) ); } #[test] fn test_rel_oid() { let empty = &b""[..]; assert_eq!( parse_der(&[0x0d, 0x04, 0xc2, 0x7b, 0x03, 0x02]), Ok(( empty, BerObject::from_obj(BerObjectContent::RelativeOID(Oid::from(&[8571, 3, 2]))) )) ); } #[test] fn test_unknown_tag() { let bytes = hex!("1d 01 00"); let res = parse_ber(&bytes).expect("parsing failed"); assert!(res.0.is_empty()); assert_eq!( res.1, BerObject::from_obj(BerObjectContent::Unknown(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..])) ); } #[test] fn test_unknown_context_specific() { let bytes = hex!("80 01 00"); let res = parse_ber(&bytes).expect("parsing failed"); assert!(res.0.is_empty()); assert_eq!( res.1, BerObject { class: 2, structured: 0, tag: BerTag(0), content: BerObjectContent::Unknown(BerTag(0x0), &bytes[2..]) } ); } #[test] fn test_unknown_long_tag() { let bytes = hex!("9f 22 01 00"); let res = parse_ber(&bytes).expect("parsing failed"); assert!(res.0.is_empty()); assert_eq!( res.1, BerObject { class: 2, structured: 0, tag: BerTag(0x22), content: BerObjectContent::Unknown(BerTag(0x22), &bytes[3..]) } ); } #[test] fn test_unknown_longer_tag() { let bytes = hex!("9f a2 22 01 00"); let res = parse_ber(&bytes).expect("parsing failed"); assert!(res.0.is_empty()); assert_eq!( res.1, BerObject { class: 2, structured: 0, tag: BerTag(0x1122), content: BerObjectContent::Unknown(BerTag(0x1122), &bytes[4..]) } ); } #[test] fn test_incomplete_tag() { let bytes = hex!("9f a2 a2"); let res = parse_ber(&bytes); assert!(res.is_err()); } #[test] fn test_overflow_tag() { let bytes = hex!("9f a2 a2 a2 a2 a2 22 01 00"); let res = parse_ber(&bytes); assert!(res.is_err()); } #[test] fn test_incomplete_length() { let bytes = hex!("30"); let res = parse_ber(&bytes).err().expect("expected error"); assert_eq!(res, Err::Incomplete(Needed::Size(1))); let res = parse_der(&bytes).err().expect("expected error"); assert_eq!(res, Err::Incomplete(Needed::Size(1))); let bytes = hex!("02"); let res = parse_ber(&bytes).err().expect("expected error"); assert_eq!(res, Err::Incomplete(Needed::Size(1))); let bytes = hex!("02 05"); let _ = parse_ber(&bytes).err().expect("expected error"); let bytes = hex!("02 85"); let res = parse_ber(&bytes).err().expect("expected error"); assert_eq!(res, Err::Incomplete(Needed::Size(5))); let bytes = hex!("02 85 ff"); let res = parse_ber(&bytes).err().expect("expected error"); assert_eq!(res, Err::Incomplete(Needed::Size(5))); } #[test] fn test_invalid_length() { let bytes = hex!("02 ff 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10"); let _ = parse_ber(&bytes).err().expect("expected error"); let _ = ber_read_element_header(&bytes) .err() .expect("expected error"); let bytes = hex!("02 85 ff ff ff ff ff 00"); let res = parse_ber(&bytes) .err() .expect("parsing should have returned error"); // get error match res { Err::Error(e) => { assert_eq!(e, BerError::InvalidLength); } _ => assert!(false), } let bytes = hex!("02 02 00"); let res = parse_der(&bytes).err().expect("expected error"); assert_eq!(res, Err::Incomplete(Needed::Size(2))); } #[test] fn test_invalid_param() { let bytes = hex!("00"); let hdr = BerObjectHeader { class: 8, structured: 0, tag: BerTag(2), len: 1, }; der_read_element_content(&bytes, hdr) .err() .expect("expected erreur"); } #[test] fn test_pretty_print() { let bytes = hex!("01 01 ff"); let obj = parse_der(&bytes).map(|(_, b)| b).expect("expected error"); println!("{:?}", obj.as_pretty(0, 2)); // controlling the pretty-printer let mut pp = obj.as_pretty(0, 4); pp.set_flag(PrettyPrinterFlag::ShowHeader); println!("{:?}", pp); } der-parser-3.0.3/.cargo_vcs_info.json0000644000000001120000000000000131340ustar00{ "git": { "sha1": "3faf359891a0e5dd52896c59f2d5f38f5c49a981" } }