mitm.application.djigzo.ws.impl.CertificateValidatorWSImpl.java Source code

Java tutorial

Introduction

Here is the source code for mitm.application.djigzo.ws.impl.CertificateValidatorWSImpl.java

Source

/*
 * Copyright (c) 2008-2012, Martijn Brinkers, Djigzo.
 * 
 * This file is part of Djigzo email encryption.
 *
 * Djigzo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License 
 * version 3, 19 November 2007 as published by the Free Software 
 * Foundation.
 *
 * Djigzo 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public 
 * License along with Djigzo. If not, see <http://www.gnu.org/licenses/>
 *
 * Additional permission under GNU AGPL version 3 section 7
 * 
 * If you modify this Program, or any covered work, by linking or 
 * combining it with aspectjrt.jar, aspectjweaver.jar, tyrex-1.0.3.jar, 
 * freemarker.jar, dom4j.jar, mx4j-jmx.jar, mx4j-tools.jar, 
 * spice-classman-1.0.jar, spice-loggerstore-0.5.jar, spice-salt-0.8.jar, 
 * spice-xmlpolicy-1.0.jar, saaj-api-1.3.jar, saaj-impl-1.3.jar, 
 * wsdl4j-1.6.1.jar (or modified versions of these libraries), 
 * containing parts covered by the terms of Eclipse Public License, 
 * tyrex license, freemarker license, dom4j license, mx4j license,
 * Spice Software License, Common Development and Distribution License
 * (CDDL), Common Public License (CPL) the licensors of this Program grant 
 * you additional permission to convey the resulting work.
 */
package mitm.application.djigzo.ws.impl;

import java.security.cert.CertPath;
import java.security.cert.CertPathBuilderException;
import java.security.cert.CertPathBuilderResult;
import java.security.cert.CertStoreException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.PKIXCertPathBuilderResult;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.List;

