ASN1StreamParser.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. namespace Best.HTTP.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. public virtual IAsn1Convertible ReadObject()
  33. {
  34. int tagHdr = _in.ReadByte();
  35. if (tagHdr < 0)
  36. return null;
  37. return ImplParseObject(tagHdr);
  38. }
  39. internal IAsn1Convertible ImplParseObject(int tagHdr)
  40. {
  41. // turn off looking for "00" while we resolve the tag
  42. Set00Check(false);
  43. //
  44. // calculate tag number
  45. //
  46. int tagNo = Asn1InputStream.ReadTagNumber(_in, tagHdr);
  47. //
  48. // calculate length
  49. //
  50. int length = Asn1InputStream.ReadLength(_in, _limit,
  51. tagNo == Asn1Tags.BitString || tagNo == Asn1Tags.OctetString || tagNo == Asn1Tags.Sequence ||
  52. tagNo == Asn1Tags.Set || tagNo == Asn1Tags.External);
  53. if (length < 0) // indefinite-length method
  54. {
  55. if (0 == (tagHdr & Asn1Tags.Constructed))
  56. throw new IOException("indefinite-length primitive encoding encountered");
  57. IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
  58. Asn1StreamParser sp = new Asn1StreamParser(indIn, _limit, tmpBuffers);
  59. int tagClass = tagHdr & Asn1Tags.Private;
  60. if (0 != tagClass)
  61. return new BerTaggedObjectParser(tagClass, tagNo, sp);
  62. return sp.ParseImplicitConstructedIL(tagNo);
  63. }
  64. else
  65. {
  66. DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length, _limit);
  67. if (0 == (tagHdr & Asn1Tags.Flags))
  68. return ParseImplicitPrimitive(tagNo, defIn);
  69. Asn1StreamParser sp = new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers);
  70. int tagClass = tagHdr & Asn1Tags.Private;
  71. if (0 != tagClass)
  72. {
  73. bool isConstructed = (tagHdr & Asn1Tags.Constructed) != 0;
  74. return new DLTaggedObjectParser(tagClass, tagNo, isConstructed, sp);
  75. }
  76. return sp.ParseImplicitConstructedDL(tagNo);
  77. }
  78. }
  79. internal Asn1Object LoadTaggedDL(int tagClass, int tagNo, bool constructed)
  80. {
  81. if (!constructed)
  82. {
  83. byte[] contentsOctets = ((DefiniteLengthInputStream)_in).ToArray();
  84. return Asn1TaggedObject.CreatePrimitive(tagClass, tagNo, contentsOctets);
  85. }
  86. Asn1EncodableVector contentsElements = ReadVector();
  87. return Asn1TaggedObject.CreateConstructedDL(tagClass, tagNo, contentsElements);
  88. }
  89. internal Asn1Object LoadTaggedIL(int tagClass, int tagNo)
  90. {
  91. Asn1EncodableVector contentsElements = ReadVector();
  92. return Asn1TaggedObject.CreateConstructedIL(tagClass, tagNo, contentsElements);
  93. }
  94. internal IAsn1Convertible ParseImplicitConstructedDL(int univTagNo)
  95. {
  96. switch (univTagNo)
  97. {
  98. case Asn1Tags.BitString:
  99. // TODO[asn1] DLConstructedBitStringParser
  100. return new BerBitStringParser(this);
  101. case Asn1Tags.External:
  102. return new DerExternalParser(this);
  103. case Asn1Tags.OctetString:
  104. // TODO[asn1] DLConstructedOctetStringParser
  105. return new BerOctetStringParser(this);
  106. case Asn1Tags.Set:
  107. return new DerSetParser(this);
  108. case Asn1Tags.Sequence:
  109. return new DerSequenceParser(this);
  110. default:
  111. throw new Asn1Exception("unknown DL object encountered: 0x" + univTagNo.ToString("X"));
  112. }
  113. }
  114. internal IAsn1Convertible ParseImplicitConstructedIL(int univTagNo)
  115. {
  116. switch (univTagNo)
  117. {
  118. case Asn1Tags.BitString:
  119. return new BerBitStringParser(this);
  120. case Asn1Tags.External:
  121. // TODO[asn1] BERExternalParser
  122. return new DerExternalParser(this);
  123. case Asn1Tags.OctetString:
  124. return new BerOctetStringParser(this);
  125. case Asn1Tags.Sequence:
  126. return new BerSequenceParser(this);
  127. case Asn1Tags.Set:
  128. return new BerSetParser(this);
  129. default:
  130. throw new Asn1Exception("unknown BER object encountered: 0x" + univTagNo.ToString("X"));
  131. }
  132. }
  133. internal IAsn1Convertible ParseImplicitPrimitive(int univTagNo)
  134. {
  135. return ParseImplicitPrimitive(univTagNo, (DefiniteLengthInputStream)_in);
  136. }
  137. internal IAsn1Convertible ParseImplicitPrimitive(int univTagNo, DefiniteLengthInputStream defIn)
  138. {
  139. // Some primitive encodings can be handled by parsers too...
  140. switch (univTagNo)
  141. {
  142. case Asn1Tags.BitString:
  143. return new DLBitStringParser(defIn);
  144. case Asn1Tags.External:
  145. throw new Asn1Exception("externals must use constructed encoding (see X.690 8.18)");
  146. case Asn1Tags.OctetString:
  147. return new DerOctetStringParser(defIn);
  148. case Asn1Tags.Set:
  149. throw new Asn1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
  150. case Asn1Tags.Sequence:
  151. throw new Asn1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
  152. }
  153. try
  154. {
  155. return Asn1InputStream.CreatePrimitiveDerObject(univTagNo, defIn, tmpBuffers);
  156. }
  157. catch (ArgumentException e)
  158. {
  159. throw new Asn1Exception("corrupted stream detected", e);
  160. }
  161. }
  162. internal IAsn1Convertible ParseObject(int univTagNo)
  163. {
  164. if (univTagNo < 0 || univTagNo > 30)
  165. throw new ArgumentException("invalid universal tag number: " + univTagNo, "univTagNo");
  166. int tagHdr = _in.ReadByte();
  167. if (tagHdr < 0)
  168. return null;
  169. if ((tagHdr & ~Asn1Tags.Constructed) != univTagNo)
  170. throw new IOException("unexpected identifier encountered: " + tagHdr);
  171. return ImplParseObject(tagHdr);
  172. }
  173. internal Asn1TaggedObjectParser ParseTaggedObject()
  174. {
  175. int tagHdr = _in.ReadByte();
  176. if (tagHdr< 0)
  177. return null;
  178. int tagClass = tagHdr & Asn1Tags.Private;
  179. if (0 == tagClass)
  180. throw new Asn1Exception("no tagged object found");
  181. return (Asn1TaggedObjectParser)ImplParseObject(tagHdr);
  182. }
  183. // TODO[asn1] Prefer 'LoadVector'
  184. internal Asn1EncodableVector ReadVector()
  185. {
  186. int tagHdr = _in.ReadByte();
  187. if (tagHdr < 0)
  188. return new Asn1EncodableVector(0);
  189. Asn1EncodableVector v = new Asn1EncodableVector();
  190. do
  191. {
  192. IAsn1Convertible obj = ImplParseObject(tagHdr);
  193. v.Add(obj.ToAsn1Object());
  194. }
  195. while ((tagHdr = _in.ReadByte()) >= 0);
  196. return v;
  197. }
  198. private void Set00Check(bool enabled)
  199. {
  200. if (_in is IndefiniteLengthInputStream indef)
  201. {
  202. indef.SetEofOn00(enabled);
  203. }
  204. }
  205. }
  206. }
  207. #pragma warning restore
  208. #endif