Package org.ejbca.core.model.ca.caadmin.extendedcaservices

Source Code of org.ejbca.core.model.ca.caadmin.extendedcaservices.XKMSCAService

/*************************************************************************
*                                                                       *
*  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.model.ca.caadmin.extendedcaservices;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureException;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.ejbca.config.EjbcaConfiguration;
import org.ejbca.core.model.InternalResources;
import org.ejbca.core.model.ca.caadmin.CA;
import org.ejbca.core.model.ca.caadmin.IllegalKeyStoreException;
import org.ejbca.core.model.ca.certificateprofiles.XKMSCertificateProfile;
import org.ejbca.core.model.ra.UserDataVO;
import org.ejbca.util.Base64;
import org.ejbca.util.CertTools;
import org.ejbca.util.CryptoProviderTools;
import org.ejbca.util.StringTools;
import org.ejbca.util.keystore.KeyTools;
import org.w3c.dom.Document;

/** Handles and maintains the CA-part of the XKMS functionality.
*  The service have it's own certificate used for signing and encryption
*
* @author Philip Vendil
* @version $Id: XKMSCAService.java 11731 2011-04-13 17:52:27Z jeklund $
*/
public class XKMSCAService extends ExtendedCAService implements Serializable {

    private static Logger m_log = Logger.getLogger(XKMSCAService.class);
    /** Internal localization of logs and errors */
    private static final InternalResources intres = InternalResources.getInstance();

    public static final float LATEST_VERSION = 2;
   
    public static final String SERVICENAME = "XKMSCASERVICE";         

    private PrivateKey xKMSkey = null;
    private List<Certificate> xKMScertificatechain  = null;
   
    private XKMSCAServiceInfo info = null
   
    private static final String XKMSKEYSTORE   = "xkmskeystore";
    private static final String KEYSPEC        = "keyspec";
  private static final String KEYALGORITHM   = "keyalgorithm";
  private static final String SUBJECTDN      = "subjectdn";
  private static final String SUBJECTALTNAME = "subjectaltname";
   
  private static final String PRIVATESIGNKEYALIAS = "privatesignkeyalias";  

  public XKMSCAService(final ExtendedCAServiceInfo serviceinfo) {
    m_log.debug("XKMSCAService : constructor " + serviceinfo.getStatus());
    CryptoProviderTools.installBCProviderIfNotAvailable();
    // Currently only RSA keys are supported
    final XKMSCAServiceInfo info = (XKMSCAServiceInfo) serviceinfo;
    data = new HashMap();
    data.put(ExtendedCAServiceInfo.IMPLEMENTATIONCLASS, this.getClass().getName())// For integration with CESeCore
    data.put(EXTENDEDCASERVICETYPE, Integer.valueOf(ExtendedCAServiceInfo.TYPE_XKMSEXTENDEDSERVICE))// For current version of EJBCA
    data.put(KEYSPEC, info.getKeySpec());
    data.put(KEYALGORITHM, info.getKeyAlgorithm());
    setSubjectDN(info.getSubjectDN());
    setSubjectAltName(info.getSubjectAltName());
    setStatus(serviceinfo.getStatus());
    data.put(VERSION, new Float(LATEST_VERSION));
    }
   
