RFC4519Style.java revision 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96
1package org.bouncycastle.asn1.x500.style;
2
3import java.io.IOException;
4import java.util.Enumeration;
5import java.util.Hashtable;
6
7import org.bouncycastle.asn1.ASN1Encodable;
8import org.bouncycastle.asn1.ASN1ObjectIdentifier;
9import org.bouncycastle.asn1.DERIA5String;
10import org.bouncycastle.asn1.DERPrintableString;
11import org.bouncycastle.asn1.DERUTF8String;
12import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
13import org.bouncycastle.asn1.x500.RDN;
14import org.bouncycastle.asn1.x500.X500Name;
15import org.bouncycastle.asn1.x500.X500NameStyle;
16
17public class RFC4519Style
18    implements X500NameStyle
19{
20    public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15");
21    public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6");
22    public static final ASN1ObjectIdentifier cn = new ASN1ObjectIdentifier("2.5.4.3");
23    public static final ASN1ObjectIdentifier dc = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25");
24    public static final ASN1ObjectIdentifier description = new ASN1ObjectIdentifier("2.5.4.13");
25    public static final ASN1ObjectIdentifier destinationIndicator = new ASN1ObjectIdentifier("2.5.4.27");
26    public static final ASN1ObjectIdentifier distinguishedName = new ASN1ObjectIdentifier("2.5.4.49");
27    public static final ASN1ObjectIdentifier dnQualifier = new ASN1ObjectIdentifier("2.5.4.46");
28    public static final ASN1ObjectIdentifier enhancedSearchGuide = new ASN1ObjectIdentifier("2.5.4.47");
29    public static final ASN1ObjectIdentifier facsimileTelephoneNumber = new ASN1ObjectIdentifier("2.5.4.23");
30    public static final ASN1ObjectIdentifier generationQualifier = new ASN1ObjectIdentifier("2.5.4.44");
31    public static final ASN1ObjectIdentifier givenName = new ASN1ObjectIdentifier("2.5.4.42");
32    public static final ASN1ObjectIdentifier houseIdentifier = new ASN1ObjectIdentifier("2.5.4.51");
33    public static final ASN1ObjectIdentifier initials = new ASN1ObjectIdentifier("2.5.4.43");
34    public static final ASN1ObjectIdentifier internationalISDNNumber = new ASN1ObjectIdentifier("2.5.4.25");
35    public static final ASN1ObjectIdentifier l = new ASN1ObjectIdentifier("2.5.4.7");
36    public static final ASN1ObjectIdentifier member = new ASN1ObjectIdentifier("2.5.4.31");
37    public static final ASN1ObjectIdentifier name = new ASN1ObjectIdentifier("2.5.4.41");
38    public static final ASN1ObjectIdentifier o = new ASN1ObjectIdentifier("2.5.4.10");
39    public static final ASN1ObjectIdentifier ou = new ASN1ObjectIdentifier("2.5.4.11");
40    public static final ASN1ObjectIdentifier owner = new ASN1ObjectIdentifier("2.5.4.32");
41    public static final ASN1ObjectIdentifier physicalDeliveryOfficeName = new ASN1ObjectIdentifier("2.5.4.19");
42    public static final ASN1ObjectIdentifier postalAddress = new ASN1ObjectIdentifier("2.5.4.16");
43    public static final ASN1ObjectIdentifier postalCode = new ASN1ObjectIdentifier("2.5.4.17");
44    public static final ASN1ObjectIdentifier postOfficeBox = new ASN1ObjectIdentifier("2.5.4.18");
45    public static final ASN1ObjectIdentifier preferredDeliveryMethod = new ASN1ObjectIdentifier("2.5.4.28");
46    public static final ASN1ObjectIdentifier registeredAddress = new ASN1ObjectIdentifier("2.5.4.26");
47    public static final ASN1ObjectIdentifier roleOccupant = new ASN1ObjectIdentifier("2.5.4.33");
48    public static final ASN1ObjectIdentifier searchGuide = new ASN1ObjectIdentifier("2.5.4.14");
49    public static final ASN1ObjectIdentifier seeAlso = new ASN1ObjectIdentifier("2.5.4.34");
50    public static final ASN1ObjectIdentifier serialNumber = new ASN1ObjectIdentifier("2.5.4.5");
51    public static final ASN1ObjectIdentifier sn = new ASN1ObjectIdentifier("2.5.4.4");
52    public static final ASN1ObjectIdentifier st = new ASN1ObjectIdentifier("2.5.4.8");
53    public static final ASN1ObjectIdentifier street = new ASN1ObjectIdentifier("2.5.4.9");
54    public static final ASN1ObjectIdentifier telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20");
55    public static final ASN1ObjectIdentifier teletexTerminalIdentifier = new ASN1ObjectIdentifier("2.5.4.22");
56    public static final ASN1ObjectIdentifier telexNumber = new ASN1ObjectIdentifier("2.5.4.21");
57    public static final ASN1ObjectIdentifier title = new ASN1ObjectIdentifier("2.5.4.12");
58    public static final ASN1ObjectIdentifier uid = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1");
59    public static final ASN1ObjectIdentifier uniqueMember = new ASN1ObjectIdentifier("2.5.4.50");
60    public static final ASN1ObjectIdentifier userPassword = new ASN1ObjectIdentifier("2.5.4.35");
61    public static final ASN1ObjectIdentifier x121Address = new ASN1ObjectIdentifier("2.5.4.24");
62    public static final ASN1ObjectIdentifier x500UniqueIdentifier = new ASN1ObjectIdentifier("2.5.4.45");
63
64    /**
65     * default look up table translating OID values into their common symbols following
66     * the convention in RFC 2253 with a few extras
67     */
68    private static final Hashtable DefaultSymbols = new Hashtable();
69
70    /**
71     * look up table translating common symbols into their OIDS.
72     */
73    private static final Hashtable DefaultLookUp = new Hashtable();
74
75    static
76    {
77        DefaultSymbols.put(businessCategory, "businessCategory");
78        DefaultSymbols.put(c, "c");
79        DefaultSymbols.put(cn, "cn");
80        DefaultSymbols.put(dc, "dc");
81        DefaultSymbols.put(description, "description");
82        DefaultSymbols.put(destinationIndicator, "destinationIndicator");
83        DefaultSymbols.put(distinguishedName, "distinguishedName");
84        DefaultSymbols.put(dnQualifier, "dnQualifier");
85        DefaultSymbols.put(enhancedSearchGuide, "enhancedSearchGuide");
86        DefaultSymbols.put(facsimileTelephoneNumber, "facsimileTelephoneNumber");
87        DefaultSymbols.put(generationQualifier, "generationQualifier");
88        DefaultSymbols.put(givenName, "givenName");
89        DefaultSymbols.put(houseIdentifier, "houseIdentifier");
90        DefaultSymbols.put(initials, "initials");
91        DefaultSymbols.put(internationalISDNNumber, "internationalISDNNumber");
92        DefaultSymbols.put(l, "l");
93        DefaultSymbols.put(member, "member");
94        DefaultSymbols.put(name, "name");
95        DefaultSymbols.put(o, "o");
96        DefaultSymbols.put(ou, "ou");
97        DefaultSymbols.put(owner, "owner");
98        DefaultSymbols.put(physicalDeliveryOfficeName, "physicalDeliveryOfficeName");
99        DefaultSymbols.put(postalAddress, "postalAddress");
100        DefaultSymbols.put(postalCode, "postalCode");
101        DefaultSymbols.put(postOfficeBox, "postOfficeBox");
102        DefaultSymbols.put(preferredDeliveryMethod, "preferredDeliveryMethod");
103        DefaultSymbols.put(registeredAddress, "registeredAddress");
104        DefaultSymbols.put(roleOccupant, "roleOccupant");
105        DefaultSymbols.put(searchGuide, "searchGuide");
106        DefaultSymbols.put(seeAlso, "seeAlso");
107        DefaultSymbols.put(serialNumber, "serialNumber");
108        DefaultSymbols.put(sn, "sn");
109        DefaultSymbols.put(st, "st");
110        DefaultSymbols.put(street, "street");
111        DefaultSymbols.put(telephoneNumber, "telephoneNumber");
112        DefaultSymbols.put(teletexTerminalIdentifier, "teletexTerminalIdentifier");
113        DefaultSymbols.put(telexNumber, "telexNumber");
114        DefaultSymbols.put(title, "title");
115        DefaultSymbols.put(uid, "uid");
116        DefaultSymbols.put(uniqueMember, "uniqueMember");
117        DefaultSymbols.put(userPassword, "userPassword");
118        DefaultSymbols.put(x121Address, "x121Address");
119        DefaultSymbols.put(x500UniqueIdentifier, "x500UniqueIdentifier");
120
121        DefaultLookUp.put("businesscategory", businessCategory);
122        DefaultLookUp.put("c", c);
123        DefaultLookUp.put("cn", cn);
124        DefaultLookUp.put("dc", dc);
125        DefaultLookUp.put("description", description);
126        DefaultLookUp.put("destinationindicator", destinationIndicator);
127        DefaultLookUp.put("distinguishedname", distinguishedName);
128        DefaultLookUp.put("dnqualifier", dnQualifier);
129        DefaultLookUp.put("enhancedsearchguide", enhancedSearchGuide);
130        DefaultLookUp.put("facsimiletelephonenumber", facsimileTelephoneNumber);
131        DefaultLookUp.put("generationqualifier", generationQualifier);
132        DefaultLookUp.put("givenname", givenName);
133        DefaultLookUp.put("houseidentifier", houseIdentifier);
134        DefaultLookUp.put("initials", initials);
135        DefaultLookUp.put("internationalisdnnumber", internationalISDNNumber);
136        DefaultLookUp.put("l", l);
137        DefaultLookUp.put("member", member);
138        DefaultLookUp.put("name", name);
139        DefaultLookUp.put("o", o);
140        DefaultLookUp.put("ou", ou);
141        DefaultLookUp.put("owner", owner);
142        DefaultLookUp.put("physicaldeliveryofficename", physicalDeliveryOfficeName);
143        DefaultLookUp.put("postaladdress", postalAddress);
144        DefaultLookUp.put("postalcode", postalCode);
145        DefaultLookUp.put("postofficebox", postOfficeBox);
146        DefaultLookUp.put("preferreddeliverymethod", preferredDeliveryMethod);
147        DefaultLookUp.put("registeredaddress", registeredAddress);
148        DefaultLookUp.put("roleoccupant", roleOccupant);
149        DefaultLookUp.put("searchguide", searchGuide);
150        DefaultLookUp.put("seealso", seeAlso);
151        DefaultLookUp.put("serialnumber", serialNumber);
152        DefaultLookUp.put("sn", sn);
153        DefaultLookUp.put("st", st);
154        DefaultLookUp.put("street", street);
155        DefaultLookUp.put("telephonenumber", telephoneNumber);
156        DefaultLookUp.put("teletexterminalidentifier", teletexTerminalIdentifier);
157        DefaultLookUp.put("telexnumber", telexNumber);
158        DefaultLookUp.put("title", title);
159        DefaultLookUp.put("uid", uid);
160        DefaultLookUp.put("uniquemember", uniqueMember);
161        DefaultLookUp.put("userpassword", userPassword);
162        DefaultLookUp.put("x121address", x121Address);
163        DefaultLookUp.put("x500uniqueidentifier", x500UniqueIdentifier);
164
165        // TODO: need to add correct matching for equality comparisons.
166    }
167
168    /**
169     * Singleton instance.
170     */
171    public static final X500NameStyle INSTANCE = new RFC4519Style();
172
173    protected final Hashtable defaultLookUp;
174    protected final Hashtable defaultSymbols;
175
176    protected RFC4519Style()
177    {
178        defaultSymbols = copyHashTable(DefaultSymbols);
179        defaultLookUp = copyHashTable(DefaultLookUp);
180    }
181
182    public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
183    {
184        if (value.length() != 0 && value.charAt(0) == '#')
185        {
186            try
187            {
188                return IETFUtils.valueFromHexString(value, 1);
189            }
190            catch (IOException e)
191            {
192                throw new RuntimeException("can't recode value for oid " + oid.getId());
193            }
194        }
195        else
196        {
197            if (value.length() != 0 && value.charAt(0) == '\\')
198            {
199                value = value.substring(1);
200            }
201            if (oid.equals(dc))
202            {
203                return new DERIA5String(value);
204            }
205            else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier)
206                || oid.equals(telephoneNumber))
207            {
208                return new DERPrintableString(value);
209            }
210        }
211
212        return new DERUTF8String(value);
213    }
214
215    public String oidToDisplayName(ASN1ObjectIdentifier oid)
216    {
217        return (String)DefaultSymbols.get(oid);
218    }
219
220    public String[] oidToAttrNames(ASN1ObjectIdentifier oid)
221    {
222        return IETFUtils.findAttrNamesForOID(oid, defaultLookUp);
223    }
224
225    public ASN1ObjectIdentifier attrNameToOID(String attrName)
226    {
227        return IETFUtils.decodeAttrName(attrName, defaultLookUp);
228    }
229
230    public boolean areEqual(X500Name name1, X500Name name2)
231    {
232        RDN[] rdns1 = name1.getRDNs();
233        RDN[] rdns2 = name2.getRDNs();
234
235        if (rdns1.length != rdns2.length)
236        {
237            return false;
238        }
239
240        boolean reverse = false;
241
242        if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null)
243        {
244            reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType());  // guess forward
245        }
246
247        for (int i = 0; i != rdns1.length; i++)
248        {
249            if (!foundMatch(reverse, rdns1[i], rdns2))
250            {
251                return false;
252            }
253        }
254
255        return true;
256    }
257
258    private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs)
259    {
260        if (reverse)
261        {
262            for (int i = possRDNs.length - 1; i >= 0; i--)
263            {
264                if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
265                {
266                    possRDNs[i] = null;
267                    return true;
268                }
269            }
270        }
271        else
272        {
273            for (int i = 0; i != possRDNs.length; i++)
274            {
275                if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
276                {
277                    possRDNs[i] = null;
278                    return true;
279                }
280            }
281        }
282
283        return false;
284    }
285
286    protected boolean rdnAreEqual(RDN rdn1, RDN rdn2)
287    {
288        return IETFUtils.rDNAreEqual(rdn1, rdn2);
289    }
290
291    // parse backwards
292    public RDN[] fromString(String dirName)
293    {
294        RDN[] tmp = IETFUtils.rDNsFromString(dirName, this);
295        RDN[] res = new RDN[tmp.length];
296
297        for (int i = 0; i != tmp.length; i++)
298        {
299            res[res.length - i - 1] = tmp[i];
300        }
301
302        return res;
303    }
304
305    public int calculateHashCode(X500Name name)
306    {
307        int hashCodeValue = 0;
308        RDN[] rdns = name.getRDNs();
309
310        // this needs to be order independent, like equals
311        for (int i = 0; i != rdns.length; i++)
312        {
313            if (rdns[i].isMultiValued())
314            {
315                AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
316
317                for (int j = 0; j != atv.length; j++)
318                {
319                    hashCodeValue ^= atv[j].getType().hashCode();
320                    hashCodeValue ^= calcHashCode(atv[j].getValue());
321                }
322            }
323            else
324            {
325                hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
326                hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
327            }
328        }
329
330        return hashCodeValue;
331    }
332
333    private int calcHashCode(ASN1Encodable enc)
334    {
335        String value = IETFUtils.valueToString(enc);
336
337        value = IETFUtils.canonicalize(value);
338
339        return value.hashCode();
340    }
341
342    // convert in reverse
343    public String toString(X500Name name)
344    {
345        StringBuffer buf = new StringBuffer();
346        boolean first = true;
347
348        RDN[] rdns = name.getRDNs();
349
350        for (int i = rdns.length - 1; i >= 0; i--)
351        {
352            if (first)
353            {
354                first = false;
355            }
356            else
357            {
358                buf.append(',');
359            }
360
361            IETFUtils.appendRDN(buf, rdns[i], defaultSymbols);
362        }
363
364        return buf.toString();
365    }
366
367    private static Hashtable copyHashTable(Hashtable paramsMap)
368    {
369        Hashtable newTable = new Hashtable();
370
371        Enumeration keys = paramsMap.keys();
372        while (keys.hasMoreElements())
373        {
374            Object key = keys.nextElement();
375            newTable.put(key, paramsMap.get(key));
376        }
377
378        return newTable;
379    }
380}
381