GeneralName.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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 EdiPartyName:
  164. case OtherName:
  165. case X400Address:
  166. return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
  167. case DnsName:
  168. case Rfc822Name:
  169. case UniformResourceIdentifier:
  170. return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
  171. case DirectoryName:
  172. return new GeneralName(tag, X509Name.GetInstance(tagObj, true));
  173. case IPAddress:
  174. return new GeneralName(tag, Asn1OctetString.GetInstance(tagObj, false));
  175. case RegisteredID:
  176. return new GeneralName(tag, DerObjectIdentifier.GetInstance(tagObj, false));
  177. default:
  178. throw new ArgumentException("unknown tag: " + tag);
  179. }
  180. }
  181. if (obj is byte[])
  182. {
  183. try
  184. {
  185. return GetInstance(Asn1Object.FromByteArray((byte[])obj));
  186. }
  187. catch (IOException)
  188. {
  189. throw new ArgumentException("unable to parse encoded general name");
  190. }
  191. }
  192. throw new ArgumentException("unknown object in GetInstance: " + BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.GetTypeName(obj), "obj");
  193. }
  194. public static GeneralName GetInstance(
  195. Asn1TaggedObject tagObj,
  196. bool explicitly)
  197. {
  198. return GetInstance(Asn1TaggedObject.GetInstance(tagObj, true));
  199. }
  200. public int TagNo
  201. {
  202. get { return tag; }
  203. }
  204. public Asn1Encodable Name
  205. {
  206. get { return obj; }
  207. }
  208. public override string ToString()
  209. {
  210. StringBuilder buf = new StringBuilder();
  211. buf.Append(tag);
  212. buf.Append(": ");
  213. switch (tag)
  214. {
  215. case Rfc822Name:
  216. case DnsName:
  217. case UniformResourceIdentifier:
  218. buf.Append(DerIA5String.GetInstance(obj).GetString());
  219. break;
  220. case DirectoryName:
  221. buf.Append(X509Name.GetInstance(obj).ToString());
  222. break;
  223. default:
  224. buf.Append(obj.ToString());
  225. break;
  226. }
  227. return buf.ToString();
  228. }
  229. private byte[] toGeneralNameEncoding(
  230. string ip)
  231. {
  232. if (NetUtils.IPAddress.IsValidIPv6WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv6(ip))
  233. {
  234. int slashIndex = ip.IndexOf('/');
  235. if (slashIndex < 0)
  236. {
  237. byte[] addr = new byte[16];
  238. int[] parsedIp = parseIPv6(ip);
  239. copyInts(parsedIp, addr, 0);
  240. return addr;
  241. }
  242. else
  243. {
  244. byte[] addr = new byte[32];
  245. int[] parsedIp = parseIPv6(ip.Substring(0, slashIndex));
  246. copyInts(parsedIp, addr, 0);
  247. string mask = ip.Substring(slashIndex + 1);
  248. if (mask.IndexOf(':') > 0)
  249. {
  250. parsedIp = parseIPv6(mask);
  251. }
  252. else
  253. {
  254. parsedIp = parseMask(mask);
  255. }
  256. copyInts(parsedIp, addr, 16);
  257. return addr;
  258. }
  259. }
  260. else if (NetUtils.IPAddress.IsValidIPv4WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv4(ip))
  261. {
  262. int slashIndex = ip.IndexOf('/');
  263. if (slashIndex < 0)
  264. {
  265. byte[] addr = new byte[4];
  266. parseIPv4(ip, addr, 0);
  267. return addr;
  268. }
  269. else
  270. {
  271. byte[] addr = new byte[8];
  272. parseIPv4(ip.Substring(0, slashIndex), addr, 0);
  273. string mask = ip.Substring(slashIndex + 1);
  274. if (mask.IndexOf('.') > 0)
  275. {
  276. parseIPv4(mask, addr, 4);
  277. }
  278. else
  279. {
  280. parseIPv4Mask(mask, addr, 4);
  281. }
  282. return addr;
  283. }
  284. }
  285. return null;
  286. }
  287. private void parseIPv4Mask(string mask, byte[] addr, int offset)
  288. {
  289. int maskVal = Int32.Parse(mask);
  290. for (int i = 0; i != maskVal; i++)
  291. {
  292. addr[(i / 8) + offset] |= (byte)(1 << (i % 8));
  293. }
  294. }
  295. private void parseIPv4(string ip, byte[] addr, int offset)
  296. {
  297. foreach (string token in ip.Split('.', '/'))
  298. {
  299. addr[offset++] = (byte)Int32.Parse(token);
  300. }
  301. }
  302. private int[] parseMask(string mask)
  303. {
  304. int[] res = new int[8];
  305. int maskVal = Int32.Parse(mask);
  306. for (int i = 0; i != maskVal; i++)
  307. {
  308. res[i / 16] |= 1 << (i % 16);
  309. }
  310. return res;
  311. }
  312. private void copyInts(int[] parsedIp, byte[] addr, int offSet)
  313. {
  314. for (int i = 0; i != parsedIp.Length; i++)
  315. {
  316. addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8);
  317. addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i];
  318. }
  319. }
  320. private int[] parseIPv6(string ip)
  321. {
  322. if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.StartsWith(ip, "::"))
  323. {
  324. ip = ip.Substring(1);
  325. }
  326. else if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.EndsWith(ip, "::"))
  327. {
  328. ip = ip.Substring(0, ip.Length - 1);
  329. }
  330. IEnumerator sEnum = ip.Split(':').GetEnumerator();
  331. int index = 0;
  332. int[] val = new int[8];
  333. int doubleColon = -1;
  334. while (sEnum.MoveNext())
  335. {
  336. string e = (string) sEnum.Current;
  337. if (e.Length == 0)
  338. {
  339. doubleColon = index;
  340. val[index++] = 0;
  341. }
  342. else
  343. {
  344. if (e.IndexOf('.') < 0)
  345. {
  346. val[index++] = Int32.Parse(e, NumberStyles.AllowHexSpecifier);
  347. }
  348. else
  349. {
  350. string[] tokens = e.Split('.');
  351. val[index++] = (Int32.Parse(tokens[0]) << 8) | Int32.Parse(tokens[1]);
  352. val[index++] = (Int32.Parse(tokens[2]) << 8) | Int32.Parse(tokens[3]);
  353. }
  354. }
  355. }
  356. if (index != val.Length)
  357. {
  358. Array.Copy(val, doubleColon, val, val.Length - (index - doubleColon), index - doubleColon);
  359. for (int i = doubleColon; i != val.Length - (index - doubleColon); i++)
  360. {
  361. val[i] = 0;
  362. }
  363. }
  364. return val;
  365. }
  366. public override Asn1Object ToAsn1Object()
  367. {
  368. // directoryName is explicitly tagged as it is a CHOICE
  369. bool isExplicit = (tag == DirectoryName);
  370. return new DerTaggedObject(isExplicit, tag, obj);
  371. }
  372. }
  373. }
  374. #pragma warning restore
  375. #endif