Write TLV tests, update code accordingly

This commit is contained in:
Matt Nadareski
2024-11-26 12:47:15 -05:00
parent d722f1fad2
commit 92d5a097a8
5 changed files with 237 additions and 9 deletions

View File

@@ -6,6 +6,8 @@ namespace SabreTools.ASN1.Test
{
public class TypeLengthValueTests
{
#region Construction
[Fact]
public void Constructor_EmptyArray_Throws()
{
@@ -31,7 +33,7 @@ namespace SabreTools.ASN1.Test
}
[Fact]
public void Constructor_ValidMinimalArray_Returns()
public void Constructor_ValidMinimalArray()
{
int index = 0;
byte[] data = [0x00];
@@ -50,7 +52,7 @@ namespace SabreTools.ASN1.Test
}
[Fact]
public void Constructor_ValidMinimalStream_Returns()
public void Constructor_ValidMinimalStream()
{
Stream data = new MemoryStream([0x00]);
var tlv = new TypeLengthValue(data);
@@ -61,7 +63,7 @@ namespace SabreTools.ASN1.Test
}
[Fact]
public void Constructor_ValidBoolean_Returns()
public void Constructor_ValidBoolean()
{
Stream data = new MemoryStream([0x01, 0x01, 0x01]);
var tlv = new TypeLengthValue(data);
@@ -85,7 +87,7 @@ namespace SabreTools.ASN1.Test
[InlineData(new byte[] { 0x26, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
[InlineData(new byte[] { 0x26, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
[InlineData(new byte[] { 0x26, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
public void Constructor_ComplexValue_Returns(byte[] arr)
public void Constructor_ComplexValue(byte[] arr)
{
Stream data = new MemoryStream(arr);
var tlv = new TypeLengthValue(data);
@@ -111,5 +113,210 @@ namespace SabreTools.ASN1.Test
Stream data = new MemoryStream(arr);
Assert.Throws<InvalidOperationException>(() => new TypeLengthValue(data));
}
#endregion
#region Formatting
[Fact]
public void Format_EOC()
{
string expected = "Type: V_ASN1_EOC";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_EOC, 0, null);
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ZeroLength()
{
string expected = "Type: V_ASN1_NULL, Length: 0";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_NULL, 0, null);
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_InvalidConstructed()
{
string expected = "Type: V_ASN1_OBJECT, V_ASN1_CONSTRUCTED, Length: 1, Value: [INVALID DATA TYPE]";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT | ASN1Type.V_ASN1_CONSTRUCTED, 1, (object?)false);
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
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(ASN1Type.V_ASN1_BOOLEAN, 1, new byte[] { 0x01 });
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT | ASN1Type.V_ASN1_CONSTRUCTED, 3, new TypeLengthValue[] { boolTlv });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_InvalidDataType()
{
string expected = "Type: V_ASN1_OBJECT, Length: 1, Value: [INVALID DATA TYPE]";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT, 1, (object?)false);
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_InvalidLength()
{
string expected = "Type: V_ASN1_NULL, Length: 1, Value: [NO DATA]";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_NULL, 1, Array.Empty<byte>());
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_InvalidBooleanLength()
{
string expected = "Type: V_ASN1_BOOLEAN, Length: 2 [Expected length of 1], Value: True";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 2, new byte[] { 0x01 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_InvalidBooleanArrayLength()
{
string expected = "Type: V_ASN1_BOOLEAN, Length: 1 [Expected value length of 1], Value: True";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 1, new byte[] { 0x01, 0x00 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidBoolean()
{
string expected = "Type: V_ASN1_BOOLEAN, Length: 1, Value: True";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 1, new byte[] { 0x01 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidInteger()
{
string expected = "Type: V_ASN1_INTEGER, Length: 1, Value: 1";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_INTEGER, 1, new byte[] { 0x01 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidBitString_NoBits()
{
string expected = "Type: V_ASN1_BIT_STRING, Length: 1, Value with 0 unused bits";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BIT_STRING, 1, new byte[] { 0x00 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidBitString_Bits()
{
string expected = "Type: V_ASN1_BIT_STRING, Length: 1, Value with 1 unused bits: 01";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BIT_STRING, 1, new byte[] { 0x01, 0x01 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidOctetString()
{
string expected = "Type: V_ASN1_OCTET_STRING, Length: 1, Value: 01";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OCTET_STRING, 1, new byte[] { 0x01 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
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(ASN1Type.V_ASN1_OBJECT, 3, new byte[] { 0x01, 0x02, 0x03 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidUTF8String()
{
string expected = "Type: V_ASN1_UTF8STRING, Length: 3, Value: ABC";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_UTF8STRING, 3, new byte[] { 0x41, 0x42, 0x43 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidPrintableString()
{
string expected = "Type: V_ASN1_PRINTABLESTRING, Length: 3, Value: ABC";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_PRINTABLESTRING, 3, new byte[] { 0x41, 0x42, 0x43 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidTeletexString()
{
string expected = "Type: V_ASN1_TELETEXSTRING, Length: 3, Value: ABC";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_TELETEXSTRING, 3, new byte[] { 0x41, 0x42, 0x43 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidIA5String()
{
string expected = "Type: V_ASN1_IA5STRING, Length: 3, Value: ABC";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_IA5STRING, 3, new byte[] { 0x41, 0x42, 0x43 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_InvalidUTCTime()
{
string expected = "Type: V_ASN1_UTCTIME, Length: 3, Value: ABC";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_UTCTIME, 3, new byte[] { 0x41, 0x42, 0x43 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidUTCTime()
{
string expected = "Type: V_ASN1_UTCTIME, Length: 3, Value: 1980-01-01 00:00:00";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_UTCTIME, 3, 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);
}
[Fact]
public void Format_ValidBmpString()
{
string expected = "Type: V_ASN1_BMPSTRING, Length: 6, Value: ABC";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BMPSTRING, 6, new byte[] { 0x41, 0x00, 0x42, 0x00, 0x43, 0x00 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
[Fact]
public void Format_ValidUnformatted()
{
string expected = "Type: V_ASN1_OBJECT_DESCRIPTOR, Length: 1, Value: 01";
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT_DESCRIPTOR, 1, new byte[] { 0x01 });
string actual = tlv.Format();
Assert.Equal(expected, actual);
}
#endregion
}
}

View File

@@ -73,7 +73,7 @@ namespace SabreTools.ASN1
#region Start
var oidPath = $"/{values[index]}";
var oidPath = string.Empty;
switch (values[index++])
{
case 0: goto oid_0;

View File

@@ -24,7 +24,7 @@ namespace SabreTools.ASN1
int firstNode = Math.DivRem(data[0], 40, out int secondNode);
// Create a list for all nodes
List<ulong> nodes = new List<ulong> { (ulong)firstNode, (ulong)secondNode };
List<ulong> nodes = [(ulong)firstNode, (ulong)secondNode];
// All other nodes are encoded uniquely
int offset = 1;

View File

@@ -20,6 +20,10 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="SabreTools.ASN1.Test" />
</ItemGroup>
<ItemGroup>
<None Include="../README.md" Pack="true" PackagePath="" />
</ItemGroup>

View File

@@ -27,6 +27,16 @@ namespace SabreTools.ASN1
/// </summary>
public object? Value { get; private set; }
/// <summary>
/// Manual constructor
/// </summary>
public TypeLengthValue(ASN1Type type, ulong length, object? value)
{
Type = type;
Length = length;
Value = value;
}
/// <summary>
/// Read from the source data array at an index
/// </summary>
@@ -109,14 +119,21 @@ namespace SabreTools.ASN1
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 || valueAsByteArray.Length > 1)
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}");
@@ -179,7 +196,7 @@ namespace SabreTools.ASN1
case ASN1Type.V_ASN1_UTCTIME:
string utctimeString = Encoding.ASCII.GetString(valueAsByteArray);
if (DateTime.TryParse(utctimeString, out DateTime utctimeDateTime))
formatBuilder.Append($", Value: {utctimeDateTime}");
formatBuilder.Append($", Value: {utctimeDateTime:yyyy-MM-dd HH:mm:ss}");
else
formatBuilder.Append($", Value: {utctimeString}");
break;
@@ -190,7 +207,7 @@ namespace SabreTools.ASN1
break;
default:
formatBuilder.Append($", Value (Unknown Format): {BitConverter.ToString(valueAsByteArray).Replace('-', ' ')}");
formatBuilder.Append($", Value: {BitConverter.ToString(valueAsByteArray).Replace('-', ' ')}");
break;
}