Path: blob/master/src/java.base/share/classes/sun/security/ssl/ClientHello.java
41159 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// the max protocol version this client is supporting.405ProtocolVersion maxProtocolVersion = chc.maximumActiveProtocol;406407// session ID of the ClientHello message408SessionId sessionId = new SessionId(new byte[0]);409410// a list of cipher suites sent by the client411List<CipherSuite> cipherSuites = chc.activeCipherSuites;412413//414// Try to resume an existing session.415//416SSLSessionContextImpl ssci = (SSLSessionContextImpl)417chc.sslContext.engineGetClientSessionContext();418SSLSessionImpl session = ssci.get(419chc.conContext.transport.getPeerHost(),420chc.conContext.transport.getPeerPort());421if (session != null) {422// If unsafe server certificate change is not allowed, reserve423// current server certificates if the previous handshake is a424// session-resumption abbreviated initial handshake.425if (!ClientHandshakeContext.allowUnsafeServerCertChange &&426session.isSessionResumption()) {427try {428// If existing, peer certificate chain cannot be null.429chc.reservedServerCerts =430(X509Certificate[])session.getPeerCertificates();431} catch (SSLPeerUnverifiedException puve) {432// Maybe not certificate-based, ignore the exception.433}434}435436if (!session.isRejoinable()) {437session = null;438if (SSLLogger.isOn &&439SSLLogger.isOn("ssl,handshake,verbose")) {440SSLLogger.finest(441"Can't resume, the session is not rejoinable");442}443}444}445446CipherSuite sessionSuite = null;447if (session != null) {448sessionSuite = session.getSuite();449if (!chc.isNegotiable(sessionSuite)) {450session = null;451if (SSLLogger.isOn &&452SSLLogger.isOn("ssl,handshake,verbose")) {453SSLLogger.finest(454"Can't resume, unavailable session cipher suite");455}456}457}458459ProtocolVersion sessionVersion = null;460if (session != null) {461sessionVersion = session.getProtocolVersion();462if (!chc.isNegotiable(sessionVersion)) {463session = null;464if (SSLLogger.isOn &&465SSLLogger.isOn("ssl,handshake,verbose")) {466SSLLogger.finest(467"Can't resume, unavailable protocol version");468}469}470}471472if (session != null &&473!sessionVersion.useTLS13PlusSpec() &&474SSLConfiguration.useExtendedMasterSecret) {475476boolean isEmsAvailable = chc.sslConfig.isAvailable(477SSLExtension.CH_EXTENDED_MASTER_SECRET, sessionVersion);478if (isEmsAvailable && !session.useExtendedMasterSecret &&479!SSLConfiguration.allowLegacyResumption) {480// perform full handshake instead481//482// The client SHOULD NOT offer an abbreviated handshake483// to resume a session that does not use an extended484// master secret. Instead, it SHOULD offer a full485// handshake.486session = null;487}488489if ((session != null) &&490!ClientHandshakeContext.allowUnsafeServerCertChange) {491// It is fine to move on with abbreviate handshake if492// endpoint identification is enabled.493String identityAlg = chc.sslConfig.identificationProtocol;494if (identityAlg == null || identityAlg.isEmpty()) {495if (isEmsAvailable) {496if (!session.useExtendedMasterSecret) {497// perform full handshake instead498session = null;499} // Otherwise, use extended master secret.500} else {501// The extended master secret extension does not502// apply to SSL 3.0. Perform a full handshake503// instead.504//505// Note that the useExtendedMasterSecret is506// extended to protect SSL 3.0 connections,507// by discarding abbreviate handshake.508session = null;509}510}511}512}513514// ensure that the endpoint identification algorithm matches the515// one in the session516String identityAlg = chc.sslConfig.identificationProtocol;517if (session != null && identityAlg != null) {518String sessionIdentityAlg =519session.getIdentificationProtocol();520if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) {521if (SSLLogger.isOn &&522SSLLogger.isOn("ssl,handshake,verbose")) {523SSLLogger.finest("Can't resume, endpoint id" +524" algorithm does not match, requested: " +525identityAlg + ", cached: " + sessionIdentityAlg);526}527session = null;528}529}530531if (session != null) {532if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {533SSLLogger.finest("Try resuming session", session);534}535536// only set session id if session is 1.2 or earlier537if (!session.getProtocolVersion().useTLS13PlusSpec()) {538sessionId = session.getSessionId();539}540if (!maxProtocolVersion.equals(sessionVersion)) {541maxProtocolVersion = sessionVersion;542543// Update protocol version number in underlying socket and544// handshake output stream, so that the output records545// (at the record layer) have the correct version546chc.setVersion(sessionVersion);547}548549// If no new session is allowed, force use of the previous550// session ciphersuite, and add the renegotiation SCSV if551// necessary.552if (!chc.sslConfig.enableSessionCreation) {553if (!chc.conContext.isNegotiated &&554!sessionVersion.useTLS13PlusSpec() &&555cipherSuites.contains(556CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {557cipherSuites = Arrays.asList(sessionSuite,558CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);559} else { // otherwise, use renegotiation_info extension560cipherSuites = List.of(sessionSuite);561}562563if (SSLLogger.isOn &&564SSLLogger.isOn("ssl,handshake,verbose")) {565SSLLogger.finest(566"No new session is allowed, so try to resume " +567"the session cipher suite only", sessionSuite);568}569}570571chc.isResumption = true;572chc.resumingSession = session;573}574575if (session == null) {576if (!chc.sslConfig.enableSessionCreation) {577throw new SSLHandshakeException(578"No new session is allowed and " +579"no existing session can be resumed");580}581582if (maxProtocolVersion.useTLS13PlusSpec() &&583SSLConfiguration.useCompatibilityMode) {584// In compatibility mode, the TLS 1.3 legacy_session_id585// field MUST be non-empty, so a client not offering a586// pre-TLS 1.3 session MUST generate a new 32-byte value.587sessionId =588new SessionId(true, chc.sslContext.getSecureRandom());589}590}591592ProtocolVersion minimumVersion = ProtocolVersion.NONE;593for (ProtocolVersion pv : chc.activeProtocols) {594if (minimumVersion == ProtocolVersion.NONE ||595pv.compare(minimumVersion) < 0) {596minimumVersion = pv;597}598}599600// exclude SCSV for secure renegotiation601if (!minimumVersion.useTLS13PlusSpec()) {602if (chc.conContext.secureRenegotiation &&603cipherSuites.contains(604CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {605// The cipherSuites may be unmodifiable606cipherSuites = new LinkedList<>(cipherSuites);607cipherSuites.remove(608CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);609}610}611612// make sure there is a negotiable cipher suite.613boolean negotiable = false;614for (CipherSuite suite : cipherSuites) {615if (chc.isNegotiable(suite)) {616negotiable = true;617break;618}619}620if (!negotiable) {621throw new SSLHandshakeException("No negotiable cipher suite");622}623624// Create the handshake message.625ProtocolVersion clientHelloVersion = maxProtocolVersion;626if (clientHelloVersion.useTLS13PlusSpec()) {627// In (D)TLS 1.3, the client indicates its version preferences628// in the "supported_versions" extension and the client_version629// (legacy_version) field MUST be set to (D)TLS 1.2.630if (clientHelloVersion.isDTLS) {631clientHelloVersion = ProtocolVersion.DTLS12;632} else {633clientHelloVersion = ProtocolVersion.TLS12;634}635}636637ClientHelloMessage chm = new ClientHelloMessage(chc,638clientHelloVersion.id, sessionId, cipherSuites,639chc.sslContext.getSecureRandom());640641// cache the client random number for further using642chc.clientHelloRandom = chm.clientRandom;643chc.clientHelloVersion = clientHelloVersion.id;644645// Produce extensions for ClientHello handshake message.646SSLExtension[] extTypes = chc.sslConfig.getEnabledExtensions(647SSLHandshake.CLIENT_HELLO, chc.activeProtocols);648chm.extensions.produce(chc, extTypes);649650if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {651SSLLogger.fine("Produced ClientHello handshake message", chm);652}653654// Output the handshake message.655chm.write(chc.handshakeOutput);656chc.handshakeOutput.flush();657658// Reserve the initial ClientHello message for the follow on659// cookie exchange if needed.660chc.initialClientHelloMsg = chm;661662// What's the expected response?663chc.handshakeConsumers.put(664SSLHandshake.SERVER_HELLO.id, SSLHandshake.SERVER_HELLO);665if (chc.sslContext.isDTLS() &&666!minimumVersion.useTLS13PlusSpec()) {667chc.handshakeConsumers.put(668SSLHandshake.HELLO_VERIFY_REQUEST.id,669SSLHandshake.HELLO_VERIFY_REQUEST);670}671672// The handshake message has been delivered.673return null;674}675}676677private static final678class ClientHelloProducer implements HandshakeProducer {679// Prevent instantiation of this class.680private ClientHelloProducer() {681// blank682}683684// Response to one of the following handshake message:685// HelloRequest (SSL 3.0/TLS 1.0/1.1/1.2)686// ServerHello(HelloRetryRequest) (TLS 1.3)687// HelloVerifyRequest (DTLS 1.0/1.2)688@Override689public byte[] produce(ConnectionContext context,690HandshakeMessage message) throws IOException {691// The producing happens in client side only.692ClientHandshakeContext chc = (ClientHandshakeContext)context;693694SSLHandshake ht = message.handshakeType();695if (ht == null) {696throw new UnsupportedOperationException("Not supported yet.");697}698699switch (ht) {700case HELLO_REQUEST:701// SSL 3.0/TLS 1.0/1.1/1.2702try {703chc.kickstart();704} catch (IOException ioe) {705throw chc.conContext.fatal(706Alert.HANDSHAKE_FAILURE, ioe);707}708709// The handshake message has been delivered.710return null;711case HELLO_VERIFY_REQUEST:712// DTLS 1.0/1.2713//714// The HelloVerifyRequest consumer should have updated the715// ClientHello handshake message with cookie.716if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {717SSLLogger.fine(718"Produced ClientHello(cookie) handshake message",719chc.initialClientHelloMsg);720}721722// Output the handshake message.723chc.initialClientHelloMsg.write(chc.handshakeOutput);724chc.handshakeOutput.flush();725726// What's the expected response?727chc.handshakeConsumers.put(SSLHandshake.SERVER_HELLO.id,728SSLHandshake.SERVER_HELLO);729730ProtocolVersion minimumVersion = ProtocolVersion.NONE;731for (ProtocolVersion pv : chc.activeProtocols) {732if (minimumVersion == ProtocolVersion.NONE ||733pv.compare(minimumVersion) < 0) {734minimumVersion = pv;735}736}737if (chc.sslContext.isDTLS() &&738!minimumVersion.useTLS13PlusSpec()) {739chc.handshakeConsumers.put(740SSLHandshake.HELLO_VERIFY_REQUEST.id,741SSLHandshake.HELLO_VERIFY_REQUEST);742}743744// The handshake message has been delivered.745return null;746case HELLO_RETRY_REQUEST:747// TLS 1.3748// The HelloRetryRequest consumer should have updated the749// ClientHello handshake message with cookie.750if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {751SSLLogger.fine(752"Produced ClientHello(HRR) handshake message",753chc.initialClientHelloMsg);754}755756// Output the handshake message.757chc.initialClientHelloMsg.write(chc.handshakeOutput);758chc.handshakeOutput.flush();759760// What's the expected response?761chc.conContext.consumers.putIfAbsent(762ContentType.CHANGE_CIPHER_SPEC.id,763ChangeCipherSpec.t13Consumer);764chc.handshakeConsumers.put(SSLHandshake.SERVER_HELLO.id,765SSLHandshake.SERVER_HELLO);766767// The handshake message has been delivered.768return null;769default:770throw new UnsupportedOperationException(771"Not supported yet.");772}773}774}775776/**777* The "ClientHello" handshake message consumer.778*/779private static final class ClientHelloConsumer implements SSLConsumer {780// Prevent instantiation of this class.781private ClientHelloConsumer() {782// blank783}784785@Override786public void consume(ConnectionContext context,787ByteBuffer message) throws IOException {788// The consuming happens in server side only.789ServerHandshakeContext shc = (ServerHandshakeContext)context;790791// clean up this consumer792shc.handshakeConsumers.remove(SSLHandshake.CLIENT_HELLO.id);793if (!shc.handshakeConsumers.isEmpty()) {794throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,795"No more handshake message allowed " +796"in a ClientHello flight");797}798799// Get enabled extension types in ClientHello handshake message.800SSLExtension[] enabledExtensions =801shc.sslConfig.getEnabledExtensions(802SSLHandshake.CLIENT_HELLO);803804ClientHelloMessage chm =805new ClientHelloMessage(shc, message, enabledExtensions);806if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {807SSLLogger.fine("Consuming ClientHello handshake message", chm);808}809810shc.clientHelloVersion = chm.clientVersion;811onClientHello(shc, chm);812}813814private void onClientHello(ServerHandshakeContext context,815ClientHelloMessage clientHello) throws IOException {816// Negotiate protocol version.817//818// Check and launch SupportedVersions.819SSLExtension[] extTypes = new SSLExtension[] {820SSLExtension.CH_SUPPORTED_VERSIONS821};822clientHello.extensions.consumeOnLoad(context, extTypes);823824ProtocolVersion negotiatedProtocol;825CHSupportedVersionsSpec svs =826(CHSupportedVersionsSpec)context.handshakeExtensions.get(827SSLExtension.CH_SUPPORTED_VERSIONS);828if (svs != null) {829negotiatedProtocol =830negotiateProtocol(context, svs.requestedProtocols);831} else {832negotiatedProtocol =833negotiateProtocol(context, clientHello.clientVersion);834}835context.negotiatedProtocol = negotiatedProtocol;836if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {837SSLLogger.fine(838"Negotiated protocol version: " + negotiatedProtocol.name);839}840841// Consume the handshake message for the specific protocol version.842if (negotiatedProtocol.isDTLS) {843if (negotiatedProtocol.useTLS13PlusSpec()) {844d13HandshakeConsumer.consume(context, clientHello);845} else {846d12HandshakeConsumer.consume(context, clientHello);847}848} else {849if (negotiatedProtocol.useTLS13PlusSpec()) {850t13HandshakeConsumer.consume(context, clientHello);851} else {852t12HandshakeConsumer.consume(context, clientHello);853}854}855}856857// Select a protocol version according to the858// ClientHello.client_version.859private ProtocolVersion negotiateProtocol(860ServerHandshakeContext context,861int clientHelloVersion) throws SSLException {862863// Per TLS 1.3 specification, server MUST negotiate TLS 1.2 or prior864// even if ClientHello.client_version is 0x0304 or later.865int chv = clientHelloVersion;866if (context.sslContext.isDTLS()) {867if (chv < ProtocolVersion.DTLS12.id) {868chv = ProtocolVersion.DTLS12.id;869}870} else {871if (chv > ProtocolVersion.TLS12.id) {872chv = ProtocolVersion.TLS12.id;873}874}875876// Select a protocol version from the activated protocols.877ProtocolVersion pv = ProtocolVersion.selectedFrom(878context.activeProtocols, chv);879if (pv == null || pv == ProtocolVersion.NONE ||880pv == ProtocolVersion.SSL20Hello) {881throw context.conContext.fatal(Alert.PROTOCOL_VERSION,882"Client requested protocol " +883ProtocolVersion.nameOf(clientHelloVersion) +884" is not enabled or supported in server context");885}886887return pv;888}889890// Select a protocol version according to the891// supported_versions extension.892private ProtocolVersion negotiateProtocol(893ServerHandshakeContext context,894int[] clientSupportedVersions) throws SSLException {895896// The client supported protocol versions are present in client897// preference order. This implementation chooses to use the server898// preference of protocol versions instead.899for (ProtocolVersion spv : context.activeProtocols) {900if (spv == ProtocolVersion.SSL20Hello) {901continue;902}903for (int cpv : clientSupportedVersions) {904if (cpv == ProtocolVersion.SSL20Hello.id) {905continue;906}907if (spv.id == cpv) {908return spv;909}910}911}912913// No protocol version can be negotiated.914throw context.conContext.fatal(Alert.PROTOCOL_VERSION,915"The client supported protocol versions " + Arrays.toString(916ProtocolVersion.toStringArray(clientSupportedVersions)) +917" are not accepted by server preferences " +918context.activeProtocols);919}920}921922/**923* The "ClientHello" handshake message consumer for TLS 1.2 and924* prior SSL/TLS protocol versions.925*/926private static final927class T12ClientHelloConsumer implements HandshakeConsumer {928// Prevent instantiation of this class.929private T12ClientHelloConsumer() {930// blank931}932933@Override934public void consume(ConnectionContext context,935HandshakeMessage message) throws IOException {936// The consuming happens in server side only.937ServerHandshakeContext shc = (ServerHandshakeContext)context;938ClientHelloMessage clientHello = (ClientHelloMessage)message;939940//941// validate942//943944// Reject client initiated renegotiation?945//946// If server side should reject client-initiated renegotiation,947// send an Alert.HANDSHAKE_FAILURE fatal alert, not a948// no_renegotiation warning alert (no_renegotiation must be a949// warning: RFC 2246). no_renegotiation might seem more950// natural at first, but warnings are not appropriate because951// the sending party does not know how the receiving party952// will behave. This state must be treated as a fatal server953// condition.954//955// This will not have any impact on server initiated renegotiation.956if (shc.conContext.isNegotiated) {957if (!shc.conContext.secureRenegotiation &&958!HandshakeContext.allowUnsafeRenegotiation) {959throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,960"Unsafe renegotiation is not allowed");961}962963if (ServerHandshakeContext.rejectClientInitiatedRenego &&964!shc.kickstartMessageDelivered) {965throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,966"Client initiated renegotiation is not allowed");967}968}969970// Consume a Session Ticket Extension if it exists971SSLExtension[] ext = new SSLExtension[]{972SSLExtension.CH_SESSION_TICKET973};974clientHello.extensions.consumeOnLoad(shc, ext);975976// Does the client want to resume a session?977if (clientHello.sessionId.length() != 0 || shc.statelessResumption) {978SSLSessionContextImpl cache = (SSLSessionContextImpl)shc.sslContext979.engineGetServerSessionContext();980981SSLSessionImpl previous;982// Use the stateless session ticket if provided983if (shc.statelessResumption) {984previous = shc.resumingSession;985} else {986previous = cache.get(clientHello.sessionId.getId());987}988989boolean resumingSession =990(previous != null) && previous.isRejoinable();991if (!resumingSession) {992if (SSLLogger.isOn &&993SSLLogger.isOn("ssl,handshake,verbose")) {994SSLLogger.finest(995"Can't resume, " +996"the existing session is not rejoinable");997}998}999// Validate the negotiated protocol version.1000if (resumingSession) {1001ProtocolVersion sessionProtocol =1002previous.getProtocolVersion();1003if (sessionProtocol != shc.negotiatedProtocol) {1004resumingSession = false;1005if (SSLLogger.isOn &&1006SSLLogger.isOn("ssl,handshake,verbose")) {1007SSLLogger.finest(1008"Can't resume, not the same protocol version");1009}1010}1011}10121013// Validate the required client authentication.1014if (resumingSession &&1015(shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED)) {1016try {1017previous.getPeerPrincipal();1018} catch (SSLPeerUnverifiedException e) {1019resumingSession = false;1020if (SSLLogger.isOn &&1021SSLLogger.isOn("ssl,handshake,verbose")) {1022SSLLogger.finest(1023"Can't resume, " +1024"client authentication is required");1025}1026}1027}10281029// Validate that the cached cipher suite.1030if (resumingSession) {1031CipherSuite suite = previous.getSuite();1032if ((!shc.isNegotiable(suite)) ||1033(!clientHello.cipherSuites.contains(suite))) {1034resumingSession = false;1035if (SSLLogger.isOn &&1036SSLLogger.isOn("ssl,handshake,verbose")) {1037SSLLogger.finest(1038"Can't resume, " +1039"the session cipher suite is absent");1040}1041}1042}10431044// ensure that the endpoint identification algorithm matches the1045// one in the session1046String identityAlg = shc.sslConfig.identificationProtocol;1047if (resumingSession && identityAlg != null) {1048String sessionIdentityAlg =1049previous.getIdentificationProtocol();1050if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) {1051if (SSLLogger.isOn &&1052SSLLogger.isOn("ssl,handshake,verbose")) {1053SSLLogger.finest("Can't resume, endpoint id" +1054" algorithm does not match, requested: " +1055identityAlg + ", cached: " + sessionIdentityAlg);1056}1057resumingSession = false;1058}1059}10601061// So far so good. Note that the handshake extensions may reset1062// the resuming options later.1063shc.isResumption = resumingSession;1064shc.resumingSession = resumingSession ? previous : null;10651066if (!resumingSession && SSLLogger.isOn &&1067SSLLogger.isOn("ssl,handshake")) {1068SSLLogger.fine("Session not resumed.");1069}1070}10711072// cache the client random number for further using1073shc.clientHelloRandom = clientHello.clientRandom;10741075// Check and launch ClientHello extensions.1076SSLExtension[] extTypes = shc.sslConfig.getExclusiveExtensions(1077SSLHandshake.CLIENT_HELLO,1078List.of(SSLExtension.CH_SESSION_TICKET));1079clientHello.extensions.consumeOnLoad(shc, extTypes);10801081//1082// update1083//1084if (!shc.conContext.isNegotiated) {1085shc.conContext.protocolVersion = shc.negotiatedProtocol;1086shc.conContext.outputRecord.setVersion(shc.negotiatedProtocol);1087}10881089// update the responders1090//1091// Only need to ServerHello, which may add more responders later.1092// Note that ServerHello and HelloRetryRequest share the same1093// handshake type/id. The ServerHello producer may be replaced1094// by HelloRetryRequest producer if needed.1095shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,1096SSLHandshake.SERVER_HELLO);10971098//1099// produce1100//1101SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {1102SSLHandshake.SERVER_HELLO,11031104// full handshake messages1105SSLHandshake.CERTIFICATE,1106SSLHandshake.CERTIFICATE_STATUS,1107SSLHandshake.SERVER_KEY_EXCHANGE,1108SSLHandshake.CERTIFICATE_REQUEST,1109SSLHandshake.SERVER_HELLO_DONE,11101111// abbreviated handshake messages1112SSLHandshake.FINISHED1113};11141115for (SSLHandshake hs : probableHandshakeMessages) {1116HandshakeProducer handshakeProducer =1117shc.handshakeProducers.remove(hs.id);1118if (handshakeProducer != null) {1119handshakeProducer.produce(context, clientHello);1120}1121}1122}1123}11241125/**1126* The "ClientHello" handshake message consumer for TLS 1.3.1127*/1128private static final1129class T13ClientHelloConsumer implements HandshakeConsumer {1130// Prevent instantiation of this class.1131private T13ClientHelloConsumer() {1132// blank1133}11341135@Override1136public void consume(ConnectionContext context,1137HandshakeMessage message) throws IOException {1138// The consuming happens in server side only.1139ServerHandshakeContext shc = (ServerHandshakeContext)context;1140ClientHelloMessage clientHello = (ClientHelloMessage)message;11411142// [RFC 8446] TLS 1.3 forbids renegotiation. If a server has1143// negotiated TLS 1.3 and receives a ClientHello at any other1144// time, it MUST terminate the connection with an1145// "unexpected_message" alert.1146if (shc.conContext.isNegotiated) {1147throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,1148"Received unexpected renegotiation handshake message");1149}11501151if (clientHello.clientVersion != ProtocolVersion.TLS12.id) {1152throw shc.conContext.fatal(Alert.PROTOCOL_VERSION,1153"The ClientHello.legacy_version field is not TLS 1.2");1154}11551156// The client may send a dummy change_cipher_spec record1157// immediately after the first ClientHello.1158shc.conContext.consumers.putIfAbsent(1159ContentType.CHANGE_CIPHER_SPEC.id,1160ChangeCipherSpec.t13Consumer);11611162// Is it a resumption?1163//1164// Check and launch the "psk_key_exchange_modes" and1165// "pre_shared_key" extensions first, which will reset the1166// resuming session, no matter the extensions present or not.1167shc.isResumption = true;1168SSLExtension[] extTypes = new SSLExtension[] {1169SSLExtension.PSK_KEY_EXCHANGE_MODES,1170SSLExtension.CH_PRE_SHARED_KEY1171};1172clientHello.extensions.consumeOnLoad(shc, extTypes);11731174// Check and launch ClientHello extensions other than1175// "psk_key_exchange_modes", "pre_shared_key", "protocol_version"1176// and "key_share" extensions.1177//1178// These extensions may discard session resumption, or ask for1179// hello retry.1180extTypes = shc.sslConfig.getExclusiveExtensions(1181SSLHandshake.CLIENT_HELLO,1182Arrays.asList(1183SSLExtension.PSK_KEY_EXCHANGE_MODES,1184SSLExtension.CH_PRE_SHARED_KEY,1185SSLExtension.CH_SUPPORTED_VERSIONS));1186clientHello.extensions.consumeOnLoad(shc, extTypes);11871188if (!shc.handshakeProducers.isEmpty()) {1189// Should be HelloRetryRequest producer.1190goHelloRetryRequest(shc, clientHello);1191} else {1192goServerHello(shc, clientHello);1193}1194}11951196private void goHelloRetryRequest(ServerHandshakeContext shc,1197ClientHelloMessage clientHello) throws IOException {1198HandshakeProducer handshakeProducer =1199shc.handshakeProducers.remove(1200SSLHandshake.HELLO_RETRY_REQUEST.id);1201if (handshakeProducer != null) {1202handshakeProducer.produce(shc, clientHello);1203} else {1204// unlikely1205throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,1206"No HelloRetryRequest producer: " + shc.handshakeProducers);1207}12081209if (!shc.handshakeProducers.isEmpty()) {1210// unlikely, but please double check.1211throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,1212"unknown handshake producers: " + shc.handshakeProducers);1213}1214}12151216private void goServerHello(ServerHandshakeContext shc,1217ClientHelloMessage clientHello) throws IOException {1218//1219// validate1220//1221shc.clientHelloRandom = clientHello.clientRandom;12221223//1224// update1225//1226if (!shc.conContext.isNegotiated) {1227shc.conContext.protocolVersion = shc.negotiatedProtocol;1228shc.conContext.outputRecord.setVersion(shc.negotiatedProtocol);1229}12301231// update the responders1232//1233// Only ServerHello/HelloRetryRequest producer, which adds1234// more responders later.1235shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,1236SSLHandshake.SERVER_HELLO);12371238SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {1239SSLHandshake.SERVER_HELLO,12401241// full handshake messages1242SSLHandshake.ENCRYPTED_EXTENSIONS,1243SSLHandshake.CERTIFICATE_REQUEST,1244SSLHandshake.CERTIFICATE,1245SSLHandshake.CERTIFICATE_VERIFY,1246SSLHandshake.FINISHED1247};12481249//1250// produce1251//1252for (SSLHandshake hs : probableHandshakeMessages) {1253HandshakeProducer handshakeProducer =1254shc.handshakeProducers.remove(hs.id);1255if (handshakeProducer != null) {1256handshakeProducer.produce(shc, clientHello);1257}1258}1259}1260}12611262/**1263* The "ClientHello" handshake message consumer for DTLS 1.2 and1264* previous DTLS protocol versions.1265*/1266private static final1267class D12ClientHelloConsumer implements HandshakeConsumer {1268// Prevent instantiation of this class.1269private D12ClientHelloConsumer() {1270// blank1271}12721273@Override1274public void consume(ConnectionContext context,1275HandshakeMessage message) throws IOException {1276// The consuming happens in server side only.1277ServerHandshakeContext shc = (ServerHandshakeContext)context;1278ClientHelloMessage clientHello = (ClientHelloMessage)message;12791280//1281// validate1282//12831284// Reject client initiated renegotiation?1285//1286// If server side should reject client-initiated renegotiation,1287// send an Alert.HANDSHAKE_FAILURE fatal alert, not a1288// no_renegotiation warning alert (no_renegotiation must be a1289// warning: RFC 2246). no_renegotiation might seem more1290// natural at first, but warnings are not appropriate because1291// the sending party does not know how the receiving party1292// will behave. This state must be treated as a fatal server1293// condition.1294//1295// This will not have any impact on server initiated renegotiation.1296if (shc.conContext.isNegotiated) {1297if (!shc.conContext.secureRenegotiation &&1298!HandshakeContext.allowUnsafeRenegotiation) {1299throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,1300"Unsafe renegotiation is not allowed");1301}13021303if (ServerHandshakeContext.rejectClientInitiatedRenego &&1304!shc.kickstartMessageDelivered) {1305throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,1306"Client initiated renegotiation is not allowed");1307}1308}130913101311// Does the client want to resume a session?1312if (clientHello.sessionId.length() != 0) {1313SSLSessionContextImpl cache = (SSLSessionContextImpl)shc.sslContext1314.engineGetServerSessionContext();13151316// Consume a Session Ticket Extension if it exists1317SSLExtension[] ext = new SSLExtension[]{1318SSLExtension.CH_SESSION_TICKET1319};1320clientHello.extensions.consumeOnLoad(shc, ext);13211322SSLSessionImpl previous;1323// Use stateless session ticket if provided.1324if (shc.statelessResumption) {1325previous = shc.resumingSession;1326} else {1327previous = cache.get(clientHello.sessionId.getId());1328}13291330boolean resumingSession =1331(previous != null) && previous.isRejoinable();1332if (!resumingSession) {1333if (SSLLogger.isOn &&1334SSLLogger.isOn("ssl,handshake,verbose")) {1335SSLLogger.finest(1336"Can't resume, " +1337"the existing session is not rejoinable");1338}1339}1340// Validate the negotiated protocol version.1341if (resumingSession) {1342ProtocolVersion sessionProtocol =1343previous.getProtocolVersion();1344if (sessionProtocol != shc.negotiatedProtocol) {1345resumingSession = false;1346if (SSLLogger.isOn &&1347SSLLogger.isOn("ssl,handshake,verbose")) {1348SSLLogger.finest(1349"Can't resume, not the same protocol version");1350}1351}1352}13531354// Validate the required client authentication.1355if (resumingSession &&1356(shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED)) {13571358try {1359previous.getPeerPrincipal();1360} catch (SSLPeerUnverifiedException e) {1361resumingSession = false;1362if (SSLLogger.isOn &&1363SSLLogger.isOn("ssl,handshake,verbose")) {1364SSLLogger.finest(1365"Can't resume, " +1366"client authentication is required");1367}1368}1369}13701371// Validate that the cached cipher suite.1372if (resumingSession) {1373CipherSuite suite = previous.getSuite();1374if ((!shc.isNegotiable(suite)) ||1375(!clientHello.cipherSuites.contains(suite))) {1376resumingSession = false;1377if (SSLLogger.isOn &&1378SSLLogger.isOn("ssl,handshake,verbose")) {1379SSLLogger.finest(1380"Can't resume, " +1381"the session cipher suite is absent");1382}1383}1384}13851386// So far so good. Note that the handshake extensions may reset1387// the resuming options later.1388shc.isResumption = resumingSession;1389shc.resumingSession = resumingSession ? previous : null;1390}13911392HelloCookieManager hcm =1393shc.sslContext.getHelloCookieManager(ProtocolVersion.DTLS10);1394if (!shc.isResumption &&1395!hcm.isCookieValid(shc, clientHello, clientHello.cookie)) {1396//1397// Perform cookie exchange for DTLS handshaking if no cookie1398// or the cookie is invalid in the ClientHello message.1399//1400// update the responders1401shc.handshakeProducers.put(1402SSLHandshake.HELLO_VERIFY_REQUEST.id,1403SSLHandshake.HELLO_VERIFY_REQUEST);14041405//1406// produce response handshake message1407//1408SSLHandshake.HELLO_VERIFY_REQUEST.produce(context, clientHello);14091410return;1411}14121413// cache the client random number for further using1414shc.clientHelloRandom = clientHello.clientRandom;14151416// Check and launch ClientHello extensions.1417SSLExtension[] extTypes = shc.sslConfig.getEnabledExtensions(1418SSLHandshake.CLIENT_HELLO);1419clientHello.extensions.consumeOnLoad(shc, extTypes);14201421//1422// update1423//1424if (!shc.conContext.isNegotiated) {1425shc.conContext.protocolVersion = shc.negotiatedProtocol;1426shc.conContext.outputRecord.setVersion(shc.negotiatedProtocol);1427}14281429// update the responders1430//1431// Only need to ServerHello, which may add more responders later.1432shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,1433SSLHandshake.SERVER_HELLO);14341435//1436// produce1437//1438SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {1439SSLHandshake.SERVER_HELLO,14401441// full handshake messages1442SSLHandshake.CERTIFICATE,1443SSLHandshake.CERTIFICATE_STATUS,1444SSLHandshake.SERVER_KEY_EXCHANGE,1445SSLHandshake.CERTIFICATE_REQUEST,1446SSLHandshake.SERVER_HELLO_DONE,14471448// abbreviated handshake messages1449SSLHandshake.FINISHED1450};14511452for (SSLHandshake hs : probableHandshakeMessages) {1453HandshakeProducer handshakeProducer =1454shc.handshakeProducers.remove(hs.id);1455if (handshakeProducer != null) {1456handshakeProducer.produce(context, clientHello);1457}1458}1459}1460}14611462/**1463* The "ClientHello" handshake message consumer for DTLS 1.3.1464*/1465private static final1466class D13ClientHelloConsumer implements HandshakeConsumer {1467// Prevent instantiation of this class.1468private D13ClientHelloConsumer() {1469// blank1470}14711472@Override1473public void consume(ConnectionContext context,1474HandshakeMessage message) throws IOException {1475throw new UnsupportedOperationException("Not supported yet.");1476}1477}1478}147914801481