Java tutorial
/* * Copyright (c) 2008-2011, 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.common.security.crl; import java.io.IOException; import java.net.URI; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.cert.CRL; import java.security.cert.CRLException; import java.security.cert.CertPathBuilderException; import java.security.cert.CertPathBuilderResult; import java.security.cert.CertStoreException; import java.security.cert.Certificate; import java.security.cert.CertificateExpiredException; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.security.cert.X509Extension; import java.util.Collection; import java.util.HashSet; import java.util.Set; import mitm.common.security.NoSuchProviderRuntimeException; import mitm.common.security.SecurityFactoryFactoryException; import mitm.common.security.certificate.X509CertificateInspector; import mitm.common.security.certificate.X509ExtensionInspector; import mitm.common.security.certpath.CertificatePathBuilder; import mitm.common.security.certstore.BasicCertStore; import mitm.common.security.certstore.CertStoreUtils; import mitm.common.security.crlstore.CRLStoreException; import mitm.common.util.CloseableIterator; import mitm.common.util.CloseableIteratorException; import org.apache.commons.lang.SystemUtils; import org.apache.commons.lang.exception.ExceptionUtils; import org.bouncycastle.asn1.x509.CRLDistPoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Implementation of CRLStoreUpdater. * * @author Martijn Brinkers * */ public class CRLStoreUpdaterImpl implements CRLStoreUpdater { private final static Logger logger = LoggerFactory.getLogger(CRLStoreUpdaterImpl.class); private final CRLStoreUpdaterParameters updaterParameters; public CRLStoreUpdaterImpl(CRLStoreUpdaterParameters updaterParameters) { this.updaterParameters = updaterParameters; } /* * Check if the certificate is trusted up to a Trust Anchor. */ private boolean isTrusted(X509Certificate certificate) throws NoSuchProviderException { boolean trusted = false; try { CertificatePathBuilder pathBuilder = updaterParameters.getCertificatePathBuilderFactory() .createCertificatePathBuilder(); /* * add the certificate to the PathBuilder so it is found using X509CertSelector */ try { pathBuilder.addCertStore(CertStoreUtils.createCertStore(certificate)); } catch (InvalidAlgorithmParameterException e) { throw new CertPathBuilderException(e); } catch (NoSuchAlgorithmException e) { throw new CertPathBuilderException(e); } catch (SecurityFactoryFactoryException e) { throw new CertPathBuilderException(e); } CertPathBuilderResult result = pathBuilder.buildPath(certificate); if (result == null) { throw new CertPathBuilderException("No valid CertPath found."); } trusted = true; } catch (CertPathBuilderException e) { /* * CertPathBuilderException is thrown for a lot of reasons so we will try to extract the reason. * Because this exception can happen frequently under 'normal' circumstances * (for example when a root is not installed) we will log the messages with the WARN level. */ Throwable rootCause = ExceptionUtils.getRootCause(e); Throwable cause = (rootCause != null ? rootCause : e); if (cause instanceof CertificateExpiredException) { logger.warn("Certificate is expired. Certificate: " + X509CertificateInspector.toString(certificate) + ". Message: " + cause.getMessage()); } else { String errorMessage = "Error while building path for certificate. Certificate: " + X509CertificateInspector.toString(certificate); if (logger.isDebugEnabled()) { logger.warn(errorMessage, cause); } else { logger.warn(errorMessage + ". Message: " + cause.getMessage()); } } } return trusted; } /* * Check if the CRL is trusted up to a Trust Anchor. */ private boolean isTrusted(X509CRL crl) throws NoSuchProviderException { boolean trusted = false; try { updaterParameters.getCRLPathBuilderFactory().createCRLPathBuilder().buildPath(crl); trusted = true; } catch (CertPathBuilderException e) { /* * CertPathBuilderException is thrown for a lot of reasons so we will try to extract the reason. * Because this exception can happen frequently under 'normal' circumstances * (for example when a root is not installed) we will log the messages with the WARN level. */ Throwable rootCause = ExceptionUtils.getRootCause(e); Throwable cause = (rootCause != null ? rootCause : e); if (cause instanceof CertificateExpiredException) { logger.warn("CRL is expired. CRL: " + X509CRLInspector.toString(crl) + ". Message: " + cause.getMessage()); } else { String errorMessage = "Error while building path for CRL. CRL: " + X509CRLInspector.toString(crl); if (logger.isDebugEnabled()) { logger.warn(errorMessage, cause); } else { logger.warn(errorMessage + ". Message: " + cause.getMessage()); } } } catch (CRLStoreException e) { logger.error("Error while building path for CRL.", e); } return trusted; } private boolean isTrusted(X509Extension extension) throws NoSuchProviderException { if (extension instanceof X509Certificate) { return isTrusted((X509Certificate) extension); } else if (extension instanceof X509CRL) { return isTrusted((X509CRL) extension); } else { throw new IllegalArgumentException("Unsupported extension."); } } private void addURIsFromCRLDistPoint(X509Extension extension, CRLDistPoint crlDistPoint, Set<URI> uris) throws NoSuchProviderException, CRLException { if (crlDistPoint != null) { Set<URI> certificateURIs = CRLUtils.getAllDistributionPointURIs(crlDistPoint); for (URI uri : certificateURIs) { if (!uris.contains(uri)) { /* if it's a new uri we must check the validity of the object */ if (updaterParameters.checkTrust() && !isTrusted(extension)) { logger.debug( "Certificate or CRL is not trusted so CRL will not be downloaded. URI: " + uri); } else { uris.add(uri); } } } } } private void addURIsFromExtension(X509Extension extension, Set<URI> uris) throws NoSuchProviderException, CRLException { try { CRLDistPoint crlDistPoint = X509ExtensionInspector.getCRLDistibutionPoints(extension); addURIsFromCRLDistPoint(extension, crlDistPoint, uris); } catch (IOException e) { logger.error("Error getting CRL Distibution Points for:" + SystemUtils.LINE_SEPARATOR + extension, e); } try { CRLDistPoint crlDistPoint = X509ExtensionInspector.getFreshestCRL(extension); addURIsFromCRLDistPoint(extension, crlDistPoint, uris); } catch (IOException e) { logger.error( "Error getting Freshest CRL distibution Points for:" + SystemUtils.LINE_SEPARATOR + extension, e); } } private void addURIsFromCertificates(CloseableIterator<? extends Certificate> iterator, Set<URI> uris) throws NoSuchProviderException, CloseableIteratorException { while (iterator.hasNext()) { try { Certificate certificate = iterator.next(); if (!(certificate instanceof X509Extension)) { logger.warn("Certificate is not a X509Extension."); continue; } addURIsFromExtension((X509Extension) certificate, uris); } catch (Exception e) { logger.error("Error getting URIs from certificate. Skipping certificate.", e); } } } private void addURIsFromCRLs(CloseableIterator<? extends CRL> iterator, Set<URI> uris) throws NoSuchProviderException, CloseableIteratorException { while (iterator.hasNext()) { try { CRL crl = iterator.next(); if (!(crl instanceof X509Extension)) { logger.warn("CRL is not a X509Extension."); continue; } addURIsFromExtension((X509Extension) crl, uris); } catch (Exception e) { logger.error("Error getting URIs from CRL. Skipping CRL.", e); } } } private int downloadCRLs(Set<URI> uris) { int crlsAdded = 0; for (URI uri : uris) { if (uri == null) { logger.warn("URL is null."); continue; } if (uri.getScheme() == null) { logger.warn("Missing scheme. " + uri); } logger.debug("Downloading CRL from: " + uri); try { Collection<? extends CRL> downloadedCrls = updaterParameters.getCRLDownloader().downloadCRLs(uri); logger.debug("Successfully downloaded CRLs from: " + uri); int newAdded = updaterParameters.getCRLStoreMaintainer().addCRLs(downloadedCrls); crlsAdded = crlsAdded + newAdded; } catch (CRLException e) { logger.error("Error handling CRL. URI: " + uri, e); } catch (IOException e) { /* * We will log WARN level because downloading CRLs often result in IOException's because the CRL * distribution point is no longer available for a lot of roots. */ logger.warn("IO Exception downloading CRL. URI: " + uri + ". Message: " + e.getMessage()); if (logger.isDebugEnabled()) { logger.debug("More info.", e); } } catch (Exception e) { /* * Catch all exceptions to make sure that other CRLs are downloaded. */ logger.error("Error while downloading CRL. URI: " + uri, e); } } return crlsAdded; } @Override public void update() throws CRLStoreException { Set<URI> uris = new HashSet<URI>(); try { Collection<? extends BasicCertStore> stores = updaterParameters.getCertStores(); for (BasicCertStore store : stores) { /* Add CRL distribution points from the certificates in the CertStore */ CloseableIterator<? extends Certificate> certificateIterator = store.getCertificateIterator(null); try { addURIsFromCertificates(certificateIterator, uris); } finally { certificateIterator.close(); } /* Add CRL distribution points from the CRLs in the CRLStore */ CloseableIterator<? extends CRL> crlIterator = updaterParameters.getCRLStore().getCRLIterator(null); try { addURIsFromCRLs(crlIterator, uris); } finally { crlIterator.close(); } } } catch (NoSuchProviderException e) { throw new NoSuchProviderRuntimeException(e); } catch (CloseableIteratorException e) { throw new CRLStoreException(e); } catch (CertStoreException e) { throw new CRLStoreException(e); } logger.info(uris.size() + " CRL distibution points found."); int crlsAdded = downloadCRLs(uris); logger.info(crlsAdded + " new CRLs added to the CRL store."); } }