| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.ssl;  | 
 | 
 | 
 | 
import java.io.IOException;  | 
 | 
import java.nio.ByteBuffer;  | 
 | 
import java.nio.charset.StandardCharsets;  | 
 | 
import java.util.ArrayList;  | 
 | 
import java.util.Collection;  | 
 | 
import java.util.Collections;  | 
 | 
import java.util.LinkedHashMap;  | 
 | 
import java.util.List;  | 
 | 
import java.util.Map;  | 
 | 
import java.util.Objects;  | 
 | 
import javax.net.ssl.SNIHostName;  | 
 | 
import javax.net.ssl.SNIMatcher;  | 
 | 
import javax.net.ssl.SNIServerName;  | 
 | 
import javax.net.ssl.SSLProtocolException;  | 
 | 
import javax.net.ssl.StandardConstants;  | 
 | 
import static sun.security.ssl.SSLExtension.CH_SERVER_NAME;  | 
 | 
import static sun.security.ssl.SSLExtension.EE_SERVER_NAME;  | 
 | 
import sun.security.ssl.SSLExtension.ExtensionConsumer;  | 
 | 
import static sun.security.ssl.SSLExtension.SH_SERVER_NAME;  | 
 | 
import sun.security.ssl.SSLExtension.SSLExtensionSpec;  | 
 | 
