1package org.bouncycastle.asn1.x509;
2
3import org.bouncycastle.asn1.ASN1Choice;
4import org.bouncycastle.asn1.ASN1Encodable;
5import org.bouncycastle.asn1.ASN1OctetString;
6import org.bouncycastle.asn1.ASN1Sequence;
7import org.bouncycastle.asn1.ASN1TaggedObject;
8import org.bouncycastle.asn1.DEREncodable;
9import org.bouncycastle.asn1.DERIA5String;
10import org.bouncycastle.asn1.DERObject;
11import org.bouncycastle.asn1.DERObjectIdentifier;
12import org.bouncycastle.asn1.DERTaggedObject;
13
14/**
15 * The GeneralName object.
16 * <pre>
17 * GeneralName ::= CHOICE {
18 *      otherName                       [0]     OtherName,
19 *      rfc822Name                      [1]     IA5String,
20 *      dNSName                         [2]     IA5String,
21 *      x400Address                     [3]     ORAddress,
22 *      directoryName                   [4]     Name,
23 *      ediPartyName                    [5]     EDIPartyName,
24 *      uniformResourceIdentifier       [6]     IA5String,
25 *      iPAddress                       [7]     OCTET STRING,
26 *      registeredID                    [8]     OBJECT IDENTIFIER}
27 *
28 * OtherName ::= SEQUENCE {
29 *      type-id    OBJECT IDENTIFIER,
30 *      value      [0] EXPLICIT ANY DEFINED BY type-id }
31 *
32 * EDIPartyName ::= SEQUENCE {
33 *      nameAssigner            [0]     DirectoryString OPTIONAL,
34 *      partyName               [1]     DirectoryString }
35 *
36 * Name ::= CHOICE { RDNSequence }
37 * </pre>
38 */
39public class GeneralName
40    extends ASN1Encodable
41    implements ASN1Choice
42{
43    public static final int otherName                     = 0;
44    public static final int rfc822Name                    = 1;
45    public static final int dNSName                       = 2;
46    public static final int x400Address                   = 3;
47    public static final int directoryName                 = 4;
48    public static final int ediPartyName                  = 5;
49    public static final int uniformResourceIdentifier     = 6;
50    public static final int iPAddress                     = 7;
51    public static final int registeredID                  = 8;
52
53    DEREncodable      obj;
54    int               tag;
55
56    public GeneralName(
57        X509Name  dirName)
58    {
59        this.obj = dirName;
60        this.tag = 4;
61    }
62
63    /**
64     * @deprecated this constructor seems the wrong way round! Use GeneralName(tag, name).
65     */
66    public GeneralName(
67        DERObject name, int tag)
68    {
69        this.obj = name;
70        this.tag = tag;
71    }
72
73    /**
74     * When the subjectAltName extension contains an Internet mail address,
75     * the address MUST be included as an rfc822Name. The format of an
76     * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
77     *
78     * When the subjectAltName extension contains a domain name service
79     * label, the domain name MUST be stored in the dNSName (an IA5String).
80     * The name MUST be in the "preferred name syntax," as specified by RFC
81     * 1034 [RFC 1034].
82     *
83     * When the subjectAltName extension contains a URI, the name MUST be
84     * stored in the uniformResourceIdentifier (an IA5String). The name MUST
85     * be a non-relative URL, and MUST follow the URL syntax and encoding
86     * rules specified in [RFC 1738].  The name must include both a scheme
87     * (e.g., "http" or "ftp") and a scheme-specific-part.  The scheme-
88     * specific-part must include a fully qualified domain name or IP
89     * address as the host.
90     *
91     * When the subjectAltName extension contains a iPAddress, the address
92     * MUST be stored in the octet string in "network byte order," as
93     * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
94     * each octet is the LSB of the corresponding byte in the network
95     * address. For IP Version 4, as specified in RFC 791, the octet string
96     * MUST contain exactly four octets.  For IP Version 6, as specified in
97     * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
98     * 1883].
99     */
100    public GeneralName(
101        int           tag,
102        ASN1Encodable name)
103    {
104        this.obj = name;
105        this.tag = tag;
106    }
107
108    /**
109     * Create a General name for the given tag from the passed in String.
110     *
111     * @param tag tag number
112     * @param name string representation of name
113     */
114    public GeneralName(
115        int       tag,
116        String    name)
117    {
118        if (tag == rfc822Name || tag == dNSName || tag == uniformResourceIdentifier)
119        {
120            this.tag = tag;
121            this.obj = new DERIA5String(name);
122        }
123        else if (tag == registeredID)
124        {
125            this.tag = tag;
126            this.obj = new DERObjectIdentifier(name);
127        }
128        else
129        {
130            throw new IllegalArgumentException("can't process String for tag: " + tag);
131        }
132    }
133
134    public static GeneralName getInstance(
135        Object obj)
136    {
137        if (obj == null || obj instanceof GeneralName)
138        {
139            return (GeneralName)obj;
140        }
141
142        if (obj instanceof ASN1TaggedObject)
143        {
144            ASN1TaggedObject    tagObj = (ASN1TaggedObject)obj;
145            int                 tag = tagObj.getTagNo();
146
147            switch (tag)
148            {
149            case otherName:
150                return new GeneralName(ASN1Sequence.getInstance(tagObj, false), tag);
151            case rfc822Name:
152                return new GeneralName(DERIA5String.getInstance(tagObj, false), tag);
153            case dNSName:
154                return new GeneralName(DERIA5String.getInstance(tagObj, false), tag);
155            case x400Address:
156                throw new IllegalArgumentException("unknown tag: " + tag);
157            case directoryName:
158                return new GeneralName(ASN1Sequence.getInstance(tagObj, true), tag);
159            case ediPartyName:
160                return new GeneralName(ASN1Sequence.getInstance(tagObj, false), tag);
161            case uniformResourceIdentifier:
162                return new GeneralName(DERIA5String.getInstance(tagObj, false), tag);
163            case iPAddress:
164                return new GeneralName(ASN1OctetString.getInstance(tagObj, false), tag);
165            case registeredID:
166                return new GeneralName(DERObjectIdentifier.getInstance(tagObj, false), tag);
167            }
168        }
169
170        throw new IllegalArgumentException("unknown object in getInstance");
171    }
172
173    public static GeneralName getInstance(
174        ASN1TaggedObject tagObj,
175        boolean          explicit)
176    {
177        return GeneralName.getInstance(ASN1TaggedObject.getInstance(tagObj, true));
178    }
179
180    public int getTagNo()
181    {
182        return tag;
183    }
184
185    public DEREncodable getName()
186    {
187        return obj;
188    }
189
190    public DERObject toASN1Object()
191    {
192        if (tag == directoryName)       // directoryName is explicitly tagged as it is a CHOICE
193        {
194            return new DERTaggedObject(true, tag, obj);
195        }
196        else
197        {
198            return new DERTaggedObject(false, tag, obj);
199        }
200    }
201}
202