Simplify ASN.1 integration

This commit is contained in:
Matt Nadareski
2025-09-24 09:19:46 -04:00
parent 0db5de204e
commit e03852bd7e
5 changed files with 49 additions and 154 deletions

View File

@@ -1,62 +0,0 @@
using System;
using System.IO;
using SabreTools.Serialization.ASN1;
using Xunit;
namespace SabreTools.Serialization.Test.ASN1
{
public class AbstractSyntaxNotationOneTests
{
[Fact]
public void Parse_EmptyArray_Throws()
{
byte[] data = [];
Assert.Throws<InvalidDataException>(() => AbstractSyntaxNotationOne.Parse(data, 0));
}
[Fact]
public void Parse_ValidArrayNegativeIndex_Throws()
{
byte[] data = [0x00];
Assert.Throws<IndexOutOfRangeException>(() => AbstractSyntaxNotationOne.Parse(data, -1));
}
[Fact]
public void Parse_ValidArrayOverIndex_Throws()
{
byte[] data = [0x00];
Assert.Throws<IndexOutOfRangeException>(() => AbstractSyntaxNotationOne.Parse(data, 10));
}
[Fact]
public void Parse_ValidMinimalArray()
{
byte[] data = [0x00];
var tlvs = AbstractSyntaxNotationOne.Parse(data, 0);
var tlv = Assert.Single(tlvs);
Assert.Equal(ASN1Type.V_ASN1_EOC, tlv.Type);
Assert.Equal(default, tlv.Length);
Assert.Null(tlv.Value);
}
[Fact]
public void Parse_EmptyStream_Throws()
{
Stream data = new MemoryStream([], 0, 0, false, false);
Assert.Throws<InvalidDataException>(() => AbstractSyntaxNotationOne.Parse(data));
}
[Fact]
public void Parse_ValidMinimalStream()
{
Stream data = new MemoryStream([0x00]);
var tlvs = AbstractSyntaxNotationOne.Parse(data);
var tlv = Assert.Single(tlvs);
Assert.Equal(ASN1Type.V_ASN1_EOC, tlv.Type);
Assert.Equal(default, tlv.Length);
Assert.Null(tlv.Value);
}
}
}

View File

