KickJava   Java API By Example, From Geeks To Geeks.

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


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.BufferedInputStream JavaDoc;
17 import java.io.File JavaDoc;
18 import java.io.FileInputStream JavaDoc;
19 import java.io.IOException JavaDoc;
20 import java.io.PrintWriter JavaDoc;
21 import java.io.StringWriter JavaDoc;
22 import java.math.BigInteger JavaDoc;
23 import java.security.KeyStore JavaDoc;
24 import java.security.PrivateKey JavaDoc;
25 import java.security.PublicKey JavaDoc;
26 import java.security.cert.Certificate JavaDoc;
27 import java.security.cert.CertificateFactory JavaDoc;
28 import java.security.cert.X509Certificate JavaDoc;
29 import java.security.interfaces.RSAPublicKey JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.Arrays JavaDoc;
32 import java.util.Collection JavaDoc;
33 import java.util.Enumeration JavaDoc;
34 import java.util.HashMap JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.Map JavaDoc;
38
39 import javax.ejb.EJBException JavaDoc;
40 import javax.servlet.ServletConfig JavaDoc;
41 import javax.servlet.ServletException JavaDoc;
42
43 import org.apache.log4j.Logger;
44 import org.bouncycastle.ocsp.BasicOCSPResp;
45 import org.ejbca.core.ejb.ServiceLocator;
46 import org.ejbca.core.ejb.ca.store.ICertificateStoreOnlyDataSessionLocal;
47 import org.ejbca.core.ejb.ca.store.ICertificateStoreOnlyDataSessionLocalHome;
48 import org.ejbca.core.model.InternalResources;
49 import org.ejbca.core.model.ca.caadmin.extendedcaservices.ExtendedCAServiceNotActiveException;
50 import org.ejbca.core.model.ca.caadmin.extendedcaservices.ExtendedCAServiceRequestException;
51 import org.ejbca.core.model.ca.caadmin.extendedcaservices.OCSPCAServiceRequest;
52 import org.ejbca.core.model.ca.caadmin.extendedcaservices.OCSPCAServiceResponse;
53 import org.ejbca.core.model.ca.crl.RevokedCertInfo;
54 import org.ejbca.core.model.log.Admin;
55 import org.ejbca.core.protocol.ocsp.OCSPUtil;
56 import org.ejbca.ui.web.pub.cluster.ExtOCSPHealthCheck;
57
58 /**
59  * Servlet implementing server side of the Online Certificate Status Protocol (OCSP)
60  * For a detailed description of OCSP refer to RFC2560.
61  *
62  * @web.servlet name = "OCSP"
63  * display-name = "OCSPServletStandAlone"
64  * description="Answers OCSP requests"
65  * load-on-startup = "99"
66  *
67  * @web.servlet-mapping url-pattern = "/ocsp"
68  *
69  * @web.servlet-init-param description="Directory name of the soft keystores. The signing keys will be fetched from all files in this directory. Valid formats of the files are JKS and PKCS12 (p12)."
70  * name="softKeyDirectoryName"
71  * value="${ocsp.keys.dir}"
72  *
73  * @web.servlet-init-param description="Signing key password. Must be same for all signing keys."
74  * name="keyPassword"
75  * value="${ocsp.keys.keyPassword}"
76  *
77  * @web.servlet-init-param description="Keystore password. Keystore password for all keystores in the keystore directory."
78  * name="storePassword"
79  * value="${ocsp.keys.storePassword}"
80  *
81  * @web.servlet-init-param description="Keystore password. Keystore password for all keystores in the keystore directory."
82  * name="cardPassword"
83  * value="${ocsp.keys.cardPassword}"
84  *
85  * @web.servlet-init-param description="Keystore password. Keystore password for all keystores in the keystore directory."
86  * name="hardTokenClassName"
87  * value="${ocsp.hardToken.className}"
88  *
89  * @web.resource-ref
90  * name="${datasource.jndi-name-prefix}${datasource.jndi-name}"
91  * type="javax.sql.DataSource"
92  * auth="Container"
93  *
94  * @web.ejb-local-ref
95  * name="ejb/CertificateStoreOnlyDataSessionLocal"
96  * type="Session"
97  * link="CertificateStoreOnlyDataSession"
98  * home="org.ejbca.core.ejb.ca.store.ICertificateStoreOnlyDataSessionLocalHome"
99  * local="org.ejbca.core.ejb.ca.store.ICertificateStoreOnlyDataSessionLocal"
100  *
101  * @author Lars Silven PrimeKey
102  * @version $Id: OCSPServletStandAlone.java,v 1.35 2007/01/09 15:53:55 anatom Exp $
103  */

