using GostCryptography.Properties; using System; using System.IO; namespace GostCryptography.Asn1.Ber { public class Asn1BerDecodeBuffer : Asn1DecodeBuffer { private readonly IntHolder _lenHolder; private readonly Asn1Tag _tagHolder; private Asn1Tag _lastParsedTag; private MemoryStream _openTypeCaptureBuffer; private MemoryStream _parserCaptureBuffer; public Asn1BerDecodeBuffer(byte[] msgdata) : base(msgdata) { _tagHolder = new Asn1Tag(); _lenHolder = new IntHolder(); } public Asn1BerDecodeBuffer(Stream inputStream) : base(inputStream) { _tagHolder = new Asn1Tag(); _lenHolder = new IntHolder(); } public virtual Asn1Tag LastTag { get { return _lastParsedTag; } } public static int CalcIndefLen(byte[] data, int offset, int len) { Asn1BerDecodeBuffer buffer; if ((offset == 0) && (len == data.Length)) { buffer = new Asn1BerDecodeBuffer(data); } else { var destinationArray = new byte[len]; Array.Copy(data, offset, destinationArray, 0, len); buffer = new Asn1BerDecodeBuffer(destinationArray); } var tag = new Asn1Tag(); var num = buffer.DecodeTagAndLength(tag); if (num == Asn1Status.IndefiniteLength) { var num2 = 1; num = 0; while (num2 > 0) { var byteCount = buffer.ByteCount; var num4 = buffer.DecodeTagAndLength(tag); num += buffer.ByteCount - byteCount; if (num4 > 0) { buffer.Skip(num4); num += num4; } else { if (num4 == Asn1Status.IndefiniteLength) { num2++; continue; } if (tag.IsEoc() && (num4 == 0)) { num2--; } } } } return num; } public virtual int DecodeLength() { var num3 = 0; var num2 = Read(); if (num2 < 0) { throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount); } if (num2 <= 0x80) { if (num2 == 0x80) { return Asn1Status.IndefiniteLength; } return num2; } var num = num2 & 0x7f; if (num > 4) { throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException); } while (num > 0) { num2 = Read(); if (num2 < 0) { throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount); } num3 = (num3 * 0x100) + num2; num--; } return num3; } public virtual byte[] DecodeOpenType() { return DecodeOpenType(true); } public virtual byte[] DecodeOpenType(bool saveData) { if (saveData) { if (_openTypeCaptureBuffer == null) { _openTypeCaptureBuffer = new MemoryStream(0x100); } else { _openTypeCaptureBuffer.Seek(0L, SeekOrigin.Begin); _openTypeCaptureBuffer.SetLength(0L); } AddCaptureBuffer(_openTypeCaptureBuffer); } DecodeOpenTypeElement(_tagHolder, _lenHolder, saveData); if (saveData) { var buffer = _openTypeCaptureBuffer.ToArray(); RemoveCaptureBuffer(_openTypeCaptureBuffer); return buffer; } return null; } private void DecodeOpenTypeElement(Asn1Tag tag, IntHolder len, bool saveData) { var nbytes = DecodeTagAndLength(tag); var byteCount = base.ByteCount; if (nbytes > 0) { if (saveData) { Capture(nbytes); } else { Skip(nbytes); } } else if (nbytes == Asn1Status.IndefiniteLength) { MovePastEoc(saveData); } len.Value = base.ByteCount - byteCount; } public virtual void DecodeTag(Asn1Tag tag) { var num = Read(); if (num < 0) { throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount); } tag.Class = (short)(num & 0xc0); tag.Form = (short)(num & 0x20); tag.IdCode = num & 0x1f; if (tag.IdCode == 0x1f) { var num2 = 0L; var num3 = 0; do { num = Read(); if (num < 0) { throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount); } num2 = (num2 * 0x80L) + (num & 0x7f); if ((num2 > 0x7fffffffL) || (num3++ > 8)) { throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidTagValue); } } while ((num & 0x80) != 0); tag.IdCode = (int)num2; } _lastParsedTag = tag; } public virtual int DecodeTagAndLength(Asn1Tag tag) { DecodeTag(tag); return DecodeLength(); } public virtual bool MatchTag(Asn1Tag tag) { return MatchTag(tag.Class, tag.Form, tag.IdCode, null, null); } public virtual bool MatchTag(Asn1Tag tag, Asn1Tag parsedTag, IntHolder parsedLen) { return MatchTag(tag.Class, tag.Form, tag.IdCode, parsedTag, parsedLen); } public virtual bool MatchTag(short tagClass, short tagForm, int tagIdCode, Asn1Tag parsedTag, IntHolder parsedLen) { Mark(); var tag = parsedTag ?? _tagHolder; var holder = parsedLen ?? _lenHolder; holder.Value = DecodeTagAndLength(tag); if (!tag.Equals(tagClass, tagForm, tagIdCode)) { Reset(); return false; } return true; } protected void MovePastEoc(bool saveData) { var tag = new Asn1Tag(); var num = 1; while (num > 0) { var nbytes = DecodeTagAndLength(tag); if (nbytes > 0) { if (saveData) { Capture(nbytes); } else { Skip(nbytes); } } else if (nbytes == Asn1Status.IndefiniteLength) { num++; } else if (tag.IsEoc() && (nbytes == 0)) { num--; } } } public virtual void Parse(IAsn1TaggedEventHandler handler) { if (_parserCaptureBuffer == null) { RemoveCaptureBuffer(_parserCaptureBuffer); } if (_parserCaptureBuffer == null) { _parserCaptureBuffer = new MemoryStream(0x100); AddCaptureBuffer(_parserCaptureBuffer); } else { _parserCaptureBuffer.Seek(0L, SeekOrigin.Begin); _parserCaptureBuffer.SetLength(0L); } ParseElement(handler, _tagHolder, _lenHolder); } private void ParseCons(IAsn1TaggedEventHandler handler, int len) { var tag2 = new Asn1Tag(); var holder = new IntHolder(); var byteCount = base.ByteCount; while (true) { ParseElement(handler, tag2, holder); if (len == Asn1Status.IndefiniteLength) { if (tag2.IsEoc() && (holder.Value == 0)) { return; } continue; } if ((base.ByteCount - byteCount) >= len) { return; } } } private void ParseElement(IAsn1TaggedEventHandler handler, Asn1Tag tag, IntHolder len) { _parserCaptureBuffer.Seek(0L, SeekOrigin.Begin); _parserCaptureBuffer.SetLength(0L); len.Value = DecodeTagAndLength(tag); if (!tag.IsEoc() || (len.Value != 0)) { handler.StartElement(tag, len.Value, _parserCaptureBuffer.ToArray()); _parserCaptureBuffer.Seek(0L, SeekOrigin.Begin); _parserCaptureBuffer.SetLength(0L); if ((len.Value > 0) || (len.Value == Asn1Status.IndefiniteLength)) { if (tag.Constructed) { ParseCons(handler, len.Value); } else { ParsePrim(handler, len.Value); } } handler.EndElement(tag); } } private void ParsePrim(IAsn1TaggedEventHandler handler, int len) { var buffer = new byte[len]; Read(buffer); handler.Contents(buffer); } public virtual Asn1Tag PeekTag() { var parsedTag = new Asn1Tag(); PeekTag(parsedTag); return parsedTag; } public virtual void PeekTag(Asn1Tag parsedTag) { Mark(); DecodeTag(parsedTag); Reset(); } public override int ReadByte() { return Read(); } } }