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
26package javax.net.ssl;
27
28import java.security.AlgorithmConstraints;
29import java.util.Map;
30import java.util.List;
31import java.util.HashMap;
32import java.util.ArrayList;
33import java.util.Collection;
34import java.util.Collections;
35import 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 */
66public 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     */
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     */
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     */
114    public SSLParameters(String[] cipherSuites, String[] protocols) {
115        setCipherSuites(cipherSuites);
116        setProtocols(protocols);
117    }
118
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
464    public final boolean getUseCipherSuitesOrder() {
465        return preferLocalCipherSuites;
466    }
467}
468