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