GeneralName.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections;
  5. using System.Globalization;
  6. using System.IO;
  7. using System.Text;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  9. using NetUtils = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Net;
  10. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509
  11. {
  12. /**
  13. * The GeneralName object.
  14. * <pre>
  15. * GeneralName ::= CHOICE {
  16. * otherName [0] OtherName,
  17. * rfc822Name [1] IA5String,
  18. * dNSName [2] IA5String,
  19. * x400Address [3] ORAddress,
  20. * directoryName [4] Name,
  21. * ediPartyName [5] EDIPartyName,
  22. * uniformResourceIdentifier [6] IA5String,
  23. * iPAddress [7] OCTET STRING,
  24. * registeredID [8] OBJECT IDENTIFIER}
  25. *
  26. * OtherName ::= Sequence {
  27. * type-id OBJECT IDENTIFIER,
  28. * value [0] EXPLICIT ANY DEFINED BY type-id }
  29. *
  30. * EDIPartyName ::= Sequence {
  31. * nameAssigner [0] DirectoryString OPTIONAL,
  32. * partyName [1] DirectoryString }
  33. * </pre>
  34. */
  35. public class GeneralName
  36. : Asn1Encodable, IAsn1Choice
  37. {
  38. public const int OtherName = 0;
  39. public const int Rfc822Name = 1;
  40. public const int DnsName = 2;
  41. public const int X400Address = 3;
  42. public const int DirectoryName = 4;
  43. public const int EdiPartyName = 5;
  44. public const int UniformResourceIdentifier = 6;
  45. public const int IPAddress = 7;
  46. public const int RegisteredID = 8;
  47. internal readonly Asn1Encodable obj;
  48. internal readonly int tag;
  49. public GeneralName(
  50. X509Name directoryName)
  51. {
  52. this.obj = directoryName;
  53. this.tag = 4;
  54. }
  55. /**
  56. * When the subjectAltName extension contains an Internet mail address,
  57. * the address MUST be included as an rfc822Name. The format of an
  58. * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
  59. *
  60. * When the subjectAltName extension contains a domain name service
  61. * label, the domain name MUST be stored in the dNSName (an IA5String).
  62. * The name MUST be in the "preferred name syntax," as specified by RFC
  63. * 1034 [RFC 1034].
  64. *
  65. * When the subjectAltName extension contains a URI, the name MUST be
  66. * stored in the uniformResourceIdentifier (an IA5String). The name MUST
  67. * be a non-relative URL, and MUST follow the URL syntax and encoding
  68. * rules specified in [RFC 1738]. The name must include both a scheme
  69. * (e.g., "http" or "ftp") and a scheme-specific-part. The scheme-
  70. * specific-part must include a fully qualified domain name or IP
  71. * address as the host.
  72. *
  73. * When the subjectAltName extension contains a iPAddress, the address
  74. * MUST be stored in the octet string in "network byte order," as
  75. * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
  76. * each octet is the LSB of the corresponding byte in the network
  77. * address. For IP Version 4, as specified in RFC 791, the octet string
  78. * MUST contain exactly four octets. For IP Version 6, as specified in
  79. * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
  80. * 1883].
  81. */
  82. public GeneralName(
  83. Asn1Object name,
  84. int tag)
  85. {
  86. this.obj = name;
  87. this.tag = tag;
  88. }
  89. public GeneralName(
  90. int tag,
  91. Asn1Encodable name)
  92. {
  93. this.obj = name;
  94. this.tag = tag;
  95. }
  96. /**
  97. * Create a GeneralName for the given tag from the passed in string.
  98. * <p>
  99. * This constructor can handle:
  100. * <ul>
  101. * <li>rfc822Name</li>
  102. * <li>iPAddress</li>
  103. * <li>directoryName</li>
  104. * <li>dNSName</li>
  105. * <li>uniformResourceIdentifier</li>
  106. * <li>registeredID</li>
  107. * </ul>
  108. * For x400Address, otherName and ediPartyName there is no common string
  109. * format defined.
  110. * </p><p>
  111. * Note: A directory name can be encoded in different ways into a byte
  112. * representation. Be aware of this if the byte representation is used for
  113. * comparing results.
  114. * </p>
  115. *
  116. * @param tag tag number
  117. * @param name string representation of name
  118. * @throws ArgumentException if the string encoding is not correct or
  119. * not supported.
  120. */
  121. public GeneralName(
  122. int tag,
  123. string name)
  124. {
  125. this.tag = tag;
  126. if (tag == Rfc822Name || tag == DnsName || tag == UniformResourceIdentifier)
  127. {
  128. this.obj = new DerIA5String(name);
  129. }
  130. else if (tag == RegisteredID)
  131. {
  132. this.obj = new DerObjectIdentifier(name);
  133. }
  134. else if (tag == DirectoryName)
  135. {
  136. this.obj = new X509Name(name);
  137. }
  138. else if (tag == IPAddress)
  139. {
  140. byte[] enc = toGeneralNameEncoding(name);
  141. if (enc == null)
  142. throw new ArgumentException("IP Address is invalid", "name");
  143. this.obj = new DerOctetString(enc);
  144. }
  145. else
  146. {
  147. throw new ArgumentException("can't process string for tag: " + tag, "tag");
  148. }
  149. }
  150. public static GeneralName GetInstance(
  151. object obj)
  152. {
  153. if (obj == null || obj is GeneralName)
  154. {
  155. return (GeneralName) obj;
  156. }
  157. if (obj is Asn1TaggedObject)
  158. {
  159. Asn1TaggedObject tagObj = (Asn1TaggedObject) obj;
  160. int tag = tagObj.TagNo;
  161. switch (tag)
  162. {
  163. case OtherName:
  164. return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
  165. case Rfc822Name:
  166. return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
  167. case DnsName:
  168. return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
  169. case X400Address:
  170. throw new ArgumentException("unknown tag: " + tag);
  171. case DirectoryName:
  172. return new GeneralName(tag, X509Name.GetInstance(tagObj, true));
  173. case EdiPartyName:
  174. return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
  175. case UniformResourceIdentifier:
  176. return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
  177. case IPAddress:
  178. return new GeneralName(tag, Asn1OctetString.GetInstance(tagObj, false));
  179. case RegisteredID:
  180. return new GeneralName(tag, DerObjectIdentifier.GetInstance(tagObj, false));
  181. }
  182. }
  183. if (obj is byte[])
  184. {
  185. try
  186. {
  187. return GetInstance(Asn1Object.FromByteArray((byte[])obj));
  188. }
  189. catch (IOException)
  190. {
  191. throw new ArgumentException("unable to parse encoded general name");
  192. }
  193. }
  194. throw new ArgumentException("unknown object in GetInstance: " + BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.GetTypeName(obj), "obj");
  195. }
  196. public static GeneralName GetInstance(
  197. Asn1TaggedObject tagObj,
  198. bool explicitly)
  199. {
  200. return GetInstance(Asn1TaggedObject.GetInstance(tagObj, true));
  201. }
  202. public int TagNo
  203. {
  204. get { return tag; }
  205. }
  206. public Asn1Encodable Name
  207. {
  208. get { return obj; }
  209. }
  210. public override string ToString()
  211. {
  212. StringBuilder buf = new StringBuilder();
  213. buf.Append(tag);
  214. buf.Append(": ");
  215. switch (tag)
  216. {
  217. case Rfc822Name:
  218. case DnsName:
  219. case UniformResourceIdentifier:
  220. buf.Append(DerIA5String.GetInstance(obj).GetString());
  221. break;
  222. case DirectoryName:
  223. buf.Append(X509Name.GetInstance(obj).ToString());
  224. break;
  225. default:
  226. buf.Append(obj.ToString());
  227. break;
  228. }
  229. return buf.ToString();
  230. }
  231. private byte[] toGeneralNameEncoding(
  232. string ip)
  233. {
  234. if (NetUtils.IPAddress.IsValidIPv6WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv6(ip))
  235. {
  236. int slashIndex = ip.IndexOf('/');
  237. if (slashIndex < 0)
  238. {
  239. byte[] addr = new byte[16];
  240. int[] parsedIp = parseIPv6(ip);
  241. copyInts(parsedIp, addr, 0);
  242. return addr;
  243. }
  244. else
  245. {
  246. byte[] addr = new byte[32];
  247. int[] parsedIp = parseIPv6(ip.Substring(0, slashIndex));
  248. copyInts(parsedIp, addr, 0);
  249. string mask = ip.Substring(slashIndex + 1);
  250. if (mask.IndexOf(':') > 0)
  251. {
  252. parsedIp = parseIPv6(mask);
  253. }
  254. else
  255. {
  256. parsedIp = parseMask(mask);
  257. }
  258. copyInts(parsedIp, addr, 16);
  259. return addr;
  260. }
  261. }
  262. else if (NetUtils.IPAddress.IsValidIPv4WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv4(ip))
  263. {
  264. int slashIndex = ip.IndexOf('/');
  265. if (slashIndex < 0)
  266. {
  267. byte[] addr = new byte[4];
  268. parseIPv4(ip, addr, 0);
  269. return addr;
  270. }
  271. else
  272. {
  273. byte[] addr = new byte[8];
  274. parseIPv4(ip.Substring(0, slashIndex), addr, 0);
  275. string mask = ip.Substring(slashIndex + 1);
  276. if (mask.IndexOf('.') > 0)
  277. {
  278. parseIPv4(mask, addr, 4);
  279. }
  280. else
  281. {
  282. parseIPv4Mask(mask, addr, 4);
  283. }
  284. return addr;
  285. }
  286. }
  287. return null;
  288. }
  289. private void parseIPv4Mask(string mask, byte[] addr, int offset)
  290. {
  291. int maskVal = Int32.Parse(mask);
  292. for (int i = 0; i != maskVal; i++)
  293. {
  294. addr[(i / 8) + offset] |= (byte)(1 << (i % 8));
  295. }
  296. }
  297. private void parseIPv4(string ip, byte[] addr, int offset)
  298. {
  299. foreach (string token in ip.Split('.', '/'))
  300. {
  301. addr[offset++] = (byte)Int32.Parse(token);
  302. }
  303. }
  304. private int[] parseMask(string mask)
  305. {
  306. int[] res = new int[8];
  307. int maskVal = Int32.Parse(mask);
  308. for (int i = 0; i != maskVal; i++)
  309. {
  310. res[i / 16] |= 1 << (i % 16);
  311. }
  312. return res;
  313. }
  314. private void copyInts(int[] parsedIp, byte[] addr, int offSet)
  315. {
  316. for (int i = 0; i != parsedIp.Length; i++)
  317. {
  318. addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8);
  319. addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i];
  320. }
  321. }
  322. private int[] parseIPv6(string ip)
  323. {
  324. if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.StartsWith(ip, "::"))
  325. {
  326. ip = ip.Substring(1);
  327. }
  328. else if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.EndsWith(ip, "::"))
  329. {
  330. ip = ip.Substring(0, ip.Length - 1);
  331. }
  332. IEnumerator sEnum = ip.Split(':').GetEnumerator();
  333. int index = 0;
  334. int[] val = new int[8];
  335. int doubleColon = -1;
  336. while (sEnum.MoveNext())
  337. {
  338. string e = (string) sEnum.Current;
  339. if (e.Length == 0)
  340. {
  341. doubleColon = index;
  342. val[index++] = 0;
  343. }
  344. else
  345. {
  346. if (e.IndexOf('.') < 0)
  347. {
  348. val[index++] = Int32.Parse(e, NumberStyles.AllowHexSpecifier);
  349. }
  350. else
  351. {
  352. string[] tokens = e.Split('.');
  353. val[index++] = (Int32.Parse(tokens[0]) << 8) | Int32.Parse(tokens[1]);
  354. val[index++] = (Int32.Parse(tokens[2]) << 8) | Int32.Parse(tokens[3]);
  355. }
  356. }
  357. }
  358. if (index != val.Length)
  359. {
  360. Array.Copy(val, doubleColon, val, val.Length - (index - doubleColon), index - doubleColon);
  361. for (int i = doubleColon; i != val.Length - (index - doubleColon); i++)
  362. {
  363. val[i] = 0;
  364. }
  365. }
  366. return val;
  367. }
  368. public override Asn1Object ToAsn1Object()
  369. {
  370. // Explicitly tagged if DirectoryName
  371. return new DerTaggedObject(tag == DirectoryName, tag, obj);
  372. }
  373. }
  374. }
  375. #pragma warning restore
  376. #endif