RFC4519Style.java revision e1142c149e244797ce73b0e7fad40816e447a817
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        return IETFUtils.rDNAreEqual(rdn1, rdn2);
271    }
272
273    // parse backwards
274    public RDN[] fromString(String dirName)
275    {
276        RDN[] tmp = IETFUtils.rDNsFromString(dirName, this);
277        RDN[] res = new RDN[tmp.length];
278
279        for (int i = 0; i != tmp.length; i++)
280        {
281            res[res.length - i - 1] = tmp[i];
282        }
283
284        return res;
285    }
286
287    public int calculateHashCode(X500Name name)
288    {
289        int hashCodeValue = 0;
290        RDN[] rdns = name.getRDNs();
291
292        // this needs to be order independent, like equals
293        for (int i = 0; i != rdns.length; i++)
294        {
295            if (rdns[i].isMultiValued())
296            {
297                AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
298
299                for (int j = 0; j != atv.length; j++)
300                {
301                    hashCodeValue ^= atv[j].getType().hashCode();
302                    hashCodeValue ^= calcHashCode(atv[j].getValue());
303                }
304            }
305            else
306            {
307                hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
308                hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
309            }
310        }
311
312        return hashCodeValue;
313    }
314
315    private int calcHashCode(ASN1Encodable enc)
316    {
317        String value = IETFUtils.valueToString(enc);
318
319        value = IETFUtils.canonicalize(value);
320
321        return value.hashCode();
322    }
323
324    // convert in reverse
325    public String toString(X500Name name)
326    {
327        StringBuffer buf = new StringBuffer();
328        boolean first = true;
329
330        RDN[] rdns = name.getRDNs();
331
332        for (int i = rdns.length - 1; i >= 0; i--)
333        {
334            if (first)
335            {
336                first = false;
337            }
338            else
339            {
340                buf.append(',');
341            }
342
343            IETFUtils.appendRDN(buf, rdns[i], DefaultSymbols);
344        }
345
346        return buf.toString();
347    }
348}
349