de.mendelson.util.security.csr.CSRUtil.java Source code

Java tutorial

Introduction

Here is the source code for de.mendelson.util.security.csr.CSRUtil.java

Source

//$Header: /cvsroot/mec-as2/b47/de/mendelson/util/security/csr/CSRUtil.java,v 1.1 2015/01/06 11:08:02 heller Exp $
package de.mendelson.util.security.csr;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.StringWriter;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import javax.security.auth.x500.X500Principal;

import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.openssl.PEMWriter;

import de.mendelson.util.MecResourceBundle;
import de.mendelson.util.security.KeyStoreUtil;
import de.mendelson.util.security.cert.CertificateManager;

/*
 * Copyright (C) mendelson-e-commerce GmbH Berlin Germany
 *
 * This software is subject to the license agreement set forth in the license.
 * Please read and agree to all terms before using this software.
 * Other product and brand names are trademarks of their respective owners.
 */
/**
 * Handles csr related activities on a certificate
 * @author S.Heller
 * @version $Revision: 1.1 $
 */
public class CSRUtil {

    private MecResourceBundle rb;

    public CSRUtil() {
        //load resource bundle
        try {
            this.rb = (MecResourceBundle) ResourceBundle.getBundle(ResourceBundleCSRUtil.class.getName());
        } catch (MissingResourceException e) {
            throw new RuntimeException("Oops..resource bundle " + e.getClassName() + " not found.");
        }
    }

    /**
     * Generates a PKCS10 CertificationRequest. The passed private key must not be trusted
     */
    public PKCS10CertificationRequest generateCSR(PrivateKey key, X509Certificate cert) throws Exception {
        X509Name subject = new X509Name(cert.getSubjectDN().toString());
        PKCS10CertificationRequest csr = new PKCS10CertificationRequest(cert.getSigAlgName(), subject,
                cert.getPublicKey(), null, key);
        boolean verified = csr.verify();
        if (!verified) {
            throw new Exception(this.rb.getResourceString("verification.failed"));
        }
        return (csr);
    }

    /**
     * Generates a PKCS10 CertificationRequest. The passed private key must not be trusted
     */
    public PKCS10CertificationRequest generateCSR(CertificateManager manager, String alias) throws Exception {
        PrivateKey key = manager.getPrivateKey(alias);
        KeyStoreUtil keystoreUtil = new KeyStoreUtil();
        Certificate[] certchain = manager.getCertificateChain(alias);
        X509Certificate[] x509Certchain = new X509Certificate[certchain.length];
        for (int i = 0; i < certchain.length; i++) {
            x509Certchain[i] = (X509Certificate) certchain[i];
        }
        x509Certchain = keystoreUtil.orderX509CertChain(x509Certchain);
        PKCS10CertificationRequest csr = this.generateCSR(key, x509Certchain[0]);
        return (csr);
    }

    /**Writes the CSR to a string*/
    public String storeCSRPEM(PKCS10CertificationRequest csr) throws Exception {
        PEMWriter pemWriter = null;
        StringWriter stringWriter = new StringWriter();
        ;
        try {
            pemWriter = new PEMWriter(stringWriter);
            pemWriter.writeObject(csr);
            pemWriter.flush();
        } finally {
            if (pemWriter != null) {
                pemWriter.close();
            }
        }
        return (stringWriter.toString());
    }

    /**Writes a csr to a file, PEM encoded*/
    public void storeCSRPEM(PKCS10CertificationRequest csr, File outFile) throws Exception {
        PEMWriter pemWriter = null;
        try {
            pemWriter = new PEMWriter(new FileWriter(outFile));
            pemWriter.writeObject(csr);
            pemWriter.flush();
        } finally {
            if (pemWriter != null) {
                pemWriter.close();
            }
        }
    }

