Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / javax / security / auth / x500 / X500Principal.java
blobfcbb4950a394705f38d7feb497c48fc3bbe3ae2a
1 /* X500Principal.java -- X.500 principal.
2 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.security.auth.x500;
41 import gnu.java.security.OID;
42 import gnu.java.security.der.DER;
43 import gnu.java.security.der.DERReader;
44 import gnu.java.security.der.DERValue;
46 import java.io.ByteArrayInputStream;
47 import java.io.EOFException;
48 import java.io.IOException;
49 import java.io.InputStream;
50 import java.io.NotActiveException;
51 import java.io.ObjectInputStream;
52 import java.io.ObjectOutputStream;
53 import java.io.Reader;
54 import java.io.Serializable;
55 import java.io.StringReader;
57 import java.security.Principal;
59 import java.util.ArrayList;
60 import java.util.HashSet;
61 import java.util.Iterator;
62 import java.util.LinkedHashMap;
63 import java.util.LinkedList;
64 import java.util.List;
65 import java.util.Locale;
66 import java.util.Map;
67 import java.util.Set;
69 public final class X500Principal implements Principal, Serializable
71 private static final long serialVersionUID = -500463348111345721L;
73 // Constants and fields.
74 // ------------------------------------------------------------------------
76 public static final String CANONICAL = "CANONICAL";
77 public static final String RFC1779 = "RFC1779";
78 public static final String RFC2253 = "RFC2253";
80 private static final OID CN = new OID("2.5.4.3");
81 private static final OID C = new OID("2.5.4.6");
82 private static final OID L = new OID("2.5.4.7");
83 private static final OID ST = new OID("2.5.4.8");
84 private static final OID STREET = new OID("2.5.4.9");
85 private static final OID O = new OID("2.5.4.10");
86 private static final OID OU = new OID("2.5.4.11");
87 private static final OID DC = new OID("0.9.2342.19200300.100.1.25");
88 private static final OID UID = new OID("0.9.2342.19200300.100.1.1");
90 private transient List components;
91 private transient Map currentRdn;
92 private transient boolean fixed;
93 private transient byte[] encoded;
95 // Constructors.
96 // ------------------------------------------------------------------------
98 private X500Principal()
100 components = new LinkedList();
101 currentRdn = new LinkedHashMap();
102 components.add (currentRdn);
105 public X500Principal (String name)
107 this();
108 if (name == null)
109 throw new NullPointerException();
112 parseString (name);
114 catch (IOException ioe)
116 IllegalArgumentException iae = new IllegalArgumentException("malformed name");
117 iae.initCause (ioe);
118 throw iae;
122 public X500Principal (byte[] encoded)
124 this(new ByteArrayInputStream (encoded));
127 public X500Principal (InputStream encoded)
129 this();
132 parseDer (encoded);
134 catch (IOException ioe)
136 throw new IllegalArgumentException (ioe.toString());
140 // Instance methods.
141 // ------------------------------------------------------------------------
143 public int hashCode()
145 int result = size();
146 for (int i = 0; i < size(); ++i)
148 Map m = (Map) components.get(i);
149 for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
151 Map.Entry e = (Map.Entry) it2.next();
152 // We don't bother looking at the value of the entry.
153 result = result * 31 + ((OID) e.getKey()).hashCode();
156 return result;
159 public boolean equals(Object o)
161 if (!(o instanceof X500Principal))
162 return false;
163 if (size() != ((X500Principal) o).size())
164 return false;
165 for (int i = 0; i < size(); i++)
167 Map m = (Map) components.get (i);
168 for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
170 Map.Entry e = (Map.Entry) it2.next();
171 OID oid = (OID) e.getKey();
172 String v1 = (String) e.getValue();
173 String v2 = ((X500Principal) o).getComponent (oid, i);
174 if (v2 == null)
175 return false;
176 if (!compressWS (v1).equalsIgnoreCase (compressWS (v2)))
177 return false;
180 return true;
183 public byte[] getEncoded()
185 if (encoded == null)
186 encodeDer();
187 return (byte[]) encoded.clone();
190 public String getName()
192 return getName (RFC2253);
195 public String getName (final String format)
197 boolean rfc2253 = RFC2253.equalsIgnoreCase (format) ||
198 CANONICAL.equalsIgnoreCase (format);
199 boolean rfc1779 = RFC1779.equalsIgnoreCase (format);
200 boolean canon = CANONICAL.equalsIgnoreCase (format);
201 if (! (rfc2253 || rfc1779 || canon))
202 throw new IllegalArgumentException ("unsupported format " + format);
203 StringBuffer str = new StringBuffer();
204 for (Iterator it = components.iterator(); it.hasNext(); )
206 Map m = (Map) it.next();
207 for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
209 Map.Entry entry = (Map.Entry) it2.next();
210 OID oid = (OID) entry.getKey();
211 String value = (String) entry.getValue();
212 if (oid.equals (CN))
213 str.append ("CN");
214 else if (oid.equals (C))
215 str.append ("C");
216 else if (oid.equals (L))
217 str.append ("L");
218 else if (oid.equals (ST))
219 str.append ("ST");
220 else if (oid.equals (STREET))
221 str.append ("STREET");
222 else if (oid.equals (O))
223 str.append ("O");
224 else if (oid.equals (OU))
225 str.append ("OU");
226 else if (oid.equals (DC) && rfc2253)
227 str.append ("DC");
228 else if (oid.equals (UID) && rfc2253)
229 str.append ("UID");
230 else
231 str.append (oid.toString());
232 str.append('=');
233 str.append(value);
234 if (it2.hasNext())
235 str.append('+');
237 if (it.hasNext())
238 str.append(',');
240 if (canon)
241 return str.toString().toUpperCase (Locale.US).toLowerCase (Locale.US);
242 return str.toString();
245 public String toString()
247 return getName (RFC2253);
250 // Serialization methods.
251 // ------------------------------------------------------------------------
253 private void writeObject (ObjectOutputStream out) throws IOException
255 if (encoded != null)
256 encodeDer();
257 out.writeObject (encoded);
260 private void readObject (ObjectInputStream in)
261 throws IOException, NotActiveException, ClassNotFoundException
263 byte[] buf = (byte[]) in.readObject();
264 parseDer (new ByteArrayInputStream (buf));
267 // Own methods.
268 // -------------------------------------------------------------------------
270 private int size()
272 return components.size();
275 private String getComponent(OID oid, int rdn)
277 if (rdn >= size())
278 return null;
279 return (String) ((Map) components.get (rdn)).get (oid);
282 private void encodeDer()
284 ArrayList name = new ArrayList(components.size());
285 for (Iterator it = components.iterator(); it.hasNext(); )
287 Map m = (Map) it.next();
288 if (m.isEmpty())
289 continue;
290 Set rdn = new HashSet();
291 for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
293 Map.Entry e = (Map.Entry) it2.next();
294 ArrayList atav = new ArrayList(2);
295 atav.add(new DERValue(DER.OBJECT_IDENTIFIER, e.getKey()));
296 atav.add(new DERValue(DER.UTF8_STRING, e.getValue()));
297 rdn.add(new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, atav));
299 name.add(new DERValue(DER.SET|DER.CONSTRUCTED, rdn));
301 DERValue val = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, name);
302 encoded = val.getEncoded();
305 private int sep;
307 private void parseString(String str) throws IOException
309 Reader in = new StringReader(str);
310 while (true)
312 String key = readAttributeType(in);
313 if (key == null)
314 break;
315 String value = readAttributeValue(in);
316 putComponent(key, value);
317 if (sep == ',')
318 newRelativeDistinguishedName();
319 if (sep == -1)
320 break;
324 private String readAttributeType(Reader in) throws IOException
326 StringBuffer buf = new StringBuffer();
327 int ch;
328 while ((ch = in.read()) != '=')
330 if (ch == -1)
332 if (buf.length() > 0)
333 throw new EOFException("partial name read: " + buf);
334 return null;
336 if (ch > 127)
337 throw new IOException("Invalid char: " + (char) ch);
338 if (Character.isLetterOrDigit((char) ch) || ch == '-' || ch == '.')
339 buf.append((char) ch);
340 else
341 throw new IOException("Invalid char: " + (char) ch);
343 return buf.toString();
346 private String readAttributeValue(Reader in) throws IOException
348 StringBuffer buf = new StringBuffer();
349 int ch = in.read();
350 if (ch == '#')
352 while (true)
354 ch = in.read();
355 if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
356 || Character.isDigit((char) ch))
357 buf.append((char) ch);
358 else if (ch == '+' || ch == ',')
360 sep = ch;
361 String hex = buf.toString();
362 return new String(toByteArray(hex));
364 else
365 throw new IOException("illegal character: " + (char) ch);
368 else if (ch == '"')
370 while (true)
372 ch = in.read();
373 if (ch == '"')
374 break;
375 else if (ch == '\\')
377 ch = in.read();
378 if (ch == -1)
379 throw new EOFException();
380 if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
381 || Character.isDigit((char) ch))
383 int i = Character.digit((char) ch, 16) << 4;
384 ch = in.read();
385 if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
386 || Character.isDigit((char) ch)))
387 throw new IOException("illegal hex char");
388 i |= Character.digit((char) ch, 16);
389 buf.append((char) i);
391 else
392 buf.append((char) ch);
394 else
395 buf.append((char) ch);
397 sep = in.read();
398 if (sep != '+' || sep != ',')
399 throw new IOException("illegal character: " + (char) ch);
400 return buf.toString();
402 else
404 while (true)
406 switch (ch)
408 case '+':
409 case ',':
410 sep = ch;
411 return buf.toString();
412 case '\\':
413 ch = in.read();
414 if (ch == -1)
415 throw new EOFException();
416 if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
417 || Character.isDigit((char) ch))
419 int i = Character.digit((char) ch, 16) << 4;
420 ch = in.read();
421 if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
422 || Character.isDigit((char) ch)))
423 throw new IOException("illegal hex char");
424 i |= Character.digit((char) ch, 16);
425 buf.append((char) i);
427 else
428 buf.append((char) ch);
429 break;
430 case '=':
431 case '<':
432 case '>':
433 case '#':
434 case ';':
435 throw new IOException("illegal character: " + (char) ch);
436 case -1:
437 sep = -1;
438 return buf.toString ();
439 default:
440 buf.append((char) ch);
442 ch = in.read ();
447 private void parseDer (InputStream encoded) throws IOException
449 DERReader der = new DERReader (encoded);
450 DERValue name = der.read();
451 if (!name.isConstructed())
452 throw new IOException ("malformed Name");
453 this.encoded = name.getEncoded();
454 int len = 0;
455 while (len < name.getLength())
457 DERValue rdn = der.read();
458 if (!rdn.isConstructed())
459 throw new IOException ("badly formed RDNSequence");
460 int len2 = 0;
461 while (len2 < rdn.getLength())
463 DERValue atav = der.read();
464 if (!atav.isConstructed())
465 throw new IOException ("badly formed AttributeTypeAndValue");
466 DERValue val = der.read();
467 if (val.getTag() != DER.OBJECT_IDENTIFIER)
468 throw new IOException ("badly formed AttributeTypeAndValue");
469 OID oid = (OID) val.getValue();
470 val = der.read();
471 if (!(val.getValue() instanceof String))
472 throw new IOException ("badly formed AttributeTypeAndValue");
473 String value = (String) val.getValue();
474 putComponent(oid, value);
475 len2 += atav.getEncodedLength();
477 len += rdn.getEncodedLength();
478 if (len < name.getLength())
479 newRelativeDistinguishedName();
483 private void newRelativeDistinguishedName()
485 currentRdn = new LinkedHashMap();
486 components.add(currentRdn);
489 private void putComponent(OID oid, String value)
491 currentRdn.put(oid, value);
494 private void putComponent(String name, String value)
496 name = name.trim().toLowerCase();
497 if (name.equals("cn"))
498 putComponent(CN, value);
499 else if (name.equals("c"))
500 putComponent(C, value);
501 else if (name.equals("l"))
502 putComponent(L, value);
503 else if (name.equals("street"))
504 putComponent(STREET, value);
505 else if (name.equals("st"))
506 putComponent(ST, value);
507 else if (name.equals ("o"))
508 putComponent (O, value);
509 else if (name.equals ("ou"))
510 putComponent (OU, value);
511 else if (name.equals("dc"))
512 putComponent(DC, value);
513 else if (name.equals("uid"))
514 putComponent(UID, value);
515 else
516 putComponent(new OID(name), value);
519 private static String compressWS(String str)
521 StringBuffer buf = new StringBuffer();
522 char lastChar = 0;
523 for (int i = 0; i < str.length(); i++)
525 char c = str.charAt(i);
526 if (Character.isWhitespace(c))
528 if (!Character.isWhitespace(lastChar))
529 buf.append(' ');
531 else
532 buf.append(c);
533 lastChar = c;
535 return buf.toString().trim();
538 private static byte[] toByteArray (String str)
540 int limit = str.length();
541 byte[] result = new byte[((limit + 1) / 2)];
542 int i = 0, j = 0;
543 if ((limit % 2) == 1)
545 result[j++] = (byte) Character.digit (str.charAt(i++), 16);
547 while (i < limit)
549 result[j ] = (byte) (Character.digit (str.charAt(i++), 16) << 4);
550 result[j++] |= (byte) Character.digit (str.charAt(i++), 16);
552 return result;