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