src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
Print this page
*** 25,34 ****
--- 25,35 ----
package sun.security.ssl;
import java.io.*;
+ import java.nio.*;
import java.net.*;
import java.security.GeneralSecurityException;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
*** 157,186 ****
private static final int cs_ERROR = 4;
private static final int cs_SENT_CLOSE = 5;
private static final int cs_CLOSED = 6;
private static final int cs_APP_CLOSED = 7;
-
/*
- * Client authentication be off, requested, or required.
- *
- * Migrated to SSLEngineImpl:
- * clauth_none/cl_auth_requested/clauth_required
- */
-
- /*
* Drives the protocol state machine.
*/
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
* a change cipher spec message is followed by a finished message.
*/
private boolean expectingFinished;
--- 158,173 ----
*** 195,205 ****
/*
* Per-connection private state that doesn't change when the
* session is changed.
*/
! private byte doClientAuth;
private boolean roleIsServer;
private boolean enableSessionCreation = true;
private String host;
private boolean autoClose = true;
private AccessControlContext acc;
--- 182,193 ----
/*
* Per-connection private state that doesn't change when the
* session is changed.
*/
! private ClientAuthType doClientAuth =
! ClientAuthType.CLIENT_AUTH_NONE;
private boolean roleIsServer;
private boolean enableSessionCreation = true;
private String host;
private boolean autoClose = true;
private AccessControlContext acc;
*** 282,311 ****
* handshaker to change its mode. If handshaking has started,
* we simply store that request until the next pending session
* is created, at which time the new handshaker's state is set.
*
* The readLock is held during readRecord(), which is responsible
! * for reading an InputRecord, decrypting it, and processing it.
* The readLock ensures that these three steps are done atomically
! * and that once started, no other thread can block on InputRecord.read.
* This is necessary so that processing of close_notify alerts
* from the peer are handled properly.
*/
final private Object handshakeLock = new Object();
final ReentrantLock writeLock = new ReentrantLock();
final private Object readLock = new Object();
! private InputRecord inrec;
/*
- * Crypto state that's reinitialized when the session changes.
- */
- private Authenticator readAuthenticator, writeAuthenticator;
- private CipherBox readCipher, writeCipher;
- // NOTE: compression state would be saved here
-
- /*
* security parameters for secure renegotiation.
*/
private boolean secureRenegotiation;
private byte[] clientVerifyData;
private byte[] serverVerifyData;
--- 270,293 ----
* handshaker to change its mode. If handshaking has started,
* we simply store that request until the next pending session
* is created, at which time the new handshaker's state is set.
*
* The readLock is held during readRecord(), which is responsible
! * for reading an SSLInputRecord, decrypting it, and processing it.
* The readLock ensures that these three steps are done atomically
! * and that once started, no other thread can block on SSLInputRecord.read.
* This is necessary so that processing of close_notify alerts
* from the peer are handled properly.
*/
final private Object handshakeLock = new Object();
final ReentrantLock writeLock = new ReentrantLock();
final private Object readLock = new Object();
! InputRecord inputRecord;
! OutputRecord outputRecord;
/*
* security parameters for secure renegotiation.
*/
private boolean secureRenegotiation;
private byte[] clientVerifyData;
private byte[] serverVerifyData;
*** 366,376 ****
private ProtocolList enabledProtocols;
/*
* The SSL version associated with this connection.
*/
! private ProtocolVersion protocolVersion = ProtocolVersion.DEFAULT;
/* Class and subclass dynamic debugging support */
private static final Debug debug = Debug.getInstance("ssl");
/*
--- 348,358 ----
private ProtocolList enabledProtocols;
/*
* The SSL version associated with this connection.
*/
! private ProtocolVersion protocolVersion = ProtocolVersion.DEFAULT_TLS;
/* Class and subclass dynamic debugging support */
private static final Debug debug = Debug.getInstance("ssl");
/*
*** 388,397 ****
--- 370,384 ----
* Whether local cipher suites preference in server side should be
* honored during handshaking?
*/
private boolean preferLocalCipherSuites = false;
+ /*
+ * The maximum expected network packet size for SSL/TLS/DTLS records.
+ */
+ private int maximumPacketSize = 0;
+
//
// CONSTRUCTORS AND INITIALIZATION CODE
//
/**
*** 489,499 ****
* java.net package accepts the TCP connection after this call is
* made. This just initializes handshake state to use "server mode",
* giving control over the use of SSL client authentication.
*/
SSLSocketImpl(SSLContextImpl context, boolean serverMode,
! CipherSuiteList suites, byte clientAuth,
boolean sessionCreation, ProtocolList protocols,
String identificationProtocol,
AlgorithmConstraints algorithmConstraints,
Collection<SNIMatcher> sniMatchers,
boolean preferLocalCipherSuites) throws IOException {
--- 476,486 ----
* java.net package accepts the TCP connection after this call is
* made. This just initializes handshake state to use "server mode",
* giving control over the use of SSL client authentication.
*/
SSLSocketImpl(SSLContextImpl context, boolean serverMode,
! CipherSuiteList suites, ClientAuthType clientAuth,
boolean sessionCreation, ProtocolList protocols,
String identificationProtocol,
AlgorithmConstraints algorithmConstraints,
Collection<SNIMatcher> sniMatchers,
boolean preferLocalCipherSuites) throws IOException {
*** 592,613 ****
* role is as specified, state is START until after
* the low level connection's established.
*/
roleIsServer = isServer;
connectionState = cs_START;
- receivedCCS = false;
- /*
- * default read and write side cipher and MAC support
- *
- * Note: compression support would go here too
- */
- readCipher = CipherBox.NULL;
- readAuthenticator = MAC.NULL;
- writeCipher = CipherBox.NULL;
- writeAuthenticator = MAC.NULL;
-
// initial security parameters for secure renegotiation
secureRenegotiation = false;
clientVerifyData = new byte[0];
serverVerifyData = new byte[0];
--- 579,589 ----
*** 614,625 ****
enabledCipherSuites =
sslContext.getDefaultCipherSuiteList(roleIsServer);
enabledProtocols =
sslContext.getDefaultProtocolList(roleIsServer);
! inrec = null;
// save the acc
acc = AccessController.getContext();
input = new AppInputStream(this);
output = new AppOutputStream(this);
--- 590,604 ----
enabledCipherSuites =
sslContext.getDefaultCipherSuiteList(roleIsServer);
enabledProtocols =
sslContext.getDefaultProtocolList(roleIsServer);
! inputRecord = new SSLSocketInputRecord();;
! outputRecord = new SSLSocketOutputRecord();
+ maximumPacketSize = outputRecord.getMaxPacketSize();
+
// save the acc
acc = AccessController.getContext();
input = new AppInputStream(this);
output = new AppOutputStream(this);
*** 670,679 ****
--- 649,661 ----
* we get some pretty bizarre failure modes.
*/
sockInput = super.getInputStream();
sockOutput = super.getOutputStream();
+ inputRecord.setDeliverStream(sockOutput);
+ outputRecord.setDeliverStream(sockOutput);
+
/*
* Move to handshaking state, with pending session initialized
* to defaults and the appropriate kind of handshaker set up.
*/
initHandshaker();
*** 694,726 ****
//
// READING AND WRITING RECORDS
//
/*
! * AppOutputStream calls may need to buffer multiple outbound
! * application packets.
*
! * All other writeRecord() calls will not buffer, so do not hold
! * these records.
*/
! void writeRecord(OutputRecord r) throws IOException {
! writeRecord(r, false);
! }
!
/*
- * Record Output. Application data can't be sent until the first
- * handshake establishes a session.
- *
- * NOTE: we let empty records be written as a hook to force some
- * TCP-level activity, notably handshaking, to occur.
- */
- void writeRecord(OutputRecord r, boolean holdRecord) throws IOException {
- /*
* The loop is in case of HANDSHAKE --> ERROR transitions, etc
*/
! loop:
! while (r.contentType() == Record.ct_application_data) {
/*
* Not all states support passing application data. We
* synchronize access to the connection state, so that
* synchronous handshakes can complete cleanly.
*/
--- 676,697 ----
//
// READING AND WRITING RECORDS
//
/*
! * Application data record output.
*
! * Application data can't be sent until the first handshake establishes
! * a session.
*/
! void writeRecord(byte[] source, int offset, int length) throws IOException {
/*
* The loop is in case of HANDSHAKE --> ERROR transitions, etc
*/
! // Don't bother to check the emptiness of source applicatoin data
! // before the security connection established.
! for (boolean readyForApp = false; !readyForApp;) {
/*
* Not all states support passing application data. We
* synchronize access to the connection state, so that
* synchronous handshakes can complete cleanly.
*/
*** 736,746 ****
performInitialHandshake();
break;
case cs_DATA:
case cs_RENEGOTIATE:
! break loop;
case cs_ERROR:
fatal(Alerts.alert_close_notify,
"error while writing to socket");
break; // dummy
--- 707,718 ----
performInitialHandshake();
break;
case cs_DATA:
case cs_RENEGOTIATE:
! readyForApp = true;
! break;
case cs_ERROR:
fatal(Alerts.alert_close_notify,
"error while writing to socket");
break; // dummy
*** 758,768 ****
/*
* Else something's goofy in this state machine's use.
*/
default:
! throw new SSLProtocolException("State error, send app data");
}
}
//
// Don't bother to really write empty records. We went this
--- 730,741 ----
/*
* Else something's goofy in this state machine's use.
*/
default:
! throw new SSLProtocolException(
! "State error, send app data");
}
}
//
// Don't bother to really write empty records. We went this
*** 770,792 ****
// writing empty records improves performance by cutting CPU
// time and network resource usage. However, some protocol
// implementations are fragile and don't like to see empty
// records, so this also increases robustness.
//
! if (!r.isEmpty()) {
// If the record is a close notify alert, we need to honor
// socket option SO_LINGER. Note that we will try to send
// the close notify even if the SO_LINGER set to zero.
! if (r.isAlert(Alerts.alert_close_notify) && getSoLinger() >= 0) {
// keep and clear the current thread interruption status.
boolean interrupted = Thread.interrupted();
try {
if (writeLock.tryLock(getSoLinger(), TimeUnit.SECONDS)) {
try {
! writeRecordInternal(r, holdRecord);
} finally {
writeLock.unlock();
}
} else {
SSLException ssle = new SSLException(
--- 743,813 ----
// writing empty records improves performance by cutting CPU
// time and network resource usage. However, some protocol
// implementations are fragile and don't like to see empty
// records, so this also increases robustness.
//
! if (length > 0) {
! writeLock.lock();
! try {
! outputRecord.deliver(source, offset, length);
! } catch (SSLHandshakeException she) {
! // may be record sequence number overflow
! fatal(Alerts.alert_handshake_failure, she);
! } catch (IOException e) {
! fatal(Alerts.alert_unexpected_message, e);
! } finally {
! writeLock.unlock();
! }
! }
+ /*
+ * Check the sequence number state
+ *
+ * Note that in order to maintain the connection I/O
+ * properly, we check the sequence number after the last
+ * record writing process. As we request renegotiation
+ * or close the connection for wrapped sequence number
+ * when there is enough sequence number space left to
+ * handle a few more records, so the sequence number
+ * of the last record cannot be wrapped.
+ *
+ * Don't bother to kickstart the renegotiation when the
+ * local is asking for it.
+ */
+ if ((connectionState == cs_DATA) && outputRecord.seqNumIsHuge()) {
+ /*
+ * Ask for renegotiation when need to renew sequence number.
+ *
+ * Don't bother to kickstart the renegotiation when the local is
+ * asking for it.
+ */
+ if (debug != null && Debug.isOn("ssl")) {
+ System.out.println(Thread.currentThread().getName() +
+ ", request renegotiation " +
+ "to avoid sequence number overflow");
+ }
+
+ startHandshake();
+ }
+ }
+
+ /*
+ * Alert record output.
+ */
+ void writeAlert(byte level, byte description) throws IOException {
+
// If the record is a close notify alert, we need to honor
// socket option SO_LINGER. Note that we will try to send
// the close notify even if the SO_LINGER set to zero.
! if ((description == Alerts.alert_close_notify) && getSoLinger() >= 0) {
// keep and clear the current thread interruption status.
boolean interrupted = Thread.interrupted();
try {
if (writeLock.tryLock(getSoLinger(), TimeUnit.SECONDS)) {
try {
! outputRecord.encodeAlert(level, description);
} finally {
writeLock.unlock();
}
} else {
SSLException ssle = new SSLException(
*** 831,941 ****
Thread.currentThread().interrupt();
}
} else {
writeLock.lock();
try {
! writeRecordInternal(r, holdRecord);
} finally {
writeLock.unlock();
}
}
}
}
! private void writeRecordInternal(OutputRecord r,
! boolean holdRecord) throws IOException {
! // r.compress(c);
! r.encrypt(writeAuthenticator, writeCipher);
! if (holdRecord) {
! // If we were requested to delay the record due to possibility
! // of Nagle's being active when finally got to writing, and
! // it's actually not, we don't really need to delay it.
! if (getTcpNoDelay()) {
! holdRecord = false;
} else {
! // We need to hold the record, so let's provide
! // a per-socket place to do it.
! if (heldRecordBuffer == null) {
! // Likely only need 37 bytes.
! heldRecordBuffer = new ByteArrayOutputStream(40);
}
}
}
- r.write(sockOutput, holdRecord, heldRecordBuffer);
! /*
! * Check the sequence number state
! *
! * Note that in order to maintain the connection I/O
! * properly, we check the sequence number after the last
! * record writing process. As we request renegotiation
! * or close the connection for wrapped sequence number
! * when there is enough sequence number space left to
! * handle a few more records, so the sequence number
! * of the last record cannot be wrapped.
! */
! if (connectionState < cs_ERROR) {
! checkSequenceNumber(writeAuthenticator, r.contentType());
}
! // turn off the flag of the first application record
! if (isFirstAppOutputRecord &&
! r.contentType() == Record.ct_application_data) {
! isFirstAppOutputRecord = false;
}
- }
/*
! * Need to split the payload except the following cases:
*
! * 1. protocol version is TLS 1.1 or later;
! * 2. bulk cipher does not use CBC mode, including null bulk cipher suites.
! * 3. the payload is the first application record of a freshly
! * negotiated TLS session.
! * 4. the CBC protection is disabled;
! *
! * More details, please refer to AppOutputStream.write(byte[], int, int).
*/
! boolean needToSplitPayload() {
! writeLock.lock();
! try {
! return (protocolVersion.v <= ProtocolVersion.TLS10.v) &&
! writeCipher.isCBCMode() && !isFirstAppOutputRecord &&
! Record.enableCBCProtection;
! } finally {
! writeLock.unlock();
}
}
/*
! * Read an application data record. Alerts and handshake
! * messages are handled directly.
*/
! void readDataRecord(InputRecord r) throws IOException {
! if (getConnectionState() == cs_HANDSHAKE) {
! performInitialHandshake();
}
- readRecord(r, true);
- }
-
/*
* Clear the pipeline of records from the peer, optionally returning
* application data. Caller is responsible for knowing that it's
* possible to do this kind of clearing, if they don't want app
* data -- e.g. since it's the initial SSL handshake.
*
* Don't synchronize (this) during a blocking read() since it
* protects data which is accessed on the write side as well.
*/
! private void readRecord(InputRecord r, boolean needAppData)
throws IOException {
int state;
! // readLock protects reading and processing of an InputRecord.
// It keeps the reading from sockInput and processing of the record
// atomic so that no two threads can be blocked on the
// read from the same input stream at the same time.
// This is required for example when a reader thread is
// blocked on the read and another thread is trying to
--- 852,958 ----
Thread.currentThread().interrupt();
}
} else {
writeLock.lock();
try {
! outputRecord.encodeAlert(level, description);
} finally {
writeLock.unlock();
}
}
+
+ // Don't bother to check sequence number overlap here. If sequence
+ // number is huge, there should be enough sequence number space to
+ // request renegotiation in next application data read and write.
}
+
+
+ int bytesInCompletePacket() throws IOException {
+ if (getConnectionState() == cs_HANDSHAKE) {
+ performInitialHandshake();
}
! synchronized (readLock) {
! int state = getConnectionState();
! if ((state == cs_CLOSED) ||
! (state == cs_ERROR) || (state == cs_APP_CLOSED)) {
! return -1;
! }
! try {
! return inputRecord.bytesInCompletePacket(sockInput);
! } catch (EOFException eofe) {
! boolean handshaking = (connectionState <= cs_HANDSHAKE);
! boolean rethrow = requireCloseNotify || handshaking;
! if ((debug != null) && Debug.isOn("ssl")) {
! System.out.println(Thread.currentThread().getName() +
! ", received EOFException: "
! + (rethrow ? "error" : "ignored"));
! }
! if (!rethrow) {
! // treat as if we had received a close_notify
! closeInternal(false);
} else {
! SSLException e;
! if (handshaking) {
! e = new SSLHandshakeException(
! "Remote host terminated the handshake");
! } else {
! e = new SSLProtocolException(
! "Remote host terminated the handshake");
}
+ e.initCause(eofe);
+ throw e;
}
}
! return -1;
}
+ }
! // the caller have synchronized readLock
! void expectingFinishFlight() {
! inputRecord.expectingFinishFlight();
}
/*
! * Read an application data record.
*
! * Alerts and handshake messages are internally handled directly.
*/
! int readRecord(ByteBuffer buffer) throws IOException {
! if (getConnectionState() == cs_HANDSHAKE) {
! performInitialHandshake();
}
+
+ return readRecord(buffer, true);
}
/*
! * Read a record, no application data input required.
! *
! * Alerts and handshake messages are internally handled directly.
*/
! int readRecord(boolean needAppData) throws IOException {
! return readRecord(null, needAppData);
}
/*
* Clear the pipeline of records from the peer, optionally returning
* application data. Caller is responsible for knowing that it's
* possible to do this kind of clearing, if they don't want app
* data -- e.g. since it's the initial SSL handshake.
*
* Don't synchronize (this) during a blocking read() since it
* protects data which is accessed on the write side as well.
*/
! private int readRecord(ByteBuffer buffer, boolean needAppData)
throws IOException {
int state;
! // readLock protects reading and processing of an SSLInputRecord.
// It keeps the reading from sockInput and processing of the record
// atomic so that no two threads can be blocked on the
// read from the same input stream at the same time.
// This is required for example when a reader thread is
// blocked on the read and another thread is trying to
*** 947,990 ****
synchronized (readLock) {
/*
* Read and handle records ... return application data
* ONLY if it's needed.
*/
!
while (((state = getConnectionState()) != cs_CLOSED) &&
(state != cs_ERROR) && (state != cs_APP_CLOSED)) {
/*
* Read a record ... maybe emitting an alert if we get a
* comprehensible but unsupported "hello" message during
* format checking (e.g. V2).
*/
try {
! r.setAppDataValid(false);
! r.read(sockInput, sockOutput);
! } catch (SSLProtocolException e) {
try {
! fatal(Alerts.alert_unexpected_message, e);
} catch (IOException x) {
! // discard this exception
}
! throw e;
} catch (EOFException eof) {
! boolean handshaking = (getConnectionState() <= cs_HANDSHAKE);
boolean rethrow = requireCloseNotify || handshaking;
if ((debug != null) && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
", received EOFException: "
+ (rethrow ? "error" : "ignored"));
}
if (rethrow) {
SSLException e;
if (handshaking) {
! e = new SSLHandshakeException
! ("Remote host closed connection during handshake");
} else {
! e = new SSLProtocolException
! ("Remote host closed connection incorrectly");
}
e.initCause(eof);
throw e;
} else {
// treat as if we had received a close_notify
--- 964,1019 ----
synchronized (readLock) {
/*
* Read and handle records ... return application data
* ONLY if it's needed.
*/
! Plaintext plainText = null;
while (((state = getConnectionState()) != cs_CLOSED) &&
(state != cs_ERROR) && (state != cs_APP_CLOSED)) {
+ // clean the buffer
+ if (buffer != null) {
+ buffer.clear();
+ }
+
/*
* Read a record ... maybe emitting an alert if we get a
* comprehensible but unsupported "hello" message during
* format checking (e.g. V2).
*/
try {
! plainText = inputRecord.decode(sockInput, buffer);
! } catch (BadPaddingException bpe) {
! byte alertType = (state != cs_DATA) ?
! Alerts.alert_handshake_failure :
! Alerts.alert_bad_record_mac;
! fatal(alertType, bpe.getMessage(), bpe);
! } catch (SSLProtocolException spe) {
try {
! fatal(Alerts.alert_unexpected_message, spe);
} catch (IOException x) {
! // discard this exception, throw the original exception
}
! throw spe;
! } catch (SSLHandshakeException she) {
! // may be record sequence number overflow
! fatal(Alerts.alert_handshake_failure, she);
} catch (EOFException eof) {
! boolean handshaking = (connectionState <= cs_HANDSHAKE);
boolean rethrow = requireCloseNotify || handshaking;
if ((debug != null) && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
", received EOFException: "
+ (rethrow ? "error" : "ignored"));
}
if (rethrow) {
SSLException e;
if (handshaking) {
! e = new SSLHandshakeException(
! "Remote host terminated the handshake");
} else {
! e = new SSLProtocolException(
! "Remote host terminated the connection");
}
e.initCause(eof);
throw e;
} else {
// treat as if we had received a close_notify
*** 991,1025 ****
closeInternal(false);
continue;
}
}
! /*
! * The basic SSLv3 record protection involves (optional)
! * encryption for privacy, and an integrity check ensuring
! * data origin authentication. We do them both here, and
! * throw a fatal alert if the integrity check fails.
! */
! try {
! r.decrypt(readAuthenticator, readCipher);
! } catch (BadPaddingException e) {
! byte alertType = (r.contentType() == Record.ct_handshake)
! ? Alerts.alert_handshake_failure
! : Alerts.alert_bad_record_mac;
! fatal(alertType, e.getMessage(), e);
}
! // if (!r.decompress(c))
! // fatal(Alerts.alert_decompression_failure,
! // "decompression failure");
/*
* Process the record.
*/
! synchronized (this) {
! switch (r.contentType()) {
case Record.ct_handshake:
/*
* Handshake messages always go to a pending session
* handshaker ... if there isn't one, create one. This
* must work asynchronously, for renegotiation.
--- 1020,1063 ----
closeInternal(false);
continue;
}
}
+ // PlainText should never be null. Process input record.
+ int volume = processInputRecord(plainText, needAppData);
! if (plainText.contentType == Record.ct_application_data) {
! return volume;
}
! if (plainText.contentType == Record.ct_handshake) {
! if (!needAppData && connectionState == cs_DATA) {
! return volume;
! } // otherwise, need to read more for app data.
! }
+ // continue to read more net data
+ } // while
+
+ //
+ // couldn't read, due to some kind of error
+ //
+ return -1;
+ } // readLock synchronization
+ }
+
/*
+ * Process the plainText input record.
+ */
+ private synchronized int processInputRecord(
+ Plaintext plainText, boolean needAppData) throws IOException {
+
+ /*
* Process the record.
*/
! int volume = 0; // no application data
! switch (plainText.contentType) {
case Record.ct_handshake:
/*
* Handshake messages always go to a pending session
* handshaker ... if there isn't one, create one. This
* must work asynchronously, for renegotiation.
*** 1046,1061 ****
* a partial handshake message or multiple messages.
*
* The handshaker state machine will ensure that it's
* a finished message.
*/
! handshaker.process_record(r, expectingFinished);
expectingFinished = false;
if (handshaker.invalidated) {
handshaker = null;
! receivedCCS = false;
// if state is cs_RENEGOTIATE, revert it to cs_DATA
if (connectionState == cs_RENEGOTIATE) {
connectionState = cs_DATA;
}
} else if (handshaker.isDone()) {
--- 1084,1101 ----
* a partial handshake message or multiple messages.
*
* The handshaker state machine will ensure that it's
* a finished message.
*/
! handshaker.processRecord(plainText.fragment, expectingFinished);
expectingFinished = false;
if (handshaker.invalidated) {
handshaker = null;
! inputRecord.setHandshakeHash(null);
! outputRecord.setHandshakeHash(null);
!
// if state is cs_RENEGOTIATE, revert it to cs_DATA
if (connectionState == cs_RENEGOTIATE) {
connectionState = cs_DATA;
}
} else if (handshaker.isDone()) {
*** 1066,1101 ****
serverVerifyData = handshaker.getServerVerifyData();
sess = handshaker.getSession();
handshakeSession = null;
handshaker = null;
connectionState = cs_DATA;
- receivedCCS = false;
//
// Tell folk about handshake completion, but do
// it in a separate thread.
//
if (handshakeListeners != null) {
HandshakeCompletedEvent event =
new HandshakeCompletedEvent(this, sess);
! Thread t = new ManagedLocalsThread(
new NotifyHandshake(
handshakeListeners.entrySet(), event),
"HandshakeCompletedNotify-Thread");
! t.start();
}
}
- if (needAppData || connectionState != cs_DATA) {
- continue;
- }
break;
case Record.ct_application_data:
- // Pass this right back up to the application.
if (connectionState != cs_DATA
&& connectionState != cs_RENEGOTIATE
&& connectionState != cs_SENT_CLOSE) {
throw new SSLProtocolException(
"Data received in non-data state: " +
--- 1106,1138 ----
serverVerifyData = handshaker.getServerVerifyData();
sess = handshaker.getSession();
handshakeSession = null;
handshaker = null;
+ inputRecord.setHandshakeHash(null);
+ outputRecord.setHandshakeHash(null);
connectionState = cs_DATA;
//
// Tell folk about handshake completion, but do
// it in a separate thread.
//
if (handshakeListeners != null) {
HandshakeCompletedEvent event =
new HandshakeCompletedEvent(this, sess);
! Thread thread = new ManagedLocalsThread(
new NotifyHandshake(
handshakeListeners.entrySet(), event),
"HandshakeCompletedNotify-Thread");
! thread.start();
}
}
break;
case Record.ct_application_data:
if (connectionState != cs_DATA
&& connectionState != cs_RENEGOTIATE
&& connectionState != cs_SENT_CLOSE) {
throw new SSLProtocolException(
"Data received in non-data state: " +
*** 1107,1167 ****
}
if (!needAppData) {
throw new SSLException("Discarding app data");
}
! r.setAppDataValid(true);
break;
case Record.ct_alert:
! recvAlert(r);
! continue;
case Record.ct_change_cipher_spec:
if ((connectionState != cs_HANDSHAKE
! && connectionState != cs_RENEGOTIATE)
! || !handshaker.sessionKeysCalculated()
! || receivedCCS) {
// 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);
! } 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,
// else it's a protocol violation. We force this
// to be checked by a minor tweak to the state
// machine.
//
! changeReadCiphers();
// next message MUST be a finished message
expectingFinished = true;
- continue;
default:
//
// TLS requires that unrecognized records be ignored.
//
if (debug != null && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
! ", Received record type: "
! + r.contentType());
}
! continue;
! } // switch
/*
* Check the sequence number state
*
* Note that in order to maintain the connection I/O
--- 1144,1209 ----
}
if (!needAppData) {
throw new SSLException("Discarding app data");
}
! volume = plainText.fragment.remaining();
break;
case Record.ct_alert:
! recvAlert(plainText.fragment);
! break;
case Record.ct_change_cipher_spec:
if ((connectionState != cs_HANDSHAKE
! && 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);
! } else if (plainText.fragment.remaining() != 1
! || plainText.fragment.get() != 1) {
// For structural/content issues with the CCS
fatal(Alerts.alert_unexpected_message,
"Malformed change cipher spec msg");
}
//
// The first message after a change_cipher_spec
// record MUST be a "Finished" handshake record,
// else it's a protocol violation. We force this
// to be checked by a minor tweak to the state
// machine.
//
! handshaker.receiveChangeCipherSpec();
!
! CipherBox readCipher;
! Authenticator readAuthenticator;
! try {
! readCipher = handshaker.newReadCipher();
! readAuthenticator = handshaker.newReadAuthenticator();
! } catch (GeneralSecurityException e) {
! // can't happen
! throw new SSLException("Algorithm missing: ", e);
! }
! inputRecord.changeReadCiphers(readAuthenticator, readCipher);
!
// next message MUST be a finished message
expectingFinished = true;
+ break;
+
default:
//
// TLS requires that unrecognized records be ignored.
//
if (debug != null && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
! ", Received record type: " + plainText.contentType);
}
! break;
! }
/*
* Check the sequence number state
*
* Note that in order to maintain the connection I/O
*** 1169,1251 ****
* record reading process. As we request renegotiation
* or close the connection for wrapped sequence number
* when there is enough sequence number space left to
* handle a few more records, so the sequence number
* of the last record cannot be wrapped.
- */
- if (connectionState < cs_ERROR) {
- checkSequenceNumber(readAuthenticator, r.contentType());
- }
-
- return;
- } // synchronized (this)
- }
-
- //
- // couldn't read, due to some kind of error
- //
- r.close();
- return;
- } // synchronized (readLock)
- }
-
- /**
- * Check the sequence number state
*
! * RFC 4346 states that, "Sequence numbers are of type uint64 and
! * may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS
! * implementation would need to wrap a sequence number, it must
! * renegotiate instead."
*/
! private void checkSequenceNumber(Authenticator authenticator, byte type)
! throws IOException {
!
/*
- * Don't bother to check the sequence number for error or
- * closed connections, or NULL MAC.
- */
- if (connectionState >= cs_ERROR || authenticator == MAC.NULL) {
- return;
- }
-
- /*
- * Conservatively, close the connection immediately when the
- * sequence number is close to overflow
- */
- if (authenticator.seqNumOverflow()) {
- /*
- * TLS protocols do not define a error alert for sequence
- * number overflow. We use handshake_failure error alert
- * for handshaking and bad_record_mac for other records.
- */
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(Thread.currentThread().getName() +
- ", sequence number extremely close to overflow " +
- "(2^64-1 packets). Closing connection.");
-
- }
-
- fatal(Alerts.alert_handshake_failure, "sequence number overflow");
- }
-
- /*
* Ask for renegotiation when need to renew sequence number.
*
* Don't bother to kickstart the renegotiation when the local is
* asking for it.
*/
- if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) {
if (debug != null && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
", request renegotiation " +
"to avoid sequence number overflow");
}
startHandshake();
}
}
//
// HANDSHAKE RELATED CODE
//
/**
--- 1211,1244 ----
* record reading process. As we request renegotiation
* or close the connection for wrapped sequence number
* when there is enough sequence number space left to
* handle a few more records, so the sequence number
* of the last record cannot be wrapped.
*
! * Don't bother to kickstart the renegotiation when the
! * local is asking for it.
*/
! if ((connectionState == cs_DATA) && inputRecord.seqNumIsHuge()) {
/*
* Ask for renegotiation when need to renew sequence number.
*
* Don't bother to kickstart the renegotiation when the local is
* asking for it.
*/
if (debug != null && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
", request renegotiation " +
"to avoid sequence number overflow");
}
startHandshake();
}
+
+ return volume;
}
+
//
// HANDSHAKE RELATED CODE
//
/**
*** 1321,1330 ****
--- 1314,1324 ----
enabledProtocols,
protocolVersion, connectionState == cs_HANDSHAKE,
secureRenegotiation, clientVerifyData, serverVerifyData);
handshaker.setSNIServerNames(serverNames);
}
+ handshaker.setMaximumPacketSize(maximumPacketSize);
handshaker.setEnabledCipherSuites(enabledCipherSuites);
handshaker.setEnableSessionCreation(enableSessionCreation);
}
/**
*** 1340,1375 ****
synchronized (handshakeLock) {
if (getConnectionState() == cs_HANDSHAKE) {
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.
*
! * Keep this local so that it goes out of scope and is
! * eventually GC'd.
*/
! if (inrec == null) {
! inrec = new InputRecord();
!
! /*
! * Grab the characteristics already assigned to
! * AppInputStream's InputRecord. Enable checking for
! * SSLv2 hellos on this first handshake.
! */
! inrec.setHandshakeHash(input.r.getHandshakeHash());
! inrec.setHelloVersion(input.r.getHelloVersion());
! inrec.enableFormatChecks();
}
-
- readRecord(inrec, false);
- inrec = null;
}
}
- }
/**
* Starts an SSL handshake on this connection.
*/
@Override
--- 1334,1352 ----
synchronized (handshakeLock) {
if (getConnectionState() == cs_HANDSHAKE) {
kickstartHandshake();
/*
! * All initial handshaking goes through this operation
! * until we have a valid SSL connection.
*
! * Handle handshake messages only, need no application data.
*/
! readRecord(false);
}
}
}
/**
* Starts an SSL handshake on this connection.
*/
@Override
*** 1480,1492 ****
if (connectionState == cs_HANDSHAKE) {
// initial handshake, no kickstart message to send
} else {
// we want to renegotiate, send hello request
handshaker.kickstart();
- // hello request is not included in the handshake
- // hashes, reset them
- handshaker.handshakeHash.reset();
}
}
}
}
--- 1457,1466 ----
*** 1545,1555 ****
// we are at EOF, write must throw Exception
throw new SocketException("Connection closed by remote host");
}
}
! protected void closeSocket() throws IOException {
if ((debug != null) && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
", called closeSocket()");
}
--- 1519,1529 ----
// we are at EOF, write must throw Exception
throw new SocketException("Connection closed by remote host");
}
}
! private void closeSocket() throws IOException {
if ((debug != null) && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
", called closeSocket()");
}
*** 1589,1598 ****
--- 1563,1589 ----
if ((debug != null) && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
", called close()");
}
closeInternal(true); // caller is initiating close
+
+ // Clearup the resources.
+ try {
+ synchronized (readLock) {
+ inputRecord.close();
+ }
+
+ writeLock.lock();
+ try {
+ outputRecord.close();
+ } finally {
+ writeLock.unlock();
+ }
+ } catch (IOException ioe) {
+ // ignore
+ }
+
setConnectionState(cs_APP_CLOSED);
}
/**
* Don't synchronize the whole method because waitForClose()
*** 1712,1734 ****
connectionState = (connectionState == cs_APP_CLOSED)
? cs_APP_CLOSED : cs_CLOSED;
// notify any threads waiting for the closing to finish
this.notifyAll();
}
! if (closeSocketCalled) {
! // Dispose of ciphers since we've closed socket
! disposeCiphers();
! }
if (cachedThrowable != null) {
/*
* Rethrow the error to the calling method
* The Throwable caught can only be an Error or RuntimeException
*/
! if (cachedThrowable instanceof Error)
! throw (Error) cachedThrowable;
! if (cachedThrowable instanceof RuntimeException)
! throw (RuntimeException) cachedThrowable;
}
}
}
/**
--- 1703,1723 ----
connectionState = (connectionState == cs_APP_CLOSED)
? cs_APP_CLOSED : cs_CLOSED;
// notify any threads waiting for the closing to finish
this.notifyAll();
}
!
if (cachedThrowable != null) {
/*
* Rethrow the error to the calling method
* The Throwable caught can only be an Error or RuntimeException
*/
! if (cachedThrowable instanceof Error) {
! throw (Error)cachedThrowable;
! } else if (cachedThrowable instanceof RuntimeException) {
! throw (RuntimeException)cachedThrowable;
! } // Otherwise, unlikely
}
}
}
/**
*** 1748,1770 ****
try {
int state;
while (((state = getConnectionState()) != cs_CLOSED) &&
(state != cs_ERROR) && (state != cs_APP_CLOSED)) {
- // create the InputRecord if it isn't initialized.
- if (inrec == null) {
- inrec = new InputRecord();
- }
// Ask for app data and then throw it away
try {
! readRecord(inrec, true);
} catch (SocketTimeoutException e) {
// if time out, ignore the exception and continue
}
}
- inrec = null;
} catch (IOException e) {
if (debug != null && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
", Exception while waiting for close " +e);
}
--- 1737,1754 ----
try {
int state;
while (((state = getConnectionState()) != cs_CLOSED) &&
(state != cs_ERROR) && (state != cs_APP_CLOSED)) {
// Ask for app data and then throw it away
try {
! readRecord(true);
} catch (SocketTimeoutException e) {
// if time out, ignore the exception and continue
}
}
} catch (IOException e) {
if (debug != null && Debug.isOn("ssl")) {
System.out.println(Thread.currentThread().getName() +
", Exception while waiting for close " +e);
}
*** 1772,1799 ****
throw e; // pass exception up
}
}
}
- /**
- * Called by closeInternal() only. Be sure to consider the
- * synchronization locks carefully before calling it elsewhere.
- */
- private void disposeCiphers() {
- // See comment in changeReadCiphers()
- synchronized (readLock) {
- readCipher.dispose();
- }
- // See comment in changeReadCiphers()
- writeLock.lock();
- try {
- writeCipher.dispose();
- } finally {
- writeLock.unlock();
- }
- }
-
//
// EXCEPTION AND ALERT HANDLING
//
/**
--- 1756,1765 ----
*** 1851,1861 ****
}
}
// need to perform error shutdown
boolean isSSLException = (e instanceof SSLException);
! if ((isSSLException == false) && (e instanceof IOException)) {
// IOException from the socket
// this means the TCP connection is already dead
// we call fatal just to set the error status
try {
fatal(Alerts.alert_unexpected_message, e);
--- 1817,1827 ----
}
}
// need to perform error shutdown
boolean isSSLException = (e instanceof SSLException);
! if ((!isSSLException) && (e instanceof IOException)) {
// IOException from the socket
// this means the TCP connection is already dead
// we call fatal just to set the error status
try {
fatal(Alerts.alert_unexpected_message, e);
*** 1901,1913 ****
* Send a fatal alert, and throw an exception so that callers will
* need to stand on their heads to accidentally continue processing.
*/
synchronized void fatal(byte description, String diagnostic,
Throwable cause) throws IOException {
! if ((input != null) && (input.r != null)) {
! input.r.close();
}
sess.invalidate();
if (handshakeSession != null) {
handshakeSession.invalidate();
}
--- 1867,1884 ----
* Send a fatal alert, and throw an exception so that callers will
* need to stand on their heads to accidentally continue processing.
*/
synchronized void fatal(byte description, String diagnostic,
Throwable cause) throws IOException {
!
! // Be care of deadlock. Please don't synchronize readLock.
! try {
! inputRecord.close();
! } catch (IOException ioe) {
! // ignore
}
+
sess.invalidate();
if (handshakeSession != null) {
handshakeSession.invalidate();
}
*** 1943,1961 ****
/*
* Clean up our side.
*/
closeSocket();
- // Another thread may have disposed the ciphers during closing
- if (connectionState < cs_CLOSED) {
- connectionState = (oldState == cs_APP_CLOSED) ? cs_APP_CLOSED
- : cs_CLOSED;
! // We should lock readLock and writeLock if no deadlock risks.
! // See comment in changeReadCiphers()
! readCipher.dispose();
! writeCipher.dispose();
}
throw closeReason;
}
--- 1914,1929 ----
/*
* Clean up our side.
*/
closeSocket();
! // Be care of deadlock. Please don't synchronize writeLock.
! try {
! outputRecord.close();
! } catch (IOException ioe) {
! // ignore
}
throw closeReason;
}
*** 1962,1974 ****
/*
* Process an incoming alert ... caller must already have synchronized
* access to "this".
*/
! private void recvAlert(InputRecord r) throws IOException {
! byte level = (byte)r.read();
! byte description = (byte)r.read();
if (description == -1) { // check for short message
fatal(Alerts.alert_illegal_parameter, "Short alert message");
}
if (debug != null && (Debug.isOn("record") ||
--- 1930,1943 ----
/*
* Process an incoming alert ... caller must already have synchronized
* access to "this".
*/
! private void recvAlert(ByteBuffer fragment) throws IOException {
! byte level = fragment.get();
! byte description = fragment.get();
!
if (description == -1) { // check for short message
fatal(Alerts.alert_illegal_parameter, "Short alert message");
}
if (debug != null && (Debug.isOn("record") ||
*** 2027,2044 ****
return;
}
// For initial handshaking, don't send alert message to peer if
// handshaker has not started.
! if (connectionState == cs_HANDSHAKE &&
! (handshaker == null || !handshaker.started())) {
return;
}
- OutputRecord r = new OutputRecord(Record.ct_alert);
- r.setVersion(protocolVersion);
-
boolean useDebug = debug != null && Debug.isOn("ssl");
if (useDebug) {
synchronized (System.out) {
System.out.print(Thread.currentThread().getName());
System.out.print(", SEND " + protocolVersion + " ALERT: ");
--- 1996,2013 ----
return;
}
// For initial handshaking, don't send alert message to peer if
// handshaker has not started.
! //
! // Shall we send an fatal alter to terminate the connection gracefully?
! if (connectionState <= cs_HANDSHAKE &&
! (handshaker == null || !handshaker.started() ||
! !handshaker.activated())) {
return;
}
boolean useDebug = debug != null && Debug.isOn("ssl");
if (useDebug) {
synchronized (System.out) {
System.out.print(Thread.currentThread().getName());
System.out.print(", SEND " + protocolVersion + " ALERT: ");
*** 2052,2065 ****
System.out.println("description = "
+ Alerts.alertDescription(description));
}
}
- r.write(level);
- r.write(description);
try {
! writeRecord(r);
} catch (IOException e) {
if (useDebug) {
System.out.println(Thread.currentThread().getName() +
", Exception sending alert: " + e);
}
--- 2021,2032 ----
System.out.println("description = "
+ Alerts.alertDescription(description));
}
}
try {
! writeAlert(level, description);
} catch (IOException e) {
if (useDebug) {
System.out.println(Thread.currentThread().getName() +
", Exception sending alert: " + e);
}
*** 2068,2154 ****
//
// VARIOUS OTHER METHODS
//
- /*
- * When a connection finishes handshaking by enabling use of a newly
- * negotiated session, each end learns about it in two halves (read,
- * and write). When both read and write ciphers have changed, and the
- * last handshake message has been read, the connection has joined
- * (rejoined) the new session.
- *
- * NOTE: The SSLv3 spec is rather unclear on the concepts here.
- * Sessions don't change once they're established (including cipher
- * suite and master secret) but connections can join them (and leave
- * them). They're created by handshaking, though sometime handshaking
- * causes connections to join up with pre-established sessions.
- */
- 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 {
- readCipher = handshaker.newReadCipher();
- readAuthenticator = handshaker.newReadAuthenticator();
- } catch (GeneralSecurityException e) {
- // "can't happen"
- throw new SSLException("Algorithm missing: ", e);
- }
-
- /*
- * Dispose of any intermediate state in the underlying cipher.
- * For PKCS11 ciphers, this will release any attached sessions,
- * and thus make finalization faster.
- *
- * Since MAC's doFinal() is called for every SSL/TLS packet, it's
- * not necessary to do the same with MAC's.
- */
- oldCipher.dispose();
- }
-
// used by Handshaker
! void changeWriteCiphers() throws SSLException {
! if (connectionState != cs_HANDSHAKE
! && connectionState != cs_RENEGOTIATE) {
! throw new SSLProtocolException(
! "State error, change cipher specs");
! }
!
! // ... create compressor
!
! CipherBox oldCipher = writeCipher;
!
try {
writeCipher = handshaker.newWriteCipher();
writeAuthenticator = handshaker.newWriteAuthenticator();
} catch (GeneralSecurityException e) {
// "can't happen"
throw new SSLException("Algorithm missing: ", e);
}
!
! // See comment above.
! oldCipher.dispose();
!
! // reset the flag of the first application record
! isFirstAppOutputRecord = true;
}
/*
* Updates the SSL version associated with this connection.
* Called from Handshaker once it has determined the negotiated version.
*/
synchronized void setVersion(ProtocolVersion protocolVersion) {
this.protocolVersion = protocolVersion;
! output.r.setVersion(protocolVersion);
}
synchronized String getHost() {
// Note that the host may be null or empty for localhost.
if (host == null || host.length() == 0) {
--- 2035,2065 ----
//
// VARIOUS OTHER METHODS
//
// used by Handshaker
! void changeWriteCiphers() throws IOException {
! Authenticator writeAuthenticator;
! CipherBox writeCipher;
try {
writeCipher = handshaker.newWriteCipher();
writeAuthenticator = handshaker.newWriteAuthenticator();
} catch (GeneralSecurityException e) {
// "can't happen"
throw new SSLException("Algorithm missing: ", e);
}
! outputRecord.changeWriteCiphers(writeAuthenticator, writeCipher);
}
/*
* Updates the SSL version associated with this connection.
* Called from Handshaker once it has determined the negotiated version.
*/
synchronized void setVersion(ProtocolVersion protocolVersion) {
this.protocolVersion = protocolVersion;
! outputRecord.setVersion(protocolVersion);
}
synchronized String getHost() {
// Note that the host may be null or empty for localhost.
if (host == null || host.length() == 0) {
*** 2243,2252 ****
--- 2154,2167 ----
synchronized public SSLSession getHandshakeSession() {
return handshakeSession;
}
synchronized void setHandshakeSession(SSLSessionImpl session) {
+ // update the fragment size, which may be negotiated during handshaking
+ inputRecord.changeFragmentSize(session.getNegotiatedMaxFragSize());
+ outputRecord.changeFragmentSize(session.getNegotiatedMaxFragSize());
+
handshakeSession = session;
}
/**
* Controls whether new connections may cause creation of new SSL
*** 2283,2294 ****
* whether client authentication is needed. Otherwise,
* we will need to wait for the next handshake.
*/
@Override
synchronized public void setNeedClientAuth(boolean flag) {
! doClientAuth = (flag ?
! SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none);
if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) &&
!handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
--- 2198,2209 ----
* whether client authentication is needed. Otherwise,
* we will need to wait for the next handshake.
*/
@Override
synchronized public void setNeedClientAuth(boolean flag) {
! doClientAuth = (flag ? ClientAuthType.CLIENT_AUTH_REQUIRED :
! ClientAuthType.CLIENT_AUTH_NONE);
if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) &&
!handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
*** 2295,2305 ****
}
}
@Override
synchronized public boolean getNeedClientAuth() {
! return (doClientAuth == SSLEngineImpl.clauth_required);
}
/**
* Sets the flag controlling whether a server mode socket
* *REQUESTS* SSL client authentication.
--- 2210,2220 ----
}
}
@Override
synchronized public boolean getNeedClientAuth() {
! return (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED);
}
/**
* Sets the flag controlling whether a server mode socket
* *REQUESTS* SSL client authentication.
*** 2308,2319 ****
* whether client authentication is requested. Otherwise,
* we will need to wait for the next handshake.
*/
@Override
synchronized public void setWantClientAuth(boolean flag) {
! doClientAuth = (flag ?
! SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none);
if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) &&
!handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
--- 2223,2234 ----
* whether client authentication is requested. Otherwise,
* we will need to wait for the next handshake.
*/
@Override
synchronized public void setWantClientAuth(boolean flag) {
! doClientAuth = (flag ? ClientAuthType.CLIENT_AUTH_REQUESTED :
! ClientAuthType.CLIENT_AUTH_NONE);
if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) &&
!handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
*** 2320,2330 ****
}
}
@Override
synchronized public boolean getWantClientAuth() {
! return (doClientAuth == SSLEngineImpl.clauth_requested);
}
/**
* Sets the flag controlling whether the socket is in SSL
--- 2235,2245 ----
}
}
@Override
synchronized public boolean getWantClientAuth() {
! return (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUESTED);
}
/**
* Sets the flag controlling whether the socket is in SSL
*** 2337,2353 ****
switch (connectionState) {
case cs_START:
/*
* If we need to change the socket mode and the enabled
! * protocols haven't specifically been set by the user,
! * change them to the corresponding default ones.
*/
! if (roleIsServer != (!flag) &&
! sslContext.isDefaultProtocolList(enabledProtocols)) {
! enabledProtocols = sslContext.getDefaultProtocolList(!flag);
}
roleIsServer = !flag;
break;
case cs_HANDSHAKE:
/*
--- 2252,2277 ----
switch (connectionState) {
case cs_START:
/*
* If we need to change the socket mode and the enabled
! * protocols and cipher suites haven't specifically been
! * set by the user, change them to the corresponding
! * default ones.
*/
! if (roleIsServer != (!flag)) {
! if (sslContext.isDefaultProtocolList(enabledProtocols)) {
! enabledProtocols =
! sslContext.getDefaultProtocolList(!flag);
}
+
+ if (sslContext.isDefaultCipherSuiteList(enabledCipherSuites)) {
+ enabledCipherSuites =
+ sslContext.getDefaultCipherSuiteList(!flag);
+ }
+ }
+
roleIsServer = !flag;
break;
case cs_HANDSHAKE:
/*
*** 2359,2375 ****
*/
assert(handshaker != null);
if (!handshaker.activated()) {
/*
* If we need to change the socket mode and the enabled
! * protocols haven't specifically been set by the user,
! * change them to the corresponding default ones.
*/
! if (roleIsServer != (!flag) &&
! sslContext.isDefaultProtocolList(enabledProtocols)) {
! enabledProtocols = sslContext.getDefaultProtocolList(!flag);
}
roleIsServer = !flag;
connectionState = cs_START;
initHandshaker();
break;
}
--- 2283,2309 ----
*/
assert(handshaker != null);
if (!handshaker.activated()) {
/*
* If we need to change the socket mode and the enabled
! * protocols and cipher suites haven't specifically been
! * set by the user, change them to the corresponding
! * default ones.
*/
! if (roleIsServer != (!flag)) {
! if (sslContext.isDefaultProtocolList(enabledProtocols)) {
! enabledProtocols =
! sslContext.getDefaultProtocolList(!flag);
}
+
+ if (sslContext.isDefaultCipherSuiteList(
+ enabledCipherSuites)) {
+ enabledCipherSuites =
+ sslContext.getDefaultCipherSuiteList(!flag);
+ }
+ }
+
roleIsServer = !flag;
connectionState = cs_START;
initHandshaker();
break;
}
*** 2533,2543 ****
--- 2467,2480 ----
params.setEndpointIdentificationAlgorithm(identificationProtocol);
params.setAlgorithmConstraints(algorithmConstraints);
params.setSNIMatchers(sniMatchers);
params.setServerNames(serverNames);
params.setUseCipherSuitesOrder(preferLocalCipherSuites);
+ params.setMaximumPacketSize(maximumPacketSize);
+ // DTLS handshake retransmissions parameter does not apply here.
+
return params;
}
/**
* Applies SSLParameters to this socket.
*** 2548,2558 ****
--- 2485,2505 ----
// the super implementation does not handle the following parameters
identificationProtocol = params.getEndpointIdentificationAlgorithm();
algorithmConstraints = params.getAlgorithmConstraints();
preferLocalCipherSuites = params.getUseCipherSuitesOrder();
+ maximumPacketSize = params.getMaximumPacketSize();
+ // DTLS handshake retransmissions parameter does not apply here.
+
+ if (maximumPacketSize != 0) {
+ outputRecord.changePacketSize(maximumPacketSize);
+ } else {
+ // use the implicit maximum packet size.
+ maximumPacketSize = outputRecord.getMaxPacketSize();
+ }
+
List<SNIServerName> sniNames = params.getServerNames();
if (sniNames != null) {
serverNames = sniNames;
}
*** 2562,2571 ****
--- 2509,2519 ----
}
if ((handshaker != null) && !handshaker.started()) {
handshaker.setIdentificationProtocol(identificationProtocol);
handshaker.setAlgorithmConstraints(algorithmConstraints);
+ handshaker.setMaximumPacketSize(maximumPacketSize);
if (roleIsServer) {
handshaker.setSNIMatchers(sniMatchers);
handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
} else {
handshaker.setSNIServerNames(serverNames);
*** 2609,2626 ****
}, acc);
}
}
}
- /**
- * 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.
*/
@Override
public String toString() {
--- 2557,2566 ----