KickJava   Java API By Example, From Geeks To Geeks.

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


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.ByteArrayOutputStream JavaDoc;
17 import java.io.IOException JavaDoc;
18 import java.security.cert.X509Certificate JavaDoc;
19 import java.util.Collection JavaDoc;
20 import java.util.Iterator JavaDoc;
21
22 import javax.ejb.EJBException JavaDoc;
23 import javax.servlet.ServletConfig JavaDoc;
24 import javax.servlet.ServletException JavaDoc;
25 import javax.servlet.ServletInputStream JavaDoc;
26 import javax.servlet.http.HttpServlet JavaDoc;
27 import javax.servlet.http.HttpServletRequest JavaDoc;
28 import javax.servlet.http.HttpServletResponse JavaDoc;
29
30 import org.apache.commons.lang.StringUtils;
31 import org.apache.log4j.Logger;
32 import org.ejbca.core.ejb.ServiceLocator;
33 import org.ejbca.core.ejb.ca.caadmin.ICAAdminSessionLocal;
34 import org.ejbca.core.ejb.ca.caadmin.ICAAdminSessionLocalHome;
35 import org.ejbca.core.ejb.ca.sign.ISignSessionLocal;
36 import org.ejbca.core.ejb.ca.sign.ISignSessionLocalHome;
37 import org.ejbca.core.model.InternalResources;
38 import org.ejbca.core.model.authorization.AuthorizationDeniedException;
39 import org.ejbca.core.model.ca.AuthLoginException;
40 import org.ejbca.core.model.ca.AuthStatusException;
41 import org.ejbca.core.model.ca.caadmin.CADoesntExistsException;
42 import org.ejbca.core.model.ca.caadmin.CAInfo;
43 import org.ejbca.core.model.log.Admin;
44 import org.ejbca.ui.web.RequestHelper;
45 import org.ejbca.util.Base64;
46 import org.ejbca.util.CertTools;
47
48
49 /**
50  * Servlet implementing server side of the Simple Certificate Enrollment Protocol (SCEP)
51  * -----
52  * This processes does the following:
53  * 1. decode a PKCS#7 signed data message from the standard input
54  * 2. extract the signed attributes from the the message, which indicate the type of request
55  * 3. decrypt the enveloped data PKCS#7 inside
56  * 4. branch to different actions depending on the type of the message:
57  * - PKCSReq
58  * - GetCertInitial
59  * - GetCert
60  * - GetCRL
61  * - v2PKCSReq or Proxy request
62  * 5. envelop (PKCS#7) the reply data from the previous step
63  * 6. sign the reply data (PKCS#7) from the previous step
64  * 7. output the result as a der encoded block on stdout
65  * -----
66  *
67  * @version $Id: ScepServlet.java,v 1.8 2006/12/20 08:33:31 anatom Exp $
68  */

