1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18/**
19* @author Vladimir N. Molotkov, Alexander Y. Kleymenov
20* @version $Revision$
21*/
22
23package org.apache.harmony.security.x509;
24
25import java.io.IOException;
26import java.net.InetAddress;
27import java.net.URI;
28import java.net.URISyntaxException;
29import java.net.UnknownHostException;
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.Collections;
33import java.util.List;
34import java.util.Locale;
35import javax.security.auth.x500.X500Principal;
36import org.apache.harmony.security.asn1.ASN1Choice;
37import org.apache.harmony.security.asn1.ASN1Implicit;
38import org.apache.harmony.security.asn1.ASN1OctetString;
39import org.apache.harmony.security.asn1.ASN1Oid;
40import org.apache.harmony.security.asn1.ASN1StringType;
41import org.apache.harmony.security.asn1.ASN1Type;
42import org.apache.harmony.security.asn1.BerInputStream;
43import org.apache.harmony.security.asn1.ObjectIdentifier;
44import org.apache.harmony.security.utils.Array;
45import org.apache.harmony.security.x501.Name;
46
47/**
48 * The class encapsulates the ASN.1 DER encoding/decoding work
49 * with the GeneralName structure which is a part of X.509 certificate
50 * (as specified in RFC 3280 -
51 *  Internet X.509 Public Key Infrastructure.
52 *  Certificate and Certificate Revocation List (CRL) Profile.
53 *  http://www.ietf.org/rfc/rfc3280.txt):
54 *
55 * <pre>
56 *
57 *   GeneralName::= CHOICE {
58 *        otherName                       [0]     OtherName,
59 *        rfc822Name                      [1]     IA5String,
60 *        dNSName                         [2]     IA5String,
61 *        x400Address                     [3]     ORAddress,
62 *        directoryName                   [4]     Name,
63 *        ediPartyName                    [5]     EDIPartyName,
64 *        uniformResourceIdentifier       [6]     IA5String,
65 *        iPAddress                       [7]     OCTET STRING,
66 *        registeredID                    [8]     OBJECT IDENTIFIER
67 *   }
68 *
69 *   OtherName::= SEQUENCE {
70 *        type-id    OBJECT IDENTIFIER,
71 *        value      [0] EXPLICIT ANY DEFINED BY type-id
72 *   }
73 *
74 *   EDIPartyName::= SEQUENCE {
75 *        nameAssigner            [0]     DirectoryString OPTIONAL,
76 *        partyName               [1]     DirectoryString
77 *   }
78 *
79 *   DirectoryString::= CHOICE {
80 *        teletexString             TeletexString   (SIZE (1..MAX)),
81 *        printableString           PrintableString (SIZE (1..MAX)),
82 *        universalString           UniversalString (SIZE (1..MAX)),
83 *        utf8String              UTF8String      (SIZE (1..MAX)),
84 *        bmpString               BMPString       (SIZE (1..MAX))
85 *   }
86 *
87 * </pre>
88 *
89 * <p>This class doesn't support masked addresses like "10.9.8.0/255.255.255.0".
90 * These are only necessary for NameConstraints, which are not exposed in the
91 * Java certificate API.
92 *
93 * @see org.apache.harmony.security.x509.NameConstraints
94 * @see org.apache.harmony.security.x509.GeneralSubtree
95 */
96public final class GeneralName {
97
98    /**
99     * The values of the tags of fields
100     */
101    public static final int OTHER_NAME = 0;
102    public static final int RFC822_NAME = 1;
103    public static final int DNS_NAME = 2;
104    public static final int X400_ADDR = 3;
105    public static final int DIR_NAME = 4;
106    public static final int EDIP_NAME = 5;
107    public static final int UR_ID = 6;
108    public static final int IP_ADDR = 7;
109    public static final int REG_ID = 8;
110
111    // ASN1 encoders/decoders for name choices
112    private static ASN1Type[] nameASN1 = new ASN1Type[9];
113
114    static {
115        nameASN1[OTHER_NAME] = OtherName.ASN1;
116        nameASN1[RFC822_NAME] = ASN1StringType.IA5STRING;
117        nameASN1[DNS_NAME] = ASN1StringType.IA5STRING;
118        nameASN1[UR_ID] = ASN1StringType.IA5STRING;
119        nameASN1[X400_ADDR] = ORAddress.ASN1;
120        nameASN1[DIR_NAME] = Name.ASN1;
121        nameASN1[EDIP_NAME] = EDIPartyName.ASN1;
122        nameASN1[IP_ADDR] = ASN1OctetString.getInstance();
123        nameASN1[REG_ID] = ASN1Oid.getInstance();
124    }
125
126    /** the tag of the name type */
127    private int tag;
128    /** the name value (can be String or byte array) */
129    private Object name;
130    /** the ASN.1 encoded form of GeneralName */
131    private byte[] encoding;
132    /** the ASN.1 encoded form of GeneralName's field */
133    private byte[] name_encoding;
134
135    /**
136     * Makes the GeneralName object from the tag type and corresponding
137     * well established string representation of the name value.
138     * The String representation of [7] iPAddress is such as:
139     *  For IP v4, as specified in RFC 791, the address must
140     *  contain exactly 4 byte component.  For IP v6, as specified in
141     *  RFC 1883, the address must contain exactly 16 byte component.
142     *  If GeneralName structure is used as a part of Name Constraints
143     *  extension, to represent an address range the number of address
144     *  component is doubled (to 8 and 32 bytes respectively).
145     * Note that the names:
146     * [0] otherName, [3] x400Address, [5] ediPartyName
147     *   have no the string representation, so exception will be thrown.
148     * To make the GeneralName object with such names use another constructor.
149     * @param tag is an integer which value corresponds to the name type.
150     * @param name is a name value corresponding to the tag.
151     */
152    public GeneralName(int tag, String name) throws IOException {
153        if (name == null) {
154            throw new IOException("name == null");
155        }
156        this.tag = tag;
157        switch (tag) {
158            case OTHER_NAME :
159            case X400_ADDR :
160            case EDIP_NAME :
161                throw new IOException("Unknown string representation for type [" + tag + "]");
162            case DNS_NAME :
163                // according to RFC 3280 p.34 the DNS name should be
164                // checked against the
165                // RFC 1034 p.10 (3.5. Preferred name syntax):
166                checkDNS(name);
167                this.name = name;
168                break;
169            case UR_ID :
170                // check the uniformResourceIdentifier for correctness
171                // according to RFC 3280 p.34
172                checkURI(name);
173                this.name = name;
174                break;
175            case RFC822_NAME :
176                this.name = name;
177                break;
178            case REG_ID:
179                this.name = oidStrToInts(name);
180                break;
181            case DIR_NAME :
182                this.name = new Name(name);
183                break;
184            case IP_ADDR :
185                this.name = ipStrToBytes(name);
186                break;
187            default:
188                throw new IOException("Unknown type: [" + tag + "]");
189        }
190    }
191
192    public GeneralName(OtherName name) {
193        this.tag = OTHER_NAME;
194        this.name = name;
195    }
196
197    public GeneralName(ORAddress name) {
198        this.tag = X400_ADDR;
199        this.name = name;
200    }
201
202    public GeneralName(Name name) {
203        this.tag = DIR_NAME;
204        this.name = name;
205    }
206
207    public GeneralName(EDIPartyName name) {
208        this.tag = EDIP_NAME;
209        this.name = name;
210    }
211    /**
212     * Constructor for type [7] iPAddress.
213     * name is an array of bytes such as:
214     *  For IP v4, as specified in RFC 791, the address must
215     *  contain exactly 4 byte component.  For IP v6, as specified in
216     *  RFC 1883, the address must contain exactly 16 byte component.
217     *  If GeneralName structure is used as a part of Name Constraints
218     *  extension, to represent an address range the number of address
219     *  component is doubled (to 8 and 32 bytes respectively).
220     */
221    public GeneralName(byte[] name) throws IllegalArgumentException {
222        int length = name.length;
223        if (length != 4 && length != 8 && length != 16 && length != 32) {
224            throw new IllegalArgumentException("name.length invalid");
225        }
226        this.tag = IP_ADDR;
227        this.name = new byte[name.length];
228        System.arraycopy(name, 0, this.name, 0, name.length);
229    }
230
231    /**
232     * Constructs an object representing the value of GeneralName.
233     * @param tag is an integer which value corresponds
234     * to the name type (0-8),
235     * @param name is a DER encoded for of the name value
236     */
237    public GeneralName(int tag, byte[] name) throws IOException {
238        if (name == null) {
239            throw new NullPointerException("name == null");
240        }
241        if ((tag < 0) || (tag > 8)) {
242            throw new IOException("GeneralName: unknown tag: " + tag);
243        }
244        this.tag = tag;
245        this.name_encoding = new byte[name.length];
246        System.arraycopy(name, 0, this.name_encoding, 0, name.length);
247        this.name = nameASN1[tag].decode(this.name_encoding);
248    }
249
250    /**
251     * Returns the tag of the name in the structure
252     */
253    public int getTag() {
254        return tag;
255    }
256
257    /**
258     * @return the value of the name.
259     * The class of name object depends on the tag as follows:
260     * [0] otherName - OtherName object,
261     * [1] rfc822Name - String object,
262     * [2] dNSName - String object,
263     * [3] x400Address - ORAddress object,
264     * [4] directoryName - instance of Name object,
265     * [5] ediPartyName - EDIPartyName object,
266     * [6] uniformResourceIdentifier - String object,
267     * [7] iPAddress - array of bytes such as:
268     *  For IP v4, as specified in RFC 791, the address must
269     *  contain exactly 4 byte component.  For IP v6, as specified in
270     *  RFC 1883, the address must contain exactly 16 byte component.
271     *  If GeneralName structure is used as a part of Name Constraints
272     *  extension, to represent an address range the number of address
273     *  component is doubled (to 8 and 32 bytes respectively).
274     * [8] registeredID - String.
275     */
276    public Object getName() {
277        return name;
278    }
279
280    public boolean equals(Object other) {
281        if (!(other instanceof GeneralName)) {
282            return false;
283        }
284        GeneralName gname = (GeneralName) other;
285        if (this.tag != gname.tag) {
286            return false;
287        }
288        switch(tag) {
289            case RFC822_NAME:
290            case DNS_NAME:
291            case UR_ID:
292                return ((String) name).equalsIgnoreCase(
293                        (String) gname.getName());
294            case REG_ID:
295                return Arrays.equals((int[]) name, (int[]) gname.name);
296            case IP_ADDR:
297                // iPAddress [7], check by using ranges.
298                return Arrays.equals((byte[]) name, (byte[]) gname.name);
299            case DIR_NAME:
300            case X400_ADDR:
301            case OTHER_NAME:
302            case EDIP_NAME:
303                return Arrays.equals(getEncoded(), gname.getEncoded());
304            default:
305                // should never happen
306        }
307        return false;
308    }
309
310    public int hashCode() {
311        switch (tag) {
312        case RFC822_NAME:
313        case DNS_NAME:
314        case UR_ID:
315        case REG_ID:
316        case IP_ADDR:
317            return name.hashCode();
318        case DIR_NAME:
319        case X400_ADDR:
320        case OTHER_NAME:
321        case EDIP_NAME:
322            return Arrays.hashCode(getEncoded());
323        default:
324            return super.hashCode();
325        }
326    }
327
328    /**
329     * Checks if the other general name is acceptable by this object.
330     * The name is acceptable if it has the same type name and its
331     * name value is equal to name value of this object. Also the name
332     * is acceptable if this general name object is a part of name
333     * constraints and the specified name is satisfied the restriction
334     * provided by this object (for more detail see section 4.2.1.11
335     * of rfc 3280).
336     * Note that for X400Address [3] check procedure is unclear so method
337     * just checks the equality of encoded forms.
338     * For otherName [0], ediPartyName [5], and registeredID [8]
339     * the check procedure if not defined by rfc 3280 and for names of
340     * these types this method also checks only for equality of encoded forms.
341     */
342    public boolean isAcceptable(GeneralName gname) {
343        if (this.tag != gname.getTag()) {
344            return false;
345        }
346        switch (this.tag) {
347            case RFC822_NAME:
348                // Mail address [1]:
349                // a@b.c - particular address is acceptable by the same address,
350                // or by b.c - host name.
351                return ((String) gname.getName()).toLowerCase(Locale.US)
352                    .endsWith(((String) name).toLowerCase(Locale.US));
353            case DNS_NAME:
354                // DNS name [2] that can be constructed by simply adding
355                // to the left hand side of the name satisfies the name
356                // constraint: aaa.aa.aa satisfies to aaa.aa.aa, aa.aa, ..
357                String dns = (String) name;
358                String _dns = (String) gname.getName();
359                if (dns.equalsIgnoreCase(_dns)) {
360                    return true;
361                } else {
362                    return _dns.toLowerCase(Locale.US).endsWith("." + dns.toLowerCase(Locale.US));
363                }
364            case UR_ID:
365                // For URIs the constraint ".xyz.com" is satisfied by both
366                // abc.xyz.com and abc.def.xyz.com.  However, the constraint
367                // ".xyz.com" is not satisfied by "xyz.com".
368                // When the constraint does not begin with a period, it
369                // specifies a host.
370                // Extract the host from URI:
371                String uri = (String) name;
372                int begin = uri.indexOf("://")+3;
373                int end = uri.indexOf('/', begin);
374                String host = (end == -1)
375                                ? uri.substring(begin)
376                                : uri.substring(begin, end);
377                uri = (String) gname.getName();
378                begin = uri.indexOf("://")+3;
379                end = uri.indexOf('/', begin);
380                String _host = (end == -1)
381                                ? uri.substring(begin)
382                                : uri.substring(begin, end);
383                if (host.startsWith(".")) {
384                    return _host.toLowerCase(Locale.US).endsWith(host.toLowerCase(Locale.US));
385                } else {
386                    return host.equalsIgnoreCase(_host);
387                }
388            case IP_ADDR:
389                // iPAddress [7], check by using ranges.
390                byte[] address = (byte[]) name;
391                byte[] _address = (byte[]) gname.getName();
392                int length = address.length;
393                int _length = _address.length;
394                if (length == _length) {
395                    return Arrays.equals(address, _address);
396                } else if (length == 2*_length) {
397                    for (int i = 0; i < _address.length; i++) {
398                        // TODO: should the 2nd IP address be treated as a range or as a mask?
399                        int octet = _address[i] & 0xff;
400                        int min = address[i] & 0xff;
401                        int max = address[i + _length] & 0xff;
402                        if ((octet < min) || (octet > max)) {
403                            return false;
404                        }
405                    }
406                    return true;
407                } else {
408                    return false;
409                }
410            case DIR_NAME:
411                // FIXME: false:
412                // directoryName according to 4.1.2.4
413                // comparing the encoded forms of the names
414                //TODO:
415                //Legacy implementations exist where an RFC 822 name
416                //is embedded in the subject distinguished name in an
417                //attribute of type EmailAddress
418            case X400_ADDR:
419            case OTHER_NAME:
420            case EDIP_NAME:
421            case REG_ID:
422                return Arrays.equals(getEncoded(), gname.getEncoded());
423            default:
424                // should never happen
425        }
426        return true;
427    }
428
429    /**
430     * Gets a list representation of this GeneralName object.
431     * The first entry of the list is an Integer object representing
432     * the type of mane (0-8), and the second entry is a value of the name:
433     * string or ASN.1 DER encoded form depending on the type as follows:
434     * rfc822Name, dNSName, uniformResourceIdentifier names are returned
435     * as Strings, using the string formats for those types (rfc 3280)
436     * IP v4 address names are returned using dotted quad notation.
437     * IP v6 address names are returned in the form "p1:p2:...:p8",
438     * where p1-p8 are hexadecimal values representing the eight 16-bit
439     * pieces of the address. registeredID name are returned as Strings
440     * represented as a series of nonnegative integers separated by periods.
441     * And directory names (distinguished names) are returned in
442     * RFC 2253 string format.
443     * otherName, X400Address, ediPartyName returned as byte arrays
444     * containing the ASN.1 DER encoded form of the name.
445     */
446    public List<Object> getAsList() {
447        ArrayList<Object> result = new ArrayList<Object>();
448        result.add(tag);
449        switch (tag) {
450            case OTHER_NAME:
451                result.add(((OtherName) name).getEncoded());
452                break;
453            case RFC822_NAME:
454            case DNS_NAME:
455            case UR_ID:
456                result.add(name); // String
457                break;
458            case REG_ID:
459                result.add(ObjectIdentifier.toString((int[]) name));
460                break;
461            case X400_ADDR:
462                result.add(((ORAddress) name).getEncoded());
463                break;
464            case DIR_NAME: // directoryName is returned as a String
465                result.add(((Name) name).getName(X500Principal.RFC2253));
466                break;
467            case EDIP_NAME:
468                result.add(((EDIPartyName) name).getEncoded());
469                break;
470            case IP_ADDR: //iPAddress is returned as a String, not as a byte array
471                result.add(ipBytesToStr((byte[]) name));
472                break;
473            default:
474                // should never happen
475        }
476        return Collections.unmodifiableList(result);
477    }
478
479    public String toString() {
480        String result = "";
481        switch (tag) {
482            case OTHER_NAME:
483                result = "otherName[0]: "
484                         + Array.getBytesAsString(getEncoded());
485                break;
486            case RFC822_NAME:
487                result = "rfc822Name[1]: " + name;
488                break;
489            case DNS_NAME:
490                result = "dNSName[2]: " + name;
491                break;
492            case UR_ID:
493                result = "uniformResourceIdentifier[6]: " + name;
494                break;
495            case REG_ID:
496                result = "registeredID[8]: " + ObjectIdentifier.toString((int[]) name);
497                break;
498            case X400_ADDR:
499                result = "x400Address[3]: "
500                         + Array.getBytesAsString(getEncoded());
501                break;
502            case DIR_NAME:
503                result = "directoryName[4]: "
504                         + ((Name) name).getName(X500Principal.RFC2253);
505                break;
506            case EDIP_NAME:
507                result = "ediPartyName[5]: "
508                         + Array.getBytesAsString(getEncoded());
509                break;
510            case IP_ADDR:
511                result = "iPAddress[7]: " + ipBytesToStr((byte[]) name);
512                break;
513            default:
514                // should never happen
515        }
516        return result;
517    }
518
519    /**
520     * Returns ASN.1 encoded form of this X.509 GeneralName value.
521     */
522    public byte[] getEncoded() {
523        if (encoding == null) {
524            encoding = ASN1.encode(this);
525        }
526        return encoding;
527    }
528
529    /**
530     * @return the encoded value of the name without the tag associated
531     *         with the name in the GeneralName structure
532     * @throws  IOException
533     */
534    public byte[] getEncodedName() {
535        if (name_encoding == null) {
536            name_encoding = nameASN1[tag].encode(name);
537        }
538        return name_encoding;
539    }
540
541    /**
542     * Checks the correctness of the string representation of DNS name as
543     * specified in RFC 1034 p. 10 and RFC 1123 section 2.1.
544     *
545     * <p>This permits a wildcard character '*' anywhere in the name; it is up
546     * to the application to check which wildcards are permitted. See RFC 6125
547     * for recommended wildcard matching rules.
548     */
549    public static void checkDNS(String dns) throws IOException {
550        String string = dns.toLowerCase(Locale.US);
551        int length = string.length();
552        // indicates if it is a first letter of the label
553        boolean first_letter = true;
554        for (int i = 0; i < length; i++) {
555            char ch = string.charAt(i);
556            if (first_letter) {
557                if ((ch > 'z' || ch < 'a') && (ch < '0' || ch > '9') && (ch != '*')) {
558                    throw new IOException("DNS name must start with a letter: " + dns);
559                }
560                first_letter = false;
561                continue;
562            }
563            if (!((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
564                    || (ch == '-') || (ch == '.') || (ch == '*'))) {
565                throw new IOException("Incorrect DNS name: " + dns);
566            }
567            if (ch == '.') {
568                // check the end of the previous label, it should not
569                // be '-' sign
570                if (string.charAt(i-1) == '-') {
571                    throw new IOException("Incorrect DNS name: label ends with '-': " + dns);
572                }
573                first_letter = true;
574            }
575        }
576    }
577
578    /**
579     * Checks the correctness of the string representation of URI name.
580     * The correctness is checked as pointed out in RFC 3280 p. 34.
581     */
582    public static void checkURI(String uri) throws IOException {
583        try {
584            URI ur = new URI(uri);
585            if (ur.getScheme() == null || ur.getRawSchemeSpecificPart().isEmpty()) {
586                throw new IOException("No scheme or scheme-specific-part in uniformResourceIdentifier: " + uri);
587            }
588            if (!ur.isAbsolute()) {
589                throw new IOException("Relative uniformResourceIdentifier: " + uri);
590            }
591        } catch (URISyntaxException e) {
592            throw (IOException) new IOException("Bad representation of uniformResourceIdentifier: " + uri).initCause(e);
593
594        }
595    }
596
597    /**
598     * Converts OID into array of ints.
599     */
600    public static int[] oidStrToInts(String oid) throws IOException {
601        int length = oid.length();
602        if (oid.charAt(length-1) == '.') {
603            throw new IOException("Bad OID: " + oid);
604        }
605        int[] result = new int[length/2+1]; // best case: a.b.c.d.e
606        int number = 0; // the number of OID's components
607        for (int i = 0; i < length; i++) {
608            int value = 0;
609            int pos = i;
610            for (; i < length; i++) {
611                char ch = oid.charAt(i);
612                if ((ch < '0') || (ch > '9')) {
613                    break;
614                }
615                value = 10 * value + (ch - '0');
616            }
617            if (i == pos) {
618                // the number was not read
619                throw new IOException("Bad OID: " + oid);
620            }
621            result[number++] = value;
622            if (i == length) {
623                break;
624            }
625            char ch = oid.charAt(i);
626            if (ch != '.') {
627                throw new IOException("Bad OID: " + oid);
628            }
629        }
630        if (number < 2) {
631            throw new IOException("OID should consist of no less than 2 components: " + oid);
632        }
633        return Arrays.copyOfRange(result, 0, number);
634    }
635
636    /**
637     * Returns the bytes of the given IP address or masked IP address.
638     */
639    public static byte[] ipStrToBytes(String ip) throws IOException {
640        if (!InetAddress.isNumeric(ip)) {
641            throw new IOException("Not an IP address: " + ip);
642        }
643        return InetAddress.getByName(ip).getAddress();
644    }
645
646    /**
647     * Returns the string form of the given IP address. Addresses of length 2x
648     * the canonical length are treated as a route/mask pair.
649     */
650    public static String ipBytesToStr(byte[] ip) {
651        try {
652            return InetAddress.getByAddress(null, ip).getHostAddress();
653        } catch (UnknownHostException e) {
654            throw new IllegalArgumentException("Unexpected IP address: " + Arrays.toString(ip));
655        }
656    }
657
658    public static final ASN1Choice ASN1 = new ASN1Choice(new ASN1Type[] {
659           new ASN1Implicit(0, OtherName.ASN1),
660           new ASN1Implicit(1, ASN1StringType.IA5STRING),
661           new ASN1Implicit(2, ASN1StringType.IA5STRING),
662           new ASN1Implicit(3, ORAddress.ASN1),
663           new ASN1Implicit(4, Name.ASN1),
664           new ASN1Implicit(5, EDIPartyName.ASN1),
665           new ASN1Implicit(6, ASN1StringType.IA5STRING),
666           new ASN1Implicit(7, ASN1OctetString.getInstance()),
667           new ASN1Implicit(8, ASN1Oid.getInstance()) }) {
668
669        public Object getObjectToEncode(Object value) {
670            return ((GeneralName) value).name;
671        }
672
673        public int getIndex(java.lang.Object object) {
674            return  ((GeneralName) object).tag;
675        }
676
677        @Override public Object getDecodedObject(BerInputStream in) throws IOException {
678            GeneralName result;
679            switch (in.choiceIndex) {
680                case OTHER_NAME: // OtherName
681                    result = new GeneralName((OtherName) in.content);
682                    break;
683                case RFC822_NAME: // rfc822Name
684                case DNS_NAME: // dNSName
685                    result = new GeneralName(in.choiceIndex, (String) in.content);
686                    break;
687                case X400_ADDR:
688                    result = new GeneralName((ORAddress) in.content);
689                    break;
690                case DIR_NAME: // directoryName (X.500 Name)
691                    result = new GeneralName((Name) in.content);
692                    break;
693                case EDIP_NAME: // ediPartyName
694                    result = new GeneralName((EDIPartyName) in.content);
695                    break;
696                case UR_ID: // uniformResourceIdentifier
697                    String uri = (String) in.content;
698                    if (uri.indexOf(":") == -1) {
699                        throw new IOException("GeneralName: scheme is missing in URI: " + uri);
700                    }
701                    result = new GeneralName(in.choiceIndex, uri);
702                    break;
703                case IP_ADDR: // iPAddress
704                    result = new GeneralName((byte[]) in.content);
705                    break;
706                case REG_ID: // registeredID
707                    result = new GeneralName(in.choiceIndex,
708                            ObjectIdentifier.toString((int[]) in.content));
709                    break;
710                default:
711                    throw new IOException("GeneralName: unknown tag: " + in.choiceIndex);
712            }
713            result.encoding = in.getEncoded();
714            return result;
715        }
716    };
717}
718