KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ejbca > ui > web > protocol > OCSPServletBase


1 /*************************************************************************
2  * *
3  * EJBCA: The OpenSource Certificate Authority *
4  * *
5  * This software is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU Lesser General Public *
7  * License as published by the Free Software Foundation; either *
8  * version 2.1 of the License, or any later version. *
9  * *
10  * See terms of license at gnu.org. *
11  * *
12  *************************************************************************/

13
14 package org.ejbca.ui.web.protocol;
15
16 import java.io.BufferedReader JavaDoc;
17 import java.io.ByteArrayOutputStream JavaDoc;
18 import java.io.IOException JavaDoc;
19 import java.math.BigInteger JavaDoc;
20 import java.security.cert.Certificate JavaDoc;
21 import java.security.cert.X509Certificate JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.Date JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Hashtable JavaDoc;
28 import java.util.Iterator JavaDoc;
29
30 import javax.servlet.ServletConfig JavaDoc;
31 import javax.servlet.ServletException JavaDoc;
32 import javax.servlet.http.HttpServlet JavaDoc;
33 import javax.servlet.http.HttpServletRequest JavaDoc;
34 import javax.servlet.http.HttpServletResponse JavaDoc;
35
36 import org.apache.commons.lang.StringUtils;
37 import org.apache.log4j.Logger;
38 import org.bouncycastle.asn1.DERGeneralizedTime;
39 import org.bouncycastle.asn1.DERObjectIdentifier;
40 import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
41 import org.bouncycastle.asn1.ocsp.RevokedInfo;
42 import org.bouncycastle.asn1.x509.CRLReason;
43 import org.bouncycastle.asn1.x509.X509Extension;
44 import org.bouncycastle.asn1.x509.X509Extensions;
45 import org.bouncycastle.ocsp.BasicOCSPResp;
46 import org.bouncycastle.ocsp.CertificateID;
47 import org.bouncycastle.ocsp.CertificateStatus;
48 import org.bouncycastle.ocsp.OCSPException;
49 import org.bouncycastle.ocsp.OCSPReq;
50 import org.bouncycastle.ocsp.OCSPResp;
51 import org.bouncycastle.ocsp.OCSPRespGenerator;
52 import org.bouncycastle.ocsp.Req;
53 import org.bouncycastle.ocsp.RevokedStatus;
54 import org.bouncycastle.ocsp.UnknownStatus;
55 import org.bouncycastle.util.encoders.Hex;
56 import org.ejbca.core.ejb.ca.store.CertificateDataBean;
57 import org.ejbca.core.model.InternalResources;
58 import org.ejbca.core.model.ca.MalformedRequestException;
59 import org.ejbca.core.model.ca.SignRequestException;
60 import org.ejbca.core.model.ca.SignRequestSignatureException;
61 import org.ejbca.core.model.ca.caadmin.CADoesntExistsException;
62 import org.ejbca.core.model.ca.caadmin.extendedcaservices.ExtendedCAServiceNotActiveException;
63 import org.ejbca.core.model.ca.caadmin.extendedcaservices.ExtendedCAServiceRequestException;
64 import org.ejbca.core.model.ca.caadmin.extendedcaservices.IllegalExtendedCAServiceRequestException;
65 import org.ejbca.core.model.ca.caadmin.extendedcaservices.OCSPCAServiceRequest;
66 import org.ejbca.core.model.ca.caadmin.extendedcaservices.OCSPCAServiceResponse;
67 import org.ejbca.core.model.ca.crl.RevokedCertInfo;
68 import org.ejbca.core.model.log.Admin;
69 import org.ejbca.core.protocol.ocsp.IOCSPExtension;
70 import org.ejbca.core.protocol.ocsp.OCSPResponseItem;
71 import org.ejbca.util.CertTools;
72
73 /**
74  * @web.servlet-init-param description="Algorithm used by server to generate signature on OCSP responses"
75  * name="SignatureAlgorithm"
76  * value="${ocsp.signaturealgorithm}"
77  *
78  * @web.servlet-init-param description="If set to true the servlet will enforce OCSP request signing"
79  * name="enforceRequestSigning"
80  * value="false"
81  *
82  * @web.servlet-init-param description="If set to true the certificate chain will be returned with the OCSP response"
83  * name="includeCertChain"
84  * value="true"
85  *
86  * @web.servlet-init-param description="If set to true the OCSP reponses will be signed directly by the CAs certificate instead of the CAs OCSP responder"
87  * name="useCASigningCert"
88  * value="${ocsp.usecasigningcert}"
89  *
90  * @web.servlet-init-param description="Specifies the subject of a certificate which is used to identifiy the responder which will generate responses when no real CA can be found from the request. This is used to generate 'unknown' responses when a request is received for a certificate that is not signed by any CA on this server"
91  * name="defaultResponderID"
92  * value="${ocsp.defaultresponder}"
93  *
94  * @web.servlet-init-param description="Specifies OCSP extension oids that will result in a call to an extension class, separate multiple entries with ;"
95  * name="extensionOid"
96  * value="${ocsp.extensionoid}"
97  *
98  * @web.servlet-init-param description="Specifies classes implementing OCSP extensions matching oids above, separate multiple entries with ;"
99  * name="extensionClass"
100  * value="${ocsp.extensionclass}"
101  *
102  * @web.servlet-init-param description="Specifies classes implementing OCSP extensions matching oids above, separate multiple entries with ;"
103  * name="unidDataSource"
104  * value="${ocsp.uniddatsource}"
105  *
106  * @web.servlet-init-param description="Directory containing certificates of trusted entities allowed to query for Fnrs."
107  * name="unidTrustDir"
108  * value="${ocsp.unidtrustdir}"
109  *
110  * @web.servlet-init-param description="File containing the CA-certificate, in PEM format, that signed the trusted clients."
111  * name="unidCACert"
112  * value="${ocsp.unidcacert}"
113  *
114  * @author Thomas Meckel (Ophios GmbH), Tomas Gustavsson, Lars Silven
115  * @version $Id: OCSPServletBase.java,v 1.28 2007/01/16 11:46:14 anatom Exp $
116  */

