diff options
Diffstat (limited to 'rust/vendor/der-parser-6.0.1')
31 files changed, 9524 insertions, 0 deletions
diff --git a/rust/vendor/der-parser-6.0.1/.cargo-checksum.json b/rust/vendor/der-parser-6.0.1/.cargo-checksum.json new file mode 100644 index 0000000..9c3841d --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"3525e594d2b397d7c1c9921871fe494c27d003b7b5c84459c1d881dbd2afe2f3","Cargo.toml":"f226a20732969e80e305eefd56c45157434b1626af9f1118ce14e0d1f531d0e9","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a5c61b93b6ee1d104af9920cf020ff3c7efe818e31fe562c72261847a728f513","README.md":"f11dfcb7f73a917e02e12398c416142ae1d3f6fdf94d9b4c0585a31e5122a5e8","UPGRADING.md":"0225b97be90b6a5323ce1697843efb27773c6e15edfae05935dd0dafcc0d3d88","src/ber/ber.rs":"6de5e67a1e2ab1e593f793c9fd8b1a6991ef728baa009867431d77d788996828","src/ber/integer.rs":"509cc8017ac90b0f0231be2e09dae80674460653521bbdda65622e04405ac010","src/ber/mod.rs":"6deb7bf5a82931816c749b4542232d8c00737d1afd303662784bf06f5b2b5dab","src/ber/multi.rs":"42c93d96215c38704918b31f92d30725f870dfd3d71c5bc036981c5a23cd462f","src/ber/parser.rs":"dc59e670105e58ef7254f34a42c13af98c766d66238f75b715240721a4ba77d7","src/ber/print.rs":"72eef562f72a5476610ba7c5bd79a9b468b5fc73fc19ea99e3cd00e21c30cd9a","src/ber/serialize.rs":"bb516e8e73a077b212ad2b4e16ab739ae90c8518bef5d15de9708abe1759387a","src/ber/tagged.rs":"380e74d9a5c347d453cc539f3cc4eca5125a42c86d42164452a37ac49563f162","src/der/mod.rs":"378cf1382be9bdbf824682985ebdd861298d9e38f2639efcc2d0f832e8f9a7af","src/der/multi.rs":"ff6bdba861f5eb1d186084b6b31a07224cc1f013dca58b8b7c586c50f86ea5bb","src/der/parser.rs":"8516566c2ca05c5f469924ec803658fa33624c4f783faa489408acdf6ce63dfa","src/der/tagged.rs":"2c25b88971e2b0d0b4c0d1db9d2cb9e149a347682f11fdea2692932c88da22e1","src/error.rs":"328516dbb0a7df2ed088f5ee2260636ac49345d31fc5b465d830606198476225","src/lib.rs":"4fa3dc08646c540db025f14e1d0649ce255fe56f976dd85248696f44e6dd1ae6","src/oid.rs":"e567aa4215b78aac9b0e8ab19e0342bdebae269d484d0f7c3d2104d224fbd5f8","tests/ber_parser.rs":"998cff869c91615e2f303498983669937e4c0545f16c7a69bb16a7050c3a0d8b","tests/constructed.rs":"0414c8cf65eb7b6340d87ce86c6d64c1a5b127598b4c67464a2900bd05f17953","tests/custom_error.rs":"8f92380a8b71df6033e15806c162bc502c6beea086ebed7c3106c76da71ec95b","tests/der_constructed.rs":"08e01714292e789260fed3bed2c2444e6dd38c5182401a55ed27c929b216a9a4","tests/der_parser.rs":"0c67e70eeb160725529e28f6e0771a2dabdc4c68cc830bd5f3ee116da80a702a","tests/fuzz01.rs":"b1929c8183fdba11ea73618ef48b23d4d3d39df79ac70e1c46787c3dcfcf9ec9","tests/fuzz02.rs":"b1e4ae20a40bb74887b7d62e9bbec5919f7c963b3f699e01888755e3637877a5","tests/oid.rs":"925d7317d9947a500128e5c707dd73fd2da8e29c25b48ea9174dfa719a8fe818","tests/primitive.rs":"124a252e140b08a1fb7fd1fe6d30181c9ebdf6aa730878af9da21a7f2066c9ce"},"package":"4cddf120f700b411b2b02ebeb7f04dc0b7c8835909a6c2f52bf72ed0dd3433b2"}
\ No newline at end of file diff --git a/rust/vendor/der-parser-6.0.1/CHANGELOG.md b/rust/vendor/der-parser-6.0.1/CHANGELOG.md new file mode 100644 index 0000000..cba3b02 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/CHANGELOG.md @@ -0,0 +1,319 @@ +# 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. diff --git a/rust/vendor/der-parser-6.0.1/Cargo.toml b/rust/vendor/der-parser-6.0.1/Cargo.toml new file mode 100644 index 0000000..c87704d --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/Cargo.toml @@ -0,0 +1,65 @@ +# 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 <chifflier@wzdftpd.net>"] +include = ["LICENSE-*", "CHANGELOG.md", "README.md", "UPGRADING.md", ".gitignore", "Cargo.toml", "bench/*.rs", "src/*.rs", "src/ber/*.rs", "src/der/*.rs", "tests/*.rs", "der-oid-macro/Cargo.toml", "der-oid-macro/src/*.rs"] +description = "Parser/encoder for ASN.1 BER/DER data" +homepage = "https://github.com/rusticata/der-parser" +readme = "README.md" +keywords = ["BER", "DER", "ASN1", "parser", "nom"] +categories = ["parser-implementations"] +license = "MIT/Apache-2.0" +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 = [] diff --git a/rust/vendor/der-parser-6.0.1/LICENSE-APACHE b/rust/vendor/der-parser-6.0.1/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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. diff --git a/rust/vendor/der-parser-6.0.1/LICENSE-MIT b/rust/vendor/der-parser-6.0.1/LICENSE-MIT new file mode 100644 index 0000000..290e7b9 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (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. diff --git a/rust/vendor/der-parser-6.0.1/README.md b/rust/vendor/der-parser-6.0.1/README.md new file mode 100644 index 0000000..42f3ee4 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/README.md @@ -0,0 +1,244 @@ +<!-- cargo-sync-readme start --> + +[![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)." +<!-- cargo-sync-readme end --> + +## 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. diff --git a/rust/vendor/der-parser-6.0.1/UPGRADING.md b/rust/vendor/der-parser-6.0.1/UPGRADING.md new file mode 100644 index 0000000..e06b13f --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/UPGRADING.md @@ -0,0 +1,101 @@ +## 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<MyStruct> { +``` + +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). diff --git a/rust/vendor/der-parser-6.0.1/src/ber/ber.rs b/rust/vendor/der-parser-6.0.1/src/ber/ber.rs new file mode 100644 index 0000000..47d5069 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/ber/ber.rs @@ -0,0 +1,1174 @@ +use 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<BerObject<'a>>), + /// SET: list of objects + Set(Vec<BerObject<'a>>), + + /// 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<Box<BerObject<'a>>>), + /// Tagged object (EXPLICIT): class, tag and content of inner object + Tagged(BerClass, BerTag, Box<BerObject<'a>>), + /// Private + Private(BerObjectHeader<'a>, &'a [u8]), + + /// Unknown object: object tag (copied from header), and raw content + Unknown(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<u32> 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<usize, BerError> { + match self { + BerSize::Definite(sz) => Ok(*sz), + BerSize::Indefinite => Err(BerError::IndefiniteLengthUnexpected), + } + } +} + +impl From<usize> for BerSize { + fn from(v: usize) -> Self { + BerSize::Definite(v) + } +} + +impl TryFrom<u64> for BerSize { + type Error = BerSizeError; + + fn try_from(value: u64) -> Result<Self, Self::Error> { + let v = usize::try_from(value).or(Err(BerSizeError(())))?; + Ok(BerSize::Definite(v)) + } +} + +impl TryFrom<BerSize> for usize { + type Error = BerSizeError; + + #[inline] + fn try_from(value: BerSize) -> Result<Self, Self::Error> { + match value { + BerSize::Definite(sz) => Ok(sz), + BerSize::Indefinite => Err(BerSizeError(())), + } + } +} + +impl TryFrom<u8> for BerClass { + type Error = BerClassFromIntError; + + #[inline] + fn try_from(value: u8) -> Result<Self, Self::Error> { + 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<Len: Into<BerSize>>(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 { + 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 { + 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<i64, BerError> { + self.content.as_i64() + } + + /// Attempt to read a signed integer value from DER object. + /// + /// This can fail if the object is not an integer, or if it is too large. + /// + /// # Examples + /// + /// ```rust + /// # use der_parser::ber::BerObject; + /// let der_int = BerObject::from_int_slice(b"\x80"); + /// assert_eq!( + /// der_int.as_i32(), + /// Ok(-128) + /// ); + /// ``` + pub fn as_i32(&self) -> Result<i32, BerError> { + self.content.as_i32() + } + + /// Attempt to read integer value from DER object. + /// + /// This can fail if the object is not an unsigned integer, or if it is too large. + /// + /// # Examples + /// + /// ```rust + /// # use der_parser::ber::BerObject; + /// let der_int = BerObject::from_int_slice(b"\x01\x00\x01"); + /// assert_eq!( + /// der_int.as_u64(), + /// Ok(0x10001) + /// ); + /// ``` + pub fn as_u64(&self) -> Result<u64, BerError> { + 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<u32, BerError> { + 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<bool, BerError> { + 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<Oid<'a>, 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<Option<&'_ BerObject<'a>>, 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<BitStringObject<'a>, 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<Msb0, u8>, 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<BerObject<'a>>, 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<BerObject<'a>>, 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<Oid<'a>> 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<BerObjectContent<'a>> 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<BerObjectHeader<'a>> 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<i64, BerError> { + if let BerObjectContent::Integer(bytes) = self { + let result = if is_highest_bit_set(bytes) { + <i64>::from_be_bytes(decode_array_int8(bytes)?) + } else { + <u64>::from_be_bytes(decode_array_uint8(bytes)?) as i64 + }; + Ok(result) + } else { + Err(BerError::InvalidTag) + } + } + + /// Attempt to read a signed integer value from this object. + /// + /// This can fail if the object is not an integer, or if it is too large. + /// + /// # Examples + /// + /// ```rust + /// # use der_parser::ber::BerObject; + /// let der_int = BerObject::from_int_slice(b"\x80"); + /// assert_eq!( + /// der_int.as_i32(), + /// Ok(-128) + /// ); + /// ``` + pub fn as_i32(&self) -> Result<i32, BerError> { + if let BerObjectContent::Integer(bytes) = self { + let result = if is_highest_bit_set(bytes) { + <i32>::from_be_bytes(decode_array_int4(bytes)?) + } else { + <u32>::from_be_bytes(decode_array_uint4(bytes)?) as i32 + }; + Ok(result) + } else { + Err(BerError::InvalidTag) + } + } + + /// Attempt to read integer value from this object. + /// + /// This can fail if the object is not an unsigned integer, or if it is too large. + /// + /// # Examples + /// + /// ```rust + /// # use der_parser::ber::BerObject; + /// let der_int = BerObject::from_int_slice(b"\x01\x00\x01"); + /// assert_eq!( + /// der_int.as_u64(), + /// Ok(0x10001) + /// ); + /// ``` + pub fn as_u64(&self) -> Result<u64, BerError> { + match self { + BerObjectContent::Integer(i) => { + let result = <u64>::from_be_bytes(decode_array_uint8(i)?); + Ok(result) + } + BerObjectContent::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<u32, BerError> { + match self { + BerObjectContent::Integer(i) => { + let result = <u32>::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<bool, BerError> { + 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<Oid<'a>, BerError> { + self.as_oid().map(|o| o.clone()) + } + + pub fn as_optional(&'a self) -> Result<Option<&'_ BerObject<'a>>, 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<BitStringObject<'a>, 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<Msb0, u8>, BerError> { + self.as_slice() + .and_then(|s| BitSlice::<Msb0, _>::from_slice(s).map_err(|_| BerError::BerValueError)) + } + + pub fn as_sequence(&self) -> Result<&Vec<BerObject<'a>>, BerError> { + match *self { + BerObjectContent::Sequence(ref s) => Ok(s), + _ => Err(BerError::BerTypeError), + } + } + + pub fn as_set(&self) -> Result<&Vec<BerObject<'a>>, 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<BigInt, BerError> { + 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<BigUint, BerError> { + 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<BerObject<'a>> { + // 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<BerObjectContent<'a>> { +// 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<usize> 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<Msb0, u8>> { + BitSlice::<Msb0, _>::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<T: AsRef<[u8]>>(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)); + } +} diff --git a/rust/vendor/der-parser-6.0.1/src/ber/integer.rs b/rust/vendor/der-parser-6.0.1/src/ber/integer.rs new file mode 100644 index 0000000..1c05bec --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/ber/integer.rs @@ -0,0 +1,130 @@ +use crate::error::*; + +/// Decode an unsigned integer into a big endian byte slice with all leading +/// zeroes removed. +/// +/// Returns a byte array of the requested size containing a big endian integer. +fn remove_zeroes(bytes: &[u8]) -> Result<&[u8], BerError> { + // skip leading 0s + match bytes { + // [] => Err(BerError::DerConstraintFailed), + [0] => Ok(bytes), + // [0, byte, ..] if *byte < 0x80 => Err(BerError::DerConstraintFailed), + // [0, rest @ ..] => Ok(&rest), + [0, rest @ ..] => remove_zeroes(rest), + // [byte, ..] if *byte >= 0x80 => Err(BerError::IntegerTooLarge), + _ => Ok(bytes), + } +} + +// XXX const generics require rustc >= 1.51 +// /// Decode an unsigned integer into a byte array of the requested size +// /// containing a big endian integer. +// pub(crate) fn decode_array_uint<const N: usize>(bytes: &[u8]) -> Result<[u8; N], BerError> { +// // Check if MSB is set *before* leading zeroes +// if is_highest_bit_set(bytes) { +// return Err(BerError::IntegerNegative); +// } +// let input = remove_zeroes(bytes)?; + +// if input.len() > N { +// return Err(BerError::IntegerTooLarge); +// } + +// // Input has leading zeroes removed, so we need to add them back +// let mut output = [0u8; N]; +// assert!(input.len() <= N); +// output[N.saturating_sub(input.len())..].copy_from_slice(input); +// Ok(output) +// } + +pub(crate) fn decode_array_uint8(bytes: &[u8]) -> Result<[u8; 8], BerError> { + // Check if MSB is set *before* leading zeroes + if is_highest_bit_set(bytes) { + return Err(BerError::IntegerNegative); + } + let input = remove_zeroes(bytes)?; + + if input.len() > 8 { + return Err(BerError::IntegerTooLarge); + } + + // Input has leading zeroes removed, so we need to add them back + let mut output = [0u8; 8]; + assert!(input.len() <= 8); + output[8_usize.saturating_sub(input.len())..].copy_from_slice(input); + Ok(output) +} + +pub(crate) fn decode_array_uint4(bytes: &[u8]) -> Result<[u8; 4], BerError> { + // Check if MSB is set *before* leading zeroes + if is_highest_bit_set(bytes) { + return Err(BerError::IntegerNegative); + } + let input = remove_zeroes(bytes)?; + + if input.len() > 4 { + return Err(BerError::IntegerTooLarge); + } + + // Input has leading zeroes removed, so we need to add them back + let mut output = [0u8; 4]; + assert!(input.len() <= 4); + output[4_usize.saturating_sub(input.len())..].copy_from_slice(input); + Ok(output) +} + +// XXX const generics require rustc >= 1.51 +// /// Decode an unsigned integer of the specified size. +// /// +// /// Returns a byte array of the requested size containing a big endian integer. +// pub(crate) fn decode_array_int<const N: usize>(input: &[u8]) -> Result<[u8; N], BerError> { +// let input = remove_zeroes(input)?; + +// if input.len() > N { +// return Err(BerError::IntegerTooLarge); +// } + +// // any.tag().assert_eq(Tag::Integer)?; +// let mut output = [0xFFu8; N]; +// let offset = N.saturating_sub(input.len()); +// output[offset..].copy_from_slice(input); +// Ok(output) +// } + +pub(crate) fn decode_array_int8(input: &[u8]) -> Result<[u8; 8], BerError> { + let input = remove_zeroes(input)?; + + if input.len() > 8 { + return Err(BerError::IntegerTooLarge); + } + + // any.tag().assert_eq(Tag::Integer)?; + let mut output = [0xFFu8; 8]; + let offset = 8_usize.saturating_sub(input.len()); + output[offset..].copy_from_slice(input); + Ok(output) +} + +pub(crate) fn decode_array_int4(input: &[u8]) -> Result<[u8; 4], BerError> { + let input = remove_zeroes(input)?; + + if input.len() > 4 { + return Err(BerError::IntegerTooLarge); + } + + // any.tag().assert_eq(Tag::Integer)?; + let mut output = [0xFFu8; 4]; + let offset = 4_usize.saturating_sub(input.len()); + output[offset..].copy_from_slice(input); + Ok(output) +} + +/// Is the highest bit of the first byte in the slice 1? (if present) +#[inline] +pub(crate) fn is_highest_bit_set(bytes: &[u8]) -> bool { + bytes + .get(0) + .map(|byte| byte & 0b10000000 != 0) + .unwrap_or(false) +} diff --git a/rust/vendor/der-parser-6.0.1/src/ber/mod.rs b/rust/vendor/der-parser-6.0.1/src/ber/mod.rs new file mode 100644 index 0000000..c674d93 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/ber/mod.rs @@ -0,0 +1,69 @@ +//! 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}; diff --git a/rust/vendor/der-parser-6.0.1/src/ber/multi.rs b/rust/vendor/der-parser-6.0.1/src/ber/multi.rs new file mode 100644 index 0000000..dc030d2 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/ber/multi.rs @@ -0,0 +1,533 @@ +use 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<BerObject> { +/// 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<Vec<BerObject>> { +/// 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<T>, E> +where + F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, + E: ParseError<&'a [u8]> + From<BerError>, +{ + 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<Vec<BerObject>>, +{ + 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<MyObject> { +/// 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<BerError>, +{ + 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<BerObject> { +/// 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<Vec<BerObject>> { +/// 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<T>, E> +where + F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, + E: ParseError<&'a [u8]> + From<BerError>, +{ + 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<Vec<BerObject>>, +{ + 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<MyObject> { +/// 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<BerError>, +{ + 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<MyObject> { +/// 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<BerError>, +{ + 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)) + } +} diff --git a/rust/vendor/der-parser-6.0.1/src/ber/parser.rs b/rust/vendor/der-parser-6.0.1/src/ber/parser.rs new file mode 100644 index 0000000..24cbfc7 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/ber/parser.rs @@ -0,0 +1,1313 @@ +use 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<u64, BerError> { + 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<u64, BerError> { + 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<BerObjectHeader> { + 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<BerObjectContent> { + Ok((i, BerObjectContent::EndOfContent)) +} + +#[inline] +fn ber_read_content_bool(i: &[u8]) -> BerResult<BerObjectContent> { + 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<BerObjectContent> { + map(take(len), BerObjectContent::Integer)(i) +} + +#[inline] +fn ber_read_content_bitstring(i: &[u8], len: usize) -> BerResult<BerObjectContent> { + 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<BerObjectContent> { + map(take(len), BerObjectContent::OctetString)(i) +} + +#[allow(clippy::unnecessary_wraps)] +#[inline] +fn ber_read_content_null(i: &[u8]) -> BerResult<BerObjectContent> { + Ok((i, BerObjectContent::Null)) +} + +fn ber_read_content_oid(i: &[u8], len: usize) -> BerResult<BerObjectContent> { + 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<BerObjectContent> { + 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<BerObjectContent> { + 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<BerObjectContent> { + 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<BerObjectContent> { + 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<BerObjectContent> { + 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<BerObjectContent<'a>> { + // 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<BerObjectContent<'a>> { + // 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<BerObjectContent<'a>> { + // 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<BerObjectContent> { + map(take(len), BerObjectContent::T61String)(i) +} + +#[inline] +fn ber_read_content_videotexstring(i: &[u8], len: usize) -> BerResult<BerObjectContent> { + map(take(len), BerObjectContent::VideotexString)(i) +} + +fn ber_read_content_ia5string<'a>(i: &'a [u8], len: usize) -> BerResult<BerObjectContent<'a>> { + 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<BerObjectContent<'a>> { + // 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<BerObjectContent<'a>> { + // 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<BerObjectContent> { + map(take(len), BerObjectContent::ObjectDescriptor)(i) +} + +#[inline] +fn ber_read_content_graphicstring(i: &[u8], len: usize) -> BerResult<BerObjectContent> { + map(take(len), BerObjectContent::GraphicString)(i) +} + +#[inline] +fn ber_read_content_generalstring(i: &[u8], len: usize) -> BerResult<BerObjectContent> { + map(take(len), BerObjectContent::GeneralString)(i) +} + +#[inline] +fn ber_read_content_bmpstring(i: &[u8], len: usize) -> BerResult<BerObjectContent> { + map(take(len), BerObjectContent::BmpString)(i) +} + +#[inline] +fn ber_read_content_universalstring(i: &[u8], len: usize) -> BerResult<BerObjectContent> { + 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<BerObjectContent> { + 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<Tag: Into<BerTag>>(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<F>(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<BerObject> { +/// 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<BerTag>, +{ + 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<BerObject>` 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<i32> { + let (rem, ber) = parse_ber_integer(i)?; + let int = ber.as_i32().map_err(nom::Err::Error)?; + Ok((rem, int)) +} + +/// Parse BER object and try to decode it as a 64-bits signed integer +/// +/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target +/// integer type. +#[inline] +pub fn parse_ber_i64(i: &[u8]) -> BerResult<i64> { + let (rem, ber) = parse_ber_integer(i)?; + let int = ber.as_i64().map_err(nom::Err::Error)?; + Ok((rem, int)) +} + +/// Parse BER object and try to decode it as a 32-bits unsigned integer +/// +/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target +/// integer type. +#[inline] +pub fn parse_ber_u32(i: &[u8]) -> BerResult<u32> { + let (rem, ber) = parse_ber_integer(i)?; + let int = ber.as_u32().map_err(nom::Err::Error)?; + Ok((rem, int)) +} + +/// Parse BER 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<u64> { + 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<Tag: Into<BerTag>>(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)); +} diff --git a/rust/vendor/der-parser-6.0.1/src/ber/print.rs b/rust/vendor/der-parser-6.0.1/src/ber/print.rs new file mode 100644 index 0000000..e80eb5e --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/ber/print.rs @@ -0,0 +1,173 @@ +use 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<PrettyPrinterFlag>, +} + +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, "{}({:?}) <error decoding utf8 string: {:?}>", ty, s, e), + } + } + fn print_utf16_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result { + let chars: Vec<u16> = 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, "{}({:?}) <error decoding utf16 string: {:?}>", ty, s, e), + } + } + fn print_utf32_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result { + let chars: Option<Vec<char>> = s + .chunks_exact(4) + .map(|a| 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, "{}({:?}) <error decoding utf32 string>", 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); + } +} diff --git a/rust/vendor/der-parser-6.0.1/src/ber/serialize.rs b/rust/vendor/der-parser-6.0.1/src/ber/serialize.rs new file mode 100644 index 0000000..8c82e29 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/ber/serialize.rs @@ -0,0 +1,413 @@ +#![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<BerSize>>(len: Len) -> impl SerializeFn<W> + '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<u8> = 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<W> + '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<W> + '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<W> + '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<W> + '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<W> + '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<W> + '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<u8> = 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<W> + '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<W> + '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<Vec<u8>, 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<BerObject> { + 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); + } +} diff --git a/rust/vendor/der-parser-6.0.1/src/ber/tagged.rs b/rust/vendor/der-parser-6.0.1/src/ber/tagged.rs new file mode 100644 index 0000000..84a9208 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/ber/tagged.rs @@ -0,0 +1,262 @@ +use 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<u32> { +/// 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<BerObject>, + Tag: Into<BerTag>, +{ + 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<u32> { +/// 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<BerError>, + Tag: Into<BerTag>, +{ + 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<BerObject> { +/// 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<u32> { +/// 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<BerTag>, +{ + 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<BerObjectContent> { +/// 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<u32> { +/// 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<BerError>, + Tag: Into<BerTag>, +{ + 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 + }) +} diff --git a/rust/vendor/der-parser-6.0.1/src/der/mod.rs b/rust/vendor/der-parser-6.0.1/src/der/mod.rs new file mode 100644 index 0000000..bad3f23 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/der/mod.rs @@ -0,0 +1,88 @@ +//! 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>; diff --git a/rust/vendor/der-parser-6.0.1/src/der/multi.rs b/rust/vendor/der-parser-6.0.1/src/der/multi.rs new file mode 100644 index 0000000..f4f22fa --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/der/multi.rs @@ -0,0 +1,535 @@ +use 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<DerObject> { +/// 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<Vec<DerObject>> { +/// 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<T>, E> +where + F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, + E: ParseError<&'a [u8]> + From<BerError>, +{ + 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<Vec<DerObject>>, +{ + 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<MyObject> { +/// 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<BerError>, +{ + 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<DerObject> { +/// 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<Vec<DerObject>> { +/// 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<T>, E> +where + F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, + E: ParseError<&'a [u8]> + From<BerError>, +{ + 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<Vec<DerObject>>, +{ + 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<MyObject> { +/// 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<BerError>, +{ + 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<MyObject> { +/// 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<BerError>, +{ + 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)) + } +} diff --git a/rust/vendor/der-parser-6.0.1/src/der/parser.rs b/rust/vendor/der-parser-6.0.1/src/der/parser.rs new file mode 100644 index 0000000..04b4b23 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/der/parser.rs @@ -0,0 +1,668 @@ +use 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<Tag: Into<DerTag>>(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<F>(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<DerTag>, +{ + parse_ber_implicit(i, tag, f) +} + +/// Parse DER object and try to decode it as a 32-bits signed integer +/// +/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target +/// integer type. +#[inline] +pub fn parse_der_i32(i: &[u8]) -> BerResult<i32> { + let (rem, der) = parse_der_integer(i)?; + let int = der.as_i32().map_err(nom::Err::Error)?; + Ok((rem, int)) +} + +/// Parse DER object and try to decode it as a 64-bits signed integer +/// +/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target +/// integer type. +#[inline] +pub fn parse_der_i64(i: &[u8]) -> BerResult<i64> { + let (rem, der) = parse_der_integer(i)?; + let int = der.as_i64().map_err(nom::Err::Error)?; + Ok((rem, int)) +} + +/// Parse DER object and try to decode it as a 32-bits unsigned integer +/// +/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target +/// integer type. +pub fn parse_der_u32(i: &[u8]) -> BerResult<u32> { + let (rem, der) = parse_der_integer(i)?; + let int = der.as_u32().map_err(nom::Err::Error)?; + Ok((rem, int)) +} + +/// Parse DER 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<u64> { + 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<Tag: Into<DerTag>>(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<DerObjectContent> { + // 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<DerObjectContent> { + 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<DerObjectHeader> { + 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)) +} diff --git a/rust/vendor/der-parser-6.0.1/src/der/tagged.rs b/rust/vendor/der-parser-6.0.1/src/der/tagged.rs new file mode 100644 index 0000000..c7d0fec --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/der/tagged.rs @@ -0,0 +1,263 @@ +use 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<u32> { +/// 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<DerObject>, + Tag: Into<DerTag>, +{ + 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<u32> { +/// 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<BerError>, + Tag: Into<DerTag>, +{ + 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<DerObject> { +/// 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<u32> { +/// 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<DerTag>, +{ + 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<DerObjectContent> { +/// 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<u32> { +/// 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<BerError>, + Tag: Into<DerTag>, +{ + 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 + }) +} diff --git a/rust/vendor/der-parser-6.0.1/src/error.rs b/rust/vendor/der-parser-6.0.1/src/error.rs new file mode 100644 index 0000000..8a496a8 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/error.rs @@ -0,0 +1,114 @@ +//! 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<BerError> for nom::Err<BerError> { + fn from(e: BerError) -> nom::Err<BerError> { + nom::Err::Error(e) + } +} + +impl<I> ParseError<I> 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<I, E> FromExternalError<I, E> 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<dyn Error>> = Err(Box::new(e)); + } +} diff --git a/rust/vendor/der-parser-6.0.1/src/lib.rs b/rust/vendor/der-parser-6.0.1/src/lib.rs new file mode 100644 index 0000000..a5f6e2e --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/lib.rs @@ -0,0 +1,294 @@ +//! [![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)*) + ) + ) + }}; +} diff --git a/rust/vendor/der-parser-6.0.1/src/oid.rs b/rust/vendor/der-parser-6.0.1/src/oid.rs new file mode 100644 index 0000000..618988d --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/src/oid.rs @@ -0,0 +1,463 @@ +//! 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<Item = u8> + '_ { + 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<Oid<'static>, 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<u8> = [(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<Oid<'static>, ParseError> { + if s.is_empty() { + return Err(ParseError::TooShort); + } + let asn1_encoded: Vec<u8> = 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<String> = 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<String> = 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<Item = BigUint> + 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<impl Iterator<Item = u64> + 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<usize, Output = Self> + From<u8> {} +impl<N> Repr for N where N: Num + Shl<usize, Output = N> + From<u8> {} + +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<Self::Item> { + 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 = <N as Zero>::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(")?; + <Oid as fmt::Display>::fmt(self, f)?; + f.write_str(")") + } +} + +impl<'a> FromStr for Oid<'a> { + type Err = ParseError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let v: Result<Vec<_>, _> = s.split('.').map(|c| c.parse::<u64>()).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<BigUint> = 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<u64> = 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]); + } +} diff --git a/rust/vendor/der-parser-6.0.1/tests/ber_parser.rs b/rust/vendor/der-parser-6.0.1/tests/ber_parser.rs new file mode 100644 index 0000000..6f020e3 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/tests/ber_parser.rs @@ -0,0 +1,550 @@ +use 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<bool>) { + 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<Vec<BerObject>> { + 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<u32, BerError>) { + 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<u64, BerError>) { + 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<i64, BerError>) { + let res = parse_ber_i64(i); + match out { + Ok(expected) => { + pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); + } + Err(e) => { + pretty_assertions::assert_eq!(res, Err(Err::Error(e))); + } + } +} + +#[cfg(feature = "bigint")] +#[test_case(&hex!("02 01 01"), Ok(BigInt::from(1)) ; "bigint-1")] +#[test_case(&hex!("02 02 00 ff"), Ok(BigInt::from(255)) ; "bigint-255")] +#[test_case(&hex!("02 01 ff"), Ok(BigInt::from(-1)) ; "bigint-neg1")] +#[test_case(&hex!("02 01 80"), Ok(BigInt::from(-128)) ; "bigint-neg128")] +#[test_case(&hex!("02 02 ff 7f"), Ok(BigInt::from(-129)) ; "bigint-neg129")] +#[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(BigInt::from(0xffff_ffff_ffff_ffff_u64)) ; "bigint-long2-ok")] +#[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(BigInt::from_bytes_be(Sign::Plus, &hex!("01 23 45 67 01 23 45 67 ab"))) ; "bigint-longer1")] +fn tc_ber_bigint(i: &[u8], out: Result<BigInt, BerError>) { + let res = parse_ber_integer(i); + match out { + Ok(expected) => { + let (rem, ber) = res.expect("parsing failed"); + assert!(rem.is_empty()); + let int = ber.as_bigint().expect("failed to convert to bigint"); + pretty_assertions::assert_eq!(int, expected); + } + Err(e) => { + pretty_assertions::assert_eq!(res, Err(Err::Error(e))); + } + } +} + +#[cfg(feature = "bigint")] +#[test_case(&hex!("02 01 01"), Ok(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<BigUint, BerError>) { + 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<BerError>>) { + 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<BerError>>) { + 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<BerError>>) { + 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<BerError>>) { + 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<BerError>>) { + 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(_, _))); +} diff --git a/rust/vendor/der-parser-6.0.1/tests/constructed.rs b/rust/vendor/der-parser-6.0.1/tests/constructed.rs new file mode 100644 index 0000000..20a83a0 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/tests/constructed.rs @@ -0,0 +1,438 @@ +use 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<MyStruct> { + 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<MyStruct> { + 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<MyStruct> { + 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<BerError>>) { + 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<BerError>>) { + fn parser(i: &[u8]) -> BerResult<BerObject> { + 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<BerError>>) { + 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<BerError>>) { + fn parser(i: &[u8]) -> BerResult<BerObject> { + 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<Rdn<'a>>, + } + 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<Attr> { + fn clone_oid(x: BerObject) -> Result<Oid, BerError> { + 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<Rdn> { + 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<Name> { + 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<u32, BerError>) { + fn parse_int_explicit(i: &[u8]) -> BerResult<u32> { + 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<u32> { + map_res( + parse_der_tagged_explicit(2, parse_der_integer), + |x: BerObject| x.as_tagged()?.2.as_u32(), + )(i) + } + let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; + // EXPLICIT tagged value parsing + let (rem, val) = parse_int_explicit(bytes).expect("Could not parse explicit int"); + assert!(rem.is_empty()); + assert_eq!(val, 0x10001); + // 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<u32, BerError>) { + fn parse_int_implicit(i: &[u8]) -> BerResult<u32> { + 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<u32> { + map_res( + parse_der_tagged_implicit(2, parse_der_content(DerTag::Integer)), + |x: BerObject| x.as_u32(), + )(i) + } + let bytes = &[0x82, 0x03, 0x01, 0x00, 0x01]; + // IMPLICIT tagged value parsing + 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<SimpleStruct> { + 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"); +} diff --git a/rust/vendor/der-parser-6.0.1/tests/custom_error.rs b/rust/vendor/der-parser-6.0.1/tests/custom_error.rs new file mode 100644 index 0000000..2281510 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/tests/custom_error.rs @@ -0,0 +1,53 @@ +//! 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<BerError> 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]); +} diff --git a/rust/vendor/der-parser-6.0.1/tests/der_constructed.rs b/rust/vendor/der-parser-6.0.1/tests/der_constructed.rs new file mode 100644 index 0000000..0785189 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/tests/der_constructed.rs @@ -0,0 +1,173 @@ +use 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<u32, BerError>) { + fn parse_int_explicit(i: &[u8]) -> BerResult<u32> { + 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<u32, BerError>) { + fn parse_int_implicit(i: &[u8]) -> BerResult<u32> { + 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<BerError>>) { + fn parser(i: &[u8]) -> BerResult<DerObject> { + 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<BerError>>) { + fn parser(i: &[u8]) -> BerResult<DerObject> { + 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)); + } + } +} diff --git a/rust/vendor/der-parser-6.0.1/tests/der_parser.rs b/rust/vendor/der-parser-6.0.1/tests/der_parser.rs new file mode 100644 index 0000000..33665f3 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/tests/der_parser.rs @@ -0,0 +1,582 @@ +#![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<Vec<BerObject>> { + 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<u32, BerError>) { + 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<i32, BerError>) { + let res = parse_der_i32(i); + match out { + Ok(expected) => { + pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); + } + Err(e) => { + pretty_assertions::assert_eq!(res, Err(Err::Error(e))); + } + } +} + +#[test_case(&hex!("02 01 01"), Ok(1) ; "u64-1")] +#[test_case(&hex!("02 02 00 ff"), Ok(255) ; "u64-255")] +#[test_case(&hex!("02 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<u64, BerError>) { + 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))); + } + } +} diff --git a/rust/vendor/der-parser-6.0.1/tests/fuzz01.rs b/rust/vendor/der-parser-6.0.1/tests/fuzz01.rs new file mode 100644 index 0000000..c971b56 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/tests/fuzz01.rs @@ -0,0 +1,5 @@ +#[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); +} diff --git a/rust/vendor/der-parser-6.0.1/tests/fuzz02.rs b/rust/vendor/der-parser-6.0.1/tests/fuzz02.rs new file mode 100644 index 0000000..bea7c21 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/tests/fuzz02.rs @@ -0,0 +1,22 @@ +#[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); +} diff --git a/rust/vendor/der-parser-6.0.1/tests/oid.rs b/rust/vendor/der-parser-6.0.1/tests/oid.rs new file mode 100644 index 0000000..5cffad4 --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/tests/oid.rs @@ -0,0 +1,25 @@ +//! 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)); +} diff --git a/rust/vendor/der-parser-6.0.1/tests/primitive.rs b/rust/vendor/der-parser-6.0.1/tests/primitive.rs new file mode 100644 index 0000000..4c07b0a --- /dev/null +++ b/rust/vendor/der-parser-6.0.1/tests/primitive.rs @@ -0,0 +1,228 @@ +extern 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); +} |