001: package org.bouncycastle.ocsp;
002:
003: import org.bouncycastle.asn1.ASN1OutputStream;
004: import org.bouncycastle.asn1.ASN1Sequence;
005: import org.bouncycastle.asn1.DERObjectIdentifier;
006: import org.bouncycastle.asn1.DEROutputStream;
007: import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
008: import org.bouncycastle.asn1.ocsp.ResponseData;
009: import org.bouncycastle.asn1.ocsp.SingleResponse;
010: import org.bouncycastle.asn1.x509.X509Extension;
011: import org.bouncycastle.asn1.x509.X509Extensions;
012:
013: import java.io.ByteArrayInputStream;
014: import java.io.ByteArrayOutputStream;
015: import java.io.IOException;
016: import java.security.InvalidAlgorithmParameterException;
017: import java.security.NoSuchAlgorithmException;
018: import java.security.NoSuchProviderException;
019: import java.security.PublicKey;
020: import java.security.cert.CertStore;
021: import java.security.cert.CertificateException;
022: import java.security.cert.CertificateFactory;
023: import java.security.cert.CollectionCertStoreParameters;
024: import java.security.cert.X509Certificate;
025: import java.text.ParseException;
026: import java.util.ArrayList;
027: import java.util.Date;
028: import java.util.Enumeration;
029: import java.util.HashSet;
030: import java.util.List;
031: import java.util.Set;
032:
033: /**
034: * <pre>
035: * BasicOCSPResponse ::= SEQUENCE {
036: * tbsResponseData ResponseData,
037: * signatureAlgorithm AlgorithmIdentifier,
038: * signature BIT STRING,
039: * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
040: * </pre>
041: */
042: public class BasicOCSPResp implements java.security.cert.X509Extension {
043: BasicOCSPResponse resp;
044: ResponseData data;
045: X509Certificate[] chain = null;
046:
047: public BasicOCSPResp(BasicOCSPResponse resp) {
048: this .resp = resp;
049: this .data = resp.getTbsResponseData();
050: }
051:
052: /**
053: * Return the DER encoding of the tbsResponseData field.
054: * @return DER encoding of tbsResponseData
055: * @throws OCSPException in the event of an encoding error.
056: */
057: public byte[] getTBSResponseData() throws OCSPException {
058: try {
059: return resp.getTbsResponseData().getEncoded();
060: } catch (IOException e) {
061: throw new OCSPException("problem encoding tbsResponseData",
062: e);
063: }
064: }
065:
066: public int getVersion() {
067: return data.getVersion().getValue().intValue() + 1;
068: }
069:
070: public RespID getResponderId() {
071: return new RespID(data.getResponderID());
072: }
073:
074: public Date getProducedAt() {
075: try {
076: return data.getProducedAt().getDate();
077: } catch (ParseException e) {
078: throw new IllegalStateException("ParseException:"
079: + e.getMessage());
080: }
081: }
082:
083: public SingleResp[] getResponses() {
084: ASN1Sequence s = data.getResponses();
085: SingleResp[] rs = new SingleResp[s.size()];
086:
087: for (int i = 0; i != rs.length; i++) {
088: rs[i] = new SingleResp(SingleResponse.getInstance(s
089: .getObjectAt(i)));
090: }
091:
092: return rs;
093: }
094:
095: public X509Extensions getResponseExtensions() {
096: return data.getResponseExtensions();
097: }
098:
099: /**
100: * RFC 2650 doesn't specify any critical extensions so we return true
101: * if any are encountered.
102: *
103: * @return true if any critical extensions are present.
104: */
105: public boolean hasUnsupportedCriticalExtension() {
106: Set extns = getCriticalExtensionOIDs();
107: if (extns != null && !extns.isEmpty()) {
108: return true;
109: }
110:
111: return false;
112: }
113:
114: private Set getExtensionOIDs(boolean critical) {
115: Set set = new HashSet();
116: X509Extensions extensions = this .getResponseExtensions();
117:
118: if (extensions != null) {
119: Enumeration e = extensions.oids();
120:
121: while (e.hasMoreElements()) {
122: DERObjectIdentifier oid = (DERObjectIdentifier) e
123: .nextElement();
124: X509Extension ext = extensions.getExtension(oid);
125:
126: if (critical == ext.isCritical()) {
127: set.add(oid.getId());
128: }
129: }
130: }
131:
132: return set;
133: }
134:
135: public Set getCriticalExtensionOIDs() {
136: return getExtensionOIDs(true);
137: }
138:
139: public Set getNonCriticalExtensionOIDs() {
140: return getExtensionOIDs(false);
141: }
142:
143: public byte[] getExtensionValue(String oid) {
144: X509Extensions exts = this .getResponseExtensions();
145:
146: if (exts != null) {
147: X509Extension ext = exts
148: .getExtension(new DERObjectIdentifier(oid));
149:
150: if (ext != null) {
151: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
152: DEROutputStream dOut = new DEROutputStream(bOut);
153:
154: try {
155: dOut.writeObject(ext.getValue());
156:
157: return bOut.toByteArray();
158: } catch (Exception e) {
159: throw new RuntimeException("error encoding "
160: + e.toString());
161: }
162: }
163: }
164:
165: return null;
166: }
167:
168: public String getSignatureAlgName() {
169: return OCSPUtil.getAlgorithmName(resp.getSignatureAlgorithm()
170: .getObjectId());
171: }
172:
173: public String getSignatureAlgOID() {
174: return resp.getSignatureAlgorithm().getObjectId().getId();
175: }
176:
177: /**
178: * @deprecated RespData class is no longer required as all functionality is
179: * available on this class.
180: * @return the RespData object
181: */
182: public RespData getResponseData() {
183: return new RespData(resp.getTbsResponseData());
184: }
185:
186: public byte[] getSignature() {
187: return resp.getSignature().getBytes();
188: }
189:
190: private List getCertList(String provider) throws OCSPException,
191: NoSuchProviderException {
192: List certs = new ArrayList();
193: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
194: ASN1OutputStream aOut = new ASN1OutputStream(bOut);
195: CertificateFactory cf;
196:
197: try {
198: cf = CertificateFactory.getInstance("X.509", provider);
199: } catch (CertificateException ex) {
200: throw new OCSPException("can't get certificate factory.",
201: ex);
202: }
203:
204: //
205: // load the certificates and revocation lists if we have any
206: //
207: ASN1Sequence s = resp.getCerts();
208:
209: if (s != null) {
210: Enumeration e = s.getObjects();
211:
212: while (e.hasMoreElements()) {
213: try {
214: aOut.writeObject(e.nextElement());
215:
216: certs
217: .add(cf
218: .generateCertificate(new ByteArrayInputStream(
219: bOut.toByteArray())));
220: } catch (IOException ex) {
221: throw new OCSPException(
222: "can't re-encode certificate!", ex);
223: } catch (CertificateException ex) {
224: throw new OCSPException(
225: "can't re-encode certificate!", ex);
226: }
227:
228: bOut.reset();
229: }
230: }
231:
232: return certs;
233: }
234:
235: public X509Certificate[] getCerts(String provider)
236: throws OCSPException, NoSuchProviderException {
237: List certs = getCertList(provider);
238:
239: return (X509Certificate[]) certs
240: .toArray(new X509Certificate[certs.size()]);
241: }
242:
243: /**
244: * Return the certificates, if any associated with the response.
245: * @param type type of CertStore to create
246: * @param provider provider to use
247: * @return a CertStore, possibly empty
248: * @throws NoSuchAlgorithmException
249: * @throws NoSuchProviderException
250: * @throws OCSPException
251: */
252: public CertStore getCertificates(String type, String provider)
253: throws NoSuchAlgorithmException, NoSuchProviderException,
254: OCSPException {
255: try {
256: return CertStore.getInstance(type,
257: new CollectionCertStoreParameters(this
258: .getCertList(provider)), provider);
259: } catch (InvalidAlgorithmParameterException e) {
260: throw new OCSPException("can't setup the CertStore", e);
261: }
262: }
263:
264: /**
265: * verify the signature against the tbsResponseData object we contain.
266: */
267: public boolean verify(PublicKey key, String sigProvider)
268: throws OCSPException, NoSuchProviderException {
269: try {
270: java.security.Signature signature = java.security.Signature
271: .getInstance(this .getSignatureAlgName(),
272: sigProvider);
273:
274: signature.initVerify(key);
275:
276: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
277: DEROutputStream dOut = new DEROutputStream(bOut);
278:
279: dOut.writeObject(resp.getTbsResponseData());
280:
281: signature.update(bOut.toByteArray());
282:
283: return signature.verify(this .getSignature());
284: } catch (NoSuchProviderException e) {
285: throw e;
286: } catch (Exception e) {
287: throw new OCSPException("exception processing sig: " + e, e);
288: }
289: }
290:
291: /**
292: * return the ASN.1 encoded representation of this object.
293: */
294: public byte[] getEncoded() throws IOException {
295: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
296: ASN1OutputStream aOut = new ASN1OutputStream(bOut);
297:
298: aOut.writeObject(resp);
299:
300: return bOut.toByteArray();
301: }
302:
303: public boolean equals(Object o) {
304: if (o == this ) {
305: return true;
306: }
307:
308: if (!(o instanceof BasicOCSPResp)) {
309: return false;
310: }
311:
312: BasicOCSPResp r = (BasicOCSPResp) o;
313:
314: return resp.equals(r.resp);
315: }
316:
317: public int hashCode() {
318: return resp.hashCode();
319: }
320: }
|