117 abstract class OCSPServletBase extends HttpServlet JavaDoc {
118
119     private static final Logger m_log = Logger.getLogger(OCSPServletBase.class);
120     /** Internal localization of logs and errors */
121     private static final InternalResources intres = InternalResources.getInstance();
122
123     private Admin m_adm;
124
125     private String JavaDoc m_sigAlg;
126     private boolean m_reqMustBeSigned;
127     Collection JavaDoc m_cacerts = null;
128     /** Cache time counter */
129     private long m_certValidTo = 0;
130     /** Cached list of cacerts is valid 5 minutes */
131     private static final long VALID_TIME = 5 * 60 * 1000;
132     /** String used to identify default responder id, used to generatwe responses when a request
133      * for a certificate not signed by a CA on this server is received.
134      */

135     private String JavaDoc m_defaultResponderId;
136     /** Marks if the CAs certificate or the CAs OCSP responder certificate should be used for
137      * signing the OCSP response. Defined in web.xml
138      */

139     private boolean m_useCASigningCert;
140     /** Marks if the CAs certificate chain shoudl be included in the OCSP response or not
141      * Defined in web.xml
142      */

143     private boolean m_includeChain;
144     /** Configures OCSP extensions, these init-params are optional
145      */

146     private Collection JavaDoc m_extensionOids = new ArrayList JavaDoc();
147     private Collection JavaDoc m_extensionClasses = new ArrayList JavaDoc();
148     private HashMap JavaDoc m_extensionMap = null;
149     
150
151     /** Loads cacertificates but holds a cache so it's reloaded only every five minutes is needed.
152      */

153     protected synchronized void loadCertificates() throws IOException JavaDoc, ServletException JavaDoc {
154         // Kolla om vi har en cachad collection och om den inte ?r f?r gammal
155
if (m_cacerts != null && m_certValidTo > new Date JavaDoc().getTime()) {
156             return;
157         }
158         m_cacerts = findCertificatesByType(m_adm, CertificateDataBean.CERTTYPE_SUBCA + CertificateDataBean.CERTTYPE_ROOTCA, null);
159         if (m_log.isDebugEnabled()) {
160             m_log.debug("Loaded "+m_cacerts == null ? "0":m_cacerts.size()+" ca certificates");
161         }
162         loadPrivateKeys(m_adm);
163         m_certValidTo = new Date JavaDoc().getTime() + VALID_TIME;
164     }
165     abstract protected void loadPrivateKeys(Admin adm) throws ServletException JavaDoc, IOException JavaDoc;
166
167     abstract protected Collection JavaDoc findCertificatesByType(Admin adm, int i, String JavaDoc issuerDN);
168
169     abstract protected Certificate JavaDoc findCertificateByIssuerAndSerno(Admin adm, String JavaDoc issuerDN, BigInteger JavaDoc serno);
170
171     abstract protected OCSPCAServiceResponse extendedService(Admin m_adm2, int caid, OCSPCAServiceRequest request) throws CADoesntExistsException, ExtendedCAServiceRequestException, IllegalExtendedCAServiceRequestException, ExtendedCAServiceNotActiveException;
172
173     abstract protected RevokedCertInfo isRevoked(Admin m_adm2, String JavaDoc name, BigInteger JavaDoc serialNumber);
174
175     protected X509Certificate JavaDoc findCAByHash(CertificateID certId, Collection JavaDoc certs) throws OCSPException {
176         if (null == certId) {
177             throw new IllegalArgumentException JavaDoc();
178         }
179         if (null == certs || certs.isEmpty()) {
180             String JavaDoc iMsg = intres.getLocalizedMessage("ocsp.certcollectionempty");
181             m_log.info(iMsg);
182             return null;
183         }
184         Iterator JavaDoc iter = certs.iterator();
185         while (iter.hasNext()) {
186             X509Certificate JavaDoc cacert = (X509Certificate JavaDoc) iter.next();
187             try {
188                 CertificateID issuerId = new CertificateID(certId.getHashAlgOID(), cacert, cacert.getSerialNumber());
189                 if (m_log.isDebugEnabled()) {
190                     m_log.debug("Comparing the following certificate hashes:\n"
191                             + " Hash algorithm : '" + certId.getHashAlgOID() + "'\n"
192                             + " CA certificate\n"
193                             + " CA SubjectDN: '" + cacert.getSubjectDN().getName() + "'\n"
194                             + " SerialNumber: '" + cacert.getSerialNumber().toString(16) + "'\n"
195                             + " CA certificate hashes\n"
196                             + " Name hash : '" + new String JavaDoc(Hex.encode(issuerId.getIssuerNameHash())) + "'\n"
197                             + " Key hash : '" + new String JavaDoc(Hex.encode(issuerId.getIssuerKeyHash())) + "'\n"
198                             + " OCSP certificate hashes\n"
199                             + " Name hash : '" + new String JavaDoc(Hex.encode(certId.getIssuerNameHash())) + "'\n"
200                             + " Key hash : '" + new String JavaDoc(Hex.encode(certId.getIssuerKeyHash())) + "'\n");
201                 }
202                 if ((issuerId.toASN1Object().getIssuerNameHash().equals(certId.toASN1Object().getIssuerNameHash()))
203                         && (issuerId.toASN1Object().getIssuerKeyHash().equals(certId.toASN1Object().getIssuerKeyHash()))) {
204                     if (m_log.isDebugEnabled()) {
205                         m_log.debug("Found matching CA-cert with:\n"
206                                 + " Name hash : '" + new String JavaDoc(Hex.encode(issuerId.getIssuerNameHash())) + "'\n"
207                                 + " Key hash : '" + new String JavaDoc(Hex.encode(issuerId.getIssuerKeyHash())) + "'\n");
208                     }
209                     return cacert;
210                 }
211             } catch (OCSPException e) {
212                 String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorcomparehash", cacert.getIssuerDN());
213                 m_log.error(errMsg, e);
214             }
215         }
216         if (m_log.isDebugEnabled()) {
217             m_log.debug("Did not find matching CA-cert for:\n"
218                     + " Name hash : '" + new String JavaDoc(Hex.encode(certId.getIssuerNameHash())) + "'\n"
219                     + " Key hash : '" + new String JavaDoc(Hex.encode(certId.getIssuerKeyHash())) + "'\n");
220         }
221         return null;
222     }
223
224     protected X509Certificate JavaDoc findCertificateBySubject(String JavaDoc subjectDN, Collection JavaDoc certs) {
225         if (certs == null || null == subjectDN) {
226             throw new IllegalArgumentException JavaDoc();
227         }
228
229         if (null == certs || certs.isEmpty()) {
230             String JavaDoc iMsg = intres.getLocalizedMessage("ocsp.certcollectionempty");
231             m_log.info(iMsg);
232             return null;
233         }
234         String JavaDoc dn = CertTools.stringToBCDNString(subjectDN);
235         Iterator JavaDoc iter = certs.iterator();
236         while (iter.hasNext()) {
237             X509Certificate JavaDoc cacert = (X509Certificate JavaDoc) iter.next();
238             if (m_log.isDebugEnabled()) {
239                 m_log.debug("Comparing the following certificates:\n"
240                         + " CA certificate DN: " + cacert.getSubjectDN()
241                         + "\n Subject DN: " + dn);
242             }
243             if (dn.equalsIgnoreCase(CertTools.stringToBCDNString(cacert.getSubjectDN().getName()))) {
244                 return cacert;
245             }
246         }
247         String JavaDoc iMsg = intres.getLocalizedMessage("ocsp.nomatchingcacert", subjectDN);
248         m_log.info(iMsg);
249         return null;
250     }
251
252     /** returns an HashTable of responseExtensions to be added to the BacisOCSPResponseGenerator with
253      * <code>
254      * X509Extensions exts = new X509Extensions(table);
255      * basicRes.setResponseExtensions(responseExtensions);
256      * </code>
257      *
258      * @param req OCSPReq
259      * @return a Hashtable, can be empty nut not null
260      */

261     private Hashtable JavaDoc getStandardResponseExtensions(OCSPReq req) {
262         X509Extensions reqexts = req.getRequestExtensions();
263         Hashtable JavaDoc table = new Hashtable JavaDoc();
264         if (reqexts != null) {
265             // Table of extensions to include in the response
266
X509Extension ext = reqexts.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
267             if (null != ext) {
268                 //m_log.debug("Found extension Nonce");
269
table.put(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, ext);
270             }
271         }
272         return table;
273     }
274     
275     protected int getCaid( X509Certificate JavaDoc cacert ) {
276         int result = CertTools.stringToBCDNString(cacert.getSubjectDN().toString()).hashCode();
277         m_log.debug( cacert.getSubjectDN() + " has caid: " + result );
278         return result;
279     }
280
281     private BasicOCSPResp signOCSPResponse(OCSPReq req, ArrayList JavaDoc responseList, X509Extensions exts, X509Certificate JavaDoc cacert)
282             throws CADoesntExistsException, ExtendedCAServiceRequestException, ExtendedCAServiceNotActiveException, IllegalExtendedCAServiceRequestException {
283         // Find the OCSP signing key and cert for the issuer
284
BasicOCSPResp retval = null;
285         {
286             // Call extended CA services to get our OCSP stuff
287
OCSPCAServiceResponse caserviceresp = extendedService(m_adm, getCaid(cacert), new OCSPCAServiceRequest(req, responseList, exts, m_sigAlg, m_useCASigningCert, m_includeChain));
288             // Now we can use the returned OCSPServiceResponse to get private key and cetificate chain to sign the ocsp response
289
if (m_log.isDebugEnabled()) {
290                 Collection JavaDoc coll = caserviceresp.getOCSPSigningCertificateChain();
291                 m_log.debug("Cert chain for OCSP signing is of size " + coll.size());
292             }
293             retval = caserviceresp.getBasicOCSPResp();
294         }
295         return retval;
296     }
297
298     public void init(ServletConfig JavaDoc config) throws ServletException JavaDoc {
299         super.init(config);
300         CertTools.installBCProvider();
301         m_adm = new Admin(Admin.TYPE_INTERNALUSER);
302         
303         // Parameters for OCSP signing (private) key
304
m_sigAlg = config.getInitParameter("SignatureAlgorithm");
305         if (StringUtils.isEmpty(m_sigAlg)) {
306             m_log.error("Signature algorithm not defined in initialization parameters.");
307             throw new ServletException JavaDoc("Missing signature algorithm in initialization parameters.");
308         }
309         m_defaultResponderId = config.getInitParameter("defaultResponderID");
310         if (StringUtils.isEmpty(m_defaultResponderId)) {
311             m_log.error("Default responder id not defined in initialization parameters.");
312             throw new ServletException JavaDoc("Missing default responder id in initialization parameters.");
313         }
314         String JavaDoc initparam = config.getInitParameter("enforceRequestSigning");
315         if (m_log.isDebugEnabled()) {
316             m_log.debug("Enforce request signing : '"
317                         + (StringUtils.isEmpty(initparam) ? "<not set>" : initparam)
318                         + "'");
319         }
320         m_reqMustBeSigned = true;
321         if (!StringUtils.isEmpty(initparam)) {
322             if (initparam.equalsIgnoreCase("false")
323                     || initparam.equalsIgnoreCase("no")) {
324                 m_reqMustBeSigned = false;
325             }
326         }
327         initparam = config.getInitParameter("useCASigningCert");
328         if (m_log.isDebugEnabled()) {
329             m_log.debug("Use CA signing cert : '"
330                         + (StringUtils.isEmpty(initparam) ? "<not set>" : initparam)
331                         + "'");
332         }
333         m_useCASigningCert = false;
334         if (!StringUtils.isEmpty(initparam)) {
335             if (initparam.equalsIgnoreCase("true")
336                     || initparam.equalsIgnoreCase("yes")) {
337                 m_useCASigningCert = true;
338             }
339         }
340         initparam = config.getInitParameter("includeCertChain");
341         if (m_log.isDebugEnabled()) {
342             m_log.debug("Include certificate chain: '"
343                         + (StringUtils.isEmpty(initparam) ? "<not set>" : initparam)
344                         + "'");
345         }
346         m_includeChain = true;
347         if (!StringUtils.isEmpty(initparam)) {
348             if (initparam.equalsIgnoreCase("false")
349                     || initparam.equalsIgnoreCase("no")) {
350                 m_includeChain = false;
351             }
352         }
353         String JavaDoc extensionOid = null;
354         String JavaDoc extensionClass = null;
355         extensionOid = config.getInitParameter("extensionOid");
356         if (StringUtils.isEmpty(extensionOid)) {
357             m_log.info("ExtensionOid not defined in initialization parameters.");
358         } else {
359             String JavaDoc[] oids = extensionOid.split(";");
360             m_extensionOids = Arrays.asList(oids);
361             
362         }
363         extensionClass = config.getInitParameter("extensionClass");
364         if (StringUtils.isEmpty(extensionClass)) {
365             m_log.info("ExtensionClass not defined in initialization parameters.");
366         } else {
367             String JavaDoc[] classes = extensionClass.split(";");
368             m_extensionClasses = Arrays.asList(classes);
369         }
370         // Check that we have the same amount of extension oids as classes
371
if (m_extensionClasses.size() != m_extensionOids.size()) {
372             throw new ServletException JavaDoc("Number of extension classes does not match no of extension oids.");
373         }
374         // Init extensions
375
Iterator JavaDoc iter = m_extensionClasses.iterator();
376         Iterator JavaDoc iter2 = m_extensionOids.iterator();
377         m_extensionMap = new HashMap JavaDoc();
378         while (iter.hasNext()) {
379             String JavaDoc clazz = (String JavaDoc)iter.next();
380             String JavaDoc oid = (String JavaDoc)iter2.next();
381             IOCSPExtension ext = null;
382             try {
383                  ext = (IOCSPExtension)Class.forName(clazz).newInstance();
384                  ext.init(config);
385             } catch (Exception JavaDoc e) {
386                 m_log.error("Can not create extension with class "+clazz, e);
387                 continue;
388             }
389             m_extensionMap.put(oid,ext);
390         }
391     }
392
393     public void doPost(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
394             throws IOException JavaDoc, ServletException JavaDoc {
395         m_log.debug(">doPost()");
396         String JavaDoc contentType = request.getHeader("Content-Type");
397         if (!contentType.equalsIgnoreCase("application/ocsp-request")) {
398             m_log.debug("Content type is not application/ocsp-request");
399             response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Content type is not application/ocsp-request");
400             return;
401         }
402         // Get the request data
403
BufferedReader JavaDoc in = request.getReader();
404         ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
405         // This works for small requests, and OCSP requests are small
406
int b = in.read();
407         while (b != -1) {
408             baos.write(b);
409             b = in.read();
410         }
411         baos.flush();
412         in.close();
413         byte[] reqBytes = baos.toByteArray();
414         // Do it...
415
service(request, response, reqBytes);
416         m_log.debug("<doPost()");
417     } //doPost
418

419     public void doGet(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
420             throws IOException JavaDoc, ServletException JavaDoc {
421         m_log.debug(">doGet()");
422         /**
423          * We only support POST operation, so return
424          * an appropriate HTTP error code to caller.
425          */

426         // We have one command though, to force reloading of keys, can only be run from localhost
427
String JavaDoc reloadCAKeys = request.getParameter("reloadkeys");
428         if (StringUtils.equals(reloadCAKeys, "true")) {
429             String JavaDoc remote = request.getRemoteAddr();
430             if (StringUtils.equals(remote, "127.0.0.1")) {
431                 String JavaDoc iMsg = intres.getLocalizedMessage("ocsp.reloadkeys", remote);
432                 m_log.info(iMsg);
433                 m_certValidTo = 0;
434             } else {
435                 m_log.info("Got reloadKeys command from unauthorized ip: "+remote);
436             }
437         }
438         response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "OCSP only supports POST");
439         m_log.debug("<doGet()");
440     } // doGet
441

442     public void service(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, byte[] reqBytes)
443             throws IOException JavaDoc, ServletException JavaDoc {
444         if (m_log.isDebugEnabled()) {
445             m_log.debug(">service()");
446         }
447         if ((reqBytes == null) || (reqBytes.length == 0)) {
448             m_log.debug("No request bytes");
449             response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No request bytes.");
450             return;
451         }
452         try {
453             OCSPResp ocspresp = null;
454             ArrayList JavaDoc responseList = new ArrayList JavaDoc();
455             OCSPRespGenerator res = new OCSPRespGenerator();
456             X509Certificate JavaDoc cacert = null; // CA-certificate used to sign response
457
OCSPReq req = new OCSPReq(reqBytes);
458             try {
459                 //m_log.debug("OCSPReq: "+new String(Base64.encode(req.getEncoded())));
460

461                 loadCertificates();
462
463                 if (m_log.isDebugEnabled()) {
464                     StringBuffer JavaDoc certInfo = new StringBuffer JavaDoc();
465                     Iterator JavaDoc iter = m_cacerts.iterator();
466                     while (iter.hasNext()) {
467                         X509Certificate JavaDoc cert = (X509Certificate JavaDoc) iter.next();
468                         certInfo.append(cert.getSubjectDN().getName());
469                         certInfo.append(',');
470                         certInfo.append(cert.getSerialNumber().toString(16));
471                         certInfo.append('\n');
472                     }
473                     m_log.debug("Found the following CA certificates : \n"
474                             + certInfo.toString());
475                 }
476
477             
478                 /**
479                  * check the signature if contained in request.
480                  * if the request does not contain a signature
481                  * and the servlet is configured in the way
482                  * the a signature is required we send back
483                  * 'sigRequired' response.
484                  */

485                 if (m_log.isDebugEnabled()) {
486                     m_log.debug("Incoming OCSP request is signed : " + req.isSigned());
487                 }
488                 if (m_reqMustBeSigned) {
489                     if (!req.isSigned()) {
490                         String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorunsignedreq");
491                         m_log.error(errMsg);
492                         throw new SignRequestException(errMsg);
493                     }
494                     //GeneralName requestor = req.getRequestorName();
495
X509Certificate JavaDoc[] certs = req.getCerts("BC");
496                     // We must find a cert to verify the signature with...
497
boolean verifyOK = false;
498                     for (int i = 0; i < certs.length; i++) {
499                         if (req.verify(certs[i].getPublicKey(), "BC") == true) {
500                             verifyOK = true;
501                             break;
502                         }
503                     }
504                     if (!verifyOK) {
505                         String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorinvalidsignature");
506                         m_log.error(errMsg);
507                         throw new SignRequestSignatureException(errMsg);
508                     }
509                 }
510
511                 Req[] requests = req.getRequestList();
512                 if (requests.length <= 0) {
513                     String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errornoreqentities");
514                     m_log.error(errMsg);
515                     {
516                         // All this just so we can create an error response
517
cacert = findCertificateBySubject(m_defaultResponderId, m_cacerts);
518                     }
519                     throw new MalformedRequestException(errMsg);
520                 }
521                 if (m_log.isDebugEnabled()) {
522                     m_log.debug("The OCSP request contains " + requests.length + " simpleRequests.");
523                 }
524                 
525                 // Add standard response extensions
526
Hashtable JavaDoc responseExtensions = getStandardResponseExtensions(req);
527
528                 for (int i = 0; i < requests.length; i++) {
529                     CertificateID certId = requests[i].getCertID();
530                     byte[] hashbytes = certId.getIssuerNameHash();
531                     String JavaDoc hash = null;
532                     if (hashbytes != null) {
533                         hash = new String JavaDoc(Hex.encode(hashbytes));
534                     }
535                     String JavaDoc infoMsg = intres.getLocalizedMessage("ocsp.inforeceivedrequest", certId.getSerialNumber().toString(16), hash);
536                     m_log.info(infoMsg);
537                     boolean unknownCA = false; // if the certId was issued by an unknown CA
538
// The algorithm here:
539
// We will sign the response with the CA that issued the first
540
// certificate(certId) in the request. If the issuing CA is not available
541
// on this server, we sign the response with the default responderId (from params in web.xml).
542
// We have to look up the ca-certificate for each certId in the request though, as we will check
543
// for revocation on the ca-cert as well when checking for revocation on the certId.
544
try {
545                         cacert = findCAByHash(certId, m_cacerts);
546                         if (cacert == null) {
547                             // We could not find certificate for this request so get certificate for default responder
548
cacert = findCertificateBySubject(m_defaultResponderId, m_cacerts);
549                             unknownCA = true;
550                         }
551                     } catch (OCSPException e) {
552                         String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorgencerthash");
553                         m_log.error(errMsg, e);
554                         cacert = null;
555                         continue;
556                     }
557                     if (cacert == null) {
558                         String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorfindcacert", new String JavaDoc(Hex.encode(certId.getIssuerNameHash())), m_defaultResponderId);
559                         m_log.error(errMsg);
560                         continue;
561                     }
562                     if (unknownCA == true) {
563                         String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorfindcacertusedefault", new String JavaDoc(Hex.encode(certId.getIssuerNameHash())));
564                         m_log.info(errMsg);
565                         // If we can not find the CA, answer UnknowStatus
566
responseList.add(new OCSPResponseItem(certId, new UnknownStatus()));
567                         continue;
568                     }
569
570                     /*
571                      * Implement logic according to
572                      * chapter 2.7 in RFC2560
573                      *
574                      * 2.7 CA Key Compromise
575                      * If an OCSP responder knows that a particular CA's private key has
576                      * been compromised, it MAY return the revoked state for all
577                      * certificates issued by that CA.
578                      */

579                     RevokedCertInfo rci;
580                     rci = isRevoked(m_adm, cacert.getIssuerDN().getName(), cacert.getSerialNumber());
581                     if (null != rci && rci.getReason() == RevokedCertInfo.NOT_REVOKED) {
582                         rci = null;
583                     }
584                     CertificateStatus certStatus = null; // null mean good
585
if (null == rci) {
586                         rci = isRevoked(m_adm, cacert.getSubjectDN().getName(), certId.getSerialNumber());
587                         if (null == rci) {
588                             if (m_log.isDebugEnabled()) {
589                                 m_log.debug("Unable to find revocation information for certificate with serial '"
590                                         + certId.getSerialNumber().toString(16) + "'"
591                                         + " from issuer '" + cacert.getSubjectDN().getName() + "'");
592                             }
593                             infoMsg = intres.getLocalizedMessage("ocsp.infoaddedstatusinfo", "unknown", certId.getSerialNumber().toString(16), cacert.getSubjectDN().getName());
594                             m_log.info(infoMsg);
595                             responseList.add(new OCSPResponseItem(certId, new UnknownStatus()));
596                         } else {
597                             BigInteger JavaDoc rciSerno = rci.getUserCertificate();
598                             if (rciSerno.compareTo(certId.getSerialNumber()) == 0) {
599                                 if (rci.getReason() != RevokedCertInfo.NOT_REVOKED) {
600                                     certStatus = new RevokedStatus(new RevokedInfo(new DERGeneralizedTime(rci.getRevocationDate()),
601                                             new CRLReason(rci.getReason())));
602                                 } else {
603                                     certStatus = null;
604                                 }
605                                 String JavaDoc status = "good";
606                                 if (certStatus != null) {
607                                     status ="revoked";
608                                 }
609                                 infoMsg = intres.getLocalizedMessage("ocsp.infoaddedstatusinfo", status, certId.getSerialNumber().toString(16), cacert.getSubjectDN().getName());
610                                 m_log.info(infoMsg);
611                                 responseList.add(new OCSPResponseItem(certId, certStatus));
612                             } else {
613                                 m_log.error("ERROR: Certificate serialNumber ("+rciSerno.toString(16)+") in response from database does not match request ("
614                                         +certId.getSerialNumber().toString(16)+").");
615                                 infoMsg = intres.getLocalizedMessage("ocsp.infoaddedstatusinfo", "unknown", certId.getSerialNumber().toString(16), cacert.getSubjectDN().getName());
616                                 m_log.info(infoMsg);
617                                 responseList.add(new OCSPResponseItem(certId, new UnknownStatus()));
618                             }
619                         }
620                     } else {
621                         certStatus = new RevokedStatus(new RevokedInfo(new DERGeneralizedTime(rci.getRevocationDate()),
622                                 new CRLReason(rci.getReason())));
623                         infoMsg = intres.getLocalizedMessage("ocsp.infoaddedstatusinfo", "revoked", certId.getSerialNumber().toString(16), cacert.getSubjectDN().getName());
624                         m_log.info(infoMsg);
625                         responseList.add(new OCSPResponseItem(certId, certStatus));
626                     }
627
628                     // Look for extension OIDs
629
Iterator JavaDoc iter = m_extensionOids.iterator();
630                     while (iter.hasNext()) {
631                         String JavaDoc oidstr = (String JavaDoc)iter.next();
632                         DERObjectIdentifier oid = new DERObjectIdentifier(oidstr);
633                         X509Extensions reqexts = req.getRequestExtensions();
634                         if (reqexts != null) {
635                             X509Extension ext = reqexts.getExtension(oid);
636                             if (null != ext) {
637                                 // We found an extension, call the extenstion class
638
if (m_log.isDebugEnabled()) {
639                                     m_log.debug("Found OCSP extension oid: "+oidstr);
640                                 }
641                                 IOCSPExtension extObj = (IOCSPExtension)m_extensionMap.get(oidstr);
642                                 if (extObj != null) {
643                                     // Find the certificate from the certId
644
X509Certificate JavaDoc cert = null;
645                                     cert = (X509Certificate JavaDoc)findCertificateByIssuerAndSerno(m_adm, cacert.getSubjectDN().getName(), certId.getSerialNumber());
646                                     if (cert != null) {
647                                         // Call the OCSP extension
648
Hashtable JavaDoc retext = extObj.process(request, cert, certStatus);
649                                         if (retext != null) {
650                                             // Add the returned X509Extensions to the responseExtension we will add to the basic OCSP response
651
responseExtensions.putAll(retext);
652                                         } else {
653                                             String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorprocessextension", extObj.getClass().getName(), new Integer JavaDoc(extObj.getLastErrorCode()));
654                                             m_log.error(errMsg);
655                                         }
656                                     }
657                                 }
658                             }
659                         }
660                     }
661                     
662                 }
663                 if ((req != null) && (cacert != null)) {
664                     // Add responseExtensions
665
X509Extensions exts = new X509Extensions(responseExtensions);
666                     // generate the signed response object
667
BasicOCSPResp basicresp = signOCSPResponse(req, responseList, exts, cacert);
668                     ocspresp = res.generate(OCSPRespGenerator.SUCCESSFUL, basicresp);
669                 } else {
670                     String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errornocacreateresp");
671                     m_log.error(errMsg);
672                     throw new ServletException JavaDoc(errMsg);
673                 }
674             } catch (MalformedRequestException e) {
675                 String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq");
676                 m_log.info(errMsg, e);
677                 // generate the signed response object
678
BasicOCSPResp basicresp = signOCSPResponse(req, null, null, cacert);
679                 ocspresp = res.generate(OCSPRespGenerator.MALFORMED_REQUEST, basicresp);
680             } catch (SignRequestException e) {
681                 String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq");
682                 m_log.info(errMsg, e);
683                 // generate the signed response object
684
BasicOCSPResp basicresp = signOCSPResponse(req, null, null, cacert);
685                 ocspresp = res.generate(OCSPRespGenerator.SIG_REQUIRED, basicresp);
686             } catch (Exception JavaDoc e) {
687                 if (e instanceof ServletException JavaDoc)
688                     throw (ServletException JavaDoc) e;
689                 String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq");
690                 m_log.error(errMsg, e);
691                 // generate the signed response object
692
BasicOCSPResp basicresp = signOCSPResponse(req, null, null, cacert);
693                 ocspresp = res.generate(OCSPRespGenerator.INTERNAL_ERROR, basicresp);
694             }
695             byte[] respBytes = ocspresp.getEncoded();
696             response.setContentType("application/ocsp-response");
697             //response.setHeader("Content-transfer-encoding", "binary");
698
response.setContentLength(respBytes.length);
699             response.getOutputStream().write(respBytes);
700             response.getOutputStream().flush();
701         } catch (OCSPException e) {
702             String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq");
703             m_log.error(errMsg, e);
704             throw new ServletException JavaDoc(e);
705         } catch (IllegalExtendedCAServiceRequestException e) {
706             String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq");
707             m_log.error(errMsg, e);
708             throw new ServletException JavaDoc(e);
709         } catch (CADoesntExistsException e) {
710             String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq");
711             m_log.error(errMsg, e);
712             throw new ServletException JavaDoc(e);
713         } catch (ExtendedCAServiceNotActiveException e) {
714             String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq");
715             m_log.error(errMsg, e);
716             throw new ServletException JavaDoc(e);
717         } catch (ExtendedCAServiceRequestException e) {
718             String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq");
719             m_log.error(errMsg, e);
720             throw new ServletException JavaDoc(e);
721         }
722         if (m_log.isDebugEnabled()) {
723             m_log.debug("<service()");
724         }
725     }
726
727 } // OCSPServlet
728
Popular Tags