104 public class OCSPServletStandAlone extends OCSPServletBase implements IHealtChecker {
105
106     static final private Logger m_log = Logger.getLogger(OCSPServletStandAlone.class);
107     /** Internal localization of logs and errors */
108     private static final InternalResources intres = InternalResources.getInstance();
109
110     private String JavaDoc mKeystoreDirectoryName;
111     private char mKeyPassword[];
112     private char mStorePassword[];
113     private CardKeys mHardTokenObject;
114     private final Map JavaDoc mSignEntity;
115     private ICertificateStoreOnlyDataSessionLocal m_certStore = null;
116
117     public OCSPServletStandAlone() {
118         super();
119         mSignEntity = new HashMap JavaDoc();
120     }
121     public void init(ServletConfig JavaDoc config) throws ServletException JavaDoc {
122         super.init(config);
123         try {
124             {
125                 final String JavaDoc keyPassword = config.getInitParameter("keyPassword");
126                 mKeyPassword = keyPassword!=null ? keyPassword.toCharArray() : null;
127             }
128             if ( mKeyPassword==null || mKeyPassword.length==0 )
129                 throw new ServletException JavaDoc("no keystore password given");
130             {
131                 final String JavaDoc storePassword = config.getInitParameter("storePassword");
132                 mStorePassword = storePassword!=null ? storePassword.toCharArray() : null;
133             }
134             if ( mHardTokenObject==null ) {
135                 final String JavaDoc hardTokenClassName = config.getInitParameter("hardTokenClassName");
136                 if ( hardTokenClassName!=null && hardTokenClassName.length()>0 ) {
137                     String JavaDoc sCardPassword = config.getInitParameter("cardPassword");
138                     sCardPassword = sCardPassword!=null ? sCardPassword.trim() : null;
139                     if ( sCardPassword!=null && sCardPassword.length()>0 ) {
140                         try {
141                             mHardTokenObject = (CardKeys)OCSPServletStandAlone.class.getClassLoader().loadClass(hardTokenClassName).newInstance();
142                             mHardTokenObject.autenticate(sCardPassword);
143                         } catch( ClassNotFoundException JavaDoc e) {
144                             String JavaDoc iMsg = intres.getLocalizedMessage("ocsp.classnotfound", hardTokenClassName);
145                             m_log.info(iMsg);
146                         }
147                     } else {
148                         String JavaDoc iMsg = intres.getLocalizedMessage("ocsp.nocardpwd");
149                         m_log.info(iMsg);
150                     }
151                 } else {
152                     String JavaDoc iMsg = intres.getLocalizedMessage("ocsp.nohwsigningclass");
153                     m_log.info(iMsg);
154                 }
155             }
156             if ( mStorePassword==null || mStorePassword.length==0 )
157                 mStorePassword = mKeyPassword;
158             mKeystoreDirectoryName = config.getInitParameter("softKeyDirectoryName");
159             if ( mKeystoreDirectoryName!=null && mKeystoreDirectoryName.length()>0 ) {
160                 ExtOCSPHealthCheck.setHealtChecker(this);
161                 return;
162             } else {
163                 String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errornovalidkeys");
164                 throw new ServletException JavaDoc(errMsg);
165             }
166         } catch( ServletException JavaDoc e ) {
167             throw e;
168         } catch (Exception JavaDoc e) {
169             String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorinitialize");
170             m_log.error(errMsg, e);
171             throw new ServletException JavaDoc(e);
172         }
173     }
174     
175     /**
176      * Returns the certificate data only session bean
177      */

178     private synchronized ICertificateStoreOnlyDataSessionLocal getStoreSessionOnlyData(){
179         if(m_certStore == null){
180             try {
181                 ServiceLocator locator = ServiceLocator.getInstance();
182                 ICertificateStoreOnlyDataSessionLocalHome castorehome =
183                     (ICertificateStoreOnlyDataSessionLocalHome)locator.getLocalHome(ICertificateStoreOnlyDataSessionLocalHome.COMP_NAME);
184                 m_certStore = castorehome.create();
185             }catch(Exception JavaDoc e){
186                 throw new EJBException JavaDoc(e);
187             }
188         }
189         return m_certStore;
190     }
191
192     private X509Certificate JavaDoc[] getCertificateChain(X509Certificate JavaDoc cert, Admin adm) {
193         RevokedCertInfo revokedInfo = isRevoked(adm, cert.getIssuerDN().getName(),
194                 cert.getSerialNumber());
195         String JavaDoc wMsg = intres.getLocalizedMessage("ocsp.signcertnotindb", cert.getSerialNumber(), cert.getIssuerDN());
196         if ( revokedInfo==null ) {
197             m_log.warn(wMsg);
198             return null;
199         }
200         if ( revokedInfo.getReason()!=RevokedCertInfo.NOT_REVOKED ) {
201             wMsg = intres.getLocalizedMessage("ocsp.signcertrevoked", cert.getSerialNumber(), cert.getIssuerDN());
202             m_log.warn(wMsg);
203             return null;
204         }
205         X509Certificate JavaDoc chain[] = null;
206         final List JavaDoc list = new ArrayList JavaDoc();
207         X509Certificate JavaDoc current = cert;
208         while( true ) {
209             list.add(current);
210             if ( current.getIssuerX500Principal().equals(current.getSubjectX500Principal()) ) {
211                 chain = (X509Certificate JavaDoc[])list.toArray(new X509Certificate JavaDoc[0]);
212                 break;
213             }
214             Iterator JavaDoc j = m_cacerts.iterator();
215             boolean isNotFound = true;
216             while( isNotFound && j.hasNext() ) {
217                 X509Certificate JavaDoc target = (X509Certificate JavaDoc)j.next();
218                 if (m_log.isDebugEnabled()) {
219                     m_log.debug( "current issuer '" + current.getIssuerX500Principal() +
220                             "'. target subject: '" + target.getSubjectX500Principal() + "'.");
221                 }
222                 if ( current.getIssuerX500Principal().equals(target.getSubjectX500Principal()) ) {
223                     current = target;
224                     isNotFound = false;
225                 }
226             }
227             if ( isNotFound )
228                 break;
229         }
230         if ( chain==null ) {
231             wMsg = intres.getLocalizedMessage("ocsp.signcerthasnochain", cert.getSerialNumber(), cert.getIssuerDN());
232             m_log.warn(wMsg);
233         }
234         return chain;
235     }
236     private boolean loadFromKeyStore(Admin adm, String JavaDoc fileName) {
237         final Enumeration JavaDoc eAlias;
238         final KeyStore JavaDoc keyStore;
239         try {
240             KeyStore JavaDoc tmpKeyStore;
241             try {
242                 tmpKeyStore = KeyStore.getInstance("JKS");
243                 tmpKeyStore.load(new FileInputStream JavaDoc(fileName), mStorePassword);
244             } catch( IOException JavaDoc e ) {
245                 tmpKeyStore = KeyStore.getInstance("PKCS12", "BC");
246                 tmpKeyStore.load(new FileInputStream JavaDoc(fileName), mStorePassword);
247             }
248             keyStore = tmpKeyStore;
249             eAlias = keyStore.aliases();
250         } catch( Exception JavaDoc e ) {
251             m_log.debug("Unable to load key file "+fileName+". Exception: "+e.getMessage());
252             return false;
253         }
254         while( eAlias.hasMoreElements() ) {
255             final String JavaDoc alias = (String JavaDoc)eAlias.nextElement();
256             try {
257                 final PrivateKey JavaDoc key = (PrivateKey JavaDoc)keyStore.getKey(alias, mKeyPassword);
258                 final X509Certificate JavaDoc cert = (X509Certificate JavaDoc)keyStore.getCertificate(alias);
259                 if ( key!=null && cert!=null )
260                     putSignEntity(new PrivateKeyFactorySW(key), cert, adm, "BC");
261             } catch (Exception JavaDoc e) {
262                 String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorgetalias", alias, fileName);
263                 m_log.error(errMsg, e);
264             }
265         }
266         return true;
267     }
268     private boolean putSignEntity( PrivateKeyFactory keyFactory, X509Certificate JavaDoc cert, Admin adm, String JavaDoc providerName ) {
269         if ( keyFactory!=null && cert!=null ) {
270             X509Certificate JavaDoc[] chain = getCertificateChain(cert, adm);
271             if ( chain!=null ) {
272                 int caid = getCaid(chain[1]);
273                 m_log.debug("CA with ID "+caid+" now has a OCSP signing key.");
274                 SigningEntity oldSigningEntity = (SigningEntity)mSignEntity.get(new Integer JavaDoc(caid));
275                 if ( oldSigningEntity!=null && !oldSigningEntity.getCertificateChain().equals(chain) ) {
276                     String JavaDoc wMsg = intres.getLocalizedMessage("ocsp.newsigningkey", chain[1].getSubjectDN(), chain[0].getSubjectDN());
277                     m_log.warn(wMsg);
278                 }
279                 mSignEntity.put( new Integer JavaDoc(caid), new SigningEntity(chain, keyFactory, providerName) );
280             }
281             return true;
282         }
283         return false;
284     }
285     public String JavaDoc healtCheck() {
286         StringWriter JavaDoc sw = new StringWriter JavaDoc();
287         PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw);
288         try {
289             loadCertificates();
290             Iterator JavaDoc i = mSignEntity.values().iterator();
291             while ( i.hasNext() ) {
292                 SigningEntity signingEntity = (SigningEntity)i.next();
293                 if ( !signingEntity.isOK() ) {
294                     pw.println();
295                     String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorocspkeynotusable", signingEntity.getCertificateChain()[1].getSubjectDN(), signingEntity.getCertificateChain()[0].getSerialNumber().toString(16));
296                     pw.print(errMsg);
297                     m_log.error(errMsg);
298                 }
299             }
300         } catch (Exception JavaDoc e) {
301             String JavaDoc errMsg = intres.getLocalizedMessage("ocsp.errorloadsigningcerts");
302             m_log.error(errMsg, e);
303             pw.print(errMsg + ": "+e.getMessage());
304         }
305         pw.flush();
306         return sw.toString();
307     }
308     interface PrivateKeyFactory {
309         PrivateKey JavaDoc getKey() throws Exception JavaDoc;
310
311         boolean isOK();
312     }
313     private class PrivateKeyFactorySW implements PrivateKeyFactory {
314         final private PrivateKey JavaDoc privateKey;
315         PrivateKeyFactorySW( PrivateKey JavaDoc key) {
316             privateKey = key;
317         }
318         public PrivateKey JavaDoc getKey() throws Exception JavaDoc {
319             return privateKey;
320         }
321         public boolean isOK() {
322             // SW checked when initialized
323
return privateKey!=null;
324         }
325     }
326     private class PrivateKeyFactoryHW implements PrivateKeyFactory {
327         final private RSAPublicKey JavaDoc publicKey;
328         PrivateKeyFactoryHW( RSAPublicKey JavaDoc key) {
329             publicKey = key;
330         }
331         public PrivateKey JavaDoc getKey() throws Exception JavaDoc {
332             return mHardTokenObject.getPrivateKey(publicKey);
333         }
334         public boolean isOK() {
335             return mHardTokenObject.isOK(publicKey);
336         }
337     }
338     private boolean putSignEntityHW( Object JavaDoc obj, Admin adm ) {
339         if ( obj!=null && obj instanceof X509Certificate JavaDoc ) {
340             X509Certificate JavaDoc cert = (X509Certificate JavaDoc)obj;
341             PrivateKeyFactory keyFactory = new PrivateKeyFactoryHW((RSAPublicKey JavaDoc)cert.getPublicKey());
342             putSignEntity( keyFactory, cert, adm, "PrimeKey" );
343             m_log.debug("HW key added. Serial number: "+cert.getSerialNumber().toString(0x10));
344             return true;
345         } else
346             return false;
347     }
348     private void loadFromKeyCards(Admin adm, String JavaDoc fileName) {
349         final CertificateFactory JavaDoc cf;
350         try {
351             cf = CertificateFactory.getInstance("X.509");
352         } catch (java.security.cert.CertificateException JavaDoc e) {
353             throw new Error JavaDoc(e);
354         }
355         String JavaDoc fileType = null;
356         try {// read certs from PKCS#7 file
357
final Collection JavaDoc c = cf.generateCertificates(new FileInputStream JavaDoc(fileName));
358             if ( c!=null && !c.isEmpty() ) {
359                 Iterator JavaDoc i = c.iterator();
360                 while (i.hasNext()) {
361                     if ( putSignEntityHW(i.next(), adm) )
362                         fileType = "PKCS#7";
363                 }
364             }
365         } catch( Exception JavaDoc e) {
366         }
367         if ( fileType==null ) {
368             try {// read concatinated cert in PEM format
369
BufferedInputStream JavaDoc bis = new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(fileName));
370                 while (bis.available() > 0) {
371                     if ( putSignEntityHW(cf.generateCertificate(bis), adm) )
372                         fileType="PEM";
373                 }
374             } catch(Exception JavaDoc e){
375             }
376         }
377         if ( fileType!=null )
378             m_log.debug("Certificate(s) found in file "+fileName+" of "+fileType+".");
379         else
380             m_log.debug("File "+fileName+" has no cert.");
381     }
382     protected void loadPrivateKeys(Admin adm) throws ServletException JavaDoc, IOException JavaDoc {
383         mSignEntity.clear();
384         File JavaDoc dir = new File JavaDoc(mKeystoreDirectoryName);
385         if ( dir==null || dir.isDirectory()==false )
386             throw new ServletException JavaDoc(dir.getCanonicalPath() + " is not a directory.");
387         File JavaDoc files[] = dir.listFiles();
388         if ( files==null || files.length==0 )
389             throw new ServletException JavaDoc("No files in soft key directory: " + dir.getCanonicalPath());
390         for ( int i=0; i<files.length; i++ ) {
391             final String JavaDoc fileName = files[i].getCanonicalPath();
392             if ( !loadFromKeyStore(adm, fileName) )
393                 loadFromKeyCards(adm, fileName);
394         }
395         if ( mSignEntity.size()==0 )
396             throw new ServletException JavaDoc("No valid keys in directory " + dir.getCanonicalPath());
397     }
398     private class SigningEntity {
399         final private X509Certificate JavaDoc mChain[];
400         final private PrivateKeyFactory mKeyFactory;
401         final private String JavaDoc providerName;
402         SigningEntity(X509Certificate JavaDoc c[], PrivateKeyFactory f, String JavaDoc sName) {
403             mChain = c;
404             mKeyFactory = f;
405             providerName = sName;
406         }
407         OCSPCAServiceResponse sign( OCSPCAServiceRequest request) throws ExtendedCAServiceRequestException {
408             X509Certificate JavaDoc signerCert = mChain[0];
409             final String JavaDoc sigAlgs = request.getSigAlg();
410             PublicKey JavaDoc pk = signerCert.getPublicKey();
411             String JavaDoc sigAlg = OCSPUtil.getSigningAlgFromAlgSelection(sigAlgs, pk);
412             m_log.debug("Signing algorithm: "+sigAlg);
413             final X509Certificate JavaDoc[] chain = request.includeChain() ? mChain : null;
414             try {
415                 BasicOCSPResp ocspresp = OCSPUtil.generateBasicOCSPResp(request, sigAlg, signerCert, mKeyFactory.getKey(), providerName, chain);
416                 return new OCSPCAServiceResponse(ocspresp, chain == null ? null : Arrays.asList(chain));
417             } catch (Exception JavaDoc e) {
418                 throw new ExtendedCAServiceRequestException(e);
419             }
420         }
421         boolean isOK() {
422             try {
423                 return mKeyFactory.isOK();
424             } catch (Exception JavaDoc e) {
425                 m_log.debug("Exception thrown when accessing the private key", e);
426                 return false;
427             }
428         }
429         X509Certificate JavaDoc[] getCertificateChain() {
430             return mChain;
431         }
432     }
433
434     protected Collection JavaDoc findCertificatesByType(Admin adm, int type, String JavaDoc issuerDN) {
435         return getStoreSessionOnlyData().findCertificatesByType(adm, type, issuerDN);
436     }
437
438     protected Certificate JavaDoc findCertificateByIssuerAndSerno(Admin adm, String JavaDoc issuer, BigInteger JavaDoc serno) {
439         return getStoreSessionOnlyData().findCertificateByIssuerAndSerno(adm, issuer, serno);
440     }
441     
442     protected OCSPCAServiceResponse extendedService(Admin adm, int caid, OCSPCAServiceRequest request) throws ExtendedCAServiceRequestException,
443                                                                                                     ExtendedCAServiceNotActiveException {
444         SigningEntity se =(SigningEntity)mSignEntity.get(new Integer JavaDoc(caid));
445         if ( se!=null ) {
446             return se.sign(request);
447         }
448         throw new ExtendedCAServiceNotActiveException("No ocsp signing key for caid "+caid);
449     }
450
451     protected RevokedCertInfo isRevoked(Admin adm, String JavaDoc name, BigInteger JavaDoc serialNumber) {
452         return getStoreSessionOnlyData().isRevoked(adm, name, serialNumber);
453     }
454 }
455
Popular Tags