| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @author Vladimir N. Molotkov, Alexander Y. Kleymenov |
| * @version $Revision$ |
| */ |
| |
| package org.apache.harmony.security.x509; |
| |
| import java.io.IOException; |
| import java.net.InetAddress; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.UnknownHostException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Locale; |
| import javax.security.auth.x500.X500Principal; |
| import org.apache.harmony.security.asn1.ASN1Choice; |
| import org.apache.harmony.security.asn1.ASN1Implicit; |
| import org.apache.harmony.security.asn1.ASN1OctetString; |
| import org.apache.harmony.security.asn1.ASN1Oid; |
| import org.apache.harmony.security.asn1.ASN1SequenceOf; |
| import org.apache.harmony.security.asn1.ASN1StringType; |
| import org.apache.harmony.security.asn1.ASN1Type; |
| import org.apache.harmony.security.asn1.BerInputStream; |
| import org.apache.harmony.security.asn1.ObjectIdentifier; |
| import org.apache.harmony.security.utils.Array; |
| import org.apache.harmony.security.x501.Name; |
| |
| /** |
| * The class encapsulates the ASN.1 DER encoding/decoding work |
| * with the GeneralName structure which is a part of X.509 certificate |
| * (as specified in RFC 3280 - |
| * Internet X.509 Public Key Infrastructure. |
| * Certificate and Certificate Revocation List (CRL) Profile. |
| * http://www.ietf.org/rfc/rfc3280.txt): |
| * |
| * <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 |
| * } |
| * |
| * DirectoryString::= CHOICE { |
| * teletexString TeletexString (SIZE (1..MAX)), |
| * printableString PrintableString (SIZE (1..MAX)), |
| * universalString UniversalString (SIZE (1..MAX)), |
| * utf8String UTF8String (SIZE (1..MAX)), |
| * bmpString BMPString (SIZE (1..MAX)) |
| * } |
| * |
| * </pre> |
| * |
| * <p>This class doesn't support masked addresses like "10.9.8.0/255.255.255.0". |
| * These are only necessary for NameConstraints, which are not exposed in the |
| * Java certificate API. |
| * |
| * @see org.apache.harmony.security.x509.NameConstraints |
| * @see org.apache.harmony.security.x509.GeneralSubtree |
| */ |
| public final class GeneralName { |
| |
| /** |
| * The values of the tags of fields |
| */ |
| public static final int OTHER_NAME = 0; |
| public static final int RFC822_NAME = 1; |
| public static final int DNS_NAME = 2; |
| public static final int X400_ADDR = 3; |
| public static final int DIR_NAME = 4; |
| public static final int EDIP_NAME = 5; |
| public static final int UR_ID = 6; |
| public static final int IP_ADDR = 7; |
| public static final int REG_ID = 8; |
| |
| // ASN1 encoders/decoders for name choices |
| private static ASN1Type[] nameASN1 = new ASN1Type[9]; |
| |
| static { |
| nameASN1[OTHER_NAME] = OtherName.ASN1; |
| nameASN1[RFC822_NAME] = ASN1StringType.IA5STRING; |
| nameASN1[DNS_NAME] = ASN1StringType.IA5STRING; |
| nameASN1[UR_ID] = ASN1StringType.IA5STRING; |
| nameASN1[X400_ADDR] = ORAddress.ASN1; |
| nameASN1[DIR_NAME] = Name.ASN1; |
| nameASN1[EDIP_NAME] = EDIPartyName.ASN1; |
| nameASN1[IP_ADDR] = ASN1OctetString.getInstance(); |
| nameASN1[REG_ID] = ASN1Oid.getInstance(); |
| } |
| |
| /** the tag of the name type */ |
| private int tag; |
| /** the name value (can be String or byte array) */ |
| private Object name; |
| /** the ASN.1 encoded form of GeneralName */ |
| private byte[] encoding; |
| /** the ASN.1 encoded form of GeneralName's field */ |
| private byte[] name_encoding; |
| |
| /** |
| * Makes the GeneralName object from the tag type and corresponding |
| * well established string representation of the name value. |
| * The String representation of [7] iPAddress is such as: |
| * For IP v4, as specified in RFC 791, the address must |
| * contain exactly 4 byte component. For IP v6, as specified in |
| * RFC 1883, the address must contain exactly 16 byte component. |
| * If GeneralName structure is used as a part of Name Constraints |
| * extension, to represent an address range the number of address |
| * component is doubled (to 8 and 32 bytes respectively). |
| * Note that the names: |
| * [0] otherName, [3] x400Address, [5] ediPartyName |
| * have no the string representation, so exception will be thrown. |
| * To make the GeneralName object with such names use another constructor. |
| * @param tag is an integer which value corresponds to the name type. |
| * @param name is a name value corresponding to the tag. |
| */ |
| public GeneralName(int tag, String name) throws IOException { |
| if (name == null) { |
| throw new IOException("name == null"); |
| } |
| this.tag = tag; |
| switch (tag) { |
| case OTHER_NAME : |
| case X400_ADDR : |
| case EDIP_NAME : |
| throw new IOException("Unknown string representation for type [" + tag + "]"); |
| case DNS_NAME : |
| // according to RFC 3280 p.34 the DNS name should be |
| // checked against the |
| // RFC 1034 p.10 (3.5. Preferred name syntax): |
| checkDNS(name); |
| this.name = name; |
| break; |
| case UR_ID : |
| // check the uniformResourceIdentifier for correctness |
| // according to RFC 3280 p.34 |
| checkURI(name); |
| this.name = name; |
| break; |
| case RFC822_NAME : |
| this.name = name; |
| break; |
| case REG_ID: |
| this.name = oidStrToInts(name); |
| break; |
| case DIR_NAME : |
| this.name = new Name(name); |
| break; |
| case IP_ADDR : |
| this.name = ipStrToBytes(name); |
| break; |
| default: |
| throw new IOException("Unknown type: [" + tag + "]"); |
| } |
| } |
| |
| public GeneralName(OtherName name) { |
| this.tag = OTHER_NAME; |
| this.name = name; |
| } |
| |
| public GeneralName(ORAddress name) { |
| this.tag = X400_ADDR; |
| this.name = name; |
| } |
| |
| public GeneralName(Name name) { |
| this.tag = DIR_NAME; |
| this.name = name; |
| } |
| |
| public GeneralName(EDIPartyName name) { |
| this.tag = EDIP_NAME; |
| this.name = name; |
| } |
| /** |
| * Constructor for type [7] iPAddress. |
| * name is an array of bytes such as: |
| * For IP v4, as specified in RFC 791, the address must |
| * contain exactly 4 byte component. For IP v6, as specified in |
| * RFC 1883, the address must contain exactly 16 byte component. |
| * If GeneralName structure is used as a part of Name Constraints |
| * extension, to represent an address range the number of address |
| * component is doubled (to 8 and 32 bytes respectively). |
| */ |
| public GeneralName(byte[] name) throws IllegalArgumentException { |
| this.tag = IP_ADDR; |
| this.name = new byte[name.length]; |
| System.arraycopy(name, 0, this.name, 0, name.length); |
| } |
| |
| /** |
| * Constructs an object representing the value of GeneralName. |
| * @param tag is an integer which value corresponds |
| * to the name type (0-8), |
| * @param name is a DER encoded for of the name value |
| */ |
| public GeneralName(int tag, byte[] name) throws IOException { |
| if (name == null) { |
| throw new NullPointerException("name == null"); |
| } |
| if ((tag < 0) || (tag > 8)) { |
| throw new IOException("GeneralName: unknown tag: " + tag); |
| } |
| this.tag = tag; |
| this.name_encoding = new byte[name.length]; |
| System.arraycopy(name, 0, this.name_encoding, 0, name.length); |
| this.name = nameASN1[tag].decode(this.name_encoding); |
| } |
| |
| /** |
| * Returns the tag of the name in the structure |
| */ |
| public int getTag() { |
| return tag; |
| } |
| |
| /** |
| * @return the value of the name. |
| * The class of name object depends on the tag as follows: |
| * [0] otherName - OtherName object, |
| * [1] rfc822Name - String object, |
| * [2] dNSName - String object, |
| * [3] x400Address - ORAddress object, |
| * [4] directoryName - instance of Name object, |
| * [5] ediPartyName - EDIPartyName object, |
| * [6] uniformResourceIdentifier - String object, |
| * [7] iPAddress - array of bytes such as: |
| * For IP v4, as specified in RFC 791, the address must |
| * contain exactly 4 byte component. For IP v6, as specified in |
| * RFC 1883, the address must contain exactly 16 byte component. |
| * If GeneralName structure is used as a part of Name Constraints |
| * extension, to represent an address range the number of address |
| * component is doubled (to 8 and 32 bytes respectively). |
| * [8] registeredID - String. |
| */ |
| public Object getName() { |
| return name; |
| } |
| |
| public boolean equals(Object other) { |
| if (!(other instanceof GeneralName)) { |
| return false; |
| } |
| GeneralName gname = (GeneralName) other; |
| if (this.tag != gname.tag) { |
| return false; |
| } |
| switch(tag) { |
| case RFC822_NAME: |
| case DNS_NAME: |
| case UR_ID: |
| return ((String) name).equalsIgnoreCase( |
| (String) gname.getName()); |
| case REG_ID: |
| return Arrays.equals((int[]) name, (int[]) gname.name); |
| case IP_ADDR: |
| // iPAddress [7], check by using ranges. |
| return Arrays.equals((byte[]) name, (byte[]) gname.name); |
| case DIR_NAME: |
| case X400_ADDR: |
| case OTHER_NAME: |
| case EDIP_NAME: |
| return Arrays.equals(getEncoded(), gname.getEncoded()); |
| default: |
| // should never happen |
| } |
| return false; |
| } |
| |
| public int hashCode() { |
| switch (tag) { |
| case RFC822_NAME: |
| case DNS_NAME: |
| case UR_ID: |
| case REG_ID: |
| case IP_ADDR: |
| return name.hashCode(); |
| case DIR_NAME: |
| case X400_ADDR: |
| case OTHER_NAME: |
| case EDIP_NAME: |
| return Arrays.hashCode(getEncoded()); |
| default: |
| return super.hashCode(); |
| } |
| } |
| |
| /** |
| * Checks if the other general name is acceptable by this object. |
| * The name is acceptable if it has the same type name and its |
| * name value is equal to name value of this object. Also the name |
| * is acceptable if this general name object is a part of name |
| * constraints and the specified name is satisfied the restriction |
| * provided by this object (for more detail see section 4.2.1.11 |
| * of rfc 3280). |
| * Note that for X400Address [3] check procedure is unclear so method |
| * just checks the equality of encoded forms. |
| * For otherName [0], ediPartyName [5], and registeredID [8] |
| * the check procedure if not defined by rfc 3280 and for names of |
| * these types this method also checks only for equality of encoded forms. |
| */ |
| public boolean isAcceptable(GeneralName gname) { |
| if (this.tag != gname.getTag()) { |
| return false; |
| } |
| switch (this.tag) { |
| case RFC822_NAME: |
| // Mail address [1]: |
| // a@b.c - particular address is acceptable by the same address, |
| // or by b.c - host name. |
| return ((String) gname.getName()).toLowerCase(Locale.US) |
| .endsWith(((String) name).toLowerCase(Locale.US)); |
| case DNS_NAME: |
| // DNS name [2] that can be constructed by simply adding |
| // to the left hand side of the name satisfies the name |
| // constraint: aaa.aa.aa satisfies to aaa.aa.aa, aa.aa, .. |
| String dns = (String) name; |
| String _dns = (String) gname.getName(); |
| if (dns.equalsIgnoreCase(_dns)) { |
| return true; |
| } else { |
| return _dns.toLowerCase(Locale.US).endsWith("." + dns.toLowerCase(Locale.US)); |
| } |
| case UR_ID: |
| // For URIs the constraint ".xyz.com" is satisfied by both |
| // abc.xyz.com and abc.def.xyz.com. However, the constraint |
| // ".xyz.com" is not satisfied by "xyz.com". |
| // When the constraint does not begin with a period, it |
| // specifies a host. |
| // Extract the host from URI: |
| String uri = (String) name; |
| int begin = uri.indexOf("://")+3; |
| int end = uri.indexOf('/', begin); |
| String host = (end == -1) |
| ? uri.substring(begin) |
| : uri.substring(begin, end); |
| uri = (String) gname.getName(); |
| begin = uri.indexOf("://")+3; |
| end = uri.indexOf('/', begin); |
| String _host = (end == -1) |
| ? uri.substring(begin) |
| : uri.substring(begin, end); |
| if (host.startsWith(".")) { |
| return _host.toLowerCase(Locale.US).endsWith(host.toLowerCase(Locale.US)); |
| } else { |
| return host.equalsIgnoreCase(_host); |
| } |
| case IP_ADDR: |
| // iPAddress [7], check by using ranges. |
| byte[] address = (byte[]) name; |
| byte[] _address = (byte[]) gname.getName(); |
| int length = address.length; |
| |
| /* |
| * For IP v4, as specified in RFC 791, the address must contain |
| * exactly 4 byte component. For IP v6, as specified in RFC |
| * 1883, the address must contain exactly 16 byte component. If |
| * GeneralName structure is used as a part of Name Constraints |
| * extension, to represent an address range the number of |
| * address component is doubled (to 8 and 32 bytes |
| * respectively). |
| */ |
| if (length != 4 && length != 8 && length != 16 && length != 32) { |
| return false; |
| } |
| |
| int _length = _address.length; |
| if (length == _length) { |
| return Arrays.equals(address, _address); |
| } else if (length == 2*_length) { |
| for (int i = 0; i < _address.length; i++) { |
| // TODO: should the 2nd IP address be treated as a range or as a mask? |
| int octet = _address[i] & 0xff; |
| int min = address[i] & 0xff; |
| int max = address[i + _length] & 0xff; |
| if ((octet < min) || (octet > max)) { |
| return false; |
| } |
| } |
| return true; |
| } else { |
| return false; |
| } |
| case DIR_NAME: |
| // FIXME: false: |
| // directoryName according to 4.1.2.4 |
| // comparing the encoded forms of the names |
| //TODO: |
| //Legacy implementations exist where an RFC 822 name |
| //is embedded in the subject distinguished name in an |
| //attribute of type EmailAddress |
| case X400_ADDR: |
| case OTHER_NAME: |
| case EDIP_NAME: |
| case REG_ID: |
| return Arrays.equals(getEncoded(), gname.getEncoded()); |
| default: |
| // should never happen |
| } |
| return true; |
| } |
| |
| /** |
| * Gets a list representation of this GeneralName object. |
| * The first entry of the list is an Integer object representing |
| * the type of mane (0-8), and the second entry is a value of the name: |
| * string or ASN.1 DER encoded form depending on the type as follows: |
| * rfc822Name, dNSName, uniformResourceIdentifier names are returned |
| * as Strings, using the string formats for those types (rfc 3280) |
| * IP v4 address names are returned using dotted quad notation. |
| * IP v6 address names are returned in the form "p1:p2:...:p8", |
| * where p1-p8 are hexadecimal values representing the eight 16-bit |
| * pieces of the address. registeredID name are returned as Strings |
| * represented as a series of nonnegative integers separated by periods. |
| * And directory names (distinguished names) are returned in |
| * RFC 2253 string format. |
| * otherName, X400Address, ediPartyName returned as byte arrays |
| * containing the ASN.1 DER encoded form of the name. |
| */ |
| public List<Object> getAsList() { |
| ArrayList<Object> result = new ArrayList<Object>(); |
| result.add(tag); |
| switch (tag) { |
| case OTHER_NAME: |
| result.add(((OtherName) name).getEncoded()); |
| break; |
| case RFC822_NAME: |
| case DNS_NAME: |
| case UR_ID: |
| result.add(name); // String |
| break; |
| case REG_ID: |
| result.add(ObjectIdentifier.toString((int[]) name)); |
| break; |
| case X400_ADDR: |
| result.add(((ORAddress) name).getEncoded()); |
| break; |
| case DIR_NAME: // directoryName is returned as a String |
| result.add(((Name) name).getName(X500Principal.RFC2253)); |
| break; |
| case EDIP_NAME: |
| result.add(((EDIPartyName) name).getEncoded()); |
| break; |
| case IP_ADDR: //iPAddress is returned as a String, not as a byte array |
| result.add(ipBytesToStr((byte[]) name)); |
| break; |
| default: |
| // should never happen |
| } |
| return Collections.unmodifiableList(result); |
| } |
| |
| public String toString() { |
| String result = ""; |
| switch (tag) { |
| case OTHER_NAME: |
| result = "otherName[0]: " |
| + Array.getBytesAsString(getEncoded()); |
| break; |
| case RFC822_NAME: |
| result = "rfc822Name[1]: " + name; |
| break; |
| case DNS_NAME: |
| result = "dNSName[2]: " + name; |
| break; |
| case UR_ID: |
| result = "uniformResourceIdentifier[6]: " + name; |
| break; |
| case REG_ID: |
| result = "registeredID[8]: " + ObjectIdentifier.toString((int[]) name); |
| break; |
| case X400_ADDR: |
| result = "x400Address[3]: " |
| + Array.getBytesAsString(getEncoded()); |
| break; |
| case DIR_NAME: |
| result = "directoryName[4]: " |
| + ((Name) name).getName(X500Principal.RFC2253); |
| break; |
| case EDIP_NAME: |
| result = "ediPartyName[5]: " |
| + Array.getBytesAsString(getEncoded()); |
| break; |
| case IP_ADDR: |
| result = "iPAddress[7]: " + ipBytesToStr((byte[]) name); |
| break; |
| default: |
| // should never happen |
| } |
| return result; |
| } |
| |
| /** |
| * Returns ASN.1 encoded form of this X.509 GeneralName value. |
| */ |
| public byte[] getEncoded() { |
| if (encoding == null) { |
| encoding = ASN1.encode(this); |
| } |
| return encoding; |
| } |
| |
| /** |
| * @return the encoded value of the name without the tag associated |
| * with the name in the GeneralName structure |
| * @throws IOException |
| */ |
| public byte[] getEncodedName() { |
| if (name_encoding == null) { |
| name_encoding = nameASN1[tag].encode(name); |
| } |
| return name_encoding; |
| } |
| |
| /** |
| * Checks the correctness of the string representation of DNS name as |
| * specified in RFC 1034 p. 10 and RFC 1123 section 2.1. |
| * |
| * <p>This permits a wildcard character '*' anywhere in the name; it is up |
| * to the application to check which wildcards are permitted. See RFC 6125 |
| * for recommended wildcard matching rules. |
| */ |
| public static void checkDNS(String dns) throws IOException { |
| String string = dns.toLowerCase(Locale.US); |
| int length = string.length(); |
| // indicates if it is a first letter of the label |
| boolean first_letter = true; |
| for (int i = 0; i < length; i++) { |
| char ch = string.charAt(i); |
| if (first_letter) { |
| if ((ch > 'z' || ch < 'a') && (ch < '0' || ch > '9') && (ch != '*')) { |
| throw new IOException("DNS name must start with a letter: " + dns); |
| } |
| first_letter = false; |
| continue; |
| } |
| if (!((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') |
| || (ch == '-') || (ch == '.') || (ch == '*'))) { |
| throw new IOException("Incorrect DNS name: " + dns); |
| } |
| if (ch == '.') { |
| // check the end of the previous label, it should not |
| // be '-' sign |
| if (string.charAt(i-1) == '-') { |
| throw new IOException("Incorrect DNS name: label ends with '-': " + dns); |
| } |
| first_letter = true; |
| } |
| } |
| } |
| |
| /** |
| * Checks the correctness of the string representation of URI name. |
| * The correctness is checked as pointed out in RFC 3280 p. 34. |
| */ |
| public static void checkURI(String uri) throws IOException { |
| try { |
| URI ur = new URI(uri); |
| if (ur.getScheme() == null || ur.getRawSchemeSpecificPart().isEmpty()) { |
| throw new IOException("No scheme or scheme-specific-part in uniformResourceIdentifier: " + uri); |
| } |
| if (!ur.isAbsolute()) { |
| throw new IOException("Relative uniformResourceIdentifier: " + uri); |
| } |
| } catch (URISyntaxException e) { |
| throw (IOException) new IOException("Bad representation of uniformResourceIdentifier: " + uri).initCause(e); |
| |
| } |
| } |
| |
| /** |
| * Converts OID into array of ints. |
| */ |
| public static int[] oidStrToInts(String oid) throws IOException { |
| int length = oid.length(); |
| if (oid.charAt(length-1) == '.') { |
| throw new IOException("Bad OID: " + oid); |
| } |
| int[] result = new int[length/2+1]; // best case: a.b.c.d.e |
| int number = 0; // the number of OID's components |
| for (int i = 0; i < length; i++) { |
| int value = 0; |
| int pos = i; |
| for (; i < length; i++) { |
| char ch = oid.charAt(i); |
| if ((ch < '0') || (ch > '9')) { |
| break; |
| } |
| value = 10 * value + (ch - '0'); |
| } |
| if (i == pos) { |
| // the number was not read |
| throw new IOException("Bad OID: " + oid); |
| } |
| result[number++] = value; |
| if (i == length) { |
| break; |
| } |
| char ch = oid.charAt(i); |
| if (ch != '.') { |
| throw new IOException("Bad OID: " + oid); |
| } |
| } |
| if (number < 2) { |
| throw new IOException("OID should consist of no less than 2 components: " + oid); |
| } |
| return Arrays.copyOfRange(result, 0, number); |
| } |
| |
| /** |
| * Returns the bytes of the given IP address or masked IP address. |
| */ |
| public static byte[] ipStrToBytes(String ip) throws IOException { |
| if (!InetAddress.isNumeric(ip)) { |
| throw new IOException("Not an IP address: " + ip); |
| } |
| return InetAddress.getByName(ip).getAddress(); |
| } |
| |
| /** |
| * Returns the string form of the given IP address. If the address is not 4 |
| * octets for IPv4 or 16 octets for IPv6, an IllegalArgumentException will |
| * be thrown. |
| */ |
| public static String ipBytesToStr(byte[] ip) { |
| try { |
| return InetAddress.getByAddress(null, ip).getHostAddress(); |
| } catch (UnknownHostException e) { |
| throw new IllegalArgumentException("Unexpected IP address: " + Arrays.toString(ip)); |
| } |
| } |
| |
| /** |
| * The "Name" is actually a CHOICE of one entry, so we need to pretend it's |
| * a SEQUENCE OF and just grab the first entry. |
| */ |
| private static final ASN1SequenceOf NAME_ASN1 = new ASN1SequenceOf(Name.ASN1) { |
| @Override |
| public Object decode(BerInputStream in) throws IOException { |
| return ((List<?>) super.decode(in)).get(0); |
| } |
| }; |
| |
| public static final ASN1Choice ASN1 = new ASN1Choice(new ASN1Type[] { |
| new ASN1Implicit(0, OtherName.ASN1), |
| new ASN1Implicit(1, ASN1StringType.IA5STRING), |
| new ASN1Implicit(2, ASN1StringType.IA5STRING), |
| new ASN1Implicit(3, ORAddress.ASN1), |
| new ASN1Implicit(4, NAME_ASN1), |
| new ASN1Implicit(5, EDIPartyName.ASN1), |
| new ASN1Implicit(6, ASN1StringType.IA5STRING), |
| new ASN1Implicit(7, ASN1OctetString.getInstance()), |
| new ASN1Implicit(8, ASN1Oid.getInstance()) }) { |
| |
| public Object getObjectToEncode(Object value) { |
| return ((GeneralName) value).name; |
| } |
| |
| public int getIndex(java.lang.Object object) { |
| return ((GeneralName) object).tag; |
| } |
| |
| @Override public Object getDecodedObject(BerInputStream in) throws IOException { |
| GeneralName result; |
| switch (in.choiceIndex) { |
| case OTHER_NAME: // OtherName |
| result = new GeneralName((OtherName) in.content); |
| break; |
| case RFC822_NAME: // rfc822Name |
| case DNS_NAME: // dNSName |
| result = new GeneralName(in.choiceIndex, (String) in.content); |
| break; |
| case X400_ADDR: |
| result = new GeneralName((ORAddress) in.content); |
| break; |
| case DIR_NAME: // directoryName (X.500 Name) |
| result = new GeneralName((Name) in.content); |
| break; |
| case EDIP_NAME: // ediPartyName |
| result = new GeneralName((EDIPartyName) in.content); |
| break; |
| case UR_ID: // uniformResourceIdentifier |
| String uri = (String) in.content; |
| if (uri.indexOf(":") == -1) { |
| throw new IOException("GeneralName: scheme is missing in URI: " + uri); |
| } |
| result = new GeneralName(in.choiceIndex, uri); |
| break; |
| case IP_ADDR: // iPAddress |
| result = new GeneralName((byte[]) in.content); |
| break; |
| case REG_ID: // registeredID |
| result = new GeneralName(in.choiceIndex, |
| ObjectIdentifier.toString((int[]) in.content)); |
| break; |
| default: |
| throw new IOException("GeneralName: unknown tag: " + in.choiceIndex); |
| } |
| result.encoding = in.getEncoded(); |
| return result; |
| } |
| }; |
| } |