Search code examples
c#encodingasn.1ber

Can I specify an Application or Context-Specific tag with C# BerConverter.Encode()?


.NET's System.DirectoryServices.Protocols assembly specifies a light-weight ASN.1 BER encoder, but the documentation is not great: BerConverter.

You call it by specifying a format string and a list of objects to encode.

  • INTEGERs can be encoded with format characters i or e
  • OCTET STRINGs can be encoded with o character
  • SEQUENCEs can be encoded with { and }
  • etc.

I'd really like to make use of this simple converter so I don't have to take on an additional dependency. Taking on a dependency is undesirable because C# is callable from Powershell, and it is great to distribute a script that does something fancy with C# so long as it doesn't require an assembly that isn't included with .NET.

However, BerConverter doesn't seem to have a way to specify an Application or Context-Specific tag, which are often used to remove ambiguity in ASN.1, for example when components of a constructed type are marked as OPTIONAL

So, I can encode the following:

BerConverter.Encode("{i{i}}", 1, 2);

Which gives:

30 84 00 00 00 0c 02 01 01 30 84 00 00 00 03 02 01 02

But, if that second sequence needs to be [Application 1] or 61... I'm not sure what to put in the format string to emit that in the encoding.

Does BerConverter even have this capability?


Solution

  • I'm not sure why I didn't just do this up front, but I used a decompiler to look at the code. I found that BerConverter.Encode() is based on ber_printf(), which has much better documentation.

    From the docs:

    Character: 't'

    Description:

    Tag. The next argument is a ber_tag_t that specifies the tag to override the next element written to the BerElement. This works across calls.

    So, I was able to change my code to:

    BerConverter.Encode("{it{i}}", 1, 0x61, 2)

    Which allows me to set the tag value to 0x61 and the code emits:

    30 84 00 00 00 0c 02 01 01 61 84 00 00 00 03 02 01 02