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}