1/* 2 * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package javax.rmi.ssl; 27 28import java.io.IOException; 29import java.net.ServerSocket; 30import java.net.Socket; 31import java.rmi.server.RMIServerSocketFactory; 32import java.util.Arrays; 33import java.util.List; 34import javax.net.ssl.SSLContext; 35import javax.net.ssl.SSLServerSocketFactory; 36import javax.net.ssl.SSLSocket; 37import javax.net.ssl.SSLSocketFactory; 38 39/** 40 * <p>An <code>SslRMIServerSocketFactory</code> instance is used by the RMI 41 * runtime in order to obtain server sockets for RMI calls via SSL.</p> 42 * 43 * <p>This class implements <code>RMIServerSocketFactory</code> over 44 * the Secure Sockets Layer (SSL) or Transport Layer Security (TLS) 45 * protocols.</p> 46 * 47 * <p>This class creates SSL sockets using the default 48 * <code>SSLSocketFactory</code> (see {@link 49 * SSLSocketFactory#getDefault}) or the default 50 * <code>SSLServerSocketFactory</code> (see {@link 51 * SSLServerSocketFactory#getDefault}) unless the 52 * constructor taking an <code>SSLContext</code> is 53 * used in which case the SSL sockets are created using 54 * the <code>SSLSocketFactory</code> returned by 55 * {@link SSLContext#getSocketFactory} or the 56 * <code>SSLServerSocketFactory</code> returned by 57 * {@link SSLContext#getServerSocketFactory}. 58 * 59 * When an <code>SSLContext</code> is not supplied all the instances of this 60 * class share the same keystore, and the same truststore (when client 61 * authentication is required by the server). This behavior can be modified 62 * by supplying an already initialized <code>SSLContext</code> instance. 63 * 64 * @see javax.net.ssl.SSLSocketFactory 65 * @see javax.net.ssl.SSLServerSocketFactory 66 * @see javax.rmi.ssl.SslRMIClientSocketFactory 67 * @since 1.5 68 */ 69public class SslRMIServerSocketFactory implements RMIServerSocketFactory { 70 71 /** 72 * <p>Creates a new <code>SslRMIServerSocketFactory</code> with 73 * the default SSL socket configuration.</p> 74 * 75 * <p>SSL connections accepted by server sockets created by this 76 * factory have the default cipher suites and protocol versions 77 * enabled and do not require client authentication.</p> 78 */ 79 public SslRMIServerSocketFactory() { 80 this(null, null, false); 81 } 82 83 /** 84 * <p>Creates a new <code>SslRMIServerSocketFactory</code> with 85 * the specified SSL socket configuration.</p> 86 * 87 * @param enabledCipherSuites names of all the cipher suites to 88 * enable on SSL connections accepted by server sockets created by 89 * this factory, or <code>null</code> to use the cipher suites 90 * that are enabled by default 91 * 92 * @param enabledProtocols names of all the protocol versions to 93 * enable on SSL connections accepted by server sockets created by 94 * this factory, or <code>null</code> to use the protocol versions 95 * that are enabled by default 96 * 97 * @param needClientAuth <code>true</code> to require client 98 * authentication on SSL connections accepted by server sockets 99 * created by this factory; <code>false</code> to not require 100 * client authentication 101 * 102 * @exception IllegalArgumentException when one or more of the cipher 103 * suites named by the <code>enabledCipherSuites</code> parameter is 104 * not supported, when one or more of the protocols named by the 105 * <code>enabledProtocols</code> parameter is not supported or when 106 * a problem is encountered while trying to check if the supplied 107 * cipher suites and protocols to be enabled are supported. 108 * 109 * @see SSLSocket#setEnabledCipherSuites 110 * @see SSLSocket#setEnabledProtocols 111 * @see SSLSocket#setNeedClientAuth 112 */ 113 public SslRMIServerSocketFactory( 114 String[] enabledCipherSuites, 115 String[] enabledProtocols, 116 boolean needClientAuth) 117 throws IllegalArgumentException { 118 this(null, enabledCipherSuites, enabledProtocols, needClientAuth); 119 } 120 121 /** 122 * <p>Creates a new <code>SslRMIServerSocketFactory</code> with the 123 * specified <code>SSLContext</code> and SSL socket configuration.</p> 124 * 125 * @param context the SSL context to be used for creating SSL sockets. 126 * If <code>context</code> is null the default <code>SSLSocketFactory</code> 127 * or the default <code>SSLServerSocketFactory</code> will be used to 128 * create SSL sockets. Otherwise, the socket factory returned by 129 * <code>SSLContext.getSocketFactory()</code> or 130 * <code>SSLContext.getServerSocketFactory()</code> will be used instead. 131 * 132 * @param enabledCipherSuites names of all the cipher suites to 133 * enable on SSL connections accepted by server sockets created by 134 * this factory, or <code>null</code> to use the cipher suites 135 * that are enabled by default 136 * 137 * @param enabledProtocols names of all the protocol versions to 138 * enable on SSL connections accepted by server sockets created by 139 * this factory, or <code>null</code> to use the protocol versions 140 * that are enabled by default 141 * 142 * @param needClientAuth <code>true</code> to require client 143 * authentication on SSL connections accepted by server sockets 144 * created by this factory; <code>false</code> to not require 145 * client authentication 146 * 147 * @exception IllegalArgumentException when one or more of the cipher 148 * suites named by the <code>enabledCipherSuites</code> parameter is 149 * not supported, when one or more of the protocols named by the 150 * <code>enabledProtocols</code> parameter is not supported or when 151 * a problem is encountered while trying to check if the supplied 152 * cipher suites and protocols to be enabled are supported. 153 * 154 * @see SSLSocket#setEnabledCipherSuites 155 * @see SSLSocket#setEnabledProtocols 156 * @see SSLSocket#setNeedClientAuth 157 * @since 1.7 158 */ 159 public SslRMIServerSocketFactory( 160 SSLContext context, 161 String[] enabledCipherSuites, 162 String[] enabledProtocols, 163 boolean needClientAuth) 164 throws IllegalArgumentException { 165 // Initialize the configuration parameters. 166 // 167 this.enabledCipherSuites = enabledCipherSuites == null ? 168 null : enabledCipherSuites.clone(); 169 this.enabledProtocols = enabledProtocols == null ? 170 null : enabledProtocols.clone(); 171 this.needClientAuth = needClientAuth; 172 173 // Force the initialization of the default at construction time, 174 // rather than delaying it to the first time createServerSocket() 175 // is called. 176 // 177 this.context = context; 178 final SSLSocketFactory sslSocketFactory = 179 context == null ? 180 getDefaultSSLSocketFactory() : context.getSocketFactory(); 181 SSLSocket sslSocket = null; 182 if (this.enabledCipherSuites != null || this.enabledProtocols != null) { 183 try { 184 sslSocket = (SSLSocket) sslSocketFactory.createSocket(); 185 } catch (Exception e) { 186 final String msg = "Unable to check if the cipher suites " + 187 "and protocols to enable are supported"; 188 throw (IllegalArgumentException) 189 new IllegalArgumentException(msg).initCause(e); 190 } 191 } 192 193 // Check if all the cipher suites and protocol versions to enable 194 // are supported by the underlying SSL/TLS implementation and if 195 // true create lists from arrays. 196 // 197 if (this.enabledCipherSuites != null) { 198 sslSocket.setEnabledCipherSuites(this.enabledCipherSuites); 199 enabledCipherSuitesList = Arrays.asList(this.enabledCipherSuites); 200 } 201 if (this.enabledProtocols != null) { 202 sslSocket.setEnabledProtocols(this.enabledProtocols); 203 enabledProtocolsList = Arrays.asList(this.enabledProtocols); 204 } 205 } 206 207 /** 208 * <p>Returns the names of the cipher suites enabled on SSL 209 * connections accepted by server sockets created by this factory, 210 * or <code>null</code> if this factory uses the cipher suites 211 * that are enabled by default.</p> 212 * 213 * @return an array of cipher suites enabled, or <code>null</code> 214 * 215 * @see SSLSocket#setEnabledCipherSuites 216 */ 217 public final String[] getEnabledCipherSuites() { 218 return enabledCipherSuites == null ? 219 null : enabledCipherSuites.clone(); 220 } 221 222 /** 223 * <p>Returns the names of the protocol versions enabled on SSL 224 * connections accepted by server sockets created by this factory, 225 * or <code>null</code> if this factory uses the protocol versions 226 * that are enabled by default.</p> 227 * 228 * @return an array of protocol versions enabled, or 229 * <code>null</code> 230 * 231 * @see SSLSocket#setEnabledProtocols 232 */ 233 public final String[] getEnabledProtocols() { 234 return enabledProtocols == null ? 235 null : enabledProtocols.clone(); 236 } 237 238 /** 239 * <p>Returns <code>true</code> if client authentication is 240 * required on SSL connections accepted by server sockets created 241 * by this factory.</p> 242 * 243 * @return <code>true</code> if client authentication is required 244 * 245 * @see SSLSocket#setNeedClientAuth 246 */ 247 public final boolean getNeedClientAuth() { 248 return needClientAuth; 249 } 250 251 /** 252 * <p>Creates a server socket that accepts SSL connections 253 * configured according to this factory's SSL socket configuration 254 * parameters.</p> 255 */ 256 public ServerSocket createServerSocket(int port) throws IOException { 257 final SSLSocketFactory sslSocketFactory = 258 context == null ? 259 getDefaultSSLSocketFactory() : context.getSocketFactory(); 260 return new ServerSocket(port) { 261 public Socket accept() throws IOException { 262 Socket socket = super.accept(); 263 SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket( 264 socket, socket.getInetAddress().getHostName(), 265 socket.getPort(), true); 266 sslSocket.setUseClientMode(false); 267 if (enabledCipherSuites != null) { 268 sslSocket.setEnabledCipherSuites(enabledCipherSuites); 269 } 270 if (enabledProtocols != null) { 271 sslSocket.setEnabledProtocols(enabledProtocols); 272 } 273 sslSocket.setNeedClientAuth(needClientAuth); 274 return sslSocket; 275 } 276 }; 277 } 278 279 /** 280 * <p>Indicates whether some other object is "equal to" this one.</p> 281 * 282 * <p>Two <code>SslRMIServerSocketFactory</code> objects are equal 283 * if they have been constructed with the same SSL context and 284 * SSL socket configuration parameters.</p> 285 * 286 * <p>A subclass should override this method (as well as 287 * {@link #hashCode()}) if it adds instance state that affects 288 * equality.</p> 289 */ 290 public boolean equals(Object obj) { 291 if (obj == null) return false; 292 if (obj == this) return true; 293 if (!(obj instanceof SslRMIServerSocketFactory)) 294 return false; 295 SslRMIServerSocketFactory that = (SslRMIServerSocketFactory) obj; 296 return (getClass().equals(that.getClass()) && checkParameters(that)); 297 } 298 299 private boolean checkParameters(SslRMIServerSocketFactory that) { 300 // SSL context 301 // 302 if (context == null ? that.context != null : !context.equals(that.context)) 303 return false; 304 305 // needClientAuth flag 306 // 307 if (needClientAuth != that.needClientAuth) 308 return false; 309 310 // enabledCipherSuites 311 // 312 if ((enabledCipherSuites == null && that.enabledCipherSuites != null) || 313 (enabledCipherSuites != null && that.enabledCipherSuites == null)) 314 return false; 315 if (enabledCipherSuites != null && that.enabledCipherSuites != null) { 316 List<String> thatEnabledCipherSuitesList = 317 Arrays.asList(that.enabledCipherSuites); 318 if (!enabledCipherSuitesList.equals(thatEnabledCipherSuitesList)) 319 return false; 320 } 321 322 // enabledProtocols 323 // 324 if ((enabledProtocols == null && that.enabledProtocols != null) || 325 (enabledProtocols != null && that.enabledProtocols == null)) 326 return false; 327 if (enabledProtocols != null && that.enabledProtocols != null) { 328 List<String> thatEnabledProtocolsList = 329 Arrays.asList(that.enabledProtocols); 330 if (!enabledProtocolsList.equals(thatEnabledProtocolsList)) 331 return false; 332 } 333 334 return true; 335 } 336 337 /** 338 * <p>Returns a hash code value for this 339 * <code>SslRMIServerSocketFactory</code>.</p> 340 * 341 * @return a hash code value for this 342 * <code>SslRMIServerSocketFactory</code>. 343 */ 344 public int hashCode() { 345 return getClass().hashCode() + 346 (context == null ? 0 : context.hashCode()) + 347 (needClientAuth ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode()) + 348 (enabledCipherSuites == null ? 0 : enabledCipherSuitesList.hashCode()) + 349 (enabledProtocols == null ? 0 : enabledProtocolsList.hashCode()); 350 } 351 352 // We use a static field because: 353 // 354 // SSLSocketFactory.getDefault() always returns the same object 355 // (at least on Sun's implementation), and we want to make sure 356 // that the Javadoc & the implementation stay in sync. 357 // 358 // If someone needs to have different SslRMIServerSocketFactory 359 // factories with different underlying SSLSocketFactory objects 360 // using different keystores and truststores, he/she can always 361 // use the constructor that takes an SSLContext as input. 362 // 363 private static SSLSocketFactory defaultSSLSocketFactory = null; 364 365 private static synchronized SSLSocketFactory getDefaultSSLSocketFactory() { 366 if (defaultSSLSocketFactory == null) 367 defaultSSLSocketFactory = 368 (SSLSocketFactory) SSLSocketFactory.getDefault(); 369 return defaultSSLSocketFactory; 370 } 371 372 private final String[] enabledCipherSuites; 373 private final String[] enabledProtocols; 374 private final boolean needClientAuth; 375 private List<String> enabledCipherSuitesList; 376 private List<String> enabledProtocolsList; 377 private SSLContext context; 378} 379