1 package org.bouncycastle.asn1.x500; 2 3 import java.util.Enumeration; 4 5 import org.bouncycastle.asn1.ASN1Choice; 6 import org.bouncycastle.asn1.ASN1Encodable; 7 import org.bouncycastle.asn1.ASN1Object; 8 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 9 import org.bouncycastle.asn1.ASN1Primitive; 10 import org.bouncycastle.asn1.ASN1Sequence; 11 import org.bouncycastle.asn1.ASN1TaggedObject; 12 import org.bouncycastle.asn1.DERSequence; 13 import org.bouncycastle.asn1.x500.style.BCStyle; 14 15 /** 16 * The X.500 Name object. 17 * <pre> 18 * Name ::= CHOICE { 19 * RDNSequence } 20 * 21 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName 22 * 23 * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue 24 * 25 * AttributeTypeAndValue ::= SEQUENCE { 26 * type OBJECT IDENTIFIER, 27 * value ANY } 28 * </pre> 29 */ 30 public class X500Name 31 extends ASN1Object 32 implements ASN1Choice 33 { 34 private static X500NameStyle defaultStyle = BCStyle.INSTANCE; 35 36 private boolean isHashCodeCalculated; 37 private int hashCodeValue; 38 39 private X500NameStyle style; 40 private RDN[] rdns; 41 42 /** 43 * @deprecated use the getInstance() method that takes a style. 44 */ 45 public X500Name(X500NameStyle style, X500Name name) 46 { 47 this.rdns = name.rdns; 48 this.style = style; 49 } 50 51 /** 52 * Return a X500Name based on the passed in tagged object. 53 * 54 * @param obj tag object holding name. 55 * @param explicit true if explicitly tagged false otherwise. 56 * @return the X500Name 57 */ 58 public static X500Name getInstance( 59 ASN1TaggedObject obj, 60 boolean explicit) 61 { 62 // must be true as choice item 63 return getInstance(ASN1Sequence.getInstance(obj, true)); 64 } 65 66 public static X500Name getInstance( 67 Object obj) 68 { 69 if (obj instanceof X500Name) 70 { 71 return (X500Name)obj; 72 } 73 else if (obj != null) 74 { 75 return new X500Name(ASN1Sequence.getInstance(obj)); 76 } 77 78 return null; 79 } 80 81 public static X500Name getInstance( 82 X500NameStyle style, 83 Object obj) 84 { 85 if (obj instanceof X500Name) 86 { 87 return new X500Name(style, (X500Name)obj); 88 } 89 else if (obj != null) 90 { 91 return new X500Name(style, ASN1Sequence.getInstance(obj)); 92 } 93 94 return null; 95 } 96 97 /** 98 * Constructor from ASN1Sequence 99 * 100 * the principal will be a list of constructed sets, each containing an (OID, String) pair. 101 */ 102 private X500Name( 103 ASN1Sequence seq) 104 { 105 this(defaultStyle, seq); 106 } 107 108 private X500Name( 109 X500NameStyle style, 110 ASN1Sequence seq) 111 { 112 this.style = style; 113 this.rdns = new RDN[seq.size()]; 114 115 int index = 0; 116 117 for (Enumeration e = seq.getObjects(); e.hasMoreElements();) 118 { 119 rdns[index++] = RDN.getInstance(e.nextElement()); 120 } 121 } 122 123 public X500Name( 124 RDN[] rDNs) 125 { 126 this(defaultStyle, rDNs); 127 } 128 129 public X500Name( 130 X500NameStyle style, 131 RDN[] rDNs) 132 { 133 this.rdns = rDNs; 134 this.style = style; 135 } 136 137 public X500Name( 138 String dirName) 139 { 140 this(defaultStyle, dirName); 141 } 142 143 public X500Name( 144 X500NameStyle style, 145 String dirName) 146 { 147 this(style.fromString(dirName)); 148 149 this.style = style; 150 } 151 152 /** 153 * return an array of RDNs in structure order. 154 * 155 * @return an array of RDN objects. 156 */ 157 public RDN[] getRDNs() 158 { 159 RDN[] tmp = new RDN[this.rdns.length]; 160 161 System.arraycopy(rdns, 0, tmp, 0, tmp.length); 162 163 return tmp; 164 } 165 166 /** 167 * return an array of OIDs contained in the attribute type of each RDN in structure order. 168 * 169 * @return an array, possibly zero length, of ASN1ObjectIdentifiers objects. 170 */ 171 public ASN1ObjectIdentifier[] getAttributeTypes() 172 { 173 int count = 0; 174 175 for (int i = 0; i != rdns.length; i++) 176 { 177 RDN rdn = rdns[i]; 178 179 count += rdn.size(); 180 } 181 182 ASN1ObjectIdentifier[] res = new ASN1ObjectIdentifier[count]; 183 184 count = 0; 185 186 for (int i = 0; i != rdns.length; i++) 187 { 188 RDN rdn = rdns[i]; 189 190 if (rdn.isMultiValued()) 191 { 192 AttributeTypeAndValue[] attr = rdn.getTypesAndValues(); 193 for (int j = 0; j != attr.length; j++) 194 { 195 res[count++] = attr[j].getType(); 196 } 197 } 198 else if (rdn.size() != 0) 199 { 200 res[count++] = rdn.getFirst().getType(); 201 } 202 } 203 204 return res; 205 } 206 207 /** 208 * return an array of RDNs containing the attribute type given by OID in structure order. 209 * 210 * @param attributeType the type OID we are looking for. 211 * @return an array, possibly zero length, of RDN objects. 212 */ 213 public RDN[] getRDNs(ASN1ObjectIdentifier attributeType) 214 { 215 RDN[] res = new RDN[rdns.length]; 216 int count = 0; 217 218 for (int i = 0; i != rdns.length; i++) 219 { 220 RDN rdn = rdns[i]; 221 222 if (rdn.isMultiValued()) 223 { 224 AttributeTypeAndValue[] attr = rdn.getTypesAndValues(); 225 for (int j = 0; j != attr.length; j++) 226 { 227 if (attr[j].getType().equals(attributeType)) 228 { 229 res[count++] = rdn; 230 break; 231 } 232 } 233 } 234 else 235 { 236 if (rdn.getFirst().getType().equals(attributeType)) 237 { 238 res[count++] = rdn; 239 } 240 } 241 } 242 243 RDN[] tmp = new RDN[count]; 244 245 System.arraycopy(res, 0, tmp, 0, tmp.length); 246 247 return tmp; 248 } 249 250 public ASN1Primitive toASN1Primitive() 251 { 252 return new DERSequence(rdns); 253 } 254 255 public int hashCode() 256 { 257 if (isHashCodeCalculated) 258 { 259 return hashCodeValue; 260 } 261 262 isHashCodeCalculated = true; 263 264 hashCodeValue = style.calculateHashCode(this); 265 266 return hashCodeValue; 267 } 268 269 /** 270 * test for equality - note: case is ignored. 271 */ 272 public boolean equals(Object obj) 273 { 274 if (obj == this) 275 { 276 return true; 277 } 278 279 if (!(obj instanceof X500Name || obj instanceof ASN1Sequence)) 280 { 281 return false; 282 } 283 284 ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive(); 285 286 if (this.toASN1Primitive().equals(derO)) 287 { 288 return true; 289 } 290 291 try 292 { 293 return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((ASN1Encodable)obj).toASN1Primitive()))); 294 } 295 catch (Exception e) 296 { 297 return false; 298 } 299 } 300 301 public String toString() 302 { 303 return style.toString(this); 304 } 305 306 /** 307 * Set the default style for X500Name construction. 308 * 309 * @param style an X500NameStyle 310 */ 311 public static void setDefaultStyle(X500NameStyle style) 312 { 313 if (style == null) 314 { 315 throw new NullPointerException("cannot set style to null"); 316 } 317 318 defaultStyle = style; 319 } 320 321 /** 322 * Return the current default style. 323 * 324 * @return default style for X500Name construction. 325 */ 326 public static X500NameStyle getDefaultStyle() 327 { 328 return defaultStyle; 329 } 330 } 331