DerApplicationSpecific.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  6. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1
  7. {
  8. /**
  9. * Base class for an application specific object
  10. */
  11. public class DerApplicationSpecific
  12. : Asn1Object
  13. {
  14. private readonly bool isConstructed;
  15. private readonly int tag;
  16. private readonly byte[] octets;
  17. internal DerApplicationSpecific(
  18. bool isConstructed,
  19. int tag,
  20. byte[] octets)
  21. {
  22. this.isConstructed = isConstructed;
  23. this.tag = tag;
  24. this.octets = octets;
  25. }
  26. public DerApplicationSpecific(
  27. int tag,
  28. byte[] octets)
  29. : this(false, tag, octets)
  30. {
  31. }
  32. public DerApplicationSpecific(
  33. int tag,
  34. Asn1Encodable obj)
  35. : this(true, tag, obj)
  36. {
  37. }
  38. public DerApplicationSpecific(
  39. bool isExplicit,
  40. int tag,
  41. Asn1Encodable obj)
  42. {
  43. Asn1Object asn1Obj = obj.ToAsn1Object();
  44. byte[] data = asn1Obj.GetDerEncoded();
  45. this.isConstructed = Asn1TaggedObject.IsConstructed(isExplicit, asn1Obj);
  46. this.tag = tag;
  47. if (isExplicit)
  48. {
  49. this.octets = data;
  50. }
  51. else
  52. {
  53. int lenBytes = GetLengthOfHeader(data);
  54. byte[] tmp = new byte[data.Length - lenBytes];
  55. Array.Copy(data, lenBytes, tmp, 0, tmp.Length);
  56. this.octets = tmp;
  57. }
  58. }
  59. public DerApplicationSpecific(
  60. int tagNo,
  61. Asn1EncodableVector vec)
  62. {
  63. this.tag = tagNo;
  64. this.isConstructed = true;
  65. MemoryStream bOut = new MemoryStream();
  66. for (int i = 0; i != vec.Count; i++)
  67. {
  68. try
  69. {
  70. byte[] bs = vec[i].GetDerEncoded();
  71. bOut.Write(bs, 0, bs.Length);
  72. }
  73. catch (IOException e)
  74. {
  75. throw new InvalidOperationException("malformed object", e);
  76. }
  77. }
  78. this.octets = bOut.ToArray();
  79. }
  80. private int GetLengthOfHeader(
  81. byte[] data)
  82. {
  83. int length = data[1]; // TODO: assumes 1 byte tag
  84. if (length == 0x80)
  85. {
  86. return 2; // indefinite-length encoding
  87. }
  88. if (length > 127)
  89. {
  90. int size = length & 0x7f;
  91. // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
  92. if (size > 4)
  93. {
  94. throw new InvalidOperationException("DER length more than 4 bytes: " + size);
  95. }
  96. return size + 2;
  97. }
  98. return 2;
  99. }
  100. public bool IsConstructed()
  101. {
  102. return isConstructed;
  103. }
  104. public byte[] GetContents()
  105. {
  106. return octets;
  107. }
  108. public int ApplicationTag
  109. {
  110. get { return tag; }
  111. }
  112. /**
  113. * Return the enclosed object assuming explicit tagging.
  114. *
  115. * @return the resulting object
  116. * @throws IOException if reconstruction fails.
  117. */
  118. public Asn1Object GetObject()
  119. {
  120. return FromByteArray(GetContents());
  121. }
  122. /**
  123. * Return the enclosed object assuming implicit tagging.
  124. *
  125. * @param derTagNo the type tag that should be applied to the object's contents.
  126. * @return the resulting object
  127. * @throws IOException if reconstruction fails.
  128. */
  129. public Asn1Object GetObject(
  130. int derTagNo)
  131. {
  132. if (derTagNo >= 0x1f)
  133. throw new IOException("unsupported tag number");
  134. byte[] orig = this.GetEncoded();
  135. byte[] tmp = ReplaceTagNumber(derTagNo, orig);
  136. if ((orig[0] & Asn1Tags.Constructed) != 0)
  137. {
  138. tmp[0] |= Asn1Tags.Constructed;
  139. }
  140. return FromByteArray(tmp);
  141. }
  142. internal override int EncodedLength(bool withID)
  143. {
  144. return Asn1OutputStream.GetLengthOfEncodingDL(withID, tag, octets.Length);
  145. }
  146. internal override void Encode(Asn1OutputStream asn1Out, bool withID)
  147. {
  148. int flags = Asn1Tags.Application;
  149. if (isConstructed)
  150. {
  151. flags |= Asn1Tags.Constructed;
  152. }
  153. asn1Out.WriteEncodingDL(withID, flags, tag, octets);
  154. }
  155. protected override bool Asn1Equals(
  156. Asn1Object asn1Object)
  157. {
  158. DerApplicationSpecific other = asn1Object as DerApplicationSpecific;
  159. if (other == null)
  160. return false;
  161. return this.isConstructed == other.isConstructed
  162. && this.tag == other.tag
  163. && Arrays.AreEqual(this.octets, other.octets);
  164. }
  165. protected override int Asn1GetHashCode()
  166. {
  167. return isConstructed.GetHashCode() ^ tag.GetHashCode() ^ Arrays.GetHashCode(octets);
  168. }
  169. private byte[] ReplaceTagNumber(
  170. int newTag,
  171. byte[] input)
  172. {
  173. int tagNo = input[0] & 0x1f;
  174. int index = 1;
  175. // with tagged object tag number is bottom 5 bits, or stored at the start of the content
  176. if (tagNo == 0x1f)
  177. {
  178. int b = input[index++];
  179. // X.690-0207 8.1.2.4.2
  180. // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
  181. if ((b & 0x7f) == 0) // Note: -1 will pass
  182. throw new IOException("corrupted stream - invalid high tag number found");
  183. while ((b & 0x80) != 0)
  184. {
  185. b = input[index++];
  186. }
  187. }
  188. int remaining = input.Length - index;
  189. byte[] tmp = new byte[1 + remaining];
  190. tmp[0] = (byte)newTag;
  191. Array.Copy(input, index, tmp, 1, remaining);
  192. return tmp;
  193. }
  194. }
  195. }
  196. #pragma warning restore
  197. #endif