Skip to content

Commit 92d5a09

Browse files
committed
Write TLV tests, update code accordingly
1 parent d722f1f commit 92d5a09

File tree

5 files changed

+237
-9
lines changed

5 files changed

+237
-9
lines changed

SabreTools.ASN1.Test/TypeLengthValueTests.cs

Lines changed: 211 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ namespace SabreTools.ASN1.Test
66
{
77
public class TypeLengthValueTests
88
{
9+
#region Construction
10+
911
[Fact]
1012
public void Constructor_EmptyArray_Throws()
1113
{
@@ -31,7 +33,7 @@ public void Constructor_ValidArrayOverIndex_Throws()
3133
}
3234

3335
[Fact]
34-
public void Constructor_ValidMinimalArray_Returns()
36+
public void Constructor_ValidMinimalArray()
3537
{
3638
int index = 0;
3739
byte[] data = [0x00];
@@ -50,7 +52,7 @@ public void Constructor_EmptyStream_Throws()
5052
}
5153

5254
[Fact]
53-
public void Constructor_ValidMinimalStream_Returns()
55+
public void Constructor_ValidMinimalStream()
5456
{
5557
Stream data = new MemoryStream([0x00]);
5658
var tlv = new TypeLengthValue(data);
@@ -61,7 +63,7 @@ public void Constructor_ValidMinimalStream_Returns()
6163
}
6264

6365
[Fact]
64-
public void Constructor_ValidBoolean_Returns()
66+
public void Constructor_ValidBoolean()
6567
{
6668
Stream data = new MemoryStream([0x01, 0x01, 0x01]);
6769
var tlv = new TypeLengthValue(data);
@@ -85,7 +87,7 @@ public void Constructor_ValidBoolean_Returns()
8587
[InlineData(new byte[] { 0x26, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
8688
[InlineData(new byte[] { 0x26, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
8789
[InlineData(new byte[] { 0x26, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
88-
public void Constructor_ComplexValue_Returns(byte[] arr)
90+
public void Constructor_ComplexValue(byte[] arr)
8991
{
9092
Stream data = new MemoryStream(arr);
9193
var tlv = new TypeLengthValue(data);
@@ -111,5 +113,210 @@ public void Constructor_ComplexValueInvalidLength_Throws(byte[] arr)
111113
Stream data = new MemoryStream(arr);
112114
Assert.Throws<InvalidOperationException>(() => new TypeLengthValue(data));
113115
}
116+
117+
#endregion
118+
119+
#region Formatting
120+
121+
[Fact]
122+
public void Format_EOC()
123+
{
124+
string expected = "Type: V_ASN1_EOC";
125+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_EOC, 0, null);
126+
string actual = tlv.Format();
127+
Assert.Equal(expected, actual);
128+
}
129+
130+
[Fact]
131+
public void Format_ZeroLength()
132+
{
133+
string expected = "Type: V_ASN1_NULL, Length: 0";
134+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_NULL, 0, null);
135+
string actual = tlv.Format();
136+
Assert.Equal(expected, actual);
137+
}
138+
139+
[Fact]
140+
public void Format_InvalidConstructed()
141+
{
142+
string expected = "Type: V_ASN1_OBJECT, V_ASN1_CONSTRUCTED, Length: 1, Value: [INVALID DATA TYPE]";
143+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT | ASN1Type.V_ASN1_CONSTRUCTED, 1, (object?)false);
144+
string actual = tlv.Format();
145+
Assert.Equal(expected, actual);
146+
}
147+
148+
[Fact]
149+
public void Format_ValidConstructed()
150+
{
151+
string expected = "Type: V_ASN1_OBJECT, V_ASN1_CONSTRUCTED, Length: 3, Value:\n Type: V_ASN1_BOOLEAN, Length: 1, Value: True";
152+
var boolTlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 1, new byte[] { 0x01 });
153+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT | ASN1Type.V_ASN1_CONSTRUCTED, 3, new TypeLengthValue[] { boolTlv });
154+
string actual = tlv.Format();
155+
Assert.Equal(expected, actual);
156+
}
157+
158+
[Fact]
159+
public void Format_InvalidDataType()
160+
{
161+
string expected = "Type: V_ASN1_OBJECT, Length: 1, Value: [INVALID DATA TYPE]";
162+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT, 1, (object?)false);
163+
string actual = tlv.Format();
164+
Assert.Equal(expected, actual);
165+
}
166+
167+
[Fact]
168+
public void Format_InvalidLength()
169+
{
170+
string expected = "Type: V_ASN1_NULL, Length: 1, Value: [NO DATA]";
171+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_NULL, 1, Array.Empty<byte>());
172+
string actual = tlv.Format();
173+
Assert.Equal(expected, actual);
174+
}
175+
176+
[Fact]
177+
public void Format_InvalidBooleanLength()
178+
{
179+
string expected = "Type: V_ASN1_BOOLEAN, Length: 2 [Expected length of 1], Value: True";
180+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 2, new byte[] { 0x01 });
181+
string actual = tlv.Format();
182+
Assert.Equal(expected, actual);
183+
}
184+
185+
[Fact]
186+
public void Format_InvalidBooleanArrayLength()
187+
{
188+
string expected = "Type: V_ASN1_BOOLEAN, Length: 1 [Expected value length of 1], Value: True";
189+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 1, new byte[] { 0x01, 0x00 });
190+
string actual = tlv.Format();
191+
Assert.Equal(expected, actual);
192+
}
193+
194+
[Fact]
195+
public void Format_ValidBoolean()
196+
{
197+
string expected = "Type: V_ASN1_BOOLEAN, Length: 1, Value: True";
198+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 1, new byte[] { 0x01 });
199+
string actual = tlv.Format();
200+
Assert.Equal(expected, actual);
201+
}
202+
203+
[Fact]
204+
public void Format_ValidInteger()
205+
{
206+
string expected = "Type: V_ASN1_INTEGER, Length: 1, Value: 1";
207+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_INTEGER, 1, new byte[] { 0x01 });
208+
string actual = tlv.Format();
209+
Assert.Equal(expected, actual);
210+
}
211+
212+
[Fact]
213+
public void Format_ValidBitString_NoBits()
214+
{
215+
string expected = "Type: V_ASN1_BIT_STRING, Length: 1, Value with 0 unused bits";
216+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BIT_STRING, 1, new byte[] { 0x00 });
217+
string actual = tlv.Format();
218+
Assert.Equal(expected, actual);
219+
}
220+
221+
[Fact]
222+
public void Format_ValidBitString_Bits()
223+
{
224+
string expected = "Type: V_ASN1_BIT_STRING, Length: 1, Value with 1 unused bits: 01";
225+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BIT_STRING, 1, new byte[] { 0x01, 0x01 });
226+
string actual = tlv.Format();
227+
Assert.Equal(expected, actual);
228+
}
229+
230+
[Fact]
231+
public void Format_ValidOctetString()
232+
{
233+
string expected = "Type: V_ASN1_OCTET_STRING, Length: 1, Value: 01";
234+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OCTET_STRING, 1, new byte[] { 0x01 });
235+
string actual = tlv.Format();
236+
Assert.Equal(expected, actual);
237+
}
238+
239+
[Fact]
240+
public void Format_ValidObject()
241+
{
242+
string expected = "Type: V_ASN1_OBJECT, Length: 3, Value: 0.1.2.3 (/ITU-T/1/2/3)";
243+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT, 3, new byte[] { 0x01, 0x02, 0x03 });
244+
string actual = tlv.Format();
245+
Assert.Equal(expected, actual);
246+
}
247+
248+
[Fact]
249+
public void Format_ValidUTF8String()
250+
{
251+
string expected = "Type: V_ASN1_UTF8STRING, Length: 3, Value: ABC";
252+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_UTF8STRING, 3, new byte[] { 0x41, 0x42, 0x43 });
253+
string actual = tlv.Format();
254+
Assert.Equal(expected, actual);
255+
}
256+
257+
[Fact]
258+
public void Format_ValidPrintableString()
259+
{
260+
string expected = "Type: V_ASN1_PRINTABLESTRING, Length: 3, Value: ABC";
261+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_PRINTABLESTRING, 3, new byte[] { 0x41, 0x42, 0x43 });
262+
string actual = tlv.Format();
263+
Assert.Equal(expected, actual);
264+
}
265+
266+
[Fact]
267+
public void Format_ValidTeletexString()
268+
{
269+
string expected = "Type: V_ASN1_TELETEXSTRING, Length: 3, Value: ABC";
270+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_TELETEXSTRING, 3, new byte[] { 0x41, 0x42, 0x43 });
271+
string actual = tlv.Format();
272+
Assert.Equal(expected, actual);
273+
}
274+
275+
[Fact]
276+
public void Format_ValidIA5String()
277+
{
278+
string expected = "Type: V_ASN1_IA5STRING, Length: 3, Value: ABC";
279+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_IA5STRING, 3, new byte[] { 0x41, 0x42, 0x43 });
280+
string actual = tlv.Format();
281+
Assert.Equal(expected, actual);
282+
}
283+
284+
[Fact]
285+
public void Format_InvalidUTCTime()
286+
{
287+
string expected = "Type: V_ASN1_UTCTIME, Length: 3, Value: ABC";
288+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_UTCTIME, 3, new byte[] { 0x41, 0x42, 0x43 });
289+
string actual = tlv.Format();
290+
Assert.Equal(expected, actual);
291+
}
292+
293+
[Fact]
294+
public void Format_ValidUTCTime()
295+
{
296+
string expected = "Type: V_ASN1_UTCTIME, Length: 3, Value: 1980-01-01 00:00:00";
297+
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 });
298+
string actual = tlv.Format();
299+
Assert.Equal(expected, actual);
300+
}
301+
302+
[Fact]
303+
public void Format_ValidBmpString()
304+
{
305+
string expected = "Type: V_ASN1_BMPSTRING, Length: 6, Value: ABC";
306+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BMPSTRING, 6, new byte[] { 0x41, 0x00, 0x42, 0x00, 0x43, 0x00 });
307+
string actual = tlv.Format();
308+
Assert.Equal(expected, actual);
309+
}
310+
311+
[Fact]
312+
public void Format_ValidUnformatted()
313+
{
314+
string expected = "Type: V_ASN1_OBJECT_DESCRIPTOR, Length: 1, Value: 01";
315+
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT_DESCRIPTOR, 1, new byte[] { 0x01 });
316+
string actual = tlv.Format();
317+
Assert.Equal(expected, actual);
318+
}
319+
320+
#endregion
114321
}
115322
}

