    001/*
    002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.15/src/java/org/apache/commons/ssl/SSL.java $
    003 * $Revision: 155 $
    004 * $Date: 2009-09-17 14:00:58 -0700 (Thu, 17 Sep 2009) $
    005 *
    006 * ====================================================================
    007 * Licensed to the Apache Software Foundation (ASF) under one
    008 * or more contributor license agreements.  See the NOTICE file
    009 * distributed with this work for additional information
    010 * regarding copyright ownership.  The ASF licenses this file
    011 * to you under the Apache License, Version 2.0 (the
    012 * "License"); you may not use this file except in compliance
    013 * with the License.  You may obtain a copy of the License at
    014 *
    015 *   http://www.apache.org/licenses/LICENSE-2.0
    016 *
    017 * Unless required by applicable law or agreed to in writing,
    018 * software distributed under the License is distributed on an
    019 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    020 * KIND, either express or implied.  See the License for the
    021 * specific language governing permissions and limitations
    022 * under the License.
    023 * ====================================================================
    024 *
    025 * This software consists of voluntary contributions made by many
    026 * individuals on behalf of the Apache Software Foundation.  For more
    027 * information on the Apache Software Foundation, please see
    028 * <http://www.apache.org/>.
    029 *
    030 */
    031
    032package org.apache.commons.ssl;
    033
    034import javax.net.SocketFactory;
    035import javax.net.ssl.*;
    036import java.io.File;
    037import java.io.IOException;
    038import java.net.InetAddress;
    039import java.net.ServerSocket;
    040import java.net.Socket;
    041import java.net.UnknownHostException;
    042import java.security.GeneralSecurityException;
    043import java.security.KeyManagementException;
    044import java.security.KeyStoreException;
    045import java.security.NoSuchAlgorithmException;
    046import java.security.cert.CertificateException;
    047import java.security.cert.X509Certificate;
    048import java.util.*;
    049
    050/**
    051 * Not thread-safe.  (But who would ever share this thing across multiple
    052 * threads???)
    053 *
    054 * @author Credit Union Central of British Columbia
    055 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
    056 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
    057 * @since May 1, 2006
    058 */
    059public class SSL {
    060    private final static String[] KNOWN_PROTOCOLS =
    061            {"TLSv1", "SSLv3", "SSLv2", "SSLv2Hello"};
    062
    063    // SUPPORTED_CIPHERS_ARRAY is initialized in the static constructor.
    064    private final static String[] SUPPORTED_CIPHERS;
    065
    066    public final static SortedSet KNOWN_PROTOCOLS_SET;
    067    public final static SortedSet SUPPORTED_CIPHERS_SET;
    068
    069    // RC4
    070    public final static String SSL_RSA_WITH_RC4_128_SHA = "SSL_RSA_WITH_RC4_128_SHA";
    071
    072    // 3DES
    073    public final static String SSL_RSA_WITH_3DES_EDE_CBC_SHA = "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
    074    public final static String SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA = "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
    075    public final static String SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA = "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
    076
    077    // AES-128
    078    public final static String TLS_RSA_WITH_AES_128_CBC_SHA = "TLS_RSA_WITH_AES_128_CBC_SHA";
    079    public final static String TLS_DHE_RSA_WITH_AES_128_CBC_SHA = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
    080    public final static String TLS_DHE_DSS_WITH_AES_128_CBC_SHA = "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
    081
    082    // AES-256
    083    public final static String TLS_RSA_WITH_AES_256_CBC_SHA = "TLS_RSA_WITH_AES_256_CBC_SHA";
    084    public final static String TLS_DHE_RSA_WITH_AES_256_CBC_SHA = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
    085    public final static String TLS_DHE_DSS_WITH_AES_256_CBC_SHA = "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
    086
    087    static {
    088        TreeSet ts = new TreeSet(Collections.reverseOrder());
    089        ts.addAll(Arrays.asList(KNOWN_PROTOCOLS));
    090        KNOWN_PROTOCOLS_SET = Collections.unmodifiableSortedSet(ts);
    091
    092        // SSLSocketFactory.getDefault() sometimes blocks on FileInputStream
    093        // reads of "/dev/random" (Linux only?).  You might find you system
    094        // stuck here.  Move the mouse around a little!
    095        SSLSocketFactory s = (SSLSocketFactory) SSLSocketFactory.getDefault();
    096        ts = new TreeSet();
    097        SUPPORTED_CIPHERS = s.getSupportedCipherSuites();
    098        Arrays.sort(SUPPORTED_CIPHERS);
    099        ts.addAll(Arrays.asList(SUPPORTED_CIPHERS));
    100        SUPPORTED_CIPHERS_SET = Collections.unmodifiableSortedSet(ts);
    101    }
    102
    103    private Object sslContext = null;
    104    private int initCount = 0;
    105    private SSLSocketFactory socketFactory = null;
    106    private SSLServerSocketFactory serverSocketFactory = null;
    107    private HostnameVerifier hostnameVerifier = HostnameVerifier.DEFAULT;
    108    private boolean isSecure = true;  // if false, the client-style operations only create plain sockets.
    109    private boolean checkHostname = true;
    110    private boolean checkCRL = true;
    111    private boolean checkExpiry = true;
    112    private boolean useClientMode = false;
    113    private boolean useClientModeDefault = true;
    114    private int soTimeout = 24 * 60 * 60 * 1000; // default: one day
    115    private int connectTimeout = 60 * 60 * 1000; // default: one hour
    116    private TrustChain trustChain = null;
    117    private KeyMaterial keyMaterial = null;
    118    private String[] enabledCiphers = null;
    119    private String[] enabledProtocols = null;
    120    private String defaultProtocol = "TLS";
    121    private X509Certificate[] currentServerChain;
    122    private X509Certificate[] currentClientChain;
    123    private boolean wantClientAuth = true;
    124    private boolean needClientAuth = false;
    125    private SSLWrapperFactory sslWrapperFactory = SSLWrapperFactory.NO_WRAP;
    126    private Map dnsOverride;
    127
    128    protected final boolean usingSystemProperties;
    129
    130    public SSL()
    131            throws GeneralSecurityException, IOException {
    132        boolean usingSysProps = false;
    133        Properties props = System.getProperties();
    134        boolean ksSet = props.containsKey("javax.net.ssl.keyStore");
    135        boolean tsSet = props.containsKey("javax.net.ssl.trustStore");
    136        if (ksSet) {
    137            String path = System.getProperty("javax.net.ssl.keyStore");
    138            String pwd = System.getProperty("javax.net.ssl.keyStorePassword");
    139            pwd = pwd != null ? pwd : ""; // JSSE default is "".
    140            File f = new File(path);
    141            if (f.exists()) {
    142                KeyMaterial km = new KeyMaterial(path, pwd.toCharArray());
    143                setKeyMaterial(km);
    144                usingSysProps = true;
    145            }
    146        }
    147        boolean trustMaterialSet = false;
    148        if (tsSet) {
    149            String path = System.getProperty("javax.net.ssl.trustStore");
    150            String pwd = System.getProperty("javax.net.ssl.trustStorePassword");
    151            boolean pwdWasNull = pwd == null;
    152            pwd = pwdWasNull ? "" : pwd; // JSSE default is "".
    153            File f = new File(path);
    154            if (f.exists()) {
    155                TrustMaterial tm;
    156                try {
    157                    tm = new TrustMaterial(path, pwd.toCharArray());
    158                }
    159                catch (GeneralSecurityException gse) {
    160                    // Probably a bad password.  If we're using the default password,
    161                    // let's try and survive this setback.
    162                    if (pwdWasNull) {
    163                        tm = new TrustMaterial(path);
    164                    } else {
    165                        throw gse;
    166                    }
    167                }
    168
    169                setTrustMaterial(tm);
    170                usingSysProps = true;
    171                trustMaterialSet = true;
    172            }
    173        }
    174
    175        /*
    176            No default trust material was set.  We'll use the JSSE standard way
    177            where we test for "JSSE_CACERTS" first, and then fall back on
    178            "CACERTS".  We could just leave TrustMaterial null, but then our
    179            setCheckCRL() and setCheckExpiry() features won't work.  We need a
    180            non-null TrustMaterial object in order to intercept and decorate
    181            the JVM's default TrustManager.
    182          */
    183        if (!trustMaterialSet) {
    184            setTrustMaterial(TrustMaterial.DEFAULT);
    185        }
    186        this.usingSystemProperties = usingSysProps;
    187
    188        // By default we only use the strong ciphers (128 bit and higher).
    189        // Consumers can call "useDefaultJavaCiphers()" to get the 40 and 56 bit
    190        // ciphers back that Java normally has turned on.
    191        useStrongCiphers();
    192        dirtyAndReloadIfYoung();
    193    }
    194
    195    private void dirty() {
    196        this.sslContext = null;
    197        this.socketFactory = null;
    198        this.serverSocketFactory = null;
    199    }
    200
    201    private void dirtyAndReloadIfYoung()
    202            throws NoSuchAlgorithmException, KeyStoreException,
    203            KeyManagementException, IOException, CertificateException {
    204        dirty();
    205        if (initCount >= 0 && initCount <= 5) {
    206            // The first five init's we do early (before any sockets are
    207            // created) in the hope that will trigger any explosions nice
    208            // and early, with the correct exception type.
    209
    210            // After the first five init's, we revert to a regular
    211            // dirty / init pattern, and the "init" happens very late:
    212            // just before the socket is created.  If badness happens, a
    213            // wrapping RuntimeException will be thrown.
    214            init();
    215        }
    216    }
    217
    218    String dnsOverride(String host) {
    219        if (dnsOverride != null && dnsOverride.containsKey(host)) {
    220            String override = (String) dnsOverride.get(host);
    221            if (override != null && !"".equals(override.trim())) {
    222                return override;
    223            }
    224        }
    225        return host;
    226    }
    227
    228    public void setDnsOverride(Map m) {
    229        this.dnsOverride = m;
    230    }
    231
    232    public void setIsSecure(boolean b) {
    233        this.isSecure = b;
    234    }
    235
    236    public boolean isSecure() {
    237        return isSecure;
    238    }
    239
    240    public SSLContext getSSLContext()
    241            throws GeneralSecurityException, IOException
    242
    243    {
    244        Object obj = getSSLContextAsObject();
    245        if (JavaImpl.isJava13()) {
    246            try {
    247                return (SSLContext) obj;
    248            }
    249            catch (ClassCastException cce) {
    250                throw new ClassCastException("When using Java13 SSL, you must call SSL.getSSLContextAsObject() - " + cce);
    251            }
    252        }
    253        return (SSLContext) obj;
    254    }
    255
    256    /**
    257     * @return com.sun.net.ssl.SSLContext or javax.net.ssl.SSLContext depending
    258     *         on the JSSE implementation we're using.
    259     * @throws GeneralSecurityException problem creating SSLContext
    260     * @throws IOException              problem creating SSLContext
    261     */
    262    public Object getSSLContextAsObject()
    263            throws GeneralSecurityException, IOException
    264
    265    {
    266        if (sslContext == null) {
    267            init();
    268        }
    269        return sslContext;
    270    }
    271
    272    public void addTrustMaterial(TrustChain trustChain)
    273            throws NoSuchAlgorithmException, KeyStoreException,
    274            KeyManagementException, IOException, CertificateException {
    275        if (this.trustChain == null || trustChain == TrustMaterial.TRUST_ALL) {
    276            this.trustChain = trustChain;
    277        } else {
    278            this.trustChain.addTrustMaterial(trustChain);
    279        }
    280        dirtyAndReloadIfYoung();
    281    }
    282
    283    public void setTrustMaterial(TrustChain trustChain)
    284            throws NoSuchAlgorithmException, KeyStoreException,
    285            KeyManagementException, IOException, CertificateException {
    286        this.trustChain = trustChain;
    287        dirtyAndReloadIfYoung();
    288    }
    289
    290    public void setKeyMaterial(KeyMaterial keyMaterial)
    291            throws NoSuchAlgorithmException, KeyStoreException,
    292            KeyManagementException, IOException, CertificateException {
    293        this.keyMaterial = keyMaterial;
    294        dirtyAndReloadIfYoung();
    295    }
    296
    297    public X509Certificate[] getAssociatedCertificateChain() {
    298        if (keyMaterial != null) {
    299            List list = keyMaterial.getAssociatedCertificateChains();
    300            return (X509Certificate[]) list.get(0);
    301        } else {
    302            return null;
    303        }
    304    }
    305
    306    public String[] getEnabledCiphers() {
    307        return enabledCiphers != null ? enabledCiphers : getDefaultCipherSuites();
    308    }
    309
    310    public void useDefaultJavaCiphers() {
    311        this.enabledCiphers = null;
    312    }
    313
    314    public void useStrongCiphers() {
    315        LinkedList list = new LinkedList();
    316        addCipher(list, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, false);
    317        addCipher(list, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, false);
    318        addCipher(list, SSL_RSA_WITH_3DES_EDE_CBC_SHA, false);
    319        addCipher(list, SSL_RSA_WITH_RC4_128_SHA, false);
    320        addCipher(list, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, false);
    321        addCipher(list, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, false);
    322        addCipher(list, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, false);
    323        addCipher(list, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, false);
    324        addCipher(list, TLS_RSA_WITH_AES_128_CBC_SHA, false);
    325        addCipher(list, TLS_RSA_WITH_AES_256_CBC_SHA, false);
    326        String[] strongCiphers = new String[list.size()];
    327        list.toArray(strongCiphers);
    328        String[] currentCiphers = getEnabledCiphers();
    329        // Current ciphers must be default or something.  Odd that it's null,
    330        // though.
    331        if (currentCiphers == null) {
    332            setEnabledCiphers(strongCiphers);
    333        }
    334
    335        Arrays.sort(strongCiphers);
    336        Arrays.sort(currentCiphers);
    337        // Let's only call "setEnabledCiphers" if our array is actually different
    338        // than what's already set.
    339        if (!Arrays.equals(strongCiphers, currentCiphers)) {
    340            setEnabledCiphers(strongCiphers);
    341        }
    342    }
    343
    344    public void setEnabledCiphers(String[] ciphers) {
    345        HashSet desired = new HashSet(Arrays.asList(ciphers));
    346        desired.removeAll(SUPPORTED_CIPHERS_SET);
    347        if (!desired.isEmpty()) {
    348            throw new IllegalArgumentException("following ciphers not supported: " + desired);
    349        }
    350        this.enabledCiphers = ciphers;
    351    }
    352
    353    public String[] getEnabledProtocols() {
    354        return enabledProtocols != null ? enabledProtocols : KNOWN_PROTOCOLS;
    355    }
    356
    357    public void setEnabledProtocols(String[] protocols) {
    358        HashSet desired = new HashSet(Arrays.asList(protocols));
    359        desired.removeAll(KNOWN_PROTOCOLS_SET);
    360        if (!desired.isEmpty()) {
    361            throw new IllegalArgumentException("following protocols not supported: " + desired);
    362        }
    363        this.enabledProtocols = protocols;
    364    }
    365
    366    public String getDefaultProtocol() {
    367        return defaultProtocol;
    368    }
    369
    370    public void setDefaultProtocol(String protocol) {
    371        this.defaultProtocol = protocol;
    372        dirty();
    373    }
    374
    375    public boolean getCheckHostname() {
    376        return checkHostname;
    377    }
    378
    379    public void setCheckHostname(boolean checkHostname) {
    380        this.checkHostname = checkHostname;
    381    }
    382
    383    public void setHostnameVerifier(HostnameVerifier verifier) {
    384        if (verifier == null) {
    385            verifier = HostnameVerifier.DEFAULT;
    386        }
    387        this.hostnameVerifier = verifier;
    388    }
    389
    390    public HostnameVerifier getHostnameVerifier() {
    391        return hostnameVerifier;
    392    }
    393
    394    public boolean getCheckCRL() {
    395        return checkCRL;
    396    }
    397
    398    public void setCheckCRL(boolean checkCRL) {
    399        this.checkCRL = checkCRL;
    400    }
    401
    402    public boolean getCheckExpiry() {
    403        return checkExpiry;
    404    }
    405
    406    public void setCheckExpiry(boolean checkExpiry) {
    407        this.checkExpiry = checkExpiry;
    408    }
    409
    410    public void setSoTimeout(int soTimeout) {
    411        if (soTimeout < 0) {
    412            throw new IllegalArgumentException("soTimeout must not be negative");
    413        }
    414        this.soTimeout = soTimeout;
    415    }
    416
    417    public int getSoTimeout() {
    418        return soTimeout;
    419    }
    420
    421    public void setConnectTimeout(int connectTimeout) {
    422        if (connectTimeout < 0) {
    423            throw new IllegalArgumentException("connectTimeout must not be negative");
    424        }
    425        this.connectTimeout = connectTimeout;
    426    }
    427
    428    public void setUseClientMode(boolean useClientMode) {
    429        this.useClientModeDefault = false;
    430        this.useClientMode = useClientMode;
    431    }
    432
    433    public boolean getUseClientModeDefault() {
    434        return useClientModeDefault;
    435    }
    436
    437    public boolean getUseClientMode() {
    438        return useClientMode;
    439    }
    440
    441    public void setWantClientAuth(boolean wantClientAuth) {
    442        this.wantClientAuth = wantClientAuth;
    443    }
    444
    445    public void setNeedClientAuth(boolean needClientAuth) {
    446        this.needClientAuth = needClientAuth;
    447    }
    448
    449    public boolean getWantClientAuth() {
    450        return wantClientAuth;
    451    }
    452
    453    public boolean getNeedClientAuth() {
    454        return needClientAuth;
    455    }
    456
    457    public SSLWrapperFactory getSSLWrapperFactory() {
    458        return this.sslWrapperFactory;
    459    }
    460
    461    public void setSSLWrapperFactory(SSLWrapperFactory wf) {
    462        this.sslWrapperFactory = wf;
    463    }
    464
    465    private void initThrowRuntime() {
    466        try {
    467            init();
    468        }
    469        catch (GeneralSecurityException gse) {
    470            throw JavaImpl.newRuntimeException(gse);
    471        }
    472        catch (IOException ioe) {
    473            throw JavaImpl.newRuntimeException(ioe);
    474        }
    475    }
    476
    477    private void init()
    478            throws NoSuchAlgorithmException, KeyStoreException,
    479            KeyManagementException, IOException, CertificateException {
    480        socketFactory = null;
    481        serverSocketFactory = null;
    482        this.sslContext = JavaImpl.init(this, trustChain, keyMaterial);
    483        initCount++;
    484    }
    485
    486    public void doPreConnectSocketStuff(Socket s) throws IOException {
    487        if (s instanceof SSLSocket && !useClientModeDefault) {
    488            ((SSLSocket) s).setUseClientMode(useClientMode);
    489        }
    490        if (soTimeout > 0) {
    491            s.setSoTimeout(soTimeout);
    492        }
    493        if (s instanceof SSLSocket) {
    494            if (enabledProtocols != null) {
    495                JavaImpl.setEnabledProtocols(s, enabledProtocols);
    496            }
    497            if (enabledCiphers != null) {
    498                ((SSLSocket) s).setEnabledCipherSuites(enabledCiphers);
    499            }
    500        }
    501    }
    502
    503    public void doPostConnectSocketStuff(Socket s, String host)
    504            throws IOException {
    505        if (checkHostname && s instanceof SSLSocket) {
    506            hostnameVerifier.check(host, (SSLSocket) s);
    507        }
    508    }
    509
    510    public Socket createSocket() throws IOException {
    511        if (isSecure) {
    512            return sslWrapperFactory.wrap(JavaImpl.createSocket(this));
    513        } else {
    514            Socket s = SocketFactory.getDefault().createSocket();
    515            doPreConnectSocketStuff(s);
    516            return s;
    517        }
    518    }
    519
    520    /**
    521     * Attempts to get a new socket connection to the given host within the
    522     * given time limit.
    523     *
    524     * @param remoteHost the host name/IP
    525     * @param remotePort the port on the host
    526     * @param localHost  the local host name/IP to bind the socket to
    527     * @param localPort  the port on the local machine
    528     * @param timeout    the connection timeout (0==infinite)
    529     * @return Socket a new socket
    530     * @throws IOException          if an I/O error occurs while creating the socket
    531     * @throws UnknownHostException if the IP address of the host cannot be
    532     *                              determined
    533     */
    534    public Socket createSocket(
    535            String remoteHost, int remotePort, InetAddress localHost, int localPort, int timeout
    536    ) throws IOException {
    537        // Only use our factory-wide connectTimeout if this method was passed
    538        // in a timeout of 0 (infinite).
    539        int factoryTimeout = getConnectTimeout();
    540        int connectTimeout = timeout == 0 ? factoryTimeout : timeout;
    541        Socket s;
    542        if (isSecure) {
    543            s = JavaImpl.createSocket(
    544                    this, remoteHost, remotePort, localHost, localPort, connectTimeout
    545            );
    546        } else {
    547            s = JavaImpl.createPlainSocket(
    548                    this, remoteHost, remotePort, localHost, localPort, connectTimeout
    549            );
    550        }
    551        return sslWrapperFactory.wrap(s);
    552    }
    553
    554    public Socket createSocket(
    555            Socket s, String remoteHost, int remotePort, boolean autoClose
    556    ) throws IOException {
    557        SSLSocketFactory sf = getSSLSocketFactory();
    558        s = sf.createSocket(s, remoteHost, remotePort, autoClose);
    559        doPreConnectSocketStuff(s);
    560        doPostConnectSocketStuff(s, remoteHost);
    561        return sslWrapperFactory.wrap(s);
    562    }
    563
    564    public ServerSocket createServerSocket() throws IOException {
    565        SSLServerSocket ss = JavaImpl.createServerSocket(this);
    566        return getSSLWrapperFactory().wrap(ss, this);
    567    }
    568
    569    /**
    570     * Attempts to get a new socket connection to the given host within the
    571     * given time limit.
    572     *
    573     * @param localHost the local host name/IP to bind against (null == ANY)
    574     * @param port      the port to listen on
    575     * @param backlog   number of connections allowed to queue up for accept().
    576     * @return SSLServerSocket a new server socket
    577     * @throws IOException if an I/O error occurs while creating thesocket
    578     */
    579    public ServerSocket createServerSocket(int port, int backlog,
    580                                           InetAddress localHost)
    581            throws IOException {
    582        SSLServerSocketFactory f = getSSLServerSocketFactory();
    583        ServerSocket ss = f.createServerSocket(port, backlog, localHost);
    584        SSLServerSocket s = (SSLServerSocket) ss;
    585        doPreConnectServerSocketStuff(s);
    586        return getSSLWrapperFactory().wrap(s, this);
    587    }
    588
    589    public void doPreConnectServerSocketStuff(SSLServerSocket s)
    590            throws IOException {
    591        if (soTimeout > 0) {
    592            s.setSoTimeout(soTimeout);
    593        }
    594        if (enabledProtocols != null) {
    595            JavaImpl.setEnabledProtocols(s, enabledProtocols);
    596        }
    597        if (enabledCiphers != null) {
    598            s.setEnabledCipherSuites(enabledCiphers);
    599        }
    600
    601        /*
    602          setNeedClientAuth( false ) has an annoying side effect:  it seems to
    603          reset setWantClient( true ) back to to false.  So I do things this
    604          way to make sure setting things "true" happens after setting things
    605          "false" - giving "true" priority.
    606          */
    607        if (!wantClientAuth) {
    608            JavaImpl.setWantClientAuth(s, wantClientAuth);
    609        }
    610        if (!needClientAuth) {
    611            s.setNeedClientAuth(needClientAuth);
    612        }
    613        if (wantClientAuth) {
    614            JavaImpl.setWantClientAuth(s, wantClientAuth);
    615        }
    616        if (needClientAuth) {
    617            s.setNeedClientAuth(needClientAuth);
    618        }
    619    }
    620
    621    public SSLSocketFactory getSSLSocketFactory() {
    622        if (sslContext == null) {
    623            initThrowRuntime();
    624        }
    625        if (socketFactory == null) {
    626            socketFactory = JavaImpl.getSSLSocketFactory(sslContext);
    627        }
    628        return socketFactory;
    629    }
    630
    631    public SSLServerSocketFactory getSSLServerSocketFactory() {
    632        if (sslContext == null) {
    633            initThrowRuntime();
    634        }
    635        if (serverSocketFactory == null) {
    636            serverSocketFactory = JavaImpl.getSSLServerSocketFactory(sslContext);
    637        }
    638        return serverSocketFactory;
    639    }
    640
    641    public int getConnectTimeout() {
    642        return connectTimeout;
    643    }
    644
    645    public String[] getDefaultCipherSuites() {
    646        return getSSLSocketFactory().getDefaultCipherSuites();
    647    }
    648
    649    public String[] getSupportedCipherSuites() {
    650        String[] s = new String[SUPPORTED_CIPHERS.length];
    651        System.arraycopy(SUPPORTED_CIPHERS, 0, s, 0, s.length);
    652        return s;
    653    }
    654
    655    public TrustChain getTrustChain() {
    656        return trustChain;
    657    }
    658
    659    public void setCurrentServerChain(X509Certificate[] chain) {
    660        this.currentServerChain = chain;
    661    }
    662
    663    public void setCurrentClientChain(X509Certificate[] chain) {
    664        this.currentClientChain = chain;
    665    }
    666
    667    public X509Certificate[] getCurrentServerChain() {
    668        return currentServerChain;
    669    }
    670
    671    public X509Certificate[] getCurrentClientChain() {
    672        return currentClientChain;
    673    }
    674
    675    public static void main(String[] args) {
    676        for (int i = 0; i < SUPPORTED_CIPHERS.length; i++) {
    677            System.out.println(SUPPORTED_CIPHERS[i]);
    678        }
    679        System.out.println();
    680        System.out.println("----------------------------------------------");
    681        addCipher(null, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, true);
    682        addCipher(null, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, true);
    683        addCipher(null, SSL_RSA_WITH_3DES_EDE_CBC_SHA, true);
    684        addCipher(null, SSL_RSA_WITH_RC4_128_SHA, true);
    685        addCipher(null, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, true);
    686        addCipher(null, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, true);
    687        addCipher(null, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, true);
    688        addCipher(null, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true);
    689        addCipher(null, TLS_RSA_WITH_AES_128_CBC_SHA, true);
    690        addCipher(null, TLS_RSA_WITH_AES_256_CBC_SHA, true);
    691    }
    692
    693    private static void addCipher(List l, String c, boolean printOnStandardOut) {
    694        boolean supported = false;
    695        if (c != null && SUPPORTED_CIPHERS_SET.contains(c)) {
    696            if (l != null) {
    697                l.add(c);
    698            }
    699            supported = true;
    700        }
    701        if (printOnStandardOut) {
    702            System.out.println(c + ":\t" + supported);
    703        }
    704    }
    705
    706
    707}