69 public class ScepServlet extends HttpServlet JavaDoc {
70     private static final Logger log = Logger.getLogger(ScepServlet.class);
71     /** Internal localization of logs and errors */
72     private static final InternalResources intres = InternalResources.getInstance();
73
74     private ISignSessionLocal signsession = null;
75     private ICAAdminSessionLocal casession = null;
76
77     private synchronized ISignSessionLocal getSignSession(){
78         if(signsession == null){
79             try {
80                 ISignSessionLocalHome signhome = (ISignSessionLocalHome)ServiceLocator.getInstance().getLocalHome(ISignSessionLocalHome.COMP_NAME);
81                 signsession = signhome.create();
82             }catch(Exception JavaDoc e){
83                 throw new EJBException JavaDoc(e);
84             }
85         }
86         return signsession;
87     }
88     private synchronized ICAAdminSessionLocal getCASession(){
89         if(casession == null){
90             try {
91                 ICAAdminSessionLocalHome cahome = (ICAAdminSessionLocalHome)ServiceLocator.getInstance().getLocalHome(ICAAdminSessionLocalHome.COMP_NAME);
92                 casession = cahome.create();
93             }catch(Exception JavaDoc e){
94                 throw new EJBException JavaDoc(e);
95             }
96         }
97         return casession;
98     }
99     /**
100      * Inits the SCEP servlet
101      *
102      * @param config servlet configuration
103      *
104      * @throws ServletException on error during initialization
105      */

106     public void init(ServletConfig JavaDoc config) throws ServletException JavaDoc {
107         super.init(config);
108         try {
109             // Install BouncyCastle provider
110
CertTools.installBCProvider();
111         } catch (Exception JavaDoc e) {
112             throw new ServletException JavaDoc(e);
113         }
114     }
115
116     /**
117      * Handles HTTP post
118      *
119      * @param request java standard arg
120      * @param response java standard arg
121      *
122      * @throws IOException input/output error
123      * @throws ServletException if the post could not be handled
124      */

125     public void doPost(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
126             throws IOException JavaDoc, ServletException JavaDoc {
127         log.debug(">doPost()");
128         /*
129          If the remote CA supports it, any of the PKCS#7-encoded SCEP messages
130          may be sent via HTTP POST instead of HTTP GET. This is allowed for
131          any SCEP message except GetCACert, GetCACertChain, GetNextCACert,
132          or GetCACaps. In this form of the message, Base 64 encoding is not
133          used.
134          
135          POST /cgi-bin/pkiclient.exe?operation=PKIOperation
136          <binary PKCS7 data>
137          */

138         String JavaDoc operation = "PKIOperation";
139         ServletInputStream JavaDoc sin = request.getInputStream();
140         // This small code snippet is inspired/copied by apache IO utils to Tomas Gustavsson...
141
ByteArrayOutputStream JavaDoc output = new ByteArrayOutputStream JavaDoc();
142         byte[] buf = new byte[1024];
143         int n = 0;
144         while (-1 != (n = sin.read(buf))) {
145             output.write(buf, 0, n);
146         }
147         String JavaDoc message = new String JavaDoc(Base64.encode(output.toByteArray()));
148         service(operation, message, request.getRemoteAddr(), response);
149         log.debug("<doPost()");
150     } //doPost
151

152     /**
153      * Handles HTTP get
154      *
155      * @param request java standard arg
156      * @param response java standard arg
157      *
158      * @throws IOException input/output error
159      * @throws ServletException if the post could not be handled
160      */

161     public void doGet(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
162             throws java.io.IOException JavaDoc, ServletException JavaDoc {
163         log.debug(">doGet()");
164
165             log.debug("query string=" + request.getQueryString());
166
167             // These are mandatory in SCEP GET
168
/*
169              GET /cgi-bin/pkiclient.exe?operation=PKIOperation&message=MIAGCSqGSIb3D
170              QEHA6CAMIACAQAxgDCBzAIBADB2MGIxETAPBgNVBAcTCE ......AAAAAA==
171              */

172             String JavaDoc operation = request.getParameter("operation");
173             String JavaDoc message = request.getParameter("message");
174
175             service(operation, message, request.getRemoteAddr(), response);
176             
177         log.debug("<doGet()");
178     } // doGet
179

180     private void service(String JavaDoc operation, String JavaDoc message, String JavaDoc remoteAddr, HttpServletResponse JavaDoc response) throws IOException JavaDoc {
181         try {
182             if ((operation == null) || (message == null)) {
183                 String JavaDoc errMsg = intres.getLocalizedMessage("scep.errormissingparam", remoteAddr);
184                 log.error(errMsg);
185                 response.sendError(HttpServletResponse.SC_BAD_REQUEST,errMsg);
186                 return;
187             }
188             
189             Admin administrator = new Admin(Admin.TYPE_PUBLIC_WEB_USER, remoteAddr);
190             log.debug("Got request '" + operation + "'");
191             log.debug("Message: " + message);
192             String JavaDoc iMsg = intres.getLocalizedMessage("scep.receivedmsg", remoteAddr);
193             log.info(iMsg);
194             if (operation.equals("PKIOperation")) {
195                 byte[] scepmsg = Base64.decode(message.getBytes());
196                 ISignSessionLocal signsession = getSignSession();
197                 ScepPkiOpHelper helper = new ScepPkiOpHelper(administrator, signsession);
198                 
199                 // Read the message end get the cert, this also checksauthorization
200
boolean includeCACert = true;
201                 if (StringUtils.equals("0", getInitParameter("includeCACert"))) {
202                     includeCACert = false;
203                 }
204                 byte[] reply = helper.scepCertRequest(scepmsg, includeCACert);
205                 if (reply == null) {
206                     // This is probably a getCert message?
207
response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "Can not handle request");
208                     return;
209                 }
210                 // Send back Scep response, PKCS#7 which contains the end entity's certificate (or failure)
211
RequestHelper.sendBinaryBytes(reply, response, "application/x-pki-message", null);
212                 iMsg = intres.getLocalizedMessage("scep.sentresponsemsg", "PKIOperation", remoteAddr);
213                 log.info(iMsg);
214             } else if (operation.equals("GetCACert")) {
215                 // The response has the content type tagged as application/x-x509-ca-cert.
216
// The body of the response is a DER encoded binary X.509 certificate.
217
// For example: "Content-Type:application/x-x509-ca-cert\n\n"<BER-encoded X509>
218

219                 // CA_IDENT is the message for this request to indicate which CA we are talking about
220
log.debug("Got SCEP cert request for CA '" + message + "'");
221                 Collection JavaDoc certs = null;
222                 ICAAdminSessionLocal caadminsession = getCASession();
223                 CAInfo cainfo = caadminsession.getCAInfo(administrator, message);
224                 if (cainfo != null) {
225                     certs = cainfo.getCertificateChain();
226                 }
227                 if ((certs != null) && (certs.size() > 0)) {
228                     // CAs certificate is in the first position in the Collection
229
Iterator JavaDoc iter = certs.iterator();
230                     X509Certificate JavaDoc cert = (X509Certificate JavaDoc) iter.next();
231                     log.debug("Sent certificate for CA '" + message + "' to SCEP client.");
232                     RequestHelper.sendNewX509CaCert(cert.getEncoded(), response);
233                     iMsg = intres.getLocalizedMessage("scep.sentresponsemsg", "GetCACert", remoteAddr);
234                     log.info(iMsg);
235                 } else {
236                     String JavaDoc errMsg = intres.getLocalizedMessage("scep.errorunknownca", "cert");
237                     log.error(errMsg);
238                     response.sendError(HttpServletResponse.SC_NOT_FOUND, "No CA certificates found.");
239                 }
240             } else if (operation.equals("GetCACertChain")) {
241                 // The response for GetCACertChain is a certificates-only PKCS#7
242
// SignedDatato carry the certificates to the end entity, with a
243
// Content-Type of application/x-x509-ca-ra-cert-chain.
244

245                 // CA_IDENT is the message for this request to indicate which CA we are talking about
246
log.debug("Got SCEP pkcs7 request for CA '" + message + "'");
247                 ICAAdminSessionLocal caadminsession = getCASession();
248                 CAInfo cainfo = caadminsession.getCAInfo(administrator, message);
249                 ISignSessionLocal signsession = getSignSession();
250                 byte[] pkcs7 = signsession.createPKCS7(administrator, cainfo.getCAId(), true);
251                 if ((pkcs7 != null) && (pkcs7.length > 0)) {
252                     log.debug("Sent PKCS7 for CA '" + message + "' to SCEP client.");
253                     RequestHelper.sendBinaryBytes(pkcs7, response, "application/x-x509-ca-ra-cert-chain", null);
254                     iMsg = intres.getLocalizedMessage("scep.sentresponsemsg", "GetCACertChain", remoteAddr);
255                     log.info(iMsg);
256                 } else {
257                     String JavaDoc errMsg = intres.getLocalizedMessage("scep.errorunknownca", "pkcs7");
258                     log.error(errMsg);
259                     response.sendError(HttpServletResponse.SC_NOT_FOUND,"No CA certificates found.");
260                 }
261             } else if (operation.equals("GetCACaps")) {
262                 // The response for GetCACaps is a <lf> separated list of capabilities
263

264                 /*
265                  "GetNextCACert" CA Supports the GetNextCACert message.
266                  "POSTPKIOperation" PKIOPeration messages may be sent via HTTP POST.
267                  "SHA-1" CA Supports the SHA-1 hashing algorithm in
268                                        signatures and fingerprints. If present, the
269                                        client SHOULD use SHA-1. If absent, the client
270                                        MUST use MD5 to maintain backward compatability.
271                  "Renewal" Clients may use current certificate and key to
272                                        authenticate an enrollment request for a new
273                                        certificate.
274                  */

275                 log.debug("Got SCEP CACaps request for CA '" + message + "'");
276                 response.setContentType("text/plain");
277                 response.getOutputStream().print("POSTPKIOperation\nSHA-1");
278             } else {
279                 log.error("Invalid parameter '" + operation);
280                 // TODO: Send back proper Failure Response
281
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid parameter: " + operation);
282             }
283         } catch (CADoesntExistsException cae) {
284             String JavaDoc errMsg = intres.getLocalizedMessage("scep.errorunknownca", "cert");
285             log.error(errMsg, cae);
286             // TODO: Send back proper Failure Response
287
response.sendError(HttpServletResponse.SC_NOT_FOUND, cae.getMessage());
288         } catch (java.lang.ArrayIndexOutOfBoundsException JavaDoc ae) {
289             String JavaDoc errMsg = intres.getLocalizedMessage("scep.errorinvalidreq");
290             log.error(errMsg, ae);
291             // TODO: Send back proper Failure Response
292
response.sendError(HttpServletResponse.SC_BAD_REQUEST, ae.getMessage());
293         } catch (AuthorizationDeniedException ae) {
294             String JavaDoc errMsg = intres.getLocalizedMessage("scep.errorauth");
295             log.error(errMsg, ae);
296             // TODO: Send back proper Failure Response
297
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ae.getMessage());
298         } catch (AuthLoginException ae) {
299             String JavaDoc errMsg = intres.getLocalizedMessage("scep.errorauth");
300             log.error(errMsg, ae);
301             // TODO: Send back proper Failure Response
302
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ae.getMessage());
303         } catch (AuthStatusException ae) {
304             String JavaDoc errMsg = intres.getLocalizedMessage("scep.errorclientstatus");
305             log.error(errMsg, ae);
306             // TODO: Send back proper Failure Response
307
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ae.getMessage());
308         } catch (Exception JavaDoc e) {
309             String JavaDoc errMsg = intres.getLocalizedMessage("scep.errorgeneral");
310             log.error(errMsg, e);
311             // TODO: Send back proper Failure Response
312
response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
313         }
314     }
315     
316 } // ScepServlet
317
Popular Tags