SabreTools.ASN1/ObjectIdentifier.OIDIRI.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public static partial class ObjectIdentifier
7373

7474
#region Start
7575

76-
var oidPath = $"/{values[index]}";
76+
var oidPath = string.Empty;
7777
switch (values[index++])
7878
{
7979
case 0: goto oid_0;

SabreTools.ASN1/ObjectIdentifier.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static ulong[] ParseDERIntoArray(byte[] data, ulong length)
2424
int firstNode = Math.DivRem(data[0], 40, out int secondNode);
2525

2626
// Create a list for all nodes
27-
List<ulong> nodes = new List<ulong> { (ulong)firstNode, (ulong)secondNode };
27+
List<ulong> nodes = [(ulong)firstNode, (ulong)secondNode];
2828

2929
// All other nodes are encoded uniquely
3030
int offset = 1;

SabreTools.ASN1/SabreTools.ASN1.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2121
</PropertyGroup>
2222

23+
<ItemGroup>
24+
<InternalsVisibleTo Include="SabreTools.ASN1.Test" />
25+
</ItemGroup>
26+
2327
<ItemGroup>
2428
<None Include="../README.md" Pack="true" PackagePath="" />
2529
</ItemGroup>

SabreTools.ASN1/TypeLengthValue.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ public class TypeLengthValue
2727
/// </summary>
2828
public object? Value { get; private set; }
2929

30+
/// <summary>
31+
/// Manual constructor
32+
/// </summary>
33+
public TypeLengthValue(ASN1Type type, ulong length, object? value)
34+
{
35+
Type = type;
36+
Length = length;
37+
Value = value;
38+
}
39+
3040
/// <summary>
3141
/// Read from the source data array at an index
3242
/// </summary>
@@ -109,14 +119,21 @@ public string Format(int paddingLevel = 0)
109119
formatBuilder.Append(", Value: [INVALID DATA TYPE]");
110120
return formatBuilder.ToString();
111121
}
122+
else if (valueAsByteArray.Length == 0)
123+
{
124+
formatBuilder.Append(", Value: [NO DATA]");
125+
return formatBuilder.ToString();
126+
}
112127

