Package org.ejbca.core.ejb.ra

Source Code of org.ejbca.core.ejb.ra.CertificateRequestSessionBean

/*************************************************************************
*                                                                       *
*  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.core.ejb.ra;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.ObjectNotFoundException;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.PersistenceException;

import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.netscape.NetscapeCertRequest;
import org.cesecore.core.ejb.ra.raadmin.EndEntityProfileSessionLocal;
import org.ejbca.core.EjbcaException;
import org.ejbca.core.ejb.JndiHelper;
import org.ejbca.core.ejb.authorization.AuthorizationSessionLocal;
import org.ejbca.core.ejb.ca.auth.AuthenticationSessionLocal;
import org.ejbca.core.ejb.ca.caadmin.CAAdminSessionLocal;
import org.ejbca.core.ejb.ca.sign.SignSessionLocal;
import org.ejbca.core.ejb.config.GlobalConfigurationSessionLocal;
import org.ejbca.core.ejb.hardtoken.HardTokenSessionLocal;
import org.ejbca.core.ejb.keyrecovery.KeyRecoverySessionLocal;
import org.ejbca.core.model.SecConst;
import org.ejbca.core.model.approval.ApprovalException;
import org.ejbca.core.model.approval.WaitingForApprovalException;
import org.ejbca.core.model.authorization.AccessRulesConstants;
import org.ejbca.core.model.authorization.AuthorizationDeniedException;
import org.ejbca.core.model.authorization.Authorizer;
import org.ejbca.core.model.ca.SignRequestSignatureException;
import org.ejbca.core.model.ca.WrongTokenTypeException;
import org.ejbca.core.model.ca.caadmin.CADoesntExistsException;
import org.ejbca.core.model.log.Admin;
import org.ejbca.core.model.ra.NotFoundException;
import org.ejbca.core.model.ra.UserDataConstants;
import org.ejbca.core.model.ra.UserDataVO;
import org.ejbca.core.model.ra.raadmin.EndEntityProfile;
import org.ejbca.core.model.ra.raadmin.UserDoesntFullfillEndEntityProfile;
import org.ejbca.core.model.util.GenerateToken;
import org.ejbca.core.protocol.IRequestMessage;
import org.ejbca.core.protocol.IResponseMessage;
import org.ejbca.core.protocol.SimpleRequestMessage;
import org.ejbca.util.Base64;
import org.ejbca.util.CertTools;
import org.ejbca.util.FileTools;
import org.ejbca.util.RequestMessageUtils;

import com.novosec.pkix.asn1.crmf.CertRequest;

/**
* Combines EditUser (RA) with CertReq (CA) methods using transactions.
*
* @version $Id: CertificateRequestSessionBean.java 11802 2011-04-23 19:26:26Z netmackan $
*/
@Stateless(mappedName = JndiHelper.APP_JNDI_PREFIX + "CertificateRequestSessionRemote")
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class CertificateRequestSessionBean implements CertificateRequestSessionRemote, CertificateRequestSessionLocal {

    private static final long serialVersionUID = 1L;
    private static final Logger log = Logger.getLogger(CertificateRequestSessionBean.class);
   
    @EJB
    private AuthenticationSessionLocal authenticationSession;
    @EJB
    private AuthorizationSessionLocal authorizationSession;
    @EJB
    private CAAdminSessionLocal caAdminSession;
    @EJB
    private EndEntityProfileSessionLocal endEntityProfileSession;
    @EJB
    private HardTokenSessionLocal hardTokenSession;
    @EJB
    private KeyRecoverySessionLocal keyRecoverySession;
    @EJB
    private GlobalConfigurationSessionLocal globalConfigurationSession;
    @EJB
    private UserAdminSessionLocal userAdminSession;
    @EJB
    private SignSessionLocal signSession;
    @Resource
    private SessionContext sessionContext;

    @Override
  public byte[] processCertReq(Admin admin, UserDataVO userdata, String req, int reqType,
      String hardTokenSN, int responseType) throws CADoesntExistsException,
      AuthorizationDeniedException, NotFoundException, InvalidKeyException,
      NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException,
      SignatureException, IOException, ObjectNotFoundException, CertificateException,
      UserDoesntFullfillEndEntityProfile, ApprovalException, EjbcaException {
    byte[] retval = null;

    // Check tokentype
    if(userdata.getTokenType() != SecConst.TOKEN_SOFT_BROWSERGEN){
      throw new WrongTokenTypeException ("Error: Wrong Token Type of user, must be 'USERGENERATED' for PKCS10/SPKAC/CRMF/CVC requests");
    }
    // This is the secret sauce, do the end entity handling automagically here before we get the cert
    addOrEditUser(admin, userdata, false, true);
    // Process request
    try {
      String password = userdata.getPassword();
      String username = userdata.getUsername();
      IRequestMessage imsg = null;
      if (reqType == SecConst.CERT_REQ_TYPE_PKCS10) {       
        IRequestMessage pkcs10req = RequestMessageUtils.genPKCS10RequestMessage(req.getBytes());
        PublicKey pubKey = pkcs10req.getRequestPublicKey();
        imsg = new SimpleRequestMessage(pubKey, username, password);
      } else if (reqType == SecConst.CERT_REQ_TYPE_SPKAC) {
        // parts copied from request helper.
        byte[] reqBytes = req.getBytes();
        if (reqBytes != null) {
          log.debug("Received NS request: "+new String(reqBytes));
          byte[] buffer = Base64.decode(reqBytes);
          if (buffer == null) {
            return null;
          }
          ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream(buffer));
          ASN1Sequence spkacSeq = (ASN1Sequence) in.readObject();
          in.close();
          NetscapeCertRequest nscr = new NetscapeCertRequest(spkacSeq);
          // Verify POPO, we don't care about the challenge, it's not important.
          nscr.setChallenge("challenge");
          if (nscr.verify("challenge") == false) {
            log.debug("POPO verification Failed");
            throw new SignRequestSignatureException("Invalid signature in NetscapeCertRequest, popo-verification failed.");
          }
          log.debug("POPO verification successful");
          PublicKey pubKey = nscr.getPublicKey();
          imsg = new SimpleRequestMessage(pubKey, username, password);
        }   
      } else if (reqType == SecConst.CERT_REQ_TYPE_CRMF) {
        byte[] request = Base64.decode(req.getBytes());
        ASN1InputStream in = new ASN1InputStream(request);
        ASN1Sequence    crmfSeq = (ASN1Sequence) in.readObject();
        ASN1Sequence reqSeq =  (ASN1Sequence) ((ASN1Sequence) crmfSeq.getObjectAt(0)).getObjectAt(0);
        CertRequest certReq = new CertRequest( reqSeq );
        SubjectPublicKeyInfo pKeyInfo = certReq.getCertTemplate().getPublicKey();
        KeyFactory keyFact = KeyFactory.getInstance("RSA", "BC");
        KeySpec keySpec = new X509EncodedKeySpec( pKeyInfo.getEncoded() );
        PublicKey pubKey = keyFact.generatePublic(keySpec); // just check it's ok
        imsg = new SimpleRequestMessage(pubKey, username, password);
        // a simple crmf is not a complete PKI message, as desired by the CrmfRequestMessage class
        //PKIMessage msg = PKIMessage.getInstance(new ASN1InputStream(new ByteArrayInputStream(request)).readObject());
        //CrmfRequestMessage reqmsg = new CrmfRequestMessage(msg, null, true, null);
        //imsg = reqmsg;
      } else if (reqType == SecConst.CERT_REQ_TYPE_PUBLICKEY) {
        byte[] request;
        // Request can be Base64 encoded or in PEM format
        try {
          request = FileTools.getBytesFromPEM(req.getBytes(), CertTools.BEGIN_PUBLIC_KEY, CertTools.END_PUBLIC_KEY);
        } catch (IOException ex) {
          try {
            request = Base64.decode(req.getBytes());
            if (request == null) {
              throw new IOException("Base64 decode of buffer returns null");
            }         
          } catch (ArrayIndexOutOfBoundsException ae) {
            throw new IOException("Base64 decode fails, message not base64 encoded: " + ae.getMessage());
          }
        }
        final ASN1InputStream in = new ASN1InputStream(request);
        final SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(in.readObject());
        final AlgorithmIdentifier keyAlg = keyInfo.getAlgorithmId();
        final X509EncodedKeySpec xKeySpec = new X509EncodedKeySpec(new DERBitString(keyInfo).getBytes());
        final KeyFactory keyFact = KeyFactory.getInstance(keyAlg.getObjectId().getId(), "BC");
        final PublicKey pubKey = keyFact.generatePublic(xKeySpec);
        imsg = new SimpleRequestMessage(pubKey, username, password);
      }
      if (imsg != null) {
        retval = getCertResponseFromPublicKey(admin, imsg, hardTokenSN, responseType, userdata);
      }
    } catch (NotFoundException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (InvalidKeyException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (NoSuchAlgorithmException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (InvalidKeySpecException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (NoSuchProviderException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (SignatureException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (IOException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (CertificateException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (EjbcaException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    }
    return retval;
  }

    @Override
  public IResponseMessage processCertReq(Admin admin, UserDataVO userdata, IRequestMessage req, Class responseClass) throws PersistenceException, AuthorizationDeniedException, UserDoesntFullfillEndEntityProfile, EjbcaException {
    // Check tokentype
    if(userdata.getTokenType() != SecConst.TOKEN_SOFT_BROWSERGEN){
      throw new WrongTokenTypeException ("Error: Wrong Token Type of user, must be 'USERGENERATED' for PKCS10/SPKAC/CRMF/CVC requests");
    }
    // This is the secret sauce, do the end entity handling automagically here before we get the cert
    addOrEditUser(admin, userdata, false, true);
    IResponseMessage retval = null;
    try {
      retval = signSession.createCertificate(admin, req, responseClass, userdata);
    } catch (NotFoundException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (EjbcaException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    }
    return retval;
  }
 
  /**
   * @throws CADoesntExistsException if userdata.caId is not a valid caid. This is checked in editUser or addUserFromWS
   */
  private void addOrEditUser(Admin admin, UserDataVO userdata, boolean clearpwd, boolean fromwebservice) throws AuthorizationDeniedException,
      UserDoesntFullfillEndEntityProfile, ApprovalException,
      PersistenceException, CADoesntExistsException, EjbcaException {
   
    int caid = userdata.getCAId();
    if(!authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.CAPREFIX +caid)) {
        Authorizer.throwAuthorizationException(admin, AccessRulesConstants.CAPREFIX +caid, null);
    }
    if(!authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.REGULAR_CREATECERTIFICATE)) {
        Authorizer.throwAuthorizationException(admin, AccessRulesConstants.REGULAR_CREATECERTIFICATE, null);
    }
    // First we need to fetch the CA configuration to see if we save UserData, if not, we still run addUserFromWS to
    // get all the proper authentication checks for CA and end entity profile.
    boolean useUserStorage = caAdminSession.getCAInfo(admin, caid).isUseUserStorage();
    // Add or edit user
    try {
      String username = userdata.getUsername();
      if (useUserStorage && userAdminSession.existsUser(admin, username)) {
        if (log.isDebugEnabled()) {
          log.debug("User " + username + " exists, update the userdata. New status of user '"+userdata.getStatus()+"'." );
        }
        userAdminSession.changeUser(admin,userdata, clearpwd, fromwebservice);
      } else {
        if (log.isDebugEnabled()) {
          log.debug("New User " + username + ", adding userdata. New status of user '"+userdata.getStatus()+"'." );
        }
        // addUserfromWS also checks useUserStorage internally, so don't dupliace the check
        userAdminSession.addUserFromWS(admin,userdata,clearpwd);
      }
    } catch (WaitingForApprovalException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      String msg = "Single transaction enrollment request rejected since approvals are enabled for this CA ("+caid+") or Certificate Profile ("+userdata.getCertificateProfileId()+").";
      log.info(msg);
      throw new ApprovalException(msg);
    }
  }

  /**
   * Process a request in the CA module.
   *
   * @param admin is the requesting administrator
   * @param msg is the request message processed by the CA
   * @param hardTokenSN is the hard token to associate this or null
   * @param responseType is one of SecConst.CERT_RES_TYPE_...
     * @return a encoded certificate of the type specified in responseType
   */
  private byte[] getCertResponseFromPublicKey(Admin admin, IRequestMessage msg, String hardTokenSN, int responseType, UserDataVO userData)
  throws EjbcaException, CertificateEncodingException, CertificateException, IOException {
    byte[] retval = null;
    Class respClass = org.ejbca.core.protocol.X509ResponseMessage.class;
    IResponseMessage resp =  signSession.createCertificate(admin, msg, respClass, userData);
    java.security.cert.Certificate cert = CertTools.getCertfromByteArray(resp.getResponseMessage());
    if(responseType == SecConst.CERT_RES_TYPE_CERTIFICATE){
      retval = cert.getEncoded();
    }
    if(responseType == SecConst.CERT_RES_TYPE_PKCS7){
      retval = signSession.createPKCS7(admin, cert, false);
    }
    if(responseType == SecConst.CERT_RES_TYPE_PKCS7WITHCHAIN){
      retval = signSession.createPKCS7(admin, cert, true);
    }

    if(hardTokenSN != null){
      hardTokenSession.addHardTokenCertificateMapping(admin,hardTokenSN,cert);         
    }
    return retval;
  }

  @Override
  public byte[] processSoftTokenReq(Admin admin, UserDataVO userdata, String hardTokenSN, String keyspec, String keyalg, boolean createJKS)
  throws CADoesntExistsException, AuthorizationDeniedException, NotFoundException, InvalidKeyException, InvalidKeySpecException, NoSuchProviderException,
  SignatureException, IOException, ObjectNotFoundException, CertificateException,UserDoesntFullfillEndEntityProfile,
  ApprovalException, EjbcaException, KeyStoreException, NoSuchAlgorithmException,
  InvalidAlgorithmParameterException, PersistenceException {
   
    // This is the secret sauce, do the end entity handling automagically here before we get the cert
    addOrEditUser(admin, userdata, true, true);
    // Process request
    byte[] ret = null;
    try {
      // Get key recovery info
      boolean usekeyrecovery = globalConfigurationSession.getCachedGlobalConfiguration(admin).getEnableKeyRecovery();
      if (log.isDebugEnabled()) {
        log.debug("usekeyrecovery: "+usekeyrecovery);
      }
      boolean savekeys = userdata.getKeyRecoverable() && usekeyrecovery &&  (userdata.getStatus() != UserDataConstants.STATUS_KEYRECOVERY);
      if (log.isDebugEnabled()) {
        log.debug("userdata.getKeyRecoverable(): "+userdata.getKeyRecoverable());
        log.debug("userdata.getStatus(): "+userdata.getStatus());
        log.debug("savekeys: "+savekeys);
      }
      boolean loadkeys = (userdata.getStatus() == UserDataConstants.STATUS_KEYRECOVERY) && usekeyrecovery;
      if (log.isDebugEnabled()) {
        log.debug("loadkeys: "+loadkeys);
      }
      int endEntityProfileId = userdata.getEndEntityProfileId();
      EndEntityProfile endEntityProfile = endEntityProfileSession.getEndEntityProfile(admin, endEntityProfileId);
      boolean reusecertificate = endEntityProfile.getReUseKeyRecoveredCertificate();
      if (log.isDebugEnabled()) {
        log.debug("reusecertificate: "+reusecertificate);
      }
      // Generate keystore
      String password = userdata.getPassword();
      String username = userdata.getUsername();
      int caid = userdata.getCAId();
        GenerateToken tgen = new GenerateToken(authenticationSession, userAdminSession, caAdminSession, keyRecoverySession, signSession);
        KeyStore keyStore = tgen.generateOrKeyRecoverToken(admin, username, password, caid, keyspec, keyalg, createJKS, loadkeys, savekeys, reusecertificate, endEntityProfileId);
      String alias = keyStore.aliases().nextElement();
        X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
        if ( (hardTokenSN != null) && (cert != null) ) {
          hardTokenSession.addHardTokenCertificateMapping(admin,hardTokenSN,cert);                
        }
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      keyStore.store(baos, password.toCharArray());
      ret = baos.toByteArray();
    } catch (NotFoundException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (InvalidKeyException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (NoSuchAlgorithmException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (InvalidKeySpecException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (NoSuchProviderException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (SignatureException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (IOException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (CertificateException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (EjbcaException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (InvalidAlgorithmParameterException e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw e;
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
      sessionContext.setRollbackOnly()// This is an application exception so it wont trigger a roll-back automatically
      throw new KeyStoreException(e);
    }
      return ret;
  }
}
TOP

Related Classes of org.ejbca.core.ejb.ra.CertificateRequestSessionBean

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.