initial checkin
[org.ibex.nanogoat.git] / src / org / bouncycastle / asn1 / x509 / X509Name.java
1 package org.bouncycastle.asn1.x509;
2
3 import java.util.*;
4
5 import org.bouncycastle.asn1.*;
6
7 public class X509Name
8     implements DEREncodable
9 {
10     /**
11      * country code - StringType(SIZE(2))
12      */
13     public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6");
14
15     /**
16      * organization - StringType(SIZE(1..64))
17      */
18     public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10");
19
20     /**
21      * organizational unit name - StringType(SIZE(1..64))
22      */
23     public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11");
24
25     /**
26      * Title
27      */
28     public static final DERObjectIdentifier T = new DERObjectIdentifier("2.5.4.12");
29
30     /**
31      * common name - StringType(SIZE(1..64))
32      */
33     public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3");
34
35     /**
36      * device serial number name - StringType(SIZE(1..64))
37      */
38     public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5");
39
40     /**
41      * locality name - StringType(SIZE(1..64))
42      */
43     public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7");
44
45     /**
46      * state, or province name - StringType(SIZE(1..64))
47      */
48     public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8");
49
50
51     /**
52      * email address (RSA PKCS#9 extension) - IA5String
53      * <p>
54      * note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
55      */
56     public static final DERObjectIdentifier EmailAddress = new DERObjectIdentifier("1.2.840.113549.1.9.1");
57         
58         /**
59          * email address in Verisign certificates
60          */
61         public static final DERObjectIdentifier E = EmailAddress;
62         
63     /*
64      * others...
65      */
66     public static final DERObjectIdentifier DC = new DERObjectIdentifier("0.9.2342.19200300.100.1.25");
67
68     /**
69      * LDAP User id.
70      */
71     public static final DERObjectIdentifier UID = new DERObjectIdentifier("0.9.2342.19200300.100.1.1");
72
73     /**
74      * look up table translating OID values into their common symbols.
75      */
76     public static Hashtable OIDLookUp = new Hashtable();
77
78     /**
79      * look up table translating common symbols into their OIDS.
80      */
81     public static Hashtable SymbolLookUp = new Hashtable();
82
83     static
84     {
85         OIDLookUp.put(C, "C");
86         OIDLookUp.put(O, "O");
87         OIDLookUp.put(T, "T");
88         OIDLookUp.put(OU, "OU");
89         OIDLookUp.put(CN, "CN");
90         OIDLookUp.put(L, "L");
91         OIDLookUp.put(ST, "ST");
92         OIDLookUp.put(SN, "SN");
93         OIDLookUp.put(EmailAddress, "E");
94         OIDLookUp.put(DC, "DC");
95         OIDLookUp.put(UID, "UID");
96
97         SymbolLookUp.put("c", C);
98         SymbolLookUp.put("o", O);
99         SymbolLookUp.put("t", T);
100         SymbolLookUp.put("ou", OU);
101         SymbolLookUp.put("cn", CN);
102         SymbolLookUp.put("l", L);
103         SymbolLookUp.put("st", ST);
104         SymbolLookUp.put("sn", SN);
105         SymbolLookUp.put("emailaddress", E);
106         SymbolLookUp.put("dc", DC);
107         SymbolLookUp.put("e", E);
108         SymbolLookUp.put("uid", UID);
109     }
110
111     private Vector                  ordering = new Vector();
112     private Vector                  values = new Vector();
113     private ASN1Sequence            seq;
114
115     public static X509Name getInstance(
116         ASN1TaggedObject obj,
117         boolean          explicit)
118     {
119         return getInstance(ASN1Sequence.getInstance(obj, explicit));
120     }
121
122     public static X509Name getInstance(
123         Object  obj)
124     {
125         if (obj == null || obj instanceof X509Name)
126         {
127             return (X509Name)obj;
128         }
129         else if (obj instanceof ASN1Sequence)
130         {
131             return new X509Name((ASN1Sequence)obj);
132         }
133
134         throw new IllegalArgumentException("unknown object in factory");
135     }
136
137     /**
138      * Constructor from ASN1Sequence
139      *
140      * the principal will be a list of constructed sets, each containing an (OID, String) pair.
141      */
142     public X509Name(
143         ASN1Sequence  seq)
144     {
145         this.seq = seq;
146
147         Enumeration e = seq.getObjects();
148
149         while (e.hasMoreElements())
150         {
151             ASN1Set         set = (ASN1Set)e.nextElement();
152             ASN1Sequence    s = (ASN1Sequence)set.getObjectAt(0);
153
154             ordering.addElement(s.getObjectAt(0));
155             values.addElement(((DERString)s.getObjectAt(1)).getString());
156         }
157     }
158
159     /**
160      * constructor from a table of attributes.
161      * <p>
162      * it's is assumed the table contains OID/String pairs, and the contents
163      * of the table are copied into an internal table as part of the 
164      * construction process.
165      * <p>
166      * <b>Note:</b> if the name you are trying to generate should be
167      * following a specific ordering, you should use the constructor
168      * with the ordering specified below.
169      */
170     public X509Name(
171         Hashtable  attributes)
172     {
173         this(null, attributes);
174     }
175
176     /**
177      * constructor from a table of attributes with ordering.
178      * <p>
179      * it's is assumed the table contains OID/String pairs, and the contents
180      * of the table are copied into an internal table as part of the 
181      * construction process. The ordering vector should contain the OIDs
182      * in the order they are meant to be encoded or printed in toString.
183      */
184     public X509Name(
185         Vector      ordering,
186         Hashtable   attributes)
187     {
188         if (ordering != null)
189         {
190             for (int i = 0; i != ordering.size(); i++)
191             {
192                 this.ordering.addElement(ordering.elementAt(i));
193             }
194         }
195         else
196         {
197             Enumeration     e = attributes.keys();
198
199             while (e.hasMoreElements())
200             {
201                 this.ordering.addElement(e.nextElement());
202             }
203         }
204
205         for (int i = 0; i != this.ordering.size(); i++)
206         {
207             DERObjectIdentifier     oid = (DERObjectIdentifier)this.ordering.elementAt(i);
208
209             if (OIDLookUp.get(oid) == null)
210             {
211                 throw new IllegalArgumentException("Unknown object id - " + oid.getId() + " - passed to distinguished name");
212             }
213
214             if (attributes.get(oid) == null)
215             {
216                 throw new IllegalArgumentException("No attribute for object id - " + oid.getId() + " - passed to distinguished name");
217             }
218
219             this.values.addElement(attributes.get(oid)); // copy the hash table
220         }
221     }
222
223     /**
224      * takes two vectors one of the oids and the other of the values.
225      */
226     public X509Name(
227         Vector  ordering,
228         Vector  values)
229     {
230         if (ordering.size() != values.size())
231         {
232             throw new IllegalArgumentException("ordering vector must be same length as values.");
233         }
234
235         for (int i = 0; i < ordering.size(); i++)
236         {
237             this.ordering.addElement(ordering.elementAt(i));
238             this.values.addElement(values.elementAt(i));
239         }
240     }
241
242     /**
243      * takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
244      * some such, converting it into an ordered set of name attributes.
245      */
246     public X509Name(
247         String  dirName)
248     {
249         X509NameTokenizer   nTok = new X509NameTokenizer(dirName);
250
251         while (nTok.hasMoreTokens())
252         {
253             String  token = nTok.nextToken();
254             int     index = token.indexOf('=');
255
256             if (index == -1)
257             {
258                 throw new IllegalArgumentException("badly formated directory string");
259             }
260
261             String              name = token.substring(0, index);
262             String              value = token.substring(index + 1);
263             DERObjectIdentifier oid = null;
264
265             if (name.toUpperCase().startsWith("OID."))
266             {
267                 oid = new DERObjectIdentifier(name.substring(4));
268             }
269             else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
270             {
271                 oid = new DERObjectIdentifier(name);
272             }
273             else
274             {
275                 oid = (DERObjectIdentifier)SymbolLookUp.get(name.toLowerCase());
276                 if (oid == null)
277                 {
278                     throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
279                 }
280             }
281
282             this.ordering.addElement(oid);
283             this.values.addElement(value);
284         }
285     }
286
287     /**
288      * return false if we have characters out of the range of a printable
289      * string, true otherwise.
290      */
291     private boolean canBePrintable(
292         String  str)
293     {
294         for (int i = str.length() - 1; i >= 0; i--)
295         {
296             if (str.charAt(i) > 0x007f)
297             {
298                 return false;
299             }
300         }
301
302         return true;
303     }
304
305     public DERObject getDERObject()
306     {
307         if (seq == null)
308         {
309             DEREncodableVector  vec = new DEREncodableVector();
310
311             for (int i = 0; i != ordering.size(); i++)
312             {
313                 DEREncodableVector      v = new DEREncodableVector();
314                 DERObjectIdentifier     oid = (DERObjectIdentifier)ordering.elementAt(i);
315
316                 v.add(oid);
317
318                 String  str = (String)values.elementAt(i);
319
320                 if (oid.equals(EmailAddress))
321                 {
322                     v.add(new DERIA5String(str));
323                 }
324                 else
325                 {
326                     if (canBePrintable(str))
327                     {
328                         v.add(new DERPrintableString(str));
329                     }
330                     else
331                     {
332                         v.add(new DERUTF8String(str));
333                     }
334                 }
335
336                 vec.add(new DERSet(new DERSequence(v)));
337             }
338
339             seq = new DERSequence(vec);
340         }
341
342         return seq;
343     }
344
345     /**
346      * test for equality - note: case is ignored.
347      */
348     public boolean equals(Object _obj) 
349     {
350         if (_obj == this)
351         {
352             return true;
353         }
354
355         if (_obj == null || !(_obj instanceof X509Name))
356         {
357             return false;
358         }
359         
360         X509Name _oxn          = (X509Name)_obj;
361         int      _orderingSize = ordering.size();
362
363         if (_orderingSize != _oxn.ordering.size()) 
364         {
365                         return false;
366                 }
367                 
368                 boolean[] _indexes = new boolean[_orderingSize];
369
370                 for(int i = 0; i < _orderingSize; i++) 
371                 {
372                         boolean _found = false;
373                         String  _oid   = ((DERObjectIdentifier)ordering.elementAt(i)).getId();
374                         String  _val   = (String)values.elementAt(i);
375                         
376                         for(int j = 0; j < _orderingSize; j++) 
377                         {
378                                 if(_indexes[j] == true)
379                                 {
380                                         continue;
381                                 }
382                                 
383                                 String _oOID = ((DERObjectIdentifier)_oxn.ordering.elementAt(j)).getId();
384                                 String _oVal = (String)_oxn.values.elementAt(j);
385
386                 // was equalsIgnoreCase but MIDP doesn't like that.
387                                 if(_oid.equals(_oOID) && _val.toLowerCase().equals(_oVal.toLowerCase()))
388                                 {
389                                         _indexes[j] = true;
390                                         _found      = true;
391                                         break;
392                                 }
393
394                         }
395
396                         if(!_found)
397                         {
398                                 return false;
399                         }
400                 }
401                 
402                 return true;
403         }
404         
405     public int hashCode()
406     {
407         ASN1Sequence  seq = (ASN1Sequence)this.getDERObject();
408         Enumeration   e = seq.getObjects();
409         int           hashCode = 0;
410
411         while (e.hasMoreElements())
412         {
413             hashCode ^= e.nextElement().hashCode();
414         }
415
416         return hashCode;
417     }
418
419     public String toString()
420     {
421         StringBuffer            buf = new StringBuffer();
422         boolean                 first = true;
423         Enumeration             e1 = ordering.elements();
424         Enumeration             e2 = values.elements();
425
426         while (e1.hasMoreElements())
427         {
428             Object                  oid = e1.nextElement();
429             String                  sym = (String)OIDLookUp.get(oid);
430             
431             if (first)
432             {
433                 first = false;
434             }
435             else
436             {
437                 buf.append(",");
438             }
439
440             if (sym != null)
441             {
442                 buf.append(sym);
443             }
444             else
445             {
446                 buf.append(((DERObjectIdentifier)oid).getId());
447             }
448
449             buf.append("=");
450
451             int     index = buf.length();
452
453             buf.append((String)e2.nextElement());
454
455             int     end = buf.length();
456
457             while (index != end)
458             {
459                 if ((buf.charAt(index) == ',')
460                    || (buf.charAt(index) == '"')
461                    || (buf.charAt(index) == '\\')
462                    || (buf.charAt(index) == '+')
463                    || (buf.charAt(index) == '<')
464                    || (buf.charAt(index) == '>')
465                    || (buf.charAt(index) == ';'))
466                 {
467                     buf.insert(index, "\\");
468                     index++;
469                     end++;
470                 }
471
472                 index++;
473             }
474         }
475
476         return buf.toString();
477     }
478 }