001: package org.bouncycastle.ocsp;
002:
003: import org.bouncycastle.asn1.ASN1EncodableVector;
004: import org.bouncycastle.asn1.ASN1InputStream;
005: import org.bouncycastle.asn1.ASN1Sequence;
006: import org.bouncycastle.asn1.DERBitString;
007: import org.bouncycastle.asn1.DERGeneralizedTime;
008: import org.bouncycastle.asn1.DERNull;
009: import org.bouncycastle.asn1.DERObject;
010: import org.bouncycastle.asn1.DERObjectIdentifier;
011: import org.bouncycastle.asn1.DEROutputStream;
012: import org.bouncycastle.asn1.DERSequence;
013: import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
014: import org.bouncycastle.asn1.ocsp.CertStatus;
015: import org.bouncycastle.asn1.ocsp.ResponseData;
016: import org.bouncycastle.asn1.ocsp.RevokedInfo;
017: import org.bouncycastle.asn1.ocsp.SingleResponse;
018: import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
019: import org.bouncycastle.asn1.x509.CRLReason;
020: import org.bouncycastle.asn1.x509.X509CertificateStructure;
021: import org.bouncycastle.asn1.x509.X509Extensions;
022:
023: import java.io.ByteArrayOutputStream;
024: import java.io.IOException;
025: import java.security.InvalidKeyException;
026: import java.security.NoSuchAlgorithmException;
027: import java.security.NoSuchProviderException;
028: import java.security.PrivateKey;
029: import java.security.PublicKey;
030: import java.security.SecureRandom;
031: import java.security.Signature;
032: import java.security.cert.CertificateEncodingException;
033: import java.security.cert.X509Certificate;
034: import java.util.ArrayList;
035: import java.util.Date;
036: import java.util.Iterator;
037: import java.util.List;
038:
039: /**
040: * Generator for basic OCSP response objects.
041: */
042: public class BasicOCSPRespGenerator {
043: private List list = new ArrayList();
044: private X509Extensions responseExtensions = null;
045: private RespID responderID;
046:
047: private class ResponseObject {
048: CertificateID certId;
049: CertStatus certStatus;
050: DERGeneralizedTime this Update;
051: DERGeneralizedTime nextUpdate;
052: X509Extensions extensions;
053:
054: public ResponseObject(CertificateID certId,
055: CertificateStatus certStatus, Date this Update,
056: Date nextUpdate, X509Extensions extensions) {
057: this .certId = certId;
058:
059: if (certStatus == null) {
060: this .certStatus = new CertStatus();
061: } else if (certStatus instanceof UnknownStatus) {
062: this .certStatus = new CertStatus(2, new DERNull());
063: } else {
064: RevokedStatus rs = (RevokedStatus) certStatus;
065:
066: if (rs.hasRevocationReason()) {
067: this .certStatus = new CertStatus(new RevokedInfo(
068: new DERGeneralizedTime(rs
069: .getRevocationTime()),
070: new CRLReason(rs.getRevocationReason())));
071: } else {
072: this .certStatus = new CertStatus(new RevokedInfo(
073: new DERGeneralizedTime(rs
074: .getRevocationTime()), null));
075: }
076: }
077:
078: this .this Update = new DERGeneralizedTime(this Update);
079:
080: if (nextUpdate != null) {
081: this .nextUpdate = new DERGeneralizedTime(nextUpdate);
082: } else {
083: this .nextUpdate = null;
084: }
085:
086: this .extensions = extensions;
087: }
088:
089: public SingleResponse toResponse() throws Exception {
090: return new SingleResponse(certId.toASN1Object(),
091: certStatus, this Update, nextUpdate, extensions);
092: }
093: }
094:
095: private DERObject makeObj(byte[] encoding) throws IOException {
096: if (encoding == null) {
097: return null;
098: }
099:
100: ASN1InputStream aIn = new ASN1InputStream(encoding);
101:
102: return aIn.readObject();
103: }
104:
105: /**
106: * basic constructor
107: */
108: public BasicOCSPRespGenerator(RespID responderID) {
109: this .responderID = responderID;
110: }
111:
112: /**
113: * construct with the responderID to be the SHA-1 keyHash of the passed in public key.
114: */
115: public BasicOCSPRespGenerator(PublicKey key) throws OCSPException {
116: this .responderID = new RespID(key);
117: }
118:
119: /**
120: * Add a response for a particular Certificate ID.
121: *
122: * @param certID certificate ID details
123: * @param certStatus status of the certificate - null if okay
124: */
125: public void addResponse(CertificateID certID,
126: CertificateStatus certStatus) {
127: list.add(new ResponseObject(certID, certStatus, new Date(),
128: null, null));
129: }
130:
131: /**
132: * Add a response for a particular Certificate ID.
133: *
134: * @param certID certificate ID details
135: * @param certStatus status of the certificate - null if okay
136: * @param singleExtensions optional extensions
137: */
138: public void addResponse(CertificateID certID,
139: CertificateStatus certStatus,
140: X509Extensions singleExtensions) {
141: list.add(new ResponseObject(certID, certStatus, new Date(),
142: null, singleExtensions));
143: }
144:
145: /**
146: * Add a response for a particular Certificate ID.
147: *
148: * @param certID certificate ID details
149: * @param nextUpdate date when next update should be requested
150: * @param certStatus status of the certificate - null if okay
151: * @param singleExtensions optional extensions
152: */
153: public void addResponse(CertificateID certID,
154: CertificateStatus certStatus, Date nextUpdate,
155: X509Extensions singleExtensions) {
156: list.add(new ResponseObject(certID, certStatus, new Date(),
157: nextUpdate, singleExtensions));
158: }
159:
160: /**
161: * Add a response for a particular Certificate ID.
162: *
163: * @param certID certificate ID details
164: * @param thisUpdate date this response was valid on
165: * @param nextUpdate date when next update should be requested
166: * @param certStatus status of the certificate - null if okay
167: * @param singleExtensions optional extensions
168: */
169: public void addResponse(CertificateID certID,
170: CertificateStatus certStatus, Date this Update,
171: Date nextUpdate, X509Extensions singleExtensions) {
172: list.add(new ResponseObject(certID, certStatus, this Update,
173: nextUpdate, singleExtensions));
174: }
175:
176: /**
177: * Set the extensions for the response.
178: *
179: * @param responseExtensions the extension object to carry.
180: */
181: public void setResponseExtensions(X509Extensions responseExtensions) {
182: this .responseExtensions = responseExtensions;
183: }
184:
185: private BasicOCSPResp generateResponse(String signatureName,
186: PrivateKey key, X509Certificate[] chain, Date producedAt,
187: String provider, SecureRandom random) throws OCSPException,
188: NoSuchProviderException {
189: Iterator it = list.iterator();
190: DERObjectIdentifier signingAlgorithm;
191:
192: try {
193: signingAlgorithm = OCSPUtil.getAlgorithmOID(signatureName);
194: } catch (Exception e) {
195: throw new IllegalArgumentException(
196: "unknown signing algorithm specified");
197: }
198:
199: ASN1EncodableVector responses = new ASN1EncodableVector();
200:
201: while (it.hasNext()) {
202: try {
203: responses
204: .add(((ResponseObject) it.next()).toResponse());
205: } catch (Exception e) {
206: throw new OCSPException("exception creating Request", e);
207: }
208: }
209:
210: ResponseData tbsResp = new ResponseData(responderID
211: .toASN1Object(), new DERGeneralizedTime(producedAt),
212: new DERSequence(responses), responseExtensions);
213:
214: Signature sig = null;
215:
216: try {
217: sig = Signature.getInstance(signatureName, provider);
218: if (random != null) {
219: sig.initSign(key, random);
220: } else {
221: sig.initSign(key);
222: }
223: } catch (NoSuchAlgorithmException e) {
224: throw new OCSPException("exception creating signature: "
225: + e, e);
226: } catch (InvalidKeyException e) {
227: throw new OCSPException("exception creating signature: "
228: + e, e);
229: }
230:
231: DERBitString bitSig = null;
232:
233: try {
234: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
235: DEROutputStream dOut = new DEROutputStream(bOut);
236:
237: dOut.writeObject(tbsResp);
238:
239: sig.update(bOut.toByteArray());
240:
241: bitSig = new DERBitString(sig.sign());
242: } catch (Exception e) {
243: throw new OCSPException("exception processing TBSRequest: "
244: + e, e);
245: }
246:
247: AlgorithmIdentifier sigAlgId = OCSPUtil
248: .getSigAlgID(signingAlgorithm);
249:
250: if (chain != null && chain.length > 0) {
251: ASN1EncodableVector v = new ASN1EncodableVector();
252: try {
253: for (int i = 0; i != chain.length; i++) {
254: v.add(new X509CertificateStructure(
255: (ASN1Sequence) makeObj(chain[i]
256: .getEncoded())));
257: }
258: } catch (IOException e) {
259: throw new OCSPException("error processing certs", e);
260: } catch (CertificateEncodingException e) {
261: throw new OCSPException("error encoding certs", e);
262: }
263:
264: return new BasicOCSPResp(new BasicOCSPResponse(tbsResp,
265: sigAlgId, bitSig, new DERSequence(v)));
266: } else {
267: return new BasicOCSPResp(new BasicOCSPResponse(tbsResp,
268: sigAlgId, bitSig, null));
269: }
270: }
271:
272: public BasicOCSPResp generate(String signingAlgorithm,
273: PrivateKey key, X509Certificate[] chain, Date this Update,
274: String provider) throws OCSPException,
275: NoSuchProviderException, IllegalArgumentException {
276: return generate(signingAlgorithm, key, chain, this Update,
277: provider, null);
278: }
279:
280: public BasicOCSPResp generate(String signingAlgorithm,
281: PrivateKey key, X509Certificate[] chain, Date producedAt,
282: String provider, SecureRandom random) throws OCSPException,
283: NoSuchProviderException, IllegalArgumentException {
284: if (signingAlgorithm == null) {
285: throw new IllegalArgumentException(
286: "no signing algorithm specified");
287: }
288:
289: return generateResponse(signingAlgorithm, key, chain,
290: producedAt, provider, random);
291: }
292:
293: /**
294: * Return an iterator of the signature names supported by the generator.
295: *
296: * @return an iterator containing recognised names.
297: */
298: public Iterator getSignatureAlgNames() {
299: return OCSPUtil.getAlgNames();
300: }
301: }
|