Package org.ejbca.externalra.gui

Source Code of org.ejbca.externalra.gui.EnrollInterfaceBean

/*************************************************************************
*                                                                       *
*  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.externalra.gui;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.cert.CertPath;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.List;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.jce.netscape.NetscapeCertRequest;
import org.ejbca.config.InternalConfiguration;
import org.ejbca.core.model.SecConst;
import org.ejbca.extra.db.CertificateRequestRequest;
import org.ejbca.util.Base64;
import org.ejbca.util.CertTools;
import org.ejbca.util.FileTools;

import com.icesoft.faces.component.inputfile.InputFile;
import com.icesoft.faces.context.ByteArrayResource;
import com.icesoft.faces.context.Resource;
import com.icesoft.faces.context.effects.JavascriptContext;
import com.novosec.pkix.asn1.crmf.CertReqMessages;

/**
* This is the backing bean for the enrollment part of the External RA GUI.
*
* @version $Id: EnrollInterfaceBean.java 9330 2010-06-30 18:16:53Z anatom $
*/
public class EnrollInterfaceBean {

  private static final String PEM_CSR_BEGIN       = "-----BEGIN CERTIFICATE REQUEST-----";
  private static final String PEM_CSR_END         = "-----END CERTIFICATE REQUEST-----";
  private static final String PEM_CSR_BEGIN_VISTA = "-----BEGIN NEW CERTIFICATE REQUEST-----";
  private static final String PEM_CSR_END_VISTA   = "-----END NEW CERTIFICATE REQUEST-----";
  private static final String PEM_PKCS7_BEGIN     = "-----BEGIN PKCS7-----";
  private static final String PEM_PKCS7_END       = "-----END PKCS7-----";

  private static final Logger log = Logger.getLogger(EnrollInterfaceBean.class);

  private IRequestDispatcher requestDispatcher = null;
 
  // General variables
  private String userAgentString = null;
  private String username = null;
  private String password = null;
  private boolean showPassword = false;
  private String filename = null;
  private Resource resource = null;
  private String mimeType = null;
 
  // Variables used to get a certificate from a CSR
  private String certificateRequest = PEM_CSR_BEGIN + "\n...base 64 encoded request...\n" + PEM_CSR_END;
  private String requestedResponseType = "der";

  private String certificateRequestType = null;
  private String certificateResponse = "";
  private String certificateResponseType = null;
 
  private String cspSelectValue = null;
 
  public String getUsername() { return username; }
  public void setUsername(String username) { this.username = username; }
  public String getPassword() { return password; }
  public void setPassword(String password) { this.password = password; }
  public boolean getShowPassword() { return showPassword; }
  public void setShowPassword(boolean showPassword) { this.showPassword = showPassword; }
 
  public boolean isDownloadAvailable() { return resource!=null; }
  public String getFilename() { return filename; }
  public Resource getResource() { return resource; }
  public String getMimeType() { return mimeType; }
 
  public String getCertificateRequest() { return certificateRequest; }
  public void setCertificateRequest(String certificateRequest) { this.certificateRequest = certificateRequest; }
  public String getRequestedResponseType() { return requestedResponseType; }
  public void setRequestedResponseType(String requestedResponseType) { this.requestedResponseType = requestedResponseType; }

  public String getCertificateRequestType() { return certificateRequestType; }
  public void setCertificateRequestType(String certificateRequestType) { this.certificateRequestType = certificateRequestType; }
  public String getCertificateResponseType() { return certificateResponseType; }
  public String getCertificateResponse() { return certificateResponse; }
  public void setCertificateResponse(String certificateResponse) { this.certificateResponse = certificateResponse; }
 
  public String getCspSelectValue() { return cspSelectValue; }
  public void setCspSelectValue(String cspSelectValue) { this.cspSelectValue = cspSelectValue; }
 
  public String getKeySpec() { return ExternalRaGuiConfiguration.getKeySpec(); }
  public String getExportable() { return ExternalRaGuiConfiguration.getExportable() ? "1" : "0"; }

  public String getVersionString() { return InternalConfiguration.getAppVersionNumber() + " (" + InternalConfiguration.getSvnRevision() + ")"; }
  public String getHelpUrl() { return ExternalRaGuiConfiguration.getHelpUrl(); }

  /** @return The host's name or "unknown" if it could not be determined. */
    public String getHostName() {
      String hostname = "unknown";
      try {
          hostname = InetAddress.getLocalHost().getHostName();
      } catch (UnknownHostException e) {
        // Ignored
      }
      return hostname;
    }

    /** @return true if the user-agent String contains MSIE **/
  public boolean isInternetExplorer() {
    return getUserAgenString().indexOf("MSIE") != -1;
  }

  /**
   * XEnroll:
   *  "Windows NT 5.1" = Win XP x86
   *  "Windows NT 5.2" = Win XP x64, Server 2003
   * CertEnroll:
   *  "Windows NT 6.0" = Win Vista, Server 2008
   *  "Windows NT 6.1" = Windows 7, Server 2008 R2
   */
  public boolean isWindowsNT5() {
    return getUserAgenString().indexOf("Windows NT 5.") != -1;
  }

  /**
   * Prevent the web framework from rendering an empty table if there are no global messages
   * by using this method. Empty tables results in error messages in the Safari log.
   */
  public boolean isMessagesPending() {
    return FacesContext.getCurrentInstance().getMessages(null).hasNext();
  }

  /**
   * @return the current user-agent string that identifies the clients browser and operating system.
   */
  private String getUserAgenString() {
    if (userAgentString == null) {
      userAgentString = (String) FacesContext.getCurrentInstance().getExternalContext().getRequestHeaderMap().get("user-agent");
      log.debug("User agent: " + userAgentString);
    }
    return userAgentString;
  }

  /**
   * @return an implementation for communication with the EJBCA instance.
   */
  private IRequestDispatcher getRequestDispatcher() {
    if (requestDispatcher == null) {
      // Change this to read the class name from the externalra-gui configuration if we add additional implementations.
      String className = ExternalRARequestDispatcher.class.getName();
      try {
        requestDispatcher = (IRequestDispatcher) Class.forName(className).newInstance();
      } catch (ClassNotFoundException e) {
        log.error("Could not find request implementaion :" + className);
      } catch (InstantiationException e) {
        log.error("Could not instantiate request implementaion :" + className);
      } catch (IllegalAccessException e) {
        log.error("Could not access request implementaion :" + className);
      }
    }
    return requestDispatcher;
  }

