Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/Finished.java
38830 views
/*1* Copyright (c) 2015, 2018, 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;4243import sun.security.internal.spec.TlsPrfParameterSpec;44import sun.security.ssl.CipherSuite.HashAlg;45import static sun.security.ssl.CipherSuite.HashAlg.H_NONE;46import sun.security.ssl.SSLBasicKeyDerivation.SecretSizeSpec;47import sun.security.ssl.SSLCipher.SSLReadCipher;48import sun.security.ssl.SSLCipher.SSLWriteCipher;49import sun.security.ssl.SSLHandshake.HandshakeMessage;50import sun.misc.HexDumpEncoder;5152/**53* Pack of the Finished handshake message.54*/55final class Finished {56static final SSLConsumer t12HandshakeConsumer =57new T12FinishedConsumer();58static final HandshakeProducer t12HandshakeProducer =59new T12FinishedProducer();6061static final SSLConsumer t13HandshakeConsumer =62new T13FinishedConsumer();63static final HandshakeProducer t13HandshakeProducer =64new T13FinishedProducer();6566/**67* The Finished handshake message.68*/69private static final class FinishedMessage extends HandshakeMessage {70private final byte[] verifyData;7172FinishedMessage(HandshakeContext context) throws IOException {73super(context);7475VerifyDataScheme vds =76VerifyDataScheme.valueOf(context.negotiatedProtocol);7778byte[] vd = null;79try {80vd = vds.createVerifyData(context, false);81} catch (IOException ioe) {82throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,83"Failed to generate verify_data", ioe);84}8586this.verifyData = vd;87}8889FinishedMessage(HandshakeContext context,90ByteBuffer m) throws IOException {91super(context);92int verifyDataLen = 12;93if (context.negotiatedProtocol == ProtocolVersion.SSL30) {94verifyDataLen = 36;95} else if (context.negotiatedProtocol.useTLS13PlusSpec()) {96verifyDataLen =97context.negotiatedCipherSuite.hashAlg.hashLength;98}99100if (m.remaining() != verifyDataLen) {101throw context.conContext.fatal(Alert.DECODE_ERROR,102"Inappropriate finished message: need " + verifyDataLen +103" but remaining " + m.remaining() + " bytes verify_data");104}105106this.verifyData = new byte[verifyDataLen];107m.get(verifyData);108109VerifyDataScheme vd =110VerifyDataScheme.valueOf(context.negotiatedProtocol);111byte[] myVerifyData;112try {113myVerifyData = vd.createVerifyData(context, true);114} catch (IOException ioe) {115throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,116"Failed to generate verify_data", ioe);117}118if (!MessageDigest.isEqual(myVerifyData, verifyData)) {119throw context.conContext.fatal(Alert.DECRYPT_ERROR,120"The Finished message cannot be verified.");121}122}123124@Override125public SSLHandshake handshakeType() {126return SSLHandshake.FINISHED;127}128129@Override130public int messageLength() {131return verifyData.length;132}133134@Override135public void send(HandshakeOutStream hos) throws IOException {136hos.write(verifyData);137}138139@Override140public String toString() {141MessageFormat messageFormat = new MessageFormat(142"\"Finished\": '{'\n" +143" \"verify data\": '{'\n" +144"{0}\n" +145" '}'" +146"'}'",147Locale.ENGLISH);148149HexDumpEncoder hexEncoder = new HexDumpEncoder();150Object[] messageFields = {151Utilities.indent(hexEncoder.encode(verifyData), " "),152};153return messageFormat.format(messageFields);154}155}156157interface VerifyDataGenerator {158byte[] createVerifyData(HandshakeContext context,159boolean isValidation) throws IOException;160}161162enum VerifyDataScheme {163SSL30 ("kdf_ssl30", new S30VerifyDataGenerator()),164TLS10 ("kdf_tls10", new T10VerifyDataGenerator()),165TLS12 ("kdf_tls12", new T12VerifyDataGenerator()),166TLS13 ("kdf_tls13", new T13VerifyDataGenerator());167168final String name;169final VerifyDataGenerator generator;170171VerifyDataScheme(String name, VerifyDataGenerator verifyDataGenerator) {172this.name = name;173this.generator = verifyDataGenerator;174}175176static VerifyDataScheme valueOf(ProtocolVersion protocolVersion) {177switch (protocolVersion) {178case SSL30:179return VerifyDataScheme.SSL30;180case TLS10:181case TLS11:182return VerifyDataScheme.TLS10;183case TLS12:184return VerifyDataScheme.TLS12;185case TLS13:186return VerifyDataScheme.TLS13;187default:188return null;189}190}191192public byte[] createVerifyData(HandshakeContext context,193boolean isValidation) throws IOException {194if (generator != null) {195return generator.createVerifyData(context, isValidation);196}197198throw new UnsupportedOperationException("Not supported yet.");199}200}201202// SSL 3.0203private static final204class S30VerifyDataGenerator implements VerifyDataGenerator {205@Override206public byte[] createVerifyData(HandshakeContext context,207boolean isValidation) throws IOException {208HandshakeHash handshakeHash = context.handshakeHash;209SecretKey masterSecretKey =210context.handshakeSession.getMasterSecret();211212boolean useClientLabel =213(context.sslConfig.isClientMode && !isValidation) ||214(!context.sslConfig.isClientMode && isValidation);215return handshakeHash.digest(useClientLabel, masterSecretKey);216}217}218219// TLS 1.0, TLS 1.1220private static final221class T10VerifyDataGenerator implements VerifyDataGenerator {222@Override223public byte[] createVerifyData(HandshakeContext context,224boolean isValidation) throws IOException {225HandshakeHash handshakeHash = context.handshakeHash;226SecretKey masterSecretKey =227context.handshakeSession.getMasterSecret();228229boolean useClientLabel =230(context.sslConfig.isClientMode && !isValidation) ||231(!context.sslConfig.isClientMode && isValidation);232String tlsLabel;233if (useClientLabel) {234tlsLabel = "client finished";235} else {236tlsLabel = "server finished";237}238239try {240byte[] seed = handshakeHash.digest();241String prfAlg = "SunTlsPrf";242HashAlg hashAlg = H_NONE;243244/*245* RFC 5246/7.4.9 says that finished messages can246* be ciphersuite-specific in both length/PRF hash247* algorithm. If we ever run across a different248* length, this call will need to be updated.249*/250@SuppressWarnings("deprecation")251TlsPrfParameterSpec spec = new TlsPrfParameterSpec(252masterSecretKey, tlsLabel, seed, 12,253hashAlg.name, hashAlg.hashLength, hashAlg.blockSize);254KeyGenerator kg = JsseJce.getKeyGenerator(prfAlg);255kg.init(spec);256SecretKey prfKey = kg.generateKey();257if (!"RAW".equals(prfKey.getFormat())) {258throw new ProviderException(259"Invalid PRF output, format must be RAW. " +260"Format received: " + prfKey.getFormat());261}262byte[] finished = prfKey.getEncoded();263return finished;264} catch (GeneralSecurityException e) {265throw new RuntimeException("PRF failed", e);266}267}268}269270// TLS 1.2271private static final272class T12VerifyDataGenerator implements VerifyDataGenerator {273@Override274public byte[] createVerifyData(HandshakeContext context,275boolean isValidation) throws IOException {276CipherSuite cipherSuite = context.negotiatedCipherSuite;277HandshakeHash handshakeHash = context.handshakeHash;278SecretKey masterSecretKey =279context.handshakeSession.getMasterSecret();280281boolean useClientLabel =282(context.sslConfig.isClientMode && !isValidation) ||283(!context.sslConfig.isClientMode && isValidation);284String tlsLabel;285if (useClientLabel) {286tlsLabel = "client finished";287} else {288tlsLabel = "server finished";289}290291try {292byte[] seed = handshakeHash.digest();293String prfAlg = "SunTls12Prf";294HashAlg hashAlg = cipherSuite.hashAlg;295296/*297* RFC 5246/7.4.9 says that finished messages can298* be ciphersuite-specific in both length/PRF hash299* algorithm. If we ever run across a different300* length, this call will need to be updated.301*/302@SuppressWarnings("deprecation")303TlsPrfParameterSpec spec = new TlsPrfParameterSpec(304masterSecretKey, tlsLabel, seed, 12,305hashAlg.name, hashAlg.hashLength, hashAlg.blockSize);306KeyGenerator kg = JsseJce.getKeyGenerator(prfAlg);307kg.init(spec);308SecretKey prfKey = kg.generateKey();309if (!"RAW".equals(prfKey.getFormat())) {310throw new ProviderException(311"Invalid PRF output, format must be RAW. " +312"Format received: " + prfKey.getFormat());313}314byte[] finished = prfKey.getEncoded();315return finished;316} catch (GeneralSecurityException e) {317throw new RuntimeException("PRF failed", e);318}319}320}321322// TLS 1.2323private static final324class T13VerifyDataGenerator implements VerifyDataGenerator {325private static final byte[] hkdfLabel = "tls13 finished".getBytes();326private static final byte[] hkdfContext = new byte[0];327328@Override329public byte[] createVerifyData(HandshakeContext context,330boolean isValidation) throws IOException {331// create finished secret key332HashAlg hashAlg =333context.negotiatedCipherSuite.hashAlg;334SecretKey secret = isValidation ?335context.baseReadSecret : context.baseWriteSecret;336SSLBasicKeyDerivation kdf = new SSLBasicKeyDerivation(337secret, hashAlg.name,338hkdfLabel, hkdfContext, hashAlg.hashLength);339AlgorithmParameterSpec keySpec =340new SecretSizeSpec(hashAlg.hashLength);341SecretKey finishedSecret =342kdf.deriveKey("TlsFinishedSecret", keySpec);343344String hmacAlg =345"Hmac" + hashAlg.name.replace("-", "");346try {347Mac hmac = JsseJce.getMac(hmacAlg);348hmac.init(finishedSecret);349return hmac.doFinal(context.handshakeHash.digest());350} catch (NoSuchAlgorithmException |InvalidKeyException ex) {351throw new ProviderException(352"Failed to generate verify_data", ex);353}354}355}356357/**358* The "Finished" handshake message producer.359*/360private static final361class T12FinishedProducer implements HandshakeProducer {362// Prevent instantiation of this class.363private T12FinishedProducer() {364// blank365}366367@Override368public byte[] produce(ConnectionContext context,369HandshakeMessage message) throws IOException {370// The consuming happens in handshake context only.371HandshakeContext hc = (HandshakeContext)context;372if (hc.sslConfig.isClientMode) {373return onProduceFinished(374(ClientHandshakeContext)context, message);375} else {376return onProduceFinished(377(ServerHandshakeContext)context, message);378}379}380381private byte[] onProduceFinished(ClientHandshakeContext chc,382HandshakeMessage message) throws IOException {383// Refresh handshake hash384chc.handshakeHash.update();385386FinishedMessage fm = new FinishedMessage(chc);387388// Change write cipher and delivery ChangeCipherSpec message.389ChangeCipherSpec.t10Producer.produce(chc, message);390391if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {392SSLLogger.fine(393"Produced client Finished handshake message", fm);394}395396// Output the handshake message.397fm.write(chc.handshakeOutput);398chc.handshakeOutput.flush();399400/*401* save server verify data for secure renegotiation402*/403if (chc.conContext.secureRenegotiation) {404chc.conContext.clientVerifyData = fm.verifyData;405}406407// update the consumers and producers408if (!chc.isResumption) {409chc.conContext.consumers.put(ContentType.CHANGE_CIPHER_SPEC.id,410ChangeCipherSpec.t10Consumer);411chc.handshakeConsumers.put(412SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);413} else {414if (chc.handshakeSession.isRejoinable()) {415((SSLSessionContextImpl)chc.sslContext.416engineGetClientSessionContext()).put(417chc.handshakeSession);418}419chc.conContext.conSession = chc.handshakeSession.finish();420chc.conContext.protocolVersion = chc.negotiatedProtocol;421422// handshake context cleanup.423chc.handshakeFinished = true;424425chc.conContext.finishHandshake();426}427428// The handshake message has been delivered.429return null;430}431432private byte[] onProduceFinished(ServerHandshakeContext shc,433HandshakeMessage message) throws IOException {434// Refresh handshake hash435shc.handshakeHash.update();436437FinishedMessage fm = new FinishedMessage(shc);438439// Change write cipher and delivery ChangeCipherSpec message.440ChangeCipherSpec.t10Producer.produce(shc, message);441442if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {443SSLLogger.fine(444"Produced server Finished handshake message", fm);445}446447// Output the handshake message.448fm.write(shc.handshakeOutput);449shc.handshakeOutput.flush();450451/*452* save client verify data for secure renegotiation453*/454if (shc.conContext.secureRenegotiation) {455shc.conContext.serverVerifyData = fm.verifyData;456}457458// update the consumers and producers459if (shc.isResumption) {460shc.conContext.consumers.put(ContentType.CHANGE_CIPHER_SPEC.id,461ChangeCipherSpec.t10Consumer);462shc.handshakeConsumers.put(463SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);464} else {465if (shc.handshakeSession.isRejoinable()) {466((SSLSessionContextImpl)shc.sslContext.467engineGetServerSessionContext()).put(468shc.handshakeSession);469}470shc.conContext.conSession = shc.handshakeSession.finish();471shc.conContext.protocolVersion = shc.negotiatedProtocol;472473// handshake context cleanup.474shc.handshakeFinished = true;475476shc.conContext.finishHandshake();477}478479// The handshake message has been delivered.480return null;481}482}483484/**485* The "Finished" handshake message consumer.486*/487private static final class T12FinishedConsumer implements SSLConsumer {488// Prevent instantiation of this class.489private T12FinishedConsumer() {490// blank491}492493@Override494public void consume(ConnectionContext context,495ByteBuffer message) throws IOException {496// The consuming happens in handshake context only.497HandshakeContext hc = (HandshakeContext)context;498499// This consumer can be used only once.500hc.handshakeConsumers.remove(SSLHandshake.FINISHED.id);501502// We should not be processing finished messages unless503// we have received ChangeCipherSpec504if (hc.conContext.consumers.containsKey(505ContentType.CHANGE_CIPHER_SPEC.id)) {506throw hc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,507"Missing ChangeCipherSpec message");508}509510if (hc.sslConfig.isClientMode) {511onConsumeFinished((ClientHandshakeContext)context, message);512} else {513onConsumeFinished((ServerHandshakeContext)context, message);514}515}516517private void onConsumeFinished(ClientHandshakeContext chc,518ByteBuffer message) throws IOException {519FinishedMessage fm = new FinishedMessage(chc, message);520if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {521SSLLogger.fine(522"Consuming server Finished handshake message", fm);523}524525if (chc.conContext.secureRenegotiation) {526chc.conContext.serverVerifyData = fm.verifyData;527}528529if (!chc.isResumption) {530if (chc.handshakeSession.isRejoinable()) {531((SSLSessionContextImpl)chc.sslContext.532engineGetClientSessionContext()).put(533chc.handshakeSession);534}535chc.conContext.conSession = chc.handshakeSession.finish();536chc.conContext.protocolVersion = chc.negotiatedProtocol;537538// handshake context cleanup.539chc.handshakeFinished = true;540541chc.conContext.finishHandshake();542} else {543chc.handshakeProducers.put(SSLHandshake.FINISHED.id,544SSLHandshake.FINISHED);545}546547//548// produce549//550SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {551SSLHandshake.FINISHED552};553554for (SSLHandshake hs : probableHandshakeMessages) {555HandshakeProducer handshakeProducer =556chc.handshakeProducers.remove(hs.id);557if (handshakeProducer != null) {558handshakeProducer.produce(chc, fm);559}560}561}562563private void onConsumeFinished(ServerHandshakeContext shc,564ByteBuffer message) throws IOException {565// Make sure that any expected CertificateVerify message566// has been received and processed.567if (!shc.isResumption) {568if (shc.handshakeConsumers.containsKey(569SSLHandshake.CERTIFICATE_VERIFY.id)) {570throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,571"Unexpected Finished handshake message");572}573}574575FinishedMessage fm = new FinishedMessage(shc, message);576if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {577SSLLogger.fine(578"Consuming client Finished handshake message", fm);579}580581if (shc.conContext.secureRenegotiation) {582shc.conContext.clientVerifyData = fm.verifyData;583}584585if (shc.isResumption) {586if (shc.handshakeSession.isRejoinable()) {587((SSLSessionContextImpl)shc.sslContext.588engineGetServerSessionContext()).put(589shc.handshakeSession);590}591shc.conContext.conSession = shc.handshakeSession.finish();592shc.conContext.protocolVersion = shc.negotiatedProtocol;593594// handshake context cleanup.595shc.handshakeFinished = true;596597shc.conContext.finishHandshake();598} else {599shc.handshakeProducers.put(SSLHandshake.FINISHED.id,600SSLHandshake.FINISHED);601}602603//604// produce605//606SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {607SSLHandshake.FINISHED608};609610for (SSLHandshake hs : probableHandshakeMessages) {611HandshakeProducer handshakeProducer =612shc.handshakeProducers.remove(hs.id);613if (handshakeProducer != null) {614handshakeProducer.produce(shc, fm);615}616}617}618}619620/**621* The "Finished" handshake message producer.622*/623private static final624class T13FinishedProducer implements HandshakeProducer {625// Prevent instantiation of this class.626private T13FinishedProducer() {627// blank628}629630@Override631public byte[] produce(ConnectionContext context,632HandshakeMessage message) throws IOException {633// The consuming happens in handshake context only.634HandshakeContext hc = (HandshakeContext)context;635if (hc.sslConfig.isClientMode) {636return onProduceFinished(637(ClientHandshakeContext)context, message);638} else {639return onProduceFinished(640(ServerHandshakeContext)context, message);641}642}643644private byte[] onProduceFinished(ClientHandshakeContext chc,645HandshakeMessage message) throws IOException {646// Refresh handshake hash647chc.handshakeHash.update();648649FinishedMessage fm = new FinishedMessage(chc);650if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {651SSLLogger.fine(652"Produced client Finished handshake message", fm);653}654655// Output the handshake message.656fm.write(chc.handshakeOutput);657chc.handshakeOutput.flush();658659// save server verify data for secure renegotiation660if (chc.conContext.secureRenegotiation) {661chc.conContext.clientVerifyData = fm.verifyData;662}663664// update the context665// Change client/server application traffic secrets.666SSLKeyDerivation kd = chc.handshakeKeyDerivation;667if (kd == null) {668// unlikely669throw chc.conContext.fatal(Alert.INTERNAL_ERROR,670"no key derivation");671}672673SSLTrafficKeyDerivation kdg =674SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);675if (kdg == null) {676// unlikely677throw chc.conContext.fatal(Alert.INTERNAL_ERROR,678"Not supported key derivation: " +679chc.negotiatedProtocol);680}681682try {683// update the application traffic read keys.684SecretKey writeSecret = kd.deriveKey(685"TlsClientAppTrafficSecret", null);686687SSLKeyDerivation writeKD =688kdg.createKeyDerivation(chc, writeSecret);689SecretKey writeKey = writeKD.deriveKey(690"TlsKey", null);691SecretKey writeIvSecret = writeKD.deriveKey(692"TlsIv", null);693IvParameterSpec writeIv =694new IvParameterSpec(writeIvSecret.getEncoded());695SSLWriteCipher writeCipher =696chc.negotiatedCipherSuite.bulkCipher.createWriteCipher(697Authenticator.valueOf(chc.negotiatedProtocol),698chc.negotiatedProtocol, writeKey, writeIv,699chc.sslContext.getSecureRandom());700701if (writeCipher == null) {702throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,703"Illegal cipher suite (" + chc.negotiatedCipherSuite +704") and protocol version (" + chc.negotiatedProtocol +705")");706}707708chc.baseWriteSecret = writeSecret;709chc.conContext.outputRecord.changeWriteCiphers(710writeCipher, false);711712} catch (GeneralSecurityException gse) {713throw chc.conContext.fatal(Alert.INTERNAL_ERROR,714"Failure to derive application secrets", gse);715}716717// The resumption master secret is stored in the session so718// it can be used after the handshake is completed.719SSLSecretDerivation sd = ((SSLSecretDerivation) kd).forContext(chc);720SecretKey resumptionMasterSecret = sd.deriveKey(721"TlsResumptionMasterSecret", null);722chc.handshakeSession.setResumptionMasterSecret(723resumptionMasterSecret);724725chc.conContext.conSession = chc.handshakeSession.finish();726chc.conContext.protocolVersion = chc.negotiatedProtocol;727728// handshake context cleanup.729chc.handshakeFinished = true;730chc.conContext.finishHandshake();731732733// The handshake message has been delivered.734return null;735}736737private byte[] onProduceFinished(ServerHandshakeContext shc,738HandshakeMessage message) throws IOException {739// Refresh handshake hash740shc.handshakeHash.update();741742FinishedMessage fm = new FinishedMessage(shc);743if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {744SSLLogger.fine(745"Produced server Finished handshake message", fm);746}747748// Output the handshake message.749fm.write(shc.handshakeOutput);750shc.handshakeOutput.flush();751752// Change client/server application traffic secrets.753SSLKeyDerivation kd = shc.handshakeKeyDerivation;754if (kd == null) {755// unlikely756throw shc.conContext.fatal(Alert.INTERNAL_ERROR,757"no key derivation");758}759760SSLTrafficKeyDerivation kdg =761SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);762if (kdg == null) {763// unlikely764throw shc.conContext.fatal(Alert.INTERNAL_ERROR,765"Not supported key derivation: " +766shc.negotiatedProtocol);767}768769// derive salt secret770try {771SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);772773// derive application secrets774HashAlg hashAlg = shc.negotiatedCipherSuite.hashAlg;775HKDF hkdf = new HKDF(hashAlg.name);776byte[] zeros = new byte[hashAlg.hashLength];777SecretKeySpec sharedSecret =778new SecretKeySpec(zeros, "TlsZeroSecret");779SecretKey masterSecret =780hkdf.extract(saltSecret, sharedSecret, "TlsMasterSecret");781782SSLKeyDerivation secretKD =783new SSLSecretDerivation(shc, masterSecret);784785// update the handshake traffic write keys.786SecretKey writeSecret = secretKD.deriveKey(787"TlsServerAppTrafficSecret", null);788SSLKeyDerivation writeKD =789kdg.createKeyDerivation(shc, writeSecret);790SecretKey writeKey = writeKD.deriveKey(791"TlsKey", null);792SecretKey writeIvSecret = writeKD.deriveKey(793"TlsIv", null);794IvParameterSpec writeIv =795new IvParameterSpec(writeIvSecret.getEncoded());796SSLWriteCipher writeCipher =797shc.negotiatedCipherSuite.bulkCipher.createWriteCipher(798Authenticator.valueOf(shc.negotiatedProtocol),799shc.negotiatedProtocol, writeKey, writeIv,800shc.sslContext.getSecureRandom());801802if (writeCipher == null) {803throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,804"Illegal cipher suite (" + shc.negotiatedCipherSuite +805") and protocol version (" + shc.negotiatedProtocol +806")");807}808809shc.baseWriteSecret = writeSecret;810shc.conContext.outputRecord.changeWriteCiphers(811writeCipher, false);812813// update the context for the following key derivation814shc.handshakeKeyDerivation = secretKD;815} catch (GeneralSecurityException gse) {816throw shc.conContext.fatal(Alert.INTERNAL_ERROR,817"Failure to derive application secrets", gse);818}819820/*821* save client verify data for secure renegotiation822*/823if (shc.conContext.secureRenegotiation) {824shc.conContext.serverVerifyData = fm.verifyData;825}826827// update the context828shc.handshakeConsumers.put(829SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);830831// The handshake message has been delivered.832return null;833}834}835836/**837* The "Finished" handshake message consumer.838*/839private static final class T13FinishedConsumer implements SSLConsumer {840// Prevent instantiation of this class.841private T13FinishedConsumer() {842// blank843}844845@Override846public void consume(ConnectionContext context,847ByteBuffer message) throws IOException {848// The consuming happens in handshake context only.849HandshakeContext hc = (HandshakeContext)context;850if (hc.sslConfig.isClientMode) {851onConsumeFinished(852(ClientHandshakeContext)context, message);853} else {854onConsumeFinished(855(ServerHandshakeContext)context, message);856}857}858859private void onConsumeFinished(ClientHandshakeContext chc,860ByteBuffer message) throws IOException {861// Make sure that any expected CertificateVerify message862// has been received and processed.863if (!chc.isResumption) {864if (chc.handshakeConsumers.containsKey(865SSLHandshake.CERTIFICATE.id) ||866chc.handshakeConsumers.containsKey(867SSLHandshake.CERTIFICATE_VERIFY.id)) {868throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,869"Unexpected Finished handshake message");870}871}872873FinishedMessage fm = new FinishedMessage(chc, message);874if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {875SSLLogger.fine(876"Consuming server Finished handshake message", fm);877}878879// Save client verify data for secure renegotiation.880if (chc.conContext.secureRenegotiation) {881chc.conContext.serverVerifyData = fm.verifyData;882}883884//885// validate886//887// blank888889//890// update891//892// A change_cipher_spec record received after the peer's Finished893// message MUST be treated as an unexpected record type.894chc.conContext.consumers.remove(ContentType.CHANGE_CIPHER_SPEC.id);895896// Change client/server application traffic secrets.897// Refresh handshake hash898chc.handshakeHash.update();899SSLKeyDerivation kd = chc.handshakeKeyDerivation;900if (kd == null) {901// unlikely902throw chc.conContext.fatal(Alert.INTERNAL_ERROR,903"no key derivation");904}905906SSLTrafficKeyDerivation kdg =907SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);908if (kdg == null) {909// unlikely910throw chc.conContext.fatal(Alert.INTERNAL_ERROR,911"Not supported key derivation: " +912chc.negotiatedProtocol);913}914915// save the session916if (!chc.isResumption && chc.handshakeSession.isRejoinable()) {917SSLSessionContextImpl sessionContext = (SSLSessionContextImpl)918chc.sslContext.engineGetClientSessionContext();919sessionContext.put(chc.handshakeSession);920}921922// derive salt secret923try {924SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);925926// derive application secrets927HashAlg hashAlg = chc.negotiatedCipherSuite.hashAlg;928HKDF hkdf = new HKDF(hashAlg.name);929byte[] zeros = new byte[hashAlg.hashLength];930SecretKeySpec sharedSecret =931new SecretKeySpec(zeros, "TlsZeroSecret");932SecretKey masterSecret =933hkdf.extract(saltSecret, sharedSecret, "TlsMasterSecret");934935SSLKeyDerivation secretKD =936new SSLSecretDerivation(chc, masterSecret);937938// update the handshake traffic read keys.939SecretKey readSecret = secretKD.deriveKey(940"TlsServerAppTrafficSecret", null);941SSLKeyDerivation writeKD =942kdg.createKeyDerivation(chc, readSecret);943SecretKey readKey = writeKD.deriveKey(944"TlsKey", null);945SecretKey readIvSecret = writeKD.deriveKey(946"TlsIv", null);947IvParameterSpec readIv =948new IvParameterSpec(readIvSecret.getEncoded());949SSLReadCipher readCipher =950chc.negotiatedCipherSuite.bulkCipher.createReadCipher(951Authenticator.valueOf(chc.negotiatedProtocol),952chc.negotiatedProtocol, readKey, readIv,953chc.sslContext.getSecureRandom());954955if (readCipher == null) {956throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,957"Illegal cipher suite (" + chc.negotiatedCipherSuite +958") and protocol version (" + chc.negotiatedProtocol +959")");960}961962chc.baseReadSecret = readSecret;963chc.conContext.inputRecord.changeReadCiphers(readCipher);964965// update the context for the following key derivation966chc.handshakeKeyDerivation = secretKD;967} catch (GeneralSecurityException gse) {968throw chc.conContext.fatal(Alert.INTERNAL_ERROR,969"Failure to derive application secrets", gse);970}971972//973// produce974//975chc.handshakeProducers.put(SSLHandshake.FINISHED.id,976SSLHandshake.FINISHED);977SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {978// full handshake messages979SSLHandshake.CERTIFICATE,980SSLHandshake.CERTIFICATE_VERIFY,981SSLHandshake.FINISHED982};983984for (SSLHandshake hs : probableHandshakeMessages) {985HandshakeProducer handshakeProducer =986chc.handshakeProducers.remove(hs.id);987if (handshakeProducer != null) {988handshakeProducer.produce(chc, null);989}990}991}992993private void onConsumeFinished(ServerHandshakeContext shc,994ByteBuffer message) throws IOException {995// Make sure that any expected CertificateVerify message996// has been received and processed.997if (!shc.isResumption) {998if (shc.handshakeConsumers.containsKey(999SSLHandshake.CERTIFICATE.id) ||1000shc.handshakeConsumers.containsKey(1001SSLHandshake.CERTIFICATE_VERIFY.id)) {1002throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,1003"Unexpected Finished handshake message");1004}1005}10061007FinishedMessage fm = new FinishedMessage(shc, message);1008if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {1009SSLLogger.fine(1010"Consuming client Finished handshake message", fm);1011}10121013if (shc.conContext.secureRenegotiation) {1014shc.conContext.clientVerifyData = fm.verifyData;1015}10161017//1018// validate1019//1020// blank10211022//1023// update1024//1025// Change client/server application traffic secrets.1026SSLKeyDerivation kd = shc.handshakeKeyDerivation;1027if (kd == null) {1028// unlikely1029throw shc.conContext.fatal(Alert.INTERNAL_ERROR,1030"no key derivation");1031}10321033SSLTrafficKeyDerivation kdg =1034SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);1035if (kdg == null) {1036// unlikely1037throw shc.conContext.fatal(Alert.INTERNAL_ERROR,1038"Not supported key derivation: " +1039shc.negotiatedProtocol);1040}10411042// save the session1043if (!shc.isResumption && shc.handshakeSession.isRejoinable()) {1044SSLSessionContextImpl sessionContext = (SSLSessionContextImpl)1045shc.sslContext.engineGetServerSessionContext();1046sessionContext.put(shc.handshakeSession);1047}10481049try {1050// update the application traffic read keys.1051SecretKey readSecret = kd.deriveKey(1052"TlsClientAppTrafficSecret", null);10531054SSLKeyDerivation readKD =1055kdg.createKeyDerivation(shc, readSecret);1056SecretKey readKey = readKD.deriveKey(1057"TlsKey", null);1058SecretKey readIvSecret = readKD.deriveKey(1059"TlsIv", null);1060IvParameterSpec readIv =1061new IvParameterSpec(readIvSecret.getEncoded());1062SSLReadCipher readCipher =1063shc.negotiatedCipherSuite.bulkCipher.createReadCipher(1064Authenticator.valueOf(shc.negotiatedProtocol),1065shc.negotiatedProtocol, readKey, readIv,1066shc.sslContext.getSecureRandom());10671068if (readCipher == null) {1069throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,1070"Illegal cipher suite (" + shc.negotiatedCipherSuite +1071") and protocol version (" + shc.negotiatedProtocol +1072")");1073}10741075shc.baseReadSecret = readSecret;1076shc.conContext.inputRecord.changeReadCiphers(readCipher);10771078// The resumption master secret is stored in the session so1079// it can be used after the handshake is completed.1080shc.handshakeHash.update();1081SSLSecretDerivation sd =1082((SSLSecretDerivation)kd).forContext(shc);1083SecretKey resumptionMasterSecret = sd.deriveKey(1084"TlsResumptionMasterSecret", null);1085shc.handshakeSession.setResumptionMasterSecret(1086resumptionMasterSecret);1087} catch (GeneralSecurityException gse) {1088throw shc.conContext.fatal(Alert.INTERNAL_ERROR,1089"Failure to derive application secrets", gse);1090}10911092// update connection context1093shc.conContext.conSession = shc.handshakeSession.finish();1094shc.conContext.protocolVersion = shc.negotiatedProtocol;10951096// handshake context cleanup.1097shc.handshakeFinished = true;10981099shc.conContext.finishHandshake();11001101//1102// produce1103if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {1104SSLLogger.fine(1105"Sending new session ticket");1106}1107NewSessionTicket.kickstartProducer.produce(shc);11081109}1110}11111112}111311141115