1 /*
   2  * Copyright (c) 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.text.MessageFormat;
  31 import java.util.Locale;
  32 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  33 
  34 /**
  35  * Pack of the EncryptedExtensions handshake message.
  36  */
  37 final class EncryptedExtensions {
  38     static final HandshakeProducer handshakeProducer =
  39         new EncryptedExtensionsProducer();
  40     static final SSLConsumer handshakeConsumer =
  41         new EncryptedExtensionsConsumer();
  42 
  43     /**
  44      * The EncryptedExtensions handshake message.
  45      */
  46     static final class EncryptedExtensionsMessage extends HandshakeMessage {
  47         private final SSLExtensions extensions;
  48 
  49         EncryptedExtensionsMessage(
  50                 HandshakeContext handshakeContext) throws IOException {
  51             super(handshakeContext);
  52             this.extensions = new SSLExtensions(this);
  53         }
  54 
  55         EncryptedExtensionsMessage(HandshakeContext handshakeContext,
  56                 ByteBuffer m) throws IOException {
  57             super(handshakeContext);
  58 
  59             // struct {
  60             //     Extension extensions<0..2^16-1>;
  61             // } EncryptedExtensions;
  62             if (m.remaining() < 2) {
  63                 handshakeContext.conContext.fatal(Alert.ILLEGAL_PARAMETER,
  64                         "Invalid EncryptedExtensions handshake message: " +
  65                         "no sufficient data");
  66             }
  67 
  68             SSLExtension[] encryptedExtensions =
  69                     handshakeContext.sslConfig.getEnabledExtensions(
  70                             SSLHandshake.ENCRYPTED_EXTENSIONS);
  71             this.extensions = new SSLExtensions(this, m, encryptedExtensions);
  72         }
  73 
  74         @Override
  75         SSLHandshake handshakeType() {
  76             return SSLHandshake.ENCRYPTED_EXTENSIONS;
  77         }
  78 
  79         @Override
  80         int messageLength() {
  81             int extLen = extensions.length();
  82             if (extLen == 0) {
  83                 extLen = 2;     // empty extensions
  84             }
  85             return extLen;
  86         }
  87 
  88         @Override
  89         void send(HandshakeOutStream hos) throws IOException {
  90             // Is it an empty extensions?
  91             if (extensions.length() == 0) {
  92                 hos.putInt16(0);
  93             } else {
  94                 extensions.send(hos);
  95             }
  96         }
  97 
  98         @Override
  99         public String toString() {
 100             MessageFormat messageFormat = new MessageFormat(
 101                     "\"EncryptedExtensions\": [\n" +
 102                     "{0}\n" +
 103                     "]",
 104                     Locale.ENGLISH);
 105             Object[] messageFields = {
 106                 Utilities.indent(extensions.toString())
 107             };
 108 
 109             return messageFormat.format(messageFields);
 110         }
 111     }
 112 
 113     /**
 114      * The EncryptedExtensions handshake message consumer.
 115      */
 116     private static final class EncryptedExtensionsProducer
 117             implements HandshakeProducer {
 118         // Prevent instantiation of this class.
 119         private EncryptedExtensionsProducer() {
 120             // blank
 121         }
 122 
 123         @Override
 124         public byte[] produce(ConnectionContext context,
 125                 HandshakeMessage message) throws IOException {
 126             // The producing happens in server side only.
 127             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 128 
 129             // Change client/server handshake traffic secrets.
 130             // TODO
 131 
 132             EncryptedExtensionsMessage eem =
 133                     new EncryptedExtensionsMessage(shc);
 134             SSLExtension[] extTypes =
 135                     shc.sslConfig.getEnabledExtensions(
 136                             SSLHandshake.ENCRYPTED_EXTENSIONS,
 137                             shc.negotiatedProtocol);
 138             eem.extensions.produce(shc, extTypes);
 139             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 140                 SSLLogger.fine("Produced EncryptedExtensions message", eem);
 141             }
 142 
 143             // Output the handshake message.
 144             eem.write(shc.handshakeOutput);
 145             shc.handshakeOutput.flush();
 146 
 147             // The handshake message has been delivered.
 148             return null;
 149         }
 150     }
 151 
 152     /**
 153      * The EncryptedExtensions handshake message consumer.
 154      */
 155     private static final class EncryptedExtensionsConsumer
 156             implements SSLConsumer {
 157         // Prevent instantiation of this class.
 158         private EncryptedExtensionsConsumer() {
 159             // blank
 160         }
 161 
 162         @Override
 163         public void consume(ConnectionContext context,
 164                 ByteBuffer message) throws IOException {
 165             // The consuming happens in client side only.
 166             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 167 
 168             // clean up this consumer
 169             chc.handshakeConsumers.remove(SSLHandshake.ENCRYPTED_EXTENSIONS.id);
 170 
 171             EncryptedExtensionsMessage eem =
 172                     new EncryptedExtensionsMessage(chc, message);
 173             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 174                 SSLLogger.fine(
 175                         "Consuming EncryptedExtensions handshake message", eem);
 176             }
 177 
 178             //
 179             // validate
 180             //
 181             SSLExtension[] extTypes = chc.sslConfig.getEnabledExtensions(
 182                     SSLHandshake.ENCRYPTED_EXTENSIONS);
 183             eem.extensions.consumeOnLoad(chc, extTypes);
 184 
 185             //
 186             // update
 187             //
 188             // TODO: all extensions should be considered.
 189             eem.extensions.consumeOnTrade(chc, extTypes);
 190 
 191             //
 192             // produce
 193             //
 194             // Need no new handshake message producers here.
 195         }
 196     }
 197 }