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 * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the 217 * extensions contained in this holder's attribute certificate. 218 * 219 * @return a list of extension OIDs. 220 */ 221 public List getExtensionOIDs() 222 { 223 return CertUtils.getExtensionOIDs(extensions); 224 } 225 226 /** 227 * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the 228 * critical extensions contained in this holder's attribute certificate. 229 * 230 * @return a set of critical extension OIDs. 231 */ 232 public Set getCriticalExtensionOIDs() 233 { 234 return CertUtils.getCriticalExtensionOIDs(extensions); 235 } 236 237 /** 238 * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the 239 * non-critical extensions contained in this holder's attribute certificate. 240 * 241 * @return a set of non-critical extension OIDs. 242 */ 243 public Set getNonCriticalExtensionOIDs() 244 { 245 return CertUtils.getNonCriticalExtensionOIDs(extensions); 246 } 247 248 public boolean[] getIssuerUniqueID() 249 { 250 return CertUtils.bitStringToBoolean(attrCert.getAcinfo().getIssuerUniqueID()); 251 } 252 253 /** 254 * Return the details of the signature algorithm used to create this attribute certificate. 255 * 256 * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate. 257 */ 258 public AlgorithmIdentifier getSignatureAlgorithm() 259 { 260 return attrCert.getSignatureAlgorithm(); 261 } 262 263 /** 264 * Return the bytes making up the signature associated with this attribute certificate. 265 * 266 * @return the attribute certificate signature bytes. 267 */ 268 public byte[] getSignature() 269 { 270 return attrCert.getSignatureValue().getBytes(); 271 } 272 273 /** 274 * Return the underlying ASN.1 structure for the attribute certificate in this holder. 275 * 276 * @return a AttributeCertificate object. 277 */ 278 public AttributeCertificate toASN1Structure() 279 { 280 return attrCert; 281 } 282 283 /** 284 * Return whether or not this attribute certificate is valid on a particular date. 285 * 286 * @param date the date of interest. 287 * @return true if the attribute certificate is valid, false otherwise. 288 */ 289 public boolean isValidOn(Date date) 290 { 291 AttCertValidityPeriod certValidityPeriod = attrCert.getAcinfo().getAttrCertValidityPeriod(); 292 293 return !date.before(CertUtils.recoverDate(certValidityPeriod.getNotBeforeTime())) && !date.after(CertUtils.recoverDate(certValidityPeriod.getNotAfterTime())); 294 } 295 296 /** 297 * Validate the signature on the attribute certificate in this holder. 298 * 299 * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature. 300 * @return true if the signature is valid, false otherwise. 301 * @throws CertException if the signature cannot be processed or is inappropriate. 302 */ 303 public boolean isSignatureValid(ContentVerifierProvider verifierProvider) 304 throws CertException 305 { 306 AttributeCertificateInfo acinfo = attrCert.getAcinfo(); 307 308 if (!acinfo.getSignature().equals(attrCert.getSignatureAlgorithm())) 309 { 310 throw new CertException("signature invalid - algorithm identifier mismatch"); 311 } 312 313 ContentVerifier verifier; 314 315 try 316 { 317 verifier = verifierProvider.get((acinfo.getSignature())); 318 319 OutputStream sOut = verifier.getOutputStream(); 320 DEROutputStream dOut = new DEROutputStream(sOut); 321 322 dOut.writeObject(acinfo); 323 324 sOut.close(); 325 } 326 catch (Exception e) 327 { 328 throw new CertException("unable to process signature: " + e.getMessage(), e); 329 } 330 331 return verifier.verify(attrCert.getSignatureValue().getBytes()); 332 } 333 334 public boolean equals( 335 Object o) 336 { 337 if (o == this) 338 { 339 return true; 340 } 341 342 if (!(o instanceof X509AttributeCertificateHolder)) 343 { 344 return false; 345 } 346 347 X509AttributeCertificateHolder other = (X509AttributeCertificateHolder)o; 348 349 return this.attrCert.equals(other.attrCert); 350 } 351 352 public int hashCode() 353 { 354 return this.attrCert.hashCode(); 355 } 356} 357