mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-02-04 05:36:12 +00:00
Make TypeLengthValue more model-like
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using SabreTools.Serialization.ASN1;
|
||||
using SabreTools.Serialization.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.Serialization.Test.ASN1
|
||||
namespace SabreTools.Serialization.Test.Extensions
|
||||
{
|
||||
public class TypeLengthValueTests
|
||||
{
|
||||
@@ -12,7 +13,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_EOC()
|
||||
{
|
||||
string expected = "Type: V_ASN1_EOC";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_EOC, Length = 0, Value = null };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_EOC, Length = 0, Value = null };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -21,7 +22,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ZeroLength()
|
||||
{
|
||||
string expected = "Type: V_ASN1_NULL, Length: 0";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_NULL, Length = 0, Value = null };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_NULL, Length = 0, Value = null };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -30,7 +31,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_InvalidConstructed()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OBJECT, V_ASN1_CONSTRUCTED, Length: 1, Value: [INVALID DATA TYPE]";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_OBJECT | ASN1Type.V_ASN1_CONSTRUCTED, Length = 1, Value = (object?)false };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_OBJECT | ASN1Type.V_ASN1_CONSTRUCTED, Length = 1, Value = (object?)false };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -39,8 +40,8 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidConstructed()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OBJECT, V_ASN1_CONSTRUCTED, Length: 3, Value:\n Type: V_ASN1_BOOLEAN, Length: 1, Value: True";
|
||||
var boolTlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_BOOLEAN, Length = 1, Value = new byte[] { 0x01 } };
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_OBJECT | ASN1Type.V_ASN1_CONSTRUCTED, Length = 3, Value = new TypeLengthValue[] { boolTlv } };
|
||||
var boolTlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_BOOLEAN, Length = 1, Value = new byte[] { 0x01 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_OBJECT | ASN1Type.V_ASN1_CONSTRUCTED, Length = 3, Value = new Serialization.ASN1.TypeLengthValue[] { boolTlv } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -49,7 +50,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_InvalidDataType()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OBJECT, Length: 1, Value: [INVALID DATA TYPE]";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_OBJECT, Length = 1, Value = (object?)false };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_OBJECT, Length = 1, Value = (object?)false };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -58,7 +59,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_InvalidLength()
|
||||
{
|
||||
string expected = "Type: V_ASN1_NULL, Length: 1, Value: [NO DATA]";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_NULL, Length = 1, Value = Array.Empty<byte>() };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_NULL, Length = 1, Value = Array.Empty<byte>() };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -67,7 +68,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_InvalidBooleanLength()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BOOLEAN, Length: 2 [Expected length of 1], Value: True";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_BOOLEAN, Length = 2, Value = new byte[] { 0x01 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_BOOLEAN, Length = 2, Value = new byte[] { 0x01 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -76,7 +77,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_InvalidBooleanArrayLength()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BOOLEAN, Length: 1 [Expected value length of 1], Value: True";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_BOOLEAN, Length = 1, Value = new byte[] { 0x01, 0x00 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_BOOLEAN, Length = 1, Value = new byte[] { 0x01, 0x00 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -85,7 +86,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidBoolean()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BOOLEAN, Length: 1, Value: True";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_BOOLEAN, Length = 1, Value = new byte[] { 0x01 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_BOOLEAN, Length = 1, Value = new byte[] { 0x01 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -94,7 +95,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidInteger()
|
||||
{
|
||||
string expected = "Type: V_ASN1_INTEGER, Length: 1, Value: 1";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_INTEGER, Length = 1, Value = new byte[] { 0x01 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_INTEGER, Length = 1, Value = new byte[] { 0x01 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -103,7 +104,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidBitString_NoBits()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BIT_STRING, Length: 1, Value with 0 unused bits";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_BIT_STRING, Length = 1, Value = new byte[] { 0x00 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_BIT_STRING, Length = 1, Value = new byte[] { 0x00 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -112,7 +113,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidBitString_Bits()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BIT_STRING, Length: 1, Value with 1 unused bits: 01";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_BIT_STRING, Length = 1, Value = new byte[] { 0x01, 0x01 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_BIT_STRING, Length = 1, Value = new byte[] { 0x01, 0x01 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -121,7 +122,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidOctetString()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OCTET_STRING, Length: 1, Value: 01";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_OCTET_STRING, Length = 1, Value = new byte[] { 0x01 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_OCTET_STRING, Length = 1, Value = new byte[] { 0x01 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -130,7 +131,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidObject()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OBJECT, Length: 3, Value: 0.1.2.3 (/ITU-T/1/2/3)";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_OBJECT, Length = 3, Value = new byte[] { 0x01, 0x02, 0x03 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_OBJECT, Length = 3, Value = new byte[] { 0x01, 0x02, 0x03 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -139,7 +140,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidUTF8String()
|
||||
{
|
||||
string expected = "Type: V_ASN1_UTF8STRING, Length: 3, Value: ABC";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_UTF8STRING, Length = 3, Value = new byte[] { 0x41, 0x42, 0x43 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_UTF8STRING, Length = 3, Value = new byte[] { 0x41, 0x42, 0x43 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -148,7 +149,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidPrintableString()
|
||||
{
|
||||
string expected = "Type: V_ASN1_PRINTABLESTRING, Length: 3, Value: ABC";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_PRINTABLESTRING, Length = 3, Value = new byte[] { 0x41, 0x42, 0x43 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_PRINTABLESTRING, Length = 3, Value = new byte[] { 0x41, 0x42, 0x43 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -157,7 +158,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidTeletexString()
|
||||
{
|
||||
string expected = "Type: V_ASN1_TELETEXSTRING, Length: 3, Value: ABC";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_TELETEXSTRING, Length = 3, Value = new byte[] { 0x41, 0x42, 0x43 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_TELETEXSTRING, Length = 3, Value = new byte[] { 0x41, 0x42, 0x43 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -166,7 +167,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidIA5String()
|
||||
{
|
||||
string expected = "Type: V_ASN1_IA5STRING, Length: 3, Value: ABC";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_IA5STRING, Length = 3, Value = new byte[] { 0x41, 0x42, 0x43 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_IA5STRING, Length = 3, Value = new byte[] { 0x41, 0x42, 0x43 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -175,7 +176,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_InvalidUTCTime()
|
||||
{
|
||||
string expected = "Type: V_ASN1_UTCTIME, Length: 3, Value: ABC";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_UTCTIME, Length = 3, Value = new byte[] { 0x41, 0x42, 0x43 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_UTCTIME, Length = 3, Value = new byte[] { 0x41, 0x42, 0x43 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -184,7 +185,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidUTCTime()
|
||||
{
|
||||
string expected = "Type: V_ASN1_UTCTIME, Length: 3, Value: 1980-01-01 00:00:00";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_UTCTIME, Length = 3, Value = new byte[] { 0x31, 0x39, 0x38, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31, 0x20, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x3A, 0x30, 0x30 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_UTCTIME, Length = 3, Value = new byte[] { 0x31, 0x39, 0x38, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31, 0x20, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x3A, 0x30, 0x30 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -193,7 +194,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidBmpString()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BMPSTRING, Length: 6, Value: ABC";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_BMPSTRING, Length = 6, Value = new byte[] { 0x41, 0x00, 0x42, 0x00, 0x43, 0x00 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_BMPSTRING, Length = 6, Value = new byte[] { 0x41, 0x00, 0x42, 0x00, 0x43, 0x00 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -202,7 +203,7 @@ namespace SabreTools.Serialization.Test.ASN1
|
||||
public void Format_ValidUnformatted()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OBJECT_DESCRIPTOR, Length: 1, Value: 01";
|
||||
var tlv = new TypeLengthValue { Type = ASN1Type.V_ASN1_OBJECT_DESCRIPTOR, Length = 1, Value = new byte[] { 0x01 } };
|
||||
var tlv = new Serialization.ASN1.TypeLengthValue { Type = ASN1Type.V_ASN1_OBJECT_DESCRIPTOR, Length = 1, Value = new byte[] { 0x01 } };
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.Serialization.ASN1
|
||||
namespace SabreTools.Serialization.ASN1
|
||||
{
|
||||
/// <summary>
|
||||
/// ASN.1 type/length/value class that all types are based on
|
||||
@@ -23,154 +19,5 @@ namespace SabreTools.Serialization.ASN1
|
||||
/// Generic value associated with <see cref="Type"/>
|
||||
/// </summary>
|
||||
public object? Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Format the TLV as a string
|
||||
/// </summary>
|
||||
/// <param name="paddingLevel">Padding level of the item when formatting</param>
|
||||
/// <returns>String representing the TLV, if possible</returns>
|
||||
public string Format(int paddingLevel = 0)
|
||||
{
|
||||
// Create the left-padding string
|
||||
string padding = new(' ', paddingLevel);
|
||||
|
||||
// Create the string builder
|
||||
var formatBuilder = new StringBuilder();
|
||||
|
||||
// Append the type
|
||||
formatBuilder.Append($"{padding}Type: {Type}");
|
||||
if (Type == ASN1Type.V_ASN1_EOC)
|
||||
return formatBuilder.ToString();
|
||||
|
||||
// Append the length
|
||||
formatBuilder.Append($", Length: {Length}");
|
||||
if (Length == 0)
|
||||
return formatBuilder.ToString();
|
||||
|
||||
// If we have a constructed type
|
||||
#if NET20 || NET35
|
||||
if ((Type & ASN1Type.V_ASN1_CONSTRUCTED) != 0)
|
||||
#else
|
||||
if (Type.HasFlag(ASN1Type.V_ASN1_CONSTRUCTED))
|
||||
#endif
|
||||
{
|
||||
if (Value is not TypeLengthValue[] valueAsObjectArray)
|
||||
{
|
||||
formatBuilder.Append(", Value: [INVALID DATA TYPE]");
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
|
||||
formatBuilder.Append(", Value:\n");
|
||||
for (int i = 0; i < valueAsObjectArray.Length; i++)
|
||||
{
|
||||
var child = valueAsObjectArray[i];
|
||||
string childString = child.Format(paddingLevel + 1);
|
||||
formatBuilder.Append($"{childString}\n");
|
||||
}
|
||||
|
||||
return formatBuilder.ToString().TrimEnd('\n');
|
||||
}
|
||||
|
||||
// Get the value as a byte array
|
||||
if (Value is not byte[] valueAsByteArray)
|
||||
{
|
||||
formatBuilder.Append(", Value: [INVALID DATA TYPE]");
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
else if (valueAsByteArray.Length == 0)
|
||||
{
|
||||
formatBuilder.Append(", Value: [NO DATA]");
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
|
||||
// If we have a primitive type
|
||||
switch (Type)
|
||||
{
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-boolean"/>
|
||||
case ASN1Type.V_ASN1_BOOLEAN:
|
||||
if (Length > 1)
|
||||
formatBuilder.Append($" [Expected length of 1]");
|
||||
else if (valueAsByteArray.Length > 1)
|
||||
formatBuilder.Append($" [Expected value length of 1]");
|
||||
|
||||
bool booleanValue = valueAsByteArray[0] != 0x00;
|
||||
formatBuilder.Append($", Value: {booleanValue}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-integer"/>
|
||||
case ASN1Type.V_ASN1_INTEGER:
|
||||
Array.Reverse(valueAsByteArray);
|
||||
var integerValue = new BigInteger(valueAsByteArray);
|
||||
formatBuilder.Append($", Value: {integerValue}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-bit-string"/>
|
||||
case ASN1Type.V_ASN1_BIT_STRING:
|
||||
// TODO: Read into a BitArray and print that out instead?
|
||||
int unusedBits = valueAsByteArray[0];
|
||||
if (unusedBits == 0)
|
||||
formatBuilder.Append($", Value with {unusedBits} unused bits");
|
||||
else
|
||||
formatBuilder.Append($", Value with {unusedBits} unused bits: {BitConverter.ToString(valueAsByteArray, 1).Replace('-', ' ')}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-octet-string"/>
|
||||
case ASN1Type.V_ASN1_OCTET_STRING:
|
||||
formatBuilder.Append($", Value: {BitConverter.ToString(valueAsByteArray).Replace('-', ' ')}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-object-identifier"/>
|
||||
/// <see cref="http://snmpsharpnet.com/index.php/2009/03/02/ber-encoding-and-decoding-oid-values/"/>
|
||||
case ASN1Type.V_ASN1_OBJECT:
|
||||
// Derive array of values
|
||||
ulong[] objectNodes = ObjectIdentifier.ParseDERIntoArray(valueAsByteArray, Length);
|
||||
|
||||
// Append the dot and modified OID-IRI notations
|
||||
string? dotNotationString = ObjectIdentifier.ParseOIDToDotNotation(objectNodes);
|
||||
string? oidIriString = ObjectIdentifier.ParseOIDToOIDIRINotation(objectNodes);
|
||||
formatBuilder.Append($", Value: {dotNotationString} ({oidIriString})");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-utf8string"/>
|
||||
case ASN1Type.V_ASN1_UTF8STRING:
|
||||
formatBuilder.Append($", Value: {Encoding.UTF8.GetString(valueAsByteArray)}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-printablestring"/>
|
||||
case ASN1Type.V_ASN1_PRINTABLESTRING:
|
||||
formatBuilder.Append($", Value: {Encoding.ASCII.GetString(valueAsByteArray)}");
|
||||
break;
|
||||
|
||||
//case ASN1Type.V_ASN1_T61STRING:
|
||||
case ASN1Type.V_ASN1_TELETEXSTRING:
|
||||
formatBuilder.Append($", Value: {Encoding.ASCII.GetString(valueAsByteArray)}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-ia5string"/>
|
||||
case ASN1Type.V_ASN1_IA5STRING:
|
||||
formatBuilder.Append($", Value: {Encoding.ASCII.GetString(valueAsByteArray)}");
|
||||
break;
|
||||
|
||||
case ASN1Type.V_ASN1_UTCTIME:
|
||||
string utctimeString = Encoding.ASCII.GetString(valueAsByteArray);
|
||||
if (DateTime.TryParse(utctimeString, out DateTime utctimeDateTime))
|
||||
formatBuilder.Append($", Value: {utctimeDateTime:yyyy-MM-dd HH:mm:ss}");
|
||||
else
|
||||
formatBuilder.Append($", Value: {utctimeString}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-bmpstring"/>
|
||||
case ASN1Type.V_ASN1_BMPSTRING:
|
||||
formatBuilder.Append($", Value: {Encoding.Unicode.GetString(valueAsByteArray)}");
|
||||
break;
|
||||
|
||||
default:
|
||||
formatBuilder.Append($", Value: {BitConverter.ToString(valueAsByteArray).Replace('-', ' ')}");
|
||||
break;
|
||||
}
|
||||
|
||||
// Return the formatted string
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
158
SabreTools.Serialization/Extensions/TypeLengthValue.cs
Normal file
158
SabreTools.Serialization/Extensions/TypeLengthValue.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.Serialization.Extensions
|
||||
{
|
||||
public static class TypeLengthValue
|
||||
{
|
||||
/// <summary>
|
||||
/// Format a TypeLengthValue as a string
|
||||
/// </summary>
|
||||
/// <param name="paddingLevel">Padding level of the item when formatting</param>
|
||||
/// <returns>String representing the TypeLengthValue, if possible</returns>
|
||||
public static string Format(this ASN1.TypeLengthValue tlv, int paddingLevel = 0)
|
||||
{
|
||||
// Create the left-padding string
|
||||
string padding = new(' ', paddingLevel);
|
||||
|
||||
// Create the string builder
|
||||
var formatBuilder = new StringBuilder();
|
||||
|
||||
// Append the type
|
||||
formatBuilder.Append($"{padding}Type: {tlv.Type}");
|
||||
if (tlv.Type == ASN1.ASN1Type.V_ASN1_EOC)
|
||||
return formatBuilder.ToString();
|
||||
|
||||
// Append the length
|
||||
formatBuilder.Append($", Length: {tlv.Length}");
|
||||
if (tlv.Length == 0)
|
||||
return formatBuilder.ToString();
|
||||
|
||||
// If we have a constructed type
|
||||
#if NET20 || NET35
|
||||
if ((tlv.Type & ASN1.ASN1Type.V_ASN1_CONSTRUCTED) != 0)
|
||||
#else
|
||||
if (tlv.Type.HasFlag(ASN1.ASN1Type.V_ASN1_CONSTRUCTED))
|
||||
#endif
|
||||
{
|
||||
if (tlv.Value is not ASN1.TypeLengthValue[] valueAsObjectArray)
|
||||
{
|
||||
formatBuilder.Append(", Value: [INVALID DATA TYPE]");
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
|
||||
formatBuilder.Append(", Value:\n");
|
||||
for (int i = 0; i < valueAsObjectArray.Length; i++)
|
||||
{
|
||||
var child = valueAsObjectArray[i];
|
||||
string childString = child.Format(paddingLevel + 1);
|
||||
formatBuilder.Append($"{childString}\n");
|
||||
}
|
||||
|
||||
return formatBuilder.ToString().TrimEnd('\n');
|
||||
}
|
||||
|
||||
// Get the value as a byte array
|
||||
if (tlv.Value is not byte[] valueAsByteArray)
|
||||
{
|
||||
formatBuilder.Append(", Value: [INVALID DATA TYPE]");
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
else if (valueAsByteArray.Length == 0)
|
||||
{
|
||||
formatBuilder.Append(", Value: [NO DATA]");
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
|
||||
// If we have a primitive type
|
||||
switch (tlv.Type)
|
||||
{
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-boolean"/>
|
||||
case ASN1.ASN1Type.V_ASN1_BOOLEAN:
|
||||
if (tlv.Length > 1)
|
||||
formatBuilder.Append($" [Expected length of 1]");
|
||||
else if (valueAsByteArray.Length > 1)
|
||||
formatBuilder.Append($" [Expected value length of 1]");
|
||||
|
||||
bool booleanValue = valueAsByteArray[0] != 0x00;
|
||||
formatBuilder.Append($", Value: {booleanValue}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-integer"/>
|
||||
case ASN1.ASN1Type.V_ASN1_INTEGER:
|
||||
Array.Reverse(valueAsByteArray);
|
||||
var integerValue = new BigInteger(valueAsByteArray);
|
||||
formatBuilder.Append($", Value: {integerValue}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-bit-string"/>
|
||||
case ASN1.ASN1Type.V_ASN1_BIT_STRING:
|
||||
// TODO: Read into a BitArray and print that out instead?
|
||||
int unusedBits = valueAsByteArray[0];
|
||||
if (unusedBits == 0)
|
||||
formatBuilder.Append($", Value with {unusedBits} unused bits");
|
||||
else
|
||||
formatBuilder.Append($", Value with {unusedBits} unused bits: {BitConverter.ToString(valueAsByteArray, 1).Replace('-', ' ')}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-octet-string"/>
|
||||
case ASN1.ASN1Type.V_ASN1_OCTET_STRING:
|
||||
formatBuilder.Append($", Value: {BitConverter.ToString(valueAsByteArray).Replace('-', ' ')}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-object-identifier"/>
|
||||
/// <see cref="http://snmpsharpnet.com/index.php/2009/03/02/ber-encoding-and-decoding-oid-values/"/>
|
||||
case ASN1.ASN1Type.V_ASN1_OBJECT:
|
||||
// Derive array of values
|
||||
ulong[] objectNodes = ASN1.ObjectIdentifier.ParseDERIntoArray(valueAsByteArray, tlv.Length);
|
||||
|
||||
// Append the dot and modified OID-IRI notations
|
||||
string? dotNotationString = ASN1.ObjectIdentifier.ParseOIDToDotNotation(objectNodes);
|
||||
string? oidIriString = ASN1.ObjectIdentifier.ParseOIDToOIDIRINotation(objectNodes);
|
||||
formatBuilder.Append($", Value: {dotNotationString} ({oidIriString})");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-utf8string"/>
|
||||
case ASN1.ASN1Type.V_ASN1_UTF8STRING:
|
||||
formatBuilder.Append($", Value: {Encoding.UTF8.GetString(valueAsByteArray)}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-printablestring"/>
|
||||
case ASN1.ASN1Type.V_ASN1_PRINTABLESTRING:
|
||||
formatBuilder.Append($", Value: {Encoding.ASCII.GetString(valueAsByteArray)}");
|
||||
break;
|
||||
|
||||
//case ASN1Type.V_ASN1_T61STRING:
|
||||
case ASN1.ASN1Type.V_ASN1_TELETEXSTRING:
|
||||
formatBuilder.Append($", Value: {Encoding.ASCII.GetString(valueAsByteArray)}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-ia5string"/>
|
||||
case ASN1.ASN1Type.V_ASN1_IA5STRING:
|
||||
formatBuilder.Append($", Value: {Encoding.ASCII.GetString(valueAsByteArray)}");
|
||||
break;
|
||||
|
||||
case ASN1.ASN1Type.V_ASN1_UTCTIME:
|
||||
string utctimeString = Encoding.ASCII.GetString(valueAsByteArray);
|
||||
if (DateTime.TryParse(utctimeString, out DateTime utctimeDateTime))
|
||||
formatBuilder.Append($", Value: {utctimeDateTime:yyyy-MM-dd HH:mm:ss}");
|
||||
else
|
||||
formatBuilder.Append($", Value: {utctimeString}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-bmpstring"/>
|
||||
case ASN1.ASN1Type.V_ASN1_BMPSTRING:
|
||||
formatBuilder.Append($", Value: {Encoding.Unicode.GetString(valueAsByteArray)}");
|
||||
break;
|
||||
|
||||
default:
|
||||
formatBuilder.Append($", Value: {BitConverter.ToString(valueAsByteArray).Replace('-', ' ')}");
|
||||
break;
|
||||
}
|
||||
|
||||
// Return the formatted string
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,7 +478,7 @@ namespace SabreTools.Serialization.Printers
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (TypeLengthValue tlv in topLevelValues)
|
||||
foreach (ASN1.TypeLengthValue tlv in topLevelValues)
|
||||
{
|
||||
string tlvString = tlv.Format(paddingLevel: 4);
|
||||
builder.AppendLine(tlvString);
|
||||
|
||||
Reference in New Issue
Block a user