    public XKMSCAService(final HashMap data) throws IllegalArgumentException, IllegalKeyStoreException {
      CryptoProviderTools.installBCProviderIfNotAvailable();
      loadData(data);
      if (data.get(XKMSKEYSTORE) != null) {
        // lookup keystore passwords
        final String keystorepass = StringTools.passwordDecryption(EjbcaConfiguration.getCaXkmsKeyStorePass(), "ca.xkmskeystorepass");
        int status = ExtendedCAServiceInfo.STATUS_INACTIVE;
        try {
          m_log.debug("Loading XKMS keystore");
          final KeyStore keystore = KeyStore.getInstance("PKCS12", "BC");
          keystore.load(new ByteArrayInputStream(Base64.decode(((String) data.get(XKMSKEYSTORE)).getBytes())), keystorepass.toCharArray());
          m_log.debug("Finished loading XKMS keystore");
          this.xKMSkey = (PrivateKey) keystore.getKey(PRIVATESIGNKEYALIAS, null);
          // Due to a bug in Glassfish v1 (fixed in v2), we used to have to make sure all certificates in this
          // Array were of SUNs own provider, using CertTools.SYSTEM_SECURITY_PROVIDER.
          // As of EJBCA 3.9.3 we decided that we don't have to support Glassfish v1 anymore.
          this.xKMScertificatechain = CertTools.getCertCollectionFromArray(keystore.getCertificateChain(PRIVATESIGNKEYALIAS), null);
          status = getStatus();
          try {
            if (!keystore.getCertificate(PRIVATESIGNKEYALIAS).getPublicKey().equals(((Certificate)this.xKMScertificatechain.get(0)).getPublicKey())) {
              m_log.error("Keystore does not hold the same public key as XKMS service certificate.");
            }
          } catch (Exception e2) {
            m_log.error("Could not compare public keys. " + e2.getMessage());
          }
        } catch (Exception e) {
          m_log.error("Could not load keystore or certificate for CA XKMS service. Perhaps the password was changed? " + e.getMessage());
        } finally {
          this.info = new XKMSCAServiceInfo(status, getSubjectDN(), getSubjectAltName(), (String)data.get(KEYSPEC),
              (String) data.get(KEYALGORITHM), this.xKMScertificatechain);
        }
        data.put(EXTENDEDCASERVICETYPE, Integer.valueOf(ExtendedCAServiceInfo.TYPE_XKMSEXTENDEDSERVICE));       
      }
    }
   
    @Override
    public void init(final CA ca) throws Exception {
      m_log.trace(">init");
      // lookup keystore passwords     
      final String keystorepass = StringTools.passwordDecryption(EjbcaConfiguration.getCaXkmsKeyStorePass(), "ca.xkmskeystorepass");
      // Currently only RSA keys are supported
      final XKMSCAServiceInfo info = (XKMSCAServiceInfo) getExtendedCAServiceInfo();      
      // Create XKMS KeyStore     
      final KeyStore keystore = KeyStore.getInstance("PKCS12", "BC");
      keystore.load(null, null);                             
      final KeyPair xKMSkeys = KeyTools.genKeys(info.getKeySpec(), info.getKeyAlgorithm());
      final UserDataVO user = new UserDataVO("NOUSERNAME", info.getSubjectDN(), 0, info.getSubjectAltName(), "NOEMAIL", 0,0,0,0, null,null,0,0,null);
      final Certificate xKMSCertificate = ca.generateCertificate(user, xKMSkeys.getPublic(),
          -1, // KeyUsage
          ca.getValidity(), new XKMSCertificateProfile(),
          null // sequence
      );
      xKMScertificatechain = new ArrayList<Certificate>();
      xKMScertificatechain.add(xKMSCertificate);
      xKMScertificatechain.addAll(ca.getCertificateChain());
      this.xKMSkey = xKMSkeys.getPrivate();           
      keystore.setKeyEntry(PRIVATESIGNKEYALIAS,xKMSkeys.getPrivate(), null, (Certificate[]) xKMScertificatechain.toArray(new Certificate[xKMScertificatechain.size()]));             
      final ByteArrayOutputStream baos = new ByteArrayOutputStream();
      keystore.store(baos, keystorepass.toCharArray());
      data.put(XKMSKEYSTORE, new String(Base64.encode(baos.toByteArray())));     
      // Store XKMS KeyStore
      setStatus(info.getStatus());
      this.info = new XKMSCAServiceInfo(info.getStatus(), getSubjectDN(), getSubjectAltName(), (String)data.get(KEYSPEC), (String) data.get(KEYALGORITHM), xKMScertificatechain);
      m_log.trace("<init");
    }  

    @Override
    public void update(final ExtendedCAServiceInfo serviceinfo, final CA ca) throws Exception {
      final XKMSCAServiceInfo info = (XKMSCAServiceInfo) serviceinfo;
      m_log.trace(">update: " + serviceinfo.getStatus());
      setStatus(serviceinfo.getStatus());
      if (info.getRenewFlag()) {
        // Renew The XKMS Signers certificate.
        this.init(ca);
      }
      // Only status is updated
      this.info = new XKMSCAServiceInfo(serviceinfo.getStatus(), getSubjectDN(), getSubjectAltName(), (String) data.get(KEYSPEC), (String) data.get(KEYALGORITHM), xKMScertificatechain);                                                                         
      m_log.trace("<update: " + serviceinfo.getStatus());
    }

