Home | History | Annotate | Download | only in x509
      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 
     23 package org.apache.harmony.security.x509;
     24 
     25 import java.io.IOException;
     26 import java.net.InetAddress;
     27 import java.net.URI;
     28 import java.net.URISyntaxException;
     29 import java.net.UnknownHostException;
     30 import java.util.ArrayList;
     31 import java.util.Arrays;
     32 import java.util.Collections;
     33 import java.util.List;
     34 import java.util.Locale;
     35 import javax.security.auth.x500.X500Principal;
     36 import org.apache.harmony.security.asn1.ASN1Choice;
     37 import org.apache.harmony.security.asn1.ASN1Implicit;
     38 import org.apache.harmony.security.asn1.ASN1OctetString;
     39 import org.apache.harmony.security.asn1.ASN1Oid;
     40 import org.apache.harmony.security.asn1.ASN1StringType;
     41 import org.apache.harmony.security.asn1.ASN1Type;
     42 import org.apache.harmony.security.asn1.BerInputStream;
     43 import org.apache.harmony.security.asn1.ObjectIdentifier;
     44 import org.apache.harmony.security.utils.Array;
     45 import 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  */
     96 public 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 (at) 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