der-parser-10.0.0/.cargo_vcs_info.json0000644000000001360000000000100131560ustar { "git": { "sha1": "79ec2d0cfe1e3ba2deb49ee1f68f984f4ef3a971" }, "path_in_vcs": "" }der-parser-10.0.0/.gitignore000064400000000000000000000000251046102023000137330ustar 00000000000000target .*.swp /.idea der-parser-10.0.0/CHANGELOG.md000064400000000000000000000301661046102023000135650ustar 00000000000000# 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. der-parser-10.0.0/Cargo.lock0000644000000247360000000000100111450ustar # 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" der-parser-10.0.0/Cargo.toml0000644000000056320000000000100111620ustar # 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 "] 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 = [] der-parser-10.0.0/Cargo.toml.orig000064400000000000000000000026431046102023000146420ustar 00000000000000[package] description = "Parser/encoder for ASN.1 BER/DER data" license = "MIT OR Apache-2.0" keywords = ["BER","DER","ASN1","parser","nom"] homepage = "https://github.com/rusticata/der-parser" repository = "https://github.com/rusticata/der-parser.git" name = "der-parser" version = "10.0.0" authors = ["Pierre Chifflier "] categories = ["parser-implementations"] readme = "README.md" edition = "2018" rust-version = "1.63" 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", ] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] asn1-rs = "0.7" bitvec = { version="1.0", optional=true } cookie-factory = { version="0.3.0", optional=true } displaydoc = { version="0.2", default-features=false } nom = "7.0" rusticata-macros = "4.0" num-traits = "0.2" num-bigint = { version = "0.4", optional = true } [features] default = ["std"] as_bitvec = ["bitvec"] bigint = ["num-bigint"] serialize = ["std", "cookie-factory"] unstable = [] std = [] [dev-dependencies] hex-literal = "0.4" pretty_assertions = "1.0" test-case = "3.0" [package.metadata.cargo_check_external_types] allowed_external_types = [ "asn1_rs", "asn1_rs::*", "nom", "nom::*", "rusticata_macros", ] der-parser-10.0.0/LICENSE-APACHE000064400000000000000000000251371046102023000137020ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. der-parser-10.0.0/LICENSE-MIT000064400000000000000000000020441046102023000134020ustar 00000000000000Copyright (c) 2017 Pierre Chifflier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. der-parser-10.0.0/README.md000064400000000000000000000237531046102023000132370ustar 00000000000000 [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE-MIT) [![Apache License 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE-APACHE) [![docs.rs](https://docs.rs/der-parser/badge.svg)](https://docs.rs/der-parser) [![crates.io](https://img.shields.io/crates/v/der-parser.svg)](https://crates.io/crates/der-parser) [![Download numbers](https://img.shields.io/crates/d/der-parser.svg)](https://crates.io/crates/der-parser) [![dependency status](https://deps.rs/crate/der-parser/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)." ## Changes See `CHANGELOG.md`, and `UPGRADING.md` for instructions for upgrading major versions. ## License Licensed under either of * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ## Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. der-parser-10.0.0/UPGRADING.md000064400000000000000000000117341046102023000136160ustar 00000000000000## 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 { ``` The header was usually ignored, so this should simplify most uses of this macro. To get the header, use `parse_ber_container` directly. ## Upgrading from 3.x to 4.0 ### Ber Object and Header The `class`, `structured` and `tag` fields were duplicated in `BerObject` and the header. Now, a header is always created and embedded in the BER object, with the following changes: - To access these fields, use the header: `obj.tag` becomes `obj.header.tag`, etc. - `BerObject::to_header()` is now deprecated - The `len` field is now public. However, in some cases it can be 0 (when creating an object, 0 means that serialization will calculate the length) - As a consequence, `PartialEq` on BER objects and headers compare `len` only if set in both objects ### BER String types verification Some BER String types (`IA5String`, `NumericString`, `PrintableString` and `UTF8String`) are now verified, and will now only parse if the characters are valid. Their types have change from slice to `str` in the `BerObjectContent` enum. ### BerClass The `class` field of `BerObject` struct now uses the newtype `BerClass`. Use the provided constants (for ex `BerClass:Universal`). To access the value, just use `class.0`. ### Maximum depth The `depth` argument of functions (for ex. `ber_read_element_content_as`) has changed, and is now the maximum possible depth while parsing. Change it (usually from `0`) to a possible limit, for ex `der_parser::ber::MAX_RECURSION`. ### Oid This is probably the most impacting change. OID objects have been refactored, and are now zero-copy. This has several consequences: - `Oid` struct now has a lifetime, which must be propagated to objects using them - This makes having globally static structs difficult. Obtaining a `'static` object is possible using the `oid` macro. For ex: ```rust const SOME_STATIC_OID: Oid<'static> = oid!(1.2.456); ``` - Due to limitations of procedural macros ([rust issue](https://github.com/rust-lang/rust/issues/54727)) and constants used in patterns ([rust issue](https://github.com/rust-lang/rust/issues/31434)), the `oid` macro can not directly be used in patterns, also not through constants. You can do this, though: ```rust # use der_parser::{oid, oid::Oid}; # let some_oid: Oid<'static> = oid!(1.2.456); const SOME_OID: Oid<'static> = oid!(1.2.456); if some_oid == SOME_OID || some_oid == oid!(1.2.456) { println!("match"); } // Alternatively, compare the DER encoded form directly: const SOME_OID_RAW: &[u8] = &oid!(raw 1.2.456); match some_oid.bytes() { SOME_OID_RAW => println!("match"), _ => panic!("no match"), } ``` *Attention*, be aware that the latter version might not handle the case of a relative oid correctly. An extra check might be necessary. - To build an `Oid`, the `from`, `new` or `new_relative` methods can be used. - The `from` method now returns a `Result` (failure can happen if the first components are too large, for ex) - An `oid` macro has also been added in the `der-oid-macro` crate to easily build an `Oid` (see above). der-parser-10.0.0/examples/dump-der.rs000064400000000000000000000063021046102023000156500ustar 00000000000000use 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(()) } der-parser-10.0.0/src/ber/ber.rs000064400000000000000000000777471046102023000144510ustar 00000000000000use super::{Class, Header, Length, Tag}; use crate::ber::ber_read_element_content_as; use crate::ber::bitstring_to_u64; use crate::ber::integer::*; use crate::ber::MAX_RECURSION; use crate::error::BerError; use crate::oid::Oid; use alloc::borrow::ToOwned; use alloc::boxed::Box; use alloc::vec::Vec; use asn1_rs::ASN1DateTime; use asn1_rs::Any; #[cfg(feature = "as_bitvec")] use bitvec::{order::Msb0, slice::BitSlice}; use core::convert::TryFrom; use core::ops::Index; /// Representation of a BER-encoded (X.690) object /// /// A BER object is composed of a header describing the object class, type and length, /// and the content. /// /// Note that the content may sometimes not match the header tag (for ex when parsing IMPLICIT /// tagged values). #[derive(Debug, Clone, PartialEq)] pub struct BerObject<'a> { pub header: Header<'a>, pub content: BerObjectContent<'a>, } /// BER object content #[derive(Debug, Clone, PartialEq)] #[allow(clippy::upper_case_acronyms)] pub enum BerObjectContent<'a> { /// EOC (no content) EndOfContent, /// BOOLEAN: decoded value Boolean(bool), /// INTEGER: raw bytes /// /// Note: the reason to store the raw bytes is that integers have non-finite length in the /// spec, and also that the raw encoding is also important for some applications. /// /// To extract the number, see the `as_u64`, `as_u32`, `as_bigint` and `as_biguint` methods. Integer(&'a [u8]), /// BIT STRING: number of unused bits, and object BitString(u8, BitStringObject<'a>), /// OCTET STRING: slice OctetString(&'a [u8]), /// NULL (no content) Null, /// ENUMERATED: decoded enum number Enum(u64), /// OID OID(Oid<'a>), /// RELATIVE OID RelativeOID(Oid<'a>), /// NumericString: decoded string NumericString(&'a str), /// VisibleString: decoded string VisibleString(&'a str), /// PrintableString: decoded string PrintableString(&'a str), /// IA5String: decoded string IA5String(&'a str), /// UTF8String: decoded string UTF8String(&'a str), /// T61String: decoded string T61String(&'a str), /// VideotexString: decoded string VideotexString(&'a str), /// BmpString: raw object bytes /// /// Note: the string is stored as raw bytes because not all UTF-16 sequences can be stored as /// `&str`. To access content, use `String::from_utf16` or `String::from_utf16_lossy`. BmpString(&'a [u8]), /// UniversalString: raw object bytes UniversalString(&'a [u8]), /// SEQUENCE: list of objects Sequence(Vec>), /// SET: list of objects Set(Vec>), /// UTCTime: decoded string UTCTime(ASN1DateTime), /// GeneralizedTime: decoded string GeneralizedTime(ASN1DateTime), /// Object descriptor: decoded string ObjectDescriptor(&'a str), /// GraphicString: decoded string GraphicString(&'a str), /// GeneralString: decoded string GeneralString(&'a str), /// Optional object Optional(Option>>), /// Tagged object (EXPLICIT): class, tag and content of inner object Tagged(Class, Tag, Box>), /// Private or Unknown (for ex. unknown tag) object Unknown(Any<'a>), } impl<'a> BerObject<'a> { /// Build a BerObject from a header and content. /// /// Note: values are not checked, so the tag can be different from the real content, or flags /// can be invalid. #[inline] pub const fn from_header_and_content<'o>( header: Header<'o>, content: BerObjectContent<'o>, ) -> BerObject<'o> { BerObject { header, content } } /// Build a BerObject from its content, using default flags (no class, correct tag, /// and constructed flag set only for Set and Sequence) pub const fn from_obj(c: BerObjectContent) -> BerObject { let class = Class::Universal; let tag = c.tag(); let constructed = matches!(tag, Tag::Sequence | Tag::Set); let header = Header::new(class, constructed, tag, Length::Definite(0)); BerObject { header, content: c } } /// Build a DER integer object from a slice containing an encoded integer pub const fn from_int_slice(i: &'a [u8]) -> BerObject<'a> { let header = Header::new(Class::Universal, false, Tag::Integer, Length::Definite(0)); BerObject { header, content: BerObjectContent::Integer(i), } } /// Set a tag for the BER object pub fn set_raw_tag(self, raw_tag: Option<&'a [u8]>) -> BerObject<'a> { let header = self.header.with_raw_tag(raw_tag.map(|x| x.into())); BerObject { header, ..self } } /// Build a DER sequence object from a vector of DER objects pub const fn from_seq(l: Vec) -> BerObject { BerObject::from_obj(BerObjectContent::Sequence(l)) } /// Build a DER set object from a vector of DER objects pub const fn from_set(l: Vec) -> BerObject { BerObject::from_obj(BerObjectContent::Set(l)) } /// Attempt to read a signed integer value from DER object. /// /// This can fail if the object is not an integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x80"); /// assert_eq!( /// der_int.as_i64(), /// Ok(-128) /// ); /// ``` pub fn as_i64(&self) -> Result { self.content.as_i64() } /// Attempt to read a signed integer value from DER object. /// /// This can fail if the object is not an integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x80"); /// assert_eq!( /// der_int.as_i32(), /// Ok(-128) /// ); /// ``` pub fn as_i32(&self) -> Result { self.content.as_i32() } /// Attempt to read integer value from DER object. /// /// This can fail if the object is not an unsigned integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x01\x00\x01"); /// assert_eq!( /// der_int.as_u64(), /// Ok(0x10001) /// ); /// ``` pub fn as_u64(&self) -> Result { self.content.as_u64() } /// Attempt to read integer value from DER object. /// /// This can fail if the object is not an unsigned integer, or if it is too large. /// /// # Examples /// /// ```rust /// # extern crate der_parser; /// # use der_parser::ber::{BerObject,BerObjectContent}; /// let der_int = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); /// assert_eq!( /// der_int.as_u32(), /// Ok(0x10001) /// ); /// ``` pub fn as_u32(&self) -> Result { self.content.as_u32() } /// Attempt to read integer value from DER object. /// This can fail if the object is not a boolean. pub fn as_bool(&self) -> Result { self.content.as_bool() } /// Attempt to read an OID value from DER object. /// This can fail if the object is not an OID. pub fn as_oid(&self) -> Result<&Oid<'a>, BerError> { self.content.as_oid() } /// Attempt to read an OID value from DER object. /// This can fail if the object is not an OID. pub fn as_oid_val(&self) -> Result, BerError> { self.content.as_oid_val() } /// Attempt to get a reference on the content from an optional object. /// This can fail if the object is not optional. pub fn as_optional(&self) -> Result>, BerError> { self.content.as_optional() } /// Attempt to get a reference on the content from a tagged object. /// This can fail if the object is not tagged. pub fn as_tagged(&self) -> Result<(Class, Tag, &BerObject<'a>), BerError> { self.content.as_tagged() } /// Attempt to read a reference to a BitString value from DER object. /// This can fail if the object is not an BitString. /// /// Note that this function returns a reference to the BitString. To get an owned value, /// use [`as_bitstring`](struct.BerObject.html#method.as_bitstring) pub fn as_bitstring_ref(&self) -> Result<&BitStringObject, BerError> { self.content.as_bitstring_ref() } /// Attempt to read a BitString value from DER object. /// This can fail if the object is not an BitString. pub fn as_bitstring(&self) -> Result, BerError> { self.content.as_bitstring() } /// Constructs a shared `&BitSlice` reference over the object data, if available as slice. #[cfg(feature = "as_bitvec")] pub fn as_bitslice(&self) -> Result<&BitSlice, BerError> { self.content.as_bitslice() } /// Attempt to extract the list of objects from a DER sequence. /// This can fail if the object is not a sequence. pub fn as_sequence(&self) -> Result<&Vec>, BerError> { self.content.as_sequence() } /// Attempt to extract the list of objects from a DER set. /// This can fail if the object is not a set. pub fn as_set(&self) -> Result<&Vec>, BerError> { self.content.as_set() } /// Attempt to get the content from a DER object, as a slice. /// This can fail if the object does not contain a type directly equivalent to a slice (e.g a /// sequence). /// This function mostly concerns string types, integers, or unknown DER objects. pub fn as_slice(&self) -> Result<&'a [u8], BerError> { self.content.as_slice() } /// Attempt to get the content from a DER object, as a str. /// This can fail if the object does not contain a string type. /// /// Only some string types are considered here. Other /// string types can be read using `as_slice`. pub fn as_str(&self) -> Result<&'a str, BerError> { self.content.as_str() } /// Get the BER object header's class. #[inline] pub const fn class(&self) -> Class { self.header.class() } /// Get the BER object header's tag. #[inline] pub const fn tag(&self) -> Tag { self.header.tag() } /// Get the BER object header's length. #[inline] pub const fn length(&self) -> Length { self.header.length() } /// Test if object class is Universal #[inline] pub const fn is_universal(&self) -> bool { self.header.is_universal() } /// Test if object class is Application #[inline] pub const fn is_application(&self) -> bool { self.header.is_application() } /// Test if object class is Context-specific #[inline] pub const fn is_contextspecific(&self) -> bool { self.header.is_contextspecific() } /// Test if object class is Private #[inline] pub fn is_private(&self) -> bool { self.header.is_private() } /// Test if object is primitive #[inline] pub const fn is_primitive(&self) -> bool { self.header.is_primitive() } /// Test if object is constructed #[inline] pub const fn is_constructed(&self) -> bool { self.header.is_constructed() } /// Return error if `class` is not the expected class #[inline] pub const fn assert_class(&self, class: Class) -> Result<(), BerError> { self.header.assert_class(class) } /// Return error if `tag` is not the expected tag #[inline] pub const fn assert_tag(&self, tag: Tag) -> Result<(), BerError> { self.header.assert_tag(tag) } /// Return error if object is not constructed #[inline] pub const fn assert_constructed(&self) -> Result<(), BerError> { self.header.assert_constructed() } /// Return error if object is not primitive #[inline] pub const fn assert_primitive(&self) -> Result<(), BerError> { self.header.assert_primitive() } } /// Build a DER object from an OID. impl<'a> From> for BerObject<'a> { fn from(oid: Oid<'a>) -> BerObject<'a> { BerObject::from_obj(BerObjectContent::OID(oid)) } } /// Build a DER object from a BerObjectContent. impl<'a> From> for BerObject<'a> { fn from(obj: BerObjectContent<'a>) -> BerObject<'a> { BerObject::from_obj(obj) } } impl<'a> BerObjectContent<'a> { /// Attempt to read a signed integer value from this object. /// /// This can fail if the object is not an integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x80"); /// assert_eq!( /// der_int.as_i64(), /// Ok(-128) /// ); /// ``` pub fn as_i64(&self) -> Result { if let BerObjectContent::Integer(bytes) = self { let result = if is_highest_bit_set(bytes) { ::from_be_bytes(decode_array_int8(bytes)?) } else { ::from_be_bytes(decode_array_uint8(bytes)?) as i64 }; Ok(result) } else { Err(BerError::BerValueError) } } /// Attempt to read a signed integer value from this object. /// /// This can fail if the object is not an integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x80"); /// assert_eq!( /// der_int.as_i32(), /// Ok(-128) /// ); /// ``` pub fn as_i32(&self) -> Result { if let BerObjectContent::Integer(bytes) = self { let result = if is_highest_bit_set(bytes) { ::from_be_bytes(decode_array_int4(bytes)?) } else { ::from_be_bytes(decode_array_uint4(bytes)?) as i32 }; Ok(result) } else { Err(BerError::BerValueError) } } /// Attempt to read integer value from this object. /// /// This can fail if the object is not an unsigned integer, or if it is too large. /// /// # Examples /// /// ```rust /// # use der_parser::ber::BerObject; /// let der_int = BerObject::from_int_slice(b"\x01\x00\x01"); /// assert_eq!( /// der_int.as_u64(), /// Ok(0x10001) /// ); /// ``` pub fn as_u64(&self) -> Result { match self { BerObjectContent::Integer(i) => { let result = ::from_be_bytes(decode_array_uint8(i)?); Ok(result) } BerObjectContent::BitString(ignored_bits, data) => { bitstring_to_u64(*ignored_bits as usize, data) } BerObjectContent::Enum(i) => Ok(*i), _ => Err(BerError::BerTypeError), } } /// Attempt to read integer value from this object. /// /// This can fail if the object is not an unsigned integer, or if it is too large. /// /// # Examples /// /// ```rust /// # extern crate der_parser; /// # use der_parser::ber::{BerObject,BerObjectContent}; /// let der_int = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); /// assert_eq!( /// der_int.as_u32(), /// Ok(0x10001) /// ); /// ``` pub fn as_u32(&self) -> Result { match self { BerObjectContent::Integer(i) => { let result = ::from_be_bytes(decode_array_uint4(i)?); Ok(result) } BerObjectContent::BitString(ignored_bits, data) => { bitstring_to_u64(*ignored_bits as usize, data).and_then(|x| { if x > u64::from(u32::MAX) { Err(BerError::IntegerTooLarge) } else { Ok(x as u32) } }) } BerObjectContent::Enum(i) => { if *i > u64::from(u32::MAX) { Err(BerError::IntegerTooLarge) } else { Ok(*i as u32) } } _ => Err(BerError::BerTypeError), } } pub fn as_bool(&self) -> Result { match *self { BerObjectContent::Boolean(b) => Ok(b), _ => Err(BerError::BerTypeError), } } pub fn as_oid(&self) -> Result<&Oid<'a>, BerError> { match *self { BerObjectContent::OID(ref o) => Ok(o), BerObjectContent::RelativeOID(ref o) => Ok(o), _ => Err(BerError::BerTypeError), } } pub fn as_oid_val(&self) -> Result, BerError> { self.as_oid().cloned() } pub fn as_optional(&self) -> Result>, BerError> { match *self { BerObjectContent::Optional(Some(ref o)) => Ok(Some(o)), BerObjectContent::Optional(None) => Ok(None), _ => Err(BerError::BerTypeError), } } pub fn as_tagged(&self) -> Result<(Class, Tag, &BerObject<'a>), BerError> { match *self { BerObjectContent::Tagged(class, tag, ref o) => Ok((class, tag, o.as_ref())), _ => Err(BerError::BerTypeError), } } pub fn as_bitstring_ref(&self) -> Result<&BitStringObject, BerError> { match *self { BerObjectContent::BitString(_, ref b) => Ok(b), _ => Err(BerError::BerTypeError), } } pub fn as_bitstring(&self) -> Result, BerError> { match *self { BerObjectContent::BitString(_, ref b) => Ok(b.to_owned()), _ => Err(BerError::BerTypeError), } } /// Constructs a shared `&BitSlice` reference over the object data, if available as slice. #[cfg(feature = "as_bitvec")] pub fn as_bitslice(&self) -> Result<&BitSlice, BerError> { self.as_slice().and_then(|s| { BitSlice::<_, Msb0>::try_from_slice(s).map_err(|_| BerError::BerValueError) }) } pub fn as_sequence(&self) -> Result<&Vec>, BerError> { match *self { BerObjectContent::Sequence(ref s) => Ok(s), _ => Err(BerError::BerTypeError), } } pub fn as_set(&self) -> Result<&Vec>, BerError> { match *self { BerObjectContent::Set(ref s) => Ok(s), _ => Err(BerError::BerTypeError), } } #[rustfmt::skip] pub fn as_slice(&self) -> Result<&'a [u8],BerError> { match *self { BerObjectContent::NumericString(s) | BerObjectContent::VisibleString(s) | BerObjectContent::PrintableString(s) | BerObjectContent::GeneralString(s) | BerObjectContent::ObjectDescriptor(s) | BerObjectContent::GraphicString(s) | BerObjectContent::T61String(s) | BerObjectContent::VideotexString(s) | BerObjectContent::UTF8String(s) | BerObjectContent::IA5String(s) => Ok(s.as_ref()), BerObjectContent::Integer(s) | BerObjectContent::BitString(_,BitStringObject{data:s}) | BerObjectContent::OctetString(s) | BerObjectContent::BmpString(s) | BerObjectContent::UniversalString(s) => Ok(s), BerObjectContent::Unknown(ref any) => Ok(any.data), _ => Err(BerError::BerTypeError), } } #[rustfmt::skip] pub fn as_str(&self) -> Result<&'a str,BerError> { match *self { BerObjectContent::NumericString(s) | BerObjectContent::VisibleString(s) | BerObjectContent::PrintableString(s) | BerObjectContent::GeneralString(s) | BerObjectContent::ObjectDescriptor(s) | BerObjectContent::GraphicString(s) | BerObjectContent::T61String(s) | BerObjectContent::VideotexString(s) | BerObjectContent::UTF8String(s) | BerObjectContent::IA5String(s) => Ok(s), _ => Err(BerError::BerTypeError), } } #[rustfmt::skip] const fn tag(&self) -> Tag { match self { BerObjectContent::EndOfContent => Tag::EndOfContent, BerObjectContent::Boolean(_) => Tag::Boolean, BerObjectContent::Integer(_) => Tag::Integer, BerObjectContent::BitString(_,_) => Tag::BitString, BerObjectContent::OctetString(_) => Tag::OctetString, BerObjectContent::Null => Tag::Null, BerObjectContent::Enum(_) => Tag::Enumerated, BerObjectContent::OID(_) => Tag::Oid, BerObjectContent::NumericString(_) => Tag::NumericString, BerObjectContent::VisibleString(_) => Tag::VisibleString, BerObjectContent::PrintableString(_) => Tag::PrintableString, BerObjectContent::IA5String(_) => Tag::Ia5String, BerObjectContent::UTF8String(_) => Tag::Utf8String, BerObjectContent::RelativeOID(_) => Tag::RelativeOid, BerObjectContent::T61String(_) => Tag::T61String, BerObjectContent::VideotexString(_) => Tag::VideotexString, BerObjectContent::BmpString(_) => Tag::BmpString, BerObjectContent::UniversalString(_) => Tag::UniversalString, BerObjectContent::Sequence(_) => Tag::Sequence, BerObjectContent::Set(_) => Tag::Set, BerObjectContent::UTCTime(_) => Tag::UtcTime, BerObjectContent::GeneralizedTime(_) => Tag::GeneralizedTime, BerObjectContent::ObjectDescriptor(_) => Tag::ObjectDescriptor, BerObjectContent::GraphicString(_) => Tag::GraphicString, BerObjectContent::GeneralString(_) => Tag::GeneralString, BerObjectContent::Tagged(_,x,_) => *x, BerObjectContent::Unknown(any) => any.tag(), BerObjectContent::Optional(Some(obj)) => obj.content.tag(), BerObjectContent::Optional(None) => Tag(0x00), // XXX invalid ! } } } #[cfg(feature = "bigint")] #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))] use num_bigint::{BigInt, BigUint}; #[cfg(feature = "bigint")] #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))] impl BerObject<'_> { /// Attempt to read an integer value from this object. /// /// This can fail if the object is not an integer. /// /// # Examples /// /// ```rust /// use der_parser::ber::*; /// /// let data = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// /// let (_, object) = parse_ber_integer(data).expect("parsing failed"); /// # #[cfg(feature = "bigint")] /// assert_eq!(object.as_bigint(), Ok(65537.into())) /// ``` pub fn as_bigint(&self) -> Result { match self.content { BerObjectContent::Integer(s) => Ok(BigInt::from_signed_bytes_be(s)), _ => Err(BerError::BerValueError), } } /// Attempt to read a positive integer value from this object. /// /// This can fail if the object is not an integer, or is negative. /// /// # Examples /// /// ```rust /// use der_parser::ber::*; /// /// let data = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// /// let (_, object) = parse_ber_integer(data).expect("parsing failed"); /// # #[cfg(feature = "bigint")] /// assert_eq!(object.as_biguint(), Ok(65537_u32.into())) /// ``` pub fn as_biguint(&self) -> Result { match self.content { BerObjectContent::Integer(s) => { if is_highest_bit_set(s) { return Err(BerError::IntegerNegative); } Ok(BigUint::from_bytes_be(s)) } _ => Err(BerError::BerValueError), } } } impl<'a> TryFrom> for BerObject<'a> { type Error = asn1_rs::Error; fn try_from(any: Any<'a>) -> Result { let (header, data) = (any.header, any.data); let (_, content) = ber_read_element_content_as( data, header.tag(), header.length(), header.constructed(), MAX_RECURSION, )?; let obj = BerObject::from_header_and_content(header, content); Ok(obj) } } impl<'a, 'b> TryFrom<&'b Any<'a>> for BerObject<'a> { type Error = asn1_rs::Error; fn try_from(any: &'b Any<'a>) -> Result { let (header, data) = (any.header.clone(), any.data); let (_, content) = ber_read_element_content_as( data, header.tag(), header.length(), header.constructed(), MAX_RECURSION, )?; let obj = BerObject::from_header_and_content(header, content); Ok(obj) } } // This is a consuming iterator impl<'a> IntoIterator for BerObject<'a> { type Item = BerObject<'a>; type IntoIter = BerObjectIntoIterator<'a>; fn into_iter(self) -> Self::IntoIter { // match self { // BerObjectContent::Sequence(ref v) => (), // _ => (), // }; BerObjectIntoIterator { val: self, idx: 0 } } } #[derive(Debug)] pub struct BerObjectIntoIterator<'a> { val: BerObject<'a>, idx: usize, } impl<'a> Iterator for BerObjectIntoIterator<'a> { type Item = BerObject<'a>; fn next(&mut self) -> Option> { // let result = if self.idx < self.vec.len() { // Some(self.vec[self.idx].clone()) // } else { // None // }; let res = match self.val.content { BerObjectContent::Sequence(ref v) if self.idx < v.len() => Some(v[self.idx].clone()), BerObjectContent::Set(ref v) if self.idx < v.len() => Some(v[self.idx].clone()), _ => { if self.idx == 0 { Some(self.val.clone()) } else { None } } }; self.idx += 1; res } } // impl<'a> Iterator for BerObjectContent<'a> { // type Item = BerObjectContent<'a>; // // fn next(&mut self) -> Option> { // None // } // } #[derive(Debug)] pub struct BerObjectRefIterator<'a> { obj: &'a BerObject<'a>, idx: usize, } impl<'a> Iterator for BerObjectRefIterator<'a> { type Item = &'a BerObject<'a>; fn next(&mut self) -> Option<&'a BerObject<'a>> { let res = match (self.obj).content { BerObjectContent::Sequence(ref v) if self.idx < v.len() => Some(&v[self.idx]), BerObjectContent::Set(ref v) if self.idx < v.len() => Some(&v[self.idx]), _ => None, }; self.idx += 1; res } } impl<'a> BerObject<'a> { pub fn ref_iter(&'a self) -> BerObjectRefIterator<'a> { BerObjectRefIterator { obj: self, idx: 0 } } } impl<'a> Index for BerObject<'a> { type Output = BerObject<'a>; fn index(&self, idx: usize) -> &BerObject<'a> { match (self).content { BerObjectContent::Sequence(ref v) if idx < v.len() => &v[idx], BerObjectContent::Set(ref v) if idx < v.len() => &v[idx], _ => panic!("Try to index BerObjectContent which is not constructed"), } // XXX the following // self.ref_iter().nth(idx).unwrap() // fails with: // error: cannot infer an appropriate lifetime for autoref due to conflicting requirements [E0495] // self.ref_iter().nth(idx).unwrap() } } /// BitString wrapper #[derive(Clone, Debug, PartialEq)] pub struct BitStringObject<'a> { pub data: &'a [u8], } impl BitStringObject<'_> { /// Test if bit `bitnum` is set pub fn is_set(&self, bitnum: usize) -> bool { let byte_pos = bitnum / 8; if byte_pos >= self.data.len() { return false; } let b = 7 - (bitnum % 8); (self.data[byte_pos] & (1 << b)) != 0 } /// Constructs a shared `&BitSlice` reference over the object data. #[cfg(feature = "as_bitvec")] pub fn as_bitslice(&self) -> Option<&BitSlice> { BitSlice::<_, Msb0>::try_from_slice(self.data).ok() } } impl AsRef<[u8]> for BitStringObject<'_> { fn as_ref(&self) -> &[u8] { self.data } } #[cfg(test)] mod tests { use asn1_rs::{Any, FromDer}; use core::convert::TryFrom; use crate::ber::*; use crate::oid::*; #[test] fn ber_from_any() { let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; let (rem, any) = Any::from_der(bytes).expect("parsing failed"); assert!(rem.is_empty()); let obj = BerObject::try_from(any).expect("try_from(any) failed"); assert_eq!(obj.as_u32(), Ok(0x10001_u32)); } #[test] fn test_der_as_u64() { let der_obj = BerObject::from_int_slice(b"\x01\x00\x02"); assert_eq!(der_obj.as_u64(), Ok(0x10002)); } #[test] fn test_ber_as_u64_bitstring() { let (_, ber_obj) = parse_ber_bitstring(b"\x03\x04\x06\x6e\x5d\xc0").unwrap(); assert_eq!(ber_obj.as_u64(), Ok(0b011011100101110111)); let (_, ber_obj_with_nonzero_padding) = parse_ber_bitstring(b"\x03\x04\x06\x6e\x5d\xe0").unwrap(); assert_eq!( ber_obj_with_nonzero_padding.as_u64(), Ok(0b011011100101110111) ); } #[test] fn test_der_seq_iter() { let der_obj = BerObject::from_obj(BerObjectContent::Sequence(vec![ BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_int_slice(b"\x01\x00\x00"), ])); let expected_values = vec![ BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_int_slice(b"\x01\x00\x00"), ]; for (idx, v) in der_obj.ref_iter().enumerate() { // println!("v: {:?}", v); assert_eq!((*v), expected_values[idx]); } } #[test] fn test_der_from_oid() { let obj: BerObject = Oid::from(&[1, 2]).unwrap().into(); let expected = BerObject::from_obj(BerObjectContent::OID(Oid::from(&[1, 2]).unwrap())); assert_eq!(obj, expected); } #[test] fn test_der_bitstringobject() { let obj = BitStringObject { data: &[0x0f, 0x00, 0x40], }; assert!(!obj.is_set(0)); assert!(obj.is_set(7)); assert!(!obj.is_set(9)); assert!(obj.is_set(17)); } #[cfg(feature = "as_bitvec")] #[test] fn test_der_bitslice() { use std::string::String; let obj = BitStringObject { data: &[0x0f, 0x00, 0x40], }; let slice = obj.as_bitslice().expect("as_bitslice"); assert_eq!(slice.get(0).as_deref(), Some(&false)); assert_eq!(slice.get(7).as_deref(), Some(&true)); assert_eq!(slice.get(9).as_deref(), Some(&false)); assert_eq!(slice.get(17).as_deref(), Some(&true)); let s = slice.iter().fold(String::with_capacity(24), |mut acc, b| { acc += if *b { "1" } else { "0" }; acc }); assert_eq!(&s, "000011110000000001000000"); } #[test] fn test_der_bistringobject_asref() { fn assert_equal>(s: T, b: &[u8]) { assert_eq!(s.as_ref(), b); } let b: &[u8] = &[0x0f, 0x00, 0x40]; let obj = BitStringObject { data: b }; assert_equal(obj, b); } #[cfg(feature = "bigint")] #[test] fn test_der_to_bigint() { let obj = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); let expected = ::num_bigint::BigInt::from(0x10001); assert_eq!(obj.as_bigint(), Ok(expected)); } #[cfg(feature = "bigint")] #[test] fn test_der_to_biguint() { let obj = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); let expected = ::num_bigint::BigUint::from(0x10001_u32); assert_eq!(obj.as_biguint(), Ok(expected)); } } der-parser-10.0.0/src/ber/compat.rs000064400000000000000000000003451046102023000151400ustar 00000000000000//! 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>; der-parser-10.0.0/src/ber/integer.rs000064400000000000000000000101311046102023000153040ustar 00000000000000use crate::error::*; /// Decode an unsigned integer into a big endian byte slice with all leading /// zeroes removed. /// /// Returns a byte array of the requested size containing a big endian integer. fn remove_zeroes(bytes: &[u8]) -> Result<&[u8], BerError> { // skip leading 0s match bytes { // [] => Err(BerError::DerConstraintFailed), [0] => Ok(bytes), // [0, byte, ..] if *byte < 0x80 => Err(BerError::DerConstraintFailed), // [0, rest @ ..] => Ok(&rest), [0, rest @ ..] => remove_zeroes(rest), // [byte, ..] if *byte >= 0x80 => Err(BerError::IntegerTooLarge), _ => Ok(bytes), } } // XXX const generics require rustc >= 1.51 // /// Decode an unsigned integer into a byte array of the requested size // /// containing a big endian integer. // pub(crate) fn decode_array_uint(bytes: &[u8]) -> Result<[u8; N], BerError> { // // Check if MSB is set *before* leading zeroes // if is_highest_bit_set(bytes) { // return Err(BerError::IntegerNegative); // } // let input = remove_zeroes(bytes)?; // if input.len() > N { // return Err(BerError::IntegerTooLarge); // } // // Input has leading zeroes removed, so we need to add them back // let mut output = [0u8; N]; // assert!(input.len() <= N); // output[N.saturating_sub(input.len())..].copy_from_slice(input); // Ok(output) // } pub(crate) fn decode_array_uint8(bytes: &[u8]) -> Result<[u8; 8], BerError> { // Check if MSB is set *before* leading zeroes if is_highest_bit_set(bytes) { return Err(BerError::IntegerNegative); } let input = remove_zeroes(bytes)?; if input.len() > 8 { return Err(BerError::IntegerTooLarge); } // Input has leading zeroes removed, so we need to add them back let mut output = [0u8; 8]; assert!(input.len() <= 8); output[8_usize.saturating_sub(input.len())..].copy_from_slice(input); Ok(output) } pub(crate) fn decode_array_uint4(bytes: &[u8]) -> Result<[u8; 4], BerError> { // Check if MSB is set *before* leading zeroes if is_highest_bit_set(bytes) { return Err(BerError::IntegerNegative); } let input = remove_zeroes(bytes)?; if input.len() > 4 { return Err(BerError::IntegerTooLarge); } // Input has leading zeroes removed, so we need to add them back let mut output = [0u8; 4]; assert!(input.len() <= 4); output[4_usize.saturating_sub(input.len())..].copy_from_slice(input); Ok(output) } // XXX const generics require rustc >= 1.51 // /// Decode an unsigned integer of the specified size. // /// // /// Returns a byte array of the requested size containing a big endian integer. // pub(crate) fn decode_array_int(input: &[u8]) -> Result<[u8; N], BerError> { // let input = remove_zeroes(input)?; // if input.len() > N { // return Err(BerError::IntegerTooLarge); // } // // any.tag().assert_eq(Tag::Integer)?; // let mut output = [0xFFu8; N]; // let offset = N.saturating_sub(input.len()); // output[offset..].copy_from_slice(input); // Ok(output) // } pub(crate) fn decode_array_int8(input: &[u8]) -> Result<[u8; 8], BerError> { let input = remove_zeroes(input)?; if input.len() > 8 { return Err(BerError::IntegerTooLarge); } // any.tag().assert_eq(Tag::Integer)?; let mut output = [0xFFu8; 8]; let offset = 8_usize.saturating_sub(input.len()); output[offset..].copy_from_slice(input); Ok(output) } pub(crate) fn decode_array_int4(input: &[u8]) -> Result<[u8; 4], BerError> { let input = remove_zeroes(input)?; if input.len() > 4 { return Err(BerError::IntegerTooLarge); } // any.tag().assert_eq(Tag::Integer)?; let mut output = [0xFFu8; 4]; let offset = 4_usize.saturating_sub(input.len()); output[offset..].copy_from_slice(input); Ok(output) } /// Is the highest bit of the first byte in the slice 1? (if present) #[inline] pub(crate) fn is_highest_bit_set(bytes: &[u8]) -> bool { bytes .first() .map(|byte| byte & 0b10000000 != 0) .unwrap_or(false) } der-parser-10.0.0/src/ber/mod.rs000064400000000000000000000041131046102023000144310ustar 00000000000000//! Basic Encoding Rules (BER) objects and parser //! //! # BER Objects //! //! The main object of this crate is [`BerObject`]. It contains a header (ber tag, class, and size) //! and content. //! //! To parse primitive objects (for ex. integers or strings), use the `parse_ber_` set of //! functions. //! //! Constructed objects (like sequences, sets or tagged objects) require to use a combinator. This //! combinator takes a function or closure as input, and returns a new, specialized parser. //! See the [nom](https://github.com/geal/nom) parser combinator library for more details on //! combinators. //! //! # Examples //! //! Parse two BER integers: //! //! ```rust //! use der_parser::ber::parse_ber_integer; //! //! let bytes = [ 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x02, 0x03, 0x01, 0x00, 0x00, //! ]; //! //! let (rem, obj1) = parse_ber_integer(&bytes).expect("parsing failed"); //! let (rem, obj2) = parse_ber_integer(&bytes).expect("parsing failed"); //! ``` //! //! Parse a BER sequence containing one integer and an octetstring: //! //! ```rust //! use der_parser::ber::*; //! //! let bytes = [ 0x30, 0x0a, //! 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x04, 0x03, 0x62, 0x61, 0x64, //! ]; //! //! let (rem, seq) = parse_ber_sequence_defined(|content| { //! let (rem, obj1) = parse_ber_integer(content)?; //! let (rem, obj2) = parse_ber_octetstring(rem)?; //! Ok((rem, vec![obj1, obj2])) //! })(&bytes) //! .expect("parsing failed"); //! ``` mod ber; mod integer; mod multi; mod parser; mod print; #[cfg(feature = "serialize")] mod serialize; mod tagged; 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; der-parser-10.0.0/src/ber/multi.rs000064400000000000000000000414531046102023000150140ustar 00000000000000use 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 { /// 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> { /// parse_ber_sequence_of_v(parse_ber_integer)(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = vec![ /// # BerObject::from_int_slice(b"\x01\x00\x01"), /// # BerObject::from_int_slice(b"\x01\x00\x00"), /// # ]; /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// # assert_eq!(v, expected); /// ``` pub fn parse_ber_sequence_of_v<'a, T, F, E>( f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Vec, E> where F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, E: ParseError<&'a [u8]> + From, { let mut subparser = all_consuming(many0(complete(cut(f)))); parse_ber_sequence_defined_g(move |data, _| subparser(data)) } /// Parse a defined sequence of DER elements (function version) /// /// Given a list of expected parsers, apply them to build a DER sequence and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the sequence: any bytes that are part of the sequence but not /// parsed are ignored. /// /// The object header is not available to the parsing function, and the returned type is always a /// `BerObject`. /// For a generic version, see /// [`parse_ber_sequence_defined_g`](fn.parse_ber_sequence_defined_g.html). /// /// # Examples /// /// Parsing a sequence of identical types (same as `parse_ber_sequence_of`): /// /// ```rust /// # use der_parser::ber::{parse_ber_integer, parse_ber_sequence_defined, BerObject}; /// # use der_parser::error::BerResult; /// use nom::combinator::complete; /// use nom::multi::many1; /// /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_ber_sequence_defined( /// many1(complete(parse_ber_integer)) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = BerObject::from_seq(vec![ /// # BerObject::from_int_slice(b"\x01\x00\x01"), /// # BerObject::from_int_slice(b"\x01\x00\x00"), /// # ]); /// # assert_eq!(localparse_seq(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` /// /// Parsing a defined sequence with different types: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map; /// use nom::sequence::tuple; /// /// /// Read a DER-encoded object: /// /// SEQUENCE { /// /// a INTEGER, /// /// b OCTETSTRING /// /// } /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_ber_sequence_defined( /// // the nom `tuple` combinator returns a tuple, so we have to map it /// // to a list /// map( /// tuple((parse_ber_integer, parse_ber_octetstring)), /// |(a, b)| vec![a, b] /// ) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = BerObject::from_seq(vec![ /// # BerObject::from_int_slice(b"\x01\x00\x01"), /// # BerObject::from_obj(BerObjectContent::OctetString(b"\x01\x00\x00")), /// # ]); /// # assert_eq!(localparse_seq(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_sequence_defined<'a, F>(mut f: F) -> impl FnMut(&'a [u8]) -> BerResult<'a> where F: FnMut(&'a [u8]) -> BerResult<'a, Vec>>, { map( parse_ber_sequence_defined_g(move |data, _| f(data)), BerObject::from_seq, ) } /// Parse a defined SEQUENCE object (generic function) /// /// Given a parser for sequence content, apply it to build a DER sequence and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the sequence: any bytes that are part of the sequence but not /// parsed are ignored. /// /// Unlike `parse_ber_sequence_defined`, this function allows returning any object or error type, /// and also passes the object header to the callback. /// /// # Examples /// /// Parsing a defined sequence with different types: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// # #[derive(Debug, PartialEq)] /// pub struct MyObject<'a> { /// a: u32, /// b: &'a [u8], /// } /// /// /// Read a DER-encoded object: /// /// SEQUENCE { /// /// a INTEGER (0..4294967295), /// /// b OCTETSTRING /// /// } /// fn parse_myobject(i: &[u8]) -> BerResult { /// parse_ber_sequence_defined_g( /// |i:&[u8], _| { /// let (i, a) = parse_ber_u32(i)?; /// let (i, obj) = parse_ber_octetstring(i)?; /// let b = obj.as_slice().unwrap(); /// Ok((i, MyObject{ a, b })) /// } /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = MyObject { /// # a: 0x010001, /// # b: &[01, 00, 00] /// # }; /// # assert_eq!(parse_myobject(&bytes), Ok((empty, expected))); /// let (rem, v) = parse_myobject(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_sequence_defined_g<'a, O, F, E>( mut f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E> where F: FnMut(&'a [u8], Header<'a>) -> IResult<&'a [u8], O, E>, E: ParseError<&'a [u8]> + From, { 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 { /// 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> { /// parse_ber_set_of_v(parse_ber_integer)(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = vec![ /// # BerObject::from_int_slice(b"\x01\x00\x01"), /// # BerObject::from_int_slice(b"\x01\x00\x00"), /// # ]; /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// # assert_eq!(v, expected); /// ``` pub fn parse_ber_set_of_v<'a, T, F, E>(f: F) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Vec, E> where F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, E: ParseError<&'a [u8]> + From, { let mut subparser = all_consuming(many0(complete(cut(f)))); parse_ber_set_defined_g(move |data, _| subparser(data)) } /// Parse a defined set of DER elements (function version) /// /// Given a list of expected parsers, apply them to build a DER set and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the set: any bytes that are part of the sequence but not /// parsed are ignored. /// The nom combinator `all_consuming` can be used to ensure all the content is parsed. /// /// The object header is not available to the parsing function, and the returned type is always a /// `BerObject`. /// For a generic version, see [`parse_ber_set_defined_g`](fn.parse_ber_set_defined_g.html). /// /// # Examples /// /// Parsing a set of identical types (same as `parse_ber_set_of`): /// /// ```rust /// # use der_parser::ber::{parse_ber_integer, parse_ber_set_defined, BerObject}; /// # use der_parser::error::BerResult; /// use nom::combinator::complete; /// use nom::multi::many1; /// /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_ber_set_defined( /// many1(complete(parse_ber_integer)) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = BerObject::from_set(vec![ /// # BerObject::from_int_slice(b"\x01\x00\x01"), /// # BerObject::from_int_slice(b"\x01\x00\x00"), /// # ]); /// # assert_eq!(localparse_seq(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` /// /// Parsing a defined set with different types: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map; /// use nom::sequence::tuple; /// /// /// Read a DER-encoded object: /// /// SET { /// /// a INTEGER, /// /// b OCTETSTRING /// /// } /// fn localparse_set(i:&[u8]) -> BerResult { /// parse_ber_set_defined( /// // the nom `tuple` combinator returns a tuple, so we have to map it /// // to a list /// map( /// tuple((parse_ber_integer, parse_ber_octetstring)), /// |(a, b)| vec![a, b] /// ) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = BerObject::from_set(vec![ /// # BerObject::from_int_slice(b"\x01\x00\x01"), /// # BerObject::from_obj(BerObjectContent::OctetString(b"\x01\x00\x00")), /// # ]); /// # assert_eq!(localparse_set(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_set(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_set_defined<'a, F>(mut f: F) -> impl FnMut(&'a [u8]) -> BerResult<'a> where F: FnMut(&'a [u8]) -> BerResult<'a, Vec>>, { map( parse_ber_set_defined_g(move |data, _| f(data)), BerObject::from_set, ) } /// Parse a defined SET object (generic version) /// /// Given a parser for set content, apply it to build a DER set and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the set: any bytes that are part of the sequence but not /// parsed are ignored. /// The nom combinator `all_consuming` can be used to ensure all the content is parsed. /// /// Unlike `parse_ber_set_defined`, this function allows returning any object or error type, /// and also passes the object header to the callback. /// /// # Examples /// /// Parsing a defined set with different types: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// # #[derive(Debug, PartialEq)] /// pub struct MyObject<'a> { /// a: u32, /// b: &'a [u8], /// } /// /// /// Read a DER-encoded object: /// /// SET { /// /// a INTEGER (0..4294967295), /// /// b OCTETSTRING /// /// } /// fn parse_myobject(i: &[u8]) -> BerResult { /// parse_ber_set_defined_g( /// |i:&[u8], _| { /// let (i, a) = parse_ber_u32(i)?; /// let (i, obj) = parse_ber_octetstring(i)?; /// let b = obj.as_slice().unwrap(); /// Ok((i, MyObject{ a, b })) /// } /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = MyObject { /// # a: 0x010001, /// # b: &[01, 00, 00] /// # }; /// # assert_eq!(parse_myobject(&bytes), Ok((empty, expected))); /// let (rem, v) = parse_myobject(&bytes).expect("parsing failed"); /// ``` pub fn parse_ber_set_defined_g<'a, O, F, E>( mut f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E> where F: FnMut(&'a [u8], Header<'a>) -> IResult<&'a [u8], O, E>, E: ParseError<&'a [u8]> + From, { 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 { /// 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, { 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)) } } der-parser-10.0.0/src/ber/parser.rs000064400000000000000000000503311046102023000151510ustar 00000000000000use 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 { 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::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 { 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>(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(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 { /// 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, { parse_ber_tagged_implicit(tag, f)(i) } /// Combinator for building optional BER values /// /// To read optional BER values, it is to use the nom `opt()` combinator. However, this results in /// a `Option` and prevents using some functions from this crate (the generic functions /// can still be used). /// /// This combinator is used when parsing BER values, while keeping `BerObject` output only. /// /// This function will never fail: if parsing content failed, the BER value `Optional(None)` is /// returned. /// /// ### Example /// /// ``` /// # use der_parser::ber::*; /// # /// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; /// let mut parser = parse_ber_optional(parse_ber_integer); /// let (_, obj) = parser(bytes).expect("parsing failed"); /// /// assert_eq!(obj.header.tag(), 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 { ::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 { ::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 { ::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 { ::from_ber(i) } /// Parse BER object and get content as slice #[inline] pub fn parse_ber_slice>(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)); } der-parser-10.0.0/src/ber/print.rs000064400000000000000000000201641046102023000150120ustar 00000000000000use 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, } 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, 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, "{}({:?}) ", ty, s), } } fn print_utf32_string_with_type(f: &mut fmt::Formatter, s: &[u8], ty: &str) -> fmt::Result { let chars: Option> = s .chunks_exact(4) .map(|a| core::char::from_u32(u32::from_be_bytes([a[0], a[1], a[2], a[3]]))) .collect(); match chars { Some(b) => writeln!(f, "{}(\"{}\")", ty, String::from_iter(b)), None => writeln!(f, "{}({:?}) ", ty, s), } } match self.obj.content { BerObjectContent::EndOfContent => 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); } } der-parser-10.0.0/src/ber/serialize.rs000064400000000000000000000362701046102023000156520ustar 00000000000000#![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>(len: Len) -> impl SerializeFn + '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 = 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 + '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 + '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 + '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 + '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 + '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 + '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 + 'a { move |out| match c { BerObjectContent::EndOfContent => be_u8(0)(out), BerObjectContent::Boolean(b) => { let b0 = if *b { 0xff } else { 0x00 }; be_u8(b0)(out) } BerObjectContent::Integer(s) => slice(s)(out), BerObjectContent::BitString(ignored_bits, s) => { tuple((be_u8(*ignored_bits), slice(s)))(out) } BerObjectContent::OctetString(s) => slice(s)(out), BerObjectContent::Null => Ok(out), BerObjectContent::Enum(i) => { let v: Vec = i .to_be_bytes() .iter() .cloned() .skip_while(|&b| b == 0) .collect(); slice(v)(out) } BerObjectContent::OID(oid) | BerObjectContent::RelativeOID(oid) => ber_encode_oid(oid)(out), BerObjectContent::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 + 'a { tuple((ber_encode_header(hdr), ber_encode_object_content(content))) } /// Encode object as BER /// /// Note that the encoding will not check that the values of the `BerObject` fields are correct. /// The length is automatically calculated, and the field is ignored. /// /// `Tagged` objects will be encoded as EXPLICIT. /// /// *This function is only available if the `serialize` feature is enabled.* #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] pub fn ber_encode_object<'a, 'b: 'a, W: Write + Default + AsRef<[u8]> + 'a>( obj: &'b BerObject, ) -> impl SerializeFn + 'a { move |out| { // XXX should we make an exception for tagged values here ? let v = gen_simple(ber_encode_object_content(&obj.content), W::default())?; let len = v.as_ref().len(); let hdr = obj.header.clone().with_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, 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 { 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); } } der-parser-10.0.0/src/ber/tagged.rs000064400000000000000000000171361046102023000151160ustar 00000000000000use crate::ber::*; use crate::error::*; use nom::error::ParseError; use nom::{Err, IResult}; /// Read a TAGGED EXPLICIT value (combinator) /// /// The built object will use the outer header (and tag), and contains a `Tagged` object /// with class, value and content. /// /// For a generic version (different output and error types), see /// [parse_ber_tagged_explicit_g](fn.parse_ber_tagged_explicit_g.html). /// /// The following parses `[2] EXPLICIT INTEGER`: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map_res; /// # /// fn parse_int_explicit(i:&[u8]) -> BerResult { /// map_res( /// parse_ber_tagged_explicit(2, parse_ber_integer), /// |x: BerObject| x.as_tagged()?.2.as_u32() /// )(i) /// } /// /// # let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; /// let res = parse_int_explicit(bytes); /// # match res { /// # Ok((rem,val)) => { /// # assert!(rem.is_empty()); /// # assert_eq!(val, 0x10001); /// # }, /// # _ => assert!(false) /// # } /// ``` pub fn parse_ber_tagged_explicit<'a, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult<'a> where F: Fn(&'a [u8]) -> BerResult<'a, BerObject<'a>>, T: Into, { let tag = tag.into(); parse_ber_tagged_explicit_g(tag, move |content, hdr| { let (rem, obj) = f(content)?; let class = hdr.class(); let obj2 = BerObject::from_header_and_content( hdr, BerObjectContent::Tagged(class, tag, Box::new(obj)), ); Ok((rem, obj2)) }) } /// Read a TAGGED EXPLICIT value (generic version) /// /// The following parses `[2] EXPLICIT INTEGER`: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// fn parse_int_explicit(i:&[u8]) -> BerResult { /// parse_ber_tagged_explicit_g(2, move |content, hdr| { /// let (rem, obj) = parse_ber_integer(content)?; /// let value = obj.as_u32()?; /// Ok((rem, value)) /// })(i) /// } /// /// # let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; /// let res = parse_int_explicit(bytes); /// # match res { /// # Ok((rem,val)) => { /// # assert!(rem.is_empty()); /// # assert_eq!(val, 0x10001); /// # }, /// # _ => assert!(false) /// # } /// ``` pub fn parse_ber_tagged_explicit_g<'a, 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, T: Into, { 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 { /// 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 { /// 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, { let tag = tag.into(); parse_ber_tagged_implicit_g(tag, move |i, hdr, depth| { let (rem, content) = f(i, &hdr, depth)?; // trailing bytes are ignored let obj = BerObject::from_header_and_content(hdr, content); Ok((rem, obj)) }) } /// Read a TAGGED IMPLICIT value (generic version) /// /// Parse a TAGGED IMPLICIT value, given the expected tag, and the content parsing function. /// /// # Examples /// /// The following parses `[1] IMPLICIT OCTETSTRING`, returning a `BerObject`: /// /// ```rust /// # use der_parser::ber::*; /// # use der_parser::error::BerResult; /// # /// fn parse_implicit_0_octetstring(i:&[u8]) -> BerResult { /// parse_ber_tagged_implicit_g( /// 2, /// parse_ber_content2(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 { /// 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, T: Into, { 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 }) } der-parser-10.0.0/src/ber/visit.rs000064400000000000000000000175041046102023000150200ustar 00000000000000use 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()); } } } der-parser-10.0.0/src/ber/visit_mut.rs000064400000000000000000000211101046102023000156710ustar 00000000000000use 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>, depth: usize) {} /// Called for BER set objects fn visit_ber_set_mut(&mut self, ber: &'_ mut Vec>, 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()); } } } der-parser-10.0.0/src/ber/wrap_any.rs000064400000000000000000000247451046102023000155070ustar 00000000000000use 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::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 { 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 { 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 = 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> = SequenceIterator::::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> = SetIterator::::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 { let (rem, res) = parse_ber_any_r(i, MAX_RECURSION)?; assert!(rem.is_empty()); // dbg!(&res); Ok(res) } } der-parser-10.0.0/src/der/mod.rs000064400000000000000000000057211046102023000144410ustar 00000000000000//! Distinguished Encoding Rules (DER) objects and parser //! //! All functions in this crate use BER parsing functions (see the `ber` module) //! internally, adding constraints verification where needed. //! //! The objects [`BerObject`] and [`DerObject`] are the same (type alias): all BER functions, //! combinators and macros can be used, and provide additional tools for DER parsing. //! However, DER parsing functions enforce DER constraints in addition of their BER counterparts. //! //! # DER Objects //! //! The main object of this crate is [`DerObject`]. It contains a header (ber tag, class, and size) //! and content. //! //! To parse primitive objects (for ex. integers or strings), use the `parse_der_` set of //! functions. //! //! Constructed objects (like sequences, sets or tagged objects) require to use a combinator. This //! combinator takes a function or closure as input, and returns a new, specialized parser. //! See the [nom](https://github.com/geal/nom) parser combinator library for more details on //! combinators. //! //! # Examples //! //! Parse two DER integers: //! //! ```rust //! use der_parser::der::parse_der_integer; //! //! let bytes = [ 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x02, 0x03, 0x01, 0x00, 0x00, //! ]; //! //! let (rem, obj1) = parse_der_integer(&bytes).expect("parsing failed"); //! let (rem, obj2) = parse_der_integer(&bytes).expect("parsing failed"); //! ``` //! //! Parse a BER sequence containing one integer and an octetstring: //! //! ```rust //! use der_parser::der::*; //! //! let bytes = [ 0x30, 0x0a, //! 0x02, 0x03, 0x01, 0x00, 0x01, //! 0x04, 0x03, 0x62, 0x61, 0x64, //! ]; //! //! let (rem, seq) = parse_der_sequence_defined(|content| { //! let (rem, obj1) = parse_der_integer(content)?; //! let (rem, obj2) = parse_der_octetstring(rem)?; //! Ok((rem, vec![obj1, obj2])) //! })(&bytes) //! .expect("parsing failed"); //! ``` use crate::ber::{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>; der-parser-10.0.0/src/der/multi.rs000064400000000000000000000417171046102023000150210ustar 00000000000000use 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 { /// 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> { /// parse_der_sequence_of_v(parse_der_integer)(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = vec![ /// # DerObject::from_int_slice(b"\x01\x00\x01"), /// # DerObject::from_int_slice(b"\x01\x00\x00"), /// # ]; /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// # assert_eq!(v, expected); /// ``` pub fn parse_der_sequence_of_v<'a, T, F, E>( f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Vec, E> where F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, E: ParseError<&'a [u8]> + From, { let mut subparser = all_consuming(many0(complete(cut(f)))); parse_der_sequence_defined_g(move |data, _| subparser(data)) } /// Parse a defined sequence of DER elements (function version) /// /// Given a list of expected parsers, apply them to build a DER sequence and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the sequence: any bytes that are part of the sequence but not /// parsed are ignored. /// /// The object header is not available to the parsing function, and the returned type is always a /// `DerObject`. /// For a generic version, see /// [`parse_der_sequence_defined_g`](fn.parse_der_sequence_defined_g.html). /// /// # Examples /// /// Parsing a sequence of identical types (same as `parse_der_sequence_of`): /// /// ```rust /// # use der_parser::der::{parse_der_integer, parse_der_sequence_defined, DerObject}; /// # use der_parser::error::BerResult; /// use nom::combinator::complete; /// use nom::multi::many1; /// /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_der_sequence_defined( /// many1(complete(parse_der_integer)) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = DerObject::from_seq(vec![ /// # DerObject::from_int_slice(b"\x01\x00\x01"), /// # DerObject::from_int_slice(b"\x01\x00\x00"), /// # ]); /// # assert_eq!(localparse_seq(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` /// /// Parsing a defined sequence with different types: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map; /// use nom::sequence::tuple; /// /// /// Read a DER-encoded object: /// /// SEQUENCE { /// /// a INTEGER, /// /// b OCTETSTRING /// /// } /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_der_sequence_defined( /// // the nom `tuple` combinator returns a tuple, so we have to map it /// // to a list /// map( /// tuple((parse_der_integer, parse_der_octetstring)), /// |(a, b)| vec![a, b] /// ) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = DerObject::from_seq(vec![ /// # DerObject::from_int_slice(b"\x01\x00\x01"), /// # DerObject::from_obj(DerObjectContent::OctetString(b"\x01\x00\x00")), /// # ]); /// # assert_eq!(localparse_seq(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_sequence_defined<'a, F>(mut f: F) -> impl FnMut(&'a [u8]) -> BerResult<'a> where F: FnMut(&'a [u8]) -> BerResult<'a, Vec>>, { map( parse_der_sequence_defined_g(move |data, _| f(data)), DerObject::from_seq, ) } /// Parse a defined SEQUENCE object (generic function) /// /// Given a parser for sequence content, apply it to build a DER sequence and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the sequence: any bytes that are part of the sequence but not /// parsed are ignored. /// /// Unlike `parse_der_sequence_defined`, this function allows returning any object or error type, /// and also passes the object header to the callback. /// /// # Examples /// /// Parsing a defined sequence with different types: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// # /// # #[derive(Debug, PartialEq)] /// pub struct MyObject<'a> { /// a: u32, /// b: &'a [u8], /// } /// /// /// Read a DER-encoded object: /// /// SEQUENCE { /// /// a INTEGER (0..4294967295), /// /// b OCTETSTRING /// /// } /// fn parse_myobject(i: &[u8]) -> BerResult { /// parse_der_sequence_defined_g( /// |i:&[u8], _| { /// let (i, a) = parse_der_u32(i)?; /// let (i, obj) = parse_der_octetstring(i)?; /// let b = obj.as_slice().unwrap(); /// Ok((i, MyObject{ a, b })) /// } /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x30, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = MyObject { /// # a: 0x010001, /// # b: &[01, 00, 00] /// # }; /// # assert_eq!(parse_myobject(&bytes), Ok((empty, expected))); /// let (rem, v) = parse_myobject(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_sequence_defined_g<'a, O, F, E>( mut f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E> where F: FnMut(&'a [u8], Header<'a>) -> IResult<&'a [u8], O, E>, E: ParseError<&'a [u8]> + From, { 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 { /// 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> { /// parse_der_set_of_v(parse_der_integer)(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = vec![ /// # DerObject::from_int_slice(b"\x01\x00\x01"), /// # DerObject::from_int_slice(b"\x01\x00\x00"), /// # ]; /// let (rem, v) = parser(&bytes).expect("parsing failed"); /// # assert_eq!(v, expected); /// ``` pub fn parse_der_set_of_v<'a, T, F, E>(f: F) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Vec, E> where F: FnMut(&'a [u8]) -> IResult<&'a [u8], T, E>, E: ParseError<&'a [u8]> + From, { let mut subparser = all_consuming(many0(complete(cut(f)))); parse_der_set_defined_g(move |data, _| subparser(data)) } /// Parse a defined set of DER elements (function version) /// /// Given a list of expected parsers, apply them to build a DER set and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the set: any bytes that are part of the sequence but not /// parsed are ignored. /// The nom combinator `all_consuming` can be used to ensure all the content is parsed. /// /// The object header is not available to the parsing function, and the returned type is always a /// `DerObject`. /// For a generic version, see [`parse_der_set_defined_g`](fn.parse_der_set_defined_g.html). /// /// # Examples /// /// Parsing a set of identical types (same as `parse_der_set_of`): /// /// ```rust /// # use der_parser::der::{parse_der_integer, parse_der_set_defined, DerObject}; /// # use der_parser::error::BerResult; /// use nom::combinator::complete; /// use nom::multi::many1; /// /// fn localparse_seq(i:&[u8]) -> BerResult { /// parse_der_set_defined( /// many1(complete(parse_der_integer)) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x02, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = DerObject::from_set(vec![ /// # DerObject::from_int_slice(b"\x01\x00\x01"), /// # DerObject::from_int_slice(b"\x01\x00\x00"), /// # ]); /// # assert_eq!(localparse_seq(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_seq(&bytes).expect("parsing failed"); /// ``` /// /// Parsing a defined set with different types: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map; /// use nom::sequence::tuple; /// /// /// Read a DER-encoded object: /// /// SET { /// /// a INTEGER, /// /// b OCTETSTRING /// /// } /// fn localparse_set(i:&[u8]) -> BerResult { /// parse_der_set_defined( /// // the nom `tuple` combinator returns a tuple, so we have to map it /// // to a list /// map( /// tuple((parse_der_integer, parse_der_octetstring)), /// |(a, b)| vec![a, b] /// ) /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = DerObject::from_set(vec![ /// # DerObject::from_int_slice(b"\x01\x00\x01"), /// # DerObject::from_obj(DerObjectContent::OctetString(b"\x01\x00\x00")), /// # ]); /// # assert_eq!(localparse_set(&bytes), Ok((empty, expected))); /// let (rem, v) = localparse_set(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_set_defined<'a, F>(mut f: F) -> impl FnMut(&'a [u8]) -> BerResult<'a> where F: FnMut(&'a [u8]) -> BerResult<'a, Vec>>, { map( parse_der_set_defined_g(move |data, _| f(data)), DerObject::from_set, ) } /// Parse a defined SET object (generic version) /// /// Given a parser for set content, apply it to build a DER set and /// return the remaining bytes and the built object. /// /// The remaining bytes point *after* the set: any bytes that are part of the sequence but not /// parsed are ignored. /// The nom combinator `all_consuming` can be used to ensure all the content is parsed. /// /// Unlike `parse_der_set_defined`, this function allows returning any object or error type, /// and also passes the object header to the callback. /// /// # Examples /// /// Parsing a defined set with different types: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// # /// # #[derive(Debug, PartialEq)] /// pub struct MyObject<'a> { /// a: u32, /// b: &'a [u8], /// } /// /// /// Read a DER-encoded object: /// /// SET { /// /// a INTEGER (0..4294967295), /// /// b OCTETSTRING /// /// } /// fn parse_myobject(i: &[u8]) -> BerResult { /// parse_der_set_defined_g( /// |i:&[u8], _| { /// let (i, a) = parse_der_u32(i)?; /// let (i, obj) = parse_der_octetstring(i)?; /// let b = obj.as_slice().unwrap(); /// Ok((i, MyObject{ a, b })) /// } /// )(i) /// } /// /// # let empty = &b""[..]; /// # let bytes = [ 0x31, 0x0a, /// # 0x02, 0x03, 0x01, 0x00, 0x01, /// # 0x04, 0x03, 0x01, 0x00, 0x00, /// # ]; /// # let expected = MyObject { /// # a: 0x010001, /// # b: &[01, 00, 00] /// # }; /// # assert_eq!(parse_myobject(&bytes), Ok((empty, expected))); /// let (rem, v) = parse_myobject(&bytes).expect("parsing failed"); /// ``` pub fn parse_der_set_defined_g<'a, O, F, E>( mut f: F, ) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E> where F: FnMut(&'a [u8], Header<'a>) -> IResult<&'a [u8], O, E>, E: ParseError<&'a [u8]> + From, { 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 { /// 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, { 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)) } } der-parser-10.0.0/src/der/parser.rs000064400000000000000000000506551046102023000151640ustar 00000000000000use 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>(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(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, { 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 { ::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 { ::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 { ::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 { ::from_der(i) } /// Parse DER object and get content as slice #[inline] pub fn parse_der_slice>(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 { // 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 { 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::from_der(i) } der-parser-10.0.0/src/der/tagged.rs000064400000000000000000000172541046102023000151210ustar 00000000000000use crate::ber::MAX_RECURSION; use crate::der::*; use crate::error::*; use nom::error::ParseError; use nom::{Err, IResult}; /// Read a TAGGED EXPLICIT value (combinator) /// /// The built object will use the outer header (and tag), and contains a `Tagged` object /// with class, value and content. /// /// For a generic version (different output and error types), see /// [parse_der_tagged_explicit_g](fn.parse_der_tagged_explicit_g.html). /// /// The following parses `[2] EXPLICIT INTEGER`: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// use nom::combinator::map_res; /// # /// fn parse_int_explicit(i:&[u8]) -> BerResult { /// map_res( /// parse_der_tagged_explicit(2, parse_der_integer), /// |x: DerObject| x.as_tagged()?.2.as_u32() /// )(i) /// } /// /// # let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; /// let res = parse_int_explicit(bytes); /// # match res { /// # Ok((rem,val)) => { /// # assert!(rem.is_empty()); /// # assert_eq!(val, 0x10001); /// # }, /// # _ => assert!(false) /// # } /// ``` pub fn parse_der_tagged_explicit<'a, T, F>(tag: T, f: F) -> impl FnMut(&'a [u8]) -> BerResult<'a> where F: Fn(&'a [u8]) -> BerResult<'a, DerObject<'a>>, T: Into, { let tag = tag.into(); parse_der_tagged_explicit_g(tag, move |content, hdr| { let (rem, obj) = f(content)?; let class = hdr.class(); let obj2 = DerObject::from_header_and_content( hdr, DerObjectContent::Tagged(class, tag, Box::new(obj)), ); Ok((rem, obj2)) }) } /// Read a TAGGED EXPLICIT value (generic version) /// /// The following parses `[2] EXPLICIT INTEGER`: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// # /// fn parse_int_explicit(i:&[u8]) -> BerResult { /// parse_der_tagged_explicit_g(2, move |content, hdr| { /// let (rem, obj) = parse_der_integer(content)?; /// let value = obj.as_u32()?; /// Ok((rem, value)) /// })(i) /// } /// /// # let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; /// let res = parse_int_explicit(bytes); /// # match res { /// # Ok((rem,val)) => { /// # assert!(rem.is_empty()); /// # assert_eq!(val, 0x10001); /// # }, /// # _ => assert!(false) /// # } /// ``` pub fn parse_der_tagged_explicit_g<'a, 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, T: Into, { 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 { /// 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 { /// 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, { let tag = tag.into(); parse_der_tagged_implicit_g(tag, move |i, hdr, depth| { let (rem, content) = f(i, &hdr, depth)?; // trailing bytes are ignored let obj = DerObject::from_header_and_content(hdr, content); Ok((rem, obj)) }) } /// Read a TAGGED IMPLICIT value (generic version) /// /// Parse a TAGGED IMPLICIT value, given the expected tag, and the content parsing function. /// /// # Examples /// /// The following parses `[1] IMPLICIT OCTETSTRING`, returning a `DerObject`: /// /// ```rust /// # use der_parser::der::*; /// # use der_parser::error::BerResult; /// # /// fn parse_implicit_0_octetstring(i:&[u8]) -> BerResult { /// parse_der_tagged_implicit_g( /// 2, /// parse_der_content2(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 { /// 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, T: Into, { 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 }) } der-parser-10.0.0/src/error.rs000064400000000000000000000020521046102023000142330ustar 00000000000000//! 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> = Err(Box::new(e)); } } der-parser-10.0.0/src/lib.rs000064400000000000000000000255041046102023000136570ustar 00000000000000//! [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE-MIT) //! [![Apache License 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE-APACHE) //! [![docs.rs](https://docs.rs/der-parser/badge.svg)](https://docs.rs/der-parser) //! [![crates.io](https://img.shields.io/crates/v/der-parser.svg)](https://crates.io/crates/der-parser) //! [![Download numbers](https://img.shields.io/crates/d/der-parser.svg)](https://crates.io/crates/der-parser) //! [![dependency status](https://deps.rs/crate/der-parser/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)*) }}; } der-parser-10.0.0/src/oid.rs000064400000000000000000000000261046102023000136540ustar 00000000000000pub use asn1_rs::Oid; der-parser-10.0.0/tests/ber_parser.rs000064400000000000000000000526071046102023000156140ustar 00000000000000// 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) { let res = parse_ber_bool(i); if let Some(b) = out { let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } else { assert!(res.is_err()); } } #[test] fn test_ber_bool() { let empty = &b""[..]; let b_true = BerObject::from_obj(BerObjectContent::Boolean(true)); let b_false = BerObject::from_obj(BerObjectContent::Boolean(false)); assert_eq!(parse_ber_bool(&[0x01, 0x01, 0x00]), Ok((empty, b_false))); assert_eq!( parse_ber_bool(&[0x01, 0x01, 0xff]), Ok((empty, b_true.clone())) ); assert_eq!(parse_ber_bool(&[0x01, 0x01, 0x7f]), Ok((empty, b_true))); assert_eq!( parse_ber_bool(&[0x01, 0x02, 0x12, 0x34]), Err(Err::Error(BerError::InvalidLength)) ); } #[test] fn test_seq_indefinite_length() { let data = hex!("30 80 04 03 56 78 90 00 00 02 01 01"); let res = parse_ber(&data); assert_eq!( res, Ok(( &data[9..], BerObject::from_seq(vec![BerObject::from_obj(BerObjectContent::OctetString( &data[4..=6] )),]) )) ); let res = parse_ber_sequence(&data); assert_eq!( res, Ok(( &data[9..], BerObject::from_seq(vec![BerObject::from_obj(BerObjectContent::OctetString( &data[4..=6] )),]) )) ); } #[test] fn test_ber_set_of() { let empty = &b""[..]; let bytes = [ 0x31, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let expected = BerObject::from_set(vec![ BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_int_slice(b"\x01\x00\x00"), ]); fn parser(i: &[u8]) -> BerResult { parse_ber_set_of(parse_ber_integer)(i) } assert_eq!(parser(&bytes), Ok((empty, expected))); // empty input should raise error (could not read set header) assert!(parser(&[]).is_err()); // empty set is ok (returns empty vec) assert!(parser(&[0x31, 0x00]).is_ok()); } #[test] fn test_ber_set_of_v() { let empty = &b""[..]; let bytes = [ 0x31, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let expected = vec![ BerObject::from_int_slice(b"\x01\x00\x01"), BerObject::from_int_slice(b"\x01\x00\x00"), ]; fn parser(i: &[u8]) -> BerResult> { parse_ber_set_of_v(parse_ber_integer)(i) } assert_eq!(parser(&bytes), Ok((empty, expected))); // empty input should raise error (could not read set header) assert!(parser(&[]).is_err()); // empty set is ok (returns empty vec) assert_eq!(parser(&[0x31, 0x00]), Ok((empty, vec![]))); } #[test] fn test_set_indefinite_length() { let data = hex!("31 80 04 03 56 78 90 00 00"); let res = parse_ber(&data); assert_eq!( res, Ok(( &data[9..], BerObject::from_set(vec![BerObject::from_obj(BerObjectContent::OctetString( &data[4..=6] )),]) )) ); let res = parse_ber_set(&data); assert_eq!( res, Ok(( &data[9..], BerObject::from_set(vec![BerObject::from_obj(BerObjectContent::OctetString( &data[4..=6] )),]) )) ); } #[test] fn test_ber_int() { let empty = &b""[..]; let bytes = [0x02, 0x03, 0x01, 0x00, 0x01]; let expected = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); assert_eq!(parse_ber_integer(&bytes), Ok((empty, expected))); } #[test_case(&hex!("02 01 01"), Ok(1) ; "u32-1")] #[test_case(&hex!("02 02 00 ff"), Ok(255) ; "u32-255")] #[test_case(&hex!("02 02 01 23"), Ok(0x123) ; "u32-0x123")] #[test_case(&hex!("02 04 01 23 45 67"), Ok(0x0123_4567) ; "u32-long-ok")] #[test_case(&hex!("02 05 00 ff ff ff ff"), Ok(0xffff_ffff) ; "u32-long2-ok")] #[test_case(&hex!("02 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) { 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) { 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) { let res = parse_ber_i64(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[cfg(feature = "bigint")] #[test_case(&hex!("02 01 01"), Ok(BigInt::from(1)) ; "bigint-1")] #[test_case(&hex!("02 02 00 ff"), Ok(BigInt::from(255)) ; "bigint-255")] #[test_case(&hex!("02 01 ff"), Ok(BigInt::from(-1)) ; "bigint-neg1")] #[test_case(&hex!("02 01 80"), Ok(BigInt::from(-128)) ; "bigint-neg128")] #[test_case(&hex!("02 02 ff 7f"), Ok(BigInt::from(-129)) ; "bigint-neg129")] #[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(BigInt::from(0xffff_ffff_ffff_ffff_u64)) ; "bigint-long2-ok")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(BigInt::from_bytes_be(Sign::Plus, &hex!("01 23 45 67 01 23 45 67 ab"))) ; "bigint-longer1")] fn tc_ber_bigint(i: &[u8], out: Result) { let res = parse_ber_integer(i); match out { Ok(expected) => { let (rem, ber) = res.expect("parsing failed"); assert!(rem.is_empty()); let int = ber.as_bigint().expect("failed to convert to bigint"); pretty_assertions::assert_eq!(int, expected); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[cfg(feature = "bigint")] #[test_case(&hex!("02 01 01"), Ok(BigUint::from(1_u8)) ; "biguint-1")] #[test_case(&hex!("02 02 00 ff"), Ok(BigUint::from(255_u8)) ; "biguint-255")] #[test_case(&hex!("02 01 ff"), Err(BerError::IntegerNegative) ; "biguint-neg1")] #[test_case(&hex!("02 01 80"), Err(BerError::IntegerNegative) ; "biguint-neg128")] #[test_case(&hex!("02 02 ff 7f"), Err(BerError::IntegerNegative) ; "biguint-neg129")] #[test_case(&hex!("02 09 00 ff ff ff ff ff ff ff ff"), Ok(BigUint::from(0xffff_ffff_ffff_ffff_u64)) ; "biguint-long2-ok")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(BigUint::from_bytes_be(&hex!("01 23 45 67 01 23 45 67 ab"))) ; "biguint-longer1")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::unexpected_tag(Some(Tag(2)), Tag(3))) ; "invalid tag")] fn tc_ber_biguint(i: &[u8], out: Result) { let res = parse_ber_integer(i).and_then(|(rem, ber)| Ok((rem, ber.as_biguint()?))); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("02 01 01"), Ok(&[1]) ; "slice 1")] #[test_case(&hex!("02 01 ff"), Ok(&[255]) ; "slice 2")] #[test_case(&hex!("02 09 01 23 45 67 01 23 45 67 ab"), Ok(&hex!("01 23 45 67 01 23 45 67 ab")) ; "slice 3")] #[test_case(&hex!("22 80 02 01 01 00 00"), Ok(&[2, 1, 1]) ; "constructed slice")] #[test_case(&hex!("03 03 01 00 01"), Err(BerError::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>) { let res = parse_ber_utf8string(i); match out { Ok(b) => { let (rem, res) = res.expect("could not parse utf8string"); assert!(rem.is_empty()); let r = res.as_str().expect("could not convert to string"); // let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(r, b); } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("12 04 31 32 33 34"), Ok("1234") ; "numeric string")] #[test_case(&hex!("12 05 68 65 6c 6c 6f"), Err(Err::Error(BerError::StringInvalidCharset)) ; "invalid chars")] #[test_case(&hex!("12 05 01 02 03 04 05"), Err(Err::Error(BerError::StringInvalidCharset)) ; "invalid chars2")] fn tc_ber_numeric_string(i: &[u8], out: Result<&str, Err>) { let res = parse_ber_numericstring(i); match out { Ok(b) => { let (rem, res) = res.expect("could not parse numericstring"); assert!(rem.is_empty()); let r = res.as_str().expect("could not convert to string"); // let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(r, b); } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("13 04 31 32 33 34"), Ok("1234") ; "printable: numeric")] #[test_case(&hex!("13 05 68 65 6c 6c 6f"), Ok("hello") ; "printable: string")] #[test_case(&hex!("13 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64"), Ok("hello world") ; "printable: string with spaces")] #[test_case(&hex!("13 0b 68 65 6c 6c 6f 5c 77 6f 72 6c 64"), Err(Err::Error(BerError::StringInvalidCharset)) ; "printable: string with backspace")] #[test_case(&hex!("13 0b 68 65 6c 6c 6f 2b 77 6f 72 6c 64"), Ok("hello+world") ; "printable: string with plus")] #[test_case(&hex!("13 05 01 02 03 04 05"), Err(Err::Error(BerError::StringInvalidCharset)) ; "invalid chars")] fn tc_ber_printable_string(i: &[u8], out: Result<&str, Err>) { let res = parse_ber_printablestring(i); match out { Ok(b) => { let (rem, res) = res.expect("could not parse printablestring"); assert!(rem.is_empty()); let r = res.as_str().expect("could not convert to string"); // let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(r, b); } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("16 04 31 32 33 34"), Ok("1234") ; "ia5: numeric")] #[test_case(&hex!("16 05 68 65 6c 6c 6f"), Ok("hello") ; "ia5: string")] #[test_case(&hex!("16 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64"), Ok("hello world") ; "ia5: string with spaces")] #[test_case(&hex!("16 0b 68 65 6c 6c 6f 5c 77 6f 72 6c 64"), Ok("hello\\world") ; "ia5: string with backspace")] #[test_case(&hex!("16 0b 68 65 6c 6c 6f 2b 77 6f 72 6c 64"), Ok("hello+world") ; "ia5: string with plus")] #[test_case(&hex!("16 05 01 02 03 04 05"), Ok("\x01\x02\x03\x04\x05") ; "invalid chars")] #[test_case(&hex!("16 0d d0 bf d1 80 d0 b8 d0 b2 d0 b5 cc 81 d1 82"), Err(Err::Error(BerError::StringInvalidCharset)) ; "utf8")] fn tc_ber_ia5_string(i: &[u8], out: Result<&str, Err>) { let res = parse_ber_ia5string(i); match out { Ok(b) => { let (rem, res) = res.expect("could not parse ia5string"); assert!(rem.is_empty()); let r = res.as_str().expect("could not convert to string"); // let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(r, b); } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("1a 04 31 32 33 34"), Ok("1234") ; "visible: numeric")] #[test_case(&hex!("1a 05 68 65 6c 6c 6f"), Ok("hello") ; "visible: string")] #[test_case(&hex!("1a 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64"), Ok("hello world") ; "visible: string with spaces")] #[test_case(&hex!("1a 0b 68 65 6c 6c 6f 5c 77 6f 72 6c 64"), Ok("hello\\world") ; "printable: string with backspace")] #[test_case(&hex!("1a 0b 68 65 6c 6c 6f 2b 77 6f 72 6c 64"), Ok("hello+world") ; "printable: string with plus")] #[test_case(&hex!("1a 05 01 02 03 04 05"), Err(Err::Error(BerError::StringInvalidCharset)) ; "invalid chars")] fn tc_ber_visible_string(i: &[u8], out: Result<&str, Err>) { let res = parse_ber_visiblestring(i); match out { Ok(b) => { let (rem, res) = res.expect("could not parse visiblestring"); assert!(rem.is_empty()); let r = res.as_str().expect("could not convert to string"); // let expected = BerObject::from_obj(BerObjectContent::Boolean(b)); pretty_assertions::assert_eq!(r, b); } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test] fn test_ber_utf8string() { let empty = &b""[..]; let bytes = [ 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, ]; let expected = BerObject::from_obj(BerObjectContent::UTF8String("Some-State")); assert_eq!(parse_ber_utf8string(&bytes), Ok((empty, expected))); } #[test] fn test_ber_relativeoid() { let empty = &b""[..]; let bytes = hex!("0d 04 c2 7b 03 02"); let expected = BerObject::from_obj(BerObjectContent::RelativeOID( Oid::from_relative(&[8571, 3, 2]).unwrap(), )); assert_eq!(parse_ber_relative_oid(&bytes), Ok((empty, expected))); } #[test] fn test_ber_bmpstring() { let empty = &b""[..]; let bytes = hex!("1e 08 00 55 00 73 00 65 00 72"); let expected = BerObject::from_obj(BerObjectContent::BmpString(b"\x00U\x00s\x00e\x00r")); assert_eq!(parse_ber_bmpstring(&bytes), Ok((empty, expected))); } #[test] fn test_ber_customtags() { let bytes = hex!("8f 02 12 34"); let hdr = ber_read_element_header(&bytes) .expect("ber_read_element_header") .1; // println!("{:?}", hdr); let expected: &[u8] = &[0x8f]; assert_eq!(hdr.raw_tag(), Some(expected)); let bytes = hex!("9f 0f 02 12 34"); let hdr = ber_read_element_header(&bytes) .expect("ber_read_element_header") .1; // println!("{:?}", hdr); let expected: &[u8] = &[0x9f, 0x0f]; assert_eq!(hdr.raw_tag(), Some(expected)); } #[test] fn test_ber_indefinite() { let bytes = hex!("30 80 02 03 01 00 01 00 00"); let (rem, val) = parse_ber_container::<_, _, BerError>(|i, _| { assert!(!i.is_empty()); let (_, val) = parse_ber_u32(i)?; Ok((i, val)) })(&bytes) .unwrap(); assert!(rem.is_empty()); assert_eq!(val, 0x10001); } #[test] fn test_ber_indefinite_recursion() { let data = &hex!( " 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 24 80 00 00" ); let _ = parse_ber_container::<_, _, BerError>(|i, _| Ok((i, ())))(data) .expect_err("max parsing depth overflow"); } #[test] fn test_parse_ber_content() { let bytes = &hex!("02 03 01 00 01"); let (i, header) = ber_read_element_header(bytes).expect("parsing failed"); let (rem, content) = parse_ber_content(header.tag())(i, &header, MAX_RECURSION).expect("parsing failed"); assert!(rem.is_empty()); assert_eq!(header.tag(), 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(_))); } der-parser-10.0.0/tests/constructed.rs000064400000000000000000000374231046102023000160240ustar 00000000000000// 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 { parse_der_sequence_defined_g(|i: &[u8], _| { let (i, a) = parse_ber_integer(i)?; let (i, b) = parse_ber_integer(i)?; Ok((i, MyStruct { a, b })) })(i) } fn parse_struct01_complete(i: &[u8]) -> BerResult { parse_der_sequence_defined_g(|i: &[u8], _| { let (i, a) = parse_ber_integer(i)?; let (i, b) = parse_ber_integer(i)?; eof(i)?; Ok((i, MyStruct { a, b })) })(i) } // verifying tag fn parse_struct04(i: &[u8], tag: Tag) -> BerResult { parse_der_container(|i: &[u8], hdr| { if hdr.tag() != tag { return Err(Err::Error(BerError::InvalidTag)); } let (i, a) = parse_ber_integer(i)?; let (i, b) = parse_ber_integer(i)?; eof(i)?; Ok((i, MyStruct { a, b })) })(i) } #[test_case(&hex!("30 00"), Ok(&[]) ; "empty seq")] #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "seq ok")] #[test_case(&hex!("30 07 02 03 01 00 01 02 03 01"), Err(Err::Error(BerError::NomError(ErrorKind::Eof))) ; "incomplete")] #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Err(Err::Error(BerError::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>) { 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>) { fn parser(i: &[u8]) -> BerResult { parse_ber_sequence_defined(map( tuple((parse_ber_integer, parse_ber_integer)), |(a, b)| vec![a, b], ))(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse sequence"); assert!(rem.is_empty()); if let BerObjectContent::Sequence(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("31 00"), Ok(&[]) ; "empty set")] #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "set ok")] #[test_case(&hex!("31 07 02 03 01 00 01 02 03 01"), Err(Err::Error(BerError::NomError(ErrorKind::Eof))) ; "incomplete")] #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Err(Err::Error(BerError::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>) { 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>) { fn parser(i: &[u8]) -> BerResult { parse_ber_set_defined(map( tuple((parse_ber_integer, parse_ber_integer)), |(a, b)| vec![a, b], ))(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse set"); assert!(rem.is_empty()); if let BerObjectContent::Set(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test] fn empty_seq() { let data = &hex!("30 00"); let (_, res) = parse_ber_sequence(data).expect("parsing empty sequence failed"); assert!(res.as_sequence().unwrap().is_empty()); } #[test] fn struct01() { let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let empty = &b""[..]; let expected = MyStruct { a: BerObject::from_int_slice(b"\x01\x00\x01"), b: BerObject::from_int_slice(b"\x01\x00\x00"), }; let res = parse_struct01(&bytes); assert_eq!(res, Ok((empty, expected))); } #[test] fn struct02() { let empty = &b""[..]; let bytes = [ 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x46, 0x52, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x16, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, ]; #[derive(Debug, PartialEq)] struct Attr<'a> { oid: Oid<'a>, val: BerObject<'a>, } #[derive(Debug, PartialEq)] struct Rdn<'a> { a: Attr<'a>, } #[derive(Debug, PartialEq)] struct Name<'a> { l: Vec>, } let expected = Name { l: vec![ Rdn { a: Attr { oid: Oid::from(&[2, 5, 4, 6]).unwrap(), // countryName val: BerObject::from_obj(BerObjectContent::PrintableString("FR")), }, }, Rdn { a: Attr { oid: Oid::from(&[2, 5, 4, 8]).unwrap(), // stateOrProvinceName val: BerObject::from_obj(BerObjectContent::UTF8String("Some-State")), }, }, Rdn { a: Attr { oid: Oid::from(&[2, 5, 4, 10]).unwrap(), // organizationName val: BerObject::from_obj(BerObjectContent::IA5String( "Internet Widgits Pty Ltd", )), }, }, ], }; fn parse_directory_string(i: &[u8]) -> BerResult { alt(( parse_ber_utf8string, parse_ber_printablestring, parse_ber_ia5string, ))(i) } fn parse_attr_type_and_value(i: &[u8]) -> BerResult { fn clone_oid(x: BerObject) -> Result { x.as_oid().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 { parse_der_set_defined_g(|i: &[u8], _| { let (i, a) = parse_attr_type_and_value(i)?; Ok((i, Rdn { a })) })(i) } fn parse_name(i: &[u8]) -> BerResult { parse_der_sequence_defined_g(|i: &[u8], _| { let (i, l) = many0(complete(parse_rdn))(i)?; Ok((i, Name { l })) })(i) } let parsed = parse_name(&bytes).unwrap(); assert_eq!(parsed, (empty, expected)); // assert_eq!(parsed.1.l[0].a.val.as_str(), Ok("FR")); assert_eq!(parsed.1.l[1].a.val.as_str(), Ok("Some-State")); assert_eq!(parsed.1.l[2].a.val.as_str(), Ok("Internet Widgits Pty Ltd")); } #[test] fn struct_with_garbage() { let bytes = [ 0x30, 0x0c, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, 0xff, 0xff, ]; let empty = &b""[..]; let expected = MyStruct { a: BerObject::from_int_slice(b"\x01\x00\x01"), b: BerObject::from_int_slice(b"\x01\x00\x00"), }; assert_eq!(parse_struct01(&bytes), Ok((empty, expected))); assert_eq!( parse_struct01_complete(&bytes), Err(Err::Error(error_position!(&bytes[12..], ErrorKind::Eof))) ); } #[test] fn struct_verify_tag() { let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let empty = &b""[..]; let expected = MyStruct { a: BerObject::from_int_slice(b"\x01\x00\x01"), b: BerObject::from_int_slice(b"\x01\x00\x00"), }; let res = parse_struct04(&bytes, 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) { fn parse_int_explicit(i: &[u8]) -> BerResult { parse_ber_tagged_explicit_g(2, move |content, _hdr| { let (rem, obj) = parse_ber_integer(content)?; let value = obj.as_u32()?; Ok((rem, value)) })(i) } let res = parse_int_explicit(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test] fn tagged_explicit() { fn parse_int_explicit(i: &[u8]) -> BerResult { map_res( parse_der_tagged_explicit(2, parse_der_integer), |x: BerObject| x.as_tagged()?.2.as_u32(), )(i) } let bytes = &[0xa2, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01]; // EXPLICIT tagged value parsing let (rem, val) = parse_int_explicit(bytes).expect("Could not parse explicit int"); assert!(rem.is_empty()); assert_eq!(val, 0x10001); // wrong tag assert_eq!( parse_der_tagged_explicit(3, parse_der_integer)(bytes as &[u8]), Err(Err::Error(BerError::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) { fn parse_int_implicit(i: &[u8]) -> BerResult { 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 { 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 { 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"); } der-parser-10.0.0/tests/custom_error.rs000064400000000000000000000027261046102023000162100ustar 00000000000000//! This test file ensures the functions to parse containers like sequences and sets //! work correctly with custom errors. use der_parser::ber::{parse_ber_sequence_of_v, parse_ber_u32}; use der_parser::error::BerError; use nom::error::{ErrorKind, ParseError}; use nom::{Err, IResult}; #[derive(Debug)] pub enum MyError<'a> { Variant1, Variant2, BerError(BerError), NomError(&'a [u8], ErrorKind), } impl<'a> ParseError<&'a [u8]> for MyError<'a> { fn from_error_kind(input: &'a [u8], kind: ErrorKind) -> Self { MyError::NomError(input, kind) } fn append(_input: &'a [u8], _kind: ErrorKind, other: Self) -> Self { other } } impl From 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]); } der-parser-10.0.0/tests/der_constructed.rs000064400000000000000000000171331046102023000166520ustar 00000000000000// 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) { fn parse_int_explicit(i: &[u8]) -> BerResult { parse_der_tagged_explicit_g(2, move |content, _hdr| { let (rem, obj) = parse_der_integer(content)?; let value = obj.as_u32()?; Ok((rem, value)) })(i) } let res = parse_int_explicit(i); match out { Ok(expected) => { pretty_assertions::assert_eq!(res, Ok((&b""[..], expected))); } Err(e) => { pretty_assertions::assert_eq!(res, Err(Err::Error(e))); } } } #[test_case(&hex!("82 03 01 00 01"), Ok(0x10001) ; "tag ok")] #[test_case(&hex!("83 03 01 00 01"), Err(BerError::unexpected_tag(Some(Tag(2)), Tag(3))) ; "invalid tag")] fn tc_der_tagged_implicit_g(i: &[u8], out: Result) { fn parse_int_implicit(i: &[u8]) -> BerResult { parse_der_tagged_implicit_g(2, |content, hdr, depth| { let (rem, obj) = parse_der_content(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>) { fn parser(i: &[u8]) -> BerResult { parse_der_sequence_defined(map( tuple((parse_der_integer, parse_der_integer)), |(a, b)| vec![a, b], ))(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse sequence"); assert!(rem.is_empty()); if let DerObjectContent::Sequence(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } #[test_case(&hex!("31 00"), Ok(&[]) ; "empty set")] #[test_case(&hex!("31 0a 02 03 01 00 01 02 03 01 00 00"), Ok(&[0x10001, 0x10000]) ; "set ok")] #[test_case(&hex!("31 07 02 03 01 00 01 02 03 01"), Err(BerError::NomError(ErrorKind::Eof)) ; "incomplete")] #[test_case(&hex!("30 0a 02 03 01 00 01 02 03 01 00 00"), Err(BerError::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>) { fn parser(i: &[u8]) -> BerResult { parse_der_set_defined(map( tuple((parse_der_integer, parse_der_integer)), |(a, b)| vec![a, b], ))(i) } let res = parser(i); match out { Ok(l) => { let (rem, res) = res.expect("could not parse set"); assert!(rem.is_empty()); if let DerObjectContent::Set(res) = res.content { pretty_assertions::assert_eq!(res.len(), l.len()); for (a, b) in res.iter().zip(l.iter()) { pretty_assertions::assert_eq!(a.as_u32().unwrap(), *b); } } else { panic!("wrong type for parsed object"); } } Err(e) => { pretty_assertions::assert_eq!(res, Err(e)); } } } der-parser-10.0.0/tests/der_parser.rs000064400000000000000000000531521046102023000156120ustar 00000000000000// 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> { 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) { 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) { 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) { 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))); } } } der-parser-10.0.0/tests/fuzz01.rs000064400000000000000000000004151046102023000146150ustar 00000000000000#[test] fn test01() { let data = b"\x03\x00\x00kk\x00\x00\x00\x00\x00\x00\x00.\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff;\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00\x00\x00\xff\x0a\xff"; let _ = der_parser::parse_der(data); } der-parser-10.0.0/tests/fuzz02.rs000064400000000000000000000014111046102023000146130ustar 00000000000000#[test] fn test02() { let data = b"\x06\x00\x01\x00\x00\x2a"; let _ = der_parser::parse_der(data); } #[test] fn test03() { let data = b"\x06\x0a*\xf1\x0a*\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe"; let _ = der_parser::parse_der(data); } #[test] fn test04() { let data = &[ 0x50, 0x2a, 0xa, 0x8d, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa, 0x0, 0xb, 0x22, 0x56, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf1, 0xa, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ]; let _ = der_parser::parse_der(data); } der-parser-10.0.0/tests/issue-76.rs000064400000000000000000000015521046102023000150430ustar 00000000000000use 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()); } der-parser-10.0.0/tests/oid.rs000064400000000000000000000013241046102023000142310ustar 00000000000000//! Test the API provided to compare OIDs extern crate alloc; use der_parser::oid; use der_parser::oid::Oid; const OID_RSA_ENCRYPTION: &[u8] = &oid!(raw 1.2.840.113549.1.1.1); const OID_EC_PUBLIC_KEY: &[u8] = &oid!(raw 1.2.840.10045.2.1); #[allow(clippy::match_like_matches_macro)] fn compare_oid(oid: &Oid) -> bool { match oid.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)); } der-parser-10.0.0/tests/primitive.rs000064400000000000000000000156361046102023000155010ustar 00000000000000extern 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); }