/* * Copyright 1999-2006 University of Chicago Licensed under the Apache License, * Version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law * or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.cagrid.gts.service.impl; import java.io.File; import java.io.FilenameFilter; import java.security.cert.X509CRL; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.ListIterator; import java.util.Map; import java.util.StringTokenizer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.globus.common.CoGProperties; import org.globus.gsi.CertUtil; import org.globus.util.TimestampEntry; public class CertificateRevocationLists { private static Log logger = LogFactory.getLog(CertificateRevocationLists.class.getName()); public static final CrlFilter crlFileFilter = new CrlFilter(); // the list of ca cert locations needed for getDefaultCRL call private static String prevCaCertLocations = null; // the default crl locations list derived from prevCaCertLocations private static String defaultCrlLocations = null; private static CertificateRevocationLists defaultCrl = null; private Map crlFileMap; private Map crlIssuerDNMap; private CertificateRevocationLists() { } public X509CRL[] getCrls() { if (this.crlIssuerDNMap == null) { return null; } Collection crls = this.crlIssuerDNMap.values(); X509CRL[] retCrls = new X509CRL[crls.size()]; Iterator iterator = crls.iterator(); int i = 0; while (iterator.hasNext()) { retCrls[i] = (X509CRL) iterator.next(); i++; } return retCrls; } public X509CRL getCrl(String issuerName) { if (this.crlIssuerDNMap == null) { return null; } return (X509CRL) this.crlIssuerDNMap.get(issuerName); } public static FilenameFilter getCrlFilter() { return crlFileFilter; } public static class CrlFilter implements FilenameFilter { public boolean accept(File dir, String file) { int length = file.length(); if (length > 3 && file.charAt(length - 3) == '.' && file.charAt(length - 2) == 'r' && file.charAt(length - 1) >= '0' && file.charAt(length - 1) <= '9') { return true; } return false; } } public void refresh() { reload(null); } public synchronized void loadCRLS(X509CRL[] crls) { if (crls == null) { return; } Map newCrlFileMap = new HashMap(); Map newCrlIssuerDNMap = new HashMap(); for (int i = 0; i < crls.length; i++) { newCrlIssuerDNMap.put(crls[i].getIssuerDN().getName(), crls[i]); } this.crlFileMap = newCrlFileMap; this.crlIssuerDNMap = newCrlIssuerDNMap; } public synchronized void reload(String locations) { if (locations == null) { return; } StringTokenizer tokens = new StringTokenizer(locations, ","); File crlFile = null; Map newCrlFileMap = new HashMap(); Map newCrlIssuerDNMap = new HashMap(); while (tokens.hasMoreTokens()) { crlFile = new File(tokens.nextToken().toString().trim()); if (!crlFile.canRead()) { logger.debug("Cannot read: " + crlFile.getAbsolutePath()); continue; } if (crlFile.isDirectory()) { String[] crlFiles = crlFile.list(getCrlFilter()); if (crlFiles == null) { logger.debug("Cannot load CRLs from " + crlFile.getAbsolutePath() + " directory."); } else { logger.debug("Loading CRLs from " + crlFile.getAbsolutePath() + " directory."); for (int i = 0; i < crlFiles.length; i++) { String crlFilename = crlFile.getPath() + File.separatorChar + crlFiles[i]; File crlFilenameFile = new File(crlFilename); if (crlFilenameFile.canRead()) { loadCrl(crlFilename, crlFilenameFile.lastModified(), newCrlFileMap, newCrlIssuerDNMap); } else { logger.debug("Cannot read: " + crlFilenameFile.getAbsolutePath()); } } } } else { loadCrl(crlFile.getAbsolutePath(), crlFile.lastModified(), newCrlFileMap, newCrlIssuerDNMap); } } this.crlFileMap = newCrlFileMap; this.crlIssuerDNMap = newCrlIssuerDNMap; } /** * Method loads a CRL provided a mapping for it is<br> * a) Not already in the HashMap b) In the HashMap, but - mapped to null * object - the CRLEntry has a modified time that is older that latest time */ private void loadCrl(String crlPath, long latestLastModified, Map newCrlFileMap, Map newCrlIssuerDNMap) { X509CRL crl = null; if (this.crlFileMap == null) { this.crlFileMap = new HashMap(); } TimestampEntry crlEntry = (TimestampEntry) this.crlFileMap.get(crlPath); try { if (crlEntry == null) { logger.debug("Loading " + crlPath + " CRL."); crl = CertUtil.loadCrl(crlPath); crlEntry = new TimestampEntry(crl, latestLastModified); } else if (latestLastModified > crlEntry.getLastModified()) { logger.debug("Reloading " + crlPath + " CRL."); crl = CertUtil.loadCrl(crlPath); crlEntry.setValue(crl); crlEntry.setLastModified(latestLastModified); } else { logger.debug("CRL " + crlPath + " is up-to-date."); crl = (X509CRL) crlEntry.getValue(); } newCrlFileMap.put(crlPath, crlEntry); newCrlIssuerDNMap.put(crl.getIssuerDN().getName(), crl); } catch (Exception e) { logger.error("CRL " + crlPath + " failed to load.", e); } } /* * public static CertificateRevocationLists * getCertificateRevocationLists(String locations) { * CertificateRevocationLists crl = new CertificateRevocationLists(); * crl.reload(locations); return crl; } */ public static CertificateRevocationLists getCertificateRevocationLists(X509CRL[] crls) { CertificateRevocationLists crl = new CertificateRevocationLists(); crl.loadCRLS(crls); return crl; } public static synchronized CertificateRevocationLists getDefaultCertificateRevocationLists() { return getDefault(); } public static void setDefaultCertificateRevocationList(CertificateRevocationLists crl) { defaultCrl = crl; } public static synchronized CertificateRevocationLists getDefault() { if (defaultCrl == null) { defaultCrl = new DefaultCertificateRevocationLists(); } defaultCrl.refresh(); return defaultCrl; } public String toString() { if (this.crlIssuerDNMap == null) { return "crl list is empty"; } else { return this.crlIssuerDNMap.toString(); } } private static class DefaultCertificateRevocationLists extends CertificateRevocationLists { public void refresh() { reload(getDefaultCRLLocations()); } private static synchronized String getDefaultCRLLocations() { String caCertLocations = CoGProperties.getDefault().getCaCertLocations(); if (prevCaCertLocations == null || !prevCaCertLocations.equals(caCertLocations)) { if (caCertLocations == null) { logger.debug("No CA cert locations specified"); prevCaCertLocations = null; defaultCrlLocations = null; } else { StringTokenizer tokens = new StringTokenizer(caCertLocations, ","); File crlFile = null; LinkedList crlDirs = new LinkedList(); while (tokens.hasMoreTokens()) { String crlFileName = tokens.nextToken().toString().trim(); crlFile = new File(crlFileName); if (crlFile.isDirectory()) { // all all directories } else if (crlFile.isFile()) { // add parent directory crlFileName = crlFile.getParent(); } else { // skip other types continue; } // don't add directories twice if (crlFileName != null && !crlDirs.contains(crlFileName)) { crlDirs.add(crlFileName); } } ListIterator iterator = crlDirs.listIterator(0); String locations = null; while (iterator.hasNext()) { if (locations == null) { locations = (String) iterator.next(); } else { locations = locations + "," + (String) iterator.next(); } } // set defaults prevCaCertLocations = caCertLocations; defaultCrlLocations = locations; } } return defaultCrlLocations; } } }