Package org.ejbca.ui.web.protocol

Source Code of org.ejbca.ui.web.protocol.ScepServlet

/*************************************************************************
*                                                                       *
*  EJBCA: The OpenSource Certificate Authority                          *
*                                                                       *
*  This software is free software; you can redistribute it and/or       *
*  modify it under the terms of the GNU Lesser General Public           *
*  License as published by the Free Software Foundation; either         *
*  version 2.1 of the License, or any later version.                    *
*                                                                       *
*  See terms of license at gnu.org.                                     *
*                                                                       *
*************************************************************************/

package org.ejbca.ui.web.protocol;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Iterator;

import javax.ejb.EJB;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.ejbca.core.ejb.ca.caadmin.CAAdminSessionLocal;
import org.ejbca.core.ejb.ca.sign.SignSessionLocal;
import org.ejbca.core.model.InternalResources;
import org.ejbca.core.model.authorization.AuthorizationDeniedException;
import org.ejbca.core.model.ca.AuthLoginException;
import org.ejbca.core.model.ca.AuthStatusException;
import org.ejbca.core.model.ca.caadmin.CADoesntExistsException;
import org.ejbca.core.model.ca.caadmin.CAInfo;
import org.ejbca.core.model.ca.catoken.CATokenOfflineException;
import org.ejbca.core.model.log.Admin;
import org.ejbca.ui.web.RequestHelper;
import org.ejbca.util.Base64;
import org.ejbca.util.CertTools;


/**
* Servlet implementing server side of the Simple Certificate Enrollment Protocol (SCEP)
* -----
* This processes does the following:
* 1. decode a PKCS#7 signed data message from the standard input
* 2. extract the signed attributes from the the message, which indicate the type of request
* 3. decrypt the enveloped data PKCS#7 inside
* 4. branch to different actions depending on the type of the message:
* - PKCSReq
* - GetCertInitial
* - GetCert
* - GetCRL
* - v2PKCSReq or Proxy request
* 5. envelop (PKCS#7) the reply data from the previous step
* 6. sign the reply data (PKCS#7) from the previous step
* 7. output the result as a der encoded block on stdout
* -----
*
* @version $Id: ScepServlet.java 10963 2010-12-22 15:27:45Z anatom $
*/
public class ScepServlet extends HttpServlet {
    private static final Logger log = Logger.getLogger(ScepServlet.class);
    /** Internal localization of logs and errors */
    private static final InternalResources intres = InternalResources.getInstance();

    @EJB
    private SignSessionLocal signsession;
    @EJB
    private CAAdminSessionLocal casession;