@@ -6,14 +6,14 @@ using Xunit;
namespace SabreTools.Serialization.Test.Deserializers
{
public class ASN1TypeLengthValueTests
public class AbstractSyntaxNotationOneTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var deserializer = new ASN1TypeLengthValue();
var deserializer = new AbstractSyntaxNotationOne();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
@@ -24,7 +24,7 @@ namespace SabreTools.Serialization.Test.Deserializers
{
byte[]? data = [];
int offset = 0;
var deserializer = new ASN1TypeLengthValue();
var deserializer = new AbstractSyntaxNotationOne();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
@@ -35,7 +35,7 @@ namespace SabreTools.Serialization.Test.Deserializers
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var deserializer = new ASN1TypeLengthValue();
var deserializer = new AbstractSyntaxNotationOne();
var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
@@ -45,7 +45,7 @@ namespace SabreTools.Serialization.Test.Deserializers
public void NullStream_Null()
{
Stream? data = null;
var deserializer = new ASN1TypeLengthValue();
var deserializer = new AbstractSyntaxNotationOne();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
@@ -55,7 +55,7 @@ namespace SabreTools.Serialization.Test.Deserializers
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var deserializer = new ASN1TypeLengthValue();
var deserializer = new AbstractSyntaxNotationOne();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
@@ -65,7 +65,7 @@ namespace SabreTools.Serialization.Test.Deserializers
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var deserializer = new ASN1TypeLengthValue();
var deserializer = new AbstractSyntaxNotationOne();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
@@ -75,28 +75,32 @@ namespace SabreTools.Serialization.Test.Deserializers
public void ValidMinimalStream_NotNull()
{
Stream data = new MemoryStream([0x00]);
var deserializer = new ASN1TypeLengthValue();
var deserializer = new AbstractSyntaxNotationOne();
var actual = deserializer.Deserialize(data);
Assert.NotNull(actual);
Assert.Equal(ASN1Type.V_ASN1_EOC, actual.Type);
Assert.Equal(default, actual.Length);
Assert.Null(actual.Value);
var actualSingle = Assert.Single(actual);
Assert.Equal(ASN1Type.V_ASN1_EOC, actualSingle.Type);
Assert.Equal(default, actualSingle.Length);
Assert.Null(actualSingle.Value);
}
[Fact]
public void ValidBoolean_NotNull()
{
Stream data = new MemoryStream([0x01, 0x01, 0x01]);
var deserializer = new ASN1TypeLengthValue();
var deserializer = new AbstractSyntaxNotationOne();
var actual = deserializer.Deserialize(data);
Assert.NotNull(actual);
Assert.Equal(ASN1Type.V_ASN1_BOOLEAN, actual.Type);
Assert.Equal(1UL, actual.Length);
Assert.NotNull(actual.Value);
byte[]? valueAsArray = actual.Value as byte[];
var actualSingle = Assert.Single(actual);
Assert.Equal(ASN1Type.V_ASN1_BOOLEAN, actualSingle.Type);
Assert.Equal(1UL, actualSingle.Length);
Assert.NotNull(actualSingle.Value);
byte[]? valueAsArray = actualSingle.Value as byte[];
Assert.NotNull(valueAsArray);
byte actualValue = Assert.Single(valueAsArray);
Assert.Equal(0x01, actualValue);
@@ -114,15 +118,17 @@ namespace SabreTools.Serialization.Test.Deserializers
public void ComplexValue_NotNull(byte[] arr)
{
Stream data = new MemoryStream(arr);
var deserializer = new ASN1TypeLengthValue();
var deserializer = new AbstractSyntaxNotationOne();
var actual = deserializer.Deserialize(data);
Assert.NotNull(actual);
Assert.Equal(ASN1Type.V_ASN1_CONSTRUCTED | ASN1Type.V_ASN1_OBJECT, actual.Type);
Assert.Equal(3UL, actual.Length);
Assert.NotNull(actual.Value);
TypeLengthValue[]? valueAsArray = actual.Value as TypeLengthValue[];
var actualSingle = Assert.Single(actual);
Assert.Equal(ASN1Type.V_ASN1_CONSTRUCTED | ASN1Type.V_ASN1_OBJECT, actualSingle.Type);
Assert.Equal(3UL, actualSingle.Length);
Assert.NotNull(actualSingle.Value);
TypeLengthValue[]? valueAsArray = actualSingle.Value as TypeLengthValue[];
Assert.NotNull(valueAsArray);
TypeLengthValue actualSub = Assert.Single(valueAsArray);
@@ -134,13 +140,14 @@ namespace SabreTools.Serialization.Test.Deserializers
[Theory]
[InlineData(new byte[] { 0x26, 0x80 })]
[InlineData(new byte[] { 0x26, 0x89 })]
public void ComplexValueInvalidLength_Null(byte[] arr)
public void ComplexValueInvalidLength_Empty(byte[] arr)
{
Stream data = new MemoryStream(arr);
var deserializer = new ASN1TypeLengthValue();
var deserializer = new AbstractSyntaxNotationOne();
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
Assert.NotNull(actual);
Assert.Empty(actual);
}
}
}

View File

@@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using SabreTools.Serialization.Deserializers;
namespace SabreTools.Serialization.ASN1
{
/// <summary>
/// ASN.1 Parser
/// </summary>
public static class AbstractSyntaxNotationOne
{
/// <summary>
/// Parse a byte array into a DER-encoded ASN.1 structure
/// </summary>
/// <param name="data">Byte array representing the data</param>
/// <param name="pointer">Current pointer into the data</param>
public static List<TypeLengthValue> Parse(byte[] data, int pointer)
{
// If the data is invalid
if (data.Length == 0)
throw new InvalidDataException(nameof(data));
if (pointer < 0 || pointer >= data.Length)
throw new IndexOutOfRangeException(nameof(pointer));
using var stream = new MemoryStream(data);
stream.Seek(pointer, SeekOrigin.Begin);
return Parse(stream);
}
/// <summary>
/// Parse a stream into a DER-encoded ASN.1 structure
/// </summary>
/// <param name="data">Stream representing the data</param>
public static List<TypeLengthValue> Parse(Stream data)
{
// If the data is invalid
if (data.Length == 0 || !data.CanRead)
throw new InvalidDataException(nameof(data));
if (data.Position < 0 || data.Position >= data.Length)
throw new IndexOutOfRangeException(nameof(data));
// Create the deserializer
var deserializer = new ASN1TypeLengthValue();
// Loop through the data and return all top-level values
var topLevelValues = new List<TypeLengthValue>();
while (data.Position < data.Length)
{
var topLevelValue = deserializer.Deserialize(data);
if (topLevelValue == null)
break;
topLevelValues.Add(topLevelValue);
}
return topLevelValues;
}
}
}

View File

@@ -4,10 +4,10 @@ using SabreTools.IO.Extensions;
namespace SabreTools.Serialization.Deserializers
{
public class ASN1TypeLengthValue : BaseBinaryDeserializer<ASN1.TypeLengthValue>
public class AbstractSyntaxNotationOne : BaseBinaryDeserializer<ASN1.TypeLengthValue[]>
{
/// <inheritdoc/>
public override ASN1.TypeLengthValue? Deserialize(Stream? data)
public override ASN1.TypeLengthValue[]? Deserialize(Stream? data)
{
// If the data is invalid
if (data == null || !data.CanRead)
@@ -18,12 +18,19 @@ namespace SabreTools.Serialization.Deserializers
// Cache the current offset
long initialOffset = data.Position;
var tlv = ParseTypeLengthValue(data);
if (tlv == null)
return null;
// Loop through the data and return all top-level values
var topLevelValues = new List<ASN1.TypeLengthValue>();
while (data.Position < data.Length)
{
var topLevelValue = ParseTypeLengthValue(data);
if (topLevelValue == null)
break;
// Return the Type/Length/Value
return tlv;
topLevelValues.Add(topLevelValue);
}
// Return the top-level values
return [.. topLevelValues];
}
catch
{

View File

@@ -451,6 +451,9 @@ namespace SabreTools.Serialization.Printers
return;
}
// Create the deserializer
var deserializer = new Deserializers.AbstractSyntaxNotationOne();
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
@@ -470,7 +473,7 @@ namespace SabreTools.Serialization.Printers
}
else
{
var topLevelValues = AbstractSyntaxNotationOne.Parse(entry.Certificate, 0);
var topLevelValues = deserializer.Deserialize(entry.Certificate, 0);
if (topLevelValues == null)
{
builder.AppendLine(" INVALID DATA FOUND");