/******************************************************************************* * Copyright 2014 Federal Chancellery Austria * MOA-ID has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. ******************************************************************************/ /* * Copyright 2003 Federal Chancellery Austria * MOA-ID has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. */ package at.gv.egovernment.moa.id.commons.utils.ssl; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URL; import java.security.GeneralSecurityException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.Base64Utils; import at.gv.egovernment.moa.util.MiscUtil; import at.gv.egovernment.moaspss.logging.LoggingContext; import at.gv.egovernment.moaspss.logging.LoggingContextManager; import iaik.pki.jsse.IAIKX509TrustManager; /** * TrustManager implementation featuring CRL checking (inherited from * IAIKX509TrustManager), plus server-end-SSL-certificate checking. * * @author Paul Ivancsics * @version $Id$ */ public class MOAIDTrustManager extends IAIKX509TrustManager { /** an x509Certificate array containing all accepted server certificates*/ private X509Certificate[] acceptedServerCertificates = null; /** * Constructor * @param acceptedServerCertificateStoreURL the url leading to the acceptedServer cert store * @throws GeneralSecurityException occurs on security errors * @throws IOException occurs on IO errors * @throws SSLConfigurationException */ public MOAIDTrustManager(String acceptedServerCertificateStoreURL) throws IOException, GeneralSecurityException, SSLConfigurationException { if (acceptedServerCertificateStoreURL != null && MiscUtil.isNotEmpty(acceptedServerCertificateStoreURL.trim())) { Logger.info("Initialize SSL-TrustStore with explicit accepted server-certificates"); buildAcceptedServerCertificates(acceptedServerCertificateStoreURL); } else { Logger.info("Initialize SSL-TrustStore without explicit accepted server-certificates"); acceptedServerCertificates = null; } } /** * Initializes the LoggingContextManager logging context. * Fixes a bug occuring in the case MOA-SP is called by API. * In this case, IAIKX509TrustManager uses the LogginConfig of MOA-SP. * This method must be called before a MOAIDTrustManager is constructed, * from every thread. */ public static void initializeLoggingContext() { if (LoggingContextManager.getInstance().getLoggingContext() == null) LoggingContextManager.getInstance().setLoggingContext( new LoggingContext(Thread.currentThread().getName())); } /** * Builds an Array of accepted server certificates from an URL, * and stores it in acceptedServerCertificates. * @param acceptedServerCertificateStoreURL file URL pointing to the directory * containing accepted server X509 certificates * @throws GeneralSecurityException on security errors * @throws IOException on any IO errors * @throws SSLConfigurationException */ private void buildAcceptedServerCertificates(String acceptedServerCertificateStoreURL) throws IOException, GeneralSecurityException, SSLConfigurationException { List certList = new ArrayList(); URL storeURL = new URL(acceptedServerCertificateStoreURL); //check URL to TrustStore if (storeURL.getFile() == null) { Logger.error("Can NOT initialize SSLTrustManager. TrustStore: " + acceptedServerCertificateStoreURL + " is NOT found"); throw new SSLConfigurationException("config.29", new Object[]{acceptedServerCertificateStoreURL, "File or Directory NOT found!"}); } File storeDir = new File(storeURL.getFile()); //check directory and files if (storeDir == null || storeDir.listFiles() == null) { Logger.error("Can NOT initialize SSLTrustManager. TrustStore: " + acceptedServerCertificateStoreURL + " is NOT found"); throw new SSLConfigurationException("config.29", new Object[]{acceptedServerCertificateStoreURL, "Files or Directory NOT found!"}); } // list certificate files in directory File[] certFiles = storeDir.listFiles(); for (int i = 0; i < certFiles.length; i++) { // for each: create an X509Certificate and store it in list File certFile = certFiles[i]; FileInputStream fis = null; try { fis = new FileInputStream(certFile.getPath()); CertificateFactory certFact = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate)certFact.generateCertificate(fis); certList.add(cert); } catch (Exception e) { Logger.warn("Can NOT import Certificate: " + certFile.getPath() + " into SSLTrustManager. Reason: " + e.getMessage()); if (Logger.isDebugEnabled()) { try { if (fis != null) Logger.debug("Certificate: " + Base64Utils.encode(fis)); } catch (Exception e1) { Logger.warn("Can NOT log content of certificate: " + certFile.getPath() + ". Reason: " + e.getMessage(), e); } } //throw new SSLConfigurationException("config.28", new Object[]{certFile.getPath(), e.getMessage()}, e); } finally { if (fis != null) fis.close(); } } // store acceptedServerCertificates acceptedServerCertificates = (X509Certificate[]) certList.toArray(new X509Certificate[0]); Logger.debug("Add #" + acceptedServerCertificates.length + " certificates as 'AcceptedServerCertificates' from: " + acceptedServerCertificateStoreURL ); } /** * Does additional server-end-SSL-certificate checking. * @see com.sun.net.ssl.X509TrustManager#isServerTrusted(java.security.cert.X509Certificate[]) */ public boolean isServerTrusted(X509Certificate[] certChain) { boolean trusted = super.isServerTrusted(certChain); if (! trusted || acceptedServerCertificates == null) return trusted; else { // check server-end-SSL-certificate with acceptedServerCertificates X509Certificate serverCert = certChain[0]; for (int i = 0; i < acceptedServerCertificates.length; i++) { X509Certificate acceptedServerCert = acceptedServerCertificates[i]; if (serverCert.equals(acceptedServerCert)) return true; } Logger.warn("SSL certificate validation FAILED."); return false; } } /** * In rare cases, this method is being called although it should not be. * @see com.sun.net.ssl.X509TrustManager#isClientTrusted(X509Certificate[]) */ public boolean isClientTrusted(java.security.cert.X509Certificate arg0[]) { return true; } // public void init(PKIConfiguration pkiConfig, PKIProfile pkiProfile) throws PKIException { // if (pkiProfile == null) { // throw new NullPointerException("pkiConfig parameter must not be null"); // // } // // TransactionId tid = new TransactionIdImpl("Init"); // log_.info(tid, "Setting up IAIKX509TrustManager", null); // if (pkiConfig != null) { // PKIFactory.getInstance().configure(pkiConfig, tid); //// log_.info(tid, "Registering LDAP protocol handler", null); //// String protocolHandlers = //// System.getProperty("java.protocol.handler.pkgs"); //// if (protocolHandlers == null) { //// protocolHandlers = "iaik.pki"; //// //// } else { //// protocolHandlers = protocolHandlers + "|iaik.pki"; //// //// } //// //// System.setProperty("java.protocol.handler.pkgs", protocolHandlers); //// log_.info(tid, "Registered protocol handlers: " + protocolHandlers, null); // // } // // pkiProfile_ = pkiProfile; // pkiFactory_ = PKIFactory.getInstance(); // initialized_ = true; // } }