1 package org.bouncycastle.x509; 2 3 import java.io.IOException; 4 import java.math.BigInteger; 5 import java.security.MessageDigest; 6 import java.security.Principal; 7 import java.security.cert.CertSelector; 8 import java.security.cert.Certificate; 9 import java.security.cert.CertificateEncodingException; 10 import java.security.cert.CertificateParsingException; 11 import java.security.cert.X509Certificate; 12 import java.util.ArrayList; 13 import java.util.List; 14 15 import javax.security.auth.x500.X500Principal; 16 17 import org.bouncycastle.asn1.ASN1Encodable; 18 import org.bouncycastle.asn1.ASN1Sequence; 19 import org.bouncycastle.asn1.DERInteger; 20 import org.bouncycastle.asn1.DERSequence; 21 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 22 import org.bouncycastle.asn1.x509.GeneralName; 23 import org.bouncycastle.asn1.x509.GeneralNames; 24 import org.bouncycastle.asn1.x509.Holder; 25 import org.bouncycastle.asn1.x509.IssuerSerial; 26 import org.bouncycastle.asn1.x509.ObjectDigestInfo; 27 import org.bouncycastle.jce.PrincipalUtil; 28 import org.bouncycastle.jce.X509Principal; 29 import org.bouncycastle.util.Arrays; 30 import org.bouncycastle.util.Selector; 31 32 /** 33 * The Holder object. 34 * 35 * <pre> 36 * Holder ::= SEQUENCE { 37 * baseCertificateID [0] IssuerSerial OPTIONAL, 38 * -- the issuer and serial number of 39 * -- the holder's Public Key Certificate 40 * entityName [1] GeneralNames OPTIONAL, 41 * -- the name of the claimant or role 42 * objectDigestInfo [2] ObjectDigestInfo OPTIONAL 43 * -- used to directly authenticate the holder, 44 * -- for example, an executable 45 * } 46 * </pre> 47 * @deprecated use org.bouncycastle.cert.AttributeCertificateHolder 48 */ 49 public class AttributeCertificateHolder 50 implements CertSelector, Selector 51 { 52 final Holder holder; 53 54 AttributeCertificateHolder(ASN1Sequence seq) 55 { 56 holder = Holder.getInstance(seq); 57 } 58 59 public AttributeCertificateHolder(X509Principal issuerName, 60 BigInteger serialNumber) 61 { 62 holder = new org.bouncycastle.asn1.x509.Holder(new IssuerSerial( 63 new GeneralNames(new DERSequence(new GeneralName(issuerName))), 64 new DERInteger(serialNumber))); 65 } 66 67 public AttributeCertificateHolder(X500Principal issuerName, 68 BigInteger serialNumber) 69 { 70 this(X509Util.convertPrincipal(issuerName), serialNumber); 71 } 72 73 public AttributeCertificateHolder(X509Certificate cert) 74 throws CertificateParsingException 75 { 76 X509Principal name; 77 78 try 79 { 80 name = PrincipalUtil.getIssuerX509Principal(cert); 81 } 82 catch (Exception e) 83 { 84 throw new CertificateParsingException(e.getMessage()); 85 } 86 87 holder = new Holder(new IssuerSerial(generateGeneralNames(name), 88 new DERInteger(cert.getSerialNumber()))); 89 } 90 91 public AttributeCertificateHolder(X509Principal principal) 92 { 93 holder = new Holder(generateGeneralNames(principal)); 94 } 95 96 public AttributeCertificateHolder(X500Principal principal) 97 { 98 this(X509Util.convertPrincipal(principal)); 99 } 100 101 /** 102 * Constructs a holder for v2 attribute certificates with a hash value for 103 * some type of object. 104 * <p> 105 * <code>digestedObjectType</code> can be one of the following: 106 * <ul> 107 * <li>0 - publicKey - A hash of the public key of the holder must be 108 * passed. 109 * <li>1 - publicKeyCert - A hash of the public key certificate of the 110 * holder must be passed. 111 * <li>2 - otherObjectDigest - A hash of some other object type must be 112 * passed. <code>otherObjectTypeID</code> must not be empty. 113 * </ul> 114 * <p> 115 * This cannot be used if a v1 attribute certificate is used. 116 * 117 * @param digestedObjectType The digest object type. 118 * @param digestAlgorithm The algorithm identifier for the hash. 119 * @param otherObjectTypeID The object type ID if 120 * <code>digestedObjectType</code> is 121 * <code>otherObjectDigest</code>. 122 * @param objectDigest The hash value. 123 */ 124 public AttributeCertificateHolder(int digestedObjectType, 125 String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest) 126 { 127 holder = new Holder(new ObjectDigestInfo(digestedObjectType, 128 otherObjectTypeID, new AlgorithmIdentifier(digestAlgorithm), Arrays 129 .clone(objectDigest))); 130 } 131 132 /** 133 * Returns the digest object type if an object digest info is used. 134 * <p> 135 * <ul> 136 * <li>0 - publicKey - A hash of the public key of the holder must be 137 * passed. 138 * <li>1 - publicKeyCert - A hash of the public key certificate of the 139 * holder must be passed. 140 * <li>2 - otherObjectDigest - A hash of some other object type must be 141 * passed. <code>otherObjectTypeID</code> must not be empty. 142 * </ul> 143 * 144 * @return The digest object type or -1 if no object digest info is set. 145 */ 146 public int getDigestedObjectType() 147 { 148 if (holder.getObjectDigestInfo() != null) 149 { 150 return holder.getObjectDigestInfo().getDigestedObjectType() 151 .getValue().intValue(); 152 } 153 return -1; 154 } 155 156 /** 157 * Returns the other object type ID if an object digest info is used. 158 * 159 * @return The other object type ID or <code>null</code> if no object 160 * digest info is set. 161 */ 162 public String getDigestAlgorithm() 163 { 164 if (holder.getObjectDigestInfo() != null) 165 { 166 return holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId() 167 .getId(); 168 } 169 return null; 170 } 171 172 /** 173 * Returns the hash if an object digest info is used. 174 * 175 * @return The hash or <code>null</code> if no object digest info is set. 176 */ 177 public byte[] getObjectDigest() 178 { 179 if (holder.getObjectDigestInfo() != null) 180 { 181 return holder.getObjectDigestInfo().getObjectDigest().getBytes(); 182 } 183 return null; 184 } 185 186 /** 187 * Returns the digest algorithm ID if an object digest info is used. 188 * 189 * @return The digest algorithm ID or <code>null</code> if no object 190 * digest info is set. 191 */ 192 public String getOtherObjectTypeID() 193 { 194 if (holder.getObjectDigestInfo() != null) 195 { 196 holder.getObjectDigestInfo().getOtherObjectTypeID().getId(); 197 } 198 return null; 199 } 200 201 private GeneralNames generateGeneralNames(X509Principal principal) 202 { 203 return new GeneralNames(new DERSequence(new GeneralName(principal))); 204 } 205 206 private boolean matchesDN(X509Principal subject, GeneralNames targets) 207 { 208 GeneralName[] names = targets.getNames(); 209 210 for (int i = 0; i != names.length; i++) 211 { 212 GeneralName gn = names[i]; 213 214 if (gn.getTagNo() == GeneralName.directoryName) 215 { 216 try 217 { 218 if (new X509Principal(((ASN1Encodable)gn.getName()) 219 .getEncoded()).equals(subject)) 220 { 221 return true; 222 } 223 } 224 catch (IOException e) 225 { 226 } 227 } 228 } 229 230 return false; 231 } 232 233 private Object[] getNames(GeneralName[] names) 234 { 235 List l = new ArrayList(names.length); 236 237 for (int i = 0; i != names.length; i++) 238 { 239 if (names[i].getTagNo() == GeneralName.directoryName) 240 { 241 try 242 { 243 l.add(new X500Principal( 244 ((ASN1Encodable)names[i].getName()).getEncoded())); 245 } 246 catch (IOException e) 247 { 248 throw new RuntimeException("badly formed Name object"); 249 } 250 } 251 } 252 253 return l.toArray(new Object[l.size()]); 254 } 255 256 private Principal[] getPrincipals(GeneralNames names) 257 { 258 Object[] p = this.getNames(names.getNames()); 259 List l = new ArrayList(); 260 261 for (int i = 0; i != p.length; i++) 262 { 263 if (p[i] instanceof Principal) 264 { 265 l.add(p[i]); 266 } 267 } 268 269 return (Principal[])l.toArray(new Principal[l.size()]); 270 } 271 272 /** 273 * Return any principal objects inside the attribute certificate holder 274 * entity names field. 275 * 276 * @return an array of Principal objects (usually X500Principal), null if no 277 * entity names field is set. 278 */ 279 public Principal[] getEntityNames() 280 { 281 if (holder.getEntityName() != null) 282 { 283 return getPrincipals(holder.getEntityName()); 284 } 285 286 return null; 287 } 288 289 /** 290 * Return the principals associated with the issuer attached to this holder 291 * 292 * @return an array of principals, null if no BaseCertificateID is set. 293 */ 294 public Principal[] getIssuer() 295 { 296 if (holder.getBaseCertificateID() != null) 297 { 298 return getPrincipals(holder.getBaseCertificateID().getIssuer()); 299 } 300 301 return null; 302 } 303 304 /** 305 * Return the serial number associated with the issuer attached to this 306 * holder. 307 * 308 * @return the certificate serial number, null if no BaseCertificateID is 309 * set. 310 */ 311 public BigInteger getSerialNumber() 312 { 313 if (holder.getBaseCertificateID() != null) 314 { 315 return holder.getBaseCertificateID().getSerial().getValue(); 316 } 317 318 return null; 319 } 320 321 public Object clone() 322 { 323 return new AttributeCertificateHolder((ASN1Sequence)holder 324 .toASN1Object()); 325 } 326 327 public boolean match(Certificate cert) 328 { 329 if (!(cert instanceof X509Certificate)) 330 { 331 return false; 332 } 333 334 X509Certificate x509Cert = (X509Certificate)cert; 335 336 try 337 { 338 if (holder.getBaseCertificateID() != null) 339 { 340 return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber()) 341 && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer()); 342 } 343 344 if (holder.getEntityName() != null) 345 { 346 if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), 347 holder.getEntityName())) 348 { 349 return true; 350 } 351 } 352 if (holder.getObjectDigestInfo() != null) 353 { 354 MessageDigest md = null; 355 try 356 { 357 md = MessageDigest.getInstance(getDigestAlgorithm(), "BC"); 358 359 } 360 catch (Exception e) 361 { 362 return false; 363 } 364 switch (getDigestedObjectType()) 365 { 366 case ObjectDigestInfo.publicKey: 367 // TODO: DSA Dss-parms 368 md.update(cert.getPublicKey().getEncoded()); 369 break; 370 case ObjectDigestInfo.publicKeyCert: 371 md.update(cert.getEncoded()); 372 break; 373 } 374 if (!Arrays.areEqual(md.digest(), getObjectDigest())) 375 { 376 return false; 377 } 378 } 379 } 380 catch (CertificateEncodingException e) 381 { 382 return false; 383 } 384 385 return false; 386 } 387 388 public boolean equals(Object obj) 389 { 390 if (obj == this) 391 { 392 return true; 393 } 394 395 if (!(obj instanceof AttributeCertificateHolder)) 396 { 397 return false; 398 } 399 400 AttributeCertificateHolder other = (AttributeCertificateHolder)obj; 401 402 return this.holder.equals(other.holder); 403 } 404 405 public int hashCode() 406 { 407 return this.holder.hashCode(); 408 } 409 410 public boolean match(Object obj) 411 { 412 if (!(obj instanceof X509Certificate)) 413 { 414 return false; 415 } 416 417 return match((Certificate)obj); 418 } 419 } 420