提交 40f676c5 编写于 作者: P pkoppula

8074462: Handshake messages can be strictly ordered

Reviewed-by: xuelei
Contributed-by: prasadarao.koppula@oracle.com, sean.coffey@oracle.com
上级 1f86a9b8
......@@ -191,19 +191,24 @@ final class ClientHandshaker extends Handshaker {
*/
@Override
void processMessage(byte type, int messageLen) throws IOException {
if (state >= type
&& (type != HandshakeMessage.ht_hello_request)) {
throw new SSLProtocolException(
"Handshake message sequence violation, " + type);
}
// check the handshake state
List<Byte> ignoredOptStates = handshakeState.check(type);
switch (type) {
case HandshakeMessage.ht_hello_request:
this.serverHelloRequest(new HelloRequest(input));
HelloRequest helloRequest = new HelloRequest(input);
handshakeState.update(helloRequest, resumingSession);
this.serverHelloRequest(helloRequest);
break;
case HandshakeMessage.ht_server_hello:
this.serverHello(new ServerHello(input, messageLen));
ServerHello serverHello = new ServerHello(input, messageLen);
this.serverHello(serverHello);
// This handshake state update needs the resumingSession value
// set by serverHello().
handshakeState.update(serverHello, resumingSession);
break;
case HandshakeMessage.ht_certificate:
......@@ -213,7 +218,9 @@ final class ClientHandshaker extends Handshaker {
"unexpected server cert chain");
// NOTREACHED
}
this.serverCertificate(new CertificateMsg(input));
CertificateMsg certificateMsg = new CertificateMsg(input);
handshakeState.update(certificateMsg, resumingSession);
this.serverCertificate(certificateMsg);
serverKey =
session.getPeerCertificates()[0].getPublicKey();
break;
......@@ -249,15 +256,20 @@ final class ClientHandshaker extends Handshaker {
}
try {
this.serverKeyExchange(new RSA_ServerKeyExchange(input));
RSA_ServerKeyExchange rsaSrvKeyExchange =
new RSA_ServerKeyExchange(input);
handshakeState.update(rsaSrvKeyExchange, resumingSession);
this.serverKeyExchange(rsaSrvKeyExchange);
} catch (GeneralSecurityException e) {
throwSSLException("Server key", e);
}
break;
case K_DH_ANON:
try {
this.serverKeyExchange(new DH_ServerKeyExchange(
input, protocolVersion));
DH_ServerKeyExchange dhSrvKeyExchange =
new DH_ServerKeyExchange(input, protocolVersion);
handshakeState.update(dhSrvKeyExchange, resumingSession);
this.serverKeyExchange(dhSrvKeyExchange);
} catch (GeneralSecurityException e) {
throwSSLException("Server key", e);
}
......@@ -265,11 +277,14 @@ final class ClientHandshaker extends Handshaker {
case K_DHE_DSS:
case K_DHE_RSA:
try {
this.serverKeyExchange(new DH_ServerKeyExchange(
DH_ServerKeyExchange dhSrvKeyExchange =
new DH_ServerKeyExchange(
input, serverKey,
clnt_random.random_bytes, svr_random.random_bytes,
messageLen,
getLocalSupportedSignAlgs(), protocolVersion));
getLocalSupportedSignAlgs(), protocolVersion);
handshakeState.update(dhSrvKeyExchange, resumingSession);
this.serverKeyExchange(dhSrvKeyExchange);
} catch (GeneralSecurityException e) {
throwSSLException("Server key", e);
}
......@@ -278,10 +293,13 @@ final class ClientHandshaker extends Handshaker {
case K_ECDHE_RSA:
case K_ECDH_ANON:
try {
this.serverKeyExchange(new ECDH_ServerKeyExchange
ECDH_ServerKeyExchange ecdhSrvKeyExchange =
new ECDH_ServerKeyExchange
(input, serverKey, clnt_random.random_bytes,
svr_random.random_bytes,
getLocalSupportedSignAlgs(), protocolVersion));
getLocalSupportedSignAlgs(), protocolVersion);
handshakeState.update(ecdhSrvKeyExchange, resumingSession);
this.serverKeyExchange(ecdhSrvKeyExchange);
} catch (GeneralSecurityException e) {
throwSSLException("Server key", e);
}
......@@ -320,6 +338,7 @@ final class ClientHandshaker extends Handshaker {
if (debug != null && Debug.isOn("handshake")) {
certRequest.print(System.out);
}
handshakeState.update(certRequest, resumingSession);
if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
Collection<SignatureAndHashAlgorithm> peerSignAlgs =
......@@ -345,33 +364,23 @@ final class ClientHandshaker extends Handshaker {
break;
case HandshakeMessage.ht_server_hello_done:
this.serverHelloDone(new ServerHelloDone(input));
ServerHelloDone serverHelloDone = new ServerHelloDone(input);
handshakeState.update(serverHelloDone, resumingSession);
this.serverHelloDone(serverHelloDone);
break;
case HandshakeMessage.ht_finished:
// A ChangeCipherSpec record must have been received prior to
// reception of the Finished message (RFC 5246, 7.4.9).
if (!receivedChangeCipherSpec()) {
fatalSE(Alerts.alert_handshake_failure,
"Received Finished message before ChangeCipherSpec");
}
Finished serverFinished =
new Finished(protocolVersion, input, cipherSuite);
handshakeState.update(serverFinished, resumingSession);
this.serverFinished(serverFinished);
this.serverFinished(
new Finished(protocolVersion, input, cipherSuite));
break;
default:
throw new SSLProtocolException(
"Illegal client handshake msg, " + type);
}
//
// Move state machine forward if the message handling
// code didn't already do so
//
if (state < type) {
state = type;
}
}
/*
......@@ -389,7 +398,7 @@ final class ClientHandshaker extends Handshaker {
// Could be (e.g. at connection setup) that we already
// sent the "client hello" but the server's not seen it.
//
if (state < HandshakeMessage.ht_client_hello) {
if (!clientHelloDelivered) {
if (!secureRenegotiation && !allowUnsafeRenegotiation) {
// renegotiation is not allowed.
if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) {
......@@ -613,7 +622,6 @@ final class ClientHandshaker extends Handshaker {
// looks fine; resume it, and update the state machine.
resumingSession = true;
state = HandshakeMessage.ht_finished - 1;
calculateConnectionKeys(session.getMasterSecret());
if (debug != null && Debug.isOn("session")) {
System.out.println("%% Server resumed " + session);
......@@ -903,6 +911,7 @@ final class ClientHandshaker extends Handshaker {
m1.print(System.out);
}
m1.write(output);
handshakeState.update(m1, resumingSession);
}
}
......@@ -1067,6 +1076,7 @@ final class ClientHandshaker extends Handshaker {
}
m2.write(output);
handshakeState.update(m2, resumingSession);
/*
* THIRD, send a "change_cipher_spec" record followed by the
......@@ -1169,6 +1179,7 @@ final class ClientHandshaker extends Handshaker {
m3.print(System.out);
}
m3.write(output);
handshakeState.update(m3, resumingSession);
output.doHashes();
}
......@@ -1226,6 +1237,8 @@ final class ClientHandshaker extends Handshaker {
if (resumingSession) {
input.digestNow();
sendChangeCipherAndFinish(true);
} else {
handshakeFinished = true;
}
session.setLastAccessedTime(System.currentTimeMillis());
......@@ -1271,13 +1284,6 @@ final class ClientHandshaker extends Handshaker {
if (secureRenegotiation) {
clientVerifyData = mesg.getVerifyData();
}
/*
* Update state machine so server MUST send 'finished' next.
* (In "long" handshake case; in short case, we're responding
* to its message.)
*/
state = HandshakeMessage.ht_finished - 1;
}
......
......@@ -89,6 +89,8 @@ public abstract class HandshakeMessage {
static final byte ht_finished = 20;
static final byte ht_not_applicable = -1; // N/A
/* Class and subclass dynamic debugging support */
public static final Debug debug = Debug.getInstance("ssl");
......
/*
* Copyright (c) 2015, 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.util.Collections;
import java.util.List;
import java.util.LinkedList;
import java.util.HashMap;
import javax.net.ssl.SSLProtocolException;
import static sun.security.ssl.CipherSuite.KeyExchange;
import static sun.security.ssl.CipherSuite.KeyExchange.*;
import static sun.security.ssl.HandshakeStateManager.HandshakeState.*;
import static sun.security.ssl.HandshakeMessage.*;
/*
* Handshake state manager.
*
* Messages flow for a full handshake:
*
* - -
* | HelloRequest (No.0, RFC 5246) [*] |
* | <-------------------------------------------- |
* | |
* | ClientHello (No.1, RFC 5246) |
* | --------------------------------------------> |
* | |
* C | ServerHello (No.2, RFC 5246) | S
* L | SupplementalData (No.23, RFC4680) [*] | E
* I | Certificate (No.11, RFC 5246) [*] | R
* E | CertificateStatus (No.22, RFC 6066) [*] | V
* N | ServerKeyExchange (No.12, RFC 5246) [*] | E
* T | CertificateRequest (No.13, RFC 5246) [*] | R
* | ServerHelloDone (No.14, RFC 5246) |
* | <-------------------------------------------- |
* | |
* | SupplementalData (No.23, RFC4680) [*] |
* | Certificate (No.11, RFC 5246) [*] Or |
* | CertificateURL (No.21, RFC6066) [*] |
* | ClientKeyExchange (No.16, RFC 5246) |
* | CertificateVerify (No.15, RFC 5246) [*] |
* | [ChangeCipherSpec] (RFC 5246) |
* | Finished (No.20, RFC 5246) |
* | --------------------------------------------> |
* | |
* | NewSessionTicket (No.4, RFC4507) [*] |
* | [ChangeCipherSpec] (RFC 5246) |
* | Finished (No.20, RFC 5246) |
* | <-------------------------------------------- |
* - -
* [*] Indicates optional or situation-dependent messages that are not
* always sent.
*
* Message flow for an abbreviated handshake:
* - -
* | ClientHello (No.1, RFC 5246) |
* | --------------------------------------------> |
* | |
* C | ServerHello (No.2, RFC 5246) | S
* L | NewSessionTicket (No.4, RFC4507) [*] | E
* I | [ChangeCipherSpec] (RFC 5246) | R
* E | Finished (No.20, RFC 5246) | V
* N | <-------------------------------------------- | E
* T | | R
* | [ChangeCipherSpec] (RFC 5246) |
* | Finished (No.20, RFC 5246) |
* | --------------------------------------------> |
* - -
*
*
* State machine of handshake states:
*
* +--------------+
* START -----> | HelloRequest |
* | +--------------+
* | |
* v v
* +---------------------+ --> +---------------------+
* | ClientHello | | HelloVerifyRequest |
* +---------------------+ <-- +---------------------+
* |
* |
* =========================================================================
* |
* v
* +---------------------+
* | ServerHello | ----------------------------------+------+
* +---------------------+ --> +-------------------------+ | |
* | | Server SupplementalData | | |
* | +-------------------------+ | |
* | | | |
* v v | |
* +---------------------+ | |
* +---- | Server Certificate | | |
* | +---------------------+ | |
* | | | |
* | | +--------------------+ | |
* | +-> | CertificateStatus | | |
* | | +--------------------+ v |
* | | | | +--------------------+ |
* | v v +--> | ServerKeyExchange | |
* | +---------------------+ | +--------------------+ |
* | | CertificateRequest | | | |
* | +---------------------+ <-+---------+ |
* | | | | |
* v v | | |
* +---------------------+ <-------+ | |
* | ServerHelloDone | <-----------------+ |
* +---------------------+ |
* | | |
* | | |
* | | |
* =========================================================================
* | | |
* | v |
* | +-------------------------+ |
* | | Client SupplementalData | --------------+ |
* | +-------------------------+ | |
* | | | |
* | v | |
* | +--------------------+ | |
* +-> | Client Certificate | ALT. | |
* | +--------------------+----------------+ | |
* | | CertificateURL | | |
* | +----------------+ | |
* v | |
* +-------------------+ <------------------------+ |
* | ClientKeyExchange | |
* +-------------------+ |
* | | |
* | v |
* | +-------------------+ |
* | | CertificateVerify | |
* | +-------------------+ |
* | | |
* v v |
* +-------------------------+ |
* | Client ChangeCipherSpec | <---------------+ |
* +-------------------------+ | |
* | | |
* v | |
* +-----------------+ (abbreviated) | |
* | Client Finished | -------------> END | |
* +-----------------+ (Abbreviated handshake) | |
* | | |
* | (full) | |
* | | |
* ================================ | |
* | | |
* | ================================
* | | |
* v | |
* +------------------+ | (abbreviated) |
* | NewSessionTicket | <--------------------------------+
* +------------------+ | |
* | | |
* v | |
* +-------------------------+ | (abbreviated) |
* | Server ChangeCipherSpec | <-------------------------------------+
* +-------------------------+ |
* | |
* v |
* +-----------------+ (abbreviated) |
* | Server Finished | -------------------------+
* +-----------------+
* | (full)
* v
* END (Full handshake)
*
*
* The scenarios of the use of this class:
* 1. Create an instance of HandshakeStateManager during the initializtion
* handshake.
* 2. If receiving a handshake message, call HandshakeStateManager.check()
* to make sure that the message is of the expected handshake type. And
* then call HandshakeStateManager.update() in case handshake states may
* be impacted by this new incoming handshake message.
* 3. On delivering a handshake message, call HandshakeStateManager.update()
* in case handshake states may by thie new outgoing handshake message.
* 4. On receiving and delivering ChangeCipherSpec message, call
* HandshakeStateManager.changeCipherSpec() to check the present sequence
* of this message, and update the states if necessary.
*/
final class HandshakeStateManager {
// upcoming handshake states.
private LinkedList<HandshakeState> upcomingStates;
private LinkedList<HandshakeState> alternatives;
private static final boolean debugIsOn;
private static final HashMap<Byte, String> handshakeTypes;
static {
debugIsOn = (Handshaker.debug != null) &&
Debug.isOn("handshake") && Debug.isOn("verbose");
handshakeTypes = new HashMap<>(8);
handshakeTypes.put(ht_hello_request, "hello_request");
handshakeTypes.put(ht_client_hello, "client_hello");
handshakeTypes.put(ht_server_hello, "server_hello");
handshakeTypes.put(ht_certificate, "certificate");
handshakeTypes.put(ht_server_key_exchange, "server_key_exchange");
handshakeTypes.put(ht_server_hello_done, "server_hello_done");
handshakeTypes.put(ht_certificate_verify, "certificate_verify");
handshakeTypes.put(ht_client_key_exchange, "client_key_exchange");
handshakeTypes.put(ht_finished, "finished");
}
HandshakeStateManager() {
this.upcomingStates = new LinkedList<>();
this.alternatives = new LinkedList<>();
}
//
// enumation of handshake type
//
static enum HandshakeState {
HS_HELLO_REQUEST(
"hello_request",
HandshakeMessage.ht_hello_request),
HS_CLIENT_HELLO(
"client_hello",
HandshakeMessage.ht_client_hello),
HS_SERVER_HELLO(
"server_hello",
HandshakeMessage.ht_server_hello),
HS_SERVER_CERTIFICATE(
"server certificate",
HandshakeMessage.ht_certificate),
HS_SERVER_KEY_EXCHANGE(
"server_key_exchange",
HandshakeMessage.ht_server_key_exchange, true),
HS_CERTIFICATE_REQUEST(
"certificate_request",
HandshakeMessage.ht_certificate_request, true),
HS_SERVER_HELLO_DONE(
"server_hello_done",
HandshakeMessage.ht_server_hello_done),
HS_CLIENT_CERTIFICATE(
"client certificate",
HandshakeMessage.ht_certificate, true),
HS_CLIENT_KEY_EXCHANGE(
"client_key_exchange",
HandshakeMessage.ht_client_key_exchange),
HS_CERTIFICATE_VERIFY(
"certificate_verify",
HandshakeMessage.ht_certificate_verify, true),
HS_CLIENT_CHANGE_CIPHER_SPEC(
"client change_cipher_spec",
HandshakeMessage.ht_not_applicable),
HS_CLIENT_FINISHED(
"client finished",
HandshakeMessage.ht_finished),
HS_SERVER_CHANGE_CIPHER_SPEC(
"server change_cipher_spec",
HandshakeMessage.ht_not_applicable),
HS_SERVER_FINISHED(
"server finished",
HandshakeMessage.ht_finished);
final String description;
final byte handshakeType;
final boolean isOptional;
HandshakeState(String description, byte handshakeType) {
this.description = description;
this.handshakeType = handshakeType;
this.isOptional = false;
}
HandshakeState(String description,
byte handshakeType, boolean isOptional) {
this.description = description;
this.handshakeType = handshakeType;
this.isOptional = isOptional;
}
public String toString() {
return description + "[" + handshakeType + "]" +
(isOptional ? "(optional)" : "");
}
}
boolean isEmpty() {
return upcomingStates.isEmpty();
}
List<Byte> check(byte handshakeType) throws SSLProtocolException {
List<Byte> ignoredOptional = new LinkedList<>();
String exceptionMsg =
"Handshake message sequence violation, " + handshakeType;
if (debugIsOn) {
System.out.println(
"check handshake state: " + toString(handshakeType));
}
if (upcomingStates.isEmpty()) {
// Is it a kickstart message?
if ((handshakeType != HandshakeMessage.ht_hello_request) &&
(handshakeType != HandshakeMessage.ht_client_hello)) {
throw new SSLProtocolException(
"Handshake message sequence violation, " + handshakeType);
}
// It is a kickstart message.
return Collections.emptyList();
}
// Ignore the checking for HelloRequest messages as they
// may be sent by the server at any time.
if (handshakeType == HandshakeMessage.ht_hello_request) {
return Collections.emptyList();
}
for (HandshakeState handshakeState : upcomingStates) {
if (handshakeState.handshakeType == handshakeType) {
// It's the expected next handshake type.
return ignoredOptional;
}
if (handshakeState.isOptional) {
ignoredOptional.add(handshakeState.handshakeType);
continue;
} else {
for (HandshakeState alternative : alternatives) {
if (alternative.handshakeType == handshakeType) {
return ignoredOptional;
}
if (alternative.isOptional) {
continue;
} else {
throw new SSLProtocolException(exceptionMsg);
}
}
}
throw new SSLProtocolException(exceptionMsg);
}
// Not an expected Handshake message.
throw new SSLProtocolException(
"Handshake message sequence violation, " + handshakeType);
}
void update(HandshakeMessage handshakeMessage,
boolean isAbbreviated) throws SSLProtocolException {
byte handshakeType = (byte)handshakeMessage.messageType();
String exceptionMsg =
"Handshake message sequence violation, " + handshakeType;
if (debugIsOn) {
System.out.println(
"update handshake state: " + toString(handshakeType));
}
boolean hasPresentState = false;
switch (handshakeType) {
case HandshakeMessage.ht_hello_request:
//
// State machine:
// PRESENT: START
// TO : ClientHello
//
// No old state to update.
// Add the upcoming states.
if (!upcomingStates.isEmpty()) {
// A ClientHello message should be followed.
upcomingStates.add(HS_CLIENT_HELLO);
} // Otherwise, ignore this HelloRequest message.
break;
case HandshakeMessage.ht_client_hello:
//
// State machine:
// PRESENT: START
// HS_CLIENT_HELLO
// TO : HS_SERVER_HELLO
//
// Check and update the present state.
if (!upcomingStates.isEmpty()) {
// The current state should be HS_CLIENT_HELLO.
HandshakeState handshakeState = upcomingStates.pop();
if (handshakeState != HS_CLIENT_HELLO) {
throw new SSLProtocolException(exceptionMsg);
}
}
// Add the upcoming states.
ClientHello clientHello = (ClientHello)handshakeMessage;
upcomingStates.add(HS_SERVER_HELLO);
break;
case HandshakeMessage.ht_server_hello:
//
// State machine:
// PRESENT: HS_SERVER_HELLO
// TO :
// Full handshake state stacks
// (ServerHello Flight)
// HS_SERVER_SUPPLEMENTAL_DATA [optional]
// --> HS_SERVER_CERTIFICATE [optional]
// --> HS_CERTIFICATE_STATUS [optional]
// --> HS_SERVER_KEY_EXCHANGE [optional]
// --> HS_CERTIFICATE_REQUEST [optional]
// --> HS_SERVER_HELLO_DONE
// (Client ClientKeyExchange Flight)
// --> HS_CLIENT_SUPPLEMENTAL_DATA [optional]
// --> HS_CLIENT_CERTIFICATE or
// HS_CERTIFICATE_URL
// --> HS_CLIENT_KEY_EXCHANGE
// --> HS_CERTIFICATE_VERIFY [optional]
// --> HS_CLIENT_CHANGE_CIPHER_SPEC
// --> HS_CLIENT_FINISHED
// (Server Finished Flight)
// --> HS_CLIENT_SUPPLEMENTAL_DATA [optional]
//
// Abbreviated handshake state stacks
// (Server Finished Flight)
// HS_NEW_SESSION_TICKET
// --> HS_SERVER_CHANGE_CIPHER_SPEC
// --> HS_SERVER_FINISHED
// (Client Finished Flight)
// --> HS_CLIENT_CHANGE_CIPHER_SPEC
// --> HS_CLIENT_FINISHED
//
// Note that this state may have an alternative option.
// Check and update the present state.
if (!upcomingStates.isEmpty()) {
// The current state should be HS_SERVER_HELLO
HandshakeState handshakeState = upcomingStates.pop();
HandshakeState alternative = null;
if (!alternatives.isEmpty()) {
alternative = alternatives.pop();
}
if ((handshakeState != HS_SERVER_HELLO) &&
(alternative != HS_SERVER_HELLO)) {
throw new SSLProtocolException(exceptionMsg);
}
} else {
// No present state.
throw new SSLProtocolException(exceptionMsg);
}
// Add the upcoming states.
ServerHello serverHello = (ServerHello)handshakeMessage;
HelloExtensions hes = serverHello.extensions;
// Not support SessionTicket extension yet.
//
// boolean hasSessionTicketExt =
// (hes.get(HandshakeMessage.ht_new_session_ticket) != null);
if (isAbbreviated) {
// Not support SessionTicket extension yet.
//
// // Mandatory NewSessionTicket message
// if (hasSessionTicketExt) {
// upcomingStates.add(HS_NEW_SESSION_TICKET);
// }
// Mandatory server ChangeCipherSpec and Finished messages
upcomingStates.add(HS_SERVER_CHANGE_CIPHER_SPEC);
upcomingStates.add(HS_SERVER_FINISHED);
// Mandatory client ChangeCipherSpec and Finished messages
upcomingStates.add(HS_CLIENT_CHANGE_CIPHER_SPEC);
upcomingStates.add(HS_CLIENT_FINISHED);
} else {
// Not support SupplementalData extension yet.
//
// boolean hasSupplementalDataExt =
// (hes.get(HandshakeMessage.ht_supplemental_data) != null);
// Not support CertificateURL extension yet.
//
// boolean hasCertificateUrlExt =
// (hes.get(ExtensionType EXT_CLIENT_CERTIFICATE_URL)
// != null);
// Not support SupplementalData extension yet.
//
// // Optional SupplementalData message
// if (hasSupplementalDataExt) {
// upcomingStates.add(HS_SERVER_SUPPLEMENTAL_DATA);
// }
// Need server Certificate message or not?
KeyExchange keyExchange = serverHello.cipherSuite.keyExchange;
if ((keyExchange != K_KRB5) &&
(keyExchange != K_KRB5_EXPORT) &&
(keyExchange != K_DH_ANON) &&
(keyExchange != K_ECDH_ANON)) {
// Mandatory Certificate message
upcomingStates.add(HS_SERVER_CERTIFICATE);
}
// Need ServerKeyExchange message or not?
if ((keyExchange == K_RSA_EXPORT) ||
(keyExchange == K_DHE_RSA) ||
(keyExchange == K_DHE_DSS) ||
(keyExchange == K_DH_ANON) ||
(keyExchange == K_ECDHE_RSA) ||
(keyExchange == K_ECDHE_ECDSA) ||
(keyExchange == K_ECDH_ANON)) {
// Optional ServerKeyExchange message
upcomingStates.add(HS_SERVER_KEY_EXCHANGE);
}
// Optional CertificateRequest message
upcomingStates.add(HS_CERTIFICATE_REQUEST);
// Mandatory ServerHelloDone message
upcomingStates.add(HS_SERVER_HELLO_DONE);
// Not support SupplementalData extension yet.
//
// // Optional SupplementalData message
// if (hasSupplementalDataExt) {
// upcomingStates.add(HS_CLIENT_SUPPLEMENTAL_DATA);
// }
// Optional client Certificate message
upcomingStates.add(HS_CLIENT_CERTIFICATE);
// Not support CertificateURL extension yet.
//
// // Alternative CertificateURL message, optional too.
// //
// // Please put CertificateURL rather than Certificate
// // message in the alternatives list. So that we can
// // simplify the process of this alternative pair later.
// if (hasCertificateUrlExt) {
// alternatives.add(HS_CERTIFICATE_URL);
// }
// Mandatory ClientKeyExchange message
upcomingStates.add(HS_CLIENT_KEY_EXCHANGE);
// Optional CertificateVerify message
upcomingStates.add(HS_CERTIFICATE_VERIFY);
// Mandatory client ChangeCipherSpec and Finished messages
upcomingStates.add(HS_CLIENT_CHANGE_CIPHER_SPEC);
upcomingStates.add(HS_CLIENT_FINISHED);
// Not support SessionTicket extension yet.
//
// // Mandatory NewSessionTicket message
// if (hasSessionTicketExt) {
// upcomingStates.add(HS_NEW_SESSION_TICKET);
// }
// Mandatory server ChangeCipherSpec and Finished messages
upcomingStates.add(HS_SERVER_CHANGE_CIPHER_SPEC);
upcomingStates.add(HS_SERVER_FINISHED);
}
break;
case HandshakeMessage.ht_certificate:
//
// State machine:
// PRESENT: HS_CERTIFICATE_URL or
// HS_CLIENT_CERTIFICATE
// TO : HS_CLIENT_KEY_EXCHANGE
//
// Or
//
// PRESENT: HS_SERVER_CERTIFICATE
// TO : HS_CERTIFICATE_STATUS [optional]
// HS_SERVER_KEY_EXCHANGE [optional]
// HS_CERTIFICATE_REQUEST [optional]
// HS_SERVER_HELLO_DONE
//
// Note that this state may have an alternative option.
// Check and update the present state.
while (!upcomingStates.isEmpty()) {
HandshakeState handshakeState = upcomingStates.pop();
if (handshakeState.handshakeType == handshakeType) {
hasPresentState = true;
// The current state should be HS_CLIENT_CERTIFICATE or
// HS_SERVER_CERTIFICATE.
//
// Note that we won't put HS_CLIENT_CERTIFICATE into
// the alternative list.
if ((handshakeState != HS_CLIENT_CERTIFICATE) &&
(handshakeState != HS_SERVER_CERTIFICATE)) {
throw new SSLProtocolException(exceptionMsg);
}
// Is it an expected client Certificate message?
boolean isClientMessage = false;
if (!upcomingStates.isEmpty()) {
// If the next expected message is ClientKeyExchange,
// this one should be an expected client Certificate
// message.
HandshakeState nextState = upcomingStates.getFirst();
if (nextState == HS_CLIENT_KEY_EXCHANGE) {
isClientMessage = true;
}
}
if (isClientMessage) {
if (handshakeState != HS_CLIENT_CERTIFICATE) {
throw new SSLProtocolException(exceptionMsg);
}
// Not support CertificateURL extension yet.
/*******************************************
// clear up the alternatives list
if (!alternatives.isEmpty()) {
HandshakeState alternative = alternatives.pop();
if (alternative != HS_CERTIFICATE_URL) {
throw new SSLProtocolException(exceptionMsg);
}
}
********************************************/
} else {
if ((handshakeState != HS_SERVER_CERTIFICATE)) {
throw new SSLProtocolException(exceptionMsg);
}
}
break;
} else if (!handshakeState.isOptional) {
throw new SSLProtocolException(exceptionMsg);
} // Otherwise, looking for next state track.
}
// No present state.
if (!hasPresentState) {
throw new SSLProtocolException(exceptionMsg);
}
// no new upcoming states.
break;
default:
// Check and update the present state.
while (!upcomingStates.isEmpty()) {
HandshakeState handshakeState = upcomingStates.pop();
if (handshakeState.handshakeType == handshakeType) {
hasPresentState = true;
break;
} else if (!handshakeState.isOptional) {
throw new SSLProtocolException(exceptionMsg);
} // Otherwise, looking for next state track.
}
// No present state.
if (!hasPresentState) {
throw new SSLProtocolException(exceptionMsg);
}
// no new upcoming states.
}
if (debugIsOn) {
for (HandshakeState handshakeState : upcomingStates) {
System.out.println(
"upcoming handshake states: " + handshakeState);
}
for (HandshakeState handshakeState : alternatives) {
System.out.println(
"upcoming handshake alternative state: " + handshakeState);
}
}
}
void changeCipherSpec(boolean isInput,
boolean isClient) throws SSLProtocolException {
if (debugIsOn) {
System.out.println(
"update handshake state: change_cipher_spec");
}
String exceptionMsg = "ChangeCipherSpec message sequence violation";
HandshakeState expectedState;
if ((isClient && isInput) || (!isClient && !isInput)) {
expectedState = HS_SERVER_CHANGE_CIPHER_SPEC;
} else {
expectedState = HS_CLIENT_CHANGE_CIPHER_SPEC;
}
boolean hasPresentState = false;
// Check and update the present state.
while (!upcomingStates.isEmpty()) {
HandshakeState handshakeState = upcomingStates.pop();
if (handshakeState == expectedState) {
hasPresentState = true;
break;
} else if (!handshakeState.isOptional) {
throw new SSLProtocolException(exceptionMsg);
} // Otherwise, looking for next state track.
}
// No present state.
if (!hasPresentState) {
throw new SSLProtocolException(exceptionMsg);
}
// no new upcoming states.
if (debugIsOn) {
for (HandshakeState handshakeState : upcomingStates) {
System.out.println(
"upcoming handshake states: " + handshakeState);
}
for (HandshakeState handshakeState : alternatives) {
System.out.println(
"upcoming handshake alternative state: " + handshakeState);
}
}
}
private static String toString(byte handshakeType) {
String s = handshakeTypes.get(handshakeType);
if (s == null) {
s = "unknown";
}
return (s + "[" + handshakeType + "]");
}
}
......@@ -118,10 +118,14 @@ abstract class Handshaker {
HandshakeHash handshakeHash;
HandshakeInStream input;
HandshakeOutStream output;
int state;
SSLContextImpl sslContext;
RandomCookie clnt_random, svr_random;
SSLSessionImpl session;
HandshakeStateManager handshakeState;
boolean clientHelloDelivered;
boolean serverHelloRequested;
boolean handshakeActivated;
boolean handshakeFinished;
// current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL
CipherSuite cipherSuite;
......@@ -135,10 +139,6 @@ abstract class Handshaker {
// True if it's OK to start a new SSL session
boolean enableNewSession;
// True if session keys have been calculated and the caller may receive
// and process a ChangeCipherSpec message
private boolean sessKeysCalculated;
// Whether local cipher suites preference should be honored during
// handshaking?
//
......@@ -277,9 +277,13 @@ abstract class Handshaker {
this.secureRenegotiation = secureRenegotiation;
this.clientVerifyData = clientVerifyData;
this.serverVerifyData = serverVerifyData;
enableNewSession = true;
invalidated = false;
sessKeysCalculated = false;
this.enableNewSession = true;
this.invalidated = false;
this.handshakeState = new HandshakeStateManager();
this.clientHelloDelivered = false;
this.serverHelloRequested = false;
this.handshakeActivated = false;
this.handshakeFinished = false;
setCipherSuite(CipherSuite.C_NULL);
setEnabledProtocols(enabledProtocols);
......@@ -289,22 +293,6 @@ abstract class Handshaker {
} else { // engine != null
algorithmConstraints = new SSLAlgorithmConstraints(engine, true);
}
//
// In addition to the connection state machine, controlling
// how the connection deals with the different sorts of records
// that get sent (notably handshake transitions!), there's
// also a handshaking state machine that controls message
// sequencing.
//
// It's a convenient artifact of the protocol that this can,
// with only a couple of minor exceptions, be driven by the
// type constant for the last message seen: except for the
// client's cert verify, those constants are in a convenient
// order to drastically simplify state machine checking.
//
state = -2; // initialized but not activated
}
/*
......@@ -386,14 +374,6 @@ abstract class Handshaker {
}
}
final boolean receivedChangeCipherSpec() {
if (conn != null) {
return conn.receivedChangeCipherSpec();
} else {
return engine.receivedChangeCipherSpec();
}
}
String getEndpointIdentificationAlgorithmSE() {
SSLParameters paras;
if (conn != null) {
......@@ -573,8 +553,7 @@ abstract class Handshaker {
engine.outputRecord.setHelloVersion(helloVersion);
}
// move state to activated
state = -1;
handshakeActivated = true;
}
/**
......@@ -919,10 +898,9 @@ abstract class Handshaker {
* this freshly created session can become the current one.
*/
boolean isDone() {
return state == HandshakeMessage.ht_finished;
return started() && handshakeState.isEmpty() && handshakeFinished;
}
/*
* Returns the session which was created through this
* handshake sequence ... should be called after isDone()
......@@ -1028,6 +1006,13 @@ abstract class Handshaker {
return;
}
// Set the flags in the message receiving side.
if (messageType == HandshakeMessage.ht_client_hello) {
clientHelloDelivered = true;
} else if (messageType == HandshakeMessage.ht_hello_request) {
serverHelloRequested = true;
}
/*
* Process the message. We require
* that processMessage() consumes the entire message. In
......@@ -1062,15 +1047,14 @@ abstract class Handshaker {
* In activated state, the handshaker may not send any messages out.
*/
boolean activated() {
return state >= -1;
return handshakeActivated;
}
/**
* Returns true iff the handshaker has sent any messages.
*/
boolean started() {
return state >= 0; // 0: HandshakeMessage.ht_hello_request
// 1: HandshakeMessage.ht_client_hello
return (serverHelloRequested || clientHelloDelivered);
}
......@@ -1080,11 +1064,13 @@ abstract class Handshaker {
* the subclass returns. NOP if handshaking's already started.
*/
void kickstart() throws IOException {
if (state >= 0) {
if ((isClient && clientHelloDelivered) ||
(!isClient && serverHelloRequested)) {
return;
}
HandshakeMessage m = getKickstartMessage();
handshakeState.update(m, resumingSession);
if (debug != null && Debug.isOn("handshake")) {
m.print(System.out);
......@@ -1092,7 +1078,14 @@ abstract class Handshaker {
m.write(output);
output.flush();
state = m.messageType();
// Set the flags in the message delivering side.
int handshakeType = m.messageType();
if (handshakeType == HandshakeMessage.ht_hello_request) {
serverHelloRequested = true;
} else { // HandshakeMessage.ht_client_hello
clientHelloDelivered = true;
}
}
/**
......@@ -1124,16 +1117,6 @@ abstract class Handshaker {
output.flush(); // i.e. handshake data
/*
* The write cipher state is protected by the connection write lock
* so we must grab it while making the change. We also
* make sure no writes occur between sending the ChangeCipherSpec
* message, installing the new cipher state, and sending the
* Finished message.
*
* We already hold SSLEngine/SSLSocket "this" by virtue
* of this being called from the readRecord code.
*/
OutputRecord r;
if (conn != null) {
r = new OutputRecord(Record.ct_change_cipher_spec);
......@@ -1144,14 +1127,27 @@ abstract class Handshaker {
r.setVersion(protocolVersion);
r.write(1); // single byte of data
/*
* The write cipher state is protected by the connection write lock
* so we must grab it while making the change. We also
* make sure no writes occur between sending the ChangeCipherSpec
* message, installing the new cipher state, and sending the
* Finished message.
*
* We already hold SSLEngine/SSLSocket "this" by virtue
* of this being called from the readRecord code.
*/
if (conn != null) {
conn.writeLock.lock();
try {
handshakeState.changeCipherSpec(false, isClient);
conn.writeRecord(r);
conn.changeWriteCiphers();
if (debug != null && Debug.isOn("handshake")) {
mesg.print(System.out);
}
handshakeState.update(mesg, resumingSession);
mesg.write(output);
output.flush();
} finally {
......@@ -1159,19 +1155,28 @@ abstract class Handshaker {
}
} else {
synchronized (engine.writeLock) {
handshakeState.changeCipherSpec(false, isClient);
engine.writeRecord((EngineOutputRecord)r);
engine.changeWriteCiphers();
if (debug != null && Debug.isOn("handshake")) {
mesg.print(System.out);
}
mesg.write(output);
handshakeState.update(mesg, resumingSession);
mesg.write(output);
if (lastMessage) {
output.setFinishedMsg();
}
output.flush();
}
}
if (lastMessage) {
handshakeFinished = true;
}
}
void receiveChangeCipherSpec() throws IOException {
handshakeState.changeCipherSpec(true, isClient);
}
/*
......@@ -1353,10 +1358,6 @@ abstract class Handshaker {
throw new ProviderException(e);
}
// Mark a flag that allows outside entities (like SSLSocket/SSLEngine)
// determine if a ChangeCipherSpec message could be processed.
sessKeysCalculated = true;
//
// Dump the connection keys as they're generated.
//
......@@ -1411,15 +1412,6 @@ abstract class Handshaker {
}
}
/**
* Return whether or not the Handshaker has derived session keys for
* this handshake. This is used for determining readiness to process
* an incoming ChangeCipherSpec message.
*/
boolean sessionKeysCalculated() {
return sessKeysCalculated;
}
private static void printHex(HexDumpEncoder dump, byte[] bytes) {
if (bytes == null) {
System.out.println("(key bytes not available)");
......
......@@ -211,11 +211,6 @@ final public class SSLEngineImpl extends SSLEngine {
static final byte clauth_requested = 1;
static final byte clauth_required = 2;
/*
* Flag indicating that the engine has received a ChangeCipherSpec message.
*/
private boolean receivedCCS;
/*
* Flag indicating if the next record we receive MUST be a Finished
* message. Temporarily set during the handshake to ensure that
......@@ -377,7 +372,6 @@ final public class SSLEngineImpl extends SSLEngine {
*/
roleIsServer = true;
connectionState = cs_START;
receivedCCS = false;
// default server name indication
serverNames =
......@@ -525,7 +519,6 @@ final public class SSLEngineImpl extends SSLEngine {
return HandshakeStatus.NEED_UNWRAP;
} // else not handshaking
}
return HandshakeStatus.NOT_HANDSHAKING;
}
}
......@@ -587,14 +580,6 @@ final public class SSLEngineImpl extends SSLEngine {
* Synchronized on "this" from readRecord.
*/
private void changeReadCiphers() throws SSLException {
if (connectionState != cs_HANDSHAKE
&& connectionState != cs_RENEGOTIATE) {
throw new SSLProtocolException(
"State error, change cipher specs");
}
// ... create decompressor
CipherBox oldCipher = readCipher;
try {
......@@ -780,6 +765,10 @@ final public class SSLEngineImpl extends SSLEngine {
synchronized (unwrapLock) {
return readNetRecord(ea);
}
} catch (SSLProtocolException spe) {
// may be an unexpected handshake message
fatal(Alerts.alert_unexpected_message, spe.getMessage(), spe);
return null; // make compiler happy
} catch (Exception e) {
/*
* Don't reset position so it looks like we didn't
......@@ -1004,6 +993,7 @@ final public class SSLEngineImpl extends SSLEngine {
* session (new keys exchanged) with just this connection
* in it.
*/
initHandshaker();
if (!handshaker.activated()) {
// prior to handshaking, activate the handshake
......@@ -1027,7 +1017,6 @@ final public class SSLEngineImpl extends SSLEngine {
if (handshaker.invalidated) {
handshaker = null;
receivedCCS = false;
// if state is cs_RENEGOTIATE, revert it to cs_DATA
if (connectionState == cs_RENEGOTIATE) {
connectionState = cs_DATA;
......@@ -1046,8 +1035,6 @@ final public class SSLEngineImpl extends SSLEngine {
}
handshaker = null;
connectionState = cs_DATA;
receivedCCS = false;
// No handshakeListeners here. That's a
// SSLSocket thing.
} else if (handshaker.taskOutstanding()) {
......@@ -1085,14 +1072,11 @@ final public class SSLEngineImpl extends SSLEngine {
case Record.ct_change_cipher_spec:
if ((connectionState != cs_HANDSHAKE
&& connectionState != cs_RENEGOTIATE)
|| !handshaker.sessionKeysCalculated()
|| receivedCCS) {
&& connectionState != cs_RENEGOTIATE)) {
// For the CCS message arriving in the wrong state
fatal(Alerts.alert_unexpected_message,
"illegal change cipher spec msg, conn state = "
+ connectionState + ", handshake state = "
+ handshaker.state);
+ connectionState);
} else if (inputRecord.available() != 1
|| inputRecord.read() != 1) {
// For structural/content issues with the CCS
......@@ -1100,11 +1084,6 @@ final public class SSLEngineImpl extends SSLEngine {
"Malformed change cipher spec msg");
}
// Once we've received CCS, update the flag.
// If the remote endpoint sends it again in this handshake
// we won't process it.
receivedCCS = true;
//
// The first message after a change_cipher_spec
// record MUST be a "Finished" handshake record,
......@@ -1112,6 +1091,7 @@ final public class SSLEngineImpl extends SSLEngine {
// to be checked by a minor tweak to the state
// machine.
//
handshaker.receiveChangeCipherSpec();
changeReadCiphers();
// next message MUST be a finished message
expectingFinished = true;
......@@ -1151,7 +1131,6 @@ final public class SSLEngineImpl extends SSLEngine {
}
} // synchronized (this)
}
return hsStatus;
}
......@@ -1185,6 +1164,10 @@ final public class SSLEngineImpl extends SSLEngine {
synchronized (wrapLock) {
return writeAppRecord(ea);
}
} catch (SSLProtocolException spe) {
// may be an unexpected handshake message
fatal(Alerts.alert_unexpected_message, spe.getMessage(), spe);
return null; // make compiler happy
} catch (Exception e) {
ea.resetPos();
......@@ -1212,7 +1195,6 @@ final public class SSLEngineImpl extends SSLEngine {
* See if the handshaker needs to report back some SSLException.
*/
checkTaskThrown();
/*
* short circuit if we're closed/closing.
*/
......@@ -1234,7 +1216,6 @@ final public class SSLEngineImpl extends SSLEngine {
* without trying to wrap anything.
*/
hsStatus = getHSStatus(null);
if (hsStatus == HandshakeStatus.NEED_UNWRAP) {
return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
}
......@@ -2148,14 +2129,6 @@ final public class SSLEngineImpl extends SSLEngine {
}
}
/*
* Returns a boolean indicating whether the ChangeCipherSpec message
* has been received for this handshake.
*/
boolean receivedChangeCipherSpec() {
return receivedCCS;
}
/**
* Returns a printable representation of this end of the connection.
*/
......
......@@ -174,12 +174,6 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
*/
private volatile int connectionState;
/*
* Flag indicating that the engine's handshaker has done the necessary
* steps so the engine may process a ChangeCipherSpec message.
*/
private boolean receivedCCS;
/*
* Flag indicating if the next record we receive MUST be a Finished
* message. Temporarily set during the handshake to ensure that
......@@ -610,7 +604,6 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
*/
roleIsServer = isServer;
connectionState = cs_START;
receivedCCS = false;
/*
* default read and write side cipher and MAC support
......@@ -940,7 +933,6 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
readRecord(r, true);
}
/*
* Clear the pipeline of records from the peer, optionally returning
* application data. Caller is responsible for knowing that it's
......@@ -1074,7 +1066,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
if (handshaker.invalidated) {
handshaker = null;
receivedCCS = false;
inrec.setHandshakeHash(null);
// if state is cs_RENEGOTIATE, revert it to cs_DATA
if (connectionState == cs_RENEGOTIATE) {
connectionState = cs_DATA;
......@@ -1090,7 +1083,6 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
handshakeSession = null;
handshaker = null;
connectionState = cs_DATA;
receivedCCS = false;
//
// Tell folk about handshake completion, but do
......@@ -1137,25 +1129,17 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
case Record.ct_change_cipher_spec:
if ((connectionState != cs_HANDSHAKE
&& connectionState != cs_RENEGOTIATE)
|| !handshaker.sessionKeysCalculated()
|| receivedCCS) {
&& connectionState != cs_RENEGOTIATE)) {
// For the CCS message arriving in the wrong state
fatal(Alerts.alert_unexpected_message,
"illegal change cipher spec msg, conn state = "
+ connectionState + ", handshake state = "
+ handshaker.state);
+ connectionState);
} else if (r.available() != 1 || r.read() != 1) {
// For structural/content issues with the CCS
fatal(Alerts.alert_unexpected_message,
"Malformed change cipher spec msg");
}
// Once we've received CCS, update the flag.
// If the remote endpoint sends it again in this handshake
// we won't process it.
receivedCCS = true;
//
// The first message after a change_cipher_spec
// record MUST be a "Finished" handshake record,
......@@ -1163,6 +1147,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
// to be checked by a minor tweak to the state
// machine.
//
handshaker.receiveChangeCipherSpec();
changeReadCiphers();
// next message MUST be a finished message
expectingFinished = true;
......@@ -1361,13 +1346,10 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
kickstartHandshake();
/*
* All initial handshaking goes through this
* InputRecord until we have a valid SSL connection.
* Once initial handshaking is finished, AppInputStream's
* InputRecord can handle any future renegotiation.
* All initial handshaking goes through this operation
* until we have a valid SSL connection.
*
* Keep this local so that it goes out of scope and is
* eventually GC'd.
* Handle handshake messages only, need no application data.
*/
if (inrec == null) {
inrec = new InputRecord();
......@@ -2675,14 +2657,6 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
}
}
/*
* Returns a boolean indicating whether the ChangeCipherSpec message
* has been received for this handshake.
*/
boolean receivedChangeCipherSpec() {
return receivedCCS;
}
//
// We allocate a separate thread to deliver handshake completion
// events. This ensures that the notifications don't block the
......
......@@ -207,21 +207,14 @@ final class ServerHandshaker extends Handshaker {
@Override
void processMessage(byte type, int message_len)
throws IOException {
//
// In SSLv3 and TLS, messages follow strictly increasing
// numerical order _except_ for one annoying special case.
//
if ((state >= type)
&& (state != HandshakeMessage.ht_client_key_exchange
&& type != HandshakeMessage.ht_certificate_verify)) {
throw new SSLProtocolException(
"Handshake message sequence violation, state = " + state
+ ", type = " + type);
}
// check the handshake state
handshakeState.check(type);
switch (type) {
case HandshakeMessage.ht_client_hello:
ClientHello ch = new ClientHello(input, message_len);
handshakeState.update(ch, resumingSession);
/*
* send it off for processing.
*/
......@@ -234,7 +227,9 @@ final class ServerHandshaker extends Handshaker {
"client sent unsolicited cert chain");
// NOTREACHED
}
this.clientCertificate(new CertificateMsg(input));
CertificateMsg certificateMsg = new CertificateMsg(input);
handshakeState.update(certificateMsg, resumingSession);
this.clientCertificate(certificateMsg);
break;
case HandshakeMessage.ht_client_key_exchange:
......@@ -252,17 +247,20 @@ final class ServerHandshaker extends Handshaker {
protocolVersion, clientRequestedVersion,
sslContext.getSecureRandom(), input,
message_len, privateKey);
handshakeState.update(pms, resumingSession);
preMasterSecret = this.clientKeyExchange(pms);
break;
case K_KRB5:
case K_KRB5_EXPORT:
preMasterSecret = this.clientKeyExchange(
KerberosClientKeyExchange kke =
new KerberosClientKeyExchange(protocolVersion,
clientRequestedVersion,
sslContext.getSecureRandom(),
input,
this.getAccSE(),
serviceCreds));
serviceCreds);
handshakeState.update(kke, resumingSession);
preMasterSecret = this.clientKeyExchange(kke);
break;
case K_DHE_RSA:
case K_DHE_DSS:
......@@ -273,16 +271,19 @@ final class ServerHandshaker extends Handshaker {
* protocol difference in these five flavors is in how
* the ServerKeyExchange message was constructed!
*/
preMasterSecret = this.clientKeyExchange(
new DHClientKeyExchange(input));
DHClientKeyExchange dhcke = new DHClientKeyExchange(input);
handshakeState.update(dhcke, resumingSession);
preMasterSecret = this.clientKeyExchange(dhcke);
break;
case K_ECDH_RSA:
case K_ECDH_ECDSA:
case K_ECDHE_RSA:
case K_ECDHE_ECDSA:
case K_ECDH_ANON:
preMasterSecret = this.clientKeyExchange
(new ECDHClientKeyExchange(input));
ECDHClientKeyExchange ecdhcke =
new ECDHClientKeyExchange(input);
handshakeState.update(ecdhcke, resumingSession);
preMasterSecret = this.clientKeyExchange(ecdhcke);
break;
default:
throw new SSLProtocolException
......@@ -302,38 +303,24 @@ final class ServerHandshaker extends Handshaker {
break;
case HandshakeMessage.ht_certificate_verify:
this.clientCertificateVerify(new CertificateVerify(input,
getLocalSupportedSignAlgs(), protocolVersion));
CertificateVerify cvm =
new CertificateVerify(input,
getLocalSupportedSignAlgs(), protocolVersion);
handshakeState.update(cvm, resumingSession);
this.clientCertificateVerify(cvm);
break;
case HandshakeMessage.ht_finished:
// A ChangeCipherSpec record must have been received prior to
// reception of the Finished message (RFC 5246, 7.4.9).
if (!receivedChangeCipherSpec()) {
fatalSE(Alerts.alert_handshake_failure,
"Received Finished message before ChangeCipherSpec");
}
this.clientFinished(
new Finished(protocolVersion, input, cipherSuite));
Finished cfm =
new Finished(protocolVersion, input, cipherSuite);
handshakeState.update(cfm, resumingSession);
this.clientFinished(cfm);
break;
default:
throw new SSLProtocolException(
"Illegal server handshake msg, " + type);
}
//
// Move state machine forward if the message handling
// code didn't already do so
//
if (state < type) {
if(type == HandshakeMessage.ht_certificate_verify) {
state = type + 2; // an annoying special case
} else {
state = type;
}
}
}
......@@ -364,7 +351,7 @@ final class ServerHandshaker extends Handshaker {
//
// This will not have any impact on server initiated renegotiation.
if (rejectClientInitiatedRenego && !isInitialHandshake &&
state != HandshakeMessage.ht_hello_request) {
!serverHelloRequested) {
fatalSE(Alerts.alert_handshake_failure,
"Client initiated renegotiation is not allowed");
}
......@@ -856,6 +843,7 @@ final class ServerHandshaker extends Handshaker {
System.out.println("Cipher suite: " + session.getSuite());
}
m1.write(output);
handshakeState.update(m1, resumingSession);
//
// If we are resuming a session, we finish writing handshake
......@@ -895,6 +883,7 @@ final class ServerHandshaker extends Handshaker {
m2.print(System.out);
}
m2.write(output);
handshakeState.update(m2, resumingSession);
// XXX has some side effects with OS TCP buffering,
// leave it out for now
......@@ -990,6 +979,7 @@ final class ServerHandshaker extends Handshaker {
m3.print(System.out);
}
m3.write(output);
handshakeState.update(m3, resumingSession);
}
//
......@@ -1039,6 +1029,7 @@ final class ServerHandshaker extends Handshaker {
m4.print(System.out);
}
m4.write(output);
handshakeState.update(m4, resumingSession);
}
/*
......@@ -1050,6 +1041,7 @@ final class ServerHandshaker extends Handshaker {
m5.print(System.out);
}
m5.write(output);
handshakeState.update(m5, resumingSession);
/*
* Flush any buffered messages so the client will see them.
......@@ -1797,6 +1789,8 @@ final class ServerHandshaker extends Handshaker {
if (!resumingSession) {
input.digestNow();
sendChangeCipherAndFinish(true);
} else {
handshakeFinished = true;
}
/*
......@@ -1844,16 +1838,6 @@ final class ServerHandshaker extends Handshaker {
if (secureRenegotiation) {
serverVerifyData = mesg.getVerifyData();
}
/*
* Update state machine so client MUST send 'finished' next
* The update should only take place if it is not in the fast
* handshake mode since the server has to wait for a finished
* message from the client.
*/
if (finishedTag) {
state = HandshakeMessage.ht_finished;
}
}
......
......@@ -23,7 +23,7 @@
/*
* @test
* @bug 8044860
* @bug 8044860 8074462
* @summary Vectors and fixed length fields should be verified
* for allowed sizes.
* @run main/othervm LengthCheckTest
......@@ -231,7 +231,7 @@ public class LengthCheckTest {
// sent back to the server.
if (gotException == false ||
!isTlsMessage(cTOs, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
TLS_ALERT_INTERNAL_ERROR)) {
TLS_ALERT_UNEXPECTED_MSG)) {
throw new SSLException(
"Client failed to throw Alert:fatal:internal_error");
}
......@@ -283,7 +283,7 @@ public class LengthCheckTest {
// sent back to the client.
if (gotException == false ||
!isTlsMessage(sTOc, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
TLS_ALERT_INTERNAL_ERROR)) {
TLS_ALERT_UNEXPECTED_MSG)) {
throw new SSLException(
"Server failed to throw Alert:fatal:internal_error");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册