1 /*
   2  * Copyright (c) 2005, 2015, 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      */
  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}/../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      *
 343      * @return null or an immutable list of non-null {@link SNIServerName}s
 344      *
 345      * @see List
 346      * @see #setServerNames(List)
 347      *
 348      * @since 1.8
 349      */
 350     public final List<SNIServerName> getServerNames() {
 351         if (sniNames != null) {
 352             if (!sniNames.isEmpty()) {
 353                 return Collections.<SNIServerName>unmodifiableList(
 354                                         new ArrayList<>(sniNames.values()));
 355             } else {
 356                 return Collections.<SNIServerName>emptyList();
 357             }
 358         }
 359 
 360         return null;
 361     }
 362 
 363     /**
 364      * Sets the {@link SNIMatcher}s of the Server Name Indication (SNI)
 365      * parameter.
 366      * <P>
 367      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
 368      * operating in server mode.
 369      * <P>
 370      * Note that the {@code matchers} collection is cloned to protect
 371      * against subsequent modification.
 372      *
 373      * @param  matchers
 374      *         the collection of {@link SNIMatcher}s (or null)
 375      *
 376      * @throws NullPointerException if the {@code matchers}
 377      *         contains {@code null} element
 378      * @throws IllegalArgumentException if the {@code matchers}
 379      *         contains more than one name of the same name type
 380      *
 381      * @see Collection
 382      * @see SNIMatcher
 383      * @see #getSNIMatchers()
 384      *
 385      * @since 1.8
 386      */
 387     public final void setSNIMatchers(Collection<SNIMatcher> matchers) {
 388         if (matchers != null) {
 389             if (!matchers.isEmpty()) {
 390                 sniMatchers = new HashMap<>(matchers.size());
 391                 for (SNIMatcher matcher : matchers) {
 392                     if (sniMatchers.put(matcher.getType(),
 393                                                 matcher) != null) {
 394                         throw new IllegalArgumentException(
 395                                     "Duplicated server name of type " +
 396                                     matcher.getType());
 397                     }
 398                 }
 399             } else {
 400                 sniMatchers = Collections.<Integer, SNIMatcher>emptyMap();
 401             }
 402         } else {
 403             sniMatchers = null;
 404         }
 405     }
 406 
 407     /**
 408      * Returns a {@link Collection} containing all {@link SNIMatcher}s of the
 409      * Server Name Indication (SNI) parameter, or null if none has been set.
 410      * <P>
 411      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
 412      * operating in server mode.
 413      * <P>
 414      * For better interoperability, providers generally will not define
 415      * default matchers so that by default servers will ignore the SNI
 416      * extension and continue the handshake.
 417      *
 418      * @return null or an immutable collection of non-null {@link SNIMatcher}s
 419      *
 420      * @see SNIMatcher
 421      * @see #setSNIMatchers(Collection)
 422      *
 423      * @since 1.8
 424      */
 425     public final Collection<SNIMatcher> getSNIMatchers() {
 426         if (sniMatchers != null) {
 427             if (!sniMatchers.isEmpty()) {
 428                 return Collections.<SNIMatcher>unmodifiableList(
 429                                         new ArrayList<>(sniMatchers.values()));
 430             } else {
 431                 return Collections.<SNIMatcher>emptyList();
 432             }
 433         }
 434 
 435         return null;
 436     }
 437 
 438     /**
 439      * Sets whether the local cipher suites preference should be honored.
 440      *
 441      * @param honorOrder whether local cipher suites order in
 442      *        {@code #getCipherSuites} should be honored during
 443      *        SSL/TLS handshaking.
 444      *
 445      * @see #getUseCipherSuitesOrder()
 446      *
 447      * @since 1.8
 448      */
 449     public final void setUseCipherSuitesOrder(boolean honorOrder) {
 450         this.preferLocalCipherSuites = honorOrder;
 451     }
 452 
 453     /**
 454      * Returns whether the local cipher suites preference should be honored.
 455      *
 456      * @return whether local cipher suites order in {@code #getCipherSuites}
 457      *         should be honored during SSL/TLS handshaking.
 458      *
 459      * @see #setUseCipherSuitesOrder(boolean)
 460      *
 461      * @since 1.8
 462      */
 463     public final boolean getUseCipherSuitesOrder() {
 464         return preferLocalCipherSuites;
 465     }
 466 }
 467