Asn1Set.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections;
  5. using System.Diagnostics;
  6. using System.IO;
  7. #if PORTABLE || NETFX_CORE
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. #endif
  11. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  12. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Collections;
  13. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1
  14. {
  15. abstract public class Asn1Set
  16. : Asn1Object, IEnumerable
  17. {
  18. // NOTE: Only non-readonly to support LazyDerSet
  19. internal Asn1Encodable[] elements;
  20. /**
  21. * return an ASN1Set from the given object.
  22. *
  23. * @param obj the object we want converted.
  24. * @exception ArgumentException if the object cannot be converted.
  25. */
  26. public static Asn1Set GetInstance(
  27. object obj)
  28. {
  29. if (obj == null || obj is Asn1Set)
  30. {
  31. return (Asn1Set)obj;
  32. }
  33. else if (obj is Asn1SetParser)
  34. {
  35. return Asn1Set.GetInstance(((Asn1SetParser)obj).ToAsn1Object());
  36. }
  37. else if (obj is byte[])
  38. {
  39. try
  40. {
  41. return Asn1Set.GetInstance(FromByteArray((byte[])obj));
  42. }
  43. catch (IOException e)
  44. {
  45. throw new ArgumentException("failed to construct set from byte[]: " + e.Message);
  46. }
  47. }
  48. else if (obj is Asn1Encodable)
  49. {
  50. Asn1Object primitive = ((Asn1Encodable)obj).ToAsn1Object();
  51. if (primitive is Asn1Set)
  52. {
  53. return (Asn1Set)primitive;
  54. }
  55. }
  56. throw new ArgumentException("Unknown object in GetInstance: " + BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.GetTypeName(obj), "obj");
  57. }
  58. /**
  59. * Return an ASN1 set from a tagged object. There is a special
  60. * case here, if an object appears to have been explicitly tagged on
  61. * reading but we were expecting it to be implicitly tagged in the
  62. * normal course of events it indicates that we lost the surrounding
  63. * set - so we need to add it back (this will happen if the tagged
  64. * object is a sequence that contains other sequences). If you are
  65. * dealing with implicitly tagged sets you really <b>should</b>
  66. * be using this method.
  67. *
  68. * @param obj the tagged object.
  69. * @param explicitly true if the object is meant to be explicitly tagged
  70. * false otherwise.
  71. * @exception ArgumentException if the tagged object cannot
  72. * be converted.
  73. */
  74. public static Asn1Set GetInstance(
  75. Asn1TaggedObject obj,
  76. bool explicitly)
  77. {
  78. Asn1Object inner = obj.GetObject();
  79. if (explicitly)
  80. {
  81. if (!obj.IsExplicit())
  82. throw new ArgumentException("object implicit - explicit expected.");
  83. return (Asn1Set) inner;
  84. }
  85. //
  86. // constructed object which appears to be explicitly tagged
  87. // and it's really implicit means we have to add the
  88. // surrounding sequence.
  89. //
  90. if (obj.IsExplicit())
  91. {
  92. return new DerSet(inner);
  93. }
  94. if (inner is Asn1Set)
  95. {
  96. return (Asn1Set) inner;
  97. }
  98. //
  99. // in this case the parser returns a sequence, convert it
  100. // into a set.
  101. //
  102. if (inner is Asn1Sequence)
  103. {
  104. Asn1EncodableVector v = new Asn1EncodableVector();
  105. Asn1Sequence s = (Asn1Sequence) inner;
  106. foreach (Asn1Encodable ae in s)
  107. {
  108. v.Add(ae);
  109. }
  110. // TODO Should be able to construct set directly from sequence?
  111. return new DerSet(v, false);
  112. }
  113. throw new ArgumentException("Unknown object in GetInstance: " + BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.GetTypeName(obj), "obj");
  114. }
  115. protected internal Asn1Set()
  116. {
  117. this.elements = Asn1EncodableVector.EmptyElements;
  118. }
  119. protected internal Asn1Set(Asn1Encodable element)
  120. {
  121. if (null == element)
  122. throw new ArgumentNullException("element");
  123. this.elements = new Asn1Encodable[]{ element };
  124. }
  125. protected internal Asn1Set(params Asn1Encodable[] elements)
  126. {
  127. if (Arrays.IsNullOrContainsNull(elements))
  128. throw new NullReferenceException("'elements' cannot be null, or contain null");
  129. this.elements = Asn1EncodableVector.CloneElements(elements);
  130. }
  131. protected internal Asn1Set(Asn1EncodableVector elementVector)
  132. {
  133. if (null == elementVector)
  134. throw new ArgumentNullException("elementVector");
  135. this.elements = elementVector.TakeElements();
  136. }
  137. public virtual IEnumerator GetEnumerator()
  138. {
  139. return elements.GetEnumerator();
  140. }
  141. /**
  142. * return the object at the set position indicated by index.
  143. *
  144. * @param index the set number (starting at zero) of the object
  145. * @return the object at the set position indicated by index.
  146. */
  147. public virtual Asn1Encodable this[int index]
  148. {
  149. get { return elements[index]; }
  150. }
  151. public virtual int Count
  152. {
  153. get { return elements.Length; }
  154. }
  155. public virtual Asn1Encodable[] ToArray()
  156. {
  157. return Asn1EncodableVector.CloneElements(elements);
  158. }
  159. private class Asn1SetParserImpl
  160. : Asn1SetParser
  161. {
  162. private readonly Asn1Set outer;
  163. private readonly int max;
  164. private int index;
  165. public Asn1SetParserImpl(
  166. Asn1Set outer)
  167. {
  168. this.outer = outer;
  169. this.max = outer.Count;
  170. }
  171. public IAsn1Convertible ReadObject()
  172. {
  173. if (index == max)
  174. return null;
  175. Asn1Encodable obj = outer[index++];
  176. if (obj is Asn1Sequence)
  177. return ((Asn1Sequence)obj).Parser;
  178. if (obj is Asn1Set)
  179. return ((Asn1Set)obj).Parser;
  180. // NB: Asn1OctetString implements Asn1OctetStringParser directly
  181. // if (obj is Asn1OctetString)
  182. // return ((Asn1OctetString)obj).Parser;
  183. return obj;
  184. }
  185. public virtual Asn1Object ToAsn1Object()
  186. {
  187. return outer;
  188. }
  189. }
  190. public Asn1SetParser Parser
  191. {
  192. get { return new Asn1SetParserImpl(this); }
  193. }
  194. protected override int Asn1GetHashCode()
  195. {
  196. //return Arrays.GetHashCode(elements);
  197. int i = elements.Length;
  198. int hc = i + 1;
  199. while (--i >= 0)
  200. {
  201. hc *= 257;
  202. hc ^= elements[i].ToAsn1Object().CallAsn1GetHashCode();
  203. }
  204. return hc;
  205. }
  206. protected override bool Asn1Equals(Asn1Object asn1Object)
  207. {
  208. Asn1Set that = asn1Object as Asn1Set;
  209. if (null == that)
  210. return false;
  211. int count = this.Count;
  212. if (that.Count != count)
  213. return false;
  214. for (int i = 0; i < count; ++i)
  215. {
  216. Asn1Object o1 = this.elements[i].ToAsn1Object();
  217. Asn1Object o2 = that.elements[i].ToAsn1Object();
  218. if (o1 != o2 && !o1.CallAsn1Equals(o2))
  219. return false;
  220. }
  221. return true;
  222. }
  223. protected internal void Sort()
  224. {
  225. if (elements.Length < 2)
  226. return;
  227. #if PORTABLE || NETFX_CORE
  228. this.elements = elements
  229. .Cast<Asn1Encodable>()
  230. .Select(a => new { Item = a, Key = a.GetEncoded(Asn1Encodable.Der) })
  231. .OrderBy(t => t.Key, new DerComparer())
  232. .Select(t => t.Item)
  233. .ToArray();
  234. #else
  235. int count = elements.Length;
  236. byte[][] keys = new byte[count][];
  237. for (int i = 0; i < count; ++i)
  238. {
  239. keys[i] = elements[i].GetEncoded(Der);
  240. }
  241. Array.Sort(keys, elements, new DerComparer());
  242. #endif
  243. }
  244. public override string ToString()
  245. {
  246. return CollectionUtilities.ToString(elements);
  247. }
  248. #if PORTABLE || NETFX_CORE
  249. private class DerComparer
  250. : IComparer<byte[]>
  251. {
  252. public int Compare(byte[] x, byte[] y)
  253. {
  254. byte[] a = x, b = y;
  255. #else
  256. private class DerComparer
  257. : IComparer
  258. {
  259. public int Compare(object x, object y)
  260. {
  261. byte[] a = (byte[])x, b = (byte[])y;
  262. #endif
  263. Debug.Assert(a.Length >= 2 && b.Length >= 2);
  264. /*
  265. * NOTE: Set elements in DER encodings are ordered first according to their tags (class and
  266. * number); the CONSTRUCTED bit is not part of the tag.
  267. *
  268. * For SET-OF, this is unimportant. All elements have the same tag and DER requires them to
  269. * either all be in constructed form or all in primitive form, according to that tag. The
  270. * elements are effectively ordered according to their content octets.
  271. *
  272. * For SET, the elements will have distinct tags, and each will be in constructed or
  273. * primitive form accordingly. Failing to ignore the CONSTRUCTED bit could therefore lead to
  274. * ordering inversions.
  275. */
  276. int a0 = a[0] & ~Asn1Tags.Constructed;
  277. int b0 = b[0] & ~Asn1Tags.Constructed;
  278. if (a0 != b0)
  279. return a0 < b0 ? -1 : 1;
  280. int len = System.Math.Min(a.Length, b.Length);
  281. for (int i = 1; i < len; ++i)
  282. {
  283. byte ai = a[i], bi = b[i];
  284. if (ai != bi)
  285. return ai < bi ? -1 : 1;
  286. }
  287. Debug.Assert(a.Length == b.Length);
  288. return 0;
  289. }
  290. }
  291. }
  292. }
  293. #pragma warning restore
  294. #endif