import sun.security.ssl.SSLHandshake.HandshakeMessage;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
final class ServerNameExtension { | 
 | 
    static final HandshakeProducer chNetworkProducer =  | 
 | 
            new CHServerNameProducer();  | 
 | 
    static final ExtensionConsumer chOnLoadConsumer =  | 
 | 
            new CHServerNameConsumer();  | 
 | 
    static final SSLStringizer chStringizer =  | 
 | 
            new CHServerNamesStringizer();  | 
 | 
 | 
 | 
    static final HandshakeProducer shNetworkProducer =  | 
 | 
            new SHServerNameProducer();  | 
 | 
    static final ExtensionConsumer shOnLoadConsumer =  | 
 | 
            new SHServerNameConsumer();  | 
 | 
    static final SSLStringizer shStringizer =  | 
 | 
            new SHServerNamesStringizer();  | 
 | 
 | 
 | 
    static final HandshakeProducer eeNetworkProducer =  | 
 | 
            new EEServerNameProducer();  | 
 | 
    static final ExtensionConsumer eeOnLoadConsumer =  | 
 | 
            new EEServerNameConsumer();  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static final class CHServerNamesSpec implements SSLExtensionSpec { | 
 | 
        // For backward compatibility, all future data structures associated  | 
 | 
        // with new NameTypes MUST begin with a 16-bit length field.  | 
 | 
        static final int NAME_HEADER_LENGTH = 3;      | 
 | 
                                                      | 
 | 
        final List<SNIServerName> serverNames;  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        private CHServerNamesSpec(List<SNIServerName> serverNames) { | 
 | 
            this.serverNames = Collections.<SNIServerName>unmodifiableList(  | 
 | 
                    new ArrayList<>(serverNames));  | 
 | 
        }  | 
 | 
 | 
 | 
        private CHServerNamesSpec(ByteBuffer buffer) throws IOException { | 
 | 
            if (buffer.remaining() < 2) { | 
 | 
                throw new SSLProtocolException(  | 
 | 
                    "Invalid server_name extension: insufficient data");  | 
 | 
            }  | 
 | 
 | 
 | 
            int sniLen = Record.getInt16(buffer);  | 
 | 
            if ((sniLen == 0) || sniLen != buffer.remaining()) { | 
 | 
                throw new SSLProtocolException(  | 
 | 
                    "Invalid server_name extension: incomplete data");  | 
 | 
            }  | 
 | 
 | 
 | 
            Map<Integer, SNIServerName> sniMap = new LinkedHashMap<>();  | 
 | 
            while (buffer.hasRemaining()) { | 
 | 
                int nameType = Record.getInt8(buffer);  | 
 | 
                SNIServerName serverName;  | 
 | 
 | 
 | 
                // HostName (length read in getBytes16);  | 
 | 
                //  | 
 | 
                // [RFC 6066] The data structure associated with the host_name  | 
 | 
                // NameType is a variable-length vector that begins with a  | 
 | 
                // 16-bit length.  For backward compatibility, all future data  | 
 | 
                // structures associated with new NameTypes MUST begin with a  | 
 | 
                // 16-bit length field.  TLS MAY treat provided server names as  | 
 | 
                  | 
 | 
                byte[] encoded = Record.getBytes16(buffer);  | 
 | 
                if (nameType == StandardConstants.SNI_HOST_NAME) { | 
 | 
                    if (encoded.length == 0) { | 
 | 
                        throw new SSLProtocolException(  | 
 | 
                            "Empty HostName in server_name extension");  | 
 | 
                    }  | 
 | 
 | 
 | 
                    try { | 
 | 
                        serverName = new SNIHostName(encoded);  | 
 | 
                    } catch (IllegalArgumentException iae) { | 
 | 
                        SSLProtocolException spe = new SSLProtocolException(  | 
 | 
                            "Illegal server name, type=host_name(" + | 
 | 
                            nameType + "), name=" +  | 
 | 
                            (new String(encoded, StandardCharsets.UTF_8)) +  | 
 | 
                            ", value={" + | 
 | 
                            Utilities.toHexString(encoded) + "}");  | 
 | 
                        throw (SSLProtocolException)spe.initCause(iae);  | 
 | 
                    }  | 
 | 
                } else { | 
 | 
                    try { | 
 | 
                        serverName = new UnknownServerName(nameType, encoded);  | 
 | 
                    } catch (IllegalArgumentException iae) { | 
 | 
                        SSLProtocolException spe = new SSLProtocolException(  | 
 | 
                            "Illegal server name, type=(" + nameType + | 
 | 
                            "), value={" + | 
 | 
                            Utilities.toHexString(encoded) + "}");  | 
 | 
                        throw (SSLProtocolException)spe.initCause(iae);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
 | 
 | 
                  | 
 | 
                if (sniMap.put(serverName.getType(), serverName) != null) { | 
 | 
                    throw new SSLProtocolException(  | 
 | 
                            "Duplicated server name of type " +  | 
 | 
                            serverName.getType());  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            this.serverNames = new ArrayList<>(sniMap.values());  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public String toString() { | 
 | 
            if (serverNames == null || serverNames.isEmpty()) { | 
 | 
                return "<no server name indicator specified>";  | 
 | 
            } else { | 
 | 
                StringBuilder builder = new StringBuilder(512);  | 
 | 
                for (SNIServerName sn : serverNames) { | 
 | 
                    builder.append(sn.toString());  | 
 | 
                    builder.append("\n"); | 
 | 
                }  | 
 | 
 | 
 | 
                return builder.toString();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        private static class UnknownServerName extends SNIServerName { | 
 | 
            UnknownServerName(int code, byte[] encoded) { | 
 | 
                super(code, encoded);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class CHServerNamesStringizer implements SSLStringizer { | 
 | 
        @Override  | 
 | 
        public String toString(ByteBuffer buffer) { | 
 | 
            try { | 
 | 
                return (new CHServerNamesSpec(buffer)).toString();  | 
 | 
            } catch (IOException ioe) { | 
 | 
                  | 
 | 
                return ioe.getMessage();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class CHServerNameProducer implements HandshakeProducer { | 
 | 
          | 
 | 
        private CHServerNameProducer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public byte[] produce(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ClientHandshakeContext chc = (ClientHandshakeContext)context;  | 
 | 
 | 
 | 
              | 
 | 
            if (!chc.sslConfig.isAvailable(CH_SERVER_NAME)) { | 
 | 
                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                    SSLLogger.warning(  | 
 | 
                        "Ignore unavailable server_name extension");  | 
 | 
                }  | 
 | 
                return null;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            List<SNIServerName> serverNames;  | 
 | 
            if (chc.isResumption && (chc.resumingSession != null)) { | 
 | 
                serverNames =  | 
 | 
                        chc.resumingSession.getRequestedServerNames();  | 
 | 
            } else { | 
 | 
                serverNames = chc.sslConfig.serverNames;  | 
 | 
            }   // Shall we use host too?  | 
 | 
 | 
 | 
              | 
 | 
            if ((serverNames != null) && !serverNames.isEmpty()) { | 
 | 
                int sniLen = 0;  | 
 | 
                for (SNIServerName sniName : serverNames) { | 
 | 
                    // For backward compatibility, all future data structures  | 
 | 
                    // associated with new NameTypes MUST begin with a 16-bit  | 
 | 
                    // length field.  The header length of server name is 3  | 
 | 
                    // bytes, including 1 byte NameType, and 2 bytes length  | 
 | 
                      | 
 | 
                    sniLen += CHServerNamesSpec.NAME_HEADER_LENGTH;  | 
 | 
                    sniLen += sniName.getEncoded().length;  | 
 | 
                }  | 
 | 
 | 
 | 
                byte[] extData = new byte[sniLen + 2];  | 
 | 
                ByteBuffer m = ByteBuffer.wrap(extData);  | 
 | 
                Record.putInt16(m, sniLen);  | 
 | 
                for (SNIServerName sniName : serverNames) { | 
 | 
                    Record.putInt8(m, sniName.getType());  | 
 | 
                    Record.putBytes16(m, sniName.getEncoded());  | 
 | 
                }  | 
 | 
 | 
 | 
                  | 
 | 
                chc.requestedServerNames = serverNames;  | 
 | 
                chc.handshakeExtensions.put(CH_SERVER_NAME,  | 
 | 
                        new CHServerNamesSpec(serverNames));  | 
 | 
 | 
 | 
                return extData;  | 
 | 
            }  | 
 | 
 | 
 | 
            if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                SSLLogger.warning("Unable to indicate server name"); | 
 | 
            }  | 
 | 
            return null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class CHServerNameConsumer implements ExtensionConsumer { | 
 | 
          | 
 | 
        private CHServerNameConsumer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public void consume(ConnectionContext context,  | 
 | 
            HandshakeMessage message, ByteBuffer buffer) throws IOException { | 
 | 
              | 
 | 
            ServerHandshakeContext shc = (ServerHandshakeContext)context;  | 
 | 
 | 
 | 
              | 
 | 
            if (!shc.sslConfig.isAvailable(CH_SERVER_NAME)) { | 
 | 
                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                    SSLLogger.fine(  | 
 | 
                        "Ignore unavailable extension: " + CH_SERVER_NAME.name);  | 
 | 
                }  | 
 | 
                return;       | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            CHServerNamesSpec spec;  | 
 | 
            try { | 
 | 
                spec = new CHServerNamesSpec(buffer);  | 
 | 
            } catch (IOException ioe) { | 
 | 
                throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            shc.handshakeExtensions.put(CH_SERVER_NAME, spec);  | 
 | 
 | 
 | 
              | 
 | 
            SNIServerName sni = null;  | 
 | 
            if (!shc.sslConfig.sniMatchers.isEmpty()) { | 
 | 
                sni = chooseSni(shc.sslConfig.sniMatchers, spec.serverNames);  | 
 | 
                if (sni != null) { | 
 | 
                    if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                        SSLLogger.fine(  | 
 | 
                                "server name indication (" + | 
 | 
                                sni + ") is accepted");  | 
 | 
                    }  | 
 | 
                } else { | 
 | 
                      | 
 | 
                    throw shc.conContext.fatal(Alert.UNRECOGNIZED_NAME,  | 
 | 
                            "Unrecognized server name indication");  | 
 | 
                }  | 
 | 
            } else { | 
 | 
                // Note: Servers MAY require clients to send a valid  | 
 | 
                // "server_name" extension and respond to a ClientHello  | 
 | 
                // lacking a "server_name" extension by terminating the  | 
 | 
                // connection with a "missing_extension" alert.  | 
 | 
                //  | 
 | 
                  | 
 | 
                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                    SSLLogger.fine(  | 
 | 
                            "no server name matchers, " +  | 
 | 
                            "ignore server name indication");  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            // Impact on session resumption.  | 
 | 
            //  | 
 | 
              | 
 | 
            if (shc.isResumption && shc.resumingSession != null) { | 
 | 
                // A server that implements this extension MUST NOT accept  | 
 | 
                // the request to resume the session if the server_name  | 
 | 
                // extension contains a different name.  | 
 | 
                //  | 
 | 
                // May only need to check that the session SNI is one of  | 
 | 
                  | 
 | 
                if (!Objects.equals(  | 
 | 
                        sni, shc.resumingSession.serverNameIndication)) { | 
 | 
                    shc.isResumption = false;  | 
 | 
                    shc.resumingSession = null;  | 
 | 
                    if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                        SSLLogger.fine(  | 
 | 
                                "abort session resumption, " +  | 
 | 
                                "different server name indication used");  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            shc.requestedServerNames = spec.serverNames;  | 
 | 
            shc.negotiatedServerName = sni;  | 
 | 
        }  | 
 | 
 | 
 | 
        private static SNIServerName chooseSni(Collection<SNIMatcher> matchers,  | 
 | 
                List<SNIServerName> sniNames) { | 
 | 
            if (sniNames != null && !sniNames.isEmpty()) { | 
 | 
                for (SNIMatcher matcher : matchers) { | 
 | 
                    int matcherType = matcher.getType();  | 
 | 
                    for (SNIServerName sniName : sniNames) { | 
 | 
                        if (sniName.getType() == matcherType) { | 
 | 
                            if (matcher.matches(sniName)) { | 
 | 
                                return sniName;  | 
 | 
                            }  | 
 | 
 | 
 | 
                              | 
 | 
                            break;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            return null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static final class SHServerNamesSpec implements SSLExtensionSpec { | 
 | 
        static final SHServerNamesSpec DEFAULT = new SHServerNamesSpec();  | 
 | 
 | 
 | 
        private SHServerNamesSpec() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        private SHServerNamesSpec(ByteBuffer buffer) throws IOException { | 
 | 
            if (buffer.remaining() != 0) { | 
 | 
                throw new SSLProtocolException(  | 
 | 
                    "Invalid ServerHello server_name extension: not empty");  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public String toString() { | 
 | 
            return "<empty extension_data field>";  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final class SHServerNamesStringizer implements SSLStringizer { | 
 | 
        @Override  | 
 | 
        public String toString(ByteBuffer buffer) { | 
 | 
            try { | 
 | 
                return (new SHServerNamesSpec(buffer)).toString();  | 
 | 
            } catch (IOException ioe) { | 
 | 
                  | 
 | 
                return ioe.getMessage();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class SHServerNameProducer implements HandshakeProducer { | 
 | 
          | 
 | 
        private SHServerNameProducer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public byte[] produce(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ServerHandshakeContext shc = (ServerHandshakeContext)context;  | 
 | 
 | 
 | 
              | 
 | 
            CHServerNamesSpec spec = (CHServerNamesSpec)  | 
 | 
                    shc.handshakeExtensions.get(CH_SERVER_NAME);  | 
 | 
            if (spec == null) { | 
 | 
                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                    SSLLogger.finest(  | 
 | 
                        "Ignore unavailable extension: " + SH_SERVER_NAME.name);  | 
 | 
                }  | 
 | 
                return null;          | 
 | 
            }  | 
 | 
 | 
 | 
            // When resuming a session, the server MUST NOT include a  | 
 | 
              | 
 | 
            if (shc.isResumption || shc.negotiatedServerName == null) { | 
 | 
                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                    SSLLogger.finest(  | 
 | 
                        "No expected server name indication response");  | 
 | 
                }  | 
 | 
                return null;          | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            shc.handshakeExtensions.put(  | 
 | 
                    SH_SERVER_NAME, SHServerNamesSpec.DEFAULT);  | 
 | 
 | 
 | 
            return (new byte[0]);     | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class SHServerNameConsumer implements ExtensionConsumer { | 
 | 
          | 
 | 
        private SHServerNameConsumer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public void consume(ConnectionContext context,  | 
 | 
            HandshakeMessage message, ByteBuffer buffer) throws IOException { | 
 | 
              | 
 | 
            ClientHandshakeContext chc = (ClientHandshakeContext)context;  | 
 | 
 | 
 | 
              | 
 | 
            CHServerNamesSpec spec = (CHServerNamesSpec)  | 
 | 
                    chc.handshakeExtensions.get(CH_SERVER_NAME);  | 
 | 
            if (spec == null) { | 
 | 
                throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,  | 
 | 
                    "Unexpected ServerHello server_name extension");  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            if (buffer.remaining() != 0) { | 
 | 
                throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,  | 
 | 
                    "Invalid ServerHello server_name extension");  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            chc.handshakeExtensions.put(  | 
 | 
                    SH_SERVER_NAME, SHServerNamesSpec.DEFAULT);  | 
 | 
            // The negotiated server name is unknown in client side. Just  | 
 | 
            // use the first request name as the value is not actually used  | 
 | 
              | 
 | 
            chc.negotiatedServerName = spec.serverNames.get(0);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class EEServerNameProducer implements HandshakeProducer { | 
 | 
          | 
 | 
        private EEServerNameProducer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public byte[] produce(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ServerHandshakeContext shc = (ServerHandshakeContext)context;  | 
 | 
 | 
 | 
              | 
 | 
            CHServerNamesSpec spec = (CHServerNamesSpec)  | 
 | 
                    shc.handshakeExtensions.get(CH_SERVER_NAME);  | 
 | 
            if (spec == null) { | 
 | 
                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                    SSLLogger.finest(  | 
 | 
                        "Ignore unavailable extension: " + EE_SERVER_NAME.name);  | 
 | 
                }  | 
 | 
                return null;          | 
 | 
            }  | 
 | 
 | 
 | 
            // When resuming a session, the server MUST NOT include a  | 
 | 
              | 
 | 
            if (shc.isResumption || shc.negotiatedServerName == null) { | 
 | 
                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                    SSLLogger.finest(  | 
 | 
                        "No expected server name indication response");  | 
 | 
                }  | 
 | 
                return null;          | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            shc.handshakeExtensions.put(  | 
 | 
                    EE_SERVER_NAME, SHServerNamesSpec.DEFAULT);  | 
 | 
 | 
 | 
            return (new byte[0]);     | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class EEServerNameConsumer implements ExtensionConsumer { | 
 | 
          | 
 | 
        private EEServerNameConsumer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public void consume(ConnectionContext context,  | 
 | 
            HandshakeMessage message, ByteBuffer buffer) throws IOException { | 
 | 
              | 
 | 
            ClientHandshakeContext chc = (ClientHandshakeContext)context;  | 
 | 
 | 
 | 
              | 
 | 
            CHServerNamesSpec spec = (CHServerNamesSpec)  | 
 | 
                    chc.handshakeExtensions.get(CH_SERVER_NAME);  | 
 | 
            if (spec == null) { | 
 | 
                throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,  | 
 | 
                    "Unexpected EncryptedExtensions server_name extension");  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            if (buffer.remaining() != 0) { | 
 | 
                throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,  | 
 | 
                    "Invalid EncryptedExtensions server_name extension");  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            chc.handshakeExtensions.put(  | 
 | 
                    EE_SERVER_NAME, SHServerNamesSpec.DEFAULT);  | 
 | 
            // The negotiated server name is unknown in client side. Just  | 
 | 
            // use the first request name as the value is not actually used  | 
 | 
              | 
 | 
            chc.negotiatedServerName = spec.serverNames.get(0);  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |