GeneralName.cs 11 KB

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