    /**
     * Inits the SCEP servlet
     *
     * @param config servlet configuration
     *
     * @throws ServletException on error during initialization
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        try {
            // Install BouncyCastle provider
            CertTools.installBCProvider();
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }

    /**
     * Handles HTTP post
     *
     * @param request java standard arg
     * @param response java standard arg
     *
     * @throws IOException input/output error
     * @throws ServletException if the post could not be handled
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        log.trace(">doPost()");
        /*
         If the remote CA supports it, any of the PKCS#7-encoded SCEP messages
         may be sent via HTTP POST instead of HTTP GET.   This is allowed for
         any SCEP message except GetCACert, GetCACertChain, GetNextCACert,
         or GetCACaps.  In this form of the message, Base 64 encoding is not
         used.
        
         POST /cgi-bin/pkiclient.exe?operation=PKIOperation
         <binary PKCS7 data>
         */
        String operation = "PKIOperation";
        ServletInputStream sin = request.getInputStream();
        // This small code snippet is inspired/copied by apache IO utils to Tomas Gustavsson...
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];
        int n = 0;
        while (-1 != (n = sin.read(buf))) {
            output.write(buf, 0, n);
        }
        String message = new String(Base64.encode(output.toByteArray()));
        service(operation, message, request.getRemoteAddr(), response);
        log.trace("<doPost()");
    } //doPost

    /**
     * Handles HTTP get
     *
     * @param request java standard arg
     * @param response java standard arg
     *
     * @throws IOException input/output error
     * @throws ServletException if the post could not be handled
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws java.io.IOException, ServletException {
        log.trace(">doGet()");

            log.debug("query string=" + request.getQueryString());

            // These are mandatory in SCEP GET
            /*
             GET /cgi-bin/pkiclient.exe?operation=PKIOperation&message=MIAGCSqGSIb3D
             QEHA6CAMIACAQAxgDCBzAIBADB2MGIxETAPBgNVBAcTCE ......AAAAAA==
             */
            String operation = request.getParameter("operation");
            String message = request.getParameter("message");
          // Some clients don't url encode the + sign in the request
            if (message != null) {
              message = message.replace(' ', '+');
            }

            service(operation, message, request.getRemoteAddr(), response);
           
        log.trace("<doGet()");
    } // doGet

    private void service(String operation, String message, String remoteAddr, HttpServletResponse response) throws IOException {
        try {
            if ((operation == null) || (message == null)) {
            String errMsg = intres.getLocalizedMessage("scep.errormissingparam", remoteAddr);
                log.error(errMsg);
                response.sendError(HttpServletResponse.SC_BAD_REQUEST,errMsg);
                return;
            }
           
            Admin administrator = new Admin(Admin.TYPE_PUBLIC_WEB_USER, remoteAddr);
            log.debug("Got request '" + operation + "'");
            log.debug("Message: " + message);
        String iMsg = intres.getLocalizedMessage("scep.receivedmsg", remoteAddr);
      log.info(iMsg);
            if (operation.equals("PKIOperation")) {
                byte[] scepmsg = Base64.decode(message.getBytes());
                ScepPkiOpHelper helper = new ScepPkiOpHelper(administrator, signsession);
               
                // Read the message end get the cert, this also checksauthorization
                boolean includeCACert = true;
                if (StringUtils.equals("0", getInitParameter("includeCACert"))) {
                  includeCACert = false;
                }
                byte[] reply = helper.scepCertRequest(scepmsg, includeCACert);
                if (reply == null) {
                    // This is probably a getCert message?
                    response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "Can not handle request");
                    return;
                }
                // Send back Scep response, PKCS#7 which contains the end entity's certificate (or failure)
                RequestHelper.sendBinaryBytes(reply, response, "application/x-pki-message", null);
            iMsg = intres.getLocalizedMessage("scep.sentresponsemsg", "PKIOperation", remoteAddr);
          log.info(iMsg);
            } else if (operation.equals("GetCACert")) {
                // The response has the content type tagged as application/x-x509-ca-cert.
                // The body of the response is a DER encoded binary X.509 certificate.
                // For example: "Content-Type:application/x-x509-ca-cert\n\n"<BER-encoded X509>
               
                // CA_IDENT is the message for this request to indicate which CA we are talking about
                log.debug("Got SCEP cert request for CA '" + message + "'");
                Collection certs = null;
                CAInfo cainfo = casession.getCAInfo(administrator, message);
                if (cainfo != null) {
                    certs = cainfo.getCertificateChain();
                }
                if ((certs != null) && (certs.size() > 0)) {
                    // CAs certificate is in the first position in the Collection
                    Iterator iter = certs.iterator();
                    X509Certificate cert = (X509Certificate) iter.next();
                    log.debug("Sent certificate for CA '" + message + "' to SCEP client.");
                    RequestHelper.sendNewX509CaCert(cert.getEncoded(), response);
                iMsg = intres.getLocalizedMessage("scep.sentresponsemsg", "GetCACert", remoteAddr);
              log.info(iMsg);
                } else {
                String errMsg = intres.getLocalizedMessage("scep.errorunknownca", "cert");
                    log.error(errMsg);
                    response.sendError(HttpServletResponse.SC_NOT_FOUND, "No CA certificates found.");
                }
            } else if (operation.equals("GetCACertChain")) {
                // The response for GetCACertChain is a certificates-only PKCS#7
                // SignedDatato carry the certificates to the end entity, with a
                // Content-Type of application/x-x509-ca-ra-cert-chain.
               
                // CA_IDENT is the message for this request to indicate which CA we are talking about
                log.debug("Got SCEP pkcs7 request for CA '" + message + "'");
 
                CAInfo cainfo = casession.getCAInfo(administrator, message);
                byte[] pkcs7 = signsession.createPKCS7(administrator, cainfo.getCAId(), true);
                if ((pkcs7 != null) && (pkcs7.length > 0)) {
                    log.debug("Sent PKCS7 for CA '" + message + "' to SCEP client.");
                    RequestHelper.sendBinaryBytes(pkcs7, response, "application/x-x509-ca-ra-cert-chain", null);
                iMsg = intres.getLocalizedMessage("scep.sentresponsemsg", "GetCACertChain", remoteAddr);
              log.info(iMsg);
                } else {
                String errMsg = intres.getLocalizedMessage("scep.errorunknownca", "pkcs7");
                    log.error(errMsg);
                    response.sendError(HttpServletResponse.SC_NOT_FOUND,"No CA certificates found.");
                }
            } else if (operation.equals("GetCACaps")) {
                // The response for GetCACaps is a <lf> separated list of capabilities

                /*
                 "GetNextCACert"       CA Supports the GetNextCACert message.
                 "POSTPKIOperation"    PKIOPeration messages may be sent via HTTP POST.
                 "SHA-1"               CA Supports the SHA-1 hashing algorithm in
                                       signatures and fingerprints.  If present, the
                                       client SHOULD use SHA-1.  If absent, the client
                                       MUST use MD5 to maintain backward compatability.
                 "Renewal"             Clients may use current certificate and key to
                                       authenticate an enrollment request for a new
                                       certificate. 
                 */
                log.debug("Got SCEP CACaps request for CA '" + message + "'");
                response.setContentType("text/plain");
                response.getOutputStream().print("POSTPKIOperation\nSHA-1");
            } else {
                log.error("Invalid parameter '" + operation);
                // TODO: Send back proper Failure Response
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid parameter: " + operation);
            }
        } catch (CADoesntExistsException cae) {
        String errMsg = intres.getLocalizedMessage("scep.errorunknownca", "cert");
            log.error(errMsg, cae);
            // TODO: Send back proper Failure Response
            response.sendError(HttpServletResponse.SC_NOT_FOUND, cae.getMessage());
        } catch (java.lang.ArrayIndexOutOfBoundsException ae) {
        String errMsg = intres.getLocalizedMessage("scep.errorinvalidreq");
            log.error(errMsg, ae);
            // TODO: Send back proper Failure Response
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, ae.getMessage());
        } catch (AuthorizationDeniedException ae) {
        String errMsg = intres.getLocalizedMessage("scep.errorauth");
            log.error(errMsg, ae);
            // TODO: Send back proper Failure Response
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ae.getMessage());
        } catch (AuthLoginException ae) {
        String errMsg = intres.getLocalizedMessage("scep.errorauth");
            log.error(errMsg, ae);
            // TODO: Send back proper Failure Response
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ae.getMessage());
        } catch (AuthStatusException ae) {
        String errMsg = intres.getLocalizedMessage("scep.errorclientstatus");
            log.error(errMsg, ae);
            // TODO: Send back proper Failure Response
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ae.getMessage());
        } catch (CATokenOfflineException ee) {
        String errMsg = intres.getLocalizedMessage("scep.errorgeneral");
            log.error(errMsg, ee);
            // TODO: Send back proper Failure Response
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ee.getMessage());
        } catch (Exception e) {
        String errMsg = intres.getLocalizedMessage("scep.errorgeneral");
            log.error(errMsg, e);
            // TODO: Send back proper Failure Response
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
        }
    }
   
} // ScepServlet
TOP

Related Classes of org.ejbca.ui.web.protocol.ScepServlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.