ec.gov.informatica.firmadigital.signature.BouncyCastleSignatureProcessor.java Source code

Java tutorial

Introduction

Here is the source code for ec.gov.informatica.firmadigital.signature.BouncyCastleSignatureProcessor.java

Source

/*
 * Copyright (C) 2009 Libreria para Firma Digital development team.
 * 
 * This library 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 (at your option) any later version.
 */
package ec.gov.informatica.firmadigital.signature;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSProcessable;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.NoSuchStoreException;
import org.bouncycastle.x509.X509Store;

import ec.gov.informatica.firmadigital.DatosUsuario;

/**
 * Implementacion de SignatureProcessor que utliza BouncyCastle para implementar
 * firma en formato CMS.
 * 
 * @author Ricardo Arguello <ricardo.arguello@soportelibre.com>
 * @version $Revision: 15 $
 */
public class BouncyCastleSignatureProcessor implements CMSSignatureProcessor {

    private KeyStore keyStore;
    private X509Certificate cert;

    public X509Certificate getCert() {
        return cert;
    }

    public void setCert(X509Certificate cert) {
        this.cert = cert;
    }

    public BouncyCastleSignatureProcessor(KeyStore keyStore) {
        this.keyStore = keyStore;
        Security.addProvider(new BouncyCastleProvider());
    }

