Skip to content

Commit bbcf82f

Browse files
committed
obsoleting Asn1Reader.RawData, it is private only.
-- Adding Length property to Asn1Reader to measure raw data length -- Adding index access (read-only) to internal raw stream -- Adding GetRawData() to get a copy of internal stream
1 parent 87d73d5 commit bbcf82f

7 files changed

Lines changed: 74 additions & 43 deletions

File tree

Asn1Parser/Asn1Parser.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<Company>Sysadmins LV</Company>
77
<Description>ASN.1 binary parser and utility set for binary data encoded with Distinguished Encoding Rules (DER).</Description>
88
<Copyright>Copyright © Sysadmins LV 2012 - 2018</Copyright>
9-
<AssemblyVersion>1.2.7.52</AssemblyVersion>
10-
<FileVersion>1.2.7.52</FileVersion>
9+
<AssemblyVersion>1.2.7.53</AssemblyVersion>
10+
<FileVersion>1.2.7.53</FileVersion>
1111
<AssemblyName>SysadminsLV.Asn1Parser</AssemblyName>
1212
<RootNamespace>SysadminsLV.Asn1Parser</RootNamespace>
1313
<PackageLicenseUrl>https://github.com/Crypt32/Asn1DerParser.NET/blob/master/LICENSE.md</PackageLicenseUrl>

