/[classpath]/classpath/javax/security/auth/x500/X500Principal.java
ViewVC logotype

Diff of /classpath/javax/security/auth/x500/X500Principal.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.4 by robilad, Mon Apr 19 12:01:42 2004 UTC revision 1.5 by rsdio, Sat Aug 14 18:21:35 2004 UTC
# Line 7  GNU Classpath is free software; you can Line 7  GNU Classpath is free software; you can
7  it under the terms of the GNU General Public License as published by  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)  the Free Software Foundation; either version 2, or (at your option)
9  any later version.  any later version.
10    
11  GNU Classpath is distributed in the hope that it will be useful, but  GNU Classpath is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Line 38  exception statement from your version. * Line 38  exception statement from your version. *
38    
39  package javax.security.auth.x500;  package javax.security.auth.x500;
40    
41  import gnu.java.security.x509.X500DistinguishedName;  import gnu.java.security.OID;
42    import gnu.java.security.der.BitString;
43    import gnu.java.security.der.DER;
44    import gnu.java.security.der.DEREncodingException;
45    import gnu.java.security.der.DERReader;
46    import gnu.java.security.der.DERValue;
47    
48    import java.io.ByteArrayInputStream;
49  import java.io.IOException;  import java.io.IOException;
50  import java.io.InputStream;  import java.io.InputStream;
51    import java.io.EOFException;
52  import java.io.NotActiveException;  import java.io.NotActiveException;
53  import java.io.ObjectInputStream;  import java.io.ObjectInputStream;
54  import java.io.ObjectOutputStream;  import java.io.ObjectOutputStream;
55    import java.io.Reader;
56  import java.io.Serializable;  import java.io.Serializable;
57    import java.io.StringReader;
58    
59  import java.security.Principal;  import java.security.Principal;
60    
61    import java.util.ArrayList;
62    import java.util.Collections;
63    import java.util.HashSet;
64    import java.util.Iterator;
65    import java.util.LinkedHashMap;
66    import java.util.LinkedList;
67    import java.util.List;
68    import java.util.Locale;
69    import java.util.Map;
70    import java.util.Set;
71    import java.util.TreeMap;
72    
73  public final class X500Principal implements Principal, Serializable  public final class X500Principal implements Principal, Serializable
74  {  {
75    private static final long serialVersionUID = -500463348111345721L;    private static final long serialVersionUID = -500463348111345721L;
# Line 56  public final class X500Principal impleme Line 78  public final class X500Principal impleme
78    // ------------------------------------------------------------------------    // ------------------------------------------------------------------------
79    
80    public static final String CANONICAL = "CANONICAL";    public static final String CANONICAL = "CANONICAL";
   
81    public static final String RFC1779 = "RFC1779";    public static final String RFC1779 = "RFC1779";
   
82    public static final String RFC2253 = "RFC2253";    public static final String RFC2253 = "RFC2253";
83    
84    private transient X500DistinguishedName name;    private static final OID CN         = new OID("2.5.4.3");
85      private static final OID C          = new OID("2.5.4.6");
86      private static final OID L          = new OID("2.5.4.7");
87      private static final OID ST         = new OID("2.5.4.8");
88      private static final OID STREET     = new OID("2.5.4.9");
89      private static final OID O          = new OID("2.5.4.10");
90      private static final OID OU         = new OID("2.5.4.11");
91      private static final OID DC         = new OID("0.9.2342.19200300.100.1.25");
92      private static final OID UID        = new OID("0.9.2342.19200300.100.1.1");
93    
94      private transient List components;
95      private transient Map currentRdn;
96      private transient boolean fixed;
97      private transient byte[] encoded;
98    
99    // Constructors.    // Constructors.
100    // ------------------------------------------------------------------------    // ------------------------------------------------------------------------
101    
102    public X500Principal(String name)    private X500Principal()
103    {    {
104      if (name == null)      components = new LinkedList();
105        throw new NullPointerException();      currentRdn = new LinkedHashMap();
106      this.name = new X500DistinguishedName(name);      components.add (currentRdn);
107    }    }
108    
109    public X500Principal(byte[] encoded)    public X500Principal (String name)
110    {    {
111        this();
112        if (name == null)
113          throw new NullPointerException();
114      try      try
115        {        {
116          name = new X500DistinguishedName(encoded);          parseString (name);
117        }        }
118      catch (IOException ioe)      catch (IOException ioe)
119        {        {
120          throw new IllegalArgumentException(ioe.toString());          IllegalArgumentException iae = new IllegalArgumentException("malformed name");
121            iae.initCause (ioe);
122            throw iae;
123        }        }
124    }    }
125    
126    public X500Principal(InputStream encoded)    public X500Principal (byte[] encoded)
127      {
128        this(new ByteArrayInputStream (encoded));
129      }
130    
131      public X500Principal (InputStream encoded)
132    {    {
133        this();
134      try      try
135        {        {
136          name = new X500DistinguishedName(encoded);          parseDer (encoded);
137        }        }
138      catch (IOException ioe)      catch (IOException ioe)
139        {        {
140          throw new IllegalArgumentException(ioe.toString());          throw new IllegalArgumentException (ioe.toString());
141        }        }
142    }    }
143    
# Line 102  public final class X500Principal impleme Line 146  public final class X500Principal impleme
146    
147    public boolean equals(Object o)    public boolean equals(Object o)
148    {    {
149      return ((X500Principal) o).name.equals(name);      if (!(o instanceof X500Principal))
150          return false;
151        if (size() != ((X500Principal) o).size())
152          return false;
153        for (int i = 0; i < size(); i++)
154          {
155            Map m = (Map) components.get (i);
156            for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
157              {
158                Map.Entry e = (Map.Entry) it2.next();
159                OID oid = (OID) e.getKey();
160                String v1 = (String) e.getValue();
161                String v2 = ((X500Principal) o).getComponent (oid, i);
162                if (v2 == null)
163                  return false;
164                if (!compressWS (v1).equalsIgnoreCase (compressWS (v2)))
165                  return false;
166              }
167          }
168        return true;
169    }    }
170    
171    public byte[] getEncoded()    public byte[] getEncoded()
172    {    {
173      return name.getEncoded();      if (encoded == null)
174          encodeDer();
175        return (byte[]) encoded.clone();
176    }    }
177    
178    public String getName()    public String getName()
179    {    {
180      return getName(RFC2253);      return getName (RFC2253);
181      }
182    
183      public String getName (final String format)
184      {
185        boolean rfc2253 = RFC2253.equalsIgnoreCase (format) ||
186          CANONICAL.equalsIgnoreCase (format);
187        boolean rfc1779 = RFC1779.equalsIgnoreCase (format);
188        boolean canon   = CANONICAL.equalsIgnoreCase (format);
189        if (! (rfc2253 || rfc1779 || canon))
190          throw new IllegalArgumentException ("unsupported format " + format);
191        StringBuffer str = new StringBuffer();
192        for (Iterator it = components.iterator(); it.hasNext(); )
193          {
194            Map m = (Map) it.next();
195            for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
196              {
197                Map.Entry entry = (Map.Entry) it2.next();
198                OID oid = (OID) entry.getKey();
199                String value = (String) entry.getValue();
200                if (oid.equals (CN))
201                  str.append ("CN");
202                else if (oid.equals (C))
203                  str.append ("C");
204                else if (oid.equals (L))
205                  str.append ("L");
206                else if (oid.equals (ST))
207                  str.append ("ST");
208                else if (oid.equals (STREET))
209                  str.append ("STREET");
210                else if (oid.equals (O))
211                  str.append ("O");
212                else if (oid.equals (OU))
213                  str.append ("OU");
214                else if (oid.equals (DC) && rfc2253)
215                  str.append ("DC");
216                else if (oid.equals ("UID") && rfc2253)
217                  str.append ("UID");
218                else
219                  str.append (oid.toString());
220                str.append('=');
221                str.append(value);
222                if (it2.hasNext())
223                  str.append('+');
224              }
225            if (it.hasNext())
226              str.append(',');
227          }
228        if (canon)
229          return str.toString().toUpperCase (Locale.US).toLowerCase (Locale.US);
230        return str.toString();
231    }    }
232    
233    public String getName(String format)    public String toString()
234    {    {
235      if (format.equalsIgnoreCase(RFC2253))      return getName (RFC2253);
       return name.toRFC2253();  
     else if (format.equalsIgnoreCase(RFC1779))  
       return name.toRFC1779();  
     else if (format.equalsIgnoreCase(CANONICAL))  
       return name.toCanonical();  
     throw new IllegalArgumentException("unsupported format " + format);  
236    }    }
237    
238    // Serialization methods.    // Serialization methods.
239    // ------------------------------------------------------------------------    // ------------------------------------------------------------------------
240    
241    private void writeObject(ObjectOutputStream out) throws IOException    private void writeObject (ObjectOutputStream out) throws IOException
242    {    {
243      out.writeObject(name.getEncoded());      if (encoded != null)
244          encodeDer();
245        out.writeObject (encoded);
246    }    }
247    
248    private void readObject(ObjectInputStream in)    private void readObject (ObjectInputStream in)
249      throws IOException, NotActiveException, ClassNotFoundException      throws IOException, NotActiveException, ClassNotFoundException
250    {    {
251      byte[] buf = (byte[]) in.readObject();      byte[] buf = (byte[]) in.readObject();
252      name = new X500DistinguishedName(buf);      parseDer (new ByteArrayInputStream (buf));
253      }
254    
255      // Own methods.
256      // -------------------------------------------------------------------------
257    
258      private int size()
259      {
260        return components.size();
261      }
262    
263      private String getComponent(OID oid, int rdn)
264      {
265        if (rdn >= size())
266          return null;
267        return (String) ((Map) components.get (rdn)).get (oid);
268      }
269    
270      private void encodeDer()
271      {
272        ArrayList name = new ArrayList(components.size());
273        for (Iterator it = components.iterator(); it.hasNext(); )
274          {
275            Map m = (Map) it.next();
276            if (m.isEmpty())
277              continue;
278            Set rdn = new HashSet();
279            for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); )
280              {
281                Map.Entry e = (Map.Entry) it.next();
282                ArrayList atav = new ArrayList(2);
283                atav.add(new DERValue(DER.OBJECT_IDENTIFIER, e.getKey()));
284                atav.add(new DERValue(DER.UTF8_STRING, e.getValue()));
285                rdn.add(new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, atav));
286              }
287            name.add(new DERValue(DER.SET|DER.CONSTRUCTED, rdn));
288          }
289        DERValue val = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, name);
290        encoded = val.getEncoded();
291      }
292    
293      private int sep;
294    
295      private void parseString(String str) throws IOException
296      {
297        Reader in = new StringReader(str);
298        while (true)
299          {
300            String key = readAttributeType(in);
301            if (key == null)
302              break;
303            String value = readAttributeValue(in);
304            putComponent(key, value);
305            if (sep == ',')
306              newRelativeDistinguishedName();
307          }
308      }
309    
310      private String readAttributeType(Reader in) throws IOException
311      {
312        StringBuffer buf = new StringBuffer();
313        int ch;
314        while ((ch = in.read()) != '=')
315          {
316            if (ch == -1)
317              {
318                if (buf.length() > 0)
319                  throw new EOFException();
320                return null;
321              }
322            if (ch > 127)
323              throw new IOException("Invalid char: " + (char) ch);
324            if (Character.isLetterOrDigit((char) ch) || ch == '-' || ch == '.')
325              buf.append((char) ch);
326            else
327              throw new IOException("Invalid char: " + (char) ch);
328          }
329        return buf.toString();
330      }
331    
332      private String readAttributeValue(Reader in) throws IOException
333      {
334        StringBuffer buf = new StringBuffer();
335        int ch = in.read();
336        if (ch == '#')
337          {
338            while (true)
339              {
340                ch = in.read();
341                if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
342                    || Character.isDigit((char) ch))
343                  buf.append((char) ch);
344                else if (ch == '+' || ch == ',')
345                  {
346                    sep = ch;
347                    String hex = buf.toString();
348                    return new String(toByteArray(hex));
349                  }
350                else
351                  throw new IOException("illegal character: " + (char) ch);
352              }
353          }
354        else if (ch == '"')
355          {
356            while (true)
357              {
358                ch = in.read();
359                if (ch == '"')
360                  break;
361                else if (ch == '\\')
362                  {
363                    ch = in.read();
364                    if (ch == -1)
365                      throw new EOFException();
366                    if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
367                        || Character.isDigit((char) ch))
368                      {
369                        int i = Character.digit((char) ch, 16) << 4;
370                        ch = in.read();
371                        if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
372                              || Character.isDigit((char) ch)))
373                          throw new IOException("illegal hex char");
374                        i |= Character.digit((char) ch, 16);
375                        buf.append((char) i);
376                      }
377                    else
378                      buf.append((char) ch);
379                  }
380                else
381                  buf.append((char) ch);
382              }
383            sep = in.read();
384            if (sep != '+' || sep != ',')
385              throw new IOException("illegal character: " + (char) ch);
386            return buf.toString();
387          }
388        else
389          {
390            while (true)
391              {
392                switch (ch)
393                  {
394                  case '+':
395                  case ',':
396                    sep = ch;
397                    return buf.toString();
398                  case '\\':
399                    ch = in.read();
400                    if (ch == -1)
401                      throw new EOFException();
402                    if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
403                        || Character.isDigit((char) ch))
404                      {
405                        int i = Character.digit((char) ch, 16) << 4;
406                        ch = in.read();
407                        if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
408                              || Character.isDigit((char) ch)))
409                          throw new IOException("illegal hex char");
410                        i |= Character.digit((char) ch, 16);
411                        buf.append((char) i);
412                      }
413                    else
414                      buf.append((char) ch);
415                    break;
416                  case '=':
417                  case '<':
418                  case '>':
419                  case '#':
420                  case ';':
421                    throw new IOException("illegal character: " + (char) ch);
422                  case -1:
423                    throw new EOFException();
424                  default:
425                    buf.append((char) ch);
426                  }
427              }
428          }
429      }
430    
431      private void parseDer (InputStream encoded) throws IOException
432      {
433        DERReader der = new DERReader (encoded);
434        DERValue name = der.read();
435        if (!name.isConstructed())
436          throw new IOException ("malformed Name");
437        this.encoded = name.getEncoded();
438        int len = 0;
439        while (len < name.getLength())
440          {
441            DERValue rdn = der.read();
442            if (!rdn.isConstructed())
443              throw new IOException ("badly formed RDNSequence");
444            int len2 = 0;
445            while (len2 < rdn.getLength())
446              {
447                DERValue atav = der.read();
448                if (!atav.isConstructed())
449                  throw new IOException ("badly formed AttributeTypeAndValue");
450                DERValue val = der.read();
451                if (val.getTag() != DER.OBJECT_IDENTIFIER)
452                  throw new IOException ("badly formed AttributeTypeAndValue");
453                OID oid = (OID) val.getValue();
454                val = der.read();
455                if (!(val.getValue() instanceof String))
456                  throw new IOException ("badly formed AttributeTypeAndValue");
457                String value = (String) val.getValue();
458                putComponent(oid, value);
459                len2 += atav.getEncodedLength();
460              }
461            len += rdn.getEncodedLength();
462            if (len < name.getLength())
463              newRelativeDistinguishedName();
464          }
465      }
466    
467      private void newRelativeDistinguishedName()
468      {
469        currentRdn = new LinkedHashMap();
470        components.add(currentRdn);
471      }
472    
473      private void putComponent(OID oid, String value)
474      {
475        currentRdn.put(oid, value);
476      }
477    
478      private void putComponent(String name, String value)
479      {
480        name = name.trim().toLowerCase();
481        if (name.equals("cn"))
482          putComponent(CN, value);
483        else if (name.equals("c"))
484          putComponent(C, value);
485        else if (name.equals("l"))
486          putComponent(L, value);
487        else if (name.equals("street"))
488          putComponent(STREET, value);
489        else if (name.equals("st"))
490          putComponent(ST, value);
491        else if (name.equals("dc"))
492          putComponent(DC, value);
493        else if (name.equals("uid"))
494          putComponent(UID, value);
495        else
496          putComponent(new OID(name), value);
497      }
498    
499      private static String compressWS(String str)
500      {
501        StringBuffer buf = new StringBuffer();
502        char lastChar = 0;
503        for (int i = 0; i < str.length(); i++)
504          {
505            char c = str.charAt(i);
506            if (Character.isWhitespace(c))
507              {
508                if (!Character.isWhitespace(lastChar))
509                  buf.append(' ');
510              }
511            else
512              buf.append(c);
513            lastChar = c;
514          }
515        return buf.toString().trim();
516      }
517    
518      private static byte[] toByteArray (String str)
519      {
520        int limit = str.length();
521        byte[] result = new byte[((limit + 1) / 2)];
522        int i = 0, j = 0;
523        if ((limit % 2) == 1)
524          {
525            result[j++] = (byte) Character.digit (str.charAt(i++), 16);
526          }
527        while (i < limit)
528          {
529            result[j  ]  = (byte) (Character.digit (str.charAt(i++), 16) << 4);
530            result[j++] |= (byte)  Character.digit (str.charAt(i++), 16);
531          }
532        return result;
533    }    }
534  }  }

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.5

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26