diff options
Diffstat (limited to 'rust/vendor/asn1-rs/doc/DERIVE.md')
-rw-r--r-- | rust/vendor/asn1-rs/doc/DERIVE.md | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/rust/vendor/asn1-rs/doc/DERIVE.md b/rust/vendor/asn1-rs/doc/DERIVE.md new file mode 100644 index 0000000..5322140 --- /dev/null +++ b/rust/vendor/asn1-rs/doc/DERIVE.md @@ -0,0 +1,323 @@ +# BER/DER Custom Derive Attributes + +## BER/DER Sequence parsers + +### `BER` + +To derive a BER `SEQUENCE` parser, add the [`BerSequence`] derive attribute to an existing struct. Parsers will be derived automatically for all fields, which must implement the [`FromBer`] trait. + +For ex: + +```rust +# use asn1_rs::*; +#[derive(Debug, PartialEq, BerSequence)] +pub struct S { + a: u32, + b: u16, + c: u16, +} + +# let parser = |input| -> Result<(), Error> { +let (rest, result) = S::from_ber(input)?; +# Ok(()) }; +``` + +After parsing b, any bytes that were leftover and not used to fill val will be returned in `rest`. + +When parsing a `SEQUENCE` into a struct, any trailing elements of the `SEQUENCE` that do +not have matching fields in val will not be included in `rest`, as these are considered +valid elements of the `SEQUENCE` and not trailing data. + +### `DER` + +To derive a `DER` parser, use the [`DerSequence`] custom attribute. + +*Note: the `DerSequence` attributes derive both `BER` and `DER` parsers.* + +## Tagged values + +### `EXPLICIT` + +There are several ways of parsing tagged values: either using types like [`TaggedExplicit`], or using custom annotations. + +Using `TaggedExplicit` works as usual. The only drawback is that the type is visible in the structure, so accessing the value must be done using `.as_ref()` or `.into_inner()`: + +```rust +# use asn1_rs::*; +#[derive(Debug, PartialEq, DerSequence)] +pub struct S2 { + a: u16, +} + +// test with EXPLICIT Vec +#[derive(Debug, PartialEq, DerSequence)] +pub struct S { + // a INTEGER + a: u32, + // b INTEGER + b: u16, + // c [0] EXPLICIT SEQUENCE OF S2 + c: TaggedExplicit<Vec<S2>, Error, 0>, +} + +# let parser = |input| -> Result<(), Error> { +let (rem, result) = S::from_ber(input)?; + +// Get a reference on c (type is &Vec<S2>) +let ref_c = result.c.as_ref(); +# Ok(()) }; +``` + +*Note: tags are context-specific by default. To specify other kind of tags (like `APPLICATION`) use [`TaggedValue`].* + +### `tag_explicit` + +To "hide" the tag from the parser, the `tag_explicit` attribute is provided. This attribute must specify the tag value (as an integer), and will automatically wrap reading the value with the specified tag. + +```rust +# use asn1_rs::*; +#[derive(Debug, PartialEq, DerSequence)] +pub struct S { + // a [0] EXPLICIT INTEGER + #[tag_explicit(0)] + a: u16, +} + +# let parser = |input| -> Result<(), Error> { +let (rem, result) = S::from_ber(input)?; +# Ok(()) }; +``` + +This method handles transparently the encapsulation and the read of the tagged value. + +*Note: tags are context-specific by default. To specify other kind of tags (like `APPLICATION`) add the tag class before the value in the `tag_explicit` attribute.* +For ex: `tag_explicit(APPLICATION 0)` or `tag_explicit(PRIVATE 2)`. + +### Tagged optional values + +The `optional` custom attribute can be used in addition of `tag_explicit` to specify that the value is `OPTIONAL`. + +The type of the annotated field member must be resolvable to `Option`. + +```rust +# use asn1_rs::*; +#[derive(Debug, PartialEq, DerSequence)] +pub struct S { + // a [0] EXPLICIT INTEGER OPTIONAL + #[tag_explicit(0)] + #[optional] + a: Option<u16>, + // b INTEGER + b: u16, +} + +# let parser = |input| -> Result<(), Error> { +let (rem, result) = S::from_ber(input)?; +# Ok(()) }; +``` + +### `IMPLICIT` + +Tagged `IMPLICIT` values are handled similarly as for `EXPLICIT`, and can be parsed either using the [`TaggedImplicit`] type, or using the `tag_implicit` custom attribute. + +For ex: +```rust +# use asn1_rs::*; +#[derive(Debug, PartialEq, DerSequence)] +pub struct S { + // a [0] IMPLICIT INTEGER OPTIONAL + #[tag_implicit(0)] + #[optional] + a: Option<u16>, + // b INTEGER + b: u16, +} + +# let parser = |input| -> Result<(), Error> { +let (rem, result) = S::from_ber(input)?; +# Ok(()) }; +``` + +## `OPTIONAL` values (not tagged) + +The `optional` custom attribute can be specified to indicate the value is `OPTIONAL`. + +```rust +# use asn1_rs::*; +#[derive(Debug, PartialEq, DerSequence)] +pub struct S { + // a INTEGER + a: u16, + // b INTEGER OPTIONAL + #[optional] + b: Option<u16>, +} + +# let parser = |input| -> Result<(), Error> { +let (rem, result) = S::from_ber(input)?; +# Ok(()) }; +``` + +**Important**: there are several limitations to this attribute. + +In particular, the parser is eager: when an `OPTIONAL` value of some type is followed by another value (not `OPTIONAL`) of the same type, this can create problem. +If only one value is present, the parser will affect it to the first field, and then raise an error because the second is absent. + +Note that this does not concern tagged optional values (unless they have the same tag). + +## `DEFAULT` + +The `default` custom attribute can be specified to indicate the value has a `DEFAULT` attribute. The value can also be marked as +`OPTIONAL`, but this can be omitted. + +Since the value can always be obtained, the type should not be `Option<T>`, but should use `T` directly. + +```rust +# use asn1_rs::*; +#[derive(Debug, PartialEq, DerSequence)] +#[debug_derive] +pub struct S { + // a INTEGER + a: u16, + // b INTEGER DEFAULT 0 + #[default(0_u16)] + b: u16, +} + +# let parser = |input| -> Result<(), Error> { +let (rem, result) = S::from_ber(input)?; +# Ok(()) }; +``` + +Limitations are the same as for `OPTIONAL` attribute. + +## Debugging + +To help debugging the generated code, the `#[debug_derive]` attribute has been added. + +When this attribute is specified, the generated code will be printed to `stderr` during compilation. + +Example: +```rust +use asn1_rs::*; + +#[derive(BerSequence)] +#[debug_derive] +struct S { + a: u32, +} +``` + +## BER/DER Set parsers + +Parsing BER/DER `SET` objects is very similar to `SEQUENCE`. Use the [`BerSet`] and [`DerSet`] custom derive attributes on the structure, and everything else is exactly the same as for sequences (see above for documentation). + +Example: +```rust +# use asn1_rs::*; +use std::collections::BTreeSet; + +// `Ord` is needed because we will parse as a `BTreeSet` later +#[derive(Debug, DerSet, PartialEq, Eq, PartialOrd, Ord)] +pub struct S2 { + a: u16, +} + +// test with EXPLICIT Vec +#[derive(Debug, PartialEq, DerSet)] +pub struct S { + // a INTEGER + a: u32, + // b INTEGER + b: u16, + // c [0] EXPLICIT SET OF S2 + c: TaggedExplicit<BTreeSet<S2>, Error, 0>, +} + +# let parser = |input| -> Result<(), Error> { +let (rem, result) = S::from_ber(input)?; + +// Get a reference on c (type is &BTreeSet<S2>) +let ref_c = result.c.as_ref(); +# Ok(()) }; +``` + +# Advanced + +## Custom errors + +Derived parsers can use the `error` attribute to specify the error type of the parser. + +The custom error type must implement `From<Error>`, so the derived parsers will transparently convert errors using the [`Into`] trait. + + +Example: +```rust +# use asn1_rs::*; +# +#[derive(Debug, PartialEq)] +pub enum MyError { + NotYetImplemented, +} + +impl From<asn1_rs::Error> for MyError { + fn from(_: asn1_rs::Error) -> Self { + MyError::NotYetImplemented + } +} + +#[derive(DerSequence)] +#[error(MyError)] +pub struct T2 { + pub a: u32, +} +``` + +## Mapping errors + +Sometimes, it is necessary to map the returned error to another type, for example when a subparser returns a different error type than the parser's, and the [`Into`] trait cannot be implemented. This is often used in combination with the `error` attribute, but can also be used alone. + +The `map_err` attribute can be used to specify a function or closure to map errors. The function signature is `fn (e1: E1) -> E2`. + +Example: +```rust +# use asn1_rs::*; +# +#[derive(Debug, PartialEq)] +pub enum MyError { + NotYetImplemented, +} + +impl From<asn1_rs::Error> for MyError { + fn from(_: asn1_rs::Error) -> Self { + MyError::NotYetImplemented + } +} + +#[derive(DerSequence)] +#[error(MyError)] +pub struct T2 { + pub a: u32, +} + +// subparser returns an error of type MyError, +// which is mapped to `Error` +#[derive(DerSequence)] +pub struct T4 { + #[map_err(|_| Error::BerTypeError)] + pub a: T2, +} +``` + +*Note*: when deriving BER and DER parsers, errors paths are different (`TryFrom` returns the error type, while [`FromDer`] returns a [`ParseResult`]). Some code will be inserted by the `map_err` attribute to handle this transparently and keep the same function signature. + +[`FromBer`]: crate::FromBer +[`FromDer`]: crate::FromDer +[`BerSequence`]: crate::BerSequence +[`DerSequence`]: crate::DerSequence +[`BerSet`]: crate::BerSet +[`DerSet`]: crate::DerSet +[`ParseResult`]: crate::ParseResult +[`TaggedExplicit`]: crate::TaggedExplicit +[`TaggedImplicit`]: crate::TaggedImplicit +[`TaggedValue`]: crate::TaggedValue |