Asn1Parser/Asn1Reader.cs

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class Asn1Reader {
2424
static readonly List<Byte> _excludedTags = new List<Byte>(
2525
new Byte[] { 0, 1, 2, 5, 6, 9, 10, 13 }
2626
);
27+
readonly List<Byte> _rawData = new List<Byte>();
2728
readonly Dictionary<Int64, AsnInternalMap> _offsetMap = new Dictionary<Int64, AsnInternalMap>();
2829
readonly List<Byte> _multiNestedTypes = new List<Byte>(
2930
new[] {
@@ -94,6 +95,10 @@ public Asn1Reader(Byte[] rawData) : this(rawData, 0) { }
9495
/// </summary>
9596
public Int32 PayloadLength { get; private set; }
9697
/// <summary>
98+
/// Gets the internal ASN.1 stream length in bytes.
99+
/// </summary>
100+
public Int32 Length => _rawData.Count;
101+
/// <summary>
97102
/// This property is subject to change.
98103
/// </summary>
99104
[Obsolete("Use 'NextSiblingOffset' property instead", false)]
@@ -113,17 +118,27 @@ public Asn1Reader(Byte[] rawData) : this(rawData, 0) { }
113118
/// <summary>
114119
/// Get's original ASN.1-encoded byte array.
115120
/// </summary>
116-
public Byte[] RawData { get; private set; }
121+
[Obsolete("", true)]
122+
public Byte[] RawData => _rawData.ToArray();
123+
/// <summary>
124+
///
125+
/// </summary>
126+
/// <param name="index"></param>
127+
public Byte this[Int32 index] => _rawData[index];
117128

118129
void decode(Byte[] raw, Int32 pOffset) {
119130
IsConstructed = false;
120-
if (raw != null) { RawData = raw; }
131+
if (raw != null) {
132+
_rawData.Clear();
133+
_rawData.AddRange(raw);
134+
}
121135
Offset = pOffset;
122-
Tag = RawData[Offset];
136+
Tag = _rawData[Offset];
123137
calculateLength();
124138
// strip possible unnecessary bytes
125-
if (raw != null && TagLength != RawData.Length) {
126-
RawData = raw.Take(TagLength).ToArray();
139+
if (raw != null && TagLength != _rawData.Count) {
140+
_rawData.Clear();
141+
_rawData.AddRange(raw.Take(TagLength).ToArray());
127142
}
128143
TagName = GetTagName(Tag);
129144
// 0 Tag is reserved for BER and is not available in DER
@@ -138,7 +153,7 @@ void decode(Byte[] raw, Int32 pOffset) {
138153
}
139154
if (PayloadLength == 0) {
140155
// if current node is the last node in binary data, set NextOffset to 0, this means EOF.
141-
NextOffset = Offset + TagLength == RawData.Length
156+
NextOffset = Offset + TagLength == _rawData.Count
142157
? 0
143158
: Offset + TagLength;
144159
NextSiblingOffset = currentPosition.LevelEnd == 0 || Offset - currentPosition.LevelStart + TagLength == currentPosition.LevelEnd
@@ -155,7 +170,7 @@ void decode(Byte[] raw, Int32 pOffset) {
155170
// skip unused bits byte
156171
? PayloadStartOffset + 1
157172
: PayloadStartOffset
158-
: Offset + TagLength < RawData.Length
173+
: Offset + TagLength < _rawData.Count
159174
? Offset + TagLength
160175
: 0;
161176
}
@@ -194,7 +209,10 @@ void parseNestedType() {
194209
}
195210
}
196211
Boolean validateArrayBoundaries(Int64 start) {
197-
return start >= 0 && start < RawData.Length && RawData[start] != 0;
212+
if (start > Int32.MaxValue) {
213+
return false;
214+
}
215+
return start >= 0 && start < _rawData.Count && _rawData[(Int32)start] != 0;
198216
}
199217
/// <summary>
200218
/// Checks if current primitive type is sub-typed (contains nested types) or not.
@@ -207,8 +225,11 @@ Boolean validateArrayBoundaries(Int64 start) {
207225
/// <strong>True</strong> if current type has proper single nested type, otherwise <strong>False</strong>.
208226
/// </returns>
209227
Boolean testNestedForUniversal(Int64 start, Int32 estimatedLength) {
228+
if (start > Int32.MaxValue) {
229+
return false;
230+
}
210231
// if current type is primitive, then nested type can be either, primitive or constructed only.
211-
if (RawData[start] >= (Byte)Asn1Class.APPLICATION) {
232+
if (_rawData[(Int32)start] >= (Byte)Asn1Class.APPLICATION) {
212233
return false;
213234
}
214235
// otherwise, attempt to resolve nested type. Only single nested type is allowed for primitive types.
@@ -243,20 +264,20 @@ Boolean predict(Int64 start, Int32 projectedLength, Boolean assignMap, out Int32
243264
return sum == projectedLength;
244265
}
245266
void calculateLength() {
246-
if (RawData[Offset + 1] < 128) {
267+
if (_rawData[Offset + 1] < 128) {
247268
PayloadStartOffset = Offset + 2;
248-
PayloadLength = RawData[Offset + 1];
269+
PayloadLength = _rawData[Offset + 1];
249270
TagLength = PayloadLength + 2;
250271
} else {
251-
Int32 lengthBytes = RawData[Offset + 1] - 128;
272+
Int32 lengthBytes = _rawData[Offset + 1] - 128;
252273
// max length can be encoded by using 4 bytes.
253274
if (lengthBytes > 4) {
254275
throw new OverflowException("Data length is too large.");
255276
}
256277
PayloadStartOffset = Offset + 2 + lengthBytes;
257-
PayloadLength = RawData[Offset + 2];
278+
PayloadLength = _rawData[Offset + 2];
258279
for (Int32 i = Offset + 3; i < PayloadStartOffset; i++) {
259-
PayloadLength = (PayloadLength << 8) | RawData[i];
280+
PayloadLength = (PayloadLength << 8) | _rawData[i];
260281
}
261282
TagLength = PayloadLength + lengthBytes + 2;
262283
}
@@ -267,18 +288,21 @@ void calculateLength() {
267288
/// <param name="offset">Start offset for suggested nested type.</param>
268289
/// <returns>Estimated full tag length for nested type.</returns>
269290
Int64 calculatePredictLength(Int64 offset) {
270-
if (offset + 1 >= RawData.Length || offset < 0) { return Int32.MaxValue; }
271-
if (RawData[offset + 1] < 128) {
272-
return RawData[offset + 1] + 2;
291+
if (offset + 1 >= _rawData.Count || offset < 0) {
292+
return Int32.MaxValue;
293+
}
294+
295+
if (_rawData[(Int32)(offset + 1)] < 128) {
296+
return _rawData[(Int32) (offset + 1)] + 2;
273297
}
274-
Int32 lengthBytes = RawData[offset + 1] - 128;
298+
Int32 lengthBytes = _rawData[(Int32)(offset + 1)] - 128;
275299
// max length can be encoded by using 4 bytes.
276-
if (lengthBytes > 4) {
300+
if (lengthBytes > 4 || offset + 2 >= _rawData.Count) {
277301
return Int32.MaxValue;
278302
}
279-
Int32 ppayloadLength = RawData[offset + 2];
280-
for (Int64 i = offset + 3; i < offset + 2 + lengthBytes; i++) {
281-
ppayloadLength = (ppayloadLength << 8) | RawData[i];
303+
Int32 ppayloadLength = _rawData[(Int32)(offset + 2)];
304+
for (Int32 i = (Int32)(offset + 3); i < offset + 2 + lengthBytes; i++) {
305+
ppayloadLength = (ppayloadLength << 8) | _rawData[i];
282306
}
283307
// 2 -- transitional + tag
284308
return ppayloadLength + lengthBytes + 2;
@@ -301,21 +325,28 @@ void moveAndExpectTypes(Func<Boolean> action, params Byte[] expectedTypes) {
301325
/// </summary>
302326
/// <returns>Current structure header. Header contains tag and tag length byte (or bytes).</returns>
303327
public Byte[] GetHeader() {
304-
return RawData.Skip(Offset).Take(PayloadStartOffset - Offset).ToArray();
328+
return _rawData.Skip(Offset).Take(PayloadStartOffset - Offset).ToArray();
305329
}
306330
/// <summary>
307331
/// Gets the byte array of the current structure's payload.
308332
/// </summary>
309333
/// <returns>Byte array of the current structure's payload</returns>
310334
public Byte[] GetPayload() {
311-
return RawData.Skip(PayloadStartOffset).Take(PayloadLength).ToArray();
335+
return _rawData.Skip(PayloadStartOffset).Take(PayloadLength).ToArray();
312336
}
313337
/// <summary>
314338
/// Gets the raw data of the tag, which includes tag, length bytes and payload.
315339
/// </summary>
316340
/// <returns>A full binary copy of the tag.</returns>
317341
public Byte[] GetTagRawData() {
318-
return RawData.Skip(Offset).Take(TagLength).ToArray();
342+
return _rawData.Skip(Offset).Take(TagLength).ToArray();
343+
}
344+
/// <summary>
345+
/// Gets a copy of internal ASN.1 stream. The size of the stream is equals to <see cref="Length"/> member value.
346+
/// </summary>
347+
/// <returns>A full binary copy of the internal byte stream.</returns>
348+
public Byte[] GetRawData() {
349+
return _rawData.ToArray();
319350
}
320351
/// <summary>
321352
/// Gets the count of nested nodes under node in the current position.

Asn1Parser/Asn1Utils.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -650,14 +650,14 @@ static String DecodeBoolean(Asn1Reader asn) {
650650
throw new InvalidDataException("Invalid Boolean.");
651651
}
652652
// non-zero value is True
653-
return asn.RawData[asn.PayloadStartOffset] == 0 ? false.ToString() : true.ToString();
653+
return asn[asn.PayloadStartOffset] == 0 ? false.ToString() : true.ToString();
654654
}
655655
static String DecodeBitString(Asn1Reader asn) {
656656
return String.Format(
657657
"Unused bits: {0} : {1}",
658-
asn.RawData[asn.PayloadStartOffset],
658+
asn[asn.PayloadStartOffset],
659659
AsnFormatter.BinaryToString(
660-
asn.RawData,
660+
asn.GetRawData(),
661661
EncodingType.HexRaw,
662662
EncodingFormat.NOCRLF,
663663
asn.PayloadStartOffset + 1,
@@ -666,7 +666,7 @@ static String DecodeBitString(Asn1Reader asn) {
666666
}
667667
static String DecodeOctetString(Asn1Reader asn) {
668668
return AsnFormatter.BinaryToString(
669-
asn.RawData,
669+
asn.GetRawData(),
670670
EncodingType.HexRaw,
671671
EncodingFormat.NOCRLF, asn.PayloadStartOffset, asn.PayloadLength);
672672
}
@@ -677,10 +677,10 @@ static String DecodeObjectIdentifier(Asn1Reader asn) {
677677
: $"{oid.Value.FriendlyName} ({oid.Value})";
678678
}
679679
static String DecodeUTF8String(Asn1Reader asn) {
680-
return Encoding.UTF8.GetString(asn.RawData, asn.PayloadStartOffset, asn.PayloadLength);
680+
return Encoding.UTF8.GetString(asn.GetRawData(), asn.PayloadStartOffset, asn.PayloadLength);
681681
}
682682
static String DecodeAsciiString(Asn1Reader asn) {
683-
return Encoding.ASCII.GetString(asn.RawData, asn.PayloadStartOffset, asn.PayloadLength);
683+
return Encoding.ASCII.GetString(asn.GetRawData(), asn.PayloadStartOffset, asn.PayloadLength);
684684
}
685685
static String DecodeUtcTime(Asn1Reader asn) {
686686
var dt = new Asn1UtcTime(asn).Value;
@@ -691,7 +691,7 @@ static String DecodeGeneralizedTime(Asn1Reader asn) {
691691
return dt.ToShortDateString() + " " + dt.ToShortTimeString();
692692
}
693693
static String DecodeBMPString(Asn1Reader asn) {
694-
return Encoding.BigEndianUnicode.GetString(asn.RawData, asn.PayloadStartOffset, asn.PayloadLength);
694+
return Encoding.BigEndianUnicode.GetString(asn.GetRawData(), asn.PayloadStartOffset, asn.PayloadLength);
695695
}
696696
#endregion
697697
#endregion

Asn1Parser/AsnFormatter.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ public static String BinaryToString(Asn1Reader asn, EncodingType encoding = Enco
9999
case EncodingType.Base64:
100100
case EncodingType.Base64Header:
101101
case EncodingType.Base64CrlHeader:
102-
case EncodingType.Base64RequestHeader: return toBase64(asn.RawData, encoding, format, asn.PayloadStartOffset, asn.PayloadLength);
103-
case EncodingType.Hex: return toHex(asn.RawData, format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase);
104-
case EncodingType.HexAddress: return toHexAddr(asn.RawData, format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase);
105-
case EncodingType.HexAscii: return toHexAscii(asn.RawData, format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase);
106-
case EncodingType.HexAsciiAddress: return toHexAddrAscii(asn.RawData, format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase);
107-
case EncodingType.HexRaw: return toHexRaw(asn.RawData, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase);
102+
case EncodingType.Base64RequestHeader: return toBase64(asn.GetRawData(), encoding, format, asn.PayloadStartOffset, asn.PayloadLength);
103+
case EncodingType.Hex: return toHex(asn.GetRawData(), format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase);
104+
case EncodingType.HexAddress: return toHexAddr(asn.GetRawData(), format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase);
105+
case EncodingType.HexAscii: return toHexAscii(asn.GetRawData(), format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase);
106+
case EncodingType.HexAsciiAddress: return toHexAddrAscii(asn.GetRawData(), format, asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase);
107+
case EncodingType.HexRaw: return toHexRaw(asn.GetRawData(), asn.PayloadStartOffset, asn.PayloadLength, forceUpperCase);
108108
default: throw new ArgumentException("An invalid encoding type is specified");
109109
}
110110
}

Asn1Parser/Universal/Asn1BitString.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public Asn1BitString(Asn1Reader asn) : base(asn) {
2222
if (asn.Tag != TAG) {
2323
throw new Asn1InvalidTagException(String.Format(InvalidType, TYPE.ToString()));
2424
}
25-
UnusedBits = asn.RawData[asn.PayloadStartOffset];
25+
UnusedBits = asn[asn.PayloadStartOffset];
2626
Value = asn.GetPayload().Skip(1).ToArray();
2727
}
2828
/// <summary>

Asn1Parser/Universal/Asn1ObjectIdentifier.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ void m_encode(Oid oid) {
7575
Initialize(new Asn1Reader(Asn1Utils.Encode(encode(tokens), TAG)));
7676
}
7777
void m_decode(Asn1Reader asn) {
78-
Value = new Oid(decode(asn.RawData, asn.PayloadStartOffset, asn.PayloadLength));
78+
Value = new Oid(decode(asn.GetRawData(), asn.PayloadStartOffset, asn.PayloadLength));
7979
}
8080

8181
static Byte[] encode(IList<UInt64> tokens) {

Asn1Parser/Utils/DateTimeUtils.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public static Byte[] Encode(DateTime time, TimeZoneInfo zone, Boolean UTC, Boole
3636
public static DateTime Decode(Asn1Reader asn, out TimeZoneInfo zone) {
3737
StringBuilder SB = new StringBuilder();
3838
for (Int32 i = asn.PayloadStartOffset; i < asn.PayloadStartOffset + asn.PayloadLength; i++) {
39-
SB.Append(Convert.ToChar(asn.RawData[i]));
39+
SB.Append(Convert.ToChar(asn[i]));
4040
}
4141
return extractDateTime(SB.ToString(), out zone);
4242
}

0 commit comments

Comments
 (0)