be.fedict.trust.service.bean.TrustServiceTrustLinker.java Source code

Java tutorial

Introduction

Here is the source code for be.fedict.trust.service.bean.TrustServiceTrustLinker.java

Source

/*
 * eID Trust Service Project.
 * Copyright (C) 2009-2010 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.trust.service.bean;

import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URI;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.EntityManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import be.fedict.trust.RevocationData;
import be.fedict.trust.TrustLinker;
import be.fedict.trust.TrustLinkerResult;
import be.fedict.trust.TrustLinkerResultReason;
import be.fedict.trust.crl.CrlTrustLinker;
import be.fedict.trust.service.SnmpConstants;
import be.fedict.trust.service.dao.AuditDAO;
import be.fedict.trust.service.entity.CertificateAuthorityEntity;
import be.fedict.trust.service.entity.RevokedCertificateEntity;
import be.fedict.trust.service.entity.RevokedCertificatePK;
import be.fedict.trust.service.entity.Status;
import be.fedict.trust.service.snmp.SNMPInterceptor;

/**
 * Implementation of a trust linker based on the trust service infrastructure.
 * 
 * @author fcorneli
 */
public class TrustServiceTrustLinker implements TrustLinker {

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

    private final EntityManager entityManager;

    public TrustServiceTrustLinker(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public TrustLinkerResult hasTrustLink(X509Certificate childCertificate, X509Certificate certificate,
            Date validationDate, RevocationData revocationData) {

        LOG.debug("certificate: " + childCertificate.getSubjectX500Principal());
        LOG.debug("certificate Issuer: " + childCertificate.getIssuerX500Principal().toString());

        LOG.debug("Issuer: " + certificate.getSubjectX500Principal());

        BigInteger issuerSerialNumber = certificate.getSerialNumber();
        String key = new String();
        key += certificate.getSubjectX500Principal().toString() + "|" + issuerSerialNumber.toString();

        String issuerName = childCertificate.getIssuerX500Principal().toString();

        CertificateAuthorityEntity certificateAuthority = this.entityManager
                //.find(CertificateAuthorityEntity.class, issuerName);
                .find(CertificateAuthorityEntity.class, key);
        if (null == certificateAuthority) {
            LOG.debug("no data cache entry for CA: " + issuerName + " - Serial Number: "
                    + issuerSerialNumber.toString());
            /*
             * Cache Miss
             */
            SNMPInterceptor.increment(SnmpConstants.CACHE_MISSES, SnmpConstants.SNMP_SERVICE, 1L);

            /*
             * Lookup Root CA's trust point via parent certificates' CA entity.
             */
            String parentIssuerName = certificate.getIssuerX500Principal().toString();
            CertificateAuthorityEntity parentCertificateAuthority = this.entityManager
                    .find(CertificateAuthorityEntity.class, parentIssuerName);
            if (null == parentCertificateAuthority) {
                logAudit("CA not found for " + parentIssuerName);
                LOG.error("CA not found for " + parentIssuerName + " ?!");
                return null;
            }

            // create new CA
            try {
                certificateAuthority = new CertificateAuthorityEntity(getCrlUrl(childCertificate), certificate);
                certificateAuthority.setTrustPoint(parentCertificateAuthority.getTrustPoint());
            } catch (CertificateEncodingException e) {
                LOG.error("certificate encoding error: " + e.getMessage(), e);
                return null;
            }
            this.entityManager.persist(certificateAuthority);
            return null;
        }
        if (Status.ACTIVE != certificateAuthority.getStatus()) {
            LOG.debug("CA revocation data cache not yet active: " + issuerName);
            /*
             * Harvester is still busy processing the first CRL.
             */
            if (null == certificateAuthority.getCrlUrl()) {
                certificateAuthority.setCrlUrl(getCrlUrl(childCertificate));
            }

            if (Status.NONE != certificateAuthority.getStatus()) {
                // none means no CRL is available so not really a cache miss
                SNMPInterceptor.increment(SnmpConstants.CACHE_MISSES, SnmpConstants.SNMP_SERVICE, 1L);
            }
            return null;
        }
        /*
         * Let's use the cached revocation data
         */
        Date thisUpdate = certificateAuthority.getThisUpdate();
        if (null == thisUpdate) {
            LOG.warn("no thisUpdate value: " + certificateAuthority.getName());
            SNMPInterceptor.increment(SnmpConstants.CACHE_MISSES, SnmpConstants.SNMP_SERVICE, 1L);
            return null;
        }
        Date nextUpdate = certificateAuthority.getNextUpdate();
        if (null == nextUpdate) {
            LOG.warn("no nextUpdate value: " + certificateAuthority.getName());
            SNMPInterceptor.increment(SnmpConstants.CACHE_MISSES, SnmpConstants.SNMP_SERVICE, 1L);
            return null;
        }
        /*
         * First check whether the cached revocation data is up-to-date.
         */
        if (thisUpdate.after(validationDate)) {
            LOG.warn("cached CRL data too recent: " + certificateAuthority.getName());
            SNMPInterceptor.increment(SnmpConstants.CACHE_MISSES, SnmpConstants.SNMP_SERVICE, 1L);
            return null;
        }
        if (validationDate.after(nextUpdate)) {
            LOG.warn("cached CRL data too old: " + certificateAuthority.getName());
            SNMPInterceptor.increment(SnmpConstants.CACHE_MISSES, SnmpConstants.SNMP_SERVICE, 1L);
            return null;
        }
        LOG.debug("using cached CRL data");
        /*
         * Cache Hit
         */
        SNMPInterceptor.increment(SnmpConstants.CACHE_HITS, SnmpConstants.SNMP_SERVICE, 1L);

        BigInteger serialNumber = childCertificate.getSerialNumber();
        RevokedCertificateEntity revokedCertificate = findRevokedCertificate(issuerName, serialNumber);
        if (null == revokedCertificate) {
            LOG.debug("certificate valid: " + childCertificate.getSubjectX500Principal());
            return new TrustLinkerResult(true);
        }
        if (revokedCertificate.getRevocationDate().after(validationDate)) {
            LOG.debug("CRL OK for: " + childCertificate.getSubjectX500Principal() + " at " + validationDate);
            return new TrustLinkerResult(true);
        }
        LOG.debug("certificate invalid: " + childCertificate.getSubjectX500Principal());
        return new TrustLinkerResult(false, TrustLinkerResultReason.INVALID_REVOCATION_STATUS,
                "certificate revoked by cached CRL");
    }

    private String getCrlUrl(X509Certificate childCertificate) {

        URI crlUri = CrlTrustLinker.getCrlUri(childCertificate);
        if (null == crlUri) {
            LOG.warn("No CRL uri for: " + childCertificate.getIssuerX500Principal().toString());
            return null;
        }
        try {
            return crlUri.toURL().toString();
        } catch (MalformedURLException e) {
            LOG.warn("malformed URL: " + e.getMessage(), e);
            return null;
        }
    }

    private void logAudit(String message) {

        try {
            InitialContext initialContext = new InitialContext();
            AuditDAO auditDAO = (AuditDAO) initialContext.lookup(AuditDAO.JNDI_BINDING);
            auditDAO.logAudit(message);
        } catch (NamingException e) {
            LOG.error("Failed to log audit message: " + message, e);
        }

    }

    private RevokedCertificateEntity findRevokedCertificate(String issuer, BigInteger serialNumber) {

        return this.entityManager.find(RevokedCertificateEntity.class,
                new RevokedCertificatePK(issuer, serialNumber.toString()));
    }
}