der-parser-6.0.1/.cargo_vcs_info.json0000644000000001360000000000100131040ustar { "git": { "sha1": "73273e8d5d2f15b3ee825d3d0b0ba0c1990ac60f" }, "path_in_vcs": "" }der-parser-6.0.1/.gitignore000064400000000000000000000000310072674642500137060ustar 00000000000000target Cargo.lock .*.swp der-parser-6.0.1/CHANGELOG.md000064400000000000000000000225350072674642500135440ustar 00000000000000# Change Log ## [Unreleased][unreleased] ### Changed/Fixed ### Added ### Thanks ## 6.0.1 ### Changed/Fixed - Report number of missing bytes when having a complete header and incomplete data ## 6.0.0 This release has several major changes: - upgrade to nom 7 - add support for `no_std` - remove all macros - update MSRV to 1.48 ### Changed/Fixed - Do not attempt to parse PRIVATE object contents (closes #48) - BER: raise error if using Indefinite length and not constructed - Fix `oid!` macro to be independant of `der_parser` crate name and path (#46) - Simplify `der-oid-macro`, do not depend on `nom` - Fix `INTEGER` signed/unsigned parsing (#49) - Change `as_bigint()` and `as_uint()` to return a `Result` - Remove deprecated functions ### Added - Added support for `no_std` (#50) - Make `BerError` Copy + Clone (#51) - Add feature 'bitvec' for `.as_bitslice()` methods ### Removed - Remove all macros ### Thanks - @yoguorui for `no_std` support - @SergioBenitez for `BerError` traits - @lilyball for `INTEGER` parsing ## 5.1.0 ### Changed/Fixed - Remove dependency on proc-macro-hack (attempt to fix #36) - Update pretty_assertions requirement from 0.6 to 0.7 - Update num-bigint to 0.4 (Closes #42) ## 5.0.1 ### Changed/Fixed - Fix typos in the `parse_[ber|der]_[u32|u64]` doc comments - Add documentation for BerObjectContent variants (#41) - Fixes for clippy ### Added ## 5.0.0 See changelog entries for 5.0.0-beta1 and -beta2 for changes since 4.1 ### Changed/Fixed The following changes applies since 5.0.0-beta1, and do not affect 4.x - Fix potential integer underflow in `bytes_to_u64` - Fix potential stack recursion overflow for indefinite length objects (Add maximum depth). - Fix potential UB in bitstring_to_u64 with large input and many ignored bits - Fix constructed objects parsing with indefinite length (do not include EOC) - Constructed objects: use `InvalidTag` everywhere if tag is not expected - Integer parsing functions now all return `IntegerTooLarge` instead of `MapRes` - Ensure Indefinite length form is only used in BER constructed objects ### Added - Add new error `StringInvalidCharset` and update string parsing methods - Add methods `parse_ber_slice` and `parse_der_slice` to parse an expected Tag and get content as slice ## 5.0.0-beta2 ### Changed/Fixed - Consistency: reorder arguments or function callbacks, always set input slice as first argument (`parse_ber_sequence_defined_g`, `parse_ber_container`, `parse_ber_tagged_explicit_g`, ...) - Make functions `parse_ber_sequence_of_v` and `parse_ber_set_of_v` accept generic error types ### Added - Add `parse_ber_content2`, owned version of `parse_ber_content`, which can directly be combined with `parse_ber_tagged_implicit_g` - Add methods to parse DER tagged values and containers (with constraints) ## 5.0.0-beta1 ### Changed/Fixed - Upgrade to nom 6 - Switch all parsers to function-based parsers - Change representation of size (new type `BerSize`) to support BER indefinite lengths - Rewrite BER/DER parsing macros to use functional parsing combinators - The constructed bit is now tested for explicit tagged structures - Some checks (for ex. tags in constructed objects) now return specific errors (`InvalidTag`) instead of generic errors (`Verify`) - Refactor BerObject for parsing of tagged and optional values - Add method `as_bitslice()` to BerObject - Remove Copy trait from BerObjectHeader, copy is non-trivial and should be explicit - Fix the bug that caused OIDs longer than two subidentifiers which started by subidentifiers "0.0" ("itu-t recommenation") not to be decoded correctly - Implement the `as_u64` and `as_u32` methods for BerObjects with contents of type `BerObjectContent::BitString`. - Implement the `VideotexString`, `ObjectDescriptor` `GraphicString`, and `VisibleString` string types. (Non-breaking changes) - Correctly decode `BMPString` as UTF-16 instead of UTF-8 when printing. (Non-breaking change) - Turn `UTCTime` and `GeneralizedTime` into a `&str` instead of `&[u8]`, as they inherit from `VisibleString` which is a subset of ASCII. (Breaking change) ### Added - Add combinator `parse_ber_optional` ### Thanks By alphabetic order of handle: - `@cccs-sadugas` - `@nickelc` - `@p1-mmr` ## 4.1.0 ### Added/Changed - Re-export num-bigint so crate users do not have to import it - Add function versions to parse BER sequences/sets (#20) - Add function versions to parse BER tagged objects (#20) - Add generic error type to structured parsing functions - Add function to parse a generic BER container object - Document that trailing bytes from SEQUENCE/SET are ignored - Deprecate functions `parse_{ber,der}_explicit` (use `_optional`) ## 4.0.2 ### Changed/Fixed - Upgrade dependencies on num-bigint and der-oid-macro ## 4.0.1 ### Changed/Fixed - Add workaround to fix parsing of empty sequence or set ## 4.0.0 **Attention** This is a major release, with several API-breaking changes. See `UPGRADING.md` for instructions. ### Thanks - Jannik Schürg (oid, string verifications) ### Added - Add functions `parse_ber_recursive` and `parse_der_recursive`, allowing to specify maximum recursion depth when parsing - The string types `IA5String`, `NumericString`, `PrintableString` and `UTF8String` do now only parse if the characters are valid. - `as_str()` was added to `BerObjectContent` to obtain a `&str` for the types above. `as_slice()` works as before. - Implement `Error` trait for `BerError` - Add method to extract raw tag from header - `BerObjectHeader` now has a lifetime and a `raw_tag` field - `BerObject` now has a `raw_tag` field - Implement `PartialEq` manually for `BerObject`: `raw_tag` is compared only if both fields provide it - Add type `BerClass` - Start adding serialization support (experimental) using the `serialize` feature ### Changed/Fixed - Make header part of `BerObject`, remove duplicate fields - Maximum recursion logic has changed. Instead of providing the current depth, the argument is now the maximum possible depth. - Change the api around `Oid` to achieve zero-copy. The following changed: - The `Oid` struct now has a lifetime and uses `Cow` internally. - The procedural macro `oid!` was added. - `Oid::from` returns a `Result` now. - The `Oid` struct now encodes whether the oid is relative or not. - The `Debug` implementation now shows whether the oid is relative and uses the bigint feature if available. - The `Oid::iter` method now returns an `Option`. `Oid::iter_bigint` was added. - `Hash` is now derived for `Oid`. - Minimum rust version is now 1.34 ## 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. der-parser-6.0.1/Cargo.lock0000644000000160020000000000100110560ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "ansi_term" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ "winapi", ] [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitvec" version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527" dependencies = [ "funty", "radium", "tap", "wyz", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cookie-factory" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" [[package]] name = "ctor" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" dependencies = [ "quote", "syn", ] [[package]] name = "der-oid-macro" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c73af209b6a5dc8ca7cbaba720732304792cddc933cfea3d74509c2b1ef2f436" dependencies = [ "num-bigint", "num-traits", "syn", ] [[package]] name = "der-parser" version = "6.0.1" dependencies = [ "bitvec", "cookie-factory", "der-oid-macro", "hex-literal", "nom", "num-bigint", "num-traits", "pretty_assertions", "rusticata-macros", "test-case", ] [[package]] name = "diff" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] name = "funty" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" [[package]] name = "hex-literal" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" [[package]] name = "memchr" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nom" version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" dependencies = [ "memchr", "minimal-lexical", "version_check", ] [[package]] name = "num-bigint" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-integer" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg", "num-traits", ] [[package]] name = "num-traits" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg", ] [[package]] name = "output_vt100" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" dependencies = [ "winapi", ] [[package]] name = "pretty_assertions" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0cfe1b2403f172ba0f234e500906ee0a3e493fb81092dac23ebefe129301cc" dependencies = [ "ansi_term", "ctor", "diff", "output_vt100", ] [[package]] name = "proc-macro2" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" dependencies = [ "proc-macro2", ] [[package]] name = "radium" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" [[package]] name = "rusticata-macros" version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65c52377bb2288aa522a0c8208947fada1e0c76397f108cc08f57efe6077b50d" dependencies = [ "nom", ] [[package]] name = "syn" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "test-case" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7cad0a06f9a61e94355aa3b3dc92d85ab9c83406722b1ca5e918d4297c12c23" dependencies = [ "cfg-if", "proc-macro2", "quote", "syn", "version_check", ] [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "wyz" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188" dependencies = [ "tap", ] der-parser-6.0.1/Cargo.toml0000644000000034240000000000100111050ustar # 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 are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "der-parser" version = "6.0.1" authors = ["Pierre Chifflier "] include = ["LICENSE-*", "CHANGELOG.md", "README.md", "UPGRADING.md", ".gitignore", "Cargo.toml", "bench/*.rs", "src/*.rs", "src/ber/*.rs", "src/der/*.rs", "tests/*.rs", "der-oid-macro/Cargo.toml", "der-oid-macro/src/*.rs"] description = "Parser/encoder for ASN.1 BER/DER data" 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 rustdoc-args = ["--cfg", "docsrs"] [dependencies.bitvec] version = "0.22" optional = true [dependencies.cookie-factory] version = "0.3.0" optional = true [dependencies.der-oid-macro] version = "0.5" [dependencies.nom] version = "7.0" [dependencies.num-bigint] version = "0.4" optional = true [dependencies.num-traits] version = "0.2" [dependencies.rusticata-macros] version = "4.0" [dev-dependencies.hex-literal] version = "0.3" [dev-dependencies.pretty_assertions] version = "1.0" [dev-dependencies.test-case] version = "1.0" [features] bigint = ["num-bigint"] default = ["std"] serialize = ["std", "cookie-factory"] std = [] unstable = [] der-parser-6.0.1/Cargo.toml.orig000064400000000000000000000023240072674642500146140ustar 00000000000000[package] description = "Parser/encoder for ASN.1 BER/DER data" license = "MIT/Apache-2.0" keywords = ["BER","DER","ASN1","parser","nom"] homepage = "https://github.com/rusticata/der-parser" repository = "https://github.com/rusticata/der-parser.git" name = "der-parser" version = "6.0.1" authors = ["Pierre Chifflier "] categories = ["parser-implementations"] readme = "README.md" edition = "2018" include = [ "LICENSE-*", "CHANGELOG.md", "README.md", "UPGRADING.md", ".gitignore", "Cargo.toml", "bench/*.rs", "src/*.rs", "src/ber/*.rs", "src/der/*.rs", "tests/*.rs", "der-oid-macro/Cargo.toml", "der-oid-macro/src/*.rs", ] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] bitvec = { version="0.22", optional=true } cookie-factory = { version="0.3.0", optional=true } nom = "7.0" rusticata-macros = "4.0" num-traits = "0.2" num-bigint = { version = "0.4", optional = true } der-oid-macro = { version = "0.5", path = "./der-oid-macro" } [features] default = ["std"] bigint = ["num-bigint"] serialize = ["std", "cookie-factory"] unstable = [] std = [] [dev-dependencies] hex-literal = "0.3" pretty_assertions = "1.0" test-case = "1.0" der-parser-6.0.1/LICENSE-APACHE000064400000000000000000000251370072674642500136600ustar 00000000000000 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-6.0.1/LICENSE-MIT000064400000000000000000000020440072674642500133600ustar 00000000000000Copyright (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-6.0.1/README.md000064400000000000000000000237170072674642500132150ustar 00000000000000 [![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) [![docs.rs](https://docs.rs/der-parser/badge.svg)](https://docs.rs/der-parser) [![crates.io](https://img.shields.io/crates/v/der-parser.svg)](https://crates.io/crates/der-parser) [![Download numbers](https://img.shields.io/crates/d/der-parser.svg)](https://crates.io/crates/der-parser) [![dependency status](https://deps.rs/crate/der-parser/5.0.0/status.svg)](https://deps.rs/crate/der-parser/5.0.1) [![Github CI](https://github.com/rusticata/der-parser/workflows/Continuous%20integration/badge.svg)](https://github.com/rusticata/der-parser/actions) [![Minimum rustc version](https://img.shields.io/badge/rustc-1.48.0+-lightgray.svg)](#rust-version-requirements) # 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. It is written in pure Rust, fast, and makes extensive use of zero-copy. A lot of care is taken to ensure security and safety of this crate, including design (recursion limit, defensive programming), tests, and fuzzing. It also aims to be panic-free. Historically, this parser was intended for DER only, and BER support was added later. This may still reflect on some naming schemes, but has no other consequence: the `BerObject` and `DerObject` used in this crate are type aliases, so all functions are compatible. DER parsing functions have additional constraints verification, however. Serialization has also been added (see [Serialization](#serialization) ) The code is available on [Github](https://github.com/rusticata/der-parser) and is part of the [Rusticata](https://github.com/rusticata) project. # BER/DER parsers BER stands for Basic Encoding Rules, and is defined in [X.690]. It defines a set of rules to encode and decode ASN.1 objects in binary. [X.690] also defines Distinguished Encoding Rules (DER), which is BER with added rules to ensure canonical and unequivocal binary representation of objects. The choice of which one to use is usually guided by the speficication of the data format based on BER or DER: for example, X.509 uses DER as encoding representation. See the related modules for object definitions, functions, and example: - [`ber`]: Basic Encoding Rules - [`der`]: Distinguished Encoding Rules ## Examples Parse two BER integers (see [BER/DER Integers](#berder-integers)): ```rust use der_parser::ber::parse_ber_integer; let bytes = [ 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let (rem, obj1) = parse_ber_integer(&bytes).expect("parsing failed"); let (rem, obj2) = parse_ber_integer(&bytes).expect("parsing failed"); ``` Parse a DER sequence of integers: ```rust use der_parser::der::{parse_der_integer, parse_der_sequence_of}; let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let (rem, seq) = parse_der_sequence_of(parse_der_integer)(&bytes) .expect("parsing failed"); ``` Note: all parsing functions return the remaining (unparsed) bytes and the parsed object, or an error. # DER parser design Parsing functions are inspired from `nom`, and follow the same interface. The most common return type is [`BerResult`](https://docs.rs/der-parser/latest/der_parser/error/type.BerResult.html), that stores the remaining bytes and parsed [`BerObject`](https://docs.rs/der-parser/latest/der_parser/ber/struct.BerObject.html), or an error. Reading the nom documentation may help understanding how to write parsers and use the output. 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`](https://docs.rs/der-parser/latest/der_parser/ber/fn.parse_ber.html) and [`parse_der`](https://docs.rs/der-parser/latest/der_parser/der/fn.parse_der.html) methods. It is useful when decoding an arbitrary DER object. 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 functions can be used: - [`parse_ber_sequence_defined`](https://docs.rs/der-parser/latest/der_parser/ber/fn.parse_ber_sequence_defined.html) and similar functions for sequences and sets variants - [`parse_ber_tagged_explicit`](https://docs.rs/der-parser/latest/der_parser/ber/fn.parse_ber_tagged_explicit.html) for tagged explicit - [`parse_ber_tagged_implicit`](https://docs.rs/der-parser/latest/der_parser/ber/fn.parse_ber_tagged_implicit.html) for tagged implicit - [`parse_ber_container`](https://docs.rs/der-parser/latest/der_parser/ber/fn.parse_ber_container.html) for generic parsing, etc. - DER objects use the `_der_` variants For example, to read a BER sequence containing two integers: ```rust use der_parser::ber::*; use der_parser::error::BerResult; fn localparse_seq(i:&[u8]) -> BerResult { parse_ber_sequence_defined(|data| { let (rem, a) = parse_ber_integer(data)?; let (rem, b) = parse_ber_integer(rem)?; Ok((rem, vec![a, b])) })(i) } let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let (_, parsed) = localparse_seq(&bytes).expect("parsing failed"); assert_eq!(parsed[0].as_u64(), Ok(65537)); assert_eq!(parsed[1].as_u64(), Ok(65536)); ``` All functions return a [`BerResult`](https://docs.rs/der-parser/latest/der_parser/error/type.BerResult.html) object: the parsed [`BerObject`](https://docs.rs/der-parser/latest/der_parser/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 ## BER/DER Integers DER integers can be of any size, so it is not possible to store them as simple integers (they are stored as raw bytes). Note that, by default, BER/DER integers are signed. Functions are provided to request reading unsigned values, but they will fail if the integer value is negative. To get the integer value for all possible integer sign and size, use [`BerObject::as_bigint`](https://docs.rs/der-parser/latest/der_parser/ber/struct.BerObject.html#method.as_bigint)) (requires the `bigint` feature). To get a simple value expected to be in a known range, use methods like [`BerObject::as_i32`](ber/struct.BerObject.html#method.as_i32)) and [`BerObject::as_i64`](ber/struct.BerObject.html#method.as_i64) (or the unsigned versions [`BerObject::as_u32`](ber/struct.BerObject.html#method.as_u32) and [`BerObject::as_u64`](ber/struct.BerObject.html#method.as_u64) ), which will return the value, or an error if the integer is too large (or is negative). ```rust use der_parser::ber::*; let data = &[0x02, 0x03, 0x01, 0x00, 0x01]; let (_, object) = parse_ber_integer(data).expect("parsing failed"); assert_eq!(object.as_u64(), Ok(65537)); #[cfg(feature = "bigint")] assert_eq!(object.as_bigint(), Ok(65537.into())) ``` Access to the raw value is possible using the `as_slice` method. ## Parsers, combinators, macros Some parsing tools (for ex for tagged objects) are available in different forms: - parsers: (regular) functions that takes input and create an object - combinators: functions that takes parsers (or combinators) as input, and return a function (usually, the parser). They are used (combined) as building blocks to create more complex parsers. - macros: these are generally previous (historic) versions of parsers, kept for compatibility. They can sometime reduce the amount of code to write, but are hard to debug. Parsers should be preferred when possible. ## Misc 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*. ## Rust version requirements The 6.0 series of `der-parser` requires **Rustc version 1.48 or greater**, based on nom 7 dependencies. # Serialization Support for encoding BER/DER objects is currently being tested and can be used by activating the `serialize` feature. Note that current status is **experimental**. See the `ber_encode_*` functions in the [`ber`](https://docs.rs/der-parser/latest/der_parser/ber/index.html) module, and [`BerObject::to_vec`](https://docs.rs/der-parser/latest/der_parser/ber/struct.BerObject.html#method.to_vec) # 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 See `CHANGELOG.md`, and `UPGRADING.md` for instructions for upgrading major versions. ## 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-6.0.1/UPGRADING.md000064400000000000000000000100720072674642500135660ustar 00000000000000## Upgrading from 4.x to 5.0 ### BER variants: ContextSpecific, Optional, Tagged The variant `ContextSpecific` has been removed from `BerObject`, and 2 new variants have been added: - `Tagged` for explicit tagged objects, - `Optional` to simplify writing subparsers with only `BerObject` This is also used to clarify parsing of tagged values, and the API now clearly says if trying to parse an optional value or not. ### Ber Size The `len` field of `BerObjectHeader` is now an enum, to represent definite and indefinite lengths. To get the value, either match the type, or use `try_from` (which will fail if indefinite). ### Struct parsing Macros Functions and combinators are now the preferred way of parsing constructed objects. Macros have been upgrading and use the combinators internally. As a consequence, they do not return a tuple `(BerObjectHeader, T)` but only the built object `T`. The header should be removed from function signatures, for ex: ``` -fn parse_struct01(i: &[u8]) -> BerResult<(BerObjectHeader,MyStruct)> { +fn parse_struct01(i: &[u8]) -> BerResult { ``` The header was usually ignored, so this should simplify most uses of this macro. To get the header, use `parse_ber_container` directly. ## Upgrading from 3.x to 4.0 ### Ber Object and Header The `class`, `structured` and `tag` fields were duplicated in `BerObject` and the header. Now, a header is always created and embedded in the BER object, with the following changes: - To access these fields, use the header: `obj.tag` becomes `obj.header.tag`, etc. - `BerObject::to_header()` is now deprecated - The `len` field is now public. However, in some cases it can be 0 (when creating an object, 0 means that serialization will calculate the length) - As a consequence, `PartialEq` on BER objects and headers compare `len` only if set in both objects ### BER String types verification Some BER String types (`IA5String`, `NumericString`, `PrintableString` and `UTF8String`) are now verified, and will now only parse if the characters are valid. Their types have change from slice to `str` in the `BerObjectContent` enum. ### BerClass The `class` field of `BerObject` struct now uses the newtype `BerClass`. Use the provided constants (for ex `BerClass:Universal`). To access the value, just use `class.0`. ### Maximum depth The `depth` argument of functions (for ex. `ber_read_element_content_as`) has changed, and is now the maximum possible depth while parsing. Change it (usually from `0`) to a possible limit, for ex `der_parser::ber::MAX_RECURSION`. ### Oid This is probably the most impacting change. OID objects have been refactored, and are now zero-copy. This has several consequences: - `Oid` struct now has a lifetime, which must be propagated to objects using them - This makes having globally static structs difficult. Obtaining a `'static` object is possible using the `oid` macro. For ex: ```rust const SOME_STATIC_OID: Oid<'static> = oid!(1.2.456); ``` - Due to limitations of procedural macros ([rust issue](https://github.com/rust-lang/rust/issues/54727)) and constants used in patterns ([rust issue](https://github.com/rust-lang/rust/issues/31434)), the `oid` macro can not directly be used in patterns, also not through constants. You can do this, though: ```rust # use der_parser::{oid, oid::Oid}; # let some_oid: Oid<'static> = oid!(1.2.456); const SOME_OID: Oid<'static> = oid!(1.2.456); if some_oid == SOME_OID || some_oid == oid!(1.2.456) { println!("match"); } // Alternatively, compare the DER encoded form directly: const SOME_OID_RAW: &[u8] = &oid!(raw 1.2.456); match some_oid.bytes() { SOME_OID_RAW => println!("match"), _ => panic!("no match"), } ``` *Attention*, be aware that the latter version might not handle the case of a relative oid correctly. An extra check might be necessary. - To build an `Oid`, the `from`, `new` or `new_relative` methods can be used. - The `from` method now returns a `Result` (failure can happen if the first components are too large, for ex) - An `oid` macro has also been added in the `der-oid-macro` crate to easily build an `Oid` (see above). der-parser-6.0.1/src/ber/ber.rs000064400000000000000000001103320072674642500144010ustar 00000000000000use crate::ber::bitstring_to_u64; use crate::ber::integer::*; use crate::error::BerError; use crate::oid::Oid; use alloc::borrow::ToOwned; use alloc::boxed::Box; use alloc::vec::Vec; #[cfg(feature = "bitvec")] use bitvec::{order::Msb0, slice::BitSlice}; use core::convert::AsRef; use core::convert::From; use core::convert::TryFrom; use core::fmt; use core::ops::Index; use rusticata_macros::newtype_enum; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct BerClassFromIntError(pub(crate) ()); #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct BerSizeError(pub(crate) ()); /// BER Object class of tag #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[repr(u8)] pub enum BerClass { Universal = 0b00, Application = 0b01, ContextSpecific = 0b10, Private = 0b11, } /// Ber Object Length #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum BerSize { /// Definite form (X.690 8.1.3.3) Definite(usize), /// Indefinite form (X.690 8.1.3.6) Indefinite, } /// BER/DER Tag as defined in X.680 section 8.4 /// /// X.690 doesn't specify the maximum 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, VideotexString = 0x15, Ia5String = 0x16, UtcTime = 0x17, GeneralizedTime = 0x18, GraphicString = 25, // 0x19 VisibleString = 26, // 0x1a GeneralString = 27, // 0x1b UniversalString = 0x1c, BmpString = 0x1e, Invalid = 0xff, } } /// Representation of a BER-encoded (X.690) object /// /// A BER object is composed of a header describing the object class, type and length, /// and the content. /// /// Note that the content may sometimes not match the header tag (for ex when parsing IMPLICIT /// tagged values). #[derive(Debug, Clone, PartialEq)] pub struct BerObject<'a> { pub header: BerObjectHeader<'a>, pub content: BerObjectContent<'a>, } /// BER object header (identifier and length) #[derive(Clone, Debug)] pub struct BerObjectHeader<'a> { /// Object class: universal, application, context-specific, or private pub class: BerClass, /// Constructed attribute: 1 if constructed, else 0 pub structured: u8, /// Tag number pub tag: BerTag, /// Object length: definite or indefinite pub len: BerSize, /// Optionally, the raw encoding of the tag /// /// This is useful in some cases, where different representations of the same /// BER tags have different meanings (BER only) pub raw_tag: Option<&'a [u8]>, } /// BER object content #[derive(Debug, Clone, PartialEq)] #[allow(clippy::upper_case_acronyms)] pub enum BerObjectContent<'a> { /// EOC (no content) EndOfContent, /// BOOLEAN: decoded value Boolean(bool), /// INTEGER: raw bytes /// /// Note: the reason to store the raw bytes is that integers have non-finite length in the /// spec, and also that the raw encoding is also important for some applications. /// /// To extract the number, see the `as_u64`, `as_u32`, `as_bigint` and `as_biguint` methods. Integer(&'a [u8]), /// BIT STRING: number of unused bits, and object BitString(u8, BitStringObject<'a>), /// OCTET STRING: slice OctetString(&'a [u8]), /// NULL (no content) Null, /// ENUMERATED: decoded enum number Enum(u64), /// OID OID(Oid<'a>), /// RELATIVE OID RelativeOID(Oid<'a>), /// NumericString: decoded string NumericString(&'a str), /// VisibleString: decoded string VisibleString(&'a str), /// PrintableString: decoded string PrintableString(&'a str), /// IA5String: decoded string IA5String(&'a str), /// UTF8String: decoded string UTF8String(&'a str), /// T61String: raw object bytes T61String(&'a [u8]), /// VideotexString: raw object bytes VideotexString(&'a [u8]), /// BmpString: raw object bytes BmpString(&'a [u8]), /// UniversalString: raw object bytes UniversalString(&'a [u8]), /// SEQUENCE: list of objects Sequence(Vec>), /// SET: list of objects Set(Vec>), /// UTCTime: decoded string UTCTime(&'a str), /// GeneralizedTime: decoded string GeneralizedTime(&'a str), /// Object descriptor: raw object bytes ObjectDescriptor(&'a [u8]), /// GraphicString: raw object bytes GraphicString(&'a [u8]), /// GeneralString: raw object bytes GeneralString(&'a [u8]), /// Optional object Optional(Option>>), /// Tagged object (EXPLICIT): class, tag and content of inner object Tagged(BerClass, BerTag, Box>), /// Private Private(BerObjectHeader<'a>, &'a [u8]), /// Unknown object: object tag (copied from header), and raw content Unknown(BerClass, BerTag, &'a [u8]), } impl fmt::Display for BerClass { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { BerClass::Universal => "UNIVERSAL", BerClass::Application => "APPLICATION", BerClass::ContextSpecific => "CONTEXT-SPECIFIC", BerClass::Private => "PRIVATE", }; write!(f, "{}", s) } } impl From for BerTag { fn from(v: u32) -> Self { BerTag(v) } } impl BerSize { /// Return true if length is definite and equal to 0 pub fn is_null(&self) -> bool { *self == BerSize::Definite(0) } /// Get length of primitive object #[inline] pub fn primitive(&self) -> Result { match self { BerSize::Definite(sz) => Ok(*sz), BerSize::Indefinite => Err(BerError::IndefiniteLengthUnexpected), } } } impl From for BerSize { fn from(v: usize) -> Self { BerSize::Definite(v) } } impl TryFrom for BerSize { type Error = BerSizeError; fn try_from(value: u64) -> Result { let v = usize::try_from(value).or(Err(BerSizeError(())))?; Ok(BerSize::Definite(v)) } } impl TryFrom for usize { type Error = BerSizeError; #[inline] fn try_from(value: BerSize) -> Result { match value { BerSize::Definite(sz) => Ok(sz), BerSize::Indefinite => Err(BerSizeError(())), } } } impl TryFrom for BerClass { type Error = BerClassFromIntError; #[inline] fn try_from(value: u8) -> Result { match value { 0b00 => Ok(BerClass::Universal), 0b01 => Ok(BerClass::Application), 0b10 => Ok(BerClass::ContextSpecific), 0b11 => Ok(BerClass::Private), _ => Err(BerClassFromIntError(())), } } } impl<'a> BerObjectHeader<'a> { /// Build a new BER header pub fn new>(class: BerClass, structured: u8, tag: BerTag, len: Len) -> Self { BerObjectHeader { tag, structured, class, len: len.into(), raw_tag: None, } } /// Update header class #[inline] pub fn with_class(self, class: BerClass) -> Self { BerObjectHeader { class, ..self } } /// Update header tag #[inline] pub fn with_tag(self, tag: BerTag) -> Self { BerObjectHeader { tag, ..self } } /// Update header length #[inline] pub fn with_len(self, len: BerSize) -> Self { BerObjectHeader { len, ..self } } /// Update header to add reference to raw tag #[inline] pub fn with_raw_tag(self, raw_tag: Option<&'a [u8]>) -> Self { BerObjectHeader { raw_tag, ..self } } /// Test if object class is Universal #[inline] pub fn is_universal(&self) -> bool { self.class == BerClass::Universal } /// Test if object class is Application #[inline] pub fn is_application(&self) -> bool { self.class == BerClass::Application } /// Test if object class is Context-specific #[inline] pub fn is_contextspecific(&self) -> bool { self.class == BerClass::ContextSpecific } /// Test if object class is Private #[inline] pub fn is_private(&self) -> bool { self.class == BerClass::Private } /// 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<'o>( header: BerObjectHeader<'o>, content: BerObjectContent<'o>, ) -> BerObject<'o> { BerObject { header, content } } /// 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 = BerClass::Universal; let tag = c.tag(); let structured = match tag { BerTag::Sequence | BerTag::Set => 1, _ => 0, }; let header = BerObjectHeader::new(class, structured, tag, BerSize::Definite(0)); BerObject { header, content: c } } /// Build a DER integer object from a slice containing an encoded integer pub fn from_int_slice(i: &'a [u8]) -> BerObject<'a> { let header = BerObjectHeader::new( BerClass::Universal, 0, BerTag::Integer, BerSize::Definite(0), ); BerObject { header, content: BerObjectContent::Integer(i), } } /// Set a tag for the BER object pub fn set_raw_tag(self, raw_tag: Option<&'a [u8]>) -> BerObject { let header = BerObjectHeader { raw_tag, ..self.header }; BerObject { header, ..self } } /// 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 a signed integer value from DER object. /// /// This can fail if the object is not an integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x80"); /// assert_eq!( /// der_int.as_i64(), /// Ok(-128) /// ); /// ``` pub fn as_i64(&self) -> Result { self.content.as_i64() } /// Attempt to read a signed integer value from DER object. /// /// This can fail if the object is not an integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x80"); /// assert_eq!( /// der_int.as_i32(), /// Ok(-128) /// ); /// ``` pub fn as_i32(&self) -> Result { self.content.as_i32() } /// Attempt to read integer value from DER object. /// /// This can fail if the object is not an unsigned integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x01\x00\x01"); /// assert_eq!( /// der_int.as_u64(), /// Ok(0x10001) /// ); /// ``` pub fn as_u64(&self) -> Result { self.content.as_u64() } /// Attempt to read integer value from DER object. /// /// This can fail if the object is not an unsigned integer, or if it is too large. /// /// # Examples /// /// ```rust /// # extern crate der_parser; /// # use der_parser::ber::{BerObject,BerObjectContent}; /// let der_int = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); /// assert_eq!( /// der_int.as_u32(), /// Ok(0x10001) /// ); /// ``` pub fn as_u32(&self) -> Result { 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. pub fn as_oid(&self) -> Result<&Oid<'a>, 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, BerError> { self.content.as_oid_val() } /// Attempt to get a reference on the content from an optional object. /// This can fail if the object is not optional. pub fn as_optional(&'a self) -> Result>, BerError> { self.content.as_optional() } /// Attempt to get a reference on the content from a tagged object. /// This can fail if the object is not tagged. pub fn as_tagged(&'a self) -> Result<(BerClass, BerTag, &'_ BerObject<'a>), BerError> { self.content.as_tagged() } /// 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() } /// Constructs a shared `&BitSlice` reference over the object data, if available as slice. #[cfg(feature = "bitvec")] pub fn as_bitslice(&self) -> Result<&BitSlice, BerError> { self.content.as_bitslice() } /// 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() } /// Attempt to get the content from a DER object, as a str. /// This can fail if the object does not contain a string type. /// /// Only NumericString, VisibleString, UTCTime, GeneralizedTime, /// PrintableString, UTF8String and IA5String are considered here. Other /// string types can be read using `as_slice`. pub fn as_str(&self) -> Result<&'a str, BerError> { self.content.as_str() } /// Test if object class is Universal pub fn is_universal(&self) -> bool { self.header.class == BerClass::Universal } /// Test if object class is Application pub fn is_application(&self) -> bool { self.header.class == BerClass::Application } /// Test if object class is Context-specific pub fn is_contextspecific(&self) -> bool { self.header.class == BerClass::ContextSpecific } /// Test if object class is Private pub fn is_private(&self) -> bool { self.header.class == BerClass::Private } /// Test if object is primitive pub fn is_primitive(&self) -> bool { self.header.structured == 0 } /// Test if object is constructed pub fn is_constructed(&self) -> bool { self.header.structured == 1 } } /// Build a DER object from an OID. impl<'a> From> for BerObject<'a> { fn from(oid: Oid<'a>) -> 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) } } /// Compare two BER headers. `len` fields are compared only if both objects have it set (same for `raw_tag`) impl<'a> PartialEq> for BerObjectHeader<'a> { fn eq(&self, other: &BerObjectHeader) -> bool { self.class == other.class && self.tag == other.tag && self.structured == other.structured && { if self.len.is_null() && other.len.is_null() { self.len == other.len } else { true } } && { // it tag is present for both, compare it if self.raw_tag.xor(other.raw_tag).is_none() { self.raw_tag == other.raw_tag } else { true } } } } impl<'a> BerObjectContent<'a> { /// Attempt to read a signed integer value from this object. /// /// This can fail if the object is not an integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x80"); /// assert_eq!( /// der_int.as_i64(), /// Ok(-128) /// ); /// ``` pub fn as_i64(&self) -> Result { if let BerObjectContent::Integer(bytes) = self { let result = if is_highest_bit_set(bytes) { ::from_be_bytes(decode_array_int8(bytes)?) } else { ::from_be_bytes(decode_array_uint8(bytes)?) as i64 }; Ok(result) } else { Err(BerError::InvalidTag) } } /// Attempt to read a signed integer value from this object. /// /// This can fail if the object is not an integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x80"); /// assert_eq!( /// der_int.as_i32(), /// Ok(-128) /// ); /// ``` pub fn as_i32(&self) -> Result { if let BerObjectContent::Integer(bytes) = self { let result = if is_highest_bit_set(bytes) { ::from_be_bytes(decode_array_int4(bytes)?) } else { ::from_be_bytes(decode_array_uint4(bytes)?) as i32 }; Ok(result) } else { Err(BerError::InvalidTag) } } /// Attempt to read integer value from this object. /// /// This can fail if the object is not an unsigned integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x01\x00\x01"); /// assert_eq!( /// der_int.as_u64(), /// Ok(0x10001) /// ); /// ``` pub fn as_u64(&self) -> Result { match self { BerObjectContent::Integer(i) => { let result = ::from_be_bytes(decode_array_uint8(i)?); Ok(result) } BerObjectContent::BitString(ignored_bits, data) => { bitstring_to_u64(*ignored_bits as usize, data) } BerObjectContent::Enum(i) => Ok(*i as u64), _ => Err(BerError::BerTypeError), } } /// Attempt to read integer value from this object. /// /// This can fail if the object is not an unsigned integer, or if it is too large. /// /// # Examples /// /// ```rust /// # extern crate der_parser; /// # use der_parser::ber::{BerObject,BerObjectContent}; /// let der_int = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); /// assert_eq!( /// der_int.as_u32(), /// Ok(0x10001) /// ); /// ``` pub fn as_u32(&self) -> Result { match self { BerObjectContent::Integer(i) => { let result = ::from_be_bytes(decode_array_uint4(i)?); Ok(result) } BerObjectContent::BitString(ignored_bits, data) => { bitstring_to_u64(*ignored_bits as usize, data).and_then(|x| { if x > u64::from(core::u32::MAX) { Err(BerError::IntegerTooLarge) } else { Ok(x as u32) } }) } BerObjectContent::Enum(i) => { if *i > u64::from(core::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<'a>, 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, BerError> { self.as_oid().map(|o| o.clone()) } pub fn as_optional(&'a self) -> Result>, BerError> { match *self { BerObjectContent::Optional(Some(ref o)) => Ok(Some(o)), BerObjectContent::Optional(None) => Ok(None), _ => Err(BerError::BerTypeError), } } pub fn as_tagged(&'a self) -> Result<(BerClass, BerTag, &'_ BerObject<'a>), BerError> { match *self { BerObjectContent::Tagged(class, tag, ref o) => Ok((class, tag, o.as_ref())), _ => 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), } } /// Constructs a shared `&BitSlice` reference over the object data, if available as slice. #[cfg(feature = "bitvec")] pub fn as_bitslice(&self) -> Result<&BitSlice, BerError> { self.as_slice() .and_then(|s| BitSlice::::from_slice(s).map_err(|_| BerError::BerValueError)) } 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::NumericString(s) | BerObjectContent::GeneralizedTime(s) | BerObjectContent::UTCTime(s) | BerObjectContent::VisibleString(s) | BerObjectContent::PrintableString(s) | BerObjectContent::UTF8String(s) | BerObjectContent::IA5String(s) => Ok(s.as_ref()), BerObjectContent::Integer(s) | BerObjectContent::BitString(_,BitStringObject{data:s}) | BerObjectContent::OctetString(s) | BerObjectContent::T61String(s) | BerObjectContent::VideotexString(s) | BerObjectContent::BmpString(s) | BerObjectContent::UniversalString(s) | BerObjectContent::ObjectDescriptor(s) | BerObjectContent::GraphicString(s) | BerObjectContent::GeneralString(s) | BerObjectContent::Unknown(_, _,s) | BerObjectContent::Private(_,s) => Ok(s), _ => Err(BerError::BerTypeError), } } #[rustfmt::skip] pub fn as_str(&self) -> Result<&'a str,BerError> { match *self { BerObjectContent::NumericString(s) | BerObjectContent::GeneralizedTime(s) | BerObjectContent::UTCTime(s) | BerObjectContent::VisibleString(s) | BerObjectContent::PrintableString(s) | BerObjectContent::UTF8String(s) | BerObjectContent::IA5String(s) => Ok(s), _ => Err(BerError::BerTypeError), } } #[rustfmt::skip] 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::VisibleString(_) => BerTag::VisibleString, BerObjectContent::PrintableString(_) => BerTag::PrintableString, BerObjectContent::IA5String(_) => BerTag::Ia5String, BerObjectContent::UTF8String(_) => BerTag::Utf8String, BerObjectContent::RelativeOID(_) => BerTag::RelativeOid, BerObjectContent::T61String(_) => BerTag::T61String, BerObjectContent::VideotexString(_) => BerTag::VideotexString, BerObjectContent::BmpString(_) => BerTag::BmpString, BerObjectContent::UniversalString(_) => BerTag::UniversalString, BerObjectContent::Sequence(_) => BerTag::Sequence, BerObjectContent::Set(_) => BerTag::Set, BerObjectContent::UTCTime(_) => BerTag::UtcTime, BerObjectContent::GeneralizedTime(_) => BerTag::GeneralizedTime, BerObjectContent::ObjectDescriptor(_) => BerTag::ObjDescriptor, BerObjectContent::GraphicString(_) => BerTag::GraphicString, BerObjectContent::GeneralString(_) => BerTag::GeneralString, BerObjectContent::Tagged(_,x,_) | BerObjectContent::Unknown(_, x,_) => *x, &BerObjectContent::Private(ref hdr, _) => hdr.tag, BerObjectContent::Optional(Some(obj)) => obj.content.tag(), BerObjectContent::Optional(None) => BerTag(0x00), // XXX invalid ! } } } #[cfg(feature = "bigint")] #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))] use num_bigint::{BigInt, BigUint}; #[cfg(feature = "bigint")] #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))] impl<'a> BerObject<'a> { /// Attempt to read an integer value from this object. /// /// This can fail if the object is not an integer. /// /// # Examples /// /// ```rust /// use der_parser::ber::*; /// /// let data = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// /// let (_, object) = parse_ber_integer(data).expect("parsing failed"); /// # #[cfg(feature = "bigint")] /// assert_eq!(object.as_bigint(), Ok(65537.into())) /// ``` pub fn as_bigint(&self) -> Result { match self.content { BerObjectContent::Integer(s) => Ok(BigInt::from_signed_bytes_be(s)), _ => Err(BerError::InvalidTag), } } /// Attempt to read a positive integer value from this object. /// /// This can fail if the object is not an integer, or is negative. /// /// # Examples /// /// ```rust /// use der_parser::ber::*; /// /// let data = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// /// let (_, object) = parse_ber_integer(data).expect("parsing failed"); /// # #[cfg(feature = "bigint")] /// assert_eq!(object.as_biguint(), Ok(65537_u32.into())) /// ``` pub fn as_biguint(&self) -> Result { match self.content { BerObjectContent::Integer(s) => { if is_highest_bit_set(s) { return Err(BerError::IntegerNegative); } Ok(BigUint::from_bytes_be(s)) } _ => Err(BerError::InvalidTag), } } } // 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 } } } #[derive(Debug)] 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 // } // } #[derive(Debug)] 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 } /// Constructs a shared `&BitSlice` reference over the object data. #[cfg(feature = "bitvec")] pub fn as_bitslice(&self) -> Option<&BitSlice> { BitSlice::::from_slice(self.data).ok() } } 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_ber_as_u64_bitstring() { let (_, ber_obj) = parse_ber_bitstring(b"\x03\x04\x06\x6e\x5d\xc0").unwrap(); assert_eq!(ber_obj.as_u64(), Ok(0b011011100101110111)); let (_, ber_obj_with_nonzero_padding) = parse_ber_bitstring(b"\x03\x04\x06\x6e\x5d\xe0").unwrap(); assert_eq!( ber_obj_with_nonzero_padding.as_u64(), Ok(0b011011100101110111) ); } #[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]).unwrap().into(); let expected = BerObject::from_obj(BerObjectContent::OID(Oid::from(&[1, 2]).unwrap())); assert_eq!(obj, expected); } #[test] fn test_der_bitstringobject() { 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)); } #[cfg(feature = "bitvec")] #[test] fn test_der_bitslice() { use std::string::String; let obj = BitStringObject { data: &[0x0f, 0x00, 0x40], }; let slice = obj.as_bitslice().expect("as_bitslice"); assert_eq!(slice.get(0).as_deref(), Some(&false)); assert_eq!(slice.get(7).as_deref(), Some(&true)); assert_eq!(slice.get(9).as_deref(), Some(&false)); assert_eq!(slice.get(17).as_deref(), Some(&true)); let s = slice.iter().fold(String::with_capacity(24), |mut acc, b| { acc += if *b { "1" } else { "0" }; acc }); assert_eq!(&s, "000011110000000001000000"); } #[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(), Ok(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_u32); assert_eq!(obj.as_biguint(), Ok(expected)); } } der-parser-6.0.1/src/ber/integer.rs000064400000000000000000000101300072674642500152610ustar 00000000000000use crate::error::*; /// Decode an unsigned integer into a big endian byte slice with all leading /// zeroes removed. /// /// Returns a byte array of the requested size containing a big endian integer. fn remove_zeroes(bytes: &[u8]) -> Result<&[u8], BerError> { // skip leading 0s match bytes { // [] => Err(BerError::DerConstraintFailed), [0] => Ok(bytes), // [0, byte, ..] if *byte < 0x80 => Err(BerError::DerConstraintFailed), // [0, rest @ ..] => Ok(&rest), [0, rest @ ..] => remove_zeroes(rest), // [byte, ..] if *byte >= 0x80 => Err(BerError::IntegerTooLarge), _ => Ok(bytes), } } // XXX const generics require rustc >= 1.51 // /// Decode an unsigned integer into a byte array of the requested size // /// containing a big endian integer. // pub(crate) fn decode_array_uint(bytes: &[u8]) -> Result<[u8; N], BerError> { // // Check if MSB is set *before* leading zeroes // if is_highest_bit_set(bytes) { // return Err(BerError::IntegerNegative); // } // let input = remove_zeroes(bytes)?; // if input.len() > N { // return Err(BerError::IntegerTooLarge); // } // // Input has leading zeroes removed, so we need to add them back // let mut output = [0u8; N]; // assert!(input.len() <= N); // output[N.saturating_sub(input.len())..].copy_from_slice(input); // Ok(output) // } pub(crate) fn decode_array_uint8(bytes: &[u8]) -> Result<[u8; 8], BerError> { // Check if MSB is set *before* leading zeroes if is_highest_bit_set(bytes) { return Err(BerError::IntegerNegative); } let input = remove_zeroes(bytes)?; if input.len() > 8 { return Err(BerError::IntegerTooLarge); } // Input has leading zeroes removed, so we need to add them back let mut output = [0u8; 8]; assert!(input.len() <= 8); output[8_usize.saturating_sub(input.len())..].copy_from_slice(input); Ok(output) } pub(crate) fn decode_array_uint4(bytes: &[u8]) -> Result<[u8; 4], BerError> { // Check if MSB is set *before* leading zeroes if is_highest_bit_set(bytes) { return Err(BerError::IntegerNegative); } let input = remove_zeroes(bytes)?; if input.len() > 4 { return Err(BerError::IntegerTooLarge); } // Input has leading zeroes removed, so we need to add them back let mut output = [0u8; 4]; assert!(input.len() <= 4); output[4_usize.saturating_sub(input.len())..].copy_from_slice(input); Ok(output) } // XXX const generics require rustc >= 1.51 // /// Decode an unsigned integer of the specified size. // /// // /// Returns a byte array of the requested size containing a big endian integer. // pub(crate) fn decode_array_int(input: &[u8]) -> Result<[u8; N], BerError> { // let input = remove_zeroes(input)?; // if input.len() > N { // return Err(BerError::IntegerTooLarge); // } // // any.tag().assert_eq(Tag::Integer)?; // let mut output = [0xFFu8; N]; // let offset = N.saturating_sub(input.len()); // output[offset..].copy_from_slice(input); // Ok(output) // } pub(crate) fn decode_array_int8(input: &[u8]) -> Result<[u8; 8], BerError> { let input = remove_zeroes(input)?; if input.len() > 8 { return Err(BerError::IntegerTooLarge); } // any.tag().assert_eq(Tag::Integer)?; let mut output = [0xFFu8; 8]; let offset = 8_usize.saturating_sub(input.len()); output[offset..].copy_from_slice(input); Ok(output) } pub(crate) fn decode_array_int4(input: &[u8]) -> Result<[u8; 4], BerError> { let input = remove_zeroes(input)?; if input.len() > 4 { return Err(BerError::IntegerTooLarge); } // any.tag().assert_eq(Tag::Integer)?; let mut output = [0xFFu8; 4]; let offset = 4_usize.saturating_sub(input.len()); output[offset..].copy_from_slice(input); Ok(output) } /// Is the highest bit of the first byte in the slice 1? (if present) #[inline] pub(crate) fn is_highest_bit_set(bytes: &[u8]) -> bool { bytes .get(0) .map(|byte| byte & 0b10000000 != 0) .unwrap_or(false) } der-parser-6.0.1/src/ber/mod.rs000064400000000000000000000036440072674642500144170ustar 00000000000000//! Basic Encoding Rules (BER) objects and parser //! //! # BER Objects //! //! The main object of this crate is [`BerObject`]. It contains a header (ber tag, class, and size) //! and content. //! //! To parse primitive objects (for ex. integers or strings), use the `parse_ber_` set of //! functions. //! //! Constructed objects (like sequences, sets or tagged objects) require to use a combinator. This //! combinator takes a function or closure as input, and returns a new, specialized parser. //! See the [nom](https://github.com/geal/nom) parser combinator library for more details on //! combinators. //! //! # Examples //! //! Parse two BER integers: //! //! ```rust //! use der_parser::ber::parse_ber_integer; //! //! let bytes = [ 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x02, 0x03, 0x01, 0x00, 0x00, //! ]; //! //! let (rem, obj1) = parse_ber_integer(&bytes).expect("parsing failed"); //! let (rem, obj2) = parse_ber_integer(&bytes).expect("parsing failed"); //! ``` //! //! Parse a BER sequence containing one integer and an octetstring: //! //! ```rust //! use der_parser::ber::*; //! //! let bytes = [ 0x30, 0x0a, //! 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x04, 0x03, 0x62, 0x61, 0x64, //! ]; //! //! let (rem, seq) = parse_ber_sequence_defined(|content| { //! let (rem, obj1) = parse_ber_integer(content)?; //! let (rem, obj2) = parse_ber_octetstring(rem)?; //! Ok((rem, vec![obj1, obj2])) //! })(&bytes) //! .expect("parsing failed"); //! ``` mod ber; mod integer; mod multi; mod parser; mod print; #[cfg(feature = "serialize")] mod serialize; mod tagged; pub use crate::ber::ber::*; pub use crate::ber::multi::*; pub use crate::ber::parser::*; pub use crate::ber::print::*; #[cfg(feature = "serialize")] pub use crate::ber::serialize::*; pub use crate::ber::tagged::*; use alloc::borrow::Cow; use alloc::boxed::Box; use alloc::vec::Vec; use core::convert::{Into, TryFrom}; der-parser-6.0.1/src/ber/multi.rs000064400000000000000000000415660072674642500147770ustar 00000000000000use crate::ber::*; use crate::error::*; use nom::bytes::streaming::take; use nom::combinator::{all_consuming, complete, cut, map}; use nom::error::ParseError; use nom::multi::many0; use nom::{Err, IResult}; /// Parse a SEQUENCE OF object /// /// Given a subparser for a BER type, parse a sequence of identical objects. /// /// ```rust /// # use der_parser::ber::{parse_ber_integer, parse_ber_sequence_of, BerObject}; /// # use der_parser::error::BerResult; /// # /// /// Read a SEQUENCE OF INTEGER /// fn parser(i:&[u8]) -> BerResult { /// parse_ber_sequence_of(parse_ber_integer)(i) /// } /// /// # 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))); /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_sequence_of<'a, F>(f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: Fn(&'a [u8]) -> BerResult, { map(parse_ber_sequence_of_v(f), BerObject::from_seq) } /// Parse a SEQUENCE OF object (returning a vec) /// /// Given a subparser for a BER type, parse a sequence of identical objects. /// /// This differs from `parse_ber_sequence_of` in the parse function and return type. /// /// ```rust /// # use der_parser::ber::{parse_ber_integer, parse_ber_sequence_of_v, BerObject}; /// # use der_parser::error::BerResult; /// # /// /// Read a SEQUENCE OF INTEGER /// fn parser(i:&[u8]) -> BerResult> { /// parse_ber_sequence_of_v(parse_ber_integer)(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = vec![ /// # BerObject::from_int_slice(b"\x01\x00\x01"), /// # BerObject::from_int_slice(b"\x01\x00\x00"), /// # ]; /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// # assert_eq!(v, expected); /// ``` pub fn parse_ber_sequence_of_v<'a, T, F, E>( f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Vec, E> where F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, E: ParseError<&'a [u8]> + From, { let mut subparser = all_consuming(many0(complete(cut(f)))); parse_ber_sequence_defined_g(move |data, _| subparser(data)) } /// Parse a defined sequence of DER elements (function version) /// /// Given a list of expected parsers, apply them to build a DER sequence and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the sequence: any bytes that are part of the sequence but not /// parsed are ignored. /// /// The object header is not available to the parsing function, and the returned type is always a /// `BerObject`. /// For a generic version, see /// [`parse_ber_sequence_defined_g`](fn.parse_ber_sequence_defined_g.html). /// /// # Examples /// /// Parsing a sequence of identical types (same as `parse_ber_sequence_of`): /// /// ```rust /// # use der_parser::ber::{parse_ber_integer, parse_ber_sequence_defined, BerObject}; /// # use der_parser::error::BerResult; /// use nom::combinator::complete; /// use nom::multi::many1; /// /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_ber_sequence_defined( /// many1(complete(parse_ber_integer)) /// )(i) /// } /// /// # 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))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` /// /// Parsing a defined sequence with different types: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map; /// use nom::sequence::tuple; /// /// /// Read a DER-encoded object: /// /// SEQUENCE { /// /// a INTEGER, /// /// b OCTETSTRING /// /// } /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_ber_sequence_defined( /// // the nom `tuple` combinator returns a tuple, so we have to map it /// // to a list /// map( /// tuple((parse_ber_integer, parse_ber_octetstring)), /// |(a, b)| vec![a, b] /// ) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = BerObject::from_seq(vec![ /// # BerObject::from_int_slice(b"\x01\x00\x01"), /// # BerObject::from_obj(BerObjectContent::OctetString(b"\x01\x00\x00")), /// # ]); /// # assert_eq!(localparse_seq(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_sequence_defined<'a, F>(mut f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: FnMut(&'a [u8]) -> BerResult>, { map( parse_ber_sequence_defined_g(move |data, _| f(data)), BerObject::from_seq, ) } /// Parse a defined SEQUENCE object (generic function) /// /// Given a parser for sequence content, apply it to build a DER sequence and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the sequence: any bytes that are part of the sequence but not /// parsed are ignored. /// /// Unlike `parse_ber_sequence_defined`, this function allows returning any object or error type, /// and also passes the object header to the callback. /// /// # Examples /// /// Parsing a defined sequence with different types: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// # #[derive(Debug, PartialEq)] /// pub struct MyObject<'a> { /// a: u32, /// b: &'a [u8], /// } /// /// /// Read a DER-encoded object: /// /// SEQUENCE { /// /// a INTEGER (0..4294967295), /// /// b OCTETSTRING /// /// } /// fn parse_myobject(i: &[u8]) -> BerResult { /// parse_ber_sequence_defined_g( /// |i:&[u8], _| { /// let (i, a) = parse_ber_u32(i)?; /// let (i, obj) = parse_ber_octetstring(i)?; /// let b = obj.as_slice().unwrap(); /// Ok((i, MyObject{ a, b })) /// } /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = MyObject { /// # a: 0x010001, /// # b: &[01, 00, 00] /// # }; /// # assert_eq!(parse_myobject(&bytes), Ok((empty, expected))); /// let (rem, v) = parse_myobject(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_sequence_defined_g<'a, O, F, E>( mut f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E> where F: FnMut(&'a [u8], BerObjectHeader<'a>) -> IResult<&'a [u8], O, E>, E: ParseError<&'a [u8]> + From, { parse_ber_container(move |i, hdr| { if hdr.tag != BerTag::Sequence { return Err(Err::Error(BerError::InvalidTag.into())); } f(i, hdr) }) } /// Parse a SET OF object /// /// Given a subparser for a BER type, parse a set of identical objects. /// /// ```rust /// # use der_parser::ber::{parse_ber_integer, parse_ber_set_of, BerObject}; /// # use der_parser::error::BerResult; /// # /// /// Read a SET OF INTEGER /// fn parser(i:&[u8]) -> BerResult { /// parse_ber_set_of(parse_ber_integer)(i) /// } /// /// # 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))); /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_set_of<'a, F>(f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: Fn(&'a [u8]) -> BerResult, { map(parse_ber_set_of_v(f), BerObject::from_set) } /// Parse a SET OF object (returning a vec) /// /// Given a subparser for a BER type, parse a set of identical objects. /// /// This differs from `parse_ber_set_of` in the parse function and return type. /// /// ```rust /// # use der_parser::ber::{parse_ber_integer, parse_ber_set_of_v, BerObject}; /// # use der_parser::error::BerResult; /// # /// /// Read a SET OF INTEGER /// fn parser(i:&[u8]) -> BerResult> { /// parse_ber_set_of_v(parse_ber_integer)(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = vec![ /// # BerObject::from_int_slice(b"\x01\x00\x01"), /// # BerObject::from_int_slice(b"\x01\x00\x00"), /// # ]; /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// # assert_eq!(v, expected); /// ``` pub fn parse_ber_set_of_v<'a, T, F, E>(f: F) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Vec, E> where F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, E: ParseError<&'a [u8]> + From, { let mut subparser = all_consuming(many0(complete(cut(f)))); parse_ber_set_defined_g(move |data, _| subparser(data)) } /// Parse a defined set of DER elements (function version) /// /// Given a list of expected parsers, apply them to build a DER set and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the set: any bytes that are part of the sequence but not /// parsed are ignored. /// The nom combinator `all_consuming` can be used to ensure all the content is parsed. /// /// The object header is not available to the parsing function, and the returned type is always a /// `BerObject`. /// For a generic version, see [`parse_ber_set_defined_g`](fn.parse_ber_set_defined_g.html). /// /// # Examples /// /// Parsing a set of identical types (same as `parse_ber_set_of`): /// /// ```rust /// # use der_parser::ber::{parse_ber_integer, parse_ber_set_defined, BerObject}; /// # use der_parser::error::BerResult; /// use nom::combinator::complete; /// use nom::multi::many1; /// /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_ber_set_defined( /// many1(complete(parse_ber_integer)) /// )(i) /// } /// /// # 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_seq(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` /// /// Parsing a defined set with different types: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map; /// use nom::sequence::tuple; /// /// /// Read a DER-encoded object: /// /// SET { /// /// a INTEGER, /// /// b OCTETSTRING /// /// } /// fn localparse_set(i:&[u8]) -> BerResult { /// parse_ber_set_defined( /// // the nom `tuple` combinator returns a tuple, so we have to map it /// // to a list /// map( /// tuple((parse_ber_integer, parse_ber_octetstring)), /// |(a, b)| vec![a, b] /// ) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = BerObject::from_set(vec![ /// # BerObject::from_int_slice(b"\x01\x00\x01"), /// # BerObject::from_obj(BerObjectContent::OctetString(b"\x01\x00\x00")), /// # ]); /// # assert_eq!(localparse_set(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_set(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_set_defined<'a, F>(mut f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: FnMut(&'a [u8]) -> BerResult>, { map( parse_ber_set_defined_g(move |data, _| f(data)), BerObject::from_set, ) } /// Parse a defined SET object (generic version) /// /// Given a parser for set content, apply it to build a DER set and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the set: any bytes that are part of the sequence but not /// parsed are ignored. /// The nom combinator `all_consuming` can be used to ensure all the content is parsed. /// /// Unlike `parse_ber_set_defined`, this function allows returning any object or error type, /// and also passes the object header to the callback. /// /// # Examples /// /// Parsing a defined set with different types: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// # #[derive(Debug, PartialEq)] /// pub struct MyObject<'a> { /// a: u32, /// b: &'a [u8], /// } /// /// /// Read a DER-encoded object: /// /// SET { /// /// a INTEGER (0..4294967295), /// /// b OCTETSTRING /// /// } /// fn parse_myobject(i: &[u8]) -> BerResult { /// parse_ber_set_defined_g( /// |i:&[u8], _| { /// let (i, a) = parse_ber_u32(i)?; /// let (i, obj) = parse_ber_octetstring(i)?; /// let b = obj.as_slice().unwrap(); /// Ok((i, MyObject{ a, b })) /// } /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = MyObject { /// # a: 0x010001, /// # b: &[01, 00, 00] /// # }; /// # assert_eq!(parse_myobject(&bytes), Ok((empty, expected))); /// let (rem, v) = parse_myobject(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_set_defined_g<'a, O, F, E>( mut f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E> where F: FnMut(&'a [u8], BerObjectHeader<'a>) -> IResult<&'a [u8], O, E>, E: ParseError<&'a [u8]> + From, { parse_ber_container(move |i, hdr| { if hdr.tag != BerTag::Set { return Err(Err::Error(BerError::InvalidTag.into())); } f(i, hdr) }) } /// Parse a BER object and apply provided function to content /// /// Given a parser for content, read BER object header and apply parser to /// return the remaining bytes and the parser result. /// /// The remaining bytes point *after* the content: any bytes that are part of the content but not /// parsed are ignored. /// The nom combinator `all_consuming` can be used to ensure all the content is parsed. /// /// This function is mostly intended for structured objects, but can be used for any valid BER /// object. /// /// # Examples /// /// Parsing a defined sequence with different types: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::{BerError, BerResult}; /// # /// # #[derive(Debug, PartialEq)] /// pub struct MyObject<'a> { /// a: u32, /// b: &'a [u8], /// } /// /// /// Read a DER-encoded object: /// /// SEQUENCE { /// /// a INTEGER (0..4294967295), /// /// b OCTETSTRING /// /// } /// fn parse_myobject(i: &[u8]) -> BerResult { /// parse_ber_container( /// |i: &[u8], hdr: BerObjectHeader| { /// if hdr.tag != BerTag::Sequence { /// return Err(nom::Err::Error(BerError::BerTypeError.into())); /// } /// let (i, a) = parse_ber_u32(i)?; /// let (i, obj) = parse_ber_octetstring(i)?; /// let b = obj.as_slice().unwrap(); /// Ok((i, MyObject{ a, b })) /// } /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = MyObject { /// # a: 0x010001, /// # b: &[01, 00, 00] /// # }; /// # assert_eq!(parse_myobject(&bytes), Ok((empty, expected))); /// let (rem, v) = parse_myobject(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_container<'a, O, F, E>(mut f: F) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E> where F: FnMut(&'a [u8], BerObjectHeader<'a>) -> IResult<&'a [u8], O, E>, E: ParseError<&'a [u8]> + From, { move |i: &[u8]| { let (i, hdr) = ber_read_element_header(i).map_err(nom::Err::convert)?; let (i, data) = match hdr.len { BerSize::Definite(len) => take(len)(i)?, BerSize::Indefinite => { ber_get_object_content(i, &hdr, MAX_RECURSION).map_err(nom::Err::convert)? } }; let (_rest, v) = f(data, hdr)?; Ok((i, v)) } } der-parser-6.0.1/src/ber/parser.rs000064400000000000000000001276500072674642500151400ustar 00000000000000use crate::ber::*; use crate::error::*; use crate::oid::*; use nom::bytes::streaming::take; use nom::combinator::{complete, map, verify}; use nom::multi::{many0, many_till}; use nom::number::streaming::be_u8; use nom::{Err, Needed, Offset}; use rusticata_macros::{combinator::parse_hex_to_u64, custom_check}; /// Default maximum recursion limit pub const MAX_RECURSION: usize = 50; /// Default maximum object size (2^32) pub const MAX_OBJECT_SIZE: usize = 4_294_967_295; /// Skip object content, and return true if object was End-Of-Content pub(crate) fn ber_skip_object_content<'a>( i: &'a [u8], hdr: &BerObjectHeader, max_depth: usize, ) -> BerResult<'a, bool> { if max_depth == 0 { return Err(Err::Error(BerError::BerMaxDepth)); } match hdr.len { BerSize::Definite(l) => { if l == 0 && hdr.tag == BerTag::EndOfContent { return Ok((i, true)); } let (i, _) = take(l)(i)?; Ok((i, false)) } BerSize::Indefinite => { if hdr.is_primitive() { return Err(Err::Error(BerError::ConstructExpected)); } // read objects until EndOfContent (00 00) // this is recursive let mut i = i; loop { let (i2, header2) = ber_read_element_header(i)?; let (i3, eoc) = ber_skip_object_content(i2, &header2, max_depth - 1)?; if eoc { // return false, since top object was not EndOfContent return Ok((i3, false)); } i = i3; } } } } /// Read object raw content (bytes) pub(crate) fn ber_get_object_content<'a>( i: &'a [u8], hdr: &BerObjectHeader, max_depth: usize, ) -> BerResult<'a, &'a [u8]> { let start_i = i; let (i, _) = ber_skip_object_content(i, hdr, max_depth)?; let len = start_i.offset(i); let (content, i) = start_i.split_at(len); // if len is indefinite, there are 2 extra bytes for EOC if hdr.len == BerSize::Indefinite { let len = content.len(); assert!(len >= 2); Ok((i, &content[..len - 2])) } else { Ok((i, content)) } } /// Try to parse input bytes as u64 #[inline] 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) } /// Try to parse an input bit string as u64. /// /// Note: this is for the primitive BER/DER encoding only, the /// constructed BER encoding for BIT STRING does not seem to be /// supported at all by the library currently. #[inline] pub(crate) fn bitstring_to_u64( padding_bits: usize, data: &BitStringObject, ) -> Result { let raw_bytes = data.data; let bit_size = (raw_bytes.len() * 8) .checked_sub(padding_bits) .ok_or(BerError::InvalidLength)?; if bit_size > 64 { return Err(BerError::IntegerTooLarge); } let padding_bits = padding_bits % 8; let num_bytes = if bit_size % 8 > 0 { (bit_size / 8) + 1 } else { bit_size / 8 }; let mut resulting_integer: u64 = 0; for &c in &raw_bytes[..num_bytes] { resulting_integer <<= 8; resulting_integer |= c as u64; } Ok(resulting_integer >> padding_bits) } pub(crate) fn parse_identifier(i: &[u8]) -> BerResult<(u8, u8, u32, &[u8])> { if i.is_empty() { Err(Err::Incomplete(Needed::new(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; } } } let (raw_tag, rem) = i.split_at(tag_byte_count); Ok((rem, (a, b, c, raw_tag))) } } /// Return the MSB and the rest of the first byte, or an error pub(crate) fn parse_ber_length_byte(i: &[u8]) -> BerResult<(u8, u8)> { if i.is_empty() { Err(Err::Incomplete(Needed::new(1))) } else { let a = i[0] >> 7; let b = i[0] & 0b0111_1111; Ok((&i[1..], (a, b))) } } /// Read an object header /// /// ### Example /// /// ``` /// # use der_parser::ber::{ber_read_element_header, BerClass, BerSize, BerTag}; /// # /// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (i, hdr) = ber_read_element_header(bytes).expect("could not read header"); /// /// assert_eq!(hdr.class, BerClass::Universal); /// assert_eq!(hdr.tag, BerTag::Integer); /// assert_eq!(hdr.len, BerSize::Definite(3)); /// ``` pub fn ber_read_element_header(i: &[u8]) -> BerResult { let (i1, el) = parse_identifier(i)?; let class = match BerClass::try_from(el.0) { Ok(c) => c, Err(_) => unreachable!(), // Cannot fail, we have read exactly 2 bits }; let (i2, len) = parse_ber_length_byte(i1)?; let (i3, len) = match (len.0, len.1) { (0, l1) => { // Short form: MSB is 0, the rest encodes the length (which can be 0) (8.1.3.4) (i2, BerSize::Definite(usize::from(l1))) } (_, 0) => { // Indefinite form: MSB is 1, the rest is 0 (8.1.3.6) // If encoding is primitive, definite form shall be used (8.1.3.2) if el.1 == 0 { return Err(Err::Error(BerError::ConstructExpected)); } (i2, BerSize::Indefinite) } (_, l1) => { // if len is 0xff -> error (8.1.3.5) if l1 == 0b0111_1111 { return Err(::nom::Err::Error(BerError::InvalidTag)); } let (i3, llen) = take(l1)(i2)?; match bytes_to_u64(llen) { Ok(l) => { let l = usize::try_from(l).or(Err(::nom::Err::Error(BerError::InvalidLength)))?; (i3, BerSize::Definite(l)) } Err(_) => { return Err(::nom::Err::Error(BerError::InvalidTag)); } } } }; let hdr = BerObjectHeader::new(class, el.1, BerTag(el.2), len).with_raw_tag(Some(el.3)); Ok((i3, hdr)) } #[allow(clippy::unnecessary_wraps)] #[inline] fn ber_read_content_eoc(i: &[u8]) -> BerResult { Ok((i, BerObjectContent::EndOfContent)) } #[inline] 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] fn ber_read_content_integer(i: &[u8], len: usize) -> BerResult { map(take(len), BerObjectContent::Integer)(i) } #[inline] fn ber_read_content_bitstring(i: &[u8], len: usize) -> BerResult { custom_check!(i, len == 0, BerError::InvalidLength)?; let (i, ignored_bits) = be_u8(i)?; let (i, data) = take(len - 1)(i)?; Ok(( i, BerObjectContent::BitString(ignored_bits, BitStringObject { data }), )) } #[inline] fn ber_read_content_octetstring(i: &[u8], len: usize) -> BerResult { map(take(len), BerObjectContent::OctetString)(i) } #[allow(clippy::unnecessary_wraps)] #[inline] fn ber_read_content_null(i: &[u8]) -> BerResult { Ok((i, BerObjectContent::Null)) } fn ber_read_content_oid(i: &[u8], len: usize) -> BerResult { custom_check!(i, len == 0, BerError::InvalidLength)?; let (i1, oid) = verify(take(len), |os: &[u8]| os.last().unwrap() >> 7 == 0u8)(i)?; let obj = BerObjectContent::OID(Oid::new(Cow::Borrowed(oid))); Ok((i1, obj)) } #[inline] fn ber_read_content_enum(i: &[u8], len: usize) -> BerResult { let (rem, num) = parse_hex_to_u64(i, len).map_err(|_| BerError::BerValueError)?; Ok((rem, BerObjectContent::Enum(num))) } fn ber_read_content_utf8string(i: &[u8], len: usize) -> BerResult { let (i, bytes) = take(len)(i)?; let s = core::str::from_utf8(bytes) .map_err(|_| Err::Error(BerError::StringInvalidCharset)) .map(BerObjectContent::UTF8String)?; Ok((i, s)) } fn ber_read_content_relativeoid(i: &[u8], len: usize) -> BerResult { custom_check!(i, len == 0, BerError::InvalidLength)?; let (i1, oid) = verify(take(len), |os: &[u8]| os.last().unwrap() >> 7 == 0u8)(i)?; let obj = BerObjectContent::RelativeOID(Oid::new_relative(Cow::Borrowed(oid))); Ok((i1, obj)) } fn ber_read_content_sequence( i: &[u8], len: BerSize, max_depth: usize, ) -> BerResult { custom_check!(i, max_depth == 0, BerError::BerMaxDepth)?; match len { BerSize::Definite(len) => { let (i, data) = take(len)(i)?; let (_, l) = many0(complete(r_parse_ber(max_depth - 1)))(data)?; // trailing bytes are ignored Ok((i, BerObjectContent::Sequence(l))) } BerSize::Indefinite => { // indefinite form // read until end-of-content let (rem, (l, _)) = many_till(r_parse_ber(max_depth - 1), parse_ber_endofcontent)(i)?; Ok((rem, BerObjectContent::Sequence(l))) } } } fn ber_read_content_set(i: &[u8], len: BerSize, max_depth: usize) -> BerResult { custom_check!(i, max_depth == 0, BerError::BerMaxDepth)?; match len { BerSize::Definite(len) => { let (i, data) = take(len)(i)?; let (_, l) = many0(complete(r_parse_ber(max_depth - 1)))(data)?; // trailing bytes are ignored Ok((i, BerObjectContent::Set(l))) } BerSize::Indefinite => { // indefinite form // read until end-of-content let (rem, (l, _)) = many_till(r_parse_ber(max_depth - 1), parse_ber_endofcontent)(i)?; Ok((rem, BerObjectContent::Set(l))) } } } fn ber_read_content_numericstring<'a>(i: &'a [u8], len: usize) -> BerResult> { // Argument must be a reference, because of the .iter().all(F) call below #[allow(clippy::trivially_copy_pass_by_ref)] fn is_numeric(b: &u8) -> bool { matches!(*b, b'0'..=b'9' | b' ') } let (i, bytes) = take(len)(i)?; if !bytes.iter().all(is_numeric) { return Err(Err::Error(BerError::StringInvalidCharset)); } let s = core::str::from_utf8(bytes) .map_err(|_| Err::Error(BerError::StringInvalidCharset)) .map(BerObjectContent::NumericString)?; Ok((i, s)) } fn ber_read_content_visiblestring<'a>(i: &'a [u8], len: usize) -> BerResult> { // Argument must be a reference, because of the .iter().all(F) call below #[allow(clippy::trivially_copy_pass_by_ref)] fn is_visible(b: &u8) -> bool { 0x20 <= *b && *b <= 0x7f } let (i, bytes) = take(len)(i)?; if !bytes.iter().all(is_visible) { return Err(Err::Error(BerError::StringInvalidCharset)); } let s = core::str::from_utf8(bytes) .map_err(|_| Err::Error(BerError::StringInvalidCharset)) .map(BerObjectContent::VisibleString)?; Ok((i, s)) } fn ber_read_content_printablestring<'a>( i: &'a [u8], len: usize, ) -> BerResult> { // Argument must be a reference, because of the .iter().all(F) call below #[allow(clippy::trivially_copy_pass_by_ref)] fn is_printable(b: &u8) -> bool { matches!(*b, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b' ' | b'\'' | b'(' | b')' | b'+' | b',' | b'-' | b'.' | b'/' | b':' | b'=' | b'?') } let (i, bytes) = take(len)(i)?; if !bytes.iter().all(is_printable) { return Err(Err::Error(BerError::StringInvalidCharset)); } let s = core::str::from_utf8(bytes) .map_err(|_| Err::Error(BerError::StringInvalidCharset)) .map(BerObjectContent::PrintableString)?; Ok((i, s)) } #[inline] fn ber_read_content_t61string(i: &[u8], len: usize) -> BerResult { map(take(len), BerObjectContent::T61String)(i) } #[inline] fn ber_read_content_videotexstring(i: &[u8], len: usize) -> BerResult { map(take(len), BerObjectContent::VideotexString)(i) } fn ber_read_content_ia5string<'a>(i: &'a [u8], len: usize) -> BerResult> { let (i, bytes) = take(len)(i)?; if !bytes.iter().all(u8::is_ascii) { return Err(Err::Error(BerError::StringInvalidCharset)); } let s = core::str::from_utf8(bytes) .map_err(|_| Err::Error(BerError::StringInvalidCharset)) .map(BerObjectContent::IA5String)?; Ok((i, s)) } fn ber_read_content_utctime<'a>(i: &'a [u8], len: usize) -> BerResult> { // Argument must be a reference, because of the .iter().all(F) call below #[allow(clippy::trivially_copy_pass_by_ref)] fn is_visible(b: &u8) -> bool { 0x20 <= *b && *b <= 0x7f } let (i, bytes) = take(len)(i)?; if !bytes.iter().all(is_visible) { return Err(Err::Error(BerError::StringInvalidCharset)); } let s = core::str::from_utf8(bytes) .map_err(|_| Err::Error(BerError::StringInvalidCharset)) .map(BerObjectContent::UTCTime)?; Ok((i, s)) } fn ber_read_content_generalizedtime<'a>( i: &'a [u8], len: usize, ) -> BerResult> { // Argument must be a reference, because of the .iter().all(F) call below #[allow(clippy::trivially_copy_pass_by_ref)] fn is_visible(b: &u8) -> bool { 0x20 <= *b && *b <= 0x7f } let (i, bytes) = take(len)(i)?; if !bytes.iter().all(is_visible) { return Err(Err::Error(BerError::StringInvalidCharset)); } let s = core::str::from_utf8(bytes) .map_err(|_| Err::Error(BerError::StringInvalidCharset)) .map(BerObjectContent::GeneralizedTime)?; Ok((i, s)) } #[inline] fn ber_read_content_objectdescriptor(i: &[u8], len: usize) -> BerResult { map(take(len), BerObjectContent::ObjectDescriptor)(i) } #[inline] fn ber_read_content_graphicstring(i: &[u8], len: usize) -> BerResult { map(take(len), BerObjectContent::GraphicString)(i) } #[inline] fn ber_read_content_generalstring(i: &[u8], len: usize) -> BerResult { map(take(len), BerObjectContent::GeneralString)(i) } #[inline] fn ber_read_content_bmpstring(i: &[u8], len: usize) -> BerResult { map(take(len), BerObjectContent::BmpString)(i) } #[inline] fn ber_read_content_universalstring(i: &[u8], len: usize) -> BerResult { map(take(len), BerObjectContent::UniversalString)(i) } /// Parse the next bytes as the *content* of a BER object. /// /// Content type is *not* checked to match tag, caller is responsible of providing the correct tag /// /// This function is mostly used when parsing implicit tagged objects, when reading primitive /// types. /// /// `max_depth` is the maximum allowed recursion for objects. /// /// ### Example /// /// ``` /// # use der_parser::ber::{ber_read_element_content_as, ber_read_element_header, BerTag}; /// # /// # let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (i, hdr) = ber_read_element_header(bytes).expect("could not read header"); /// let (_, content) = ber_read_element_content_as( /// i, hdr.tag, hdr.len, hdr.is_constructed(), 5 /// ).expect("parsing failed"); /// # /// # assert_eq!(hdr.tag, BerTag::Integer); /// # assert_eq!(content.as_u32(), Ok(0x10001)); /// ``` pub fn ber_read_element_content_as( i: &[u8], tag: BerTag, len: BerSize, constructed: bool, max_depth: usize, ) -> BerResult { if let BerSize::Definite(l) = len { custom_check!(i, l > MAX_OBJECT_SIZE, BerError::InvalidLength)?; if i.len() < l { return Err(Err::Incomplete(Needed::new(l))); } } match tag { // 0x00 end-of-content BerTag::EndOfContent => { custom_check!(i, len != BerSize::Definite(0), BerError::InvalidLength)?; ber_read_content_eoc(i) } // 0x01 bool BerTag::Boolean => { let len = len.primitive()?; custom_check!(i, len != 1, BerError::InvalidLength)?; ber_read_content_bool(i) } // 0x02 BerTag::Integer => { custom_check!(i, constructed, BerError::ConstructUnexpected)?; let len = len.primitive()?; ber_read_content_integer(i, len) } // 0x03: bitstring BerTag::BitString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.6.3) let len = len.primitive()?; ber_read_content_bitstring(i, len) } // 0x04: octetstring BerTag::OctetString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.7.1) let len = len.primitive()?; ber_read_content_octetstring(i, len) } // 0x05: null BerTag::Null => { custom_check!(i, constructed, BerError::ConstructUnexpected)?; let len = len.primitive()?; custom_check!(i, len != 0, BerError::InvalidLength)?; ber_read_content_null(i) } // 0x06: object identifier BerTag::Oid => { custom_check!(i, constructed, BerError::ConstructUnexpected)?; // forbidden in 8.19.1 let len = len.primitive()?; ber_read_content_oid(i, len) } // 0x07: object descriptor - Alias for GraphicString with a different // implicit tag, see below BerTag::ObjDescriptor => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_objectdescriptor(i, len) } // 0x0a: enumerated BerTag::Enumerated => { custom_check!(i, constructed, BerError::ConstructUnexpected)?; // forbidden in 8.4 let len = len.primitive()?; ber_read_content_enum(i, len) } // 0x0c: UTF8String - Unicode encoded with the UTF-8 charset (ISO/IEC // 10646-1, Annex D) BerTag::Utf8String => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_utf8string(i, len) } // 0x0d: relative object identified BerTag::RelativeOid => { custom_check!(i, constructed, BerError::ConstructUnexpected)?; let len = len.primitive()?; ber_read_content_relativeoid(i, len) } // 0x10: sequence BerTag::Sequence => { custom_check!(i, !constructed, BerError::ConstructExpected)?; ber_read_content_sequence(i, len, max_depth) } // 0x11: set BerTag::Set => { custom_check!(i, !constructed, BerError::ConstructExpected)?; ber_read_content_set(i, len, max_depth) } // 0x12: numericstring - ASCII string with digits an spaces only BerTag::NumericString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_numericstring(i, len) } // 0x13: printablestring - ASCII string with certain printable // characters only (specified in Table 10 of X.680) BerTag::PrintableString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_printablestring(i, len) } // 0x14: t61string - ISO 2022 string with a Teletex (T.61) charset, // ASCII is possible but only when explicit escaped, as by default // the G0 character range (0x20-0x7f) will match the graphic character // set. https://en.wikipedia.org/wiki/ITU_T.61 BerTag::T61String => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_t61string(i, len) } // 0x15: videotexstring - ISO 2022 string with a Videotex (T.100/T.101) // charset, excluding ASCII. https://en.wikipedia.org/wiki/Videotex_character_set BerTag::VideotexString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_videotexstring(i, len) } // 0x16: ia5string - ASCII string BerTag::Ia5String => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_ia5string(i, len) } // 0x17: utctime - Alias for a VisibleString with a different implicit // tag, see below BerTag::UtcTime => { let len = len.primitive()?; ber_read_content_utctime(i, len) } // 0x18: generalizedtime - Alias for a VisibleString with a different // implicit tag, see below BerTag::GeneralizedTime => { let len = len.primitive()?; ber_read_content_generalizedtime(i, len) } // 0x19: graphicstring - Generic ISO 2022 container with explicit // escape sequences, without control characters BerTag::GraphicString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_graphicstring(i, len) } // 0x1a: visiblestring - ASCII string with no control characters except // SPACE BerTag::VisibleString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_visiblestring(i, len) } // 0x1b: generalstring - Generic ISO 2022 container with explicit // escape sequences BerTag::GeneralString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_generalstring(i, len) } // 0x1e: bmpstring - Unicode encoded with the UCS-2 big-endian charset // (ISO/IEC 10646-1, section 13.1), restricted to the BMP (Basic // Multilingual Plane) except certain control cahracters BerTag::BmpString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_bmpstring(i, len) } // 0x1c: universalstring - Unicode encoded with the UCS-4 big-endian // charset (ISO/IEC 10646-1, section 13.2) BerTag::UniversalString => { custom_check!(i, constructed, BerError::Unsupported)?; // XXX valid in BER (8.21) let len = len.primitive()?; ber_read_content_universalstring(i, len) } // all unknown values _ => Err(Err::Error(BerError::UnknownTag)), } } /// Parse the next bytes as the content of a BER object (combinator, header reference) /// /// Content type is *not* checked to match tag, caller is responsible of providing the correct tag /// /// Caller is also responsible to check if parsing function consumed the expected number of /// bytes (`header.len`). /// /// The arguments of the parse function are: `(input, ber_object_header, max_recursion)`. /// /// This function differs from [`parse_ber_content2`](fn.parse_ber_content2.html) because it passes /// the BER object header by reference (required for ex. by `parse_ber_implicit`). /// /// Example: manually parsing header and content /// /// ``` /// # use der_parser::ber::*; /// # /// # let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (i, header) = ber_read_element_header(bytes).expect("parsing failed"); /// let (rem, content) = parse_ber_content(header.tag)(i, &header, MAX_RECURSION) /// .expect("parsing failed"); /// # /// # assert_eq!(header.tag, BerTag::Integer); /// ``` pub fn parse_ber_content<'a>( tag: BerTag, ) -> impl Fn(&'a [u8], &'_ BerObjectHeader, usize) -> BerResult<'a, BerObjectContent<'a>> { move |i: &[u8], hdr: &BerObjectHeader, max_recursion: usize| { ber_read_element_content_as(i, tag, hdr.len, hdr.is_constructed(), max_recursion) } } /// Parse the next bytes as the content of a BER object (combinator, owned header) /// /// Content type is *not* checked to match tag, caller is responsible of providing the correct tag /// /// Caller is also responsible to check if parsing function consumed the expected number of /// bytes (`header.len`). /// /// The arguments of the parse function are: `(input, ber_object_header, max_recursion)`. /// /// This function differs from [`parse_ber_content`](fn.parse_ber_content.html) because it passes /// an owned BER object header (required for ex. by `parse_ber_tagged_implicit_g`). /// /// Example: manually parsing header and content /// /// ``` /// # use der_parser::ber::*; /// # /// # let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (i, header) = ber_read_element_header(bytes).expect("parsing failed"); /// let (rem, content) = parse_ber_content(header.tag)(i, &header, MAX_RECURSION) /// .expect("parsing failed"); /// # /// # assert_eq!(header.tag, BerTag::Integer); /// ``` pub fn parse_ber_content2<'a>( tag: BerTag, ) -> impl Fn(&'a [u8], BerObjectHeader<'a>, usize) -> BerResult<'a, BerObjectContent<'a>> { move |i: &[u8], hdr: BerObjectHeader, max_recursion: usize| { ber_read_element_content_as(i, tag, hdr.len, hdr.is_constructed(), max_recursion) } } /// Parse a BER object, expecting a value with specified tag /// /// The object is parsed recursively, with a maximum depth of `MAX_RECURSION`. /// /// ### Example /// /// ``` /// use der_parser::ber::BerTag; /// use der_parser::ber::parse_ber_with_tag; /// /// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (_, obj) = parse_ber_with_tag(bytes, BerTag::Integer).expect("parsing failed"); /// /// assert_eq!(obj.header.tag, BerTag::Integer); /// ``` pub fn parse_ber_with_tag>(i: &[u8], tag: Tag) -> BerResult { let tag = tag.into(); let (i, hdr) = ber_read_element_header(i)?; if hdr.tag != tag { return Err(nom::Err::Error(BerError::InvalidTag)); } let (i, content) = ber_read_element_content_as(i, hdr.tag, hdr.len, hdr.is_constructed(), MAX_RECURSION)?; Ok((i, BerObject::from_header_and_content(hdr, content))) } /// 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 /// # extern crate nom; /// # use der_parser::ber::parse_ber_integer; /// # use der_parser::ber::{BerObject,BerObjectContent}; /// 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. The encoding is checked. #[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. The content is verified to /// contain only digits and spaces. #[inline] pub fn parse_ber_numericstring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::NumericString) } /// Read a visible string value. The content is verified to /// contain only the allowed characters. #[inline] pub fn parse_ber_visiblestring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::VisibleString) } /// Read a printable string value. The content is verified to /// contain only the allowed characters. #[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 a Videotex string value #[inline] pub fn parse_ber_videotexstring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::VideotexString) } /// Read an IA5 string value. The content is verified to be ASCII. #[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 an ObjectDescriptor value #[inline] pub fn parse_ber_objectdescriptor(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::ObjDescriptor) } /// Read a GraphicString value #[inline] pub fn parse_ber_graphicstring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::GraphicString) } /// 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) } /// Read a UniversalString value #[inline] pub fn parse_ber_universalstring(i: &[u8]) -> BerResult { parse_ber_with_tag(i, BerTag::UniversalString) } /// Parse an optional tagged object, applying function to get content /// /// This function returns a `BerObject`, trying to read content as generic BER objects. /// If parsing failed, return an optional object containing `None`. /// /// To support other return or error types, use /// [parse_ber_tagged_explicit_g](fn.parse_ber_tagged_explicit_g.html) /// /// This function will never fail: if parsing content failed, the BER value `Optional(None)` is /// returned. pub fn parse_ber_explicit_optional(i: &[u8], tag: BerTag, f: F) -> BerResult where F: Fn(&[u8]) -> BerResult, { parse_ber_optional(parse_ber_tagged_explicit_g(tag, |content, hdr| { let (rem, obj) = f(content)?; let content = BerObjectContent::Tagged(hdr.class, hdr.tag, Box::new(obj)); let tagged = BerObject::from_header_and_content(hdr, content); Ok((rem, tagged)) }))(i) } /// Parse an implicit tagged object, applying function to read content /// /// Note: unlike explicit tagged functions, the callback must be a *content* parsing function, /// often based on the [`parse_ber_content`](fn.parse_ber_content.html) combinator. /// /// The built object will use the original header (and tag), so the content may not match the tag /// value. /// /// For a combinator version, see [parse_ber_tagged_implicit](fn.parse_ber_tagged_implicit.html). /// /// For a generic version (different output and error types), see /// [parse_ber_tagged_implicit_g](fn.parse_ber_tagged_implicit_g.html). /// /// # Examples /// /// The following parses `[3] IMPLICIT INTEGER` into a `BerObject`: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// fn parse_int_implicit(i:&[u8]) -> BerResult { /// parse_ber_implicit( /// i, /// 3, /// parse_ber_content(BerTag::Integer), /// ) /// } /// /// # let bytes = &[0x83, 0x03, 0x01, 0x00, 0x01]; /// let res = parse_int_implicit(bytes); /// # match res { /// # Ok((rem, content)) => { /// # assert!(rem.is_empty()); /// # assert_eq!(content.as_u32(), Ok(0x10001)); /// # }, /// # _ => assert!(false) /// # } /// ``` #[inline] pub fn parse_ber_implicit<'a, Tag, F>(i: &'a [u8], tag: Tag, f: F) -> BerResult<'a> where F: Fn(&'a [u8], &'_ BerObjectHeader, usize) -> BerResult<'a, BerObjectContent<'a>>, Tag: Into, { parse_ber_tagged_implicit(tag, f)(i) } /// Combinator for building optional BER values /// /// To read optional BER values, it is to use the nom `opt()` combinator. However, this results in /// a `Option` and prevents using some functions from this crate (the generic functions /// can still be used). /// /// This combinator is used when parsing BER values, while keeping `BerObject` output only. /// /// This function will never fail: if parsing content failed, the BER value `Optional(None)` is /// returned. /// /// ### Example /// /// ``` /// # use der_parser::ber::*; /// # /// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let mut parser = parse_ber_optional(parse_ber_integer); /// let (_, obj) = parser(bytes).expect("parsing failed"); /// /// assert_eq!(obj.header.tag, BerTag::Integer); /// assert!(obj.as_optional().is_ok()); /// ``` pub fn parse_ber_optional<'a, F>(mut f: F) -> impl FnMut(&'a [u8]) -> BerResult<'a> where F: FnMut(&'a [u8]) -> BerResult<'a>, { move |i: &[u8]| { let res = f(i); match res { Ok((rem, inner)) => { let opt = BerObject::from_header_and_content( inner.header.clone(), BerObjectContent::Optional(Some(Box::new(inner))), ); Ok((rem, opt)) } Err(_) => Ok((i, BerObject::from_obj(BerObjectContent::Optional(None)))), } } } /// Parse BER object and try to decode it as a 32-bits signed integer /// /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. #[inline] pub fn parse_ber_i32(i: &[u8]) -> BerResult { let (rem, ber) = parse_ber_integer(i)?; let int = ber.as_i32().map_err(nom::Err::Error)?; Ok((rem, int)) } /// Parse BER object and try to decode it as a 64-bits signed integer /// /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. #[inline] pub fn parse_ber_i64(i: &[u8]) -> BerResult { let (rem, ber) = parse_ber_integer(i)?; let int = ber.as_i64().map_err(nom::Err::Error)?; Ok((rem, int)) } /// Parse BER object and try to decode it as a 32-bits unsigned integer /// /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. #[inline] pub fn parse_ber_u32(i: &[u8]) -> BerResult { let (rem, ber) = parse_ber_integer(i)?; let int = ber.as_u32().map_err(nom::Err::Error)?; Ok((rem, int)) } /// Parse BER object and try to decode it as a 64-bits unsigned integer /// /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. #[inline] pub fn parse_ber_u64(i: &[u8]) -> BerResult { let (rem, ber) = parse_ber_integer(i)?; let int = ber.as_u64().map_err(nom::Err::Error)?; Ok((rem, int)) } /// Parse BER object and get content as slice #[inline] pub fn parse_ber_slice>(i: &[u8], tag: Tag) -> BerResult<&[u8]> { let tag = tag.into(); parse_ber_container(move |content, hdr| { if hdr.tag != tag { return Err(Err::Error(BerError::InvalidTag)); } Ok((&b""[..], content)) })(i) } /// Helper combinator, to create a parser with a maximum parsing depth #[inline] pub(crate) fn r_parse_ber(max_depth: usize) -> impl Fn(&[u8]) -> BerResult { move |i: &[u8]| parse_ber_recursive(i, max_depth) } /// Parse BER object recursively, specifying the maximum recursion depth /// /// Return a tuple containing the remaining (unparsed) bytes and the BER Object, or an error. /// /// ### Example /// /// ``` /// use der_parser::ber::{parse_ber_recursive, BerTag}; /// /// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (_, obj) = parse_ber_recursive(bytes, 1).expect("parsing failed"); /// /// assert_eq!(obj.header.tag, BerTag::Integer); /// ``` pub fn parse_ber_recursive(i: &[u8], max_depth: usize) -> BerResult { custom_check!(i, max_depth == 0, BerError::BerMaxDepth)?; let (rem, hdr) = ber_read_element_header(i)?; if let BerSize::Definite(l) = hdr.len { custom_check!(i, l > MAX_OBJECT_SIZE, BerError::InvalidLength)?; } match hdr.class { BerClass::Universal => (), BerClass::Private => { let (rem, content) = ber_get_object_content(rem, &hdr, max_depth)?; let content = BerObjectContent::Private(hdr.clone(), content); let obj = BerObject::from_header_and_content(hdr, content); return Ok((rem, obj)); } _ => { let (rem, content) = ber_get_object_content(rem, &hdr, max_depth)?; let content = BerObjectContent::Unknown(hdr.class, hdr.tag, content); let obj = BerObject::from_header_and_content(hdr, content); return Ok((rem, obj)); } } match ber_read_element_content_as(rem, hdr.tag, hdr.len, hdr.is_constructed(), max_depth) { Ok((rem, content)) => Ok((rem, BerObject::from_header_and_content(hdr, content))), Err(Err::Error(BerError::UnknownTag)) => { let (rem, content) = ber_get_object_content(rem, &hdr, max_depth)?; let content = BerObjectContent::Unknown(hdr.class, hdr.tag, content); let obj = BerObject::from_header_and_content(hdr, content); Ok((rem, obj)) } Err(e) => Err(e), } } /// Parse BER object recursively /// /// Return a tuple containing the remaining (unparsed) bytes and the BER Object, or an error. /// /// *Note*: this is the same as calling `parse_ber_recursive` with `MAX_RECURSION`. /// /// ### Example /// /// ``` /// use der_parser::ber::{parse_ber, BerTag}; /// /// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (_, obj) = parse_ber(bytes).expect("parsing failed"); /// /// assert_eq!(obj.header.tag, BerTag::Integer); /// ``` #[inline] pub fn parse_ber(i: &[u8]) -> BerResult { parse_ber_recursive(i, MAX_RECURSION) } #[test] fn test_numericstring() { assert_eq!( ber_read_content_numericstring(b" 0123 4495768 ", 15), Ok(( [].as_ref(), BerObjectContent::NumericString(" 0123 4495768 ") )), ); assert_eq!( ber_read_content_numericstring(b"", 0), Ok(([].as_ref(), BerObjectContent::NumericString(""))), ); assert!(ber_read_content_numericstring(b"123a", 4).is_err()); } #[test] fn text_visiblestring() { assert_eq!( ber_read_content_visiblestring(b"AZaz]09 '()+,-./:=?", 19), Ok(( [].as_ref(), BerObjectContent::VisibleString("AZaz]09 '()+,-./:=?") )), ); assert_eq!( ber_read_content_visiblestring(b"", 0), Ok(([].as_ref(), BerObjectContent::VisibleString(""))), ); assert!(ber_read_content_visiblestring(b"\n", 1).is_err()); } #[test] fn test_printablestring() { assert_eq!( ber_read_content_printablestring(b"AZaz09 '()+,-./:=?", 18), Ok(( [].as_ref(), BerObjectContent::PrintableString("AZaz09 '()+,-./:=?") )), ); assert_eq!( ber_read_content_printablestring(b"", 0), Ok(([].as_ref(), BerObjectContent::PrintableString(""))), ); assert!(ber_read_content_printablestring(b"]\n", 2).is_err()); } #[test] fn test_ia5string() { assert_eq!( ber_read_content_ia5string(b"AZaz\n09 '()+,-./:=?[]{}\0\n", 25), Ok(( [].as_ref(), BerObjectContent::IA5String("AZaz\n09 '()+,-./:=?[]{}\0\n") )), ); assert_eq!( ber_read_content_ia5string(b"", 0), Ok(([].as_ref(), BerObjectContent::IA5String(""))), ); assert!(ber_read_content_ia5string(b"\xFF", 1).is_err()); } #[test] fn test_utf8string() { assert_eq!( ber_read_content_utf8string("AZaz09 '()+,-./:=?[]{}\0\nüÜ".as_ref(), 28), Ok(( [].as_ref(), BerObjectContent::UTF8String("AZaz09 '()+,-./:=?[]{}\0\nüÜ") )), ); assert_eq!( ber_read_content_utf8string(b"", 0), Ok(([].as_ref(), BerObjectContent::UTF8String(""))), ); assert!(ber_read_content_utf8string(b"\xe2\x28\xa1", 3).is_err()); } #[test] fn test_bitstring_to_u64() { // ignored bits modulo 8 to 0 let data = &hex_literal::hex!("0d 71 82"); let r = bitstring_to_u64(8, &BitStringObject { data }); assert_eq!(r, Ok(0x0d71)); // input too large to fit a 64-bits integer let data = &hex_literal::hex!("0d 71 82 0e 73 72 76 6e 67 6e 62 6c 6e 2d 65 78 30 31"); let r = bitstring_to_u64(0, &BitStringObject { data }); assert!(r.is_err()); // test large number but with many ignored bits let data = &hex_literal::hex!("0d 71 82 0e 73 72 76 6e 67 6e 62 6c 6e 2d 65 78 30 31"); let r = bitstring_to_u64(130, &BitStringObject { data }); // 2 = 130 % 8 assert_eq!(r, Ok(0x0d71 >> 2)); } der-parser-6.0.1/src/ber/print.rs000064400000000000000000000163100072674642500147660ustar 00000000000000use crate::ber::BitStringObject; use crate::ber::{BerObject, BerObjectContent, BerTag}; use alloc::string::String; use alloc::vec::Vec; use core::fmt; use core::iter::FromIterator; use core::str; use rusticata_macros::debug; #[derive(Clone, Debug, 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.header.class, self.obj.header.structured, self.obj.header.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), } } fn print_utf16_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result { let chars: Vec = s .chunks_exact(2) .map(|a| u16::from_be_bytes([a[0], a[1]])) .collect(); match String::from_utf16(&chars) { Ok(b) => writeln!(f, "{}(\"{}\")", ty, b), Err(e) => writeln!(f, "{}({:?}) ", ty, s, e), } } fn print_utf32_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result { let chars: Option> = s .chunks_exact(4) .map(|a| core::char::from_u32(u32::from_be_bytes([a[0], a[1], a[2], a[3]]))) .collect(); match chars { Some(b) => writeln!(f, "{}(\"{}\")", ty, String::from_iter(b)), None => writeln!(f, "{}({:?}) ", ty, s), } } 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) => writeln!(f, "GeneralizedTime(\"{}\")", s), BerObjectContent::UTCTime(s) => writeln!(f, "UTCTime(\"{}\")", s), BerObjectContent::VisibleString(s) => writeln!(f, "VisibleString(\"{}\")", s), BerObjectContent::PrintableString(s) => writeln!(f, "PrintableString(\"{}\")", s), BerObjectContent::NumericString(s) => writeln!(f, "NumericString(\"{}\")", s), BerObjectContent::UTF8String(s) => writeln!(f, "UTF8String(\"{}\")", s), BerObjectContent::IA5String(s) => writeln!(f, "IA5String(\"{}\")", s), BerObjectContent::T61String(v) => writeln!(f, "T61String({:?})", debug::HexSlice(v)), BerObjectContent::VideotexString(v) => writeln!(f, "VideotexString({:?})", debug::HexSlice(v)), BerObjectContent::BmpString(s) => print_utf16_string_with_type(f, s, "BmpString"), BerObjectContent::UniversalString(s) => print_utf32_string_with_type(f, s, "UniversalString"), BerObjectContent::ObjectDescriptor(s) => print_utf8_string_with_type(f, s, "ObjectDescriptor"), BerObjectContent::GraphicString(s) => print_utf8_string_with_type(f, s, "GraphicString"), BerObjectContent::GeneralString(s) => print_utf8_string_with_type(f, s, "GeneralString"), BerObjectContent::Optional(ref o) => { match o { Some(obj) => writeln!(f, "OPTION {:?}", obj), None => writeln!(f, "NONE"), } } BerObjectContent::Private(ref hdr, bytes) => { writeln!(f, "Private(c:{} s:{} t:{}): {:?}", hdr.class, hdr.structured, hdr.tag.0, debug::HexSlice(bytes)) }, BerObjectContent::Tagged(class, tag, ref obj) => { writeln!(f, "ContextSpecific [{} {}] {{", class, tag)?; write!(f, "{:?}", self.next_indent(obj))?; 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.header.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(class, tag,o) => writeln!(f, "Unknown({:?},{:?},{:x?})", class, 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-6.0.1/src/ber/serialize.rs000064400000000000000000000360270072674642500156300ustar 00000000000000#![cfg(feature = "std")] use crate::ber::*; use crate::oid::Oid; use cookie_factory::bytes::be_u8; use cookie_factory::combinator::slice; use cookie_factory::gen_simple; use cookie_factory::multi::many_ref; use cookie_factory::sequence::tuple; use cookie_factory::{GenError, SerializeFn}; use std::io::Write; fn encode_length<'a, W: Write + 'a, Len: Into>(len: Len) -> impl SerializeFn + 'a { let l = len.into(); move |out| { match l { BerSize::Definite(sz) => { if sz <= 128 { // definite, short form be_u8(sz as u8)(out) } else { // definite, long form let v: Vec = sz .to_be_bytes() .iter() .cloned() .skip_while(|&b| b == 0) .collect(); let b0 = 0b1000_0000 | (v.len() as u8); tuple((be_u8(b0 as u8), slice(v)))(out) } } BerSize::Indefinite => be_u8(0b1000_0000)(out), } } } /// Encode header as object /// /// The `len` field must be correct #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] pub fn ber_encode_header<'a, 'b: 'a, W: Write + 'a>( hdr: &'b BerObjectHeader, ) -> impl SerializeFn + 'a { move |out| { // identifier octets (X.690 8.1.2) let class_u8 = (hdr.class as u8) << 6; let pc_u8 = (hdr.structured & 1) << 5; if hdr.tag.0 >= 30 { unimplemented!(); } let byte_0 = class_u8 | pc_u8 | (hdr.tag.0 as u8); // length octets (X.690 8.1.3) tuple((be_u8(byte_0), encode_length(hdr.len)))(out) } } fn ber_encode_oid<'a, W: Write + 'a>(oid: &'a Oid) -> impl SerializeFn + 'a { move |out| { // check oid.relative attribute ? this should not be necessary slice(oid.bytes())(out) } } fn ber_encode_sequence<'a, W: Write + Default + AsRef<[u8]> + 'a>( v: &'a [BerObject], ) -> impl SerializeFn + 'a { many_ref(v, ber_encode_object) } /// Encode the provided object in an EXPLICIT tagged value, using the provided tag ans class /// /// Note: `obj` should be the object to be encapsulated, not the `ContextSpecific` variant. #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] pub fn ber_encode_tagged_explicit<'a, W: Write + Default + AsRef<[u8]> + 'a>( tag: BerTag, class: BerClass, obj: &'a BerObject, ) -> impl SerializeFn + 'a { move |out| { // encode inner object let v = gen_simple(ber_encode_object(obj), W::default())?; let len = v.as_ref().len(); // encode the application header, using the tag let hdr = BerObjectHeader::new(class, 1 /* X.690 8.14.2 */, tag, len); let v_hdr = gen_simple(ber_encode_header(&hdr), W::default())?; tuple((slice(v_hdr), slice(v)))(out) } } /// Encode the provided object in an IMPLICIT tagged value, using the provided tag and class /// /// Note: `obj` should be the object to be encapsulated, not the `ContextSpecific` variant. #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] pub fn ber_encode_tagged_implicit<'a, W: Write + Default + AsRef<[u8]> + 'a>( tag: BerTag, class: BerClass, obj: &'a BerObject, ) -> impl SerializeFn + 'a { move |out| { // encode inner object content let v = gen_simple(ber_encode_object_content(&obj.content), W::default())?; // but replace the tag (keep structured attribute) let len = v.as_ref().len(); let hdr = BerObjectHeader::new(class, obj.header.structured, tag, len); let v_hdr = gen_simple(ber_encode_header(&hdr), W::default())?; tuple((slice(v_hdr), slice(v)))(out) } } fn ber_encode_object_content<'a, W: Write + Default + AsRef<[u8]> + 'a>( c: &'a BerObjectContent, ) -> impl SerializeFn + 'a { move |out| match c { BerObjectContent::EndOfContent => be_u8(0)(out), BerObjectContent::Boolean(b) => { let b0 = if *b { 0xff } else { 0x00 }; be_u8(b0)(out) } BerObjectContent::Integer(s) => slice(s)(out), BerObjectContent::BitString(ignored_bits, s) => { tuple((be_u8(*ignored_bits), slice(s)))(out) } BerObjectContent::OctetString(s) => slice(s)(out), BerObjectContent::Null => Ok(out), BerObjectContent::Enum(i) => { let v: Vec = i .to_be_bytes() .iter() .cloned() .skip_while(|&b| b == 0) .collect(); slice(v)(out) } BerObjectContent::OID(oid) | BerObjectContent::RelativeOID(oid) => ber_encode_oid(oid)(out), BerObjectContent::NumericString(s) | BerObjectContent::UTCTime(s) | BerObjectContent::GeneralizedTime(s) | BerObjectContent::VisibleString(s) | BerObjectContent::PrintableString(s) | BerObjectContent::IA5String(s) | BerObjectContent::UTF8String(s) => slice(s)(out), BerObjectContent::T61String(s) | BerObjectContent::VideotexString(s) | BerObjectContent::BmpString(s) | BerObjectContent::UniversalString(s) | BerObjectContent::ObjectDescriptor(s) | BerObjectContent::GraphicString(s) | BerObjectContent::GeneralString(s) => slice(s)(out), BerObjectContent::Sequence(v) | BerObjectContent::Set(v) => ber_encode_sequence(v)(out), // best we can do is tagged-explicit, but we don't know BerObjectContent::Optional(inner) => { // directly encode inner object match inner { Some(obj) => ber_encode_object_content(&obj.content)(out), None => slice(&[])(out), // XXX encode NOP ? } } BerObjectContent::Private(_hdr, bytes) => slice(bytes)(out), BerObjectContent::Tagged(_class, _tag, inner) => { // directly encode inner object // XXX wrong, we should wrap it! ber_encode_object(inner)(out) } BerObjectContent::Unknown(_, _, s) => slice(s)(out), } } /// Encode header and object content as BER, without any validation /// /// Note that the encoding will not check *any* `field of the header (including length) /// This can be used to craft invalid objects. /// /// *This function is only available if the `serialize` feature is enabled.* #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] pub fn ber_encode_object_raw<'a, 'b: 'a, 'c: 'a, W: Write + Default + AsRef<[u8]> + 'a>( hdr: &'b BerObjectHeader, content: &'c BerObjectContent, ) -> impl SerializeFn + 'a { tuple((ber_encode_header(hdr), ber_encode_object_content(content))) } /// Encode object as BER /// /// Note that the encoding will not check that the values of the `BerObject` fields are correct. /// The length is automatically calculated, and the field is ignored. /// /// `Tagged` objects will be encoded as EXPLICIT. /// /// *This function is only available if the `serialize` feature is enabled.* #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] pub fn ber_encode_object<'a, 'b: 'a, W: Write + Default + AsRef<[u8]> + 'a>( obj: &'b BerObject, ) -> impl SerializeFn + 'a { move |out| { // XXX should we make an exception for tagged values here ? let v = gen_simple(ber_encode_object_content(&obj.content), W::default())?; let len = v.as_ref().len(); let hdr = obj.header.clone().with_len(len.into()); let v_hdr = gen_simple(ber_encode_header(&hdr), W::default())?; tuple((slice(v_hdr), slice(v)))(out) } } impl<'a> BerObject<'a> { /// Attempt to encode object as BER /// /// Note that the encoding will not check that the values of the `BerObject` fields are correct. /// The length is automatically calculated, and the field is ignored. /// /// `Tagged` objects will be encoded as EXPLICIT. /// /// *This function is only available if the `serialize` feature is enabled.* #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] pub fn to_vec(&self) -> Result, GenError> { gen_simple(ber_encode_object(self), Vec::new()) } } #[cfg(test)] mod test { use super::*; use crate::error::BerResult; use cookie_factory::gen_simple; use hex_literal::hex; macro_rules! encode_and_parse { ($obj:ident, $encode:ident, $parse:ident) => {{ let v = gen_simple($encode(&$obj), Vec::new()).expect("could not encode"); let (_, obj2) = $parse(&v).expect("could not re-parse"); assert_eq!($obj, obj2); v }}; } #[test] fn test_encode_length() { let l = 38; let v = gen_simple(encode_length(l), Vec::new()).expect("could not serialize"); assert_eq!(&v[..], &[38]); let l = 201; let v = gen_simple(encode_length(l), Vec::new()).expect("could not serialize"); assert_eq!(&v[..], &[129, 201]); let l = 0x1234_5678; let v = gen_simple(encode_length(l), Vec::new()).expect("could not serialize"); assert_eq!(&v[..], &[132, 0x12, 0x34, 0x56, 0x78]); } #[test] fn test_encode_header() { // simple header (integer) let bytes = hex!("02 03 01 00 01"); let (_, hdr) = ber_read_element_header(&bytes).expect("could not parse"); let v = encode_and_parse!(hdr, ber_encode_header, ber_read_element_header); assert_eq!(&v[..], &bytes[..2]); } #[test] fn test_encode_bool() { let b_true = BerObject::from_obj(BerObjectContent::Boolean(true)); let b_false = BerObject::from_obj(BerObjectContent::Boolean(false)); encode_and_parse!(b_true, ber_encode_object, parse_ber_bool); encode_and_parse!(b_false, ber_encode_object, parse_ber_bool); } #[test] fn test_encode_integer() { let i = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); encode_and_parse!(i, ber_encode_object, parse_ber_integer); } #[test] fn test_encode_bitstring() { let bytes = hex!("03 04 06 6e 5d e0"); let b = BerObject::from_obj(BerObjectContent::BitString( 6, BitStringObject { data: &bytes[3..] }, )); let v = encode_and_parse!(b, ber_encode_object, parse_ber_bitstring); assert_eq!(&v[..], bytes) } #[test] fn test_encode_octetstring() { let i = BerObject::from_obj(BerObjectContent::OctetString(b"AAAAA")); let v = encode_and_parse!(i, ber_encode_object, parse_ber_octetstring); assert_eq!(&v[..], hex!("04 05 41 41 41 41 41")) } #[test] fn test_encode_enum() { let i = BerObject::from_obj(BerObjectContent::Enum(2)); let v = encode_and_parse!(i, ber_encode_object, parse_ber_enum); assert_eq!(&v[..], hex!("0a 01 02")) } #[test] fn test_encode_null() { let i = BerObject::from_obj(BerObjectContent::Null); encode_and_parse!(i, ber_encode_object, parse_ber_null); } #[test] fn test_encode_oid() { let bytes = hex!("06 09 2A 86 48 86 F7 0D 01 01 05"); let obj = BerObject::from_obj(BerObjectContent::OID( Oid::from(&[1, 2, 840, 113_549, 1, 1, 5]).unwrap(), )); let v = encode_and_parse!(obj, ber_encode_object, parse_ber_oid); assert_eq!(&v[..], bytes); } #[test] fn test_encode_relative_oid() { let bytes = hex!("0d 04 c2 7b 03 02"); let obj = BerObject::from_obj(BerObjectContent::RelativeOID( Oid::from_relative(&[8571, 3, 2]).unwrap(), )); let v = encode_and_parse!(obj, ber_encode_object, parse_ber_relative_oid); assert_eq!(&v[..], bytes); } #[test] fn test_encode_sequence() { let bytes = hex!("30 0a 02 03 01 00 01 02 03 01 00 00"); let obj = BerObject::from_seq(vec![ BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_int_slice(b"\x01\x00\x00"), ]); let v = encode_and_parse!(obj, ber_encode_object, parse_ber_sequence); assert_eq!(&v[..], bytes); } #[test] fn test_encode_set() { let bytes = hex!("31 0a 02 03 01 00 01 02 03 01 00 00"); let obj = BerObject::from_set(vec![ BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_int_slice(b"\x01\x00\x00"), ]); let v = encode_and_parse!(obj, ber_encode_object, parse_ber_set); assert_eq!(&v[..], bytes); } #[test] fn test_encode_tagged_explicit() { fn local_parse(i: &[u8]) -> BerResult { parse_ber_explicit_optional(i, BerTag(0), parse_ber_integer) } let bytes = hex!("a0 03 02 01 02"); let obj = BerObject::from_int_slice(b"\x02"); let v = gen_simple( ber_encode_tagged_explicit(BerTag(0), BerClass::ContextSpecific, &obj), Vec::new(), ) .expect("could not encode"); let (_, obj2) = local_parse(&v).expect("could not re-parse"); let obj2 = obj2 .as_optional() .expect("tagged object not found") .expect("optional object empty"); let (_class, tag, inner) = obj2.as_tagged().expect("not a tagged object"); assert_eq!(tag, BerTag(0)); assert_eq!(&obj, inner); assert_eq!(&v[..], bytes); } #[test] fn test_encode_tagged_implicit() { fn der_read_integer_content<'a>( i: &'a [u8], hdr: &BerObjectHeader, depth: usize, ) -> BerResult<'a, BerObjectContent<'a>> { ber_read_element_content_as(i, BerTag::Integer, hdr.len, false, depth) } fn local_parse(i: &[u8]) -> BerResult { parse_ber_implicit(i, BerTag(3), der_read_integer_content) } let obj = BerObject::from_int_slice(b"\x02"); let v = gen_simple( ber_encode_tagged_implicit(BerTag(3), BerClass::ContextSpecific, &obj), Vec::new(), ) .expect("could not encode"); let (_, obj2) = local_parse(&v).expect("could not re-parse"); assert_eq!(obj2.header.tag, BerTag(3)); assert_eq!(&obj.content, &obj2.content); let bytes = hex!("83 01 02"); assert_eq!(&v[..], bytes); } #[test] fn test_encode_tagged_application() { fn local_parse(i: &[u8]) -> BerResult { parse_ber_explicit_optional(i, BerTag(2), parse_ber_integer) } let obj = BerObject::from_int_slice(b"\x02"); let v = gen_simple( ber_encode_tagged_explicit(BerTag(2), BerClass::Application, &obj), Vec::new(), ) .expect("could not encode"); let (_, obj2) = local_parse(&v).expect("could not re-parse"); let obj2 = obj2 .as_optional() .expect("tagged object not found") .expect("optional object empty"); let (_class, tag, inner) = obj2.as_tagged().expect("not a tagged object"); assert_eq!(tag, BerTag(2)); assert_eq!(&obj, inner); let bytes = hex!("62 03 02 01 02"); assert_eq!(&v[..], bytes); } } der-parser-6.0.1/src/ber/tagged.rs000064400000000000000000000173340072674642500150740ustar 00000000000000use crate::ber::*; use crate::error::*; use nom::error::ParseError; use nom::{Err, IResult}; /// Read a TAGGED EXPLICIT value (combinator) /// /// The built object will use the outer header (and tag), and contains a `Tagged` object /// with class, value and content. /// /// For a generic version (different output and error types), see /// [parse_ber_tagged_explicit_g](fn.parse_ber_tagged_explicit_g.html). /// /// The following parses `[2] EXPLICIT INTEGER`: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map_res; /// # /// fn parse_int_explicit(i:&[u8]) -> BerResult { /// map_res( /// parse_ber_tagged_explicit(2, parse_ber_integer), /// |x: BerObject| x.as_tagged()?.2.as_u32() /// )(i) /// } /// /// # 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) /// # } /// ``` pub fn parse_ber_tagged_explicit<'a, Tag, F>(tag: Tag, f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: Fn(&'a [u8]) -> BerResult, Tag: Into, { let tag = tag.into(); parse_ber_tagged_explicit_g(tag, move |content, hdr| { let (rem, obj) = f(content)?; let class = hdr.class; let obj2 = BerObject::from_header_and_content( hdr, BerObjectContent::Tagged(class, tag, Box::new(obj)), ); Ok((rem, obj2)) }) } /// Read a TAGGED EXPLICIT value (generic version) /// /// The following parses `[2] EXPLICIT INTEGER`: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// fn parse_int_explicit(i:&[u8]) -> BerResult { /// parse_ber_tagged_explicit_g(2, move |content, hdr| { /// let (rem, obj) = parse_ber_integer(content)?; /// let value = obj.as_u32()?; /// Ok((rem, value)) /// })(i) /// } /// /// # 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) /// # } /// ``` pub fn parse_ber_tagged_explicit_g<'a, Tag, Output, F, E>( tag: Tag, f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Output, E> where F: Fn(&'a [u8], BerObjectHeader<'a>) -> IResult<&'a [u8], Output, E>, E: ParseError<&'a [u8]> + From, Tag: Into, { let tag = tag.into(); parse_ber_container(move |i, hdr| { if hdr.class == BerClass::Universal { return Err(Err::Error(BerError::InvalidClass.into())); } if hdr.tag != tag { return Err(Err::Error(BerError::InvalidTag.into())); } // X.690 8.14.2: if implicit tagging was not used, the encoding shall be constructed if !hdr.is_constructed() { return Err(Err::Error(BerError::ConstructExpected.into())); } f(i, hdr) // trailing bytes are ignored }) } /// Read a TAGGED IMPLICIT value (combinator) /// /// Parse a TAGGED IMPLICIT value, given the expected tag, and the content parsing function. /// /// The built object will use the original header (and tag), so the content may not match the tag /// value. /// /// For a generic version (different output and error types), see /// [parse_ber_tagged_implicit_g](fn.parse_ber_tagged_implicit_g.html). /// /// # Examples /// /// The following parses `[2] IMPLICIT INTEGER` into a `BerObject`: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// fn parse_int_implicit(i:&[u8]) -> BerResult { /// parse_ber_tagged_implicit( /// 2, /// parse_ber_content(BerTag::Integer), /// )(i) /// } /// /// # let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01]; /// let res = parse_int_implicit(bytes); /// # match res { /// # Ok((rem, content)) => { /// # assert!(rem.is_empty()); /// # assert_eq!(content.as_u32(), Ok(0x10001)); /// # }, /// # _ => assert!(false) /// # } /// ``` /// /// The following parses `[2] IMPLICIT INTEGER` into an `u32`, raising an error if the integer is /// too large: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map_res; /// # /// fn parse_int_implicit(i:&[u8]) -> BerResult { /// map_res( /// parse_ber_tagged_implicit( /// 2, /// parse_ber_content(BerTag::Integer), /// ), /// |x: BerObject| x.as_u32() /// )(i) /// } /// /// # 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) /// # } /// ``` pub fn parse_ber_tagged_implicit<'a, Tag, F>(tag: Tag, f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: Fn(&'a [u8], &'_ BerObjectHeader, usize) -> BerResult<'a, BerObjectContent<'a>>, Tag: Into, { let tag = tag.into(); parse_ber_tagged_implicit_g(tag, move |i, hdr, depth| { let (rem, content) = f(i, &hdr, depth)?; // trailing bytes are ignored let obj = BerObject::from_header_and_content(hdr, content); Ok((rem, obj)) }) } /// Read a TAGGED IMPLICIT value (generic version) /// /// Parse a TAGGED IMPLICIT value, given the expected tag, and the content parsing function. /// /// # Examples /// /// The following parses `[1] IMPLICIT OCTETSTRING`, returning a `BerObject`: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// fn parse_implicit_0_octetstring(i:&[u8]) -> BerResult { /// parse_ber_tagged_implicit_g( /// 2, /// parse_ber_content2(BerTag::OctetString) /// )(i) /// } /// /// # let bytes = &[0x02, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f]; /// let res = parse_implicit_0_octetstring(bytes); /// # match res { /// # Ok((rem, val)) => { /// # assert!(rem.is_empty()); /// # let s = val.as_slice().unwrap(); /// # assert_eq!(s, b"hello"); /// # }, /// # _ => assert!(false) /// # } /// ``` /// /// The following parses `[2] IMPLICIT INTEGER` into an `u32`, raising an error if the integer is /// too large: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// fn parse_int_implicit(i:&[u8]) -> BerResult { /// parse_ber_tagged_implicit_g( /// 2, /// |content, hdr, depth| { /// let (rem, obj_content) = parse_ber_content(BerTag::Integer)(content, &hdr, depth)?; /// let value = obj_content.as_u32()?; /// Ok((rem, value)) /// } /// )(i) /// } /// /// # 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) /// # } /// ``` pub fn parse_ber_tagged_implicit_g<'a, Tag, Output, F, E>( tag: Tag, f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&[u8], Output, E> where F: Fn(&'a [u8], BerObjectHeader<'a>, usize) -> IResult<&'a [u8], Output, E>, E: ParseError<&'a [u8]> + From, Tag: Into, { let tag = tag.into(); parse_ber_container(move |i, hdr| { if hdr.tag != tag { return Err(Err::Error(BerError::InvalidTag.into())); } // XXX MAX_RECURSION should not be used, it resets the depth counter f(i, hdr, MAX_RECURSION) // trailing bytes are ignored }) } der-parser-6.0.1/src/der/mod.rs000064400000000000000000000054400072674642500144150ustar 00000000000000//! Distinguished Encoding Rules (DER) objects and parser //! //! All functions in this crate use BER parsing functions (see the `ber` module) //! internally, adding constraints verification where needed. //! //! The objects [`BerObject`] and [`DerObject`] are the same (type alias): all BER functions, //! combinators and macros can be used, and provide additional tools for DER parsing. //! However, DER parsing functions enforce DER constraints in addition of their BER counterparts. //! //! # DER Objects //! //! The main object of this crate is [`DerObject`]. It contains a header (ber tag, class, and size) //! and content. //! //! To parse primitive objects (for ex. integers or strings), use the `parse_der_` set of //! functions. //! //! Constructed objects (like sequences, sets or tagged objects) require to use a combinator. This //! combinator takes a function or closure as input, and returns a new, specialized parser. //! See the [nom](https://github.com/geal/nom) parser combinator library for more details on //! combinators. //! //! # Examples //! //! Parse two DER integers: //! //! ```rust //! use der_parser::der::parse_der_integer; //! //! let bytes = [ 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x02, 0x03, 0x01, 0x00, 0x00, //! ]; //! //! let (rem, obj1) = parse_der_integer(&bytes).expect("parsing failed"); //! let (rem, obj2) = parse_der_integer(&bytes).expect("parsing failed"); //! ``` //! //! Parse a BER sequence containing one integer and an octetstring: //! //! ```rust //! use der_parser::der::*; //! //! let bytes = [ 0x30, 0x0a, //! 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x04, 0x03, 0x62, 0x61, 0x64, //! ]; //! //! let (rem, seq) = parse_der_sequence_defined(|content| { //! let (rem, obj1) = parse_der_integer(content)?; //! let (rem, obj2) = parse_der_octetstring(rem)?; //! Ok((rem, vec![obj1, obj2])) //! })(&bytes) //! .expect("parsing failed"); //! ``` use crate::ber::{BerClass, BerObject, BerObjectContent, BerObjectHeader, BerTag}; mod multi; mod parser; mod tagged; pub use crate::der::multi::*; pub use crate::der::parser::*; pub use crate::der::tagged::*; use alloc::boxed::Box; use alloc::vec::Vec; use core::convert::{Into, TryFrom}; /// DER Object class of tag (same as `BerClass`) pub type DerClass = BerClass; /// 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 object header (identifier and length) /// /// This is the same object as `BerObjectHeader`. pub type DerObjectHeader<'a> = BerObjectHeader<'a>; /// BER object content /// /// This is the same object as `BerObjectContent`. pub type DerObjectContent<'a> = BerObjectContent<'a>; der-parser-6.0.1/src/der/multi.rs000064400000000000000000000417160072674642500147760ustar 00000000000000use crate::ber::BerSize; use crate::der::*; use crate::error::*; use nom::bytes::streaming::take; use nom::combinator::{all_consuming, complete, cut, map}; use nom::error::ParseError; use nom::multi::many0; use nom::{Err, IResult}; /// Parse a SEQUENCE OF object /// /// Given a subparser for a DER type, parse a sequence of identical objects. /// /// ```rust /// # use der_parser::der::{parse_der_integer, parse_der_sequence_of, DerObject}; /// # use der_parser::error::BerResult; /// # /// /// Read a SEQUENCE OF INTEGER /// fn parser(i:&[u8]) -> BerResult { /// parse_der_sequence_of(parse_der_integer)(i) /// } /// /// # 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!(parser(&bytes), Ok((empty, expected))); /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_sequence_of<'a, F>(f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: Fn(&'a [u8]) -> BerResult, { map(parse_der_sequence_of_v(f), DerObject::from_seq) } /// Parse a SEQUENCE OF object (returning a vec) /// /// Given a subparser for a DER type, parse a sequence of identical objects. /// /// This differs from `parse_der_sequence_of` in the parse function and return type. /// /// ```rust /// # use der_parser::der::{parse_der_integer, parse_der_sequence_of_v, DerObject}; /// # use der_parser::error::BerResult; /// # /// /// Read a SEQUENCE OF INTEGER /// fn parser(i:&[u8]) -> BerResult> { /// parse_der_sequence_of_v(parse_der_integer)(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = vec![ /// # DerObject::from_int_slice(b"\x01\x00\x01"), /// # DerObject::from_int_slice(b"\x01\x00\x00"), /// # ]; /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// # assert_eq!(v, expected); /// ``` pub fn parse_der_sequence_of_v<'a, T, F, E>( f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Vec, E> where F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, E: ParseError<&'a [u8]> + From, { let mut subparser = all_consuming(many0(complete(cut(f)))); parse_der_sequence_defined_g(move |data, _| subparser(data)) } /// Parse a defined sequence of DER elements (function version) /// /// Given a list of expected parsers, apply them to build a DER sequence and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the sequence: any bytes that are part of the sequence but not /// parsed are ignored. /// /// The object header is not available to the parsing function, and the returned type is always a /// `DerObject`. /// For a generic version, see /// [`parse_der_sequence_defined_g`](fn.parse_der_sequence_defined_g.html). /// /// # Examples /// /// Parsing a sequence of identical types (same as `parse_der_sequence_of`): /// /// ```rust /// # use der_parser::der::{parse_der_integer, parse_der_sequence_defined, DerObject}; /// # use der_parser::error::BerResult; /// use nom::combinator::complete; /// use nom::multi::many1; /// /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_der_sequence_defined( /// many1(complete(parse_der_integer)) /// )(i) /// } /// /// # 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))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` /// /// Parsing a defined sequence with different types: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map; /// use nom::sequence::tuple; /// /// /// Read a DER-encoded object: /// /// SEQUENCE { /// /// a INTEGER, /// /// b OCTETSTRING /// /// } /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_der_sequence_defined( /// // the nom `tuple` combinator returns a tuple, so we have to map it /// // to a list /// map( /// tuple((parse_der_integer, parse_der_octetstring)), /// |(a, b)| vec![a, b] /// ) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = DerObject::from_seq(vec![ /// # DerObject::from_int_slice(b"\x01\x00\x01"), /// # DerObject::from_obj(DerObjectContent::OctetString(b"\x01\x00\x00")), /// # ]); /// # assert_eq!(localparse_seq(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_sequence_defined<'a, F>(mut f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: FnMut(&'a [u8]) -> BerResult>, { map( parse_der_sequence_defined_g(move |data, _| f(data)), DerObject::from_seq, ) } /// Parse a defined SEQUENCE object (generic function) /// /// Given a parser for sequence content, apply it to build a DER sequence and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the sequence: any bytes that are part of the sequence but not /// parsed are ignored. /// /// Unlike `parse_der_sequence_defined`, this function allows returning any object or error type, /// and also passes the object header to the callback. /// /// # Examples /// /// Parsing a defined sequence with different types: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// # /// # #[derive(Debug, PartialEq)] /// pub struct MyObject<'a> { /// a: u32, /// b: &'a [u8], /// } /// /// /// Read a DER-encoded object: /// /// SEQUENCE { /// /// a INTEGER (0..4294967295), /// /// b OCTETSTRING /// /// } /// fn parse_myobject(i: &[u8]) -> BerResult { /// parse_der_sequence_defined_g( /// |i:&[u8], _| { /// let (i, a) = parse_der_u32(i)?; /// let (i, obj) = parse_der_octetstring(i)?; /// let b = obj.as_slice().unwrap(); /// Ok((i, MyObject{ a, b })) /// } /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = MyObject { /// # a: 0x010001, /// # b: &[01, 00, 00] /// # }; /// # assert_eq!(parse_myobject(&bytes), Ok((empty, expected))); /// let (rem, v) = parse_myobject(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_sequence_defined_g<'a, O, F, E>( mut f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E> where F: FnMut(&'a [u8], DerObjectHeader<'a>) -> IResult<&'a [u8], O, E>, E: ParseError<&'a [u8]> + From, { parse_der_container(move |i, hdr| { if hdr.tag != DerTag::Sequence { return Err(Err::Error(BerError::InvalidTag.into())); } f(i, hdr) }) } /// Parse a SET OF object /// /// Given a subparser for a DER type, parse a set of identical objects. /// /// ```rust /// # use der_parser::der::{parse_der_integer, parse_der_set_of, DerObject}; /// # use der_parser::error::BerResult; /// # /// /// Read a SET OF INTEGER /// fn parser(i:&[u8]) -> BerResult { /// parse_der_set_of(parse_der_integer)(i) /// } /// /// # 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!(parser(&bytes), Ok((empty, expected))); /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_set_of<'a, F>(f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: Fn(&'a [u8]) -> BerResult, { map(parse_der_set_of_v(f), DerObject::from_set) } /// Parse a SET OF object (returning a vec) /// /// Given a subparser for a DER type, parse a set of identical objects. /// /// This differs from `parse_der_set_of` in the parse function and return type. /// /// ```rust /// # use der_parser::der::{parse_der_integer, parse_der_set_of_v, DerObject}; /// # use der_parser::error::BerResult; /// # /// /// Read a SET OF INTEGER /// fn parser(i:&[u8]) -> BerResult> { /// parse_der_set_of_v(parse_der_integer)(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = vec![ /// # DerObject::from_int_slice(b"\x01\x00\x01"), /// # DerObject::from_int_slice(b"\x01\x00\x00"), /// # ]; /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// # assert_eq!(v, expected); /// ``` pub fn parse_der_set_of_v<'a, T, F, E>(f: F) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Vec, E> where F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, E: ParseError<&'a [u8]> + From, { let mut subparser = all_consuming(many0(complete(cut(f)))); parse_der_set_defined_g(move |data, _| subparser(data)) } /// Parse a defined set of DER elements (function version) /// /// Given a list of expected parsers, apply them to build a DER set and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the set: any bytes that are part of the sequence but not /// parsed are ignored. /// The nom combinator `all_consuming` can be used to ensure all the content is parsed. /// /// The object header is not available to the parsing function, and the returned type is always a /// `DerObject`. /// For a generic version, see [`parse_der_set_defined_g`](fn.parse_der_set_defined_g.html). /// /// # Examples /// /// Parsing a set of identical types (same as `parse_der_set_of`): /// /// ```rust /// # use der_parser::der::{parse_der_integer, parse_der_set_defined, DerObject}; /// # use der_parser::error::BerResult; /// use nom::combinator::complete; /// use nom::multi::many1; /// /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_der_set_defined( /// many1(complete(parse_der_integer)) /// )(i) /// } /// /// # 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_seq(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` /// /// Parsing a defined set with different types: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map; /// use nom::sequence::tuple; /// /// /// Read a DER-encoded object: /// /// SET { /// /// a INTEGER, /// /// b OCTETSTRING /// /// } /// fn localparse_set(i:&[u8]) -> BerResult { /// parse_der_set_defined( /// // the nom `tuple` combinator returns a tuple, so we have to map it /// // to a list /// map( /// tuple((parse_der_integer, parse_der_octetstring)), /// |(a, b)| vec![a, b] /// ) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = DerObject::from_set(vec![ /// # DerObject::from_int_slice(b"\x01\x00\x01"), /// # DerObject::from_obj(DerObjectContent::OctetString(b"\x01\x00\x00")), /// # ]); /// # assert_eq!(localparse_set(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_set(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_set_defined<'a, F>(mut f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: FnMut(&'a [u8]) -> BerResult>, { map( parse_der_set_defined_g(move |data, _| f(data)), DerObject::from_set, ) } /// Parse a defined SET object (generic version) /// /// Given a parser for set content, apply it to build a DER set and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the set: any bytes that are part of the sequence but not /// parsed are ignored. /// The nom combinator `all_consuming` can be used to ensure all the content is parsed. /// /// Unlike `parse_der_set_defined`, this function allows returning any object or error type, /// and also passes the object header to the callback. /// /// # Examples /// /// Parsing a defined set with different types: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// # /// # #[derive(Debug, PartialEq)] /// pub struct MyObject<'a> { /// a: u32, /// b: &'a [u8], /// } /// /// /// Read a DER-encoded object: /// /// SET { /// /// a INTEGER (0..4294967295), /// /// b OCTETSTRING /// /// } /// fn parse_myobject(i: &[u8]) -> BerResult { /// parse_der_set_defined_g( /// |i:&[u8], _| { /// let (i, a) = parse_der_u32(i)?; /// let (i, obj) = parse_der_octetstring(i)?; /// let b = obj.as_slice().unwrap(); /// Ok((i, MyObject{ a, b })) /// } /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = MyObject { /// # a: 0x010001, /// # b: &[01, 00, 00] /// # }; /// # assert_eq!(parse_myobject(&bytes), Ok((empty, expected))); /// let (rem, v) = parse_myobject(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_set_defined_g<'a, O, F, E>( mut f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E> where F: FnMut(&'a [u8], DerObjectHeader<'a>) -> IResult<&'a [u8], O, E>, E: ParseError<&'a [u8]> + From, { parse_der_container(move |i, hdr| { if hdr.tag != DerTag::Set { return Err(Err::Error(BerError::InvalidTag.into())); } f(i, hdr) }) } /// Parse a DER object and apply provided function to content /// /// Given a parser for content, read DER object header and apply parser to /// return the remaining bytes and the parser result. /// /// The remaining bytes point *after* the content: any bytes that are part of the content but not /// parsed are ignored. /// The nom combinator `all_consuming` can be used to ensure all the content is parsed. /// /// This function is mostly intended for structured objects, but can be used for any valid DER /// object. /// /// # Examples /// /// Parsing a defined sequence with different types: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::{BerError, BerResult}; /// # /// # #[derive(Debug, PartialEq)] /// pub struct MyObject<'a> { /// a: u32, /// b: &'a [u8], /// } /// /// /// Read a DER-encoded object: /// /// SEQUENCE { /// /// a INTEGER (0..4294967295), /// /// b OCTETSTRING /// /// } /// fn parse_myobject(i: &[u8]) -> BerResult { /// parse_der_container( /// |i: &[u8], hdr: DerObjectHeader| { /// if hdr.tag != DerTag::Sequence { /// return Err(nom::Err::Error(BerError::BerTypeError.into())); /// } /// let (i, a) = parse_der_u32(i)?; /// let (i, obj) = parse_der_octetstring(i)?; /// let b = obj.as_slice().unwrap(); /// Ok((i, MyObject{ a, b })) /// } /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = MyObject { /// # a: 0x010001, /// # b: &[01, 00, 00] /// # }; /// # assert_eq!(parse_myobject(&bytes), Ok((empty, expected))); /// let (rem, v) = parse_myobject(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_container<'a, O, F, E>(mut f: F) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E> where F: FnMut(&'a [u8], DerObjectHeader<'a>) -> IResult<&'a [u8], O, E>, E: ParseError<&'a [u8]> + From, { move |i: &[u8]| { let (i, hdr) = der_read_element_header(i).map_err(nom::Err::convert)?; // X.690 10.1: the definitive form of length encoding shall be used let (i, data) = match hdr.len { BerSize::Definite(len) => take(len)(i)?, BerSize::Indefinite => { return Err(Err::Error(BerError::DerConstraintFailed.into())); } }; let (_rest, v) = f(data, hdr)?; Ok((i, v)) } } der-parser-6.0.1/src/der/parser.rs000064400000000000000000000545030072674642500151360ustar 00000000000000use crate::ber::*; use crate::der::*; use crate::error::*; use nom::bytes::streaming::take; use nom::number::streaming::be_u8; use nom::{Err, Needed}; use rusticata_macros::custom_check; /// Parse DER object recursively /// /// Return a tuple containing the remaining (unparsed) bytes and the DER Object, or an error. /// /// *Note: this is the same as calling `parse_der_recursive` with `MAX_RECURSION`. /// /// ### Example /// /// ``` /// use der_parser::der::{parse_der, DerTag}; /// /// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (_, obj) = parse_der(bytes).expect("parsing failed"); /// /// assert_eq!(obj.header.tag, DerTag::Integer); /// ``` #[inline] pub fn parse_der(i: &[u8]) -> DerResult { parse_der_recursive(i, MAX_RECURSION) } /// Parse DER object recursively, specifying the maximum recursion depth /// /// Return a tuple containing the remaining (unparsed) bytes and the DER Object, or an error. /// /// ### Example /// /// ``` /// use der_parser::der::{parse_der_recursive, DerTag}; /// /// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (_, obj) = parse_der_recursive(bytes, 1).expect("parsing failed"); /// /// assert_eq!(obj.header.tag, DerTag::Integer); /// ``` pub fn parse_der_recursive(i: &[u8], max_depth: usize) -> DerResult { let (i, hdr) = der_read_element_header(i)?; // safety check: length cannot be more than 2^32 bytes if let BerSize::Definite(l) = hdr.len { custom_check!(i, l > MAX_OBJECT_SIZE, BerError::InvalidLength)?; } der_read_element_content_recursive(i, hdr, max_depth) } #[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 specified tag /// /// The object is parsed recursively, with a maximum depth of `MAX_RECURSION`. /// /// ### Example /// /// ``` /// use der_parser::der::{parse_der_with_tag, DerTag}; /// /// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (_, obj) = parse_der_with_tag(bytes, DerTag::Integer).expect("parsing failed"); /// /// assert_eq!(obj.header.tag, DerTag::Integer); /// ``` pub fn parse_der_with_tag>(i: &[u8], tag: Tag) -> DerResult { let tag = tag.into(); let (i, hdr) = der_read_element_header(i)?; if hdr.tag != tag { return Err(nom::Err::Error(BerError::InvalidTag)); } let (i, content) = der_read_element_content_as(i, hdr.tag, hdr.len, hdr.is_constructed(), MAX_RECURSION)?; Ok((i, DerObject::from_header_and_content(hdr, content))) } /// Read end of content marker #[inline] pub fn parse_der_endofcontent(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::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, DerTag::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 /// # use der_parser::der::{parse_der_integer, DerObject, DerObjectContent}; /// let empty = &b""[..]; /// let bytes = [0x02, 0x03, 0x01, 0x00, 0x01]; /// let expected = DerObject::from_obj(DerObjectContent::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, DerTag::Integer) } /// Read an bitstring value /// /// To access the content as plain bytes, you will have to /// interprete the resulting tuple which will contain in /// its first item the number of padding bits left at /// the end of the bit string, and in its second item /// a `BitStringObject` structure which will, in its sole /// structure field called `data`, contain a byte slice /// representing the value of the bit string which can /// be interpreted as a big-endian value with the padding /// bits on the right (as in ASN.1 raw BER or DER encoding). /// /// To access the content as an integer, use the [`as_u64`](struct.BerObject.html#method.as_u64) /// or [`as_u32`](struct.BerObject.html#method.as_u32) methods. /// Remember that a BER bit string has unlimited size, so these methods return `Result` or `Option` /// objects. #[inline] pub fn parse_der_bitstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::BitString) } /// Read an octetstring value #[inline] pub fn parse_der_octetstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::OctetString) } /// Read a null value #[inline] pub fn parse_der_null(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::Null) } /// Read an object identifier value #[inline] pub fn parse_der_oid(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::Oid) } /// Read an enumerated value #[inline] pub fn parse_der_enum(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::Enumerated) } /// Read a UTF-8 string value. The encoding is checked. #[inline] pub fn parse_der_utf8string(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::Utf8String) } /// Read a relative object identifier value #[inline] pub fn parse_der_relative_oid(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::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_der_sequence_defined`](macro.parse_der_sequence_defined.html) macro. #[inline] pub fn parse_der_sequence(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::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_der_set_defined`](macro.parse_der_set_defined.html) macro. #[inline] pub fn parse_der_set(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::Set) } /// Read a numeric string value. The content is verified to /// contain only digits and spaces. #[inline] pub fn parse_der_numericstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::NumericString) } /// Read a printable string value. The content is verified to /// contain only the allowed characters. #[inline] pub fn visiblestring(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::VisibleString) } /// Read a printable string value. The content is verified to /// contain only the allowed characters. #[inline] pub fn parse_der_printablestring(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::PrintableString) } /// Read a T61 string value #[inline] pub fn parse_der_t61string(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::T61String) } /// Read a Videotex string value #[inline] pub fn parse_der_videotexstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::VideotexString) } /// Read an IA5 string value. The content is verified to be ASCII. #[inline] pub fn parse_der_ia5string(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::Ia5String) } /// Read an UTC time value #[inline] pub fn parse_der_utctime(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::UtcTime) } /// Read a Generalized time value #[inline] pub fn parse_der_generalizedtime(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::GeneralizedTime) } /// Read a ObjectDescriptor value #[inline] pub fn parse_der_objectdescriptor(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::ObjDescriptor) } /// Read a GraphicString value #[inline] pub fn parse_der_graphicstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::GraphicString) } /// Read a GeneralString value #[inline] pub fn parse_der_generalstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::GeneralString) } /// Read a BmpString value #[inline] pub fn parse_der_bmpstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::BmpString) } /// Read a UniversalString value #[inline] pub fn parse_der_universalstring(i: &[u8]) -> DerResult { parse_der_with_tag(i, DerTag::UniversalString) } /// Parse an optional tagged object, applying function to get content /// /// This function returns a `DerObject`, trying to read content as generic DER objects. /// If parsing failed, return an optional object containing `None`. /// /// To support other return or error types, use /// [parse_der_tagged_explicit_g](fn.parse_der_tagged_explicit_g.html) /// /// This function will never fail: if parsing content failed, the BER value `Optional(None)` is /// returned. #[inline] pub fn parse_der_explicit_optional(i: &[u8], tag: DerTag, f: F) -> DerResult where F: Fn(&[u8]) -> DerResult, { parse_ber_explicit_optional(i, tag, f) } /// Parse an implicit tagged object, applying function to read content /// /// Note: unlike explicit tagged functions, the callback must be a *content* parsing function, /// often based on the [`parse_der_content`](fn.parse_der_content.html) combinator. /// /// The built object will use the original header (and tag), so the content may not match the tag /// value. /// /// For a combinator version, see [parse_der_tagged_implicit](../ber/fn.parse_der_tagged_implicit.html). /// /// For a generic version (different output and error types), see /// [parse_der_tagged_implicit_g](../ber/fn.parse_der_tagged_implicit_g.html). /// /// # Examples /// /// The following parses `[3] IMPLICIT INTEGER` into a `DerObject`: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::DerResult; /// # /// fn parse_int_implicit(i:&[u8]) -> DerResult { /// parse_der_implicit( /// i, /// 3, /// parse_der_content(DerTag::Integer), /// ) /// } /// /// # let bytes = &[0x83, 0x03, 0x01, 0x00, 0x01]; /// let res = parse_int_implicit(bytes); /// # match res { /// # Ok((rem, content)) => { /// # assert!(rem.is_empty()); /// # assert_eq!(content.as_u32(), Ok(0x10001)); /// # }, /// # _ => assert!(false) /// # } /// ``` #[inline] pub fn parse_der_implicit<'a, Tag, F>(i: &'a [u8], tag: Tag, f: F) -> DerResult<'a> where F: Fn(&'a [u8], &'_ DerObjectHeader, usize) -> BerResult<'a, DerObjectContent<'a>>, Tag: Into, { parse_ber_implicit(i, tag, f) } /// Parse DER object and try to decode it as a 32-bits signed integer /// /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. #[inline] pub fn parse_der_i32(i: &[u8]) -> BerResult { let (rem, der) = parse_der_integer(i)?; let int = der.as_i32().map_err(nom::Err::Error)?; Ok((rem, int)) } /// Parse DER object and try to decode it as a 64-bits signed integer /// /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. #[inline] pub fn parse_der_i64(i: &[u8]) -> BerResult { let (rem, der) = parse_der_integer(i)?; let int = der.as_i64().map_err(nom::Err::Error)?; Ok((rem, int)) } /// Parse DER object and try to decode it as a 32-bits unsigned integer /// /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. pub fn parse_der_u32(i: &[u8]) -> BerResult { let (rem, der) = parse_der_integer(i)?; let int = der.as_u32().map_err(nom::Err::Error)?; Ok((rem, int)) } /// Parse DER object and try to decode it as a 64-bits unsigned integer /// /// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target /// integer type. pub fn parse_der_u64(i: &[u8]) -> BerResult { let (rem, der) = parse_der_integer(i)?; let int = der.as_u64().map_err(nom::Err::Error)?; Ok((rem, int)) } /// Parse DER object and get content as slice #[inline] pub fn parse_der_slice>(i: &[u8], tag: Tag) -> BerResult<&[u8]> { let tag = tag.into(); parse_der_container(move |content, hdr| { if hdr.tag != tag { return Err(Err::Error(BerError::InvalidTag)); } Ok((&b""[..], content)) })(i) } /// Parse the next bytes as the content of a DER object (combinator, header reference) /// /// Content type is *not* checked to match tag, caller is responsible of providing the correct tag /// /// Caller is also responsible to check if parsing function consumed the expected number of /// bytes (`header.len`). /// /// This function differs from [`parse_der_content2`](fn.parse_der_content2.html) because it passes /// the BER object header by reference (required for ex. by `parse_der_implicit`). /// /// The arguments of the parse function are: `(input, ber_object_header, max_recursion)`. /// /// Example: manually parsing header and content /// /// ``` /// # use der_parser::ber::MAX_RECURSION; /// # use der_parser::der::*; /// # /// # let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (i, header) = der_read_element_header(bytes).expect("parsing failed"); /// let (rem, content) = parse_der_content(header.tag)(i, &header, MAX_RECURSION) /// .expect("parsing failed"); /// # /// # assert_eq!(header.tag, DerTag::Integer); /// ``` pub fn parse_der_content<'a>( tag: DerTag, ) -> impl Fn(&'a [u8], &'_ DerObjectHeader, usize) -> BerResult<'a, DerObjectContent<'a>> { move |i: &[u8], hdr: &DerObjectHeader, max_recursion: usize| { der_read_element_content_as(i, tag, hdr.len, hdr.is_constructed(), max_recursion) } } /// Parse the next bytes as the content of a DER object (combinator, owned header) /// /// Content type is *not* checked to match tag, caller is responsible of providing the correct tag /// /// Caller is also responsible to check if parsing function consumed the expected number of /// bytes (`header.len`). /// /// The arguments of the parse function are: `(input, ber_object_header, max_recursion)`. /// /// This function differs from [`parse_der_content`](fn.parse_der_content.html) because it passes /// an owned BER object header (required for ex. by `parse_der_tagged_implicit_g`). /// /// Example: manually parsing header and content /// /// ``` /// # use der_parser::ber::MAX_RECURSION; /// # use der_parser::der::*; /// # /// # let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let (i, header) = der_read_element_header(bytes).expect("parsing failed"); /// # assert_eq!(header.tag, DerTag::Integer); /// let (rem, content) = parse_der_content2(header.tag)(i, header, MAX_RECURSION) /// .expect("parsing failed"); /// ``` pub fn parse_der_content2<'a>( tag: DerTag, ) -> impl Fn(&'a [u8], DerObjectHeader<'a>, usize) -> BerResult<'a, DerObjectContent<'a>> { move |i: &[u8], hdr: DerObjectHeader, max_recursion: usize| { der_read_element_content_as(i, tag, hdr.len, hdr.is_constructed(), max_recursion) } } // --------- end of parse_der_xxx functions ---------- /// Parse the next bytes as the content of a DER object. /// /// Content type is *not* checked, caller is responsible of providing the correct tag pub fn der_read_element_content_as( i: &[u8], tag: DerTag, len: BerSize, constructed: bool, max_depth: usize, ) -> BerResult { // Indefinite lengths are not allowed in DER (X.690 section 10.1) let l = len.primitive()?; if i.len() < l { return Err(Err::Incomplete(Needed::new(l))); } match tag { DerTag::Boolean => { custom_check!(i, l != 1, BerError::InvalidLength)?; der_constraint_fail_if!(i, i[0] != 0 && i[0] != 0xff); } DerTag::BitString => { der_constraint_fail_if!(i, constructed); // exception: read and verify padding bits return der_read_content_bitstring(i, l); } DerTag::Integer => { // verify leading zeros match i[..l] { [] => return Err(nom::Err::Error(BerError::DerConstraintFailed)), [0, 0, ..] => return Err(nom::Err::Error(BerError::DerConstraintFailed)), [0, byte, ..] if byte < 0x80 => { return Err(nom::Err::Error(BerError::DerConstraintFailed)); } _ => (), } } DerTag::NumericString | DerTag::VisibleString | DerTag::PrintableString | DerTag::Ia5String | DerTag::Utf8String | DerTag::T61String | DerTag::VideotexString | DerTag::BmpString | DerTag::UniversalString | DerTag::ObjDescriptor | DerTag::GraphicString | DerTag::GeneralString => { der_constraint_fail_if!(i, constructed); } DerTag::UtcTime | DerTag::GeneralizedTime => { if l == 0 || i.get(l - 1).cloned() != Some(b'Z') { return Err(Err::Error(BerError::DerConstraintFailed)); } } _ => (), } ber_read_element_content_as(i, tag, len, constructed, max_depth) } /// Parse DER object content recursively /// /// *Note: an error is raised if recursion depth exceeds `MAX_RECURSION`. pub fn der_read_element_content<'a>(i: &'a [u8], hdr: DerObjectHeader<'a>) -> DerResult<'a> { der_read_element_content_recursive(i, hdr, MAX_RECURSION) } fn der_read_element_content_recursive<'a>( i: &'a [u8], hdr: DerObjectHeader<'a>, max_depth: usize, ) -> DerResult<'a> { match hdr.class { BerClass::Universal => (), BerClass::Private => { let (rem, content) = ber_get_object_content(i, &hdr, max_depth)?; let content = BerObjectContent::Private(hdr.clone(), content); let obj = BerObject::from_header_and_content(hdr, content); return Ok((rem, obj)); } _ => { let (i, content) = ber_get_object_content(i, &hdr, max_depth)?; let content = DerObjectContent::Unknown(hdr.class, hdr.tag, content); let obj = DerObject::from_header_and_content(hdr, content); return Ok((i, obj)); } } match der_read_element_content_as(i, hdr.tag, hdr.len, hdr.is_constructed(), max_depth) { Ok((rem, content)) => Ok((rem, DerObject::from_header_and_content(hdr, content))), Err(Err::Error(BerError::UnknownTag)) => { let (rem, content) = ber_get_object_content(i, &hdr, max_depth)?; let content = DerObjectContent::Unknown(hdr.class, hdr.tag, content); let obj = DerObject::from_header_and_content(hdr, content); Ok((rem, obj)) } Err(e) => Err(e), } } fn der_read_content_bitstring(i: &[u8], len: usize) -> BerResult { let (i, ignored_bits) = be_u8(i)?; if ignored_bits > 7 { return Err(Err::Error(BerError::DerConstraintFailed)); } if len == 0 { return Err(Err::Error(BerError::InvalidLength)); } let (i, data) = take(len - 1)(i)?; if len > 1 { let mut last_byte = data[len - 2]; for _ in 0..ignored_bits as usize { der_constraint_fail_if!(i, last_byte & 1 != 0); last_byte >>= 1; } } Ok(( i, DerObjectContent::BitString(ignored_bits, BitStringObject { data }), )) // 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,())) // }) >> // ( DerObjectContent::BitString(ignored_bits,BitStringObject{ data:s }) ) // } } /// Read an object header (DER) pub fn der_read_element_header(i: &[u8]) -> BerResult { let (i1, el) = parse_identifier(i)?; let class = match DerClass::try_from(el.0) { Ok(c) => c, Err(_) => unreachable!(), // Cannot fail, we have read exactly 2 bits }; let (i2, len) = parse_ber_length_byte(i1)?; let (i3, len) = match (len.0, len.1) { (0, l1) => { // Short form: MSB is 0, the rest encodes the length (which can be 0) (8.1.3.4) (i2, BerSize::Definite(usize::from(l1))) } (_, 0) => { // Indefinite form is not allowed in DER (10.1) return Err(::nom::Err::Error(BerError::DerConstraintFailed)); } (_, l1) => { // if len is 0xff -> error (8.1.3.5) if l1 == 0b0111_1111 { return Err(::nom::Err::Error(BerError::InvalidTag)); } // 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); let (i3, llen) = take(l1)(i2)?; match bytes_to_u64(llen) { Ok(l) => { // DER: should have been encoded in short form (< 127) der_constraint_fail_if!(i, l < 127); let l = usize::try_from(l).or(Err(::nom::Err::Error(BerError::InvalidLength)))?; (i3, BerSize::Definite(l)) } Err(_) => { return Err(::nom::Err::Error(BerError::InvalidTag)); } } } }; let hdr = DerObjectHeader::new(class, el.1, BerTag(el.2), len).with_raw_tag(Some(el.3)); Ok((i3, hdr)) } der-parser-6.0.1/src/der/tagged.rs000064400000000000000000000173730072674642500151010ustar 00000000000000use crate::ber::MAX_RECURSION; use crate::der::*; use crate::error::*; use nom::error::ParseError; use nom::{Err, IResult}; /// Read a TAGGED EXPLICIT value (combinator) /// /// The built object will use the outer header (and tag), and contains a `Tagged` object /// with class, value and content. /// /// For a generic version (different output and error types), see /// [parse_der_tagged_explicit_g](fn.parse_der_tagged_explicit_g.html). /// /// The following parses `[2] EXPLICIT INTEGER`: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map_res; /// # /// fn parse_int_explicit(i:&[u8]) -> BerResult { /// map_res( /// parse_der_tagged_explicit(2, parse_der_integer), /// |x: DerObject| x.as_tagged()?.2.as_u32() /// )(i) /// } /// /// # 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) /// # } /// ``` pub fn parse_der_tagged_explicit<'a, Tag, F>(tag: Tag, f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: Fn(&'a [u8]) -> BerResult, Tag: Into, { let tag = tag.into(); parse_der_tagged_explicit_g(tag, move |content, hdr| { let (rem, obj) = f(content)?; let class = hdr.class; let obj2 = DerObject::from_header_and_content( hdr, DerObjectContent::Tagged(class, tag, Box::new(obj)), ); Ok((rem, obj2)) }) } /// Read a TAGGED EXPLICIT value (generic version) /// /// The following parses `[2] EXPLICIT INTEGER`: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// # /// fn parse_int_explicit(i:&[u8]) -> BerResult { /// parse_der_tagged_explicit_g(2, move |content, hdr| { /// let (rem, obj) = parse_der_integer(content)?; /// let value = obj.as_u32()?; /// Ok((rem, value)) /// })(i) /// } /// /// # 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) /// # } /// ``` pub fn parse_der_tagged_explicit_g<'a, Tag, Output, F, E>( tag: Tag, f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Output, E> where F: Fn(&'a [u8], DerObjectHeader<'a>) -> IResult<&'a [u8], Output, E>, E: ParseError<&'a [u8]> + From, Tag: Into, { let tag = tag.into(); parse_der_container(move |i, hdr| { if hdr.class == DerClass::Universal { return Err(Err::Error(BerError::InvalidClass.into())); } if hdr.tag != tag { return Err(Err::Error(BerError::InvalidTag.into())); } // X.690 8.14.2: if implicit tagging was not used, the encoding shall be constructed if !hdr.is_constructed() { return Err(Err::Error(BerError::ConstructExpected.into())); } f(i, hdr) // trailing bytes are ignored }) } /// Read a TAGGED IMPLICIT value (combinator) /// /// Parse a TAGGED IMPLICIT value, given the expected tag, and the content parsing function. /// /// The built object will use the original header (and tag), so the content may not match the tag /// value. /// /// For a generic version (different output and error types), see /// [parse_der_tagged_implicit_g](fn.parse_der_tagged_implicit_g.html). /// /// # Examples /// /// The following parses `[2] IMPLICIT INTEGER` into a `DerObject`: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// # /// fn parse_int_implicit(i:&[u8]) -> BerResult { /// parse_der_tagged_implicit( /// 2, /// parse_der_content(DerTag::Integer), /// )(i) /// } /// /// # let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01]; /// let res = parse_int_implicit(bytes); /// # match res { /// # Ok((rem, content)) => { /// # assert!(rem.is_empty()); /// # assert_eq!(content.as_u32(), Ok(0x10001)); /// # }, /// # _ => assert!(false) /// # } /// ``` /// /// The following parses `[2] IMPLICIT INTEGER` into an `u32`, raising an error if the integer is /// too large: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map_res; /// # /// fn parse_int_implicit(i:&[u8]) -> BerResult { /// map_res( /// parse_der_tagged_implicit( /// 2, /// parse_der_content(DerTag::Integer), /// ), /// |x: DerObject| x.as_u32() /// )(i) /// } /// /// # 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) /// # } /// ``` pub fn parse_der_tagged_implicit<'a, Tag, F>(tag: Tag, f: F) -> impl FnMut(&'a [u8]) -> BerResult where F: Fn(&'a [u8], &'_ DerObjectHeader, usize) -> BerResult<'a, DerObjectContent<'a>>, Tag: Into, { let tag = tag.into(); parse_der_tagged_implicit_g(tag, move |i, hdr, depth| { let (rem, content) = f(i, &hdr, depth)?; // trailing bytes are ignored let obj = DerObject::from_header_and_content(hdr, content); Ok((rem, obj)) }) } /// Read a TAGGED IMPLICIT value (generic version) /// /// Parse a TAGGED IMPLICIT value, given the expected tag, and the content parsing function. /// /// # Examples /// /// The following parses `[1] IMPLICIT OCTETSTRING`, returning a `DerObject`: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// # /// fn parse_implicit_0_octetstring(i:&[u8]) -> BerResult { /// parse_der_tagged_implicit_g( /// 2, /// parse_der_content2(DerTag::OctetString) /// )(i) /// } /// /// # let bytes = &[0x02, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f]; /// let res = parse_implicit_0_octetstring(bytes); /// # match res { /// # Ok((rem, val)) => { /// # assert!(rem.is_empty()); /// # let s = val.as_slice().unwrap(); /// # assert_eq!(s, b"hello"); /// # }, /// # _ => assert!(false) /// # } /// ``` /// /// The following parses `[2] IMPLICIT INTEGER` into an `u32`, raising an error if the integer is /// too large: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// # /// fn parse_int_implicit(i:&[u8]) -> BerResult { /// parse_der_tagged_implicit_g( /// 2, /// |content, hdr, depth| { /// let (rem, obj_content) = parse_der_content(DerTag::Integer)(content, &hdr, depth)?; /// let value = obj_content.as_u32()?; /// Ok((rem, value)) /// } /// )(i) /// } /// /// # 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) /// # } /// ``` pub fn parse_der_tagged_implicit_g<'a, Tag, Output, F, E>( tag: Tag, f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&[u8], Output, E> where F: Fn(&'a [u8], DerObjectHeader<'a>, usize) -> IResult<&'a [u8], Output, E>, E: ParseError<&'a [u8]> + From, Tag: Into, { let tag = tag.into(); parse_der_container(move |i, hdr| { if hdr.tag != tag { return Err(Err::Error(BerError::InvalidTag.into())); } // XXX MAX_RECURSION should not be used, it resets the depth counter f(i, hdr, MAX_RECURSION) // trailing bytes are ignored }) } der-parser-6.0.1/src/error.rs000064400000000000000000000061650072674642500142220ustar 00000000000000//! Error type for BER/DER parsers use crate::ber::BerObject; use crate::der::DerObject; use alloc::fmt; use nom::error::{ErrorKind, FromExternalError, ParseError}; use nom::IResult; /// 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>> = 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, Copy, Clone)] pub enum BerError { /// BER object does not have the expected type BerTypeError, /// BER object does not have the expected value BerValueError, InvalidTag, InvalidClass, InvalidLength, IndefiniteLengthUnexpected, /// 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 string has characters forbidden in standard StringInvalidCharset, /// BER integer is too large to fit in a native type. Use `as_bigint()` IntegerTooLarge, /// BER integer is negative, while an unsigned integer was requested IntegerNegative, /// BER recursive parsing reached maximum depth (See /// [MAX_RECURSION](../ber/constant.MAX_RECURSION.html)) 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 From for nom::Err { fn from(e: BerError) -> nom::Err { nom::Err::Error(e) } } 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) } } impl FromExternalError for BerError { fn from_external_error(_input: I, kind: ErrorKind, _e: E) -> BerError { BerError::NomError(kind) } } impl fmt::Display for BerError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } #[cfg(feature = "std")] impl std::error::Error for BerError {} #[cfg(all(test, feature = "std"))] mod tests { use super::*; use std::boxed::Box; use std::error::Error; #[test] fn test_unwrap_bererror() { let e = BerError::IntegerTooLarge; // println!("{}", e); let _: Result<(), Box> = Err(Box::new(e)); } } der-parser-6.0.1/src/lib.rs000064400000000000000000000264070072674642500136400ustar 00000000000000//! [![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) //! [![docs.rs](https://docs.rs/der-parser/badge.svg)](https://docs.rs/der-parser) //! [![crates.io](https://img.shields.io/crates/v/der-parser.svg)](https://crates.io/crates/der-parser) //! [![Download numbers](https://img.shields.io/crates/d/der-parser.svg)](https://crates.io/crates/der-parser) //! [![dependency status](https://deps.rs/crate/der-parser/5.0.0/status.svg)](https://deps.rs/crate/der-parser/5.0.1) //! [![Github CI](https://github.com/rusticata/der-parser/workflows/Continuous%20integration/badge.svg)](https://github.com/rusticata/der-parser/actions) //! [![Minimum rustc version](https://img.shields.io/badge/rustc-1.48.0+-lightgray.svg)](#rust-version-requirements) //! //! # 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. //! //! It is written in pure Rust, fast, and makes extensive use of zero-copy. A lot of care is taken //! to ensure security and safety of this crate, including design (recursion limit, defensive //! programming), tests, and fuzzing. It also aims to be panic-free. //! //! Historically, this parser was intended for DER only, and BER support was added later. This may //! still reflect on some naming schemes, but has no other consequence: the `BerObject` and //! `DerObject` used in this crate are type aliases, so all functions are compatible. //! //! DER parsing functions have additional constraints verification, however. //! //! Serialization has also been added (see [Serialization](#serialization) ) //! //! The code is available on [Github](https://github.com/rusticata/der-parser) //! and is part of the [Rusticata](https://github.com/rusticata) project. //! //! # BER/DER parsers //! //! BER stands for Basic Encoding Rules, and is defined in [X.690]. It defines a set of rules to //! encode and decode ASN.1 objects in binary. //! //! [X.690] also defines Distinguished Encoding Rules (DER), which is BER with added rules to //! ensure canonical and unequivocal binary representation of objects. //! //! The choice of which one to use is usually guided by the speficication of the data format based //! on BER or DER: for example, X.509 uses DER as encoding representation. //! //! See the related modules for object definitions, functions, and example: //! - [`ber`]: Basic Encoding Rules //! - [`der`]: Distinguished Encoding Rules //! //! ## Examples //! //! Parse two BER integers (see [BER/DER Integers](#berder-integers)): //! //! ```rust //! use der_parser::ber::parse_ber_integer; //! //! let bytes = [ 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x02, 0x03, 0x01, 0x00, 0x00, //! ]; //! //! let (rem, obj1) = parse_ber_integer(&bytes).expect("parsing failed"); //! let (rem, obj2) = parse_ber_integer(&bytes).expect("parsing failed"); //! ``` //! //! Parse a DER sequence of integers: //! //! ```rust //! use der_parser::der::{parse_der_integer, parse_der_sequence_of}; //! //! let bytes = [ 0x30, 0x0a, //! 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x02, 0x03, 0x01, 0x00, 0x00, //! ]; //! //! let (rem, seq) = parse_der_sequence_of(parse_der_integer)(&bytes) //! .expect("parsing failed"); //! ``` //! //! Note: all parsing functions return the remaining (unparsed) bytes and the parsed object, or an //! error. //! //! # DER parser design //! //! Parsing functions are inspired from `nom`, and follow the same interface. The most common //! return type is [`BerResult`](error/type.BerResult.html), that stores the remaining bytes and //! parsed [`BerObject`](ber/struct.BerObject.html), or an error. Reading the nom documentation may //! help understanding how to write parsers and use the output. //! //! 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. //! It is useful when decoding an arbitrary DER object. //! 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 functions can be used: //! - [`parse_ber_sequence_defined`](ber/fn.parse_ber_sequence_defined.html) and similar functions //! for sequences and sets variants //! - [`parse_ber_tagged_explicit`](ber/fn.parse_ber_tagged_explicit.html) for tagged explicit //! - [`parse_ber_tagged_implicit`](ber/fn.parse_ber_tagged_implicit.html) for tagged implicit //! - [`parse_ber_container`](ber/fn.parse_ber_container.html) for generic parsing, etc. //! - DER objects use the `_der_` variants //! //! For example, to read a BER sequence containing two integers: //! //! ```rust //! use der_parser::ber::*; //! use der_parser::error::BerResult; //! //! fn localparse_seq(i:&[u8]) -> BerResult { //! parse_ber_sequence_defined(|data| { //! let (rem, a) = parse_ber_integer(data)?; //! let (rem, b) = parse_ber_integer(rem)?; //! Ok((rem, vec![a, b])) //! })(i) //! } //! //! let bytes = [ 0x30, 0x0a, //! 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x02, 0x03, 0x01, 0x00, 0x00, //! ]; //! //! let (_, parsed) = localparse_seq(&bytes).expect("parsing failed"); //! //! assert_eq!(parsed[0].as_u64(), Ok(65537)); //! assert_eq!(parsed[1].as_u64(), Ok(65536)); //! ``` //! //! 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 //! //! ## BER/DER Integers //! //! DER integers can be of any size, so it is not possible to store them as simple integers (they //! are stored as raw bytes). //! //! Note that, by default, BER/DER integers are signed. Functions are provided to request reading //! unsigned values, but they will fail if the integer value is negative. //! //! To get the integer value for all possible integer sign and size, use //! [`BerObject::as_bigint`](ber/struct.BerObject.html#method.as_bigint)) (requires the `bigint` feature). //! //! To get a simple value expected to be in a known range, use methods like //! [`BerObject::as_i32`](ber/struct.BerObject.html#method.as_i32)) and //! [`BerObject::as_i64`](ber/struct.BerObject.html#method.as_i64) (or the unsigned versions //! [`BerObject::as_u32`](ber/struct.BerObject.html#method.as_u32) and //! [`BerObject::as_u64`](ber/struct.BerObject.html#method.as_u64) //!), //! which will return the value, or an error if the integer is too large (or is negative). //! //! ```rust //! use der_parser::ber::*; //! //! let data = &[0x02, 0x03, 0x01, 0x00, 0x01]; //! //! let (_, object) = parse_ber_integer(data).expect("parsing failed"); //! assert_eq!(object.as_u64(), Ok(65537)); //! //! #[cfg(feature = "bigint")] //! assert_eq!(object.as_bigint(), Ok(65537.into())) //! ``` //! //! Access to the raw value is possible using the `as_slice` method. //! //! ## Parsers, combinators, macros //! //! Some parsing tools (for ex for tagged objects) are available in different forms: //! - parsers: (regular) functions that takes input and create an object //! - combinators: functions that takes parsers (or combinators) as input, and return a function //! (usually, the parser). They are used (combined) as building blocks to create more complex //! parsers. //! - macros: these are generally previous (historic) versions of parsers, kept for compatibility. //! They can sometime reduce the amount of code to write, but are hard to debug. //! Parsers should be preferred when possible. //! //! ## Misc 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*. //! //! ## Rust version requirements //! //! The 6.0 series of `der-parser` requires **Rustc version 1.48 or greater**, based on nom 7 //! dependencies. //! //! # Serialization //! //! Support for encoding BER/DER objects is currently being tested and can be used by activating the `serialize` feature. //! Note that current status is **experimental**. //! //! See the `ber_encode_*` functions in the [`ber`](ber/index.html) module, and //! [`BerObject::to_vec`](ber/struct.BerObject.html#method.to_vec) //! //! # 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,*/ unstable_features, unused_import_braces, unused_qualifications, unreachable_pub)] #![forbid(unsafe_code)] #![warn( /* missing_docs, rust_2018_idioms,*/ missing_debug_implementations, )] // pragmas for doc #![deny(broken_intra_doc_links)] #![cfg_attr(docsrs, feature(doc_cfg))] #![doc(test( no_crate_inject, attr(deny(warnings/*, rust_2018_idioms*/), allow(dead_code, unused_variables)) ))] #![no_std] #[cfg(any(test, feature = "std"))] #[macro_use] extern crate std; extern crate alloc; #[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; pub use nom; #[cfg(feature = "bigint")] #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))] pub use num_bigint; // re-exports nom macros, so this crate's macros can be used without importing nom pub use nom::IResult; #[doc(hidden)] pub use rusticata_macros::custom_check; #[doc(hidden)] pub mod exports { pub use alloc::borrow; pub use der_oid_macro; } /// Procedural macro to get encoded oids, see the [oid module](oid/index.html). #[macro_export] macro_rules! oid { (raw $($args:tt)*) => {{ $crate::exports::der_oid_macro::encode_oid!($($args)*) }}; (rel $($args:tt)*) => {{ $crate::oid::Oid::new_relative( $crate::exports::borrow::Cow::Borrowed(& $crate::exports::der_oid_macro::encode_oid!(rel $($args)*) ) ) }}; ($($args:tt)*) => {{ $crate::oid::Oid::new( $crate::exports::borrow::Cow::Borrowed(& $crate::exports::der_oid_macro::encode_oid!($($args)*) ) ) }}; } der-parser-6.0.1/src/oid.rs000064400000000000000000000356410072674642500136450ustar 00000000000000//! Object ID (OID) representations. //! //! The parser does not copy oids when parsing. The [Oid struct](struct.Oid.html) //! only has a reference to the DER encoded form of the oid. //! //! # The `der_parser::oid!` macro //! //! Since the DER encoded oids are not very readable we provide a //! procedural macro `oid!`. The macro can be used the following ways: //! //! - `oid!(1.4.42.23)`: Create a const expression for the corresponding `Oid<'static>` //! - `oid!(rel 42.23)`: Create a const expression for the corresponding relative `Oid<'static>` //! - `oid!(raw 1.4.42.23)`/`oid!(raw rel 42.23)`: Obtain the DER encoded form as a byte array. //! //! # Comparing oids //! //! Comparing a parsed oid to a static oid is probably the most common //! thing done with oids in your code. The `oid!` macro can be used in expression positions for //! this purpose. For example //! ``` //! use der_parser::{oid, oid::Oid}; //! //! # let some_oid: Oid<'static> = oid!(1.2.456); //! const SOME_STATIC_OID: Oid<'static> = oid!(1.2.456); //! assert_eq!(some_oid, SOME_STATIC_OID) //! ``` //! To get a relative Oid use `oid!(rel 1.2)`. //! //! Because of limitations for procedural macros ([rust issue](https://github.com/rust-lang/rust/issues/54727)) //! and constants used in patterns ([rust issue](https://github.com/rust-lang/rust/issues/31434)) //! the `oid` macro can not directly be used in patterns, also not through constants. //! You can do this, though: //! ``` //! # use der_parser::{oid, oid::Oid}; //! # let some_oid: Oid<'static> = oid!(1.2.456); //! const SOME_OID: Oid<'static> = oid!(1.2.456); //! if some_oid == SOME_OID || some_oid == oid!(1.2.456) { //! println!("match"); //! } //! //! // Alternatively, compare the DER encoded form directly: //! const SOME_OID_RAW: &[u8] = &oid!(raw 1.2.456); //! match some_oid.bytes() { //! SOME_OID_RAW => println!("match"), //! _ => panic!("no match"), //! } //! ``` //! *Attention*, be aware that the latter version might not handle the case of a relative oid correctly. An //! extra check might be necessary. use alloc::borrow::Cow; use alloc::fmt; use alloc::str::FromStr; use alloc::string::{String, ToString}; use alloc::vec::Vec; use core::convert::From; use core::iter::{ExactSizeIterator, FusedIterator, Iterator}; use core::ops::Shl; #[cfg(feature = "bigint")] use num_bigint::BigUint; use num_traits::Num; #[cfg(not(feature = "std"))] use alloc::format; #[derive(Debug)] pub enum ParseError { TooShort, /// Signalizes that the first or second component is too large. /// The first must be within the range 0 to 6 (inclusive). /// The second component must be less than 40. FirstComponentsTooLarge, ParseIntError, } /// Object ID (OID) representation which can be relative or non-relative. /// An example for an oid in string representation is "1.2.840.113549.1.1.5". /// /// For non-relative oids restrictions apply to the first two components. /// /// This library contains a procedural macro `oid` which can be used to /// create oids. For example `oid!(1.2.44.233)` or `oid!(rel 44.233)` /// for relative oids. See the [module documentation](index.html) for more information. #[derive(Hash, PartialEq, Eq, Clone)] pub struct Oid<'a> { asn1: Cow<'a, [u8]>, pub relative: bool, } fn encode_relative(ids: &'_ [u64]) -> impl Iterator + '_ { ids.iter() .map(|id| { let bit_count = 64 - id.leading_zeros(); let octets_needed = ((bit_count + 6) / 7).max(1); (0..octets_needed).map(move |i| { let flag = if i == octets_needed - 1 { 0 } else { 1 << 7 }; ((id >> (7 * (octets_needed - 1 - i))) & 0b111_1111) as u8 | flag }) }) .flatten() } impl<'a> Oid<'a> { /// Create an OID from the ASN.1 DER encoded form. See the [module documentation](index.html) /// for other ways to create oids. pub const fn new(asn1: Cow<'a, [u8]>) -> Oid { Oid { asn1, relative: false, } } /// Create a relative OID from the ASN.1 DER encoded form. See the [module documentation](index.html) /// for other ways to create relative oids. pub const fn new_relative(asn1: Cow<'a, [u8]>) -> Oid { Oid { asn1, relative: true, } } /// Build an OID from an array of object identifier components. /// This method allocates memory on the heap. // we do not use .copied() for compatibility with 1.34 #[allow(clippy::map_clone)] pub fn from<'b>(s: &'b [u64]) -> Result, ParseError> { if s.len() < 2 { if s.len() == 1 && s[0] == 0 { return Ok(Oid { asn1: Cow::Borrowed(&[0]), relative: false, }); } return Err(ParseError::TooShort); } if s[0] >= 7 || s[1] >= 40 { return Err(ParseError::FirstComponentsTooLarge); } let asn1_encoded: Vec = [(s[0] * 40 + s[1]) as u8] .iter() .map(|&x| x) .chain(encode_relative(&s[2..])) .collect(); Ok(Oid { asn1: Cow::from(asn1_encoded), relative: false, }) } /// Build a relative OID from an array of object identifier components. pub fn from_relative<'b>(s: &'b [u64]) -> Result, ParseError> { if s.is_empty() { return Err(ParseError::TooShort); } let asn1_encoded: Vec = encode_relative(s).collect(); Ok(Oid { asn1: Cow::from(asn1_encoded), relative: true, }) } /// Create a deep copy of the oid. /// /// This method allocates data on the heap. The returned oid /// can be used without keeping the ASN.1 representation around. /// /// Cloning the returned oid does again allocate data. pub fn to_owned(&self) -> Oid<'static> { Oid { asn1: Cow::from(self.asn1.to_vec()), relative: self.relative, } } /// Get the encoded oid without the header. pub fn bytes(&self) -> &[u8] { self.asn1.as_ref() } /// Convert the OID to a string representation. /// The string contains the IDs separated by dots, for ex: "1.2.840.113549.1.1.5" #[cfg(feature = "bigint")] pub fn to_id_string(&self) -> String { let ints: Vec = self.iter_bigint().map(|i| i.to_string()).collect(); ints.join(".") } #[cfg(not(feature = "bigint"))] /// Convert the OID to a string representation. /// /// If every arc fits into a u64 a string like "1.2.840.113549.1.1.5" /// is returned, otherwise a hex representation. /// /// See also the "bigint" feature of this crate. pub fn to_id_string(&self) -> String { if let Some(arcs) = self.iter() { let ints: Vec = arcs.map(|i| i.to_string()).collect(); ints.join(".") } else { let mut ret = String::with_capacity(self.asn1.len() * 3); for (i, o) in self.asn1.iter().enumerate() { ret.push_str(&format!("{:02x}", o)); if i + 1 != self.asn1.len() { ret.push(' '); } } ret } } /// Return an iterator over the sub-identifiers (arcs). #[cfg(feature = "bigint")] pub fn iter_bigint( &'_ self, ) -> impl Iterator + FusedIterator + ExactSizeIterator + '_ { SubIdentifierIterator { oid: self, pos: 0, first: false, n: core::marker::PhantomData, } } /// Return an iterator over the sub-identifiers (arcs). /// Returns `None` if at least one arc does not fit into `u64`. pub fn iter( &'_ self, ) -> Option + FusedIterator + ExactSizeIterator + '_> { // Check that every arc fits into u64 let bytes = if self.relative { &self.asn1 } else if self.asn1.is_empty() { &[] } else { &self.asn1[1..] }; let max_bits = bytes .iter() .fold((0usize, 0usize), |(max, cur), c| { let is_end = (c >> 7) == 0u8; if is_end { (max.max(cur + 7), 0) } else { (max, cur + 7) } }) .0; if max_bits > 64 { return None; } Some(SubIdentifierIterator { oid: self, pos: 0, first: false, n: core::marker::PhantomData, }) } } trait Repr: Num + Shl + From {} impl Repr for N where N: Num + Shl + From {} struct SubIdentifierIterator<'a, N: Repr> { oid: &'a Oid<'a>, pos: usize, first: bool, n: core::marker::PhantomData<&'a N>, } impl<'a, N: Repr> Iterator for SubIdentifierIterator<'a, N> { type Item = N; fn next(&mut self) -> Option { use num_traits::identities::Zero; if self.pos == self.oid.asn1.len() { return None; } if !self.oid.relative { if !self.first { debug_assert!(self.pos == 0); self.first = true; return Some((self.oid.asn1[0] / 40).into()); } else if self.pos == 0 { self.pos += 1; if self.oid.asn1[0] == 0 && self.oid.asn1.len() == 1 { return None; } return Some((self.oid.asn1[0] % 40).into()); } } // decode objet sub-identifier according to the asn.1 standard let mut res = ::zero(); for o in self.oid.asn1[self.pos..].iter() { self.pos += 1; res = (res << 7) + (o & 0b111_1111).into(); let flag = o >> 7; if flag == 0u8 { break; } } Some(res) } } impl<'a, N: Repr> FusedIterator for SubIdentifierIterator<'a, N> {} impl<'a, N: Repr> ExactSizeIterator for SubIdentifierIterator<'a, N> { fn len(&self) -> usize { if self.oid.relative { self.oid.asn1.iter().filter(|o| (*o >> 7) == 0u8).count() } else if self.oid.asn1.len() == 0 { 0 } else if self.oid.asn1.len() == 1 { if self.oid.asn1[0] == 0 { 1 } else { 2 } } else { 2 + self.oid.asn1[2..] .iter() .filter(|o| (*o >> 7) == 0u8) .count() } } #[cfg(feature = "exact_size_is_empty")] fn is_empty(&self) -> bool { self.oid.asn1.is_empty() } } impl<'a> fmt::Display for Oid<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.relative { f.write_str("rel. ")?; } f.write_str(&self.to_id_string()) } } impl<'a> fmt::Debug for Oid<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("OID(")?; ::fmt(self, f)?; f.write_str(")") } } impl<'a> FromStr for Oid<'a> { type Err = ParseError; fn from_str(s: &str) -> Result { let v: Result, _> = s.split('.').map(|c| c.parse::()).collect(); v.map_err(|_| ParseError::ParseIntError) .and_then(|v| Oid::from(&v)) } } #[cfg(test)] mod tests { use crate::oid::Oid; use std::borrow::Cow; use std::borrow::ToOwned; use std::str::FromStr; #[test] fn test_oid_fmt() { let oid = Oid::from(&[1, 2, 840, 113_549, 1, 1, 5]).unwrap(); 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()); let oid = Oid::from_relative(&[840, 113_549, 1, 1, 5]).unwrap(); let byte_ref = [0x86, 0x48, 0x86, 0xf7, 0x0d, 1, 1, 5]; assert_eq!(byte_ref.as_ref(), oid.asn1.as_ref()); assert_eq!(format!("{}", oid), "rel. 840.113549.1.1.5".to_owned()); assert_eq!( format!("{:?}", oid), "OID(rel. 840.113549.1.1.5)".to_owned() ); } #[test] fn test_iter_len() { #[cfg(feature = "bigint")] { assert_eq!(Oid::new(Cow::Borrowed(&[])).iter_bigint().len(), 0); assert_eq!(Oid::from(&[0]).unwrap().iter_bigint().len(), 1); assert_eq!(Oid::from(&[1, 2]).unwrap().iter_bigint().len(), 2); assert_eq!( Oid::from(&[1, 29, 459, 342]).unwrap().iter_bigint().len(), 4 ); assert_eq!( Oid::from_relative(&[459, 342]).unwrap().iter_bigint().len(), 2 ); } { assert_eq!(Oid::new(Cow::Borrowed(&[])).iter().unwrap().len(), 0); assert_eq!(Oid::from(&[0]).unwrap().iter().unwrap().len(), 1); assert_eq!(Oid::from(&[1, 2]).unwrap().iter().unwrap().len(), 2); assert_eq!( Oid::from(&[1, 29, 459, 342]).unwrap().iter().unwrap().len(), 4 ); assert_eq!( Oid::from_relative(&[459, 342]) .unwrap() .iter() .unwrap() .len(), 2 ); } } #[test] fn test_oid_from_str() { let oid_ref = Oid::from(&[1, 2, 840, 113_549, 1, 1, 5]).unwrap(); let byte_ref = [42, 0x86, 0x48, 0x86, 0xf7, 0x0d, 1, 1, 5]; let oid = Oid::from_str("1.2.840.113549.1.1.5").unwrap(); assert_eq!(byte_ref.as_ref(), oid.asn1.as_ref()); assert_eq!(oid_ref, oid); } /// This test case will test an OID beginning with two zero /// subidentifiers (literally: "itu-t recommendation"), as /// used for example in the TCAP (Q.773) specification. #[test] fn test_itu_t_rec_oid() { let oid = Oid::from(&[0, 0, 17, 773, 1, 1, 1]).unwrap(); assert_eq!(format!("{}", oid), "0.0.17.773.1.1.1".to_owned()); assert_eq!(format!("{:?}", oid), "OID(0.0.17.773.1.1.1)".to_owned()); } #[test] fn test_zero_oid() { #[cfg(feature = "bigint")] { use num_bigint::BigUint; use num_traits::FromPrimitive; use std::vec::Vec; let oid_raw = Oid::new(Cow::Borrowed(&[0])); let ids: Vec = oid_raw.iter_bigint().collect(); assert_eq!(vec![BigUint::from_u8(0).unwrap()], ids); assert_eq!(oid_raw.iter_bigint().len(), 1); } { use std::vec::Vec; let oid_raw = Oid::new(Cow::Borrowed(&[0])); let ids: Vec = oid_raw.iter().unwrap().collect(); assert_eq!(vec![0], ids); assert_eq!(oid_raw.iter().unwrap().len(), 1); } let oid_from = Oid::from(&[0]).unwrap(); assert_eq!(oid_from.asn1.as_ref(), &[0]); } } der-parser-6.0.1/tests/ber_parser.rs000064400000000000000000000516570072674642500155760ustar 00000000000000use der_parser::ber::*; use der_parser::error::*; use der_parser::oid::*; use hex_literal::hex; use nom::Err; // use pretty_assertions::assert_eq; use test_case::test_case; #[cfg(feature = "bigint")] use num_bigint::{BigInt, BigUint, Sign}; #[test_case(&hex!("01 01 00"), Some(false) ; "val true")] #[test_case(&hex!("01 01 ff"), Some(true) ; "val false")] #[test_case(&hex!("01 01 7f"), Some(true) ; "true not ff")] #[test_case(&hex!("01 02 00 00"), None ; "invalid length")] #[test_case(&hex!("01 01"), None ; "incomplete")] fn tc_ber_bool(i: &[u8], out: Option) { let res = parse_ber_bool(i); if let Some(b) = out { let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } else { assert!(res.is_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_ber_set_of() { 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"), ]); fn parser(i: &[u8]) -> BerResult { parse_ber_set_of(parse_ber_integer)(i) } assert_eq!(parser(&bytes), Ok((empty, expected))); // empty input should raise error (could not read set header) assert!(parser(&[]).is_err()); // empty set is ok (returns empty vec) assert!(parser(&[0x31, 0x00]).is_ok()); } #[test] fn test_ber_set_of_v() { let empty = &b""[..]; let bytes = [ 0x31, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let expected = vec![ BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_int_slice(b"\x01\x00\x00"), ]; fn parser(i: &[u8]) -> BerResult> { parse_ber_set_of_v(parse_ber_integer)(i) } assert_eq!(parser(&bytes), Ok((empty, expected))); // empty input should raise error (could not read set header) assert!(parser(&[]).is_err()); // empty set is ok (returns empty vec) assert_eq!(parser(&[0x31, 0x00]), Ok((empty, vec![]))); } #[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_case(&hex!("02 01 01"), Ok(1) ; "u32-1")] #[test_case(&hex!("02 02 00 ff"), Ok(255) ; "u32-255")] #[test_case(&hex!("02 02 01 23"), Ok(0x123) ; "u32-0x123")] #[test_case(&hex!("02 04 01 23 45 67"), Ok(0x0123_4567) ; "u32-long-ok")] #[test_case(&hex!("02 05 00 ff ff ff ff"), Ok(0xffff_ffff) ; "u32-long2-ok")] #[test_case(&hex!("02 06 00 00 01 23 45 67"), Ok(0x0123_4567) ; "u32-long-leading-zeros-ok")] #[test_case(&hex!("02 05 01 23 45 67 01"), Err(BerError::IntegerTooLarge) ; "u32 too large")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Err(BerError::IntegerTooLarge) ; "u32 too large 2")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_ber_u32(i: &[u8], out: Result) { let res = parse_ber_u32(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("02 01 01"), Ok(1) ; "u64-1")] #[test_case(&hex!("02 02 00 ff"), Ok(255) ; "u64-255")] #[test_case(&hex!("02 02 01 23"), Ok(0x123) ; "u64-0x123")] #[test_case(&hex!("02 08 01 23 45 67 01 23 45 67"), Ok(0x0123_4567_0123_4567) ; "u64-long-ok")] #[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(0xffff_ffff_ffff_ffff) ; "u64-long2-ok")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Err(BerError::IntegerTooLarge) ; "u64 too large")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_ber_u64(i: &[u8], out: Result) { let res = parse_ber_u64(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("02 01 01"), Ok(1) ; "i64-1")] #[test_case(&hex!("02 01 ff"), Ok(-1) ; "i64-neg1")] #[test_case(&hex!("02 01 80"), Ok(-128) ; "i64-neg128")] #[test_case(&hex!("02 02 ff 7f"), Ok(-129) ; "i64-neg129")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_ber_i64(i: &[u8], out: Result) { let res = parse_ber_i64(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[cfg(feature = "bigint")] #[test_case(&hex!("02 01 01"), Ok(BigInt::from(1)) ; "bigint-1")] #[test_case(&hex!("02 02 00 ff"), Ok(BigInt::from(255)) ; "bigint-255")] #[test_case(&hex!("02 01 ff"), Ok(BigInt::from(-1)) ; "bigint-neg1")] #[test_case(&hex!("02 01 80"), Ok(BigInt::from(-128)) ; "bigint-neg128")] #[test_case(&hex!("02 02 ff 7f"), Ok(BigInt::from(-129)) ; "bigint-neg129")] #[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(BigInt::from(0xffff_ffff_ffff_ffff_u64)) ; "bigint-long2-ok")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(BigInt::from_bytes_be(Sign::Plus, &hex!("01 23 45 67 01 23 45 67 ab"))) ; "bigint-longer1")] fn tc_ber_bigint(i: &[u8], out: Result) { let res = parse_ber_integer(i); match out { Ok(expected) => { let (rem, ber) = res.expect("parsing failed"); assert!(rem.is_empty()); let int = ber.as_bigint().expect("failed to convert to bigint"); pretty_assertions::assert_eq!(int, expected); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[cfg(feature = "bigint")] #[test_case(&hex!("02 01 01"), Ok(BigUint::from(1_u8)) ; "biguint-1")] #[test_case(&hex!("02 02 00 ff"), Ok(BigUint::from(255_u8)) ; "biguint-255")] #[test_case(&hex!("02 01 ff"), Err(BerError::IntegerNegative) ; "biguint-neg1")] #[test_case(&hex!("02 01 80"), Err(BerError::IntegerNegative) ; "biguint-neg128")] #[test_case(&hex!("02 02 ff 7f"), Err(BerError::IntegerNegative) ; "biguint-neg129")] #[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(BigUint::from(0xffff_ffff_ffff_ffff_u64)) ; "biguint-long2-ok")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(BigUint::from_bytes_be(&hex!("01 23 45 67 01 23 45 67 ab"))) ; "biguint-longer1")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_ber_biguint(i: &[u8], out: Result) { let res = parse_ber_integer(i).and_then(|(rem, ber)| Ok((rem, ber.as_biguint()?))); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("02 01 01"), Ok(&[1]) ; "slice 1")] #[test_case(&hex!("02 01 ff"), Ok(&[255]) ; "slice 2")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(&hex!("01 23 45 67 01 23 45 67 ab")) ; "slice 3")] #[test_case(&hex!("22 80 02 01 01 00 00"), Ok(&[2, 1, 1]) ; "constructed slice")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_ber_slice(i: &[u8], out: Result<&[u8], BerError>) { let res = parse_ber_slice(i, 2); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[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, 113_549, 1, 1, 5]).unwrap(), )); 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_case(&hex!("0c 04 31 32 33 34"), Ok("1234") ; "utf8: numeric")] #[test_case(&hex!("0c 05 68 65 6c 6c 6f"), Ok("hello") ; "utf8: string")] #[test_case(&hex!("0c 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64"), Ok("hello world") ; "utf8: string with spaces")] #[test_case(&hex!("0c 0b 68 65 6c 6c 6f 5c 77 6f 72 6c 64"), Ok("hello\\world") ; "utf8: string with backspace")] #[test_case(&hex!("0c 0b 68 65 6c 6c 6f 2b 77 6f 72 6c 64"), Ok("hello+world") ; "utf8: string with plus")] #[test_case(&hex!("0c 05 01 02 03 04 05"), Ok("\x01\x02\x03\x04\x05") ; "invalid chars")] #[test_case(&hex!("0c 0e d0 bf d1 80 d0 b8 d0 b2 d0 b5 cc 81 d1 82"), Ok("приве́т") ; "utf8")] #[test_case(&hex!("0c 04 00 9f 92 96"), Err(Err::Error(BerError::StringInvalidCharset)) ; "invalid utf8")] fn tc_ber_utf8_string(i: &[u8], out: Result<&str, Err>) { let res = parse_ber_utf8string(i); match out { Ok(b) => { let (rem, res) = res.expect("could not parse utf8string"); assert!(rem.is_empty()); let r = res.as_str().expect("could not convert to string"); // let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(r, b); } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("12 04 31 32 33 34"), Ok("1234") ; "numeric string")] #[test_case(&hex!("12 05 68 65 6c 6c 6f"), Err(Err::Error(BerError::StringInvalidCharset)) ; "invalid chars")] #[test_case(&hex!("12 05 01 02 03 04 05"), Err(Err::Error(BerError::StringInvalidCharset)) ; "invalid chars2")] fn tc_ber_numeric_string(i: &[u8], out: Result<&str, Err>) { let res = parse_ber_numericstring(i); match out { Ok(b) => { let (rem, res) = res.expect("could not parse numericstring"); assert!(rem.is_empty()); let r = res.as_str().expect("could not convert to string"); // let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(r, b); } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("13 04 31 32 33 34"), Ok("1234") ; "printable: numeric")] #[test_case(&hex!("13 05 68 65 6c 6c 6f"), Ok("hello") ; "printable: string")] #[test_case(&hex!("13 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64"), Ok("hello world") ; "printable: string with spaces")] #[test_case(&hex!("13 0b 68 65 6c 6c 6f 5c 77 6f 72 6c 64"), Err(Err::Error(BerError::StringInvalidCharset)) ; "printable: string with backspace")] #[test_case(&hex!("13 0b 68 65 6c 6c 6f 2b 77 6f 72 6c 64"), Ok("hello+world") ; "printable: string with plus")] #[test_case(&hex!("13 05 01 02 03 04 05"), Err(Err::Error(BerError::StringInvalidCharset)) ; "invalid chars")] fn tc_ber_printable_string(i: &[u8], out: Result<&str, Err>) { let res = parse_ber_printablestring(i); match out { Ok(b) => { let (rem, res) = res.expect("could not parse printablestring"); assert!(rem.is_empty()); let r = res.as_str().expect("could not convert to string"); // let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(r, b); } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("16 04 31 32 33 34"), Ok("1234") ; "ia5: numeric")] #[test_case(&hex!("16 05 68 65 6c 6c 6f"), Ok("hello") ; "ia5: string")] #[test_case(&hex!("16 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64"), Ok("hello world") ; "ia5: string with spaces")] #[test_case(&hex!("16 0b 68 65 6c 6c 6f 5c 77 6f 72 6c 64"), Ok("hello\\world") ; "ia5: string with backspace")] #[test_case(&hex!("16 0b 68 65 6c 6c 6f 2b 77 6f 72 6c 64"), Ok("hello+world") ; "ia5: string with plus")] #[test_case(&hex!("16 05 01 02 03 04 05"), Ok("\x01\x02\x03\x04\x05") ; "invalid chars")] #[test_case(&hex!("16 0d d0 bf d1 80 d0 b8 d0 b2 d0 b5 cc 81 d1 82"), Err(Err::Error(BerError::StringInvalidCharset)) ; "utf8")] fn tc_ber_ia5_string(i: &[u8], out: Result<&str, Err>) { let res = parse_ber_ia5string(i); match out { Ok(b) => { let (rem, res) = res.expect("could not parse ia5string"); assert!(rem.is_empty()); let r = res.as_str().expect("could not convert to string"); // let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(r, b); } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("1a 04 31 32 33 34"), Ok("1234") ; "visible: numeric")] #[test_case(&hex!("1a 05 68 65 6c 6c 6f"), Ok("hello") ; "visible: string")] #[test_case(&hex!("1a 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64"), Ok("hello world") ; "visible: string with spaces")] #[test_case(&hex!("1a 0b 68 65 6c 6c 6f 5c 77 6f 72 6c 64"), Ok("hello\\world") ; "printable: string with backspace")] #[test_case(&hex!("1a 0b 68 65 6c 6c 6f 2b 77 6f 72 6c 64"), Ok("hello+world") ; "printable: string with plus")] #[test_case(&hex!("1a 05 01 02 03 04 05"), Err(Err::Error(BerError::StringInvalidCharset)) ; "invalid chars")] fn tc_ber_visible_string(i: &[u8], out: Result<&str, Err>) { let res = parse_ber_visiblestring(i); match out { Ok(b) => { let (rem, res) = res.expect("could not parse visiblestring"); assert!(rem.is_empty()); let r = res.as_str().expect("could not convert to string"); // let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(r, b); } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[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("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_relative(&[8571, 3, 2]).unwrap(), )); 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))); } #[test] fn test_ber_customtags() { let bytes = hex!("8f 02 12 34"); let hdr = ber_read_element_header(&bytes) .expect("ber_read_element_header") .1; // println!("{:?}", hdr); let expected: &[u8] = &[0x8f]; assert_eq!(hdr.raw_tag, Some(expected)); let bytes = hex!("9f 0f 02 12 34"); let hdr = ber_read_element_header(&bytes) .expect("ber_read_element_header") .1; // println!("{:?}", hdr); let expected: &[u8] = &[0x9f, 0x0f]; assert_eq!(hdr.raw_tag, Some(expected)); } #[test] fn test_ber_indefinite() { let bytes = hex!("30 80 02 03 01 00 01 00 00"); let (rem, val) = parse_ber_container::<_, _, BerError>(|i, _| { assert!(!i.is_empty()); let (_, val) = parse_ber_u32(i)?; Ok((i, val)) })(&bytes) .unwrap(); assert!(rem.is_empty()); assert_eq!(val, 0x10001); } #[test] fn test_ber_indefinite_recursion() { let data = &hex!( " 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 00 00" ); let _ = parse_ber_container::<_, _, BerError>(|i, _| Ok((i, ())))(data) .expect_err("max parsing depth overflow"); } #[test] fn test_parse_ber_content() { let bytes = &hex!("02 03 01 00 01"); let (i, header) = ber_read_element_header(bytes).expect("parsing failed"); let (rem, content) = parse_ber_content(header.tag)(i, &header, MAX_RECURSION).expect("parsing failed"); assert!(rem.is_empty()); assert_eq!(header.tag, BerTag::Integer); assert_eq!(content.as_u32(), Ok(0x10001)); } #[test] fn test_parse_ber_content2() { let bytes = &hex!("02 03 01 00 01"); let (i, header) = ber_read_element_header(bytes).expect("parsing failed"); let tag = header.tag; let (rem, content) = parse_ber_content2(tag)(i, header, MAX_RECURSION).expect("parsing failed"); assert!(rem.is_empty()); assert_eq!(tag, BerTag::Integer); assert_eq!(content.as_u32(), Ok(0x10001)); } #[test] fn parse_ber_private() { let bytes = &hex!("c0 03 01 00 01"); let (rem, res) = parse_ber(bytes).expect("parsing failed"); assert!(rem.is_empty()); assert!(matches!(res.content, BerObjectContent::Private(_, _))); } der-parser-6.0.1/tests/constructed.rs000064400000000000000000000366270072674642500160070ustar 00000000000000use der_parser::ber::*; use der_parser::der::*; use der_parser::error::*; use der_parser::*; use hex_literal::hex; use nom::branch::alt; use nom::combinator::{complete, eof, map, map_res}; use nom::error::ErrorKind; use nom::multi::many0; use nom::sequence::tuple; use nom::*; use oid::Oid; use pretty_assertions::assert_eq; use test_case::test_case; #[derive(Debug, PartialEq)] struct MyStruct<'a> { a: BerObject<'a>, b: BerObject<'a>, } fn parse_struct01(i: &[u8]) -> BerResult { parse_der_sequence_defined_g(|i: &[u8], _| { let (i, a) = parse_ber_integer(i)?; let (i, b) = parse_ber_integer(i)?; Ok((i, MyStruct { a, b })) })(i) } fn parse_struct01_complete(i: &[u8]) -> BerResult { parse_der_sequence_defined_g(|i: &[u8], _| { let (i, a) = parse_ber_integer(i)?; let (i, b) = parse_ber_integer(i)?; eof(i)?; Ok((i, MyStruct { a, b })) })(i) } // verifying tag fn parse_struct04(i: &[u8], tag: BerTag) -> BerResult { parse_der_container(|i: &[u8], hdr| { if hdr.tag != tag { return Err(Err::Error(BerError::InvalidTag)); } let (i, a) = parse_ber_integer(i)?; let (i, b) = parse_ber_integer(i)?; eof(i)?; Ok((i, MyStruct { a, b })) })(i) } #[test_case(&hex!("30 00"), Ok(&[]) ; "empty seq")] #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "seq ok")] #[test_case(&hex!("30 07 02 03 01 00 01 02 03 01"), Err(Err::Error(BerError::NomError(ErrorKind::Eof))) ; "incomplete")] #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Err(Err::Error(BerError::InvalidTag)) ; "invalid tag")] #[test_case(&hex!("30 80 02 03 01 00 01 00 00"), Ok(&[0x10001]) ; "indefinite seq ok")] #[test_case(&hex!("30 80"), Err(Err::Incomplete(Needed::new(1))) ; "indefinite incomplete")] fn tc_ber_seq_of(i: &[u8], out: Result<&[u32], Err>) { fn parser(i: &[u8]) -> BerResult { parse_ber_sequence_of(parse_ber_integer)(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse sequence of"); assert!(rem.is_empty()); if let BerObjectContent::Sequence(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "seq ok")] #[test_case(&hex!("30 07 02 03 01 00 01 02 01"), Err(Err::Incomplete(Needed::new(1))) ; "incomplete")] #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Err(Err::Error(BerError::InvalidTag)) ; "invalid tag")] #[test_case(&hex!("30 80 02 03 01 00 01 02 03 01 00 00 00 00"), Ok(&[0x10001, 0x10000]) ; "indefinite seq")] fn tc_ber_seq_defined(i: &[u8], out: Result<&[u32], Err>) { fn parser(i: &[u8]) -> BerResult { parse_ber_sequence_defined(map( tuple((parse_ber_integer, parse_ber_integer)), |(a, b)| vec![a, b], ))(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse sequence"); assert!(rem.is_empty()); if let BerObjectContent::Sequence(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("31 00"), Ok(&[]) ; "empty set")] #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "set ok")] #[test_case(&hex!("31 07 02 03 01 00 01 02 03 01"), Err(Err::Error(BerError::NomError(ErrorKind::Eof))) ; "incomplete")] #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Err(Err::Error(BerError::InvalidTag)) ; "invalid tag")] #[test_case(&hex!("31 80 02 03 01 00 01 00 00"), Ok(&[0x10001]) ; "indefinite set ok")] #[test_case(&hex!("31 80"), Err(Err::Incomplete(Needed::new(1))) ; "indefinite incomplete")] fn tc_ber_set_of(i: &[u8], out: Result<&[u32], Err>) { fn parser(i: &[u8]) -> BerResult { parse_ber_set_of(parse_ber_integer)(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse set of"); assert!(rem.is_empty()); if let BerObjectContent::Set(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "set ok")] #[test_case(&hex!("31 07 02 03 01 00 01 02 01"), Err(Err::Incomplete(Needed::new(1))) ; "incomplete")] #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Err(Err::Error(BerError::InvalidTag)) ; "invalid tag")] #[test_case(&hex!("31 80 02 03 01 00 01 02 03 01 00 00 00 00"), Ok(&[0x10001, 0x10000]) ; "indefinite set")] fn tc_ber_set_defined(i: &[u8], out: Result<&[u32], Err>) { fn parser(i: &[u8]) -> BerResult { parse_ber_set_defined(map( tuple((parse_ber_integer, parse_ber_integer)), |(a, b)| vec![a, b], ))(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse set"); assert!(rem.is_empty()); if let BerObjectContent::Set(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test] fn empty_seq() { let data = &hex!("30 00"); let (_, res) = parse_ber_sequence(data).expect("parsing empty sequence failed"); assert!(res.as_sequence().unwrap().is_empty()); } #[test] fn struct01() { let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let empty = &b""[..]; let expected = MyStruct { a: BerObject::from_int_slice(b"\x01\x00\x01"), b: BerObject::from_int_slice(b"\x01\x00\x00"), }; let res = parse_struct01(&bytes); assert_eq!(res, Ok((empty, expected))); } #[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, 0x16, 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<'a>, 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]).unwrap(), // countryName val: BerObject::from_obj(BerObjectContent::PrintableString("FR")), }, }, Rdn { a: Attr { oid: Oid::from(&[2, 5, 4, 8]).unwrap(), // stateOrProvinceName val: BerObject::from_obj(BerObjectContent::UTF8String("Some-State")), }, }, Rdn { a: Attr { oid: Oid::from(&[2, 5, 4, 10]).unwrap(), // organizationName val: BerObject::from_obj(BerObjectContent::IA5String( "Internet Widgits Pty Ltd", )), }, }, ], }; fn parse_directory_string(i: &[u8]) -> BerResult { alt(( parse_ber_utf8string, parse_ber_printablestring, parse_ber_ia5string, ))(i) } fn parse_attr_type_and_value(i: &[u8]) -> BerResult { fn clone_oid(x: BerObject) -> Result { x.as_oid().map(|o| o.clone()) } parse_der_sequence_defined_g(|i: &[u8], _| { let (i, o) = map_res(parse_ber_oid, clone_oid)(i)?; let (i, s) = parse_directory_string(i)?; Ok((i, Attr { oid: o, val: s })) })(i) } fn parse_rdn(i: &[u8]) -> BerResult { parse_der_set_defined_g(|i: &[u8], _| { let (i, a) = parse_attr_type_and_value(i)?; Ok((i, Rdn { a })) })(i) } fn parse_name(i: &[u8]) -> BerResult { parse_der_sequence_defined_g(|i: &[u8], _| { let (i, l) = many0(complete(parse_rdn))(i)?; Ok((i, Name { l })) })(i) } let parsed = parse_name(&bytes).unwrap(); assert_eq!(parsed, (empty, expected)); // assert_eq!(parsed.1.l[0].a.val.as_str(), Ok("FR")); assert_eq!(parsed.1.l[1].a.val.as_str(), Ok("Some-State")); assert_eq!(parsed.1.l[2].a.val.as_str(), Ok("Internet Widgits Pty Ltd")); } #[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 = 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 = 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(BerError::InvalidTag))); } #[test_case(&hex!("a2 05 02 03 01 00 01"), Ok(0x10001) ; "tag ok")] #[test_case(&hex!("a2 80 02 03 01 00 01 00 00"), Ok(0x10001) ; "indefinite tag ok")] #[test_case(&hex!("a3 05 02 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] #[test_case(&hex!("22 05 02 03 01 00 01"), Err(BerError::InvalidClass) ; "invalid class")] #[test_case(&hex!("82 05 02 03 01 00 01"), Err(BerError::ConstructExpected) ; "construct expected")] fn tc_ber_tagged_explicit_g(i: &[u8], out: Result) { fn parse_int_explicit(i: &[u8]) -> BerResult { parse_ber_tagged_explicit_g(2, move |content, _hdr| { let (rem, obj) = parse_ber_integer(content)?; let value = obj.as_u32()?; Ok((rem, value)) })(i) } let res = parse_int_explicit(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test] fn tagged_explicit() { fn parse_int_explicit(i: &[u8]) -> BerResult { map_res( parse_der_tagged_explicit(2, parse_der_integer), |x: BerObject| x.as_tagged()?.2.as_u32(), )(i) } let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; // EXPLICIT tagged value parsing let (rem, val) = parse_int_explicit(bytes).expect("Could not parse explicit int"); assert!(rem.is_empty()); assert_eq!(val, 0x10001); // wrong tag assert_eq!( parse_der_tagged_explicit(3, parse_der_integer)(bytes as &[u8]), Err(Err::Error(BerError::InvalidTag)) ); // wrong type assert_eq!( parse_der_tagged_explicit(2, parse_der_bool)(bytes as &[u8]), Err(Err::Error(BerError::InvalidTag)) ); } #[test_case(&hex!("82 03 01 00 01"), Ok(0x10001) ; "tag ok")] #[test_case(&hex!("83 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_ber_tagged_implicit_g(i: &[u8], out: Result) { fn parse_int_implicit(i: &[u8]) -> BerResult { parse_ber_tagged_implicit_g(2, |content, hdr, depth| { let (rem, obj) = parse_ber_content(BerTag::Integer)(content, &hdr, depth)?; let value = obj.as_u32()?; Ok((rem, value)) })(i) } let res = parse_int_implicit(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test] fn tagged_implicit() { fn parse_int_implicit(i: &[u8]) -> BerResult { map_res( parse_der_tagged_implicit(2, parse_der_content(DerTag::Integer)), |x: BerObject| x.as_u32(), )(i) } let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01]; // IMPLICIT tagged value parsing let (rem, val) = parse_int_implicit(bytes).expect("could not parse implicit int"); assert!(rem.is_empty()); assert_eq!(val, 0x10001); // wrong tag assert_eq!( parse_der_tagged_implicit(3, parse_der_content(DerTag::Integer))(bytes as &[u8]), Err(Err::Error(BerError::InvalidTag)) ); } #[test] fn application() { #[derive(Debug, PartialEq)] struct SimpleStruct { a: u32, } fn parse_app01(i: &[u8]) -> BerResult { parse_der_container(|i, hdr| { if hdr.class != BerClass::Application { return Err(Err::Error(BerError::InvalidClass)); } if hdr.tag != BerTag(2) { return Err(Err::Error(BerError::InvalidTag)); } let (i, a) = map_res(parse_ber_integer, |x: BerObject| x.as_u32())(i)?; Ok((i, SimpleStruct { a })) })(i) } let bytes = &[0x62, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; let (rem, app) = parse_app01(bytes).expect("could not parse application"); assert!(rem.is_empty()); assert_eq!(app, SimpleStruct { a: 0x10001 }); } #[test] #[ignore = "not yet implemented"] fn ber_constructed_string() { // this encoding is equivalent to "04 05 01 AB 23 7F CA" let data = &hex!( " 24 80 04 02 01 ab 04 02 23 7f 04 01 ca 00 00" ); let _ = parse_ber_octetstring(data).expect("parsing failed"); } der-parser-6.0.1/tests/custom_error.rs000064400000000000000000000027320072674642500161630ustar 00000000000000//! This test file ensures the functions to parse containers like sequences and sets //! work correctly with custom errors. use der_parser::ber::{parse_ber_sequence_of_v, parse_ber_u32}; use der_parser::error::BerError; use nom::error::{ErrorKind, ParseError}; use nom::{Err, IResult}; #[derive(Debug)] pub enum MyError<'a> { Variant1, Variant2, BerError(BerError), NomError(&'a [u8], ErrorKind), } impl<'a> ParseError<&'a [u8]> for MyError<'a> { fn from_error_kind(input: &'a [u8], kind: ErrorKind) -> Self { MyError::NomError(input, kind) } fn append(_input: &'a [u8], _kind: ErrorKind, other: Self) -> Self { other } } impl<'a> From for MyError<'a> { fn from(e: BerError) -> Self { MyError::BerError(e) } } #[test] fn parse_sequence_of_v_custom_errors() { fn parse_element(i: &[u8]) -> IResult<&[u8], u32, MyError> { // incomplete must *NOT* be mapped, or parse_ber_sequence_of_v cannot detect end of // sequence match parse_ber_u32(i) { Ok(x) => Ok(x), Err(Err::Incomplete(e)) => Err(Err::Incomplete(e)), _ => Err(Err::Error(MyError::Variant1)), } } let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let (rem, v) = parse_ber_sequence_of_v(parse_element)(&bytes).expect("Could not parse SEQUENCE OF"); assert!(rem.is_empty()); assert_eq!(&v, &[65537, 65536]); } der-parser-6.0.1/tests/der_constructed.rs000064400000000000000000000161540072674642500166320ustar 00000000000000use der_parser::der::*; use der_parser::error::*; use hex_literal::hex; use nom::combinator::map; use nom::error::ErrorKind; use nom::sequence::tuple; use nom::{Err, Needed}; use test_case::test_case; #[test_case(&hex!("a2 05 02 03 01 00 01"), Ok(0x10001) ; "tag ok")] #[test_case(&hex!("a2 80 02 03 01 00 01 00 00"), Err(BerError::DerConstraintFailed) ; "indefinite tag ok")] #[test_case(&hex!("a3 05 02 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] #[test_case(&hex!("22 05 02 03 01 00 01"), Err(BerError::InvalidClass) ; "invalid class")] #[test_case(&hex!("82 05 02 03 01 00 01"), Err(BerError::ConstructExpected) ; "construct expected")] fn tc_der_tagged_explicit_g(i: &[u8], out: Result) { fn parse_int_explicit(i: &[u8]) -> BerResult { parse_der_tagged_explicit_g(2, move |content, _hdr| { let (rem, obj) = parse_der_integer(content)?; let value = obj.as_u32()?; Ok((rem, value)) })(i) } let res = parse_int_explicit(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("82 03 01 00 01"), Ok(0x10001) ; "tag ok")] #[test_case(&hex!("83 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_der_tagged_implicit_g(i: &[u8], out: Result) { fn parse_int_implicit(i: &[u8]) -> BerResult { parse_der_tagged_implicit_g(2, |content, hdr, depth| { let (rem, obj) = parse_der_content(DerTag::Integer)(content, &hdr, depth)?; let value = obj.as_u32()?; Ok((rem, value)) })(i) } let res = parse_int_implicit(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("30 00"), Ok(&[]) ; "empty seq")] #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "seq ok")] #[test_case(&hex!("30 07 02 03 01 00 01 02 03 01"), Err(BerError::NomError(ErrorKind::Eof)) ; "incomplete")] #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Err(BerError::InvalidTag) ; "invalid tag")] #[test_case(&hex!("30 80 02 03 01 00 01 00 00"), Err(BerError::DerConstraintFailed) ; "indefinite seq ok")] fn tc_der_seq_of(i: &[u8], out: Result<&[u32], BerError>) { fn parser(i: &[u8]) -> BerResult { parse_der_sequence_of(parse_der_integer)(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse sequence of"); assert!(rem.is_empty()); if let DerObjectContent::Sequence(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "seq ok")] #[test_case(&hex!("30 07 02 03 01 00 01 02 01"), Err(Err::Incomplete(Needed::new(1))) ; "incomplete")] #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Err(Err::Error(BerError::InvalidTag)) ; "invalid tag")] #[test_case(&hex!("30 80 02 03 01 00 01 00 00"), Err(Err::Error(BerError::DerConstraintFailed)) ; "indefinite seq ok")] fn tc_der_seq_defined(i: &[u8], out: Result<&[u32], Err>) { fn parser(i: &[u8]) -> BerResult { parse_der_sequence_defined(map( tuple((parse_der_integer, parse_der_integer)), |(a, b)| vec![a, b], ))(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse sequence"); assert!(rem.is_empty()); if let DerObjectContent::Sequence(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("31 00"), Ok(&[]) ; "empty set")] #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "set ok")] #[test_case(&hex!("31 07 02 03 01 00 01 02 03 01"), Err(BerError::NomError(ErrorKind::Eof)) ; "incomplete")] #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Err(BerError::InvalidTag) ; "invalid tag")] #[test_case(&hex!("31 80 02 03 01 00 01 00 00"), Err(BerError::DerConstraintFailed) ; "indefinite set ok")] fn tc_der_set_of(i: &[u8], out: Result<&[u32], BerError>) { fn parser(i: &[u8]) -> BerResult { parse_der_set_of(parse_der_integer)(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse set of"); assert!(rem.is_empty()); if let DerObjectContent::Set(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "set ok")] #[test_case(&hex!("31 07 02 03 01 00 01 02 01"), Err(Err::Incomplete(Needed::new(1))) ; "incomplete")] #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Err(Err::Error(BerError::InvalidTag)) ; "invalid tag")] #[test_case(&hex!("31 80 02 03 01 00 01 00 00"), Err(Err::Error(BerError::DerConstraintFailed)) ; "indefinite set ok")] fn tc_der_set_defined(i: &[u8], out: Result<&[u32], Err>) { fn parser(i: &[u8]) -> BerResult { parse_der_set_defined(map( tuple((parse_der_integer, parse_der_integer)), |(a, b)| vec![a, b], ))(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse set"); assert!(rem.is_empty()); if let DerObjectContent::Set(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } der-parser-6.0.1/tests/der_parser.rs000064400000000000000000000505130072674642500155660ustar 00000000000000#![allow(deprecated)] use der_parser::ber::*; use der_parser::der::*; use der_parser::error::*; use der_parser::oid::*; use der_parser::*; use hex_literal::hex; use nom::branch::alt; use nom::combinator::map; use nom::error::ErrorKind; use nom::sequence::tuple; use nom::Err; use pretty_assertions::assert_eq; use test_case::test_case; #[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 = &hex!("23 81 0c 03 03 00 0a 3b 03 05 04 5f 29 1c d0"); assert_eq!( parse_der_bitstring(bytes), Err(Err::Error(BerError::DerConstraintFailed)) ); } #[test] fn test_der_indefinite_length() { let bytes = &hex!("23 80 03 03 00 0a 3b 03 05 04 5f 29 1c d0 00 00"); 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, 113_549, 1, 1, 5]).unwrap(), )); 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("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_relative(&[8571, 3, 2]).unwrap(), )); 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( // the nom `tuple` combinator returns a tuple, so we have to map it // to a list map(tuple((parse_der_integer, parse_der_integer)), |(a, b)| { vec![a, b] }), )(i) } assert_eq!(parser(&bytes), Ok((empty, expected))); } #[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( // the nom `tuple` combinator returns a tuple, so we have to map it // to a list map(tuple((parse_der_integer, parse_der_integer)), |(a, b)| { vec![a, b] }), )(i) } assert_eq!(parser(&bytes), Ok((empty, expected))); } #[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(parse_der_integer)(i) } assert_eq!(parser(&bytes), Ok((empty, expected.clone()))); // fn parser2(i: &[u8]) -> BerResult { parse_ber_sequence_of(parse_der_integer)(i) } assert_eq!(parser2(&bytes), Ok((empty, expected))); } // extra bytes are simply ignored #[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(parse_der_integer)(i) } assert_eq!(parser(&bytes), Err(Err::Failure(BerError::InvalidTag))); // fn parser2(i: &[u8]) -> BerResult> { parse_ber_sequence_of_v(parse_der_integer)(i) } // eprintln!("trailing data"); assert_eq!(parser2(&bytes), Err(Err::Failure(BerError::InvalidTag))); let h = &hex!("30 06 02 03 01 00 01 02"); // eprintln!("remaining 02 at end (incomplete)"); assert_eq!( parser2(h), Err(Err::Error(BerError::NomError(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(parse_der_integer)(i) } assert_eq!(parser(&bytes), Ok((empty, expected))); } #[test] fn test_der_utctime() { 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( std::str::from_utf8(&bytes[2..(2 + 0x0d)]).unwrap(), )); 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( std::str::from_utf8(&bytes[2..]).unwrap(), )); 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 { header: BerObjectHeader::new(BerClass::ContextSpecific, 1, BerTag(0), 3) .with_raw_tag(Some(&[0xa0])), content: BerObjectContent::Unknown(BerClass::ContextSpecific, BerTag(0), &bytes[2..]), }; assert_eq!(parse_der(&bytes), Ok((empty, expected))); } #[test] fn test_der_explicit_optional() { let empty = &b""[..]; let bytes = [0xa0, 0x03, 0x02, 0x01, 0x02]; let header = BerObjectHeader::new(BerClass::ContextSpecific, 1, BerTag(0), 3) .with_raw_tag(Some(&[0xa0])); let expected = DerObject { header: header.clone(), content: BerObjectContent::Optional(Some(Box::new(BerObject::from_header_and_content( header, BerObjectContent::Tagged( BerClass::ContextSpecific, BerTag(0), Box::new(DerObject::from_int_slice(b"\x02")), ), )))), }; assert_eq!( parse_der_explicit_optional(&bytes, BerTag(0), parse_der_integer), Ok((empty, expected)) ); let expected2 = DerObject::from_obj(BerObjectContent::Optional(None)); assert_eq!( parse_der_explicit_optional(&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 expected = DerObject { header: BerObjectHeader::new(BerClass::ContextSpecific, 0, BerTag(1), 4) .with_raw_tag(Some(&[0x81])), content: BerObjectContent::IA5String("pass"), }; fn der_read_ia5string_content<'a>( i: &'a [u8], hdr: &BerObjectHeader, depth: usize, ) -> BerResult<'a, BerObjectContent<'a>> { ber_read_element_content_as(i, DerTag::Ia5String, hdr.len, hdr.is_constructed(), depth) } assert_eq!( parse_der_implicit(&bytes, BerTag(1), der_read_ia5string_content), Ok((empty, expected)) ); assert_eq!( parse_der_implicit(&bytes, BerTag(2), der_read_ia5string_content), Err(Err::Error(BerError::InvalidTag)) ); } #[test] fn test_der_implicit_long_tag() { let empty = &b""[..]; let bytes = [0x5f, 0x52, 0x04, 0x70, 0x61, 0x73, 0x73]; let expected = DerObject { header: BerObjectHeader::new(BerClass::Application, 0, BerTag(0x52), 4) .with_raw_tag(Some(&[0x5f, 0x52])), content: BerObjectContent::IA5String("pass"), }; fn der_read_ia5string_content<'a>( i: &'a [u8], hdr: &BerObjectHeader, depth: usize, ) -> BerResult<'a, BerObjectContent<'a>> { ber_read_element_content_as(i, DerTag::Ia5String, hdr.len, hdr.is_constructed(), depth) } assert_eq!( parse_der_implicit(&bytes, BerTag(0x52), der_read_ia5string_content), Ok((empty, expected)) ); assert_eq!( parse_der_implicit(&bytes, BerTag(2), der_read_ia5string_content), Err(Err::Error(BerError::InvalidTag)) ); } #[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::Optional(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::Optional(None)), DerObject::from_int_slice(b"\x01\x00\x01"), ]); fn parse_optional_enum(i: &[u8]) -> DerResult { parse_ber_optional(parse_der_enum)(i) } fn parser(i: &[u8]) -> DerResult { parse_der_sequence_defined( // the nom `tuple` combinator returns a tuple, so we have to map it // to a list map(tuple((parse_optional_enum, parse_der_integer)), |(a, b)| { vec![a, b] }), )(i) } assert_eq!(parser(&bytes1), Ok((empty, expected1))); assert_eq!(parser(&bytes2), Ok((empty, expected2))); } #[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]).unwrap())), // countryName DerObject::from_obj(BerObjectContent::PrintableString("FR")), ])]), DerObject::from_set(vec![DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::OID(Oid::from(&[2, 5, 4, 8]).unwrap())), // stateOrProvinceName DerObject::from_obj(BerObjectContent::UTF8String("Some-State")), ])]), DerObject::from_set(vec![DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::OID(Oid::from(&[2, 5, 4, 10]).unwrap())), // organizationName DerObject::from_obj(BerObjectContent::UTF8String("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]).unwrap())), // countryName DerObject::from_obj(BerObjectContent::PrintableString("FR")), ])]), DerObject::from_set(vec![DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::OID(Oid::from(&[2, 5, 4, 8]).unwrap())), // stateOrProvinceName DerObject::from_obj(BerObjectContent::UTF8String("Some-State")), ])]), DerObject::from_set(vec![DerObject::from_seq(vec![ DerObject::from_obj(BerObjectContent::OID(Oid::from(&[2, 5, 4, 10]).unwrap())), // organizationName DerObject::from_obj(BerObjectContent::UTF8String("Internet Widgits Pty Ltd")), ])]), ]); #[inline] fn parse_directory_string(i: &[u8]) -> DerResult { alt(( parse_der_utf8string, parse_der_printablestring, parse_der_ia5string, ))(i) } #[inline] fn parse_attr_type_and_value(i: &[u8]) -> DerResult { parse_der_sequence_defined( // the nom `tuple` combinator returns a tuple, so we have to map it // to a list map(tuple((parse_der_oid, parse_directory_string)), |(a, b)| { vec![a, b] }), )(i) } #[inline] fn parse_rdn(i: &[u8]) -> DerResult { parse_der_set_of(parse_attr_type_and_value)(i) } #[inline] fn parse_name(i: &[u8]) -> DerResult { parse_der_sequence_of(parse_rdn)(i) } assert_eq!(parse_name(&bytes), Ok((empty, expected))); } #[test_case(&hex!("02 01 01"), Ok(1) ; "u32-1")] #[test_case(&hex!("02 01 ff"), Err(BerError::IntegerNegative) ; "negative integer")] #[test_case(&hex!("02 02 00 ff"), Ok(255) ; "u32-255")] #[test_case(&hex!("02 02 01 23"), Ok(0x123) ; "u32-0x123")] #[test_case(&hex!("02 04 01 23 45 67"), Ok(0x0123_4567) ; "u32-long-ok")] #[test_case(&hex!("02 04 ff ff ff ff"), Err(BerError::IntegerNegative) ; "u32-long2-neg")] #[test_case(&hex!("02 06 00 00 01 23 45 67"), Err(BerError::DerConstraintFailed) ; "u32-long-leading-zeros")] #[test_case(&hex!("02 05 01 23 45 67 01"), Err(BerError::IntegerTooLarge) ; "u32 too large")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Err(BerError::IntegerTooLarge) ; "u32 too large 2")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_der_u32(i: &[u8], out: Result) { let res = parse_der_u32(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("02 01 01"), Ok(1) ; "i32-1")] #[test_case(&hex!("02 01 ff"), Ok(-1) ; "i32-neg1")] #[test_case(&hex!("02 01 80"), Ok(-128) ; "i32-neg128")] #[test_case(&hex!("02 02 ff 7f"), Ok(-129) ; "i32-neg129")] #[test_case(&hex!("02 02 00 ff"), Ok(255) ; "i32-255")] fn tc_der_i32(i: &[u8], out: Result) { let res = parse_der_i32(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("02 01 01"), Ok(1) ; "u64-1")] #[test_case(&hex!("02 02 00 ff"), Ok(255) ; "u64-255")] #[test_case(&hex!("02 02 01 23"), Ok(0x123) ; "u64-0x123")] #[test_case(&hex!("02 08 01 23 45 67 01 23 45 67"), Ok(0x0123_4567_0123_4567) ; "u64-long-ok")] #[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(0xffff_ffff_ffff_ffff) ; "u64-long2-ok")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Err(BerError::IntegerTooLarge) ; "u64 too large")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_der_u64(i: &[u8], out: Result) { let res = parse_der_u64(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("02 01 01"), Ok(&[1]) ; "slice 1")] #[test_case(&hex!("02 01 ff"), Ok(&[255]) ; "slice 2")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(&hex!("01 23 45 67 01 23 45 67 ab")) ; "slice 3")] #[test_case(&hex!("22 80 02 01 01 00 00"), Err(BerError::DerConstraintFailed) ; "constructed slice")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::InvalidTag) ; "invalid tag")] fn tc_der_slice(i: &[u8], out: Result<&[u8], BerError>) { let res = parse_der_slice(i, 2); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } der-parser-6.0.1/tests/fuzz01.rs000064400000000000000000000004150072674642500145730ustar 00000000000000#[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-6.0.1/tests/fuzz02.rs000064400000000000000000000014110072674642500145710ustar 00000000000000#[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-6.0.1/tests/oid.rs000064400000000000000000000013210072674642500142040ustar 00000000000000//! Test the API provided to compare OIDs extern crate alloc; use der_parser::oid; use der_parser::oid::Oid; const OID_RSA_ENCRYPTION: &[u8] = &oid!(raw 1.2.840.113549.1.1.1); const OID_EC_PUBLIC_KEY: &[u8] = &oid!(raw 1.2.840.10045.2.1); #[allow(clippy::match_like_matches_macro)] fn compare_oid(oid: &Oid) -> bool { match oid.bytes() { OID_RSA_ENCRYPTION => true, OID_EC_PUBLIC_KEY => true, _ => false, } } #[rustfmt::skip::macros(oid)] #[test] fn test_compare_oid() { let oid = Oid::from(&[1, 2, 840, 113_549, 1, 1, 1]).unwrap(); assert_eq!(oid, oid!(1.2.840.113549.1.1.1)); let oid = Oid::from(&[1, 2, 840, 113_549, 1, 1, 1]).unwrap(); assert!(compare_oid(&oid)); } der-parser-6.0.1/tests/primitive.rs000064400000000000000000000150550072674642500154520ustar 00000000000000extern crate alloc; use der_parser::ber::*; use der_parser::der::*; use der_parser::error::*; use der_parser::oid::Oid; use hex_literal::hex; use nom::*; #[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.into(), false, MAX_RECURSION), Ok((empty, BerObjectContent::Boolean(true))) ); assert_eq!( ber_read_element_content_as(&[0x00], BerTag::Boolean, 0x01.into(), false, MAX_RECURSION), 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]).unwrap() )) )) ); // Dubuisson 433 assert_eq!( parse_der(&[0x0d, 0x05, 129, 122, 1, 16, 9]), Ok(( empty, BerObject::from_obj(BerObjectContent::RelativeOID( Oid::from_relative(&[250, 1, 16, 9]).unwrap() )) )) ); } #[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_relative(&[8571, 3, 2]).unwrap() )) )) ); } #[rustfmt::skip::macros(oid)] #[test] fn test_oid_iter_length_check() { use der_parser::oid; use std::borrow::Cow; // empty assert!(Oid::new(Cow::Borrowed(&[])).iter().is_some()); assert!(Oid::new_relative(Cow::Borrowed(&[])).iter().is_some()); // ok assert!(oid!(0).iter().is_some()); assert!(oid!(1.2).iter().is_some()); assert!(oid!(1.2.3456.23.54).iter().is_some()); // too long assert!(oid!(1.2.18445618199572250625).iter().is_none()); assert!(oid!(rel 18445618199572250625).iter().is_none()); } #[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( BerClass::Universal, BerTag(0x1d), &bytes[2..] )) ); let res = parse_der(&bytes).expect("parsing failed"); assert!(res.0.is_empty()); assert_eq!( res.1, BerObject::from_obj(BerObjectContent::Unknown( BerClass::Universal, 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 { header: BerObjectHeader::new(BerClass::ContextSpecific, 0, BerTag(0), 1) .with_raw_tag(Some(&[0x80])), content: BerObjectContent::Unknown(BerClass::ContextSpecific, 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 { header: BerObjectHeader::new(BerClass::ContextSpecific, 0, BerTag(0x22), 1) .with_raw_tag(Some(&[0x9f, 0x22])), content: BerObjectContent::Unknown( BerClass::ContextSpecific, 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 { header: BerObjectHeader::new(BerClass::ContextSpecific, 0, BerTag(0x1122), 1) .with_raw_tag(Some(&[0x9f, 0xa2, 0x22])), content: BerObjectContent::Unknown( BerClass::ContextSpecific, 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::new(1))); let res = parse_der(&bytes).err().expect("expected error"); assert_eq!(res, Err::Incomplete(Needed::new(1))); let bytes = hex!("02"); let res = parse_ber(&bytes).err().expect("expected error"); assert_eq!(res, Err::Incomplete(Needed::new(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::new(5))); let bytes = hex!("02 85 ff"); let res = parse_ber(&bytes).err().expect("expected error"); assert_eq!(res, Err::Incomplete(Needed::new(4))); } #[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).expect_err("parsing should have returned error"); // get error match res { Err::Error(e) => { assert_eq!(e, BerError::InvalidLength); } _ => panic!("not the expected nom error kind {:?}", res), } let bytes = hex!("02 02 00"); let res = parse_der(&bytes).err().expect("expected error"); assert_eq!(res, Err::Incomplete(Needed::new(2))); } #[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); }