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