forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathReadLength.cs
More file actions
259 lines (222 loc) · 9.67 KB
/
ReadLength.cs
File metadata and controls
259 lines (222 loc) · 9.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Test.Cryptography;
using Xunit;
namespace System.Formats.Asn1.Tests.Reader
{
public sealed class ReadLength
{
private static Asn1Tag ReadTagAndLength(
ReadOnlySpan<byte> source,
AsnEncodingRules ruleSet,
out int? parsedLength,
out int bytesRead)
{
Asn1Tag tag = Asn1Tag.Decode(source, out int tagLength);
parsedLength = AsnDecoder.DecodeLength(source.Slice(tagLength), ruleSet, out int lengthLength);
bytesRead = tagLength + lengthLength;
return tag;
}
private static bool TryReadTagAndLength(
ReadOnlySpan<byte> source,
AsnEncodingRules ruleSet,
out Asn1Tag tag,
out int? parsedLength,
out int bytesRead)
{
Asn1Tag localTag = Asn1Tag.Decode(source, out int tagLength);
bool read = AsnDecoder.TryDecodeLength(
source.Slice(tagLength),
ruleSet,
out parsedLength,
out int lengthLength);
if (read)
{
tag = localTag;
bytesRead = tagLength + lengthLength;
}
else
{
tag = default;
bytesRead = default;
}
return read;
}
[Theory]
[InlineData(4, 0, "0400")]
[InlineData(1, 1, "0101")]
[InlineData(4, 127, "047F")]
[InlineData(4, 128, "048180")]
[InlineData(4, 255, "0481FF")]
[InlineData(2, 256, "02820100")]
[InlineData(4, int.MaxValue, "04847FFFFFFF")]
public static void MinimalPrimitiveLength(int tagValue, int length, string inputHex)
{
byte[] inputBytes = inputHex.HexToByteArray();
foreach (AsnEncodingRules rules in Enum.GetValues(typeof(AsnEncodingRules)))
{
Asn1Tag tag = ReadTagAndLength(inputBytes, rules, out int? parsedLength, out int bytesRead);
Assert.Equal(inputBytes.Length, bytesRead);
Assert.False(tag.IsConstructed, "tag.IsConstructed");
Assert.Equal(tagValue, tag.TagValue);
Assert.Equal(length, parsedLength.Value);
Assert.True(TryReadTagAndLength(inputBytes, rules, out tag, out parsedLength, out bytesRead));
Assert.Equal(inputBytes.Length, bytesRead);
Assert.False(tag.IsConstructed, "tag.IsConstructed");
Assert.Equal(tagValue, tag.TagValue);
Assert.Equal(length, parsedLength.Value);
}
}
[Theory]
[InlineData(-1)]
[InlineData(3)]
public static void ReadWithUnknownRuleSet(int invalidRuleSetValue)
{
byte[] data = { 0x05, 0x00 };
Assert.Throws<ArgumentOutOfRangeException>(
() => new AsnReader(data, (AsnEncodingRules)invalidRuleSetValue));
Assert.Throws<ArgumentOutOfRangeException>(
() => ReadTagAndLength(data, (AsnEncodingRules)invalidRuleSetValue, out _, out _));
Assert.Throws<ArgumentOutOfRangeException>(
() => TryReadTagAndLength(data, (AsnEncodingRules)invalidRuleSetValue, out _, out _, out _));
}
private static void ReadValid(
ReadOnlySpan<byte> source,
AsnEncodingRules ruleSet,
int? expectedLength,
int expectedBytesRead = -1)
{
if (expectedBytesRead < 0)
{
expectedBytesRead = source.Length;
}
ReadTagAndLength(
source,
ruleSet,
out int? length,
out int bytesRead);
Assert.Equal(expectedBytesRead, bytesRead);
Assert.Equal(expectedLength, length);
bool read = TryReadTagAndLength(
source,
ruleSet,
out _,
out length,
out bytesRead);
Assert.True(read);
Assert.Equal(expectedBytesRead, bytesRead);
Assert.Equal(expectedLength, length);
}
private static void ReadInvalid(byte[] source, AsnEncodingRules ruleSet)
{
Assert.Throws<AsnContentException>(
() => ReadTagAndLength(source, ruleSet, out _, out _));
Asn1Tag tag;
int? decodedLength;
int bytesConsumed;
Assert.False(
TryReadTagAndLength(source, ruleSet, out tag, out decodedLength, out bytesConsumed));
Assert.True(tag == default);
Assert.Null(decodedLength);
Assert.Equal(0, bytesConsumed);
}
[Theory]
[InlineData("05")]
[InlineData("0481")]
[InlineData("048201")]
[InlineData("04830102")]
[InlineData("0484010203")]
public static void ReadWithInsufficientData(string inputHex)
{
byte[] inputData = inputHex.HexToByteArray();
ReadInvalid(inputData, AsnEncodingRules.BER);
ReadInvalid(inputData, AsnEncodingRules.CER);
ReadInvalid(inputData, AsnEncodingRules.DER);
}
[Theory]
[InlineData("DER indefinite constructed", AsnEncodingRules.DER, "3080" + "0500" + "0000")]
[InlineData("0xFF-BER", AsnEncodingRules.BER, "04FF")]
[InlineData("0xFF-CER", AsnEncodingRules.CER, "04FF")]
[InlineData("0xFF-DER", AsnEncodingRules.DER, "04FF")]
[InlineData("DER indefinite primitive", AsnEncodingRules.DER, "0480" + "0000")]
[InlineData("DER non-minimal 0", AsnEncodingRules.DER, "048100")]
[InlineData("DER non-minimal 7F", AsnEncodingRules.DER, "04817F")]
[InlineData("DER non-minimal 80", AsnEncodingRules.DER, "04820080")]
[InlineData("CER non-minimal 0", AsnEncodingRules.CER, "048100")]
[InlineData("CER non-minimal 7F", AsnEncodingRules.CER, "04817F")]
[InlineData("CER non-minimal 80", AsnEncodingRules.CER, "04820080")]
[InlineData("BER too large", AsnEncodingRules.BER, "048480000000")]
[InlineData("CER too large", AsnEncodingRules.CER, "048480000000")]
[InlineData("DER too large", AsnEncodingRules.DER, "048480000000")]
[InlineData("BER padded too large", AsnEncodingRules.BER, "0486000080000000")]
[InlineData("BER uint.MaxValue", AsnEncodingRules.BER, "0484FFFFFFFF")]
[InlineData("CER uint.MaxValue", AsnEncodingRules.CER, "0484FFFFFFFF")]
[InlineData("DER uint.MaxValue", AsnEncodingRules.DER, "0484FFFFFFFF")]
[InlineData("BER padded uint.MaxValue", AsnEncodingRules.BER, "048800000000FFFFFFFF")]
[InlineData("BER 5 byte spread", AsnEncodingRules.BER, "04850100000000")]
[InlineData("CER 5 byte spread", AsnEncodingRules.CER, "04850100000000")]
[InlineData("DER 5 byte spread", AsnEncodingRules.DER, "04850100000000")]
[InlineData("BER padded 5 byte spread", AsnEncodingRules.BER, "0486000100000000")]
public static void InvalidLengths(
string description,
AsnEncodingRules rules,
string inputHex)
{
_ = description;
byte[] inputData = inputHex.HexToByteArray();
ReadInvalid(inputData, rules);
}
[Theory]
[InlineData("CER definite constructed", AsnEncodingRules.CER, 0x0500, 4, "30820500")]
[InlineData("BER indefinite primitive", AsnEncodingRules.BER, null, 2, "0480" + "0000")]
[InlineData("CER indefinite primitive", AsnEncodingRules.CER, null, 2, "0480" + "0000")]
public static void ContextuallyInvalidLengths(
string description,
AsnEncodingRules rules,
int? expectedLength,
int expectedBytesRead,
string inputHex)
{
// These inputs will all throw from AsnDecoder.ReadTagAndLength, but require
// the tag as context.
_ = description;
byte[] inputData = inputHex.HexToByteArray();
ReadValid(inputData, rules, expectedLength, expectedBytesRead);
}
[Theory]
[InlineData(AsnEncodingRules.BER)]
[InlineData(AsnEncodingRules.CER)]
public static void IndefiniteLength(AsnEncodingRules ruleSet)
{
// SEQUENCE (indefinite)
// NULL
// End-of-Contents
byte[] data = { 0x30, 0x80, 0x05, 0x00, 0x00, 0x00 };
ReadValid(data, ruleSet, null, 2);
}
[Theory]
[InlineData(0, "0483000000")]
[InlineData(1, "048A00000000000000000001")]
[InlineData(128, "049000000000000000000000000000000080")]
public static void BerNonMinimalLength(int expectedLength, string inputHex)
{
byte[] inputData = inputHex.HexToByteArray();
ReadValid(inputData, AsnEncodingRules.BER, expectedLength);
ReadInvalid(inputData, AsnEncodingRules.CER);
ReadInvalid(inputData, AsnEncodingRules.DER);
}
[Theory]
[InlineData(AsnEncodingRules.BER, 0, 5, "0483000000" + "0500")]
[InlineData(AsnEncodingRules.DER, 1, 2, "0101" + "FF")]
[InlineData(AsnEncodingRules.CER, null, 2, "3080" + "0500" + "0000")]
public static void ReadWithDataRemaining(
AsnEncodingRules ruleSet,
int? expectedLength,
int expectedBytesRead,
string inputHex)
{
byte[] inputData = inputHex.HexToByteArray();
ReadValid(inputData, ruleSet, expectedLength, expectedBytesRead);
}
}
}