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 ConnectionParameters. * * @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(); } }