Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consume embedded SEQUENCE in a clean way #33

Open
Arenash13 opened this issue Mar 11, 2024 · 2 comments
Open

Consume embedded SEQUENCE in a clean way #33

Arenash13 opened this issue Mar 11, 2024 · 2 comments

Comments

@Arenash13
Copy link

I have a BER schema which looks like the following :

SEQUENCE {
    typeA SEQUENCE {...}
    typeB SEQUENCE {...}
}

I try to retrieve fields that are located in typeA SEQUENCE, how can I inspect it in a way to deal with errors, i.e. is it possible to do something like the following :

let (rem, result) = Sequence::from_ber_and_then(input, |i| {
     let (rem2, a) = Sequence::from_ber_and_then(input, |j| {
          let (rem2, a) = u32::from_der(input)?;
          ....
         Ok(...)
})?;

Is it the right to do that ? I'm not able to find the correct code to write in order to run that.

Thanks in advance

@chifflier
Copy link
Member

You have multiple options

If you know the definition of your types, the recommended solution is to create a struct for each sequence and derive parsers to be able to call from_der. See for example this unit test:

  • T1 is the container
  • T2 would be something like typeA in your example
  • If you want BER (and not DER), use the BerSequence derive and from_ber in all the examples below

Resulting code would look like:

#[derive(Debug, PartialEq, DerSequence)]
pub struct MyType {
    a: TypeA,
    b: TypeB,
}

#[derive(Debug, PartialEq, DerSequence)]
pub struct TypeA {
    field1: u32,
    ...
}

let (rem, obj) = MyType::from_der(input)?;

If you can't derive or prefer to use manual parsers, the solution you describe will work, but it will not be idiomatic.
You have multiple solutions (again, deriving is preferred):

  • reading the first sequence only, then parsing the content:
let (rem, seq) = Sequence::from_der(input)?;
let (inner_rem, type_a) = Sequence::from_der(seq.content)?;
let (inner_rem, type_b) = Sequence::from_der(inner_rem)?;
  • there are multiple variants of the above code, for ex:
let (rem, seq) = Sequence::from_der(input)?;
let (inner_rem, type_a) = Sequence::from_der_and_then(seq.content, |i| {
    let (rem2, a) = u32::from_der(input)?;
    ...
   Ok(...)
})?;

let (inner_rem, type_b) = Sequence::from_der(inner_rem)?;

  • you can also mix both solutions (derive and parsing):
let (rem, seq) = Sequence::from_der(input)?;
let (inner_rem, type_a) = TypeA::from_der(seq.content)?;
})?;
  • you can also not use the automatic derive, and implement FromDer. See for example x509-parser-0.16.0/src/revocation_list.rs#L128-L148 (and all other parsing code from the x509-parser crate) for example using custom errors
    Note: parse_der_sequence_defined_g is the old way to parse a sequence, equivalent to Sequence::from_der_and_then

@Arenash13
Copy link
Author

Thanks for your answer !

I will check for the idiomatic way if my use case grows. For now, I only need to retrieve a few fields in the BER data

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants