blob: 1e8ddfdd5383d6dff3c93d32ec5200662356a2ba [file] [log] [blame]
/*
* 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)) {
if (hc.conContext.isNegotiated &&
hc.conContext.protocolVersion != ProtocolVersion.NONE) {
protocolVersion = hc.conContext.protocolVersion;
} else {
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)) {
if (hc.conContext.isNegotiated &&
hc.conContext.protocolVersion != ProtocolVersion.NONE) {
protocolVersion = hc.conContext.protocolVersion;
} else {
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 boolean isKnown(byte id) {
for (SSLHandshake hs : SSLHandshake.values()) {
if (hs.id == id && id != NOT_APPLICABLE.id) {
return true;
}
}
return false;
}
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();
}
}
}