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 sun.security.ssl.SSLHandshake.HandshakeMessage;
  31 
  32 /**
  33  * Pack of the ServerHelloDone handshake message.
  34  */
  35 final class ServerHelloDone {
  36     static final SSLConsumer handshakeConsumer =
  37         new ServerHelloDoneConsumer();
  38     static final HandshakeProducer handshakeProducer =
  39         new ServerHelloDoneProducer();
  40 
  41     /**
  42      * The ServerHelloDone handshake message.
  43      */
  44     static final class ServerHelloDoneMessage extends HandshakeMessage {
  45         ServerHelloDoneMessage(HandshakeContext handshakeContext) {
  46             super(handshakeContext);
  47         }
  48 
  49         ServerHelloDoneMessage(HandshakeContext handshakeContext,
  50                 ByteBuffer m) throws IOException {
  51             super(handshakeContext);
  52             if (m.hasRemaining()) {
  53                 handshakeContext.conContext.fatal(Alert.ILLEGAL_PARAMETER,
  54                     "Error parsing ServerHelloDone message: not empty");
  55             }
  56         }
  57 
  58         @Override
  59         public SSLHandshake handshakeType() {
  60             return SSLHandshake.SERVER_HELLO_DONE;
  61         }
  62 
  63         @Override
  64         public int messageLength() {
  65             return 0;
  66         }
  67 
  68         @Override
  69         public void send(HandshakeOutStream s) throws IOException {
  70             // empty, nothing to send
  71         }
  72 
  73         @Override
  74         public String toString() {
  75             return "<empty>";
  76         }
  77     }
  78 
  79     /**
  80      * The "ServerHelloDone" handshake message producer.
  81      */
  82     private static final
  83             class ServerHelloDoneProducer implements HandshakeProducer {
  84         // Prevent instantiation of this class.
  85         private ServerHelloDoneProducer() {
  86             // blank
  87         }
  88 
  89         @Override
  90         public byte[] produce(ConnectionContext context,
  91                 HandshakeMessage message) throws IOException {
  92             // The producing happens in server side only.
  93             ServerHandshakeContext shc = (ServerHandshakeContext)context;
  94 
  95             ServerHelloDoneMessage shdm = new ServerHelloDoneMessage(shc);
  96             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
  97                 SSLLogger.fine(
  98                         "Produced ServerHelloDone handshake message", shdm);
  99             }
 100 
 101             // Output the handshake message.
 102             shdm.write(shc.handshakeOutput);
 103             shc.handshakeOutput.flush();
 104 
 105             //
 106             // update
 107             //
 108             shc.handshakeConsumers.put(SSLHandshake.CLIENT_KEY_EXCHANGE.id,
 109                     SSLHandshake.CLIENT_KEY_EXCHANGE);
 110             shc.conContext.consumers.put(ContentType.CHANGE_CIPHER_SPEC.id,
 111                     ChangeCipherSpec.t10Consumer);
 112             shc.handshakeConsumers.put(SSLHandshake.FINISHED.id,
 113                     SSLHandshake.FINISHED);
 114 
 115             // The handshake message has been delivered.
 116             return null;
 117         }
 118     }
 119 
 120     /**
 121      * The "ServerHelloDone" handshake message consumer.
 122      */
 123     private static final
 124             class ServerHelloDoneConsumer implements SSLConsumer {
 125         // Prevent instantiation of this class.
 126         private ServerHelloDoneConsumer() {
 127             // blank
 128         }
 129 
 130         @Override
 131         public void consume(ConnectionContext context,
 132                 ByteBuffer message) throws IOException {
 133             // The consuming happens in client side only.
 134             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 135 
 136             // clean up this consumer
 137             // chc.handshakeConsumers.remove(SSLHandshake.SERVER_HELLO_DONE.id);
 138             chc.handshakeConsumers.clear();
 139 
 140             ServerHelloDoneMessage shdm =
 141                     new ServerHelloDoneMessage(chc, message);
 142             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 143                 SSLLogger.fine(
 144                         "Consuming ServerHelloDone handshake message", shdm);
 145             }
 146 
 147             //
 148             // validate
 149             //
 150             // blank
 151 
 152             //
 153             // update
 154             //
 155             chc.handshakeProducers.put(SSLHandshake.CLIENT_KEY_EXCHANGE.id,
 156                     SSLHandshake.CLIENT_KEY_EXCHANGE);
 157             chc.handshakeProducers.put(SSLHandshake.FINISHED.id,
 158                     SSLHandshake.FINISHED);
 159             //
 160             // produce
 161             //
 162             SSLHandshake[] probableHandshakeMessages = new SSLHandshake[] {
 163                 // full handshake messages
 164                 SSLHandshake.CERTIFICATE,
 165                 SSLHandshake.CLIENT_KEY_EXCHANGE,
 166                 SSLHandshake.CERTIFICATE_VERIFY,
 167                 SSLHandshake.FINISHED
 168             };
 169 
 170             for (SSLHandshake hs : probableHandshakeMessages) {
 171                 HandshakeProducer handshakeProducer =
 172                         chc.handshakeProducers.remove(hs.id);
 173                 if (handshakeProducer != null) {
 174                     handshakeProducer.produce(context, null);
 175                 }
 176             }
 177         }
 178     }
 179 }