DerObjectIdentifier.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  9. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1
  10. {
  11. public class DerObjectIdentifier
  12. : Asn1Object
  13. {
  14. public static DerObjectIdentifier FromContents(byte[] contents)
  15. {
  16. return CreatePrimitive(contents, true);
  17. }
  18. private readonly string identifier;
  19. private byte[] contents;
  20. /**
  21. * return an Oid from the passed in object
  22. *
  23. * @exception ArgumentException if the object cannot be converted.
  24. */
  25. public static DerObjectIdentifier GetInstance(object obj)
  26. {
  27. if (obj == null || obj is DerObjectIdentifier)
  28. return (DerObjectIdentifier) obj;
  29. if (obj is Asn1Encodable)
  30. {
  31. Asn1Object asn1Obj = ((Asn1Encodable)obj).ToAsn1Object();
  32. if (asn1Obj is DerObjectIdentifier)
  33. return (DerObjectIdentifier)asn1Obj;
  34. }
  35. if (obj is byte[])
  36. return (DerObjectIdentifier)FromByteArray((byte[])obj);
  37. throw new ArgumentException("illegal object in GetInstance: " + BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.GetTypeName(obj), "obj");
  38. }
  39. /**
  40. * return an object Identifier from a tagged object.
  41. *
  42. * @param obj the tagged object holding the object we want
  43. * @param explicitly true if the object is meant to be explicitly
  44. * tagged false otherwise.
  45. * @exception ArgumentException if the tagged object cannot
  46. * be converted.
  47. */
  48. public static DerObjectIdentifier GetInstance(
  49. Asn1TaggedObject obj,
  50. bool explicitly)
  51. {
  52. Asn1Object o = obj.GetObject();
  53. if (explicitly || o is DerObjectIdentifier)
  54. {
  55. return GetInstance(o);
  56. }
  57. return FromContents(Asn1OctetString.GetInstance(o).GetOctets());
  58. }
  59. public DerObjectIdentifier(
  60. string identifier)
  61. {
  62. if (identifier == null)
  63. throw new ArgumentNullException("identifier");
  64. if (!IsValidIdentifier(identifier))
  65. throw new FormatException("string " + identifier + " not an OID");
  66. this.identifier = identifier;
  67. }
  68. internal DerObjectIdentifier(DerObjectIdentifier oid, string branchID)
  69. {
  70. if (!IsValidBranchID(branchID, 0))
  71. throw new ArgumentException("string " + branchID + " not a valid OID branch", "branchID");
  72. this.identifier = oid.Id + "." + branchID;
  73. }
  74. // TODO Change to ID?
  75. public string Id
  76. {
  77. get { return identifier; }
  78. }
  79. public virtual DerObjectIdentifier Branch(string branchID)
  80. {
  81. return new DerObjectIdentifier(this, branchID);
  82. }
  83. /**
  84. * Return true if this oid is an extension of the passed in branch, stem.
  85. * @param stem the arc or branch that is a possible parent.
  86. * @return true if the branch is on the passed in stem, false otherwise.
  87. */
  88. public virtual bool On(DerObjectIdentifier stem)
  89. {
  90. string id = Id, stemId = stem.Id;
  91. return id.Length > stemId.Length && id[stemId.Length] == '.' && BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.StartsWith(id, stemId);
  92. }
  93. internal DerObjectIdentifier(byte[] contents, bool clone)
  94. {
  95. this.identifier = MakeOidStringFromBytes(contents);
  96. this.contents = clone ? Arrays.Clone(contents) : contents;
  97. }
  98. private void WriteField(
  99. Stream outputStream,
  100. long fieldValue)
  101. {
  102. byte[] result = new byte[9];
  103. int pos = 8;
  104. result[pos] = (byte)(fieldValue & 0x7f);
  105. while (fieldValue >= (1L << 7))
  106. {
  107. fieldValue >>= 7;
  108. result[--pos] = (byte)((fieldValue & 0x7f) | 0x80);
  109. }
  110. outputStream.Write(result, pos, 9 - pos);
  111. }
  112. private void WriteField(
  113. Stream outputStream,
  114. BigInteger fieldValue)
  115. {
  116. int byteCount = (fieldValue.BitLength + 6) / 7;
  117. if (byteCount == 0)
  118. {
  119. outputStream.WriteByte(0);
  120. }
  121. else
  122. {
  123. BigInteger tmpValue = fieldValue;
  124. byte[] tmp = new byte[byteCount];
  125. for (int i = byteCount-1; i >= 0; i--)
  126. {
  127. tmp[i] = (byte) ((tmpValue.IntValue & 0x7f) | 0x80);
  128. tmpValue = tmpValue.ShiftRight(7);
  129. }
  130. tmp[byteCount-1] &= 0x7f;
  131. outputStream.Write(tmp, 0, tmp.Length);
  132. }
  133. }
  134. private void DoOutput(MemoryStream bOut)
  135. {
  136. OidTokenizer tok = new OidTokenizer(identifier);
  137. string token = tok.NextToken();
  138. int first = int.Parse(token) * 40;
  139. token = tok.NextToken();
  140. if (token.Length <= 18)
  141. {
  142. WriteField(bOut, first + Int64.Parse(token));
  143. }
  144. else
  145. {
  146. WriteField(bOut, new BigInteger(token).Add(BigInteger.ValueOf(first)));
  147. }
  148. while (tok.HasMoreTokens)
  149. {
  150. token = tok.NextToken();
  151. if (token.Length <= 18)
  152. {
  153. WriteField(bOut, Int64.Parse(token));
  154. }
  155. else
  156. {
  157. WriteField(bOut, new BigInteger(token));
  158. }
  159. }
  160. }
  161. private byte[] GetContents()
  162. {
  163. lock (this)
  164. {
  165. if (contents == null)
  166. {
  167. MemoryStream bOut = new MemoryStream();
  168. DoOutput(bOut);
  169. contents = bOut.ToArray();
  170. }
  171. return contents;
  172. }
  173. }
  174. internal override int EncodedLength(bool withID)
  175. {
  176. return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContents().Length);
  177. }
  178. internal override void Encode(Asn1OutputStream asn1Out, bool withID)
  179. {
  180. asn1Out.WriteEncodingDL(withID, Asn1Tags.ObjectIdentifier, GetContents());
  181. }
  182. protected override int Asn1GetHashCode()
  183. {
  184. return identifier.GetHashCode();
  185. }
  186. protected override bool Asn1Equals(
  187. Asn1Object asn1Object)
  188. {
  189. DerObjectIdentifier other = asn1Object as DerObjectIdentifier;
  190. if (other == null)
  191. return false;
  192. return this.identifier.Equals(other.identifier);
  193. }
  194. public override string ToString()
  195. {
  196. return identifier;
  197. }
  198. private static bool IsValidBranchID(string branchID, int start)
  199. {
  200. int digitCount = 0;
  201. int pos = branchID.Length;
  202. while (--pos >= start)
  203. {
  204. char ch = branchID[pos];
  205. if (ch == '.')
  206. {
  207. if (0 == digitCount || (digitCount > 1 && branchID[pos + 1] == '0'))
  208. return false;
  209. digitCount = 0;
  210. }
  211. else if ('0' <= ch && ch <= '9')
  212. {
  213. ++digitCount;
  214. }
  215. else
  216. {
  217. return false;
  218. }
  219. }
  220. if (0 == digitCount || (digitCount > 1 && branchID[pos + 1] == '0'))
  221. return false;
  222. return true;
  223. }
  224. private static bool IsValidIdentifier(string identifier)
  225. {
  226. if (identifier.Length < 3 || identifier[1] != '.')
  227. return false;
  228. char first = identifier[0];
  229. if (first < '0' || first > '2')
  230. return false;
  231. return IsValidBranchID(identifier, 2);
  232. }
  233. private const long LONG_LIMIT = (long.MaxValue >> 7) - 0x7f;
  234. private static string MakeOidStringFromBytes(
  235. byte[] bytes)
  236. {
  237. StringBuilder objId = new StringBuilder();
  238. long value = 0;
  239. BigInteger bigValue = null;
  240. bool first = true;
  241. for (int i = 0; i != bytes.Length; i++)
  242. {
  243. int b = bytes[i];
  244. if (value <= LONG_LIMIT)
  245. {
  246. value += (b & 0x7f);
  247. if ((b & 0x80) == 0) // end of number reached
  248. {
  249. if (first)
  250. {
  251. if (value < 40)
  252. {
  253. objId.Append('0');
  254. }
  255. else if (value < 80)
  256. {
  257. objId.Append('1');
  258. value -= 40;
  259. }
  260. else
  261. {
  262. objId.Append('2');
  263. value -= 80;
  264. }
  265. first = false;
  266. }
  267. objId.Append('.');
  268. objId.Append(value);
  269. value = 0;
  270. }
  271. else
  272. {
  273. value <<= 7;
  274. }
  275. }
  276. else
  277. {
  278. if (bigValue == null)
  279. {
  280. bigValue = BigInteger.ValueOf(value);
  281. }
  282. bigValue = bigValue.Or(BigInteger.ValueOf(b & 0x7f));
  283. if ((b & 0x80) == 0)
  284. {
  285. if (first)
  286. {
  287. objId.Append('2');
  288. bigValue = bigValue.Subtract(BigInteger.ValueOf(80));
  289. first = false;
  290. }
  291. objId.Append('.');
  292. objId.Append(bigValue);
  293. bigValue = null;
  294. value = 0;
  295. }
  296. else
  297. {
  298. bigValue = bigValue.ShiftLeft(7);
  299. }
  300. }
  301. }
  302. return objId.ToString();
  303. }
  304. private static readonly DerObjectIdentifier[] cache = new DerObjectIdentifier[1024];
  305. internal static DerObjectIdentifier CreatePrimitive(byte[] contents, bool clone)
  306. {
  307. int hashCode = Arrays.GetHashCode(contents);
  308. int first = hashCode & 1023;
  309. lock (cache)
  310. {
  311. DerObjectIdentifier entry = cache[first];
  312. if (entry != null && Arrays.AreEqual(contents, entry.GetContents()))
  313. {
  314. return entry;
  315. }
  316. return cache[first] = new DerObjectIdentifier(contents, clone);
  317. }
  318. }
  319. }
  320. }
  321. #pragma warning restore
  322. #endif