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