org.votingsystem.signature.util.CertUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.votingsystem.signature.util.CertUtils.java

Source

package org.votingsystem.signature.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.jce.PrincipalUtil;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.openssl.PasswordFinder;
import org.bouncycastle.x509.X509V1CertificateGenerator;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
import org.bouncycastle.x509.extension.X509ExtensionUtil;
import org.votingsystem.throwable.ExceptionVS;
import org.votingsystem.util.ContextVS;
import org.votingsystem.util.JSON;

import javax.security.auth.x500.X500Principal;
import java.io.*;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.*;
import java.security.cert.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* License: https://github.com/votingsystem/votingsystem/wiki/Licencia
* http://www.amazon.com/exec/obidos/redirect?path=ASIN/0764596330&link_code=as2&camp=1789&tag=bouncycastleo-20&creative=9325
*/
public class CertUtils {

    private static Logger log = java.util.logging.Logger.getLogger(CertUtils.class.getSimpleName());

    /**
     * Generate V3 certificate for users
     */
    public static X509Certificate generateEndEntityCert(PublicKey entityKey, PrivateKey caKey,
            X509Certificate caCert, Date dateBegin, Date dateFinish, String endEntitySubjectDN) throws Exception {
        X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
        certGen.setSerialNumber(KeyGeneratorVS.INSTANCE.getSerno());
        certGen.setIssuerDN(PrincipalUtil.getSubjectX509Principal(caCert));
        certGen.setNotBefore(dateBegin);
        certGen.setNotAfter(dateFinish);
        certGen.setSubjectDN(new X500Principal(endEntitySubjectDN));
        certGen.setPublicKey(entityKey);
        certGen.setSignatureAlgorithm(ContextVS.CERT_GENERATION_SIG_ALGORITHM);
        certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
                new AuthorityKeyIdentifierStructure(caCert));
        certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
                new SubjectKeyIdentifierStructure(entityKey));
        certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
        certGen.addExtension(X509Extensions.KeyUsage, true,
                new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
        return certGen.generate(caKey, ContextVS.PROVIDER);
    }

    /**
     * Generate V3 certificate for root CA Authority
     */
    public static X509Certificate generateV3RootCert(KeyPair pair, Date dateBegin, Date dateFinish,
            String strSubjectDN) throws Exception {
        X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
        log.info("strSubjectDN: " + strSubjectDN);
        X509Principal x509Principal = new X509Principal(strSubjectDN);
        certGen.setSerialNumber(KeyGeneratorVS.INSTANCE.getSerno());
        certGen.setIssuerDN(x509Principal);
        certGen.setNotBefore(dateBegin);
        certGen.setNotAfter(dateFinish);
        log.info("dateBegin: " + dateBegin.toString() + " - dateFinish: " + dateFinish.toString());
        certGen.setSubjectDN(x509Principal);
        certGen.setPublicKey(pair.getPublic());
        certGen.setSignatureAlgorithm(ContextVS.CERT_GENERATION_SIG_ALGORITHM);
        //The following fragment shows how to create one which indicates that 
        //the certificate containing it is a CA and that only one certificate can follow in the certificate path.
        certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true, 0));
        certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
                new SubjectKeyIdentifierStructure(pair.getPublic()));
        certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign));
        return certGen.generate(pair.getPrivate(), ContextVS.PROVIDER);
    }

    /**
     * Generate V1 certificate for root CA Authority
     */
    public static X509Certificate generateV1RootCert(KeyPair pair, long comienzo, int period, String principal)
            throws Exception {
        X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
        certGen.setSerialNumber(KeyGeneratorVS.INSTANCE.getSerno());
        certGen.setIssuerDN(new X500Principal(principal));
        certGen.setNotBefore(new Date(comienzo));
        certGen.setNotAfter(new Date(comienzo + period));
        certGen.setSubjectDN(new X500Principal(principal));
        certGen.setPublicKey(pair.getPublic());
        certGen.setSignatureAlgorithm(ContextVS.CERT_GENERATION_SIG_ALGORITHM);
        return certGen.generate(pair.getPrivate(), ContextVS.PROVIDER);
    }

    /**
     * Generate V3 certificate for TimeStamp signing
     */
    public static X509Certificate generateTimeStampingCert(PublicKey entityKey, PrivateKey caKey,
            X509Certificate caCert, long begin, long period, String endEntitySubjectDN) throws Exception {
        X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
        certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
        certGen.setIssuerDN(PrincipalUtil.getSubjectX509Principal(caCert));
        certGen.setNotBefore(new Date(begin));
        certGen.setNotAfter(new Date(begin + period));
        certGen.setSubjectDN(new X500Principal(endEntitySubjectDN));
        certGen.setPublicKey(entityKey);
        certGen.setSignatureAlgorithm(ContextVS.CERT_GENERATION_SIG_ALGORITHM);
        certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
                new AuthorityKeyIdentifierStructure(caCert));
        certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
                new SubjectKeyIdentifierStructure(entityKey));
        certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
        certGen.addExtension(X509Extensions.KeyUsage, true,
                new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
        certGen.addExtension(X509Extensions.ExtendedKeyUsage, true,
                new ExtendedKeyUsage(new DERSequence(KeyPurposeId.id_kp_timeStamping)));
        return certGen.generate(caKey, ContextVS.PROVIDER);
    }

    /**
     * Generate V3 Certificate from CSR
     */
    public static X509Certificate signCSR(PKCS10CertificationRequest csr, String organizationalUnit,
            PrivateKey caKey, X509Certificate caCert, Date dateBegin, Date dateFinish,
            DERTaggedObject... certExtensions) throws Exception {
        String strSubjectDN = csr.getCertificationRequestInfo().getSubject().toString();
        if (!csr.verify() || strSubjectDN == null)
            throw new Exception("ERROR VERIFYING CSR");
        if (organizationalUnit != null)
            strSubjectDN = organizationalUnit + "," + strSubjectDN;
        X509Certificate issuedCert = generateV3EndEntityCertFromCsr(csr, caKey, caCert, dateBegin, dateFinish,
                strSubjectDN, certExtensions);
        return issuedCert;
    }

    /**
     * Generate V3 Certificate from CSR
     */
    public static X509Certificate generateV3EndEntityCertFromCsr(PKCS10CertificationRequest csr, PrivateKey caKey,
            X509Certificate caCert, Date dateBegin, Date dateFinish, String strSubjectDN,
            DERTaggedObject... certExtensions) throws Exception {
        X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
        PublicKey requestPublicKey = csr.getPublicKey();
        X509Principal x509Principal = new X509Principal(strSubjectDN);
        certGen.setSerialNumber(KeyGeneratorVS.INSTANCE.getSerno());
        log.info("generateV3EndEntityCertFromCsr - SubjectX500Principal(): " + caCert.getSubjectX500Principal());
        certGen.setIssuerDN(PrincipalUtil.getSubjectX509Principal(caCert));
        certGen.setNotBefore(dateBegin);
        certGen.setNotAfter(dateFinish);
        certGen.setSubjectDN(x509Principal);
        certGen.setPublicKey(requestPublicKey);
        certGen.setSignatureAlgorithm(ContextVS.CERT_GENERATION_SIG_ALGORITHM);
        certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
                new AuthorityKeyIdentifierStructure(caCert));
        certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
                new SubjectKeyIdentifierStructure(requestPublicKey));
        certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));//Certificado final
        certGen.addExtension(X509Extensions.KeyUsage, true,
                new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
        ASN1Set attributes = csr.getCertificationRequestInfo().getAttributes();
        if (attributes != null) {
            for (int i = 0; i != attributes.size(); i++) {
                if (attributes.getObjectAt(i) instanceof DERTaggedObject) {
                    DERTaggedObject taggedObject = (DERTaggedObject) attributes.getObjectAt(i);
                    ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(
                            ContextVS.VOTING_SYSTEM_BASE_OID + taggedObject.getTagNo());
                    certGen.addExtension(oid, true, taggedObject);
                } else {
                    Attribute attr = Attribute.getInstance(attributes.getObjectAt(i));
                    if (attr.getAttrType().equals(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest)) {
                        X509Extensions extensions = X509Extensions.getInstance(attr.getAttrValues().getObjectAt(0));
                        Enumeration e = extensions.oids();
                        while (e.hasMoreElements()) {
                            DERObjectIdentifier oid = (DERObjectIdentifier) e.nextElement();
                            X509Extension ext = extensions.getExtension(oid);
                            certGen.addExtension(oid, ext.isCritical(), ext.getValue().getOctets());
                        }
                    }
                }
            }
        }
        if (certExtensions != null) {
            for (DERTaggedObject taggedObject : certExtensions) {
                if (taggedObject != null) {
                    ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(
                            ContextVS.VOTING_SYSTEM_BASE_OID + taggedObject.getTagNo());
                    certGen.addExtension(oid, true, taggedObject);
                }
                log.log(Level.FINE, "null taggedObject");
            }
        }
        X509Certificate cert = certGen.generate(caKey, ContextVS.PROVIDER);
        cert.verify(caCert.getPublicKey());
        return cert;
    }

    public static byte[] getPEMEncoded(Object objectToEncode) throws IOException {
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        PEMWriter pemWrt = new PEMWriter(new OutputStreamWriter(bOut));
        if (objectToEncode instanceof Collection) {
            Collection objectToEncodeColection = ((Collection) objectToEncode);
            for (Object object : objectToEncodeColection) {
                pemWrt.writeObject(object);
            }
        } else
            pemWrt.writeObject(objectToEncode);
        pemWrt.close();
        bOut.close();
        return bOut.toByteArray();
    }

    public static PKCS10CertificationRequest fromPEMToPKCS10CertificationRequest(byte[] csrBytes) throws Exception {
        PEMReader pemReader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(csrBytes)));
        PKCS10CertificationRequest result = (PKCS10CertificationRequest) pemReader.readObject();
        pemReader.close();
        return result;
    }

    public static X509Certificate fromPEMToX509Cert(byte[] pemFileBytes) throws Exception {
        InputStream in = new ByteArrayInputStream(pemFileBytes);
        CertificateFactory fact = CertificateFactory.getInstance("X.509", ContextVS.PROVIDER);
        X509Certificate x509Cert = (X509Certificate) fact.generateCertificate(in);
        in.close();
        return x509Cert;
    }

    public static PrivateKey fromPEMToRSAPrivateKey(File file) throws Exception {
        BufferedReader br = new BufferedReader(new FileReader(file));
        KeyPair kp = (KeyPair) new PEMReader(br).readObject();
        br.close();
        return kp.getPrivate();
    }

    public static PrivateKey fromPEMToRSAPrivateKey(File file, PasswordFinder pFinder) throws Exception {
        BufferedReader br = new BufferedReader(new FileReader(file));
        KeyPair kp = (KeyPair) new PEMReader(br, pFinder).readObject();
        br.close();
        return kp.getPrivate();
    }

    public static Collection<X509Certificate> fromPEMToX509CertCollection(byte[] pemChainFileBytes)
            throws Exception {
        InputStream in = new ByteArrayInputStream(pemChainFileBytes);
        CertificateFactory fact = CertificateFactory.getInstance("X.509", ContextVS.PROVIDER);
        Collection<X509Certificate> x509Certs = (Collection<X509Certificate>) fact.generateCertificates(in);
        in.close();
        return x509Certs;
    }

    public static X509Certificate loadCertificate(byte[] certBytes) throws Exception {
        ByteArrayInputStream inputStream = new ByteArrayInputStream(certBytes);
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        Collection<X509Certificate> certificateChain = (Collection<X509Certificate>) certificateFactory
                .generateCertificates(inputStream);
        X509Certificate x509Cert = certificateChain.iterator().next();
        inputStream.close();
        return x509Cert;
    }

    /**
     *
     * Verifies the validity of the given certificate, checking its signature
     * against the issuer's certificate.
     *
     * @param certs the certificate list to validate
     * @param anchors Set of trusted (usually self-signed) certificates.
     * @param checkCRL boolean to tell system to check or not check CRL's
     *
     * @return result CertUtils.CertValidatorResultVS if the certificate's signature is valid otherwise throws ExceptionVS.
     */
    public static CertValidatorResultVS verifyCertificate(Set<TrustAnchor> anchors, boolean checkCRL,
            List<X509Certificate> certs) throws ExceptionVS {
        return verifyCertificate(anchors, checkCRL, certs, new Date());
    }

    public static CertValidatorResultVS verifyCertificate(Set<TrustAnchor> anchors, boolean checkCRL,
            List<X509Certificate> certs, Date signingDate) throws ExceptionVS {
        try {
            PKIXParameters pkixParameters = new PKIXParameters(anchors);
            pkixParameters.setDate(signingDate);
            CertExtensionCheckerVS checker = new CertExtensionCheckerVS();
            pkixParameters.addCertPathChecker(checker);
            pkixParameters.setRevocationEnabled(checkCRL); // if false tell system do not check CRL's
            CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX", ContextVS.PROVIDER);
            CertificateFactory certFact = CertificateFactory.getInstance("X.509");
            CertPath certPath = certFact.generateCertPath(certs);
            CertPathValidatorResult result = certPathValidator.validate(certPath, pkixParameters);
            // Get the CA used to validate this path
            //PKIXCertPathValidatorResult pkixResult = (PKIXCertPathValidatorResult)result;
            //TrustAnchor ta = pkixResult.getTrustAnchor();
            //X509Certificate certCaResult = ta.getTrustedCert();
            //log.info("certCaResult: " + certCaResult.getSubjectDN().toString()+
            //        "- serialNumber: " + certCaResult.getSerialNumber().longValue());
            return new CertValidatorResultVS(checker, (PKIXCertPathValidatorResult) result);
        } catch (Exception ex) {
            String msg = "Empty cert list";
            if (certs != null && !certs.isEmpty())
                msg = ex.getMessage() + " - cert: " + certs.iterator().next().getSubjectDN();
            throw new ExceptionVS(msg, ex);
        }
    }

    /**
     * Checks whether given X.509 certificate is self-signed.
     * 
     * http://www.nakov.com/blog/2009/12/01/x509-certificate-validation-in-java-build-and-verify-chain-and-verify-clr-with-bouncy-castle/
     */
    public static boolean isSelfSigned(X509Certificate cert)
            throws CertificateException, NoSuchAlgorithmException, NoSuchProviderException {
        try {
            // Try to verify certificate signature with its own public key
            PublicKey key = cert.getPublicKey();
            cert.verify(key);
            return true;
        } catch (SignatureException sigEx) {
            // Invalid signature --> not self-signed
            return false;
        } catch (InvalidKeyException keyEx) {
            // Invalid key --> not self-signed
            return false;
        }
    }

    /**
     * Downloads a CRL from given HTTP/HTTPS/FTP URL, e.g.
     * http://crl.infonotary.com/crl/identity-ca.crl
     * 
     * http://www.nakov.com/blog/2009/12/01/x509-certificate-validation-in-java-build-and-verify-chain-and-verify-clr-with-bouncy-castle/
     */
    public static X509CRL downloadCRLFromWeb(String crlURL)
            throws MalformedURLException, IOException, CertificateException, CRLException {
        URL url = new URL(crlURL);
        InputStream crlStream = url.openStream();
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509CRL crl = (X509CRL) cf.generateCRL(crlStream);
            return crl;
        } finally {
            crlStream.close();
        }
    }

    public static DERObject toDERObject(byte[] data) throws IOException, IOException {
        ByteArrayInputStream inStream = new ByteArrayInputStream(data);
        ASN1InputStream DIS = new ASN1InputStream(inStream);
        return DIS.readObject();
    }

    public static Map<String, String> getCertExtensionData(X509Certificate x509Certificate, String extensionOID)
            throws IOException {
        byte[] extensionValue = x509Certificate.getExtensionValue(extensionOID);
        if (extensionValue == null)
            return null;
        DERTaggedObject derTaggedObject = (DERTaggedObject) X509ExtensionUtil.fromExtensionValue(extensionValue);
        return new ObjectMapper().readValue(((DERUTF8String) derTaggedObject.getObject()).getString(),
                new TypeReference<HashMap<String, String>>() {
                });
    }

    public static <T> T getCertExtensionData(Class<T> type, X509Certificate x509Certificate, String extensionOID)
            throws Exception {
        byte[] extensionValue = x509Certificate.getExtensionValue(extensionOID);
        if (extensionValue == null)
            return null;
        DERTaggedObject derTaggedObject = (DERTaggedObject) X509ExtensionUtil.fromExtensionValue(extensionValue);
        String extensionData = ((DERUTF8String) derTaggedObject.getObject()).getString();
        return JSON.getMapper().readValue(extensionData, type);
    }

    public static String getHashCertVS(X509Certificate x509Cert, String oid) throws IOException {
        Map<String, String> map = getCertExtensionData(x509Cert, oid);
        return map.get("hashCertVS");
    }

    public static class CertValidatorResultVS {
        CertExtensionCheckerVS checker;
        PKIXCertPathValidatorResult result;

        public CertValidatorResultVS(CertExtensionCheckerVS checker, PKIXCertPathValidatorResult result) {
            this.checker = checker;
            this.result = result;
        }

        public CertExtensionCheckerVS getChecker() {
            return checker;
        }

        public PKIXCertPathValidatorResult getResult() {
            return result;
        }
    }

}