1 package org.bouncycastle.x509; 2 3 import java.io.IOException; 4 import java.math.BigInteger; 5 import java.security.cert.CertificateExpiredException; 6 import java.security.cert.CertificateNotYetValidException; 7 import java.util.Collection; 8 import java.util.Collections; 9 import java.util.Date; 10 import java.util.HashSet; 11 import java.util.Iterator; 12 import java.util.Set; 13 14 import org.bouncycastle.asn1.ASN1InputStream; 15 import org.bouncycastle.asn1.ASN1Primitive; 16 import org.bouncycastle.asn1.DEROctetString; 17 import org.bouncycastle.asn1.x509.GeneralName; 18 import org.bouncycastle.asn1.x509.Target; 19 import org.bouncycastle.asn1.x509.TargetInformation; 20 import org.bouncycastle.asn1.x509.Targets; 21 import org.bouncycastle.asn1.x509.X509Extensions; 22 import org.bouncycastle.util.Selector; 23 24 /** 25 * This class is an <code>Selector</code> like implementation to select 26 * attribute certificates from a given set of criteria. 27 * 28 * @see org.bouncycastle.x509.X509AttributeCertificate 29 * @see org.bouncycastle.x509.X509Store 30 */ 31 public class X509AttributeCertStoreSelector 32 implements Selector 33 { 34 35 // TODO: name constraints??? 36 37 private AttributeCertificateHolder holder; 38 39 private AttributeCertificateIssuer issuer; 40 41 private BigInteger serialNumber; 42 43 private Date attributeCertificateValid; 44 45 private X509AttributeCertificate attributeCert; 46 47 private Collection targetNames = new HashSet(); 48 49 private Collection targetGroups = new HashSet(); 50 X509AttributeCertStoreSelector()51 public X509AttributeCertStoreSelector() 52 { 53 super(); 54 } 55 56 /** 57 * Decides if the given attribute certificate should be selected. 58 * 59 * @param obj The attribute certificate which should be checked. 60 * @return <code>true</code> if the attribute certificate can be selected, 61 * <code>false</code> otherwise. 62 */ match(Object obj)63 public boolean match(Object obj) 64 { 65 if (!(obj instanceof X509AttributeCertificate)) 66 { 67 return false; 68 } 69 70 X509AttributeCertificate attrCert = (X509AttributeCertificate) obj; 71 72 if (this.attributeCert != null) 73 { 74 if (!this.attributeCert.equals(attrCert)) 75 { 76 return false; 77 } 78 } 79 if (serialNumber != null) 80 { 81 if (!attrCert.getSerialNumber().equals(serialNumber)) 82 { 83 return false; 84 } 85 } 86 if (holder != null) 87 { 88 if (!attrCert.getHolder().equals(holder)) 89 { 90 return false; 91 } 92 } 93 if (issuer != null) 94 { 95 if (!attrCert.getIssuer().equals(issuer)) 96 { 97 return false; 98 } 99 } 100 101 if (attributeCertificateValid != null) 102 { 103 try 104 { 105 attrCert.checkValidity(attributeCertificateValid); 106 } 107 catch (CertificateExpiredException e) 108 { 109 return false; 110 } 111 catch (CertificateNotYetValidException e) 112 { 113 return false; 114 } 115 } 116 if (!targetNames.isEmpty() || !targetGroups.isEmpty()) 117 { 118 119 byte[] targetInfoExt = attrCert 120 .getExtensionValue(X509Extensions.TargetInformation.getId()); 121 if (targetInfoExt != null) 122 { 123 TargetInformation targetinfo; 124 try 125 { 126 targetinfo = TargetInformation 127 .getInstance(new ASN1InputStream( 128 ((DEROctetString) DEROctetString 129 .fromByteArray(targetInfoExt)).getOctets()) 130 .readObject()); 131 } 132 catch (IOException e) 133 { 134 return false; 135 } 136 catch (IllegalArgumentException e) 137 { 138 return false; 139 } 140 Targets[] targetss = targetinfo.getTargetsObjects(); 141 if (!targetNames.isEmpty()) 142 { 143 boolean found = false; 144 145 for (int i=0; i<targetss.length; i++) 146 { 147 Targets t = targetss[i]; 148 Target[] targets = t.getTargets(); 149 for (int j=0; j<targets.length; j++) 150 { 151 if (targetNames.contains(targets[j] 152 .getTargetName())) 153 { 154 found = true; 155 break; 156 } 157 } 158 } 159 if (!found) 160 { 161 return false; 162 } 163 } 164 if (!targetGroups.isEmpty()) 165 { 166 boolean found = false; 167 168 for (int i=0; i<targetss.length; i++) 169 { 170 Targets t = targetss[i]; 171 Target[] targets = t.getTargets(); 172 for (int j=0; j<targets.length; j++) 173 { 174 if (targetGroups.contains(targets[j] 175 .getTargetGroup())) 176 { 177 found = true; 178 break; 179 } 180 } 181 } 182 if (!found) 183 { 184 return false; 185 } 186 } 187 } 188 } 189 return true; 190 } 191 192 /** 193 * Returns a clone of this object. 194 * 195 * @return the clone. 196 */ clone()197 public Object clone() 198 { 199 X509AttributeCertStoreSelector sel = new X509AttributeCertStoreSelector(); 200 sel.attributeCert = attributeCert; 201 sel.attributeCertificateValid = getAttributeCertificateValid(); 202 sel.holder = holder; 203 sel.issuer = issuer; 204 sel.serialNumber = serialNumber; 205 sel.targetGroups = getTargetGroups(); 206 sel.targetNames = getTargetNames(); 207 return sel; 208 } 209 210 /** 211 * Returns the attribute certificate which must be matched. 212 * 213 * @return Returns the attribute certificate. 214 */ getAttributeCert()215 public X509AttributeCertificate getAttributeCert() 216 { 217 return attributeCert; 218 } 219 220 /** 221 * Set the attribute certificate to be matched. If <code>null</code> is 222 * given any will do. 223 * 224 * @param attributeCert The attribute certificate to set. 225 */ setAttributeCert(X509AttributeCertificate attributeCert)226 public void setAttributeCert(X509AttributeCertificate attributeCert) 227 { 228 this.attributeCert = attributeCert; 229 } 230 231 /** 232 * Get the criteria for the validity. 233 * 234 * @return Returns the attributeCertificateValid. 235 */ getAttributeCertificateValid()236 public Date getAttributeCertificateValid() 237 { 238 if (attributeCertificateValid != null) 239 { 240 return new Date(attributeCertificateValid.getTime()); 241 } 242 243 return null; 244 } 245 246 /** 247 * Set the time, when the certificate must be valid. If <code>null</code> 248 * is given any will do. 249 * 250 * @param attributeCertificateValid The attribute certificate validation 251 * time to set. 252 */ setAttributeCertificateValid(Date attributeCertificateValid)253 public void setAttributeCertificateValid(Date attributeCertificateValid) 254 { 255 if (attributeCertificateValid != null) 256 { 257 this.attributeCertificateValid = new Date(attributeCertificateValid 258 .getTime()); 259 } 260 else 261 { 262 this.attributeCertificateValid = null; 263 } 264 } 265 266 /** 267 * Gets the holder. 268 * 269 * @return Returns the holder. 270 */ getHolder()271 public AttributeCertificateHolder getHolder() 272 { 273 return holder; 274 } 275 276 /** 277 * Sets the holder. If <code>null</code> is given any will do. 278 * 279 * @param holder The holder to set. 280 */ setHolder(AttributeCertificateHolder holder)281 public void setHolder(AttributeCertificateHolder holder) 282 { 283 this.holder = holder; 284 } 285 286 /** 287 * Returns the issuer criterion. 288 * 289 * @return Returns the issuer. 290 */ getIssuer()291 public AttributeCertificateIssuer getIssuer() 292 { 293 return issuer; 294 } 295 296 /** 297 * Sets the issuer the attribute certificate must have. If <code>null</code> 298 * is given any will do. 299 * 300 * @param issuer The issuer to set. 301 */ setIssuer(AttributeCertificateIssuer issuer)302 public void setIssuer(AttributeCertificateIssuer issuer) 303 { 304 this.issuer = issuer; 305 } 306 307 /** 308 * Gets the serial number the attribute certificate must have. 309 * 310 * @return Returns the serialNumber. 311 */ getSerialNumber()312 public BigInteger getSerialNumber() 313 { 314 return serialNumber; 315 } 316 317 /** 318 * Sets the serial number the attribute certificate must have. If 319 * <code>null</code> is given any will do. 320 * 321 * @param serialNumber The serialNumber to set. 322 */ setSerialNumber(BigInteger serialNumber)323 public void setSerialNumber(BigInteger serialNumber) 324 { 325 this.serialNumber = serialNumber; 326 } 327 328 /** 329 * Adds a target name criterion for the attribute certificate to the target 330 * information extension criteria. The <code>X509AttributeCertificate</code> 331 * must contain at least one of the specified target names. 332 * <p> 333 * Each attribute certificate may contain a target information extension 334 * limiting the servers where this attribute certificate can be used. If 335 * this extension is not present, the attribute certificate is not targeted 336 * and may be accepted by any server. 337 * 338 * @param name The name as a GeneralName (not <code>null</code>) 339 */ addTargetName(GeneralName name)340 public void addTargetName(GeneralName name) 341 { 342 targetNames.add(name); 343 } 344 345 /** 346 * Adds a target name criterion for the attribute certificate to the target 347 * information extension criteria. The <code>X509AttributeCertificate</code> 348 * must contain at least one of the specified target names. 349 * <p> 350 * Each attribute certificate may contain a target information extension 351 * limiting the servers where this attribute certificate can be used. If 352 * this extension is not present, the attribute certificate is not targeted 353 * and may be accepted by any server. 354 * 355 * @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName 356 * @throws IOException if a parsing error occurs. 357 */ addTargetName(byte[] name)358 public void addTargetName(byte[] name) throws IOException 359 { 360 addTargetName(GeneralName.getInstance(ASN1Primitive.fromByteArray(name))); 361 } 362 363 /** 364 * Adds a collection with target names criteria. If <code>null</code> is 365 * given any will do. 366 * <p> 367 * The collection consists of either GeneralName objects or byte[] arrays representing 368 * DER encoded GeneralName structures. 369 * 370 * @param names A collection of target names. 371 * @throws IOException if a parsing error occurs. 372 * @see #addTargetName(byte[]) 373 * @see #addTargetName(GeneralName) 374 */ setTargetNames(Collection names)375 public void setTargetNames(Collection names) throws IOException 376 { 377 targetNames = extractGeneralNames(names); 378 } 379 380 /** 381 * Gets the target names. The collection consists of <code>List</code>s 382 * made up of an <code>Integer</code> in the first entry and a DER encoded 383 * byte array or a <code>String</code> in the second entry. 384 * <p> 385 * The returned collection is immutable. 386 * 387 * @return The collection of target names 388 * @see #setTargetNames(Collection) 389 */ getTargetNames()390 public Collection getTargetNames() 391 { 392 return Collections.unmodifiableCollection(targetNames); 393 } 394 395 /** 396 * Adds a target group criterion for the attribute certificate to the target 397 * information extension criteria. The <code>X509AttributeCertificate</code> 398 * must contain at least one of the specified target groups. 399 * <p> 400 * Each attribute certificate may contain a target information extension 401 * limiting the servers where this attribute certificate can be used. If 402 * this extension is not present, the attribute certificate is not targeted 403 * and may be accepted by any server. 404 * 405 * @param group The group as GeneralName form (not <code>null</code>) 406 */ addTargetGroup(GeneralName group)407 public void addTargetGroup(GeneralName group) 408 { 409 targetGroups.add(group); 410 } 411 412 /** 413 * Adds a target group criterion for the attribute certificate to the target 414 * information extension criteria. The <code>X509AttributeCertificate</code> 415 * must contain at least one of the specified target groups. 416 * <p> 417 * Each attribute certificate may contain a target information extension 418 * limiting the servers where this attribute certificate can be used. If 419 * this extension is not present, the attribute certificate is not targeted 420 * and may be accepted by any server. 421 * 422 * @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName 423 * @throws IOException if a parsing error occurs. 424 */ addTargetGroup(byte[] name)425 public void addTargetGroup(byte[] name) throws IOException 426 { 427 addTargetGroup(GeneralName.getInstance(ASN1Primitive.fromByteArray(name))); 428 } 429 430 /** 431 * Adds a collection with target groups criteria. If <code>null</code> is 432 * given any will do. 433 * <p> 434 * The collection consists of <code>GeneralName</code> objects or <code>byte[]</code representing DER 435 * encoded GeneralNames. 436 * 437 * @param names A collection of target groups. 438 * @throws IOException if a parsing error occurs. 439 * @see #addTargetGroup(byte[]) 440 * @see #addTargetGroup(GeneralName) 441 */ setTargetGroups(Collection names)442 public void setTargetGroups(Collection names) throws IOException 443 { 444 targetGroups = extractGeneralNames(names); 445 } 446 447 448 449 /** 450 * Gets the target groups. The collection consists of <code>List</code>s 451 * made up of an <code>Integer</code> in the first entry and a DER encoded 452 * byte array or a <code>String</code> in the second entry. 453 * <p> 454 * The returned collection is immutable. 455 * 456 * @return The collection of target groups. 457 * @see #setTargetGroups(Collection) 458 */ getTargetGroups()459 public Collection getTargetGroups() 460 { 461 return Collections.unmodifiableCollection(targetGroups); 462 } 463 extractGeneralNames(Collection names)464 private Set extractGeneralNames(Collection names) 465 throws IOException 466 { 467 if (names == null || names.isEmpty()) 468 { 469 return new HashSet(); 470 } 471 Set temp = new HashSet(); 472 for (Iterator it = names.iterator(); it.hasNext();) 473 { 474 Object o = it.next(); 475 if (o instanceof GeneralName) 476 { 477 temp.add(o); 478 } 479 else 480 { 481 temp.add(GeneralName.getInstance(ASN1Primitive.fromByteArray((byte[])o))); 482 } 483 } 484 return temp; 485 } 486 } 487