401 lines
11 KiB
C#
401 lines
11 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|