View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  
19  package org.apache.geronimo.util.asn1.x509;
20  
21  import java.util.Enumeration;
22  import java.util.Hashtable;
23  import java.util.Vector;
24  
25  import org.apache.geronimo.util.asn1.*;
26  import org.apache.geronimo.util.asn1.pkcs.PKCSObjectIdentifiers;
27  
28  /**
29   * <pre>
30   *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
31   *
32   *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
33   *
34   *     AttributeTypeAndValue ::= SEQUENCE {
35   *                                   type  OBJECT IDENTIFIER,
36   *                                   value ANY }
37   * </pre>
38   */
39  public class X509Name
40      extends ASN1Encodable
41  {
42      /**
43       * country code - StringType(SIZE(2))
44       */
45      public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6");
46  
47      /**
48       * organization - StringType(SIZE(1..64))
49       */
50      public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10");
51  
52      /**
53       * organizational unit name - StringType(SIZE(1..64))
54       */
55      public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11");
56  
57      /**
58       * Title
59       */
60      public static final DERObjectIdentifier T = new DERObjectIdentifier("2.5.4.12");
61  
62      /**
63       * common name - StringType(SIZE(1..64))
64       */
65      public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3");
66  
67      /**
68       * device serial number name - StringType(SIZE(1..64))
69       */
70      public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5");
71  
72      /**
73       * locality name - StringType(SIZE(1..64))
74       */
75      public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7");
76  
77      /**
78       * state, or province name - StringType(SIZE(1..64))
79       */
80      public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8");
81  
82      /**
83       * Naming attributes of type X520name
84       */
85      public static final DERObjectIdentifier SURNAME = new DERObjectIdentifier("2.5.4.4");
86      public static final DERObjectIdentifier GIVENNAME = new DERObjectIdentifier("2.5.4.42");
87      public static final DERObjectIdentifier INITIALS = new DERObjectIdentifier("2.5.4.43");
88      public static final DERObjectIdentifier GENERATION = new DERObjectIdentifier("2.5.4.44");
89      public static final DERObjectIdentifier UNIQUE_IDENTIFIER = new DERObjectIdentifier("2.5.4.45");
90  
91      /**
92       * Email address (RSA PKCS#9 extension) - IA5String.
93       * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
94       */
95      public static final DERObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;
96  
97      /**
98       * more from PKCS#9
99       */
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 }