2

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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
Maik Hasler
  • 1,064
  • 6
  • 36
  • Do you have a sample of your data? – Evk Oct 28 '22 at 15:24
  • @Evk Of course, initially I added an example image to this question, but removed it since it will only stretch the question even more... I think the image provided in [this SO question](https://stackoverflow.com/questions/65345927/pkcs7-cms-message-digest-calculation-process) displays my data pretty well. It's not totally the same, but the principle should be the same. – Maik Hasler Oct 28 '22 at 15:56
  • But image of data is pretty useless, need something that you can actually use (copy paste). – Evk Oct 28 '22 at 16:25
  • @Evk Okay sure no problem, I've provided a base 64 string in the question. – Maik Hasler Oct 28 '22 at 16:35

2 Answers2

1

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.

Paul Thorpe
  • 1,930
  • 17
  • 23
  • First of all thank you very much for your answer. That's what I thought, but I wanted to be sure because I'm not an ASN.1 expert at all. Besides that may I ask if you have any idea how I could improve my decoding process? The process right now is quite elaborate, since it's a stateful, forward-only reader. Is there any way to reach specific data fields faster? I might add this to my question aswell, since it seems pretty important to me thinking about it... – Maik Hasler Oct 28 '22 at 15:02
  • 1
    Since BER/DER/CER use Tag-length-Value encodings, when you encounter the tag for a field you have no interest in, you can use the length to skip over it instead of decoding all of the contents of that component. This assumes that you are familiar with the ASN.1 specification and know the tags of the components you are interested in including which components those fields are nested inside of. – Paul Thorpe Oct 31 '22 at 17:50
0

You really want a good ASN.1 compiler for C#. I don't know if such a thing exists. I maintain an open source one for C that maybe you could port.

user2259432
  • 2,239
  • 1
  • 19
  • 15
  • Sounds nice, could you give me a link to your project? – Maik Hasler Nov 04 '22 at 07:50
  • 1
    @MaikHasler Heimdal, https://github.com/heimdal/heimdal, has an ASN.1 compiler in lib/asn1/, and it is quite functional. For example, it supports just enough ASN.1 Information Object System extensions to make it possible to fully decode a `Certificate`, including all attributes, extensions, and `otherName` subject alternative names that are declared in `lib/asn1/rfc2459.asn1` in just one invocation of the decoder (ditto for encoding), and it can produce JSON too, so you can get a very nice JSON representation of a `Certificate`. – user2259432 Nov 05 '22 at 00:43
  • There are good ASN.1 compilers supporting C#, they're commercial though (Objective Systems, OSS-Nokalva being two providers). I've used both, and I can report that both are very good, and have used them on the kind of projects for which spending money on tooling was well worth doing. – bazza Nov 12 '22 at 20:14
  • Commercial ASN.1 compilers are generally very good, but not very usable for open source projects. Heimdal's ASN.1 compiler outputs a JSON representation of ASN.1 modules that is suitable for driving code generation in other languages than C and for other languages than C, and a friend of mine is doing just that. This includes the Information Object System open type traversal feature. – user2259432 Nov 20 '22 at 06:10