Rufus Buschart
Rufus Buschart

Reputation: 553

How to use System.Formats.Asn1.AsnReader

Since June 2020 .net has a an ASN1 reader implemented. In the documentation there is no example how to use it. Also a search at Google and in SO doesn't show any examples or descriptions. Where can I find some?

Upvotes: 11

Views: 4604

Answers (1)

Rufus Buschart
Rufus Buschart

Reputation: 553

I found the design document at Microsoft (very well hidden) with some examples. And kudos to Karl-Johan who found the related unit tests. Based on these examples, I was able to write a comprehensive example program which parses an OCSP response.

using System.Formats.Asn1;

// An OCSP response according  https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.1 as Base64 encoded DER
string b64OCSPResponseDER = @"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";

byte[] ocspResponseDER = Convert.FromBase64String(b64OCSPResponseDER);

AsnReader asnReader1 = new(new ReadOnlyMemory<byte>(ocspResponseDER), AsnEncodingRules.DER);

AsnReader? ocspResponse = asnReader1.ReadSequence();

OCSPResponseStatus? responseStatus = ocspResponse?.ReadEnumeratedValue<OCSPResponseStatus>();

Asn1Tag context0 = new (TagClass.ContextSpecific, 0);

AsnReader? responseBytes = ocspResponse?.ReadSequence(context0);

AsnReader? _responseBytes = responseBytes?.ReadSequence();

string? responseType = _responseBytes?.ReadObjectIdentifier();

byte[]? response = _responseBytes?.ReadOctetString();

AsnReader asnReader2 = new(new ReadOnlyMemory<byte>(response), AsnEncodingRules.DER);

AsnReader? basicOCSPResponse = asnReader2.ReadSequence();

AsnReader? tbsResponseData = basicOCSPResponse?.ReadSequence();

// Skip parsing of tbsResponseData

AsnReader? signatureAlgorithm = basicOCSPResponse?.ReadSequence();

// Skip parsing of signatureAlgorithm

int unusedBitsCounter;
byte[]? signature = basicOCSPResponse?.ReadBitString(out unusedBitsCounter);

AsnReader? certs = basicOCSPResponse?.ReadSequence(context0);

AsnReader? cert1 = certs?.ReadSequence();

ReadOnlyMemory<byte> encodedValue = cert1.ReadEncodedValue();
string b64encodedCert1 = Convert.ToBase64String(encodedValue.ToArray());

bool endReached = !certs.HasData;

Console.WriteLine(b64encodedCert1);

enum OCSPResponseStatus : byte
{
    successful = 0, // Response has valid confirmations
    malformedRequest = 1, // Illegal confirmation request
    internalError = 2, // Internal error in issuer
    tryLater = 3, // Try again later
    // (4) is not used
    sigRequired = 5, // Must sign the request
    unauthorized = 6 //   --Request unauthorized
}

Upvotes: 12

Related Questions