chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1 @@
{"files":{".cargo_vcs_info.json":"d2d61a23bb0198d70748ef7cea962b46a66419c6ead75f58f949a2a9bb8b139e","CHANGELOG.md":"81baf7ef040e0555a07ad7f59fd4ab9948f032869e34da99055d35c24eaee279","Cargo.lock":"35bcfe9f376a990a3d272ca48881d2441297d95bd60c15ef1f37efaaa45cee1c","Cargo.toml":"3b9b8368da0aaeb55edf28982baa2d924e57bac7661c5292ea081e689d62c631","Cargo.toml.orig":"4c68a13c2f092995be49719d4665750e9b6a1cb4ac36804ee8dfdcefdfd62e38","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a5c61b93b6ee1d104af9920cf020ff3c7efe818e31fe562c72261847a728f513","README.md":"c3872e8baece0f133b73af279f7302e2620edaba5a5d52631d49b0bea4b2b3ab","UPGRADING.md":"ec1f026903fda2de7adda9090863b519c9732266460dadf0eaece9bf1c00289c","examples/dump-der.rs":"367a6884bfdabadf1b35ec93d6893e7aca589e824c5399f0417273140a3f65b2","src/ber/ber.rs":"155b9c767b95dffce96f16bb50a4ebae608611fc1123ef24bb5f31e0358f2518","src/ber/compat.rs":"a220f947321d91431673d54b56f05c03b502e05c80b644ef0163d31ca83cf922","src/ber/integer.rs":"d87b78dabd3b455764b36bcd62f6dceb2fcbe4e381b2e32a71585b25967a29ed","src/ber/mod.rs":"8d208e2574dca87fbc1b65b66bad7c679fd32d60c688856a590d31b08d051ce0","src/ber/multi.rs":"a4e187ec87a4322ae478969c819dc5931bfe117d84c6565372271c9588767831","src/ber/parser.rs":"9bfa69edcb7107a9d3cf8e2fefdf13867dea9a09954b829d1043e20546e71ec9","src/ber/print.rs":"fb8378e1c79e5b8d98925d0089cc2d5a1b5b06897b66ee7dc54c62d9094f5d94","src/ber/serialize.rs":"e01d2be5cb80eda2fd3c043ff1fca82d4044fc51db4a8df041e29db7fc03d71a","src/ber/tagged.rs":"9ab039de2f2ccdbc7961fc0a86d4cd1067d30472656e2bfd59ce3e9c8007e09f","src/ber/visit.rs":"209d5f59cec659b0617bcb5032de18bf55180ec273bd8c1917b10b03e1ae53b5","src/ber/visit_mut.rs":"7d5602dfec969426edba9d87b16293a67f273d7549b84304b2aaf7675e8a93b3","src/ber/wrap_any.rs":"a3660e70e931a501c308ef78812076c2cca3b796f15f9ed439130718b15d325d","src/der/mod.rs":"70d80fc8eefaf6d15fb87e3b159796ec4e43d4b8e2854db74d715d10b36b0025","src/der/multi.rs":"78d399604926509692a4a42d874d9108188564d74ace411082f62aa4a3a4df1b","src/der/parser.rs":"2be83f4b53785048a1278da65c6cda436209fddc39b67f9f09f5fb182ba985a6","src/der/tagged.rs":"212b10cd5dc009573b733db3b4691933c34b2a71ea88fe14d918b611ba21ec59","src/error.rs":"0d83caef79ea673a5814b7068bda0f2a558f05d57661e2ca24d819c650244937","src/lib.rs":"35bef0b0020f4f9a65858875c428d6217f1fa2e3b8ee798df2b9ad8fccc7ede6","src/oid.rs":"f6ff7343c47e7d554a1bfd6f07fc17996a8f58b2153336d624cfd076c0192bf1","tests/ber_parser.rs":"dabe9989b14ace57e3b6cd73a1dc0e9821b28ae2856a52435784395ab314f878","tests/constructed.rs":"b63fd4aaf79c045dacc8e8fb4e58fcbdecc018a601761e5529d00ed2379a08ba","tests/custom_error.rs":"5a9ecdad51f17d5008f4ee334c6c33f4dc8dc7f9d8ba090bb2d6a8b1ffd6e9ea","tests/der_constructed.rs":"49f8f8d97659410ac0752a2fb9c2aec97930c6efb8cccd989946912afa0f1a6d","tests/der_parser.rs":"e00691edef8a5f83f5ea746835c061c08c47c5aad74aecae71833c9b3205fe64","tests/fuzz01.rs":"b1929c8183fdba11ea73618ef48b23d4d3d39df79ac70e1c46787c3dcfcf9ec9","tests/fuzz02.rs":"b1e4ae20a40bb74887b7d62e9bbec5919f7c963b3f699e01888755e3637877a5","tests/issue-76.rs":"d1c36ea2e829d15c89fb9489d5c3612d03d8104acd6234e30bf803a3a79e7954","tests/oid.rs":"901a1a929653eef5f1753479dc742f1e9fefca960523958d4e50b8376ac06524","tests/primitive.rs":"56870f23ad00443949acfe6d7d43579f4c74857a8d09fccbc31e61fde66e3a44"},"package":"07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6"}

