1 /*
   2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. 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 it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * 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 WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 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 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.IOException;
  29 import java.nio.ByteBuffer;
  30 import java.security.GeneralSecurityException;
  31 import java.security.InvalidKeyException;
  32 import java.security.MessageDigest;
  33 import java.security.NoSuchAlgorithmException;
  34 import java.security.ProviderException;
  35 import java.security.spec.AlgorithmParameterSpec;
  36 import java.text.MessageFormat;
  37 import java.util.Locale;
  38 import javax.crypto.KeyGenerator;
  39 import javax.crypto.Mac;
  40 import javax.crypto.SecretKey;
  41 import javax.crypto.spec.IvParameterSpec;
  42 import javax.crypto.spec.SecretKeySpec;
  43 import sun.security.internal.spec.TlsPrfParameterSpec;
  44 import sun.security.ssl.CipherSuite.HashAlg;
  45 import static sun.security.ssl.CipherSuite.HashAlg.H_NONE;
  46 import sun.security.ssl.SSLBasicKeyDerivation.SecretSizeSpec;
  47 import sun.security.ssl.SSLCipher.SSLReadCipher;
  48 import sun.security.ssl.SSLCipher.SSLWriteCipher;
  49 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  50 import sun.security.util.HexDumpEncoder;
  51 
  52 /**
  53  * Pack of the Finished handshake message.
  54  */
  55 final class Finished {
  56     static final SSLConsumer t12HandshakeConsumer =
  57         new T12FinishedConsumer();
  58     static final HandshakeProducer t12HandshakeProducer =
  59         new T12FinishedProducer();
  60 
  61     static final SSLConsumer t13HandshakeConsumer =
  62         new T13FinishedConsumer();
  63     static final HandshakeProducer t13HandshakeProducer =
  64         new T13FinishedProducer();
  65 
  66     /**
  67      * The Finished handshake message.
  68      */
  69     private static final class FinishedMessage extends HandshakeMessage {
  70         private final byte[] verifyData;
  71 
  72         FinishedMessage(HandshakeContext context) throws IOException {
  73             super(context);
  74 
  75             VerifyDataScheme vds =
  76                     VerifyDataScheme.valueOf(context.negotiatedProtocol);
  77 
  78             byte[] vd = null;
  79             try {
  80                 vd = vds.createVerifyData(context, false);
  81             } catch (IOException ioe) {
  82                 context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
  83                         "Failed to generate verify_data", ioe);
  84             }
  85 
  86             this.verifyData = vd;
  87         }
  88 
  89         FinishedMessage(HandshakeContext context,
  90                 ByteBuffer m) throws IOException {
  91             super(context);
  92             int verifyDataLen = 12;
  93             if (context.negotiatedProtocol == ProtocolVersion.SSL30) {
  94                 verifyDataLen = 36;
  95             } else if (context.negotiatedProtocol.useTLS13PlusSpec()) {
  96                 verifyDataLen =
  97                         context.negotiatedCipherSuite.hashAlg.hashLength;
  98             }
  99 
 100             if (m.remaining() != verifyDataLen) {
 101                 context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 102                     "Inappropriate finished message: need " + verifyDataLen +
 103                     " but remaining " + m.remaining() + " bytes verify_data");
 104             }
 105 
 106             this.verifyData = new byte[verifyDataLen];
 107             m.get(verifyData);
 108 
 109             VerifyDataScheme vd =
 110                     VerifyDataScheme.valueOf(context.negotiatedProtocol);
 111             byte[] myVerifyData;
 112             try {
 113                 myVerifyData = vd.createVerifyData(context, true);
 114             } catch (IOException ioe) {
 115                 context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 116                         "Failed to generate verify_data", ioe);
 117                 return;     // make the compiler happy
 118             }
 119             if (!MessageDigest.isEqual(myVerifyData, verifyData)) {
 120                 context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 121                         "The Finished message cannot be verified.");
 122             }
 123         }
 124 
 125         @Override
 126         public SSLHandshake handshakeType() {
 127             return SSLHandshake.FINISHED;
 128         }
 129 
 130         @Override
 131         public int messageLength() {
 132             return verifyData.length;
 133         }
 134 
 135         @Override
 136         public void send(HandshakeOutStream hos) throws IOException {
 137             hos.write(verifyData);
 138         }
 139 
 140         @Override
 141         public String toString() {
 142             MessageFormat messageFormat = new MessageFormat(
 143                     "\"Finished\": '{'\n" +
 144                     "  \"verify data\": '{'\n" +
 145                     "{0}\n" +
 146                     "  '}'" +
 147                     "'}'",
 148                     Locale.ENGLISH);
 149 
 150             HexDumpEncoder hexEncoder = new HexDumpEncoder();
 151             Object[] messageFields = {
 152                     Utilities.indent(hexEncoder.encode(verifyData), "    "),
 153                 };
 154             return messageFormat.format(messageFields);
 155         }
 156     }
 157 
 158     interface VerifyDataGenerator {
 159         byte[] createVerifyData(HandshakeContext context,
 160                 boolean isValidation) throws IOException;
 161     }
 162 
 163     enum VerifyDataScheme {
 164         SSL30       ("kdf_ssl30", new S30VerifyDataGenerator()),
 165         TLS10       ("kdf_tls10", new T10VerifyDataGenerator()),
 166         TLS12       ("kdf_tls12", new T12VerifyDataGenerator()),
 167         TLS13       ("kdf_tls13", new T13VerifyDataGenerator());
 168 
 169         final String name;
 170         final VerifyDataGenerator generator;
 171 
 172         VerifyDataScheme(String name, VerifyDataGenerator verifyDataGenerator) {
 173             this.name = name;
 174             this.generator = verifyDataGenerator;
 175         }
 176 
 177         static VerifyDataScheme valueOf(ProtocolVersion protocolVersion) {
 178             switch (protocolVersion) {
 179                 case SSL30:
 180                     return VerifyDataScheme.SSL30;
 181                 case TLS10:
 182                 case TLS11:
 183                 case DTLS10:
 184                     return VerifyDataScheme.TLS10;
 185                 case TLS12:
 186                 case DTLS12:
 187                     return VerifyDataScheme.TLS12;
 188                 case TLS13:
 189                     return VerifyDataScheme.TLS13;
 190                 default:
 191                     return null;
 192             }
 193         }
 194 
 195         public byte[] createVerifyData(HandshakeContext context,
 196                 boolean isValidation) throws IOException {
 197             if (generator != null) {
 198                 return generator.createVerifyData(context, isValidation);
 199             }
 200 
 201             throw new UnsupportedOperationException("Not supported yet.");
 202         }
 203     }
 204 
 205     // SSL 3.0
 206     private static final
 207             class S30VerifyDataGenerator implements VerifyDataGenerator {
 208         @Override
 209         public byte[] createVerifyData(HandshakeContext context,
 210                 boolean isValidation) throws IOException {
 211             HandshakeHash handshakeHash = context.handshakeHash;
 212             SecretKey masterSecretKey =
 213                     context.handshakeSession.getMasterSecret();
 214 
 215             boolean useClientLabel =
 216                     (context.sslConfig.isClientMode && !isValidation) ||
 217                     (!context.sslConfig.isClientMode && isValidation);
 218             return handshakeHash.digest(useClientLabel, masterSecretKey);
 219         }
 220     }
 221 
 222     // TLS 1.0, TLS 1.1, DTLS 1.0
 223     private static final
 224             class T10VerifyDataGenerator implements VerifyDataGenerator {
 225         @Override
 226         public byte[] createVerifyData(HandshakeContext context,
 227                 boolean isValidation) throws IOException {
 228             HandshakeHash handshakeHash = context.handshakeHash;
 229             SecretKey masterSecretKey =
 230                     context.handshakeSession.getMasterSecret();
 231 
 232             boolean useClientLabel =
 233                     (context.sslConfig.isClientMode && !isValidation) ||
 234                     (!context.sslConfig.isClientMode && isValidation);
 235             String tlsLabel;
 236             if (useClientLabel) {
 237                 tlsLabel = "client finished";
 238             } else {
 239                 tlsLabel = "server finished";
 240             }
 241 
 242             try {
 243                 byte[] seed = handshakeHash.digest();
 244                 String prfAlg = "SunTlsPrf";
 245                 HashAlg hashAlg = H_NONE;
 246 
 247                 /*
 248                  * RFC 5246/7.4.9 says that finished messages can
 249                  * be ciphersuite-specific in both length/PRF hash
 250                  * algorithm.  If we ever run across a different
 251                  * length, this call will need to be updated.
 252                  */
 253                 @SuppressWarnings("deprecation")
 254                 TlsPrfParameterSpec spec = new TlsPrfParameterSpec(
 255                     masterSecretKey, tlsLabel, seed, 12,
 256                     hashAlg.name, hashAlg.hashLength, hashAlg.blockSize);
 257                 KeyGenerator kg = JsseJce.getKeyGenerator(prfAlg);
 258                 kg.init(spec);
 259                 SecretKey prfKey = kg.generateKey();
 260                 if (!"RAW".equals(prfKey.getFormat())) {
 261                     throw new ProviderException(
 262                         "Invalid PRF output, format must be RAW. " +
 263                         "Format received: " + prfKey.getFormat());
 264                 }
 265                 byte[] finished = prfKey.getEncoded();
 266                 return finished;
 267             } catch (GeneralSecurityException e) {
 268                 throw new RuntimeException("PRF failed", e);
 269             }
 270         }
 271     }
 272 
 273     // TLS 1.2
 274     private static final
 275             class T12VerifyDataGenerator implements VerifyDataGenerator {
 276         @Override
 277         public byte[] createVerifyData(HandshakeContext context,
 278                 boolean isValidation) throws IOException {
 279             CipherSuite cipherSuite = context.negotiatedCipherSuite;
 280             HandshakeHash handshakeHash = context.handshakeHash;
 281             SecretKey masterSecretKey =
 282                     context.handshakeSession.getMasterSecret();
 283 
 284             boolean useClientLabel =
 285                     (context.sslConfig.isClientMode && !isValidation) ||
 286                     (!context.sslConfig.isClientMode && isValidation);
 287             String tlsLabel;
 288             if (useClientLabel) {
 289                 tlsLabel = "client finished";
 290             } else {
 291                 tlsLabel = "server finished";
 292             }
 293 
 294             try {
 295                 byte[] seed = handshakeHash.digest();
 296                 String prfAlg = "SunTls12Prf";
 297                 HashAlg hashAlg = cipherSuite.hashAlg;
 298 
 299                 /*
 300                  * RFC 5246/7.4.9 says that finished messages can
 301                  * be ciphersuite-specific in both length/PRF hash
 302                  * algorithm.  If we ever run across a different
 303                  * length, this call will need to be updated.
 304                  */
 305                 @SuppressWarnings("deprecation")
 306                 TlsPrfParameterSpec spec = new TlsPrfParameterSpec(
 307                     masterSecretKey, tlsLabel, seed, 12,
 308                     hashAlg.name, hashAlg.hashLength, hashAlg.blockSize);
 309                 KeyGenerator kg = JsseJce.getKeyGenerator(prfAlg);
 310                 kg.init(spec);
 311                 SecretKey prfKey = kg.generateKey();
 312                 if (!"RAW".equals(prfKey.getFormat())) {
 313                     throw new ProviderException(
 314                         "Invalid PRF output, format must be RAW. " +
 315                         "Format received: " + prfKey.getFormat());
 316                 }
 317                 byte[] finished = prfKey.getEncoded();
 318                 return finished;
 319             } catch (GeneralSecurityException e) {
 320                 throw new RuntimeException("PRF failed", e);
 321             }
 322         }
 323     }
 324 
 325     // TLS 1.2
 326     private static final
 327             class T13VerifyDataGenerator implements VerifyDataGenerator {
 328         private static final byte[] hkdfLabel = "tls13 finished".getBytes();
 329         private static final byte[] hkdfContext = new byte[0];
 330 
 331         @Override
 332         public byte[] createVerifyData(HandshakeContext context,
 333                 boolean isValidation) throws IOException {
 334             // create finished secret key
 335             HashAlg hashAlg =
 336                     context.negotiatedCipherSuite.hashAlg;
 337             SecretKey secret = isValidation ?
 338                     context.baseReadSecret : context.baseWriteSecret;
 339             SSLBasicKeyDerivation kdf = new SSLBasicKeyDerivation(
 340                     secret, hashAlg.name,
 341                     hkdfLabel, hkdfContext, hashAlg.hashLength);
 342             AlgorithmParameterSpec keySpec =
 343                     new SecretSizeSpec(hashAlg.hashLength);
 344             SecretKey finishedSecret =
 345                     kdf.deriveKey("TlsFinishedSecret", keySpec);
 346 
 347             String hmacAlg =
 348                 "Hmac" + hashAlg.name.replace("-", "");
 349             try {
 350                 Mac hmac = JsseJce.getMac(hmacAlg);
 351                 hmac.init(finishedSecret);
 352                 return hmac.doFinal(context.handshakeHash.digest());
 353             } catch (NoSuchAlgorithmException |InvalidKeyException ex) {
 354                 throw new ProviderException(
 355                         "Failed to generate verify_data", ex);
 356             }
 357         }
 358     }
 359 
 360     /**
 361      * The "Finished" handshake message producer.
 362      */
 363     private static final
 364             class T12FinishedProducer implements HandshakeProducer {
 365         // Prevent instantiation of this class.
 366         private T12FinishedProducer() {
 367             // blank
 368         }
 369 
 370         @Override
 371         public byte[] produce(ConnectionContext context,
 372                 HandshakeMessage message) throws IOException {
 373             // The consuming happens in handshake context only.
 374             HandshakeContext hc = (HandshakeContext)context;
 375             if (hc.sslConfig.isClientMode) {
 376                 return onProduceFinished(
 377                         (ClientHandshakeContext)context, message);
 378             } else {
 379                 return onProduceFinished(
 380                         (ServerHandshakeContext)context, message);
 381             }
 382         }
 383 
 384         private byte[] onProduceFinished(ClientHandshakeContext chc,
 385                 HandshakeMessage message) throws IOException {
 386             // Refresh handshake hash
 387             chc.handshakeHash.update();
 388 
 389             FinishedMessage fm = new FinishedMessage(chc);
 390 
 391             // Change write cipher and delivery ChangeCipherSpec message.
 392             ChangeCipherSpec.t10Producer.produce(chc, message);
 393 
 394             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 395                 SSLLogger.fine(
 396                         "Produced client Finished handshake message", fm);
 397             }
 398 
 399             // Output the handshake message.
 400             fm.write(chc.handshakeOutput);
 401             chc.handshakeOutput.flush();
 402 
 403             /*
 404              * save server verify data for secure renegotiation
 405              */
 406             if (chc.conContext.secureRenegotiation) {
 407                 chc.conContext.clientVerifyData = fm.verifyData;
 408             }
 409 
 410             // update the consumers and producers
 411             if (!chc.isResumption) {
 412                 chc.conContext.consumers.put(ContentType.CHANGE_CIPHER_SPEC.id,
 413                         ChangeCipherSpec.t10Consumer);
 414                 chc.handshakeConsumers.put(
 415                         SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);
 416                 chc.conContext.inputRecord.expectingFinishFlight();
 417             } else {
 418                 if (chc.handshakeSession.isRejoinable()) {
 419                     ((SSLSessionContextImpl)chc.sslContext.
 420                         engineGetClientSessionContext()).put(
 421                             chc.handshakeSession);
 422                 }
 423                 chc.conContext.conSession = chc.handshakeSession.finish();
 424                 chc.conContext.protocolVersion = chc.negotiatedProtocol;
 425 
 426                 // handshake context cleanup.
 427                 chc.handshakeFinished = true;
 428 
 429                 // May need to retransmit the last flight for DTLS.
 430                 if (!chc.sslContext.isDTLS()) {
 431                     chc.conContext.finishHandshake();
 432                 }
 433             }
 434 
 435             // The handshake message has been delivered.
 436             return null;
 437         }
 438 
 439         private byte[] onProduceFinished(ServerHandshakeContext shc,
 440                 HandshakeMessage message) throws IOException {
 441             // Refresh handshake hash
 442             shc.handshakeHash.update();
 443 
 444             FinishedMessage fm = new FinishedMessage(shc);
 445 
 446             // Change write cipher and delivery ChangeCipherSpec message.
 447             ChangeCipherSpec.t10Producer.produce(shc, message);
 448 
 449             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 450                 SSLLogger.fine(
 451                         "Produced server Finished handshake message", fm);
 452             }
 453 
 454             // Output the handshake message.
 455             fm.write(shc.handshakeOutput);
 456             shc.handshakeOutput.flush();
 457 
 458             /*
 459              * save client verify data for secure renegotiation
 460              */
 461             if (shc.conContext.secureRenegotiation) {
 462                 shc.conContext.serverVerifyData = fm.verifyData;
 463             }
 464 
 465             // update the consumers and producers
 466             if (shc.isResumption) {
 467                 shc.conContext.consumers.put(ContentType.CHANGE_CIPHER_SPEC.id,
 468                         ChangeCipherSpec.t10Consumer);
 469                 shc.handshakeConsumers.put(
 470                         SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);
 471                 shc.conContext.inputRecord.expectingFinishFlight();
 472             } else {
 473                 if (shc.handshakeSession.isRejoinable()) {
 474                     ((SSLSessionContextImpl)shc.sslContext.
 475                         engineGetServerSessionContext()).put(
 476                             shc.handshakeSession);
 477                 }
 478                 shc.conContext.conSession = shc.handshakeSession.finish();
 479                 shc.conContext.protocolVersion = shc.negotiatedProtocol;
 480 
 481                 // handshake context cleanup.
 482                 shc.handshakeFinished = true;
 483 
 484                 // May need to retransmit the last flight for DTLS.
 485                 if (!shc.sslContext.isDTLS()) {
 486                     shc.conContext.finishHandshake();
 487                 }
 488             }
 489 
 490             // The handshake message has been delivered.
 491             return null;
 492         }
 493     }
 494 
 495     /**
 496      * The "Finished" handshake message consumer.
 497      */
 498     private static final class T12FinishedConsumer implements SSLConsumer {
 499         // Prevent instantiation of this class.
 500         private T12FinishedConsumer() {
 501             // blank
 502         }
 503 
 504         @Override
 505         public void consume(ConnectionContext context,
 506                 ByteBuffer message) throws IOException {
 507             // The consuming happens in handshake context only.
 508             HandshakeContext hc = (HandshakeContext)context;
 509 
 510             // This consumer can be used only once.
 511             hc.handshakeConsumers.remove(SSLHandshake.FINISHED.id);
 512 
 513             // We should not be processing finished messages unless
 514             // we have received ChangeCipherSpec
 515             if (hc.conContext.consumers.containsKey(
 516                     ContentType.CHANGE_CIPHER_SPEC.id)) {
 517                 hc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
 518                         "Missing ChangeCipherSpec message");
 519             }
 520 
 521             if (hc.sslConfig.isClientMode) {
 522                 onConsumeFinished((ClientHandshakeContext)context, message);
 523             } else {
 524                 onConsumeFinished((ServerHandshakeContext)context, message);
 525             }
 526         }
 527 
 528         private void onConsumeFinished(ClientHandshakeContext chc,
 529                 ByteBuffer message) throws IOException {
 530             FinishedMessage fm = new FinishedMessage(chc, message);
 531             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 532                 SSLLogger.fine(
 533                         "Consuming server Finished handshake message", fm);
 534             }
 535 
 536             if (chc.conContext.secureRenegotiation) {
 537                 chc.conContext.serverVerifyData = fm.verifyData;
 538             }
 539 
 540             if (!chc.isResumption) {
 541                 if (chc.handshakeSession.isRejoinable()) {
 542                     ((SSLSessionContextImpl)chc.sslContext.
 543                         engineGetClientSessionContext()).put(
 544                             chc.handshakeSession);
 545                 }
 546                 chc.conContext.conSession = chc.handshakeSession.finish();
 547                 chc.conContext.protocolVersion = chc.negotiatedProtocol;
 548 
 549                 // handshake context cleanup.
 550                 chc.handshakeFinished = true;
 551 
 552                 // May need to retransmit the last flight for DTLS.
 553                 if (!chc.sslContext.isDTLS()) {
 554                     chc.conContext.finishHandshake();
 555                 }
 556             } else {
 557                 chc.handshakeProducers.put(SSLHandshake.FINISHED.id,
 558                         SSLHandshake.FINISHED);
 559             }
 560 
 561             //
 562             // produce
 563             //
 564             SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {
 565                 SSLHandshake.FINISHED
 566             };
 567 
 568             for (SSLHandshake hs : probableHandshakeMessages) {
 569                 HandshakeProducer handshakeProducer =
 570                         chc.handshakeProducers.remove(hs.id);
 571                 if (handshakeProducer != null) {
 572                     handshakeProducer.produce(chc, fm);
 573                 }
 574             }
 575         }
 576 
 577         private void onConsumeFinished(ServerHandshakeContext shc,
 578                 ByteBuffer message) throws IOException {
 579             FinishedMessage fm = new FinishedMessage(shc, message);
 580             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 581                 SSLLogger.fine(
 582                         "Consuming client Finished handshake message", fm);
 583             }
 584 
 585             if (shc.conContext.secureRenegotiation) {
 586                 shc.conContext.clientVerifyData = fm.verifyData;
 587             }
 588 
 589             if (shc.isResumption) {
 590                 if (shc.handshakeSession.isRejoinable()) {
 591                     ((SSLSessionContextImpl)shc.sslContext.
 592                         engineGetServerSessionContext()).put(
 593                             shc.handshakeSession);
 594                 }
 595                 shc.conContext.conSession = shc.handshakeSession.finish();
 596                 shc.conContext.protocolVersion = shc.negotiatedProtocol;
 597 
 598                 // handshake context cleanup.
 599                 shc.handshakeFinished = true;
 600 
 601                 // May need to retransmit the last flight for DTLS.
 602                 if (!shc.sslContext.isDTLS()) {
 603                     shc.conContext.finishHandshake();
 604                 }
 605             } else {
 606                 shc.handshakeProducers.put(SSLHandshake.FINISHED.id,
 607                         SSLHandshake.FINISHED);
 608             }
 609 
 610             //
 611             // produce
 612             //
 613             SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {
 614                 SSLHandshake.FINISHED
 615             };
 616 
 617             for (SSLHandshake hs : probableHandshakeMessages) {
 618                 HandshakeProducer handshakeProducer =
 619                         shc.handshakeProducers.remove(hs.id);
 620                 if (handshakeProducer != null) {
 621                     handshakeProducer.produce(shc, fm);
 622                 }
 623             }
 624         }
 625     }
 626 
 627     /**
 628      * The "Finished" handshake message producer.
 629      */
 630     private static final
 631             class T13FinishedProducer implements HandshakeProducer {
 632         // Prevent instantiation of this class.
 633         private T13FinishedProducer() {
 634             // blank
 635         }
 636 
 637         @Override
 638         public byte[] produce(ConnectionContext context,
 639                 HandshakeMessage message) throws IOException {
 640             // The consuming happens in handshake context only.
 641             HandshakeContext hc = (HandshakeContext)context;
 642             if (hc.sslConfig.isClientMode) {
 643                 return onProduceFinished(
 644                         (ClientHandshakeContext)context, message);
 645             } else {
 646                 return onProduceFinished(
 647                         (ServerHandshakeContext)context, message);
 648             }
 649         }
 650 
 651         private byte[] onProduceFinished(ClientHandshakeContext chc,
 652                 HandshakeMessage message) throws IOException {
 653             // Refresh handshake hash
 654             chc.handshakeHash.update();
 655 
 656             FinishedMessage fm = new FinishedMessage(chc);
 657             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 658                 SSLLogger.fine(
 659                         "Produced client Finished handshake message", fm);
 660             }
 661 
 662             // Output the handshake message.
 663             fm.write(chc.handshakeOutput);
 664             chc.handshakeOutput.flush();
 665 
 666             // save server verify data for secure renegotiation
 667             if (chc.conContext.secureRenegotiation) {
 668                 chc.conContext.clientVerifyData = fm.verifyData;
 669             }
 670 
 671             // update the context
 672             // Change client/server application traffic secrets.
 673             SSLKeyDerivation kd = chc.handshakeKeyDerivation;
 674             if (kd == null) {
 675                 // unlikely
 676                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
 677                     "no key derivation");
 678                 return null;    // make the compiler happy
 679             }
 680 
 681             SSLTrafficKeyDerivation kdg =
 682                     SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);
 683             if (kdg == null) {
 684                 // unlikely
 685                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
 686                         "Not supported key derivation: " +
 687                         chc.negotiatedProtocol);
 688                 return null;    // make the compiler happy
 689             }
 690 
 691             try {
 692                 // update the application traffic read keys.
 693                 SecretKey writeSecret = kd.deriveKey(
 694                         "TlsClientAppTrafficSecret", null);
 695 
 696                 SSLKeyDerivation writeKD =
 697                         kdg.createKeyDerivation(chc, writeSecret);
 698                 SecretKey writeKey = writeKD.deriveKey(
 699                         "TlsKey", null);
 700                 SecretKey writeIvSecret = writeKD.deriveKey(
 701                         "TlsIv", null);
 702                 IvParameterSpec writeIv =
 703                         new IvParameterSpec(writeIvSecret.getEncoded());
 704                 SSLWriteCipher writeCipher =
 705                         chc.negotiatedCipherSuite.bulkCipher.createWriteCipher(
 706                                 Authenticator.valueOf(chc.negotiatedProtocol),
 707                                 chc.negotiatedProtocol, writeKey, writeIv,
 708                                 chc.sslContext.getSecureRandom());
 709 
 710                 chc.baseWriteSecret = writeSecret;
 711                 chc.conContext.outputRecord.changeWriteCiphers(
 712                         writeCipher, false);
 713 
 714             } catch (GeneralSecurityException gse) {
 715                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
 716                         "Failure to derive application secrets", gse);
 717                 return null;    // make the compiler happy
 718             }
 719 
 720             // The resumption master secret is stored in the session so
 721             // it can be used after the handshake is completed.
 722             SSLSecretDerivation sd = ((SSLSecretDerivation) kd).forContext(chc);
 723             SecretKey resumptionMasterSecret = sd.deriveKey(
 724             "TlsResumptionMasterSecret", null);
 725             chc.handshakeSession.setResumptionMasterSecret(resumptionMasterSecret);
 726 
 727             chc.conContext.conSession = chc.handshakeSession.finish();
 728             chc.conContext.protocolVersion = chc.negotiatedProtocol;
 729 
 730             // handshake context cleanup.
 731             chc.handshakeFinished = true;
 732             chc.conContext.finishHandshake();
 733 
 734             // The handshake message has been delivered.
 735             return null;
 736         }
 737 
 738         private byte[] onProduceFinished(ServerHandshakeContext shc,
 739                 HandshakeMessage message) throws IOException {
 740             // Refresh handshake hash
 741             shc.handshakeHash.update();
 742 
 743             FinishedMessage fm = new FinishedMessage(shc);
 744             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 745                 SSLLogger.fine(
 746                         "Produced server Finished handshake message", fm);
 747             }
 748 
 749             // Output the handshake message.
 750             fm.write(shc.handshakeOutput);
 751             shc.handshakeOutput.flush();
 752 
 753             // Change client/server application traffic secrets.
 754             SSLKeyDerivation kd = shc.handshakeKeyDerivation;
 755             if (kd == null) {
 756                 // unlikely
 757                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
 758                     "no key derivation");
 759                 return null;    // make the compiler happy
 760             }
 761 
 762             SSLTrafficKeyDerivation kdg =
 763                     SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
 764             if (kdg == null) {
 765                 // unlikely
 766                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
 767                         "Not supported key derivation: " +
 768                         shc.negotiatedProtocol);
 769                 return null;    // make the compiler happy
 770             }
 771 
 772             // derive salt secret
 773             try {
 774                 SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
 775 
 776                 // derive application secrets
 777                 HashAlg hashAlg = shc.negotiatedCipherSuite.hashAlg;
 778                 HKDF hkdf = new HKDF(hashAlg.name);
 779                 byte[] zeros = new byte[hashAlg.hashLength];
 780                 SecretKeySpec sharedSecret =
 781                         new SecretKeySpec(zeros, "TlsZeroSecret");
 782                 SecretKey masterSecret =
 783                     hkdf.extract(saltSecret, sharedSecret, "TlsMasterSecret");
 784 
 785                 SSLKeyDerivation secretKD =
 786                         new SSLSecretDerivation(shc, masterSecret);
 787 
 788                 // update the handshake traffic write keys.
 789                 SecretKey writeSecret = secretKD.deriveKey(
 790                         "TlsServerAppTrafficSecret", null);
 791                 SSLKeyDerivation writeKD =
 792                         kdg.createKeyDerivation(shc, writeSecret);
 793                 SecretKey writeKey = writeKD.deriveKey(
 794                         "TlsKey", null);
 795                 SecretKey writeIvSecret = writeKD.deriveKey(
 796                         "TlsIv", null);
 797                 IvParameterSpec writeIv =
 798                         new IvParameterSpec(writeIvSecret.getEncoded());
 799                 SSLWriteCipher writeCipher =
 800                         shc.negotiatedCipherSuite.bulkCipher.createWriteCipher(
 801                                 Authenticator.valueOf(shc.negotiatedProtocol),
 802                                 shc.negotiatedProtocol, writeKey, writeIv,
 803                                 shc.sslContext.getSecureRandom());
 804 
 805                 shc.baseWriteSecret = writeSecret;
 806                 shc.conContext.outputRecord.changeWriteCiphers(
 807                         writeCipher, false);
 808 
 809                 // update the context for the following key derivation
 810                 shc.handshakeKeyDerivation = secretKD;
 811             } catch (GeneralSecurityException gse) {
 812                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
 813                         "Failure to derive application secrets", gse);
 814                 return null;    // make the compiler happy
 815             }
 816 
 817             /*
 818              * save client verify data for secure renegotiation
 819              */
 820             if (shc.conContext.secureRenegotiation) {
 821                 shc.conContext.serverVerifyData = fm.verifyData;
 822             }
 823 
 824             // update the context
 825             shc.handshakeConsumers.put(
 826                     SSLHandshake.FINISHED.id, SSLHandshake.FINISHED);
 827 
 828             // The handshake message has been delivered.
 829             return null;
 830         }
 831     }
 832 
 833     /**
 834      * The "Finished" handshake message consumer.
 835      */
 836     private static final class T13FinishedConsumer implements SSLConsumer {
 837         // Prevent instantiation of this class.
 838         private T13FinishedConsumer() {
 839             // blank
 840         }
 841 
 842         @Override
 843         public void consume(ConnectionContext context,
 844                 ByteBuffer message) throws IOException {
 845             // The consuming happens in handshake context only.
 846             HandshakeContext hc = (HandshakeContext)context;
 847             if (hc.sslConfig.isClientMode) {
 848                 onConsumeFinished(
 849                         (ClientHandshakeContext)context, message);
 850             } else {
 851                 onConsumeFinished(
 852                         (ServerHandshakeContext)context, message);
 853             }
 854         }
 855 
 856         private void onConsumeFinished(ClientHandshakeContext chc,
 857                 ByteBuffer message) throws IOException {
 858             FinishedMessage fm = new FinishedMessage(chc, message);
 859             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 860                 SSLLogger.fine(
 861                         "Consuming server Finished handshake message", fm);
 862             }
 863 
 864             // Save client verify data for secure renegotiation.
 865             if (chc.conContext.secureRenegotiation) {
 866                 chc.conContext.serverVerifyData = fm.verifyData;
 867             }
 868 
 869             //
 870             // validate
 871             //
 872             // blank
 873 
 874             //
 875             // update
 876             //
 877             // A change_cipher_spec record received after the peer's Finished
 878             // message MUST be treated as an unexpected record type.
 879             chc.conContext.consumers.remove(ContentType.CHANGE_CIPHER_SPEC.id);
 880 
 881             // Change client/server application traffic secrets.
 882             // Refresh handshake hash
 883             chc.handshakeHash.update();
 884             SSLKeyDerivation kd = chc.handshakeKeyDerivation;
 885             if (kd == null) {
 886                 // unlikely
 887                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
 888                     "no key derivation");
 889                 return;    // make the compiler happy
 890             }
 891 
 892             SSLTrafficKeyDerivation kdg =
 893                     SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);
 894             if (kdg == null) {
 895                 // unlikely
 896                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
 897                         "Not supported key derivation: " +
 898                         chc.negotiatedProtocol);
 899                 return;    // make the compiler happy
 900             }
 901 
 902             // save the session
 903             if (!chc.isResumption && chc.handshakeSession.isRejoinable()) {
 904                 SSLSessionContextImpl sessionContext = (SSLSessionContextImpl)
 905                 chc.sslContext.engineGetClientSessionContext();
 906                 sessionContext.put(chc.handshakeSession);
 907             }
 908 
 909             // derive salt secret
 910             try {
 911                 SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
 912 
 913                 // derive application secrets
 914                 HashAlg hashAlg = chc.negotiatedCipherSuite.hashAlg;
 915                 HKDF hkdf = new HKDF(hashAlg.name);
 916                 byte[] zeros = new byte[hashAlg.hashLength];
 917                 SecretKeySpec sharedSecret =
 918                         new SecretKeySpec(zeros, "TlsZeroSecret");
 919                 SecretKey masterSecret =
 920                     hkdf.extract(saltSecret, sharedSecret, "TlsMasterSecret");
 921 
 922                 SSLKeyDerivation secretKD =
 923                         new SSLSecretDerivation(chc, masterSecret);
 924 
 925                 // update the handshake traffic read keys.
 926                 SecretKey readSecret = secretKD.deriveKey(
 927                         "TlsServerAppTrafficSecret", null);
 928                 SSLKeyDerivation writeKD =
 929                         kdg.createKeyDerivation(chc, readSecret);
 930                 SecretKey readKey = writeKD.deriveKey(
 931                         "TlsKey", null);
 932                 SecretKey readIvSecret = writeKD.deriveKey(
 933                         "TlsIv", null);
 934                 IvParameterSpec readIv =
 935                         new IvParameterSpec(readIvSecret.getEncoded());
 936                 SSLReadCipher readCipher =
 937                         chc.negotiatedCipherSuite.bulkCipher.createReadCipher(
 938                                 Authenticator.valueOf(chc.negotiatedProtocol),
 939                                 chc.negotiatedProtocol, readKey, readIv,
 940                                 chc.sslContext.getSecureRandom());
 941 
 942                 chc.baseReadSecret = readSecret;
 943                 chc.conContext.inputRecord.changeReadCiphers(readCipher);
 944 
 945                 // update the context for the following key derivation
 946                 chc.handshakeKeyDerivation = secretKD;
 947             } catch (GeneralSecurityException gse) {
 948                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
 949                         "Failure to derive application secrets", gse);
 950                 return;    // make the compiler happy
 951             }
 952 
 953             //
 954             // produce
 955             //
 956             chc.handshakeProducers.put(SSLHandshake.FINISHED.id,
 957                         SSLHandshake.FINISHED);
 958             SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {
 959                 // full handshake messages
 960                 SSLHandshake.CERTIFICATE,
 961                 SSLHandshake.CERTIFICATE_VERIFY,
 962                 SSLHandshake.FINISHED
 963             };
 964 
 965             for (SSLHandshake hs : probableHandshakeMessages) {
 966                 HandshakeProducer handshakeProducer =
 967                         chc.handshakeProducers.remove(hs.id);
 968                 if (handshakeProducer != null) {
 969                     handshakeProducer.produce(chc, null);
 970                 }
 971             }
 972         }
 973 
 974         private void onConsumeFinished(ServerHandshakeContext shc,
 975                 ByteBuffer message) throws IOException {
 976             FinishedMessage fm = new FinishedMessage(shc, message);
 977             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 978                 SSLLogger.fine(
 979                         "Consuming client Finished handshake message", fm);
 980             }
 981 
 982             if (shc.conContext.secureRenegotiation) {
 983                 shc.conContext.clientVerifyData = fm.verifyData;
 984             }
 985 
 986             //
 987             // validate
 988             //
 989             // blank
 990 
 991             //
 992             // update
 993             //
 994             // Change client/server application traffic secrets.
 995             SSLKeyDerivation kd = shc.handshakeKeyDerivation;
 996             if (kd == null) {
 997                 // unlikely
 998                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
 999                     "no key derivation");
