/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program 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 * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package org.codice.ddf.security.handler.pki; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.security.GeneralSecurityException; import java.security.cert.CRL; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Properties; import org.apache.wss4j.common.crypto.Merlin; import org.codice.ddf.configuration.AbsolutePathResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ddf.security.PropertiesLoader; import ddf.security.common.audit.SecurityLogger; public class CrlChecker { public static final String CRL_PROPERTY_KEY = Merlin.OLD_PREFIX + Merlin.X509_CRL_FILE; private static final Logger LOGGER = LoggerFactory.getLogger(AbstractPKIHandler.class); private static String encryptionPropertiesLocation = new AbsolutePathResolver( "etc/ws-security/server/encryption.properties").getPath(); private CRL crl = null; /** * Constructor method. Reads encryption.properties and sets CRL location */ public CrlChecker() { Properties encryptionProperties = loadProperties(encryptionPropertiesLocation); setCrlLocation(encryptionProperties.getProperty(CRL_PROPERTY_KEY)); } /** * Checks the given certs against the CRL. The CRL is configured in this class's constructor method. * * @param certs certificates to be checked against the CRL * @return true if one of the certs passes the CRL or if CRL revocation is disabled, false if they are all revoked. */ public boolean passesCrlCheck(X509Certificate[] certs) { if (crl == null) { String errorMsg = "CRL is not set. Skipping CRL check"; LOGGER.trace(errorMsg); return true; } LOGGER.trace("Checking request certs against CRL."); return passesCrl(certs); } /** * Checks if the provided cert is listed in the CRL. * * @param certs List of certs to be checked against the CRL * @return boolean value Whether or not the client presenting the certs should be let through */ private boolean passesCrl(X509Certificate[] certs) { if (certs != null) { LOGGER.debug("Got {} certificate(s) in the incoming request", certs.length); for (X509Certificate curCert : certs) { if (crl.isRevoked(curCert)) { SecurityLogger.audit("Denying access for subject DN: " + curCert.getSubjectDN() + " due to certificate being revoked by CRL."); return false; } } } else { LOGGER.debug( "Allowing message through CRL check. There were no certificates sent by the client."); return true; } return true; } /** * Sets the location of the CRL. Enables CRL checking if property is set, disables it otherwise * * @param location Location of the DER-encoded CRL file that should be used to * check certificate revocation. */ public void setCrlLocation(String location) { if (location == null) { LOGGER.info("CRL property in {} is not set. Certs will not be checked against a CRL", encryptionPropertiesLocation); crl = null; } else { crl = createCrl(location); } } /** * Generates a new CRL object from the given location. * * @param location File Path or URL to the CRL file * @return A CRL object constructed from the given file path or URL. Null if an error occurred while attempting to read the file. */ private CRL createCrl(String location) { URL url = urlFromPath(location); //If we get a URL, use URL, otherwise use as local file path try (InputStream is = url != null ? url.openStream() : new FileInputStream(new File(location))) { CertificateFactory cf = CertificateFactory.getInstance("X.509"); return cf.generateCRL(is); } catch (IOException e) { LOGGER.debug("An error occurred while accessing {}", location, e); return null; } catch (GeneralSecurityException e) { LOGGER.warn( "Encountered an error while generating CRL from file {}. CRL checking may not work correctly. Check the CRL file.", location, e); return null; } } URL urlFromPath(String location) { try { return new URL(location); } catch (MalformedURLException e) { return null; } } /** * Loads the properties from a given location. * * @param location location of properties file * @return Properties from the file */ Properties loadProperties(String location) { return PropertiesLoader.loadProperties(location); } }