001: package org.bouncycastle.x509;
002:
003: import org.bouncycastle.asn1.ASN1Encodable;
004: import org.bouncycastle.asn1.ASN1InputStream;
005: import org.bouncycastle.asn1.ASN1Sequence;
006: import org.bouncycastle.asn1.DERBitString;
007: import org.bouncycastle.asn1.DERObjectIdentifier;
008: import org.bouncycastle.asn1.DEROutputStream;
009: import org.bouncycastle.asn1.x509.AttributeCertificate;
010: import org.bouncycastle.asn1.x509.X509Extension;
011: import org.bouncycastle.asn1.x509.X509Extensions;
012: import org.bouncycastle.util.Arrays;
013:
014: import java.io.ByteArrayInputStream;
015: import java.io.ByteArrayOutputStream;
016: import java.io.IOException;
017: import java.io.InputStream;
018: import java.math.BigInteger;
019: import java.security.InvalidKeyException;
020: import java.security.NoSuchAlgorithmException;
021: import java.security.NoSuchProviderException;
022: import java.security.PublicKey;
023: import java.security.Signature;
024: import java.security.SignatureException;
025: import java.security.cert.CertificateException;
026: import java.security.cert.CertificateExpiredException;
027: import java.security.cert.CertificateNotYetValidException;
028: import java.text.ParseException;
029: import java.util.ArrayList;
030: import java.util.Date;
031: import java.util.Enumeration;
032: import java.util.HashSet;
033: import java.util.List;
034: import java.util.Set;
035:
036: /**
037: * An implementation of a version 2 X.509 Attribute Certificate.
038: */
039: public class X509V2AttributeCertificate implements
040: X509AttributeCertificate {
041: private AttributeCertificate cert;
042: private Date notBefore;
043: private Date notAfter;
044:
045: public X509V2AttributeCertificate(InputStream encIn)
046: throws IOException {
047: this (AttributeCertificate
048: .getInstance(new ASN1InputStream(encIn).readObject()));
049: }
050:
051: public X509V2AttributeCertificate(byte[] encoded)
052: throws IOException {
053: this (new ByteArrayInputStream(encoded));
054: }
055:
056: X509V2AttributeCertificate(AttributeCertificate cert)
057: throws IOException {
058: this .cert = cert;
059:
060: try {
061: this .notAfter = cert.getAcinfo()
062: .getAttrCertValidityPeriod().getNotAfterTime()
063: .getDate();
064: this .notBefore = cert.getAcinfo()
065: .getAttrCertValidityPeriod().getNotBeforeTime()
066: .getDate();
067: } catch (ParseException e) {
068: throw new IOException(
069: "invalid data structure in certificate!");
070: }
071: }
072:
073: public int getVersion() {
074: return cert.getAcinfo().getVersion().getValue().intValue();
075: }
076:
077: public BigInteger getSerialNumber() {
078: return cert.getAcinfo().getSerialNumber().getValue();
079: }
080:
081: public AttributeCertificateHolder getHolder() {
082: return new AttributeCertificateHolder((ASN1Sequence) cert
083: .getAcinfo().getHolder().toASN1Object());
084: }
085:
086: public AttributeCertificateIssuer getIssuer() {
087: return new AttributeCertificateIssuer(cert.getAcinfo()
088: .getIssuer());
089: }
090:
091: public Date getNotBefore() {
092: return notBefore;
093: }
094:
095: public Date getNotAfter() {
096: return notAfter;
097: }
098:
099: public boolean[] getIssuerUniqueID() {
100: DERBitString id = cert.getAcinfo().getIssuerUniqueID();
101:
102: if (id != null) {
103: byte[] bytes = id.getBytes();
104: boolean[] boolId = new boolean[bytes.length * 8
105: - id.getPadBits()];
106:
107: for (int i = 0; i != boolId.length; i++) {
108: boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
109: }
110:
111: return boolId;
112: }
113:
114: return null;
115: }
116:
117: public void checkValidity() throws CertificateExpiredException,
118: CertificateNotYetValidException {
119: this .checkValidity(new Date());
120: }
121:
122: public void checkValidity(Date date)
123: throws CertificateExpiredException,
124: CertificateNotYetValidException {
125: if (date.after(this .getNotAfter())) {
126: throw new CertificateExpiredException(
127: "certificate expired on " + this .getNotAfter());
128: }
129:
130: if (date.before(this .getNotBefore())) {
131: throw new CertificateNotYetValidException(
132: "certificate not valid till " + this .getNotBefore());
133: }
134: }
135:
136: public byte[] getSignature() {
137: return cert.getSignatureValue().getBytes();
138: }
139:
140: public final void verify(PublicKey key, String provider)
141: throws CertificateException, NoSuchAlgorithmException,
142: InvalidKeyException, NoSuchProviderException,
143: SignatureException {
144: Signature signature = null;
145:
146: if (!cert.getSignatureAlgorithm().equals(
147: cert.getAcinfo().getSignature())) {
148: throw new CertificateException(
149: "Signature algorithm in certificate info not same as outer certificate");
150: }
151:
152: signature = Signature.getInstance(cert.getSignatureAlgorithm()
153: .getObjectId().getId(), provider);
154:
155: signature.initVerify(key);
156:
157: try {
158: signature.update(cert.getAcinfo().getEncoded());
159: } catch (IOException e) {
160: throw new SignatureException(
161: "Exception encoding certificate info object");
162: }
163:
164: if (!signature.verify(this .getSignature())) {
165: throw new InvalidKeyException(
166: "Public key presented not for certificate signature");
167: }
168: }
169:
170: public byte[] getEncoded() throws IOException {
171: return cert.getEncoded();
172: }
173:
174: public byte[] getExtensionValue(String oid) {
175: X509Extensions extensions = cert.getAcinfo().getExtensions();
176:
177: if (extensions != null) {
178: X509Extension ext = extensions
179: .getExtension(new DERObjectIdentifier(oid));
180:
181: if (ext != null) {
182: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
183: DEROutputStream dOut = new DEROutputStream(bOut);
184:
185: try {
186: dOut.writeObject(ext.getValue());
187:
188: return bOut.toByteArray();
189: } catch (Exception e) {
190: throw new RuntimeException("error encoding "
191: + e.toString());
192: }
193: }
194: }
195:
196: return null;
197: }
198:
199: private Set getExtensionOIDs(boolean critical) {
200: X509Extensions extensions = cert.getAcinfo().getExtensions();
201:
202: if (extensions != null) {
203: Set set = new HashSet();
204: Enumeration e = extensions.oids();
205:
206: while (e.hasMoreElements()) {
207: DERObjectIdentifier oid = (DERObjectIdentifier) e
208: .nextElement();
209: X509Extension ext = extensions.getExtension(oid);
210:
211: if (ext.isCritical() == critical) {
212: set.add(oid.getId());
213: }
214: }
215:
216: return set;
217: }
218:
219: return null;
220: }
221:
222: public Set getNonCriticalExtensionOIDs() {
223: return getExtensionOIDs(false);
224: }
225:
226: public Set getCriticalExtensionOIDs() {
227: return getExtensionOIDs(true);
228: }
229:
230: public boolean hasUnsupportedCriticalExtension() {
231: Set extensions = getCriticalExtensionOIDs();
232:
233: return extensions != null && !extensions.isEmpty();
234: }
235:
236: public X509Attribute[] getAttributes() {
237: ASN1Sequence seq = cert.getAcinfo().getAttributes();
238: X509Attribute[] attrs = new X509Attribute[seq.size()];
239:
240: for (int i = 0; i != seq.size(); i++) {
241: attrs[i] = new X509Attribute((ASN1Encodable) seq
242: .getObjectAt(i));
243: }
244:
245: return attrs;
246: }
247:
248: public X509Attribute[] getAttributes(String oid) {
249: ASN1Sequence seq = cert.getAcinfo().getAttributes();
250: List list = new ArrayList();
251:
252: for (int i = 0; i != seq.size(); i++) {
253: X509Attribute attr = new X509Attribute((ASN1Encodable) seq
254: .getObjectAt(i));
255: if (attr.getOID().equals(oid)) {
256: list.add(attr);
257: }
258: }
259:
260: if (list.size() == 0) {
261: return null;
262: }
263:
264: return (X509Attribute[]) list.toArray(new X509Attribute[list
265: .size()]);
266: }
267:
268: public boolean equals(Object o) {
269: if (o == this ) {
270: return true;
271: }
272:
273: if (!(o instanceof X509AttributeCertificate)) {
274: return false;
275: }
276:
277: X509AttributeCertificate other = (X509AttributeCertificate) o;
278:
279: try {
280: byte[] b1 = this .getEncoded();
281: byte[] b2 = other.getEncoded();
282:
283: return Arrays.areEqual(b1, b2);
284: } catch (IOException e) {
285: return false;
286: }
287: }
288:
289: public int hashCode() {
290: try {
291: byte[] b = this .getEncoded();
292: int value = 0;
293:
294: for (int i = 0; i != b.length; i++) {
295: value ^= (b[i] & 0xff) << (i % 4);
296: }
297:
298: return value;
299: } catch (IOException e) {
300: return 0;
301: }
302: }
303: }
|