1 /*
2  * Copyright (c) 2005, 2013, 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 package javax.net.ssl;
27 
28 import java.security.AlgorithmConstraints;
29 import java.util.Map;
30 import java.util.List;
31 import java.util.HashMap;
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.Collections;
35 import java.util.LinkedHashMap;
36 
37 /**
38  * Encapsulates parameters for an SSL/TLS connection. The parameters
39  * are the list of ciphersuites to be accepted in an SSL/TLS handshake,
40  * the list of protocols to be allowed, the endpoint identification
41  * algorithm during SSL/TLS handshaking, the Server Name Indication (SNI),
42  * the algorithm constraints and whether SSL/TLS servers should request
43  * or require client authentication, etc.
44  * <p>
45  * SSLParameters can be created via the constructors in this class.
46  * Objects can also be obtained using the <code>getSSLParameters()</code>
47  * methods in
48  * {@link SSLSocket#getSSLParameters SSLSocket} and
49  * {@link SSLServerSocket#getSSLParameters SSLServerSocket} and
50  * {@link SSLEngine#getSSLParameters SSLEngine} or the
51  * {@link SSLContext#getDefaultSSLParameters getDefaultSSLParameters()} and
52  * {@link SSLContext#getSupportedSSLParameters getSupportedSSLParameters()}
53  * methods in <code>SSLContext</code>.
54  * <p>
55  * SSLParameters can be applied to a connection via the methods
56  * {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and
57  * {@link SSLServerSocket#setSSLParameters SSLServerSocket.setSSLParameters()}
58  * and {@link SSLEngine#setSSLParameters SSLEngine.setSSLParameters()}.
59  *
60  * @see SSLSocket
61  * @see SSLEngine
62  * @see SSLContext
63  *
64  * @since 1.6
65  */
66 public class SSLParameters {
67 
68     private String[] cipherSuites;
69     private String[] protocols;
70     private boolean wantClientAuth;
71     private boolean needClientAuth;
72     private String identificationAlgorithm;
73     private AlgorithmConstraints algorithmConstraints;
74     private Map<Integer, SNIServerName> sniNames = null;
75     private Map<Integer, SNIMatcher> sniMatchers = null;
76     private boolean preferLocalCipherSuites;
77 
78     /**
79      * Constructs SSLParameters.
80      * <p>
81      * The values of cipherSuites, protocols, cryptographic algorithm
82      * constraints, endpoint identification algorithm, server names and
83      * server name matchers are set to <code>null</code>, useCipherSuitesOrder,
84      * wantClientAuth and needClientAuth are set to <code>false</code>.
85      */
SSLParameters()86     public SSLParameters() {
87         // empty
88     }
89 
90     /**
91      * Constructs SSLParameters from the specified array of ciphersuites.
92      * <p>
93      * Calling this constructor is equivalent to calling the no-args
94      * constructor followed by
95      * <code>setCipherSuites(cipherSuites);</code>.
96      *
97      * @param cipherSuites the array of ciphersuites (or null)
98      */
SSLParameters(String[] cipherSuites)99     public SSLParameters(String[] cipherSuites) {
100         setCipherSuites(cipherSuites);
101     }
102 
103     /**
104      * Constructs SSLParameters from the specified array of ciphersuites
105      * and protocols.
106      * <p>
107      * Calling this constructor is equivalent to calling the no-args
108      * constructor followed by
109      * <code>setCipherSuites(cipherSuites); setProtocols(protocols);</code>.
110      *
111      * @param cipherSuites the array of ciphersuites (or null)
112      * @param protocols the array of protocols (or null)
113      */
SSLParameters(String[] cipherSuites, String[] protocols)114     public SSLParameters(String[] cipherSuites, String[] protocols) {
115         setCipherSuites(cipherSuites);
116         setProtocols(protocols);
117     }
118 
clone(String[] s)119     private static String[] clone(String[] s) {
120         return (s == null) ? null : s.clone();
121     }
122 
123     /**
124      * Returns a copy of the array of ciphersuites or null if none
125      * have been set.
126      *
127      * @return a copy of the array of ciphersuites or null if none
128      * have been set.
129      */
getCipherSuites()130     public String[] getCipherSuites() {
131         return clone(cipherSuites);
132     }
133 
134     /**
135      * Sets the array of ciphersuites.
136      *
137      * @param cipherSuites the array of ciphersuites (or null)
138      */
setCipherSuites(String[] cipherSuites)139     public void setCipherSuites(String[] cipherSuites) {
140         this.cipherSuites = clone(cipherSuites);
141     }
142 
143     /**
144      * Returns a copy of the array of protocols or null if none
145      * have been set.
146      *
147      * @return a copy of the array of protocols or null if none
148      * have been set.
149      */
getProtocols()150     public String[] getProtocols() {
151         return clone(protocols);
152     }
153 
154     /**
155      * Sets the array of protocols.
156      *
157      * @param protocols the array of protocols (or null)
158      */
setProtocols(String[] protocols)159     public void setProtocols(String[] protocols) {
160         this.protocols = clone(protocols);
161     }
162 
163     /**
164      * Returns whether client authentication should be requested.
165      *
166      * @return whether client authentication should be requested.
167      */
getWantClientAuth()168     public boolean getWantClientAuth() {
169         return wantClientAuth;
170     }
171 
172     /**
173      * Sets whether client authentication should be requested. Calling
174      * this method clears the <code>needClientAuth</code> flag.
175      *
176      * @param wantClientAuth whether client authentication should be requested
177      */
setWantClientAuth(boolean wantClientAuth)178     public void setWantClientAuth(boolean wantClientAuth) {
179         this.wantClientAuth = wantClientAuth;
180         this.needClientAuth = false;
181     }
182 
183     /**
184      * Returns whether client authentication should be required.
185      *
186      * @return whether client authentication should be required.
187      */
getNeedClientAuth()188     public boolean getNeedClientAuth() {
189         return needClientAuth;
190     }
191 
192     /**
193      * Sets whether client authentication should be required. Calling
194      * this method clears the <code>wantClientAuth</code> flag.
195      *
196      * @param needClientAuth whether client authentication should be required
197      */
setNeedClientAuth(boolean needClientAuth)198     public void setNeedClientAuth(boolean needClientAuth) {
199         this.wantClientAuth = false;
200         this.needClientAuth = needClientAuth;
201     }
202 
203     /**
204      * Returns the cryptographic algorithm constraints.
205      *
206      * @return the cryptographic algorithm constraints, or null if the
207      *     constraints have not been set
208      *
209      * @see #setAlgorithmConstraints(AlgorithmConstraints)
210      *
211      * @since 1.7
212      */
getAlgorithmConstraints()213     public AlgorithmConstraints getAlgorithmConstraints() {
214         return algorithmConstraints;
215     }
216 
217     /**
218      * Sets the cryptographic algorithm constraints, which will be used
219      * in addition to any configured by the runtime environment.
220      * <p>
221      * If the <code>constraints</code> parameter is non-null, every
222      * cryptographic algorithm, key and algorithm parameters used in the
223      * SSL/TLS handshake must be permitted by the constraints.
224      *
225      * @param constraints the algorithm constraints (or null)
226      *
227      * @since 1.7
228      */
setAlgorithmConstraints(AlgorithmConstraints constraints)229     public void setAlgorithmConstraints(AlgorithmConstraints constraints) {
230         // the constraints object is immutable
231         this.algorithmConstraints = constraints;
232     }
233 
234     /**
235      * Gets the endpoint identification algorithm.
236      *
237      * @return the endpoint identification algorithm, or null if none
238      * has been set.
239      *
240      * @see X509ExtendedTrustManager
241      * @see #setEndpointIdentificationAlgorithm(String)
242      *
243      * @since 1.7
244      */
getEndpointIdentificationAlgorithm()245     public String getEndpointIdentificationAlgorithm() {
246         return identificationAlgorithm;
247     }
248 
249     /**
250      * Sets the endpoint identification algorithm.
251      * <p>
252      * If the <code>algorithm</code> parameter is non-null or non-empty, the
253      * endpoint identification/verification procedures must be handled during
254      * SSL/TLS handshaking.  This is to prevent man-in-the-middle attacks.
255      *
256      * @param algorithm The standard string name of the endpoint
257      *     identification algorithm (or null).  See Appendix A in the <a href=
258      *   "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html#AppA">
259      *     Java Cryptography Architecture API Specification &amp; Reference </a>
260      *     for information about standard algorithm names.
261      *
262      * @see X509ExtendedTrustManager
263      *
264      * @since 1.7
265      */
setEndpointIdentificationAlgorithm(String algorithm)266     public void setEndpointIdentificationAlgorithm(String algorithm) {
267         this.identificationAlgorithm = algorithm;
268     }
269 
270     /**
271      * Sets the desired {@link SNIServerName}s of the Server Name
272      * Indication (SNI) parameter.
273      * <P>
274      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
275      * operating in client mode.
276      * <P>
277      * Note that the {@code serverNames} list is cloned
278      * to protect against subsequent modification.
279      *
280      * @param  serverNames
281      *         the list of desired {@link SNIServerName}s (or null)
282      *
283      * @throws NullPointerException if the {@code serverNames}
284      *         contains {@code null} element
285      * @throws IllegalArgumentException if the {@code serverNames}
286      *         contains more than one name of the same name type
287      *
288      * @see SNIServerName
289      * @see #getServerNames()
290      *
291      * @since 1.8
292      */
setServerNames(List<SNIServerName> serverNames)293     public final void setServerNames(List<SNIServerName> serverNames) {
294         if (serverNames != null) {
295             if (!serverNames.isEmpty()) {
296                 sniNames = new LinkedHashMap<>(serverNames.size());
297                 for (SNIServerName serverName : serverNames) {
298                     if (sniNames.put(serverName.getType(),
299                                                 serverName) != null) {
300                         throw new IllegalArgumentException(
301                                     "Duplicated server name of type " +
302                                     serverName.getType());
303                     }
304                 }
305             } else {
306                 sniNames = Collections.<Integer, SNIServerName>emptyMap();
307             }
308         } else {
309             sniNames = null;
310         }
311     }
312 
313     /**
314      * Returns a {@link List} containing all {@link SNIServerName}s of the
315      * Server Name Indication (SNI) parameter, or null if none has been set.
316      * <P>
317      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
318      * operating in client mode.
319      * <P>
320      * For SSL/TLS connections, the underlying SSL/TLS provider
321      * may specify a default value for a certain server name type.  In
322      * client mode, it is recommended that, by default, providers should
323      * include the server name indication whenever the server can be located
324      * by a supported server name type.
325      * <P>
326      * It is recommended that providers initialize default Server Name
327      * Indications when creating {@code SSLSocket}/{@code SSLEngine}s.
328      * In the following examples, the server name could be represented by an
329      * instance of {@link SNIHostName} which has been initialized with the
330      * hostname "www.example.com" and type
331      * {@link StandardConstants#SNI_HOST_NAME}.
332      *
333      * <pre>
334      *     Socket socket =
335      *         sslSocketFactory.createSocket("www.example.com", 443);
336      * </pre>
337      * or
338      * <pre>
339      *     SSLEngine engine =
340      *         sslContext.createSSLEngine("www.example.com", 443);
341      * </pre>
342      * <P>
343      *
344      * @return null or an immutable list of non-null {@link SNIServerName}s
345      *
346      * @see List
347      * @see #setServerNames(List)
348      *
349      * @since 1.8
350      */
getServerNames()351     public final List<SNIServerName> getServerNames() {
352         if (sniNames != null) {
353             if (!sniNames.isEmpty()) {
354                 return Collections.<SNIServerName>unmodifiableList(
355                                         new ArrayList<>(sniNames.values()));
356             } else {
357                 return Collections.<SNIServerName>emptyList();
358             }
359         }
360 
361         return null;
362     }
363 
364     /**
365      * Sets the {@link SNIMatcher}s of the Server Name Indication (SNI)
366      * parameter.
367      * <P>
368      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
369      * operating in server mode.
370      * <P>
371      * Note that the {@code matchers} collection is cloned to protect
372      * against subsequent modification.
373      *
374      * @param  matchers
375      *         the collection of {@link SNIMatcher}s (or null)
376      *
377      * @throws NullPointerException if the {@code matchers}
378      *         contains {@code null} element
379      * @throws IllegalArgumentException if the {@code matchers}
380      *         contains more than one name of the same name type
381      *
382      * @see Collection
383      * @see SNIMatcher
384      * @see #getSNIMatchers()
385      *
386      * @since 1.8
387      */
setSNIMatchers(Collection<SNIMatcher> matchers)388     public final void setSNIMatchers(Collection<SNIMatcher> matchers) {
389         if (matchers != null) {
390             if (!matchers.isEmpty()) {
391                 sniMatchers = new HashMap<>(matchers.size());
392                 for (SNIMatcher matcher : matchers) {
393                     if (sniMatchers.put(matcher.getType(),
394                                                 matcher) != null) {
395                         throw new IllegalArgumentException(
396                                     "Duplicated server name of type " +
397                                     matcher.getType());
398                     }
399                 }
400             } else {
401                 sniMatchers = Collections.<Integer, SNIMatcher>emptyMap();
402             }
403         } else {
404             sniMatchers = null;
405         }
406     }
407 
408     /**
409      * Returns a {@link Collection} containing all {@link SNIMatcher}s of the
410      * Server Name Indication (SNI) parameter, or null if none has been set.
411      * <P>
412      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
413      * operating in server mode.
414      * <P>
415      * For better interoperability, providers generally will not define
416      * default matchers so that by default servers will ignore the SNI
417      * extension and continue the handshake.
418      *
419      * @return null or an immutable collection of non-null {@link SNIMatcher}s
420      *
421      * @see SNIMatcher
422      * @see #setSNIMatchers(Collection)
423      *
424      * @since 1.8
425      */
getSNIMatchers()426     public final Collection<SNIMatcher> getSNIMatchers() {
427         if (sniMatchers != null) {
428             if (!sniMatchers.isEmpty()) {
429                 return Collections.<SNIMatcher>unmodifiableList(
430                                         new ArrayList<>(sniMatchers.values()));
431             } else {
432                 return Collections.<SNIMatcher>emptyList();
433             }
434         }
435 
436         return null;
437     }
438 
439     /**
440      * Sets whether the local cipher suites preference should be honored.
441      *
442      * @param honorOrder whether local cipher suites order in
443      *        {@code #getCipherSuites} should be honored during
444      *        SSL/TLS handshaking.
445      *
446      * @see #getUseCipherSuitesOrder()
447      *
448      * @since 1.8
449      */
setUseCipherSuitesOrder(boolean honorOrder)450     public final void setUseCipherSuitesOrder(boolean honorOrder) {
451         this.preferLocalCipherSuites = honorOrder;
452     }
453 
454     /**
455      * Returns whether the local cipher suites preference should be honored.
456      *
457      * @return whether local cipher suites order in {@code #getCipherSuites}
458      *         should be honored during SSL/TLS handshaking.
459      *
460      * @see #setUseCipherSuitesOrder(boolean)
461      *
462      * @since 1.8
463      */
getUseCipherSuitesOrder()464     public final boolean getUseCipherSuitesOrder() {
465         return preferLocalCipherSuites;
466     }
467 }
468