Path: blob/master/src/java.base/share/classes/sun/security/ssl/ClientHello.java
67766 views
/*1* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.ssl;2627import java.io.IOException;28import java.nio.ByteBuffer;29import java.security.SecureRandom;30import java.security.cert.X509Certificate;31import java.text.MessageFormat;32import java.util.Arrays;33import java.util.Collections;34import java.util.LinkedList;35import java.util.List;36import java.util.Locale;37import javax.net.ssl.SSLException;38import javax.net.ssl.SSLHandshakeException;39import javax.net.ssl.SSLPeerUnverifiedException;40import javax.net.ssl.SSLProtocolException;41import static sun.security.ssl.ClientAuthType.CLIENT_AUTH_REQUIRED;42import sun.security.ssl.SSLHandshake.HandshakeMessage;43import sun.security.ssl.SupportedVersionsExtension.CHSupportedVersionsSpec;4445/**46* Pack of the ClientHello handshake message.47*/48final class ClientHello {49static final SSLProducer kickstartProducer =50new ClientHelloKickstartProducer();51static final SSLConsumer handshakeConsumer =52new ClientHelloConsumer();53static final HandshakeProducer handshakeProducer =54new ClientHelloProducer();5556private static final HandshakeConsumer t12HandshakeConsumer =57new T12ClientHelloConsumer();58private static final HandshakeConsumer t13HandshakeConsumer =59new T13ClientHelloConsumer();60private static final HandshakeConsumer d12HandshakeConsumer =61new D12ClientHelloConsumer();62private static final HandshakeConsumer d13HandshakeConsumer =63new D13ClientHelloConsumer();6465/**66* The ClientHello handshake message.67*68* See RFC 5264/4346/2246/6347 for the specifications.69*/70static final class ClientHelloMessage extends HandshakeMessage {71private final boolean isDTLS;7273final int clientVersion;74final RandomCookie clientRandom;75final SessionId sessionId;76private byte[] cookie; // DTLS only77final int[] cipherSuiteIds;78final List<CipherSuite> cipherSuites; // known cipher suites only79final byte[] compressionMethod;80final SSLExtensions extensions;8182private static final byte[] NULL_COMPRESSION = new byte[] {0};8384ClientHelloMessage(HandshakeContext handshakeContext,85int clientVersion, SessionId sessionId,86List<CipherSuite> cipherSuites, SecureRandom generator) {87super(handshakeContext);88this.isDTLS = handshakeContext.sslContext.isDTLS();8990this.clientVersion = clientVersion;91this.clientRandom = new RandomCookie(generator);92this.sessionId = sessionId;93if (isDTLS) {94this.cookie = new byte[0];95} else {96this.cookie = null;97}9899this.cipherSuites = cipherSuites;100this.cipherSuiteIds = getCipherSuiteIds(cipherSuites);101this.extensions = new SSLExtensions(this);102103// Don't support compression.104this.compressionMethod = NULL_COMPRESSION;105}106107/* Read up to the binders in the PSK extension. After this method108* returns, the ByteBuffer position will be at end of the message109* fragment that should be hashed to produce the PSK binder values.110* The client of this method can use this position to determine the111* message fragment and produce the binder values.112*/113static void readPartial(TransportContext tc,114ByteBuffer m) throws IOException {115boolean isDTLS = tc.sslContext.isDTLS();116117// version118Record.getInt16(m);119120new RandomCookie(m);121122// session ID123Record.getBytes8(m);124125// DTLS cookie126if (isDTLS) {127Record.getBytes8(m);128}129130// cipher suite IDs131Record.getBytes16(m);132// compression method133Record.getBytes8(m);134// read extensions, if present135if (m.remaining() >= 2) {136int remaining = Record.getInt16(m);137while (remaining > 0) {138int id = Record.getInt16(m);139int extLen = Record.getInt16(m);140remaining -= extLen + 4;141142if (id == SSLExtension.CH_PRE_SHARED_KEY.id) {143// ensure pre_shared_key is the last extension144if (remaining > 0) {145throw tc.fatal(Alert.ILLEGAL_PARAMETER,146"pre_shared_key extension is not last");147}148// read only up to the IDs149Record.getBytes16(m);150return;151} else {152m.position(m.position() + extLen);153154}155}156} // Otherwise, ignore the remaining bytes.157}158159ClientHelloMessage(HandshakeContext handshakeContext, ByteBuffer m,160SSLExtension[] supportedExtensions) throws IOException {161super(handshakeContext);162this.isDTLS = handshakeContext.sslContext.isDTLS();163164this.clientVersion = ((m.get() & 0xFF) << 8) | (m.get() & 0xFF);165this.clientRandom = new RandomCookie(m);166this.sessionId = new SessionId(Record.getBytes8(m));167try {168sessionId.checkLength(clientVersion);169} catch (SSLProtocolException ex) {170throw handshakeContext.conContext.fatal(171Alert.ILLEGAL_PARAMETER, ex);172}173if (isDTLS) {174this.cookie = Record.getBytes8(m);175} else {176this.cookie = null;177}178179byte[] encodedIds = Record.getBytes16(m);180if (encodedIds.length == 0 || (encodedIds.length & 0x01) != 0) {181throw handshakeContext.conContext.fatal(182Alert.ILLEGAL_PARAMETER,183"Invalid ClientHello message");184}185186this.cipherSuiteIds = new int[encodedIds.length >> 1];187for (int i = 0, j = 0; i < encodedIds.length; i++, j++) {188cipherSuiteIds[j] =189((encodedIds[i++] & 0xFF) << 8) | (encodedIds[i] & 0xFF);190}191this.cipherSuites = getCipherSuites(cipherSuiteIds);192193this.compressionMethod = Record.getBytes8(m);194// In TLS 1.3, use of certain extensions is mandatory.195if (m.hasRemaining()) {196this.extensions =197new SSLExtensions(this, m, supportedExtensions);198} else {199this.extensions = new SSLExtensions(this);200}201}202203void setHelloCookie(byte[] cookie) {204this.cookie = cookie;205}206207// DTLS 1.0/1.2, for cookie generation.208byte[] getHelloCookieBytes() {209HandshakeOutStream hos = new HandshakeOutStream(null);210try {211// copied from send() method212hos.putInt8((byte)((clientVersion >>> 8) & 0xFF));213hos.putInt8((byte)(clientVersion & 0xFF));214hos.write(clientRandom.randomBytes, 0, 32);215hos.putBytes8(sessionId.getId());216// ignore cookie217hos.putBytes16(getEncodedCipherSuites());218hos.putBytes8(compressionMethod);219extensions.send(hos); // In TLS 1.3, use of certain220// extensions is mandatory.221} catch (IOException ioe) {222// unlikely223}224225return hos.toByteArray();226}227228// (D)TLS 1.3, for cookie generation.229byte[] getHeaderBytes() {230HandshakeOutStream hos = new HandshakeOutStream(null);231try {232// copied from send() method233hos.putInt8((byte)((clientVersion >>> 8) & 0xFF));234hos.putInt8((byte)(clientVersion & 0xFF));235hos.write(clientRandom.randomBytes, 0, 32);236hos.putBytes8(sessionId.getId());237hos.putBytes16(getEncodedCipherSuites());238hos.putBytes8(compressionMethod);239} catch (IOException ioe) {240// unlikely241}242243return hos.toByteArray();244}245246private static int[] getCipherSuiteIds(247List<CipherSuite> cipherSuites) {248if (cipherSuites != null) {249int[] ids = new int[cipherSuites.size()];250int i = 0;251for (CipherSuite cipherSuite : cipherSuites) {252ids[i++] = cipherSuite.id;253}254255return ids;256}257258return new int[0];259}260261private static List<CipherSuite> getCipherSuites(int[] ids) {262List<CipherSuite> cipherSuites = new LinkedList<>();263for (int id : ids) {264CipherSuite cipherSuite = CipherSuite.valueOf(id);265if (cipherSuite != null) {266cipherSuites.add(cipherSuite);267}268}269270return Collections.unmodifiableList(cipherSuites);271}272273private List<String> getCipherSuiteNames() {274List<String> names = new LinkedList<>();275for (int id : cipherSuiteIds) {276names.add(CipherSuite.nameOf(id) +277"(" + Utilities.byte16HexString(id) + ")"); }278279return names;280}281282private byte[] getEncodedCipherSuites() {283byte[] encoded = new byte[cipherSuiteIds.length << 1];284int i = 0;285for (int id : cipherSuiteIds) {286encoded[i++] = (byte)(id >> 8);287encoded[i++] = (byte)id;288}289return encoded;290}291292@Override293public SSLHandshake handshakeType() {294return SSLHandshake.CLIENT_HELLO;295}296297@Override298public int messageLength() {299/*300* Add fixed size parts of each field...301* version + random + session + cipher + compress302*/303return (2 + 32 + 1 + 2 + 1304+ sessionId.length() /* ... + variable parts */305+ (isDTLS ? (1 + cookie.length) : 0)306+ (cipherSuiteIds.length * 2)307+ compressionMethod.length)308+ extensions.length(); // In TLS 1.3, use of certain309// extensions is mandatory.310}311312@Override313public void send(HandshakeOutStream hos) throws IOException {314sendCore(hos);315extensions.send(hos); // In TLS 1.3, use of certain316// extensions is mandatory.317}318319void sendCore(HandshakeOutStream hos) throws IOException {320hos.putInt8((byte) (clientVersion >>> 8));321hos.putInt8((byte) clientVersion);322hos.write(clientRandom.randomBytes, 0, 32);323hos.putBytes8(sessionId.getId());324if (isDTLS) {325hos.putBytes8(cookie);326}327hos.putBytes16(getEncodedCipherSuites());328hos.putBytes8(compressionMethod);329}330331@Override332public String toString() {333if (isDTLS) {334MessageFormat messageFormat = new MessageFormat(335"\"ClientHello\": '{'\n" +336" \"client version\" : \"{0}\",\n" +337" \"random\" : \"{1}\",\n" +338" \"session id\" : \"{2}\",\n" +339" \"cookie\" : \"{3}\",\n" +340" \"cipher suites\" : \"{4}\",\n" +341" \"compression methods\" : \"{5}\",\n" +342" \"extensions\" : [\n" +343"{6}\n" +344" ]\n" +345"'}'",346Locale.ENGLISH);347Object[] messageFields = {348ProtocolVersion.nameOf(clientVersion),349Utilities.toHexString(clientRandom.randomBytes),350sessionId.toString(),351Utilities.toHexString(cookie),352getCipherSuiteNames().toString(),353Utilities.toHexString(compressionMethod),354Utilities.indent(Utilities.indent(extensions.toString()))355};356357return messageFormat.format(messageFields);358} else {359MessageFormat messageFormat = new MessageFormat(360"\"ClientHello\": '{'\n" +361" \"client version\" : \"{0}\",\n" +362" \"random\" : \"{1}\",\n" +363" \"session id\" : \"{2}\",\n" +364" \"cipher suites\" : \"{3}\",\n" +365" \"compression methods\" : \"{4}\",\n" +366" \"extensions\" : [\n" +367"{5}\n" +368" ]\n" +369"'}'",370Locale.ENGLISH);371Object[] messageFields = {372ProtocolVersion.nameOf(clientVersion),373Utilities.toHexString(clientRandom.randomBytes),374sessionId.toString(),375getCipherSuiteNames().toString(),376Utilities.toHexString(compressionMethod),377Utilities.indent(Utilities.indent(extensions.toString()))378};379380return messageFormat.format(messageFields);381}382}383}384385/**386* The "ClientHello" handshake message kick start producer.387*/388private static final389class ClientHelloKickstartProducer implements SSLProducer {390// Prevent instantiation of this class.391private ClientHelloKickstartProducer() {392// blank393}394395// Produce kickstart handshake message.396@Override397public byte[] produce(ConnectionContext context) throws IOException {398// The producing happens in client side only.399ClientHandshakeContext chc = (ClientHandshakeContext)context;400401// clean up this producer402chc.handshakeProducers.remove(SSLHandshake.CLIENT_HELLO.id);403404// session ID of the ClientHello message405SessionId sessionId = new SessionId(new byte[0]);406407// a list of cipher suites sent by the client408List<CipherSuite> cipherSuites = chc.activeCipherSuites;409410//411// Try to resume an existing session.412//413SSLSessionContextImpl ssci = (SSLSessionContextImpl)414chc.sslContext.engineGetClientSessionContext();415SSLSessionImpl session = ssci.get(416chc.conContext.transport.getPeerHost(),417chc.conContext.transport.getPeerPort());418if (session != null) {419// If unsafe server certificate change is not allowed, reserve420// current server certificates if the previous handshake is a421// session-resumption abbreviated initial handshake.422if (!ClientHandshakeContext.allowUnsafeServerCertChange &&423session.isSessionResumption()) {424try {425// If existing, peer certificate chain cannot be null.426chc.reservedServerCerts =427(X509Certificate[])session.getPeerCertificates();428} catch (SSLPeerUnverifiedException puve) {429// Maybe not certificate-based, ignore the exception.430}431}432433if (!session.isRejoinable()) {434session = null;435if (SSLLogger.isOn &&436SSLLogger.isOn("ssl,handshake,verbose")) {437SSLLogger.finest(438"Can't resume, the session is not rejoinable");439}440}441}442443CipherSuite sessionSuite = null;444if (session != null) {445sessionSuite = session.getSuite();446if (!chc.isNegotiable(sessionSuite)) {447session = null;448if (SSLLogger.isOn &&449SSLLogger.isOn("ssl,handshake,verbose")) {450SSLLogger.finest(451"Can't resume, unavailable session cipher suite");452}453}454}455456ProtocolVersion sessionVersion = null;457if (session != null) {458sessionVersion = session.getProtocolVersion();459if (!chc.isNegotiable(sessionVersion)) {460session = null;461if (SSLLogger.isOn &&462SSLLogger.isOn("ssl,handshake,verbose")) {463SSLLogger.finest(464"Can't resume, unavailable protocol version");465}466}467}468469if (session != null &&470!sessionVersion.useTLS13PlusSpec() &&471SSLConfiguration.useExtendedMasterSecret) {472473boolean isEmsAvailable = chc.sslConfig.isAvailable(474SSLExtension.CH_EXTENDED_MASTER_SECRET, sessionVersion);475if (isEmsAvailable && !session.useExtendedMasterSecret &&476!SSLConfiguration.allowLegacyResumption) {477// perform full handshake instead478//479// The client SHOULD NOT offer an abbreviated handshake480// to resume a session that does not use an extended481// master secret. Instead, it SHOULD offer a full482// handshake.483session = null;484}485486if ((session != null) &&487!ClientHandshakeContext.allowUnsafeServerCertChange) {488// It is fine to move on with abbreviate handshake if489// endpoint identification is enabled.490String identityAlg = chc.sslConfig.identificationProtocol;491if (identityAlg == null || identityAlg.isEmpty()) {492if (isEmsAvailable) {493if (!session.useExtendedMasterSecret) {494// perform full handshake instead495session = null;496} // Otherwise, use extended master secret.497} else {498// The extended master secret extension does not499// apply to SSL 3.0. Perform a full handshake500// instead.501//502// Note that the useExtendedMasterSecret is503// extended to protect SSL 3.0 connections,504// by discarding abbreviate handshake.505session = null;506}507}508}509}510511// ensure that the endpoint identification algorithm matches the512// one in the session513String identityAlg = chc.sslConfig.identificationProtocol;514if (session != null && identityAlg != null) {515String sessionIdentityAlg =516session.getIdentificationProtocol();517if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) {518if (SSLLogger.isOn &&519SSLLogger.isOn("ssl,handshake,verbose")) {520SSLLogger.finest("Can't resume, endpoint id" +521" algorithm does not match, requested: " +522identityAlg + ", cached: " + sessionIdentityAlg);523}524session = null;525}526}527528if (session != null) {529if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {530SSLLogger.finest("Try resuming session", session);531}532533// only set session id if session is 1.2 or earlier534if (!session.getProtocolVersion().useTLS13PlusSpec()) {535sessionId = session.getSessionId();536}537538// If no new session is allowed, force use of the previous539// session ciphersuite, and add the renegotiation SCSV if540// necessary.541if (!chc.sslConfig.enableSessionCreation) {542if (!chc.conContext.isNegotiated &&543!sessionVersion.useTLS13PlusSpec() &&544cipherSuites.contains(545CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {546cipherSuites = Arrays.asList(sessionSuite,547CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);548} else { // otherwise, use renegotiation_info extension549cipherSuites = List.of(sessionSuite);550}551552if (SSLLogger.isOn &&553SSLLogger.isOn("ssl,handshake,verbose")) {554SSLLogger.finest(555"No new session is allowed, so try to resume " +556"the session cipher suite only", sessionSuite);557}558}559560chc.isResumption = true;561chc.resumingSession = session;562}563564if (session == null) {565if (!chc.sslConfig.enableSessionCreation) {566throw new SSLHandshakeException(567"No new session is allowed and " +568"no existing session can be resumed");569}570571if (chc.maximumActiveProtocol.useTLS13PlusSpec() &&572SSLConfiguration.useCompatibilityMode) {573// In compatibility mode, the TLS 1.3 legacy_session_id574// field MUST be non-empty, so a client not offering a575// pre-TLS 1.3 session MUST generate a new 32-byte value.576sessionId =577new SessionId(true, chc.sslContext.getSecureRandom());578}579}580581ProtocolVersion minimumVersion = ProtocolVersion.NONE;582for (ProtocolVersion pv : chc.activeProtocols) {583if (minimumVersion == ProtocolVersion.NONE ||584pv.compare(minimumVersion) < 0) {585minimumVersion = pv;586}587}588589// exclude SCSV for secure renegotiation590if (!minimumVersion.useTLS13PlusSpec()) {591if (chc.conContext.secureRenegotiation &&592cipherSuites.contains(593CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {594// The cipherSuites may be unmodifiable595cipherSuites = new LinkedList<>(cipherSuites);596cipherSuites.remove(597CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);598}599}600601// make sure there is a negotiable cipher suite.602boolean negotiable = false;603for (CipherSuite suite : cipherSuites) {604if (chc.isNegotiable(suite)) {605negotiable = true;606break;607}608}609if (!negotiable) {610throw new SSLHandshakeException("No negotiable cipher suite");611}612613// Create the handshake message.614ProtocolVersion clientHelloVersion = chc.maximumActiveProtocol;615if (clientHelloVersion.useTLS13PlusSpec()) {616// In (D)TLS 1.3, the client indicates its version preferences617// in the "supported_versions" extension and the client_version618// (legacy_version) field MUST be set to (D)TLS 1.2.619if (clientHelloVersion.isDTLS) {620clientHelloVersion = ProtocolVersion.DTLS12;621} else {622clientHelloVersion = ProtocolVersion.TLS12;623}624}625626ClientHelloMessage chm = new ClientHelloMessage(chc,627clientHelloVersion.id, sessionId, cipherSuites,628chc.sslContext.getSecureRandom());629630// cache the client random number for further using631chc.clientHelloRandom = chm.clientRandom;632chc.clientHelloVersion = clientHelloVersion.id;633634// Produce extensions for ClientHello handshake message.635SSLExtension[] extTypes = chc.sslConfig.getEnabledExtensions(636SSLHandshake.CLIENT_HELLO, chc.activeProtocols);637chm.extensions.produce(chc, extTypes);638639if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {640SSLLogger.fine("Produced ClientHello handshake message", chm);641}642643// Output the handshake message.644chm.write(chc.handshakeOutput);645chc.handshakeOutput.flush();646647// Reserve the initial ClientHello message for the follow on648// cookie exchange if needed.649chc.initialClientHelloMsg = chm;650651// What's the expected response?652chc.handshakeConsumers.put(653SSLHandshake.SERVER_HELLO.id, SSLHandshake.SERVER_HELLO);654if (chc.sslContext.isDTLS() &&655!minimumVersion.useTLS13PlusSpec()) {656chc.handshakeConsumers.put(657SSLHandshake.HELLO_VERIFY_REQUEST.id,658SSLHandshake.HELLO_VERIFY_REQUEST);659}660661// The handshake message has been delivered.662return null;663}664}665666private static final667class ClientHelloProducer implements HandshakeProducer {668// Prevent instantiation of this class.669private ClientHelloProducer() {670// blank671}672673// Response to one of the following handshake message:674// HelloRequest (SSL 3.0/TLS 1.0/1.1/1.2)675// ServerHello(HelloRetryRequest) (TLS 1.3)676// HelloVerifyRequest (DTLS 1.0/1.2)677@Override678public byte[] produce(ConnectionContext context,679HandshakeMessage message) throws IOException {680// The producing happens in client side only.681ClientHandshakeContext chc = (ClientHandshakeContext)context;682683SSLHandshake ht = message.handshakeType();684if (ht == null) {685throw new UnsupportedOperationException("Not supported yet.");686}687688switch (ht) {689case HELLO_REQUEST:690// SSL 3.0/TLS 1.0/1.1/1.2691try {692chc.kickstart();693} catch (IOException ioe) {694throw chc.conContext.fatal(695Alert.HANDSHAKE_FAILURE, ioe);696}697698// The handshake message has been delivered.699return null;700case HELLO_VERIFY_REQUEST:701// DTLS 1.0/1.2702//703// The HelloVerifyRequest consumer should have updated the704// ClientHello handshake message with cookie.705if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {706SSLLogger.fine(707"Produced ClientHello(cookie) handshake message",708chc.initialClientHelloMsg);709}710711// Output the handshake message.712chc.initialClientHelloMsg.write(chc.handshakeOutput);713chc.handshakeOutput.flush();714715// What's the expected response?716chc.handshakeConsumers.put(SSLHandshake.SERVER_HELLO.id,717SSLHandshake.SERVER_HELLO);718719ProtocolVersion minimumVersion = ProtocolVersion.NONE;720for (ProtocolVersion pv : chc.activeProtocols) {721if (minimumVersion == ProtocolVersion.NONE ||722pv.compare(minimumVersion) < 0) {723minimumVersion = pv;724}725}726if (chc.sslContext.isDTLS() &&727!minimumVersion.useTLS13PlusSpec()) {728chc.handshakeConsumers.put(729SSLHandshake.HELLO_VERIFY_REQUEST.id,730SSLHandshake.HELLO_VERIFY_REQUEST);731}732733// The handshake message has been delivered.734return null;735case HELLO_RETRY_REQUEST:736// TLS 1.3737// The HelloRetryRequest consumer should have updated the738// ClientHello handshake message with cookie.739if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {740SSLLogger.fine(741"Produced ClientHello(HRR) handshake message",742chc.initialClientHelloMsg);743}744745// Output the handshake message.746chc.initialClientHelloMsg.write(chc.handshakeOutput);747chc.handshakeOutput.flush();748749// What's the expected response?750chc.conContext.consumers.putIfAbsent(751ContentType.CHANGE_CIPHER_SPEC.id,752ChangeCipherSpec.t13Consumer);753chc.handshakeConsumers.put(SSLHandshake.SERVER_HELLO.id,754SSLHandshake.SERVER_HELLO);755756// The handshake message has been delivered.757return null;758default:759throw new UnsupportedOperationException(760"Not supported yet.");761}762}763}764765/**766* The "ClientHello" handshake message consumer.767*/768private static final class ClientHelloConsumer implements SSLConsumer {769// Prevent instantiation of this class.770private ClientHelloConsumer() {771// blank772}773774@Override775public void consume(ConnectionContext context,776ByteBuffer message) throws IOException {777// The consuming happens in server side only.778ServerHandshakeContext shc = (ServerHandshakeContext)context;779780// clean up this consumer781shc.handshakeConsumers.remove(SSLHandshake.CLIENT_HELLO.id);782if (!shc.handshakeConsumers.isEmpty()) {783throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,784"No more handshake message allowed " +785"in a ClientHello flight");786}787788// Get enabled extension types in ClientHello handshake message.789SSLExtension[] enabledExtensions =790shc.sslConfig.getEnabledExtensions(791SSLHandshake.CLIENT_HELLO);792793ClientHelloMessage chm =794new ClientHelloMessage(shc, message, enabledExtensions);795if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {796SSLLogger.fine("Consuming ClientHello handshake message", chm);797}798799shc.clientHelloVersion = chm.clientVersion;800onClientHello(shc, chm);801}802803private void onClientHello(ServerHandshakeContext context,804ClientHelloMessage clientHello) throws IOException {805// Negotiate protocol version.806//807// Check and launch SupportedVersions.808SSLExtension[] extTypes = new SSLExtension[] {809SSLExtension.CH_SUPPORTED_VERSIONS810};811clientHello.extensions.consumeOnLoad(context, extTypes);812813ProtocolVersion negotiatedProtocol;814CHSupportedVersionsSpec svs =815(CHSupportedVersionsSpec)context.handshakeExtensions.get(816SSLExtension.CH_SUPPORTED_VERSIONS);817if (svs != null) {818negotiatedProtocol =819negotiateProtocol(context, svs.requestedProtocols);820} else {821negotiatedProtocol =822negotiateProtocol(context, clientHello.clientVersion);823}824context.negotiatedProtocol = negotiatedProtocol;825if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {826SSLLogger.fine(827"Negotiated protocol version: " + negotiatedProtocol.name);828}829830// Consume the handshake message for the specific protocol version.831if (negotiatedProtocol.isDTLS) {832if (negotiatedProtocol.useTLS13PlusSpec()) {833d13HandshakeConsumer.consume(context, clientHello);834} else {835d12HandshakeConsumer.consume(context, clientHello);836}837} else {838if (negotiatedProtocol.useTLS13PlusSpec()) {839t13HandshakeConsumer.consume(context, clientHello);840} else {841t12HandshakeConsumer.consume(context, clientHello);842}843}844}845846// Select a protocol version according to the847// ClientHello.client_version.848private ProtocolVersion negotiateProtocol(849ServerHandshakeContext context,850int clientHelloVersion) throws SSLException {851852// Per TLS 1.3 specification, server MUST negotiate TLS 1.2 or prior853// even if ClientHello.client_version is 0x0304 or later.854int chv = clientHelloVersion;855if (context.sslContext.isDTLS()) {856if (chv < ProtocolVersion.DTLS12.id) {857chv = ProtocolVersion.DTLS12.id;858}859} else {860if (chv > ProtocolVersion.TLS12.id) {861chv = ProtocolVersion.TLS12.id;862}863}864865// Select a protocol version from the activated protocols.866ProtocolVersion pv = ProtocolVersion.selectedFrom(867context.activeProtocols, chv);868if (pv == null || pv == ProtocolVersion.NONE ||869pv == ProtocolVersion.SSL20Hello) {870throw context.conContext.fatal(Alert.PROTOCOL_VERSION,871"Client requested protocol " +872ProtocolVersion.nameOf(clientHelloVersion) +873" is not enabled or supported in server context");874}875876return pv;877}878879// Select a protocol version according to the880// supported_versions extension.881private ProtocolVersion negotiateProtocol(882ServerHandshakeContext context,883int[] clientSupportedVersions) throws SSLException {884885// The client supported protocol versions are present in client886// preference order. This implementation chooses to use the server887// preference of protocol versions instead.888for (ProtocolVersion spv : context.activeProtocols) {889if (spv == ProtocolVersion.SSL20Hello) {890continue;891}892for (int cpv : clientSupportedVersions) {893if (cpv == ProtocolVersion.SSL20Hello.id) {894continue;895}896if (spv.id == cpv) {897return spv;898}899}900}901902// No protocol version can be negotiated.903throw context.conContext.fatal(Alert.PROTOCOL_VERSION,904"The client supported protocol versions " + Arrays.toString(905ProtocolVersion.toStringArray(clientSupportedVersions)) +906" are not accepted by server preferences " +907context.activeProtocols);908}909}910911/**912* The "ClientHello" handshake message consumer for TLS 1.2 and913* prior SSL/TLS protocol versions.914*/915private static final916class T12ClientHelloConsumer implements HandshakeConsumer {917// Prevent instantiation of this class.918private T12ClientHelloConsumer() {919// blank920}921922@Override923public void consume(ConnectionContext context,924HandshakeMessage message) throws IOException {925// The consuming happens in server side only.926ServerHandshakeContext shc = (ServerHandshakeContext)context;927ClientHelloMessage clientHello = (ClientHelloMessage)message;928929//930// validate931//932933// Reject client initiated renegotiation?934//935// If server side should reject client-initiated renegotiation,936// send an Alert.HANDSHAKE_FAILURE fatal alert, not a937// no_renegotiation warning alert (no_renegotiation must be a938// warning: RFC 2246). no_renegotiation might seem more939// natural at first, but warnings are not appropriate because940// the sending party does not know how the receiving party941// will behave. This state must be treated as a fatal server942// condition.943//944// This will not have any impact on server initiated renegotiation.945if (shc.conContext.isNegotiated) {946if (!shc.conContext.secureRenegotiation &&947!HandshakeContext.allowUnsafeRenegotiation) {948throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,949"Unsafe renegotiation is not allowed");950}951952if (ServerHandshakeContext.rejectClientInitiatedRenego &&953!shc.kickstartMessageDelivered) {954throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,955"Client initiated renegotiation is not allowed");956}957}958959// Consume a Session Ticket Extension if it exists960SSLExtension[] ext = new SSLExtension[]{961SSLExtension.CH_SESSION_TICKET962};963clientHello.extensions.consumeOnLoad(shc, ext);964965// Does the client want to resume a session?966if (clientHello.sessionId.length() != 0 || shc.statelessResumption) {967SSLSessionContextImpl cache = (SSLSessionContextImpl)shc.sslContext968.engineGetServerSessionContext();969970SSLSessionImpl previous;971// Use the stateless session ticket if provided972if (shc.statelessResumption) {973previous = shc.resumingSession;974} else {975previous = cache.get(clientHello.sessionId.getId());976}977978boolean resumingSession =979(previous != null) && previous.isRejoinable();980if (!resumingSession) {981if (SSLLogger.isOn &&982SSLLogger.isOn("ssl,handshake,verbose")) {983SSLLogger.finest(984"Can't resume, " +985"the existing session is not rejoinable");986}987}988// Validate the negotiated protocol version.989if (resumingSession) {990ProtocolVersion sessionProtocol =991previous.getProtocolVersion();992if (sessionProtocol != shc.negotiatedProtocol) {993resumingSession = false;994if (SSLLogger.isOn &&995SSLLogger.isOn("ssl,handshake,verbose")) {996SSLLogger.finest(997"Can't resume, not the same protocol version");998}999}1000}10011002// Validate the required client authentication.1003if (resumingSession &&1004(shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED)) {1005try {1006previous.getPeerPrincipal();1007} catch (SSLPeerUnverifiedException e) {1008resumingSession = false;1009if (SSLLogger.isOn &&1010SSLLogger.isOn("ssl,handshake,verbose")) {1011SSLLogger.finest(1012"Can't resume, " +1013"client authentication is required");1014}1015}1016}10171018// Validate that the cached cipher suite.1019if (resumingSession) {1020CipherSuite suite = previous.getSuite();1021if ((!shc.isNegotiable(suite)) ||1022(!clientHello.cipherSuites.contains(suite))) {1023resumingSession = false;1024if (SSLLogger.isOn &&1025SSLLogger.isOn("ssl,handshake,verbose")) {1026SSLLogger.finest(1027"Can't resume, " +1028"the session cipher suite is absent");1029}1030}1031}10321033// ensure that the endpoint identification algorithm matches the1034// one in the session1035String identityAlg = shc.sslConfig.identificationProtocol;1036if (resumingSession && identityAlg != null) {1037String sessionIdentityAlg =1038previous.getIdentificationProtocol();1039if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) {1040if (SSLLogger.isOn &&1041SSLLogger.isOn("ssl,handshake,verbose")) {1042SSLLogger.finest("Can't resume, endpoint id" +1043" algorithm does not match, requested: " +1044identityAlg + ", cached: " + sessionIdentityAlg);1045}1046resumingSession = false;1047}1048}10491050// So far so good. Note that the handshake extensions may reset1051// the resuming options later.1052shc.isResumption = resumingSession;1053shc.resumingSession = resumingSession ? previous : null;10541055if (!resumingSession && SSLLogger.isOn &&1056SSLLogger.isOn("ssl,handshake")) {1057SSLLogger.fine("Session not resumed.");1058}1059}10601061// cache the client random number for further using1062shc.clientHelloRandom = clientHello.clientRandom;10631064// Check and launch ClientHello extensions.1065SSLExtension[] extTypes = shc.sslConfig.getExclusiveExtensions(1066SSLHandshake.CLIENT_HELLO,1067List.of(SSLExtension.CH_SESSION_TICKET));1068clientHello.extensions.consumeOnLoad(shc, extTypes);10691070//1071// update1072//1073if (!shc.conContext.isNegotiated) {1074shc.conContext.protocolVersion = shc.negotiatedProtocol;1075shc.conContext.outputRecord.setVersion(shc.negotiatedProtocol);1076}10771078// update the responders1079//1080// Only need to ServerHello, which may add more responders later.1081// Note that ServerHello and HelloRetryRequest share the same1082// handshake type/id. The ServerHello producer may be replaced1083// by HelloRetryRequest producer if needed.1084shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,1085SSLHandshake.SERVER_HELLO);10861087//1088// produce1089//1090SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {1091SSLHandshake.SERVER_HELLO,10921093// full handshake messages1094SSLHandshake.CERTIFICATE,1095SSLHandshake.CERTIFICATE_STATUS,1096SSLHandshake.SERVER_KEY_EXCHANGE,1097SSLHandshake.CERTIFICATE_REQUEST,1098SSLHandshake.SERVER_HELLO_DONE,10991100// abbreviated handshake messages1101SSLHandshake.FINISHED1102};11031104for (SSLHandshake hs : probableHandshakeMessages) {1105HandshakeProducer handshakeProducer =1106shc.handshakeProducers.remove(hs.id);1107if (handshakeProducer != null) {1108handshakeProducer.produce(context, clientHello);1109}1110}1111}1112}11131114/**1115* The "ClientHello" handshake message consumer for TLS 1.3.1116*/1117private static final1118class T13ClientHelloConsumer implements HandshakeConsumer {1119// Prevent instantiation of this class.1120private T13ClientHelloConsumer() {1121// blank1122}11231124@Override1125public void consume(ConnectionContext context,1126HandshakeMessage message) throws IOException {1127// The consuming happens in server side only.1128ServerHandshakeContext shc = (ServerHandshakeContext)context;1129ClientHelloMessage clientHello = (ClientHelloMessage)message;11301131// [RFC 8446] TLS 1.3 forbids renegotiation. If a server has1132// negotiated TLS 1.3 and receives a ClientHello at any other1133// time, it MUST terminate the connection with an1134// "unexpected_message" alert.1135if (shc.conContext.isNegotiated) {1136throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,1137"Received unexpected renegotiation handshake message");1138}11391140if (clientHello.clientVersion != ProtocolVersion.TLS12.id) {1141throw shc.conContext.fatal(Alert.PROTOCOL_VERSION,1142"The ClientHello.legacy_version field is not TLS 1.2");1143}11441145// The client may send a dummy change_cipher_spec record1146// immediately after the first ClientHello.1147shc.conContext.consumers.putIfAbsent(1148ContentType.CHANGE_CIPHER_SPEC.id,1149ChangeCipherSpec.t13Consumer);11501151// Is it a resumption?1152//1153// Check and launch the "psk_key_exchange_modes" and1154// "pre_shared_key" extensions first, which will reset the1155// resuming session, no matter the extensions present or not.1156shc.isResumption = true;1157SSLExtension[] extTypes = new SSLExtension[] {1158SSLExtension.PSK_KEY_EXCHANGE_MODES,1159SSLExtension.CH_PRE_SHARED_KEY1160};1161clientHello.extensions.consumeOnLoad(shc, extTypes);11621163// Check and launch ClientHello extensions other than1164// "psk_key_exchange_modes", "pre_shared_key", "protocol_version"1165// and "key_share" extensions.1166//1167// These extensions may discard session resumption, or ask for1168// hello retry.1169extTypes = shc.sslConfig.getExclusiveExtensions(1170SSLHandshake.CLIENT_HELLO,1171Arrays.asList(1172SSLExtension.PSK_KEY_EXCHANGE_MODES,1173SSLExtension.CH_PRE_SHARED_KEY,1174SSLExtension.CH_SUPPORTED_VERSIONS));1175clientHello.extensions.consumeOnLoad(shc, extTypes);11761177if (!shc.handshakeProducers.isEmpty()) {1178// Should be HelloRetryRequest producer.1179goHelloRetryRequest(shc, clientHello);1180} else {1181goServerHello(shc, clientHello);1182}1183}11841185private void goHelloRetryRequest(ServerHandshakeContext shc,1186ClientHelloMessage clientHello) throws IOException {1187HandshakeProducer handshakeProducer =1188shc.handshakeProducers.remove(1189SSLHandshake.HELLO_RETRY_REQUEST.id);1190if (handshakeProducer != null) {1191handshakeProducer.produce(shc, clientHello);1192} else {1193// unlikely1194throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,1195"No HelloRetryRequest producer: " + shc.handshakeProducers);1196}11971198if (!shc.handshakeProducers.isEmpty()) {1199// unlikely, but please double check.1200throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,1201"unknown handshake producers: " + shc.handshakeProducers);1202}1203}12041205private void goServerHello(ServerHandshakeContext shc,1206ClientHelloMessage clientHello) throws IOException {1207//1208// validate1209//1210shc.clientHelloRandom = clientHello.clientRandom;12111212//1213// update1214//1215if (!shc.conContext.isNegotiated) {1216shc.conContext.protocolVersion = shc.negotiatedProtocol;1217shc.conContext.outputRecord.setVersion(shc.negotiatedProtocol);1218}12191220// update the responders1221//1222// Only ServerHello/HelloRetryRequest producer, which adds1223// more responders later.1224shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,1225SSLHandshake.SERVER_HELLO);12261227SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {1228SSLHandshake.SERVER_HELLO,12291230// full handshake messages1231SSLHandshake.ENCRYPTED_EXTENSIONS,1232SSLHandshake.CERTIFICATE_REQUEST,1233SSLHandshake.CERTIFICATE,1234SSLHandshake.CERTIFICATE_VERIFY,1235SSLHandshake.FINISHED1236};12371238//1239// produce1240//1241for (SSLHandshake hs : probableHandshakeMessages) {1242HandshakeProducer handshakeProducer =1243shc.handshakeProducers.remove(hs.id);1244if (handshakeProducer != null) {1245handshakeProducer.produce(shc, clientHello);1246}1247}1248}1249}12501251/**1252* The "ClientHello" handshake message consumer for DTLS 1.2 and1253* previous DTLS protocol versions.1254*/1255private static final1256class D12ClientHelloConsumer implements HandshakeConsumer {1257// Prevent instantiation of this class.1258private D12ClientHelloConsumer() {1259// blank1260}12611262@Override1263public void consume(ConnectionContext context,1264HandshakeMessage message) throws IOException {1265// The consuming happens in server side only.1266ServerHandshakeContext shc = (ServerHandshakeContext)context;1267ClientHelloMessage clientHello = (ClientHelloMessage)message;12681269//1270// validate1271//12721273// Reject client initiated renegotiation?1274//1275// If server side should reject client-initiated renegotiation,1276// send an Alert.HANDSHAKE_FAILURE fatal alert, not a1277// no_renegotiation warning alert (no_renegotiation must be a1278// warning: RFC 2246). no_renegotiation might seem more1279// natural at first, but warnings are not appropriate because1280// the sending party does not know how the receiving party1281// will behave. This state must be treated as a fatal server1282// condition.1283//1284// This will not have any impact on server initiated renegotiation.1285if (shc.conContext.isNegotiated) {1286if (!shc.conContext.secureRenegotiation &&1287!HandshakeContext.allowUnsafeRenegotiation) {1288throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,1289"Unsafe renegotiation is not allowed");1290}12911292if (ServerHandshakeContext.rejectClientInitiatedRenego &&1293!shc.kickstartMessageDelivered) {1294throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,1295"Client initiated renegotiation is not allowed");1296}1297}129812991300// Does the client want to resume a session?1301if (clientHello.sessionId.length() != 0) {1302SSLSessionContextImpl cache = (SSLSessionContextImpl)shc.sslContext1303.engineGetServerSessionContext();13041305// Consume a Session Ticket Extension if it exists1306SSLExtension[] ext = new SSLExtension[]{1307SSLExtension.CH_SESSION_TICKET1308};1309clientHello.extensions.consumeOnLoad(shc, ext);13101311SSLSessionImpl previous;1312// Use stateless session ticket if provided.1313if (shc.statelessResumption) {1314previous = shc.resumingSession;1315} else {1316previous = cache.get(clientHello.sessionId.getId());1317}13181319boolean resumingSession =1320(previous != null) && previous.isRejoinable();1321if (!resumingSession) {1322if (SSLLogger.isOn &&1323SSLLogger.isOn("ssl,handshake,verbose")) {1324SSLLogger.finest(1325"Can't resume, " +1326"the existing session is not rejoinable");1327}1328}1329// Validate the negotiated protocol version.1330if (resumingSession) {1331ProtocolVersion sessionProtocol =1332previous.getProtocolVersion();1333if (sessionProtocol != shc.negotiatedProtocol) {1334resumingSession = false;1335if (SSLLogger.isOn &&1336SSLLogger.isOn("ssl,handshake,verbose")) {1337SSLLogger.finest(1338"Can't resume, not the same protocol version");1339}1340}1341}13421343// Validate the required client authentication.1344if (resumingSession &&1345(shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED)) {13461347try {1348previous.getPeerPrincipal();1349} catch (SSLPeerUnverifiedException e) {1350resumingSession = false;1351if (SSLLogger.isOn &&1352SSLLogger.isOn("ssl,handshake,verbose")) {1353SSLLogger.finest(1354"Can't resume, " +1355"client authentication is required");1356}1357}1358}13591360// Validate that the cached cipher suite.1361if (resumingSession) {1362CipherSuite suite = previous.getSuite();1363if ((!shc.isNegotiable(suite)) ||1364(!clientHello.cipherSuites.contains(suite))) {1365resumingSession = false;1366if (SSLLogger.isOn &&1367SSLLogger.isOn("ssl,handshake,verbose")) {1368SSLLogger.finest(1369"Can't resume, " +1370"the session cipher suite is absent");1371}1372}1373}13741375// So far so good. Note that the handshake extensions may reset1376// the resuming options later.1377shc.isResumption = resumingSession;1378shc.resumingSession = resumingSession ? previous : null;1379}13801381HelloCookieManager hcm =1382shc.sslContext.getHelloCookieManager(ProtocolVersion.DTLS10);1383if (!shc.isResumption &&1384!hcm.isCookieValid(shc, clientHello, clientHello.cookie)) {1385//1386// Perform cookie exchange for DTLS handshaking if no cookie1387// or the cookie is invalid in the ClientHello message.1388//1389// update the responders1390shc.handshakeProducers.put(1391SSLHandshake.HELLO_VERIFY_REQUEST.id,1392SSLHandshake.HELLO_VERIFY_REQUEST);13931394//1395// produce response handshake message1396//1397SSLHandshake.HELLO_VERIFY_REQUEST.produce(context, clientHello);13981399return;1400}14011402// cache the client random number for further using1403shc.clientHelloRandom = clientHello.clientRandom;14041405// Check and launch ClientHello extensions.1406SSLExtension[] extTypes = shc.sslConfig.getEnabledExtensions(1407SSLHandshake.CLIENT_HELLO);1408clientHello.extensions.consumeOnLoad(shc, extTypes);14091410//1411// update1412//1413if (!shc.conContext.isNegotiated) {1414shc.conContext.protocolVersion = shc.negotiatedProtocol;1415shc.conContext.outputRecord.setVersion(shc.negotiatedProtocol);1416}14171418// update the responders1419//1420// Only need to ServerHello, which may add more responders later.1421shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,1422SSLHandshake.SERVER_HELLO);14231424//1425// produce1426//1427SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {1428SSLHandshake.SERVER_HELLO,14291430// full handshake messages1431SSLHandshake.CERTIFICATE,1432SSLHandshake.CERTIFICATE_STATUS,1433SSLHandshake.SERVER_KEY_EXCHANGE,1434SSLHandshake.CERTIFICATE_REQUEST,1435SSLHandshake.SERVER_HELLO_DONE,14361437// abbreviated handshake messages1438SSLHandshake.FINISHED1439};14401441for (SSLHandshake hs : probableHandshakeMessages) {1442HandshakeProducer handshakeProducer =1443shc.handshakeProducers.remove(hs.id);1444if (handshakeProducer != null) {1445handshakeProducer.produce(context, clientHello);1446}1447}1448}1449}14501451/**1452* The "ClientHello" handshake message consumer for DTLS 1.3.1453*/1454private static final1455class D13ClientHelloConsumer implements HandshakeConsumer {1456// Prevent instantiation of this class.1457private D13ClientHelloConsumer() {1458// blank1459}14601461@Override1462public void consume(ConnectionContext context,1463HandshakeMessage message) throws IOException {1464throw new UnsupportedOperationException("Not supported yet.");1465}1466}1467}146814691470