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