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.ASN1ObjectIdentifier; 8 import org.bouncycastle.asn1.ASN1Sequence; 9 import org.bouncycastle.asn1.ASN1TaggedObject; 10 import org.bouncycastle.asn1.DEREncodable; 11 import org.bouncycastle.asn1.DERObject; 12 import org.bouncycastle.asn1.DERSequence; 13 import org.bouncycastle.asn1.x500.style.BCStyle; 14 import org.bouncycastle.asn1.x509.X509Name; 15 16 /** 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 ASN1Encodable 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 public X500Name(X500NameStyle style, X500Name name) 43 { 44 this.rdns = name.rdns; 45 this.style = style; 46 } 47 48 /** 49 * Return a X509Name based on the passed in tagged object. 50 * 51 * @param obj tag object holding name. 52 * @param explicit true if explicitly tagged false otherwise. 53 * @return the X509Name 54 */ 55 public static X500Name getInstance( 56 ASN1TaggedObject obj, 57 boolean explicit) 58 { 59 // must be true as choice item 60 return getInstance(ASN1Sequence.getInstance(obj, true)); 61 } 62 63 public static X500Name getInstance( 64 Object obj) 65 { 66 if (obj instanceof X500Name) 67 { 68 return (X500Name)obj; 69 } 70 else if (obj instanceof X509Name) 71 { 72 return new X500Name(ASN1Sequence.getInstance(((X509Name)obj).getDERObject())); 73 } 74 else if (obj != null) 75 { 76 return new X500Name(ASN1Sequence.getInstance(obj)); 77 } 78 79 return null; 80 } 81 82 /** 83 * Constructor from ASN1Sequence 84 * 85 * the principal will be a list of constructed sets, each containing an (OID, String) pair. 86 */ 87 private X500Name( 88 ASN1Sequence seq) 89 { 90 this(defaultStyle, seq); 91 } 92 93 private X500Name( 94 X500NameStyle style, 95 ASN1Sequence seq) 96 { 97 this.style = style; 98 this.rdns = new RDN[seq.size()]; 99 100 int index = 0; 101 102 for (Enumeration e = seq.getObjects(); e.hasMoreElements();) 103 { 104 rdns[index++] = RDN.getInstance(e.nextElement()); 105 } 106 } 107 108 public X500Name( 109 RDN[] rDNs) 110 { 111 this(defaultStyle, rDNs); 112 } 113 114 public X500Name( 115 X500NameStyle style, 116 RDN[] rDNs) 117 { 118 this.rdns = rDNs; 119 this.style = style; 120 } 121 122 public X500Name( 123 String dirName) 124 { 125 this(defaultStyle, dirName); 126 } 127 128 public X500Name( 129 X500NameStyle style, 130 String dirName) 131 { 132 this(style.fromString(dirName)); 133 134 this.style = style; 135 } 136 137 /** 138 * return an array of RDNs in structure order. 139 * 140 * @return an array of RDN objects. 141 */ 142 public RDN[] getRDNs() 143 { 144 RDN[] tmp = new RDN[this.rdns.length]; 145 146 System.arraycopy(rdns, 0, tmp, 0, tmp.length); 147 148 return tmp; 149 } 150 151 /** 152 * return an array of RDNs containing the attribute type given by OID in structure order. 153 * 154 * @param oid the type OID we are looking for. 155 * @return an array, possibly zero length, of RDN objects. 156 */ 157 public RDN[] getRDNs(ASN1ObjectIdentifier oid) 158 { 159 RDN[] res = new RDN[rdns.length]; 160 int count = 0; 161 162 for (int i = 0; i != rdns.length; i++) 163 { 164 RDN rdn = rdns[i]; 165 166 if (rdn.isMultiValued()) 167 { 168 AttributeTypeAndValue[] attr = rdn.getTypesAndValues(); 169 for (int j = 0; j != attr.length; j++) 170 { 171 if (attr[j].getType().equals(oid)) 172 { 173 res[count++] = rdn; 174 break; 175 } 176 } 177 } 178 else 179 { 180 if (rdn.getFirst().getType().equals(oid)) 181 { 182 res[count++] = rdn; 183 } 184 } 185 } 186 187 RDN[] tmp = new RDN[count]; 188 189 System.arraycopy(res, 0, tmp, 0, tmp.length); 190 191 return tmp; 192 } 193 194 public DERObject toASN1Object() 195 { 196 return new DERSequence(rdns); 197 } 198 199 public int hashCode() 200 { 201 if (isHashCodeCalculated) 202 { 203 return hashCodeValue; 204 } 205 206 isHashCodeCalculated = true; 207 208 hashCodeValue = style.calculateHashCode(this); 209 210 return hashCodeValue; 211 } 212 213 /** 214 * test for equality - note: case is ignored. 215 */ 216 public boolean equals(Object obj) 217 { 218 if (obj == this) 219 { 220 return true; 221 } 222 223 if (!(obj instanceof X500Name || obj instanceof ASN1Sequence)) 224 { 225 return false; 226 } 227 228 DERObject derO = ((DEREncodable)obj).getDERObject(); 229 230 if (this.getDERObject().equals(derO)) 231 { 232 return true; 233 } 234 235 try 236 { 237 return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((DEREncodable)obj).getDERObject()))); 238 } 239 catch (Exception e) 240 { 241 return false; 242 } 243 } 244 245 public String toString() 246 { 247 return style.toString(this); 248 } 249 250 /** 251 * Set the default style for X500Name construction. 252 * 253 * @param style an X500NameStyle 254 */ 255 public static void setDefaultStyle(X500NameStyle style) 256 { 257 if (style == null) 258 { 259 throw new NullPointerException("cannot set style to null"); 260 } 261 262 defaultStyle = style; 263 } 264 265 /** 266 * Return the current default style. 267 * 268 * @return default style for X500Name construction. 269 */ 270 public static X500NameStyle getDefaultStyle() 271 { 272 return defaultStyle; 273 } 274 } 275