113128
// If we have a primitive type
114129
switch (Type)
115130
{
116131
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-boolean"/>
117132
case ASN1Type.V_ASN1_BOOLEAN:
118-
if (Length > 1 || valueAsByteArray.Length > 1)
133+
if (Length > 1)
119134
formatBuilder.Append($" [Expected length of 1]");
135+
else if (valueAsByteArray.Length > 1)
136+
formatBuilder.Append($" [Expected value length of 1]");
120137

121138
bool booleanValue = valueAsByteArray[0] != 0x00;
122139
formatBuilder.Append($", Value: {booleanValue}");
@@ -179,7 +196,7 @@ public string Format(int paddingLevel = 0)
179196
case ASN1Type.V_ASN1_UTCTIME:
180197
string utctimeString = Encoding.ASCII.GetString(valueAsByteArray);
181198
if (DateTime.TryParse(utctimeString, out DateTime utctimeDateTime))
182-
formatBuilder.Append($", Value: {utctimeDateTime}");
199+
formatBuilder.Append($", Value: {utctimeDateTime:yyyy-MM-dd HH:mm:ss}");
183200
else
184201
formatBuilder.Append($", Value: {utctimeString}");
185202
break;
@@ -190,7 +207,7 @@ public string Format(int paddingLevel = 0)
190207
break;
191208

192209
default:
193-
formatBuilder.Append($", Value (Unknown Format): {BitConverter.ToString(valueAsByteArray).Replace('-', ' ')}");
210+
formatBuilder.Append($", Value: {BitConverter.ToString(valueAsByteArray).Replace('-', ' ')}");
194211
break;
195212
}
196213

0 commit comments

Comments
 (0)