/* Copyright (c) 2001-2008, The HSQL Development Group * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the HSQL Development Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.hsqldb; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.security.PrivateKey; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactorySpi; import javax.net.ssl.ManagerFactoryParameters; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactorySpi; import javax.net.ssl.X509ExtendedKeyManager; import org.apache.log4j.Logger; import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager; /** * We need to override the way that hsqldb gets its secure sockets to use our internally mananged credentials. */ public final class HsqlSocketFactorySecure extends HsqlSocketFactory { private static Logger LOG = Logger.getLogger( HsqlSocketFactorySecure.class ); protected SSLSocketFactory socketFactory; protected SSLServerSocketFactory serverSocketFactory; private static final String PROTOCOL = "TLS"; private static SSLContext SERVER_CONTEXT = null; private static SSLContext CLIENT_CONTEXT = null; private static String KEYS = System.getProperty("euca.var.dir") + File.separator + "keys"; private static String KEYSTORE = KEYS + File.separator + "euca.p12"; private static String EUCALYPTUS = "eucalyptus"; private static PrivateKey pk = null; private static X509Certificate cert = null; static { SSLContext serverContext = null; SSLContext clientContext = null; System.setProperty( "javax.net.ssl.trustStore", KEYSTORE ); System.setProperty( "javax.net.ssl.keyStore", KEYSTORE ); System.setProperty( "javax.net.ssl.trustStoreType", "PKCS12" ); System.setProperty( "javax.net.ssl.keyStoreType", "PKCS12" ); System.setProperty( "javax.net.ssl.trustStorePassword", EUCALYPTUS ); System.setProperty( "javax.net.ssl.keyStorePassword", EUCALYPTUS ); System.setProperty( "javax.net.debug", "none" );//set this to "ssl" for debugging. try { serverContext = SSLContext.getInstance( "TLS" ); serverContext.init( HsqlSocketFactorySecure.SimpleKeyManager.getKeyManagers( ), HsqlSocketFactorySecure.SimpleTrustManager.getTrustManagers( ), null ); } catch ( Exception e ) { LOG.debug( e, e ); throw new Error( "Failed to initialize the server-side SSLContext", e ); } try { clientContext = SSLContext.getInstance( "TLS" ); clientContext.init( HsqlSocketFactorySecure.SimpleKeyManager.getKeyManagers( ), HsqlSocketFactorySecure.SimpleTrustManager.getTrustManagers( ), null ); } catch ( Exception e ) { LOG.debug( e, e ); throw new Error( "Failed to initialize the client-side SSLContext", e ); } loadKeystore( ); SERVER_CONTEXT = serverContext; CLIENT_CONTEXT = clientContext; } private static void loadKeystore( ) { FileInputStream fin = null; try { KeyStore keyStore = KeyStore.getInstance( "pkcs12", "BC" ); if ( ( new File( KEYSTORE ) ).exists( ) ) { fin = new FileInputStream( KEYSTORE ); keyStore.load( fin, EUCALYPTUS.toCharArray( ) ); pk = ( PrivateKey ) keyStore.getKey( EUCALYPTUS, EUCALYPTUS.toCharArray( ) ); cert = ( X509Certificate ) keyStore.getCertificate( EUCALYPTUS ); } } catch ( Throwable t ) { LOG.error( t, t ); } finally { if ( fin != null ) { try { fin.close(); } catch ( IOException e ) { LOG.error ( e ); } } } } public static SSLContext getServerContext( ) { return SERVER_CONTEXT; } public static SSLEngine getServerEngine() { SSLEngine engine = HsqlSocketFactorySecure.getServerContext( ).createSSLEngine( ); engine.setUseClientMode( false ); return engine; } public static SSLContext getClientContext( ) { return CLIENT_CONTEXT; } public static class SimpleKeyManager extends KeyManagerFactorySpi { private static KeyManager singleton = new SimplePKCS12KeyManager( ); public static KeyManager[] getKeyManagers( ) { return new KeyManager[] { singleton }; } @Override protected KeyManager[] engineGetKeyManagers( ) { return new KeyManager[] { singleton }; } @Override protected void engineInit( ManagerFactoryParameters spec ) throws InvalidAlgorithmParameterException {} @Override protected void engineInit( KeyStore ks, char[] password ) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {} public static class SimplePKCS12KeyManager extends X509ExtendedKeyManager { @Override public String chooseClientAlias( String[] arg0, Principal[] arg1, Socket arg2 ) { return EUCALYPTUS; } @Override public String chooseServerAlias( String arg0, Principal[] arg1, Socket arg2 ) { return EUCALYPTUS; } @Override public X509Certificate[] getCertificateChain( String arg0 ) { if ( EUCALYPTUS.equals( arg0 ) ) { return trustedCerts; } else { return null; } } @Override public String[] getClientAliases( String arg0, Principal[] arg1 ) { return new String[] { EUCALYPTUS }; } @Override public PrivateKey getPrivateKey( String arg0 ) { if ( EUCALYPTUS.equals( arg0 ) ) { return trustedKey; } else { return null; } } @Override public String[] getServerAliases( String arg0, Principal[] arg1 ) { return new String[] { EUCALYPTUS }; } @Override public String chooseEngineClientAlias( String[] keyType, Principal[] issuers, SSLEngine engine ) { return EUCALYPTUS; } @Override public String chooseEngineServerAlias( String keyType, Principal[] issuers, SSLEngine engine ) { return EUCALYPTUS; } } } private static PrivateKey trustedKey = null; private static X509Certificate trusted = getTrustedCertificate( ); private static X509Certificate[] trustedCerts = new X509Certificate[] { trusted }; private static X509Certificate getTrustedCertificate( ) { try { synchronized ( HsqlSocketFactorySecure.class ) { if ( trusted == null ) { trusted = cert; trustedKey = pk; } return trusted; } } catch ( Exception e ) { LOG.error( e, e ); throw new RuntimeException( e ); } } public static class SimpleTrustManager extends TrustManagerFactorySpi { private static Logger LOG = Logger.getLogger( HsqlSocketFactorySecure.SimpleTrustManager.class ); private static final TrustManager singleton = new SimpleX509TrustManager( ); public static TrustManager[] getTrustManagers( ) { return new TrustManager[] { singleton }; } @Override protected TrustManager[] engineGetTrustManagers( ) { return getTrustManagers( ); } @Override protected void engineInit( KeyStore keystore ) throws KeyStoreException {} @Override protected void engineInit( ManagerFactoryParameters managerFactoryParameters ) throws InvalidAlgorithmParameterException {} public static class SimpleX509TrustManager extends X509ExtendedTrustManager { @Override public void checkClientTrusted( X509Certificate[] arg0, String arg1 ) throws CertificateException {} @Override public void checkServerTrusted( X509Certificate[] chain, String authType ) throws CertificateException {} @Override public X509Certificate[] getAcceptedIssuers( ) { return trustedCerts; } @Override public void checkClientTrusted( X509Certificate[] arg0, String arg1, String arg2, String arg3 ) throws CertificateException {} @Override public void checkServerTrusted( X509Certificate[] arg0, String arg1, String arg2, String arg3 ) throws CertificateException {} } } protected HsqlSocketFactorySecure( ) throws Exception {} public void configureSocket( Socket socket ) { super.configureSocket( socket ); } public ServerSocket createServerSocket( int port ) throws Exception { return ( SSLServerSocket ) getServerSocketFactoryImpl( ).createServerSocket( port ); } public ServerSocket createServerSocket( int port, String address ) throws Exception { InetAddress addr = InetAddress.getByName( address ); return ( SSLServerSocket ) getServerSocketFactoryImpl( ).createServerSocket( port, 128, addr ); } public Socket createSocket( String host, int port ) throws Exception { SSLSocket socket = ( SSLSocket ) getSocketFactoryImpl( ).createSocket( host, port ); socket.startHandshake( ); return socket; } public boolean isSecure( ) { return true; } protected SSLServerSocketFactory getServerSocketFactoryImpl( ) throws Exception { synchronized ( HsqlSocketFactorySecure.class ) { if ( serverSocketFactory == null ) { serverSocketFactory = HsqlSocketFactorySecure.getServerContext( ).getServerSocketFactory( ); } } return ( SSLServerSocketFactory ) serverSocketFactory; } protected SSLSocketFactory getSocketFactoryImpl( ) throws Exception { synchronized ( HsqlSocketFactorySecure.class ) { if ( socketFactory == null ) { socketFactory = HsqlSocketFactorySecure.getClientContext( ).getSocketFactory( ); } } return ( SSLSocketFactory ) socketFactory; } }