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