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