src/java.base/share/classes/sun/security/ssl/HandshakeContext.java
changeset 50768 68fa3d4026ea
parent 48225 718669e6b375
child 51407 910f7b56592f
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
       
     1 /*
       
     2  * Copyright (c) 2018, 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 sun.security.ssl;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.nio.ByteBuffer;
       
    30 import java.security.AlgorithmConstraints;
       
    31 import java.security.CryptoPrimitive;
       
    32 import java.util.AbstractMap.SimpleImmutableEntry;
       
    33 import java.util.ArrayList;
       
    34 import java.util.Collections;
       
    35 import java.util.EnumMap;
       
    36 import java.util.EnumSet;
       
    37 import java.util.HashMap;
       
    38 import java.util.LinkedHashMap;
       
    39 import java.util.LinkedList;
       
    40 import java.util.List;
       
    41 import java.util.Map;
       
    42 import java.util.Queue;
       
    43 import javax.crypto.SecretKey;
       
    44 import javax.net.ssl.SNIServerName;
       
    45 import javax.net.ssl.SSLHandshakeException;
       
    46 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
       
    47 import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
       
    48 import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*;
       
    49 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
       
    50 import sun.security.ssl.PskKeyExchangeModesExtension.PskKeyExchangeMode;
       
    51 
       
    52 abstract class HandshakeContext implements ConnectionContext {
       
    53     // System properties
       
    54 
       
    55     // By default, disable the unsafe legacy session renegotiation.
       
    56     static final boolean allowUnsafeRenegotiation =
       
    57             Utilities.getBooleanProperty(
       
    58                     "sun.security.ssl.allowUnsafeRenegotiation", false);
       
    59 
       
    60     // For maximum interoperability and backward compatibility, RFC 5746
       
    61     // allows server (or client) to accept ClientHello (or ServerHello)
       
    62     // message without the secure renegotiation_info extension or SCSV.
       
    63     //
       
    64     // For maximum security, RFC 5746 also allows server (or client) to
       
    65     // reject such message with a fatal "handshake_failure" alert.
       
    66     //
       
    67     // By default, allow such legacy hello messages.
       
    68     static final boolean allowLegacyHelloMessages =
       
    69             Utilities.getBooleanProperty(
       
    70                     "sun.security.ssl.allowLegacyHelloMessages", true);
       
    71 
       
    72     // registered handshake message actors
       
    73     LinkedHashMap<Byte, SSLConsumer>  handshakeConsumers;
       
    74     final HashMap<Byte, HandshakeProducer>  handshakeProducers;
       
    75 
       
    76     // context
       
    77     final SSLContextImpl                    sslContext;
       
    78     final TransportContext                  conContext;
       
    79     final SSLConfiguration                  sslConfig;
       
    80 
       
    81     // consolidated parameters
       
    82     final List<ProtocolVersion>             activeProtocols;
       
    83     final List<CipherSuite>                 activeCipherSuites;
       
    84     final AlgorithmConstraints              algorithmConstraints;
       
    85     final ProtocolVersion                   maximumActiveProtocol;
       
    86 
       
    87     // output stream
       
    88     final HandshakeOutStream                handshakeOutput;
       
    89 
       
    90     // handshake transcript hash
       
    91     final HandshakeHash                     handshakeHash;
       
    92 
       
    93     // negotiated security parameters
       
    94     SSLSessionImpl                          handshakeSession;
       
    95     boolean                                 handshakeFinished;
       
    96     // boolean                                 isInvalidated;
       
    97 
       
    98     boolean                                 kickstartMessageDelivered;
       
    99 
       
   100     // Resumption
       
   101     boolean                                 isResumption;
       
   102     SSLSessionImpl                          resumingSession;
       
   103 
       
   104     final Queue<Map.Entry<Byte, ByteBuffer>> delegatedActions;
       
   105     volatile boolean                        taskDelegated = false;
       
   106     volatile Exception                      delegatedThrown = null;
       
   107 
       
   108     ProtocolVersion                         negotiatedProtocol;
       
   109     CipherSuite                             negotiatedCipherSuite;
       
   110     final List<SSLPossession>               handshakePossessions;
       
   111     final List<SSLCredentials>              handshakeCredentials;
       
   112     SSLKeyDerivation                        handshakeKeyDerivation;
       
   113     SSLKeyExchange                          handshakeKeyExchange;
       
   114     SecretKey                               baseReadSecret;
       
   115     SecretKey                               baseWriteSecret;
       
   116 
       
   117     // protocol version being established
       
   118     int                                     clientHelloVersion;
       
   119     String                                  applicationProtocol;
       
   120 
       
   121     RandomCookie                            clientHelloRandom;
       
   122     RandomCookie                            serverHelloRandom;
       
   123     byte[]                                  certRequestContext;
       
   124 
       
   125     ////////////////////
       
   126     // Extensions
       
   127 
       
   128     // the extensions used in the handshake
       
   129     final Map<SSLExtension, SSLExtension.SSLExtensionSpec>
       
   130                                             handshakeExtensions;
       
   131 
       
   132     // MaxFragmentLength
       
   133     int                                     maxFragmentLength;
       
   134 
       
   135     // SignatureScheme
       
   136     List<SignatureScheme>                   localSupportedSignAlgs;
       
   137     List<SignatureScheme>                   peerRequestedSignatureSchemes;
       
   138     List<SignatureScheme>                   peerRequestedCertSignSchemes;
       
   139 
       
   140     // SupportedGroups
       
   141     List<NamedGroup>                        clientRequestedNamedGroups;
       
   142 
       
   143     // HelloRetryRequest
       
   144     NamedGroup                              serverSelectedNamedGroup;
       
   145 
       
   146     // if server name indicator is negotiated
       
   147     //
       
   148     // May need a public API for the indication in the future.
       
   149     List<SNIServerName>                     requestedServerNames;
       
   150     SNIServerName                           negotiatedServerName;
       
   151 
       
   152     // OCSP Stapling info
       
   153     boolean                                 staplingActive = false;
       
   154 
       
   155     protected HandshakeContext(SSLContextImpl sslContext,
       
   156             TransportContext conContext) throws IOException {
       
   157         this.sslContext = sslContext;
       
   158         this.conContext = conContext;
       
   159         this.sslConfig = (SSLConfiguration)conContext.sslConfig.clone();
       
   160 
       
   161         this.activeProtocols = getActiveProtocols(sslConfig.enabledProtocols,
       
   162                 sslConfig.enabledCipherSuites, sslConfig.algorithmConstraints);
       
   163         if (activeProtocols.isEmpty()) {
       
   164             throw new SSLHandshakeException(
       
   165                 "No appropriate protocol (protocol is disabled or " +
       
   166                 "cipher suites are inappropriate)");
       
   167         }
       
   168 
       
   169         ProtocolVersion maximumVersion = ProtocolVersion.NONE;
       
   170         for (ProtocolVersion pv : this.activeProtocols) {
       
   171             if (maximumVersion == ProtocolVersion.NONE ||
       
   172                     pv.compare(maximumVersion) > 0) {
       
   173                 maximumVersion = pv;
       
   174             }
       
   175         }
       
   176         this.maximumActiveProtocol = maximumVersion;
       
   177         this.activeCipherSuites = getActiveCipherSuites(this.activeProtocols,
       
   178                 sslConfig.enabledCipherSuites, sslConfig.algorithmConstraints);
       
   179         if (activeCipherSuites.isEmpty()) {
       
   180             throw new SSLHandshakeException("No appropriate cipher suite");
       
   181         }
       
   182         this.algorithmConstraints =
       
   183                 new SSLAlgorithmConstraints(sslConfig.algorithmConstraints);
       
   184 
       
   185         this.handshakeConsumers = new LinkedHashMap<>();
       
   186         this.handshakeProducers = new HashMap<>();
       
   187         this.handshakeHash = conContext.inputRecord.handshakeHash;
       
   188         this.handshakeOutput = new HandshakeOutStream(conContext.outputRecord);
       
   189 
       
   190         this.handshakeFinished = false;
       
   191         this.kickstartMessageDelivered = false;
       
   192 
       
   193         this.delegatedActions = new LinkedList<>();
       
   194         this.handshakeExtensions = new HashMap<>();
       
   195         this.handshakePossessions = new LinkedList<>();
       
   196         this.handshakeCredentials = new LinkedList<>();
       
   197         this.requestedServerNames = null;
       
   198         this.negotiatedServerName = null;
       
   199         this.negotiatedCipherSuite = conContext.cipherSuite;
       
   200         initialize();
       
   201     }
       
   202 
       
   203     /**
       
   204      * Constructor for PostHandshakeContext
       
   205      */
       
   206     HandshakeContext(TransportContext conContext) {
       
   207         this.sslContext = conContext.sslContext;
       
   208         this.conContext = conContext;
       
   209         this.sslConfig = conContext.sslConfig;
       
   210 
       
   211         this.negotiatedProtocol = conContext.protocolVersion;
       
   212         this.negotiatedCipherSuite = conContext.cipherSuite;
       
   213         this.handshakeOutput = new HandshakeOutStream(conContext.outputRecord);
       
   214         this.delegatedActions = new LinkedList<>();
       
   215 
       
   216         this.handshakeProducers = null;
       
   217         this.handshakeHash = null;
       
   218         this.activeProtocols = null;
       
   219         this.activeCipherSuites = null;
       
   220         this.algorithmConstraints = null;
       
   221         this.maximumActiveProtocol = null;
       
   222         this.handshakeExtensions = Collections.emptyMap();  // Not in TLS13
       
   223         this.handshakePossessions = null;
       
   224         this.handshakeCredentials = null;
       
   225     }
       
   226 
       
   227     // Initialize the non-final class variables.
       
   228     private void initialize() {
       
   229         ProtocolVersion inputHelloVersion;
       
   230         ProtocolVersion outputHelloVersion;
       
   231         if (conContext.isNegotiated) {
       
   232             inputHelloVersion = conContext.protocolVersion;
       
   233             outputHelloVersion = conContext.protocolVersion;
       
   234         } else {
       
   235             if (activeProtocols.contains(ProtocolVersion.SSL20Hello)) {
       
   236                 inputHelloVersion = ProtocolVersion.SSL20Hello;
       
   237 
       
   238                 // Per TLS 1.3 protocol, implementation MUST NOT send an SSL
       
   239                 // version 2.0 compatible CLIENT-HELLO.
       
   240                 if (maximumActiveProtocol.useTLS13PlusSpec()) {
       
   241                     outputHelloVersion = maximumActiveProtocol;
       
   242                 } else {
       
   243                     outputHelloVersion = ProtocolVersion.SSL20Hello;
       
   244                 }
       
   245             } else {
       
   246                 inputHelloVersion = maximumActiveProtocol;
       
   247                 outputHelloVersion = maximumActiveProtocol;
       
   248             }
       
   249         }
       
   250 
       
   251         conContext.inputRecord.setHelloVersion(inputHelloVersion);
       
   252         conContext.outputRecord.setHelloVersion(outputHelloVersion);
       
   253 
       
   254         if (!conContext.isNegotiated) {
       
   255             conContext.protocolVersion = maximumActiveProtocol;
       
   256         }
       
   257         conContext.outputRecord.setVersion(conContext.protocolVersion);
       
   258     }
       
   259 
       
   260     private static List<ProtocolVersion> getActiveProtocols(
       
   261             List<ProtocolVersion> enabledProtocols,
       
   262             List<CipherSuite> enabledCipherSuites,
       
   263             AlgorithmConstraints algorithmConstraints) {
       
   264         boolean enabledSSL20Hello = false;
       
   265         ArrayList<ProtocolVersion> protocols = new ArrayList<>(4);
       
   266         for (ProtocolVersion protocol : enabledProtocols) {
       
   267             if (!enabledSSL20Hello && protocol == ProtocolVersion.SSL20Hello) {
       
   268                 enabledSSL20Hello = true;
       
   269                 continue;
       
   270             }
       
   271 
       
   272             if (!algorithmConstraints.permits(
       
   273                     EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
       
   274                     protocol.name, null)) {
       
   275                 // Ignore disabled protocol.
       
   276                 continue;
       
   277             }
       
   278 
       
   279             boolean found = false;
       
   280             Map<NamedGroupType, Boolean> cachedStatus =
       
   281                     new EnumMap<>(NamedGroupType.class);
       
   282             for (CipherSuite suite : enabledCipherSuites) {
       
   283                 if (suite.isAvailable() && suite.supports(protocol)) {
       
   284                     if (isActivatable(suite,
       
   285                             algorithmConstraints, cachedStatus)) {
       
   286                         protocols.add(protocol);
       
   287                         found = true;
       
   288                         break;
       
   289                     }
       
   290                 } else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
       
   291                     SSLLogger.fine(
       
   292                         "Ignore unsupported cipher suite: " + suite +
       
   293                              " for " + protocol);
       
   294                 }
       
   295             }
       
   296 
       
   297             if (!found && (SSLLogger.isOn) && SSLLogger.isOn("handshake")) {
       
   298                 SSLLogger.fine(
       
   299                     "No available cipher suite for " + protocol);
       
   300             }
       
   301         }
       
   302 
       
   303         if (!protocols.isEmpty()) {
       
   304             if (enabledSSL20Hello) {
       
   305                 protocols.add(ProtocolVersion.SSL20Hello);
       
   306             }
       
   307             Collections.sort(protocols);
       
   308         }
       
   309 
       
   310         return Collections.unmodifiableList(protocols);
       
   311     }
       
   312 
       
   313     private static List<CipherSuite> getActiveCipherSuites(
       
   314             List<ProtocolVersion> enabledProtocols,
       
   315             List<CipherSuite> enabledCipherSuites,
       
   316             AlgorithmConstraints algorithmConstraints) {
       
   317 
       
   318         List<CipherSuite> suites = new LinkedList<>();
       
   319         if (enabledProtocols != null && !enabledProtocols.isEmpty()) {
       
   320             Map<NamedGroupType, Boolean> cachedStatus =
       
   321                     new EnumMap<>(NamedGroupType.class);
       
   322             for (CipherSuite suite : enabledCipherSuites) {
       
   323                 if (!suite.isAvailable()) {
       
   324                     continue;
       
   325                 }
       
   326 
       
   327                 boolean isSupported = false;
       
   328                 for (ProtocolVersion protocol : enabledProtocols) {
       
   329                     if (!suite.supports(protocol)) {
       
   330                         continue;
       
   331                     }
       
   332                     if (isActivatable(suite,
       
   333                             algorithmConstraints, cachedStatus)) {
       
   334                         suites.add(suite);
       
   335                         isSupported = true;
       
   336                         break;
       
   337                     }
       
   338                 }
       
   339 
       
   340                 if (!isSupported &&
       
   341                         SSLLogger.isOn && SSLLogger.isOn("verbose")) {
       
   342                     SSLLogger.finest(
       
   343                             "Ignore unsupported cipher suite: " + suite);
       
   344                 }
       
   345             }
       
   346         }
       
   347 
       
   348         return Collections.unmodifiableList(suites);
       
   349     }
       
   350 
       
   351     /**
       
   352      * Parse the handshake record and return the contentType
       
   353      */
       
   354     static byte getHandshakeType(TransportContext conContext,
       
   355             Plaintext plaintext) throws IOException {
       
   356         //     struct {
       
   357         //         HandshakeType msg_type;    /* handshake type */
       
   358         //         uint24 length;             /* bytes in message */
       
   359         //         select (HandshakeType) {
       
   360         //             ...
       
   361         //         } body;
       
   362         //     } Handshake;
       
   363 
       
   364         if (plaintext.contentType != ContentType.HANDSHAKE.id) {
       
   365             conContext.fatal(Alert.INTERNAL_ERROR,
       
   366                 "Unexpected operation for record: " + plaintext.contentType);
       
   367 
       
   368             return 0;
       
   369         }
       
   370 
       
   371         if (plaintext.fragment == null || plaintext.fragment.remaining() < 4) {
       
   372             conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   373                     "Invalid handshake message: insufficient data");
       
   374 
       
   375             return 0;
       
   376         }
       
   377 
       
   378         byte handshakeType = (byte)Record.getInt8(plaintext.fragment);
       
   379         int handshakeLen = Record.getInt24(plaintext.fragment);
       
   380         if (handshakeLen != plaintext.fragment.remaining()) {
       
   381             conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   382                     "Invalid handshake message: insufficient handshake body");
       
   383 
       
   384             return 0;
       
   385         }
       
   386 
       
   387         return handshakeType;
       
   388     }
       
   389 
       
   390     void dispatch(byte handshakeType, Plaintext plaintext) throws IOException {
       
   391         if (conContext.transport.useDelegatedTask()) {
       
   392             boolean hasDelegated = !delegatedActions.isEmpty();
       
   393             if (hasDelegated ||
       
   394                    (handshakeType != SSLHandshake.FINISHED.id &&
       
   395                     handshakeType != SSLHandshake.KEY_UPDATE.id &&
       
   396                     handshakeType != SSLHandshake.NEW_SESSION_TICKET.id)) {
       
   397                 if (!hasDelegated) {
       
   398                     taskDelegated = false;
       
   399                     delegatedThrown = null;
       
   400                 }
       
   401 
       
   402                 // Clone the fragment for delegated actions.
       
   403                 //
       
   404                 // The plaintext may share the application buffers.  It is
       
   405                 // fine to use shared buffers if no delegated actions.
       
   406                 // However, for delegated actions, the shared buffers may be
       
   407                 // polluted in application layer before the delegated actions
       
   408                 // executed.
       
   409                 ByteBuffer fragment = ByteBuffer.wrap(
       
   410                         new byte[plaintext.fragment.remaining()]);
       
   411                 fragment.put(plaintext.fragment);
       
   412                 fragment = fragment.rewind();
       
   413 
       
   414                 delegatedActions.add(new SimpleImmutableEntry<>(
       
   415                         handshakeType,
       
   416                         fragment
       
   417                     ));
       
   418             } else {
       
   419                 dispatch(handshakeType, plaintext.fragment);
       
   420             }
       
   421         } else {
       
   422             dispatch(handshakeType, plaintext.fragment);
       
   423         }
       
   424     }
       
   425 
       
   426     void dispatch(byte handshakeType,
       
   427             ByteBuffer fragment) throws IOException {
       
   428         SSLConsumer consumer;
       
   429         if (handshakeType == SSLHandshake.HELLO_REQUEST.id) {
       
   430             // For TLS 1.2 and prior versions, the HelloRequest message MAY
       
   431             // be sent by the server at any time.
       
   432             consumer = SSLHandshake.HELLO_REQUEST;
       
   433         } else {
       
   434             consumer = handshakeConsumers.get(handshakeType);
       
   435         }
       
   436 
       
   437         if (consumer == null) {
       
   438             conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   439                     "Unexpected handshake message: " +
       
   440                     SSLHandshake.nameOf(handshakeType));
       
   441             return;
       
   442         }
       
   443 
       
   444         try {
       
   445             consumer.consume(this, fragment);
       
   446         } catch (UnsupportedOperationException unsoe) {
       
   447             conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   448                     "Unsupported handshake message: " +
       
   449                     SSLHandshake.nameOf(handshakeType), unsoe);
       
   450         }
       
   451 
       
   452         // update handshake hash after handshake message consumption.
       
   453         handshakeHash.consume();
       
   454     }
       
   455 
       
   456     abstract void kickstart() throws IOException;
       
   457 
       
   458     /**
       
   459      * Check if the given cipher suite is enabled and available within
       
   460      * the current active cipher suites.
       
   461      *
       
   462      * Does not check if the required server certificates are available.
       
   463      */
       
   464     boolean isNegotiable(CipherSuite cs) {
       
   465         return isNegotiable(activeCipherSuites, cs);
       
   466     }
       
   467 
       
   468     /**
       
   469      * Check if the given cipher suite is enabled and available within
       
   470      * the proposed cipher suite list.
       
   471      *
       
   472      * Does not check if the required server certificates are available.
       
   473      */
       
   474     static final boolean isNegotiable(
       
   475             List<CipherSuite> proposed, CipherSuite cs) {
       
   476         return proposed.contains(cs) && cs.isNegotiable();
       
   477     }
       
   478 
       
   479     /**
       
   480      * Check if the given cipher suite is enabled and available within
       
   481      * the proposed cipher suite list and specific protocol version.
       
   482      *
       
   483      * Does not check if the required server certificates are available.
       
   484      */
       
   485     static final boolean isNegotiable(List<CipherSuite> proposed,
       
   486             ProtocolVersion protocolVersion, CipherSuite cs) {
       
   487         return proposed.contains(cs) &&
       
   488                 cs.isNegotiable() && cs.supports(protocolVersion);
       
   489     }
       
   490 
       
   491     /**
       
   492      * Check if the given protocol version is enabled and available.
       
   493      */
       
   494     boolean isNegotiable(ProtocolVersion protocolVersion) {
       
   495         return activeProtocols.contains(protocolVersion);
       
   496     }
       
   497 
       
   498     /**
       
   499      * Set the active protocol version and propagate it to the SSLSocket
       
   500      * and our handshake streams. Called from ClientHandshaker
       
   501      * and ServerHandshaker with the negotiated protocol version.
       
   502      */
       
   503     void setVersion(ProtocolVersion protocolVersion) {
       
   504         this.conContext.protocolVersion = protocolVersion;
       
   505     }
       
   506 
       
   507     private static boolean isActivatable(CipherSuite suite,
       
   508             AlgorithmConstraints algorithmConstraints,
       
   509             Map<NamedGroupType, Boolean> cachedStatus) {
       
   510 
       
   511         if (algorithmConstraints.permits(
       
   512                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), suite.name, null)) {
       
   513             if (suite.keyExchange == null) {
       
   514                 // TLS 1.3, no definition of key exchange in cipher suite.
       
   515                 return true;
       
   516             }
       
   517 
       
   518             boolean available;
       
   519             NamedGroupType groupType = suite.keyExchange.groupType;
       
   520             if (groupType != NAMED_GROUP_NONE) {
       
   521                 Boolean checkedStatus = cachedStatus.get(groupType);
       
   522                 if (checkedStatus == null) {
       
   523                     available = SupportedGroups.isActivatable(
       
   524                             algorithmConstraints, groupType);
       
   525                     cachedStatus.put(groupType, available);
       
   526 
       
   527                     if (!available &&
       
   528                             SSLLogger.isOn && SSLLogger.isOn("verbose")) {
       
   529                         SSLLogger.fine("No activated named group");
       
   530                     }
       
   531                 } else {
       
   532                     available = checkedStatus;
       
   533                 }
       
   534 
       
   535                 if (!available && SSLLogger.isOn && SSLLogger.isOn("verbose")) {
       
   536                     SSLLogger.fine(
       
   537                         "No active named group, ignore " + suite);
       
   538                 }
       
   539                 return available;
       
   540             } else {
       
   541                 return true;
       
   542             }
       
   543         } else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
       
   544             SSLLogger.fine("Ignore disabled cipher suite: " + suite);
       
   545         }
       
   546 
       
   547         return false;
       
   548     }
       
   549 
       
   550     List<SNIServerName> getRequestedServerNames() {
       
   551         if (requestedServerNames == null) {
       
   552             return Collections.<SNIServerName>emptyList();
       
   553         }
       
   554         return requestedServerNames;
       
   555     }
       
   556 }
       
   557