import mitm.application.djigzo.ws.CertificateStore;
import mitm.application.djigzo.ws.CertificateValidatorResult;
import mitm.application.djigzo.ws.CertificateValidatorWS;
import mitm.application.djigzo.ws.WSExceptionUtils;
import mitm.application.djigzo.ws.X509CertificateDTO;
import mitm.application.djigzo.ws.X509CertificateDTOBuilder;
import mitm.common.hibernate.annotations.StartTransaction;
import mitm.common.security.PKISecurityServices;
import mitm.common.security.certificate.validator.CertificateValidator;
import mitm.common.security.certificate.validator.IsValidForSMIMEEncryption;
import mitm.common.security.certificate.validator.IsValidForSMIMESigning;
import mitm.common.security.certificate.validator.PKITrustCheckCertificateValidator;
import mitm.common.security.certpath.CertificatePathBuilder;
import mitm.common.security.certstore.X509CertStoreEntry;
import mitm.common.security.certstore.X509CertStoreExt;
import mitm.common.util.Check;
import mitm.common.util.CollectionUtils;
import mitm.common.ws.WebServiceCheckedException;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CertificateValidatorWSImpl implements CertificateValidatorWS {
    private final static Logger logger = LoggerFactory.getLogger(CertificateValidatorWSImpl.class);

    /*
     * Gives access to all the PKI services
     */
    private final PKISecurityServices pKISecurityServices;

    /*
     * For building X509 Certificate DTOs
     */
    private final X509CertificateDTOBuilder certificateDTOBuilder;

    public CertificateValidatorWSImpl(PKISecurityServices pKISecurityServices,
            X509CertificateDTOBuilder certificateDTOBuilder) {
        Check.notNull(pKISecurityServices, "pKISecurityServices");
        Check.notNull(certificateDTOBuilder, "certificateDTOBuilder");

        this.pKISecurityServices = pKISecurityServices;
        this.certificateDTOBuilder = certificateDTOBuilder;
    }

    @Override
    @StartTransaction
    public CertificateValidatorResult checkValidityForSigning(CertificateStore store, String thumbprint)
            throws WebServiceCheckedException {
        try {
            X509Certificate certificate = getCertificate(store, thumbprint);

            CertificateValidatorResult validatorResult = checkValidity(certificate);

            if (validatorResult.isValid()) {
                /*
                 * Certificate is trusted etc. now check if it can be used for 
                 * S/MIME signatures
                 */
                CertificateValidator validator = new IsValidForSMIMESigning();

                if (!validator.isValid(certificate)) {
                    validatorResult = new CertificateValidatorResult(false /* not valid */,
                            validatorResult.isTrusted(), validatorResult.isRevoked(),
                            validatorResult.isBlackListed(), validatorResult.isWhiteListed(),
                            "Certificate cannot be used for S/MIME signatures. "
                                    + ObjectUtils.toString(validator.getFailureMessage()));
                }
            }

            return validatorResult;
        } catch (WebServiceCheckedException e) {
            logger.error("checkValidityForSigning failed.", e);

            throw new WebServiceCheckedException(WSExceptionUtils.getExceptionMessage(e));
        } catch (CertificateException e) {
            logger.error("checkValidityForSigning failed.", e);

            throw new WebServiceCheckedException(WSExceptionUtils.getExceptionMessage(e));
        } catch (RuntimeException e) {
            logger.error("checkValidityForSigning failed.", e);

            throw new WebServiceCheckedException(WSExceptionUtils.getExceptionMessage(e));
        }
    }

    @Override
    @StartTransaction
    public CertificateValidatorResult checkValidityForEncryption(CertificateStore store, String thumbprint)
            throws WebServiceCheckedException {
        try {
            X509Certificate certificate = getCertificate(store, thumbprint);

            CertificateValidatorResult validatorResult = checkValidity(certificate);

            if (validatorResult.isValid()) {
                /*
                 * Certificate is trusted etc. now check if it can be used for 
                 * S/MIME encryption
                 */
                CertificateValidator validator = new IsValidForSMIMEEncryption();

                if (!validator.isValid(certificate)) {
                    validatorResult = new CertificateValidatorResult(false /* not valid */,
                            validatorResult.isTrusted(), validatorResult.isRevoked(),
                            validatorResult.isBlackListed(), validatorResult.isWhiteListed(),
                            "Certificate cannot be used for S/MIME encryption. "
                                    + ObjectUtils.toString(validator.getFailureMessage()));
                }
            }

            return validatorResult;
        } catch (WebServiceCheckedException e) {
            logger.error("checkValidityForEncryption failed.", e);

            throw new WebServiceCheckedException(WSExceptionUtils.getExceptionMessage(e));
        } catch (CertificateException e) {
            logger.error("checkValidityForEncryption failed.", e);

            throw new WebServiceCheckedException(WSExceptionUtils.getExceptionMessage(e));
        } catch (RuntimeException e) {
            logger.error("checkValidityForEncryption failed.", e);

            throw new WebServiceCheckedException(WSExceptionUtils.getExceptionMessage(e));
        }
    }

    @Override
    @StartTransaction
    public CertificateValidatorResult checkValidity(CertificateStore store, String thumbprint)
            throws WebServiceCheckedException {
        try {
            X509Certificate certificate = getCertificate(store, thumbprint);

            return checkValidity(certificate);
        } catch (WebServiceCheckedException e) {
            logger.error("checkValidity failed.", e);

            throw new WebServiceCheckedException(WSExceptionUtils.getExceptionMessage(e));
        } catch (RuntimeException e) {
            logger.error("checkValidity failed.", e);

            throw new WebServiceCheckedException(WSExceptionUtils.getExceptionMessage(e));
        }
    }

    private X509Certificate getCertificate(CertificateStore store, String thumbprint)
            throws WebServiceCheckedException {
        try {
            X509CertStoreExt certStore = null;

            switch (store) {
            case CERTIFICATES:
                certStore = pKISecurityServices.getKeyAndCertStore();
                break;
            case ROOTS:
                certStore = pKISecurityServices.getRootStore();
                break;

            default:
                throw new IllegalArgumentException("Unknown CertificateStore.");
            }

            X509CertStoreEntry entry = certStore.getByThumbprint(thumbprint);

            X509Certificate certificate = null;

            if (entry != null) {
                certificate = entry.getCertificate();
            }

            return certificate;
        } catch (CertStoreException e) {
            throw new WebServiceCheckedException(e);
        }
    }

    private CertificateValidatorResult checkValidity(X509Certificate certificate) {
        if (certificate == null) {
            String message = "Certificate not found.";

            logger.warn(message);

            return new CertificateValidatorResult(false /* not valid */, false /* not trusted */,
                    true /* revoked */, false /* not blacklisted */, false /* not whitelisted */, message);
        }

        PKITrustCheckCertificateValidator validator = pKISecurityServices
                .getPKITrustCheckCertificateValidatorFactory().createValidator(null);

        CertificateValidatorResult result = null;

        try {
            validator.isValid(certificate);

            result = new CertificateValidatorResult(validator.isValid(), validator.isTrusted(),
                    validator.isRevoked(), validator.isBlackListed(), validator.isWhiteListed(),
                    validator.getFailureMessage());
        } catch (CertificateException e) {
            logger.error("Error while validating the certificate.", e);

            result = new CertificateValidatorResult(false /* not valid */, false /* not trusted */,
                    true /* revoked */, false /* not blacklisted */, false /* not whitelisted */,
                    "Error while validating the certificate: " + ExceptionUtils.getRootCauseMessage(e));
        }

        return result;
    }

    @Override
    @StartTransaction
    public X509CertificateDTO getIssuerCertificate(CertificateStore store, String thumbprint)
            throws WebServiceCheckedException {
        X509Certificate certificate = getCertificate(store, thumbprint);

        if (certificate == null) {
            throw new WebServiceCheckedException("Certificate not found");
        }

        X509CertificateDTO issuerDTO = null;

        try {
            CertificatePathBuilder pathBuilder = pKISecurityServices.getCertificatePathBuilderFactory()
                    .createCertificatePathBuilder();

            CertPathBuilderResult pathBuilderResult = pathBuilder.buildPath(certificate);

            CertPath certPath = pathBuilderResult.getCertPath();

            if (certPath != null) {
                X509Certificate issuer = null;
                CertificateStore issuerStore = null;

                List<? extends Certificate> path = certPath.getCertificates();

                if (CollectionUtils.isNotEmpty(path)) {
                    if (CollectionUtils.getSize(path) == 1) {
                        /*
                         * Since there is only one certificate (the certificate itself) we need
                         * to check whether there is a root in the path
                         */
                        if (pathBuilderResult instanceof PKIXCertPathBuilderResult) {
                            TrustAnchor trustAnchor = ((PKIXCertPathBuilderResult) pathBuilderResult)
                                    .getTrustAnchor();

                            if (trustAnchor != null) {
                                issuer = trustAnchor.getTrustedCert();

                                issuerStore = CertificateStore.ROOTS;
                            }
                        }
                    } else {
                        issuer = (X509Certificate) path.get(1);

                        issuerStore = CertificateStore.CERTIFICATES;
                    }
                }

                if (issuer != null) {
                    issuerDTO = certificateDTOBuilder.buildCertificateDTO(issuer, null);
                    issuerDTO.setCertificateStore(issuerStore);
                }
            }
        } catch (CertPathBuilderException e) {
            /*
             * Log on debug level because CertPathBuilderException is for example thrown
             * when trying to get the issuer of a root for example
             */
            logger.debug("getIssuer failed.", e);
        }

        return issuerDTO;
    }
}