rusticata / asn1-rs

Parsers/Encoders for ASN.1 BER/DER data
Apache License 2.0
10 stars 14 forks source link

ToBer is missing? #31

Open KarstenB opened 9 months ago

KarstenB commented 9 months ago

The main readme hints at the existence of a ToBer trait:

BER/DER encoding is symmetrical to decoding, using the traits ToBer and [ToDer] traits. 

However I can't find anything about this in the code. Am I just missing something obvious?

chifflier commented 8 months ago

Hi,

You're not missing anything! Only DER is currently supported, but since DER is a subset of BER, generating DER will result in valid BER data.

The limit is that using ToDer will always generate canonical encoding, and will not allow you to generate for example dequences with indefinite length

KarstenB commented 8 months ago

Unfortunately using ToDer is not an option for me as I try to implement this ASN.1 https://github.com/wireshark/wireshark/blob/master/epan/dissectors/asn1/sv/sv.asn

Which uses explicit tagging all the time. I am not sure I found the best solution for creating these, but it surely feels hacky:

fn write_implicit_header(
    writer: &mut dyn std::io::Write,
    tag: u8,
    field: &impl ToDer,
) -> asn1_rs::SerializeResult<usize> {
    let mut inner_buffer = Vec::new();
    let inner_header_size = field.write_der_header(&mut inner_buffer)?;
    let header = asn1_rs::Header::new(
        asn1_rs::Class::ContextSpecific,
        false,
        Tag::EndOfContent,
        asn1_rs::Length::Definite(field.to_der_len()? - inner_header_size),
    );
    let header = header.with_raw_tag(Some(Cow::Owned(vec![
        tag | 0x80, /* context specific */
    ])));
    header.write_der_raw(writer)
}

Or am I missing something very obvious on how I could generate implicit tags?

chifflier commented 8 months ago

Ah, I see.

Objects like TaggedParser and TaggedValue do implement ToDer, so you just have to build an implicit object and call .to_der_vec(). You can also use TaggedImplicit. All these APIs are equivalent, you can choose the one you prefer (I suggest TaggedImplicit), for ex something like:

let object = Integer::from(2);
let tagged: TaggedImplicit::<_, Error, 0> = TaggedValue::implicit(object); // 0 is the implicit tag here
let v = tagged.to_der_vec()?;

See this unit test for examples.

Note: I assumed you want to serialize the entire tagged object. If you want only the header, use tagged.write_der_header(v) with a writer, like v = &mut Vec<u8>, to store the result.

Serialization could be better documented, I think.