View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "79ec2d0cfe1e3ba2deb49ee1f68f984f4ef3a971"
},
"path_in_vcs": ""
}

412
vendor/der-parser/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,412 @@
# Change Log
## [Unreleased][unreleased]
### Changed/Fixed
### Added
### Thanks
## 10.0.0
### Changed/Fixed
Breaking change:
- BerObject: convert BmpString data to `&[u8]` to properly handle UTF-16 data (#76)
- Upgrade `asn1-rs` to 0.7.0
- Rename feature "bitvec" to "as_bitvec" and update to bitvec 1.0 (#73)
- Serialize: fix possible wrong encoding of length if exactly 128 (#77)
### Thanks
- Daniel McCarney
## 9.0.0
### Changed/Fixed
- Upgrade `asn1-rs` to 0.6.0
- Set MSRV to 1.63.0
- Update hex-literal to 0.4.0
- Implement `BerObject::try_from(Any)` (#67)
## 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.

425
vendor/der-parser/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,425 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "asn1-rs"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "607495ec7113b178fbba7a6166a27f99e774359ef4823adbefd756b5b81d7970"
dependencies = [
"asn1-rs-derive",
"asn1-rs-impl",
"displaydoc",
"nom",
"num-traits",
"rusticata-macros",
"thiserror",
]
[[package]]
name = "asn1-rs-derive"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "asn1-rs-impl"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cookie-factory"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2"
dependencies = [
"futures",
]
[[package]]
name = "der-parser"
version = "10.0.0"
dependencies = [
"asn1-rs",
"bitvec",
"cookie-factory",
"displaydoc",
"hex-literal",
"nom",
"num-bigint",
"num-traits",
"pretty_assertions",
"rusticata-macros",
"test-case",
]
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "futures-task"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "hex-literal"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pretty_assertions"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
dependencies = [
"diff",
"yansi",
]
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "rusticata-macros"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
dependencies = [
"nom",
]
[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
[[package]]
name = "syn"
version = "2.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "test-case"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
dependencies = [
"test-case-macros",
]
[[package]]
name = "test-case-core"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f"
dependencies = [
"cfg-if",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "test-case-macros"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
dependencies = [
"proc-macro2",
"quote",
"syn",
"test-case-core",
]
[[package]]
name = "thiserror"
version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"

163
vendor/der-parser/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,163 @@
# 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"
rust-version = "1.63"
name = "der-parser"
version = "10.0.0"
authors = ["Pierre Chifflier <chifflier@wzdftpd.net>"]
build = false
include = [
"LICENSE-*",
"CHANGELOG.md",
"README.md",
"UPGRADING.md",
".gitignore",
"Cargo.toml",
"examples/*.rs",
"src/*.rs",
"src/ber/*.rs",
"src/der/*.rs",
"tests/*.rs",
"der-oid-macro/Cargo.toml",
"der-oid-macro/src/*.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
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 OR Apache-2.0"
repository = "https://github.com/rusticata/der-parser.git"
[package.metadata.cargo_check_external_types]
allowed_external_types = [
"asn1_rs",
"asn1_rs::*",
"nom",
"nom::*",
"rusticata_macros",
]
[package.metadata.docs.rs]
all-features = true
rustdoc-args = [
"--cfg",
"docsrs",
]
[lib]
name = "der_parser"
path = "src/lib.rs"
[[example]]
name = "dump-der"
path = "examples/dump-der.rs"
[[test]]
name = "ber_parser"
path = "tests/ber_parser.rs"
[[test]]
name = "constructed"
path = "tests/constructed.rs"
[[test]]
name = "custom_error"
path = "tests/custom_error.rs"
[[test]]
name = "der_constructed"
path = "tests/der_constructed.rs"
[[test]]
name = "der_parser"
path = "tests/der_parser.rs"
[[test]]
name = "fuzz01"
path = "tests/fuzz01.rs"
[[test]]
name = "fuzz02"
path = "tests/fuzz02.rs"
[[test]]
name = "issue-76"
path = "tests/issue-76.rs"
[[test]]
name = "oid"
path = "tests/oid.rs"
[[test]]
name = "primitive"
path = "tests/primitive.rs"
[dependencies.asn1-rs]
version = "0.7"
[dependencies.bitvec]
version = "1.0"
optional = true
[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.4"
[dev-dependencies.pretty_assertions]
version = "1.0"
[dev-dependencies.test-case]
version = "3.0"
[features]
as_bitvec = ["bitvec"]
bigint = ["num-bigint"]
default = ["std"]
serialize = [
"std",
"cookie-factory",
]
std = []
unstable = []

201
vendor/der-parser/LICENSE-APACHE vendored Normal file
View File

@@ -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.

25
vendor/der-parser/LICENSE-MIT vendored Normal file
View File

@@ -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.

247
vendor/der-parser/README.md vendored Normal file
View File

@@ -0,0 +1,247 @@
<!-- 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/9.0.0/status.svg)](https://deps.rs/crate/der-parser/9.0.0)
[![Github CI](https://github.com/rusticata/der-parser/actions/workflows/rust.yml/badge.svg)](https://github.com/rusticata/der-parser/actions/workflows/rust.yml)
[![Minimum rustc version](https://img.shields.io/badge/rustc-1.63.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(&rem).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 9.0 series of `der-parser` requires **Rustc version 1.63 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.

128
vendor/der-parser/UPGRADING.md vendored Normal file
View File

@@ -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).

98
vendor/der-parser/examples/dump-der.rs vendored Normal file
View File

@@ -0,0 +1,98 @@
use der_parser::ber::*;
use der_parser::der::*;
use std::env;
use std::io;
use nom::HexDisplay;
struct BerPrinter {}
impl BerPrinter {
/// try to parse contents, constructed or not
///
/// Do not raise errors if object is not constructed
fn try_print_encapsulated(&mut self, data: &[u8], depth: usize, ber: &BerObject) {
let mut i = data;
let mut first_object = true;
while !i.is_empty() {
match parse_ber_any_r(i, MAX_RECURSION) {
Ok((rem, inner)) => {
if first_object {
println!("{:1$}encapsulates {{", " ", depth * 2);
first_object = false;
}
self.run_at(&inner, depth + 1);
i = rem;
}
Err(e) => {
if ber.is_constructed() {
// object was constructed, so should have been parsed correctly
eprintln!(
"Error while parsing constructed object at depth {}: {}",
depth, e
);
eprintln!("tried to parse\n{}", data.to_hex(16));
} else {
// does not look like encapsulated data
i = &[];
}
break;
}
}
}
if !first_object {
println!("{:1$}}}", " ", depth * 2);
}
if !i.is_empty() {
println!("WARNING: {} remaining bytes at depth {}", i.len(), depth);
}
}
}
impl<'a> Visit<'a> for BerPrinter {
fn visit_ber(&mut self, ber: &'_ BerObject<'a>, depth: usize) {
// create a printer without the recursive flag, recursion is handled by the
// visitor pattern
let pp = PrettyBer::new(ber, vec![PrettyPrinterFlag::ShowHeader], depth * 2, 2);
println!("{:?}", pp);
match ber.content {
BerObjectContent::Unknown(ref any) => {
self.try_print_encapsulated(any.data, depth, ber);
}
// Bitstring and OctetString also can encapsulate objects
BerObjectContent::OctetString(data) => {
self.try_print_encapsulated(data, depth, ber);
}
_ => (),
}
}
}
pub fn main() -> io::Result<()> {
let mut parse_as_ber = false;
for file_name in env::args().skip(1) {
match file_name.as_ref() {
"--ber" => {
parse_as_ber = true;
continue;
}
"--der" => {
parse_as_ber = false;
continue;
}
_ => (),
}
let data = std::fs::read(file_name.clone()).expect("Unable to read file");
let (rem, obj) = if parse_as_ber {
parse_ber(&data).expect("could not parse BER data")
} else {
parse_der(&data).expect("could not parse DER data")
};
let mut printer = BerPrinter {};
printer.run_at(&obj, 1);
if !rem.is_empty() {
println!("WARNING: extra bytes after BER/DER object:\n{:x?}", rem);
}
}
Ok(())
}

1001
vendor/der-parser/src/ber/ber.rs vendored Normal file

File diff suppressed because it is too large Load Diff

9
vendor/der-parser/src/ber/compat.rs vendored Normal file
View File

@@ -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>;

130
vendor/der-parser/src/ber/integer.rs vendored Normal file
View File

@@ -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)
}

78
vendor/der-parser/src/ber/mod.rs vendored Normal file
View File

@@ -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;

530
vendor/der-parser/src/ber/multi.rs vendored Normal file
View File

@@ -0,0 +1,530 @@
use crate::ber::*;
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 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<'a>
where
F: Fn(&'a [u8]) -> BerResult<'a>,
{
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<'a>
where
F: FnMut(&'a [u8]) -> BerResult<'a, Vec<BerObject<'a>>>,
{
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<'a>
where
F: Fn(&'a [u8]) -> BerResult<'a>,
{
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<'a>
where
F: FnMut(&'a [u8]) -> BerResult<'a, Vec<BerObject<'a>>>,
{
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(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(Err::convert)?
}
};
let (_rest, v) = f(data, hdr)?;
Ok((i, v))
}
}

660
vendor/der-parser/src/ber/parser.rs vendored Normal file
View File

@@ -0,0 +1,660 @@
use crate::ber::*;
use crate::error::*;
use asn1_rs::FromBer;
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));
}

221
vendor/der-parser/src/ber/print.rs vendored Normal file
View File

@@ -0,0 +1,221 @@
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 fmt::Debug for PrettyBer<'_> {
#[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_utf16_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result {
let v: Vec<_> = s
.chunks_exact(2)
.map(|a| u16::from_be_bytes([a[0], a[1]]))
.collect();
let s = String::from_utf16(&v);
match s {
Ok(s) => writeln!(f, "{}(\"{}\")", ty, s),
Err(_) => writeln!(f, "{}({:?}) <error decoding utf32 string>", ty, s),
}
}
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) => print_utf16_string_with_type(f, s, "BmpString"),
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);
}
}

419
vendor/der-parser/src/ber/serialize.rs vendored Normal file
View File

@@ -0,0 +1,419 @@
#![cfg(feature = "std")]
use crate::ber::*;
use crate::oid::Oid;
use asn1_rs::ASN1DateTime;
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 <= 0x7f {
// 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::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::BmpString(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 BerObject<'_> {
/// 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);
}
}

259
vendor/der-parser/src/ber/tagged.rs vendored Normal file
View File

@@ -0,0 +1,259 @@
use crate::ber::*;
use crate::error::*;
use nom::error::ParseError;
use nom::{Err, IResult};
/// Read a TAGGED EXPLICIT value (combinator)
///
/// The built object will use the outer header (and tag), and contains a `Tagged` object
/// with class, value and content.
///
/// For a generic version (different output and error types), see
/// [parse_ber_tagged_explicit_g](fn.parse_ber_tagged_explicit_g.html).
///
/// The following parses `[2] EXPLICIT INTEGER`:
///
/// ```rust
/// # use der_parser::ber::*;
/// # use der_parser::error::BerResult;
/// use nom::combinator::map_res;
/// #
/// fn parse_int_explicit(i:&[u8]) -> BerResult<u32> {
/// map_res(
/// parse_ber_tagged_explicit(2, parse_ber_integer),
/// |x: BerObject| x.as_tagged()?.2.as_u32()
/// )(i)
/// }
///
/// # let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01];
/// let res = parse_int_explicit(bytes);
/// # match res {
/// # Ok((rem,val)) => {
/// # assert!(rem.is_empty());
/// # assert_eq!(val, 0x10001);
/// # },
/// # _ => assert!(false)
/// # }
/// ```
pub fn parse_ber_tagged_explicit<'a, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult<'a>
where
F: Fn(&'a [u8]) -> BerResult<'a, BerObject<'a>>,
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<'a>
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<&'a [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
})
}

193
vendor/der-parser/src/ber/visit.rs vendored Normal file
View File

@@ -0,0 +1,193 @@
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 [u8], 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;
#[allow(unused)]
#[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());
}
}
}

207
vendor/der-parser/src/ber/visit_mut.rs vendored Normal file
View File

@@ -0,0 +1,207 @@
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 &'_ [u8], 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;
#[allow(unused)]
#[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());
}
}
}

226
vendor/der-parser/src/ber/wrap_any.rs vendored Normal file
View File

@@ -0,0 +1,226 @@
use alloc::string::String;
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 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 => {
custom_check!(any.data, header.constructed(), BerError::Unsupported)?; // XXX valid in BER (8.6.3)
if any.data.len() % 2 != 0 {
return Err(BerError::Unsupported);
}
let v: Vec<u16> = any
.data
.chunks_exact(2)
.map(|a| u16::from_be_bytes([a[0], a[1]]))
.collect();
let _s = String::from_utf16(&v)?;
Ok(obj_from(header, BerObjectContent::BmpString(any.data)))
}
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(b"\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)
}
}

93
vendor/der-parser/src/der/mod.rs vendored Normal file
View File

@@ -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>;

534
vendor/der-parser/src/der/multi.rs vendored Normal file
View File

@@ -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<'a>
where
F: Fn(&'a [u8]) -> BerResult<'a>,
{
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<'a>
where
F: FnMut(&'a [u8]) -> BerResult<'a, Vec<DerObject<'a>>>,
{
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<'a>
where
F: Fn(&'a [u8]) -> BerResult<'a>,
{
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<'a>
where
F: FnMut(&'a [u8]) -> BerResult<'a, Vec<DerObject<'a>>>,
{
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(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))
}
}

632
vendor/der-parser/src/der/parser.rs vendored Normal file
View File

@@ -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};
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()?;
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(Err::Error(BerError::DerConstraintFailed(
DerConstraint::IntegerEmpty,
)))
}
[0, 0, ..] => {
return Err(Err::Error(BerError::DerConstraintFailed(
DerConstraint::IntegerLeadingZeroes,
)))
}
[0, byte, ..] if byte < 0x80 => {
return Err(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)
}

261
vendor/der-parser/src/der/tagged.rs vendored Normal file
View File

@@ -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<'a>
where
F: Fn(&'a [u8]) -> BerResult<'a, DerObject<'a>>,
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<'a>
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<&'a [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
})
}

39
vendor/der-parser/src/error.rs vendored Normal file
View File

@@ -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));
}
}

