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