1000                 return;    // make the compiler happy
1001             }
1002 
1003             SSLTrafficKeyDerivation kdg =
1004                     SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
1005             if (kdg == null) {
1006                 // unlikely
1007                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
1008                         "Not supported key derivation: " +
1009                         shc.negotiatedProtocol);
1010                 return;    // make the compiler happy
1011             }
1012 
1013             // save the session
1014             if (!shc.isResumption && shc.handshakeSession.isRejoinable()) {
1015                 SSLSessionContextImpl sessionContext = (SSLSessionContextImpl)
1016                 shc.sslContext.engineGetServerSessionContext();
1017                 sessionContext.put(shc.handshakeSession);
1018             }
1019 
1020             try {
1021                 // update the application traffic read keys.
1022                 SecretKey readSecret = kd.deriveKey(
1023                         "TlsClientAppTrafficSecret", null);
1024 
1025                 SSLKeyDerivation readKD =
1026                         kdg.createKeyDerivation(shc, readSecret);
1027                 SecretKey readKey = readKD.deriveKey(
1028                         "TlsKey", null);
1029                 SecretKey readIvSecret = readKD.deriveKey(
1030                         "TlsIv", null);
1031                 IvParameterSpec readIv =
1032                         new IvParameterSpec(readIvSecret.getEncoded());
1033                 SSLReadCipher readCipher =
1034                         shc.negotiatedCipherSuite.bulkCipher.createReadCipher(
1035                                 Authenticator.valueOf(shc.negotiatedProtocol),
1036                                 shc.negotiatedProtocol, readKey, readIv,
1037                                 shc.sslContext.getSecureRandom());
1038 
1039                 shc.baseReadSecret = readSecret;
1040                 shc.conContext.inputRecord.changeReadCiphers(readCipher);
1041 
1042                 // The resumption master secret is stored in the session so
1043                 // it can be used after the handshake is completed.
1044                 shc.handshakeHash.update();
1045                 SSLSecretDerivation sd = ((SSLSecretDerivation)kd).forContext(shc);
1046                 SecretKey resumptionMasterSecret = sd.deriveKey(
1047                 "TlsResumptionMasterSecret", null);
1048                 shc.handshakeSession.setResumptionMasterSecret(resumptionMasterSecret);
1049             } catch (GeneralSecurityException gse) {
1050                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
1051                         "Failure to derive application secrets", gse);
1052                 return;    // make the compiler happy
1053             }
1054 
1055             //  update connection context
1056             shc.conContext.conSession = shc.handshakeSession.finish();
1057             shc.conContext.protocolVersion = shc.negotiatedProtocol;
1058 
1059             // handshake context cleanup.
1060             shc.handshakeFinished = true;
1061 
1062             // May need to retransmit the last flight for DTLS.
1063             if (!shc.sslContext.isDTLS()) {
1064                 shc.conContext.finishHandshake();
1065             }
1066 
1067             //
1068             // produce
1069             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1070                 SSLLogger.fine(
1071                 "Sending new session ticket");
1072             }
1073             NewSessionTicket.kickstartProducer.produce(shc);
1074 
1075         }
1076     }
1077 }