org.parosproxy.paros.network.SSLConnector.java Source code

Java tutorial

Introduction

Here is the source code for org.parosproxy.paros.network.SSLConnector.java

Source

/*
 * Created on May 31, 2004
 *
 * Paros and its related class files.
 * 
 * Paros is an HTTP/HTTPS proxy for assessing web application security.
 * Copyright (C) 2003-2004 Chinotec Technologies Company
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the Clarified Artistic License
 * as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Clarified Artistic License for more details.
 * 
 * You should have received a copy of the Clarified Artistic License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
// ZAP: 2012/04/23 Added @Override annotation to all appropriate methods.
// ZAP: 2013/01/23 Clean up of exception handling/logging.
// ZAP: 2013/01/25 Issue 462: SSLSocketFactory with TLS enabled and default Cipher options
// ZAP: 2013/06/01 Issue 669: Certificate algorithm constraints in Java 1.7
// ZAP: 2014/03/23 Tidy up, removed and deprecated unused methods other minor changes
// ZAP: 2014/03/23 Issue 951: TLS' versions 1.1 and 1.2 not enabled by default
// ZAP: 2014/07/17 Issue 704: ZAP Error: handshake alert: unrecognized_name
// ZAP: 2014/08/14 Issue 1184: Improve support for IBM JDK
// ZAP: 2014/08/14 Issue 1274: ZAP Error [javax.net.ssl.SSLException]: Unsupported record version SSLv2Hello
// ZAP: 2014/10/28 Issue 1390: Force https on cfu call
// ZAP: 2015/10/13 Issue 1975: Allow use of default disabled cipher suites (such as RC4-SHA)

package org.parosproxy.paros.network;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.security.InvalidKeyException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;

import org.apache.commons.collections.MapIterator;
import org.apache.commons.collections.map.LRUMap;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
import org.apache.log4j.Logger;
import org.parosproxy.paros.security.CachedSslCertifificateServiceImpl;
import org.parosproxy.paros.security.SslCertificateService;

import ch.csnc.extension.httpclient.SSLContextManager;

public class SSLConnector implements SecureProtocolSocketFactory {

    private static final String SSL = "SSL";

    private static final String CONTENTS_UNRECOGNIZED_NAME_EXCEPTION = "unrecognized_name";

    public static final String SECURITY_PROTOCOL_SSL_V2_HELLO = "SSLv2Hello";
    public static final String SECURITY_PROTOCOL_SSL_V3 = "SSLv3";
    public static final String SECURITY_PROTOCOL_TLS_V1 = "TLSv1";
    public static final String SECURITY_PROTOCOL_TLS_V1_1 = "TLSv1.1";
    public static final String SECURITY_PROTOCOL_TLS_V1_2 = "TLSv1.2";

    private static final String[] DEFAULT_ENABLED_PROTOCOLS = { SECURITY_PROTOCOL_SSL_V3, SECURITY_PROTOCOL_TLS_V1,
            SECURITY_PROTOCOL_TLS_V1_1, SECURITY_PROTOCOL_TLS_V1_2 };

    private static final String[] FAIL_SAFE_DEFAULT_ENABLED_PROTOCOLS = { SECURITY_PROTOCOL_TLS_V1 };

    // client socket factories
    private SSLSocketFactory clientSSLSockFactory = null;
    private SSLSocketFactory clientSSLSockCertFactory = null;

    private static String[] supportedProtocols;
    private static String[] clientEnabledProtocols;
    private static String[] serverEnabledProtocols;

    private static ServerSslSocketsDecorator serverSslSocketsDecorator;
    private ClientSslSocketsDecorator clientSslSocketsDecorator;

    /**
     * The maximum time, in minutes, that the cached misconfigured hosts are considered valid.
     * 
     * @see #cacheMisconfiguredHost(String, int, InetAddress)
     */
    private static long MAX_AGE_MISCONFIGURED_HOST_IN_MIN = 5;

    /**
     * The maximum time, in milliseconds, that the cached misconfigured hosts are considered valid.
     * 
     * @see #MAX_AGE_MISCONFIGURED_HOST_IN_MIN
     * @see #cacheMisconfiguredHost(String, int, InetAddress)
     */
    private static long MAX_AGE_MISCONFIGURED_HOST_IN_MS = TimeUnit.MINUTES
            .toMillis(MAX_AGE_MISCONFIGURED_HOST_IN_MIN);

    /**
     * A cache of misconfigured hosts (i.e. secure connection cannot be established because of "unrecognized_name" exception).
     * The hosts are cached for a (short) period of time to avoid (most likely) failed connections.
     * <p>
     * The {@code key} is the hostname+port and the {@code value} the address of the host.
     * 
     * @see #MAX_AGE_MISCONFIGURED_HOST_IN_MIN
     * @see #timeStampLastStaleCheck
     * @see #cacheMisconfiguredHost(String, int, InetAddress)
     * @see #getCachedMisconfiguredHost(String, int)
     * @see #removeStaleCachedMisconfiguredHosts()
     */
    private static LRUMap misconfiguredHosts;

    /**
     * Time stamp of last time the cache of misconfigured hosts was checked for stale entries.
     * 
     * @see #misconfiguredHosts
     * @see #removeStaleCachedMisconfiguredHosts()
     */
    private static long timeStampLastStaleCheck;

    // server related socket factories

    // ZAP: removed ServerSocketFaktory

    // ZAP: Added logger
    private static final Logger logger = Logger.getLogger(SSLConnector.class);

    private static SSLContextManager sslContextManager = null;

    /*
     * If relaxedTrust then we ignore all of the 'usual' https checks.
     * This is needed in order to test sites with custom certs
     * However we dont want to override these checks for things like the 'check-for-updates' call
     */
    private boolean relaxedTrust = true;

    public SSLConnector() {
        this(true);
    }

    public SSLConnector(boolean relaxedTrust) {
        this.relaxedTrust = relaxedTrust;
        if (clientSSLSockFactory == null) {
            serverSslSocketsDecorator = new ServerSslSocketsDecorator();
            clientSslSocketsDecorator = new ClientSslSocketsDecorator();

            clientSSLSockFactory = getClientSocketFactory(SSL);
            misconfiguredHosts = new LRUMap(10);
        }
        // ZAP: removed ServerSocketFaktory
        if (sslContextManager == null) {
            sslContextManager = new SSLContextManager();
        }

    }

    public SSLContextManager getSSLContextManager() {
        return sslContextManager;
    }

    public void setEnableClientCert(boolean enabled) {
        if (enabled) {
            clientSSLSockFactory = clientSSLSockCertFactory;
            logger.info("ClientCert enabled using: " + sslContextManager.getDefaultKey());
        } else {
            clientSSLSockFactory = getClientSocketFactory(SSL);
            logger.info("ClientCert disabled");
        }
    }

    public void setActiveCertificate() {

        SSLContext sslcont = sslContextManager.getSSLContext(sslContextManager.getDefaultKey());
        clientSSLSockCertFactory = createDecoratedClientSslSocketFactory(sslcont.getSocketFactory());
        logger.info("ActiveCertificate set to: " + sslContextManager.getDefaultKey());
    }

    // ZAP: removed server socket methods

    //FIXME: really needed?
    public ServerSocket listen(int paramPortNum, int maxConnection, InetAddress ip) throws IOException {
        // ZAP: removed ServerSocketFaktory
        //      ServerSocket sslServerPort = serverSSLSockFactory.createServerSocket(
        //            paramPortNum, maxConnection, ip);
        //      return sslServerPort;
        throw new UnsupportedOperationException(
                "this code is probably not needed any more, SSL server sockets are not \"static\", they're created on the fly");
    }

    public SSLSocketFactory getClientSocketFactory(String type) {
        // Trust all invalid server certificate
        TrustManager[] trustMgr = new TrustManager[] { new RelaxedX509TrustManager() };

        try {
            SSLContext sslContext = SSLContext.getInstance(type);
            java.security.SecureRandom x = new java.security.SecureRandom();
            x.setSeed(System.currentTimeMillis());
            if (relaxedTrust) {
                sslContext.init(null, trustMgr, x);
            } else {
                sslContext.init(null, null, x);
            }
            clientSSLSockFactory = createDecoratedClientSslSocketFactory(sslContext.getSocketFactory());
            HttpsURLConnection.setDefaultSSLSocketFactory(clientSSLSockFactory);

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        return clientSSLSockFactory;

    }

    // ZAP: removed ServerSocketFaktory

    /**
     * @deprecated (2.3.0) No longer supported since it's no longer required/called by Commons HttpClient library (version >= 
     *             3.0). Throws {@code UnsupportedOperationException}.
     */
    @Override
    @Deprecated
    public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
            throws IOException, UnknownHostException {

        throw new UnsupportedOperationException(
                "Method no longer supported since it's no longer required/called by Commons HttpClient library (version >= 3.0).");
    }

    public static String[] getSupportedProtocols() {
        if (supportedProtocols == null) {
            readSupportedProtocols(null);
        }
        return Arrays.copyOf(supportedProtocols, supportedProtocols.length);
    }

    private static synchronized void readSupportedProtocols(SSLSocket sslSocket) {
        if (supportedProtocols == null) {
            logger.info("Reading supported SSL/TLS protocols...");
            String[] tempSupportedProtocols;
            if (sslSocket != null) {
                logger.info("Using an existing SSLSocket...");
                tempSupportedProtocols = sslSocket.getSupportedProtocols();
            } else {
                logger.info("Using a SSLEngine...");
                try {
                    SSLContext ctx = SSLContext.getInstance(SSL);
                    ctx.init(null, null, null);
                    try {
                        tempSupportedProtocols = ctx.createSSLEngine().getSupportedProtocols();
                    } catch (UnsupportedOperationException e) {
                        logger.warn("Failed to use SSLEngine. Trying with unconnected socket...", e);
                        try (SSLSocket socket = (SSLSocket) ctx.getSocketFactory().createSocket()) {
                            tempSupportedProtocols = socket.getSupportedProtocols();
                        }
                    }
                } catch (NoSuchAlgorithmException | KeyManagementException | IOException e) {
                    logger.error(
                            "Failed to read the SSL/TLS supported protocols." + " Using default protocol versions: "
                                    + Arrays.toString(FAIL_SAFE_DEFAULT_ENABLED_PROTOCOLS),
                            e);
                    tempSupportedProtocols = FAIL_SAFE_DEFAULT_ENABLED_PROTOCOLS;
                }
            }
            Arrays.sort(tempSupportedProtocols);
            supportedProtocols = tempSupportedProtocols;
            logger.info("Done reading supported SSL/TLS protocols: " + Arrays.toString(supportedProtocols));
        }
    }

    public static String[] getClientEnabledProtocols() {
        if (clientEnabledProtocols == null) {
            setClientEnabledProtocols(DEFAULT_ENABLED_PROTOCOLS);
        }
        return Arrays.copyOf(clientEnabledProtocols, clientEnabledProtocols.length);
    }

    public static void setClientEnabledProtocols(String[] protocols) {
        clientEnabledProtocols = extractSupportedProtocols(protocols);
    }

    public static String[] getServerEnabledProtocols() {
        if (serverEnabledProtocols == null) {
            setServerEnabledProtocols(DEFAULT_ENABLED_PROTOCOLS);
        }
        return Arrays.copyOf(serverEnabledProtocols, serverEnabledProtocols.length);
    }

    public static void setServerEnabledProtocols(String[] protocols) {
        serverEnabledProtocols = extractSupportedProtocols(protocols);
    }

    private static String[] extractSupportedProtocols(String[] enabledProtocols) {
        if (enabledProtocols == null || enabledProtocols.length == 0) {
            throw new IllegalArgumentException("Protocol(s) required but no protocol set.");
        }
        String[] supportedProtocols = getSupportedProtocols();
        ArrayList<String> enabledSupportedProtocols = new ArrayList<>(supportedProtocols.length);
        for (String protocol : enabledProtocols) {
            if (protocol != null && Arrays.binarySearch(supportedProtocols, protocol) >= 0) {
                enabledSupportedProtocols.add(protocol);
            }
        }
        enabledSupportedProtocols.trimToSize();

        if (enabledSupportedProtocols.isEmpty()) {
            throw new IllegalArgumentException("No supported protocol(s) set.");
        }

        String[] extractedSupportedProtocols = new String[enabledSupportedProtocols.size()];
        enabledSupportedProtocols.toArray(extractedSupportedProtocols);
        return extractedSupportedProtocols;
    }

    /**
     * Attempts to get a new socket connection to the given host within the
     * given time limit.
     * 
     * @param host
     *            the host name/IP
     * @param port
     *            the port on the host
     * @param localAddress
     *            the local host name/IP to bind the socket to
     * @param localPort
     *            the port on the local machine
     * @param params
     *            {@link HttpConnectionParams Http connection parameters}
     * 
     * @return Socket a new socket
     * 
     * @throws IOException
     *             if an I/O error occurs while creating the socket
     * @throws UnknownHostException
     *             if the IP address of the host cannot be determined
     * @throws    ConnectTimeoutException        
     */
    @Override
    public Socket createSocket(final String host, final int port, final InetAddress localAddress,
            final int localPort, final HttpConnectionParams params)
            throws IOException, UnknownHostException, ConnectTimeoutException {
        if (params == null) {
            throw new IllegalArgumentException("Parameters may not be null");
        }
        int timeout = params.getConnectionTimeout();
        if (timeout == 0) {
            InetAddress hostAddress = getCachedMisconfiguredHost(host, port);
            if (hostAddress != null) {
                return clientSSLSockFactory.createSocket(hostAddress, port, localAddress, localPort);
            }
            try {
                SSLSocket sslSocket = (SSLSocket) clientSSLSockFactory.createSocket(host, port, localAddress,
                        localPort);
                sslSocket.startHandshake();

                return sslSocket;
            } catch (SSLException e) {
                if (!e.getMessage().contains(CONTENTS_UNRECOGNIZED_NAME_EXCEPTION)) {
                    throw e;
                }

                hostAddress = InetAddress.getByName(host);
                cacheMisconfiguredHost(host, port, hostAddress);
                return clientSSLSockFactory.createSocket(hostAddress, port, localAddress, localPort);
            }
        }
        Socket socket = clientSSLSockFactory.createSocket();
        SocketAddress localAddr = new InetSocketAddress(localAddress, localPort);
        socket.bind(localAddr);
        SocketAddress remoteAddr = new InetSocketAddress(host, port);
        socket.connect(remoteAddr, timeout);

        return socket;
    }

    private static void cacheMisconfiguredHost(String host, int port, InetAddress address) {
        synchronized (misconfiguredHosts) {
            if (!misconfiguredHosts.isEmpty()) {
                removeStaleCachedMisconfiguredHosts();
            }

            logger.info("Caching address of misconfigured (\"unrecognized_name\") host [host=" + host + ", port="
                    + port + "] for the next " + MAX_AGE_MISCONFIGURED_HOST_IN_MIN
                    + " minutes, following connections will not use the hostname.");
            misconfiguredHosts.put(host + port, new MisconfiguredHostCacheEntry(host, port, address));
        }
    }

    /**
     * Removes all stale cached misconfigured hosts.
     * <p>
     * <strong>Note:</strong> This method should be called in a {@code synchronized} block with the object
     * {@code misconfiguredHosts}.
     *
     * @see #misconfiguredHosts
     * @see #cacheMisconfiguredHost(String, int, InetAddress)
     * @see #getCachedMisconfiguredHost(String, int)
     */
    private static void removeStaleCachedMisconfiguredHosts() {
        long currentTime = System.currentTimeMillis();
        if (!((currentTime - timeStampLastStaleCheck) >= MAX_AGE_MISCONFIGURED_HOST_IN_MS)) {
            return;
        }
        timeStampLastStaleCheck = currentTime;

        for (MapIterator it = misconfiguredHosts.mapIterator(); it.hasNext();) {
            it.next();

            MisconfiguredHostCacheEntry entry = (MisconfiguredHostCacheEntry) it.getValue();
            if (entry.isStale(currentTime)) {
                logger.info("Removing stale cached address of misconfigured (\"unrecognized_name\") host [host="
                        + entry.getHost() + ", port=" + entry.getPort()
                        + "], following connections will be attempted with the hostname.");
                it.remove();
            }
        }
    }

    private static InetAddress getCachedMisconfiguredHost(String host, int port) {
        synchronized (misconfiguredHosts) {
            if (misconfiguredHosts.isEmpty()) {
                return null;
            }
            removeStaleCachedMisconfiguredHosts();

            MisconfiguredHostCacheEntry entry = (MisconfiguredHostCacheEntry) misconfiguredHosts.get(host + port);
            if (entry != null) {
                return entry.getAddress();
            }
            return null;
        }
    }

    /**
     * @deprecated (2.3.0) No longer supported since it's no longer required/called by Commons HttpClient library (version >= 
     *             3.0). Throws {@code UnsupportedOperationException}.
     */
    @Override
    @Deprecated
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        throw new UnsupportedOperationException(
                "Method no longer supported since it's no longer required/called by Commons HttpClient library (version >= 3.0).");
    }

    /**
     * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean)
     */
    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
            throws IOException, UnknownHostException {
        InetAddress inetAddress = getCachedMisconfiguredHost(host, port);
        if (inetAddress != null) {
            return clientSSLSockFactory.createSocket(socket, inetAddress.getHostAddress(), port, autoClose);
        }

        try {
            SSLSocket socketSSL = (SSLSocket) clientSSLSockFactory.createSocket(socket, host, port, autoClose);
            socketSSL.startHandshake();

            return socketSSL;
        } catch (SSLException e) {
            if (e.getMessage().contains(CONTENTS_UNRECOGNIZED_NAME_EXCEPTION)) {
                cacheMisconfiguredHost(host, port, InetAddress.getByName(host));
            }
            // Throw the exception anyway because the socket might no longer be usable (e.g. closed). The connection will be 
            // retried (see HttpMethodDirector#executeWithRetry(HttpMethod) for more information on the retry policy).
            throw e;
        }
    }

    /**
     * Create a SSLsocket using an existing connected socket. It can be used
     * such as a tunneled SSL proxy socket (eg when a CONNECT request is
     * received). This SSLSocket will start server side handshake immediately.
     * 
     * @param targethost the host where you want to connect to 
     * @param socket
     * @return
     * @throws IOException
     */
    public Socket createTunnelServerSocket(String targethost, Socket socket) throws IOException {
        // ZAP: added host name parameter
        SSLSocket s = (SSLSocket) getTunnelSSLSocketFactory(targethost).createSocket(socket,
                socket.getInetAddress().getHostAddress(), socket.getPort(), true);

        s.setUseClientMode(false);
        s.startHandshake();
        return s;
    }

    // ZAP: added new ServerSocketFaktory with support of dynamic SSL certificates
    public SSLSocketFactory getTunnelSSLSocketFactory(String hostname) {

        //   SSLServerSocketFactory ssf = null;
        // set up key manager to do server authentication

        //   KeyStore ks;
        try {
            SSLContext ctx = SSLContext.getInstance(SSL);
            // Normally "SunX509", "IbmX509"...
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

            SslCertificateService scs = CachedSslCertifificateServiceImpl.getService();
            KeyStore ks = scs.createCertForHost(hostname);

            kmf.init(ks, SslCertificateService.PASSPHRASE);
            java.security.SecureRandom x = new java.security.SecureRandom();
            x.setSeed(System.currentTimeMillis());
            ctx.init(kmf.getKeyManagers(), null, x);

            SSLSocketFactory tunnelSSLFactory = createDecoratedServerSslSocketFactory(ctx.getSocketFactory());

            return tunnelSSLFactory;

        } catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | UnrecoverableKeyException
                | KeyManagementException | InvalidKeyException | NoSuchProviderException | SignatureException
                | IOException e) {
            // Turn into RuntimeException. How to handle this error in a user
            // friendly way?
            throw new RuntimeException(e);
        }
    }

    private static SSLSocketFactory createDecoratedServerSslSocketFactory(final SSLSocketFactory delegate) {
        return new DecoratedSocketsSslSocketFactory(delegate, serverSslSocketsDecorator);
    }

    private SSLSocketFactory createDecoratedClientSslSocketFactory(final SSLSocketFactory delegate) {
        return new DecoratedSocketsSslSocketFactory(delegate, clientSslSocketsDecorator);
    }

    private static class ServerSslSocketsDecorator implements DecoratedSocketsSslSocketFactory.SslSocketDecorator {

        @Override
        public void decorate(SSLSocket sslSocket) {
            if (supportedProtocols == null) {
                readSupportedProtocols(sslSocket);
            }
            sslSocket.setEnabledProtocols(getServerEnabledProtocols());
        }
    }

    private class ClientSslSocketsDecorator implements DecoratedSocketsSslSocketFactory.SslSocketDecorator {

        @Override
        public void decorate(SSLSocket sslSocket) {
            if (supportedProtocols == null) {
                readSupportedProtocols(sslSocket);
            }
            sslSocket.setEnabledProtocols(getClientEnabledProtocols());
            if (relaxedTrust) {
                sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites());
            }
        }
    }

    private static class MisconfiguredHostCacheEntry {

        private final String host;
        private final int port;
        private final InetAddress address;
        private final long timeStampCreation;

        public MisconfiguredHostCacheEntry(String host, int port, InetAddress address) {
            this.host = host;
            this.port = port;
            this.address = address;
            this.timeStampCreation = System.currentTimeMillis();
        }

        public String getHost() {
            return host;
        }

        public int getPort() {
            return port;
        }

        public InetAddress getAddress() {
            return address;
        }

        public boolean isStale(long currentTime) {
            return (currentTime - timeStampCreation) >= MAX_AGE_MISCONFIGURED_HOST_IN_MS;
        }
    }

}

class RelaxedX509TrustManager extends X509ExtendedTrustManager {
    public boolean checkClientTrusted(java.security.cert.X509Certificate[] chain) {
        return true;
    }

    public boolean isServerTrusted(java.security.cert.X509Certificate[] chain) {
        return true;
    }

    public boolean isClientTrusted(java.security.cert.X509Certificate[] chain) {
        return true;
    }

    @Override
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
    }

    @Override
    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
    }

    @Override
    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
    }

    @Override
    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType, Socket socket)
            throws CertificateException {
    }

    @Override
    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType, Socket socket)
            throws CertificateException {
    }

    @Override
    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType, SSLEngine engine)
            throws CertificateException {
    }

    @Override
    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType, SSLEngine engine)
            throws CertificateException {
    }
}