1package org.bouncycastle.cert; 2 3import java.io.IOException; 4import java.io.OutputStream; 5import java.math.BigInteger; 6import java.util.ArrayList; 7import java.util.Date; 8import java.util.List; 9import java.util.Set; 10 11import org.bouncycastle.asn1.ASN1ObjectIdentifier; 12import org.bouncycastle.asn1.ASN1Primitive; 13import org.bouncycastle.asn1.ASN1Sequence; 14import org.bouncycastle.asn1.DEROutputStream; 15import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 16import org.bouncycastle.asn1.x509.AttCertValidityPeriod; 17import org.bouncycastle.asn1.x509.Attribute; 18import org.bouncycastle.asn1.x509.AttributeCertificate; 19import org.bouncycastle.asn1.x509.AttributeCertificateInfo; 20import org.bouncycastle.asn1.x509.Extension; 21import org.bouncycastle.asn1.x509.Extensions; 22import org.bouncycastle.operator.ContentVerifier; 23import org.bouncycastle.operator.ContentVerifierProvider; 24 25/** 26 * Holding class for an X.509 AttributeCertificate structure. 27 */ 28public class X509AttributeCertificateHolder 29{ 30 private static Attribute[] EMPTY_ARRAY = new Attribute[0]; 31 32 private AttributeCertificate attrCert; 33 private Extensions extensions; 34 35 private static AttributeCertificate parseBytes(byte[] certEncoding) 36 throws IOException 37 { 38 try 39 { 40 return AttributeCertificate.getInstance(ASN1Primitive.fromByteArray(certEncoding)); 41 } 42 catch (ClassCastException e) 43 { 44 throw new CertIOException("malformed data: " + e.getMessage(), e); 45 } 46 catch (IllegalArgumentException e) 47 { 48 throw new CertIOException("malformed data: " + e.getMessage(), e); 49 } 50 } 51 52 /** 53 * Create a X509AttributeCertificateHolder from the passed in bytes. 54 * 55 * @param certEncoding BER/DER encoding of the certificate. 56 * @throws IOException in the event of corrupted data, or an incorrect structure. 57 */ 58 public X509AttributeCertificateHolder(byte[] certEncoding) 59 throws IOException 60 { 61 this(parseBytes(certEncoding)); 62 } 63 64 /** 65 * Create a X509AttributeCertificateHolder from the passed in ASN.1 structure. 66 * 67 * @param attrCert an ASN.1 AttributeCertificate structure. 68 */ 69 public X509AttributeCertificateHolder(AttributeCertificate attrCert) 70 { 71 this.attrCert = attrCert; 72 this.extensions = attrCert.getAcinfo().getExtensions(); 73 } 74 75 /** 76 * Return the ASN.1 encoding of this holder's attribute certificate. 77 * 78 * @return a DER encoded byte array. 79 * @throws IOException if an encoding cannot be generated. 80 */ 81 public byte[] getEncoded() 82 throws IOException 83 { 84 return attrCert.getEncoded(); 85 } 86 87 public int getVersion() 88 { 89 return attrCert.getAcinfo().getVersion().getValue().intValue() + 1; 90 } 91 92 /** 93 * Return the serial number of this attribute certificate. 94 * 95 * @return the serial number. 96 */ 97 public BigInteger getSerialNumber() 98 { 99 return attrCert.getAcinfo().getSerialNumber().getValue(); 100 } 101 102 /** 103 * Return the holder details for this attribute certificate. 104 * 105 * @return this attribute certificate's holder structure. 106 */ 107 public AttributeCertificateHolder getHolder() 108 { 109 return new AttributeCertificateHolder((ASN1Sequence)attrCert.getAcinfo().getHolder().toASN1Primitive()); 110 } 111 112 /** 113 * Return the issuer details for this attribute certificate. 114 * 115 * @return this attribute certificate's issuer structure, 116 */ 117 public AttributeCertificateIssuer getIssuer() 118 { 119 return new AttributeCertificateIssuer(attrCert.getAcinfo().getIssuer()); 120 } 121 122 /** 123 * Return the date before which this attribute certificate is not valid. 124 * 125 * @return the start date for the attribute certificate's validity period. 126 */ 127 public Date getNotBefore() 128 { 129 return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime()); 130 } 131 132 /** 133 * Return the date after which this attribute certificate is not valid. 134 * 135 * @return the final date for the attribute certificate's validity period. 136 */ 137 public Date getNotAfter() 138 { 139 return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime()); 140 } 141 142 /** 143 * Return the attributes, if any associated with this request. 144 * 145 * @return an array of Attribute, zero length if none present. 146 */ 147 public Attribute[] getAttributes() 148 { 149 ASN1Sequence seq = attrCert.getAcinfo().getAttributes(); 150 Attribute[] attrs = new Attribute[seq.size()]; 151 152 for (int i = 0; i != seq.size(); i++) 153 { 154 attrs[i] = Attribute.getInstance(seq.getObjectAt(i)); 155 } 156 157 return attrs; 158 } 159 160 /** 161 * Return an array of attributes matching the passed in type OID. 162 * 163 * @param type the type of the attribute being looked for. 164 * @return an array of Attribute of the requested type, zero length if none present. 165 */ 166 public Attribute[] getAttributes(ASN1ObjectIdentifier type) 167 { 168 ASN1Sequence seq = attrCert.getAcinfo().getAttributes(); 169 List list = new ArrayList(); 170 171 for (int i = 0; i != seq.size(); i++) 172 { 173 Attribute attr = Attribute.getInstance(seq.getObjectAt(i)); 174 if (attr.getAttrType().equals(type)) 175 { 176 list.add(attr); 177 } 178 } 179 180 if (list.size() == 0) 181 { 182 return EMPTY_ARRAY; 183 } 184 185 return (Attribute[])list.toArray(new Attribute[list.size()]); 186 } 187 188 /** 189 * Return whether or not the holder's attribute certificate contains extensions. 190 * 191 * @return true if extension are present, false otherwise. 192 */ 193 public boolean hasExtensions() 194 { 195 return extensions != null; 196 } 197 198 /** 199 * Look up the extension associated with the passed in OID. 200 * 201 * @param oid the OID of the extension of interest. 202 * 203 * @return the extension if present, null otherwise. 204 */ 205 public Extension getExtension(ASN1ObjectIdentifier oid) 206 { 207 if (extensions != null) 208 { 209 return extensions.getExtension(oid); 210 } 211 212 return null; 213 } 214 215 /** 216 * Return the extensions block associated with this certificate if there is one. 217 * 218 * @return the extensions block, null otherwise. 219 */ 220 public Extensions getExtensions() 221 { 222 return extensions; 223 } 224 225 /** 226 * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the 227 * extensions contained in this holder's attribute certificate. 228 * 229 * @return a list of extension OIDs. 230 */ 231 public List getExtensionOIDs() 232 { 233 return CertUtils.getExtensionOIDs(extensions); 234 } 235 236 /** 237 * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the 238 * critical extensions contained in this holder's attribute certificate. 239 * 240 * @return a set of critical extension OIDs. 241 */ 242 public Set getCriticalExtensionOIDs() 243 { 244 return CertUtils.getCriticalExtensionOIDs(extensions); 245 } 246 247 /** 248 * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the 249 * non-critical extensions contained in this holder's attribute certificate. 250 * 251 * @return a set of non-critical extension OIDs. 252 */ 253 public Set getNonCriticalExtensionOIDs() 254 { 255 return CertUtils.getNonCriticalExtensionOIDs(extensions); 256 } 257 258 public boolean[] getIssuerUniqueID() 259 { 260 return CertUtils.bitStringToBoolean(attrCert.getAcinfo().getIssuerUniqueID()); 261 } 262 263 /** 264 * Return the details of the signature algorithm used to create this attribute certificate. 265 * 266 * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate. 267 */ 268 public AlgorithmIdentifier getSignatureAlgorithm() 269 { 270 return attrCert.getSignatureAlgorithm(); 271 } 272 273 /** 274 * Return the bytes making up the signature associated with this attribute certificate. 275 * 276 * @return the attribute certificate signature bytes. 277 */ 278 public byte[] getSignature() 279 { 280 return attrCert.getSignatureValue().getBytes(); 281 } 282 283 /** 284 * Return the underlying ASN.1 structure for the attribute certificate in this holder. 285 * 286 * @return a AttributeCertificate object. 287 */ 288 public AttributeCertificate toASN1Structure() 289 { 290 return attrCert; 291 } 292 293 /** 294 * Return whether or not this attribute certificate is valid on a particular date. 295 * 296 * @param date the date of interest. 297 * @return true if the attribute certificate is valid, false otherwise. 298 */ 299 public boolean isValidOn(Date date) 300 { 301 AttCertValidityPeriod certValidityPeriod = attrCert.getAcinfo().getAttrCertValidityPeriod(); 302 303 return !date.before(CertUtils.recoverDate(certValidityPeriod.getNotBeforeTime())) && !date.after(CertUtils.recoverDate(certValidityPeriod.getNotAfterTime())); 304 } 305 306 /** 307 * Validate the signature on the attribute certificate in this holder. 308 * 309 * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature. 310 * @return true if the signature is valid, false otherwise. 311 * @throws CertException if the signature cannot be processed or is inappropriate. 312 */ 313 public boolean isSignatureValid(ContentVerifierProvider verifierProvider) 314 throws CertException 315 { 316 AttributeCertificateInfo acinfo = attrCert.getAcinfo(); 317 318 if (!CertUtils.isAlgIdEqual(acinfo.getSignature(), attrCert.getSignatureAlgorithm())) 319 { 320 throw new CertException("signature invalid - algorithm identifier mismatch"); 321 } 322 323 ContentVerifier verifier; 324 325 try 326 { 327 verifier = verifierProvider.get((acinfo.getSignature())); 328 329 OutputStream sOut = verifier.getOutputStream(); 330 DEROutputStream dOut = new DEROutputStream(sOut); 331 332 dOut.writeObject(acinfo); 333 334 sOut.close(); 335 } 336 catch (Exception e) 337 { 338 throw new CertException("unable to process signature: " + e.getMessage(), e); 339 } 340 341 return verifier.verify(attrCert.getSignatureValue().getBytes()); 342 } 343 344 public boolean equals( 345 Object o) 346 { 347 if (o == this) 348 { 349 return true; 350 } 351 352 if (!(o instanceof X509AttributeCertificateHolder)) 353 { 354 return false; 355 } 356 357 X509AttributeCertificateHolder other = (X509AttributeCertificateHolder)o; 358 359 return this.attrCert.equals(other.attrCert); 360 } 361 362 public int hashCode() 363 { 364 return this.attrCert.hashCode(); 365 } 366} 367