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.DERGeneralizedTime; 9import org.bouncycastle.asn1.DERIA5String; 10import org.bouncycastle.asn1.DERPrintableString; 11import org.bouncycastle.asn1.DERUTF8String; 12import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 13import org.bouncycastle.asn1.x500.AttributeTypeAndValue; 14import org.bouncycastle.asn1.x500.RDN; 15import org.bouncycastle.asn1.x500.X500Name; 16import org.bouncycastle.asn1.x500.X500NameStyle; 17import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; 18 19public class BCStyle 20 implements X500NameStyle 21{ 22 public static final X500NameStyle INSTANCE = new BCStyle(); 23 24 /** 25 * country code - StringType(SIZE(2)) 26 */ 27 public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6"); 28 29 /** 30 * organization - StringType(SIZE(1..64)) 31 */ 32 public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10"); 33 34 /** 35 * organizational unit name - StringType(SIZE(1..64)) 36 */ 37 public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11"); 38 39 /** 40 * Title 41 */ 42 public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12"); 43 44 /** 45 * common name - StringType(SIZE(1..64)) 46 */ 47 public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3"); 48 49 /** 50 * device serial number name - StringType(SIZE(1..64)) 51 */ 52 public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5"); 53 54 /** 55 * street - StringType(SIZE(1..64)) 56 */ 57 public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9"); 58 59 /** 60 * device serial number name - StringType(SIZE(1..64)) 61 */ 62 public static final ASN1ObjectIdentifier SERIALNUMBER = SN; 63 64 /** 65 * locality name - StringType(SIZE(1..64)) 66 */ 67 public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7"); 68 69 /** 70 * state, or province name - StringType(SIZE(1..64)) 71 */ 72 public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8"); 73 74 /** 75 * Naming attributes of type X520name 76 */ 77 public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4"); 78 public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42"); 79 public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43"); 80 public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44"); 81 public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45"); 82 83 /** 84 * businessCategory - DirectoryString(SIZE(1..128) 85 */ 86 public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier( 87 "2.5.4.15"); 88 89 /** 90 * postalCode - DirectoryString(SIZE(1..40) 91 */ 92 public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier( 93 "2.5.4.17"); 94 95 /** 96 * dnQualifier - DirectoryString(SIZE(1..64) 97 */ 98 public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier( 99 "2.5.4.46"); 100 101 /** 102 * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) 103 */ 104 public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier( 105 "2.5.4.65"); 106 107 108 /** 109 * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z 110 */ 111 public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier( 112 "1.3.6.1.5.5.7.9.1"); 113 114 /** 115 * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) 116 */ 117 public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier( 118 "1.3.6.1.5.5.7.9.2"); 119 120 /** 121 * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" 122 */ 123 public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier( 124 "1.3.6.1.5.5.7.9.3"); 125 126 /** 127 * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 128 * codes only 129 */ 130 public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier( 131 "1.3.6.1.5.5.7.9.4"); 132 133 /** 134 * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166 135 * codes only 136 */ 137 public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier( 138 "1.3.6.1.5.5.7.9.5"); 139 140 141 /** 142 * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) 143 */ 144 public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14"); 145 146 /** 147 * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF 148 * DirectoryString(SIZE(1..30)) 149 */ 150 public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16"); 151 152 /** 153 * RFC 2256 dmdName 154 */ 155 public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54"); 156 157 /** 158 * id-at-telephoneNumber 159 */ 160 public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber; 161 162 /** 163 * id-at-name 164 */ 165 public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name; 166 167 /** 168 * Email address (RSA PKCS#9 extension) - IA5String. 169 * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. 170 */ 171 public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress; 172 173 /** 174 * more from PKCS#9 175 */ 176 public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName; 177 public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress; 178 179 /** 180 * email address in Verisign certificates 181 */ 182 public static final ASN1ObjectIdentifier E = EmailAddress; 183 184 /* 185 * others... 186 */ 187 public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25"); 188 189 /** 190 * LDAP User id. 191 */ 192 public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1"); 193 194 /** 195 * default look up table translating OID values into their common symbols following 196 * the convention in RFC 2253 with a few extras 197 */ 198 private static final Hashtable DefaultSymbols = new Hashtable(); 199 200 /** 201 * look up table translating common symbols into their OIDS. 202 */ 203 private static final Hashtable DefaultLookUp = new Hashtable(); 204 205 static 206 { 207 DefaultSymbols.put(C, "C"); 208 DefaultSymbols.put(O, "O"); 209 DefaultSymbols.put(T, "T"); 210 DefaultSymbols.put(OU, "OU"); 211 DefaultSymbols.put(CN, "CN"); 212 DefaultSymbols.put(L, "L"); 213 DefaultSymbols.put(ST, "ST"); 214 DefaultSymbols.put(SN, "SERIALNUMBER"); 215 DefaultSymbols.put(EmailAddress, "E"); 216 DefaultSymbols.put(DC, "DC"); 217 DefaultSymbols.put(UID, "UID"); 218 DefaultSymbols.put(STREET, "STREET"); 219 DefaultSymbols.put(SURNAME, "SURNAME"); 220 DefaultSymbols.put(GIVENNAME, "GIVENNAME"); 221 DefaultSymbols.put(INITIALS, "INITIALS"); 222 DefaultSymbols.put(GENERATION, "GENERATION"); 223 DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress"); 224 DefaultSymbols.put(UnstructuredName, "unstructuredName"); 225 DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier"); 226 DefaultSymbols.put(DN_QUALIFIER, "DN"); 227 DefaultSymbols.put(PSEUDONYM, "Pseudonym"); 228 DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress"); 229 DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth"); 230 DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship"); 231 DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence"); 232 DefaultSymbols.put(GENDER, "Gender"); 233 DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth"); 234 DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth"); 235 DefaultSymbols.put(POSTAL_CODE, "PostalCode"); 236 DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory"); 237 DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber"); 238 DefaultSymbols.put(NAME, "Name"); 239 240 DefaultLookUp.put("c", C); 241 DefaultLookUp.put("o", O); 242 DefaultLookUp.put("t", T); 243 DefaultLookUp.put("ou", OU); 244 DefaultLookUp.put("cn", CN); 245 DefaultLookUp.put("l", L); 246 DefaultLookUp.put("st", ST); 247 DefaultLookUp.put("sn", SN); 248 DefaultLookUp.put("serialnumber", SN); 249 DefaultLookUp.put("street", STREET); 250 DefaultLookUp.put("emailaddress", E); 251 DefaultLookUp.put("dc", DC); 252 DefaultLookUp.put("e", E); 253 DefaultLookUp.put("uid", UID); 254 DefaultLookUp.put("surname", SURNAME); 255 DefaultLookUp.put("givenname", GIVENNAME); 256 DefaultLookUp.put("initials", INITIALS); 257 DefaultLookUp.put("generation", GENERATION); 258 DefaultLookUp.put("unstructuredaddress", UnstructuredAddress); 259 DefaultLookUp.put("unstructuredname", UnstructuredName); 260 DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER); 261 DefaultLookUp.put("dn", DN_QUALIFIER); 262 DefaultLookUp.put("pseudonym", PSEUDONYM); 263 DefaultLookUp.put("postaladdress", POSTAL_ADDRESS); 264 DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH); 265 DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP); 266 DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE); 267 DefaultLookUp.put("gender", GENDER); 268 DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH); 269 DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH); 270 DefaultLookUp.put("postalcode", POSTAL_CODE); 271 DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY); 272 DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER); 273 DefaultLookUp.put("name", NAME); 274 } 275 276 protected BCStyle() 277 { 278 279 } 280 281 public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) 282 { 283 if (value.length() != 0 && value.charAt(0) == '#') 284 { 285 try 286 { 287 return IETFUtils.valueFromHexString(value, 1); 288 } 289 catch (IOException e) 290 { 291 throw new RuntimeException("can't recode value for oid " + oid.getId()); 292 } 293 } 294 else 295 { 296 if (value.length() != 0 && value.charAt(0) == '\\') 297 { 298 value = value.substring(1); 299 } 300 if (oid.equals(EmailAddress) || oid.equals(DC)) 301 { 302 return new DERIA5String(value); 303 } 304 else if (oid.equals(DATE_OF_BIRTH)) // accept time string as well as # (for compatibility) 305 { 306 return new DERGeneralizedTime(value); 307 } 308 else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER) 309 || oid.equals(TELEPHONE_NUMBER)) 310 { 311 return new DERPrintableString(value); 312 } 313 } 314 315 return new DERUTF8String(value); 316 } 317 318 public ASN1ObjectIdentifier attrNameToOID(String attrName) 319 { 320 return IETFUtils.decodeAttrName(attrName, DefaultLookUp); 321 } 322 323 public boolean areEqual(X500Name name1, X500Name name2) 324 { 325 RDN[] rdns1 = name1.getRDNs(); 326 RDN[] rdns2 = name2.getRDNs(); 327 328 if (rdns1.length != rdns2.length) 329 { 330 return false; 331 } 332 333 boolean reverse = false; 334 335 if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) 336 { 337 reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward 338 } 339 340 for (int i = 0; i != rdns1.length; i++) 341 { 342 if (!foundMatch(reverse, rdns1[i], rdns2)) 343 { 344 return false; 345 } 346 } 347 348 return true; 349 } 350 351 private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) 352 { 353 if (reverse) 354 { 355 for (int i = possRDNs.length - 1; i >= 0; i--) 356 { 357 if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) 358 { 359 possRDNs[i] = null; 360 return true; 361 } 362 } 363 } 364 else 365 { 366 for (int i = 0; i != possRDNs.length; i++) 367 { 368 if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) 369 { 370 possRDNs[i] = null; 371 return true; 372 } 373 } 374 } 375 376 return false; 377 } 378 379 protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) 380 { 381 if (rdn1.isMultiValued()) 382 { 383 if (rdn2.isMultiValued()) 384 { 385 AttributeTypeAndValue[] atvs1 = rdn1.getTypesAndValues(); 386 AttributeTypeAndValue[] atvs2 = rdn2.getTypesAndValues(); 387 388 if (atvs1.length != atvs2.length) 389 { 390 return false; 391 } 392 393 for (int i = 0; i != atvs1.length; i++) 394 { 395 if (!atvAreEqual(atvs1[i], atvs2[i])) 396 { 397 return false; 398 } 399 } 400 } 401 else 402 { 403 return false; 404 } 405 } 406 else 407 { 408 if (!rdn2.isMultiValued()) 409 { 410 return atvAreEqual(rdn1.getFirst(), rdn2.getFirst()); 411 } 412 else 413 { 414 return false; 415 } 416 } 417 418 return true; 419 } 420 421 private boolean atvAreEqual(AttributeTypeAndValue atv1, AttributeTypeAndValue atv2) 422 { 423 if (atv1 == atv2) 424 { 425 return true; 426 } 427 428 if (atv1 == null) 429 { 430 return false; 431 } 432 433 if (atv2 == null) 434 { 435 return false; 436 } 437 438 ASN1ObjectIdentifier o1 = atv1.getType(); 439 ASN1ObjectIdentifier o2 = atv2.getType(); 440 441 if (!o1.equals(o2)) 442 { 443 return false; 444 } 445 446 String v1 = IETFUtils.canonicalize(IETFUtils.valueToString(atv1.getValue())); 447 String v2 = IETFUtils.canonicalize(IETFUtils.valueToString(atv2.getValue())); 448 449 if (!v1.equals(v2)) 450 { 451 return false; 452 } 453 454 return true; 455 } 456 457 public RDN[] fromString(String dirName) 458 { 459 return IETFUtils.rDNsFromString(dirName, this); 460 } 461 462 public int calculateHashCode(X500Name name) 463 { 464 int hashCodeValue = 0; 465 RDN[] rdns = name.getRDNs(); 466 467 // this needs to be order independent, like equals 468 for (int i = 0; i != rdns.length; i++) 469 { 470 if (rdns[i].isMultiValued()) 471 { 472 AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); 473 474 for (int j = 0; j != atv.length; j++) 475 { 476 hashCodeValue ^= atv[j].getType().hashCode(); 477 hashCodeValue ^= calcHashCode(atv[j].getValue()); 478 } 479 } 480 else 481 { 482 hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); 483 hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); 484 } 485 } 486 487 return hashCodeValue; 488 } 489 490 private int calcHashCode(ASN1Encodable enc) 491 { 492 String value = IETFUtils.valueToString(enc); 493 494 value = IETFUtils.canonicalize(value); 495 496 return value.hashCode(); 497 } 498 499 public String toString(X500Name name) 500 { 501 StringBuffer buf = new StringBuffer(); 502 boolean first = true; 503 504 RDN[] rdns = name.getRDNs(); 505 506 for (int i = 0; i < rdns.length; i++) 507 { 508 if (first) 509 { 510 first = false; 511 } 512 else 513 { 514 buf.append(','); 515 } 516 517 if (rdns[i].isMultiValued()) 518 { 519 AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); 520 boolean firstAtv = true; 521 522 for (int j = 0; j != atv.length; j++) 523 { 524 if (firstAtv) 525 { 526 firstAtv = false; 527 } 528 else 529 { 530 buf.append('+'); 531 } 532 533 IETFUtils.appendTypeAndValue(buf, atv[j], DefaultSymbols); 534 } 535 } 536 else 537 { 538 IETFUtils.appendTypeAndValue(buf, rdns[i].getFirst(), DefaultSymbols); 539 } 540 } 541 542 return buf.toString(); 543 } 544} 545