mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
8367059: DTLS: loss of NewSessionTicket message results in handshake failure
Reviewed-by: jnimeh, djelinski
This commit is contained in:
parent
28f2591bad
commit
436dc687ba
@ -170,7 +170,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
||||
|
||||
// Buffer next epoch message if necessary.
|
||||
if (this.readEpoch < recordEpoch) {
|
||||
// Discard the record younger than the current epcoh if:
|
||||
// Discard the record younger than the current epoch if:
|
||||
// 1. it is not a handshake message, or
|
||||
// 3. it is not of next epoch.
|
||||
if ((contentType != ContentType.HANDSHAKE.id &&
|
||||
@ -1445,7 +1445,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
||||
//
|
||||
if (expectCCSFlight) {
|
||||
// Have the ChangeCipherSpec/Finished flight been received?
|
||||
boolean isReady = hasFinishedMessage(bufferedFragments);
|
||||
boolean isReady = hasFinishedMessage();
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
|
||||
SSLLogger.fine(
|
||||
"Has the final flight been received? " + isReady);
|
||||
@ -1492,7 +1492,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
||||
//
|
||||
// an abbreviated handshake
|
||||
//
|
||||
if (hasFinishedMessage(bufferedFragments)) {
|
||||
if (hasFinishedMessage()) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
|
||||
SSLLogger.fine("It's an abbreviated handshake.");
|
||||
}
|
||||
@ -1565,7 +1565,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasFinishedMessage(bufferedFragments)) {
|
||||
if (!hasFinishedMessage()) {
|
||||
// not yet have the ChangeCipherSpec/Finished messages
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
|
||||
SSLLogger.fine(
|
||||
@ -1601,35 +1601,33 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Looking for the ChangeCipherSpec and Finished messages.
|
||||
// Looking for the ChangeCipherSpec, Finished and
|
||||
// NewSessionTicket messages.
|
||||
//
|
||||
// As the cached Finished message should be a ciphertext, we don't
|
||||
// exactly know a ciphertext is a Finished message or not. According
|
||||
// to the spec of TLS/DTLS handshaking, a Finished message is always
|
||||
// sent immediately after a ChangeCipherSpec message. The first
|
||||
// ciphertext handshake message should be the expected Finished message.
|
||||
private boolean hasFinishedMessage(Set<RecordFragment> fragments) {
|
||||
|
||||
private boolean hasFinishedMessage() {
|
||||
boolean hasCCS = false;
|
||||
boolean hasFin = false;
|
||||
for (RecordFragment fragment : fragments) {
|
||||
|
||||
for (RecordFragment fragment : bufferedFragments) {
|
||||
if (fragment.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
|
||||
if (hasFin) {
|
||||
return true;
|
||||
}
|
||||
hasCCS = true;
|
||||
} else if (fragment.contentType == ContentType.HANDSHAKE.id) {
|
||||
// Finished is the first expected message of a new epoch.
|
||||
if (fragment.isCiphertext) {
|
||||
if (hasCCS) {
|
||||
return true;
|
||||
}
|
||||
hasFin = true;
|
||||
}
|
||||
} else if (fragment.contentType == ContentType.HANDSHAKE.id
|
||||
&& fragment.isCiphertext) {
|
||||
hasFin = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// NewSessionTicket message presence in the Finished flight
|
||||
// should only be expected on the client side, and only
|
||||
// if stateless resumption is enabled.
|
||||
return hasCCS && hasFin && (!tc.sslConfig.isClientMode
|
||||
|| !tc.handshakeContext.statelessResumption
|
||||
|| hasCompleted(SSLHandshake.NEW_SESSION_TICKET.id));
|
||||
}
|
||||
|
||||
// Is client CertificateVerify a mandatory message?
|
||||
@ -1674,7 +1672,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
||||
int presentMsgSeq, int endMsgSeq) {
|
||||
|
||||
// The caller should have checked the completion of the first
|
||||
// present handshake message. Need not to check it again.
|
||||
// present handshake message. Need not check it again.
|
||||
for (RecordFragment rFrag : fragments) {
|
||||
if ((rFrag.contentType != ContentType.HANDSHAKE.id) ||
|
||||
rFrag.isCiphertext) {
|
||||
|
||||
@ -286,7 +286,7 @@ enum SSLExtension implements SSLStringizer {
|
||||
ProtocolVersion.PROTOCOLS_10_12,
|
||||
SessionTicketExtension.shNetworkProducer,
|
||||
SessionTicketExtension.shOnLoadConsumer,
|
||||
null,
|
||||
SessionTicketExtension.shOnLoadAbsence,
|
||||
null,
|
||||
null,
|
||||
SessionTicketExtension.steStringizer),
|
||||
|
||||
@ -72,6 +72,8 @@ final class SessionTicketExtension {
|
||||
new T12SHSessionTicketProducer();
|
||||
static final ExtensionConsumer shOnLoadConsumer =
|
||||
new T12SHSessionTicketConsumer();
|
||||
static final HandshakeAbsence shOnLoadAbsence =
|
||||
new T12SHSessionTicketOnLoadAbsence();
|
||||
|
||||
static final SSLStringizer steStringizer = new SessionTicketStringizer();
|
||||
// No need to compress a ticket if it can fit in a single packet.
|
||||
@ -529,4 +531,27 @@ final class SessionTicketExtension {
|
||||
chc.statelessResumption = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The absence processing if a "session_ticket" extension is
|
||||
* not present in the ServerHello handshake message.
|
||||
*/
|
||||
private static final class T12SHSessionTicketOnLoadAbsence
|
||||
implements HandshakeAbsence {
|
||||
|
||||
@Override
|
||||
public void absent(ConnectionContext context,
|
||||
HandshakeMessage message) {
|
||||
ClientHandshakeContext chc = (ClientHandshakeContext) context;
|
||||
|
||||
// Disable stateless resumption if server doesn't send the extension.
|
||||
if (chc.statelessResumption) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.info(
|
||||
"Server doesn't support stateless resumption");
|
||||
}
|
||||
chc.statelessResumption = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
47
test/jdk/javax/net/ssl/DTLS/DTLSNoNewSessionTicket.java
Normal file
47
test/jdk/javax/net/ssl/DTLS/DTLSNoNewSessionTicket.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8367059
|
||||
* @summary DTLS: loss of NewSessionTicket message results in handshake failure
|
||||
* @modules java.base/sun.security.util
|
||||
* @library /test/lib
|
||||
* @build DTLSOverDatagram
|
||||
*
|
||||
* @comment Make sure client doesn't expect NewSessionTicket in the final
|
||||
* flight if server doesn't send the "session_ticket" extension with
|
||||
* ServerHello handshake message.
|
||||
*
|
||||
* @run main/othervm -Djdk.tls.client.enableSessionTicketExtension=false
|
||||
* DTLSNoNewSessionTicket
|
||||
* @run main/othervm -Djdk.tls.server.enableSessionTicketExtension=false
|
||||
* DTLSNoNewSessionTicket
|
||||
*/
|
||||
|
||||
public class DTLSNoNewSessionTicket extends DTLSOverDatagram {
|
||||
public static void main(String[] args) throws Exception {
|
||||
var testCase = new DTLSNoNewSessionTicket();
|
||||
testCase.runTest(testCase);
|
||||
}
|
||||
}
|
||||
@ -21,9 +21,6 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// SunJSSE does not support dynamic system properties, no way to re-use
|
||||
// system properties in samevm/agentvm mode.
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8043758
|
||||
@ -132,8 +129,15 @@ public class DTLSOverDatagram {
|
||||
* The remainder is support stuff for DTLS operations.
|
||||
*/
|
||||
SSLEngine createSSLEngine(boolean isClient) throws Exception {
|
||||
SSLContext context = getDTLSContext();
|
||||
SSLEngine engine = context.createSSLEngine();
|
||||
SSLContext context =
|
||||
isClient ? getClientDTLSContext() : getServerDTLSContext();
|
||||
|
||||
// Note: client and server ports are not to be used for network
|
||||
// communication, but only to be set in client and server SSL engines.
|
||||
// We must use the same context, host and port for initial and resuming
|
||||
// sessions when testing session resumption (abbreviated handshake).
|
||||
SSLEngine engine = context.createSSLEngine("localhost",
|
||||
isClient ? 51111 : 52222);
|
||||
|
||||
SSLParameters paras = engine.getSSLParameters();
|
||||
paras.setMaximumPacketSize(MAXIMUM_PACKET_SIZE);
|
||||
@ -507,7 +511,7 @@ public class DTLSOverDatagram {
|
||||
}
|
||||
|
||||
// get DTSL context
|
||||
SSLContext getDTLSContext() throws Exception {
|
||||
static SSLContext getDTLSContext() throws Exception {
|
||||
String passphrase = "passphrase";
|
||||
return SSLContextBuilder.builder()
|
||||
.trustStore(KeyStoreUtils.loadKeyStore(TRUST_FILENAME, passphrase))
|
||||
@ -517,6 +521,14 @@ public class DTLSOverDatagram {
|
||||
.build();
|
||||
}
|
||||
|
||||
protected SSLContext getServerDTLSContext() throws Exception {
|
||||
return getDTLSContext();
|
||||
}
|
||||
|
||||
protected SSLContext getClientDTLSContext() throws Exception {
|
||||
return getDTLSContext();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* =============================================================
|
||||
|
||||
@ -21,56 +21,95 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// SunJSSE does not support dynamic system properties, no way to re-use
|
||||
// system properties in samevm/agentvm mode.
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8161086
|
||||
* @bug 8161086 8367059
|
||||
* @summary DTLS handshaking fails if some messages were lost
|
||||
* @modules java.base/sun.security.util
|
||||
* @library /test/lib
|
||||
* @build DTLSOverDatagram
|
||||
*
|
||||
* @run main/othervm PacketLossRetransmission client 1 client_hello
|
||||
* @run main/othervm PacketLossRetransmission client 16 client_key_exchange
|
||||
* @run main/othervm PacketLossRetransmission client 20 finished
|
||||
* @run main/othervm PacketLossRetransmission client -1 change_cipher_spec
|
||||
* @run main/othervm PacketLossRetransmission server 2 server_hello
|
||||
* @run main/othervm PacketLossRetransmission server 3 hello_verify_request
|
||||
* @run main/othervm PacketLossRetransmission server 11 certificate
|
||||
* @run main/othervm PacketLossRetransmission server 12 server_key_exchange
|
||||
* @run main/othervm PacketLossRetransmission server 14 server_hello_done
|
||||
* @run main/othervm PacketLossRetransmission server 20 finished
|
||||
* @run main/othervm PacketLossRetransmission server -1 change_cipher_spec
|
||||
* @run main/othervm PacketLossRetransmission client full 1 client_hello
|
||||
* @run main/othervm PacketLossRetransmission client full 16 client_key_exchange
|
||||
* @run main/othervm PacketLossRetransmission client full 20 finished
|
||||
* @run main/othervm PacketLossRetransmission client full -1 change_cipher_spec
|
||||
* @run main/othervm PacketLossRetransmission server full 2 server_hello
|
||||
* @run main/othervm PacketLossRetransmission server full 3 hello_verify_request
|
||||
* @run main/othervm PacketLossRetransmission server full 11 certificate
|
||||
* @run main/othervm PacketLossRetransmission server full 12 server_key_exchange
|
||||
* @run main/othervm PacketLossRetransmission server full 14 server_hello_done
|
||||
* @run main/othervm PacketLossRetransmission server full 20 finished
|
||||
* @run main/othervm PacketLossRetransmission server full -1 change_cipher_spec
|
||||
* @run main/othervm PacketLossRetransmission server full 4 new_session_ticket
|
||||
* @run main/othervm PacketLossRetransmission client resume 1 client_hello
|
||||
* @run main/othervm PacketLossRetransmission client resume 20 finished
|
||||
* @run main/othervm PacketLossRetransmission client resume -1 change_cipher_spec
|
||||
* @run main/othervm PacketLossRetransmission server resume 2 server_hello
|
||||
* @run main/othervm PacketLossRetransmission server resume 3 hello_verify_request
|
||||
* @run main/othervm PacketLossRetransmission server resume 20 finished
|
||||
* @run main/othervm PacketLossRetransmission server resume -1 change_cipher_spec
|
||||
* @run main/othervm PacketLossRetransmission server resume 4 new_session_ticket
|
||||
*/
|
||||
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.SocketAddress;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
/**
|
||||
* Test that DTLS implementation is able to do retransmission internally
|
||||
* automatically if packet get lost.
|
||||
*/
|
||||
public class PacketLossRetransmission extends DTLSOverDatagram {
|
||||
|
||||
private static boolean isClient;
|
||||
private static byte handshakeType;
|
||||
private static final int TIMEOUT = 500;
|
||||
|
||||
private boolean needPacketLoss = true;
|
||||
private final SSLContext clientContext;
|
||||
private final SSLContext serverContext;
|
||||
|
||||
protected PacketLossRetransmission() throws Exception {
|
||||
this.clientContext = getDTLSContext();
|
||||
this.serverContext = getDTLSContext();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
isClient = args[0].equals("client");
|
||||
handshakeType = Byte.parseByte(args[1]);
|
||||
boolean isResume = args[1].equals("resume");
|
||||
handshakeType = Byte.parseByte(args[2]);
|
||||
|
||||
PacketLossRetransmission testCase = new PacketLossRetransmission();
|
||||
testCase.setSocketTimeout(TIMEOUT);
|
||||
|
||||
if (isResume) {
|
||||
System.out.println("Starting initial handshake");
|
||||
// The initial session will populate the TLS session cache.
|
||||
initialSession(testCase.createSSLEngine(true),
|
||||
testCase.createSSLEngine(false));
|
||||
}
|
||||
|
||||
testCase.runTest(testCase);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SSLContext getClientDTLSContext() throws Exception {
|
||||
return clientContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SSLContext getServerDTLSContext() throws Exception {
|
||||
return serverContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean produceHandshakePackets(SSLEngine engine, SocketAddress socketAddr,
|
||||
String side, List<DatagramPacket> packets) throws Exception {
|
||||
@ -90,4 +129,170 @@ public class PacketLossRetransmission extends DTLSOverDatagram {
|
||||
|
||||
return finished;
|
||||
}
|
||||
|
||||
private static void initialSession(SSLEngine clientEngine,
|
||||
SSLEngine serverEngine) throws SSLException {
|
||||
boolean clientDone = false;
|
||||
boolean serverDone = false;
|
||||
boolean cliDataReady = false;
|
||||
boolean servDataReady = false;
|
||||
SSLEngineResult clientResult;
|
||||
SSLEngineResult serverResult;
|
||||
SSLSession session = clientEngine.getSession();
|
||||
int appBufferMax = session.getApplicationBufferSize();
|
||||
int netBufferMax = session.getPacketBufferSize();
|
||||
ByteBuffer clientIn = ByteBuffer.allocate(appBufferMax + 50);
|
||||
ByteBuffer serverIn = ByteBuffer.allocate(appBufferMax + 50);
|
||||
ByteBuffer cTOs = ByteBuffer.allocateDirect(netBufferMax);
|
||||
ByteBuffer sTOc = ByteBuffer.allocateDirect(netBufferMax);
|
||||
HandshakeStatus hsStat;
|
||||
final ByteBuffer clientOut = ByteBuffer.wrap(
|
||||
"Hi Server, I'm Client".getBytes());
|
||||
final ByteBuffer serverOut = ByteBuffer.wrap(
|
||||
"Hello Client, I'm Server".getBytes());
|
||||
|
||||
clientEngine.beginHandshake();
|
||||
serverEngine.beginHandshake();
|
||||
while (!clientDone && !serverDone) {
|
||||
// Client processing
|
||||
hsStat = clientEngine.getHandshakeStatus();
|
||||
log("Client HS Stat: " + hsStat);
|
||||
switch (hsStat) {
|
||||
case NOT_HANDSHAKING:
|
||||
log("Closing client engine");
|
||||
clientEngine.closeOutbound();
|
||||
clientDone = true;
|
||||
break;
|
||||
case NEED_WRAP:
|
||||
log(String.format("CTOS: p:%d, l:%d, c:%d", cTOs.position(),
|
||||
cTOs.limit(), cTOs.capacity()));
|
||||
clientResult = clientEngine.wrap(clientOut, cTOs);
|
||||
log("client wrap: ", clientResult);
|
||||
if (clientResult.getStatus()
|
||||
== SSLEngineResult.Status.BUFFER_OVERFLOW) {
|
||||
// Get a larger buffer and try again
|
||||
int updateSize = 2 * netBufferMax;
|
||||
log("Resizing buffer to " + updateSize + " bytes");
|
||||
cTOs = ByteBuffer.allocate(updateSize);
|
||||
clientResult = clientEngine.wrap(clientOut, cTOs);
|
||||
log("client wrap (resized): ", clientResult);
|
||||
}
|
||||
runDelegatedTasks(clientResult, clientEngine);
|
||||
cTOs.flip();
|
||||
cliDataReady = true;
|
||||
break;
|
||||
case NEED_UNWRAP:
|
||||
if (servDataReady) {
|
||||
log(String.format("STOC: p:%d, l:%d, c:%d",
|
||||
sTOc.position(),
|
||||
sTOc.limit(), sTOc.capacity()));
|
||||
clientResult = clientEngine.unwrap(sTOc, clientIn);
|
||||
log("client unwrap: ", clientResult);
|
||||
runDelegatedTasks(clientResult, clientEngine);
|
||||
servDataReady = sTOc.hasRemaining();
|
||||
sTOc.compact();
|
||||
} else {
|
||||
log("Server-to-client data not ready, skipping client" +
|
||||
" unwrap");
|
||||
}
|
||||
break;
|
||||
case NEED_UNWRAP_AGAIN:
|
||||
clientResult = clientEngine.unwrap(ByteBuffer.allocate(0),
|
||||
clientIn);
|
||||
log("client unwrap (again): ", clientResult);
|
||||
runDelegatedTasks(clientResult, clientEngine);
|
||||
break;
|
||||
}
|
||||
|
||||
// Server processing
|
||||
hsStat = serverEngine.getHandshakeStatus();
|
||||
log("Server HS Stat: " + hsStat);
|
||||
switch (hsStat) {
|
||||
case NEED_WRAP:
|
||||
log(String.format("STOC: p:%d, l:%d, c:%d", sTOc.position(),
|
||||
sTOc.limit(), sTOc.capacity()));
|
||||
serverResult = serverEngine.wrap(serverOut, sTOc);
|
||||
log("server wrap: ", serverResult);
|
||||
if (serverResult.getStatus()
|
||||
== SSLEngineResult.Status.BUFFER_OVERFLOW) {
|
||||
// Get a new buffer and try again
|
||||
int updateSize = 2 * netBufferMax;
|
||||
log("Resizing buffer to " + updateSize + " bytes");
|
||||
sTOc = ByteBuffer.allocate(updateSize);
|
||||
serverResult = serverEngine.wrap(clientOut, sTOc);
|
||||
log("server wrap (resized): ", serverResult);
|
||||
}
|
||||
runDelegatedTasks(serverResult, serverEngine);
|
||||
sTOc.flip();
|
||||
servDataReady = true;
|
||||
break;
|
||||
case NOT_HANDSHAKING:
|
||||
log("Closing server engine");
|
||||
serverEngine.closeOutbound();
|
||||
serverDone = true;
|
||||
break;
|
||||
case NEED_UNWRAP:
|
||||
if (cliDataReady) {
|
||||
log(String.format("CTOS: p:%d, l:%d, c:%d",
|
||||
cTOs.position(),
|
||||
cTOs.limit(), cTOs.capacity()));
|
||||
serverResult = serverEngine.unwrap(cTOs, serverIn);
|
||||
log("server unwrap: ", serverResult);
|
||||
runDelegatedTasks(serverResult, serverEngine);
|
||||
cliDataReady = cTOs.hasRemaining();
|
||||
cTOs.compact();
|
||||
} else {
|
||||
log("Client-to-server data not ready, skipping server" +
|
||||
" unwrap");
|
||||
}
|
||||
break;
|
||||
case NEED_UNWRAP_AGAIN:
|
||||
serverResult = serverEngine.unwrap(ByteBuffer.allocate(0),
|
||||
serverIn);
|
||||
log("server unwrap (again): ", serverResult);
|
||||
runDelegatedTasks(serverResult, serverEngine);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void log(String str) {
|
||||
System.out.println(str);
|
||||
}
|
||||
|
||||
private static void log(String str, SSLEngineResult result) {
|
||||
System.out.println("The format of the SSLEngineResult is: \n" +
|
||||
"\t\"getStatus() / getHandshakeStatus()\" +\n" +
|
||||
"\t\"bytesConsumed() / bytesProduced()\"\n");
|
||||
|
||||
HandshakeStatus hsStatus = result.getHandshakeStatus();
|
||||
|
||||
log(str +
|
||||
result.getStatus() + "/" + hsStatus + ", " +
|
||||
result.bytesConsumed() + "/" + result.bytesProduced() +
|
||||
" bytes");
|
||||
|
||||
if (hsStatus == HandshakeStatus.FINISHED) {
|
||||
log("\t...ready for application data");
|
||||
}
|
||||
}
|
||||
|
||||
private static void runDelegatedTasks(SSLEngineResult result,
|
||||
SSLEngine engine) {
|
||||
HandshakeStatus hsStatus = result.getHandshakeStatus();
|
||||
|
||||
if (hsStatus == HandshakeStatus.NEED_TASK) {
|
||||
Runnable runnable;
|
||||
while ((runnable = engine.getDelegatedTask()) != null) {
|
||||
log("\trunning delegated task...");
|
||||
runnable.run();
|
||||
}
|
||||
hsStatus = engine.getHandshakeStatus();
|
||||
if (hsStatus == HandshakeStatus.NEED_TASK) {
|
||||
throw new RuntimeException(
|
||||
"handshake shouldn't need additional tasks");
|
||||
}
|
||||
log("\tnew HandshakeStatus: " + hsStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user