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