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. 543 * The correctness is checked as specified in RFC 1034 p. 10, and modified 544 * by RFC 1123 (section 2.1). 545 */ 546 public static void checkDNS(String dns) throws IOException { 547 String string = dns.toLowerCase(Locale.US); 548 int length = string.length(); 549 // indicates if it is a first letter of the label 550 boolean first_letter = true; 551 for (int i = 0; i < length; i++) { 552 char ch = string.charAt(i); 553 if (first_letter) { 554 if ((length > 2) && (ch == '*') && (string.charAt(1) == '.')) { 555 first_letter = false; 556 continue; 557 } 558 if ((ch > 'z' || ch < 'a') && (ch < '0' || ch > '9')) { 559 throw new IOException("DNS name must start with a letter: " + dns); 560 } 561 first_letter = false; 562 continue; 563 } 564 if (!((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') 565 || (ch == '-') || (ch == '.'))) { 566 throw new IOException("Incorrect DNS name: " + dns); 567 } 568 if (ch == '.') { 569 // check the end of the previous label, it should not 570 // be '-' sign 571 if (string.charAt(i-1) == '-') { 572 throw new IOException("Incorrect DNS name: label ends with '-': " + dns); 573 } 574 first_letter = true; 575 } 576 } 577 } 578 579 /** 580 * Checks the correctness of the string representation of URI name. 581 * The correctness is checked as pointed out in RFC 3280 p. 34. 582 */ 583 public static void checkURI(String uri) throws IOException { 584 try { 585 URI ur = new URI(uri); 586 if (ur.getScheme() == null || ur.getRawSchemeSpecificPart().isEmpty()) { 587 throw new IOException("No scheme or scheme-specific-part in uniformResourceIdentifier: " + uri); 588 } 589 if (!ur.isAbsolute()) { 590 throw new IOException("Relative uniformResourceIdentifier: " + uri); 591 } 592 } catch (URISyntaxException e) { 593 throw (IOException) new IOException("Bad representation of uniformResourceIdentifier: " + uri).initCause(e); 594 595 } 596 } 597 598 /** 599 * Converts OID into array of ints. 600 */ 601 public static int[] oidStrToInts(String oid) throws IOException { 602 int length = oid.length(); 603 if (oid.charAt(length-1) == '.') { 604 throw new IOException("Bad OID: " + oid); 605 } 606 int[] result = new int[length/2+1]; // best case: a.b.c.d.e 607 int number = 0; // the number of OID's components 608 for (int i = 0; i < length; i++) { 609 int value = 0; 610 int pos = i; 611 for (; i < length; i++) { 612 char ch = oid.charAt(i); 613 if ((ch < '0') || (ch > '9')) { 614 break; 615 } 616 value = 10 * value + (ch - '0'); 617 } 618 if (i == pos) { 619 // the number was not read 620 throw new IOException("Bad OID: " + oid); 621 } 622 result[number++] = value; 623 if (i == length) { 624 break; 625 } 626 char ch = oid.charAt(i); 627 if (ch != '.') { 628 throw new IOException("Bad OID: " + oid); 629 } 630 } 631 if (number < 2) { 632 throw new IOException("OID should consist of no less than 2 components: " + oid); 633 } 634 return Arrays.copyOfRange(result, 0, number); 635 } 636 637 /** 638 * Returns the bytes of the given IP address or masked IP address. 639 */ 640 public static byte[] ipStrToBytes(String ip) throws IOException { 641 if (!InetAddress.isNumeric(ip)) { 642 throw new IOException("Not an IP address: " + ip); 643 } 644 return InetAddress.getByName(ip).getAddress(); 645 } 646 647 /** 648 * Returns the string form of the given IP address. Addresses of length 2x 649 * the canonical length are treated as a route/mask pair. 650 */ 651 public static String ipBytesToStr(byte[] ip) { 652 try { 653 return InetAddress.getByAddress(null, ip).getHostAddress(); 654 } catch (UnknownHostException e) { 655 throw new IllegalArgumentException("Unexpected IP address: " + Arrays.toString(ip)); 656 } 657 } 658 659 public static final ASN1Choice ASN1 = new ASN1Choice(new ASN1Type[] { 660 new ASN1Implicit(0, OtherName.ASN1), 661 new ASN1Implicit(1, ASN1StringType.IA5STRING), 662 new ASN1Implicit(2, ASN1StringType.IA5STRING), 663 new ASN1Implicit(3, ORAddress.ASN1), 664 new ASN1Implicit(4, Name.ASN1), 665 new ASN1Implicit(5, EDIPartyName.ASN1), 666 new ASN1Implicit(6, ASN1StringType.IA5STRING), 667 new ASN1Implicit(7, ASN1OctetString.getInstance()), 668 new ASN1Implicit(8, ASN1Oid.getInstance()) }) { 669 670 public Object getObjectToEncode(Object value) { 671 return ((GeneralName) value).name; 672 } 673 674 public int getIndex(java.lang.Object object) { 675 return ((GeneralName) object).tag; 676 } 677 678 @Override public Object getDecodedObject(BerInputStream in) throws IOException { 679 GeneralName result; 680 switch (in.choiceIndex) { 681 case OTHER_NAME: // OtherName 682 result = new GeneralName((OtherName) in.content); 683 break; 684 case RFC822_NAME: // rfc822Name 685 case DNS_NAME: // dNSName 686 result = new GeneralName(in.choiceIndex, (String) in.content); 687 break; 688 case X400_ADDR: 689 result = new GeneralName((ORAddress) in.content); 690 break; 691 case DIR_NAME: // directoryName (X.500 Name) 692 result = new GeneralName((Name) in.content); 693 break; 694 case EDIP_NAME: // ediPartyName 695 result = new GeneralName((EDIPartyName) in.content); 696 break; 697 case UR_ID: // uniformResourceIdentifier 698 String uri = (String) in.content; 699 if (uri.indexOf(":") == -1) { 700 throw new IOException("GeneralName: scheme is missing in URI: " + uri); 701 } 702 result = new GeneralName(in.choiceIndex, uri); 703 break; 704 case IP_ADDR: // iPAddress 705 result = new GeneralName((byte[]) in.content); 706 break; 707 case REG_ID: // registeredID 708 result = new GeneralName(in.choiceIndex, 709 ObjectIdentifier.toString((int[]) in.content)); 710 break; 711 default: 712 throw new IOException("GeneralName: unknown tag: " + in.choiceIndex); 713 } 714 result.encoding = in.getEncoded(); 715 return result; 716 } 717 }; 718 } 719