using System; using System.IO; namespace Org.BouncyCastle.Asn1; public class Asn1StreamParser { private readonly Stream _in; private readonly int _limit; private readonly byte[][] tmpBuffers; public Asn1StreamParser(Stream inStream) : this(inStream, Asn1InputStream.FindLimit(inStream)) { } public Asn1StreamParser(Stream inStream, int limit) { if (!inStream.CanRead) { throw new ArgumentException("Expected stream to be readable", "inStream"); } _in = inStream; _limit = limit; tmpBuffers = new byte[16][]; } public Asn1StreamParser(byte[] encoding) : this(new MemoryStream(encoding, writable: false), encoding.Length) { } internal IAsn1Convertible ReadIndef(int tagValue) { return tagValue switch { 8 => new DerExternalParser(this), 4 => new BerOctetStringParser(this), 16 => new BerSequenceParser(this), 17 => new BerSetParser(this), _ => throw new Asn1Exception("unknown BER object encountered: 0x" + tagValue.ToString("X")), }; } internal IAsn1Convertible ReadImplicit(bool constructed, int tag) { if (_in is IndefiniteLengthInputStream) { if (!constructed) { throw new IOException("indefinite length primitive encoding encountered"); } return ReadIndef(tag); } if (constructed) { switch (tag) { case 17: return new DerSetParser(this); case 16: return new DerSequenceParser(this); case 4: return new BerOctetStringParser(this); } } else { switch (tag) { case 17: throw new Asn1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)"); case 16: throw new Asn1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)"); case 4: return new DerOctetStringParser((DefiniteLengthInputStream)_in); } } throw new Asn1Exception("implicit tagging not implemented"); } internal Asn1Object ReadTaggedObject(bool constructed, int tag) { if (!constructed) { DefiniteLengthInputStream definiteLengthInputStream = (DefiniteLengthInputStream)_in; return new DerTaggedObject(explicitly: false, tag, new DerOctetString(definiteLengthInputStream.ToArray())); } Asn1EncodableVector asn1EncodableVector = ReadVector(); if (_in is IndefiniteLengthInputStream) { if (asn1EncodableVector.Count != 1) { return new BerTaggedObject(explicitly: false, tag, BerSequence.FromVector(asn1EncodableVector)); } return new BerTaggedObject(explicitly: true, tag, asn1EncodableVector[0]); } if (asn1EncodableVector.Count != 1) { return new DerTaggedObject(explicitly: false, tag, DerSequence.FromVector(asn1EncodableVector)); } return new DerTaggedObject(explicitly: true, tag, asn1EncodableVector[0]); } public virtual IAsn1Convertible ReadObject() { int num = _in.ReadByte(); if (num == -1) { return null; } Set00Check(enabled: false); int num2 = Asn1InputStream.ReadTagNumber(_in, num); bool flag = (num & 0x20) != 0; int num3 = Asn1InputStream.ReadLength(_in, _limit); if (num3 < 0) { if (!flag) { throw new IOException("indefinite length primitive encoding encountered"); } IndefiniteLengthInputStream inStream = new IndefiniteLengthInputStream(_in, _limit); Asn1StreamParser asn1StreamParser = new Asn1StreamParser(inStream, _limit); if ((num & 0x40) != 0) { return new BerApplicationSpecificParser(num2, asn1StreamParser); } if ((num & 0x80) != 0) { return new BerTaggedObjectParser(constructed: true, num2, asn1StreamParser); } return asn1StreamParser.ReadIndef(num2); } DefiniteLengthInputStream definiteLengthInputStream = new DefiniteLengthInputStream(_in, num3); if ((num & 0x40) != 0) { return new DerApplicationSpecific(flag, num2, definiteLengthInputStream.ToArray()); } if ((num & 0x80) != 0) { return new BerTaggedObjectParser(flag, num2, new Asn1StreamParser(definiteLengthInputStream)); } if (flag) { return num2 switch { 4 => new BerOctetStringParser(new Asn1StreamParser(definiteLengthInputStream)), 16 => new DerSequenceParser(new Asn1StreamParser(definiteLengthInputStream)), 17 => new DerSetParser(new Asn1StreamParser(definiteLengthInputStream)), 8 => new DerExternalParser(new Asn1StreamParser(definiteLengthInputStream)), _ => throw new IOException("unknown tag " + num2 + " encountered"), }; } int num4 = num2; if (num4 == 4) { return new DerOctetStringParser(definiteLengthInputStream); } try { return Asn1InputStream.CreatePrimitiveDerObject(num2, definiteLengthInputStream, tmpBuffers); } catch (ArgumentException exception) { throw new Asn1Exception("corrupted stream detected", exception); } } private void Set00Check(bool enabled) { if (_in is IndefiniteLengthInputStream) { ((IndefiniteLengthInputStream)_in).SetEofOn00(enabled); } } internal Asn1EncodableVector ReadVector() { Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector(); IAsn1Convertible asn1Convertible; while ((asn1Convertible = ReadObject()) != null) { asn1EncodableVector.Add(asn1Convertible.ToAsn1Object()); } return asn1EncodableVector; } }