package at.gv.egovernment.moa.id.util;
import iaik.pki.PKIConfiguration;
import iaik.pki.PKIException;
import iaik.pki.PKIFactory;
import iaik.pki.PKIProfile;
import iaik.pki.jsse.IAIKX509TrustManager;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.Security;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.SSLSocketFactory;
import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
import at.gv.egovernment.moa.id.config.ConfigurationException;
import at.gv.egovernment.moa.id.config.ConfigurationProvider;
import at.gv.egovernment.moa.id.config.ConnectionParameter;
import at.gv.egovernment.moa.id.iaik.config.PKIConfigurationImpl;
import at.gv.egovernment.moa.id.iaik.pki.PKIProfileImpl;
import at.gv.egovernment.moa.id.iaik.pki.jsse.MOAIDTrustManager;
import at.gv.egovernment.moa.logging.Logger;
import com.sun.net.ssl.HttpsURLConnection;
import com.sun.net.ssl.KeyManager;
import com.sun.net.ssl.SSLContext;
import com.sun.net.ssl.TrustManager;
/**
* Utility for a obtaining a secure socket factory using IAIKX509TrustManager
.
* This TrustManager
implementation features CRL checking.
* SSLUtils
caches secure socket factories for given ConnectionParameter
s.
*
* @author Paul Ivancsics
* @version $Id$
*/
public class SSLUtils {
/** SSLSocketFactory store, mapping URL->SSLSocketFactory **/
private static Map sslSocketFactories = new HashMap();
/**
* Initializes the SSLSocketFactory store.
*/
public static void initialize() {
sslSocketFactories = new HashMap();
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");
}
/**
* Creates an SSLSocketFactory
which utilizes an
* IAIKX509TrustManager
for the given trust store,
* and the given key store.
*
* @param conf configuration provider providing a generic properties pointing
* to trusted CA store and certificate store root
* @param connParam connection parameter containing the client key store settings
* to be used in case of client authentication;
* if connParam.getClientKeyStore() == null
, client authentication
* is assumed to be disabled
* @return SSLSocketFactory
to be used by an HttpsURLConnection
* @throws IOException thrown while reading key store file
* @throws GeneralSecurityException thrown while creating the socket factory
* @throws ConfigurationException on invalid configuration data
* @throws PKIException while initializing the IAIKX509TrustManager
*/
public static SSLSocketFactory getSSLSocketFactory(
ConfigurationProvider conf,
ConnectionParameter connParam)
throws IOException, GeneralSecurityException, ConfigurationException, PKIException {
Logger.debug("Get SSLSocketFactory for " + connParam.getUrl());
// retrieve SSLSocketFactory if already created
SSLSocketFactory ssf = (SSLSocketFactory)sslSocketFactories.get(connParam.getUrl());
if (ssf != null)
return ssf;
// else create new SSLSocketFactory
String trustStoreURL = conf.getTrustedCACertificates();
if (trustStoreURL == null)
throw new ConfigurationException(
"config.08", new Object[] {"TrustedCACertificates"});
String acceptedServerCertURL = connParam.getAcceptedServerCertificates();
TrustManager[] tms = getTrustManagers(conf, trustStoreURL, acceptedServerCertURL);
KeyManager[] kms = at.gv.egovernment.moa.util.SSLUtils.getKeyManagers(
"pkcs12", connParam.getClientKeyStore(), connParam.getClientKeyStorePassword());
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kms, tms, null);
ssf = ctx.getSocketFactory();
// store SSLSocketFactory
sslSocketFactories.put(connParam.getUrl(), ssf);
return ssf;
}
/**
* Initializes an IAIKX509TrustManager
for a given trust store,
* using configuration data.
*
* @param conf MOA-ID configuration provider
* @param trustStoreURL trust store URL
* @param acceptedServerCertURL file URL pointing to directory containing accepted server SSL certificates
* @return TrustManager
array containing the IAIKX509TrustManager
* @throws ConfigurationException on invalid configuration data
* @throws IOException on data-reading problems
* @throws PKIException while initializing the IAIKX509TrustManager
*/
public static TrustManager[] getTrustManagers(
ConfigurationProvider conf, String trustStoreURL, String acceptedServerCertURL)
throws ConfigurationException, PKIException, IOException, GeneralSecurityException {
PKIConfiguration cfg = null;
if (! PKIFactory.getInstance().isAlreadyConfigured())
cfg = new PKIConfigurationImpl(conf);
String boolString = conf.getGenericConfigurationParameter(ConfigurationProvider.TRUST_MANAGER_REVOCATION_CHECKING);
//not using BoolUtils because default value hast to be true!
boolean checkRevocation = !("false".equals(boolString) || "0".equals(boolString));
PKIProfile profile = new PKIProfileImpl(trustStoreURL, checkRevocation);
// This call fixes a bug occuring when PKIConfiguration is
// initialized by the MOA-SP initialization code, in case
// MOA-SP is called by API
MOAIDTrustManager.initializeLoggingContext();
IAIKX509TrustManager tm = new MOAIDTrustManager(acceptedServerCertURL);
tm.init(cfg, profile);
return new TrustManager[] {tm};
}
/**
* Reads a file, given by URL, into a byte array,
* securing the connection by IAIKX509TrustManager.
* @param connParam containing URL and accepted server certificates
* @param conf ConfigurationProvider for reading
* @return String representation of content
* @throws ConfigurationException on invalid configuration data
* @throws PKIException on invalid configuration data
* @throws IOException on data-reading problems
* @throws GeneralSecurityException on security issues
*/
public static String readHttpsURL(ConfigurationProvider conf, ConnectionParameter connParam)
throws ConfigurationException, PKIException, IOException, GeneralSecurityException {
URL url = new URL(connParam.getUrl());
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setDoInput(true);
SSLSocketFactory sslSocketFactory = getSSLSocketFactory(conf, connParam);
conn.setSSLSocketFactory(sslSocketFactory);
conn.connect();
String contentType = conn.getContentType();
RE regExp = null;
try {
regExp = new RE("(;.*charset=)(\"*)(.*[^\"])");
} catch (RESyntaxException e) {
//RESyntaxException is not possible = expr. is costant
}
boolean charsetSupplied = regExp.match(contentType);
String encoding = "ISO-8859-1"; //default HTTP encoding
if (charsetSupplied) {
encoding = regExp.getParen(3);
}
InputStream instream = new BufferedInputStream(conn.getInputStream());
InputStreamReader isr = new InputStreamReader(instream, encoding);
Reader in = new BufferedReader(isr);
int ch;
StringBuffer buffer = new StringBuffer();
while ((ch = in.read()) > -1) {
buffer.append((char)ch);
}
in.close();
conn.disconnect();
return buffer.toString();
}
}