Search code examples
c#.netasn.1der

How to iterate through an complex ASN.1 sequence in C#?


Initial situation

Currently, I am trying to iterate through a complex ASN.1 sequence using the AsnReader class. Most code snippets down below are inspired by a well hidden ASN.1 BER/CER/DER Reader & Writer design document.

The ASN.1 sequence is defined as type of envelopedData, which can be identified with the OID 1.2.840.113549.1.7.3. Here you can see the visualized ASN.1 type definition. The sequence itself is DER (Distinguished Encoding Rules) encoded.

First, I tried to instantiate a new AsnReader with DER as encoding rules.

var bytes = File.ReadAllBytes(@"pathToMyFile.txt");

var reader = new AsnReader(fileBytes, AsnEncodingRules.DER);

var sequence = reader.ReadSequence();

It ended up in this exception.

System.Formats.Asn1.AsnContentException: "The encoded length is not valid under the requested encoding rules, the value may be valid under the BER encoding."

Question: Why can't I set the encoding rules to DER? Does it make any difference to use BER?

For now I set the encoding rules to BER, which worked fine until...

var reader = new AsnReader(fileBytes, AsnEncodingRules.BER);

var sequence = reader.ReadSequence();

var context = new Asn1Tag(TagClass.ContextSpecific, 0);

var next_sequence = sequence.ReadSequence(context);

The above ended up in this exception:

System.Formats.Asn1.AsnContentException: "The provided data is tagged with 'Universal' class value '6', but it should have been 'ContextSpecific' class value '0'."

Question: Does anybody knows how I could iterate through this ASN.1 sequence using the AsnReader class?

I highly appreciate any kind of help, cheers!


Edit 1: AsnReader

After some research I finally managed to read the documentation for the AsnReader class properly. The documentation describes the class as...

... a stateful, forward-only reader for BER-, CER-, or DER-encoded ASN.1 data.

That's why my initial AsnReader implementation is total nonsense.

In the following I would like to give a small example of how to iterate through the individual sequences or data fields in a complex ASN.1 structure using AsnReader.

var bytes = new ReadOnlyMemory<byte>(File.ReadAllBytes(@"pathToMyFile.txt"));

var reader = new AsnReader(fileBytes, AsnEncodingRules.BER);
var sequence = reader.ReadSequence();
reader.ThrowIfNotEmpty();

var oid = sequence.ReadObjectIdentifier();
Console.WriteLine(oid);

var context = new Asn1Tag(TagClass.ContextSpecific, 0);

if (sequence.HasData && sequence.PeekTag().HasSameClassAndValue(context))
{
    var contextSequence = sequence.ReadSequence(context);
    var subSequence = contextSequence.ReadSequence();

    var version = subSequence.ReadInteger();
    Console.WriteLine(version);
}

The above code returns the correct values as follows.

>> 1.2.840.113549.1.7.3
>> 0

Nevertheless, I still don't know why I can't set the encoding rules to DER.

Question: The decoding process right now is quite elaborate, since it's a stateful, forward-only reader. Is there any way to reach specific data fields faster?

Data to test with: This is a base 64 encoded string of type envelopedData, which can be identified with the details provided at the top of the question.

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

Solution

  • Many implementations of ASN.1 encoding rules will implement only encoders for DER and CER but decoders only for BER since DER and CER are subsets of BER, thus making the code much simpler. While it is important to be able to encode DER and CER, the decoding process tends to be more relaxed and tolerant of slight deviations in the encodings.