001: package org.bouncycastle.jce.provider;
002:
003: import org.bouncycastle.asn1.ASN1Encodable;
004: import org.bouncycastle.asn1.ASN1OutputStream;
005: import org.bouncycastle.asn1.DERObjectIdentifier;
006: import org.bouncycastle.asn1.DEROutputStream;
007: import org.bouncycastle.asn1.x509.CertificateList;
008: import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
009: import org.bouncycastle.asn1.x509.TBSCertList;
010: import org.bouncycastle.asn1.x509.X509Extension;
011: import org.bouncycastle.asn1.x509.X509Extensions;
012: import org.bouncycastle.jce.X509Principal;
013: import org.bouncycastle.x509.extension.X509ExtensionUtil;
014:
015: import javax.security.auth.x500.X500Principal;
016: import java.io.ByteArrayOutputStream;
017: import java.io.IOException;
018: import java.math.BigInteger;
019: import java.security.InvalidKeyException;
020: import java.security.NoSuchAlgorithmException;
021: import java.security.NoSuchProviderException;
022: import java.security.Principal;
023: import java.security.PublicKey;
024: import java.security.Signature;
025: import java.security.SignatureException;
026: import java.security.cert.CRLException;
027: import java.security.cert.Certificate;
028: import java.security.cert.X509CRL;
029: import java.security.cert.X509CRLEntry;
030: import java.security.cert.X509Certificate;
031: import java.util.Date;
032: import java.util.Enumeration;
033: import java.util.HashSet;
034: import java.util.Set;
035:
036: /**
037: * The following extensions are listed in RFC 2459 as relevant to CRLs
038: *
039: * Authority Key Identifier
040: * Issuer Alternative Name
041: * CRL Number
042: * Delta CRL Indicator (critical)
043: * Issuing Distribution Point (critical)
044: */
045: public class X509CRLObject extends X509CRL {
046: private CertificateList c;
047: private String sigAlgName;
048: private byte[] sigAlgParams;
049: private boolean isIndirect;
050:
051: public X509CRLObject(CertificateList c) throws CRLException {
052: this .c = c;
053:
054: try {
055: this .sigAlgName = X509SignatureUtil.getSignatureName(c
056: .getSignatureAlgorithm());
057:
058: if (c.getSignatureAlgorithm().getParameters() != null) {
059: this .sigAlgParams = ((ASN1Encodable) c
060: .getSignatureAlgorithm().getParameters())
061: .getDEREncoded();
062: } else {
063: this .sigAlgParams = null;
064: }
065:
066: this .isIndirect = isIndirectCRL();
067: } catch (Exception e) {
068: throw new CRLException("CRL contents invalid: " + e);
069: }
070: }
071:
072: /**
073: * Will return true if any extensions are present and marked
074: * as critical as we currently dont handle any extensions!
075: */
076: public boolean hasUnsupportedCriticalExtension() {
077: Set extns = getCriticalExtensionOIDs();
078: return extns != null && !extns.isEmpty();
079: }
080:
081: private Set getExtensionOIDs(boolean critical) {
082: if (this .getVersion() == 2) {
083: Set set = new HashSet();
084: X509Extensions extensions = c.getTBSCertList()
085: .getExtensions();
086: Enumeration e = extensions.oids();
087:
088: while (e.hasMoreElements()) {
089: DERObjectIdentifier oid = (DERObjectIdentifier) e
090: .nextElement();
091: X509Extension ext = extensions.getExtension(oid);
092:
093: if (critical == ext.isCritical()) {
094: set.add(oid.getId());
095: }
096: }
097:
098: return set;
099: }
100:
101: return null;
102: }
103:
104: public Set getCriticalExtensionOIDs() {
105: return getExtensionOIDs(true);
106: }
107:
108: public Set getNonCriticalExtensionOIDs() {
109: return getExtensionOIDs(false);
110: }
111:
112: public byte[] getExtensionValue(String oid) {
113: X509Extensions exts = c.getTBSCertList().getExtensions();
114:
115: if (exts != null) {
116: X509Extension ext = exts
117: .getExtension(new DERObjectIdentifier(oid));
118:
119: if (ext != null) {
120: try {
121: return ext.getValue().getEncoded();
122: } catch (Exception e) {
123: throw new IllegalStateException("error parsing "
124: + e.toString());
125: }
126: }
127: }
128:
129: return null;
130: }
131:
132: public byte[] getEncoded() throws CRLException {
133: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
134: DEROutputStream dOut = new DEROutputStream(bOut);
135:
136: try {
137: dOut.writeObject(c);
138:
139: return bOut.toByteArray();
140: } catch (IOException e) {
141: throw new CRLException(e.toString());
142: }
143: }
144:
145: public void verify(PublicKey key) throws CRLException,
146: NoSuchAlgorithmException, InvalidKeyException,
147: NoSuchProviderException, SignatureException {
148: verify(key, "BC");
149: }
150:
151: public void verify(PublicKey key, String sigProvider)
152: throws CRLException, NoSuchAlgorithmException,
153: InvalidKeyException, NoSuchProviderException,
154: SignatureException {
155: if (!c.getSignatureAlgorithm().equals(
156: c.getTBSCertList().getSignature())) {
157: throw new CRLException(
158: "Signature algorithm on CertificateList does not match TBSCertList.");
159: }
160:
161: Signature sig = Signature.getInstance(getSigAlgName(),
162: sigProvider);
163:
164: sig.initVerify(key);
165: sig.update(this .getTBSCertList());
166: if (!sig.verify(this .getSignature())) {
167: throw new SignatureException(
168: "CRL does not verify with supplied public key.");
169: }
170: }
171:
172: public int getVersion() {
173: return c.getVersion();
174: }
175:
176: public Principal getIssuerDN() {
177: return new X509Principal(c.getIssuer());
178: }
179:
180: public X500Principal getIssuerX500Principal() {
181: try {
182: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
183: ASN1OutputStream aOut = new ASN1OutputStream(bOut);
184:
185: aOut.writeObject(c.getIssuer());
186:
187: return new X500Principal(bOut.toByteArray());
188: } catch (IOException e) {
189: throw new IllegalStateException("can't encode issuer DN");
190: }
191: }
192:
193: public Date getThisUpdate() {
194: return c.getThisUpdate().getDate();
195: }
196:
197: public Date getNextUpdate() {
198: if (c.getNextUpdate() != null) {
199: return c.getNextUpdate().getDate();
200: }
201:
202: return null;
203: }
204:
205: public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
206: TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
207:
208: if (certs != null) {
209: X500Principal previousCertificateIssuer = getIssuerX500Principal();
210: for (int i = 0; i < certs.length; i++) {
211: X509CRLEntryObject crlentry = new X509CRLEntryObject(
212: certs[i], isIndirect, previousCertificateIssuer);
213: previousCertificateIssuer = crlentry
214: .getCertificateIssuer();
215: if (crlentry.getSerialNumber().equals(serialNumber)) {
216: return crlentry;
217: }
218: }
219: }
220:
221: return null;
222: }
223:
224: public Set getRevokedCertificates() {
225: TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
226:
227: if (certs != null) {
228: Set set = new HashSet();
229: X500Principal previousCertificateIssuer = getIssuerX500Principal();
230: for (int i = 0; i < certs.length; i++) {
231: X509CRLEntryObject crlentry = new X509CRLEntryObject(
232: certs[i], isIndirect, previousCertificateIssuer);
233: set.add(crlentry);
234: previousCertificateIssuer = crlentry
235: .getCertificateIssuer();
236: }
237:
238: return set;
239: }
240:
241: return null;
242: }
243:
244: public byte[] getTBSCertList() throws CRLException {
245: try {
246: return c.getTBSCertList().getEncoded("DER");
247: } catch (IOException e) {
248: throw new CRLException(e.toString());
249: }
250: }
251:
252: public byte[] getSignature() {
253: return c.getSignature().getBytes();
254: }
255:
256: public String getSigAlgName() {
257: return sigAlgName;
258: }
259:
260: public String getSigAlgOID() {
261: return c.getSignatureAlgorithm().getObjectId().getId();
262: }
263:
264: public byte[] getSigAlgParams() {
265: if (sigAlgParams != null) {
266: byte[] tmp = new byte[sigAlgParams.length];
267:
268: System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
269:
270: return tmp;
271: }
272:
273: return null;
274: }
275:
276: /**
277: * Returns a string representation of this CRL.
278: *
279: * @return a string representation of this CRL.
280: */
281: public String toString() {
282: return "X.509 CRL";
283: }
284:
285: /**
286: * Checks whether the given certificate is on this CRL.
287: *
288: * @param cert the certificate to check for.
289: * @return true if the given certificate is on this CRL,
290: * false otherwise.
291: */
292: public boolean isRevoked(Certificate cert) {
293: if (!cert.getType().equals("X.509")) {
294: throw new RuntimeException(
295: "X.509 CRL used with non X.509 Cert");
296: }
297:
298: TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
299:
300: if (certs != null) {
301: BigInteger serial = ((X509Certificate) cert)
302: .getSerialNumber();
303:
304: for (int i = 0; i < certs.length; i++) {
305: if (certs[i].getUserCertificate().getValue().equals(
306: serial)) {
307: return true;
308: }
309: }
310: }
311:
312: return false;
313: }
314:
315: private boolean isIndirectCRL() throws CRLException {
316: byte[] idp = getExtensionValue(X509Extensions.IssuingDistributionPoint
317: .getId());
318: boolean isIndirect = false;
319: try {
320: if (idp != null) {
321: isIndirect = IssuingDistributionPoint.getInstance(
322: X509ExtensionUtil.fromExtensionValue(idp))
323: .isIndirectCRL();
324: }
325: } catch (IOException e) {
326: throw new ExtCRLException(
327: "Exception reading IssuingDistributionPoint", e);
328: }
329:
330: return isIndirect;
331: }
332: }
|