001    /*
002     * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.11/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    
032    package org.apache.commons.ssl;
033    
034    import javax.net.SocketFactory;
035    import javax.net.ssl.*;
036    import java.io.File;
037    import java.io.IOException;
038    import java.net.InetAddress;
039    import java.net.ServerSocket;
040    import java.net.Socket;
041    import java.net.UnknownHostException;
042    import java.security.GeneralSecurityException;
043    import java.security.KeyManagementException;
044    import java.security.KeyStoreException;
045    import java.security.NoSuchAlgorithmException;
046    import java.security.cert.CertificateException;
047    import java.security.cert.X509Certificate;
048    import 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     */
059    public 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    }