  /**
   * Used for reading a Certificate Signing Request file upload into the certificate request String.
   * @param actionEvent is the parameter from the web framework containing the file.
   */
  public void uploadActionListener(ActionEvent actionEvent) {
        InputFile inputFile = (InputFile) actionEvent.getSource();
    FacesContext context = FacesContext.getCurrentInstance();
        if (inputFile.getFileInfo().isSaved()) {
          // Validate that it is a CSR..
          File f = inputFile.getFileInfo().getFile();
            // Assume this is a small file.. it should be..
            long len = f.length();
            if (len < 16*1024L) {
                byte[] buf = new byte[(int) len];
                try {
                    FileInputStream in = new FileInputStream(f);
                    in.read(buf);
                    in.close();
                } catch (IOException e) {
                  context.addMessage(null /*actionEvent.getComponent().getClientId(context)*/, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.csrcert.uploadfailed"), null));
                  log.debug("Rejected uploaded file due to IOException.");
                  return;
        }
                try {
                    // See if it was a PEM
                  buf = FileTools.getBytesFromPEM(buf, PEM_CSR_BEGIN, PEM_CSR_END);
                } catch (IOException e) {
                  log.debug("Uploaded file was not a PEM.. tryin to parse it as a DER encoded request.");
                }
                // See if it as a PKCS10
                try {
                    new PKCS10CertificationRequest(buf);
                } catch (Exception e) {
                  context.addMessage(null /*actionEvent.getComponent().getClientId(context)*/, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.csrcert.uploadfailednotpkcs10"), null));
                  log.debug("Rejected uploaded file since it's not a valid PKCS#10 request.");
                  return;
                }
              // Convert it back to a PEM
                String pem = PEM_CSR_BEGIN + "\n" + new String(Base64.encode(buf)) + "\n" + PEM_CSR_END;
                certificateRequest = pem;
              context.addMessage(null /*actionEvent.getComponent().getClientId(context)*/, new FacesMessage(FacesMessage.SEVERITY_INFO, getMessage("enroll.csrcert.uploadok"), null));
            } else {
              context.addMessage(null /*actionEvent.getComponent().getClientId(context)*/, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.csrcert.uploadfailedtoolarge"), null));
            }
        } else {
          log.debug("File upload failed: " + inputFile.getFileInfo().getException().getMessage());
        context.addMessage(null /*actionEvent.getComponent().getClientId(context)*/, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.csrcert.uploadfailed"), null));
        }
  }
 
  /**
   * Action that requests a KeyStore from EJBCA using the given credentials.
   */
  public void createKeystore() {
    log.info("Recieved a KeyStore request for username '" + username + "' from " + getRemoteAddress());
    FacesContext context = FacesContext.getCurrentInstance();
    if (username==null || username.length()==0 || password==null || password.length()==0) {
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.incompletefields"), null));
      return;
    }
    // Request the KeyStore from the CA
    ResponseData keyStoreResponse = getRequestDispatcher().getKeyStoreResponse(username, password);
    // Check if got a valid result
    if (keyStoreResponse == null) {
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.noresponse"), null));
      log.error("KeyStore request for '" + username + "' failed. No response from CA.");
      return;
    } else if (keyStoreResponse.getErrorMessage() != null) {
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.keystore.couldnotcreate"), null));
      log.info("KeyStore request for '" + username + "' failed. " + keyStoreResponse.getErrorMessage());
      return;
    }
    // Handle response
    resource = new ByteArrayResource(keyStoreResponse.getResponseData());
    switch (keyStoreResponse.getResponseType()) {
    case SecConst.TOKEN_SOFT_JKS:
      filename = username + ".jks";
      break;
    case SecConst.TOKEN_SOFT_P12:
      filename = username + ".p12";
      break;
    case SecConst.TOKEN_SOFT_PEM:
      filename = username + ".pem";
      break;
    default:
      filename = username + ".unknown";
      break;
    }
    mimeType = "application/octet-stream";
    log.info("KeyStore request with response-type " + keyStoreResponse.getResponseType() + " for '" + username + "' was successful.");
  }
 
  /**
   * Action that requests a certificate from EJBCA using the given credentials and the Certificate Signing Request.
   */
  public void createCertFromCSR() {
    log.info("Recieved a certificate signing request for username '" + username + "' from " + getRemoteAddress());
    if (log.isDebugEnabled()) {
      log.debug("certificateRequest: " + certificateRequest);
    }
    FacesContext context = FacesContext.getCurrentInstance();
    if (username==null || username.length()==0 || password==null || password.length()==0 || certificateRequest==null || certificateRequest.length()==0) {
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.incompletefields"), null));
      return;
    }
    // Verify that we got a valid Certificate Signing Request
    try {
          // Clean it up if windows has messed it up..
            byte[] buf = (PEM_CSR_BEGIN + certificateRequest.replaceFirst(PEM_CSR_BEGIN, "").replaceFirst(PEM_CSR_END, "").replaceAll(" ", "").replaceAll("\r", "")+PEM_CSR_END).getBytes();
            // See if it is a PEM
      buf = FileTools.getBytesFromPEM(buf, PEM_CSR_BEGIN, PEM_CSR_END);
      certificateRequest = PEM_CSR_BEGIN + "\n" + new String(Base64.encode(buf)) + "\n" + PEM_CSR_END;
      if (log.isDebugEnabled()) {
              log.debug("cleaned req: " + certificateRequest);
      }
            new PKCS10CertificationRequest(buf);
    } catch (Exception e) {
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.invalidreqdata"), null));
      return;
    }
    // Determine what kind of response the user has requested
    int responseType = CertificateRequestRequest.RESPONSE_TYPE_ENCODED;
    if ("pkcs7".equals(requestedResponseType)) {
      responseType = CertificateRequestRequest.RESPONSE_TYPE_PKCS7;
    }
    // Request the certificate from the CA
    ResponseData csrResponse = getRequestDispatcher().getCertificateSigningRequestResponse(username, password, certificateRequest, responseType);
    // Check if got a valid result
    if (csrResponse == null) {
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.noresponse"), null));
      log.error("Certificate request for '" + username + "' failed. No response from CA.");
      return;
    } else if (csrResponse.getErrorMessage() != null) {
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.csrcert.couldnotcreate"), null));
      log.info("Certificate request for '" + username + "' failed. " + csrResponse.getErrorMessage());
      return;
    }
    // Handle response
    switch (csrResponse.getResponseType()) {
    case CertificateRequestRequest.RESPONSE_TYPE_ENCODED:
      if ("pem".equals(requestedResponseType)) {
        Certificate[] certs = new Certificate[1];
        try {
          certs[0] = CertTools.getCertfromByteArray(csrResponse.getResponseData());
          resource = new ByteArrayResource(CertTools.getPEMFromCerts(CertTools.getCertCollectionFromArray(certs, "BC")));
          filename = username + ".pem";
          mimeType = "application/x-pem-file";
        } catch (Exception e) {
          log.error("",e);
          context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.invalidresponse"), null));
        }
      } else {
        resource = new ByteArrayResource(csrResponse.getResponseData());
        filename = username + ".der";
        mimeType = "application/pkix-cert";
      }
      break;
    case CertificateRequestRequest.RESPONSE_TYPE_PKCS7:
      resource = new ByteArrayResource(csrResponse.getResponseData());
      filename = username + ".p7b";
      mimeType = "application/x-pkcs7-certificates";
      break;
    default:
      filename = username + ".unknown";
      mimeType = "application/octet-stream";
      break;
    }
    log.info("Certificate request with response-type " + csrResponse.getResponseType() + " for '" + username + "' was successful.");
  }

  /**
   * Action that requests a certificate from EJBCA using the given credentials and the Certificate Signing Request created by the browser.
   */
  public void createCertFromBrowser() {
    log.info("Recieved a browser generated certificate request of type " + certificateRequestType + " for username '" + username + "' from " + getRemoteAddress());
    if (log.isDebugEnabled()) {
      log.debug("certificateRequest: " + certificateRequest);
    }
    FacesContext context = FacesContext.getCurrentInstance();
    if (username==null || username.length()==0 || password==null || password.length()==0 || certificateRequest==null || certificateRequest.length()==0
        || certificateRequestType==null || certificateRequestType.length()==0) {
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.incompletefields"), null));
      return;
    }
    // Verify that we got a valid certificate request and determine response type
    byte[] buf = null;
    int requestType = Integer.parseInt(certificateRequestType);
    int responseType;
    switch (requestType) {
    case CertificateRequestRequest.REQUEST_TYPE_CRMF:
      responseType = CertificateRequestRequest.RESPONSE_TYPE_PKCS7;
      buf = Base64.decode(certificateRequest.getBytes());
      ASN1InputStream asn1InputStream = new ASN1InputStream(buf);
      try {
        // Verify that we can parse this as a CRMF object
        CertReqMessages.getInstance(asn1InputStream.readObject()).getCertReqMsg(0);
      } catch (IOException e) {
        context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.invalidreqdata"), null));
        log.error("",e);
      }
      break;
    case CertificateRequestRequest.REQUEST_TYPE_PKCS10:
      responseType = CertificateRequestRequest.RESPONSE_TYPE_PKCS7;
      try {
        if (!isWindowsNT5()) {
          responseType = CertificateRequestRequest.RESPONSE_TYPE_UNSIGNEDPKCS7;
        }
        // Replace Vista PEM markers
        certificateRequest = certificateRequest.replaceAll(PEM_CSR_BEGIN_VISTA, PEM_CSR_BEGIN);
        certificateRequest = certificateRequest.replaceAll(PEM_CSR_END_VISTA, PEM_CSR_END);
        if (certificateRequest.indexOf(PEM_CSR_BEGIN) == -1) {
          certificateRequest = PEM_CSR_BEGIN + "\n" + certificateRequest + "\n" + PEM_CSR_END;
        }
        buf = FileTools.getBytesFromPEM(certificateRequest.getBytes(), PEM_CSR_BEGIN, PEM_CSR_END);
              new PKCS10CertificationRequest(buf);
      } catch (Exception e) {
        log.error("",e);
        context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.invalidreqdata"), null));
        return;
      }
      break;
    case CertificateRequestRequest.REQUEST_TYPE_KEYGEN:
      responseType = CertificateRequestRequest.RESPONSE_TYPE_PKCS7;
      try {
        buf = Base64.decode(certificateRequest.getBytes());
            ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream(buf));
            ASN1Sequence spkac = (ASN1Sequence) in.readObject();
            in.close();
            NetscapeCertRequest nscr = new NetscapeCertRequest(spkac);
            // Verify POPO, we don't care about the challenge, it's not important.
            nscr.setChallenge("challenge");
            if (nscr.verify("challenge") == false) {
          context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.invalidreqdata"), null));
          return;
            }
      } catch (Exception e) {
        log.error("",e);
        context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.invalidreqdata"), null));
        return;
      }
      break;
    case -1:
      // This is a workaround to hide errors when we use the KeyGenServlet..
      return;
    default:
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.unknownrequesttype"), null));
      return;
    }
    // Request the certificate from the CA
    if (log.isDebugEnabled()) {
      log.debug("Got requestType " + requestType + " and is expecting responseType " + responseType + " for user " + username);
    }
    ResponseData responseData = getRequestDispatcher().getCertificateResponse(username, password, requestType, buf, responseType);
    // Check if got a valid result
    if (responseData == null) {
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.noresponse"), null));
      log.error("Certificate request for '" + username + "' failed. No response from CA.");
      return;
    } else if (responseData.getErrorMessage() != null) {
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.browsercert.couldnotcreate"), null));
      log.info("Certificate request for '" + username + "' failed. " + responseData.getErrorMessage());
      return;
    }
    // Handle response
    certificateResponseType = "" + responseData.getResponseType();
    switch (responseData.getResponseType()) {
    case CertificateRequestRequest.RESPONSE_TYPE_PKCS7:
      if (isInternetExplorer()) {
        // Working for XP+IE7
        certificateResponse = new String(Base64.encode(responseData.getResponseData(), false));
      } else {
        resource = new ByteArrayResource(responseData.getResponseData());
        mimeType = "application/x-x509-user-cert";
      }
      break;
    case CertificateRequestRequest.RESPONSE_TYPE_UNSIGNEDPKCS7:
      // Working for Vista+IE8
      certificateResponse = new String(Base64.encode(responseData.getResponseData(), false));
            try {
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                String pkcs7 = PEM_PKCS7_BEGIN + "\n" + new String(Base64.encode(responseData.getResponseData(), true)) + "\n" + PEM_PKCS7_END + "\n";
                log.debug("pkcs7="+pkcs7);
              CertPath certPath = cf.generateCertPath(new ByteArrayInputStream(responseData.getResponseData()), "PKCS7");
              List<? extends Certificate> certList = certPath.getCertificates();
              Certificate caCert = certList.get(certList.size()-1);
              String caCertificate = new String(Base64.encode(caCert.getEncoded(), false));
        resource = new ByteArrayResource(caCertificate.getBytes());
        mimeType = "application/x-x509-ca-cert";
            } catch (CertificateException e) {
              e.printStackTrace();
            }
        if (log.isDebugEnabled()) {
          log.debug("certificateResponse: " + certificateResponse);
        }
      break;
    default:
      context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessage("enroll.unknownresponsetype"), null));
      log.error("Unknown result type: " + certificateResponseType);
      break;
    }
    log.info("Certificate request with response-type " + responseData.getResponseType() + " for '" + username + "' was successful.");
  }
 
  /**
   * Adds a JavaScript that removes the HTML from where it was called. Expects to be included inside a div with id "form:downloadDiv2".
   */
  public void removeLinks() {
    // Hide the installer links once the cert is installed
    JavascriptContext.addJavascriptCall(FacesContext.getCurrentInstance(), "if (document.getElementById('form:certificateInstalled').value == 'true') { document.getElementById('form:downloadLinkDiv2').innerHTML = 'Installed.';}");
  }
 
  /**
   * Action that does absolutely nothing. Used when we want a commandLink to just trigger an onclick or something similar.
   */
  public void noOp() { }
 
  /**
   * Get localized message from the message-bundle.
   */
  private String getMessage(String key){
    String text = null;
    FacesContext context = FacesContext.getCurrentInstance();
    ResourceBundle bundle = ResourceBundle.getBundle(context.getApplication().getMessageBundle(), context.getViewRoot().getLocale(), Thread.currentThread().getContextClassLoader());
    try{
      text = bundle.getString(key);
    } catch(MissingResourceException e){
      text = "?? key " + key + " not found ??";
    }
    return text;
  }
 
  private String getRemoteAddress() {
    return ((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest()).getRemoteAddr();
  }
}
TOP

Related Classes of org.ejbca.externalra.gui.EnrollInterfaceBean

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.