/* * Copyright (c) 2011-2012 ICM Uniwersytet Warszawski All rights reserved. * See LICENCE file for licensing information. */ package eu.emi.security.authn.x509.impl; import java.security.InvalidAlgorithmParameterException; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.List; import java.util.Set; import java.util.Timer; import eu.emi.security.authn.x509.NamespaceCheckingMode; import eu.emi.security.authn.x509.ValidationError; import eu.emi.security.authn.x509.ValidationResult; import eu.emi.security.authn.x509.helpers.crl.AbstractCRLStoreSPI; import eu.emi.security.authn.x509.helpers.crl.LazyOpensslCRLStoreSpi; import eu.emi.security.authn.x509.helpers.crl.OpensslCRLStoreSpi; import eu.emi.security.authn.x509.helpers.ns.NamespaceChecker; import eu.emi.security.authn.x509.helpers.pkipath.AbstractValidator; import eu.emi.security.authn.x509.helpers.trust.LazyOpensslTrustAnchorStoreImpl; import eu.emi.security.authn.x509.helpers.trust.OpensslTrustAnchorStore; import eu.emi.security.authn.x509.helpers.trust.OpensslTrustAnchorStoreImpl; /** * The certificate validator which uses OpenSSL directory as a truststore. The validator can work in two modes: * the default <b>lazy</b> mode when the truststore contents is loaded on-demand and in a classic mode, * when the whole truststore is loaded to the memory at startup. The latter mode can be useful for server-side * as allows to get an information about truststore problems (as expired certificates or invalid files) at startup. * Also the performance characteristic is better: validation can be faster and operation time more stable. * Unfortunately both advantages are at the cost of a longer initialization time and bigger memory footprint. * Therefore the lazy mode is strongly suggested for client tools, where this is a concern. * * * @author K. Benedyczak */ public class OpensslCertChainValidator extends AbstractValidator { private OpensslTrustAnchorStore trustStore; private AbstractCRLStoreSPI crlStore; private final NamespaceCheckingMode namespaceMode; private String path; private final boolean lazyMode; protected static final Timer timer=new Timer("caNl validator (openssl) timer", true); /** * Constructs a new validator instance. This version is equivalent to the {@link #OpensslCertChainValidator(String, boolean, NamespaceCheckingMode, long, ValidatorParams, boolean)} * with the legacy (pre 1.0) format of the truststore and the lazy mode turned on. * * @param directory path where trusted certificates are stored. * @param namespaceMode specifies how certificate namespaces should be handled * @param updateInterval specifies in miliseconds how often the directory should be * checked for updates. The files are reloaded only if their modification timestamp * was changed since last load. Use a <= 0 value to disable automatic updates. * @param params common validator settings (revocation, initial listeners, proxy support, ...) */ public OpensslCertChainValidator(String directory, NamespaceCheckingMode namespaceMode, long updateInterval, ValidatorParams params) { this(directory, false, namespaceMode, updateInterval, params, true); } /** * Constructs a new validator instance. This validator will work in the lazy mode. See * {@link #OpensslCertChainValidator(String, boolean, NamespaceCheckingMode, long, ValidatorParams, boolean)} * for details. * * @param directory path where trusted certificates are stored. * @param openssl1Mode if true then truststore is with hashes in openssl 1+ format. Otherwise * the openssl 0.x format is used. * @param namespaceMode specifies how certificate namespaces should be handled * @param updateInterval specifies in miliseconds how often the directory should be * checked for updates. The files are reloaded only if their modification timestamp * was changed since last load. Use a <= 0 value to disable automatic updates. * @param params common validator settings (revocation, initial listeners, proxy support, ...) */ public OpensslCertChainValidator(String directory, boolean openssl1Mode, NamespaceCheckingMode namespaceMode, long updateInterval, ValidatorParams params) { this(directory, openssl1Mode, namespaceMode, updateInterval, params, true); } /** * Constructs a new validator instance. * * @since 2.0.0 * @param directory path where trusted certificates are stored. * @param openssl1Mode if true then truststore is with hashes in openssl 1+ format. Otherwise * the openssl 0.x format is used. * @param namespaceMode specifies how certificate namespaces should be handled * @param updateInterval specifies in miliseconds how often the directory should be * checked for updates. The files are reloaded only if their modification timestamp * was changed since last load. Use a <= 0 value to disable automatic updates. * @param params common validator settings (revocation, initial listeners, proxy support, ...) * @param lazyMode if true then certificates, CRLs and namespace definitions are loaded on-demand * (with in-memory caching). If false then the whole truststore contents is loaded at startup and kept in memory. */ public OpensslCertChainValidator(String directory, boolean openssl1Mode, NamespaceCheckingMode namespaceMode, long updateInterval, ValidatorParams params, boolean lazyMode) { super(params.getInitialListeners()); path = directory; this.lazyMode = lazyMode; this.namespaceMode = namespaceMode; trustStore = lazyMode ? new LazyOpensslTrustAnchorStoreImpl(directory, updateInterval, observers, openssl1Mode) : new OpensslTrustAnchorStoreImpl(directory, timer, updateInterval, namespaceMode.globusEnabled(), namespaceMode.euGridPmaEnabled(), observers, openssl1Mode); try { crlStore = lazyMode ? new LazyOpensslCRLStoreSpi(directory, updateInterval, observers, openssl1Mode) : new OpensslCRLStoreSpi(directory, updateInterval, timer, observers, openssl1Mode); } catch (InvalidAlgorithmParameterException e) { throw new RuntimeException("BUG: OpensslCRLStoreSpi " + "can not be initialized", e); } init(trustStore, crlStore, params.isAllowProxy(), params.getRevocationSettings()); } /** * Constructs a new validator instance with default additional settings * (see {@link ValidatorParams#ValidatorParams()}). * * The legacy, pre openssl 1.0 format of the truststore is used as well as the lazy loading mode. * * @param directory path where trusted certificates are stored. * @param namespaceMode specifies how certificate namespaces should be handled * @param updateInterval specifies in miliseconds how often the directory should be * checked for updates. The files are reloaded only if their modification timestamp * was changed since last load. */ public OpensslCertChainValidator(String directory, NamespaceCheckingMode namespaceMode, long updateInterval) { this(directory, namespaceMode, updateInterval, new ValidatorParams()); } /** * Constructs a new validator instance using the default settings: * CRLs are used if present, proxy certificates are supported and * directory is rescanned every 10mins. EuGridPMA namespaces are checked in the first place, * if not found then Globus EACLs are tried. Lack of namespaces is ignored. * * The legacy, pre openssl 1.0 format of the truststore is used as well as the lazy loading mode. * * @param directory path where trusted certificates are stored. */ public OpensslCertChainValidator(String directory) { this(directory, NamespaceCheckingMode.EUGRIDPMA_GLOBUS, 600000, new ValidatorParamsExt()); } /** * Returns the trusted certificates directory path * @return the path */ public String getTruststorePath() { return path; } /** * Returns the namespace checking mode. * @return the namespace mode */ public NamespaceCheckingMode getNamespaceCheckingMode() { return namespaceMode; } /** * Returns the interval between subsequent checks of the trusted certificates * directory. Note that files are actually reread only if their modification * time has changed. * @return the current refresh interval in milliseconds */ public long getUpdateInterval() { return trustStore.getUpdateInterval(); } /** * Sets a new interval between subsequent checks of the trusted certificates * directory. Note that files are actually reread only if their modification * time has changed. * @param updateInterval the new interval to be set in milliseconds */ public void setUpdateInterval(long updateInterval) { trustStore.setUpdateInterval(updateInterval); crlStore.setUpdateInterval(updateInterval); } @Override public void dispose() { super.dispose(); trustStore.dispose(); crlStore.dispose(); } /** * {@inheritDoc} */ @Override public ValidationResult validate(X509Certificate[] certChain) { Set<TrustAnchor> anchors; if (lazyMode) { LazyOpensslTrustAnchorStoreImpl lazyTAStore = (LazyOpensslTrustAnchorStoreImpl) trustStore; anchors = lazyTAStore.getTrustAnchorsFor(certChain); } else { anchors = trustStore.getTrustAnchors(); } ValidationResult result = super.validate(certChain, anchors); NamespaceChecker checker = new NamespaceChecker(namespaceMode, trustStore.getPmaNsStore(), trustStore.getGlobusNsStore()); List<ValidationError> errors = checker.check(certChain); processErrorList(errors); result.addErrors(errors); return result; } }