init commit
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Asn1;
|
||||
|
||||
public class Asn1InputStream : FilterStream
|
||||
{
|
||||
private readonly int limit;
|
||||
|
||||
private readonly byte[][] tmpBuffers;
|
||||
|
||||
internal static int FindLimit(Stream input)
|
||||
{
|
||||
if (input is LimitedInputStream)
|
||||
{
|
||||
return ((LimitedInputStream)input).GetRemaining();
|
||||
}
|
||||
if (input is MemoryStream)
|
||||
{
|
||||
MemoryStream memoryStream = (MemoryStream)input;
|
||||
return (int)(memoryStream.Length - memoryStream.Position);
|
||||
}
|
||||
return int.MaxValue;
|
||||
}
|
||||
|
||||
public Asn1InputStream(Stream inputStream)
|
||||
: this(inputStream, FindLimit(inputStream))
|
||||
{
|
||||
}
|
||||
|
||||
public Asn1InputStream(Stream inputStream, int limit)
|
||||
: base(inputStream)
|
||||
{
|
||||
this.limit = limit;
|
||||
tmpBuffers = new byte[16][];
|
||||
}
|
||||
|
||||
public Asn1InputStream(byte[] input)
|
||||
: this(new MemoryStream(input, writable: false), input.Length)
|
||||
{
|
||||
}
|
||||
|
||||
private Asn1Object BuildObject(int tag, int tagNo, int length)
|
||||
{
|
||||
bool flag = (tag & 0x20) != 0;
|
||||
DefiniteLengthInputStream definiteLengthInputStream = new DefiniteLengthInputStream(s, length);
|
||||
if ((tag & 0x40) != 0)
|
||||
{
|
||||
return new DerApplicationSpecific(flag, tagNo, definiteLengthInputStream.ToArray());
|
||||
}
|
||||
if ((tag & 0x80) != 0)
|
||||
{
|
||||
return new Asn1StreamParser(definiteLengthInputStream).ReadTaggedObject(flag, tagNo);
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
return tagNo switch
|
||||
{
|
||||
4 => new BerOctetString(BuildDerEncodableVector(definiteLengthInputStream)),
|
||||
16 => CreateDerSequence(definiteLengthInputStream),
|
||||
17 => CreateDerSet(definiteLengthInputStream),
|
||||
8 => new DerExternal(BuildDerEncodableVector(definiteLengthInputStream)),
|
||||
_ => throw new IOException("unknown tag " + tagNo + " encountered"),
|
||||
};
|
||||
}
|
||||
return CreatePrimitiveDerObject(tagNo, definiteLengthInputStream, tmpBuffers);
|
||||
}
|
||||
|
||||
internal Asn1EncodableVector BuildEncodableVector()
|
||||
{
|
||||
Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector();
|
||||
Asn1Object asn1Object;
|
||||
while ((asn1Object = ReadObject()) != null)
|
||||
{
|
||||
asn1EncodableVector.Add(asn1Object);
|
||||
}
|
||||
return asn1EncodableVector;
|
||||
}
|
||||
|
||||
internal virtual Asn1EncodableVector BuildDerEncodableVector(DefiniteLengthInputStream dIn)
|
||||
{
|
||||
return new Asn1InputStream(dIn).BuildEncodableVector();
|
||||
}
|
||||
|
||||
internal virtual DerSequence CreateDerSequence(DefiniteLengthInputStream dIn)
|
||||
{
|
||||
return DerSequence.FromVector(BuildDerEncodableVector(dIn));
|
||||
}
|
||||
|
||||
internal virtual DerSet CreateDerSet(DefiniteLengthInputStream dIn)
|
||||
{
|
||||
return DerSet.FromVector(BuildDerEncodableVector(dIn), needsSorting: false);
|
||||
}
|
||||
|
||||
public Asn1Object ReadObject()
|
||||
{
|
||||
int num = ReadByte();
|
||||
if (num <= 0)
|
||||
{
|
||||
if (num == 0)
|
||||
{
|
||||
throw new IOException("unexpected end-of-contents marker");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
int num2 = ReadTagNumber(s, num);
|
||||
bool flag = (num & 0x20) != 0;
|
||||
int num3 = ReadLength(s, limit);
|
||||
if (num3 < 0)
|
||||
{
|
||||
if (!flag)
|
||||
{
|
||||
throw new IOException("indefinite length primitive encoding encountered");
|
||||
}
|
||||
IndefiniteLengthInputStream inStream = new IndefiniteLengthInputStream(s, limit);
|
||||
Asn1StreamParser parser = new Asn1StreamParser(inStream, limit);
|
||||
if ((num & 0x40) != 0)
|
||||
{
|
||||
return new BerApplicationSpecificParser(num2, parser).ToAsn1Object();
|
||||
}
|
||||
if ((num & 0x80) != 0)
|
||||
{
|
||||
return new BerTaggedObjectParser(constructed: true, num2, parser).ToAsn1Object();
|
||||
}
|
||||
return num2 switch
|
||||
{
|
||||
4 => new BerOctetStringParser(parser).ToAsn1Object(),
|
||||
16 => new BerSequenceParser(parser).ToAsn1Object(),
|
||||
17 => new BerSetParser(parser).ToAsn1Object(),
|
||||
8 => new DerExternalParser(parser).ToAsn1Object(),
|
||||
_ => throw new IOException("unknown BER object encountered"),
|
||||
};
|
||||
}
|
||||
try
|
||||
{
|
||||
return BuildObject(num, num2, num3);
|
||||
}
|
||||
catch (ArgumentException exception)
|
||||
{
|
||||
throw new Asn1Exception("corrupted stream detected", exception);
|
||||
}
|
||||
}
|
||||
|
||||
internal static int ReadTagNumber(Stream s, int tag)
|
||||
{
|
||||
int num = tag & 0x1F;
|
||||
if (num == 31)
|
||||
{
|
||||
num = 0;
|
||||
int num2 = s.ReadByte();
|
||||
if ((num2 & 0x7F) == 0)
|
||||
{
|
||||
throw new IOException("Corrupted stream - invalid high tag number found");
|
||||
}
|
||||
while (num2 >= 0 && (num2 & 0x80) != 0)
|
||||
{
|
||||
num |= num2 & 0x7F;
|
||||
num <<= 7;
|
||||
num2 = s.ReadByte();
|
||||
}
|
||||
if (num2 < 0)
|
||||
{
|
||||
throw new EndOfStreamException("EOF found inside tag value.");
|
||||
}
|
||||
num |= num2 & 0x7F;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
internal static int ReadLength(Stream s, int limit)
|
||||
{
|
||||
int num = s.ReadByte();
|
||||
if (num < 0)
|
||||
{
|
||||
throw new EndOfStreamException("EOF found when length expected");
|
||||
}
|
||||
if (num == 128)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (num > 127)
|
||||
{
|
||||
int num2 = num & 0x7F;
|
||||
if (num2 > 4)
|
||||
{
|
||||
throw new IOException("DER length more than 4 bytes: " + num2);
|
||||
}
|
||||
num = 0;
|
||||
for (int i = 0; i < num2; i++)
|
||||
{
|
||||
int num3 = s.ReadByte();
|
||||
if (num3 < 0)
|
||||
{
|
||||
throw new EndOfStreamException("EOF found reading length");
|
||||
}
|
||||
num = (num << 8) + num3;
|
||||
}
|
||||
if (num < 0)
|
||||
{
|
||||
throw new IOException("Corrupted stream - negative length found");
|
||||
}
|
||||
if (num >= limit)
|
||||
{
|
||||
throw new IOException("Corrupted stream - out of bounds length found");
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
internal static byte[] GetBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
|
||||
{
|
||||
int remaining = defIn.GetRemaining();
|
||||
if (remaining >= tmpBuffers.Length)
|
||||
{
|
||||
return defIn.ToArray();
|
||||
}
|
||||
byte[] array = tmpBuffers[remaining];
|
||||
if (array == null)
|
||||
{
|
||||
array = (tmpBuffers[remaining] = new byte[remaining]);
|
||||
}
|
||||
defIn.ReadAllIntoByteArray(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
internal static Asn1Object CreatePrimitiveDerObject(int tagNo, DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
|
||||
{
|
||||
switch (tagNo)
|
||||
{
|
||||
case 1:
|
||||
return DerBoolean.FromOctetString(GetBuffer(defIn, tmpBuffers));
|
||||
case 10:
|
||||
return DerEnumerated.FromOctetString(GetBuffer(defIn, tmpBuffers));
|
||||
case 6:
|
||||
return DerObjectIdentifier.FromOctetString(GetBuffer(defIn, tmpBuffers));
|
||||
default:
|
||||
{
|
||||
byte[] array = defIn.ToArray();
|
||||
return tagNo switch
|
||||
{
|
||||
3 => DerBitString.FromAsn1Octets(array),
|
||||
30 => new DerBmpString(array),
|
||||
24 => new DerGeneralizedTime(array),
|
||||
27 => new DerGeneralString(array),
|
||||
25 => new DerGraphicString(array),
|
||||
22 => new DerIA5String(array),
|
||||
2 => new DerInteger(array),
|
||||
5 => DerNull.Instance,
|
||||
18 => new DerNumericString(array),
|
||||
4 => new DerOctetString(array),
|
||||
19 => new DerPrintableString(array),
|
||||
20 => new DerT61String(array),
|
||||
28 => new DerUniversalString(array),
|
||||
23 => new DerUtcTime(array),
|
||||
12 => new DerUtf8String(array),
|
||||
21 => new DerVideotexString(array),
|
||||
26 => new DerVisibleString(array),
|
||||
_ => throw new IOException("unknown tag " + tagNo + " encountered"),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user