| // ======================================================================== |
| // Copyright (c) 2000-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.exssl; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.InetAddress; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| import java.security.KeyStore; |
| import java.security.SecureRandom; |
| import java.security.Security; |
| import java.security.cert.CRL; |
| import java.security.cert.CertPathBuilder; |
| import java.security.cert.CertStore; |
| import java.security.cert.CertStoreParameters; |
| import java.security.cert.Certificate; |
| import java.security.cert.CertificateFactory; |
| 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.Arrays; |
| import java.util.Collection; |
| import java.util.List; |
| |
| import javax.management.openmbean.KeyAlreadyExistsException; |
| import javax.net.ssl.CertPathTrustManagerParameters; |
| import javax.net.ssl.HandshakeCompletedEvent; |
| import javax.net.ssl.HandshakeCompletedListener; |
| import javax.net.ssl.KeyManager; |
| import javax.net.ssl.KeyManagerFactory; |
| import javax.net.ssl.SSLContext; |
| import javax.net.ssl.SSLException; |
| import javax.net.ssl.SSLServerSocket; |
| import javax.net.ssl.SSLServerSocketFactory; |
| import javax.net.ssl.SSLSession; |
| import javax.net.ssl.SSLSocket; |
| import javax.net.ssl.TrustManager; |
| import javax.net.ssl.TrustManagerFactory; |
| import javax.net.ssl.X509KeyManager; |
| |
| import org.eclipse.jetty.http.HttpSchemes; |
| import org.eclipse.jetty.http.security.Password; |
| import org.eclipse.jetty.io.EndPoint; |
| import org.eclipse.jetty.io.bio.SocketEndPoint; |
| import org.eclipse.jetty.server.Request; |
| import org.eclipse.jetty.server.bio.SocketConnector; |
| import org.eclipse.jetty.server.ssl.SslCertificates; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.resource.Resource; |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * SSL Socket Connector. |
| * |
| * This specialization of SocketConnector is an abstract listener that can be used as the basis for a |
| * specific JSSE listener. |
| * |
| * The original of this class was heavily based on the work from Court Demas, which in turn is |
| * based on the work from Forge Research. Since JSSE, this class has evolved significantly from |
| * that early work. |
| * |
| * @org.apache.xbean.XBean element="sslSocketConnector" description="Creates an ssl socket connector" |
| * |
| * |
| */ |
| public class EnhancedSslSocketConnector extends SocketConnector implements EnhancedSslConnector |
| { |
| /** Excluded cipher suites. */ |
| private String _excludeCipherSuites[]=null; |
| /** Included cipher suites. */ |
| private String _includeCipherSuites[]=null; |
| |
| /** KeyStore path. */ |
| private String _keystorePath=DEFAULT_KEYSTORE; |
| /** KeyStore provider name */ |
| private String _keystoreProvider; |
| /** KeyStore type */ |
| private String _keystoreType="JKS"; |
| /** SSL key alias */ |
| private String _keyAlias; |
| |
| /** TrustStore path */ |
| private String _truststorePath; |
| /** TrustStore provider name */ |
| private String _truststoreProvider; |
| /** TrustStore type */ |
| private String _truststoreType="JKS"; |
| |
| /** Set to true if client certificate authentication is required */ |
| private boolean _needClientAuth=false; |
| /** Set to true if client certificate authentication is desired */ |
| private boolean _wantClientAuth=false; |
| /** Set to true if renegotiation is allowed */ |
| private boolean _allowRenegotiate=false; |
| |
| /** KeyStore password */ |
| private transient Password _password; |
| /** Key password */ |
| private transient Password _keyPassword; |
| /** TrustStore password */ |
| private transient Password _trustPassword; |
| |
| /** SSL Provider name */ |
| private String _sslProvider; |
| /** SSL Protocol name */ |
| private String _sslProtocol="TLS"; |
| |
| /** SecureRandom algorithm */ |
| private String _secureRandomAlgorithm; |
| /** KeyManager factory algorithm */ |
| private String _sslKeyManagerFactoryAlgorithm=DEFAULT_KEYSTORE_ALGORITHM; |
| /** TrustManager factory algorithm */ |
| private String _sslTrustManagerFactoryAlgorithm=DEFAULT_TRUSTSTORE_ALGORITHM; |
| |
| /** Path to file that contains Certificate Revocation List */ |
| private String _crlPath; |
| /** Maximum certification path length (n - number of intermediate certs, -1 for unlimited) */ |
| private int _maxCertPathLength = -1; |
| /** Handshake timeout, 0 for maxIdleTime */ |
| private int _handshakeTimeout = 0; |
| |
| /** SSL context */ |
| private SSLContext _context; |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Constructor. |
| */ |
| public EnhancedSslSocketConnector() |
| { |
| super(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return True if SSL re-negotiation is allowed (default false) |
| */ |
| public boolean isAllowRenegotiate() |
| { |
| return _allowRenegotiate; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered |
| * a vulnerability in SSL/TLS with re-negotiation. If your JVM |
| * does not have CVE-2009-3555 fixed, then re-negotiation should |
| * not be allowed. |
| * @param allowRenegotiate true if re-negotiation is allowed (default false) |
| */ |
| public void setAllowRenegotiate(boolean allowRenegotiate) |
| { |
| _allowRenegotiate = allowRenegotiate; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| public void accept(int acceptorID) |
| throws IOException, InterruptedException |
| { |
| Socket socket = _serverSocket.accept(); |
| configure(socket); |
| |
| ConnectorEndPoint connection=new SslConnectorEndPoint(socket); |
| connection.dispatch(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| protected void configure(Socket socket) |
| throws IOException |
| { |
| super.configure(socket); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| protected SSLContext createSSLContext() throws Exception |
| { |
| KeyStore keyStore = getKeyStore(_keystorePath, _keystoreType, _keystoreProvider, _password==null?null:_password.toString()); |
| KeyStore trustStore = getTrustStore(_truststorePath, _truststoreType, _truststoreProvider, _trustPassword == null ? null : _trustPassword.toString()); |
| Collection<? extends CRL> crls = loadCRL(_crlPath); |
| |
| KeyManager[] keyManagers = getKeyManagers(keyStore, trustStore, crls); |
| TrustManager[] trustManagers = getTrustManagers(trustStore, crls); |
| |
| SecureRandom secureRandom = |
| _secureRandomAlgorithm == null ? null : SecureRandom.getInstance(_secureRandomAlgorithm); |
| SSLContext context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : |
| SSLContext.getInstance(_sslProtocol,_sslProvider); |
| context.init(keyManagers,trustManagers,secureRandom); |
| |
| return context; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| protected SSLServerSocketFactory createFactory() |
| throws Exception |
| { |
| if (_context == null) |
| _context = createSSLContext(); |
| |
| return _context.getServerSocketFactory(); |
| } |
| |
| |
| /* ------------------------------------------------------------ */ |
| protected KeyManager[] getKeyManagers(KeyStore keyStore, KeyStore trustStore, Collection<? extends CRL> crls) throws Exception |
| { |
| KeyManagerFactory keyManagerFactory=KeyManagerFactory.getInstance(_sslKeyManagerFactoryAlgorithm); |
| keyManagerFactory.init(keyStore,_keyPassword==null?(_password==null?null:_password.toString().toCharArray()):_keyPassword.toString().toCharArray()); |
| KeyManager[] managers = keyManagerFactory.getKeyManagers(); |
| |
| for (int idx=0; idx < managers.length; idx++) |
| { |
| if (managers[idx] instanceof X509KeyManager) |
| { |
| managers[idx] = new SslKeyManager(_keyAlias, (X509KeyManager)managers[idx], |
| new CertificateValidator(keyStore, trustStore, crls)); |
| } |
| } |
| |
| return managers; |
| } |
| |
| protected TrustManager[] getTrustManagers(KeyStore trustStore, Collection<? extends CRL> crls) throws Exception |
| { |
| TrustManager[] managers = null; |
| if (trustStore != null) |
| { |
| // Revocation checking is only supported for PKIX algorithm |
| if (_sslTrustManagerFactoryAlgorithm.equalsIgnoreCase("PKIX")) |
| { |
| PKIXBuilderParameters pbParams = |
| new PKIXBuilderParameters(trustStore, new X509CertSelector()); |
| |
| // Enable revocation checking |
| pbParams.setRevocationEnabled(true); |
| |
| // Set maximum certification path length |
| pbParams.setMaxPathLength(_maxCertPathLength); |
| |
| // Set static Certificate Revocation List |
| if (crls != null && !crls.isEmpty()) |
| { |
| pbParams.addCertStore(CertStore.getInstance("Collection", |
| new CollectionCertStoreParameters(crls))); |
| } |
| |
| // Enable On-Line Certificate Status Protocol (OCSP) support |
| Security.setProperty("ocsp.enable", "true"); |
| |
| // Enable Certificate Revocation List Distribution Points (CRLDP) support |
| System.setProperty("com.sun.security.enableCRLDP","true"); |
| |
| TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_sslTrustManagerFactoryAlgorithm); |
| trustManagerFactory.init(new CertPathTrustManagerParameters(pbParams)); |
| |
| managers = trustManagerFactory.getTrustManagers(); |
| } |
| else |
| { |
| TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_sslTrustManagerFactoryAlgorithm); |
| trustManagerFactory.init(trustStore); |
| |
| managers = trustManagerFactory.getTrustManagers(); |
| } |
| } |
| |
| return managers; |
| } |
| |
| private Collection<? extends CRL> loadCRL(String crlPath) throws Exception |
| { |
| Collection<? extends CRL> crlList = null; |
| |
| InputStream in = null; |
| try { |
| in = Resource.newResource(crlPath).getInputStream(); |
| crlList = CertificateFactory.getInstance("X.509").generateCRLs(in); |
| } |
| finally |
| { |
| if (in != null) |
| { |
| in.close(); |
| } |
| } |
| |
| return crlList; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| protected KeyStore getKeyStore(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 (inStream != null) |
| { |
| inStream.close(); |
| } |
| } |
| } |
| |
| protected 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); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Allow the Listener a chance to customise the request. before the server does its stuff. <br> |
| * This allows the required attributes to be set for SSL requests. <br> |
| * The requirements of the Servlet specs are: |
| * <ul> |
| * <li> an attribute named "javax.servlet.request.ssl_id" of type String (since Spec 3.0).</li> |
| * <li> an attribute named "javax.servlet.request.cipher_suite" of type String.</li> |
| * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li> |
| * <li> an attribute named "javax.servlet.request.X509Certificate" of type |
| * java.security.cert.X509Certificate[]. This is an array of objects of type X509Certificate, |
| * the order of this array is defined as being in ascending order of trust. The first |
| * certificate in the chain is the one set by the client, the next is the one used to |
| * authenticate the first, and so on. </li> |
| * </ul> |
| * |
| * @param endpoint The Socket the request arrived on. |
| * This should be a {@link SocketEndPoint} wrapping a {@link SSLSocket}. |
| * @param request HttpRequest to be customised. |
| */ |
| @Override |
| public void customize(EndPoint endpoint, Request request) |
| throws IOException |
| { |
| super.customize(endpoint, request); |
| request.setScheme(HttpSchemes.HTTPS); |
| |
| SocketEndPoint socket_end_point = (SocketEndPoint)endpoint; |
| SSLSocket sslSocket = (SSLSocket)socket_end_point.getTransport(); |
| SSLSession sslSession = sslSocket.getSession(); |
| |
| SslCertificates.customize(sslSession,endpoint,request); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String[] getExcludeCipherSuites() { |
| return _excludeCipherSuites; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String[] getIncludeCipherSuites() |
| { |
| return _includeCipherSuites; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String getKeystore() |
| { |
| return _keystorePath; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String getKeystoreType() |
| { |
| return (_keystoreType); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public boolean getNeedClientAuth() |
| { |
| return _needClientAuth; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String getProtocol() |
| { |
| return _sslProtocol; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String getProvider() { |
| return _sslProvider; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String getSecureRandomAlgorithm() |
| { |
| return (this._secureRandomAlgorithm); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String getSslKeyManagerFactoryAlgorithm() |
| { |
| return (this._sslKeyManagerFactoryAlgorithm); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String getSslTrustManagerFactoryAlgorithm() |
| { |
| return (this._sslTrustManagerFactoryAlgorithm); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String getTruststore() |
| { |
| return _truststorePath; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public String getTruststoreType() |
| { |
| return _truststoreType; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public boolean getWantClientAuth() |
| { |
| return _wantClientAuth; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * By default, we're confidential, given we speak SSL. But, if we've been told about an |
| * confidential port, and said port is not our port, then we're not. This allows separation of |
| * listeners providing INTEGRAL versus CONFIDENTIAL constraints, such as one SSL listener |
| * configured to require client certs providing CONFIDENTIAL, whereas another SSL listener not |
| * requiring client certs providing mere INTEGRAL constraints. |
| */ |
| @Override |
| public boolean isConfidential(Request request) |
| { |
| final int confidentialPort = getConfidentialPort(); |
| return confidentialPort == 0 || confidentialPort == request.getServerPort(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * By default, we're integral, given we speak SSL. But, if we've been told about an integral |
| * port, and said port is not our port, then we're not. This allows separation of listeners |
| * providing INTEGRAL versus CONFIDENTIAL constraints, such as one SSL listener configured to |
| * require client certs providing CONFIDENTIAL, whereas another SSL listener not requiring |
| * client certs providing mere INTEGRAL constraints. |
| */ |
| @Override |
| public boolean isIntegral(Request request) |
| { |
| final int integralPort = getIntegralPort(); |
| return integralPort == 0 || integralPort == request.getServerPort(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param host The host name that this server should listen on |
| * @param port the port that this server should listen on |
| * @param backlog See {@link ServerSocket#bind(java.net.SocketAddress, int)} |
| * @return A new {@link ServerSocket socket object} bound to the supplied address with all other |
| * settings as per the current configuration of this connector. |
| * @see #setWantClientAuth(boolean) |
| * @see #setNeedClientAuth(boolean) |
| * @exception IOException |
| */ |
| |
| /* ------------------------------------------------------------ */ |
| @Override |
| protected ServerSocket newServerSocket(String host, int port,int backlog) throws IOException |
| { |
| SSLServerSocketFactory factory = null; |
| SSLServerSocket socket = null; |
| |
| try |
| { |
| factory = createFactory(); |
| |
| socket = (SSLServerSocket) (host==null? |
| factory.createServerSocket(port,backlog): |
| factory.createServerSocket(port,backlog,InetAddress.getByName(host))); |
| |
| if (_wantClientAuth) |
| socket.setWantClientAuth(_wantClientAuth); |
| if (_needClientAuth) |
| socket.setNeedClientAuth(_needClientAuth); |
| |
| if ((_excludeCipherSuites!=null&&_excludeCipherSuites.length>0) |
| || (_includeCipherSuites!=null&&_includeCipherSuites.length>0)) |
| { |
| List<String> includedCSList; |
| if (_includeCipherSuites!=null) |
| { |
| includedCSList = Arrays.asList(_includeCipherSuites); |
| } else { |
| includedCSList = new ArrayList<String>(); |
| } |
| List<String> excludedCSList; |
| if (_excludeCipherSuites!=null) |
| { |
| excludedCSList = Arrays.asList(_excludeCipherSuites); |
| } else { |
| excludedCSList = new ArrayList<String>(); |
| } |
| String[] enabledCipherSuites = socket.getEnabledCipherSuites(); |
| List<String> enabledCSList = new ArrayList<String>(Arrays.asList(enabledCipherSuites)); |
| |
| String[] supportedCipherSuites = socket.getSupportedCipherSuites(); |
| List<String> supportedCSList = Arrays.asList(supportedCipherSuites); |
| |
| for (String cipherName : includedCSList) |
| { |
| if ((!enabledCSList.contains(cipherName)) |
| && supportedCSList.contains(cipherName)) |
| { |
| enabledCSList.add(cipherName); |
| } |
| } |
| |
| for (String cipherName : excludedCSList) |
| { |
| if (enabledCSList.contains(cipherName)) |
| { |
| enabledCSList.remove(cipherName); |
| } |
| } |
| enabledCipherSuites = enabledCSList.toArray(new String[enabledCSList.size()]); |
| |
| socket.setEnabledCipherSuites(enabledCipherSuites); |
| } |
| |
| } |
| catch (IOException e) |
| { |
| throw e; |
| } |
| catch (Exception e) |
| { |
| Log.warn(e.toString()); |
| Log.debug(e); |
| throw new IOException("!JsseListener: " + e); |
| } |
| return socket; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * |
| */ |
| public void setExcludeCipherSuites(String[] cipherSuites) { |
| this._excludeCipherSuites = cipherSuites; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setIncludeCipherSuites(String[] cipherSuites) |
| { |
| this._includeCipherSuites=cipherSuites; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setKeyPassword(String password) |
| { |
| _keyPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param keystore The resource path to the keystore, or null for built in keystores. |
| */ |
| public void setKeystore(String keystore) |
| { |
| _keystorePath = keystore; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setKeystoreType(String keystoreType) |
| { |
| _keystoreType = keystoreType; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Set the value of the needClientAuth property |
| * |
| * @param needClientAuth true iff we require client certificate authentication. |
| */ |
| public void setNeedClientAuth(boolean needClientAuth) |
| { |
| _needClientAuth = needClientAuth; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setPassword(String password) |
| { |
| _password = Password.getPassword(PASSWORD_PROPERTY,password,null); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setTrustPassword(String password) |
| { |
| _trustPassword = Password.getPassword(PASSWORD_PROPERTY,password,null); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setProtocol(String protocol) |
| { |
| _sslProtocol = protocol; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setProvider(String _provider) { |
| this._sslProvider = _provider; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setSecureRandomAlgorithm(String algorithm) |
| { |
| this._secureRandomAlgorithm = algorithm; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setSslKeyManagerFactoryAlgorithm(String algorithm) |
| { |
| this._sslKeyManagerFactoryAlgorithm = algorithm; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void setSslTrustManagerFactoryAlgorithm(String algorithm) |
| { |
| this._sslTrustManagerFactoryAlgorithm = algorithm; |
| } |
| |
| |
| public void setTruststore(String truststore) |
| { |
| _truststorePath = truststore; |
| } |
| |
| |
| public void setTruststoreType(String truststoreType) |
| { |
| _truststoreType = truststoreType; |
| } |
| |
| public void setSslContext(SSLContext sslContext) |
| { |
| _context = sslContext; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext) |
| */ |
| public SSLContext getSslContext() |
| { |
| try |
| { |
| if (_context == null) |
| _context=createSSLContext(); |
| } |
| catch(Exception e) |
| { |
| throw new RuntimeException(e); |
| } |
| |
| return _context; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Set the value of the _wantClientAuth property. This property is used |
| * internally when opening server sockets. |
| * |
| * @param wantClientAuth true if we want client certificate authentication. |
| * @see SSLServerSocket#setWantClientAuth |
| */ |
| public void setWantClientAuth(boolean wantClientAuth) |
| { |
| _wantClientAuth = wantClientAuth; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Set the time in milliseconds for so_timeout during ssl handshaking |
| * @param msec a non-zero value will be used to set so_timeout during |
| * ssl handshakes. A zero value means the maxIdleTime is used instead. |
| */ |
| public void setHandshakeTimeout (int msec) |
| { |
| _handshakeTimeout = msec; |
| } |
| |
| |
| /* ------------------------------------------------------------ */ |
| public int getHandshakeTimeout () |
| { |
| return _handshakeTimeout; |
| } |
| |
| public void setKeystoreProvider(String keystoreProvider) |
| { |
| _keystoreProvider = keystoreProvider; |
| } |
| |
| public String getKeystoreProvider() |
| { |
| return _keystoreProvider; |
| } |
| |
| public void setTruststoreProvider(String truststoreProvider) |
| { |
| _truststoreProvider = truststoreProvider; |
| } |
| |
| public String getTruststoreProvider() |
| { |
| return _truststoreProvider; |
| } |
| |
| public void setCrlPath(String crlPath) |
| { |
| _crlPath = crlPath; |
| } |
| |
| public String getCrlPath() |
| { |
| return _crlPath; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public class SslConnectorEndPoint extends ConnectorEndPoint |
| { |
| public SslConnectorEndPoint(Socket socket) throws IOException |
| { |
| super(socket); |
| } |
| |
| @Override |
| public void shutdownOutput() throws IOException |
| { |
| close(); |
| } |
| |
| @Override |
| public void run() |
| { |
| try |
| { |
| int handshakeTimeout = getHandshakeTimeout(); |
| int oldTimeout = _socket.getSoTimeout(); |
| if (handshakeTimeout > 0) |
| _socket.setSoTimeout(handshakeTimeout); |
| |
| final SSLSocket ssl=(SSLSocket)_socket; |
| ssl.addHandshakeCompletedListener(new HandshakeCompletedListener() |
| { |
| boolean handshook=false; |
| public void handshakeCompleted(HandshakeCompletedEvent event) |
| { |
| if (handshook) |
| { |
| if (!_allowRenegotiate) |
| { |
| Log.warn("SSL renegotiate denied: "+ssl); |
| try{ssl.close();}catch(IOException e){Log.warn(e);} |
| } |
| } |
| else |
| handshook=true; |
| } |
| }); |
| ssl.startHandshake(); |
| |
| if (handshakeTimeout>0) |
| _socket.setSoTimeout(oldTimeout); |
| |
| super.run(); |
| } |
| catch (SSLException e) |
| { |
| Log.debug(e); |
| try{close();} |
| catch(IOException e2){Log.ignore(e2);} |
| } |
| catch (IOException e) |
| { |
| Log.debug(e); |
| try{close();} |
| catch(IOException e2){Log.ignore(e2);} |
| } |
| } |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Unsupported. |
| * |
| * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) |
| */ |
| public String getAlgorithm() |
| { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Unsupported. |
| * |
| * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) |
| */ |
| public void setAlgorithm(String algorithm) |
| { |
| throw new UnsupportedOperationException(); |
| } |
| } |