Path: blob/master/src/java.base/share/classes/sun/security/ssl/Finished.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.GeneralSecurityException;30import java.security.InvalidKeyException;31import java.security.MessageDigest;32import java.security.NoSuchAlgorithmException;33import java.security.ProviderException;34import java.security.spec.AlgorithmParameterSpec;35import java.text.MessageFormat;36import java.util.Locale;37import javax.crypto.KeyGenerator;38import javax.crypto.Mac;39import javax.crypto.SecretKey;40import javax.crypto.spec.IvParameterSpec;41import javax.crypto.spec.SecretKeySpec;42import javax.net.ssl.SSLPeerUnverifiedException;4344import jdk.internal.event.EventHelper;45import jdk.internal.event.TLSHandshakeEvent;46import sun.security.internal.spec.TlsPrfParameterSpec;47import sun.security.ssl.CipherSuite.HashAlg;48import static sun.security.ssl.CipherSuite.HashAlg.H_NONE;49import sun.security.ssl.SSLBasicKeyDerivation.SecretSizeSpec;50import sun.security.ssl.SSLCipher.SSLReadCipher;51import sun.security.ssl.SSLCipher.SSLWriteCipher;52import sun.security.ssl.SSLHandshake.HandshakeMessage;53import sun.security.util.HexDumpEncoder;5455/**56* Pack of the Finished handshake message.57*/58final class Finished {59static final SSLConsumer t12HandshakeConsumer =60new T12FinishedConsumer();61static final HandshakeProducer t12HandshakeProducer =62new T12FinishedProducer();6364static final SSLConsumer t13HandshakeConsumer =65new T13FinishedConsumer();66static final HandshakeProducer t13HandshakeProducer =67new T13FinishedProducer();6869/**70* The Finished handshake message.71*/72private static final class FinishedMessage extends HandshakeMessage {73private final byte[] verifyData;7475FinishedMessage(HandshakeContext context) throws IOException {76super(context);7778VerifyDataScheme vds =79VerifyDataScheme.valueOf(context.negotiatedProtocol);8081byte[] vd;82try {83vd = vds.createVerifyData(context, false);84} catch (IOException ioe) {85throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,86"Failed to generate verify_data", ioe);87}8889this.verifyData = vd;90}9192FinishedMessage(HandshakeContext context,93ByteBuffer m) throws IOException {94super(context);95int verifyDataLen = 12;96if (context.negotiatedProtocol == ProtocolVersion.SSL30) {97verifyDataLen = 36;98} else if (context.negotiatedProtocol.useTLS13PlusSpec()) {99verifyDataLen =100context.negotiatedCipherSuite.hashAlg.hashLength;101}102103if (m.remaining() != verifyDataLen) {104throw context.conContext.fatal(Alert.DECODE_ERROR,105"Inappropriate finished message: need " + verifyDataLen +106" but remaining " + m.remaining() + " bytes verify_data");107}108109this.verifyData = new byte[verifyDataLen];110m.get(verifyData);111112VerifyDataScheme vd =113VerifyDataScheme.valueOf(context.negotiatedProtocol);114byte[] myVerifyData;115try {116myVerifyData = vd.createVerifyData(context, true);117} catch (IOException ioe) {118throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,119"Failed to generate verify_data", ioe);120}121if (!MessageDigest.isEqual(myVerifyData, verifyData)) {122throw context.conContext.fatal(Alert.DECRYPT_ERROR,123"The Finished message cannot be verified.");124}125}126127@Override128public SSLHandshake handshakeType() {129return SSLHandshake.FINISHED;130}131132@Override133public int messageLength() {134return verifyData.length;135}136137@Override138public void send(HandshakeOutStream hos) throws IOException {139hos.write(verifyData);140}141142@Override143public String toString() {144MessageFormat messageFormat = new MessageFormat(145"\"Finished\": '{'\n" +146" \"verify data\": '{'\n" +147"{0}\n" +148" '}'" +149"'}'",150Locale.ENGLISH);151152HexDumpEncoder hexEncoder = new HexDumpEncoder();153Object[] messageFields = {154Utilities.indent(hexEncoder.encode(verifyData), " "),155};156return messageFormat.format(messageFields);157}158}159160interface VerifyDataGenerator {161byte[] createVerifyData(HandshakeContext context,162boolean isValidation) throws IOException;163}164165enum VerifyDataScheme {166SSL30 ("kdf_ssl30", new S30VerifyDataGenerator()),167TLS10 ("kdf_tls10", new T10VerifyDataGenerator()),168TLS12 ("kdf_tls12", new T12VerifyDataGenerator()),169TLS13 ("kdf_tls13", new T13VerifyDataGenerator());170171final String name;172final VerifyDataGenerator generator;173174VerifyDataScheme(String name, VerifyDataGenerator verifyDataGenerator) {175this.name = name;176this.generator = verifyDataGenerator;177}178179static VerifyDataScheme valueOf(ProtocolVersion protocolVersion) {180switch (protocolVersion) {181case SSL30:182return VerifyDataScheme.SSL30;183case TLS10:184case TLS11:185case DTLS10:186return VerifyDataScheme.TLS10;187case TLS12:188case DTLS12:189return VerifyDataScheme.TLS12;190case TLS13:191return VerifyDataScheme.TLS13;192default:193return null;194}195}196197public byte[] createVerifyData(HandshakeContext context,198boolean isValidation) throws IOException {199if (generator != null) {200return generator.createVerifyData(context, isValidation);201}202203throw new UnsupportedOperationException("Not supported yet.");204}205}206207// SSL 3.0208private static final209class S30VerifyDataGenerator implements VerifyDataGenerator {210@Override211public byte[] createVerifyData(HandshakeContext context,212boolean isValidation) throws IOException {213HandshakeHash handshakeHash = context.handshakeHash;214SecretKey masterSecretKey =215context.handshakeSession.getMasterSecret();216217boolean useClientLabel =218(context.sslConfig.isClientMode && !isValidation) ||219(!context.sslConfig.isClientMode && isValidation);220return handshakeHash.digest(useClientLabel, masterSecretKey);221}222}223224// TLS 1.0, TLS 1.1, DTLS 1.0225private static final226class T10VerifyDataGenerator implements VerifyDataGenerator {227@Override228public byte[] createVerifyData(HandshakeContext context,229boolean isValidation) throws IOException {230HandshakeHash handshakeHash = context.handshakeHash;231SecretKey masterSecretKey =232context.handshakeSession.getMasterSecret();233234boolean useClientLabel =235(context.sslConfig.isClientMode && !isValidation) ||236(!context.sslConfig.isClientMode && isValidation);237String tlsLabel;238if (useClientLabel) {239tlsLabel = "client finished";240} else {241tlsLabel = "server finished";242}243244try {245byte[] seed = handshakeHash.digest();246String prfAlg = "SunTlsPrf";247HashAlg hashAlg = H_NONE;248249/*250* RFC 5246/7.4.9 says that finished messages can251* be ciphersuite-specific in both length/PRF hash252* algorithm. If we ever run across a different253* length, this call will need to be updated.254*/255@SuppressWarnings("deprecation")256TlsPrfParameterSpec spec = new TlsPrfParameterSpec(257masterSecretKey, tlsLabel, seed, 12,258hashAlg.name, hashAlg.hashLength, hashAlg.blockSize);259KeyGenerator kg = KeyGenerator.getInstance(prfAlg);260kg.init(spec);261SecretKey prfKey = kg.generateKey();262if (!"RAW".equals(prfKey.getFormat())) {263throw new ProviderException(264"Invalid PRF output, format must be RAW. " +265"Format received: " + prfKey.getFormat());266}267return prfKey.getEncoded();268} catch (GeneralSecurityException e) {269throw new RuntimeException("PRF failed", e);270}271}272}273274// TLS 1.2275private static final276class T12VerifyDataGenerator implements VerifyDataGenerator {277@Override278public byte[] createVerifyData(HandshakeContext context,279boolean isValidation) throws IOException {280CipherSuite cipherSuite = context.negotiatedCipherSuite;281HandshakeHash handshakeHash = context.handshakeHash;282SecretKey masterSecretKey =283context.handshakeSession.getMasterSecret();284285boolean useClientLabel =286(context.sslConfig.isClientMode && !isValidation) ||287(!context.sslConfig.isClientMode && isValidation);288String tlsLabel;289if (useClientLabel) {290tlsLabel = "client finished";291} else {292tlsLabel = "server finished";293}294295try {296byte[] seed = handshakeHash.digest();297String prfAlg = "SunTls12Prf";298HashAlg hashAlg = cipherSuite.hashAlg;299300/*301* RFC 5246/7.4.9 says that finished messages can302* be ciphersuite-specific in both length/PRF hash303* algorithm. If we ever run across a different304* length, this call will need to be updated.305*/306@SuppressWarnings("deprecation")307TlsPrfParameterSpec spec = new TlsPrfParameterSpec(308masterSecretKey, tlsLabel, seed, 12,309hashAlg.name, hashAlg.hashLength, hashAlg.blockSize);310KeyGenerator kg = KeyGenerator.getInstance(prfAlg);311kg.init(spec);312SecretKey prfKey = kg.generateKey();313if (!"RAW".equals(prfKey.getFormat())) {314throw new ProviderException(315"Invalid PRF output, format must be RAW. " +316"Format received: " + prfKey.getFormat());317}318return prfKey.getEncoded();319} catch (GeneralSecurityException e) {320throw new RuntimeException("PRF failed", e);321}322}323}324325// TLS 1.3326private static final327class T13VerifyDataGenerator implements VerifyDataGenerator {328private static final byte[] hkdfLabel = "tls13 finished".getBytes();329private static final byte[] hkdfContext = new byte[0];330331@Override332public byte[] createVerifyData(HandshakeContext context,333boolean isValidation) throws IOException {334// create finished secret key335HashAlg hashAlg =336context.negotiatedCipherSuite.hashAlg;337SecretKey secret = isValidation ?338context.baseReadSecret : context.baseWriteSecret;339SSLBasicKeyDerivation kdf = new SSLBasicKeyDerivation(340secret, hashAlg.name,341hkdfLabel, hkdfContext, hashAlg.hashLength);342AlgorithmParameterSpec keySpec =343new SecretSizeSpec(hashAlg.hashLength);344SecretKey finishedSecret =345kdf.deriveKey("TlsFinishedSecret", keySpec);346347String hmacAlg =348"Hmac" + hashAlg.name.replace("-", "");349try {350Mac hmac = Mac.getInstance(hmacAlg);351hmac.init(finishedSecret);352return hmac.doFinal(context.handshakeHash.digest());353} catch (NoSuchAlgorithmException |InvalidKeyException ex) {354throw new ProviderException(355"Failed to generate verify_data", ex);356}357}358}359360/**361* The "Finished" handshake message producer.362*/363private static final364class T12FinishedProducer implements HandshakeProducer {365// Prevent instantiation of this class.366private T12FinishedProducer() {367// blank368}369370@Override371public byte[] produce(ConnectionContext context,372HandshakeMessage message) throws IOException {373// The consuming happens in handshake context only.374HandshakeContext hc = (HandshakeContext)context;375if (hc.sslConfig.isClientMode) {376return onProduceFinished(377(ClientHandshakeContext)context, message);378} else {379return onProduceFinished(380(ServerHandshakeContext)context, message);381}382}383384private byte[] onProduceFinished(ClientHandshakeContext chc,385HandshakeMessage message) throws IOException {386// Refresh handshake hash387chc.handshakeHash.update();388389FinishedMessage fm = new FinishedMessage(chc);390391// Change write cipher and delivery ChangeCipherSpec message.392ChangeCipherSpec.t10Producer.produce(chc, message);393394if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {395SSLLogger.fine(396"Produced client Finished handshake message", fm);397}398399// Output the handshake message.400fm.write(chc.handshakeOutput);401chc.handshakeOutput.flush();402403/*404* save server verify data for secure renegotiation405*/406if (chc.conContext.secureRenegotiation) {407chc.conContext.clientVerifyData = fm.verifyData;408}409410if (chc.statelessResumption) {411chc.handshakeConsumers.put(412SSLHandshake.NEW_SESSION_TICKET.id, SSLHandshake.NEW_SESSION_TICKET);413}414// update the consumers and producers415if (!chc.isResumption) {416chc.conContext.consumers.put(ContentType.CHANGE_CIPHER_SPEC.id,417ChangeCipherSpec.t10Consumer);418chc.handshakeConsumers.put(419SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);420chc.conContext.inputRecord.expectingFinishFlight();421} else {422if (chc.handshakeSession.isRejoinable()) {423((SSLSessionContextImpl)chc.sslContext.424engineGetClientSessionContext()).put(425chc.handshakeSession);426}427chc.conContext.conSession = chc.handshakeSession.finish();428chc.conContext.protocolVersion = chc.negotiatedProtocol;429430// handshake context cleanup.431chc.handshakeFinished = true;432433// May need to retransmit the last flight for DTLS.434if (!chc.sslContext.isDTLS()) {435chc.conContext.finishHandshake();436}437}438439// The handshake message has been delivered.440return null;441}442443private byte[] onProduceFinished(ServerHandshakeContext shc,444HandshakeMessage message) throws IOException {445if (shc.statelessResumption) {446NewSessionTicket.handshake12Producer.produce(shc, message);447}448449// Refresh handshake hash450shc.handshakeHash.update();451452FinishedMessage fm = new FinishedMessage(shc);453454// Change write cipher and delivery ChangeCipherSpec message.455ChangeCipherSpec.t10Producer.produce(shc, message);456457if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {458SSLLogger.fine(459"Produced server Finished handshake message", fm);460}461462// Output the handshake message.463fm.write(shc.handshakeOutput);464shc.handshakeOutput.flush();465466/*467* save client verify data for secure renegotiation468*/469if (shc.conContext.secureRenegotiation) {470shc.conContext.serverVerifyData = fm.verifyData;471}472473// update the consumers and producers474if (shc.isResumption) {475shc.conContext.consumers.put(ContentType.CHANGE_CIPHER_SPEC.id,476ChangeCipherSpec.t10Consumer);477shc.handshakeConsumers.put(478SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);479shc.conContext.inputRecord.expectingFinishFlight();480} else {481// Set the session's context based on stateless/cache status482if (shc.statelessResumption &&483shc.handshakeSession.isStatelessable()) {484shc.handshakeSession.setContext((SSLSessionContextImpl)485shc.sslContext.engineGetServerSessionContext());486} else {487if (shc.handshakeSession.isRejoinable()) {488((SSLSessionContextImpl)shc.sslContext.489engineGetServerSessionContext()).put(490shc.handshakeSession);491}492}493shc.conContext.conSession = shc.handshakeSession.finish();494shc.conContext.protocolVersion = shc.negotiatedProtocol;495496// handshake context cleanup.497shc.handshakeFinished = true;498499// May need to retransmit the last flight for DTLS.500if (!shc.sslContext.isDTLS()) {501shc.conContext.finishHandshake();502}503}504505// The handshake message has been delivered.506return null;507}508}509510/**511* The "Finished" handshake message consumer.512*/513private static final class T12FinishedConsumer implements SSLConsumer {514// Prevent instantiation of this class.515private T12FinishedConsumer() {516// blank517}518519@Override520public void consume(ConnectionContext context,521ByteBuffer message) throws IOException {522// The consuming happens in handshake context only.523HandshakeContext hc = (HandshakeContext)context;524525// This consumer can be used only once.526hc.handshakeConsumers.remove(SSLHandshake.FINISHED.id);527528// We should not be processing finished messages unless529// we have received ChangeCipherSpec530if (hc.conContext.consumers.containsKey(531ContentType.CHANGE_CIPHER_SPEC.id)) {532throw hc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,533"Missing ChangeCipherSpec message");534}535536if (hc.sslConfig.isClientMode) {537onConsumeFinished((ClientHandshakeContext)context, message);538} else {539onConsumeFinished((ServerHandshakeContext)context, message);540}541}542543private void onConsumeFinished(ClientHandshakeContext chc,544ByteBuffer message) throws IOException {545FinishedMessage fm = new FinishedMessage(chc, message);546if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {547SSLLogger.fine(548"Consuming server Finished handshake message", fm);549}550551if (chc.conContext.secureRenegotiation) {552chc.conContext.serverVerifyData = fm.verifyData;553}554555if (!chc.isResumption) {556if (chc.handshakeSession.isRejoinable()) {557((SSLSessionContextImpl)chc.sslContext.558engineGetClientSessionContext()).put(559chc.handshakeSession);560}561chc.conContext.conSession = chc.handshakeSession.finish();562chc.conContext.protocolVersion = chc.negotiatedProtocol;563564// handshake context cleanup.565chc.handshakeFinished = true;566recordEvent(chc.conContext.conSession);567568// May need to retransmit the last flight for DTLS.569if (!chc.sslContext.isDTLS()) {570chc.conContext.finishHandshake();571}572} else {573chc.handshakeProducers.put(SSLHandshake.FINISHED.id,574SSLHandshake.FINISHED);575}576577//578// produce579//580SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {581SSLHandshake.FINISHED582};583584for (SSLHandshake hs : probableHandshakeMessages) {585HandshakeProducer handshakeProducer =586chc.handshakeProducers.remove(hs.id);587if (handshakeProducer != null) {588handshakeProducer.produce(chc, fm);589}590}591}592593private void onConsumeFinished(ServerHandshakeContext shc,594ByteBuffer message) throws IOException {595// Make sure that any expected CertificateVerify message596// has been received and processed.597if (!shc.isResumption) {598if (shc.handshakeConsumers.containsKey(599SSLHandshake.CERTIFICATE_VERIFY.id)) {600throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,601"Unexpected Finished handshake message");602}603}604605FinishedMessage fm = new FinishedMessage(shc, message);606if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {607SSLLogger.fine(608"Consuming client Finished handshake message", fm);609}610611if (shc.conContext.secureRenegotiation) {612shc.conContext.clientVerifyData = fm.verifyData;613}614615if (shc.isResumption) {616if (shc.handshakeSession.isRejoinable() &&617!shc.statelessResumption) {618((SSLSessionContextImpl)shc.sslContext.619engineGetServerSessionContext()).put(620shc.handshakeSession);621}622shc.conContext.conSession = shc.handshakeSession.finish();623shc.conContext.protocolVersion = shc.negotiatedProtocol;624625// handshake context cleanup.626shc.handshakeFinished = true;627recordEvent(shc.conContext.conSession);628629// May need to retransmit the last flight for DTLS.630if (!shc.sslContext.isDTLS()) {631shc.conContext.finishHandshake();632}633} else {634shc.handshakeProducers.put(SSLHandshake.FINISHED.id,635SSLHandshake.FINISHED);636}637638//639// produce640//641SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {642SSLHandshake.FINISHED643};644645for (SSLHandshake hs : probableHandshakeMessages) {646HandshakeProducer handshakeProducer =647shc.handshakeProducers.remove(hs.id);648if (handshakeProducer != null) {649handshakeProducer.produce(shc, fm);650}651}652}653}654655/**656* The "Finished" handshake message producer.657*/658private static final659class T13FinishedProducer implements HandshakeProducer {660// Prevent instantiation of this class.661private T13FinishedProducer() {662// blank663}664665@Override666public byte[] produce(ConnectionContext context,667HandshakeMessage message) throws IOException {668// The consuming happens in handshake context only.669HandshakeContext hc = (HandshakeContext)context;670if (hc.sslConfig.isClientMode) {671return onProduceFinished(672(ClientHandshakeContext)context, message);673} else {674return onProduceFinished(675(ServerHandshakeContext)context, message);676}677}678679private byte[] onProduceFinished(ClientHandshakeContext chc,680HandshakeMessage message) throws IOException {681// Refresh handshake hash682chc.handshakeHash.update();683684FinishedMessage fm = new FinishedMessage(chc);685if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {686SSLLogger.fine(687"Produced client Finished handshake message", fm);688}689690// Output the handshake message.691fm.write(chc.handshakeOutput);692chc.handshakeOutput.flush();693694// save server verify data for secure renegotiation695if (chc.conContext.secureRenegotiation) {696chc.conContext.clientVerifyData = fm.verifyData;697}698699// update the context700// Change client/server application traffic secrets.701SSLKeyDerivation kd = chc.handshakeKeyDerivation;702if (kd == null) {703// unlikely704throw chc.conContext.fatal(Alert.INTERNAL_ERROR,705"no key derivation");706}707708SSLTrafficKeyDerivation kdg =709SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);710if (kdg == null) {711// unlikely712throw chc.conContext.fatal(Alert.INTERNAL_ERROR,713"Not supported key derivation: " +714chc.negotiatedProtocol);715}716717try {718// update the application traffic read keys.719SecretKey writeSecret = kd.deriveKey(720"TlsClientAppTrafficSecret", null);721722SSLKeyDerivation writeKD =723kdg.createKeyDerivation(chc, writeSecret);724SecretKey writeKey = writeKD.deriveKey(725"TlsKey", null);726SecretKey writeIvSecret = writeKD.deriveKey(727"TlsIv", null);728IvParameterSpec writeIv =729new IvParameterSpec(writeIvSecret.getEncoded());730SSLWriteCipher writeCipher =731chc.negotiatedCipherSuite.bulkCipher.createWriteCipher(732Authenticator.valueOf(chc.negotiatedProtocol),733chc.negotiatedProtocol, writeKey, writeIv,734chc.sslContext.getSecureRandom());735736if (writeCipher == null) {737throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,738"Illegal cipher suite (" + chc.negotiatedCipherSuite +739") and protocol version (" + chc.negotiatedProtocol +740")");741}742743chc.baseWriteSecret = writeSecret;744chc.conContext.outputRecord.changeWriteCiphers(745writeCipher, false);746747} catch (GeneralSecurityException gse) {748throw chc.conContext.fatal(Alert.INTERNAL_ERROR,749"Failure to derive application secrets", gse);750}751752// The resumption master secret is stored in the session so753// it can be used after the handshake is completed.754SSLSecretDerivation sd = ((SSLSecretDerivation) kd).forContext(chc);755SecretKey resumptionMasterSecret = sd.deriveKey(756"TlsResumptionMasterSecret", null);757chc.handshakeSession.setResumptionMasterSecret(758resumptionMasterSecret);759760chc.conContext.conSession = chc.handshakeSession.finish();761chc.conContext.protocolVersion = chc.negotiatedProtocol;762763// handshake context cleanup.764chc.handshakeFinished = true;765chc.conContext.finishHandshake();766recordEvent(chc.conContext.conSession);767768769// The handshake message has been delivered.770return null;771}772773private byte[] onProduceFinished(ServerHandshakeContext shc,774HandshakeMessage message) throws IOException {775// Refresh handshake hash776shc.handshakeHash.update();777778FinishedMessage fm = new FinishedMessage(shc);779if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {780SSLLogger.fine(781"Produced server Finished handshake message", fm);782}783784// Output the handshake message.785fm.write(shc.handshakeOutput);786shc.handshakeOutput.flush();787788// Change client/server application traffic secrets.789SSLKeyDerivation kd = shc.handshakeKeyDerivation;790if (kd == null) {791// unlikely792throw shc.conContext.fatal(Alert.INTERNAL_ERROR,793"no key derivation");794}795796SSLTrafficKeyDerivation kdg =797SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);798if (kdg == null) {799// unlikely800throw shc.conContext.fatal(Alert.INTERNAL_ERROR,801"Not supported key derivation: " +802shc.negotiatedProtocol);803}804805// derive salt secret806try {807SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);808809// derive application secrets810HashAlg hashAlg = shc.negotiatedCipherSuite.hashAlg;811HKDF hkdf = new HKDF(hashAlg.name);812byte[] zeros = new byte[hashAlg.hashLength];813SecretKeySpec sharedSecret =814new SecretKeySpec(zeros, "TlsZeroSecret");815SecretKey masterSecret =816hkdf.extract(saltSecret, sharedSecret, "TlsMasterSecret");817818SSLKeyDerivation secretKD =819new SSLSecretDerivation(shc, masterSecret);820821// update the handshake traffic write keys.822SecretKey writeSecret = secretKD.deriveKey(823"TlsServerAppTrafficSecret", null);824SSLKeyDerivation writeKD =825kdg.createKeyDerivation(shc, writeSecret);826SecretKey writeKey = writeKD.deriveKey(827"TlsKey", null);828SecretKey writeIvSecret = writeKD.deriveKey(829"TlsIv", null);830IvParameterSpec writeIv =831new IvParameterSpec(writeIvSecret.getEncoded());832SSLWriteCipher writeCipher =833shc.negotiatedCipherSuite.bulkCipher.createWriteCipher(834Authenticator.valueOf(shc.negotiatedProtocol),835shc.negotiatedProtocol, writeKey, writeIv,836shc.sslContext.getSecureRandom());837838if (writeCipher == null) {839throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,840"Illegal cipher suite (" + shc.negotiatedCipherSuite +841") and protocol version (" + shc.negotiatedProtocol +842")");843}844845shc.baseWriteSecret = writeSecret;846shc.conContext.outputRecord.changeWriteCiphers(847writeCipher, false);848849// update the context for the following key derivation850shc.handshakeKeyDerivation = secretKD;851} catch (GeneralSecurityException gse) {852throw shc.conContext.fatal(Alert.INTERNAL_ERROR,853"Failure to derive application secrets", gse);854}855856/*857* save client verify data for secure renegotiation858*/859if (shc.conContext.secureRenegotiation) {860shc.conContext.serverVerifyData = fm.verifyData;861}862863// Make sure session's context is set864shc.handshakeSession.setContext((SSLSessionContextImpl)865shc.sslContext.engineGetServerSessionContext());866shc.conContext.conSession = shc.handshakeSession.finish();867868// update the context869shc.handshakeConsumers.put(870SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);871872// The handshake message has been delivered.873return null;874}875}876877/**878* The "Finished" handshake message consumer.879*/880private static final class T13FinishedConsumer implements SSLConsumer {881// Prevent instantiation of this class.882private T13FinishedConsumer() {883// blank884}885886@Override887public void consume(ConnectionContext context,888ByteBuffer message) throws IOException {889// The consuming happens in handshake context only.890HandshakeContext hc = (HandshakeContext)context;891if (hc.sslConfig.isClientMode) {892onConsumeFinished(893(ClientHandshakeContext)context, message);894} else {895onConsumeFinished(896(ServerHandshakeContext)context, message);897}898}899900private void onConsumeFinished(ClientHandshakeContext chc,901ByteBuffer message) throws IOException {902// Make sure that any expected CertificateVerify message903// has been received and processed.904if (!chc.isResumption) {905if (chc.handshakeConsumers.containsKey(906SSLHandshake.CERTIFICATE.id) ||907chc.handshakeConsumers.containsKey(908SSLHandshake.CERTIFICATE_VERIFY.id)) {909throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,910"Unexpected Finished handshake message");911}912}913914FinishedMessage fm = new FinishedMessage(chc, message);915if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {916SSLLogger.fine(917"Consuming server Finished handshake message", fm);918}919920// Save client verify data for secure renegotiation.921if (chc.conContext.secureRenegotiation) {922chc.conContext.serverVerifyData = fm.verifyData;923}924925//926// validate927//928// blank929930//931// update932//933// A change_cipher_spec record received after the peer's Finished934// message MUST be treated as an unexpected record type.935chc.conContext.consumers.remove(ContentType.CHANGE_CIPHER_SPEC.id);936937// Change client/server application traffic secrets.938// Refresh handshake hash939chc.handshakeHash.update();940SSLKeyDerivation kd = chc.handshakeKeyDerivation;941if (kd == null) {942// unlikely943throw chc.conContext.fatal(Alert.INTERNAL_ERROR,944"no key derivation");945}946947SSLTrafficKeyDerivation kdg =948SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);949if (kdg == null) {950// unlikely951throw chc.conContext.fatal(Alert.INTERNAL_ERROR,952"Not supported key derivation: " +953chc.negotiatedProtocol);954}955956// save the session957if (!chc.isResumption && chc.handshakeSession.isRejoinable()) {958((SSLSessionContextImpl)chc.sslContext.959engineGetClientSessionContext()).960put(chc.handshakeSession);961}962963// derive salt secret964try {965SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);966967// derive application secrets968HashAlg hashAlg = chc.negotiatedCipherSuite.hashAlg;969HKDF hkdf = new HKDF(hashAlg.name);970byte[] zeros = new byte[hashAlg.hashLength];971SecretKeySpec sharedSecret =972new SecretKeySpec(zeros, "TlsZeroSecret");973SecretKey masterSecret =974hkdf.extract(saltSecret, sharedSecret, "TlsMasterSecret");975976SSLKeyDerivation secretKD =977new SSLSecretDerivation(chc, masterSecret);978979// update the handshake traffic read keys.980SecretKey readSecret = secretKD.deriveKey(981"TlsServerAppTrafficSecret", null);982SSLKeyDerivation writeKD =983kdg.createKeyDerivation(chc, readSecret);984SecretKey readKey = writeKD.deriveKey(985"TlsKey", null);986SecretKey readIvSecret = writeKD.deriveKey(987"TlsIv", null);988IvParameterSpec readIv =989new IvParameterSpec(readIvSecret.getEncoded());990SSLReadCipher readCipher =991chc.negotiatedCipherSuite.bulkCipher.createReadCipher(992Authenticator.valueOf(chc.negotiatedProtocol),993chc.negotiatedProtocol, readKey, readIv,994chc.sslContext.getSecureRandom());995996if (readCipher == null) {997throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,998"Illegal cipher suite (" + chc.negotiatedCipherSuite +999") and protocol version (" + chc.negotiatedProtocol +1000")");1001}10021003chc.baseReadSecret = readSecret;1004chc.conContext.inputRecord.changeReadCiphers(readCipher);10051006// update the context for the following key derivation1007chc.handshakeKeyDerivation = secretKD;1008} catch (GeneralSecurityException gse) {1009throw chc.conContext.fatal(Alert.INTERNAL_ERROR,1010"Failure to derive application secrets", gse);1011}10121013//1014// produce1015//1016chc.handshakeProducers.put(SSLHandshake.FINISHED.id,1017SSLHandshake.FINISHED);1018SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {1019// full handshake messages1020SSLHandshake.CERTIFICATE,1021SSLHandshake.CERTIFICATE_VERIFY,1022SSLHandshake.FINISHED1023};10241025for (SSLHandshake hs : probableHandshakeMessages) {1026HandshakeProducer handshakeProducer =1027chc.handshakeProducers.remove(hs.id);1028if (handshakeProducer != null) {1029handshakeProducer.produce(chc, null);1030}1031}1032}10331034private void onConsumeFinished(ServerHandshakeContext shc,1035ByteBuffer message) throws IOException {1036// Make sure that any expected CertificateVerify message1037// has been received and processed.1038if (!shc.isResumption) {1039if (shc.handshakeConsumers.containsKey(1040SSLHandshake.CERTIFICATE.id) ||1041shc.handshakeConsumers.containsKey(1042SSLHandshake.CERTIFICATE_VERIFY.id)) {1043throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,1044"Unexpected Finished handshake message");1045}1046}10471048FinishedMessage fm = new FinishedMessage(shc, message);1049if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {1050SSLLogger.fine(1051"Consuming client Finished handshake message", fm);1052}10531054if (shc.conContext.secureRenegotiation) {1055shc.conContext.clientVerifyData = fm.verifyData;1056}10571058//1059// validate1060//1061// blank10621063//1064// update1065//1066// Change client/server application traffic secrets.1067SSLKeyDerivation kd = shc.handshakeKeyDerivation;1068if (kd == null) {1069// unlikely1070throw shc.conContext.fatal(Alert.INTERNAL_ERROR,1071"no key derivation");1072}10731074SSLTrafficKeyDerivation kdg =1075SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);1076if (kdg == null) {1077// unlikely1078throw shc.conContext.fatal(Alert.INTERNAL_ERROR,1079"Not supported key derivation: " +1080shc.negotiatedProtocol);1081}10821083try {1084// update the application traffic read keys.1085SecretKey readSecret = kd.deriveKey(1086"TlsClientAppTrafficSecret", null);10871088SSLKeyDerivation readKD =1089kdg.createKeyDerivation(shc, readSecret);1090SecretKey readKey = readKD.deriveKey(1091"TlsKey", null);1092SecretKey readIvSecret = readKD.deriveKey(1093"TlsIv", null);1094IvParameterSpec readIv =1095new IvParameterSpec(readIvSecret.getEncoded());1096SSLReadCipher readCipher =1097shc.negotiatedCipherSuite.bulkCipher.createReadCipher(1098Authenticator.valueOf(shc.negotiatedProtocol),1099shc.negotiatedProtocol, readKey, readIv,1100shc.sslContext.getSecureRandom());11011102if (readCipher == null) {1103throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,1104"Illegal cipher suite (" + shc.negotiatedCipherSuite +1105") and protocol version (" + shc.negotiatedProtocol +1106")");1107}11081109shc.baseReadSecret = readSecret;1110shc.conContext.inputRecord.changeReadCiphers(readCipher);11111112// The resumption master secret is stored in the session so1113// it can be used after the handshake is completed.1114shc.handshakeHash.update();1115SSLSecretDerivation sd =1116((SSLSecretDerivation)kd).forContext(shc);1117SecretKey resumptionMasterSecret = sd.deriveKey(1118"TlsResumptionMasterSecret", null);1119shc.handshakeSession.setResumptionMasterSecret(1120resumptionMasterSecret);1121} catch (GeneralSecurityException gse) {1122throw shc.conContext.fatal(Alert.INTERNAL_ERROR,1123"Failure to derive application secrets", gse);1124}11251126// update connection context1127shc.conContext.conSession = shc.handshakeSession.finish();1128shc.conContext.protocolVersion = shc.negotiatedProtocol;11291130// handshake context cleanup.1131shc.handshakeFinished = true;11321133// May need to retransmit the last flight for DTLS.1134if (!shc.sslContext.isDTLS()) {1135shc.conContext.finishHandshake();1136}1137recordEvent(shc.conContext.conSession);11381139//1140// produce1141NewSessionTicket.t13PosthandshakeProducer.produce(shc);1142}1143}11441145private static void recordEvent(SSLSessionImpl session) {1146TLSHandshakeEvent event = new TLSHandshakeEvent();1147if (event.shouldCommit() || EventHelper.isLoggingSecurity()) {1148int peerCertificateId = 0;1149try {1150// use hash code for Id1151peerCertificateId = session1152.getCertificateChain()[0]1153.hashCode();1154} catch (SSLPeerUnverifiedException e) {1155// not verified msg1156}1157if (event.shouldCommit()) {1158event.peerHost = session.getPeerHost();1159event.peerPort = session.getPeerPort();1160event.cipherSuite = session.getCipherSuite();1161event.protocolVersion = session.getProtocol();1162event.certificateId = peerCertificateId;1163event.commit();1164}1165if (EventHelper.isLoggingSecurity()) {1166EventHelper.logTLSHandshakeEvent(null,1167session.getPeerHost(),1168session.getPeerPort(),1169session.getCipherSuite(),1170session.getProtocol(),1171peerCertificateId);1172}1173}1174}1175}117611771178