316382: support a more strict SSL option with certificates 

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/sandbox/trunk@2749 7e9141cc-0065-0410-87d8-b60c137991c4
diff --git a/jetty-exssl/pom.xml b/jetty-exssl/pom.xml
index 2cd3556..e35eafa 100644
--- a/jetty-exssl/pom.xml
+++ b/jetty-exssl/pom.xml
@@ -74,10 +74,25 @@
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-servlet</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-http</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-client</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.eclipse.jetty</groupId>
+        <artifactId>jetty-util</artifactId>
+        <version>${project.version}</version>
+    </dependency>
+    <dependency>
         <groupId>org.eclipse.jetty.toolchain</groupId>
         <artifactId>jetty-test-helper</artifactId>
         <scope>test</scope>
diff --git a/jetty-exssl/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-exssl/src/main/java/org/eclipse/jetty/client/HttpClient.java
new file mode 100644
index 0000000..5bf5fc9
--- /dev/null
+++ b/jetty-exssl/src/main/java/org/eclipse/jetty/client/HttpClient.java
@@ -0,0 +1,817 @@
+// ========================================================================
+// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+
+package org.eclipse.jetty.client;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.UnknownHostException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import org.eclipse.jetty.client.security.Authentication;
+import org.eclipse.jetty.client.security.RealmResolver;
+import org.eclipse.jetty.client.security.SecurityListener;
+import org.eclipse.jetty.http.HttpBuffers;
+import org.eclipse.jetty.http.HttpSchemes;
+import org.eclipse.jetty.http.security.Password;
+import org.eclipse.jetty.io.Buffer;
+import org.eclipse.jetty.io.ByteArrayBuffer;
+import org.eclipse.jetty.io.SslContextFactory;
+import org.eclipse.jetty.io.nio.DirectNIOBuffer;
+import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
+import org.eclipse.jetty.util.Attributes;
+import org.eclipse.jetty.util.AttributesMap;
+import org.eclipse.jetty.util.component.LifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.eclipse.jetty.util.thread.ThreadPool;
+import org.eclipse.jetty.util.thread.Timeout;
+
+/**
+ * Http Client.
+ * <p/>
+ * HttpClient is the main active component of the client API implementation.
+ * It is the opposite of the Connectors in standard Jetty, in that it listens
+ * for responses rather than requests.   Just like the connectors, there is a
+ * blocking socket version and a non-blocking NIO version (implemented as nested classes
+ * selected by {@link #setConnectorType(int)}).
+ * <p/>
+ * The an instance of {@link HttpExchange} is passed to the {@link #send(HttpExchange)} method
+ * to send a request.  The exchange contains both the headers and content (source) of the request
+ * plus the callbacks to handle responses.   A HttpClient can have many exchanges outstanding
+ * and they may be queued on the {@link HttpDestination} waiting for a {@link HttpConnection},
+ * queued in the {@link HttpConnection} waiting to be transmitted or pipelined on the actual
+ * TCP/IP connection waiting for a response.
+ * <p/>
+ * The {@link HttpDestination} class is an aggregation of {@link HttpConnection}s for the
+ * same host, port and protocol.   A destination may limit the number of connections
+ * open and they provide a pool of open connections that may be reused.   Connections may also
+ * be allocated from a destination, so that multiple request sources are not multiplexed
+ * over the same connection.
+ *
+ * @see HttpExchange
+ * @see HttpDestination
+ */
+public class HttpClient extends HttpBuffers implements Attributes
+{
+    public static final int CONNECTOR_SOCKET = 0;
+    public static final int CONNECTOR_SELECT_CHANNEL = 2;
+
+    private int _connectorType = CONNECTOR_SELECT_CHANNEL;
+    private boolean _useDirectBuffers = true;
+    private int _maxConnectionsPerAddress = Integer.MAX_VALUE;
+    private ConcurrentMap<Address, HttpDestination> _destinations = new ConcurrentHashMap<Address, HttpDestination>();
+    ThreadPool _threadPool;
+    Connector _connector;
+    private long _idleTimeout = 20000;
+    private long _timeout = 320000;
+    private int _connectTimeout = 75000;
+    private Timeout _timeoutQ = new Timeout();
+    private Timeout _idleTimeoutQ = new Timeout();
+    private Address _proxy;
+    private Authentication _proxyAuthentication;
+    private Set<String> _noProxy;
+    private int _maxRetries = 3;
+    private int _maxRedirects = 20;
+    private LinkedList<String> _registeredListeners;
+
+    private SslContextFactory _sslContextFactory;
+
+    private RealmResolver _realmResolver;
+
+    private AttributesMap _attributes=new AttributesMap();
+    
+    public HttpClient()
+    {
+        this(new SslContextFactory());
+    }
+    
+    public HttpClient(SslContextFactory sslContextFactory)
+    {
+        _sslContextFactory = sslContextFactory;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public void dump()
+    {
+        try
+        {
+            for (Map.Entry<Address, HttpDestination> entry : _destinations.entrySet())
+            {
+                Log.info("\n" + entry.getKey() + ":");
+                entry.getValue().dump();
+            }
+        }
+        catch(Exception e)
+        {
+            Log.warn(e);
+        }
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public void send(HttpExchange exchange) throws IOException
+    {
+        boolean ssl = HttpSchemes.HTTPS_BUFFER.equalsIgnoreCase(exchange.getScheme());
+        exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_CONNECTION);
+        HttpDestination destination = getDestination(exchange.getAddress(), ssl);
+        destination.send(exchange);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return the threadPool
+     */
+    public ThreadPool getThreadPool()
+    {
+        return _threadPool;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param threadPool the threadPool to set
+     */
+    public void setThreadPool(ThreadPool threadPool)
+    {
+        _threadPool = threadPool;
+    }
+
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param name
+     * @return Attribute associated with client
+     */
+    public Object getAttribute(String name)
+    {
+        return _attributes.getAttribute(name);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return names of attributes associated with client
+     */
+    public Enumeration getAttributeNames()
+    {
+        return _attributes.getAttributeNames();
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param name
+     */
+    public void removeAttribute(String name)
+    {
+        _attributes.removeAttribute(name);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Set an attribute on the HttpClient.
+     * Attributes are not used by the client, but are provided for
+     * so that users of a shared HttpClient may share other structures.
+     * @param name
+     * @param attribute
+     */
+    public void setAttribute(String name, Object attribute)
+    {
+        _attributes.setAttribute(name,attribute);
+    }
+
+    /* ------------------------------------------------------------ */
+    public void clearAttributes()
+    {
+        _attributes.clearAttributes();
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public HttpDestination getDestination(Address remote, boolean ssl) throws UnknownHostException, IOException
+    {
+        if (remote == null)
+            throw new UnknownHostException("Remote socket address cannot be null.");
+
+        HttpDestination destination = _destinations.get(remote);
+        if (destination == null)
+        {
+            destination = new HttpDestination(this, remote, ssl, _maxConnectionsPerAddress);
+            if (_proxy != null && (_noProxy == null || !_noProxy.contains(remote.getHost())))
+            {
+                destination.setProxy(_proxy);
+                if (_proxyAuthentication != null)
+                    destination.setProxyAuthentication(_proxyAuthentication);
+            }
+            HttpDestination other =_destinations.putIfAbsent(remote, destination);
+            if (other!=null)
+                destination=other;
+        }
+        return destination;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void schedule(Timeout.Task task)
+    {
+        _timeoutQ.schedule(task);
+    }
+
+    public void schedule(Timeout.Task task, long timeout)
+    {
+        _timeoutQ.schedule(task, timeout);
+    }
+
+    /* ------------------------------------------------------------ */
+    public void scheduleIdle(Timeout.Task task)
+    {
+        _idleTimeoutQ.schedule(task);
+    }
+
+    /* ------------------------------------------------------------ */
+    public void cancel(Timeout.Task task)
+    {
+        task.cancel();
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Get whether the connector can use direct NIO buffers.
+     */
+    public boolean getUseDirectBuffers()
+    {
+        return _useDirectBuffers;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Set a RealmResolver for client Authentication.
+     * If a realmResolver is set, then the HttpDestinations created by
+     * this client will instantiate a {@link SecurityListener} so that
+     * BASIC and DIGEST authentication can be performed.
+     * @param resolver
+     */
+    public void setRealmResolver(RealmResolver resolver)
+    {
+        _realmResolver = resolver;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * returns the SecurityRealmResolver reg_realmResolveristered with the HttpClient or null
+     *
+     * @return the SecurityRealmResolver reg_realmResolveristered with the HttpClient or null
+     */
+    public RealmResolver getRealmResolver()
+    {
+        return _realmResolver;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean hasRealms()
+    {
+        return _realmResolver == null ? false : true;
+    }
+
+
+    /**
+     * Registers a listener that can listen to the stream of execution between the client and the
+     * server and influence events.  Sequential calls to the method wrapper sequentially wrap the preceding
+     * listener in a delegation model.
+     * <p/>
+     * NOTE: the SecurityListener is a special listener which doesn't need to be added via this
+     * mechanic, if you register security realms then it will automatically be added as the top listener of the
+     * delegation stack.
+     *
+     * @param listenerClass
+     */
+    public void registerListener(String listenerClass)
+    {
+        if (_registeredListeners == null)
+        {
+            _registeredListeners = new LinkedList<String>();
+        }
+        _registeredListeners.add(listenerClass);
+    }
+
+    /* ------------------------------------------------------------ */
+    public LinkedList<String> getRegisteredListeners()
+    {
+        return _registeredListeners;
+    }
+
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Set to use NIO direct buffers.
+     *
+     * @param direct If True (the default), the connector can use NIO direct
+     *               buffers. Some JVMs have memory management issues (bugs) with
+     *               direct buffers.
+     */
+    public void setUseDirectBuffers(boolean direct)
+    {
+        _useDirectBuffers = direct;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Get the type of connector (socket, blocking or select) in use.
+     */
+    public int getConnectorType()
+    {
+        return _connectorType;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setConnectorType(int connectorType)
+    {
+        this._connectorType = connectorType;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.http.HttpBuffers#newRequestBuffer(int)
+     */
+    @Override
+    protected Buffer newRequestBuffer(int size)
+    {
+        if (_connectorType == CONNECTOR_SOCKET)
+            return new ByteArrayBuffer(size);
+        return _useDirectBuffers?new DirectNIOBuffer(size):new IndirectNIOBuffer(size);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.http.HttpBuffers#newRequestHeader(int)
+     */
+    @Override
+    protected Buffer newRequestHeader(int size)
+    {
+        if (_connectorType == CONNECTOR_SOCKET)
+            return new ByteArrayBuffer(size);
+        return new IndirectNIOBuffer(size);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.http.HttpBuffers#newResponseBuffer(int)
+     */
+    @Override
+    protected Buffer newResponseBuffer(int size)
+    {
+        if (_connectorType == CONNECTOR_SOCKET)
+            return new ByteArrayBuffer(size);
+        return _useDirectBuffers?new DirectNIOBuffer(size):new IndirectNIOBuffer(size);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.http.HttpBuffers#newResponseHeader(int)
+     */
+    @Override
+    protected Buffer newResponseHeader(int size)
+    {
+        if (_connectorType == CONNECTOR_SOCKET)
+            return new ByteArrayBuffer(size);
+        return new IndirectNIOBuffer(size);
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    @Override
+    protected boolean isRequestHeader(Buffer buffer)
+    {
+        if (_connectorType == CONNECTOR_SOCKET)
+            return buffer instanceof ByteArrayBuffer;
+        return buffer instanceof IndirectNIOBuffer;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    @Override
+    protected boolean isResponseHeader(Buffer buffer)
+    {
+        if (_connectorType == CONNECTOR_SOCKET)
+            return buffer instanceof ByteArrayBuffer;
+        return buffer instanceof IndirectNIOBuffer;
+    }
+
+
+    /* ------------------------------------------------------------ */
+    public int getMaxConnectionsPerAddress()
+    {
+        return _maxConnectionsPerAddress;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setMaxConnectionsPerAddress(int maxConnectionsPerAddress)
+    {
+        _maxConnectionsPerAddress = maxConnectionsPerAddress;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    protected void doStart() throws Exception
+    {
+        super.doStart();
+
+        _timeoutQ.setDuration(_timeout);
+        _timeoutQ.setNow();
+        _idleTimeoutQ.setDuration(_idleTimeout);
+        _idleTimeoutQ.setNow();
+
+        if (_threadPool == null)
+        {
+            QueuedThreadPool pool = new QueuedThreadPool();
+            pool.setMaxThreads(16);
+            pool.setDaemon(true);
+            pool.setName("HttpClient");
+            _threadPool = pool;
+        }
+
+        if (_threadPool instanceof LifeCycle)
+        {
+            ((LifeCycle)_threadPool).start();
+        }
+
+
+        if (_connectorType == CONNECTOR_SELECT_CHANNEL)
+        {
+
+            _connector = new SelectConnector(this);
+        }
+        else
+        {
+            _connector = new SocketConnector(this);
+        }
+        _connector.start();
+
+        _threadPool.dispatch(new Runnable()
+        {
+            public void run()
+            {
+                while (isRunning())
+                {
+                    _timeoutQ.tick(System.currentTimeMillis());
+                    _idleTimeoutQ.tick(_timeoutQ.getNow());
+                    try
+                    {
+                        Thread.sleep(200);
+                    }
+                    catch (InterruptedException e)
+                    {
+                    }
+                }
+            }
+        });
+
+    }
+
+    /* ------------------------------------------------------------ */
+    long getNow()
+    {
+        return _timeoutQ.getNow();
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    protected void doStop() throws Exception
+    {
+        _connector.stop();
+        _connector = null;
+        if (_threadPool instanceof LifeCycle)
+        {
+            ((LifeCycle)_threadPool).stop();
+        }
+        for (HttpDestination destination : _destinations.values())
+        {
+            destination.close();
+        }
+
+        _timeoutQ.cancelAll();
+        _idleTimeoutQ.cancelAll();
+        super.doStop();
+    }
+
+    /* ------------------------------------------------------------ */
+    interface Connector extends LifeCycle
+    {
+        public void startConnection(HttpDestination destination) throws IOException;
+    }
+
+    /**
+     * if a keystore location has been provided then client will attempt to use it as the keystore,
+     * otherwise we simply ignore certificates and run with a loose ssl context.
+     *
+     * @return the SSL context
+     */
+    protected SSLContext getSSLContext()
+    {
+        return _sslContextFactory.getClientSslContext();
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return the period in milliseconds a {@link HttpConnection} can be idle for before it is closed.
+     */
+    public long getIdleTimeout()
+    {
+        return _idleTimeout;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param ms the period in milliseconds a {@link HttpConnection} can be idle for before it is closed.
+     */
+    public void setIdleTimeout(long ms)
+    {
+        _idleTimeout = ms;
+    }
+
+    /**
+     * @return the period in ms that an exchange will wait for a response from the server.
+     * @deprecated use {@link #getTimeout()} instead.
+     */
+    @Deprecated
+    public int getSoTimeout()
+    {
+        return Long.valueOf(getTimeout()).intValue();
+    }
+
+    /**
+     * @deprecated use {@link #setTimeout(long)} instead.
+     * @param timeout the period in ms that an exchange will wait for a response from the server.
+     */
+    @Deprecated
+    public void setSoTimeout(int timeout)
+    {
+        setTimeout(timeout);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return the period in ms that an exchange will wait for a response from the server.
+     */
+    public long getTimeout()
+    {
+        return _timeout;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param timeout the period in ms that an exchange will wait for a response from the server.
+     */
+    public void setTimeout(long timeout)
+    {
+        _timeout = timeout;
+    }
+
+    /**
+     * @return the period in ms before timing out an attempt to connect
+     */
+    public int getConnectTimeout()
+    {
+        return _connectTimeout;
+    }
+
+    /**
+     * @param connectTimeout the period in ms before timing out an attempt to connect
+     */
+    public void setConnectTimeout(int connectTimeout)
+    {
+        this._connectTimeout = connectTimeout;
+    }
+
+    /* ------------------------------------------------------------ */
+    public Address getProxy()
+    {
+        return _proxy;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setProxy(Address proxy)
+    {
+        this._proxy = proxy;
+    }
+
+    /* ------------------------------------------------------------ */
+    public Authentication getProxyAuthentication()
+    {
+        return _proxyAuthentication;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setProxyAuthentication(Authentication authentication)
+    {
+        _proxyAuthentication = authentication;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isProxied()
+    {
+        return this._proxy != null;
+    }
+
+    /* ------------------------------------------------------------ */
+    public Set<String> getNoProxy()
+    {
+        return _noProxy;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setNoProxy(Set<String> noProxyAddresses)
+    {
+        _noProxy = noProxyAddresses;
+    }
+
+    /* ------------------------------------------------------------ */
+    public int maxRetries()
+    {
+        return _maxRetries;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setMaxRetries(int retries)
+    {
+        _maxRetries = retries;
+    }
+
+    /* ------------------------------------------------------------ */
+    public int maxRedirects()
+    {
+        return _maxRedirects;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setMaxRedirects(int redirects)
+    {
+        _maxRedirects = redirects;
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getTrustStoreLocation()
+    {
+        return _sslContextFactory.getTruststore();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setTrustStoreLocation(String trustStoreLocation)
+    {
+        _sslContextFactory.setTruststore(trustStoreLocation);
+    }
+
+    public InputStream getTrustStoreInputStream()
+    {
+        return _sslContextFactory.getTruststoreInputStream();
+    }
+
+    public void setTrustStoreInputStream(InputStream trustStoreInputStream)
+    {
+        _sslContextFactory.setTruststoreInputStream(trustStoreInputStream);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getKeyStoreLocation()
+    {
+        return _sslContextFactory.getKeystore();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setKeyStoreLocation(String keyStoreLocation)
+    {
+        _sslContextFactory.setKeystore(keyStoreLocation);
+    }
+
+    public InputStream getKeyStoreInputStream()
+    {
+        return _sslContextFactory.getKeystoreInputStream();
+    }
+
+    public void setKeyStoreInputStream(InputStream keyStoreInputStream)
+    {
+        _sslContextFactory.setKeystoreInputStream(keyStoreInputStream);
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setKeyStorePassword(String keyStorePassword)
+    {
+        _sslContextFactory.setKeyStorePassword(keyStorePassword);
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setKeyManagerPassword(String keyManagerPassword)
+    {
+        _sslContextFactory.setKeyManagerPassword(keyManagerPassword);
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setTrustStorePassword(String trustStorePassword)
+    {
+        _sslContextFactory.setTrustStorePassword(trustStorePassword);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getKeyStoreType()
+    {
+        return _sslContextFactory.getKeystoreType();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setKeyStoreType(String keyStoreType)
+    {
+        _sslContextFactory.setKeystoreType(keyStoreType);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getTrustStoreType()
+    {
+        return _sslContextFactory.getTruststoreType();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setTrustStoreType(String trustStoreType)
+    {
+        _sslContextFactory.setTruststoreType(trustStoreType);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getKeyManagerAlgorithm()
+    {
+        return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setKeyManagerAlgorithm(String keyManagerAlgorithm)
+    {
+        _sslContextFactory.setSslKeyManagerFactoryAlgorithm(keyManagerAlgorithm);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getTrustManagerAlgorithm()
+    {
+        return _sslContextFactory.getTrustManagerFactoryAlgorithm();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setTrustManagerAlgorithm(String trustManagerAlgorithm)
+    {
+        _sslContextFactory.setTrustManagerFactoryAlgorithm(trustManagerAlgorithm);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getProtocol()
+    {
+        return _sslContextFactory.getProtocol();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setProtocol(String protocol)
+    {
+        _sslContextFactory.setProtocol(protocol);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getProvider()
+    {
+        return _sslContextFactory.getProvider();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setProvider(String provider)
+    {
+        setProvider(provider);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getSecureRandomAlgorithm()
+    {
+        return _sslContextFactory.getSecureRandomAlgorithm();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setSecureRandomAlgorithm(String secureRandomAlgorithm)
+    {
+        _sslContextFactory.setSecureRandomAlgorithm(secureRandomAlgorithm);
+    }
+}
diff --git a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/CertificateValidator.java b/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/CertificateValidator.java
deleted file mode 100644
index a467dfc..0000000
--- a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/CertificateValidator.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package org.eclipse.jetty.exssl;
-
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.cert.CRL;
-import java.security.cert.CertPathBuilder;
-import java.security.cert.CertPathBuilderResult;
-import java.security.cert.CertPathValidator;
-import java.security.cert.CertStore;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CollectionCertStoreParameters;
-import java.security.cert.PKIXBuilderParameters;
-import java.security.cert.X509CertSelector;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collection;
-
-import org.eclipse.jetty.util.log.Log;
-
-public class CertificateValidator
-{
-    private KeyStore _keyStore;
-    private KeyStore _trustStore;
-    private Collection<? extends CRL> _crls;
-    private int _maxCertPathLength = -1;
-    
-    public CertificateValidator(KeyStore keyStore, KeyStore trustStore, Collection<? extends CRL> crls)
-    {
-        _keyStore = keyStore;
-        _trustStore = trustStore;
-        _crls = crls;
-    }
-
-    public String validate(String keyAlias) throws CertificateException
-    {
-        String result = null;
-
-        if (keyAlias != null)
-        {
-            try
-            {
-                validate(_keyStore.getCertificate(keyAlias));
-            }
-            catch (KeyStoreException ex)
-            {
-                Log.debug(ex);
-                throw new CertificateException("Unable to validate certificate for alias [" +
-                                               keyAlias + "]: " + ex.getMessage());
-            }
-            result = keyAlias;            
-        }
-        
-        return result;
-    }
-    
-    public void validate(Certificate cert) throws CertificateException
-    {
-        if (cert != null && cert instanceof X509Certificate)
-        {
-            ((X509Certificate)cert).checkValidity();
-            
-            String certAlias = "[none]";
-            try
-            {
-                certAlias = _keyStore.getCertificateAlias((X509Certificate)cert);
-                Certificate[] certChain = _keyStore.getCertificateChain(certAlias);
-                   
-                ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
-                for (Certificate item : certChain)
-                {
-                    if (!(item instanceof X509Certificate))
-                    {
-                        throw new CertificateException("Invalid certificate type in chain");
-                    }
-                    certList.add((X509Certificate)item);
-                }
-
-                if (certList.isEmpty())
-                {
-                    throw new CertificateException("Invalid certificate chain");
-                    
-                }
-
-                X509CertSelector certSelect = new X509CertSelector();
-                certSelect.setCertificate(certList.get(0));
-                
-                // Configure certification path builder parameters
-                PKIXBuilderParameters pbParams = new PKIXBuilderParameters(_trustStore, certSelect);
-                pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList)));
-
-                // Set static Certificate Revocation List
-                if (_crls != null && !_crls.isEmpty())
-                {
-                    pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(_crls)));
-                }
-
-                // Enable revocation checking
-                pbParams.setRevocationEnabled(true);
-
-                // Set maximum certification path length
-                pbParams.setMaxPathLength(_maxCertPathLength);
- 
-                // Build certification path
-                CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);               
-                
-                // Validate certification path
-                CertPathValidator.getInstance("PKIX").validate(buildResult.getCertPath(),pbParams);
-            }
-            catch (Exception ex)
-            {
-                Log.debug(ex);
-                throw new CertificateException("Unable to validate certificate for alias [" +
-                                               certAlias + "]: " + ex.getMessage());
-            }
-        } 
-    }
-
-    public int getMaxCertPathLength()
-    {
-        return _maxCertPathLength;
-    }
-
-    public void setMaxCertPathLength(int maxCertPathLength)
-    {
-        _maxCertPathLength = maxCertPathLength;
-    }
-
-    public KeyStore getKeyStore()
-    {
-        return _keyStore;
-    }
-
-    public KeyStore getTrustStore()
-    {
-        return _trustStore;
-    }
-
-    public Collection<? extends CRL> getCrls()
-    {
-        return _crls;
-    }
-}
diff --git a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSelectChannelConnector.java b/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSelectChannelConnector.java
index c5dfabc..1508157 100644
--- a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSelectChannelConnector.java
+++ b/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSelectChannelConnector.java
@@ -28,6 +28,7 @@
 import org.eclipse.jetty.io.Buffers;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.SslContextFactory;
 import org.eclipse.jetty.io.ThreadLocalBuffers;
 import org.eclipse.jetty.io.bio.SocketEndPoint;
 import org.eclipse.jetty.io.nio.DirectNIOBuffer;
@@ -53,19 +54,19 @@
  */
 public class SslSelectChannelConnector extends SelectChannelConnector implements SslConnector
 {
-    private final SslParameters _sslParams;
+    private final SslContextFactory _sslContextFactory;
     private Buffers _sslBuffers;
 
     /* ------------------------------------------------------------ */
     public SslSelectChannelConnector()
     {
-        this(new SslParameters());
+        this(new SslContextFactory().setKeystore(SslContextFactory.DEFAULT_KEYSTORE_PATH));
     }
 
     /* ------------------------------------------------------------ */
-    public SslSelectChannelConnector(SslParameters sslParams)
+    public SslSelectChannelConnector(SslContextFactory sslContextFactory)
     {
-        _sslParams = sslParams;
+        _sslContextFactory = sslContextFactory;
         setUseDirectBuffers(false);
     }
 
@@ -114,7 +115,7 @@
      */
     public boolean isAllowRenegotiate()
     {
-        return _sslParams.isAllowRenegotiate();
+        return _sslContextFactory.isAllowRenegotiate();
     }
 
     /* ------------------------------------------------------------ */
@@ -127,7 +128,7 @@
      */
     public void setAllowRenegotiate(boolean allowRenegotiate)
     {
-        _sslParams.setAllowRenegotiate(allowRenegotiate);
+        _sslContextFactory.setAllowRenegotiate(allowRenegotiate);
     }
 
     /* ------------------------------------------------------------ */
@@ -136,7 +137,7 @@
      */
     public String[] getExcludeCipherSuites()
     {
-        return _sslParams.getExcludeCipherSuites();
+        return _sslContextFactory.getExcludeCipherSuites();
     }
 
     /* ------------------------------------------------------------ */
@@ -145,7 +146,7 @@
      */
     public void setExcludeCipherSuites(String[] cipherSuites)
     {
-        _sslParams.setExcludeCipherSuites(cipherSuites);
+        _sslContextFactory.setExcludeCipherSuites(cipherSuites);
     }
 
     /* ------------------------------------------------------------ */
@@ -154,7 +155,7 @@
      */
     public String[] getIncludeCipherSuites()
     {
-        return _sslParams.getIncludeCipherSuites();
+        return _sslContextFactory.getIncludeCipherSuites();
     }
 
     /* ------------------------------------------------------------ */
@@ -163,7 +164,7 @@
      */
     public void setIncludeCipherSuites(String[] cipherSuites)
     {
-        _sslParams.setIncludeCipherSuites(cipherSuites);
+        _sslContextFactory.setIncludeCipherSuites(cipherSuites);
     }
 
     /* ------------------------------------------------------------ */
@@ -172,7 +173,7 @@
      */
     public void setPassword(String password)
     {
-        _sslParams.setPassword(password);
+        _sslContextFactory.setKeyStorePassword(password);
     }
 
     /* ------------------------------------------------------------ */
@@ -181,7 +182,7 @@
      */
     public void setTrustPassword(String password)
     {
-        _sslParams.setTrustPassword(password);
+        _sslContextFactory.setTrustStorePassword(password);
     }
 
     /* ------------------------------------------------------------ */
@@ -190,7 +191,7 @@
      */
     public void setKeyPassword(String password)
     {
-        _sslParams.setKeyPassword(password);
+        _sslContextFactory.setKeyManagerPassword(password);
     }
 
     /* ------------------------------------------------------------ */
@@ -221,7 +222,7 @@
      */
     public String getProtocol()
     {
-        return _sslParams.getProtocol();
+        return _sslContextFactory.getProtocol();
     }
 
     /* ------------------------------------------------------------ */
@@ -230,7 +231,7 @@
      */
     public void setProtocol(String protocol)
     {
-        _sslParams.setProtocol(protocol);
+        _sslContextFactory.setProtocol(protocol);
     }
 
     /* ------------------------------------------------------------ */
@@ -239,7 +240,7 @@
      */
     public void setKeystore(String keystore)
     {
-        _sslParams.setKeystore(keystore);
+        _sslContextFactory.setKeystore(keystore);
     }
 
     /* ------------------------------------------------------------ */
@@ -248,7 +249,7 @@
      */
     public String getKeystore()
     {
-        return _sslParams.getKeystore();
+        return _sslContextFactory.getKeystore();
     }
 
     /* ------------------------------------------------------------ */
@@ -257,7 +258,7 @@
      */
     public String getKeystoreType()
     {
-        return _sslParams.getKeystoreType();
+        return _sslContextFactory.getKeystoreType();
     }
 
     /* ------------------------------------------------------------ */
@@ -266,7 +267,7 @@
      */
     public boolean getNeedClientAuth()
     {
-        return _sslParams.getNeedClientAuth();
+        return _sslContextFactory.getNeedClientAuth();
     }
 
     /* ------------------------------------------------------------ */
@@ -275,7 +276,7 @@
      */
     public boolean getWantClientAuth()
     {
-        return _sslParams.getWantClientAuth();
+        return _sslContextFactory.getWantClientAuth();
     }
 
     /* ------------------------------------------------------------ */
@@ -284,7 +285,7 @@
      */
     public void setNeedClientAuth(boolean needClientAuth)
     {
-        _sslParams.setNeedClientAuth(needClientAuth);
+        _sslContextFactory.setNeedClientAuth(needClientAuth);
     }
 
     /* ------------------------------------------------------------ */
@@ -293,7 +294,7 @@
      */
     public void setWantClientAuth(boolean wantClientAuth)
     {
-        _sslParams.setWantClientAuth(wantClientAuth);
+        _sslContextFactory.setWantClientAuth(wantClientAuth);
     }
 
     /* ------------------------------------------------------------ */
@@ -302,7 +303,7 @@
      */
     public void setKeystoreType(String keystoreType)
     {
-        _sslParams.setKeystoreType(keystoreType);
+        _sslContextFactory.setKeystoreType(keystoreType);
     }
 
     /* ------------------------------------------------------------ */
@@ -311,7 +312,7 @@
      */
     public String getProvider()
     {
-        return _sslParams.getProvider();
+        return _sslContextFactory.getProvider();
     }
 
     /* ------------------------------------------------------------ */
@@ -320,7 +321,7 @@
      */
     public String getSecureRandomAlgorithm()
     {
-        return _sslParams.getSecureRandomAlgorithm();
+        return _sslContextFactory.getSecureRandomAlgorithm();
     }
 
     /* ------------------------------------------------------------ */
@@ -329,7 +330,7 @@
      */
     public String getSslKeyManagerFactoryAlgorithm()
     {
-        return _sslParams.getSslKeyManagerFactoryAlgorithm();
+        return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
     }
 
     /* ------------------------------------------------------------ */
@@ -338,7 +339,7 @@
      */
     public String getSslTrustManagerFactoryAlgorithm()
     {
-        return _sslParams.getSslTrustManagerFactoryAlgorithm();
+        return _sslContextFactory.getTrustManagerFactoryAlgorithm();
     }
 
     /* ------------------------------------------------------------ */
@@ -347,7 +348,7 @@
      */
     public String getTruststore()
     {
-        return _sslParams.getTruststore();
+        return _sslContextFactory.getTruststore();
     }
 
     /* ------------------------------------------------------------ */
@@ -356,7 +357,7 @@
      */
     public String getTruststoreType()
     {
-        return _sslParams.getTruststoreType();
+        return _sslContextFactory.getTruststoreType();
     }
 
     /* ------------------------------------------------------------ */
@@ -365,7 +366,7 @@
      */
     public void setProvider(String provider)
     {
-        _sslParams.setProvider(provider);
+        _sslContextFactory.setProvider(provider);
     }
 
     /* ------------------------------------------------------------ */
@@ -374,7 +375,7 @@
      */
     public void setSecureRandomAlgorithm(String algorithm)
     {
-        _sslParams.setSecureRandomAlgorithm(algorithm);
+        _sslContextFactory.setSecureRandomAlgorithm(algorithm);
     }
 
     /* ------------------------------------------------------------ */
@@ -383,7 +384,7 @@
      */
     public void setSslKeyManagerFactoryAlgorithm(String algorithm)
     {
-        _sslParams.setSslKeyManagerFactoryAlgorithm(algorithm);
+        _sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm);
     }
 
     /* ------------------------------------------------------------ */
@@ -392,7 +393,7 @@
      */
     public void setSslTrustManagerFactoryAlgorithm(String algorithm)
     {
-        _sslParams.setSslTrustManagerFactoryAlgorithm(algorithm);
+        _sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm);
     }
 
     /* ------------------------------------------------------------ */
@@ -401,7 +402,7 @@
      */
     public void setTruststore(String truststore)
     {
-        _sslParams.setTruststore(truststore);
+        _sslContextFactory.setTruststore(truststore);
     }
 
     /* ------------------------------------------------------------ */
@@ -410,7 +411,7 @@
      */
     public void setTruststoreType(String truststoreType)
     {
-        _sslParams.setTruststoreType(truststoreType);
+        _sslContextFactory.setTruststoreType(truststoreType);
     }
 
     /* ------------------------------------------------------------ */
@@ -419,7 +420,7 @@
      */
     public void setSslContext(SSLContext sslContext)
     {
-        _sslParams.setSslContext(sslContext);
+        _sslContextFactory.setSslContext(sslContext);
     }
 
     /* ------------------------------------------------------------ */
@@ -428,7 +429,7 @@
      */
     public SSLContext getSslContext()
     {
-        return _sslParams.getSslContext();
+        return _sslContextFactory.getSslContext();
     }
 
     /* ------------------------------------------------------------ */
@@ -468,7 +469,7 @@
     protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException
     {
         SslSelectChannelEndPoint endp = new SslSelectChannelEndPoint(_sslBuffers,channel,selectSet,key,createSSLEngine(), SslSelectChannelConnector.this._maxIdleTime);
-        endp.setAllowRenegotiate(_sslParams.isAllowRenegotiate());
+        endp.setAllowRenegotiate(_sslContextFactory.isAllowRenegotiate());
         return endp;
     }
 
@@ -505,15 +506,15 @@
     @Override
     protected void doStart() throws Exception
     {
-        _sslParams.createSSLContext(); // called here to prevent exception wrapping 
+        _sslContextFactory.createSSLContext(); // called here to prevent exception wrapping 
         
-        SSLEngine sslEngine = _sslParams.getSslContext().createSSLEngine();
+        SSLEngine sslEngine = _sslContextFactory.getSslContext().createSSLEngine();
 
         sslEngine.setUseClientMode(false);
-        sslEngine.setWantClientAuth(_sslParams.getWantClientAuth());
-        sslEngine.setNeedClientAuth(_sslParams.getNeedClientAuth());
+        sslEngine.setWantClientAuth(_sslContextFactory.getWantClientAuth());
+        sslEngine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
         
-        sslEngine.setEnabledCipherSuites(_sslParams.selectCipherSuites(
+        sslEngine.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites(
                                             sslEngine.getEnabledCipherSuites(),
                                             sslEngine.getSupportedCipherSuites()));
         
diff --git a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSocketConnector.java b/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSocketConnector.java
index a441329..b826344 100644
--- a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSocketConnector.java
+++ b/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslSocketConnector.java
@@ -29,6 +29,7 @@
 
 import org.eclipse.jetty.http.HttpSchemes;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.SslContextFactory;
 import org.eclipse.jetty.io.bio.SocketEndPoint;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.bio.SocketConnector;
@@ -53,7 +54,7 @@
  */
 public class SslSocketConnector extends SocketConnector  implements SslConnector
 {
-    private final SslParameters _sslParams;
+    private final SslContextFactory _sslContextFactory;
     private int _handshakeTimeout = 0; //0 means use maxIdleTime
 
     /* ------------------------------------------------------------ */
@@ -62,12 +63,12 @@
      */
     public SslSocketConnector()
     {
-        this(new SslParameters());
+        this(new SslContextFactory().setKeystore(SslContextFactory.DEFAULT_KEYSTORE_PATH));
     }
 
-    public SslSocketConnector(SslParameters sslParams)
+    public SslSocketConnector(SslContextFactory sslContextFactory)
     {
-        _sslParams = sslParams;
+        _sslContextFactory = sslContextFactory;
     }
 
     /* ------------------------------------------------------------ */
@@ -76,7 +77,7 @@
      */
     public boolean isAllowRenegotiate()
     {
-        return _sslParams.isAllowRenegotiate();
+        return _sslContextFactory.isAllowRenegotiate();
     }
 
     /* ------------------------------------------------------------ */
@@ -89,7 +90,7 @@
      */
     public void setAllowRenegotiate(boolean allowRenegotiate)
     {
-        _sslParams.setAllowRenegotiate(allowRenegotiate);
+        _sslContextFactory.setAllowRenegotiate(allowRenegotiate);
     }
 
     /* ------------------------------------------------------------ */
@@ -148,78 +149,78 @@
 
     /* ------------------------------------------------------------ */    
     public String[] getExcludeCipherSuites() {
-        return _sslParams.getExcludeCipherSuites();
+        return _sslContextFactory.getExcludeCipherSuites();
     }
     
     /* ------------------------------------------------------------ */
     public String[] getIncludeCipherSuites()
     {
-        return _sslParams.getIncludeCipherSuites();
+        return _sslContextFactory.getIncludeCipherSuites();
     }
 
     /* ------------------------------------------------------------ */
     public String getKeystore()
     {
-        return _sslParams.getKeystore();
+        return _sslContextFactory.getKeystore();
     }
 
     /* ------------------------------------------------------------ */
     public String getKeystoreType() 
     {
-        return _sslParams.getKeystoreType();
+        return _sslContextFactory.getKeystoreType();
     }
 
     /* ------------------------------------------------------------ */
     public boolean getNeedClientAuth()
     {
-        return _sslParams.getNeedClientAuth();
+        return _sslContextFactory.getNeedClientAuth();
     }
 
     /* ------------------------------------------------------------ */
     public String getProtocol() 
     {
-        return _sslParams.getProtocol();
+        return _sslContextFactory.getProtocol();
     }
 
     /* ------------------------------------------------------------ */
     public String getProvider() {
-	return _sslParams.getProvider();
+	return _sslContextFactory.getProvider();
     }
 
     /* ------------------------------------------------------------ */
     public String getSecureRandomAlgorithm() 
     {
-        return _sslParams.getSecureRandomAlgorithm();
+        return _sslContextFactory.getSecureRandomAlgorithm();
     }
 
     /* ------------------------------------------------------------ */
     public String getSslKeyManagerFactoryAlgorithm() 
     {
-        return _sslParams.getSslKeyManagerFactoryAlgorithm();
+        return _sslContextFactory.getSslKeyManagerFactoryAlgorithm();
     }
 
     /* ------------------------------------------------------------ */
     public String getSslTrustManagerFactoryAlgorithm() 
     {
-        return _sslParams.getSslTrustManagerFactoryAlgorithm();
+        return _sslContextFactory.getTrustManagerFactoryAlgorithm();
     }
 
     /* ------------------------------------------------------------ */
     public String getTruststore()
     {
-        return _sslParams.getTruststore();
+        return _sslContextFactory.getTruststore();
     }
 
     /* ------------------------------------------------------------ */
     public String getTruststoreType()
     {
-        return _sslParams.getTruststoreType();
+        return _sslContextFactory.getTruststoreType();
     }
 
     /* ------------------------------------------------------------ */
     public boolean getWantClientAuth()
     {
-        return _sslParams.getWantClientAuth();
+        return _sslContextFactory.getWantClientAuth();
     }
 
     /* ------------------------------------------------------------ */
@@ -259,7 +260,7 @@
     @Override
     protected void doStart() throws Exception
     {
-        _sslParams.createSSLContext(); // called here to prevent exception wrapping
+        _sslContextFactory.createSSLContext(); // called here to prevent exception wrapping
         
         super.doStart();
     }
@@ -278,17 +279,17 @@
     @Override
     protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException
     {
-        SSLServerSocketFactory factory = _sslParams.getSslContext().getServerSocketFactory();
+        SSLServerSocketFactory factory = _sslContextFactory.getSslContext().getServerSocketFactory();
 
         SSLServerSocket socket = 
             (SSLServerSocket) (host==null ?
                         factory.createServerSocket(port,backlog):
                         factory.createServerSocket(port,backlog,InetAddress.getByName(host)));
 
-        socket.setWantClientAuth(_sslParams.getWantClientAuth());
-        socket.setNeedClientAuth(_sslParams.getNeedClientAuth());
+        socket.setWantClientAuth(_sslContextFactory.getWantClientAuth());
+        socket.setNeedClientAuth(_sslContextFactory.getNeedClientAuth());
 
-        socket.setEnabledCipherSuites(_sslParams.selectCipherSuites(
+        socket.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites(
                                             socket.getEnabledCipherSuites(),
                                             socket.getSupportedCipherSuites()));
         return socket;
@@ -300,19 +301,19 @@
      */
     public void setExcludeCipherSuites(String[] cipherSuites)
     {
-        _sslParams.setExcludeCipherSuites(cipherSuites);
+        _sslContextFactory.setExcludeCipherSuites(cipherSuites);
     }
 
     /* ------------------------------------------------------------ */
     public void setIncludeCipherSuites(String[] cipherSuites)
     {
-        _sslParams.setIncludeCipherSuites(cipherSuites);
+        _sslContextFactory.setIncludeCipherSuites(cipherSuites);
     }
 
     /* ------------------------------------------------------------ */
     public void setKeyPassword(String password)
     {
-        _sslParams.setKeyPassword(password);
+        _sslContextFactory.setKeyManagerPassword(password);
     }
 
     /* ------------------------------------------------------------ */
@@ -321,13 +322,13 @@
      */
     public void setKeystore(String keystore)
     {
-        _sslParams.setKeystore(keystore);
+        _sslContextFactory.setKeystore(keystore);
     }
 
     /* ------------------------------------------------------------ */
     public void setKeystoreType(String keystoreType) 
     {
-        _sslParams.setKeystoreType(keystoreType);
+        _sslContextFactory.setKeystoreType(keystoreType);
     }
 
     /* ------------------------------------------------------------ */
@@ -338,65 +339,65 @@
      */
     public void setNeedClientAuth(boolean needClientAuth)
     {
-        _sslParams.setNeedClientAuth(needClientAuth);
+        _sslContextFactory.setNeedClientAuth(needClientAuth);
     }
     
     /* ------------------------------------------------------------ */
     public void setPassword(String password)
     {
-        _sslParams.setPassword(password);
+        _sslContextFactory.setKeyStorePassword(password);
     }
     
     /* ------------------------------------------------------------ */
     public void setTrustPassword(String password)
     {
-        _sslParams.setTrustPassword(password);
+        _sslContextFactory.setTrustStorePassword(password);
     }
 
     /* ------------------------------------------------------------ */
     public void setProtocol(String protocol) 
     {
-        _sslParams.setProtocol(protocol);
+        _sslContextFactory.setProtocol(protocol);
     }
 
     /* ------------------------------------------------------------ */
     public void setProvider(String provider) {
-        _sslParams.setProvider(provider);
+        _sslContextFactory.setProvider(provider);
     }
 
     /* ------------------------------------------------------------ */
     public void setSecureRandomAlgorithm(String algorithm) 
     {
-        _sslParams.setSecureRandomAlgorithm(algorithm);
+        _sslContextFactory.setSecureRandomAlgorithm(algorithm);
     }
 
     /* ------------------------------------------------------------ */
     public void setSslKeyManagerFactoryAlgorithm(String algorithm) 
     {
-        _sslParams.setSslKeyManagerFactoryAlgorithm(algorithm);
+        _sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm);
     }
     
     /* ------------------------------------------------------------ */
     public void setSslTrustManagerFactoryAlgorithm(String algorithm) 
     {
-        _sslParams.setSslTrustManagerFactoryAlgorithm(algorithm);
+        _sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm);
     }
 
 
     public void setTruststore(String truststore)
     {
-        _sslParams.setTruststore(truststore);
+        _sslContextFactory.setTruststore(truststore);
     }
     
 
     public void setTruststoreType(String truststoreType)
     {
-        _sslParams.setTruststoreType(truststoreType);
+        _sslContextFactory.setTruststoreType(truststoreType);
     }
     
     public void setSslContext(SSLContext sslContext)
     {
-        _sslParams.setSslContext(sslContext);
+        _sslContextFactory.setSslContext(sslContext);
     }
 
     /* ------------------------------------------------------------ */
@@ -405,7 +406,7 @@
      */
     public SSLContext getSslContext()
     {
-        return _sslParams.getSslContext();
+        return _sslContextFactory.getSslContext();
     }
 
     /* ------------------------------------------------------------ */
@@ -418,7 +419,7 @@
      */
     public void setWantClientAuth(boolean wantClientAuth)
     {
-        _sslParams.setWantClientAuth(wantClientAuth);
+        _sslContextFactory.setWantClientAuth(wantClientAuth);
     }
 
     /* ------------------------------------------------------------ */
@@ -471,7 +472,7 @@
                     {
                         if (handshook)
                         {
-                            if (!_sslParams.isAllowRenegotiate())
+                            if (!_sslContextFactory.isAllowRenegotiate())
                             {
                                 Log.warn("SSL renegotiate denied: "+ssl);
                                 try{ssl.close();}catch(IOException e){Log.warn(e);}
diff --git a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslParameters.java b/jetty-exssl/src/main/java/org/eclipse/jetty/io/SslContextFactory.java
similarity index 65%
rename from jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslParameters.java
rename to jetty-exssl/src/main/java/org/eclipse/jetty/io/SslContextFactory.java
index 90f9e40..b052194 100644
--- a/jetty-exssl/src/main/java/org/eclipse/jetty/exssl/SslParameters.java
+++ b/jetty-exssl/src/main/java/org/eclipse/jetty/io/SslContextFactory.java
@@ -1,6 +1,9 @@
-package org.eclipse.jetty.exssl;
+package org.eclipse.jetty.io;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 import java.security.KeyStore;
 import java.security.SecureRandom;
@@ -26,21 +29,25 @@
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
 
+import org.eclipse.jetty.exssl.SslExtendedKeyManager;
 import org.eclipse.jetty.http.security.Password;
+import org.eclipse.jetty.util.IO;
 import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.security.CertificateValidator;
 
-public class SslParameters
+public class SslContextFactory
 {
-    public static final String DEFAULT_KEYSTORE_ALGORITHM = 
+    public static final String DEFAULT_KEYMANAGERFACTORY_ALGORITHM = 
         (Security.getProperty("ssl.KeyManagerFactory.algorithm") == null ?
                 "SunX509" : Security.getProperty("ssl.KeyManagerFactory.algorithm"));
-    public static final String DEFAULT_TRUSTSTORE_ALGORITHM = 
+    public static final String DEFAULT_TRUSTMANAGERFACTORY_ALGORITHM = 
         (Security.getProperty("ssl.TrustManagerFactory.algorithm") == null ?
                 "SunX509" : Security.getProperty("ssl.TrustManagerFactory.algorithm"));
 
     /** Default value for the keystore location path. */
-    public static final String DEFAULT_KEYSTORE = 
+    public static final String DEFAULT_KEYSTORE_PATH = 
         System.getProperty("user.home") + File.separator + ".keystore";
 
     /** String name of key password property. */
@@ -54,21 +61,26 @@
     /** Included cipher suites. */
     private String _includeCipherSuites[] = null;
 
-    /** KeyStore path. */
-    private String _keystorePath = DEFAULT_KEYSTORE;
-    /** KeyStore provider name */
+    /** Keystore path. */
+    private String _keystorePath;
+    /** Keystore provider name */
     private String _keystoreProvider;
-    /** KeyStore type */
+    /** Keystore type */
     private String _keystoreType = "JKS";
+    /** Keystore input stream */
+    private InputStream _keystoreInputStream;
+    
     /** SSL certificate alias */
     private String _certAlias;
 
-    /** TrustStore path */
+    /** Truststore path */
     private String _truststorePath;
-    /** TrustStore provider name */
+    /** Truststore provider name */
     private String _truststoreProvider;
-    /** TrustStore type */
+    /** Truststore type */
     private String _truststoreType = "JKS";
+    /** Truststore input stream */
+    private InputStream _truststoreInputStream;
 
     /** Set to true if client certificate authentication is required */
     private boolean _needClientAuth = false;
@@ -80,11 +92,11 @@
     private boolean _allowRenegotiate = false;
 
     /** KeyStore password */
-    private transient Password _password;
+    private transient Password _keystorePassword;
     /** Key password */
-    private transient Password _keyPassword;
+    private transient Password _keymanagerPassword;
     /** TrustStore password */
-    private transient Password _trustPassword;
+    private transient Password _truststorePassword;
 
     /** SSL Provider name */
     private String _sslProvider;
@@ -94,9 +106,9 @@
     /** SecureRandom algorithm */
     private String _secureRandomAlgorithm;
     /** KeyManager factory algorithm */
-    private String _sslKeyManagerFactoryAlgorithm = DEFAULT_KEYSTORE_ALGORITHM;
+    private String _keyManagerFactoryAlgorithm = DEFAULT_KEYMANAGERFACTORY_ALGORITHM;
     /** TrustManager factory algorithm */
-    private String _sslTrustManagerFactoryAlgorithm = DEFAULT_TRUSTSTORE_ALGORITHM;
+    private String _trustManagerFactoryAlgorithm = DEFAULT_TRUSTMANAGERFACTORY_ALGORITHM;
 
     /** Path to file that contains Certificate Revocation List */
     private String _crlPath;
@@ -122,9 +134,11 @@
      *            The array of cipher suite names to exclude from
      *            {@link SSLEngine#setEnabledCipherSuites(String[])}
      */
-    public void setExcludeCipherSuites(String[] cipherSuites)
+    public SslContextFactory setExcludeCipherSuites(String[] cipherSuites)
     {
         _excludeCipherSuites = cipherSuites;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -143,9 +157,11 @@
      *            The array of cipher suite names to include in
      *            {@link SSLEngine#setEnabledCipherSuites(String[])}
      */
-    public void setIncludeCipherSuites(String[] cipherSuites)
+    public SslContextFactory setIncludeCipherSuites(String[] cipherSuites)
     {
         _includeCipherSuites = cipherSuites;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -162,9 +178,11 @@
      * @param keystore
      *            The file or URL of the SSL Key store.
      */
-    public void setKeystore(String keystore)
+    public SslContextFactory setKeystore(String keystore)
     {
         _keystorePath = keystore;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -181,9 +199,11 @@
      * @param keystoreProvider
      *            The provider of the key store
      */
-    public void setKeystoreProvider(String keystoreProvider)
+    public SslContextFactory setKeystoreProvider(String keystoreProvider)
     {
         _keystoreProvider = keystoreProvider;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -200,9 +220,33 @@
      * @param keystoreType
      *            The type of the key store (default "JKS")
      */
-    public void setKeystoreType(String keystoreType)
+    public SslContextFactory setKeystoreType(String keystoreType)
     {
         _keystoreType = keystoreType;
+        
+        return this;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Get the _keystoreInputStream.
+     * @return the _keystoreInputStream
+     */
+    public InputStream getKeystoreInputStream()
+    {
+        checkConfig();
+        
+        return _keystoreInputStream;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Set the _keystoreInputStream.
+     * @param _keystoreInputStream the _keystoreInputStream to set
+     */
+    public SslContextFactory setKeystoreInputStream(InputStream keystoreInputStream)
+    {
+        _keystoreInputStream = keystoreInputStream;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -219,9 +263,11 @@
      * @param certAlias
      *            Alias of SSL certificate for the connector
      */
-    public void setCertAlias(String certAlias)
+    public SslContextFactory setCertAlias(String certAlias)
     {
         _certAlias = certAlias;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -238,9 +284,11 @@
      * @param truststore
      *            The file name or URL of the trust store location
      */
-    public void setTruststore(String truststore)
+    public SslContextFactory setTruststore(String truststore)
     {
         _truststorePath = truststore;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -257,9 +305,11 @@
      * @param truststoreProvider
      *            The provider of the trust store
      */
-    public void setTruststoreProvider(String truststoreProvider)
+    public SslContextFactory setTruststoreProvider(String truststoreProvider)
     {
         _truststoreProvider = truststoreProvider;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -276,9 +326,33 @@
      * @param truststoreType
      *            The type of the trust store (default "JKS")
      */
-    public void setTruststoreType(String truststoreType)
+    public SslContextFactory setTruststoreType(String truststoreType)
     {
         _truststoreType = truststoreType;
+        
+        return this;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Get the _truststoreInputStream.
+     * @return the _truststoreInputStream
+     */
+    public InputStream getTruststoreInputStream()
+    {
+        checkConfig();
+        
+        return _truststoreInputStream;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Set the _truststoreInputStream.
+     * @param _truststoreInputStream the _truststoreInputStream to set
+     */
+    public SslContextFactory setTruststoreInputStream(InputStream truststoreInputStream)
+    {
+        _truststoreInputStream = truststoreInputStream;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -297,9 +371,11 @@
      *            True if SSL needs client authentication.
      * @see SSLEngine#getNeedClientAuth()
      */
-    public void setNeedClientAuth(boolean needClientAuth)
+    public SslContextFactory setNeedClientAuth(boolean needClientAuth)
     {
         _needClientAuth = needClientAuth;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -318,9 +394,11 @@
      *            True if SSL wants client authentication.
      * @see SSLEngine#getWantClientAuth()
      */
-    public void setWantClientAuth(boolean wantClientAuth)
+    public SslContextFactory setWantClientAuth(boolean wantClientAuth)
     {
         _wantClientAuth = wantClientAuth;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -337,9 +415,11 @@
      * @param validateServerCert
      *            true if SSL certificate has to be validated
      */
-    public void setValidateCerts(boolean validateCerts)
+    public SslContextFactory setValidateCerts(boolean validateCerts)
     {
         _validateCerts = validateCerts;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -360,9 +440,11 @@
      * @param allowRenegotiate
      *            true if re-negotiation is allowed (default false)
      */
-    public void setAllowRenegotiate(boolean allowRenegotiate)
+    public SslContextFactory setAllowRenegotiate(boolean allowRenegotiate)
     {
         _allowRenegotiate = allowRenegotiate;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -370,9 +452,11 @@
      * @param password
      *            The password for the key store
      */
-    public void setPassword(String password)
+    public SslContextFactory setKeyStorePassword(String password)
     {
-        _password = Password.getPassword(PASSWORD_PROPERTY,password,null);
+        _keystorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -380,9 +464,11 @@
      * @param password
      *            The password (if any) for the specific key within the key store
      */
-    public void setKeyPassword(String password)
+    public SslContextFactory setKeyManagerPassword(String password)
     {
-        _keyPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
+        _keymanagerPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -390,9 +476,11 @@
      * @param password
      *            The password for the trust store
      */
-    public void setTrustPassword(String password)
+    public SslContextFactory setTrustStorePassword(String password)
     {
-        _trustPassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
+        _truststorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -411,9 +499,11 @@
      *            The SSL provider name, which if set is passed to
      *            {@link SSLContext#getInstance(String, String)}
      */
-    public void setProvider(String provider)
+    public SslContextFactory setProvider(String provider)
     {
         _sslProvider = provider;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -432,9 +522,11 @@
      *            The SSL protocol (default "TLS") passed to
      *            {@link SSLContext#getInstance(String, String)}
      */
-    public void setProtocol(String protocol)
+    public SslContextFactory setProtocol(String protocol)
     {
         _sslProtocol = protocol;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -455,9 +547,11 @@
      *            {@link SecureRandom#getInstance(String)} to obtain the {@link SecureRandom} instance passed to
      *            {@link SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], SecureRandom)}
      */
-    public void setSecureRandomAlgorithm(String algorithm)
+    public SslContextFactory setSecureRandomAlgorithm(String algorithm)
     {
         _secureRandomAlgorithm = algorithm;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -466,7 +560,7 @@
      */
     public String getSslKeyManagerFactoryAlgorithm()
     {
-        return (_sslKeyManagerFactoryAlgorithm);
+        return (_keyManagerFactoryAlgorithm);
     }
 
     /* ------------------------------------------------------------ */
@@ -474,18 +568,20 @@
      * @param algorithm
      *            The algorithm name (default "SunX509") used by the {@link KeyManagerFactory}
      */
-    public void setSslKeyManagerFactoryAlgorithm(String algorithm)
+    public SslContextFactory setSslKeyManagerFactoryAlgorithm(String algorithm)
     {
-        _sslKeyManagerFactoryAlgorithm = algorithm;
+        _keyManagerFactoryAlgorithm = algorithm;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
     /**
      * @return The algorithm name (default "SunX509") used by the {@link TrustManagerFactory}
      */
-    public String getSslTrustManagerFactoryAlgorithm()
+    public String getTrustManagerFactoryAlgorithm()
     {
-        return (_sslTrustManagerFactoryAlgorithm);
+        return (_trustManagerFactoryAlgorithm);
     }
 
     /* ------------------------------------------------------------ */
@@ -493,9 +589,11 @@
      * @param algorithm
      *            The algorithm name (default "SunX509") used by the {@link TrustManagerFactory}
      */
-    public void setSslTrustManagerFactoryAlgorithm(String algorithm)
+    public SslContextFactory setTrustManagerFactoryAlgorithm(String algorithm)
     {
-        _sslTrustManagerFactoryAlgorithm = algorithm;
+        _trustManagerFactoryAlgorithm = algorithm;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -512,9 +610,11 @@
      * @param crlPath
      *            Path to file that contains Certificate Revocation List
      */
-    public void setCrlPath(String crlPath)
+    public SslContextFactory setCrlPath(String crlPath)
     {
         _crlPath = crlPath;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -533,9 +633,11 @@
      *            maximum number of intermediate certificates in
      *            the certification path (-1 for unlimited)
      */
-    public void setMaxCertPathLength(int maxCertPathLength)
+    public SslContextFactory setMaxCertPathLength(int maxCertPathLength)
     {
         _maxCertPathLength = maxCertPathLength;
+        
+        return this;
     }
 
     /* ------------------------------------------------------------ */
@@ -562,16 +664,80 @@
      * @param sslContext
      *            Set a preconfigured SSLContext
      */
-    public void setSslContext(SSLContext sslContext)
+    public SslContextFactory setSslContext(SSLContext sslContext)
     {
         _context = sslContext;
+        
+        return this;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @return The SSLContext
+     */
+    public SSLContext getClientSslContext()
+    {
+        try
+        {
+            if (_context == null)
+                _context = createClientSSLContext();
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+
+        return _context;
     }
 
     /* ------------------------------------------------------------ */
-    protected SSLContext createSSLContext() throws Exception
+    /**
+     * @return SSL context for the client code
+     */
+    public SSLContext createClientSSLContext() throws Exception
     {
-        KeyStore keyStore = getKeyStore(_keystorePath,_keystoreType,_keystoreProvider,_password == null?null:_password.toString());
-        KeyStore trustStore = getTrustStore(_truststorePath,_truststoreType,_truststoreProvider,_trustPassword == null?null:_trustPassword.toString());
+        SSLContext sslContext = null;
+        
+        if (_keystoreInputStream == null && _keystorePath == null &&
+                _truststoreInputStream == null && _truststorePath == null )
+        {
+            // Create a trust manager that does not validate certificate chains
+            TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager()
+            {
+                public java.security.cert.X509Certificate[] getAcceptedIssuers()
+                {
+                    return null;
+                }
+
+                public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
+                {
+                }
+
+                public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
+                {
+                }
+            }};
+
+            sslContext = SSLContext.getInstance(_sslProtocol);
+            sslContext.init(null, trustAllCerts, null);
+        }
+        else
+        {
+            sslContext = createSSLContext();
+        }
+        
+        return sslContext;
+    }
+
+    /* ------------------------------------------------------------ */
+    public SSLContext createSSLContext() throws Exception
+    {
+        checkConfig();
+        
+        KeyStore keyStore = getKeyStore(_keystoreInputStream, _keystorePath, _keystoreType, 
+                _keystoreProvider, _keystorePassword==null? null: _keystorePassword.toString());
+        KeyStore trustStore = getKeyStore(_truststoreInputStream, _truststorePath, _truststoreType, 
+                _truststoreProvider, _truststorePassword==null? null: _truststorePassword.toString());
         Collection<? extends CRL> crls = loadCRL(_crlPath);
 
         if (_certAlias == null)
@@ -588,8 +754,8 @@
 
         if (_validateCerts)
         {
-            CertificateValidator validator = new CertificateValidator(keyStore,trustStore,crls);
-            validator.validate(cert);
+            CertificateValidator validator = new CertificateValidator(trustStore,crls);
+            validator.validate(keyStore, cert);
         }
 
         KeyManager[] keyManagers = getKeyManagers(keyStore);
@@ -603,10 +769,10 @@
     }
 
     /* ------------------------------------------------------------ */
-    public KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception
+    protected KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception
     {
-        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(_sslKeyManagerFactoryAlgorithm);
-        keyManagerFactory.init(keyStore,_keyPassword == null?(_password == null?null:_password.toString().toCharArray()):_keyPassword.toString().toCharArray());
+        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(_keyManagerFactoryAlgorithm);
+        keyManagerFactory.init(keyStore,_keymanagerPassword == null?(_keystorePassword == null?null:_keystorePassword.toString().toCharArray()):_keymanagerPassword.toString().toCharArray());
         KeyManager[] managers = keyManagerFactory.getKeyManagers();
 
         if (_certAlias != null)
@@ -624,13 +790,13 @@
     }
 
     /* ------------------------------------------------------------ */
-    public TrustManager[] getTrustManagers(KeyStore trustStore, Collection<? extends CRL> crls) throws Exception
+    protected TrustManager[] getTrustManagers(KeyStore trustStore, Collection<? extends CRL> crls) throws Exception
     {
         TrustManager[] managers = null;
         if (trustStore != null && _validateCerts)
         {
             // Revocation checking is only supported for PKIX algorithm
-            if (_sslTrustManagerFactoryAlgorithm.equalsIgnoreCase("PKIX"))
+            if (_trustManagerFactoryAlgorithm.equalsIgnoreCase("PKIX"))
             {
                 PKIXBuilderParameters pbParams = new PKIXBuilderParameters(trustStore,new X509CertSelector());
 
@@ -651,14 +817,14 @@
                 // Enable Certificate Revocation List Distribution Points (CRLDP) support
                 System.setProperty("com.sun.security.enableCRLDP","true");
 
-                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_sslTrustManagerFactoryAlgorithm);
+                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_trustManagerFactoryAlgorithm);
                 trustManagerFactory.init(new CertPathTrustManagerParameters(pbParams));
 
                 managers = trustManagerFactory.getTrustManagers();
             }
             else
             {
-                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_sslTrustManagerFactoryAlgorithm);
+                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_trustManagerFactoryAlgorithm);
                 trustManagerFactory.init(trustStore);
 
                 managers = trustManagerFactory.getTrustManagers();
@@ -669,63 +835,45 @@
     }
 
     /* ------------------------------------------------------------ */
-    public KeyStore getKeyStore(String storePath, String storeType, String storeProvider, String storePassword) throws Exception
+    protected KeyStore getKeyStore(InputStream storeStream, String storePath, String storeType, String storeProvider, String storePassword) throws Exception
     {
-        if (storePath == null)
-            return null;
-
         KeyStore keystore = null;
-        InputStream inStream = null;
-        try
-        {
-            if (storeProvider != null)
-            {
-                keystore = KeyStore.getInstance(storeType,storeProvider);
-            }
-            else
-            {
-                keystore = KeyStore.getInstance(storeType);
-            }
 
-            inStream = Resource.newResource(storePath).getInputStream();
-            keystore.load(inStream,storePassword == null?null:storePassword.toCharArray());
-
-            return keystore;
-        }
-        finally
+        if (storeStream != null || storePath != null)
         {
-            if (inStream != null)
+            InputStream inStream = storeStream;
+            try
             {
-                inStream.close();
+                if (inStream == null)
+                {
+                    inStream = Resource.newResource(storePath).getInputStream();
+                }
+                
+                if (storeProvider != null)
+                {
+                    keystore = KeyStore.getInstance(storeType, storeProvider);
+                }
+                else
+                {
+                    keystore = KeyStore.getInstance(storeType);
+                }
+    
+                keystore.load(inStream, storePassword == null ? null : storePassword.toCharArray());
+            }
+            finally
+            {
+                if (inStream != null)
+                {
+                    inStream.close();
+                }
             }
         }
+        
+        return keystore;
     }
 
     /* ------------------------------------------------------------ */
-    public KeyStore getTrustStore(String trustPath, String trustType, String trustProvider, String trustPassword) throws Exception
-    {
-        if (trustPath == null)
-        {
-            trustPath = System.getProperty("javax.net.ssl.trustStore");
-            trustType = System.getProperty("javax.net.ssl.trustStoreType");
-            trustProvider = System.getProperty("javax.net.ssl.trustStoreProvider");
-            trustPassword = System.getProperty("javax.net.ssl.trustStorePassword");
-        }
-
-        if (trustPath == null)
-        {
-            trustPath = _keystorePath;
-            trustType = _keystoreType;
-            trustProvider = _keystoreProvider;
-            trustPassword = _password.toString();
-            _sslTrustManagerFactoryAlgorithm = _sslKeyManagerFactoryAlgorithm;
-        }
-
-        return getKeyStore(trustPath,trustType,trustProvider,trustPassword);
-    }
-
-    /* ------------------------------------------------------------ */
-    private Collection<? extends CRL> loadCRL(String crlPath) throws Exception
+    protected Collection<? extends CRL> loadCRL(String crlPath) throws Exception
     {
         Collection<? extends CRL> crlList = null;
 
@@ -748,6 +896,43 @@
 
         return crlList;
     }
+    
+    protected void checkConfig()
+    {
+        /*
+         * if the keystore exists but the trust store doesn't use the keystore as the trust store
+         */
+        if (_keystoreInputStream != null || _keystorePath != null)
+        {
+            if (_truststoreInputStream == null && _truststorePath == null)
+            {
+                _truststorePath = _keystorePath;
+                _truststoreInputStream = _keystoreInputStream;
+                _truststoreType = _keystoreType;
+                _truststoreProvider = _keystoreProvider;
+                _truststorePassword = _keystorePassword;
+                _trustManagerFactoryAlgorithm = _keyManagerFactoryAlgorithm;
+            }
+        }
+        
+        // It's the same stream and we cannot read it twice, so we read it once in memory
+        if (_keystoreInputStream != null && _keystoreInputStream == _truststoreInputStream)
+        {
+            try
+            {
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                IO.copy(_keystoreInputStream, baos);
+                _keystoreInputStream.close();
+    
+                _keystoreInputStream = new ByteArrayInputStream(baos.toByteArray());
+                _truststoreInputStream = new ByteArrayInputStream(baos.toByteArray());
+            }
+            catch (Exception ex)
+            {
+                throw new RuntimeException(ex);
+            }
+        }
+    }
 
     public String[] selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites)
     {
diff --git a/jetty-exssl/src/test/java/org/eclipse/jetty/client/ContentExchangeTest.java b/jetty-exssl/src/test/java/org/eclipse/jetty/client/ContentExchangeTest.java
new file mode 100644
index 0000000..3267530
--- /dev/null
+++ b/jetty-exssl/src/test/java/org/eclipse/jetty/client/ContentExchangeTest.java
@@ -0,0 +1,346 @@
+// ========================================================================
+// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+
+package org.eclipse.jetty.client;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLDecoder;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jetty.client.security.Realm;
+import org.eclipse.jetty.client.security.SimpleRealmResolver;
+import org.eclipse.jetty.http.HttpMethods;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.io.ByteArrayBuffer;
+import org.eclipse.jetty.io.EofException;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.server.nio.SelectChannelConnector;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.IO;
+
+public class ContentExchangeTest
+    extends TestCase
+{
+    private static String _content =
+        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+
+        "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+
+        "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "+
+        "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "+
+        "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "+
+        "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "+
+        "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "+
+        "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "+
+        "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "+
+        "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "+
+        "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+
+        "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
+
+    private File _docRoot;
+    private Server _server;
+    private HttpClient _client;
+    private Realm _realm;
+    private String _protocol;
+    private String _baseUrl;
+    private String _requestContent;
+
+    public void setUp()
+        throws Exception
+    {
+        _docRoot = new File("target/test-output/docroot/");
+        _docRoot.mkdirs();
+        _docRoot.deleteOnExit();
+        
+        File content = new File(_docRoot,"input.txt");
+        FileOutputStream out = new FileOutputStream(content);
+        out.write(_content.getBytes("utf-8"));
+        out.close();
+        
+        _server = new Server();
+        configureServer(_server);
+        _server.start();
+
+        int port = _server.getConnectors()[0].getLocalPort();
+        _baseUrl = _protocol+"://localhost:"+port+ "/";
+    }
+    
+    public void tearDown()
+        throws Exception
+    {
+        if (_server != null)
+        {
+            _server.stop();
+            _server = null;
+        }
+    }
+    
+    public void testPut() throws Exception
+    {
+        startClient(_realm);
+    
+        ContentExchange putExchange = new ContentExchange();
+        putExchange.setURL(getBaseUrl() + "output.txt");
+        putExchange.setMethod(HttpMethods.PUT);
+        putExchange.setRequestContent(new ByteArrayBuffer(_content.getBytes()));
+    
+        _client.send(putExchange);
+        int state = putExchange.waitForDone();
+    
+        int responseStatus = putExchange.getResponseStatus();
+    
+        stopClient();
+    
+        boolean statusOk = (responseStatus == 200 || responseStatus == 201);
+        assertTrue(statusOk);
+        
+        String content = IO.toString(new FileInputStream(new File(_docRoot,"output.txt")));
+        assertEquals(_content,content);
+    }
+    
+    public void testGet() throws Exception
+    {
+        startClient(_realm);
+    
+        ContentExchange getExchange = new ContentExchange();
+        getExchange.setURL(getBaseUrl() + "input.txt");
+        getExchange.setMethod(HttpMethods.GET);
+    
+        _client.send(getExchange);
+        int state = getExchange.waitForDone();
+    
+        String content = "";
+        int responseStatus = getExchange.getResponseStatus();
+        if (responseStatus == HttpStatus.OK_200)
+        {
+            content = getExchange.getResponseContent();
+        }
+    
+        stopClient();
+    
+        assertEquals(HttpStatus.OK_200,responseStatus);
+        assertEquals(_content,content);
+    }
+    
+    public void testHead() throws Exception
+    {
+        startClient(_realm);
+    
+        ContentExchange getExchange = new ContentExchange();
+        getExchange.setURL(getBaseUrl() + "input.txt");
+        getExchange.setMethod(HttpMethods.HEAD);
+    
+        _client.send(getExchange);
+        getExchange.waitForDone();
+    
+        int responseStatus = getExchange.getResponseStatus();
+
+        stopClient();
+    
+        assertEquals(HttpStatus.OK_200,responseStatus);
+    }
+    
+    public void testPost() throws Exception
+    {
+        startClient(_realm);
+    
+        ContentExchange postExchange = new ContentExchange();
+        postExchange.setURL(getBaseUrl() + "test");
+        postExchange.setMethod(HttpMethods.POST);
+        postExchange.setRequestContent(new ByteArrayBuffer(_content.getBytes()));
+   
+        _client.send(postExchange);
+        int state = postExchange.waitForDone();
+    
+        int responseStatus = postExchange.getResponseStatus();
+ 
+        stopClient();
+    
+        assertEquals(HttpStatus.OK_200,responseStatus);
+        assertEquals(_content,_requestContent);
+    }
+    
+    protected void configureServer(Server server)
+        throws Exception
+    {
+        setProtocol("http");
+        
+        SelectChannelConnector connector = new SelectChannelConnector();
+        server.addConnector(connector);
+
+        Handler handler = new TestHandler(getBasePath());
+        
+        ServletContextHandler root = new ServletContextHandler();
+        root.setContextPath("/");
+        root.setResourceBase(_docRoot.getAbsolutePath());
+        ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
+        servletHolder.setInitParameter( "gzip", "true" );
+        root.addServlet( servletHolder, "/*" );    
+
+        HandlerCollection handlers = new HandlerCollection();
+        handlers.setHandlers(new Handler[]{handler, root});
+        server.setHandler( handlers ); 
+
+    }
+    
+    protected void startClient(Realm realm)
+        throws Exception
+    {
+        _client = new HttpClient();
+        _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
+        if (realm != null)
+            _client.setRealmResolver(new SimpleRealmResolver(realm));
+        _client.start();
+    }
+    
+    protected void stopClient()
+        throws Exception
+    {
+        if (_client != null)
+        {
+            _client.stop();
+            _client = null;
+        }
+    }
+    
+    protected String getBasePath()
+    {
+        return _docRoot.getAbsolutePath();
+    }
+    
+    protected String getBaseUrl()
+    {
+        return _baseUrl;
+    }
+    
+    protected HttpClient getClient()
+    {
+        return _client;
+    }
+    
+    protected Realm getRealm()
+    {
+        return _realm;
+    }
+    
+    protected String getContent()
+    {
+        return _content;
+    }
+    
+    protected void setProtocol(String protocol)
+    {
+        _protocol = protocol;
+    }
+    
+    protected void setRealm(Realm realm)
+    {
+        _realm = realm;
+    }
+    
+    public static void copyStream(InputStream in, OutputStream out)
+    {
+        try
+        {
+            byte[] buffer=new byte[1024];
+            int len;
+            while ((len=in.read(buffer))>=0)
+            {
+                out.write(buffer,0,len);
+            }
+        }
+        catch (EofException e)
+        {
+            System.err.println(e);
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    protected class TestHandler extends AbstractHandler {
+        private final String resourcePath;
+
+        public TestHandler(String repositoryPath) {
+            this.resourcePath = repositoryPath;
+        }
+
+        public void handle(String target, Request baseRequest,
+                HttpServletRequest request, HttpServletResponse response)
+            throws IOException, ServletException
+        {
+            if (baseRequest.isHandled())
+            {
+                return;
+            }
+
+            OutputStream out = null;
+            
+            if (baseRequest.getMethod().equals("PUT"))
+            {
+            	baseRequest.setHandled(true);
+
+            	File file = new File(resourcePath, URLDecoder.decode(request.getPathInfo()));
+            	file.getParentFile().mkdirs();
+            	file.deleteOnExit();
+            
+            	out = new FileOutputStream(file);
+
+	            response.setStatus(HttpServletResponse.SC_CREATED);
+            }
+            
+            if (baseRequest.getMethod().equals("POST"))
+            {
+            	baseRequest.setHandled(true);
+            	out = new ByteArrayOutputStream();
+
+	        response.setStatus(HttpServletResponse.SC_OK);
+            }
+            
+            if (out != null)
+            {
+                ServletInputStream in = request.getInputStream();
+	            try
+	            {
+	                copyStream( in, out );
+	            }
+	            finally
+	            {
+	                in.close();
+	                out.close();
+	            }
+	            
+	            if (!(out instanceof FileOutputStream))
+	            	_requestContent = out.toString();
+            }
+            
+        }
+    }
+}
diff --git a/jetty-exssl/src/test/java/org/eclipse/jetty/client/SslContentExchangeTest.java b/jetty-exssl/src/test/java/org/eclipse/jetty/client/SslContentExchangeTest.java
new file mode 100644
index 0000000..7dfb21e
--- /dev/null
+++ b/jetty-exssl/src/test/java/org/eclipse/jetty/client/SslContentExchangeTest.java
@@ -0,0 +1,56 @@
+// ========================================================================
+// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+// The Eclipse Public License is available at 
+// http://www.eclipse.org/legal/epl-v10.html
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+
+package org.eclipse.jetty.client;
+
+import java.io.File;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+
+public class SslContentExchangeTest
+	extends ContentExchangeTest
+{
+
+    protected void configureServer(Server server)
+        throws Exception
+    {
+        setProtocol("https");
+        
+        SslSelectChannelConnector connector = new SslSelectChannelConnector();
+        File keystore = MavenTestingUtils.getTestResourceFile("jetty-valid.keystore");
+        connector.setKeystore(keystore.getAbsolutePath());
+        connector.setPassword("webtide");
+        connector.setKeyPassword("webtide");
+        server.addConnector(connector);
+                
+        Handler handler = new TestHandler(getBasePath());
+
+        ServletContextHandler root = new ServletContextHandler();
+        root.setContextPath("/");
+        root.setResourceBase(getBasePath());
+        ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
+        servletHolder.setInitParameter( "gzip", "true" );
+        root.addServlet( servletHolder, "/*" );    
+
+        HandlerCollection handlers = new HandlerCollection();
+        handlers.setHandlers(new Handler[]{handler, root});
+        server.setHandler( handlers ); 
+    }
+}
diff --git a/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/CertificateValidationTestBase.java b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/CertificateValidationTestBase.java
index da25770..c823bd3 100644
--- a/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/CertificateValidationTestBase.java
+++ b/jetty-exssl/src/test/java/org/eclipse/jetty/exssl/CertificateValidationTestBase.java
@@ -4,6 +4,7 @@
 import java.lang.reflect.Constructor;
 import java.security.cert.CertificateException;
 
+import org.eclipse.jetty.io.SslContextFactory;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ssl.SslConnector;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@@ -32,17 +33,17 @@
         String trustpath = new File(System.getProperty("java.home"),"./lib/security/cacerts").getAbsolutePath();
         String crlpath = MavenTestingUtils.getTestResourceFile("crlfile.pem").getAbsolutePath();
 
-        SslParameters sslParams = new SslParameters();
-        sslParams.setValidateCerts(true);
-        sslParams.setKeystore(keypath);
-        sslParams.setPassword("webtide");
-        sslParams.setKeyPassword("webtide");
-        sslParams.setTruststore(trustpath);
-        sslParams.setTrustPassword("changeit");
-        sslParams.setCrlPath(crlpath);
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setValidateCerts(true);
+        sslContextFactory.setKeystore(keypath);
+        sslContextFactory.setKeyStorePassword("webtide");
+        sslContextFactory.setKeyManagerPassword("webtide");
+        sslContextFactory.setTruststore(trustpath);
+        sslContextFactory.setTrustStorePassword("changeit");
+        sslContextFactory.setCrlPath(crlpath);
         
-        Constructor<? extends SslConnector> constructor = _klass.getConstructor(SslParameters.class);
-        SslConnector connector = constructor.newInstance(sslParams);
+        Constructor<? extends SslConnector> constructor = _klass.getConstructor(SslContextFactory.class);
+        SslConnector connector = constructor.newInstance(sslContextFactory);
         connector.setPort(0);
 
         _server = new Server();