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 ----