培训考核三期,新版培训,网页版培训登录器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

476 lines
16 KiB

#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.Diagnostics;
using System.IO;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.IO;
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1
{
/**
* a general purpose ASN.1 decoder - note: this class differs from the
* others in that it returns null after it has read the last object in
* the stream. If an ASN.1 Null is encountered a Der/BER Null object is
* returned.
*/
public class Asn1InputStream
: FilterStream
{
private readonly int limit;
internal readonly byte[][] tmpBuffers;
internal static int FindLimit(Stream input)
{
if (input is LimitedInputStream)
return ((LimitedInputStream)input).Limit;
if (input is Asn1InputStream)
return ((Asn1InputStream)input).Limit;
if (input is MemoryStream)
{
MemoryStream mem = (MemoryStream)input;
return (int)(mem.Length - mem.Position);
}
return int.MaxValue;
}
public Asn1InputStream(Stream input)
: this(input, FindLimit(input))
{
}
/**
* Create an ASN1InputStream based on the input byte array. The length of DER objects in
* the stream is automatically limited to the length of the input array.
*
* @param input array containing ASN.1 encoded data.
*/
public Asn1InputStream(byte[] input)
: this(new MemoryStream(input, false), input.Length)
{
}
/**
* Create an ASN1InputStream where no DER object will be longer than limit.
*
* @param input stream containing ASN.1 encoded data.
* @param limit maximum size of a DER encoded object.
*/
public Asn1InputStream(Stream input, int limit)
: this(input, limit, new byte[16][])
{
}
internal Asn1InputStream(Stream input, int limit, byte[][] tmpBuffers)
: base(input)
{
this.limit = limit;
this.tmpBuffers = tmpBuffers;
}
/**
* build an object given its tag and the number of bytes to construct it from.
*/
private Asn1Object BuildObject(
int tag,
int tagNo,
int length)
{
bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length, limit);
int tagClass = tag & Asn1Tags.Private;
if (0 != tagClass)
{
if ((tag & Asn1Tags.Application) != 0)
return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
return new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers).ReadTaggedObject(isConstructed, tagNo);
}
if (!isConstructed)
return CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
switch (tagNo)
{
case Asn1Tags.BitString:
{
return BuildConstructedBitString(ReadVector(defIn));
}
case Asn1Tags.OctetString:
{
//
// yes, people actually do this...
//
return BuildConstructedOctetString(ReadVector(defIn));
}
case Asn1Tags.Sequence:
return CreateDerSequence(defIn);
case Asn1Tags.Set:
return CreateDerSet(defIn);
case Asn1Tags.External:
return new DerExternal(ReadVector(defIn));
default:
throw new IOException("unknown tag " + tagNo + " encountered");
}
}
internal virtual Asn1EncodableVector ReadVector()
{
Asn1Object o = ReadObject();
if (null == o)
return new Asn1EncodableVector(0);
Asn1EncodableVector v = new Asn1EncodableVector();
do
{
v.Add(o);
}
while ((o = ReadObject()) != null);
return v;
}
internal virtual Asn1EncodableVector ReadVector(DefiniteLengthInputStream defIn)
{
int remaining = defIn.Remaining;
if (remaining < 1)
return new Asn1EncodableVector(0);
return new Asn1InputStream(defIn, remaining, tmpBuffers).ReadVector();
}
internal virtual DerSequence CreateDerSequence(
DefiniteLengthInputStream dIn)
{
return DerSequence.FromVector(ReadVector(dIn));
}
internal virtual DerSet CreateDerSet(
DefiniteLengthInputStream dIn)
{
return DerSet.FromVector(ReadVector(dIn), false);
}
public Asn1Object ReadObject()
{
int tag = ReadByte();
if (tag <= 0)
{
if (tag == 0)
throw new IOException("unexpected end-of-contents marker");
return null;
}
int tagNo = ReadTagNumber(this, tag);
int length = ReadLength(this, limit, false);
if (length >= 0)
{
// definite-length
try
{
return BuildObject(tag, tagNo, length);
}
catch (ArgumentException e)
{
throw new Asn1Exception("corrupted stream detected", e);
}
}
// indefinite-length
if (0 == (tag & Asn1Tags.Constructed))
throw new IOException("indefinite-length primitive encoding encountered");
IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit);
Asn1StreamParser sp = new Asn1StreamParser(indIn, limit, tmpBuffers);
int tagClass = tag & Asn1Tags.Private;
if (0 != tagClass)
{
if ((tag & Asn1Tags.Application) != 0)
return new BerApplicationSpecificParser(tagNo, sp).ToAsn1Object();
return new BerTaggedObjectParser(true, tagNo, sp).ToAsn1Object();
}
// TODO There are other tags that may be constructed (e.g. BitString)
switch (tagNo)
{
case Asn1Tags.OctetString:
return BerOctetStringParser.Parse(sp);
case Asn1Tags.Sequence:
return BerSequenceParser.Parse(sp);
case Asn1Tags.Set:
return BerSetParser.Parse(sp);
case Asn1Tags.External:
return DerExternalParser.Parse(sp);
default:
throw new IOException("unknown BER object encountered");
}
}
internal virtual DerBitString BuildConstructedBitString(Asn1EncodableVector contentsElements)
{
DerBitString[] bitStrings = new DerBitString[contentsElements.Count];
for (int i = 0; i != bitStrings.Length; i++)
{
DerBitString bitString = contentsElements[i] as DerBitString;
if (null == bitString)
throw new Asn1Exception("unknown object encountered in constructed BIT STRING: "
+ BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.GetTypeName(contentsElements[i]));
bitStrings[i] = bitString;
}
// TODO Probably ought to be DLBitString
return new BerBitString(bitStrings);
}
internal virtual Asn1OctetString BuildConstructedOctetString(Asn1EncodableVector contentsElements)
{
Asn1OctetString[] octetStrings = new Asn1OctetString[contentsElements.Count];
for (int i = 0; i != octetStrings.Length; i++)
{
Asn1OctetString octetString = contentsElements[i] as Asn1OctetString;
if (null == octetString)
throw new Asn1Exception("unknown object encountered in constructed OCTET STRING: "
+ BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.GetTypeName(contentsElements[i]));
octetStrings[i] = octetString;
}
// TODO Probably ought to be DerOctetString (no DLOctetString available)
return new BerOctetString(octetStrings);
}
internal virtual int Limit
{
get { return limit; }
}
internal static int ReadTagNumber(Stream s, int tag)
{
int tagNo = tag & 0x1f;
//
// with tagged object tag number is bottom 5 bits, or stored at the start of the content
//
if (tagNo == 0x1f)
{
tagNo = 0;
int b = s.ReadByte();
if (b < 31)
{
if (b < 0)
throw new EndOfStreamException("EOF found inside tag value.");
throw new IOException("corrupted stream - high tag number < 31 found");
}
// X.690-0207 8.1.2.4.2
// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
if ((b & 0x7f) == 0)
throw new IOException("corrupted stream - invalid high tag number found");
while ((b & 0x80) != 0)
{
if (((uint)tagNo >> 24) != 0U)
throw new IOException("Tag number more than 31 bits");
tagNo |= b & 0x7f;
tagNo <<= 7;
b = s.ReadByte();
if (b < 0)
throw new EndOfStreamException("EOF found inside tag value.");
}
tagNo |= b & 0x7f;
}
return tagNo;
}
internal static int ReadLength(Stream s, int limit, bool isParsing)
{
int length = s.ReadByte();
if (0U == ((uint)length >> 7))
{
// definite-length short form
return length;
}
if (0x80 == length)
{
// indefinite-length
return -1;
}
if (length < 0)
{
throw new EndOfStreamException("EOF found when length expected");
}
if (0xFF == length)
{
throw new IOException("invalid long form definite-length 0xFF");
}
int octetsCount = length & 0x7F, octetsPos = 0;
length = 0;
do
{
int octet = s.ReadByte();
if (octet < 0)
throw new EndOfStreamException("EOF found reading length");
if (((uint)length >> 23) != 0U)
throw new IOException("long form definite-length more than 31 bits");
length = (length << 8) + octet;
}
while (++octetsPos < octetsCount);
if (length >= limit && !isParsing) // after all we must have read at least 1 byte
throw new IOException("corrupted stream - out of bounds length found: " + length + " >= " + limit);
return length;
}
private static byte[] GetBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
{
int len = defIn.Remaining;
if (len >= tmpBuffers.Length)
{
return defIn.ToArray();
}
byte[] buf = tmpBuffers[len];
if (buf == null)
{
buf = tmpBuffers[len] = new byte[len];
}
defIn.ReadAllIntoByteArray(buf);
return buf;
}
private static char[] GetBmpCharBuffer(DefiniteLengthInputStream defIn)
{
int remainingBytes = defIn.Remaining;
if (0 != (remainingBytes & 1))
throw new IOException("malformed BMPString encoding encountered");
char[] str = new char[remainingBytes / 2];
int stringPos = 0;
byte[] buf = new byte[8];
while (remainingBytes >= 8)
{
if (Streams.ReadFully(defIn, buf, 0, 8) != 8)
throw new EndOfStreamException("EOF encountered in middle of BMPString");
str[stringPos ] = (char)((buf[0] << 8) | (buf[1] & 0xFF));
str[stringPos + 1] = (char)((buf[2] << 8) | (buf[3] & 0xFF));
str[stringPos + 2] = (char)((buf[4] << 8) | (buf[5] & 0xFF));
str[stringPos + 3] = (char)((buf[6] << 8) | (buf[7] & 0xFF));
stringPos += 4;
remainingBytes -= 8;
}
if (remainingBytes > 0)
{
if (Streams.ReadFully(defIn, buf, 0, remainingBytes) != remainingBytes)
throw new EndOfStreamException("EOF encountered in middle of BMPString");
int bufPos = 0;
do
{
int b1 = buf[bufPos++] << 8;
int b2 = buf[bufPos++] & 0xFF;
str[stringPos++] = (char)(b1 | b2);
}
while (bufPos < remainingBytes);
}
if (0 != defIn.Remaining || str.Length != stringPos)
throw new InvalidOperationException();
return str;
}
internal static Asn1Object CreatePrimitiveDerObject(
int tagNo,
DefiniteLengthInputStream defIn,
byte[][] tmpBuffers)
{
switch (tagNo)
{
case Asn1Tags.BmpString:
return new DerBmpString(GetBmpCharBuffer(defIn));
case Asn1Tags.Boolean:
return DerBoolean.FromOctetString(GetBuffer(defIn, tmpBuffers));
case Asn1Tags.Enumerated:
return DerEnumerated.FromOctetString(GetBuffer(defIn, tmpBuffers));
case Asn1Tags.ObjectIdentifier:
// TODO Ideally only clone if we used a buffer
return DerObjectIdentifier.CreatePrimitive(GetBuffer(defIn, tmpBuffers), true);
}
byte[] bytes = defIn.ToArray();
switch (tagNo)
{
case Asn1Tags.BitString:
return DerBitString.CreatePrimitive(bytes);
case Asn1Tags.GeneralizedTime:
return new DerGeneralizedTime(bytes);
case Asn1Tags.GeneralString:
return new DerGeneralString(bytes);
case Asn1Tags.GraphicString:
return new DerGraphicString(bytes);
case Asn1Tags.IA5String:
return new DerIA5String(bytes);
case Asn1Tags.Integer:
return new DerInteger(bytes, false);
case Asn1Tags.Null:
{
if (0 != bytes.Length)
throw new InvalidOperationException("malformed NULL encoding encountered");
return DerNull.Instance;
}
case Asn1Tags.NumericString:
return new DerNumericString(bytes);
case Asn1Tags.OctetString:
return new DerOctetString(bytes);
case Asn1Tags.PrintableString:
return new DerPrintableString(bytes);
case Asn1Tags.T61String:
return new DerT61String(bytes);
case Asn1Tags.UniversalString:
return new DerUniversalString(bytes);
case Asn1Tags.UtcTime:
return new DerUtcTime(bytes);
case Asn1Tags.Utf8String:
return new DerUtf8String(bytes);
case Asn1Tags.VideotexString:
return new DerVideotexString(bytes);
case Asn1Tags.VisibleString:
return new DerVisibleString(bytes);
default:
throw new IOException("unknown tag " + tagNo + " encountered");
}
}
}
}
#pragma warning restore
#endif