--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java Mon Jun 25 13:41:39 2018 -0700
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Map;
+import javax.net.ssl.SSLException;
+
+enum SSLHandshake implements SSLConsumer, HandshakeProducer {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ HELLO_REQUEST ((byte)0x00, "hello_request",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ HelloRequest.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ HelloRequest.handshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ CLIENT_HELLO ((byte)0x01, "client_hello",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ ClientHello.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_13
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ ClientHello.handshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_13
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ SERVER_HELLO ((byte)0x02, "server_hello",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ ServerHello.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_13
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ ServerHello.t12HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ ),
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ ServerHello.t13HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ HELLO_RETRY_REQUEST ((byte)0x02, "hello_retry_request",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ ServerHello.handshakeConsumer, // Use ServerHello consumer
+ ProtocolVersion.PROTOCOLS_TO_13
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ ServerHello.hrrHandshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ HELLO_VERIFY_REQUEST ((byte)0x03, "hello_verify_request",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ HelloVerifyRequest.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ HelloVerifyRequest.handshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ NEW_SESSION_TICKET ((byte)0x04, "new_session_ticket",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ NewSessionTicket.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ NewSessionTicket.handshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ })),
+ END_OF_EARLY_DATA ((byte)0x05, "end_of_early_data"),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ ENCRYPTED_EXTENSIONS ((byte)0x08, "encrypted_extensions",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ EncryptedExtensions.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ EncryptedExtensions.handshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ CERTIFICATE ((byte)0x0B, "certificate",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ CertificateMessage.t12HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ ),
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ CertificateMessage.t13HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ CertificateMessage.t12HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ ),
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ CertificateMessage.t13HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ SERVER_KEY_EXCHANGE ((byte)0x0C, "server_key_exchange",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ ServerKeyExchange.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ ServerKeyExchange.handshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ CERTIFICATE_REQUEST ((byte)0x0D, "certificate_request",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ CertificateRequest.t10HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_11
+ ),
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ CertificateRequest.t12HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_12
+ ),
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ CertificateRequest.t13HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ CertificateRequest.t10HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_11
+ ),
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ CertificateRequest.t12HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_12
+ ),
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ CertificateRequest.t13HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ SERVER_HELLO_DONE ((byte)0x0E, "server_hello_done",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ ServerHelloDone.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ ServerHelloDone.handshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ CERTIFICATE_VERIFY ((byte)0x0F, "certificate_verify",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ CertificateVerify.s30HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_30
+ ),
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ CertificateVerify.t10HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_10_11
+ ),
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ CertificateVerify.t12HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_12
+ ),
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ CertificateVerify.t13HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ CertificateVerify.s30HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_30
+ ),
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ CertificateVerify.t10HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_10_11
+ ),
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ CertificateVerify.t12HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_12
+ ),
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ CertificateVerify.t13HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ CLIENT_KEY_EXCHANGE ((byte)0x10, "client_key_exchange",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ ClientKeyExchange.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ ClientKeyExchange.handshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ })),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ FINISHED ((byte)0x14, "finished",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ Finished.t12HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ ),
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ Finished.t13HandshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ Finished.t12HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ ),
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ Finished.t13HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ })),
+
+ CERTIFICATE_URL ((byte)0x15, "certificate_url"),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ CERTIFICATE_STATUS ((byte)0x16, "certificate_status",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ CertificateStatus.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ CertificateStatus.handshakeProducer,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ }),
+ (Map.Entry<HandshakeAbsence, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeAbsence, ProtocolVersion[]>(
+ CertificateStatus.handshakeAbsence,
+ ProtocolVersion.PROTOCOLS_TO_12
+ )
+ })),
+
+ SUPPLEMENTAL_DATA ((byte)0x17, "supplemental_data"),
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ KEY_UPDATE ((byte)0x18, "key_update",
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<SSLConsumer, ProtocolVersion[]>(
+ KeyUpdate.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ }),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(new Map.Entry[] {
+ new SimpleImmutableEntry<HandshakeProducer, ProtocolVersion[]>(
+ KeyUpdate.handshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ })),
+ MESSAGE_HASH ((byte)0xFE, "message_hash"),
+ NOT_APPLICABLE ((byte)0xFF, "not_applicable");
+
+ final byte id;
+ final String name;
+ final Map.Entry<SSLConsumer, ProtocolVersion[]>[] handshakeConsumers;
+ final Map.Entry<HandshakeProducer, ProtocolVersion[]>[] handshakeProducers;
+ final Map.Entry<HandshakeAbsence, ProtocolVersion[]>[] handshakeAbsences;
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ SSLHandshake(byte id, String name) {
+ this(id, name,
+ (Map.Entry<SSLConsumer, ProtocolVersion[]>[])(
+ new Map.Entry[0]),
+ (Map.Entry<HandshakeProducer, ProtocolVersion[]>[])(
+ new Map.Entry[0]),
+ (Map.Entry<HandshakeAbsence, ProtocolVersion[]>[])(
+ new Map.Entry[0]));
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ SSLHandshake(byte id, String name,
+ Map.Entry<SSLConsumer, ProtocolVersion[]>[] handshakeConsumers,
+ Map.Entry<HandshakeProducer, ProtocolVersion[]>[] handshakeProducers) {
+ this(id, name, handshakeConsumers, handshakeProducers,
+ (Map.Entry<HandshakeAbsence, ProtocolVersion[]>[])(
+ new Map.Entry[0]));
+ }
+
+ SSLHandshake(byte id, String name,
+ Map.Entry<SSLConsumer, ProtocolVersion[]>[] handshakeConsumers,
+ Map.Entry<HandshakeProducer, ProtocolVersion[]>[] handshakeProducers,
+ Map.Entry<HandshakeAbsence, ProtocolVersion[]>[] handshakeAbsence) {
+ this.id = id;
+ this.name = name;
+ this.handshakeConsumers = handshakeConsumers;
+ this.handshakeProducers = handshakeProducers;
+ this.handshakeAbsences = handshakeAbsence;
+ }
+
+ @Override
+ public void consume(ConnectionContext context,
+ ByteBuffer message) throws IOException {
+ SSLConsumer hc = getHandshakeConsumer(context);
+ if (hc != null) {
+ hc.consume(context, message);
+ } else {
+ throw new UnsupportedOperationException(
+ "Unsupported handshake consumer: " + this.name);
+ }
+ }
+
+ private SSLConsumer getHandshakeConsumer(ConnectionContext context) {
+ if (handshakeConsumers.length == 0) {
+ return null;
+ }
+
+ // The consuming happens in handshake context only.
+ HandshakeContext hc = (HandshakeContext)context;
+ ProtocolVersion protocolVersion;
+ if ((hc.negotiatedProtocol == null) ||
+ (hc.negotiatedProtocol == ProtocolVersion.NONE)) {
+ protocolVersion = hc.maximumActiveProtocol;
+ } else {
+ protocolVersion = hc.negotiatedProtocol;
+ }
+
+ for (Map.Entry<SSLConsumer,
+ ProtocolVersion[]> phe : handshakeConsumers) {
+ for (ProtocolVersion pv : phe.getValue()) {
+ if (protocolVersion == pv) {
+ return phe.getKey();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public byte[] produce(ConnectionContext context,
+ HandshakeMessage message) throws IOException {
+ HandshakeProducer hp = getHandshakeProducer(context);
+ if (hp != null) {
+ return hp.produce(context, message);
+ } else {
+ throw new UnsupportedOperationException(
+ "Unsupported handshake producer: " + this.name);
+ }
+ }
+
+ private HandshakeProducer getHandshakeProducer(
+ ConnectionContext context) {
+ if (handshakeConsumers.length == 0) {
+ return null;
+ }
+
+ // The consuming happens in handshake context only.
+ HandshakeContext hc = (HandshakeContext)context;
+ ProtocolVersion protocolVersion;
+ if ((hc.negotiatedProtocol == null) ||
+ (hc.negotiatedProtocol == ProtocolVersion.NONE)) {
+ protocolVersion = hc.maximumActiveProtocol;
+ } else {
+ protocolVersion = hc.negotiatedProtocol;
+ }
+
+ for (Map.Entry<HandshakeProducer,
+ ProtocolVersion[]> phe : handshakeProducers) {
+ for (ProtocolVersion pv : phe.getValue()) {
+ if (protocolVersion == pv) {
+ return phe.getKey();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ static String nameOf(byte id) {
+ // If two handshake message share the same handshake type, returns
+ // the first handshake message name.
+ //
+ // It is not a big issue at present as only ServerHello and
+ // HellRetryRequest share a handshake type.
+ for (SSLHandshake hs : SSLHandshake.values()) {
+ if (hs.id == id) {
+ return hs.name;
+ }
+ }
+
+ return "UNKNOWN-HANDSHAKE-MESSAGE(" + id + ")";
+ }
+
+ static final void kickstart(HandshakeContext context) throws IOException {
+ if (context instanceof ClientHandshakeContext) {
+ // For initial handshaking, including session resumption,
+ // ClientHello message is used as the kickstart message.
+ //
+ // (D)TLS 1.2 and older protocols support renegotiation on existing
+ // connections. A ClientHello messages is used to kickstart the
+ // renegotiation.
+ //
+ // (D)TLS 1.3 forbids renegotiation. The post-handshake KeyUpdate
+ // message is used to update the sending cryptographic keys.
+ if (context.conContext.isNegotiated &&
+ context.conContext.protocolVersion.useTLS13PlusSpec()) {
+ // Use KeyUpdate message for renegotiation.
+ KeyUpdate.kickstartProducer.produce(context);
+ } else {
+ // Using ClientHello message for the initial handshaking
+ // (including session resumption) or renegotiation.
+ // SSLHandshake.CLIENT_HELLO.produce(context);
+ ClientHello.kickstartProducer.produce(context);
+ }
+ } else {
+ // The server side can delivering kickstart message after the
+ // connection has established.
+ //
+ // (D)TLS 1.2 and older protocols use HelloRequest to begin a
+ // negotiation process anew.
+ //
+ // While (D)TLS 1.3 uses the post-handshake KeyUpdate message
+ // to update the sending cryptographic keys.
+ if (context.conContext.protocolVersion.useTLS13PlusSpec()) {
+ // Use KeyUpdate message for renegotiation.
+ KeyUpdate.kickstartProducer.produce(context);
+ } else {
+ // SSLHandshake.HELLO_REQUEST.produce(context);
+ HelloRequest.kickstartProducer.produce(context);
+ }
+ }
+ }
+
+ /**
+ * A (transparent) specification of handshake message.
+ */
+ static abstract class HandshakeMessage {
+ final HandshakeContext handshakeContext;
+
+ HandshakeMessage(HandshakeContext handshakeContext) {
+ this.handshakeContext = handshakeContext;
+ }
+
+ abstract SSLHandshake handshakeType();
+ abstract int messageLength();
+ abstract void send(HandshakeOutStream hos) throws IOException;
+
+ void write(HandshakeOutStream hos) throws IOException {
+ int len = messageLength();
+ if (len >= Record.OVERFLOW_OF_INT24) {
+ throw new SSLException("Handshake message is overflow"
+ + ", type = " + handshakeType() + ", len = " + len);
+ }
+ hos.write(handshakeType().id);
+ hos.putInt24(len);
+ send(hos);
+ hos.complete();
+ }
+ }
+}