281
vendor/der-parser/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,281 @@
//! [![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/9.0.0/status.svg)](https://deps.rs/crate/der-parser/9.0.0)
//! [![Github CI](https://github.com/rusticata/der-parser/actions/workflows/rust.yml/badge.svg)](https://github.com/rusticata/der-parser/actions/workflows/rust.yml)
//! [![Minimum rustc version](https://img.shields.io/badge/rustc-1.63.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(&rem).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 9.0 series of `der-parser` requires **Rustc version 1.63 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(rustdoc::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)*)
}};
}

1
vendor/der-parser/src/oid.rs vendored Normal file
View File

@@ -0,0 +1 @@
pub use asn1_rs::Oid;

556
vendor/der-parser/tests/ber_parser.rs vendored Normal file
View File

@@ -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(b"\x00U\x00s\x00e\x00r"));
assert_eq!(parse_ber_bmpstring(&bytes), Ok((empty, expected)));
}
#[test]
fn test_ber_customtags() {
let bytes = hex!("8f 02 12 34");
let hdr = ber_read_element_header(&bytes)
.expect("ber_read_element_header")
.1;
// println!("{:?}", hdr);
let expected: &[u8] = &[0x8f];
assert_eq!(hdr.raw_tag(), Some(expected));
let bytes = hex!("9f 0f 02 12 34");
let hdr = ber_read_element_header(&bytes)
.expect("ber_read_element_header")
.1;
// println!("{:?}", hdr);
let expected: &[u8] = &[0x9f, 0x0f];
assert_eq!(hdr.raw_tag(), Some(expected));
}
#[test]
fn test_ber_indefinite() {
let bytes = hex!("30 80 02 03 01 00 01 00 00");
let (rem, val) = parse_ber_container::<_, _, BerError>(|i, _| {
assert!(!i.is_empty());
let (_, val) = parse_ber_u32(i)?;
Ok((i, val))
})(&bytes)
.unwrap();
assert!(rem.is_empty());
assert_eq!(val, 0x10001);
}
#[test]
fn test_ber_indefinite_recursion() {
let data = &hex!(
"
24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80
24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80
24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80
24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80
24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80
24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80
24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80
24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80
24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 00 00"
);
let _ = parse_ber_container::<_, _, BerError>(|i, _| Ok((i, ())))(data)
.expect_err("max parsing depth overflow");
}
#[test]
fn test_parse_ber_content() {
let bytes = &hex!("02 03 01 00 01");
let (i, header) = ber_read_element_header(bytes).expect("parsing failed");
let (rem, content) =
parse_ber_content(header.tag())(i, &header, MAX_RECURSION).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(header.tag(), 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(_)));
}

