/*******************************************************************************
* 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.error("Can NOT initialize SSLTrustManager. Certificate: " + certFile.getPath()
+ " is not loadable, 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;
// }
}