fASN1.NET
1.3.0
dotnet add package fASN1.NET --version 1.3.0
NuGet\Install-Package fASN1.NET -Version 1.3.0
<PackageReference Include="fASN1.NET" Version="1.3.0" />
paket add fASN1.NET --version 1.3.0
#r "nuget: fASN1.NET, 1.3.0"
// Install fASN1.NET as a Cake Addin #addin nuget:?package=fASN1.NET&version=1.3.0 // Install fASN1.NET as a Cake Tool #tool nuget:?package=fASN1.NET&version=1.3.0
fASN1.NET
fASN1.NET is a .NET library for working with ASN.1 (Abstract Syntax Notation One) data. It provides functionality for serializing and deserializing ASN.1 data, as well as extracting various pieces of information from ASN.1 encoded certificates.
Features
- Serialize and deserialize ASN.1 data.
- ASN.1 data structured string representation.
- Extract key usage, extended key usage, SAN (Subject Alternative Name), and other certificate details.
- Support for long string content handling, including wrapping and word wrapping.
ASN.1 references
Table of Contents
Installation
fASN1.NET is available as a NuGet package. You can install it using the following command:
dotnet add package fASN1.NET
Usage
Deserialize ASN.1 Data and get certificate details
The main purpose of the library is to work with ASN.1 encoded certificates. The following example demonstrates how to deserialize an ASN.1 encoded certificate and extract various pieces of information from it.
using System;
using System.Collections.Generic;
using System.IO;
using fASN1.NET;
//current github ssl cert (as of 04.08.2024)
var data = Convert.FromBase64String("MIIEozCCBEmgAwIBAgIQTij3hrZsGjuULNLEDrdCpTAKBggqhkjOPQQDAjCBjzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIEVDQyBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMB4XDTI0MDMwNzAwMDAwMFoXDTI1MDMwNzIzNTk1OVowFTETMBEGA1UEAxMKZ2l0aHViLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABARO/Ho9XdkY1qh9mAgjOUkWmXTb05jgRulKciMVBuKB3ZHexvCdyoiCRHEMBfFXoZhWkQVMogNLo/lW215X3pGjggL+MIIC+jAfBgNVHSMEGDAWgBT2hQo7EYbhBH0Oqgss0u7MZHt7rjAdBgNVHQ4EFgQUO2g/NDr1RzTK76ZOPZq9Xm56zJ8wDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEkGA1UdIARCMEAwNAYLKwYBBAGyMQECAgcwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQIBMIGEBggrBgEFBQcBAQR4MHYwTwYIKwYBBQUHMAKGQ2h0dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb0VDQ0RvbWFpblZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMIIBgAYKKwYBBAHWeQIEAgSCAXAEggFsAWoAdwDPEVbu1S58r/OHW9lpLpvpGnFnSrAX7KwB0lt3zsw7CAAAAY4WOvAZAAAEAwBIMEYCIQD7oNz/2oO8VGaWWrqrsBQBzQH0hRhMLm11oeMpg1fNawIhAKWc0q7Z+mxDVYV/6ov7f/i0H/aAcHSCIi/QJcECraOpAHYAouMK5EXvva2bfjjtR2d3U9eCW4SU1yteGyzEuVCkR+cAAAGOFjrv+AAABAMARzBFAiEAyupEIVAMk0c8BVVpF0QbisfoEwy5xJQKQOe8EvMU4W8CIGAIIuzjxBFlHpkqcsa7UZy24y/B6xZnktUw/Ne5q5hCAHcATnWjJ1yaEMM4W2zU3z9S6x3w4I4bjWnAsfpksWKaOd8AAAGOFjrv9wAABAMASDBGAiEA+8OvQzpgRf31uLBsCE8ktCUfvsiRT7zWSqeXliA09TUCIQDcB7Xn97aEDMBKXIbdm5KZ9GjvRyoF9skD5/4GneoMWzAlBgNVHREEHjAcggpnaXRodWIuY29tgg53d3cuZ2l0aHViLmNvbTAKBggqhkjOPQQDAgNIADBFAiEAru2McPr0eNwcWNuDEY0a/rGzXRfRrm+6XfZeSzhYZewCIBq4TUEBCgapv7xvAtRKdVdi/b4m36Uyej1ggyJsiesA");
using var ms = new MemoryStream(data);
var tag = Asn1Serializer.Deserialize(ms);
if (Asn1Serializer.TryDeserialize(data, out var tag2, out var error) is false)
{
Console.WriteLine($"Data deserialization error: {error}");
return;
}
if (tag.TryGetCertificateSubjectItem(SubjectItemKind.CommonName, true, out List<string> issuerCn))
{
Console.WriteLine($"Issuer CN: {issuerCn[0]}");
}
if (tag.TryGetCertificateSubjectItem(SubjectItemKind.CommonName, false, out List<string> subjectCn))
{
Console.WriteLine($"Subject CN: {subjectCn[0]}");
}
if(tag.TryGetCertificateNotAfter(out var notAfter))
{
Console.WriteLine($"Not After: {notAfter}");
}
if (tag.TryGetKeyUsage(out var ku))
{
Console.WriteLine($"Key Usage: {ku}");
}
Output:
Issuer CN: Sectigo ECC Domain Validation Secure Server CA
Subject CN: github.com
Not After: 07.03.2025 23:59:59
Key Usage: DigitalSignature, NonRepudiation
Serialize ASN.1 Data
This library also provides functionality for serializing ASN.1 data. The following example demonstrates how to serialize an ASN.1 tag.
using System;
using System.Text;
using fASN1.NET;
using fASN1.NET.Tags;
var root = new Sequence([
new Integer([1]),
new Sequence([
new ObjectIdentifier([0,1,35,45,55,127,126]),
new Utf8String(Encoding.UTF8.GetBytes("Random text")),
new ContextSpecific_0(children: [
new BitString(content: [123,125,222,255,0,1,4])
])
])
]);
var serialized = Asn1Serializer.Serialize(root);
var deserializedTag = Asn1Serializer.Deserialize(serialized);
var deserializedText = Asn1Serializer.TagToString(deserializedTag);
Console.WriteLine(deserializedText);
The data looks like this after serialization into a string:
Sequence
| Integer 1
| Sequence
| | ObjectIdentifier 0.0.1.35.45.55.127.126
| | UTF8String Random text
| | [0]
| | | BitString 011110110111110111011110111111110000000000000001000
Get Subject Director Attributes (SDA) from a certificate
The fASN1.NET
library provides a predefined class for working with Subject Directory Attributes (SDA), as specified in (https://datatracker.ietf.org/doc/html/rfc3739#page-9).
The SubjectDirectoryAttributes
class includes the following properties:
/// <summary>
/// Gets the gender.
/// </summary>
/// <remarks>
/// If this property is <see langword="null"/>, you may use <see cref="GenderString"/> property to get value that is not in the enum range.
/// </remarks>
public Gender? Gender { get; protected set; }
/// <summary>
/// Gets the gender as a string.
/// </summary>
public string? GenderString { get; protected set; }
/// <summary>
/// Gets the date of birth.
/// </summary>
public DateTime? DateOfBirth { get; protected set; }
/// <summary>
/// Gets the place of birth.
/// </summary>
public string? PlaceOfBirth { get; protected set; }
/// <summary>
/// Gets the country of residence.
/// </summary>
public IReadOnlyList<string> CountryOfResidence { get; protected set; }
/// <summary>
/// Gets the country of citizenship.
/// </summary>
public IReadOnlyList<string> CountryOfCitizenship { get; protected set; }
The SubjectDirectoryAttributes
class is not sealed, allowing developers to inherit it to add custom properties or override setters for existing ones.
SubjectDirectoryAttributes
class in the following file: SubjectDirectory/SubjectDirectoryAttributes.cs
The example below demonstrates how to extract Subject Directory Attributes (SDA) from an X.509v3 certificate:
ITag cert = new X509Certificate2(_pem);
bool sda = SubjectDirectoryAttributes.FromCertificate(cert);
You can also extract the Subject Directory Attributes (SDA) directly from an ASN.1 tag:
ITag tag = Asn1Serializer.Deserialize(_pem);
bool success = tag.TryGetSubjectDirectoryAttributesFromCertificate(out var sda);
Performance
The following table shows the performance of the current implementation when working with certificates.
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3)
AMD Ryzen 7 7840HS with Radeon 780M Graphics, 1 CPU, 16 logical and 8 physical cores
.NET SDK 8.0.300
[Host] : .NET 8.0.5 (8.0.524.21615), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
DefaultJob : .NET 8.0.5 (8.0.524.21615), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
---|---|---|---|---|---|---|
DeserializeCertificate | 4.846 us | 0.0961 us | 0.1733 us | 2.0294 | 0.1068 | 16.61 KB |
SerializeCertificateTagToString | 50.612 us | 0.3710 us | 0.3470 us | 10.9863 | 0.4883 | 90.45 KB |
The previous version of the library (Asn1DecoderNet5) was like this:
Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
---|---|---|---|---|---|---|
DeserializeCertificate | 27.93 us | 0.105 us | 0.088 us | 2.7161 | 0.1526 | 22.23 KB |
SerializeCertificateTagToString | 89.47 us | 1.723 us | 1.527 us | 46.6309 | 7.2021 | 381.05 KB |
The performance has been significantly improved, especially when serializing the data to a string.
Note: The smaller and less complex the data, the better the performance (especially the memory allocation).
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.5.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.