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