src/java.base/share/classes/sun/security/ssl/HelloVerifyRequest.java
branchJDK-8145252-TLS13-branch
changeset 56542 56aaa6cb3693
child 56559 a423173d0578
equal deleted inserted replaced
56541:92cbbfc996f3 56542:56aaa6cb3693
       
     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.text.MessageFormat;
       
    31 import java.util.Locale;
       
    32 import sun.security.ssl.ClientHello.ClientHelloMessage;
       
    33 import sun.security.ssl.SSLHandshake.HandshakeMessage;
       
    34 
       
    35 /**
       
    36  * Pack of the HelloVerifyRequest handshake message.
       
    37  */
       
    38 final class HelloVerifyRequest {
       
    39     static final SSLConsumer handshakeConsumer =
       
    40             new HelloVerifyRequestConsumer();
       
    41     static final HandshakeProducer handshakeProducer =
       
    42             new HelloVerifyRequestProducer();
       
    43 
       
    44     /**
       
    45      * The HelloVerifyRequest handshake message [RFC 6347].
       
    46      */
       
    47     static final class HelloVerifyRequestMessage extends HandshakeMessage {
       
    48         final int                   serverVersion;
       
    49         final byte[]                cookie;
       
    50 
       
    51         HelloVerifyRequestMessage(HandshakeContext context,
       
    52                 HandshakeMessage message) throws IOException {
       
    53             super(context);
       
    54             // This happens in server side only.
       
    55             ServerHandshakeContext shc =
       
    56                     (ServerHandshakeContext)context;
       
    57             ClientHelloMessage clientHello = (ClientHelloMessage)message;
       
    58 
       
    59             HelloCookieManager hcMgr =
       
    60                 shc.sslContext.getHelloCookieManager(ProtocolVersion.DTLS10);
       
    61             this.serverVersion = shc.clientHelloVersion;
       
    62             this.cookie = hcMgr.createCookie(shc, clientHello);
       
    63         }
       
    64 
       
    65         HelloVerifyRequestMessage(HandshakeContext context,
       
    66                 ByteBuffer m) throws IOException {
       
    67             super(context);
       
    68             // This happens in client side only.
       
    69             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
    70 
       
    71             //  struct {
       
    72             //      ProtocolVersion server_version;
       
    73             //      opaque cookie<0..2^8-1>;
       
    74             //  } HelloVerifyRequest;
       
    75             if (m.remaining() < 3) {
       
    76                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
    77                     "Invalid HelloVerifyRequest: no sufficient data");
       
    78             }
       
    79 
       
    80             byte major = m.get();
       
    81             byte minor = m.get();
       
    82             this.serverVersion = ((major & 0xFF) << 8) | (minor & 0xFF);
       
    83             this.cookie = Record.getBytes8(m);
       
    84         }
       
    85 
       
    86         @Override
       
    87         public SSLHandshake handshakeType() {
       
    88             return SSLHandshake.HELLO_VERIFY_REQUEST;
       
    89         }
       
    90 
       
    91         @Override
       
    92         public int messageLength() {
       
    93             return 2 + cookie.length;   // 2: the length of protocol version
       
    94         }
       
    95 
       
    96         @Override
       
    97         public void send(HandshakeOutStream hos) throws IOException {
       
    98             hos.putInt8((byte)((serverVersion >>> 8) & 0xFF));
       
    99             hos.putInt8((byte)(serverVersion & 0xFF));
       
   100             hos.putBytes8(cookie);
       
   101         }
       
   102 
       
   103         @Override
       
   104         public String toString() {
       
   105             MessageFormat messageFormat = new MessageFormat(
       
   106                 "\"HelloVerifyRequest\": '{'\n" +
       
   107                 "  \"server version\"      : \"{0}\",\n" +
       
   108                 "  \"cookie\"              : \"{1}\",\n" +
       
   109                 "'}'",
       
   110                 Locale.ENGLISH);
       
   111             Object[] messageFields = {
       
   112                 ProtocolVersion.nameOf(serverVersion),
       
   113                 Utilities.toHexString(cookie),
       
   114             };
       
   115 
       
   116             return messageFormat.format(messageFields);
       
   117         }
       
   118     }
       
   119 
       
   120     /**
       
   121      * The "HelloVerifyRequest" handshake message producer.
       
   122      */
       
   123     private static final
       
   124             class HelloVerifyRequestProducer implements HandshakeProducer {
       
   125         // Prevent instantiation of this class.
       
   126         private HelloVerifyRequestProducer() {
       
   127             // blank
       
   128         }
       
   129 
       
   130         @Override
       
   131         public byte[] produce(ConnectionContext context,
       
   132                 HandshakeMessage message) throws IOException {
       
   133             // The producing happens in server side only.
       
   134             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   135 
       
   136             // clean up this producer
       
   137             shc.handshakeProducers.remove(SSLHandshake.HELLO_VERIFY_REQUEST.id);
       
   138 
       
   139             HelloVerifyRequestMessage hvrm =
       
   140                     new HelloVerifyRequestMessage(shc, message);
       
   141             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   142                 SSLLogger.fine(
       
   143                         "Produced HelloVerifyRequest handshake message", hvrm);
       
   144             }
       
   145 
       
   146             // Output the handshake message.
       
   147             hvrm.write(shc.handshakeOutput);
       
   148             shc.handshakeOutput.flush();
       
   149 
       
   150             // update the context
       
   151 
       
   152             // TODO: stateless, clean up the handshake context?
       
   153             shc.handshakeHash.finish();     // forgot about the handshake hash
       
   154             shc.handshakeExtensions.clear();
       
   155 
       
   156             // What's the expected response?
       
   157             shc.handshakeConsumers.put(
       
   158                     SSLHandshake.CLIENT_HELLO.id, SSLHandshake.CLIENT_HELLO);
       
   159 
       
   160             // The handshake message has been delivered.
       
   161             return null;
       
   162         }
       
   163     }
       
   164 
       
   165     /**
       
   166      * The "HelloVerifyRequest" handshake message consumer.
       
   167      */
       
   168     private static final class HelloVerifyRequestConsumer
       
   169             implements SSLConsumer {
       
   170 
       
   171         // Prevent instantiation of this class.
       
   172         private HelloVerifyRequestConsumer() {
       
   173             // blank
       
   174         }
       
   175 
       
   176         @Override
       
   177         public void consume(ConnectionContext context,
       
   178                 ByteBuffer message) throws IOException {
       
   179             // The consuming happens in client side only.
       
   180             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   181 
       
   182             // clean up this consumer
       
   183             chc.handshakeConsumers.remove(SSLHandshake.HELLO_VERIFY_REQUEST.id);
       
   184             if (!chc.handshakeConsumers.isEmpty()) {
       
   185                 chc.handshakeConsumers.remove(SSLHandshake.SERVER_HELLO.id);
       
   186             }
       
   187             if (!chc.handshakeConsumers.isEmpty()) {
       
   188                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
       
   189                         "No more message expected before " +
       
   190                         "HelloVerifyRequest is processed");
       
   191             }
       
   192 
       
   193             // Refresh handshake hash.
       
   194             chc.handshakeHash.finish();     // forgot about the handshake hash
       
   195 
       
   196             HelloVerifyRequestMessage hvrm =
       
   197                     new HelloVerifyRequestMessage(chc, message);
       
   198             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   199                 SSLLogger.fine(
       
   200                         "Consuming HelloVerifyRequest handshake message", hvrm);
       
   201             }
       
   202 
       
   203             // Note that HelloVerifyRequest.server_version is used solely to
       
   204             // indicate packet formatting, and not as part of version
       
   205             // negotiation.  Need not to check version values match for
       
   206             // HelloVerifyRequest message.
       
   207             chc.initialClientHelloMsg.setHelloCookie(hvrm.cookie);
       
   208 
       
   209             //
       
   210             // produce response handshake message
       
   211             //
       
   212             SSLHandshake.CLIENT_HELLO.produce(context, hvrm);
       
   213         }
       
   214     }
       
   215 }
       
   216