441
vendor/der-parser/tests/constructed.rs vendored Normal file
View File

@@ -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().cloned()
}
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");
}

53
vendor/der-parser/tests/custom_error.rs vendored Normal file
View File

@@ -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 From<BerError> for MyError<'_> {
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]);
}

View File

@@ -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));
}
}
}

628
vendor/der-parser/tests/der_parser.rs vendored Normal file
View File

@@ -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)));
}
}
}

5
vendor/der-parser/tests/fuzz01.rs vendored Normal file
View File

@@ -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);
}

22
vendor/der-parser/tests/fuzz02.rs vendored Normal file
View File

@@ -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);
}

21
vendor/der-parser/tests/issue-76.rs vendored Normal file
View File

@@ -0,0 +1,21 @@
use der_parser::ber::*;
#[test]
fn issue76_example1() {
// This is a 4 bytes (2 characters) UTF-16-BE string. The first two bytes are the tag and size.
let bytes = [0x80, 0x04, 0x00, 0x4c, 0x00, 0x65];
let (i, header) = ber_read_element_header(&bytes).expect("parsing failed");
let (rem, _content) =
parse_ber_content(Tag::BmpString)(i, &header, MAX_RECURSION).expect("parsing failed");
assert!(rem.is_empty());
}
#[test]
fn issue76_example2() {
// This is a 6 bytes (3 characters) UTF-16-BE string. The first two bytes are the tag and size.
let bytes = [0x80, 0x06, 0x79, 0x3E, 0x30, 0xBA, 0x30, 0xFC];
let (i, header) = ber_read_element_header(&bytes).expect("parsing failed");
let (rem, _content) =
parse_ber_content(Tag::BmpString)(i, &header, MAX_RECURSION).expect("parsing failed");
assert!(rem.is_empty());
}

25
vendor/der-parser/tests/oid.rs vendored Normal file
View File

@@ -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));
}

234
vendor/der-parser/tests/primitive.rs vendored Normal file
View File

@@ -0,0 +1,234 @@
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).expect_err("expected error");
assert_eq!(res, Err::Incomplete(Needed::new(1)));
let res = parse_der(&bytes).expect_err("expected error");
assert_eq!(res, Err::Incomplete(Needed::new(1)));
let bytes = hex!("02");
let res = parse_ber(&bytes).expect_err("expected error");
assert_eq!(res, Err::Incomplete(Needed::new(1)));
let bytes = hex!("02 05");
let _ = parse_ber(&bytes).expect_err("expected error");
let bytes = hex!("02 85");
let res = parse_ber(&bytes).expect_err("expected error");
assert_eq!(res, Err::Incomplete(Needed::new(5)));
let bytes = hex!("02 85 ff");
let res = parse_ber(&bytes).expect_err("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).expect_err("expected error");
let _ = ber_read_element_header(&bytes).expect_err("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).expect_err("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);
}