ASN1StreamParser.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1
  6. {
  7. public class Asn1StreamParser
  8. {
  9. private readonly Stream _in;
  10. private readonly int _limit;
  11. private readonly byte[][] tmpBuffers;
  12. public Asn1StreamParser(Stream input)
  13. : this(input, Asn1InputStream.FindLimit(input))
  14. {
  15. }
  16. public Asn1StreamParser(byte[] encoding)
  17. : this(new MemoryStream(encoding, false), encoding.Length)
  18. {
  19. }
  20. public Asn1StreamParser(Stream input, int limit)
  21. : this(input, limit, new byte[16][])
  22. {
  23. }
  24. internal Asn1StreamParser(Stream input, int limit, byte[][] tmpBuffers)
  25. {
  26. if (!input.CanRead)
  27. throw new ArgumentException("Expected stream to be readable", "input");
  28. this._in = input;
  29. this._limit = limit;
  30. this.tmpBuffers = tmpBuffers;
  31. }
  32. internal IAsn1Convertible ReadIndef(int tagValue)
  33. {
  34. // Note: INDEF => CONSTRUCTED
  35. // TODO There are other tags that may be constructed (e.g. BIT_STRING)
  36. switch (tagValue)
  37. {
  38. case Asn1Tags.External:
  39. return new DerExternalParser(this);
  40. case Asn1Tags.OctetString:
  41. return new BerOctetStringParser(this);
  42. case Asn1Tags.Sequence:
  43. return new BerSequenceParser(this);
  44. case Asn1Tags.Set:
  45. return new BerSetParser(this);
  46. default:
  47. throw new Asn1Exception("unknown BER object encountered: 0x" + tagValue.ToString("X"));
  48. }
  49. }
  50. internal IAsn1Convertible ReadImplicit(bool constructed, int tag)
  51. {
  52. if (_in is IndefiniteLengthInputStream)
  53. {
  54. if (!constructed)
  55. throw new IOException("indefinite-length primitive encoding encountered");
  56. return ReadIndef(tag);
  57. }
  58. if (constructed)
  59. {
  60. switch (tag)
  61. {
  62. case Asn1Tags.Set:
  63. return new DerSetParser(this);
  64. case Asn1Tags.Sequence:
  65. return new DerSequenceParser(this);
  66. case Asn1Tags.OctetString:
  67. return new BerOctetStringParser(this);
  68. }
  69. }
  70. else
  71. {
  72. switch (tag)
  73. {
  74. case Asn1Tags.Set:
  75. throw new Asn1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
  76. case Asn1Tags.Sequence:
  77. throw new Asn1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
  78. case Asn1Tags.OctetString:
  79. return new DerOctetStringParser((DefiniteLengthInputStream)_in);
  80. }
  81. }
  82. throw new Asn1Exception("implicit tagging not implemented");
  83. }
  84. internal Asn1Object ReadTaggedObject(bool constructed, int tag)
  85. {
  86. if (!constructed)
  87. {
  88. // Note: !CONSTRUCTED => IMPLICIT
  89. DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
  90. return new DerTaggedObject(false, tag, new DerOctetString(defIn.ToArray()));
  91. }
  92. Asn1EncodableVector v = ReadVector();
  93. if (_in is IndefiniteLengthInputStream)
  94. {
  95. return v.Count == 1
  96. ? new BerTaggedObject(true, tag, v[0])
  97. : new BerTaggedObject(false, tag, BerSequence.FromVector(v));
  98. }
  99. return v.Count == 1
  100. ? new DerTaggedObject(true, tag, v[0])
  101. : new DerTaggedObject(false, tag, DerSequence.FromVector(v));
  102. }
  103. public virtual IAsn1Convertible ReadObject()
  104. {
  105. int tag = _in.ReadByte();
  106. if (tag == -1)
  107. return null;
  108. // turn of looking for "00" while we resolve the tag
  109. Set00Check(false);
  110. //
  111. // calculate tag number
  112. //
  113. int tagNo = Asn1InputStream.ReadTagNumber(_in, tag);
  114. bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
  115. //
  116. // calculate length
  117. //
  118. int length = Asn1InputStream.ReadLength(_in, _limit,
  119. tagNo == Asn1Tags.OctetString || tagNo == Asn1Tags.Sequence || tagNo == Asn1Tags.Set || tagNo == Asn1Tags.External);
  120. if (length < 0) // indefinite-length method
  121. {
  122. if (!isConstructed)
  123. throw new IOException("indefinite-length primitive encoding encountered");
  124. IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
  125. Asn1StreamParser sp = new Asn1StreamParser(indIn, _limit, tmpBuffers);
  126. int tagClass = tag & Asn1Tags.Private;
  127. if (0 != tagClass)
  128. {
  129. if ((tag & Asn1Tags.Application) != 0)
  130. return new BerApplicationSpecificParser(tagNo, sp);
  131. return new BerTaggedObjectParser(true, tagNo, sp);
  132. }
  133. return sp.ReadIndef(tagNo);
  134. }
  135. else
  136. {
  137. DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length, _limit);
  138. int tagClass = tag & Asn1Tags.Private;
  139. if (0 != tagClass)
  140. {
  141. if ((tag & Asn1Tags.Application) != 0)
  142. return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
  143. return new BerTaggedObjectParser(isConstructed, tagNo,
  144. new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers));
  145. }
  146. if (!isConstructed)
  147. {
  148. // Some primitive encodings can be handled by parsers too...
  149. switch (tagNo)
  150. {
  151. case Asn1Tags.OctetString:
  152. return new DerOctetStringParser(defIn);
  153. }
  154. try
  155. {
  156. return Asn1InputStream.CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
  157. }
  158. catch (ArgumentException e)
  159. {
  160. throw new Asn1Exception("corrupted stream detected", e);
  161. }
  162. }
  163. Asn1StreamParser sp = new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers);
  164. // TODO There are other tags that may be constructed (e.g. BitString)
  165. switch (tagNo)
  166. {
  167. case Asn1Tags.OctetString:
  168. //
  169. // yes, people actually do this...
  170. //
  171. return new BerOctetStringParser(sp);
  172. case Asn1Tags.Sequence:
  173. return new DerSequenceParser(sp);
  174. case Asn1Tags.Set:
  175. return new DerSetParser(sp);
  176. case Asn1Tags.External:
  177. return new DerExternalParser(sp);
  178. default:
  179. throw new IOException("unknown tag " + tagNo + " encountered");
  180. }
  181. }
  182. }
  183. private void Set00Check(
  184. bool enabled)
  185. {
  186. if (_in is IndefiniteLengthInputStream)
  187. {
  188. ((IndefiniteLengthInputStream) _in).SetEofOn00(enabled);
  189. }
  190. }
  191. internal Asn1EncodableVector ReadVector()
  192. {
  193. IAsn1Convertible obj = ReadObject();
  194. if (null == obj)
  195. return new Asn1EncodableVector(0);
  196. Asn1EncodableVector v = new Asn1EncodableVector();
  197. do
  198. {
  199. v.Add(obj.ToAsn1Object());
  200. }
  201. while ((obj = ReadObject()) != null);
  202. return v;
  203. }
  204. }
  205. }
  206. #pragma warning restore
  207. #endif