<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" />

Asn1InputStream

public class Asn1InputStream : FilterStream
using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.IO; using System; using System.Buffers.Binary; using System.IO; namespace Org.BouncyCastle.Asn1 { public class Asn1InputStream : FilterStream { private readonly int limit; private readonly bool m_leaveOpen; internal byte[][] tmpBuffers; internal static int FindLimit(Stream input) { LimitedInputStream limitedInputStream = input as LimitedInputStream; if (limitedInputStream != null) return limitedInputStream.Limit; Asn1InputStream asn1InputStream = input as Asn1InputStream; if (asn1InputStream != null) return asn1InputStream.limit; MemoryStream memoryStream = input as MemoryStream; if (memoryStream != null) return GetMemoryStreamLimit(memoryStream); return 2147483647; } internal static int GetMemoryStreamLimit(MemoryStream input) { return Convert.ToInt32(input.Length - input.Position); } public Asn1InputStream(byte[] input) : this(new MemoryStream(input, false), input.Length) { } public Asn1InputStream(Stream input) : this(input, FindLimit(input)) { } internal Asn1InputStream(MemoryStream input) : this(input, GetMemoryStreamLimit(input)) { } public Asn1InputStream(Stream input, int limit) : this(input, limit, false) { } public Asn1InputStream(Stream input, int limit, bool leaveOpen) : this(input, limit, leaveOpen, new byte[16][]) { } internal Asn1InputStream(Stream input, int limit, bool leaveOpen, byte[][] tmpBuffers) : base(input) { if (!input.CanRead) throw new ArgumentException("Expected stream to be readable", "input"); this.limit = limit; m_leaveOpen = leaveOpen; this.tmpBuffers = tmpBuffers; } protected override void Dispose(bool disposing) { tmpBuffers = null; if (m_leaveOpen) Detach(disposing); else base.Dispose(disposing); } private Asn1Object BuildObject(int tagHdr, int tagNo, int length) { DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(s, length, limit); if ((tagHdr & 224) == 0) return CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers); int num = tagHdr & 192; if (num == 0) { switch (tagNo) { case 3: return BuildConstructedBitString(ReadVector(defIn)); case 4: return BuildConstructedOctetString(ReadVector(defIn)); case 16: return DLSequence.FromVector(ReadVector(defIn)); case 17: return DLSet.FromVector(ReadVector(defIn)); case 8: return DLSequence.FromVector(ReadVector(defIn)).ToAsn1External(); default: throw new IOException("unknown tag " + tagNo.ToString() + " encountered"); } } bool constructed = (tagHdr & 32) != 0; return ReadTaggedObjectDL(num, tagNo, constructed, defIn); } internal Asn1Object ReadTaggedObjectDL(int tagClass, int tagNo, bool constructed, DefiniteLengthInputStream defIn) { if (!constructed) { byte[] contentsOctets = defIn.ToArray(); return Asn1TaggedObject.CreatePrimitive(tagClass, tagNo, contentsOctets); } Asn1EncodableVector contentsElements = ReadVector(defIn); return Asn1TaggedObject.CreateConstructedDL(tagClass, tagNo, contentsElements); } private Asn1EncodableVector ReadVector() { Asn1Object asn1Object = ReadObject(); if (asn1Object == null) return new Asn1EncodableVector(0); Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector(); do { asn1EncodableVector.Add(asn1Object); } while ((asn1Object = ReadObject()) != null); return asn1EncodableVector; } private Asn1EncodableVector ReadVector(DefiniteLengthInputStream defIn) { int remaining = defIn.Remaining; if (remaining < 1) return new Asn1EncodableVector(0); using (Asn1InputStream asn1InputStream = new Asn1InputStream(defIn, remaining, true, tmpBuffers)) return asn1InputStream.ReadVector(); } public Asn1Object ReadObject() { int num = s.ReadByte(); if (num <= 0) { if (num == 0) throw new IOException("unexpected end-of-contents marker"); return null; } int num2 = ReadTagNumber(s, num); int num3 = ReadLength(s, limit, false); if (num3 >= 0) try { return BuildObject(num, num2, num3); } catch (ArgumentException innerException) { throw new Asn1Exception("corrupted stream detected", innerException); } if ((num & 32) == 0) throw new IOException("indefinite-length primitive encoding encountered"); Asn1StreamParser asn1StreamParser = new Asn1StreamParser(new IndefiniteLengthInputStream(s, limit), limit, tmpBuffers); int num4 = num & 192; if (num4 == 0) { switch (num2) { case 3: return BerBitStringParser.Parse(asn1StreamParser); case 4: return BerOctetStringParser.Parse(asn1StreamParser); case 16: return BerSequenceParser.Parse(asn1StreamParser); case 17: return BerSetParser.Parse(asn1StreamParser); case 8: return DerExternalParser.Parse(asn1StreamParser); default: throw new IOException("unknown BER object encountered"); } } return asn1StreamParser.LoadTaggedIL(num4, num2); } private DerBitString BuildConstructedBitString(Asn1EncodableVector contentsElements) { DerBitString[] array = new DerBitString[contentsElements.Count]; for (int i = 0; i != array.Length; i++) { DerBitString derBitString = contentsElements[i] as DerBitString; if (derBitString == null) throw new Asn1Exception("unknown object encountered in constructed BIT STRING: " + Platform.GetTypeName(contentsElements[i])); array[i] = derBitString; } return new DLBitString(BerBitString.FlattenBitStrings(array), false); } private Asn1OctetString BuildConstructedOctetString(Asn1EncodableVector contentsElements) { Asn1OctetString[] array = new Asn1OctetString[contentsElements.Count]; for (int i = 0; i != array.Length; i++) { Asn1OctetString asn1OctetString = contentsElements[i] as Asn1OctetString; if (asn1OctetString == null) throw new Asn1Exception("unknown object encountered in constructed OCTET STRING: " + Platform.GetTypeName(contentsElements[i])); array[i] = asn1OctetString; } return DerOctetString.WithContents(BerOctetString.FlattenOctetStrings(array)); } internal static int ReadTagNumber(Stream s, int tagHdr) { int num = tagHdr & 31; if (num == 31) { int num2 = s.ReadByte(); if (num2 < 31) { if (num2 < 0) throw new EndOfStreamException("EOF found inside tag value."); throw new IOException("corrupted stream - high tag number < 31 found"); } num = (num2 & 127); if (num == 0) throw new IOException("corrupted stream - invalid high tag number found"); while ((num2 & 128) != 0) { if ((uint)num >> 24 != 0) throw new IOException("Tag number more than 31 bits"); num <<= 7; num2 = s.ReadByte(); if (num2 < 0) throw new EndOfStreamException("EOF found inside tag value."); num |= (num2 & 127); } } return num; } internal static int ReadLength(Stream s, int limit, bool isParsing) { int num = s.ReadByte(); if ((uint)num >> 7 == 0) return num; if (128 == num) return -1; if (num < 0) throw new EndOfStreamException("EOF found when length expected"); if (255 == num) throw new IOException("invalid long form definite-length 0xFF"); int num2 = num & 127; int num3 = 0; num = 0; do { int num4 = s.ReadByte(); if (num4 < 0) throw new EndOfStreamException("EOF found reading length"); if ((uint)num >> 23 != 0) throw new IOException("long form definite-length more than 31 bits"); num = (num << 8) + num4; } while (++num3 < num2); if (num >= limit && !isParsing) throw new IOException("corrupted stream - out of bounds length found: " + num.ToString() + " >= " + limit.ToString()); return num; } private static bool GetBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers, out byte[] contents) { int remaining = defIn.Remaining; if (remaining >= tmpBuffers.Length) { contents = defIn.ToArray(); return false; } byte[] array = tmpBuffers[remaining]; if (array == null) array = (tmpBuffers[remaining] = new byte[remaining]); defIn.ReadAllIntoByteArray(array); contents = array; return true; } internal static Asn1Object CreatePrimitiveDerObject(int tagNo, DefiniteLengthInputStream defIn, byte[][] tmpBuffers) { switch (tagNo) { case 30: return CreateDerBmpString(defIn); case 1: GetBuffer(defIn, tmpBuffers, out byte[] contents5); return DerBoolean.CreatePrimitive(contents5); case 10: { byte[] contents4; bool buffer3 = GetBuffer(defIn, tmpBuffers, out contents4); return DerEnumerated.CreatePrimitive(contents4, buffer3); } case 6: { DerObjectIdentifier.CheckContentsLength(defIn.Remaining); byte[] contents3; bool buffer2 = GetBuffer(defIn, tmpBuffers, out contents3); return DerObjectIdentifier.CreatePrimitive(contents3, buffer2); } case 13: { Asn1RelativeOid.CheckContentsLength(defIn.Remaining); byte[] contents2; bool buffer = GetBuffer(defIn, tmpBuffers, out contents2); return Asn1RelativeOid.CreatePrimitive(contents2, buffer); } default: { byte[] contents = defIn.ToArray(); switch (tagNo) { case 3: return DerBitString.CreatePrimitive(contents); case 24: return Asn1GeneralizedTime.CreatePrimitive(contents); case 27: return DerGeneralString.CreatePrimitive(contents); case 25: return DerGraphicString.CreatePrimitive(contents); case 22: return DerIA5String.CreatePrimitive(contents); case 2: return DerInteger.CreatePrimitive(contents); case 5: return Asn1Null.CreatePrimitive(contents); case 18: return DerNumericString.CreatePrimitive(contents); case 7: return Asn1ObjectDescriptor.CreatePrimitive(contents); case 4: return Asn1OctetString.CreatePrimitive(contents); case 19: return DerPrintableString.CreatePrimitive(contents); case 20: return DerT61String.CreatePrimitive(contents); case 28: return DerUniversalString.CreatePrimitive(contents); case 23: return Asn1UtcTime.CreatePrimitive(contents); case 12: return DerUtf8String.CreatePrimitive(contents); case 21: return DerVideotexString.CreatePrimitive(contents); case 26: return DerVisibleString.CreatePrimitive(contents); case 9: case 11: case 14: case 29: case 31: case 32: case 33: case 34: case 35: case 36: throw new IOException("unsupported tag " + tagNo.ToString() + " encountered"); default: throw new IOException("unknown tag " + tagNo.ToString() + " encountered"); } } } } private unsafe static DerBmpString CreateDerBmpString(DefiniteLengthInputStream defIn) { int remainingBytes = defIn.Remaining; if ((remainingBytes & 1) != 0) throw new IOException("malformed BMPString encoding encountered"); return DerBmpString.CreatePrimitive(remainingBytes / 2, defIn, delegate(Span<char> str, DefiniteLengthInputStream defIn) { int num = 0; Span<byte> buffer = new Span<byte>(stackalloc byte[8], 8); while (remainingBytes >= 8) { if (Streams.ReadFully(defIn, buffer) != 8) throw new EndOfStreamException("EOF encountered in middle of BMPString"); str[num] = (char)BinaryPrimitives.ReadUInt16BigEndian(buffer.Slice(0, buffer.Length)); str[num + 1] = (char)BinaryPrimitives.ReadUInt16BigEndian(buffer.Slice(2, buffer.Length - 2)); str[num + 2] = (char)BinaryPrimitives.ReadUInt16BigEndian(buffer.Slice(4, buffer.Length - 4)); str[num + 3] = (char)BinaryPrimitives.ReadUInt16BigEndian(buffer.Slice(6, buffer.Length - 6)); num += 4; remainingBytes -= 8; } if (remainingBytes > 0) { if (Streams.ReadFully(defIn, buffer) != remainingBytes) throw new EndOfStreamException("EOF encountered in middle of BMPString"); int num2 = 0; do { int num4 = buffer[num2++] << 8; int num6 = buffer[num2++] & 255; str[num++] = (char)(num4 | num6); } while (num2 < remainingBytes); } if (defIn.Remaining != 0 || str.Length != num) throw new InvalidOperationException(); }); } } }