diff options
Diffstat (limited to 'rust/vendor/der-parser')
35 files changed, 8920 insertions, 0 deletions
diff --git a/rust/vendor/der-parser/.cargo-checksum.json b/rust/vendor/der-parser/.cargo-checksum.json new file mode 100644 index 0000000..5c8cb9c --- /dev/null +++ b/rust/vendor/der-parser/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"0dd2ab03c45afe5db35191ec398b5ae56fdd252aabd1fa1b669033ff010f87f8","Cargo.toml":"213b0dfa900619e433c3999b5b2de2ce54effe7d8161a8ae3abf972196ea81b4","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a5c61b93b6ee1d104af9920cf020ff3c7efe818e31fe562c72261847a728f513","README.md":"4cb96f25c1a2b876e75e98f528a0a51dbdaa97f210e270a2f8b07f1da18ccc22","UPGRADING.md":"ec1f026903fda2de7adda9090863b519c9732266460dadf0eaece9bf1c00289c","src/ber/ber.rs":"f03f71f653cbfd3e1903d989d0b49b4fd16604e8923444b02aa4851b7f013479","src/ber/compat.rs":"a220f947321d91431673d54b56f05c03b502e05c80b644ef0163d31ca83cf922","src/ber/integer.rs":"d87b78dabd3b455764b36bcd62f6dceb2fcbe4e381b2e32a71585b25967a29ed","src/ber/mod.rs":"8d208e2574dca87fbc1b65b66bad7c679fd32d60c688856a590d31b08d051ce0","src/ber/multi.rs":"7ec726d0c320496f7093c701b1f64296a5f4f391f0fae59c2d3cb17b2e8fa23b","src/ber/parser.rs":"68b320e05527fcb06681a21e0e072aab912db9cefac2c65e66ef2dbe9e6dcb8c","src/ber/print.rs":"f5e6839e765709d6634773282b1be0e1d9513b69dc5756379d4c923afd26951b","src/ber/serialize.rs":"ec32664e1e4ebbd0468c202448ed1fed2ee8f694c690617187fd4ea536aded99","src/ber/tagged.rs":"81d05ceb46f308fb766e2f7df6cec7c2c8479b928f2be9ce7e5cc30e126815fb","src/ber/visit.rs":"20a2cddb9263943de03b2e8abc054030baab64a9a739d590dd52c32599a838e9","src/ber/visit_mut.rs":"cf2c936173c3d077113f0421edab0a6e609587ab4ad984ee2128dde89dafe5be","src/ber/wrap_any.rs":"8db018f8141cd0497aa3ae08a3a76528851585c88c22275af2be8a69887fb01b","src/der/mod.rs":"70d80fc8eefaf6d15fb87e3b159796ec4e43d4b8e2854db74d715d10b36b0025","src/der/multi.rs":"b69e1bae25f6a57b821a35f4ddf9400feedf4c0303f1087254d01a856a8a5284","src/der/parser.rs":"10a33f70973c358a7e10c1e3ecf3f6470a86c61541e91136374c0d1d1be96e7e","src/der/tagged.rs":"66bf6b755bb41cd059a31021a631462985e76732a34c2df06ad805d4d19c2a1b","src/error.rs":"0d83caef79ea673a5814b7068bda0f2a558f05d57661e2ca24d819c650244937","src/lib.rs":"1ea83ce2d6582f9b8122062cf8813119abac7cb043f09e339beceec3d9e85559","src/oid.rs":"f6ff7343c47e7d554a1bfd6f07fc17996a8f58b2153336d624cfd076c0192bf1","tests/ber_parser.rs":"bf2401c7b06b7724d81b93e696f2403c947a51b1c360dfc731c7f392b0005d08","tests/constructed.rs":"532f1fda98bc9f22da0dd905f2314be5195e9442bb3acb1584e80037101a013f","tests/custom_error.rs":"8f92380a8b71df6033e15806c162bc502c6beea086ebed7c3106c76da71ec95b","tests/der_constructed.rs":"49f8f8d97659410ac0752a2fb9c2aec97930c6efb8cccd989946912afa0f1a6d","tests/der_parser.rs":"e00691edef8a5f83f5ea746835c061c08c47c5aad74aecae71833c9b3205fe64","tests/fuzz01.rs":"b1929c8183fdba11ea73618ef48b23d4d3d39df79ac70e1c46787c3dcfcf9ec9","tests/fuzz02.rs":"b1e4ae20a40bb74887b7d62e9bbec5919f7c963b3f699e01888755e3637877a5","tests/oid.rs":"901a1a929653eef5f1753479dc742f1e9fefca960523958d4e50b8376ac06524","tests/primitive.rs":"95e6da515e34df3d4682341319bf580e51304d2c3b14e9645b2c49f0f6e41f49"},"package":"dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e"}
\ No newline at end of file diff --git a/rust/vendor/der-parser/CHANGELOG.md b/rust/vendor/der-parser/CHANGELOG.md new file mode 100644 index 0000000..9f0ee32 --- /dev/null +++ b/rust/vendor/der-parser/CHANGELOG.md @@ -0,0 +1,388 @@ +# Change Log + +## [Unreleased][unreleased] + +### Changed/Fixed + +### Added + +### Thanks + +## 8.2.0 + +### Changed/Fixed + +- Fix parser name to `parse_der_visiblestring` for `VisibleString` (Closes #64). + Keep previous function for compatibility (mark it as deprecated). +- Fix clippy warnings (rustc 1.67.1) +- Update test-case from 2.0 to 3.0 + +## 8.1.0 + +### Changed/Fixed + +- Upgrade `asn1-rs` to 0.5.0 (new features only: only increment minor number) + +## 8.0.0 + +### Changed/Fixed + +- Upgrade `asn1-rs` to 0.4.0 + This causes an increment of the major number, because `asn1-rs` is re-exported + +## 7.0.0 + +This release marks the beginning of the merge with the `asn1-rs` crate. **This will break things.** + +However, this is necessary, because the `asn1-rs` crate is much cleaner and supports more types +and features (like serialization, custom derive, etc.). +Ultimately, this crate will become a frontend to `asn1-rs`, that will be optional: crate users can +switch to `asn1-rs` and use it directly. + +### Changed/Fixed + +MSRV: The minimum supported rust version is now *1.53*. + +`BerObjectHeader`: + +- `BerSize` has been renamed to `Length` +- `BerClass` has been renamed to `Class` +- `BerTag` has been renamed to `Tag` +- Header fields are now private. Getters/setters have been added, and must be used to access/modify fields + +`BerObjectContent`: +- `Unknown` variant now contains an `Any` object, with both the header and object content +- `Private` variant has been merged into `Unknown` +- `BmpString`, `GeneralString`, `GraphicString`, `T61String`, `VideotexString` and `ObjectDescriptor` are now decoded +- `GeneralizedTime` and `UtcTime` are now decoded + +`BerError`: + +- Add error types `UnexpectedClass` and `UnexpectedTag` +- Store expected and found item in error to help debugging +- Keep `InvalidTag` for tags with invalid form (length/encoding/etc.) +- Use `displaydoc` for `BerError` +- Parsing an indefinite length in DER now raises `IndefiniteLengthUnexpected` +- Error: when a DER constraint fails, store constraint identifier + +`DER`: +- `DerClass` and `DerTag` have been deprecated. Use `Class` and `Tag` instead. +- `DerObjectHeader` has been deprecated. Use `Header` instead. + +`Oid`: +- The `Oid` object is now the same as `asn1_rs::Oid` (simply reexported) +- Remove dependency on crate `der-oid-macro` + +Misc: +- `ber_read_element_content_as` now requires a non-zero `depth`, or it + will raise a `BerMaxDepth` error (previously, 0 allowed one level of parsing) +- crate `rusticata-macros` is now re-exported (#55) + +### Thanks + +- @lilyball +- @erikmarkmartin + +## 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/Cargo.toml b/rust/vendor/der-parser/Cargo.toml new file mode 100644 index 0000000..bf192be --- /dev/null +++ b/rust/vendor/der-parser/Cargo.toml @@ -0,0 +1,94 @@ +# 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 = "8.2.0" +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.asn1-rs] +version = "0.5" + +[dependencies.cookie-factory] +version = "0.3.0" +optional = true + +[dependencies.displaydoc] +version = "0.2" +default-features = false + +[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 = "3.0" + +[features] +bigint = ["num-bigint"] +default = ["std"] +serialize = [ + "std", + "cookie-factory", +] +std = [] +unstable = [] diff --git a/rust/vendor/der-parser/LICENSE-APACHE b/rust/vendor/der-parser/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/rust/vendor/der-parser/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/LICENSE-MIT b/rust/vendor/der-parser/LICENSE-MIT new file mode 100644 index 0000000..290e7b9 --- /dev/null +++ b/rust/vendor/der-parser/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/README.md b/rust/vendor/der-parser/README.md new file mode 100644 index 0000000..780e258 --- /dev/null +++ b/rust/vendor/der-parser/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/8.2.0/status.svg)](https://deps.rs/crate/der-parser/8.2.0) +[![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.53.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 7.0 series of `der-parser` requires **Rustc version 1.53 or greater**, based on `asn1-rs` +and `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/UPGRADING.md b/rust/vendor/der-parser/UPGRADING.md new file mode 100644 index 0000000..3df0ed2 --- /dev/null +++ b/rust/vendor/der-parser/UPGRADING.md @@ -0,0 +1,128 @@ +## Upgrading from 6.x to 7.0 + +### Header refactor + +Header names have changed: +- `BerClass` is now `Class` +- `BerSize` is now `Length` +- `BerTag` is now `Tag` +- `BerObjectHeader` is now `Header` + +Changing the names should be enough for upgrades. + +To eventually ease upgrades, a new module (`der_parser::ber::compat`) has been added, to provide aliases for these types. It must be imported explicitely. + +Header fields are now private. Getters/setters have been added, and must be used to access/modify fields. Replace: +- `hdr.len` by `hdr.length()` +- `hdr.class` by `hdr.class()` +- `hdr.tag` by `hdr.tag()` + +`structured` has been renamed to `constructed` to match RFC. Since this field is now private, methods `constructed()`/`set_constructed()` must be used instead of raw access. + +### DER + +`DerClass` and `DerTag` have been deprecated. Use `Class` and `Tag` instead. + +`DerObjectHeader` has been deprecated. Use `Header` instead. + +## 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/src/ber/ber.rs b/rust/vendor/der-parser/src/ber/ber.rs new file mode 100644 index 0000000..3063ff2 --- /dev/null +++ b/rust/vendor/der-parser/src/ber/ber.rs @@ -0,0 +1,950 @@ +use super::{Class, Header, Length, Tag}; +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; +use asn1_rs::ASN1DateTime; +use asn1_rs::Any; +#[cfg(feature = "bitvec")] +use bitvec::{order::Msb0, slice::BitSlice}; +use core::convert::AsRef; +use core::convert::From; +use core::ops::Index; + +/// 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: Header<'a>, + pub content: BerObjectContent<'a>, +} + +/// 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: decoded string + T61String(&'a str), + /// VideotexString: decoded string + VideotexString(&'a str), + + /// BmpString: decoded string + BmpString(&'a str), + /// 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(ASN1DateTime), + /// GeneralizedTime: decoded string + GeneralizedTime(ASN1DateTime), + + /// Object descriptor: decoded string + ObjectDescriptor(&'a str), + /// GraphicString: decoded string + GraphicString(&'a str), + /// GeneralString: decoded string + GeneralString(&'a str), + + /// Optional object + Optional(Option<Box<BerObject<'a>>>), + /// Tagged object (EXPLICIT): class, tag and content of inner object + Tagged(Class, Tag, Box<BerObject<'a>>), + + /// Private or Unknown (for ex. unknown tag) object + Unknown(Any<'a>), +} + +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. + #[inline] + pub const fn from_header_and_content<'o>( + header: Header<'o>, + content: BerObjectContent<'o>, + ) -> BerObject<'o> { + BerObject { header, content } + } + + /// Build a BerObject from its content, using default flags (no class, correct tag, + /// and constructed flag set only for Set and Sequence) + pub const fn from_obj(c: BerObjectContent) -> BerObject { + let class = Class::Universal; + let tag = c.tag(); + let constructed = matches!(tag, Tag::Sequence | Tag::Set); + let header = Header::new(class, constructed, tag, Length::Definite(0)); + BerObject { header, content: c } + } + + /// Build a DER integer object from a slice containing an encoded integer + pub const fn from_int_slice(i: &'a [u8]) -> BerObject<'a> { + let header = Header::new(Class::Universal, false, Tag::Integer, Length::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 = self.header.with_raw_tag(raw_tag.map(|x| x.into())); + BerObject { header, ..self } + } + + /// Build a DER sequence object from a vector of DER objects + pub const 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 const 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(&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(&self) -> Result<(Class, Tag, &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(&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 some string types 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() + } + + /// Get the BER object header's class. + #[inline] + pub const fn class(&self) -> Class { + self.header.class() + } + + /// Get the BER object header's tag. + #[inline] + pub const fn tag(&self) -> Tag { + self.header.tag() + } + + /// Get the BER object header's length. + #[inline] + pub const fn length(&self) -> Length { + self.header.length() + } + + /// Test if object class is Universal + #[inline] + pub const fn is_universal(&self) -> bool { + self.header.is_universal() + } + /// Test if object class is Application + #[inline] + pub const fn is_application(&self) -> bool { + self.header.is_application() + } + /// Test if object class is Context-specific + #[inline] + pub const fn is_contextspecific(&self) -> bool { + self.header.is_contextspecific() + } + /// Test if object class is Private + #[inline] + pub fn is_private(&self) -> bool { + self.header.is_private() + } + + /// Test if object is primitive + #[inline] + pub const fn is_primitive(&self) -> bool { + self.header.is_primitive() + } + /// Test if object is constructed + #[inline] + pub const fn is_constructed(&self) -> bool { + self.header.is_constructed() + } + + /// Return error if `class` is not the expected class + #[inline] + pub const fn assert_class(&self, class: Class) -> Result<(), BerError> { + self.header.assert_class(class) + } + + /// Return error if `tag` is not the expected tag + #[inline] + pub const fn assert_tag(&self, tag: Tag) -> Result<(), BerError> { + self.header.assert_tag(tag) + } + + /// Return error if object is not constructed + #[inline] + pub const fn assert_constructed(&self) -> Result<(), BerError> { + self.header.assert_constructed() + } + + /// Return error if object is not primitive + #[inline] + pub const fn assert_primitive(&self) -> Result<(), BerError> { + self.header.assert_primitive() + } +} + +/// 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) + } +} + +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::BerValueError) + } + } + + /// 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::BerValueError) + } + } + + /// 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), + _ => 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(&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(&self) -> Result<(Class, Tag, &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(&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::BmpString(s) | + BerObjectContent::VisibleString(s) | + BerObjectContent::PrintableString(s) | + BerObjectContent::GeneralString(s) | + BerObjectContent::ObjectDescriptor(s) | + BerObjectContent::GraphicString(s) | + BerObjectContent::T61String(s) | + BerObjectContent::VideotexString(s) | + BerObjectContent::UTF8String(s) | + BerObjectContent::IA5String(s) => Ok(s.as_ref()), + BerObjectContent::Integer(s) | + BerObjectContent::BitString(_,BitStringObject{data:s}) | + BerObjectContent::OctetString(s) | + BerObjectContent::UniversalString(s) => Ok(s), + BerObjectContent::Unknown(ref any) => Ok(any.data), + _ => Err(BerError::BerTypeError), + } + } + + #[rustfmt::skip] + pub fn as_str(&self) -> Result<&'a str,BerError> { + match *self { + BerObjectContent::NumericString(s) | + BerObjectContent::BmpString(s) | + BerObjectContent::VisibleString(s) | + BerObjectContent::PrintableString(s) | + BerObjectContent::GeneralString(s) | + BerObjectContent::ObjectDescriptor(s) | + BerObjectContent::GraphicString(s) | + BerObjectContent::T61String(s) | + BerObjectContent::VideotexString(s) | + BerObjectContent::UTF8String(s) | + BerObjectContent::IA5String(s) => Ok(s), + _ => Err(BerError::BerTypeError), + } + } + + #[rustfmt::skip] + const fn tag(&self) -> Tag { + match self { + BerObjectContent::EndOfContent => Tag::EndOfContent, + BerObjectContent::Boolean(_) => Tag::Boolean, + BerObjectContent::Integer(_) => Tag::Integer, + BerObjectContent::BitString(_,_) => Tag::BitString, + BerObjectContent::OctetString(_) => Tag::OctetString, + BerObjectContent::Null => Tag::Null, + BerObjectContent::Enum(_) => Tag::Enumerated, + BerObjectContent::OID(_) => Tag::Oid, + BerObjectContent::NumericString(_) => Tag::NumericString, + BerObjectContent::VisibleString(_) => Tag::VisibleString, + BerObjectContent::PrintableString(_) => Tag::PrintableString, + BerObjectContent::IA5String(_) => Tag::Ia5String, + BerObjectContent::UTF8String(_) => Tag::Utf8String, + BerObjectContent::RelativeOID(_) => Tag::RelativeOid, + BerObjectContent::T61String(_) => Tag::T61String, + BerObjectContent::VideotexString(_) => Tag::VideotexString, + BerObjectContent::BmpString(_) => Tag::BmpString, + BerObjectContent::UniversalString(_) => Tag::UniversalString, + BerObjectContent::Sequence(_) => Tag::Sequence, + BerObjectContent::Set(_) => Tag::Set, + BerObjectContent::UTCTime(_) => Tag::UtcTime, + BerObjectContent::GeneralizedTime(_) => Tag::GeneralizedTime, + BerObjectContent::ObjectDescriptor(_) => Tag::ObjectDescriptor, + BerObjectContent::GraphicString(_) => Tag::GraphicString, + BerObjectContent::GeneralString(_) => Tag::GeneralString, + BerObjectContent::Tagged(_,x,_) => *x, + BerObjectContent::Unknown(any) => any.tag(), + BerObjectContent::Optional(Some(obj)) => obj.content.tag(), + BerObjectContent::Optional(None) => Tag(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::BerValueError), + } + } + + /// 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::BerValueError), + } + } +} + +// 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 constructed"), + } + // 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/src/ber/compat.rs b/rust/vendor/der-parser/src/ber/compat.rs new file mode 100644 index 0000000..ce52bb7 --- /dev/null +++ b/rust/vendor/der-parser/src/ber/compat.rs @@ -0,0 +1,9 @@ +//! Compatibility module for old (pre-7.0) types + +use super::{Class, Header, Length}; +pub use asn1_rs::Tag; + +pub type BerClass = Class; +pub type BerSize = Length; +pub type BerTag = Tag; +pub type BerObjectHeader<'a> = Header<'a>; diff --git a/rust/vendor/der-parser/src/ber/integer.rs b/rust/vendor/der-parser/src/ber/integer.rs new file mode 100644 index 0000000..2ddb2a0 --- /dev/null +++ b/rust/vendor/der-parser/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 + .first() + .map(|byte| byte & 0b10000000 != 0) + .unwrap_or(false) +} diff --git a/rust/vendor/der-parser/src/ber/mod.rs b/rust/vendor/der-parser/src/ber/mod.rs new file mode 100644 index 0000000..342743c --- /dev/null +++ b/rust/vendor/der-parser/src/ber/mod.rs @@ -0,0 +1,78 @@ +//! 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; +mod visit; +mod visit_mut; +mod wrap_any; + +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::*; +pub use crate::ber::visit::*; +pub use crate::ber::visit_mut::*; +pub use crate::ber::wrap_any::*; + +pub mod compat; + +pub use asn1_rs::{Class, Header, Length, Tag}; + +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::convert::Into; diff --git a/rust/vendor/der-parser/src/ber/multi.rs b/rust/vendor/der-parser/src/ber/multi.rs new file mode 100644 index 0000000..6168bc9 --- /dev/null +++ b/rust/vendor/der-parser/src/ber/multi.rs @@ -0,0 +1,531 @@ +use crate::ber::*; +use crate::error::*; +use asn1_rs::Tag; +use nom::bytes::complete::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], Header<'a>) -> IResult<&'a [u8], O, E>, + E: ParseError<&'a [u8]> + From<BerError>, +{ + parse_ber_container(move |i, hdr| { + hdr.assert_tag(Tag::Sequence) + .map_err(|e| Err::Error(e.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], Header<'a>) -> IResult<&'a [u8], O, E>, + E: ParseError<&'a [u8]> + From<BerError>, +{ + parse_ber_container(move |i, hdr| { + hdr.assert_tag(Tag::Set).map_err(|e| Err::Error(e.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 constructed 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: Header| { +/// if hdr.tag() != Tag::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], Header<'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.length() { + Length::Definite(len) => take(len)(i)?, + Length::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/src/ber/parser.rs b/rust/vendor/der-parser/src/ber/parser.rs new file mode 100644 index 0000000..f951402 --- /dev/null +++ b/rust/vendor/der-parser/src/ber/parser.rs @@ -0,0 +1,661 @@ +use crate::ber::wrap_any::parse_ber_any_r; +use crate::ber::*; +use crate::error::*; +use asn1_rs::{FromBer, Tag}; +use nom::bytes::streaming::take; +use nom::{Err, Offset}; + +/// 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: &Header, + max_depth: usize, +) -> BerResult<'a, bool> { + if max_depth == 0 { + return Err(Err::Error(BerError::BerMaxDepth)); + } + match hdr.length() { + Length::Definite(l) => { + if l == 0 && hdr.tag() == Tag::EndOfContent { + return Ok((i, true)); + } + let (i, _) = take(l)(i)?; + Ok((i, false)) + } + Length::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: &Header, + 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.length() == Length::Indefinite { + let len = content.len(); + assert!(len >= 2); + Ok((i, &content[..len - 2])) + } else { + Ok((i, content)) + } +} + +/// 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) +} + +/// Read an object header +/// +/// ### Example +/// +/// ``` +/// # use der_parser::ber::{ber_read_element_header, Class, Length, Tag}; +/// # +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (i, hdr) = ber_read_element_header(bytes).expect("could not read header"); +/// +/// assert_eq!(hdr.class(), Class::Universal); +/// assert_eq!(hdr.tag(), Tag::Integer); +/// assert_eq!(hdr.length(), Length::Definite(3)); +/// ``` +#[inline] +pub fn ber_read_element_header(i: &[u8]) -> BerResult<Header> { + Header::from_ber(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, Tag}; +/// # +/// # 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.length(), hdr.is_constructed(), 5 +/// ).expect("parsing failed"); +/// # +/// # assert_eq!(hdr.tag(), Tag::Integer); +/// # assert_eq!(content.as_u32(), Ok(0x10001)); +/// ``` +#[inline] +pub fn ber_read_element_content_as( + i: &[u8], + tag: Tag, + length: Length, + constructed: bool, + max_depth: usize, +) -> BerResult<BerObjectContent> { + try_read_berobjectcontent_as(i, tag, length, constructed, max_depth) +} + +/// 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(), Tag::Integer); +/// ``` +pub fn parse_ber_content<'a>( + tag: Tag, +) -> impl Fn(&'a [u8], &'_ Header, usize) -> BerResult<'a, BerObjectContent<'a>> { + move |i: &[u8], hdr: &Header, max_recursion: usize| { + ber_read_element_content_as(i, tag, hdr.length(), 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(), Tag::Integer); +/// ``` +pub fn parse_ber_content2<'a>( + tag: Tag, +) -> impl Fn(&'a [u8], Header<'a>, usize) -> BerResult<'a, BerObjectContent<'a>> { + move |i: &[u8], hdr: Header, max_recursion: usize| { + ber_read_element_content_as(i, tag, hdr.length(), 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::Tag; +/// use der_parser::ber::parse_ber_with_tag; +/// +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (_, obj) = parse_ber_with_tag(bytes, Tag::Integer).expect("parsing failed"); +/// +/// assert_eq!(obj.header.tag(), Tag::Integer); +/// ``` +pub fn parse_ber_with_tag<T: Into<Tag>>(i: &[u8], tag: T) -> BerResult { + let tag = tag.into(); + let (i, hdr) = ber_read_element_header(i)?; + hdr.assert_tag(tag)?; + let (i, content) = ber_read_element_content_as( + i, + hdr.tag(), + hdr.length(), + 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, Tag::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, Tag::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, Tag::Integer) +} + +/// Read an bitstring value +#[inline] +pub fn parse_ber_bitstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::BitString) +} + +/// Read an octetstring value +#[inline] +pub fn parse_ber_octetstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::OctetString) +} + +/// Read a null value +#[inline] +pub fn parse_ber_null(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Null) +} + +/// Read an object identifier value +#[inline] +pub fn parse_ber_oid(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Oid) +} + +/// Read an enumerated value +#[inline] +pub fn parse_ber_enum(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::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, Tag::Utf8String) +} + +/// Read a relative object identifier value +#[inline] +pub fn parse_ber_relative_oid(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::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 constructed 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, Tag::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 constructed 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, Tag::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, Tag::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, Tag::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, Tag::PrintableString) +} + +/// Read a T61 string value +#[inline] +pub fn parse_ber_t61string(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::T61String) +} + +/// Read a Videotex string value +#[inline] +pub fn parse_ber_videotexstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::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, Tag::Ia5String) +} + +/// Read an UTC time value +#[inline] +pub fn parse_ber_utctime(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::UtcTime) +} + +/// Read a Generalized time value +#[inline] +pub fn parse_ber_generalizedtime(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::GeneralizedTime) +} + +/// Read an ObjectDescriptor value +#[inline] +pub fn parse_ber_objectdescriptor(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::ObjectDescriptor) +} + +/// Read a GraphicString value +#[inline] +pub fn parse_ber_graphicstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::GraphicString) +} + +/// Read a GeneralString value +#[inline] +pub fn parse_ber_generalstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::GeneralString) +} + +/// Read a BmpString value +#[inline] +pub fn parse_ber_bmpstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::BmpString) +} + +/// Read a UniversalString value +#[inline] +pub fn parse_ber_universalstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::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: Tag, 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(Tag::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, T, F>(i: &'a [u8], tag: T, f: F) -> BerResult<'a> +where + F: Fn(&'a [u8], &'_ Header, usize) -> BerResult<'a, BerObjectContent<'a>>, + T: Into<Tag>, +{ + 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(), Tag::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> { + <i32>::from_ber(i) +} + +/// 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> { + <i64>::from_ber(i) +} + +/// 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> { + <u32>::from_ber(i) +} + +/// 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> { + <u64>::from_ber(i) +} + +/// Parse BER object and get content as slice +#[inline] +pub fn parse_ber_slice<T: Into<Tag>>(i: &[u8], tag: T) -> BerResult<&[u8]> { + let tag = tag.into(); + parse_ber_container(move |content, hdr| { + hdr.assert_tag(tag)?; + Ok((&b""[..], content)) + })(i) +} + +/// 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, Tag}; +/// +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (_, obj) = parse_ber_recursive(bytes, 1).expect("parsing failed"); +/// +/// assert_eq!(obj.header.tag(), Tag::Integer); +/// ``` +#[inline] +pub fn parse_ber_recursive(i: &[u8], max_depth: usize) -> BerResult { + parse_ber_any_r(i, max_depth) +} + +/// 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, Tag}; +/// +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (_, obj) = parse_ber(bytes).expect("parsing failed"); +/// +/// assert_eq!(obj.header.tag(), Tag::Integer); +/// ``` +#[inline] +pub fn parse_ber(i: &[u8]) -> BerResult { + parse_ber_recursive(i, MAX_RECURSION) +} + +#[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/src/ber/print.rs b/rust/vendor/der-parser/src/ber/print.rs new file mode 100644 index 0000000..ce15523 --- /dev/null +++ b/rust/vendor/der-parser/src/ber/print.rs @@ -0,0 +1,209 @@ +use crate::ber::BitStringObject; +use crate::ber::{BerObject, BerObjectContent}; +use alloc::string::{String, ToString}; +use alloc::vec; +use alloc::vec::Vec; +use asn1_rs::{Class, Header, Length, Tag}; +use core::fmt; +use core::iter::FromIterator; +use core::str; +use debug::HexSlice; + +use rusticata_macros::debug; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum PrettyPrinterFlag { + Recursive, + ShowHeader, +} + +/// Pretty-print BER object +/// +/// This method is recursive by default. To prevent that, unset the `Recursive` flag. +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::new(self, vec![PrettyPrinterFlag::Recursive], indent, increment) + } +} + +impl<'a> PrettyBer<'a> { + pub const fn new( + obj: &'a BerObject<'a>, + flags: Vec<PrettyPrinterFlag>, + indent: usize, + increment: usize, + ) -> Self { + Self { + obj, + indent, + inc: increment, + flags, + } + } + + pub fn set_flag(&mut self, flag: PrettyPrinterFlag) { + if !self.flags.contains(&flag) { + self.flags.push(flag); + } + } + + pub fn unset_flag(&mut self, flag: PrettyPrinterFlag) { + self.flags.retain(|&f| f != flag); + } + + pub fn is_flag_set(&self, flag: PrettyPrinterFlag) -> bool { + self.flags.contains(&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(), + } + } + + #[inline] + fn is_recursive(&self) -> bool { + self.is_flag_set(PrettyPrinterFlag::Recursive) + } +} + +fn dbg_header(header: &Header, f: &mut fmt::Formatter) -> fmt::Result { + let s_constructed = if header.is_constructed() { "+" } else { "" }; + let l = match header.length() { + Length::Definite(sz) => sz.to_string(), + Length::Indefinite => "Indefinite".to_string(), + }; + match header.class() { + Class::Universal => { + write!(f, "[{}]{} {}", header.tag(), s_constructed, l)?; + } + Class::ContextSpecific => { + write!(f, "[{}]{} {}", header.tag().0, s_constructed, l)?; + } + + class => { + write!(f, "[{} {}]{} {}", class, header.tag().0, s_constructed, l)?; + } + } + Ok(()) +} + +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) { + dbg_header(&self.obj.header, f)?; + write!(f, " ")?; + }; + 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 => write!(f, "EndOfContent"), + BerObjectContent::Boolean(b) => write!(f, "Boolean({:?})", b), + BerObjectContent::Integer(i) => write!(f, "Integer({:?})", HexSlice(i)), + BerObjectContent::Enum(i) => write!(f, "Enum({})", i), + BerObjectContent::OID(ref v) => write!(f, "OID({:?})", v), + BerObjectContent::RelativeOID(ref v) => write!(f, "RelativeOID({:?})", v), + BerObjectContent::Null => write!(f, "Null"), + BerObjectContent::OctetString(v) => write!(f, "OctetString({:?})", HexSlice(v)), + BerObjectContent::BitString(u,BitStringObject{data:v}) + => write!(f, "BitString({},{:?})", u, HexSlice(v)), + BerObjectContent::GeneralizedTime(ref time) => write!(f, "GeneralizedTime(\"{}\")", time), + BerObjectContent::UTCTime(ref time) => write!(f, "UTCTime(\"{}\")", time), + BerObjectContent::VisibleString(s) => write!(f, "VisibleString(\"{}\")", s), + BerObjectContent::GeneralString(s) => write!(f, "GeneralString(\"{}\")", s), + BerObjectContent::GraphicString(s) => write!(f, "GraphicString(\"{}\")", s), + BerObjectContent::PrintableString(s) => write!(f, "PrintableString(\"{}\")", s), + BerObjectContent::NumericString(s) => write!(f, "NumericString(\"{}\")", s), + BerObjectContent::UTF8String(s) => write!(f, "UTF8String(\"{}\")", s), + BerObjectContent::IA5String(s) => write!(f, "IA5String(\"{}\")", s), + BerObjectContent::T61String(s) => write!(f, "T61String({})", s), + BerObjectContent::VideotexString(s) => write!(f, "VideotexString({})", s), + BerObjectContent::ObjectDescriptor(s) => write!(f, "ObjectDescriptor(\"{}\")", s), + BerObjectContent::BmpString(s) => write!(f, "BmpString(\"{}\")", s), + BerObjectContent::UniversalString(s) => print_utf32_string_with_type(f, s, "UniversalString"), + BerObjectContent::Optional(ref o) => { + match o { + Some(obj) => write!(f, "OPTION {:?}", obj), + None => write!(f, "NONE"), + } + } + BerObjectContent::Tagged(class, tag, ref obj) => { + writeln!(f, "ContextSpecific [{} {}] {{", class, tag.0)?; + write!(f, "{:?}", self.next_indent(obj))?; + if self.indent > 0 { + write!(f, "{:1$}", " ", self.indent)?; + }; + write!(f, "}}")?; + Ok(()) + }, + BerObjectContent::Set(ref v) | + BerObjectContent::Sequence(ref v) => { + let ty = if self.obj.header.tag() == Tag::Sequence { "Sequence" } else { "Set" }; + if self.is_recursive() { + writeln!(f, "{}[", ty)?; + for o in v { + write!(f, "{:?}", self.next_indent(o))?; + }; + if self.indent > 0 { + write!(f, "{:1$}", " ", self.indent)?; + }; + write!(f, "]")?; + } else { + write!(f, "{}", ty)?; + } + Ok(()) + }, + BerObjectContent::Unknown(ref any) => { + write!(f, "Unknown {:x?}", HexSlice(any.data)) + }, + } + } +} + +#[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/src/ber/serialize.rs b/rust/vendor/der-parser/src/ber/serialize.rs new file mode 100644 index 0000000..0839e02 --- /dev/null +++ b/rust/vendor/der-parser/src/ber/serialize.rs @@ -0,0 +1,419 @@ +#![cfg(feature = "std")] +use crate::ber::*; +use crate::oid::Oid; +use asn1_rs::{ASN1DateTime, Tag}; +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<Length>>(len: Len) -> impl SerializeFn<W> + 'a { + let l = len.into(); + move |out| { + match l { + Length::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), slice(v)))(out) + } + } + Length::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 Header) -> impl SerializeFn<W> + 'a { + move |out| { + // identifier octets (X.690 8.1.2) + let class_u8 = (hdr.class() as u8) << 6; + let pc_u8 = (if hdr.constructed() { 1 } else { 0 }) << 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.length())))(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.as_bytes())(out) + } +} + +fn ber_encode_datetime<'a, W: Write + 'a>(time: &'a ASN1DateTime) -> impl SerializeFn<W> + 'a { + move |out| { + let s = format!("{}", time); + slice(s)(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: Tag, + class: Class, + 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 = Header::new(class, true /* X.690 8.14.2 */, tag, len.into()); + 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: Tag, + class: Class, + 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 constructed attribute) + let len = v.as_ref().len(); + let hdr = Header::new(class, obj.header.constructed(), tag, len.into()); + 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::UTCTime(time) | BerObjectContent::GeneralizedTime(time) => { + ber_encode_datetime(time)(out) + } + BerObjectContent::NumericString(s) + | BerObjectContent::BmpString(s) + | BerObjectContent::GeneralString(s) + | BerObjectContent::ObjectDescriptor(s) + | BerObjectContent::GraphicString(s) + | BerObjectContent::VisibleString(s) + | BerObjectContent::PrintableString(s) + | BerObjectContent::IA5String(s) + | BerObjectContent::T61String(s) + | BerObjectContent::VideotexString(s) + | BerObjectContent::UTF8String(s) => slice(s)(out), + BerObjectContent::UniversalString(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::Tagged(_class, _tag, inner) => { + // directly encode inner object + // XXX wrong, we should wrap it! + ber_encode_object(inner)(out) + } + BerObjectContent::Unknown(any) => slice(any.data)(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 Header, + 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_length(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, Tag(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(Tag(0), Class::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, Tag(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: &Header, + depth: usize, + ) -> BerResult<'a, BerObjectContent<'a>> { + ber_read_element_content_as(i, Tag::Integer, hdr.length(), false, depth) + } + fn local_parse(i: &[u8]) -> BerResult<BerObject> { + parse_ber_implicit(i, Tag(3), der_read_integer_content) + } + let obj = BerObject::from_int_slice(b"\x02"); + let v = gen_simple( + ber_encode_tagged_implicit(Tag(3), Class::ContextSpecific, &obj), + Vec::new(), + ) + .expect("could not encode"); + let (_, obj2) = local_parse(&v).expect("could not re-parse"); + assert_eq!(obj2.header.tag(), Tag(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, Tag(2), parse_ber_integer) + } + let obj = BerObject::from_int_slice(b"\x02"); + let v = gen_simple( + ber_encode_tagged_explicit(Tag(2), Class::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, Tag(2)); + assert_eq!(&obj, inner); + let bytes = hex!("62 03 02 01 02"); + assert_eq!(&v[..], bytes); + } +} diff --git a/rust/vendor/der-parser/src/ber/tagged.rs b/rust/vendor/der-parser/src/ber/tagged.rs new file mode 100644 index 0000000..e4614c5 --- /dev/null +++ b/rust/vendor/der-parser/src/ber/tagged.rs @@ -0,0 +1,260 @@ +use crate::ber::*; +use crate::error::*; +use asn1_rs::Tag; +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, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult +where + F: Fn(&'a [u8]) -> BerResult<BerObject>, + T: Into<Tag>, +{ + 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, T, Output, F, E>( + tag: T, + f: F, +) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Output, E> +where + F: Fn(&'a [u8], Header<'a>) -> IResult<&'a [u8], Output, E>, + E: ParseError<&'a [u8]> + From<BerError>, + T: Into<Tag>, +{ + let tag = tag.into(); + parse_ber_container(move |i, hdr| { + if hdr.class() == Class::Universal { + return Err(Err::Error( + BerError::unexpected_class(None, hdr.class()).into(), + )); + } + hdr.assert_tag(tag).map_err(|e| Err::Error(e.into()))?; + // X.690 8.14.2: if implicit tagging was not used, the encoding shall be constructed + hdr.assert_constructed().map_err(|e| Err::Error(e.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(Tag::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(Tag::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, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult +where + F: Fn(&'a [u8], &'_ Header, usize) -> BerResult<'a, BerObjectContent<'a>>, + T: Into<Tag>, +{ + 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(Tag::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(Tag::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, T, Output, F, E>( + tag: T, + f: F, +) -> impl FnMut(&'a [u8]) -> IResult<&[u8], Output, E> +where + F: Fn(&'a [u8], Header<'a>, usize) -> IResult<&'a [u8], Output, E>, + E: ParseError<&'a [u8]> + From<BerError>, + T: Into<Tag>, +{ + let tag = tag.into(); + parse_ber_container(move |i, hdr| { + hdr.assert_tag(tag).map_err(|e| Err::Error(e.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/src/ber/visit.rs b/rust/vendor/der-parser/src/ber/visit.rs new file mode 100644 index 0000000..a2d5669 --- /dev/null +++ b/rust/vendor/der-parser/src/ber/visit.rs @@ -0,0 +1,192 @@ +use super::{BerObject, BerObjectContent, BitStringObject}; +use asn1_rs::{ASN1DateTime, Any, Class, Oid, Tag}; + +/// BER object tree traversal to walk a shared borrow of a BER object +/// +/// When implementing your own visitor, define your own `visit_ber_xxx` methods. +/// +/// Note that `visit_ber` is called for every object, so if you implement multiple visitor methods they +/// will be called multiple times for the same object. Generally, if `visit_ber` is implemented, then other +/// methods are not needed. +/// +/// For example, on a `Sequence` item, `visit_ber` is called first, then `visit_ber_sequence`, and then +/// `visit_ber` for every sequence object (recursively). +/// +/// Entry point: use the [`Visit::run`] or [`Visit::run_at`] methods. +/// +/// Visitor functions +#[allow(unused_variables)] +pub trait Visit<'a> { + /// Called for every BER object + fn visit_ber(&mut self, ber: &'_ BerObject<'a>, depth: usize) {} + + /// Called for BER bitstring objects + fn visit_ber_bitstring(&mut self, ignored: u8, data: &'a BitStringObject, depth: usize) {} + + /// Called for BER bmpstring objects + fn visit_ber_bmpstring(&mut self, s: &'a str, depth: usize) {} + + /// Called for BER boolean objects + fn visit_ber_boolean(&mut self, b: bool, depth: usize) {} + + /// Called for BER end-of-content objects + fn visit_ber_endofcontent(&mut self, depth: usize) {} + + /// Called for BER enum objects + fn visit_ber_enum(&mut self, e: u64, depth: usize) {} + + /// Called for BER generalstring objects + fn visit_ber_generalstring(&mut self, s: &'a str, depth: usize) {} + + /// Called for BER generalizedtime objects + fn visit_ber_generalizedtime(&mut self, t: &'a ASN1DateTime, depth: usize) {} + + /// Called for BER graphicstring objects + fn visit_ber_graphicstring(&mut self, s: &'a str, depth: usize) {} + + /// Called for BER ia5string objects + fn visit_ber_ia5string(&mut self, s: &'a str, depth: usize) {} + + /// Called for BER integer objects + fn visit_ber_integer(&mut self, raw_bytes: &'a [u8], depth: usize) {} + + /// Called for BER null objects + fn visit_ber_null(&mut self, depth: usize) {} + + /// Called for BER numericstring objects + fn visit_ber_numericstring(&mut self, s: &'a str, depth: usize) {} + + /// Called for BER OID objects + fn visit_ber_oid(&mut self, oid: &'a Oid, depth: usize) {} + + /// Called for BER object descriptor objects + fn visit_ber_objectdescriptor(&mut self, s: &'a str, depth: usize) {} + + /// Called for BER octetstring objects + fn visit_ber_octetstring(&mut self, b: &'a [u8], depth: usize) {} + + /// Called for BER optional objects + fn visit_ber_optional(&mut self, obj: Option<&'a BerObject<'a>>, depth: usize) {} + + /// Called for BER printablestring objects + fn visit_ber_printablestring(&mut self, s: &'a str, depth: usize) {} + + /// Called for BER relative OID objects + fn visit_ber_relative_oid(&mut self, oid: &'a Oid, depth: usize) {} + + /// Called for BER sequence objects + fn visit_ber_sequence(&mut self, ber: &'_ [BerObject<'a>], depth: usize) {} + + /// Called for BER set objects + fn visit_ber_set(&mut self, ber: &'_ [BerObject<'a>], depth: usize) {} + + /// Called for BER teletexstring objects + fn visit_ber_teletexstring(&mut self, s: &'a str, depth: usize) {} + + /// Called for BER tagged objects + fn visit_ber_tagged(&mut self, class: Class, tag: Tag, obj: &'_ BerObject<'a>, depth: usize) {} + + /// Called for BER generalizedtime objects + fn visit_ber_utctime(&mut self, t: &'a ASN1DateTime, depth: usize) {} + + /// Called for BER utf8string objects + fn visit_ber_utf8string(&mut self, s: &'a str, depth: usize) {} + + /// Called for BER universalstring objects + fn visit_ber_universalstring(&mut self, raw_bytes: &'a [u8], depth: usize) {} + + /// Called for BER videotexstring objects + fn visit_ber_videotextstring(&mut self, raw_bytes: &'a str, depth: usize) {} + + /// Called for BER visiblestring objects + fn visit_ber_visiblestring(&mut self, raw_bytes: &'a str, depth: usize) {} + + /// Called for BER unknown objects + fn visit_ber_unknown(&mut self, ber: &'_ Any<'a>, depth: usize) {} + + /// Perform a BFS traversal of the BER object, calling the visitor functions during he traversal + /// + /// Usually, this method should not be redefined (unless implementing a custom traversal) + fn run(&mut self, ber: &'a BerObject<'a>) { + visit_ber_bfs(self, ber, 0) + } + + /// Perform a BFS traversal of the BER object, calling the visitor functions during he traversal + /// + /// Start at specified depth. + /// + /// Usually, this method should not be redefined (unless implementing a custom traversal) + fn run_at(&mut self, ber: &'a BerObject<'a>, depth: usize) { + visit_ber_bfs(self, ber, depth) + } +} + +fn visit_ber_bfs<'a, V>(v: &mut V, ber: &'a BerObject<'a>, depth: usize) +where + V: Visit<'a> + ?Sized, +{ + v.visit_ber(ber, depth); + + match ber.content { + BerObjectContent::BitString(ignored, ref data) => { + v.visit_ber_bitstring(ignored, data, depth); + } + BerObjectContent::BmpString(s) => v.visit_ber_bmpstring(s, depth), + BerObjectContent::Boolean(b) => v.visit_ber_boolean(b, depth), + BerObjectContent::EndOfContent => v.visit_ber_endofcontent(depth), + BerObjectContent::Enum(val) => v.visit_ber_enum(val, depth), + BerObjectContent::GeneralString(s) => v.visit_ber_generalstring(s, depth), + BerObjectContent::GeneralizedTime(ref t) => v.visit_ber_generalizedtime(t, depth), + BerObjectContent::GraphicString(s) => v.visit_ber_graphicstring(s, depth), + BerObjectContent::IA5String(s) => v.visit_ber_ia5string(s, depth), + BerObjectContent::Integer(s) => v.visit_ber_integer(s, depth), + BerObjectContent::Null => v.visit_ber_null(depth), + BerObjectContent::NumericString(s) => v.visit_ber_numericstring(s, depth), + BerObjectContent::OID(ref oid) => v.visit_ber_oid(oid, depth), + BerObjectContent::ObjectDescriptor(s) => v.visit_ber_objectdescriptor(s, depth), + BerObjectContent::OctetString(b) => v.visit_ber_octetstring(b, depth), + BerObjectContent::Optional(ref obj) => { + let opt = obj.as_ref().map(|b| b.as_ref()); + v.visit_ber_optional(opt, depth) + } + BerObjectContent::PrintableString(s) => v.visit_ber_printablestring(s, depth), + BerObjectContent::RelativeOID(ref oid) => v.visit_ber_relative_oid(oid, depth), + BerObjectContent::Sequence(ref l) => { + v.visit_ber_sequence(l, depth); + for item in l.iter() { + visit_ber_bfs(v, item, depth + 1); + } + } + BerObjectContent::Set(ref l) => { + v.visit_ber_set(l, depth); + for item in l.iter() { + visit_ber_bfs(v, item, depth + 1); + } + } + BerObjectContent::T61String(s) => v.visit_ber_teletexstring(s, depth), + BerObjectContent::Tagged(class, tag, ref obj) => { + v.visit_ber_tagged(class, tag, obj.as_ref(), depth) + } + BerObjectContent::UTCTime(ref t) => v.visit_ber_utctime(t, depth), + BerObjectContent::UTF8String(s) => v.visit_ber_utf8string(s, depth), + BerObjectContent::UniversalString(b) => v.visit_ber_universalstring(b, depth), + BerObjectContent::Unknown(ref inner) => v.visit_ber_unknown(inner, depth), + BerObjectContent::VideotexString(s) => v.visit_ber_videotextstring(s, depth), + BerObjectContent::VisibleString(s) => v.visit_ber_visiblestring(s, depth), + } +} + +#[cfg(test)] +mod tests { + use super::Visit; + use crate::ber::BerObject; + + #[derive(Debug)] + struct BerObjectVisitor {} + + impl<'a> Visit<'a> for BerObjectVisitor { + fn visit_ber(&mut self, ber: &'_ BerObject<'a>, depth: usize) { + eprintln!("Depth {}: Object with tag {}", depth, ber.tag()); + } + } +} diff --git a/rust/vendor/der-parser/src/ber/visit_mut.rs b/rust/vendor/der-parser/src/ber/visit_mut.rs new file mode 100644 index 0000000..1ff86be --- /dev/null +++ b/rust/vendor/der-parser/src/ber/visit_mut.rs @@ -0,0 +1,206 @@ +use super::{BerObject, BerObjectContent, BitStringObject}; +use alloc::vec::Vec; +use asn1_rs::{ASN1DateTime, Any, Class, Oid, Tag}; + +/// BER object tree traversal to walk a shared borrow of a BER object +/// +/// When implementing your own visitor, define your own `visit_ber_xxx` methods. +/// +/// Note that `visit_ber` is called for every object, so if you implement multiple visitor methods they +/// will be called multiple times for the same object. Generally, if `visit_ber` is implemented, then other +/// methods are not needed. +/// +/// For example, on a `Sequence` item, `visit_ber` is called first, then `visit_ber_sequence`, and then +/// `visit_ber` for every sequence object (recursively). +/// +/// Entry point: use the [`VisitMut::run`] or [`VisitMut::run_at`] methods. +/// +/// Visitor functions +#[allow(unused_variables)] +pub trait VisitMut<'a> { + /// Called for every BER object + fn visit_ber_mut(&mut self, ber: &'_ mut BerObject<'a>, depth: usize) {} + + /// Called for BER bitstring objects + fn visit_ber_bitstring_mut( + &mut self, + ignored: &mut u8, + data: &'a mut BitStringObject, + depth: usize, + ) { + } + + /// Called for BER bmpstring objects + fn visit_ber_bmpstring_mut(&mut self, s: &'a mut &'_ str, depth: usize) {} + + /// Called for BER boolean objects + fn visit_ber_boolean_mut(&mut self, b: &'a mut bool, depth: usize) {} + + /// Called for BER end-of-content objects + fn visit_ber_endofcontent_mut(&mut self, depth: usize) {} + + /// Called for BER enum objects + fn visit_ber_enum_mut(&mut self, e: &'a mut u64, depth: usize) {} + + /// Called for BER generalstring objects + fn visit_ber_generalstring_mut(&mut self, s: &'a mut &'_ str, depth: usize) {} + + /// Called for BER generalizedtime objects + fn visit_ber_generalizedtime_mut(&mut self, t: &'a ASN1DateTime, depth: usize) {} + + /// Called for BER graphicstring objects + fn visit_ber_graphicstring_mut(&mut self, s: &'a mut &'_ str, depth: usize) {} + + /// Called for BER ia5string objects + fn visit_ber_ia5string_mut(&mut self, s: &'a mut &'_ str, depth: usize) {} + + /// Called for BER integer objects + fn visit_ber_integer_mut(&mut self, raw_bytes: &'a mut &'_ [u8], depth: usize) {} + + /// Called for BER null objects + fn visit_ber_null_mut(&mut self, depth: usize) {} + + /// Called for BER numericstring objects + fn visit_ber_numericstring_mut(&mut self, s: &'a mut &'_ str, depth: usize) {} + + /// Called for BER OID objects + fn visit_ber_oid_mut(&mut self, oid: &'a mut Oid, depth: usize) {} + + /// Called for BER object descriptor objects + fn visit_ber_objectdescriptor_mut(&mut self, s: &'a mut &'_ str, depth: usize) {} + + /// Called for BER octetstring objects + fn visit_ber_octetstring_mut(&mut self, b: &'a [u8], depth: usize) {} + + /// Called for BER optional objects + fn visit_ber_optional_mut(&mut self, obj: Option<&'a mut BerObject<'a>>, depth: usize) {} + + /// Called for BER printablestring objects + fn visit_ber_printablestring_mut(&mut self, s: &'a mut &'_ str, depth: usize) {} + + /// Called for BER relative OID objects + fn visit_ber_relative_oid_mut(&mut self, oid: &'a mut Oid, depth: usize) {} + + /// Called for BER sequence objects + fn visit_ber_sequence_mut(&mut self, l: &'_ mut Vec<BerObject<'a>>, depth: usize) {} + + /// Called for BER set objects + fn visit_ber_set_mut(&mut self, ber: &'_ mut Vec<BerObject<'a>>, depth: usize) {} + + /// Called for BER teletexstring objects + fn visit_ber_teletexstring_mut(&mut self, s: &'a mut &'_ str, depth: usize) {} + + /// Called for BER tagged objects + fn visit_ber_tagged_mut( + &mut self, + class: &'a mut Class, + tag: &'a mut Tag, + obj: &'a mut BerObject<'a>, + depth: usize, + ) { + } + + /// Called for BER generalizedtime objects + fn visit_ber_utctime_mut(&mut self, t: &'a ASN1DateTime, depth: usize) {} + + /// Called for BER utf8string objects + fn visit_ber_utf8string_mut(&mut self, s: &'a str, depth: usize) {} + + /// Called for BER universalstring objects + fn visit_ber_universalstring_mut(&mut self, raw_bytes: &'a mut &'_ [u8], depth: usize) {} + + /// Called for BER videotexstring objects + fn visit_ber_videotextstring_mut(&mut self, raw_bytes: &'a mut &'_ str, depth: usize) {} + + /// Called for BER visiblestring objects + fn visit_ber_visiblestring_mut(&mut self, raw_bytes: &'a mut &'_ str, depth: usize) {} + + /// Called for BER unknown objects + fn visit_ber_unknown_mut(&mut self, ber: &'_ mut Any<'a>, depth: usize) {} + + /// Perform a BFS traversal of the BER object, calling the visitor functions during he traversal + /// + /// Usually, this method should not be redefined (unless implementing a custom traversal) + fn run(&mut self, ber: &'a mut BerObject<'a>) { + visit_ber_bfs_mut(self, ber, 0) + } + + /// Perform a BFS traversal of the BER object, calling the visitor functions during he traversal + /// + /// Start at specified depth. + /// + /// Usually, this method should not be redefined (unless implementing a custom traversal) + fn run_at(&mut self, ber: &'a mut BerObject<'a>, depth: usize) { + visit_ber_bfs_mut(self, ber, depth) + } +} + +fn visit_ber_bfs_mut<'a, V>(v: &mut V, ber: &'a mut BerObject<'a>, depth: usize) +where + V: VisitMut<'a> + ?Sized, +{ + v.visit_ber_mut(ber, depth); + + match ber.content { + BerObjectContent::BitString(ref mut ignored, ref mut data) => { + v.visit_ber_bitstring_mut(ignored, data, depth); + } + BerObjectContent::BmpString(ref mut s) => v.visit_ber_bmpstring_mut(s, depth), + BerObjectContent::Boolean(ref mut b) => v.visit_ber_boolean_mut(b, depth), + BerObjectContent::EndOfContent => v.visit_ber_endofcontent_mut(depth), + BerObjectContent::Enum(ref mut val) => v.visit_ber_enum_mut(val, depth), + BerObjectContent::GeneralString(ref mut s) => v.visit_ber_generalstring_mut(s, depth), + BerObjectContent::GeneralizedTime(ref t) => v.visit_ber_generalizedtime_mut(t, depth), + BerObjectContent::GraphicString(ref mut s) => v.visit_ber_graphicstring_mut(s, depth), + BerObjectContent::IA5String(ref mut s) => v.visit_ber_ia5string_mut(s, depth), + BerObjectContent::Integer(ref mut s) => v.visit_ber_integer_mut(s, depth), + BerObjectContent::Null => v.visit_ber_null_mut(depth), + BerObjectContent::NumericString(ref mut s) => v.visit_ber_numericstring_mut(s, depth), + BerObjectContent::OID(ref mut oid) => v.visit_ber_oid_mut(oid, depth), + BerObjectContent::ObjectDescriptor(ref mut s) => v.visit_ber_objectdescriptor_mut(s, depth), + BerObjectContent::OctetString(ref mut b) => v.visit_ber_octetstring_mut(b, depth), + BerObjectContent::Optional(ref mut obj) => { + let opt = obj.as_mut().map(|b| b.as_mut()); + v.visit_ber_optional_mut(opt, depth) + } + BerObjectContent::PrintableString(ref mut s) => v.visit_ber_printablestring_mut(s, depth), + BerObjectContent::RelativeOID(ref mut oid) => v.visit_ber_relative_oid_mut(oid, depth), + BerObjectContent::Sequence(ref mut l) => { + v.visit_ber_sequence_mut(l, depth); + for item in l.iter_mut() { + visit_ber_bfs_mut(v, item, depth + 1); + } + } + BerObjectContent::Set(ref mut l) => { + v.visit_ber_set_mut(l, depth); + for item in l.iter_mut() { + visit_ber_bfs_mut(v, item, depth + 1); + } + } + BerObjectContent::T61String(ref mut s) => v.visit_ber_teletexstring_mut(s, depth), + BerObjectContent::Tagged(ref mut class, ref mut tag, ref mut obj) => { + v.visit_ber_tagged_mut(class, tag, obj.as_mut(), depth) + } + BerObjectContent::UTCTime(ref t) => v.visit_ber_utctime_mut(t, depth), + BerObjectContent::UTF8String(ref mut s) => v.visit_ber_utf8string_mut(s, depth), + BerObjectContent::UniversalString(ref mut b) => v.visit_ber_universalstring_mut(b, depth), + BerObjectContent::Unknown(ref mut inner) => v.visit_ber_unknown_mut(inner, depth), + BerObjectContent::VideotexString(ref mut s) => v.visit_ber_videotextstring_mut(s, depth), + BerObjectContent::VisibleString(ref mut s) => v.visit_ber_visiblestring_mut(s, depth), + } +} + +#[cfg(test)] +mod tests { + use super::VisitMut; + use crate::ber::BerObject; + + #[derive(Debug)] + struct BerObjectVisitor {} + + impl<'a> VisitMut<'a> for BerObjectVisitor { + fn visit_ber_mut(&mut self, ber: &'_ mut BerObject<'a>, depth: usize) { + eprintln!("Depth {}: Object with tag {}", depth, ber.tag()); + } + } +} diff --git a/rust/vendor/der-parser/src/ber/wrap_any.rs b/rust/vendor/der-parser/src/ber/wrap_any.rs new file mode 100644 index 0000000..7543cc4 --- /dev/null +++ b/rust/vendor/der-parser/src/ber/wrap_any.rs @@ -0,0 +1,213 @@ +use super::{BerObject, BerObjectContent, BitStringObject}; +use crate::ber::{ber_get_object_content, MAX_OBJECT_SIZE}; +use crate::error::{BerError, BerResult}; +use alloc::vec::Vec; +use asn1_rs::*; +use nom::Err; +use rusticata_macros::custom_check; + +/// Parse any BER object recursively, specifying the maximum recursion depth and expected tag +/// +/// Raise an error if the maximum recursion depth was reached. +pub fn parse_ber_any_with_tag_r(i: &[u8], tag: Tag, max_depth: usize) -> BerResult { + custom_check!(i, max_depth == 0, BerError::BerMaxDepth)?; + let (rem, any) = Any::from_ber(i)?; + any.header.assert_tag(tag)?; + let obj = try_berobject_from_any(any, max_depth)?; + Ok((rem, obj)) +} + +/// Parse any BER object recursively, specifying the maximum recursion depth +/// +/// Raise an error if the maximum recursion depth was reached. +pub fn parse_ber_any_r(i: &[u8], max_depth: usize) -> BerResult { + custom_check!(i, max_depth == 0, BerError::BerMaxDepth)?; + let (rem, any) = Any::from_ber(i)?; + let obj = try_berobject_from_any(any, max_depth)?; + Ok((rem, obj)) +} + +/// Parse any BER object (not recursive) +pub fn parse_ber_any(i: &[u8]) -> BerResult<Any> { + Any::from_ber(i) +} + +macro_rules! from_obj { + ($header:ident, $content:expr) => { + BerObject::from_header_and_content($header, $content) + }; + (STRING $ty:ident, $any:ident, $header:ident) => { + from_obj!(STRING $ty, $ty, $any, $header) + }; + // macro variant when enum variant is not the same as char type + (STRING $ty:ident, $variant:ident, $any:ident, $header:ident) => {{ + custom_check!($any.data, $header.constructed(), BerError::Unsupported)?; // XXX valid in BER (8.21) + <$ty>::test_valid_charset($any.data)?; + let s = core::str::from_utf8($any.data)?; + Ok(BerObject::from_header_and_content( + $header, + BerObjectContent::$variant(s), + )) + }}; +} + +/// Read element content as Universal object, or Unknown +// TODO implement the function for BerObjectContent (to replace ber_read_element_content_as) +// note: we cannot implement TryFrom because of the `max_depth` argument +pub(crate) fn try_read_berobjectcontent_as( + i: &[u8], + tag: Tag, + length: Length, + constructed: bool, + max_depth: usize, +) -> BerResult<BerObjectContent> { + if let Length::Definite(l) = length { + custom_check!(i, l > MAX_OBJECT_SIZE, BerError::InvalidLength)?; + if i.len() < l { + return Err(Err::Incomplete(Needed::new(l))); + } + } + let header = Header::new(Class::Universal, constructed, tag, length); + let (rem, i) = ber_get_object_content(i, &header, max_depth)?; + let any = Any::new(header, i); + let object = try_berobject_from_any(any, max_depth)?; + Ok((rem, object.content)) +} + +// note: we cannot implement TryFrom because of the `max_depth` argument +fn try_berobject_from_any(any: Any, max_depth: usize) -> Result<BerObject> { + custom_check!(any.data, max_depth == 0, BerError::BerMaxDepth)?; + let obj_from = BerObject::from_header_and_content; + let header = any.header.clone(); + if any.class() != Class::Universal { + return Ok(obj_from(header, BerObjectContent::Unknown(any))); + } + match any.tag() { + Tag::BitString => { + if any.data.is_empty() { + return Err(BerError::BerValueError); + } + custom_check!(any.data, header.constructed(), BerError::Unsupported)?; // XXX valid in BER (8.6.3) + let ignored_bits = any.data[0]; + let data = &any.data[1..]; + Ok(obj_from( + header, + BerObjectContent::BitString(ignored_bits, BitStringObject { data }), + )) + } + Tag::BmpString => from_obj!(STRING BmpString, any, header), + Tag::Boolean => { + let b = any.bool()?; + Ok(obj_from(header, BerObjectContent::Boolean(b))) + } + Tag::EndOfContent => Ok(obj_from(header, BerObjectContent::EndOfContent)), + Tag::Enumerated => { + let obj = any.enumerated()?; + Ok(obj_from(header, BerObjectContent::Enum(obj.0 as u64))) + } + Tag::GeneralizedTime => { + let time = any.generalizedtime()?; + Ok(obj_from(header, BerObjectContent::GeneralizedTime(time.0))) + } + Tag::GeneralString => from_obj!(STRING GeneralString, any, header), + Tag::GraphicString => from_obj!(STRING GraphicString, any, header), + Tag::Ia5String => from_obj!(STRING Ia5String, IA5String, any, header), + Tag::Integer => { + let obj = obj_from(header, BerObjectContent::Integer(any.data)); + Ok(obj) + } + Tag::Null => Ok(obj_from(header, BerObjectContent::Null)), + Tag::NumericString => from_obj!(STRING NumericString, any, header), + Tag::ObjectDescriptor => from_obj!(STRING ObjectDescriptor, any, header), + Tag::OctetString => Ok(obj_from(header, BerObjectContent::OctetString(any.data))), + Tag::Oid => { + let oid = any.oid()?; + Ok(obj_from(header, BerObjectContent::OID(oid))) + } + Tag::PrintableString => from_obj!(STRING PrintableString, any, header), + Tag::RelativeOid => { + let oid = any.relative_oid()?; + Ok(obj_from(header, BerObjectContent::RelativeOID(oid))) + } + Tag::Sequence => { + header.assert_constructed()?; + let objects: Result<Vec<_>> = SequenceIterator::<Any, BerParser>::new(any.data) + .map(|item| { + let item = item?; + try_berobject_from_any(item, max_depth - 1) + }) + .collect(); + let objects = objects?; + Ok(obj_from(header, BerObjectContent::Sequence(objects))) + } + Tag::Set => { + header.assert_constructed()?; + let objects: Result<Vec<_>> = SetIterator::<Any, BerParser>::new(any.data) + .map(|item| { + let item = item?; + try_berobject_from_any(item, max_depth - 1) + }) + .collect(); + let objects = objects?; + Ok(obj_from(header, BerObjectContent::Set(objects))) + } + Tag::TeletexString => from_obj!(STRING TeletexString, T61String, any, header), + Tag::UtcTime => { + let time = any.utctime()?; + Ok(obj_from(header, BerObjectContent::UTCTime(time.0))) + } + Tag::UniversalString => { + custom_check!(any.data, header.constructed(), BerError::Unsupported)?; // XXX valid in BER (8.21) + + // as detailed in asn1-rs, UniversalString allocates memory since the UCS-4 to UTF-8 conversion requires a memory allocation. + // so, the charset is not checked here + Ok(obj_from( + header, + BerObjectContent::UniversalString(any.data), + )) + } + Tag::Utf8String => from_obj!(STRING Utf8String, UTF8String, any, header), + Tag::VideotexString => from_obj!(STRING VideotexString, any, header), + Tag::VisibleString => from_obj!(STRING VisibleString, any, header), + _ => { + // Note for: Tag::EmbeddedPdv | Tag::External | Tag::RealType + // these types have no mapping in the BerObjectContent enum, + // so we use the Unknown type + Ok(obj_from(header, BerObjectContent::Unknown(any))) + } + } +} + +#[cfg(test)] +mod tests { + use crate::ber::{BerObject, BerObjectContent, MAX_RECURSION}; + use crate::error::BerError; + use hex_literal::hex; + use test_case::test_case; + + use super::parse_ber_any_r; + + #[test_case(&hex!("01 01 00") => matches Ok(BerObject{header:_, content:BerObjectContent::Boolean(false)}) ; "val false")] + #[test_case(&hex!("01 01 ff") => matches Ok(BerObject{header:_, content:BerObjectContent::Boolean(true)}) ; "val true")] + #[test_case(&hex!("01 01 7f") => matches Ok(BerObject{header:_, content:BerObjectContent::Boolean(true)}) ; "true not ff")] + #[test_case(&hex!("02 02 00 ff") => matches Ok(BerObject{header:_, content:BerObjectContent::Integer(_)}) ; "u32-255")] + #[test_case(&hex!("02 02 01 23") => matches Ok(BerObject{header:_, content:BerObjectContent::Integer(_)}) ; "u32-0x123")] + #[test_case(&hex!("02 04 ff ff ff ff") => matches Ok(BerObject{header:_, content:BerObjectContent::Integer(_)}) ; "u32-long-neg")] + #[test_case(&hex!("0c 04 31 32 33 34") => matches Ok(BerObject{header:_, content:BerObjectContent::UTF8String("1234")}) ; "utf8: numeric")] + #[test_case(&hex!("0d 04 c2 7b 03 02") => matches Ok(BerObject{header:_, content:BerObjectContent::RelativeOID(_)}) ; "relative OID")] + #[test_case(&hex!("12 04 31 32 33 34") => matches Ok(BerObject{header:_, content:BerObjectContent::NumericString("1234")}) ; "numeric string")] + #[test_case(&hex!("12 04 01 02 03 04") => matches Err(BerError::StringInvalidCharset) ; "numeric string err")] + #[test_case(&hex!("13 04 31 32 33 34") => matches Ok(BerObject{header:_, content:BerObjectContent::PrintableString("1234")}) ; "printable string")] + #[test_case(&hex!("13 04 01 02 03 04") => matches Err(BerError::StringInvalidCharset) ; "printable string err")] + #[test_case(&hex!("16 04 31 32 33 34") => matches Ok(BerObject{header:_, content:BerObjectContent::IA5String("1234")}) ; "ia5: numeric")] + #[test_case(&hex!("1a 04 31 32 33 34") => matches Ok(BerObject{header:_, content:BerObjectContent::VisibleString("1234")}) ; "visible: numeric")] + #[test_case(&hex!("1e 08 00 55 00 73 00 65 00 72") => matches Ok(BerObject{header:_, content:BerObjectContent::BmpString("\x00U\x00s\x00e\x00r")}) ; "bmp")] + #[test_case(&hex!("30 80 04 03 56 78 90 00 00") => matches Ok(BerObject{header:_, content:BerObjectContent::Sequence(_)}) ; "indefinite length")] + #[test_case(&hex!("c0 03 01 00 01") => matches Ok(BerObject{header:_, content:BerObjectContent::Unknown(_)}) ; "private")] + fn ber_from_any(i: &[u8]) -> Result<BerObject, BerError> { + let (rem, res) = parse_ber_any_r(i, MAX_RECURSION)?; + assert!(rem.is_empty()); + // dbg!(&res); + Ok(res) + } +} diff --git a/rust/vendor/der-parser/src/der/mod.rs b/rust/vendor/der-parser/src/der/mod.rs new file mode 100644 index 0000000..558d25a --- /dev/null +++ b/rust/vendor/der-parser/src/der/mod.rs @@ -0,0 +1,93 @@ +//! 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::{BerObject, BerObjectContent}; +pub use crate::ber::{Class, Header}; +pub use asn1_rs::Tag; + +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; + +/// DER Object class of tag (same as `BerClass`) +#[deprecated(since = "7.0.0", note = "Use `Class` instead")] +pub type DerClass = Class; + +/// DER tag (same as BER tag) +#[deprecated(since = "7.0.0", note = "Use `Tag` instead")] +pub type DerTag = Tag; + +/// 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`. +#[deprecated(since = "7.0.0", note = "Use `Tag` instead")] +pub type DerObjectHeader<'a> = Header<'a>; + +/// BER object content +/// +/// This is the same object as `BerObjectContent`. +pub type DerObjectContent<'a> = BerObjectContent<'a>; diff --git a/rust/vendor/der-parser/src/der/multi.rs b/rust/vendor/der-parser/src/der/multi.rs new file mode 100644 index 0000000..9b20eb8 --- /dev/null +++ b/rust/vendor/der-parser/src/der/multi.rs @@ -0,0 +1,534 @@ +use crate::ber::Length; +use crate::der::*; +use crate::error::*; +use nom::bytes::complete::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], Header<'a>) -> IResult<&'a [u8], O, E>, + E: ParseError<&'a [u8]> + From<BerError>, +{ + parse_der_container(move |i, hdr| { + hdr.assert_tag(Tag::Sequence) + .map_err(|e| Err::Error(e.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], Header<'a>) -> IResult<&'a [u8], O, E>, + E: ParseError<&'a [u8]> + From<BerError>, +{ + parse_der_container(move |i, hdr| { + hdr.assert_tag(Tag::Set).map_err(|e| Err::Error(e.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 constructed 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: Header| { +/// if hdr.tag() != Tag::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], Header<'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.length() { + Length::Definite(len) => take(len)(i)?, + Length::Indefinite => { + return Err(Err::Error( + BerError::DerConstraintFailed(DerConstraint::IndefiniteLength).into(), + )); + } + }; + let (_rest, v) = f(data, hdr)?; + Ok((i, v)) + } +} diff --git a/rust/vendor/der-parser/src/der/parser.rs b/rust/vendor/der-parser/src/der/parser.rs new file mode 100644 index 0000000..273ea62 --- /dev/null +++ b/rust/vendor/der-parser/src/der/parser.rs @@ -0,0 +1,632 @@ +use crate::ber::*; +use crate::der::*; +use crate::der_constraint_fail_if; +use crate::error::*; +use alloc::borrow::ToOwned; +use asn1_rs::{Any, FromDer, Tag}; +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, Tag}; +/// +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (_, obj) = parse_der(bytes).expect("parsing failed"); +/// +/// assert_eq!(obj.header.tag(), Tag::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, Tag}; +/// +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (_, obj) = parse_der_recursive(bytes, 1).expect("parsing failed"); +/// +/// assert_eq!(obj.header.tag(), Tag::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 Length::Definite(l) = hdr.length() { + custom_check!(i, l > MAX_OBJECT_SIZE, BerError::InvalidLength)?; + } + der_read_element_content_recursive(i, hdr, max_depth) +} + +/// 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, Tag}; +/// +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (_, obj) = parse_der_with_tag(bytes, Tag::Integer).expect("parsing failed"); +/// +/// assert_eq!(obj.header.tag(), Tag::Integer); +/// ``` +pub fn parse_der_with_tag<T: Into<Tag>>(i: &[u8], tag: T) -> DerResult { + let tag = tag.into(); + let (i, hdr) = der_read_element_header(i)?; + hdr.assert_tag(tag)?; + let (i, content) = der_read_element_content_as( + i, + hdr.tag(), + hdr.length(), + 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, Tag::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, Tag::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, Tag::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, Tag::BitString) +} + +/// Read an octetstring value +#[inline] +pub fn parse_der_octetstring(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::OctetString) +} + +/// Read a null value +#[inline] +pub fn parse_der_null(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::Null) +} + +/// Read an object identifier value +#[inline] +pub fn parse_der_oid(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::Oid) +} + +/// Read an enumerated value +#[inline] +pub fn parse_der_enum(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::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, Tag::Utf8String) +} + +/// Read a relative object identifier value +#[inline] +pub fn parse_der_relative_oid(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::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 constructed 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, Tag::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 constructed 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, Tag::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, Tag::NumericString) +} + +/// Read a printable string value. The content is verified to +/// contain only the allowed characters. +#[inline] +pub fn parse_der_visiblestring(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::VisibleString) +} + +#[deprecated(since = "8.2.0", note = "Use `parse_der_visiblestring` instead")] +#[inline] +pub fn visiblestring(i: &[u8]) -> DerResult { + parse_der_visiblestring(i) +} + +/// 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, Tag::PrintableString) +} + +/// Read a T61 string value +#[inline] +pub fn parse_der_t61string(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::T61String) +} + +/// Read a Videotex string value +#[inline] +pub fn parse_der_videotexstring(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::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, Tag::Ia5String) +} + +/// Read an UTC time value +#[inline] +pub fn parse_der_utctime(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::UtcTime) +} + +/// Read a Generalized time value +#[inline] +pub fn parse_der_generalizedtime(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::GeneralizedTime) +} + +/// Read a ObjectDescriptor value +#[inline] +pub fn parse_der_objectdescriptor(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::ObjectDescriptor) +} + +/// Read a GraphicString value +#[inline] +pub fn parse_der_graphicstring(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::GraphicString) +} + +/// Read a GeneralString value +#[inline] +pub fn parse_der_generalstring(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::GeneralString) +} + +/// Read a BmpString value +#[inline] +pub fn parse_der_bmpstring(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::BmpString) +} + +/// Read a UniversalString value +#[inline] +pub fn parse_der_universalstring(i: &[u8]) -> DerResult { + parse_der_with_tag(i, Tag::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: Tag, 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(Tag::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, T, F>(i: &'a [u8], tag: T, f: F) -> DerResult<'a> +where + F: Fn(&'a [u8], &'_ Header, usize) -> BerResult<'a, DerObjectContent<'a>>, + T: Into<Tag>, +{ + 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> { + <i32>::from_der(i) +} + +/// 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> { + <i64>::from_der(i) +} + +/// 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> { + <u32>::from_der(i) +} + +/// 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> { + <u64>::from_der(i) +} + +/// Parse DER object and get content as slice +#[inline] +pub fn parse_der_slice<T: Into<Tag>>(i: &[u8], tag: T) -> BerResult<&[u8]> { + let tag = tag.into(); + parse_der_container(move |content, hdr| { + hdr.assert_tag(tag)?; + 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(), Tag::Integer); +/// ``` +pub fn parse_der_content<'a>( + tag: Tag, +) -> impl Fn(&'a [u8], &'_ Header, usize) -> BerResult<'a, DerObjectContent<'a>> { + move |i: &[u8], hdr: &Header, max_recursion: usize| { + der_read_element_content_as(i, tag, hdr.length(), 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(), Tag::Integer); +/// let (rem, content) = parse_der_content2(header.tag())(i, header, MAX_RECURSION) +/// .expect("parsing failed"); +/// ``` +pub fn parse_der_content2<'a>( + tag: Tag, +) -> impl Fn(&'a [u8], Header<'a>, usize) -> BerResult<'a, DerObjectContent<'a>> { + move |i: &[u8], hdr: Header, max_recursion: usize| { + der_read_element_content_as(i, tag, hdr.length(), 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: Tag, + length: Length, + constructed: bool, + max_depth: usize, +) -> BerResult<DerObjectContent> { + // Indefinite lengths are not allowed in DER (X.690 section 10.1) + let l = length.definite().map_err(BerError::from)?; + if i.len() < l { + return Err(Err::Incomplete(Needed::new(l))); + } + match tag { + Tag::Boolean => { + custom_check!(i, l != 1, BerError::InvalidLength)?; + der_constraint_fail_if!(i, i[0] != 0 && i[0] != 0xff, DerConstraint::InvalidBoolean); + } + Tag::BitString => { + der_constraint_fail_if!(i, constructed, DerConstraint::Constructed); + // exception: read and verify padding bits + return der_read_content_bitstring(i, l); + } + Tag::Integer => { + // verify leading zeros + match i[..l] { + [] => { + return Err(nom::Err::Error(BerError::DerConstraintFailed( + DerConstraint::IntegerEmpty, + ))) + } + [0, 0, ..] => { + return Err(nom::Err::Error(BerError::DerConstraintFailed( + DerConstraint::IntegerLeadingZeroes, + ))) + } + [0, byte, ..] if byte < 0x80 => { + return Err(nom::Err::Error(BerError::DerConstraintFailed( + DerConstraint::IntegerLeadingZeroes, + ))); + } + _ => (), + } + } + Tag::NumericString + | Tag::VisibleString + | Tag::PrintableString + | Tag::Ia5String + | Tag::Utf8String + | Tag::T61String + | Tag::VideotexString + | Tag::BmpString + | Tag::UniversalString + | Tag::ObjectDescriptor + | Tag::GraphicString + | Tag::GeneralString => { + der_constraint_fail_if!(i, constructed, DerConstraint::Constructed); + } + Tag::UtcTime | Tag::GeneralizedTime => { + if l == 0 || i.get(l - 1).cloned() != Some(b'Z') { + return Err(Err::Error(BerError::DerConstraintFailed( + DerConstraint::MissingTimeZone, + ))); + } + } + _ => (), + } + ber_read_element_content_as(i, tag, length, 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: Header<'a>) -> DerResult<'a> { + der_read_element_content_recursive(i, hdr, MAX_RECURSION) +} + +fn der_read_element_content_recursive<'a>( + i: &'a [u8], + hdr: Header<'a>, + max_depth: usize, +) -> DerResult<'a> { + match hdr.class() { + Class::Universal => (), + _ => { + let (i, data) = ber_get_object_content(i, &hdr, max_depth)?; + let any = Any::new(hdr.clone(), data); + let content = DerObjectContent::Unknown(any); + let obj = DerObject::from_header_and_content(hdr, content); + return Ok((i, obj)); + } + } + match der_read_element_content_as(i, hdr.tag(), hdr.length(), hdr.is_constructed(), max_depth) { + Ok((rem, content)) => Ok((rem, DerObject::from_header_and_content(hdr, content))), + Err(Err::Error(BerError::UnknownTag(_))) => { + let (rem, data) = ber_get_object_content(i, &hdr, max_depth)?; + let any = Any::new(hdr.clone(), data); + let content = DerObjectContent::Unknown(any); + 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::invalid_value( + Tag::BitString, + "More than 7 unused bits".to_owned(), + ))); + } + 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, DerConstraint::UnusedBitsNotZero); + 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) +#[inline] +pub fn der_read_element_header(i: &[u8]) -> BerResult<Header> { + Header::from_der(i) +} diff --git a/rust/vendor/der-parser/src/der/tagged.rs b/rust/vendor/der-parser/src/der/tagged.rs new file mode 100644 index 0000000..83b8bc7 --- /dev/null +++ b/rust/vendor/der-parser/src/der/tagged.rs @@ -0,0 +1,261 @@ +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, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult +where + F: Fn(&'a [u8]) -> BerResult<DerObject>, + T: Into<Tag>, +{ + 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, T, Output, F, E>( + tag: T, + f: F, +) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Output, E> +where + F: Fn(&'a [u8], Header<'a>) -> IResult<&'a [u8], Output, E>, + E: ParseError<&'a [u8]> + From<BerError>, + T: Into<Tag>, +{ + let tag = tag.into(); + parse_der_container(move |i, hdr| { + if hdr.class() == Class::Universal { + return Err(Err::Error( + BerError::unexpected_class(None, hdr.class()).into(), + )); + } + hdr.assert_tag(tag).map_err(|e| Err::Error(e.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(Tag::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(Tag::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, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult +where + F: Fn(&'a [u8], &'_ Header, usize) -> BerResult<'a, DerObjectContent<'a>>, + T: Into<Tag>, +{ + 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(Tag::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(Tag::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, T, Output, F, E>( + tag: T, + f: F, +) -> impl FnMut(&'a [u8]) -> IResult<&[u8], Output, E> +where + F: Fn(&'a [u8], Header<'a>, usize) -> IResult<&'a [u8], Output, E>, + E: ParseError<&'a [u8]> + From<BerError>, + T: Into<Tag>, +{ + let tag = tag.into(); + parse_der_container(move |i, hdr| { + hdr.assert_tag(tag).map_err(|e| Err::Error(e.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/src/error.rs b/rust/vendor/der-parser/src/error.rs new file mode 100644 index 0000000..1644594 --- /dev/null +++ b/rust/vendor/der-parser/src/error.rs @@ -0,0 +1,39 @@ +//! Error type for BER/DER parsers + +use crate::ber::BerObject; +use crate::der::DerObject; +use nom::IResult; + +pub use asn1_rs::{DerConstraint, Error}; + +pub type BerError = Error; + +// pub use asn1_rs::Result; + +/// 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>>; + +#[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/src/lib.rs b/rust/vendor/der-parser/src/lib.rs new file mode 100644 index 0000000..089e2b4 --- /dev/null +++ b/rust/vendor/der-parser/src/lib.rs @@ -0,0 +1,278 @@ +//! [![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/8.2.0/status.svg)](https://deps.rs/crate/der-parser/8.2.0) +//! [![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.53.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 7.0 series of `der-parser` requires **Rustc version 1.53 or greater**, based on `asn1-rs` +//! and `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 asn1_rs; +pub use nom; +#[cfg(feature = "bigint")] +#[cfg_attr(docsrs, doc(cfg(feature = "bigint")))] +pub use num_bigint; +pub use rusticata_macros; + +// re-exports nom macros, so this crate's macros can be used without importing nom +pub use nom::IResult; + +pub(crate) use asn1_rs::der_constraint_fail_if; + +pub use asn1_rs::Oid; + +/// Procedural macro to get encoded oids, see the [oid module](oid/index.html). +#[macro_export] +macro_rules! oid { + ($($args:tt)*) => {{ + $crate::asn1_rs::oid!($($args)*) + }}; +} diff --git a/rust/vendor/der-parser/src/oid.rs b/rust/vendor/der-parser/src/oid.rs new file mode 100644 index 0000000..f35b52b --- /dev/null +++ b/rust/vendor/der-parser/src/oid.rs @@ -0,0 +1 @@ +pub use asn1_rs::Oid; diff --git a/rust/vendor/der-parser/tests/ber_parser.rs b/rust/vendor/der-parser/tests/ber_parser.rs new file mode 100644 index 0000000..3d61574 --- /dev/null +++ b/rust/vendor/der-parser/tests/ber_parser.rs @@ -0,0 +1,556 @@ +// test_case seem to generate this warning - ignore it +#![allow(clippy::unused_unit)] + +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 false")] +#[test_case(&hex!("01 01 ff"), Some(true) ; "val true")] +#[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 04 ff ff ff ff"), Err(BerError::IntegerNegative) ; "u32-long2-neg")] +#[test_case(&hex!("02 06 ff ff ff ff ff ff"), Err(BerError::IntegerNegative) ; "u32-long3-neg")] +#[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::unexpected_tag(Some(Tag(2)), Tag(3))) ; "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::unexpected_tag(Some(Tag(2)), Tag(3))) ; "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!("02 04 ff ff ff ff"), Ok(-1) ; "i64-long-neg")] +#[test_case(&hex!("03 03 01 00 01"), Err(BerError::unexpected_tag(Some(Tag(2)), Tag(3))) ; "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::unexpected_tag(Some(Tag(2)), Tag(3))) ; "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::unexpected_tag(Some(Tag(2)), Tag(3))) ; "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("\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(), Tag::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, Tag::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::Unknown(_))); +} diff --git a/rust/vendor/der-parser/tests/constructed.rs b/rust/vendor/der-parser/tests/constructed.rs new file mode 100644 index 0000000..7ba6644 --- /dev/null +++ b/rust/vendor/der-parser/tests/constructed.rs @@ -0,0 +1,441 @@ +// test_case seem to generate this warning - ignore it +#![allow(clippy::unused_unit)] + +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: Tag) -> 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::unexpected_tag(Some(Tag::Sequence), Tag::Set))) ; "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::unexpected_tag(Some(Tag::Sequence), Tag::Set))) ; "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::unexpected_tag(Some(Tag::Set), Tag::Sequence))) ; "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::unexpected_tag(Some(Tag::Set), Tag::Sequence))) ; "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, Tag::Sequence); + assert_eq!(res, Ok((empty, expected))); + let res = parse_struct04(&bytes, Tag::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::unexpected_tag(Some(Tag(2)), Tag(3))) ; "invalid tag")] +#[test_case(&hex!("22 05 02 03 01 00 01"), Err(BerError::unexpected_class(None, Class::Universal)) ; "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::unexpected_tag(Some(Tag(3)), Tag(2)))) + ); + // wrong type + assert_eq!( + parse_der_tagged_explicit(2, parse_der_bool)(bytes as &[u8]), + Err(Err::Error(BerError::unexpected_tag(Some(Tag(1)), Tag(2)))) + ); +} + +#[test_case(&hex!("82 03 01 00 01"), Ok(0x10001) ; "tag ok")] +#[test_case(&hex!("83 03 01 00 01"), Err(BerError::unexpected_tag(Some(Tag(2)), Tag(3))) ; "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(Tag::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(Tag::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(Tag::Integer))(bytes as &[u8]), + Err(Err::Error(BerError::unexpected_tag(Some(Tag(3)), Tag(2)))) + ); +} + +#[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() != Class::Application { + return Err(Err::Error(BerError::unexpected_class(None, hdr.class()))); + } + if hdr.tag() != Tag(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/tests/custom_error.rs b/rust/vendor/der-parser/tests/custom_error.rs new file mode 100644 index 0000000..2281510 --- /dev/null +++ b/rust/vendor/der-parser/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/tests/der_constructed.rs b/rust/vendor/der-parser/tests/der_constructed.rs new file mode 100644 index 0000000..d10adf0 --- /dev/null +++ b/rust/vendor/der-parser/tests/der_constructed.rs @@ -0,0 +1,177 @@ +// test_case seem to generate this warning - ignore it +#![allow(clippy::unused_unit)] + +use der_parser::ber::Tag; +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(DerConstraint::IndefiniteLength)) ; "indefinite tag ok")] +#[test_case(&hex!("a3 05 02 03 01 00 01"), Err(BerError::unexpected_tag(Some(Tag(2)), Tag(3))) ; "invalid tag")] +#[test_case(&hex!("22 05 02 03 01 00 01"), Err(BerError::unexpected_class(None, Class::Universal)) ; "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::unexpected_tag(Some(Tag(2)), Tag(3))) ; "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(Tag::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::unexpected_tag(Some(Tag::Sequence), Tag::Set)) ; "invalid tag")] +#[test_case(&hex!("30 80 02 03 01 00 01 00 00"), Err(BerError::DerConstraintFailed(DerConstraint::IndefiniteLength)) ; "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::unexpected_tag(Some(Tag::Sequence), Tag::Set))) ; "invalid tag")] +#[test_case(&hex!("30 80 02 03 01 00 01 00 00"), Err(Err::Error(BerError::DerConstraintFailed(DerConstraint::IndefiniteLength))) ; "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::unexpected_tag(Some(Tag::Set), Tag::Sequence)) ; "invalid tag")] +#[test_case(&hex!("31 80 02 03 01 00 01 00 00"), Err(BerError::DerConstraintFailed(DerConstraint::IndefiniteLength)) ; "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::unexpected_tag(Some(Tag::Set), Tag::Sequence))) ; "invalid tag")] +#[test_case(&hex!("31 80 02 03 01 00 01 00 00"), Err(Err::Error(BerError::DerConstraintFailed(DerConstraint::IndefiniteLength))) ; "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/tests/der_parser.rs b/rust/vendor/der-parser/tests/der_parser.rs new file mode 100644 index 0000000..ef31c66 --- /dev/null +++ b/rust/vendor/der-parser/tests/der_parser.rs @@ -0,0 +1,628 @@ +// test_case seem to generate this warning - ignore it +#![allow(clippy::unused_unit)] + +use asn1_rs::ASN1DateTime; +use asn1_rs::ASN1TimeZone; +use asn1_rs::Any; +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 std::borrow::Cow; +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( + DerConstraint::InvalidBoolean + ))) + ); +} + +#[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( + DerConstraint::UnusedBitsNotZero + ))) + ); + // // XXX test disabled: the parser is laxist here, since *many* implementations do + // // XXX not respect this constraint! + // // 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( + DerConstraint::Constructed + ))) + ); +} + +#[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( + DerConstraint::IndefiniteLength + ))) + ); +} + +#[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::unexpected_tag(Some(Tag(2)), Tag(0)))) + ); + // + 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::unexpected_tag(Some(Tag(2)), Tag(0)))) + ); + 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 0b 39 32 30 35 32 31 32 33 34 32 5A FF"); + let expected = DerObject::from_obj(BerObjectContent::UTCTime(ASN1DateTime::new( + 92, + 5, + 21, + 23, + 42, + 0, + None, + ASN1TimeZone::Z, + ))); + assert_eq!(parse_der_utctime(&bytes), Ok((&[0xff][..], expected))); + // missing 'Z' + let bytes = hex!("17 0a 39 32 30 35 32 31 32 33 34 32"); + let e = parse_der_utctime(&bytes).expect_err("expected error"); + assert_eq!( + e, + Err::Error(BerError::DerConstraintFailed( + DerConstraint::MissingTimeZone + )) + ); +} + +#[test] +fn test_der_generalizedtime() { + let empty = &b""[..]; + let bytes = hex!("18 0D 31 39 39 32 30 35 32 31 32 33 34 32 5A"); + let expected = DerObject::from_obj(BerObjectContent::GeneralizedTime(ASN1DateTime::new( + 1992, + 5, + 21, + 23, + 42, + 0, + None, + ASN1TimeZone::Z, + ))); + 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("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 header = Header::new(Class::ContextSpecific, true, Tag(0), 3.into()) + .with_raw_tag(Some(Cow::Borrowed(&[0xa0]))); + let any = Any::new(header.clone(), &bytes[2..]); + let expected = DerObject { + header, + content: BerObjectContent::Unknown(any), + }; + 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 = Header::new(Class::ContextSpecific, true, Tag(0), 3.into()) + .with_raw_tag(Some(Cow::Borrowed(&[0xa0]))); + let expected = DerObject { + header: header.clone(), + content: BerObjectContent::Optional(Some(Box::new(BerObject::from_header_and_content( + header, + BerObjectContent::Tagged( + Class::ContextSpecific, + Tag(0), + Box::new(DerObject::from_int_slice(b"\x02")), + ), + )))), + }; + assert_eq!( + parse_der_explicit_optional(&bytes, Tag(0), parse_der_integer), + Ok((empty, expected)) + ); + let expected2 = DerObject::from_obj(BerObjectContent::Optional(None)); + assert_eq!( + parse_der_explicit_optional(&bytes, Tag(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: Header::new(Class::ContextSpecific, false, Tag(1), 4.into()) + .with_raw_tag(Some(Cow::Borrowed(&[0x81]))), + content: BerObjectContent::IA5String("pass"), + }; + fn der_read_ia5string_content<'a>( + i: &'a [u8], + hdr: &Header, + depth: usize, + ) -> BerResult<'a, BerObjectContent<'a>> { + ber_read_element_content_as(i, Tag::Ia5String, hdr.length(), hdr.is_constructed(), depth) + } + assert_eq!( + parse_der_implicit(&bytes, Tag(1), der_read_ia5string_content), + Ok((empty, expected)) + ); + assert_eq!( + parse_der_implicit(&bytes, Tag(2), der_read_ia5string_content), + Err(Err::Error(BerError::unexpected_tag(Some(Tag(2)), Tag(1)))) + ); +} + +#[test] +fn test_der_implicit_long_tag() { + let empty = &b""[..]; + let bytes = [0x5f, 0x52, 0x04, 0x70, 0x61, 0x73, 0x73]; + let expected = DerObject { + header: Header::new(Class::Application, false, Tag(0x52), 4.into()) + .with_raw_tag(Some(Cow::Borrowed(&[0x5f, 0x52]))), + content: BerObjectContent::IA5String("pass"), + }; + fn der_read_ia5string_content<'a>( + i: &'a [u8], + hdr: &Header, + depth: usize, + ) -> BerResult<'a, BerObjectContent<'a>> { + ber_read_element_content_as(i, Tag::Ia5String, hdr.length(), hdr.is_constructed(), depth) + } + assert_eq!( + parse_der_implicit(&bytes, Tag(0x52), der_read_ia5string_content), + Ok((empty, expected)) + ); + assert_eq!( + parse_der_implicit(&bytes, Tag(2), der_read_ia5string_content), + Err(Err::Error(BerError::unexpected_tag( + Some(Tag(2)), + Tag(0x52) + ))) + ); +} + +#[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")] +// XXX DER encoding is invalid (not minimal) in following test: +// #[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(DerConstraint::IntegerLeadingZeroes)) ; "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::unexpected_tag(Some(Tag(2)), Tag(3))) ; "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")] +#[test_case(&hex!("02 02 ff f0"), Err(BerError::DerConstraintFailed(DerConstraint::IntegerLeadingFF)) ; "i32-neg-leading-ff")] +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::unexpected_tag(Some(Tag(2)), Tag(3))) ; "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(DerConstraint::IndefiniteLength)) ; "constructed slice")] +#[test_case(&hex!("03 03 01 00 01"), Err(BerError::unexpected_tag(Some(Tag(2)), Tag(3))) ; "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/tests/fuzz01.rs b/rust/vendor/der-parser/tests/fuzz01.rs new file mode 100644 index 0000000..c971b56 --- /dev/null +++ b/rust/vendor/der-parser/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/tests/fuzz02.rs b/rust/vendor/der-parser/tests/fuzz02.rs new file mode 100644 index 0000000..bea7c21 --- /dev/null +++ b/rust/vendor/der-parser/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/tests/oid.rs b/rust/vendor/der-parser/tests/oid.rs new file mode 100644 index 0000000..3fa45c7 --- /dev/null +++ b/rust/vendor/der-parser/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.as_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/tests/primitive.rs b/rust/vendor/der-parser/tests/primitive.rs new file mode 100644 index 0000000..2f3aecb --- /dev/null +++ b/rust/vendor/der-parser/tests/primitive.rs @@ -0,0 +1,236 @@ +extern crate alloc; +use std::borrow::Cow; + +use asn1_rs::Any; +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], Tag::Boolean, 0x01.into(), false, MAX_RECURSION), + Ok((empty, BerObjectContent::Boolean(true))) + ); + assert_eq!( + ber_read_element_content_as(&[0x00], Tag::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(Any::from_tag_and_data( + Tag(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(Any::from_tag_and_data( + Tag(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: Header::new(Class::ContextSpecific, false, Tag(0), 1.into()) + .with_raw_tag(Some(Cow::Borrowed(&[0x80]))), + content: BerObjectContent::Unknown( + Any::from_tag_and_data(Tag(0x0), &bytes[2..]).with_class(Class::ContextSpecific) + ), + } + ); +} + +#[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: Header::new(Class::ContextSpecific, false, Tag(0x22), 1.into()) + .with_raw_tag(Some(Cow::Borrowed(&[0x9f, 0x22]))), + content: BerObjectContent::Unknown( + Any::from_tag_and_data(Tag(0x22), &bytes[3..]).with_class(Class::ContextSpecific) + ), + } + ); +} + +#[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: Header::new(Class::ContextSpecific, false, Tag(0x1122), 1.into()) + .with_raw_tag(Some(Cow::Borrowed(&[0x9f, 0xa2, 0x22]))), + content: BerObjectContent::Unknown( + Any::from_tag_and_data(Tag(0x1122), &bytes[4..]).with_class(Class::ContextSpecific) + ), + } + ); +} + +#[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 8a ff ff ff ff ff ff ff ff ff ff 00"); + let res = parse_ber(&bytes).expect_err("parsing should have returned error"); + assert_eq!(Err::Error(BerError::InvalidLength), res); + // + let bytes = hex!("02 ff 00"); + let res = parse_ber(&bytes).expect_err("parsing should have returned error"); + assert_eq!(Err::Error(BerError::InvalidLength), 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); +} + +#[test] +fn test_print_unexpected() { + let bytes = hex!("01 01 ff"); + let nom_err = parse_der_integer(&bytes).expect_err("expected error"); + nom_err.map(|e| eprintln!("{}", e)); + + eprintln!("{}", BerError::BerMaxDepth); +} |