    /**
     * Imports the answer of the CA which looks like a certificate. The patched certificate will be 
     * updated with the cert chain that is included in the returned signed certificate.
     *
     */
    public boolean importCSRReply(CertificateManager manager, String alias, File csrResponseFile) throws Throwable {
        PrivateKey key = manager.getPrivateKey(alias);
        PublicKey publicKey = manager.getPublicKey(alias);
        // Load certificates found in the PEM(!) encoded answer
        List<X509Certificate> responseCertList = new ArrayList<X509Certificate>();
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(csrResponseFile);
            for (Certificate responseCert : CertificateFactory.getInstance("X509")
                    .generateCertificates(inputStream)) {
                responseCertList.add((X509Certificate) responseCert);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
        if (responseCertList.isEmpty()) {
            throw new Exception(this.rb.getResourceString("no.certificates.in.reply"));
        }
        PublicKey responsePublicKey = responseCertList.get(responseCertList.size() - 1).getPublicKey();
        if (!publicKey.equals(responsePublicKey)) {
            throw new Exception(this.rb.getResourceString("response.public.key.does.not.match"));
        }
        List<X509Certificate> newCerts;
        if (responseCertList.size() == 1) {
            // Reply has only one certificate
            newCerts = this.buildNewTrustChain(manager, responseCertList.get(0));
        } else {
            // Reply has a chain of certificates
            newCerts = this.validateReply(responseCertList);
        }
        if (newCerts != null) {
            manager.setKeyEntry(alias, key, newCerts.toArray(new X509Certificate[newCerts.size()]));
            return true;
        } else {
            return false;
        }
    }

    private List<X509Certificate> buildNewTrustChain(CertificateManager manager, X509Certificate certReply)
            throws Exception {
        Map<X500Principal, List<X509Certificate>> knownCerts = manager.getIssuerCertificateMap();
        LinkedList<X509Certificate> newTrustChain = new LinkedList<X509Certificate>();
        this.buildNewTrustChainRecursive(manager, certReply, newTrustChain, knownCerts);
        return (newTrustChain);
    }

    /**
     * Builds a new certificate chain from the answer
     */
    private void buildNewTrustChainRecursive(CertificateManager manager, X509Certificate certificate,
            LinkedList<X509Certificate> newTrustChain,
            Map<X500Principal, List<X509Certificate>> availableCertificates) throws Exception {
        X500Principal subject = certificate.getSubjectX500Principal();
        X500Principal issuer = certificate.getIssuerX500Principal();
        // Check if the certificate is a root certificate (i.e. was issued by the same Principal that
        // is present in the subject)
        if (subject.equals(issuer)) {
            newTrustChain.addFirst(certificate);
            return;
        }
        // Get the list of known certificates of the certificate's issuer
        List<X509Certificate> issuerCerts = availableCertificates.get(issuer);
        if (issuerCerts == null || issuerCerts.isEmpty()) {
            // A certificate is in the chain that is missing in the available certificates -> has to be imported first
            throw new Exception(this.rb.getResourceString("missing.cert.in.trustchain", issuer));
        }
        for (X509Certificate issuerCert : issuerCerts) {
            PublicKey publickey = issuerCert.getPublicKey();
            // Verify the certificate with the specified public key
            certificate.verify(publickey);
            this.buildNewTrustChainRecursive(manager, issuerCert, newTrustChain, availableCertificates);
        }
        newTrustChain.addFirst(certificate);
    }

    /**
     * Validates chain in certification reply, and returns the ordered
     * elements of the chain (with user certificate first, and root
     * certificate last in the array).
     *
     * @param alias the alias name
     * @param userCert the user certificate of the alias
     * @param replyCerts the chain provided in the reply
     */
    private List<X509Certificate> validateReply(List<X509Certificate> replyCerts) throws Exception {
        // order the certs in the reply (bottom-up).
        X509Certificate tmpCert = null;
        Principal issuer = replyCerts.get(0).getIssuerDN();
        for (int i = 1; i < replyCerts.size(); i++) {
            // find a cert in the reply whose "subject" is the same as the
            // given "issuer"
            int j;
            for (j = i; j < replyCerts.size(); j++) {
                Principal subject = replyCerts.get(j).getSubjectDN();
                if (subject.equals(issuer)) {
                    tmpCert = replyCerts.get(i);
                    replyCerts.set(i, replyCerts.get(j));
                    replyCerts.set(j, tmpCert);
                    issuer = replyCerts.get(i).getIssuerDN();
                    break;
                }
            }
            if (j == replyCerts.size()) {
                throw new Exception(this.rb.getResourceString("response.chain.incomplete"));
            }
        }
        // now verify each cert in the ordered chain
        for (int i = 0; i < replyCerts.size(); i++) {
            PublicKey pubKey = replyCerts.get(i + 1).getPublicKey();
            try {
                replyCerts.get(i).verify(pubKey);
            } catch (Exception e) {
                throw new Exception(this.rb.getResourceString("response.verification.failed", e.getMessage()));
            }
        }
        return replyCerts;
    }
}