001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package org.apache.geronimo.util.asn1.x509; 020 021 import java.util.Enumeration; 022 import java.util.Hashtable; 023 import java.util.Vector; 024 025 import org.apache.geronimo.util.asn1.*; 026 import org.apache.geronimo.util.asn1.pkcs.PKCSObjectIdentifiers; 027 028 /** 029 * <pre> 030 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName 031 * 032 * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue 033 * 034 * AttributeTypeAndValue ::= SEQUENCE { 035 * type OBJECT IDENTIFIER, 036 * value ANY } 037 * </pre> 038 */ 039 public class X509Name 040 extends ASN1Encodable 041 { 042 /** 043 * country code - StringType(SIZE(2)) 044 */ 045 public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6"); 046 047 /** 048 * organization - StringType(SIZE(1..64)) 049 */ 050 public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10"); 051 052 /** 053 * organizational unit name - StringType(SIZE(1..64)) 054 */ 055 public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11"); 056 057 /** 058 * Title 059 */ 060 public static final DERObjectIdentifier T = new DERObjectIdentifier("2.5.4.12"); 061 062 /** 063 * common name - StringType(SIZE(1..64)) 064 */ 065 public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3"); 066 067 /** 068 * device serial number name - StringType(SIZE(1..64)) 069 */ 070 public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5"); 071 072 /** 073 * locality name - StringType(SIZE(1..64)) 074 */ 075 public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7"); 076 077 /** 078 * state, or province name - StringType(SIZE(1..64)) 079 */ 080 public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8"); 081 082 /** 083 * Naming attributes of type X520name 084 */ 085 public static final DERObjectIdentifier SURNAME = new DERObjectIdentifier("2.5.4.4"); 086 public static final DERObjectIdentifier GIVENNAME = new DERObjectIdentifier("2.5.4.42"); 087 public static final DERObjectIdentifier INITIALS = new DERObjectIdentifier("2.5.4.43"); 088 public static final DERObjectIdentifier GENERATION = new DERObjectIdentifier("2.5.4.44"); 089 public static final DERObjectIdentifier UNIQUE_IDENTIFIER = new DERObjectIdentifier("2.5.4.45"); 090 091 /** 092 * Email address (RSA PKCS#9 extension) - IA5String. 093 * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. 094 */ 095 public static final DERObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress; 096 097 /** 098 * more from PKCS#9 099 */ 100 public static final DERObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName; 101 public static final DERObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress; 102 103 /** 104 * email address in Verisign certificates 105 */ 106 public static final DERObjectIdentifier E = EmailAddress; 107 108 /* 109 * others... 110 */ 111 public static final DERObjectIdentifier DC = new DERObjectIdentifier("0.9.2342.19200300.100.1.25"); 112 113 /** 114 * LDAP User id. 115 */ 116 public static final DERObjectIdentifier UID = new DERObjectIdentifier("0.9.2342.19200300.100.1.1"); 117 118 /** 119 * look up table translating OID values into their common symbols - this static is scheduled for deletion 120 */ 121 public static Hashtable OIDLookUp = new Hashtable(); 122 123 /** 124 * determines whether or not strings should be processed and printed 125 * from back to front. 126 */ 127 public static boolean DefaultReverse = false; 128 129 /** 130 * default look up table translating OID values into their common symbols following 131 * the convention in RFC 2253 with a few extras 132 */ 133 public static Hashtable DefaultSymbols = OIDLookUp; 134 135 /** 136 * look up table translating OID values into their common symbols following the convention in RFC 2253 137 * with a few extras 138 */ 139 public static Hashtable RFC2253Symbols = new Hashtable(); 140 141 /** 142 * look up table translating string values into their OIDS - 143 * this static is scheduled for deletion 144 */ 145 public static Hashtable SymbolLookUp = new Hashtable(); 146 147 /** 148 * look up table translating common symbols into their OIDS. 149 */ 150 public static Hashtable DefaultLookUp = SymbolLookUp; 151 152 static 153 { 154 DefaultSymbols.put(C, "C"); 155 DefaultSymbols.put(O, "O"); 156 DefaultSymbols.put(T, "T"); 157 DefaultSymbols.put(OU, "OU"); 158 DefaultSymbols.put(CN, "CN"); 159 DefaultSymbols.put(L, "L"); 160 DefaultSymbols.put(ST, "ST"); 161 DefaultSymbols.put(SN, "SN"); 162 DefaultSymbols.put(EmailAddress, "E"); 163 DefaultSymbols.put(DC, "DC"); 164 DefaultSymbols.put(UID, "UID"); 165 DefaultSymbols.put(SURNAME, "SURNAME"); 166 DefaultSymbols.put(GIVENNAME, "GIVENNAME"); 167 DefaultSymbols.put(INITIALS, "INITIALS"); 168 DefaultSymbols.put(GENERATION, "GENERATION"); 169 DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress"); 170 DefaultSymbols.put(UnstructuredName, "unstructuredName"); 171 172 RFC2253Symbols.put(C, "C"); 173 RFC2253Symbols.put(O, "O"); 174 RFC2253Symbols.put(T, "T"); 175 RFC2253Symbols.put(OU, "OU"); 176 RFC2253Symbols.put(CN, "CN"); 177 RFC2253Symbols.put(L, "L"); 178 RFC2253Symbols.put(ST, "ST"); 179 RFC2253Symbols.put(SN, "SN"); 180 RFC2253Symbols.put(EmailAddress, "EMAILADDRESS"); 181 RFC2253Symbols.put(DC, "DC"); 182 RFC2253Symbols.put(UID, "UID"); 183 RFC2253Symbols.put(SURNAME, "SURNAME"); 184 RFC2253Symbols.put(GIVENNAME, "GIVENNAME"); 185 RFC2253Symbols.put(INITIALS, "INITIALS"); 186 RFC2253Symbols.put(GENERATION, "GENERATION"); 187 188 DefaultLookUp.put("c", C); 189 DefaultLookUp.put("o", O); 190 DefaultLookUp.put("t", T); 191 DefaultLookUp.put("ou", OU); 192 DefaultLookUp.put("cn", CN); 193 DefaultLookUp.put("l", L); 194 DefaultLookUp.put("st", ST); 195 DefaultLookUp.put("sn", SN); 196 DefaultLookUp.put("emailaddress", E); 197 DefaultLookUp.put("dc", DC); 198 DefaultLookUp.put("e", E); 199 DefaultLookUp.put("uid", UID); 200 DefaultLookUp.put("surname", SURNAME); 201 DefaultLookUp.put("givenname", GIVENNAME); 202 DefaultLookUp.put("initials", INITIALS); 203 DefaultLookUp.put("generation", GENERATION); 204 DefaultLookUp.put("unstructuredaddress", UnstructuredAddress); 205 DefaultLookUp.put("unstructuredname", UnstructuredName); 206 } 207 208 private X509NameEntryConverter converter = null; 209 private Vector ordering = new Vector(); 210 private Vector values = new Vector(); 211 private Vector added = new Vector(); 212 213 private ASN1Sequence seq; 214 215 /** 216 * Return a X509Name based on the passed in tagged object. 217 * 218 * @param obj tag object holding name. 219 * @param explicit true if explicitly tagged false otherwise. 220 * @return the X509Name 221 */ 222 public static X509Name getInstance( 223 ASN1TaggedObject obj, 224 boolean explicit) 225 { 226 return getInstance(ASN1Sequence.getInstance(obj, explicit)); 227 } 228 229 public static X509Name getInstance( 230 Object obj) 231 { 232 if (obj == null || obj instanceof X509Name) 233 { 234 return (X509Name)obj; 235 } 236 else if (obj instanceof ASN1Sequence) 237 { 238 return new X509Name((ASN1Sequence)obj); 239 } 240 241 throw new IllegalArgumentException("unknown object in factory"); 242 } 243 244 /** 245 * Constructor from ASN1Sequence 246 * 247 * the principal will be a list of constructed sets, each containing an (OID, String) pair. 248 */ 249 public X509Name( 250 ASN1Sequence seq) 251 { 252 this.seq = seq; 253 254 Enumeration e = seq.getObjects(); 255 256 while (e.hasMoreElements()) 257 { 258 ASN1Set set = (ASN1Set)e.nextElement(); 259 260 for (int i = 0; i < set.size(); i++) 261 { 262 ASN1Sequence s = (ASN1Sequence)set.getObjectAt(i); 263 264 ordering.addElement(s.getObjectAt(0)); 265 values.addElement(((DERString) s.getObjectAt(1)).getString()); 266 added.addElement((i != 0) ? new Boolean(true) : new Boolean(false)); 267 } 268 } 269 } 270 271 /** 272 * constructor from a table of attributes. 273 * <p> 274 * it's is assumed the table contains OID/String pairs, and the contents 275 * of the table are copied into an internal table as part of the 276 * construction process. 277 * <p> 278 * <b>Note:</b> if the name you are trying to generate should be 279 * following a specific ordering, you should use the constructor 280 * with the ordering specified below. 281 */ 282 public X509Name( 283 Hashtable attributes) 284 { 285 this(null, attributes); 286 } 287 288 /** 289 * Constructor from a table of attributes with ordering. 290 * <p> 291 * it's is assumed the table contains OID/String pairs, and the contents 292 * of the table are copied into an internal table as part of the 293 * construction process. The ordering vector should contain the OIDs 294 * in the order they are meant to be encoded or printed in toString. 295 */ 296 public X509Name( 297 Vector ordering, 298 Hashtable attributes) 299 { 300 this(ordering, attributes, new X509DefaultEntryConverter()); 301 } 302 303 /** 304 * Constructor from a table of attributes with ordering. 305 * <p> 306 * it's is assumed the table contains OID/String pairs, and the contents 307 * of the table are copied into an internal table as part of the 308 * construction process. The ordering vector should contain the OIDs 309 * in the order they are meant to be encoded or printed in toString. 310 * <p> 311 * The passed in converter will be used to convert the strings into their 312 * ASN.1 counterparts. 313 */ 314 public X509Name( 315 Vector ordering, 316 Hashtable attributes, 317 X509DefaultEntryConverter converter) 318 { 319 this.converter = converter; 320 321 if (ordering != null) 322 { 323 for (int i = 0; i != ordering.size(); i++) 324 { 325 this.ordering.addElement(ordering.elementAt(i)); 326 this.added.addElement(new Boolean(false)); 327 } 328 } 329 else 330 { 331 Enumeration e = attributes.keys(); 332 333 while (e.hasMoreElements()) 334 { 335 this.ordering.addElement(e.nextElement()); 336 this.added.addElement(new Boolean(false)); 337 } 338 } 339 340 for (int i = 0; i != this.ordering.size(); i++) 341 { 342 DERObjectIdentifier oid = (DERObjectIdentifier)this.ordering.elementAt(i); 343 344 if (attributes.get(oid) == null) 345 { 346 throw new IllegalArgumentException("No attribute for object id - " + oid.getId() + " - passed to distinguished name"); 347 } 348 349 this.values.addElement(attributes.get(oid)); // copy the hash table 350 } 351 } 352 353 /** 354 * Takes two vectors one of the oids and the other of the values. 355 */ 356 public X509Name( 357 Vector oids, 358 Vector values) 359 { 360 this(oids, values, new X509DefaultEntryConverter()); 361 } 362 363 /** 364 * Takes two vectors one of the oids and the other of the values. 365 * <p> 366 * The passed in converter will be used to convert the strings into their 367 * ASN.1 counterparts. 368 */ 369 public X509Name( 370 Vector oids, 371 Vector values, 372 X509NameEntryConverter converter) 373 { 374 this.converter = converter; 375 376 if (oids.size() != values.size()) 377 { 378 throw new IllegalArgumentException("oids vector must be same length as values."); 379 } 380 381 for (int i = 0; i < oids.size(); i++) 382 { 383 this.ordering.addElement(oids.elementAt(i)); 384 this.values.addElement(values.elementAt(i)); 385 this.added.addElement(new Boolean(false)); 386 } 387 } 388 389 /** 390 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 391 * some such, converting it into an ordered set of name attributes. 392 */ 393 public X509Name( 394 String dirName) 395 { 396 this(DefaultReverse, DefaultLookUp, dirName); 397 } 398 399 /** 400 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 401 * some such, converting it into an ordered set of name attributes with each 402 * string value being converted to its associated ASN.1 type using the passed 403 * in converter. 404 */ 405 public X509Name( 406 String dirName, 407 X509NameEntryConverter converter) 408 { 409 this(DefaultReverse, DefaultLookUp, dirName, converter); 410 } 411 412 /** 413 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 414 * some such, converting it into an ordered set of name attributes. If reverse 415 * is true, create the encoded version of the sequence starting from the 416 * last element in the string. 417 */ 418 public X509Name( 419 boolean reverse, 420 String dirName) 421 { 422 this(reverse, DefaultLookUp, dirName); 423 } 424 425 /** 426 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 427 * some such, converting it into an ordered set of name attributes with each 428 * string value being converted to its associated ASN.1 type using the passed 429 * in converter. If reverse is true the ASN.1 sequence representing the DN will 430 * be built by starting at the end of the string, rather than the start. 431 */ 432 public X509Name( 433 boolean reverse, 434 String dirName, 435 X509NameEntryConverter converter) 436 { 437 this(reverse, DefaultLookUp, dirName, converter); 438 } 439 440 /** 441 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 442 * some such, converting it into an ordered set of name attributes. lookUp 443 * should provide a table of lookups, indexed by lowercase only strings and 444 * yielding a DERObjectIdentifier, other than that OID. and numeric oids 445 * will be processed automatically. 446 * <br> 447 * If reverse is true, create the encoded version of the sequence 448 * starting from the last element in the string. 449 * @param reverse true if we should start scanning from the end (RFC 2553). 450 * @param lookUp table of names and their oids. 451 * @param dirName the X.500 string to be parsed. 452 */ 453 public X509Name( 454 boolean reverse, 455 Hashtable lookUp, 456 String dirName) 457 { 458 this(reverse, lookUp, dirName, new X509DefaultEntryConverter()); 459 } 460 461 private DERObjectIdentifier decodeOID( 462 String name, 463 Hashtable lookUp) 464 { 465 if (name.toUpperCase().startsWith("OID.")) 466 { 467 return new DERObjectIdentifier(name.substring(4)); 468 } 469 else if (name.charAt(0) >= '0' && name.charAt(0) <= '9') 470 { 471 return new DERObjectIdentifier(name); 472 } 473 474 DERObjectIdentifier oid = (DERObjectIdentifier)lookUp.get(name.toLowerCase()); 475 if (oid == null) 476 { 477 throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name"); 478 } 479 480 return oid; 481 } 482 483 /** 484 * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or 485 * some such, converting it into an ordered set of name attributes. lookUp 486 * should provide a table of lookups, indexed by lowercase only strings and 487 * yielding a DERObjectIdentifier, other than that OID. and numeric oids 488 * will be processed automatically. The passed in converter is used to convert the 489 * string values to the right of each equals sign to their ASN.1 counterparts. 490 * <br> 491 * @param reverse true if we should start scanning from the end, false otherwise. 492 * @param lookUp table of names and oids. 493 * @param dirName the string dirName 494 * @param converter the converter to convert string values into their ASN.1 equivalents 495 */ 496 public X509Name( 497 boolean reverse, 498 Hashtable lookUp, 499 String dirName, 500 X509NameEntryConverter converter) 501 { 502 this.converter = converter; 503 X509NameTokenizer nTok = new X509NameTokenizer(dirName); 504 505 while (nTok.hasMoreTokens()) 506 { 507 String token = nTok.nextToken(); 508 int index = token.indexOf('='); 509 510 if (index == -1) 511 { 512 throw new IllegalArgumentException("badly formated directory string"); 513 } 514 515 String name = token.substring(0, index); 516 String value = token.substring(index + 1); 517 DERObjectIdentifier oid = decodeOID(name, lookUp); 518 519 if (value.indexOf('+') > 0) 520 { 521 X509NameTokenizer vTok = new X509NameTokenizer(value, '+'); 522 523 this.ordering.addElement(oid); 524 this.values.addElement(vTok.nextToken()); 525 this.added.addElement(new Boolean(false)); 526 527 while (vTok.hasMoreTokens()) 528 { 529 String sv = vTok.nextToken(); 530 int ndx = sv.indexOf('='); 531 532 String nm = sv.substring(0, ndx); 533 String vl = sv.substring(ndx + 1); 534 this.ordering.addElement(decodeOID(nm, lookUp)); 535 this.values.addElement(vl); 536 this.added.addElement(new Boolean(true)); 537 } 538 } 539 else 540 { 541 this.ordering.addElement(oid); 542 this.values.addElement(value); 543 this.added.addElement(new Boolean(false)); 544 } 545 } 546 547 if (reverse) 548 { 549 Vector o = new Vector(); 550 Vector v = new Vector(); 551 Vector a = new Vector(); 552 553 for (int i = this.ordering.size() - 1; i >= 0; i--) 554 { 555 o.addElement(this.ordering.elementAt(i)); 556 v.addElement(this.values.elementAt(i)); 557 a.addElement(this.added.elementAt(i)); 558 } 559 560 this.ordering = o; 561 this.values = v; 562 this.added = a; 563 } 564 } 565 566 /** 567 * return a vector of the oids in the name, in the order they were found. 568 */ 569 public Vector getOIDs() 570 { 571 Vector v = new Vector(); 572 573 for (int i = 0; i != ordering.size(); i++) 574 { 575 v.addElement(ordering.elementAt(i)); 576 } 577 578 return v; 579 } 580 581 /** 582 * return a vector of the values found in the name, in the order they 583 * were found. 584 */ 585 public Vector getValues() 586 { 587 Vector v = new Vector(); 588 589 for (int i = 0; i != values.size(); i++) 590 { 591 v.addElement(values.elementAt(i)); 592 } 593 594 return v; 595 } 596 597 public DERObject toASN1Object() 598 { 599 if (seq == null) 600 { 601 ASN1EncodableVector vec = new ASN1EncodableVector(); 602 ASN1EncodableVector sVec = new ASN1EncodableVector(); 603 DERObjectIdentifier lstOid = null; 604 605 for (int i = 0; i != ordering.size(); i++) 606 { 607 ASN1EncodableVector v = new ASN1EncodableVector(); 608 DERObjectIdentifier oid = (DERObjectIdentifier)ordering.elementAt(i); 609 610 v.add(oid); 611 612 String str = (String)values.elementAt(i); 613 614 v.add(converter.getConvertedValue(oid, str)); 615 616 if (lstOid == null 617 || ((Boolean)this.added.elementAt(i)).booleanValue()) 618 { 619 sVec.add(new DERSequence(v)); 620 } 621 else 622 { 623 vec.add(new DERSet(sVec)); 624 sVec = new ASN1EncodableVector(); 625 626 sVec.add(new DERSequence(v)); 627 } 628 629 lstOid = oid; 630 } 631 632 vec.add(new DERSet(sVec)); 633 634 seq = new DERSequence(vec); 635 } 636 637 return seq; 638 } 639 640 /** 641 * @param inOrder if true the order of both X509 names must be the same, 642 * as well as the values associated with each element. 643 */ 644 public boolean equals(Object _obj, boolean inOrder) 645 { 646 if (_obj == this) 647 { 648 return true; 649 } 650 651 if (!inOrder) 652 { 653 return this.equals(_obj); 654 } 655 656 if (_obj == null || !(_obj instanceof X509Name)) 657 { 658 return false; 659 } 660 661 X509Name _oxn = (X509Name)_obj; 662 int _orderingSize = ordering.size(); 663 664 if (_orderingSize != _oxn.ordering.size()) 665 { 666 return false; 667 } 668 669 for(int i = 0; i < _orderingSize; i++) 670 { 671 String _oid = ((DERObjectIdentifier)ordering.elementAt(i)).getId(); 672 String _val = (String)values.elementAt(i); 673 674 String _oOID = ((DERObjectIdentifier)_oxn.ordering.elementAt(i)).getId(); 675 String _oVal = (String)_oxn.values.elementAt(i); 676 677 if (_oid.equals(_oOID)) 678 { 679 _val = _val.trim().toLowerCase(); 680 _oVal = _oVal.trim().toLowerCase(); 681 if (_val.equals(_oVal)) 682 { 683 continue; 684 } 685 else 686 { 687 StringBuffer v1 = new StringBuffer(); 688 StringBuffer v2 = new StringBuffer(); 689 690 if (_val.length() != 0) 691 { 692 char c1 = _val.charAt(0); 693 694 v1.append(c1); 695 696 for (int k = 1; k < _val.length(); k++) 697 { 698 char c2 = _val.charAt(k); 699 if (!(c1 == ' ' && c2 == ' ')) 700 { 701 v1.append(c2); 702 } 703 c1 = c2; 704 } 705 } 706 707 if (_oVal.length() != 0) 708 { 709 char c1 = _oVal.charAt(0); 710 711 v2.append(c1); 712 713 for (int k = 1; k < _oVal.length(); k++) 714 { 715 char c2 = _oVal.charAt(k); 716 if (!(c1 == ' ' && c2 == ' ')) 717 { 718 v2.append(c2); 719 } 720 c1 = c2; 721 } 722 } 723 724 if (!v1.toString().equals(v2.toString())) 725 { 726 return false; 727 } 728 } 729 } 730 else 731 { 732 return false; 733 } 734 } 735 736 return true; 737 } 738 739 /** 740 * test for equality - note: case is ignored. 741 */ 742 public boolean equals(Object _obj) 743 { 744 if (_obj == this) 745 { 746 return true; 747 } 748 749 if (_obj == null || !(_obj instanceof X509Name)) 750 { 751 return false; 752 } 753 754 X509Name _oxn = (X509Name)_obj; 755 756 if (this.getDERObject().equals(_oxn.getDERObject())) 757 { 758 return true; 759 } 760 761 int _orderingSize = ordering.size(); 762 763 if (_orderingSize != _oxn.ordering.size()) 764 { 765 return false; 766 } 767 768 boolean[] _indexes = new boolean[_orderingSize]; 769 770 for(int i = 0; i < _orderingSize; i++) 771 { 772 boolean _found = false; 773 String _oid = ((DERObjectIdentifier)ordering.elementAt(i)).getId(); 774 String _val = (String)values.elementAt(i); 775 776 for(int j = 0; j < _orderingSize; j++) 777 { 778 if(_indexes[j] == true) 779 { 780 continue; 781 } 782 783 String _oOID = ((DERObjectIdentifier)_oxn.ordering.elementAt(j)).getId(); 784 String _oVal = (String)_oxn.values.elementAt(j); 785 786 if (_oid.equals(_oOID)) 787 { 788 _val = _val.trim().toLowerCase(); 789 _oVal = _oVal.trim().toLowerCase(); 790 if (_val.equals(_oVal)) 791 { 792 _indexes[j] = true; 793 _found = true; 794 break; 795 } 796 else 797 { 798 StringBuffer v1 = new StringBuffer(); 799 StringBuffer v2 = new StringBuffer(); 800 801 if (_val.length() != 0) 802 { 803 char c1 = _val.charAt(0); 804 805 v1.append(c1); 806 807 for (int k = 1; k < _val.length(); k++) 808 { 809 char c2 = _val.charAt(k); 810 if (!(c1 == ' ' && c2 == ' ')) 811 { 812 v1.append(c2); 813 } 814 c1 = c2; 815 } 816 } 817 818 if (_oVal.length() != 0) 819 { 820 char c1 = _oVal.charAt(0); 821 822 v2.append(c1); 823 824 for (int k = 1; k < _oVal.length(); k++) 825 { 826 char c2 = _oVal.charAt(k); 827 if (!(c1 == ' ' && c2 == ' ')) 828 { 829 v2.append(c2); 830 } 831 c1 = c2; 832 } 833 } 834 835 if (v1.toString().equals(v2.toString())) 836 { 837 _indexes[j] = true; 838 _found = true; 839 break; 840 } 841 } 842 } 843 } 844 845 if(!_found) 846 { 847 return false; 848 } 849 } 850 851 return true; 852 } 853 854 public int hashCode() 855 { 856 ASN1Sequence seq = (ASN1Sequence)this.getDERObject(); 857 Enumeration e = seq.getObjects(); 858 int hashCode = 0; 859 860 while (e.hasMoreElements()) 861 { 862 hashCode ^= e.nextElement().hashCode(); 863 } 864 865 return hashCode; 866 } 867 868 private void appendValue( 869 StringBuffer buf, 870 Hashtable oidSymbols, 871 DERObjectIdentifier oid, 872 String value) 873 { 874 String sym = (String)oidSymbols.get(oid); 875 876 if (sym != null) 877 { 878 buf.append(sym); 879 } 880 else 881 { 882 buf.append(oid.getId()); 883 } 884 885 buf.append("="); 886 887 int index = buf.length(); 888 889 buf.append(value); 890 891 int end = buf.length(); 892 893 while (index != end) 894 { 895 if ((buf.charAt(index) == ',') 896 || (buf.charAt(index) == '"') 897 || (buf.charAt(index) == '\\') 898 || (buf.charAt(index) == '+') 899 || (buf.charAt(index) == '<') 900 || (buf.charAt(index) == '>') 901 || (buf.charAt(index) == ';')) 902 { 903 buf.insert(index, "\\"); 904 index++; 905 end++; 906 } 907 908 index++; 909 } 910 } 911 912 /** 913 * convert the structure to a string - if reverse is true the 914 * oids and values are listed out starting with the last element 915 * in the sequence (ala RFC 2253), otherwise the string will begin 916 * with the first element of the structure. If no string definition 917 * for the oid is found in oidSymbols the string value of the oid is 918 * added. Two standard symbol tables are provided DefaultSymbols, and 919 * RFC2253Symbols as part of this class. 920 * 921 * @param reverse if true start at the end of the sequence and work back. 922 * @param oidSymbols look up table strings for oids. 923 */ 924 public String toString( 925 boolean reverse, 926 Hashtable oidSymbols) 927 { 928 StringBuffer buf = new StringBuffer(); 929 boolean first = true; 930 931 if (reverse) 932 { 933 for (int i = ordering.size() - 1; i >= 0; i--) 934 { 935 if (first) 936 { 937 first = false; 938 } 939 else 940 { 941 if (((Boolean)added.elementAt(i + 1)).booleanValue()) 942 { 943 buf.append("+"); 944 } 945 else 946 { 947 buf.append(","); 948 } 949 } 950 951 appendValue(buf, oidSymbols, 952 (DERObjectIdentifier)ordering.elementAt(i), 953 (String)values.elementAt(i)); 954 } 955 } 956 else 957 { 958 for (int i = 0; i < ordering.size(); i++) 959 { 960 if (first) 961 { 962 first = false; 963 } 964 else 965 { 966 if (((Boolean)added.elementAt(i)).booleanValue()) 967 { 968 buf.append("+"); 969 } 970 else 971 { 972 buf.append(","); 973 } 974 } 975 976 appendValue(buf, oidSymbols, 977 (DERObjectIdentifier)ordering.elementAt(i), 978 (String)values.elementAt(i)); 979 } 980 } 981 982 return buf.toString(); 983 } 984 985 public String toString() 986 { 987 return toString(DefaultReverse, DefaultSymbols); 988 } 989 }