be.fedict.eid.dss.model.bean.TrustValidationServiceBean.java Source code

Java tutorial

Introduction

Here is the source code for be.fedict.eid.dss.model.bean.TrustValidationServiceBean.java

Source

/*
 * eID Digital Signature Service Project.
 * Copyright (C) 2010-2011 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package be.fedict.eid.dss.model.bean;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.security.auth.x500.X500Principal;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.SignerId;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.ocsp.OCSPResp;
import org.bouncycastle.tsp.TimeStampResponse;
import org.bouncycastle.tsp.TimeStampToken;

import be.fedict.eid.dss.model.ConfigProperty;
import be.fedict.eid.dss.model.Configuration;
import be.fedict.eid.dss.model.TrustValidationService;
import be.fedict.trust.TrustValidator;
import be.fedict.trust.client.XKMS2Client;
import be.fedict.trust.client.exception.RevocationDataNotFoundException;
import be.fedict.trust.client.exception.TrustDomainNotFoundException;
import be.fedict.trust.client.exception.ValidationFailedException;
import org.bouncycastle.asn1.x500.X500Name;

@Stateless
public class TrustValidationServiceBean implements TrustValidationService {

    private static final Log LOG = LogFactory.getLog(TrustValidationServiceBean.class);

    @EJB
    private Configuration configuration;

    /**
     * {@inheritDoc}
     */
    public void validate(List<X509Certificate> certificateChain, Date validationDate, List<OCSPResp> ocspResponses,
            List<X509CRL> crls) throws CertificateEncodingException, TrustDomainNotFoundException,
            RevocationDataNotFoundException, ValidationFailedException {

        String verifyTrustDomain = this.configuration.getValue(ConfigProperty.VERIFY_TRUST_DOMAIN, String.class);

        LOG.debug("validating certificate chain");
        LOG.debug("number of CRLs: " + crls.size());
        LOG.debug("number of OCSPs: " + ocspResponses.size());
        getXkms2Client().validate(verifyTrustDomain, certificateChain, validationDate, ocspResponses, crls);
    }

    /**
     * {@inheritDoc}
     */
    public void validate(TimeStampToken timeStampToken) throws CertificateEncodingException,
            ValidationFailedException, TrustDomainNotFoundException, RevocationDataNotFoundException {

        String tsaTrustDomain = this.configuration.getValue(ConfigProperty.TSA_TRUST_DOMAIN, String.class);

        LOG.debug("validating timestamp token");
        getXkms2Client().validate(tsaTrustDomain, timeStampToken);
    }

    /**
     * {@inheritDoc}
     */
    public XKMS2Client getXkms2Client() {

        String xkmsUrl = this.configuration.getValue(ConfigProperty.XKMS_URL, String.class);
        XKMS2Client xkms2Client = new XKMS2Client(xkmsUrl);

        Boolean useHttpProxy = this.configuration.getValue(ConfigProperty.HTTP_PROXY_ENABLED, Boolean.class);
        if (null != useHttpProxy && useHttpProxy) {
            String httpProxyHost = this.configuration.getValue(ConfigProperty.HTTP_PROXY_HOST, String.class);
            int httpProxyPort = this.configuration.getValue(ConfigProperty.HTTP_PROXY_PORT, Integer.class);
            xkms2Client.setProxy(httpProxyHost, httpProxyPort);
        } else {
            // disable previously set proxy
            xkms2Client.setProxy(null, 0);
        }

        return xkms2Client;
    }

    public void validate(TimeStampToken timeStampToken, List<OCSPResp> ocspResponses, List<X509CRL> crls)
            throws CertificateEncodingException, TrustDomainNotFoundException, RevocationDataNotFoundException,
            ValidationFailedException, NoSuchAlgorithmException, NoSuchProviderException, CMSException,
            CertStoreException, IOException {
        LOG.debug("performing historical TSA validation...");
        String tsaTrustDomain = this.configuration.getValue(ConfigProperty.TSA_TRUST_DOMAIN, String.class);
        LOG.debug("TSA trust domain: " + tsaTrustDomain);

        Date validationDate = timeStampToken.getTimeStampInfo().getGenTime();
        LOG.debug("TSA validation date is TST time: " + validationDate);
        LOG.debug("# TSA ocsp responses: " + ocspResponses.size());
        LOG.debug("# TSA CRLs: " + crls.size());

        /*
         *Building TSA chain. (Code from eID-applet)
         * 
         */

        SignerId signerId = timeStampToken.getSID();
        BigInteger signerCertSerialNumber = signerId.getSerialNumber();
        //X500Principal signerCertIssuer = signerId.getIssuer();

        X500Principal signerCertIssuer = new X500Principal(signerId.getIssuer().getEncoded());

        LOG.debug("signer cert serial number: " + signerCertSerialNumber);
        LOG.debug("signer cert issuer: " + signerCertIssuer);

        // TSP signer certificates retrieval
        CertStore certStore = timeStampToken.getCertificatesAndCRLs("Collection",
                BouncyCastleProvider.PROVIDER_NAME);
        Collection<? extends Certificate> certificates = certStore.getCertificates(null);
        X509Certificate signerCert = null;
        Map<String, X509Certificate> certificateMap = new HashMap<String, X509Certificate>();
        for (Certificate certificate : certificates) {
            X509Certificate x509Certificate = (X509Certificate) certificate;
            if (signerCertIssuer.equals(x509Certificate.getIssuerX500Principal())
                    && signerCertSerialNumber.equals(x509Certificate.getSerialNumber())) {
                signerCert = x509Certificate;
            }
            String ski = Hex.encodeHexString(getSubjectKeyId(x509Certificate));
            certificateMap.put(ski, x509Certificate);
            LOG.debug("embedded certificate: " + x509Certificate.getSubjectX500Principal() + "; SKI=" + ski);
        }

        // TSP signer cert path building
        if (null == signerCert) {
            throw new RuntimeException("TSP response token has no signer certificate");
        }
        List<X509Certificate> tspCertificateChain = new LinkedList<X509Certificate>();

        X509Certificate tsaIssuer = loadCertificate(
                "be/fedict/eid/dss/CA POLITICA SELLADO DE TIEMPO - COSTA RICA.crt");
        X509Certificate rootCA = loadCertificate("be/fedict/eid/dss/CA RAIZ NACIONAL COSTA RICA.cer");
        LOG.debug("adding to certificate chain: " + signerCert.getSubjectX500Principal());
        tspCertificateChain.add(signerCert);
        LOG.debug("adding to certificate chain: " + tsaIssuer.getSubjectX500Principal());
        tspCertificateChain.add(tsaIssuer);
        LOG.debug("adding to certificate chain: " + rootCA.getSubjectX500Principal());
        tspCertificateChain.add(rootCA);

        /*
         * Perform PKI validation via eID Trust Service.
         */
        getXkms2Client().validate(tsaTrustDomain, tspCertificateChain, validationDate, ocspResponses, crls);
    }

    private static X509Certificate loadCertificate(String resourceName) {
        LOG.debug("loading certificate: " + resourceName);
        Thread currentThread = Thread.currentThread();
        ClassLoader classLoader = currentThread.getContextClassLoader();
        InputStream certificateInputStream = classLoader.getResourceAsStream(resourceName);
        if (null == certificateInputStream) {
            throw new IllegalArgumentException("resource not found: " + resourceName);
        }
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            return (X509Certificate) certificateFactory.generateCertificate(certificateInputStream);
        } catch (CertificateException e) {
            throw new RuntimeException("X509 error: " + e.getMessage(), e);
        }
    }

    private byte[] getSubjectKeyId(X509Certificate cert) throws IOException {
        byte[] extvalue = cert.getExtensionValue(X509Extensions.SubjectKeyIdentifier.getId());
        if (extvalue == null) {
            return null;
        }
        ASN1OctetString str = ASN1OctetString
                .getInstance(new ASN1InputStream(new ByteArrayInputStream(extvalue)).readObject());
        SubjectKeyIdentifier keyId = SubjectKeyIdentifier
                .getInstance(new ASN1InputStream(new ByteArrayInputStream(str.getOctets())).readObject());
        return keyId.getKeyIdentifier();
    }

    private byte[] getAuthorityKeyId(X509Certificate cert) throws IOException {
        byte[] extvalue = cert.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
        if (extvalue == null) {
            return null;
        }
        DEROctetString oct = (DEROctetString) (new ASN1InputStream(new ByteArrayInputStream(extvalue))
                .readObject());
        /*AuthorityKeyIdentifier keyId = new AuthorityKeyIdentifier(
                    (ASN1Sequence) new ASN1InputStream(new ByteArrayInputStream(
                                    oct.getOctets())).readObject());*/
        AuthorityKeyIdentifier keyId = new AuthorityKeyIdentifier(oct.getOctets());

        return keyId.getKeyIdentifier();
    }
}