src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java
changeset 50768 68fa3d4026ea
parent 47216 71c04702a3d5
child 52890 b0e751c70385
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
     1 /*
     1 /*
     2  * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    24  */
    24  */
    25 
    25 
    26 package sun.security.ssl;
    26 package sun.security.ssl;
    27 
    27 
    28 import java.io.IOException;
    28 import java.io.IOException;
       
    29 import java.nio.ByteBuffer;
    29 import java.nio.charset.StandardCharsets;
    30 import java.nio.charset.StandardCharsets;
    30 import java.util.ArrayList;
    31 import java.util.ArrayList;
    31 import java.util.Collection;
    32 import java.util.Collection;
    32 import java.util.Collections;
    33 import java.util.Collections;
       
    34 import java.util.LinkedHashMap;
    33 import java.util.List;
    35 import java.util.List;
    34 import java.util.LinkedHashMap;
       
    35 import java.util.Map;
    36 import java.util.Map;
    36 
    37 import java.util.Objects;
    37 import javax.net.ssl.SNIHostName;
    38 import javax.net.ssl.SNIHostName;
    38 import javax.net.ssl.SNIMatcher;
    39 import javax.net.ssl.SNIMatcher;
    39 import javax.net.ssl.SNIServerName;
    40 import javax.net.ssl.SNIServerName;
    40 import javax.net.ssl.SSLProtocolException;
    41 import javax.net.ssl.SSLProtocolException;
    41 import javax.net.ssl.StandardConstants;
    42 import javax.net.ssl.StandardConstants;
    42 
    43 import static sun.security.ssl.SSLExtension.CH_SERVER_NAME;
    43 /*
    44 import static sun.security.ssl.SSLExtension.EE_SERVER_NAME;
    44  * [RFC 4366/6066] To facilitate secure connections to servers that host
    45 import sun.security.ssl.SSLExtension.ExtensionConsumer;
    45  * multiple 'virtual' servers at a single underlying network address, clients
    46 import static sun.security.ssl.SSLExtension.SH_SERVER_NAME;
    46  * MAY include an extension of type "server_name" in the (extended) client
    47 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
    47  * hello.  The "extension_data" field of this extension SHALL contain
    48 import sun.security.ssl.SSLHandshake.HandshakeMessage;
    48  * "ServerNameList" where:
    49 
    49  *
    50 /**
    50  *     struct {
    51  * Pack of the "server_name" extensions [RFC 4366/6066].
    51  *         NameType name_type;
       
    52  *         select (name_type) {
       
    53  *             case host_name: HostName;
       
    54  *         } name;
       
    55  *     } ServerName;
       
    56  *
       
    57  *     enum {
       
    58  *         host_name(0), (255)
       
    59  *     } NameType;
       
    60  *
       
    61  *     opaque HostName<1..2^16-1>;
       
    62  *
       
    63  *     struct {
       
    64  *         ServerName server_name_list<1..2^16-1>
       
    65  *     } ServerNameList;
       
    66  */
    52  */
    67 final class ServerNameExtension extends HelloExtension {
    53 final class ServerNameExtension {
    68 
    54     static final HandshakeProducer chNetworkProducer =
    69     // For backward compatibility, all future data structures associated with
    55             new CHServerNameProducer();
    70     // new NameTypes MUST begin with a 16-bit length field.
    56     static final ExtensionConsumer chOnLoadConsumer =
    71     static final int NAME_HEADER_LENGTH = 3;    // NameType: 1 byte
    57             new CHServerNameConsumer();
    72                                                 // Name length: 2 bytes
    58     static final SSLStringizer chStringizer =
    73     private Map<Integer, SNIServerName> sniMap;
    59             new CHServerNamesStringizer();
    74     private int listLength;     // ServerNameList length
    60 
    75 
    61     static final HandshakeProducer shNetworkProducer =
    76     // constructor for ServerHello
    62             new SHServerNameProducer();
    77     ServerNameExtension() throws IOException {
    63     static final ExtensionConsumer shOnLoadConsumer =
    78         super(ExtensionType.EXT_SERVER_NAME);
    64             new SHServerNameConsumer();
    79 
    65     static final SSLStringizer shStringizer =
    80         listLength = 0;
    66             new SHServerNamesStringizer();
    81         sniMap = Collections.<Integer, SNIServerName>emptyMap();
    67 
    82     }
    68     static final HandshakeProducer eeNetworkProducer =
    83 
    69             new EEServerNameProducer();
    84     // constructor for ClientHello
    70     static final ExtensionConsumer eeOnLoadConsumer =
    85     ServerNameExtension(List<SNIServerName> serverNames)
    71             new EEServerNameConsumer();
    86             throws IOException {
    72 
    87         super(ExtensionType.EXT_SERVER_NAME);
    73     /**
    88 
    74      * The "server_name" extension.
    89         listLength = 0;
    75      *
    90         sniMap = new LinkedHashMap<>();
    76      * See RFC 4366/6066 for the specification of the extension.
    91         for (SNIServerName serverName : serverNames) {
    77      */
    92             // check for duplicated server name type
    78     static final class CHServerNamesSpec implements SSLExtensionSpec {
    93             if (sniMap.put(serverName.getType(), serverName) != null) {
    79         // For backward compatibility, all future data structures associated
    94                 // unlikely to happen, but in case ...
    80         // with new NameTypes MUST begin with a 16-bit length field.
    95                 throw new RuntimeException(
    81         static final int NAME_HEADER_LENGTH = 3;    //  1: NameType
    96                     "Duplicated server name of type " + serverName.getType());
    82                                                     // +2: Name length
    97             }
    83         final List<SNIServerName> serverNames;
    98 
    84 
    99             listLength += serverName.getEncoded().length + NAME_HEADER_LENGTH;
    85         private CHServerNamesSpec(List<SNIServerName> serverNames) {
   100         }
    86             this.serverNames =
   101 
    87                     Collections.<SNIServerName>unmodifiableList(serverNames);
   102         // This constructor is used for ClientHello only.  Empty list is
    88         }
   103         // not allowed in client mode.
    89 
   104         if (listLength == 0) {
    90         private CHServerNamesSpec(ByteBuffer buffer) throws IOException {
   105             throw new RuntimeException("The ServerNameList cannot be empty");
    91             if (buffer.remaining() < 2) {
   106         }
       
   107     }
       
   108 
       
   109     // constructor for ServerHello for parsing SNI extension
       
   110     ServerNameExtension(HandshakeInStream s, int len)
       
   111             throws IOException {
       
   112         super(ExtensionType.EXT_SERVER_NAME);
       
   113 
       
   114         int remains = len;
       
   115         if (len >= 2) {    // "server_name" extension in ClientHello
       
   116             listLength = s.getInt16();     // ServerNameList length
       
   117             if (listLength == 0 || listLength + 2 != len) {
       
   118                 throw new SSLProtocolException(
    92                 throw new SSLProtocolException(
   119                         "Invalid " + type + " extension");
    93                     "Invalid server_name extension: insufficient data");
   120             }
    94             }
   121 
    95 
   122             remains -= 2;
    96             int sniLen = Record.getInt16(buffer);
   123             sniMap = new LinkedHashMap<>();
    97             if ((sniLen == 0) || sniLen != buffer.remaining()) {
   124             while (remains > 0) {
    98                 throw new SSLProtocolException(
   125                 int code = s.getInt8();       // NameType
    99                     "Invalid server_name extension: incomplete data");
       
   100             }
       
   101 
       
   102             Map<Integer, SNIServerName> sniMap = new LinkedHashMap<>();
       
   103             while (buffer.hasRemaining()) {
       
   104                 int nameType = Record.getInt8(buffer);
       
   105                 SNIServerName serverName;
   126 
   106 
   127                 // HostName (length read in getBytes16);
   107                 // HostName (length read in getBytes16);
   128                 byte[] encoded = s.getBytes16();
   108                 //
   129                 SNIServerName serverName;
   109                 // [RFC 6066] The data structure associated with the host_name
   130                 switch (code) {
   110                 // NameType is a variable-length vector that begins with a
   131                     case StandardConstants.SNI_HOST_NAME:
   111                 // 16-bit length.  For backward compatibility, all future data
   132                         if (encoded.length == 0) {
   112                 // structures associated with new NameTypes MUST begin with a
   133                             throw new SSLProtocolException(
   113                 // 16-bit length field.  TLS MAY treat provided server names as
   134                                 "Empty HostName in server name indication");
   114                 // opaque data and pass the names and types to the application.
   135                         }
   115                 byte[] encoded = Record.getBytes16(buffer);
   136                         try {
   116                 if (nameType == StandardConstants.SNI_HOST_NAME) {
   137                             serverName = new SNIHostName(encoded);
   117                     if (encoded.length == 0) {
   138                         } catch (IllegalArgumentException iae) {
   118                         throw new SSLProtocolException(
   139                             SSLProtocolException spe = new SSLProtocolException(
   119                             "Empty HostName in server_name extension");
   140                                 "Illegal server name, type=host_name(" +
   120                     }
   141                                 code + "), name=" +
   121 
   142                                 (new String(encoded, StandardCharsets.UTF_8)) +
   122                     try {
   143                                 ", value=" + Debug.toString(encoded));
   123                         serverName = new SNIHostName(encoded);
   144                             spe.initCause(iae);
   124                     } catch (IllegalArgumentException iae) {
   145                             throw spe;
   125                         SSLProtocolException spe = new SSLProtocolException(
   146                         }
   126                             "Illegal server name, type=host_name(" +
   147                         break;
   127                             nameType + "), name=" +
   148                     default:
   128                             (new String(encoded, StandardCharsets.UTF_8)) +
   149                         try {
   129                             ", value={" +
   150                             serverName = new UnknownServerName(code, encoded);
   130                             Utilities.toHexString(encoded) + "}");
   151                         } catch (IllegalArgumentException iae) {
   131                         throw (SSLProtocolException)spe.initCause(iae);
   152                             SSLProtocolException spe = new SSLProtocolException(
   132                     }
   153                                 "Illegal server name, type=(" + code +
   133                 } else {
   154                                 "), value=" + Debug.toString(encoded));
   134                     try {
   155                             spe.initCause(iae);
   135                         serverName = new UnknownServerName(nameType, encoded);
   156                             throw spe;
   136                     } catch (IllegalArgumentException iae) {
   157                         }
   137                         SSLProtocolException spe = new SSLProtocolException(
   158                 }
   138                             "Illegal server name, type=(" + nameType +
       
   139                             "), value={" +
       
   140                             Utilities.toHexString(encoded) + "}");
       
   141                         throw (SSLProtocolException)spe.initCause(iae);
       
   142                     }
       
   143                 }
       
   144 
   159                 // check for duplicated server name type
   145                 // check for duplicated server name type
   160                 if (sniMap.put(serverName.getType(), serverName) != null) {
   146                 if (sniMap.put(serverName.getType(), serverName) != null) {
   161                     throw new SSLProtocolException(
   147                     throw new SSLProtocolException(
   162                             "Duplicated server name of type " +
   148                             "Duplicated server name of type " +
   163                             serverName.getType());
   149                             serverName.getType());
   164                 }
   150                 }
   165 
   151             }
   166                 remains -= encoded.length + NAME_HEADER_LENGTH;
   152 
   167             }
   153             this.serverNames = new ArrayList<>(sniMap.values());
   168         } else if (len == 0) {     // "server_name" extension in ServerHello
   154         }
   169             listLength = 0;
   155 
   170             sniMap = Collections.<Integer, SNIServerName>emptyMap();
   156         @Override
   171         }
   157         public String toString() {
   172 
   158             if (serverNames == null || serverNames.isEmpty()) {
   173         if (remains != 0) {
   159                 return "<no server name indicator specified>";
   174             throw new SSLProtocolException("Invalid server_name extension");
   160             } else {
   175         }
   161                 StringBuilder builder = new StringBuilder(512);
   176     }
   162                 for (SNIServerName sn : serverNames) {
   177 
   163                     builder.append(sn.toString());
   178     List<SNIServerName> getServerNames() {
   164                     builder.append("\n");
   179         if (sniMap != null && !sniMap.isEmpty()) {
   165                 }
   180             return Collections.<SNIServerName>unmodifiableList(
   166 
   181                                         new ArrayList<>(sniMap.values()));
   167                 return builder.toString();
   182         }
   168             }
   183 
   169         }
   184         return Collections.<SNIServerName>emptyList();
   170 
   185     }
   171         private static class UnknownServerName extends SNIServerName {
   186 
   172             UnknownServerName(int code, byte[] encoded) {
   187     /*
   173                 super(code, encoded);
   188      * Is the extension recognized by the corresponding matcher?
   174             }
       
   175         }
       
   176     }
       
   177 
       
   178     private static final class CHServerNamesStringizer implements SSLStringizer {
       
   179         @Override
       
   180         public String toString(ByteBuffer buffer) {
       
   181             try {
       
   182                 return (new CHServerNamesSpec(buffer)).toString();
       
   183             } catch (IOException ioe) {
       
   184                 // For debug logging only, so please swallow exceptions.
       
   185                 return ioe.getMessage();
       
   186             }
       
   187         }
       
   188     }
       
   189 
       
   190     /**
       
   191      * Network data producer of a "server_name" extension in the
       
   192      * ClientHello handshake message.
       
   193      */
       
   194     private static final
       
   195             class CHServerNameProducer implements HandshakeProducer {
       
   196         // Prevent instantiation of this class.
       
   197         private CHServerNameProducer() {
       
   198             // blank
       
   199         }
       
   200 
       
   201         @Override
       
   202         public byte[] produce(ConnectionContext context,
       
   203                 HandshakeMessage message) throws IOException {
       
   204             // The producing happens in client side only.
       
   205             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   206 
       
   207             // Is it a supported and enabled extension?
       
   208             if (!chc.sslConfig.isAvailable(CH_SERVER_NAME)) {
       
   209                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   210                     SSLLogger.warning(
       
   211                         "Ignore unavailable server_name extension");
       
   212                 }
       
   213                 return null;
       
   214             }
       
   215 
       
   216             // Produce the extension.
       
   217             List<SNIServerName> serverNames;
       
   218             if (chc.isResumption && (chc.resumingSession != null)) {
       
   219                 serverNames =
       
   220                         chc.resumingSession.getRequestedServerNames();
       
   221             } else {
       
   222                 serverNames = chc.sslConfig.serverNames;
       
   223             }   // Shall we use host too?
       
   224 
       
   225             // Empty server name list is not allowed in client mode.
       
   226             if ((serverNames != null) && !serverNames.isEmpty()) {
       
   227                 int sniLen = 0;
       
   228                 for (SNIServerName sniName : serverNames) {
       
   229                     // For backward compatibility, all future data structures
       
   230                     // associated with new NameTypes MUST begin with a 16-bit
       
   231                     // length field.  The header length of server name is 3
       
   232                     // bytes, including 1 byte NameType, and 2 bytes length
       
   233                     // of the name.
       
   234                     sniLen += CHServerNamesSpec.NAME_HEADER_LENGTH;
       
   235                     sniLen += sniName.getEncoded().length;
       
   236                 }
       
   237 
       
   238                 byte[] extData = new byte[sniLen + 2];
       
   239                 ByteBuffer m = ByteBuffer.wrap(extData);
       
   240                 Record.putInt16(m, sniLen);
       
   241                 for (SNIServerName sniName : serverNames) {
       
   242                     Record.putInt8(m, sniName.getType());
       
   243                     Record.putBytes16(m, sniName.getEncoded());
       
   244                 }
       
   245 
       
   246                 // Update the context.
       
   247                 chc.requestedServerNames = serverNames;
       
   248                 chc.handshakeExtensions.put(CH_SERVER_NAME,
       
   249                         new CHServerNamesSpec(serverNames));
       
   250 
       
   251                 return extData;
       
   252             }
       
   253 
       
   254             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   255                 SSLLogger.warning("Unable to indicate server name");
       
   256             }
       
   257             return null;
       
   258         }
       
   259     }
       
   260 
       
   261     /**
       
   262      * Network data consumer of a "server_name" extension in the
       
   263      * ClientHello handshake message.
       
   264      */
       
   265     private static final
       
   266             class CHServerNameConsumer implements ExtensionConsumer {
       
   267         // Prevent instantiation of this class.
       
   268         private CHServerNameConsumer() {
       
   269             // blank
       
   270         }
       
   271 
       
   272         @Override
       
   273         public void consume(ConnectionContext context,
       
   274             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   275             // The consuming happens in server side only.
       
   276             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   277 
       
   278             // Is it a supported and enabled extension?
       
   279             if (!shc.sslConfig.isAvailable(CH_SERVER_NAME)) {
       
   280                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   281                     SSLLogger.fine(
       
   282                         "Ignore unavailable extension: " + CH_SERVER_NAME.name);
       
   283                 }
       
   284                 return;     // ignore the extension
       
   285             }
       
   286 
       
   287             // Parse the extension.
       
   288             CHServerNamesSpec spec;
       
   289             try {
       
   290                 spec = new CHServerNamesSpec(buffer);
       
   291             } catch (IOException ioe) {
       
   292                 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
       
   293                 return;     // fatal() always throws, make the compiler happy.
       
   294             }
       
   295 
       
   296             // Update the context.
       
   297             shc.handshakeExtensions.put(CH_SERVER_NAME, spec);
       
   298 
       
   299             // Does the server match the server name request?
       
   300             SNIServerName sni = null;
       
   301             if (!shc.sslConfig.sniMatchers.isEmpty()) {
       
   302                 sni = chooseSni(shc.sslConfig.sniMatchers, spec.serverNames);
       
   303                 if (sni != null) {
       
   304                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   305                         SSLLogger.fine(
       
   306                                 "server name indication (" +
       
   307                                 sni + ") is accepted");
       
   308                     }
       
   309                 } else {
       
   310                     // We do not reject client without SNI extension currently.
       
   311                     shc.conContext.fatal(Alert.UNRECOGNIZED_NAME,
       
   312                             "Unrecognized server name indication");
       
   313                 }
       
   314             } else {
       
   315                 // Note: Servers MAY require clients to send a valid
       
   316                 // "server_name" extension and respond to a ClientHello
       
   317                 // lacking a "server_name" extension by terminating the
       
   318                 // connection with a "missing_extension" alert.
       
   319                 //
       
   320                 // We do not reject client without SNI extension currently.
       
   321                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   322                     SSLLogger.fine(
       
   323                             "no server name matchers, " +
       
   324                             "ignore server name indication");
       
   325                 }
       
   326             }
       
   327 
       
   328             // Impact on session resumption.
       
   329             //
       
   330             // Does the resuming session have the same principal?
       
   331             if (shc.isResumption && shc.resumingSession != null) {
       
   332                 // A server that implements this extension MUST NOT accept
       
   333                 // the request to resume the session if the server_name
       
   334                 // extension contains a different name.
       
   335                 //
       
   336                 // May only need to check that the session SNI is one of
       
   337                 // the requested server names.
       
   338                 if (!Objects.equals(
       
   339                         sni, shc.resumingSession.serverNameIndication)) {
       
   340                     shc.isResumption = false;
       
   341                     shc.resumingSession = null;
       
   342                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   343                         SSLLogger.fine(
       
   344                                 "abort session resumption, " +
       
   345                                 "different server name indication used");
       
   346                     }
       
   347                 }
       
   348             }
       
   349 
       
   350             shc.requestedServerNames = spec.serverNames;
       
   351             shc.negotiatedServerName = sni;
       
   352         }
       
   353 
       
   354         private static SNIServerName chooseSni(Collection<SNIMatcher> matchers,
       
   355                 List<SNIServerName> sniNames) {
       
   356             if (sniNames != null && !sniNames.isEmpty()) {
       
   357                 for (SNIMatcher matcher : matchers) {
       
   358                     int matcherType = matcher.getType();
       
   359                     for (SNIServerName sniName : sniNames) {
       
   360                         if (sniName.getType() == matcherType) {
       
   361                             if (matcher.matches(sniName)) {
       
   362                                 return sniName;
       
   363                             }
       
   364 
       
   365                             // no duplicated entry in the server names list.
       
   366                             break;
       
   367                         }
       
   368                     }
       
   369                 }
       
   370             }
       
   371 
       
   372             return null;
       
   373         }
       
   374     }
       
   375 
       
   376     /**
       
   377      * The "server_name" extension in the ServerHello handshake message.
   189      *
   378      *
   190      * This method is used to check whether the server name indication can
   379      * The "extension_data" field of this extension shall be empty.
   191      * be recognized by the server name matchers.
   380      */
   192      *
   381     static final class SHServerNamesSpec implements SSLExtensionSpec {
   193      * Per RFC 6066, if the server understood the ClientHello extension but
   382         static final SHServerNamesSpec DEFAULT = new SHServerNamesSpec();
   194      * does not recognize the server name, the server SHOULD take one of two
   383 
   195      * actions: either abort the handshake by sending a fatal-level
   384         private SHServerNamesSpec() {
   196      * unrecognized_name(112) alert or continue the handshake.
   385             // blank
   197      *
   386         }
   198      * If there is an instance of SNIMatcher defined for a particular name
   387 
   199      * type, it must be used to perform match operations on the server name.
   388         private SHServerNamesSpec(ByteBuffer buffer) throws IOException {
   200      */
   389             if (buffer.remaining() != 0) {
   201     boolean isMatched(Collection<SNIMatcher> matchers) {
   390                 throw new SSLProtocolException(
   202         if (sniMap != null && !sniMap.isEmpty()) {
   391                     "Invalid ServerHello server_name extension: not empty");
   203             for (SNIMatcher matcher : matchers) {
   392             }
   204                 SNIServerName sniName = sniMap.get(matcher.getType());
   393         }
   205                 if (sniName != null && (!matcher.matches(sniName))) {
   394 
   206                     return false;
   395         @Override
   207                 }
   396         public String toString() {
   208             }
   397             return "<empty extension_data field>";
   209         }
   398         }
   210 
   399     }
   211         return true;
   400 
   212     }
   401     private static final class SHServerNamesStringizer implements SSLStringizer {
   213 
   402         @Override
   214     /*
   403         public String toString(ByteBuffer buffer) {
   215      * Is the extension is identical to a server name list?
   404             try {
   216      *
   405                 return (new SHServerNamesSpec(buffer)).toString();
   217      * This method is used to check the server name indication during session
   406             } catch (IOException ioe) {
   218      * resumption.
   407                 // For debug logging only, so please swallow exceptions.
   219      *
   408                 return ioe.getMessage();
   220      * Per RFC 6066, when the server is deciding whether or not to accept a
   409             }
   221      * request to resume a session, the contents of a server_name extension
   410         }
   222      * MAY be used in the lookup of the session in the session cache.  The
   411     }
   223      * client SHOULD include the same server_name extension in the session
   412 
   224      * resumption request as it did in the full handshake that established
   413     /**
   225      * the session.  A server that implements this extension MUST NOT accept
   414      * Network data producer of a "server_name" extension in the
   226      * the request to resume the session if the server_name extension contains
   415      * ServerHello handshake message.
   227      * a different name.  Instead, it proceeds with a full handshake to
   416      */
   228      * establish a new session.  When resuming a session, the server MUST NOT
   417     private static final
   229      * include a server_name extension in the server hello.
   418             class SHServerNameProducer implements HandshakeProducer {
   230      */
   419         // Prevent instantiation of this class.
   231     boolean isIdentical(List<SNIServerName> other) {
   420         private SHServerNameProducer() {
   232         if (other.size() == sniMap.size()) {
   421             // blank
   233             for(SNIServerName sniInOther : other) {
   422         }
   234                 SNIServerName sniName = sniMap.get(sniInOther.getType());
   423 
   235                 if (sniName == null || !sniInOther.equals(sniName)) {
   424         @Override
   236                     return false;
   425         public byte[] produce(ConnectionContext context,
   237                 }
   426                 HandshakeMessage message) throws IOException {
   238             }
   427             // The producing happens in server side only.
   239 
   428             ServerHandshakeContext shc = (ServerHandshakeContext)context;
   240             return true;
   429 
   241         }
   430             // In response to "server_name" extension request only
   242 
   431             CHServerNamesSpec spec = (CHServerNamesSpec)
   243         return false;
   432                     shc.handshakeExtensions.get(CH_SERVER_NAME);
   244     }
   433             if (spec == null) {
   245 
   434                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
   246     @Override
   435                     SSLLogger.finest(
   247     int length() {
   436                         "Ignore unavailable extension: " + SH_SERVER_NAME.name);
   248         return listLength == 0 ? 4 : 6 + listLength;
   437                 }
   249     }
   438                 return null;        // ignore the extension
   250 
   439             }
   251     @Override
   440 
   252     void send(HandshakeOutStream s) throws IOException {
   441             // When resuming a session, the server MUST NOT include a
   253         s.putInt16(type.id);
   442             // server_name extension in the server hello.
   254         if (listLength == 0) {
   443             if (shc.isResumption || shc.negotiatedServerName == null) {
   255             s.putInt16(listLength);     // in ServerHello, empty extension_data
   444                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
   256         } else {
   445                     SSLLogger.finest(
   257             s.putInt16(listLength + 2); // length of extension_data
   446                         "No expected server name indication response");
   258             s.putInt16(listLength);     // length of ServerNameList
   447                 }
   259 
   448                 return null;        // ignore the extension
   260             for (SNIServerName sniName : sniMap.values()) {
   449             }
   261                 s.putInt8(sniName.getType());         // server name type
   450 
   262                 s.putBytes16(sniName.getEncoded());   // server name value
   451             // Produce the extension and update the context.
   263             }
   452             shc.handshakeExtensions.put(
   264         }
   453                     SH_SERVER_NAME, SHServerNamesSpec.DEFAULT);
   265     }
   454 
   266 
   455             return (new byte[0]);   // the empty extension_data
   267     @Override
   456         }
   268     public String toString() {
   457     }
   269         StringBuilder sb = new StringBuilder();
   458 
   270         for (SNIServerName sniName : sniMap.values()) {
   459     /**
   271             sb.append("[" + sniName + "]");
   460      * Network data consumer of a "server_name" extension in the
   272         }
   461      * ServerHello handshake message.
   273 
   462      */
   274         return "Extension " + type + ", server_name: " + sb;
   463     private static final
   275     }
   464             class SHServerNameConsumer implements ExtensionConsumer {
   276 
   465         // Prevent instantiation of this class.
   277     private static class UnknownServerName extends SNIServerName {
   466         private SHServerNameConsumer() {
   278         UnknownServerName(int code, byte[] encoded) {
   467             // blank
   279             super(code, encoded);
   468         }
   280         }
   469 
   281     }
   470         @Override
   282 
   471         public void consume(ConnectionContext context,
       
   472             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   473             // The consuming happens in client side only.
       
   474             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   475 
       
   476             // In response to "server_name" extension request only
       
   477             CHServerNamesSpec spec = (CHServerNamesSpec)
       
   478                     chc.handshakeExtensions.get(CH_SERVER_NAME);
       
   479             if (spec == null) {
       
   480                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   481                     "Unexpected ServerHello server_name extension");
       
   482             }
       
   483 
       
   484             // Parse the extension.
       
   485             if (buffer.remaining() != 0) {
       
   486                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   487                     "Invalid ServerHello server_name extension");
       
   488             }
       
   489 
       
   490             // Update the context.
       
   491             chc.handshakeExtensions.put(
       
   492                     SH_SERVER_NAME, SHServerNamesSpec.DEFAULT);
       
   493             // The negotiated server name is unknown in client side. Just
       
   494             // use the first request name as the value is not actually used
       
   495             // in the current implementation.
       
   496             chc.negotiatedServerName = spec.serverNames.get(0);
       
   497         }
       
   498     }
       
   499 
       
   500     /**
       
   501      * Network data producer of a "server_name" extension in the
       
   502      * EncryptedExtensions handshake message.
       
   503      */
       
   504     private static final
       
   505             class EEServerNameProducer implements HandshakeProducer {
       
   506         // Prevent instantiation of this class.
       
   507         private EEServerNameProducer() {
       
   508             // blank
       
   509         }
       
   510 
       
   511         @Override
       
   512         public byte[] produce(ConnectionContext context,
       
   513                 HandshakeMessage message) throws IOException {
       
   514             // The producing happens in server side only.
       
   515             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   516 
       
   517             // In response to "server_name" extension request only
       
   518             CHServerNamesSpec spec = (CHServerNamesSpec)
       
   519                     shc.handshakeExtensions.get(CH_SERVER_NAME);
       
   520             if (spec == null) {
       
   521                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   522                     SSLLogger.finest(
       
   523                         "Ignore unavailable extension: " + EE_SERVER_NAME.name);
       
   524                 }
       
   525                 return null;        // ignore the extension
       
   526             }
       
   527 
       
   528             // When resuming a session, the server MUST NOT include a
       
   529             // server_name extension in the server hello.
       
   530             if (shc.isResumption || shc.negotiatedServerName == null) {
       
   531                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   532                     SSLLogger.finest(
       
   533                         "No expected server name indication response");
       
   534                 }
       
   535                 return null;        // ignore the extension
       
   536             }
       
   537 
       
   538             // Produce the extension and update the context.
       
   539             shc.handshakeExtensions.put(
       
   540                     EE_SERVER_NAME, SHServerNamesSpec.DEFAULT);
       
   541 
       
   542             return (new byte[0]);   // the empty extension_data
       
   543         }
       
   544     }
       
   545 
       
   546     /**
       
   547      * Network data consumer of a "server_name" extension in the
       
   548      * EncryptedExtensions handshake message.
       
   549      */
       
   550     private static final
       
   551             class EEServerNameConsumer implements ExtensionConsumer {
       
   552         // Prevent instantiation of this class.
       
   553         private EEServerNameConsumer() {
       
   554             // blank
       
   555         }
       
   556 
       
   557         @Override
       
   558         public void consume(ConnectionContext context,
       
   559             HandshakeMessage message, ByteBuffer buffer) throws IOException {
       
   560             // The consuming happens in client side only.
       
   561             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   562 
       
   563             // In response to "server_name" extension request only
       
   564             CHServerNamesSpec spec = (CHServerNamesSpec)
       
   565                     chc.handshakeExtensions.get(CH_SERVER_NAME);
       
   566             if (spec == null) {
       
   567                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   568                     "Unexpected EncryptedExtensions server_name extension");
       
   569             }
       
   570 
       
   571             // Parse the extension.
       
   572             if (buffer.remaining() != 0) {
       
   573                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   574                     "Invalid EncryptedExtensions server_name extension");
       
   575             }
       
   576 
       
   577             // Update the context.
       
   578             chc.handshakeExtensions.put(
       
   579                     EE_SERVER_NAME, SHServerNamesSpec.DEFAULT);
       
   580             // The negotiated server name is unknown in client side. Just
       
   581             // use the first request name as the value is not actually used
       
   582             // in the current implementation.
       
   583             chc.negotiatedServerName = spec.serverNames.get(0);
       
   584         }
       
   585     }
   283 }
   586 }