    public byte[] sign(byte[] data, PrivateKey privateKey, Certificate[] chain) {
        X509Certificate cert = (X509Certificate) chain[0];
        try {
            CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
            generator.addSigner(privateKey, cert, CMSSignedDataGenerator.DIGEST_SHA1);

            CertStore certsAndCRLS = CertStore.getInstance("Collection",
                    new CollectionCertStoreParameters(Arrays.asList(chain)));
            generator.addCertificatesAndCRLs(certsAndCRLS);

            CMSProcessable content = new CMSProcessableByteArray(data);
            CMSSignedData signedData = generator.generate(content, true, keyStore.getProvider().getName());

            return signedData.getEncoded();
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e); // FIXME

        } catch (CMSException e) {
            throw new RuntimeException(e); // FIXME

        } catch (IOException e) {
            throw new RuntimeException(e); // FIXME

        }
    }

    public byte[] verify(byte[] signedBytes) throws SignatureVerificationException {
        try {
            Signature sig = Signature.getInstance("Sha1withRSAEncryption");
            CMSSignedData signedData = new CMSSignedData(signedBytes);
            CertStore certs = signedData.getCertificatesAndCRLs("Collection", "BC");
            Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners();
            for (SignerInformation signer : signers) {
                Collection<? extends Certificate> certCollection = certs.getCertificates(signer.getSID());
                if (!certCollection.isEmpty()) {
                    X509Certificate cert = (X509Certificate) certCollection.iterator().next();
                    if (!signer.verify(cert.getPublicKey(), "BC")) {
                        throw new SignatureVerificationException("La firma no verifico con " + signer.getSID());
                    }
                    setCert(cert);
                }
            }

            CMSProcessable signedContent = signedData.getSignedContent();
            System.out.println("Tiene:" + signedContent.getContent());
            return (byte[]) signedContent.getContent();
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e); // FIXME

        } catch (CMSException e) {
            throw new RuntimeException(e); // FIXME

        }
    }

    @Override
    public byte[] addSignature(byte[] signedBytes, PrivateKey privateKey, Certificate[] chain) {
        X509Certificate cert = (X509Certificate) chain[0];

        try {
            CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
            generator.addSigner(privateKey, cert, CMSSignedDataGenerator.DIGEST_SHA1);

            CertStore certs = CertStore.getInstance("Collection",
                    new CollectionCertStoreParameters(Arrays.asList(chain)));

            CMSSignedData signedData = new CMSSignedData(signedBytes);
            SignerInformationStore signers = signedData.getSignerInfos();
            CertStore existingCerts = signedData.getCertificatesAndCRLs("Collection", "BC");
            X509Store x509Store = signedData.getAttributeCertificates("Collection", "BC");

            // add new certs
            generator.addCertificatesAndCRLs(certs);
            // add existing certs
            generator.addCertificatesAndCRLs(existingCerts);
            // add existing certs attributes
            generator.addAttributeCertificates(x509Store);
            // add existing signers
            generator.addSigners(signers);

            CMSProcessable content = signedData.getSignedContent();
            signedData = generator.generate(content, true, "BC");
            return signedData.getEncoded();
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        } catch (CMSException e) {
            throw new RuntimeException(e);
        } catch (NoSuchStoreException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     *  <code> crearDatosUsuario </code>
     * @param signingCert
     * @return
     * Esta funcion llena los datos del usuario encontrados en el certificado
     */
    private DatosUsuario crearDatosUsuario(X509Certificate signingCert) {
        //        depuracionActual.info("Libreria: Esta en crearDatosUsuario : ");
        DatosUsuario datosUsuario = new DatosUsuario();
        if (signingCert.getExtensionValue("1.2.3.4.1") != null) {
            datosUsuario.setCedula(new String(signingCert.getExtensionValue("1.2.3.4.1")).trim());
        }
        if (signingCert.getExtensionValue("1.2.3.4.2") != null) {
            datosUsuario.setNombre(new String(signingCert.getExtensionValue("1.2.3.4.2")).trim());
        }
        if (signingCert.getExtensionValue("1.2.3.4.3") != null) {
            String txtNombre = new String(signingCert.getExtensionValue("1.2.3.4.3")).trim();
            if (signingCert.getExtensionValue("1.2.3.4.4") != null)
                txtNombre = txtNombre + " " + new String(signingCert.getExtensionValue("1.2.3.4.4")).trim();
            datosUsuario.setApellido(txtNombre);
        }
        if (signingCert.getExtensionValue("1.2.3.4.6") != null) {
            datosUsuario.setInstitucion(new String(signingCert.getExtensionValue("1.2.3.4.6")).trim());
        }
        if (signingCert.getExtensionValue("1.2.3.4.5") != null) {
            datosUsuario.setCargo(new String(signingCert.getExtensionValue("1.2.3.4.5")).trim());
        }

        if (signingCert.getSerialNumber() != null) {
            datosUsuario.setSerial(signingCert.getSerialNumber().toString());
        }

        if (signingCert.getExtensionValue("2.5.29.31") != null) {

            //Estas declaraciones buscan un atributo del Certificado (lista CRL) que permite buscar en revocados.
            byte[] val1 = signingCert.getExtensionValue("2.5.29.31");
            if (val1 == null) {
                if (signingCert.getSubjectDN().getName().equals(signingCert.getIssuerDN().getName())) {
                    System.out.println(
                            "El certificado es un certificado raiz: " + signingCert.getSubjectDN().getName());
                } else {
                    System.out.println("El certificado NO tiene punto de distribucin de CRL : "
                            + signingCert.getSubjectDN().getName());
                }
                //return Collections.emptyList();
            } else {
                //esta es la parte que deberas aumentar en si
                try {
                    ASN1InputStream oAsnInStream = new ASN1InputStream(new ByteArrayInputStream(val1));
                    DERObject derObj = oAsnInStream.readObject();
                    DEROctetString dos = (DEROctetString) derObj;
                    byte[] val2 = dos.getOctets();
                    ASN1InputStream oAsnInStream2 = new ASN1InputStream(new ByteArrayInputStream(val2));
                    DERObject derObj2 = oAsnInStream2.readObject();
                    List<String> urls = getDERValue(derObj2);

                    for (int j = 0; j < urls.size(); j++) {
                        datosUsuario.setCrl(urls.get(7));
                    }
                    //                datosUsuario.setCrl( new String(   distrPoint.substring( distrPoint.indexOf("U")+8, distrPoint.indexOf("ldap") - 8 )     ).trim() );     //distrPoint.substring( distrPoint.indexOf("U")+8, distrPoint.indexOf("U") + 12 )
                    System.out.println(urls);// .println(urls);
                } catch (Exception e) {
                    System.out.println("Error: " + e.getMessage());
                    e.printStackTrace();
                }
            } //fin else 

        }

        return datosUsuario;
    }

    /**
    * para parsear el objeto y te devuelve el listado con las urls de los puntos de distribucin
        
    * @param derObj
    * @return
    */

    @SuppressWarnings("unchecked")
    private List<String> getDERValue(DERObject derObj) {
        if (derObj instanceof DERSequence) {
            List<String> list = new LinkedList<String>();
            DERSequence seq = (DERSequence) derObj;
            Enumeration enumeracion = seq.getObjects();
            while (enumeracion.hasMoreElements()) {
                DERObject nestedObj = (DERObject) enumeracion.nextElement();
                List<String> appo = getDERValue(nestedObj);
                if (appo != null) {
                    list.addAll(appo);
                }
            }
            return list;
        } else if (derObj instanceof DERTaggedObject) {
            DERTaggedObject derTag = (DERTaggedObject) derObj;
            if ((derTag.isExplicit() && !derTag.isEmpty()) || derTag.getObject() instanceof DERSequence) {
                DERObject nestedObj = derTag.getObject();
                List<String> ret = getDERValue(nestedObj);
                return ret;
            } else {
                DEROctetString derOct = (DEROctetString) derTag.getObject();
                String val = new String(derOct.getOctets());
                List<String> ret = new LinkedList<String>();
                ret.add(val);
                return ret;
            }
        } else if (derObj instanceof DERSet) {
            Enumeration enumSet = ((DERSet) derObj).getObjects();
            List<String> list = new LinkedList<String>();
            while (enumSet.hasMoreElements()) {
                DERObject nestedObj = (DERObject) enumSet.nextElement();
                List<String> appo = getDERValue(nestedObj);
                if (appo != null) {
                    list.addAll(appo);
                }
            }
            return list;
        } else if (derObj instanceof DERObjectIdentifier) {
            DERObjectIdentifier derId = (DERObjectIdentifier) derObj;
            List<String> list = new LinkedList<String>();
            list.add(derId.getId());
            return list;
        } else if (derObj instanceof DERPrintableString) {
            // hemos localizado un par id-valor
            String valor = ((DERPrintableString) derObj).getString();
            List<String> list = new LinkedList<String>();
            list.add(valor);
            return list;
        } else {
            System.out.println("tipo de dato en ASN1 al recuperar las crls no es reconocido : " + derObj);
        }
        return null;
    }
}