/*
* Copyright (c) 2011-2012 ICM Uniwersytet Warszawski All rights reserved.
* See LICENCE.txt file for licensing information.
*/
package eu.emi.security.authn.x509.helpers.trust;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import eu.emi.security.authn.x509.StoreUpdateListener;
import eu.emi.security.authn.x509.StoreUpdateListener.Severity;
import eu.emi.security.authn.x509.helpers.ObserversHandler;
import eu.emi.security.authn.x509.helpers.ns.EuGridPmaNamespacesStore;
import eu.emi.security.authn.x509.helpers.ns.GlobusNamespacesStore;
import eu.emi.security.authn.x509.helpers.ns.NamespacesStore;
import eu.emi.security.authn.x509.impl.CertificateUtils.Encoding;
/**
* Implementation of the truststore which uses CA certificates from a single directory
* in OpenSSL format. Each certificate should be stored in a file named HASH.NUM,
* where HASH is an 8 digit hex number. The NUM must be a number, starting from 0.
* The hash can be either of openssl pre 1.0.0 version
* (with 8 least significant digits of the MD5 hash of the certificate subject in DER format)
* or in openssl 1.0.0 and above format (SHA1 hash of specially normalized DN). The class is configured
* to use one or another, never both.
* <p>
* This class is extending the {@link DirectoryTrustAnchorStore} and restricts
* the certificates which are loaded.
*
* @author K. Benedyczak
*/
public class OpensslTrustAnchorStoreImpl extends DirectoryTrustAnchorStore implements OpensslTrustAnchorStore
{
public static final String CERT_WILDCARD = "????????.*";
private boolean loadEuGridPmaNs;
private boolean loadGlobusNs;
private boolean openssl1Mode;
private NamespacesStore pmaNsStore;
private NamespacesStore globusNsStore;
public OpensslTrustAnchorStoreImpl(String basePath, Timer t, long updateInterval, boolean loadGlobusNs,
boolean loadEuGridPmaNs, ObserversHandler observers, boolean openssl1Mode)
{
super(Collections.singletonList(basePath+File.separator+CERT_WILDCARD),
null, 0, t, updateInterval, Encoding.PEM, observers, true);
this.openssl1Mode = openssl1Mode;
pmaNsStore = new EuGridPmaNamespacesStore(observers, openssl1Mode);
globusNsStore = new GlobusNamespacesStore(observers, openssl1Mode);
this.loadEuGridPmaNs = loadEuGridPmaNs;
this.loadGlobusNs = loadGlobusNs;
update();
scheduleUpdate();
}
/**
* For all URLs tries to load a CA cert and namespaces
*/
@Override
protected void reloadCerts(Collection<URL> locations)
{
List<String> correctLocations = new ArrayList<String>();
Set<TrustAnchorExt> tmpAnchors = new HashSet<TrustAnchorExt>();
Map<URL, TrustAnchorExt> tmpLoc2anch = new HashMap<URL, TrustAnchorExt>();
for (URL location: locations)
{
boolean loaded = tryLoadCert(location, tmpAnchors, tmpLoc2anch);
if (loaded)
correctLocations.add(location.getPath());
}
synchronized(this)
{
anchors.addAll(tmpAnchors);
locations2anchors.putAll(tmpLoc2anch);
if (loadEuGridPmaNs)
pmaNsStore.setPolicies(correctLocations);
if (loadGlobusNs)
globusNsStore.setPolicies(correctLocations);
}
}
protected boolean tryLoadCert(URL location, Set<TrustAnchorExt> tmpAnchors, Map<URL, TrustAnchorExt> tmpLoc2anch)
{
String fileHash = OpensslTruststoreHelper.getFileHash(location.getPath(),
OpensslTruststoreHelper.CERT_REGEXP);
if (fileHash == null)
return false;
X509Certificate cert;
try
{
X509Certificate[] certs = loadCerts(location);
if (certs.length != 1)
throw new IOException("Each of the certificate files in the Openssl style truststore "
+ "must contain exactly one certificate");
cert = certs[0];
} catch (Exception e)
{
observers.notifyObservers(location.toExternalForm(), StoreUpdateListener.CA_CERT,
Severity.ERROR, e);
return false;
}
String certHash = OpensslTruststoreHelper.getOpenSSLCAHash(cert.getSubjectX500Principal(), openssl1Mode);
if (!fileHash.equalsIgnoreCase(certHash))
return false;
TrustAnchorExt anchor = new TrustAnchorExt(cert, null);
tmpAnchors.add(anchor);
tmpLoc2anch.put(location, anchor);
return true;
}
@Override
public NamespacesStore getPmaNsStore()
{
return pmaNsStore;
}
@Override
public NamespacesStore getGlobusNsStore()
{
return globusNsStore;
}
}