123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- using System;
- using System.Collections;
- using System.Globalization;
- using System.IO;
- using System.Text;
- using Org.BouncyCastle.Utilities;
- using NetUtils = Org.BouncyCastle.Utilities.Net;
- namespace Org.BouncyCastle.Asn1.X509
- {
- /**
- * The GeneralName object.
- * <pre>
- * GeneralName ::= CHOICE {
- * otherName [0] OtherName,
- * rfc822Name [1] IA5String,
- * dNSName [2] IA5String,
- * x400Address [3] ORAddress,
- * directoryName [4] Name,
- * ediPartyName [5] EDIPartyName,
- * uniformResourceIdentifier [6] IA5String,
- * iPAddress [7] OCTET STRING,
- * registeredID [8] OBJECT IDENTIFIER}
- *
- * OtherName ::= Sequence {
- * type-id OBJECT IDENTIFIER,
- * value [0] EXPLICIT ANY DEFINED BY type-id }
- *
- * EDIPartyName ::= Sequence {
- * nameAssigner [0] DirectoryString OPTIONAL,
- * partyName [1] DirectoryString }
- * </pre>
- */
- public class GeneralName
- : Asn1Encodable, IAsn1Choice
- {
- public const int OtherName = 0;
- public const int Rfc822Name = 1;
- public const int DnsName = 2;
- public const int X400Address = 3;
- public const int DirectoryName = 4;
- public const int EdiPartyName = 5;
- public const int UniformResourceIdentifier = 6;
- public const int IPAddress = 7;
- public const int RegisteredID = 8;
- internal readonly Asn1Encodable obj;
- internal readonly int tag;
- public GeneralName(
- X509Name directoryName)
- {
- this.obj = directoryName;
- this.tag = 4;
- }
- /**
- * When the subjectAltName extension contains an Internet mail address,
- * the address MUST be included as an rfc822Name. The format of an
- * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
- *
- * When the subjectAltName extension contains a domain name service
- * label, the domain name MUST be stored in the dNSName (an IA5String).
- * The name MUST be in the "preferred name syntax," as specified by RFC
- * 1034 [RFC 1034].
- *
- * When the subjectAltName extension contains a URI, the name MUST be
- * stored in the uniformResourceIdentifier (an IA5String). The name MUST
- * be a non-relative URL, and MUST follow the URL syntax and encoding
- * rules specified in [RFC 1738]. The name must include both a scheme
- * (e.g., "http" or "ftp") and a scheme-specific-part. The scheme-
- * specific-part must include a fully qualified domain name or IP
- * address as the host.
- *
- * When the subjectAltName extension contains a iPAddress, the address
- * MUST be stored in the octet string in "network byte order," as
- * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
- * each octet is the LSB of the corresponding byte in the network
- * address. For IP Version 4, as specified in RFC 791, the octet string
- * MUST contain exactly four octets. For IP Version 6, as specified in
- * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
- * 1883].
- */
- public GeneralName(
- Asn1Object name,
- int tag)
- {
- this.obj = name;
- this.tag = tag;
- }
- public GeneralName(
- int tag,
- Asn1Encodable name)
- {
- this.obj = name;
- this.tag = tag;
- }
- /**
- * Create a GeneralName for the given tag from the passed in string.
- * <p>
- * This constructor can handle:
- * <ul>
- * <li>rfc822Name</li>
- * <li>iPAddress</li>
- * <li>directoryName</li>
- * <li>dNSName</li>
- * <li>uniformResourceIdentifier</li>
- * <li>registeredID</li>
- * </ul>
- * For x400Address, otherName and ediPartyName there is no common string
- * format defined.
- * </p><p>
- * Note: A directory name can be encoded in different ways into a byte
- * representation. Be aware of this if the byte representation is used for
- * comparing results.
- * </p>
- *
- * @param tag tag number
- * @param name string representation of name
- * @throws ArgumentException if the string encoding is not correct or
- * not supported.
- */
- public GeneralName(
- int tag,
- string name)
- {
- this.tag = tag;
- if (tag == Rfc822Name || tag == DnsName || tag == UniformResourceIdentifier)
- {
- this.obj = new DerIA5String(name);
- }
- else if (tag == RegisteredID)
- {
- this.obj = new DerObjectIdentifier(name);
- }
- else if (tag == DirectoryName)
- {
- this.obj = new X509Name(name);
- }
- else if (tag == IPAddress)
- {
- byte[] enc = toGeneralNameEncoding(name);
- if (enc == null)
- throw new ArgumentException("IP Address is invalid", "name");
- this.obj = new DerOctetString(enc);
- }
- else
- {
- throw new ArgumentException("can't process string for tag: " + tag, "tag");
- }
- }
- public static GeneralName GetInstance(
- object obj)
- {
- if (obj == null || obj is GeneralName)
- {
- return (GeneralName) obj;
- }
- if (obj is Asn1TaggedObject)
- {
- Asn1TaggedObject tagObj = (Asn1TaggedObject) obj;
- int tag = tagObj.TagNo;
- switch (tag)
- {
- case OtherName:
- return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
- case Rfc822Name:
- return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
- case DnsName:
- return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
- case X400Address:
- throw new ArgumentException("unknown tag: " + tag);
- case DirectoryName:
- return new GeneralName(tag, X509Name.GetInstance(tagObj, true));
- case EdiPartyName:
- return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
- case UniformResourceIdentifier:
- return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
- case IPAddress:
- return new GeneralName(tag, Asn1OctetString.GetInstance(tagObj, false));
- case RegisteredID:
- return new GeneralName(tag, DerObjectIdentifier.GetInstance(tagObj, false));
- }
- }
- if (obj is byte[])
- {
- try
- {
- return GetInstance(Asn1Object.FromByteArray((byte[])obj));
- }
- catch (IOException)
- {
- throw new ArgumentException("unable to parse encoded general name");
- }
- }
- throw new ArgumentException("unknown object in GetInstance: " + Org.BouncyCastle.Utilities.Platform.GetTypeName(obj), "obj");
- }
- public static GeneralName GetInstance(
- Asn1TaggedObject tagObj,
- bool explicitly)
- {
- return GetInstance(Asn1TaggedObject.GetInstance(tagObj, true));
- }
- public int TagNo
- {
- get { return tag; }
- }
- public Asn1Encodable Name
- {
- get { return obj; }
- }
- public override string ToString()
- {
- StringBuilder buf = new StringBuilder();
- buf.Append(tag);
- buf.Append(": ");
- switch (tag)
- {
- case Rfc822Name:
- case DnsName:
- case UniformResourceIdentifier:
- buf.Append(DerIA5String.GetInstance(obj).GetString());
- break;
- case DirectoryName:
- buf.Append(X509Name.GetInstance(obj).ToString());
- break;
- default:
- buf.Append(obj.ToString());
- break;
- }
- return buf.ToString();
- }
- private byte[] toGeneralNameEncoding(
- string ip)
- {
- if (NetUtils.IPAddress.IsValidIPv6WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv6(ip))
- {
- int slashIndex = ip.IndexOf('/');
- if (slashIndex < 0)
- {
- byte[] addr = new byte[16];
- int[] parsedIp = parseIPv6(ip);
- copyInts(parsedIp, addr, 0);
- return addr;
- }
- else
- {
- byte[] addr = new byte[32];
- int[] parsedIp = parseIPv6(ip.Substring(0, slashIndex));
- copyInts(parsedIp, addr, 0);
- string mask = ip.Substring(slashIndex + 1);
- if (mask.IndexOf(':') > 0)
- {
- parsedIp = parseIPv6(mask);
- }
- else
- {
- parsedIp = parseMask(mask);
- }
- copyInts(parsedIp, addr, 16);
- return addr;
- }
- }
- else if (NetUtils.IPAddress.IsValidIPv4WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv4(ip))
- {
- int slashIndex = ip.IndexOf('/');
- if (slashIndex < 0)
- {
- byte[] addr = new byte[4];
- parseIPv4(ip, addr, 0);
- return addr;
- }
- else
- {
- byte[] addr = new byte[8];
- parseIPv4(ip.Substring(0, slashIndex), addr, 0);
- string mask = ip.Substring(slashIndex + 1);
- if (mask.IndexOf('.') > 0)
- {
- parseIPv4(mask, addr, 4);
- }
- else
- {
- parseIPv4Mask(mask, addr, 4);
- }
- return addr;
- }
- }
- return null;
- }
- private void parseIPv4Mask(string mask, byte[] addr, int offset)
- {
- int maskVal = Int32.Parse(mask);
- for (int i = 0; i != maskVal; i++)
- {
- addr[(i / 8) + offset] |= (byte)(1 << (i % 8));
- }
- }
- private void parseIPv4(string ip, byte[] addr, int offset)
- {
- foreach (string token in ip.Split('.', '/'))
- {
- addr[offset++] = (byte)Int32.Parse(token);
- }
- }
- private int[] parseMask(string mask)
- {
- int[] res = new int[8];
- int maskVal = Int32.Parse(mask);
- for (int i = 0; i != maskVal; i++)
- {
- res[i / 16] |= 1 << (i % 16);
- }
- return res;
- }
- private void copyInts(int[] parsedIp, byte[] addr, int offSet)
- {
- for (int i = 0; i != parsedIp.Length; i++)
- {
- addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8);
- addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i];
- }
- }
- private int[] parseIPv6(string ip)
- {
- if (Org.BouncyCastle.Utilities.Platform.StartsWith(ip, "::"))
- {
- ip = ip.Substring(1);
- }
- else if (Org.BouncyCastle.Utilities.Platform.EndsWith(ip, "::"))
- {
- ip = ip.Substring(0, ip.Length - 1);
- }
- IEnumerator sEnum = ip.Split(':').GetEnumerator();
- int index = 0;
- int[] val = new int[8];
- int doubleColon = -1;
- while (sEnum.MoveNext())
- {
- string e = (string) sEnum.Current;
- if (e.Length == 0)
- {
- doubleColon = index;
- val[index++] = 0;
- }
- else
- {
- if (e.IndexOf('.') < 0)
- {
- val[index++] = Int32.Parse(e, NumberStyles.AllowHexSpecifier);
- }
- else
- {
- string[] tokens = e.Split('.');
- val[index++] = (Int32.Parse(tokens[0]) << 8) | Int32.Parse(tokens[1]);
- val[index++] = (Int32.Parse(tokens[2]) << 8) | Int32.Parse(tokens[3]);
- }
- }
- }
- if (index != val.Length)
- {
- Array.Copy(val, doubleColon, val, val.Length - (index - doubleColon), index - doubleColon);
- for (int i = doubleColon; i != val.Length - (index - doubleColon); i++)
- {
- val[i] = 0;
- }
- }
- return val;
- }
- public override Asn1Object ToAsn1Object()
- {
- // Explicitly tagged if DirectoryName
- return new DerTaggedObject(tag == DirectoryName, tag, obj);
- }
- }
- }
- #endif
|