    @Override
  public ExtendedCAServiceResponse extendedService(final ExtendedCAServiceRequest request) throws ExtendedCAServiceRequestException, IllegalExtendedCAServiceRequestException,ExtendedCAServiceNotActiveException {
        m_log.trace(">extendedService");
        if (!(request instanceof XKMSCAServiceRequest)) {
            throw new IllegalExtendedCAServiceRequestException();           
        }
        if (this.getStatus() != ExtendedCAServiceInfo.STATUS_ACTIVE) {
      String msg = intres.getLocalizedMessage("caservice.notactive");
      m_log.error(msg);
      throw new ExtendedCAServiceNotActiveException(msg);                           
        }
        ExtendedCAServiceResponse returnval = null;
        final X509Certificate signerCert = (X509Certificate) xKMScertificatechain.get(0);
        final XKMSCAServiceRequest xKMSServiceReq = (XKMSCAServiceRequest)request;
        final Document doc = xKMSServiceReq.getDoc();
        if (xKMSServiceReq.isSign()) {
          try {
        XMLSignature xmlSig = new XMLSignature(doc, "", XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1, Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
        Transforms transforms = new Transforms(doc);
        transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
        transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
        xmlSig.addDocument("#" + xKMSServiceReq.getId(), transforms, Constants.ALGO_ID_DIGEST_SHA1);             
        xmlSig.addKeyInfo(signerCert);
        doc.getDocumentElement().insertBefore(xmlSig.getElement() ,doc.getDocumentElement().getFirstChild());
        xmlSig.sign(xKMSkey);
            returnval = new XKMSCAServiceResponse(doc);
          } catch (XMLSignatureException e) {
            throw new ExtendedCAServiceRequestException(e);
      } catch (XMLSecurityException e) {
        throw new ExtendedCAServiceRequestException(e);
      }
        }
        m_log.trace("<extendedService");         
    return returnval;
    }

    @Override
  public float getLatestVersion() {   
      return LATEST_VERSION;
  }

    @Override
  public void upgrade() {
      if (Float.compare(LATEST_VERSION, getVersion()) != 0) {
        // New version of the class, upgrade
        data.put(ExtendedCAServiceInfo.IMPLEMENTATIONCLASS, this.getClass().getName())// For integration with CESeCore
        data.put(VERSION, new Float(LATEST_VERSION));
      }     
  }

    @Override
  public ExtendedCAServiceInfo getExtendedCAServiceInfo() {     
      if (info == null) {
        info = new XKMSCAServiceInfo(getStatus(), getSubjectDN(), getSubjectAltName(), (String) data.get(KEYSPEC), (String) data.get(KEYALGORITHM), xKMScertificatechain);
      }
      return info;
    }

  private String getSubjectDN() {
    String retval = null;
    final String str = (String)data.get(SUBJECTDN);
     try {
      retval = new String(Base64.decode((str).getBytes("UTF-8")));
    } catch (UnsupportedEncodingException e) {
      m_log.error("Could not decode XKMS data from Base64",e);
    } catch (ArrayIndexOutOfBoundsException e) {
      // This is an old CA, where it's not Base64encoded
      m_log.debug("Old non base64 encoded DN: "+str);
      retval = str;
    }
    return retval;    
  }
   
  private void setSubjectDN(final String dn) {
    try {
      data.put(SUBJECTDN,new String(Base64.encode(dn.getBytes("UTF-8"),false)));
    } catch (UnsupportedEncodingException e) {
      m_log.error("Could not encode XKMS data from Base64",e);
    }
  }
 
  private String getSubjectAltName() {
    String retval = null;
    final String str = (String) data.get(SUBJECTALTNAME);
     try {
      retval = new String(Base64.decode((str).getBytes("UTF-8")));
    } catch (UnsupportedEncodingException e) {
      m_log.error("Could not decode XKMS data from Base64",e);
    } catch (ArrayIndexOutOfBoundsException e) {
      // This is an old CA, where it's not Base64encoded
      m_log.debug("Old non base64 encoded altname: "+str);
      retval = str;
    }
    return retval;    
  }
   
  private void setSubjectAltName(final String dn) {
    try {
      data.put(SUBJECTALTNAME,new String(Base64.encode(dn.getBytes("UTF-8"), false)));
    } catch (UnsupportedEncodingException e) {
      m_log.error("Could not encode XKMS data from Base64",e);
    }
  }
}
TOP

Related Classes of org.ejbca.core.model.ca.caadmin.extendedcaservices.XKMSCAService

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.