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