Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/ClientHello.java
38830 views
/*1* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2020, Azul Systems, Inc. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation. Oracle designates this8* particular file as subject to the "Classpath" exception as provided9* by Oracle in the LICENSE file that accompanied this code.10*11* This code is distributed in the hope that it will be useful, but WITHOUT12* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or13* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License14* version 2 for more details (a copy is included in the LICENSE file that15* accompanied this code).16*17* You should have received a copy of the GNU General Public License version18* 2 along with this work; if not, write to the Free Software Foundation,19* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.20*21* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA22* or visit www.oracle.com if you need additional information or have any23* questions.24*/2526package sun.security.ssl;2728import java.io.IOException;29import java.nio.ByteBuffer;30import java.security.AccessController;31import java.security.Principal;32import java.security.PrivilegedActionException;33import java.security.PrivilegedExceptionAction;34import java.security.SecureRandom;35import java.security.cert.X509Certificate;36import java.text.MessageFormat;37import java.util.Arrays;38import java.util.Collections;39import java.util.LinkedList;40import java.util.List;41import java.util.Locale;42import java.util.Objects;43import javax.net.ssl.SSLException;44import javax.net.ssl.SSLHandshakeException;45import javax.net.ssl.SSLPeerUnverifiedException;46import javax.net.ssl.SSLProtocolException;47import javax.security.auth.Subject;4849import static sun.security.ssl.CipherSuite.KeyExchange.K_KRB5;50import static sun.security.ssl.CipherSuite.KeyExchange.K_KRB5_EXPORT;51import static sun.security.ssl.ClientAuthType.CLIENT_AUTH_REQUIRED;52import sun.security.ssl.SSLHandshake.HandshakeMessage;53import sun.security.ssl.SupportedVersionsExtension.CHSupportedVersionsSpec;5455/**56* Pack of the ClientHello handshake message.57*/58final class ClientHello {59static final SSLProducer kickstartProducer =60new ClientHelloKickstartProducer();61static final SSLConsumer handshakeConsumer =62new ClientHelloConsumer();63static final HandshakeProducer handshakeProducer =64new ClientHelloProducer();6566private static final HandshakeConsumer t12HandshakeConsumer =67new T12ClientHelloConsumer();68private static final HandshakeConsumer t13HandshakeConsumer =69new T13ClientHelloConsumer();7071/**72* The ClientHello handshake message.73*74* See RFC 5264/4346/2246/6347 for the specifications.75*/76static final class ClientHelloMessage extends HandshakeMessage {77final int clientVersion;78final RandomCookie clientRandom;79final SessionId sessionId;80final int[] cipherSuiteIds;81final List<CipherSuite> cipherSuites; // known cipher suites only82final byte[] compressionMethod;83final SSLExtensions extensions;8485private static final byte[] NULL_COMPRESSION = new byte[] {0};8687ClientHelloMessage(HandshakeContext handshakeContext,88int clientVersion, SessionId sessionId,89List<CipherSuite> cipherSuites, SecureRandom generator) {90super(handshakeContext);9192this.clientVersion = clientVersion;93this.clientRandom = new RandomCookie(generator);94this.sessionId = sessionId;9596this.cipherSuites = cipherSuites;97this.cipherSuiteIds = getCipherSuiteIds(cipherSuites);98this.extensions = new SSLExtensions(this);99100// Don't support compression.101this.compressionMethod = NULL_COMPRESSION;102}103104/* Read up to the binders in the PSK extension. After this method105* returns, the ByteBuffer position will be at end of the message106* fragment that should be hashed to produce the PSK binder values.107* The client of this method can use this position to determine the108* message fragment and produce the binder values.109*/110static void readPartial(TransportContext tc,111ByteBuffer m) throws IOException {112// version113Record.getInt16(m);114115new RandomCookie(m);116117// session ID118Record.getBytes8(m);119120// cipher suite IDs121Record.getBytes16(m);122// compression method123Record.getBytes8(m);124// read extensions, if present125if (m.remaining() >= 2) {126int remaining = Record.getInt16(m);127while (remaining > 0) {128int id = Record.getInt16(m);129int extLen = Record.getInt16(m);130remaining -= extLen + 4;131132if (id == SSLExtension.CH_PRE_SHARED_KEY.id) {133// ensure pre_shared_key is the last extension134if (remaining > 0) {135throw tc.fatal(Alert.ILLEGAL_PARAMETER,136"pre_shared_key extension is not last");137}138// read only up to the IDs139Record.getBytes16(m);140return;141} else {142m.position(m.position() + extLen);143144}145}146} // Otherwise, ignore the remaining bytes.147}148149ClientHelloMessage(HandshakeContext handshakeContext, ByteBuffer m,150SSLExtension[] supportedExtensions) throws IOException {151super(handshakeContext);152153this.clientVersion = ((m.get() & 0xFF) << 8) | (m.get() & 0xFF);154this.clientRandom = new RandomCookie(m);155this.sessionId = new SessionId(Record.getBytes8(m));156try {157sessionId.checkLength(clientVersion);158} catch (SSLProtocolException ex) {159throw handshakeContext.conContext.fatal(160Alert.ILLEGAL_PARAMETER, ex);161}162byte[] encodedIds = Record.getBytes16(m);163if (encodedIds.length == 0 || (encodedIds.length & 0x01) != 0) {164throw handshakeContext.conContext.fatal(165Alert.ILLEGAL_PARAMETER,166"Invalid ClientHello message");167}168169this.cipherSuiteIds = new int[encodedIds.length >> 1];170for (int i = 0, j = 0; i < encodedIds.length; i++, j++) {171cipherSuiteIds[j] =172((encodedIds[i++] & 0xFF) << 8) | (encodedIds[i] & 0xFF);173}174this.cipherSuites = getCipherSuites(cipherSuiteIds);175176this.compressionMethod = Record.getBytes8(m);177// In TLS 1.3, use of certain extensions is mandatory.178if (m.hasRemaining()) {179this.extensions =180new SSLExtensions(this, m, supportedExtensions);181} else {182this.extensions = new SSLExtensions(this);183}184}185186// TLS 1.3, for cookie generation.187byte[] getHeaderBytes() {188HandshakeOutStream hos = new HandshakeOutStream(null);189try {190// copied from send() method191hos.putInt8((byte)((clientVersion >>> 8) & 0xFF));192hos.putInt8((byte)(clientVersion & 0xFF));193hos.write(clientRandom.randomBytes, 0, 32);194hos.putBytes8(sessionId.getId());195hos.putBytes16(getEncodedCipherSuites());196hos.putBytes8(compressionMethod);197} catch (IOException ioe) {198// unlikely199}200201return hos.toByteArray();202}203204private static int[] getCipherSuiteIds(205List<CipherSuite> cipherSuites) {206if (cipherSuites != null) {207int[] ids = new int[cipherSuites.size()];208int i = 0;209for (CipherSuite cipherSuite : cipherSuites) {210ids[i++] = cipherSuite.id;211}212213return ids;214}215216return new int[0];217}218219private static List<CipherSuite> getCipherSuites(int[] ids) {220List<CipherSuite> cipherSuites = new LinkedList<>();221for (int id : ids) {222CipherSuite cipherSuite = CipherSuite.valueOf(id);223if (cipherSuite != null) {224cipherSuites.add(cipherSuite);225}226}227228return Collections.unmodifiableList(cipherSuites);229}230231private List<String> getCipherSuiteNames() {232List<String> names = new LinkedList<>();233for (int id : cipherSuiteIds) {234names.add(CipherSuite.nameOf(id) +235"(" + Utilities.byte16HexString(id) + ")"); }236237return names;238}239240private byte[] getEncodedCipherSuites() {241byte[] encoded = new byte[cipherSuiteIds.length << 1];242int i = 0;243for (int id : cipherSuiteIds) {244encoded[i++] = (byte)(id >> 8);245encoded[i++] = (byte)id;246}247return encoded;248}249250@Override251public SSLHandshake handshakeType() {252return SSLHandshake.CLIENT_HELLO;253}254255@Override256public int messageLength() {257/*258* Add fixed size parts of each field...259* version + random + session + cipher + compress260*/261return (2 + 32 + 1 + 2 + 1262+ sessionId.length() /* ... + variable parts */263+ (cipherSuiteIds.length * 2)264+ compressionMethod.length)265+ extensions.length(); // In TLS 1.3, use of certain266// extensions is mandatory.267}268269@Override270public void send(HandshakeOutStream hos) throws IOException {271sendCore(hos);272extensions.send(hos); // In TLS 1.3, use of certain273// extensions is mandatory.274}275276void sendCore(HandshakeOutStream hos) throws IOException {277hos.putInt8((byte) (clientVersion >>> 8));278hos.putInt8((byte) clientVersion);279hos.write(clientRandom.randomBytes, 0, 32);280hos.putBytes8(sessionId.getId());281hos.putBytes16(getEncodedCipherSuites());282hos.putBytes8(compressionMethod);283}284285@Override286public String toString() {287MessageFormat messageFormat = new MessageFormat(288"\"ClientHello\": '{'\n" +289" \"client version\" : \"{0}\",\n" +290" \"random\" : \"{1}\",\n" +291" \"session id\" : \"{2}\",\n" +292" \"cipher suites\" : \"{3}\",\n" +293" \"compression methods\" : \"{4}\",\n" +294" \"extensions\" : [\n" +295"{5}\n" +296" ]\n" +297"'}'",298Locale.ENGLISH);299Object[] messageFields = {300ProtocolVersion.nameOf(clientVersion),301Utilities.toHexString(clientRandom.randomBytes),302sessionId.toString(),303getCipherSuiteNames().toString(),304Utilities.toHexString(compressionMethod),305Utilities.indent(Utilities.indent(extensions.toString()))306};307308return messageFormat.format(messageFields);309}310}311312/**313* The "ClientHello" handshake message kick start producer.314*/315private static final316class ClientHelloKickstartProducer implements SSLProducer {317// Prevent instantiation of this class.318private ClientHelloKickstartProducer() {319// blank320}321322// Produce kickstart handshake message.323@Override324public byte[] produce(ConnectionContext context) throws IOException {325// The producing happens in client side only.326ClientHandshakeContext chc = (ClientHandshakeContext)context;327328// clean up this producer329chc.handshakeProducers.remove(SSLHandshake.CLIENT_HELLO.id);330331// the max protocol version this client is supporting.332ProtocolVersion maxProtocolVersion = chc.maximumActiveProtocol;333334// session ID of the ClientHello message335SessionId sessionId = new SessionId(new byte[0]);336337// a list of cipher suites sent by the client338List<CipherSuite> cipherSuites = chc.activeCipherSuites;339340//341// Try to resume an existing session.342//343SSLSessionContextImpl ssci = (SSLSessionContextImpl)344chc.sslContext.engineGetClientSessionContext();345SSLSessionImpl session = ssci.get(346chc.conContext.transport.getPeerHost(),347chc.conContext.transport.getPeerPort());348if (session != null) {349// If unsafe server certificate change is not allowed, reserve350// current server certificates if the previous handshake is a351// session-resumption abbreviated initial handshake.352if (!ClientHandshakeContext.allowUnsafeServerCertChange &&353session.isSessionResumption()) {354try {355// If existing, peer certificate chain cannot be null.356chc.reservedServerCerts =357(X509Certificate[])session.getPeerCertificates();358} catch (SSLPeerUnverifiedException puve) {359// Maybe not certificate-based, ignore the exception.360}361}362363if (!session.isRejoinable()) {364session = null;365if (SSLLogger.isOn &&366SSLLogger.isOn("ssl,handshake,verbose")) {367SSLLogger.finest(368"Can't resume, the session is not rejoinable");369}370}371}372373CipherSuite sessionSuite = null;374if (session != null) {375sessionSuite = session.getSuite();376if (!chc.isNegotiable(sessionSuite)) {377session = null;378if (SSLLogger.isOn &&379SSLLogger.isOn("ssl,handshake,verbose")) {380SSLLogger.finest(381"Can't resume, unavailable session cipher suite");382}383}384}385386ProtocolVersion sessionVersion = null;387if (session != null) {388sessionVersion = session.getProtocolVersion();389if (!chc.isNegotiable(sessionVersion)) {390session = null;391if (SSLLogger.isOn &&392SSLLogger.isOn("ssl,handshake,verbose")) {393SSLLogger.finest(394"Can't resume, unavailable protocol version");395}396}397}398399if (session != null &&400!sessionVersion.useTLS13PlusSpec() &&401SSLConfiguration.useExtendedMasterSecret) {402403boolean isEmsAvailable = chc.sslConfig.isAvailable(404SSLExtension.CH_EXTENDED_MASTER_SECRET, sessionVersion);405if (isEmsAvailable && !session.useExtendedMasterSecret &&406!SSLConfiguration.allowLegacyResumption) {407// perform full handshake instead408//409// The client SHOULD NOT offer an abbreviated handshake410// to resume a session that does not use an extended411// master secret. Instead, it SHOULD offer a full412// handshake.413session = null;414}415416if ((session != null) &&417!ClientHandshakeContext.allowUnsafeServerCertChange) {418// It is fine to move on with abbreviate handshake if419// endpoint identification is enabled.420String identityAlg = chc.sslConfig.identificationProtocol;421if (identityAlg == null || identityAlg.isEmpty()) {422if (isEmsAvailable) {423if (!session.useExtendedMasterSecret) {424// perform full handshake instead425session = null;426} // Otherwise, use extended master secret.427} else {428// The extended master secret extension does not429// apply to SSL 3.0. Perform a full handshake430// instead.431//432// Note that the useExtendedMasterSecret is433// extended to protect SSL 3.0 connections,434// by discarding abbreviate handshake.435session = null;436}437}438}439}440441// ensure that the endpoint identification algorithm matches the442// one in the session443String identityAlg = chc.sslConfig.identificationProtocol;444if (session != null && identityAlg != null) {445String sessionIdentityAlg =446session.getIdentificationProtocol();447if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) {448if (SSLLogger.isOn &&449SSLLogger.isOn("ssl,handshake,verbose")) {450SSLLogger.finest("Can't resume, endpoint id" +451" algorithm does not match, requested: " +452identityAlg + ", cached: " + sessionIdentityAlg);453}454session = null;455}456}457458if (session != null) {459if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {460SSLLogger.finest("Try resuming session", session);461}462463// only set session id if session is 1.2 or earlier464if (!session.getProtocolVersion().useTLS13PlusSpec()) {465sessionId = session.getSessionId();466}467if (!maxProtocolVersion.equals(sessionVersion)) {468maxProtocolVersion = sessionVersion;469470// Update protocol version number in underlying socket and471// handshake output stream, so that the output records472// (at the record layer) have the correct version473chc.setVersion(sessionVersion);474}475476// If no new session is allowed, force use of the previous477// session ciphersuite, and add the renegotiation SCSV if478// necessary.479if (!chc.sslConfig.enableSessionCreation) {480if (!chc.conContext.isNegotiated &&481!sessionVersion.useTLS13PlusSpec() &&482cipherSuites.contains(483CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {484cipherSuites = Arrays.asList(sessionSuite,485CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);486} else { // otherwise, use renegotiation_info extension487cipherSuites = Arrays.asList(sessionSuite);488}489490if (SSLLogger.isOn &&491SSLLogger.isOn("ssl,handshake,verbose")) {492SSLLogger.finest(493"No new session is allowed, so try to resume " +494"the session cipher suite only", sessionSuite);495}496}497498chc.isResumption = true;499chc.resumingSession = session;500}501502if (session == null) {503if (!chc.sslConfig.enableSessionCreation) {504throw new SSLHandshakeException(505"No new session is allowed and " +506"no existing session can be resumed");507}508509if (maxProtocolVersion.useTLS13PlusSpec() &&510SSLConfiguration.useCompatibilityMode) {511// In compatibility mode, the TLS 1.3 legacy_session_id512// field MUST be non-empty, so a client not offering a513// pre-TLS 1.3 session MUST generate a new 32-byte value.514sessionId =515new SessionId(true, chc.sslContext.getSecureRandom());516}517}518519ProtocolVersion minimumVersion = ProtocolVersion.NONE;520for (ProtocolVersion pv : chc.activeProtocols) {521if (minimumVersion == ProtocolVersion.NONE ||522pv.compare(minimumVersion) < 0) {523minimumVersion = pv;524}525}526527// exclude SCSV for secure renegotiation528if (!minimumVersion.useTLS13PlusSpec()) {529if (chc.conContext.secureRenegotiation &&530cipherSuites.contains(531CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {532// The cipherSuites may be unmodifiable533cipherSuites = new LinkedList<>(cipherSuites);534cipherSuites.remove(535CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);536}537}538539// make sure there is a negotiable cipher suite.540boolean negotiable = false;541for (CipherSuite suite : cipherSuites) {542if (chc.isNegotiable(suite)) {543negotiable = true;544break;545}546}547if (!negotiable) {548throw new SSLHandshakeException("No negotiable cipher suite");549}550551// Create the handshake message.552ProtocolVersion clientHelloVersion = maxProtocolVersion;553if (clientHelloVersion.useTLS13PlusSpec()) {554// In TLS 1.3, the client indicates its version preferences555// in the "supported_versions" extension and the client_version556// (legacy_version) field MUST be set to TLS 1.2.557clientHelloVersion = ProtocolVersion.TLS12;558}559560ClientHelloMessage chm = new ClientHelloMessage(chc,561clientHelloVersion.id, sessionId, cipherSuites,562chc.sslContext.getSecureRandom());563564// cache the client random number for further using565chc.clientHelloRandom = chm.clientRandom;566chc.clientHelloVersion = clientHelloVersion.id;567568// Produce extensions for ClientHello handshake message.569SSLExtension[] extTypes = chc.sslConfig.getEnabledExtensions(570SSLHandshake.CLIENT_HELLO, chc.activeProtocols);571chm.extensions.produce(chc, extTypes);572573if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {574SSLLogger.fine("Produced ClientHello handshake message", chm);575}576577// Output the handshake message.578chm.write(chc.handshakeOutput);579chc.handshakeOutput.flush();580581// Reserve the initial ClientHello message for the follow on582// cookie exchange if needed.583chc.initialClientHelloMsg = chm;584585// What's the expected response?586chc.handshakeConsumers.put(587SSLHandshake.SERVER_HELLO.id, SSLHandshake.SERVER_HELLO);588589// The handshake message has been delivered.590return null;591}592}593594private static final595class ClientHelloProducer implements HandshakeProducer {596// Prevent instantiation of this class.597private ClientHelloProducer() {598// blank599}600601// Response to one of the following handshake message:602// HelloRequest (SSL 3.0/TLS 1.0/1.1/1.2)603// ServerHello(HelloRetryRequest) (TLS 1.3)604@Override605public byte[] produce(ConnectionContext context,606HandshakeMessage message) throws IOException {607// The producing happens in client side only.608ClientHandshakeContext chc = (ClientHandshakeContext)context;609610SSLHandshake ht = message.handshakeType();611if (ht == null) {612throw new UnsupportedOperationException("Not supported yet.");613}614615switch (ht) {616case HELLO_REQUEST:617// SSL 3.0/TLS 1.0/1.1/1.2618try {619chc.kickstart();620} catch (IOException ioe) {621throw chc.conContext.fatal(622Alert.HANDSHAKE_FAILURE, ioe);623}624625// The handshake message has been delivered.626return null;627case HELLO_RETRY_REQUEST:628// TLS 1.3629// The HelloRetryRequest consumer should have updated the630// ClientHello handshake message with cookie.631if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {632SSLLogger.fine(633"Produced ClientHello(HRR) handshake message",634chc.initialClientHelloMsg);635}636637// Output the handshake message.638chc.initialClientHelloMsg.write(chc.handshakeOutput);639chc.handshakeOutput.flush();640641// What's the expected response?642chc.conContext.consumers.putIfAbsent(643ContentType.CHANGE_CIPHER_SPEC.id,644ChangeCipherSpec.t13Consumer);645chc.handshakeConsumers.put(SSLHandshake.SERVER_HELLO.id,646SSLHandshake.SERVER_HELLO);647648// The handshake message has been delivered.649return null;650default:651throw new UnsupportedOperationException(652"Not supported yet.");653}654}655}656657/**658* The "ClientHello" handshake message consumer.659*/660private static final class ClientHelloConsumer implements SSLConsumer {661// Prevent instantiation of this class.662private ClientHelloConsumer() {663// blank664}665666@Override667public void consume(ConnectionContext context,668ByteBuffer message) throws IOException {669// The consuming happens in server side only.670ServerHandshakeContext shc = (ServerHandshakeContext)context;671672// clean up this consumer673shc.handshakeConsumers.remove(SSLHandshake.CLIENT_HELLO.id);674if (!shc.handshakeConsumers.isEmpty()) {675throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,676"No more handshake message allowed " +677"in a ClientHello flight");678}679680// Get enabled extension types in ClientHello handshake message.681SSLExtension[] enabledExtensions =682shc.sslConfig.getEnabledExtensions(683SSLHandshake.CLIENT_HELLO);684685ClientHelloMessage chm =686new ClientHelloMessage(shc, message, enabledExtensions);687if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {688SSLLogger.fine("Consuming ClientHello handshake message", chm);689}690691shc.clientHelloVersion = chm.clientVersion;692onClientHello(shc, chm);693}694695private void onClientHello(ServerHandshakeContext context,696ClientHelloMessage clientHello) throws IOException {697// Negotiate protocol version.698//699// Check and launch SupportedVersions.700SSLExtension[] extTypes = new SSLExtension[] {701SSLExtension.CH_SUPPORTED_VERSIONS702};703clientHello.extensions.consumeOnLoad(context, extTypes);704705ProtocolVersion negotiatedProtocol;706CHSupportedVersionsSpec svs =707(CHSupportedVersionsSpec)context.handshakeExtensions.get(708SSLExtension.CH_SUPPORTED_VERSIONS);709if (svs != null) {710negotiatedProtocol =711negotiateProtocol(context, svs.requestedProtocols);712} else {713negotiatedProtocol =714negotiateProtocol(context, clientHello.clientVersion);715}716context.negotiatedProtocol = negotiatedProtocol;717if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {718SSLLogger.fine(719"Negotiated protocol version: " + negotiatedProtocol.name);720}721722// Consume the handshake message for the specific protocol version.723if (negotiatedProtocol.useTLS13PlusSpec()) {724t13HandshakeConsumer.consume(context, clientHello);725} else {726t12HandshakeConsumer.consume(context, clientHello);727}728}729730// Select a protocol version according to the731// ClientHello.client_version.732private ProtocolVersion negotiateProtocol(733ServerHandshakeContext context,734int clientHelloVersion) throws SSLException {735736// Per TLS 1.3 specification, server MUST negotiate TLS 1.2 or prior737// even if ClientHello.client_version is 0x0304 or later.738int chv = clientHelloVersion;739if (chv > ProtocolVersion.TLS12.id) {740chv = ProtocolVersion.TLS12.id;741}742743// Select a protocol version from the activated protocols.744ProtocolVersion pv = ProtocolVersion.selectedFrom(745context.activeProtocols, chv);746if (pv == null || pv == ProtocolVersion.NONE ||747pv == ProtocolVersion.SSL20Hello) {748throw context.conContext.fatal(Alert.PROTOCOL_VERSION,749"Client requested protocol " +750ProtocolVersion.nameOf(clientHelloVersion) +751" is not enabled or supported in server context");752}753754return pv;755}756757// Select a protocol version according to the758// supported_versions extension.759private ProtocolVersion negotiateProtocol(760ServerHandshakeContext context,761int[] clientSupportedVersions) throws SSLException {762763// The client supported protocol versions are present in client764// preference order. This implementation chooses to use the server765// preference of protocol versions instead.766for (ProtocolVersion spv : context.activeProtocols) {767if (spv == ProtocolVersion.SSL20Hello) {768continue;769}770for (int cpv : clientSupportedVersions) {771if (cpv == ProtocolVersion.SSL20Hello.id) {772continue;773}774if (spv.id == cpv) {775return spv;776}777}778}779780// No protocol version can be negotiated.781throw context.conContext.fatal(Alert.PROTOCOL_VERSION,782"The client supported protocol versions " + Arrays.toString(783ProtocolVersion.toStringArray(clientSupportedVersions)) +784" are not accepted by server preferences " +785context.activeProtocols);786}787}788789/**790* The "ClientHello" handshake message consumer for TLS 1.2 and791* prior SSL/TLS protocol versions.792*/793private static final794class T12ClientHelloConsumer implements HandshakeConsumer {795// Prevent instantiation of this class.796private T12ClientHelloConsumer() {797// blank798}799800@Override801public void consume(ConnectionContext context,802HandshakeMessage message) throws IOException {803// The consuming happens in server side only.804ServerHandshakeContext shc = (ServerHandshakeContext)context;805ClientHelloMessage clientHello = (ClientHelloMessage)message;806807//808// validate809//810811// Reject client initiated renegotiation?812//813// If server side should reject client-initiated renegotiation,814// send an Alert.HANDSHAKE_FAILURE fatal alert, not a815// no_renegotiation warning alert (no_renegotiation must be a816// warning: RFC 2246). no_renegotiation might seem more817// natural at first, but warnings are not appropriate because818// the sending party does not know how the receiving party819// will behave. This state must be treated as a fatal server820// condition.821//822// This will not have any impact on server initiated renegotiation.823if (shc.conContext.isNegotiated) {824if (!shc.conContext.secureRenegotiation &&825!HandshakeContext.allowUnsafeRenegotiation) {826throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,827"Unsafe renegotiation is not allowed");828}829830if (ServerHandshakeContext.rejectClientInitiatedRenego &&831!shc.kickstartMessageDelivered) {832throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,833"Client initiated renegotiation is not allowed");834}835}836837// Is it an abbreviated handshake?838if (clientHello.sessionId.length() != 0) {839SSLSessionImpl previous = ((SSLSessionContextImpl)shc.sslContext840.engineGetServerSessionContext())841.get(clientHello.sessionId.getId());842843boolean resumingSession =844(previous != null) && previous.isRejoinable();845if (!resumingSession) {846if (SSLLogger.isOn &&847SSLLogger.isOn("ssl,handshake,verbose")) {848SSLLogger.finest(849"Can't resume, " +850"the existing session is not rejoinable");851}852}853// Validate the negotiated protocol version.854if (resumingSession) {855ProtocolVersion sessionProtocol =856previous.getProtocolVersion();857if (sessionProtocol != shc.negotiatedProtocol) {858resumingSession = false;859if (SSLLogger.isOn &&860SSLLogger.isOn("ssl,handshake,verbose")) {861SSLLogger.finest(862"Can't resume, not the same protocol version");863}864}865}866867// Validate the required client authentication.868if (resumingSession &&869(shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED)) {870try {871previous.getPeerPrincipal();872} catch (SSLPeerUnverifiedException e) {873resumingSession = false;874if (SSLLogger.isOn &&875SSLLogger.isOn("ssl,handshake,verbose")) {876SSLLogger.finest(877"Can't resume, " +878"client authentication is required");879}880}881}882883// Validate that the cached cipher suite.884if (resumingSession) {885CipherSuite suite = previous.getSuite();886if ((!shc.isNegotiable(suite)) ||887(!clientHello.cipherSuites.contains(suite))) {888resumingSession = false;889if (SSLLogger.isOn &&890SSLLogger.isOn("ssl,handshake,verbose")) {891SSLLogger.finest(892"Can't resume, " +893"the session cipher suite is absent");894}895}896}897898// Validate KRB5 cipher suites899if (resumingSession) {900CipherSuite suite = previous.getSuite();901if (suite.keyExchange == K_KRB5 ||902suite.keyExchange == K_KRB5_EXPORT) {903Principal localPrincipal = previous.getLocalPrincipal();904905Subject subject = null;906try {907subject = AccessController.doPrivileged(908new PrivilegedExceptionAction<Subject>() {909@Override910public Subject run() throws Exception {911return Krb5Helper.getServerSubject(912shc.conContext.acc);913}});914} catch (PrivilegedActionException e) {915subject = null;916if (SSLLogger.isOn &&917SSLLogger.isOn("ssl,handshake,verbose")) {918SSLLogger.finest("Attempt to obtain" +919" subject failed!");920}921}922923if (subject != null) {924// Eliminate dependency on KerberosPrincipal925if (Krb5Helper.isRelated(subject, localPrincipal)) {926if (SSLLogger.isOn &&927SSLLogger.isOn("ssl,handshake,verbose"))928SSLLogger.finest("Subject can" +929" provide creds for princ");930} else {931resumingSession = false;932if (SSLLogger.isOn &&933SSLLogger.isOn("ssl,handshake,verbose"))934SSLLogger.finest("Subject cannot" +935" provide creds for princ");936}937} else {938resumingSession = false;939if (SSLLogger.isOn &&940SSLLogger.isOn("ssl,handshake,verbose"))941SSLLogger.finest("Kerberos credentials are" +942" not present in the current Subject;" +943" check if " +944" javax.security.auth.useSubjectCredsOnly" +945" system property has been set to false");946}947}948}949950// ensure that the endpoint identification algorithm matches the951// one in the session952String identityAlg = shc.sslConfig.identificationProtocol;953if (resumingSession && identityAlg != null) {954String sessionIdentityAlg =955previous.getIdentificationProtocol();956if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) {957if (SSLLogger.isOn &&958SSLLogger.isOn("ssl,handshake,verbose")) {959SSLLogger.finest("Can't resume, endpoint id" +960" algorithm does not match, requested: " +961identityAlg + ", cached: " + sessionIdentityAlg);962}963resumingSession = false;964}965}966967// So far so good. Note that the handshake extensions may reset968// the resuming options later.969shc.isResumption = resumingSession;970shc.resumingSession = resumingSession ? previous : null;971}972973// cache the client random number for further using974shc.clientHelloRandom = clientHello.clientRandom;975976// Check and launch ClientHello extensions.977SSLExtension[] extTypes = shc.sslConfig.getEnabledExtensions(978SSLHandshake.CLIENT_HELLO);979clientHello.extensions.consumeOnLoad(shc, extTypes);980981//982// update983//984if (!shc.conContext.isNegotiated) {985shc.conContext.protocolVersion = shc.negotiatedProtocol;986shc.conContext.outputRecord.setVersion(shc.negotiatedProtocol);987}988989// update the responders990//991// Only need to ServerHello, which may add more responders later.992// Note that ServerHello and HelloRetryRequest share the same993// handshake type/id. The ServerHello producer may be replaced994// by HelloRetryRequest producer if needed.995shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,996SSLHandshake.SERVER_HELLO);997998//999// produce1000//1001SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {1002SSLHandshake.SERVER_HELLO,10031004// full handshake messages1005SSLHandshake.CERTIFICATE,1006SSLHandshake.CERTIFICATE_STATUS,1007SSLHandshake.SERVER_KEY_EXCHANGE,1008SSLHandshake.CERTIFICATE_REQUEST,1009SSLHandshake.SERVER_HELLO_DONE,10101011// abbreviated handshake messages1012SSLHandshake.FINISHED1013};10141015for (SSLHandshake hs : probableHandshakeMessages) {1016HandshakeProducer handshakeProducer =1017shc.handshakeProducers.remove(hs.id);1018if (handshakeProducer != null) {1019handshakeProducer.produce(context, clientHello);1020}1021}1022}1023}10241025/**1026* The "ClientHello" handshake message consumer for TLS 1.3.1027*/1028private static final1029class T13ClientHelloConsumer implements HandshakeConsumer {1030// Prevent instantiation of this class.1031private T13ClientHelloConsumer() {1032// blank1033}10341035@Override1036public void consume(ConnectionContext context,1037HandshakeMessage message) throws IOException {1038// The consuming happens in server side only.1039ServerHandshakeContext shc = (ServerHandshakeContext)context;1040ClientHelloMessage clientHello = (ClientHelloMessage)message;10411042// [RFC 8446] TLS 1.3 forbids renegotiation. If a server has1043// negotiated TLS 1.3 and receives a ClientHello at any other1044// time, it MUST terminate the connection with an1045// "unexpected_message" alert.1046if (shc.conContext.isNegotiated) {1047throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,1048"Received unexpected renegotiation handshake message");1049}10501051// The client may send a dummy change_cipher_spec record1052// immediately after the first ClientHello.1053shc.conContext.consumers.putIfAbsent(1054ContentType.CHANGE_CIPHER_SPEC.id,1055ChangeCipherSpec.t13Consumer);10561057// Is it a resumption?1058//1059// Check and launch the "psk_key_exchange_modes" and1060// "pre_shared_key" extensions first, which will reset the1061// resuming session, no matter the extensions present or not.1062shc.isResumption = true;1063SSLExtension[] extTypes = new SSLExtension[] {1064SSLExtension.PSK_KEY_EXCHANGE_MODES,1065SSLExtension.CH_PRE_SHARED_KEY1066};1067clientHello.extensions.consumeOnLoad(shc, extTypes);10681069// Check and launch ClientHello extensions other than1070// "psk_key_exchange_modes", "pre_shared_key", "protocol_version"1071// and "key_share" extensions.1072//1073// These extensions may discard session resumption, or ask for1074// hello retry.1075extTypes = shc.sslConfig.getExclusiveExtensions(1076SSLHandshake.CLIENT_HELLO,1077Arrays.asList(1078SSLExtension.PSK_KEY_EXCHANGE_MODES,1079SSLExtension.CH_PRE_SHARED_KEY,1080SSLExtension.CH_SUPPORTED_VERSIONS));1081clientHello.extensions.consumeOnLoad(shc, extTypes);10821083if (!shc.handshakeProducers.isEmpty()) {1084// Should be HelloRetryRequest producer.1085goHelloRetryRequest(shc, clientHello);1086} else {1087goServerHello(shc, clientHello);1088}1089}10901091private void goHelloRetryRequest(ServerHandshakeContext shc,1092ClientHelloMessage clientHello) throws IOException {1093HandshakeProducer handshakeProducer =1094shc.handshakeProducers.remove(1095SSLHandshake.HELLO_RETRY_REQUEST.id);1096if (handshakeProducer != null) {1097handshakeProducer.produce(shc, clientHello);1098} else {1099// unlikely1100throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,1101"No HelloRetryRequest producer: " + shc.handshakeProducers);1102}11031104if (!shc.handshakeProducers.isEmpty()) {1105// unlikely, but please double check.1106throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,1107"unknown handshake producers: " + shc.handshakeProducers);1108}1109}11101111private void goServerHello(ServerHandshakeContext shc,1112ClientHelloMessage clientHello) throws IOException {1113//1114// validate1115//1116shc.clientHelloRandom = clientHello.clientRandom;11171118//1119// update1120//1121if (!shc.conContext.isNegotiated) {1122shc.conContext.protocolVersion = shc.negotiatedProtocol;1123shc.conContext.outputRecord.setVersion(shc.negotiatedProtocol);1124}11251126// update the responders1127//1128// Only ServerHello/HelloRetryRequest producer, which adds1129// more responders later.1130shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,1131SSLHandshake.SERVER_HELLO);11321133SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {1134SSLHandshake.SERVER_HELLO,11351136// full handshake messages1137SSLHandshake.ENCRYPTED_EXTENSIONS,1138SSLHandshake.CERTIFICATE_REQUEST,1139SSLHandshake.CERTIFICATE,1140SSLHandshake.CERTIFICATE_VERIFY,1141SSLHandshake.FINISHED1142};11431144//1145// produce1146//1147for (SSLHandshake hs : probableHandshakeMessages) {1148HandshakeProducer handshakeProducer =1149shc.handshakeProducers.remove(hs.id);1150if (handshakeProducer != null) {1151handshakeProducer.produce(shc, clientHello);1152}1153}1154}1155}1156}115711581159