View Javadoc
1   /*
2    * Copyright (c) 1997, 2012, 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  
26  
27  package javax.net.ssl;
28  
29  import java.net.*;
30  import javax.net.SocketFactory;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.security.*;
34  import java.util.Locale;
35  
36  import sun.security.action.GetPropertyAction;
37  
38  /**
39   * <code>SSLSocketFactory</code>s create <code>SSLSocket</code>s.
40   *
41   * @since 1.4
42   * @see SSLSocket
43   * @author David Brownell
44   */
45  public abstract class SSLSocketFactory extends SocketFactory
46  {
47      private static SSLSocketFactory theFactory;
48  
49      private static boolean propertyChecked;
50  
51      static final boolean DEBUG;
52  
53      static {
54          String s = java.security.AccessController.doPrivileged(
55              new GetPropertyAction("javax.net.debug", "")).toLowerCase(
56                                                              Locale.ENGLISH);
57          DEBUG = s.contains("all") || s.contains("ssl");
58      }
59  
60      private static void log(String msg) {
61          if (DEBUG) {
62              System.out.println(msg);
63          }
64      }
65  
66      /**
67       * Constructor is used only by subclasses.
68       */
69      public SSLSocketFactory() {
70      }
71  
72      /**
73       * Returns the default SSL socket factory.
74       *
75       * <p>The first time this method is called, the security property
76       * "ssl.SocketFactory.provider" is examined. If it is non-null, a class by
77       * that name is loaded and instantiated. If that is successful and the
78       * object is an instance of SSLSocketFactory, it is made the default SSL
79       * socket factory.
80       *
81       * <p>Otherwise, this method returns
82       * <code>SSLContext.getDefault().getSocketFactory()</code>. If that
83       * call fails, an inoperative factory is returned.
84       *
85       * @return the default <code>SocketFactory</code>
86       * @see SSLContext#getDefault
87       */
88      public static synchronized SocketFactory getDefault() {
89          if (theFactory != null) {
90              return theFactory;
91          }
92  
93          if (propertyChecked == false) {
94              propertyChecked = true;
95              String clsName = getSecurityProperty("ssl.SocketFactory.provider");
96              if (clsName != null) {
97                  log("setting up default SSLSocketFactory");
98                  try {
99                      Class<?> cls = null;
100                     try {
101                         cls = Class.forName(clsName);
102                     } catch (ClassNotFoundException e) {
103                         ClassLoader cl = ClassLoader.getSystemClassLoader();
104                         if (cl != null) {
105                             cls = cl.loadClass(clsName);
106                         }
107                     }
108                     log("class " + clsName + " is loaded");
109                     SSLSocketFactory fac = (SSLSocketFactory)cls.newInstance();
110                     log("instantiated an instance of class " + clsName);
111                     theFactory = fac;
112                     return fac;
113                 } catch (Exception e) {
114                     log("SSLSocketFactory instantiation failed: " + e.toString());
115                     theFactory = new DefaultSSLSocketFactory(e);
116                     return theFactory;
117                 }
118             }
119         }
120 
121         try {
122             return SSLContext.getDefault().getSocketFactory();
123         } catch (NoSuchAlgorithmException e) {
124             return new DefaultSSLSocketFactory(e);
125         }
126     }
127 
128     static String getSecurityProperty(final String name) {
129         return AccessController.doPrivileged(new PrivilegedAction<String>() {
130             @Override
131             public String run() {
132                 String s = java.security.Security.getProperty(name);
133                 if (s != null) {
134                     s = s.trim();
135                     if (s.length() == 0) {
136                         s = null;
137                     }
138                 }
139                 return s;
140             }
141         });
142     }
143 
144     /**
145      * Returns the list of cipher suites which are enabled by default.
146      * Unless a different list is enabled, handshaking on an SSL connection
147      * will use one of these cipher suites.  The minimum quality of service
148      * for these defaults requires confidentiality protection and server
149      * authentication (that is, no anonymous cipher suites).
150      *
151      * @see #getSupportedCipherSuites()
152      * @return array of the cipher suites enabled by default
153      */
154     public abstract String [] getDefaultCipherSuites();
155 
156     /**
157      * Returns the names of the cipher suites which could be enabled for use
158      * on an SSL connection.  Normally, only a subset of these will actually
159      * be enabled by default, since this list may include cipher suites which
160      * do not meet quality of service requirements for those defaults.  Such
161      * cipher suites are useful in specialized applications.
162      *
163      * @see #getDefaultCipherSuites()
164      * @return an array of cipher suite names
165      */
166     public abstract String [] getSupportedCipherSuites();
167 
168     /**
169      * Returns a socket layered over an existing socket connected to the named
170      * host, at the given port.  This constructor can be used when tunneling SSL
171      * through a proxy or when negotiating the use of SSL over an existing
172      * socket. The host and port refer to the logical peer destination.
173      * This socket is configured using the socket options established for
174      * this factory.
175      *
176      * @param s the existing socket
177      * @param host the server host
178      * @param port the server port
179      * @param autoClose close the underlying socket when this socket is closed
180      * @return a socket connected to the specified host and port
181      * @throws IOException if an I/O error occurs when creating the socket
182      * @throws NullPointerException if the parameter s is null
183      */
184     public abstract Socket createSocket(Socket s, String host,
185             int port, boolean autoClose) throws IOException;
186 
187     /**
188      * Creates a server mode {@link Socket} layered over an
189      * existing connected socket, and is able to read data which has
190      * already been consumed/removed from the {@link Socket}'s
191      * underlying {@link InputStream}.
192      * <p>
193      * This method can be used by a server application that needs to
194      * observe the inbound data but still create valid SSL/TLS
195      * connections: for example, inspection of Server Name Indication
196      * (SNI) extensions (See section 3 of <A
197      * HREF="http://www.ietf.org/rfc/rfc6066.txt">TLS Extensions
198      * (RFC6066)</A>).  Data that has been already removed from the
199      * underlying {@link InputStream} should be loaded into the
200      * {@code consumed} stream before this method is called, perhaps
201      * using a {@link java.io.ByteArrayInputStream}.  When this
202      * {@link Socket} begins handshaking, it will read all of the data in
203      * {@code consumed} until it reaches {@code EOF}, then all further
204      * data is read from the underlying {@link InputStream} as
205      * usual.
206      * <p>
207      * The returned socket is configured using the socket options
208      * established for this factory, and is set to use server mode when
209      * handshaking (see {@link SSLSocket#setUseClientMode(boolean)}).
210      *
211      * @param  s
212      *         the existing socket
213      * @param  consumed
214      *         the consumed inbound network data that has already been
215      *         removed from the existing {@link Socket}
216      *         {@link InputStream}.  This parameter may be
217      *         {@code null} if no data has been removed.
218      * @param  autoClose close the underlying socket when this socket is closed.
219      *
220      * @return the {@link Socket} compliant with the socket options
221      *         established for this factory
222      *
223      * @throws IOException if an I/O error occurs when creating the socket
224      * @throws UnsupportedOperationException if the underlying provider
225      *         does not implement the operation
226      * @throws NullPointerException if {@code s} is {@code null}
227      *
228      * @since 1.8
229      */
230     public Socket createSocket(Socket s, InputStream consumed,
231             boolean autoClose) throws IOException {
232         throw new UnsupportedOperationException();
233     }
234 }
235 
236 
237 // file private
238 class DefaultSSLSocketFactory extends SSLSocketFactory
239 {
240     private Exception reason;
241 
242     DefaultSSLSocketFactory(Exception reason) {
243         this.reason = reason;
244     }
245 
246     private Socket throwException() throws SocketException {
247         throw (SocketException)
248             new SocketException(reason.toString()).initCause(reason);
249     }
250 
251     @Override
252     public Socket createSocket()
253     throws IOException
254     {
255         return throwException();
256     }
257 
258     @Override
259     public Socket createSocket(String host, int port)
260     throws IOException
261     {
262         return throwException();
263     }
264 
265     @Override
266     public Socket createSocket(Socket s, String host,
267                                 int port, boolean autoClose)
268     throws IOException
269     {
270         return throwException();
271     }
272 
273     @Override
274     public Socket createSocket(InetAddress address, int port)
275     throws IOException
276     {
277         return throwException();
278     }
279 
280     @Override
281     public Socket createSocket(String host, int port,
282         InetAddress clientAddress, int clientPort)
283     throws IOException
284     {
285         return throwException();
286     }
287 
288     @Override
289     public Socket createSocket(InetAddress address, int port,
290         InetAddress clientAddress, int clientPort)
291     throws IOException
292     {
293         return throwException();
294     }
295 
296     @Override
297     public String [] getDefaultCipherSuites() {
298         return new String[0];
299     }
300 
301     @Override
302     public String [] getSupportedCipherSuites() {
303         return new String[0];
304     }
305 }