8167680: DTLS implementation bugs

Reviewed-by: jnimeh, asmotrak
This commit is contained in:
Xue-Lei Andrew Fan 2016-10-29 13:34:53 +00:00
parent 7b9f0bff77
commit b8904d34fe
12 changed files with 1374 additions and 591 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2016, 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
@ -279,6 +279,16 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord {
fragmenter = null;
}
@Override
void launchRetransmission() {
// Note: Please don't retransmit if there are handshake messages
// or alerts waiting in the queue.
if (((alertMemos == null) || alertMemos.isEmpty()) &&
(fragmenter != null) && fragmenter.isRetransmittable()) {
fragmenter.setRetransmission();
}
}
// buffered record fragment
private static class RecordMemo {
byte contentType;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2016, 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
@ -84,4 +84,18 @@ interface DTLSRecord extends Record {
+ maxPadding // padding
+ maxMacSize; // MAC
/*
* Minimum record size of Certificate handshake message.
* Client sends a certificate message containing no certificates if no
* suitable certificate is available. That is, the certificate_list
* structure has a length of zero.
*
* struct {
* ASN.1Cert certificate_list<0..2^24-1>;
* } Certificate;
*/
static final int minCertPlaintextSize =
headerSize // record header
+ handshakeHeaderSize // handshake header
+ 3; // cert list length
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2016, 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
@ -144,6 +144,13 @@ public class Debug {
System.err.println(prefix + ": "+message);
}
/**
* Print a message to stdout.
*/
static void log(String message) {
System.out.println(Thread.currentThread().getName() + ": " + message);
}
/**
* print a blank line to stderr that is prefixed with the prefix.
*/
@ -156,7 +163,6 @@ public class Debug {
/**
* print a message to stderr that is prefixed with the prefix.
*/
public static void println(String prefix, String message)
{
System.err.println(prefix + ": "+message);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2016, 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
@ -194,6 +194,11 @@ abstract class OutputRecord extends ByteArrayOutputStream
// blank
}
// apply to DTLS SSLEngine
void launchRetransmission() {
// blank
}
@Override
public synchronized void close() throws IOException {
if (!isClosed) {
@ -224,6 +229,9 @@ abstract class OutputRecord extends ByteArrayOutputStream
sequenceNumber = authenticator.sequenceNumber();
}
// The sequence number may be shared for different purpose.
boolean sharedSequenceNumber = false;
// "flip" but skip over header again, add MAC & encrypt
if (authenticator instanceof MAC) {
MAC signer = (MAC)authenticator;
@ -243,6 +251,11 @@ abstract class OutputRecord extends ByteArrayOutputStream
// reset the position and limit
destination.limit(destination.position());
destination.position(dstContent);
// The signer has used and increased the sequence number.
if (isDTLS) {
sharedSequenceNumber = true;
}
}
}
@ -261,6 +274,11 @@ abstract class OutputRecord extends ByteArrayOutputStream
// Encrypt may pad, so again the limit may be changed.
encCipher.encrypt(destination, dstLim);
// The cipher has used and increased the sequence number.
if (isDTLS && encCipher.isAEADMode()) {
sharedSequenceNumber = true;
}
} else {
destination.position(destination.limit());
}
@ -290,8 +308,10 @@ abstract class OutputRecord extends ByteArrayOutputStream
destination.put(headerOffset + 11, (byte)(fragLen >> 8));
destination.put(headerOffset + 12, (byte)fragLen);
// Increase the sequence number for next use.
authenticator.increaseSequenceNumber();
// Increase the sequence number for next use if it is not shared.
if (!sharedSequenceNumber) {
authenticator.increaseSequenceNumber();
}
}
// Update destination position to reflect the amount of data produced.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2016, 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
@ -38,7 +38,7 @@ final class Plaintext {
byte majorVersion;
byte minorVersion;
int recordEpoch; // incremented on every cipher state change
long recordSN;
long recordSN; // contains epcoh number (epoch | sequence)
ByteBuffer fragment; // null if need to be reassembled
HandshakeStatus handshakeStatus; // null if not used or not handshaking

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2016, 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
@ -994,7 +994,22 @@ public final class SSLEngineImpl extends SSLEngine {
// plainText should never be null for TLS protocols
HandshakeStatus hsStatus = null;
if (!isDTLS || plainText != null) {
if (plainText == Plaintext.PLAINTEXT_NULL) {
// Only happens for DTLS protocols.
//
// Received a retransmitted flight, and need to retransmit the
// previous delivered handshake flight messages.
if (enableRetransmissions) {
if (debug != null && Debug.isOn("verbose")) {
Debug.log(
"Retransmit the previous handshake flight messages.");
}
synchronized (this) {
outputRecord.launchRetransmission();
}
} // Otherwise, discard the retransmitted flight.
} else if (!isDTLS || plainText != null) {
hsStatus = processInputRecord(plainText, appData, offset, length);
}
@ -1003,7 +1018,7 @@ public final class SSLEngineImpl extends SSLEngine {
}
if (plainText == null) {
plainText = new Plaintext();
plainText = Plaintext.PLAINTEXT_NULL;
}
plainText.handshakeStatus = hsStatus;
@ -1378,7 +1393,8 @@ public final class SSLEngineImpl extends SSLEngine {
// Acquire the buffered to-be-delivered records or retransmissions.
//
// May have buffered records, or need retransmission if handshaking.
if (!outputRecord.isEmpty() || (handshaker != null)) {
if (!outputRecord.isEmpty() ||
(enableRetransmissions && handshaker != null)) {
ciphertext = outputRecord.acquireCiphertext(netData);
}
@ -1403,13 +1419,36 @@ public final class SSLEngineImpl extends SSLEngine {
HandshakeStatus hsStatus = null;
Ciphertext.RecordType recordType = ciphertext.recordType;
if ((handshaker != null) &&
(recordType.contentType == Record.ct_handshake) &&
(recordType.handshakeType == HandshakeMessage.ht_finished) &&
handshaker.isDone() && outputRecord.isEmpty()) {
if ((recordType.contentType == Record.ct_handshake) &&
(recordType.handshakeType == HandshakeMessage.ht_finished) &&
outputRecord.isEmpty()) {
hsStatus = finishHandshake();
connectionState = cs_DATA;
if (handshaker == null) {
hsStatus = HandshakeStatus.FINISHED;
} else if (handshaker.isDone()) {
hsStatus = finishHandshake();
connectionState = cs_DATA;
// Retransmit the last flight twice.
//
// The application data transactions may begin immediately
// after the last flight. If the last flight get lost, the
// application data may be discarded accordingly. As could
// be an issue for some applications. This impact can be
// mitigated by sending the last fligth twice.
if (isDTLS && enableRetransmissions) {
if (debug != null && Debug.isOn("verbose")) {
Debug.log(
"Retransmit the last flight messages.");
}
synchronized (this) {
outputRecord.launchRetransmission();
}
hsStatus = HandshakeStatus.NEED_WRAP;
}
}
} // Otherwise, the followed call to getHSStatus() will help.
/*

View File

@ -558,73 +558,6 @@ final class ServerHandshaker extends Handshaker {
applicationProtocol = "";
}
// cookie exchange
if (isDTLS) {
HelloCookieManager hcMgr = sslContext.getHelloCookieManager();
if ((mesg.cookie == null) || (mesg.cookie.length == 0) ||
(!hcMgr.isValid(mesg))) {
//
// Perform cookie exchange for DTLS handshaking if no cookie
// or the cookie is invalid in the ClientHello message.
//
HelloVerifyRequest m0 = new HelloVerifyRequest(hcMgr, mesg);
if (debug != null && Debug.isOn("handshake")) {
m0.print(System.out);
}
m0.write(output);
handshakeState.update(m0, resumingSession);
output.flush();
return;
}
}
/*
* FIRST, construct the ServerHello using the options and priorities
* from the ClientHello. Update the (pending) cipher spec as we do
* so, and save the client's version to protect against rollback
* attacks.
*
* There are a bunch of minor tasks here, and one major one: deciding
* if the short or the full handshake sequence will be used.
*/
ServerHello m1 = new ServerHello();
clientRequestedVersion = mesg.protocolVersion;
// select a proper protocol version.
ProtocolVersion selectedVersion =
selectProtocolVersion(clientRequestedVersion);
if (selectedVersion == null ||
selectedVersion.v == ProtocolVersion.SSL20Hello.v) {
fatalSE(Alerts.alert_handshake_failure,
"Client requested protocol " + clientRequestedVersion +
" not enabled or not supported");
}
handshakeHash.protocolDetermined(selectedVersion);
setVersion(selectedVersion);
m1.protocolVersion = protocolVersion;
//
// random ... save client and server values for later use
// in computing the master secret (from pre-master secret)
// and thence the other crypto keys.
//
// NOTE: this use of three inputs to generating _each_ set
// of ciphers slows things down, but it does increase the
// security since each connection in the session can hold
// its own authenticated (and strong) keys. One could make
// creation of a session a rare thing...
//
clnt_random = mesg.clnt_random;
svr_random = new RandomCookie(sslContext.getSecureRandom());
m1.svr_random = svr_random;
session = null; // forget about the current session
//
// Here we go down either of two paths: (a) the fast one, where
@ -732,6 +665,73 @@ final class ServerHandshaker extends Handshaker {
}
} // else client did not try to resume
// cookie exchange
if (isDTLS && !resumingSession) {
HelloCookieManager hcMgr = sslContext.getHelloCookieManager();
if ((mesg.cookie == null) || (mesg.cookie.length == 0) ||
(!hcMgr.isValid(mesg))) {
//
// Perform cookie exchange for DTLS handshaking if no cookie
// or the cookie is invalid in the ClientHello message.
//
HelloVerifyRequest m0 = new HelloVerifyRequest(hcMgr, mesg);
if (debug != null && Debug.isOn("handshake")) {
m0.print(System.out);
}
m0.write(output);
handshakeState.update(m0, resumingSession);
output.flush();
return;
}
}
/*
* FIRST, construct the ServerHello using the options and priorities
* from the ClientHello. Update the (pending) cipher spec as we do
* so, and save the client's version to protect against rollback
* attacks.
*
* There are a bunch of minor tasks here, and one major one: deciding
* if the short or the full handshake sequence will be used.
*/
ServerHello m1 = new ServerHello();
clientRequestedVersion = mesg.protocolVersion;
// select a proper protocol version.
ProtocolVersion selectedVersion =
selectProtocolVersion(clientRequestedVersion);
if (selectedVersion == null ||
selectedVersion.v == ProtocolVersion.SSL20Hello.v) {
fatalSE(Alerts.alert_handshake_failure,
"Client requested protocol " + clientRequestedVersion +
" not enabled or not supported");
}
handshakeHash.protocolDetermined(selectedVersion);
setVersion(selectedVersion);
m1.protocolVersion = protocolVersion;
//
// random ... save client and server values for later use
// in computing the master secret (from pre-master secret)
// and thence the other crypto keys.
//
// NOTE: this use of three inputs to generating _each_ set
// of ciphers slows things down, but it does increase the
// security since each connection in the session can hold
// its own authenticated (and strong) keys. One could make
// creation of a session a rare thing...
//
clnt_random = mesg.clnt_random;
svr_random = new RandomCookie(sslContext.getSecureRandom());
m1.svr_random = svr_random;
//
// If client hasn't specified a session we can resume, start a
// new one and choose its cipher suite and compression options.

View File

@ -48,10 +48,6 @@ import sun.security.util.HexDumpEncoder;
*/
public class DTLSOverDatagram {
static {
System.setProperty("javax.net.debug", "ssl");
}
private static int MAX_HANDSHAKE_LOOPS = 200;
private static int MAX_APP_READ_LOOPS = 60;
private static int SOCKET_TIMEOUT = 10 * 1000; // in millis
@ -160,6 +156,7 @@ public class DTLSOverDatagram {
}
SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
log(side, "=======handshake(" + loops + ", " + hs + ")=======");
if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ||
hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
@ -239,6 +236,7 @@ public class DTLSOverDatagram {
boolean finished = produceHandshakePackets(
engine, peerAddr, side, packets);
log(side, "Produced " + packets.size() + " packets");
for (DatagramPacket p : packets) {
socket.send(p);
}
@ -252,14 +250,16 @@ public class DTLSOverDatagram {
} else if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
runDelegatedTasks(engine);
} else if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
log(side, "Handshake status is NOT_HANDSHAKING, finish the loop");
log(side,
"Handshake status is NOT_HANDSHAKING, finish the loop");
endLoops = true;
} else if (hs == SSLEngineResult.HandshakeStatus.FINISHED) {
throw new Exception(
"Unexpected status, SSLEngine.getHandshakeStatus() "
+ "shouldn't return FINISHED");
} else {
throw new Exception("Can't reach here, handshake status is " + hs);
throw new Exception(
"Can't reach here, handshake status is " + hs);
}
}
@ -279,7 +279,9 @@ public class DTLSOverDatagram {
log(side, "Negotiated cipher suite is " + session.getCipherSuite());
// handshake status should be NOT_HANDSHAKING
// according to the spec, SSLEngine.getHandshakeStatus() can't return FINISHED
//
// According to the spec, SSLEngine.getHandshakeStatus() can't
// return FINISHED.
if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
throw new Exception("Unexpected handshake status " + hs);
}
@ -348,13 +350,16 @@ public class DTLSOverDatagram {
SSLEngineResult.Status rs = r.getStatus();
SSLEngineResult.HandshakeStatus hs = r.getHandshakeStatus();
log(side, "====packet(" + loops + ", " + rs + ", " + hs + ")====");
if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
// the client maximum fragment size config does not work?
throw new Exception("Buffer overflow: " +
"incorrect server maximum fragment size");
} else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
log(side, "Produce handshake packets: BUFFER_UNDERFLOW occured");
log(side, "Produce handshake packets: Handshake status: " + hs);
log(side,
"Produce handshake packets: BUFFER_UNDERFLOW occured");
log(side,
"Produce handshake packets: Handshake status: " + hs);
// bad packet, or the client maximum fragment size
// config does not work?
if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
@ -453,6 +458,53 @@ public class DTLSOverDatagram {
return packets;
}
// Get a datagram packet for the specified handshake type.
static DatagramPacket getPacket(
List<DatagramPacket> packets, byte handshakeType) {
boolean matched = false;
for (DatagramPacket packet : packets) {
byte[] data = packet.getData();
int offset = packet.getOffset();
int length = packet.getLength();
// Normally, this pakcet should be a handshake message
// record. However, even if the underlying platform
// splits the record more, we don't really worry about
// the improper packet loss because DTLS implementation
// should be able to handle packet loss properly.
//
// See RFC 6347 for the detailed format of DTLS records.
if (handshakeType == -1) { // ChangeCipherSpec
// Is it a ChangeCipherSpec message?
matched = (length == 14) && (data[offset] == 0x14);
} else if ((length >= 25) && // 25: handshake mini size
(data[offset] == 0x16)) { // a handshake message
// check epoch number for initial handshake only
if (data[offset + 3] == 0x00) { // 3,4: epoch
if (data[offset + 4] == 0x00) { // plaintext
matched =
(data[offset + 13] == handshakeType);
} else { // cipherext
// The 1st ciphertext is a Finished message.
//
// If it is not proposed to loss the Finished
// message, it is not necessary to check the
// following packets any mroe as a Finished
// message is the last handshake message.
matched = (handshakeType == 20);
}
}
}
if (matched) {
return packet;
}
}
return null;
}
// run delegated tasks
void runDelegatedTasks(SSLEngine engine) throws Exception {
Runnable runnable;

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2016, 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.
*/
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
/*
* @test
* @bug 8161086
* @summary DTLS handshaking fails if some messages were lost
* @modules java.base/sun.security.util
* @build DTLSOverDatagram
*
* @run main/othervm PacketLossRetransmission client 0 hello_request
* @run main/othervm PacketLossRetransmission client 1 client_hello
* @run main/othervm PacketLossRetransmission client 2 server_hello
* @run main/othervm PacketLossRetransmission client 3 hello_verify_request
* @run main/othervm PacketLossRetransmission client 4 new_session_ticket
* @run main/othervm PacketLossRetransmission client 11 certificate
* @run main/othervm PacketLossRetransmission client 12 server_key_exchange
* @run main/othervm PacketLossRetransmission client 13 certificate_request
* @run main/othervm PacketLossRetransmission client 14 server_hello_done
* @run main/othervm PacketLossRetransmission client 15 certificate_verify
* @run main/othervm PacketLossRetransmission client 16 client_key_exchange
* @run main/othervm PacketLossRetransmission client 20 finished
* @run main/othervm PacketLossRetransmission client 21 certificate_url
* @run main/othervm PacketLossRetransmission client 22 certificate_status
* @run main/othervm PacketLossRetransmission client 23 supplemental_data
* @run main/othervm PacketLossRetransmission client -1 change_cipher_spec
* @run main/othervm PacketLossRetransmission server 0 hello_request
* @run main/othervm PacketLossRetransmission server 1 client_hello
* @run main/othervm PacketLossRetransmission server 2 server_hello
* @run main/othervm PacketLossRetransmission server 3 hello_verify_request
* @run main/othervm PacketLossRetransmission server 4 new_session_ticket
* @run main/othervm PacketLossRetransmission server 11 certificate
* @run main/othervm PacketLossRetransmission server 12 server_key_exchange
* @run main/othervm PacketLossRetransmission server 13 certificate_request
* @run main/othervm PacketLossRetransmission server 14 server_hello_done
* @run main/othervm PacketLossRetransmission server 15 certificate_verify
* @run main/othervm PacketLossRetransmission server 16 client_key_exchange
* @run main/othervm PacketLossRetransmission server 20 finished
* @run main/othervm PacketLossRetransmission server 21 certificate_url
* @run main/othervm PacketLossRetransmission server 22 certificate_status
* @run main/othervm PacketLossRetransmission server 23 supplemental_data
* @run main/othervm PacketLossRetransmission server -1 change_cipher_spec
*/
import java.util.List;
import java.util.ArrayList;
import java.net.DatagramPacket;
import java.net.SocketAddress;
import javax.net.ssl.SSLEngine;
/**
* 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 boolean needPacketLoss = true;
public static void main(String[] args) throws Exception {
isClient = args[0].equals("client");
handshakeType = Byte.valueOf(args[1]);
PacketLossRetransmission testCase = new PacketLossRetransmission();
testCase.runTest(testCase);
}
@Override
boolean produceHandshakePackets(SSLEngine engine, SocketAddress socketAddr,
String side, List<DatagramPacket> packets) throws Exception {
boolean finished = super.produceHandshakePackets(
engine, socketAddr, side, packets);
if (needPacketLoss && (!(isClient ^ engine.getUseClientMode()))) {
DatagramPacket packet = getPacket(packets, handshakeType);
if (packet != null) {
needPacketLoss = false;
System.out.println("Loss a packet of handshake messahe");
packets.remove(packet);
}
}
return finished;
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2016, 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.
*/
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
/*
* @test
* @bug 8161086
* @summary DTLS handshaking fails if some messages were lost
* @modules java.base/sun.security.util
* @build DTLSOverDatagram
*
* @run main/othervm RespondToRetransmit client 0 hello_request
* @run main/othervm RespondToRetransmit client 1 client_hello
* @run main/othervm RespondToRetransmit client 2 server_hello
* @run main/othervm RespondToRetransmit client 3 hello_verify_request
* @run main/othervm RespondToRetransmit client 4 new_session_ticket
* @run main/othervm RespondToRetransmit client 11 certificate
* @run main/othervm RespondToRetransmit client 12 server_key_exchange
* @run main/othervm RespondToRetransmit client 13 certificate_request
* @run main/othervm RespondToRetransmit client 14 server_hello_done
* @run main/othervm RespondToRetransmit client 15 certificate_verify
* @run main/othervm RespondToRetransmit client 16 client_key_exchange
* @run main/othervm RespondToRetransmit client 20 finished
* @run main/othervm RespondToRetransmit client 21 certificate_url
* @run main/othervm RespondToRetransmit client 22 certificate_status
* @run main/othervm RespondToRetransmit client 23 supplemental_data
* @run main/othervm RespondToRetransmit client -1 change_cipher_spec
* @run main/othervm RespondToRetransmit server 0 hello_request
* @run main/othervm RespondToRetransmit server 1 client_hello
* @run main/othervm RespondToRetransmit server 2 server_hello
* @run main/othervm RespondToRetransmit server 3 hello_verify_request
* @run main/othervm RespondToRetransmit server 4 new_session_ticket
* @run main/othervm RespondToRetransmit server 11 certificate
* @run main/othervm RespondToRetransmit server 12 server_key_exchange
* @run main/othervm RespondToRetransmit server 13 certificate_request
* @run main/othervm RespondToRetransmit server 14 server_hello_done
* @run main/othervm RespondToRetransmit server 15 certificate_verify
* @run main/othervm RespondToRetransmit server 16 client_key_exchange
* @run main/othervm RespondToRetransmit server 20 finished
* @run main/othervm RespondToRetransmit server 21 certificate_url
* @run main/othervm RespondToRetransmit server 22 certificate_status
* @run main/othervm RespondToRetransmit server 23 supplemental_data
* @run main/othervm RespondToRetransmit server -1 change_cipher_spec
*/
import java.util.List;
import java.util.ArrayList;
import java.net.DatagramPacket;
import java.net.SocketAddress;
import javax.net.ssl.SSLEngine;
/**
* Test that DTLS implementation is able to do retransmission internally
* automatically if packet get lost.
*/
public class RespondToRetransmit extends DTLSOverDatagram {
private static boolean isClient;
private static byte handshakeType;
private boolean needPacketDuplicate = true;
public static void main(String[] args) throws Exception {
isClient = args[0].equals("client");
handshakeType = Byte.valueOf(args[1]);
RespondToRetransmit testCase = new RespondToRetransmit();
testCase.runTest(testCase);
}
@Override
boolean produceHandshakePackets(SSLEngine engine, SocketAddress socketAddr,
String side, List<DatagramPacket> packets) throws Exception {
boolean finished = super.produceHandshakePackets(
engine, socketAddr, side, packets);
if (needPacketDuplicate && (!(isClient ^ engine.getUseClientMode()))) {
DatagramPacket packet = getPacket(packets, handshakeType);
if (packet != null) {
needPacketDuplicate = false;
System.out.println("Duplicate the flight.");
List<DatagramPacket> duplicates = new ArrayList<>();
finished = super.produceHandshakePackets(
engine, socketAddr, side, duplicates);
packets.addAll(duplicates);
}
}
return finished;
}
}

View File

@ -27,7 +27,9 @@ import javax.net.ssl.SNIMatcher;
import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManagerFactory;
@ -57,19 +59,21 @@ abstract public class SSLEngineTestCase {
public enum Ciphers {
/**
* Ciphers supported by the tested SSLEngine without those with kerberos
* authentication.
* Ciphers supported by the tested SSLEngine without those with
* kerberos authentication.
*/
SUPPORTED_NON_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_NON_KRB_CIPHERS,
"Supported non kerberos"),
/**
* Ciphers supported by the tested SSLEngine without those with kerberos
* authentication and without those with SHA256 ans SHA384.
* Ciphers supported by the tested SSLEngine without those with
* kerberos authentication and without those with SHA256 ans SHA384.
*/
SUPPORTED_NON_KRB_NON_SHA_CIPHERS(SSLEngineTestCase.SUPPORTED_NON_KRB_NON_SHA_CIPHERS,
SUPPORTED_NON_KRB_NON_SHA_CIPHERS(
SSLEngineTestCase.SUPPORTED_NON_KRB_NON_SHA_CIPHERS,
"Supported non kerberos non SHA256 and SHA384"),
/**
* Ciphers supported by the tested SSLEngine with kerberos authentication.
* Ciphers supported by the tested SSLEngine with kerberos
* authentication.
*/
SUPPORTED_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_KRB_CIPHERS,
"Supported kerberos"),
@ -147,13 +151,13 @@ abstract public class SSLEngineTestCase {
= System.getProperty("test.src", ".") + FS + PATH_TO_STORES
+ FS + TRUST_STORE_FILE;
// Need an enhancement to use none-static mutable global variables.
private static ByteBuffer net;
private static ByteBuffer netReplicatedClient;
private static ByteBuffer netReplicatedServer;
private static final int MAX_HANDSHAKE_LOOPS = 100;
private static final String EXCHANGE_MSG_SENT = "Hello, peer!";
private static boolean doUnwrapForNotHandshakingStatus;
private static boolean endHandshakeLoop = false;
private static final int MAX_HANDSHAKE_LOOPS = 100;
private static final String EXCHANGE_MSG_SENT = "Hello, peer!";
private static final String TEST_SRC = System.getProperty("test.src", ".");
private static final String KTAB_FILENAME = "krb5.keytab.data";
private static final String KRB_REALM = "TEST.REALM";
@ -179,11 +183,13 @@ abstract public class SSLEngineTestCase {
List<String> supportedCiphersList = new LinkedList<>();
for (String cipher : allSupportedCiphers) {
if (!cipher.contains("KRB5")
&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
supportedCiphersList.add(cipher);
}
}
SUPPORTED_NON_KRB_CIPHERS = supportedCiphersList.toArray(new String[0]);
SUPPORTED_NON_KRB_CIPHERS =
supportedCiphersList.toArray(new String[0]);
} catch (Exception ex) {
throw new Error("Unexpected issue", ex);
}
@ -220,7 +226,7 @@ abstract public class SSLEngineTestCase {
List<String> supportedCiphersList = new LinkedList<>();
for (String cipher : allSupportedCiphers) {
if (cipher.contains("KRB5")
&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
supportedCiphersList.add(cipher);
}
}
@ -240,11 +246,12 @@ abstract public class SSLEngineTestCase {
List<String> enabledCiphersList = new LinkedList<>();
for (String cipher : enabledCiphers) {
if (!cipher.contains("anon") && !cipher.contains("KRB5")
&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
&& !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
enabledCiphersList.add(cipher);
}
}
ENABLED_NON_KRB_NOT_ANON_CIPHERS = enabledCiphersList.toArray(new String[0]);
ENABLED_NON_KRB_NOT_ANON_CIPHERS =
enabledCiphersList.toArray(new String[0]);
} catch (Exception ex) {
throw new Error("Unexpected issue", ex);
}
@ -300,10 +307,10 @@ abstract public class SSLEngineTestCase {
* Wraps data with the specified engine.
*
* @param engine - SSLEngine that wraps data.
* @param wrapper - Set wrapper id, e.g. "server" of "client". Used for
* logging only.
* @param maxPacketSize - Max packet size to check that MFLN extension works
* or zero for no check.
* @param wrapper - Set wrapper id, e.g. "server" of "client".
* Used for logging only.
* @param maxPacketSize - Max packet size to check that MFLN extension
* works or zero for no check.
* @param app - Buffer with data to wrap.
* @return - Buffer with wrapped data.
* @throws SSLException - thrown on engine errors.
@ -319,13 +326,13 @@ abstract public class SSLEngineTestCase {
* Wraps data with the specified engine.
*
* @param engine - SSLEngine that wraps data.
* @param wrapper - Set wrapper id, e.g. "server" of "client". Used for
* logging only.
* @param maxPacketSize - Max packet size to check that MFLN extension works
* or zero for no check.
* @param wrapper - Set wrapper id, e.g. "server" of "client".
* Used for logging only.
* @param maxPacketSize - Max packet size to check that MFLN extension
* works or zero for no check.
* @param app - Buffer with data to wrap.
* @param result - Array which first element will be used to output wrap
* result object.
* @param result - Array which first element will be used to
* output wrap result object.
* @return - Buffer with wrapped data.
* @throws SSLException - thrown on engine errors.
*/
@ -341,10 +348,10 @@ abstract public class SSLEngineTestCase {
* Wraps data with the specified engine.
*
* @param engine - SSLEngine that wraps data.
* @param wrapper - Set wrapper id, e.g. "server" of "client". Used for
* logging only.
* @param maxPacketSize - Max packet size to check that MFLN extension works
* or zero for no check.
* @param wrapper - Set wrapper id, e.g. "server" of "client".
* Used for logging only.
* @param maxPacketSize - Max packet size to check that MFLN extension
* works or zero for no check.
* @param app - Buffer with data to wrap.
* @param wantedStatus - Specifies expected result status of wrapping.
* @return - Buffer with wrapped data.
@ -362,14 +369,14 @@ abstract public class SSLEngineTestCase {
* Wraps data with the specified engine.
*
* @param engine - SSLEngine that wraps data.
* @param wrapper - Set wrapper id, e.g. "server" of "client". Used for
* logging only.
* @param maxPacketSize - Max packet size to check that MFLN extension works
* or zero for no check.
* @param wrapper - Set wrapper id, e.g. "server" of "client".
* Used for logging only.
* @param maxPacketSize - Max packet size to check that MFLN extension
* works or zero for no check.
* @param app - Buffer with data to wrap.
* @param wantedStatus - Specifies expected result status of wrapping.
* @param result - Array which first element will be used to output wrap
* result object.
* @param result - Array which first element will be used to output
* wrap result object.
* @return - Buffer with wrapped data.
* @throws SSLException - thrown on engine errors.
*/
@ -409,9 +416,9 @@ abstract public class SSLEngineTestCase {
* @throws SSLException - thrown on engine errors.
*/
public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
ByteBuffer net)
throws SSLException {
return doUnWrap(engine, unwrapper, net, SSLEngineResult.Status.OK, null);
ByteBuffer net) throws SSLException {
return doUnWrap(engine, unwrapper,
net, SSLEngineResult.Status.OK, null);
}
/**
@ -427,26 +434,25 @@ abstract public class SSLEngineTestCase {
* @throws SSLException - thrown on engine errors.
*/
public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
ByteBuffer net, SSLEngineResult[] result)
throws SSLException {
return doUnWrap(engine, unwrapper, net, SSLEngineResult.Status.OK, result);
ByteBuffer net, SSLEngineResult[] result) throws SSLException {
return doUnWrap(engine, unwrapper,
net, SSLEngineResult.Status.OK, result);
}
/**
* Unwraps data with the specified engine.
*
* @param engine - SSLEngine that unwraps data.
* @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for
* logging only.
* @param unwrapper - Set unwrapper id, e.g. "server" of "client".
* Used for logging only.
* @param net - Buffer with data to unwrap.
* @param wantedStatus - Specifies expected result status of wrapping.
* @return - Buffer with unwrapped data.
* @throws SSLException - thrown on engine errors.
*/
public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
ByteBuffer net,
SSLEngineResult.Status wantedStatus)
throws SSLException {
ByteBuffer net,
SSLEngineResult.Status wantedStatus) throws SSLException {
return doUnWrap(engine, unwrapper, net, wantedStatus, null);
}
@ -454,25 +460,23 @@ abstract public class SSLEngineTestCase {
* Unwraps data with the specified engine.
*
* @param engine - SSLEngine that unwraps data.
* @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for
* logging only.
* @param unwrapper - Set unwrapper id, e.g. "server" of "client".
* Used for logging only.
* @param net - Buffer with data to unwrap.
* @param wantedStatus - Specifies expected result status of wrapping.
* @param result - Array which first element will be used to output wrap
* result object.
* @param result - Array which first element will be used to output
* wrap result object.
* @return - Buffer with unwrapped data.
* @throws SSLException - thrown on engine errors.
*/
public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
ByteBuffer net,
SSLEngineResult.Status wantedStatus,
SSLEngineResult[] result)
throws SSLException {
ByteBuffer app = ByteBuffer.allocate(engine.getSession()
.getApplicationBufferSize());
ByteBuffer net, SSLEngineResult.Status wantedStatus,
SSLEngineResult[] result) throws SSLException {
ByteBuffer app = ByteBuffer.allocate(
engine.getSession().getApplicationBufferSize());
int length = net.remaining();
System.out.println(unwrapper + " unwrapping "
+ length + " bytes...");
System.out.println(unwrapper + " unwrapping " + length + " bytes...");
SSLEngineResult r = engine.unwrap(net, app);
app.flip();
System.out.println(unwrapper + " handshake status is "
@ -491,13 +495,14 @@ abstract public class SSLEngineTestCase {
* @param clientEngine - Client SSLEngine.
* @param serverEngine - Server SSLEngine.
* @param maxPacketSize - Maximum packet size for MFLN of zero for no limit.
* @param mode - Handshake mode according to {@link HandshakeMode} enum.
* @param mode - Handshake mode according to
* {@link HandshakeMode} enum.
* @throws SSLException - thrown on engine errors.
*/
public static void doHandshake(SSLEngine clientEngine,
SSLEngine serverEngine,
int maxPacketSize, HandshakeMode mode)
throws SSLException {
SSLEngine serverEngine,
int maxPacketSize, HandshakeMode mode) throws SSLException {
doHandshake(clientEngine, serverEngine, maxPacketSize, mode, false);
}
@ -507,19 +512,20 @@ abstract public class SSLEngineTestCase {
*
* @param clientEngine - Client SSLEngine.
* @param serverEngine - Server SSLEngine.
* @param maxPacketSize - Maximum packet size for MFLN of zero for no limit.
* @param mode - Handshake mode according to {@link HandshakeMode} enum.
* @param maxPacketSize - Maximum packet size for MFLN of zero
* for no limit.
* @param mode - Handshake mode according to
* {@link HandshakeMode} enum.
* @param enableReplicatedPacks - Set {@code true} to enable replicated
* packet sending.
* packet sending.
* @throws SSLException - thrown on engine errors.
*/
public static void doHandshake(SSLEngine clientEngine,
SSLEngine serverEngine, int maxPacketSize,
HandshakeMode mode,
boolean enableReplicatedPacks)
throws SSLException {
System.out.println("================================================="
+ "===========");
SSLEngine serverEngine, int maxPacketSize,
HandshakeMode mode,
boolean enableReplicatedPacks) throws SSLException {
System.out.println("=============================================");
System.out.println("Starting handshake " + mode.name());
int loop = 0;
if (maxPacketSize < 0) {
@ -561,18 +567,16 @@ abstract public class SSLEngineTestCase {
if (++loop > MAX_HANDSHAKE_LOOPS) {
throw new Error("Too much loops for handshaking");
}
System.out.println("==============================================");
System.out.println("Handshake loop " + loop);
SSLEngineResult.HandshakeStatus clientHSStatus
= clientEngine.getHandshakeStatus();
SSLEngineResult.HandshakeStatus serverHSStatus
= serverEngine.getHandshakeStatus();
System.out.println("Client handshake status "
+ clientHSStatus.name());
System.out.println("Server handshake status "
+ serverHSStatus.name());
System.out.println("============================================");
System.out.println("Handshake loop " + loop + ": round 1");
System.out.println("==========================");
handshakeProcess(firstEngine, secondEngine, maxPacketSize,
enableReplicatedPacks);
if (endHandshakeLoop) {
break;
}
System.out.println("Handshake loop " + loop + ": round 2");
System.out.println("==========================");
handshakeProcess(secondEngine, firstEngine, maxPacketSize,
enableReplicatedPacks);
}
@ -596,15 +600,15 @@ abstract public class SSLEngineTestCase {
sender = "Client";
reciever = "Server";
excMsgSent += " Client.";
} else if (toEngine.getUseClientMode() && !fromEngine.getUseClientMode()) {
} else if (toEngine.getUseClientMode() &&
!fromEngine.getUseClientMode()) {
sender = "Server";
reciever = "Client";
excMsgSent += " Server.";
} else {
throw new Error("Test issue: both engines are in the same mode");
}
System.out.println("================================================="
+ "===========");
System.out.println("=============================================");
System.out.println("Trying to send application data from " + sender
+ " to " + reciever);
ByteBuffer clientAppSent
@ -643,20 +647,24 @@ abstract public class SSLEngineTestCase {
if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) {
from = "Client";
to = "Server";
} else if (toEngine.getUseClientMode() && !fromEngine.getUseClientMode()) {
} else if (toEngine.getUseClientMode() &&
!fromEngine.getUseClientMode()) {
from = "Server";
to = "Client";
} else {
throw new Error("Both engines are in the same mode");
}
System.out.println("=========================================================");
System.out.println("Trying to close engines from " + from + " to " + to);
System.out.println("=============================================");
System.out.println(
"Trying to close engines from " + from + " to " + to);
// Sending close outbound request to peer
fromEngine.closeOutbound();
app = ByteBuffer.allocate(fromEngine.getSession().getApplicationBufferSize());
app = ByteBuffer.allocate(
fromEngine.getSession().getApplicationBufferSize());
net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);
doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);
app = ByteBuffer.allocate(fromEngine.getSession().getApplicationBufferSize());
app = ByteBuffer.allocate(
fromEngine.getSession().getApplicationBufferSize());
net = doWrap(toEngine, to, 0, app, SSLEngineResult.Status.CLOSED);
doUnWrap(fromEngine, from, net, SSLEngineResult.Status.CLOSED);
if (!toEngine.isInboundDone()) {
@ -665,7 +673,8 @@ abstract public class SSLEngineTestCase {
}
// Executing close inbound
fromEngine.closeInbound();
app = ByteBuffer.allocate(fromEngine.getSession().getApplicationBufferSize());
app = ByteBuffer.allocate(
fromEngine.getSession().getApplicationBufferSize());
net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);
doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);
if (!toEngine.isOutboundDone()) {
@ -712,7 +721,8 @@ abstract public class SSLEngineTestCase {
runTests(Ciphers.SUPPORTED_KRB_CIPHERS);
break;
default:
throw new Error("Test error: unexpected test mode: " + TEST_MODE);
throw new Error(
"Test error: unexpected test mode: " + TEST_MODE);
}
}
@ -743,28 +753,36 @@ abstract public class SSLEngineTestCase {
}
/**
* Returns SSLContext with TESTED_SECURITY_PROTOCOL protocol and sets up keys.
* Returns SSLContext with TESTED_SECURITY_PROTOCOL protocol and
* sets up keys.
*
* @return - SSLContext with a protocol specified by TESTED_SECURITY_PROTOCOL.
* @return - SSLContext with a protocol specified by
* TESTED_SECURITY_PROTOCOL.
*/
public static SSLContext getContext() {
try {
java.security.Security.setProperty("jdk.tls.disabledAlgorithms", "");
java.security.Security.setProperty("jdk.certpath.disabledAlgorithms", "");
java.security.Security.setProperty(
"jdk.tls.disabledAlgorithms", "");
java.security.Security.setProperty(
"jdk.certpath.disabledAlgorithms", "");
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore ts = KeyStore.getInstance("JKS");
char[] passphrase = PASSWD.toCharArray();
try (FileInputStream keyFileStream = new FileInputStream(KEY_FILE_NAME)) {
try (FileInputStream keyFileStream =
new FileInputStream(KEY_FILE_NAME)) {
ks.load(keyFileStream, passphrase);
}
try (FileInputStream trustFileStream = new FileInputStream(TRUST_FILE_NAME)) {
try (FileInputStream trustFileStream =
new FileInputStream(TRUST_FILE_NAME)) {
ts.load(trustFileStream, passphrase);
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf =
TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
SSLContext sslCtx = SSLContext.getInstance(TESTED_SECURITY_PROTOCOL);
SSLContext sslCtx =
SSLContext.getInstance(TESTED_SECURITY_PROTOCOL);
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return sslCtx;
} catch (KeyStoreException | IOException | NoSuchAlgorithmException |
@ -791,7 +809,8 @@ abstract public class SSLEngineTestCase {
}
/**
* Sets up and starts kerberos KDC server if SSLEngineTestCase.TEST_MODE is "krb".
* Sets up and starts kerberos KDC server if
* SSLEngineTestCase.TEST_MODE is "krb".
*/
public static void setUpAndStartKDCIfNeeded() {
if (TEST_MODE.equals("krb")) {
@ -806,7 +825,9 @@ abstract public class SSLEngineTestCase {
* @param useSNI - flag used to enable or disable using SNI extension.
* Needed for Kerberos.
*/
public static SSLEngine getClientSSLEngine(SSLContext context, boolean useSNI) {
public static SSLEngine getClientSSLEngine(
SSLContext context, boolean useSNI) {
SSLEngine clientEngine = context.createSSLEngine(HOST, 80);
clientEngine.setUseClientMode(true);
if (useSNI) {
@ -827,7 +848,9 @@ abstract public class SSLEngineTestCase {
* @param useSNI - flag used to enable or disable using SNI extension.
* Needed for Kerberos.
*/
public static SSLEngine getServerSSLEngine(SSLContext context, boolean useSNI) {
public static SSLEngine getServerSSLEngine(
SSLContext context, boolean useSNI) {
SSLEngine serverEngine = context.createSSLEngine();
serverEngine.setUseClientMode(false);
if (useSNI) {
@ -860,18 +883,20 @@ abstract public class SSLEngineTestCase {
protected int testSomeCiphers(Ciphers ciphers) {
int failedNum = 0;
String description = ciphers.description;
System.out.println("==================================================="
+ "=========");
System.out.println("===============================================");
System.out.println(description + " ciphers testing");
System.out.println("==================================================="
+ "=========");
System.out.println("===========================================");
for (String cs : ciphers.ciphers) {
System.out.println("-----------------------------------------------"
+ "-------------");
System.out.println("---------------------------------------");
System.out.println("Testing cipher suite " + cs);
System.out.println("-----------------------------------------------"
+ "-------------");
System.out.println("---------------------------------------");
Throwable error = null;
// Reset global mutable static variables
net = null;
doUnwrapForNotHandshakingStatus = false;
endHandshakeLoop = false;
try {
testOneCipher(cs);
} catch (Throwable t) {
@ -894,8 +919,9 @@ abstract public class SSLEngineTestCase {
case UNSUPPORTED_CIPHERS:
if (error == null) {
System.out.println("Test Failed: " + cs);
System.err.println("Test for " + cs + " should have thrown"
+ " IllegalArgumentException, but it has not!");
System.err.println("Test for " + cs +
" should have thrown " +
"IllegalArgumentException, but it has not!");
failedNum++;
} else if (!(error instanceof IllegalArgumentException)) {
System.out.println("Test Failed: " + cs);
@ -911,6 +937,7 @@ abstract public class SSLEngineTestCase {
+ ciphers.name());
}
}
return failedNum;
}
@ -919,20 +946,20 @@ abstract public class SSLEngineTestCase {
*
* @param wrapingEngine - Engine that is expected to wrap data.
* @param unwrapingEngine - Engine that is expected to unwrap data.
* @param maxPacketSize - Maximum packet size for MFLN of zero for no limit.
* @param maxPacketSize - Maximum packet size for MFLN of zero
* for no limit.
* @param enableReplicatedPacks - Set {@code true} to enable replicated
* packet sending.
* packet sending.
* @throws SSLException - thrown on engine errors.
*/
private static void handshakeProcess(SSLEngine wrapingEngine,
SSLEngine unwrapingEngine,
int maxPacketSize,
boolean enableReplicatedPacks)
throws SSLException {
SSLEngineResult.HandshakeStatus wrapingHSStatus = wrapingEngine
.getHandshakeStatus();
SSLEngineResult.HandshakeStatus unwrapingHSStatus = unwrapingEngine
.getHandshakeStatus();
SSLEngine unwrapingEngine,
int maxPacketSize,
boolean enableReplicatedPacks) throws SSLException {
HandshakeStatus wrapingHSStatus = wrapingEngine.getHandshakeStatus();
HandshakeStatus unwrapingHSStatus =
unwrapingEngine.getHandshakeStatus();
SSLEngineResult r;
String wrapper, unwrapper;
if (wrapingEngine.getUseClientMode()
@ -946,6 +973,13 @@ abstract public class SSLEngineTestCase {
} else {
throw new Error("Both engines are in the same mode");
}
System.out.println(
wrapper + " handshake (wrap) status " + wrapingHSStatus);
System.out.println(
unwrapper + " handshake (unwrap) status " + unwrapingHSStatus);
ByteBuffer netReplicatedClient = null;
ByteBuffer netReplicatedServer = null;
switch (wrapingHSStatus) {
case NEED_WRAP:
if (enableReplicatedPacks) {
@ -960,9 +994,11 @@ abstract public class SSLEngineTestCase {
}
}
}
ByteBuffer app = ByteBuffer.allocate(wrapingEngine.getSession()
.getApplicationBufferSize());
ByteBuffer app = ByteBuffer.allocate(
wrapingEngine.getSession().getApplicationBufferSize());
net = doWrap(wrapingEngine, wrapper, maxPacketSize, app);
wrapingHSStatus = wrapingEngine.getHandshakeStatus();
// No break, falling into unwrapping.
case NOT_HANDSHAKING:
switch (unwrapingHSStatus) {
case NEED_TASK:
@ -970,12 +1006,12 @@ abstract public class SSLEngineTestCase {
case NEED_UNWRAP:
doUnWrap(unwrapingEngine, unwrapper, net);
if (enableReplicatedPacks) {
System.out.println("Unwrapping replicated packet...");
System.out.println(unwrapper +
" unwrapping replicated packet...");
if (unwrapingEngine.getHandshakeStatus()
.equals(SSLEngineResult.HandshakeStatus.NEED_TASK)) {
.equals(HandshakeStatus.NEED_TASK)) {
runDelegatedTasks(unwrapingEngine);
}
runDelegatedTasks(unwrapingEngine);
ByteBuffer netReplicated;
if (unwrapingEngine.getUseClientMode()) {
netReplicated = netReplicatedClient;
@ -983,7 +1019,8 @@ abstract public class SSLEngineTestCase {
netReplicated = netReplicatedServer;
}
if (netReplicated != null) {
doUnWrap(unwrapingEngine, unwrapper, netReplicated);
doUnWrap(unwrapingEngine,
unwrapper, netReplicated);
} else {
net.flip();
doUnWrap(unwrapingEngine, unwrapper, net);
@ -994,15 +1031,39 @@ abstract public class SSLEngineTestCase {
break;
case NOT_HANDSHAKING:
if (doUnwrapForNotHandshakingStatus) {
System.out.println("Not handshake status unwrap");
doUnWrap(unwrapingEngine, unwrapper, net);
doUnwrapForNotHandshakingStatus = false;
break;
} else {
endHandshakeLoop = true;
if (wrapingHSStatus ==
HandshakeStatus.NOT_HANDSHAKING) {
System.out.println("Handshake is completed");
endHandshakeLoop = true;
}
}
break;
case NEED_WRAP:
SSLSession session = unwrapingEngine.getSession();
int bufferSize = session.getApplicationBufferSize();
ByteBuffer b = ByteBuffer.allocate(bufferSize);
net = doWrap(unwrapingEngine,
unwrapper, maxPacketSize, b);
unwrapingHSStatus =
unwrapingEngine.getHandshakeStatus();
if ((wrapingHSStatus ==
HandshakeStatus.NOT_HANDSHAKING) &&
(unwrapingHSStatus ==
HandshakeStatus.NOT_HANDSHAKING)) {
System.out.println("Handshake is completed");
endHandshakeLoop = true;
}
break;
default:
throw new Error("Unexpected unwraping engine handshake status "
throw new Error(
"Unexpected unwraping engine handshake status "
+ unwrapingHSStatus.name());
}
break;
@ -1027,8 +1088,8 @@ abstract public class SSLEngineTestCase {
while ((runnable = engine.getDelegatedTask()) != null) {
runnable.run();
}
SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
HandshakeStatus hs = engine.getHandshakeStatus();
if (hs == HandshakeStatus.NEED_TASK) {
throw new Error("Handshake shouldn't need additional tasks.");
}
}