Home | History | Annotate | Download | only in conscrypt
      1 /*
      2  * Copyright 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package org.conscrypt;
     18 
     19 import static javax.net.ssl.SSLEngineResult.Status.OK;
     20 import static org.conscrypt.SSLUtils.EngineStates.STATE_CLOSED;
     21 import static org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_COMPLETED;
     22 import static org.conscrypt.SSLUtils.EngineStates.STATE_HANDSHAKE_STARTED;
     23 import static org.conscrypt.SSLUtils.EngineStates.STATE_NEW;
     24 import static org.conscrypt.SSLUtils.EngineStates.STATE_READY;
     25 import static org.conscrypt.SSLUtils.EngineStates.STATE_READY_HANDSHAKE_CUT_THROUGH;
     26 
     27 import java.io.EOFException;
     28 import java.io.IOException;
     29 import java.io.InputStream;
     30 import java.io.OutputStream;
     31 import java.net.InetAddress;
     32 import java.net.Socket;
     33 import java.net.SocketException;
     34 import java.nio.ByteBuffer;
     35 import java.security.PrivateKey;
     36 import javax.net.ssl.SSLEngineResult;
     37 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
     38 import javax.net.ssl.SSLException;
     39 import javax.net.ssl.SSLParameters;
     40 import javax.net.ssl.SSLSession;
     41 
     42 /**
     43  * Implements crypto handling by delegating to {@link ConscryptEngine}.
     44  */
     45 class ConscryptEngineSocket extends OpenSSLSocketImpl {
     46     private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
     47 
     48     private final ConscryptEngine engine;
     49     private final Object stateLock = new Object();
     50     private final Object handshakeLock = new Object();
     51 
     52     private SSLOutputStream out;
     53     private SSLInputStream in;
     54 
     55     // @GuardedBy("stateLock");
     56     private int state = STATE_NEW;
     57 
     58     // The constructors should not be called except from the Platform class, because we may
     59     // want to construct a subclass instead.
     60     ConscryptEngineSocket(SSLParametersImpl sslParameters) throws IOException {
     61         engine = newEngine(sslParameters, this);
     62     }
     63 
     64     ConscryptEngineSocket(String hostname, int port, SSLParametersImpl sslParameters)
     65             throws IOException {
     66         super(hostname, port);
     67         engine = newEngine(sslParameters, this);
     68     }
     69 
     70     ConscryptEngineSocket(InetAddress address, int port, SSLParametersImpl sslParameters)
     71             throws IOException {
     72         super(address, port);
     73         engine = newEngine(sslParameters, this);
     74     }
     75 
     76     ConscryptEngineSocket(String hostname, int port, InetAddress clientAddress, int clientPort,
     77             SSLParametersImpl sslParameters) throws IOException {
     78         super(hostname, port, clientAddress, clientPort);
     79         engine = newEngine(sslParameters, this);
     80     }
     81 
     82     ConscryptEngineSocket(InetAddress address, int port, InetAddress clientAddress, int clientPort,
     83             SSLParametersImpl sslParameters) throws IOException {
     84         super(address, port, clientAddress, clientPort);
     85         engine = newEngine(sslParameters, this);
     86     }
     87 
     88     ConscryptEngineSocket(Socket socket, String hostname, int port, boolean autoClose,
     89             SSLParametersImpl sslParameters) throws IOException {
     90         super(socket, hostname, port, autoClose);
     91         engine = newEngine(sslParameters, this);
     92     }
     93 
     94     private static ConscryptEngine newEngine(
     95             SSLParametersImpl sslParameters, final ConscryptEngineSocket socket) {
     96         ConscryptEngine engine = new ConscryptEngine(sslParameters, socket.peerInfoProvider());
     97 
     98         // When the handshake completes, notify any listeners.
     99         engine.setHandshakeListener(new HandshakeListener() {
    100             /**
    101              * Protected by {@code stateLock}
    102              */
    103             @Override
    104             public void onHandshakeFinished() {
    105                 // Just call the outer class method.
    106                 socket.onHandshakeFinished();
    107             }
    108         });
    109 
    110         // Transition the engine state to MODE_SET
    111         engine.setUseClientMode(sslParameters.getUseClientMode());
    112         return engine;
    113     }
    114 
    115     @Override
    116     public final SSLParameters getSSLParameters() {
    117         return engine.getSSLParameters();
    118     }
    119 
    120     @Override
    121     public final void setSSLParameters(SSLParameters sslParameters) {
    122         engine.setSSLParameters(sslParameters);
    123     }
    124 
    125     @Override
    126     public final void startHandshake() throws IOException {
    127         checkOpen();
    128 
    129         try {
    130             synchronized (handshakeLock) {
    131                 // Only lock stateLock when we begin the handshake. This is done so that we don't
    132                 // hold the stateLock when we invoke the handshake completion listeners.
    133                 synchronized (stateLock) {
    134                     // Initialize the handshake if we haven't already.
    135                     if (state == STATE_NEW) {
    136                         state = STATE_HANDSHAKE_STARTED;
    137                         engine.beginHandshake();
    138                         in = new SSLInputStream();
    139                         out = new SSLOutputStream();
    140                     } else {
    141                         // We've either started the handshake already or have been closed.
    142                         // Do nothing in both cases.
    143                         //
    144                         // NOTE: BoringSSL does not support initiating renegotiation, so we always
    145                         // ignore addition handshake calls.
    146                         return;
    147                     }
    148                 }
    149 
    150                 doHandshake();
    151             }
    152         } catch (SSLException e) {
    153             close();
    154             throw e;
    155         } catch (IOException e) {
    156             close();
    157             throw e;
    158         } catch (Exception e) {
    159             close();
    160             // Convert anything else to a handshake exception.
    161             throw SSLUtils.toSSLHandshakeException(e);
    162         }
    163     }
    164 
    165     private void doHandshake() throws IOException {
    166         try {
    167             boolean finished = false;
    168             while (!finished) {
    169                 switch (engine.getHandshakeStatus()) {
    170                     case NEED_UNWRAP:
    171                         if (in.readInternal(EmptyArray.BYTE, 0, 0) < 0) {
    172                             // Can't complete the handshake due to EOF.
    173                             throw SSLUtils.toSSLHandshakeException(new EOFException());
    174                         }
    175                         break;
    176                     case NEED_WRAP: {
    177                         out.writeInternal(EMPTY_BUFFER);
    178                         // Always flush handshake frames immediately.
    179                         out.flushInternal();
    180                         break;
    181                     }
    182                     case NEED_TASK: {
    183                         // Should never get here, since our engine never provides tasks.
    184                         throw new IllegalStateException("Engine tasks are unsupported");
    185                     }
    186                     case NOT_HANDSHAKING:
    187                     case FINISHED: {
    188                         // Handshake is complete.
    189                         finished = true;
    190                         break;
    191                     }
    192                     default: {
    193                         throw new IllegalStateException(
    194                             "Unknown handshake status: " + engine.getHandshakeStatus());
    195                     }
    196                 }
    197             }
    198         } catch (SSLException e) {
    199             close();
    200             throw e;
    201         } catch (IOException e) {
    202             close();
    203             throw e;
    204         } catch (Exception e) {
    205             close();
    206             // Convert anything else to a handshake exception.
    207             throw SSLUtils.toSSLHandshakeException(e);
    208         }
    209     }
    210 
    211     @Override
    212     public final InputStream getInputStream() throws IOException {
    213         checkOpen();
    214 
    215         // Block waiting for a handshake without a lock held. It's possible that the socket
    216         // is closed at this point. If that happens, we'll still return the input stream but
    217         // all reads on it will throw.
    218         waitForHandshake();
    219         return in;
    220     }
    221 
    222     @Override
    223     public final OutputStream getOutputStream() throws IOException {
    224         checkOpen();
    225 
    226         // Block waiting for a handshake without a lock held. It's possible that the socket
    227         // is closed at this point. If that happens, we'll still return the input stream but
    228         // all reads on it will throw.
    229         waitForHandshake();
    230 
    231         return out;
    232     }
    233 
    234     @Override
    235     public final SSLSession getHandshakeSession() {
    236         return engine.handshakeSession();
    237     }
    238 
    239     @Override
    240     public final SSLSession getSession() {
    241         SSLSession session = engine.getSession();
    242         if (SSLNullSession.isNullSession(session)) {
    243             boolean handshakeCompleted = false;
    244             try {
    245                 if (isConnected()) {
    246                     waitForHandshake();
    247                     handshakeCompleted = true;
    248                 }
    249             } catch (IOException e) {
    250                 // Fall through.
    251             }
    252 
    253             if (!handshakeCompleted) {
    254                 // Return an invalid session with invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
    255                 return session;
    256             }
    257             session = engine.getSession();
    258         }
    259         return session;
    260     }
    261 
    262     @Override
    263     final SSLSession getActiveSession() {
    264         return engine.getSession();
    265     }
    266 
    267     @Override
    268     public final boolean getEnableSessionCreation() {
    269         return engine.getEnableSessionCreation();
    270     }
    271 
    272     @Override
    273     public final void setEnableSessionCreation(boolean flag) {
    274         engine.setEnableSessionCreation(flag);
    275     }
    276 
    277     @Override
    278     public final String[] getSupportedCipherSuites() {
    279         return engine.getSupportedCipherSuites();
    280     }
    281 
    282     @Override
    283     public final String[] getEnabledCipherSuites() {
    284         return engine.getEnabledCipherSuites();
    285     }
    286 
    287     @Override
    288     public final void setEnabledCipherSuites(String[] suites) {
    289         engine.setEnabledCipherSuites(suites);
    290     }
    291 
    292     @Override
    293     public final String[] getSupportedProtocols() {
    294         return engine.getSupportedProtocols();
    295     }
    296 
    297     @Override
    298     public final String[] getEnabledProtocols() {
    299         return engine.getEnabledProtocols();
    300     }
    301 
    302     @Override
    303     public final void setEnabledProtocols(String[] protocols) {
    304         engine.setEnabledProtocols(protocols);
    305     }
    306 
    307     /**
    308      * This method enables Server Name Indication
    309      *
    310      * @param hostname the desired SNI hostname, or null to disable
    311      */
    312     @Override
    313     public final void setHostname(String hostname) {
    314         engine.setHostname(hostname);
    315         super.setHostname(hostname);
    316     }
    317 
    318     @Override
    319     public final void setUseSessionTickets(boolean useSessionTickets) {
    320         engine.setUseSessionTickets(useSessionTickets);
    321     }
    322 
    323     @Override
    324     public final void setChannelIdEnabled(boolean enabled) {
    325         engine.setChannelIdEnabled(enabled);
    326     }
    327 
    328     @Override
    329     public final byte[] getChannelId() throws SSLException {
    330         return engine.getChannelId();
    331     }
    332 
    333     @Override
    334     public final void setChannelIdPrivateKey(PrivateKey privateKey) {
    335         engine.setChannelIdPrivateKey(privateKey);
    336     }
    337 
    338     @Override
    339     byte[] getTlsUnique() {
    340         return engine.getTlsUnique();
    341     }
    342 
    343     @Override
    344     public final boolean getUseClientMode() {
    345         return engine.getUseClientMode();
    346     }
    347 
    348     @Override
    349     public final void setUseClientMode(boolean mode) {
    350         engine.setUseClientMode(mode);
    351     }
    352 
    353     @Override
    354     public final boolean getWantClientAuth() {
    355         return engine.getWantClientAuth();
    356     }
    357 
    358     @Override
    359     public final boolean getNeedClientAuth() {
    360         return engine.getNeedClientAuth();
    361     }
    362 
    363     @Override
    364     public final void setNeedClientAuth(boolean need) {
    365         engine.setNeedClientAuth(need);
    366     }
    367 
    368     @Override
    369     public final void setWantClientAuth(boolean want) {
    370         engine.setWantClientAuth(want);
    371     }
    372 
    373     @Override
    374     @SuppressWarnings("UnsynchronizedOverridesSynchronized")
    375     public final void close() throws IOException {
    376         // TODO: Close SSL sockets using a background thread so they close gracefully.
    377 
    378         if (stateLock == null) {
    379             // close() has been called before we've initialized the socket, so just
    380             // return.
    381             return;
    382         }
    383 
    384         synchronized (stateLock) {
    385             if (state == STATE_CLOSED) {
    386                 // close() has already been called, so do nothing and return.
    387                 return;
    388             }
    389 
    390             state = STATE_CLOSED;
    391 
    392             stateLock.notifyAll();
    393         }
    394 
    395         // Close the underlying socket.
    396         super.close();
    397 
    398         // Close the engine.
    399         engine.closeInbound();
    400         engine.closeOutbound();
    401     }
    402 
    403     @Override
    404     final void setApplicationProtocols(String[] protocols) {
    405         engine.setApplicationProtocols(protocols);
    406     }
    407 
    408     @Override
    409     final String[] getApplicationProtocols() {
    410         return engine.getApplicationProtocols();
    411     }
    412 
    413     @Override
    414     public final String getApplicationProtocol() {
    415         return engine.getApplicationProtocol();
    416     }
    417 
    418     @Override
    419     public final String getHandshakeApplicationProtocol() {
    420         return engine.getHandshakeApplicationProtocol();
    421     }
    422 
    423     @Override
    424     public final void setApplicationProtocolSelector(ApplicationProtocolSelector selector) {
    425         setApplicationProtocolSelector(
    426                 selector == null ? null : new ApplicationProtocolSelectorAdapter(this, selector));
    427     }
    428 
    429     @Override
    430     final void setApplicationProtocolSelector(ApplicationProtocolSelectorAdapter selector) {
    431         engine.setApplicationProtocolSelector(selector);
    432     }
    433 
    434     private void onHandshakeFinished() {
    435         boolean notify = false;
    436         synchronized (stateLock) {
    437             if (state != STATE_CLOSED) {
    438                 if (state == STATE_HANDSHAKE_STARTED) {
    439                     state = STATE_READY_HANDSHAKE_CUT_THROUGH;
    440                 } else if (state == STATE_HANDSHAKE_COMPLETED) {
    441                     state = STATE_READY;
    442                 }
    443 
    444                 // Unblock threads that are waiting for our state to transition
    445                 // into STATE_READY or STATE_READY_HANDSHAKE_CUT_THROUGH.
    446                 stateLock.notifyAll();
    447                 notify = true;
    448             }
    449         }
    450 
    451         if (notify) {
    452             notifyHandshakeCompletedListeners();
    453         }
    454     }
    455 
    456     /**
    457      * Waits for the handshake to complete.
    458      */
    459     private void waitForHandshake() throws IOException {
    460         startHandshake();
    461 
    462         synchronized (stateLock) {
    463             while (state != STATE_READY && state != STATE_READY_HANDSHAKE_CUT_THROUGH
    464                     && state != STATE_CLOSED) {
    465                 try {
    466                     stateLock.wait();
    467                 } catch (InterruptedException e) {
    468                     Thread.currentThread().interrupt();
    469                     throw new IOException("Interrupted waiting for handshake", e);
    470                 }
    471             }
    472 
    473             if (state == STATE_CLOSED) {
    474                 throw new SocketException("Socket is closed");
    475             }
    476         }
    477     }
    478 
    479     private OutputStream getUnderlyingOutputStream() throws IOException {
    480         return super.getOutputStream();
    481     }
    482 
    483     private InputStream getUnderlyingInputStream() throws IOException {
    484         return super.getInputStream();
    485     }
    486 
    487     /**
    488      * Wrap bytes written to the underlying socket.
    489      */
    490     private final class SSLOutputStream extends OutputStream {
    491         private final Object writeLock = new Object();
    492         private final ByteBuffer target;
    493         private final int targetArrayOffset;
    494         private OutputStream socketOutputStream;
    495 
    496         SSLOutputStream() {
    497             target = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
    498             targetArrayOffset = target.arrayOffset();
    499         }
    500 
    501         @Override
    502         public void close() throws IOException {
    503             ConscryptEngineSocket.this.close();
    504         }
    505 
    506         @Override
    507         public void write(int b) throws IOException {
    508             startHandshake();
    509             synchronized (writeLock) {
    510                 write(new byte[] {(byte) b});
    511             }
    512         }
    513 
    514         @Override
    515         public void write(byte[] b) throws IOException {
    516             startHandshake();
    517             synchronized (writeLock) {
    518                 writeInternal(ByteBuffer.wrap(b));
    519             }
    520         }
    521 
    522         @Override
    523         public void write(byte[] b, int off, int len) throws IOException {
    524             startHandshake();
    525             synchronized (writeLock) {
    526                 writeInternal(ByteBuffer.wrap(b, off, len));
    527             }
    528         }
    529 
    530         private void writeInternal(ByteBuffer buffer) throws IOException {
    531             Platform.blockGuardOnNetwork();
    532             checkOpen();
    533             init();
    534 
    535             // Need to loop through at least once to enable handshaking where no application
    536             // bytes are
    537             // processed.
    538             int len = buffer.remaining();
    539             SSLEngineResult engineResult;
    540             do {
    541                 target.clear();
    542                 engineResult = engine.wrap(buffer, target);
    543                 if (engineResult.getStatus() != OK) {
    544                     throw new SSLException("Unexpected engine result " + engineResult.getStatus());
    545                 }
    546                 if (target.position() != engineResult.bytesProduced()) {
    547                     throw new SSLException("Engine bytesProduced " + engineResult.bytesProduced()
    548                             + " does not match bytes written " + target.position());
    549                 }
    550                 len -= engineResult.bytesConsumed();
    551                 if (len != buffer.remaining()) {
    552                     throw new SSLException("Engine did not read the correct number of bytes");
    553                 }
    554 
    555                 target.flip();
    556 
    557                 // Write the data to the socket.
    558                 writeToSocket();
    559             } while (len > 0);
    560         }
    561 
    562         @Override
    563         public void flush() throws IOException {
    564             startHandshake();
    565             synchronized (writeLock) {
    566                 flushInternal();
    567             }
    568         }
    569 
    570         private void flushInternal() throws IOException {
    571             checkOpen();
    572             init();
    573             socketOutputStream.flush();
    574         }
    575 
    576         private void init() throws IOException {
    577             if (socketOutputStream == null) {
    578                 socketOutputStream = getUnderlyingOutputStream();
    579             }
    580         }
    581 
    582         private void writeToSocket() throws IOException {
    583             // Write the data to the socket.
    584             socketOutputStream.write(target.array(), targetArrayOffset, target.limit());
    585         }
    586     }
    587 
    588     /**
    589      * Unwrap bytes read from the underlying socket.
    590      */
    591     private final class SSLInputStream extends InputStream {
    592         private final Object readLock = new Object();
    593         private final byte[] singleByte = new byte[1];
    594         private final ByteBuffer fromEngine;
    595         private final ByteBuffer fromSocket;
    596         private final int fromSocketArrayOffset;
    597         private InputStream socketInputStream;
    598 
    599         SSLInputStream() {
    600             fromEngine = ByteBuffer.allocateDirect(engine.getSession().getApplicationBufferSize());
    601             // Initially fromEngine.remaining() == 0.
    602             fromEngine.flip();
    603             fromSocket = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
    604             fromSocketArrayOffset = fromSocket.arrayOffset();
    605         }
    606 
    607         @Override
    608         public void close() throws IOException {
    609             ConscryptEngineSocket.this.close();
    610         }
    611 
    612         @Override
    613         public int read() throws IOException {
    614             startHandshake();
    615             synchronized (readLock) {
    616                 // Handle returning of -1 if EOF is reached.
    617                 int count = read(singleByte, 0, 1);
    618                 if (count == -1) {
    619                     // Handle EOF.
    620                     return -1;
    621                 }
    622                 if (count != 1) {
    623                     throw new SSLException("read incorrect number of bytes " + count);
    624                 }
    625                 return (int) singleByte[0];
    626             }
    627         }
    628 
    629         @Override
    630         public int read(byte[] b) throws IOException {
    631             startHandshake();
    632             synchronized (readLock) {
    633                 return read(b, 0, b.length);
    634             }
    635         }
    636 
    637         @Override
    638         public int read(byte[] b, int off, int len) throws IOException {
    639             startHandshake();
    640             synchronized (readLock) {
    641                 return readInternal(b, off, len);
    642             }
    643         }
    644 
    645         @Override
    646         public int available() throws IOException {
    647             startHandshake();
    648             synchronized (readLock) {
    649                 init();
    650                 return fromEngine.remaining()
    651                         + (fromSocket.hasRemaining() || socketInputStream.available() > 0 ? 1 : 0);
    652             }
    653         }
    654 
    655         private boolean isHandshaking(HandshakeStatus status) {
    656             switch(status) {
    657                 case NEED_TASK:
    658                 case NEED_WRAP:
    659                 case NEED_UNWRAP:
    660                     return true;
    661                 default:
    662                     return false;
    663             }
    664         }
    665 
    666         private int readInternal(byte[] b, int off, int len) throws IOException {
    667             Platform.blockGuardOnNetwork();
    668             checkOpen();
    669 
    670             // Make sure the input stream has been created.
    671             init();
    672 
    673             for (;;) {
    674                 // Serve any remaining data from the engine first.
    675                 if (fromEngine.remaining() > 0) {
    676                     int readFromEngine = Math.min(fromEngine.remaining(), len);
    677                     fromEngine.get(b, off, readFromEngine);
    678                     return readFromEngine;
    679                 }
    680 
    681                 // Try to unwrap any data already in the socket buffer.
    682                 boolean needMoreDataFromSocket = true;
    683 
    684                 // Unwrap the unencrypted bytes into the engine buffer.
    685                 fromSocket.flip();
    686                 fromEngine.clear();
    687 
    688                 boolean engineHandshaking = isHandshaking(engine.getHandshakeStatus());
    689                 SSLEngineResult engineResult = engine.unwrap(fromSocket, fromEngine);
    690 
    691                 // Shift any remaining data to the beginning of the buffer so that
    692                 // we can accommodate the next full packet. After this is called,
    693                 // limit will be restored to capacity and position will point just
    694                 // past the end of the data.
    695                 fromSocket.compact();
    696                 fromEngine.flip();
    697 
    698                 switch (engineResult.getStatus()) {
    699                     case BUFFER_UNDERFLOW: {
    700                         if (engineResult.bytesProduced() == 0) {
    701                             // Need to read more data from the socket.
    702                             break;
    703                         }
    704                         // Also serve the data that was produced.
    705                         needMoreDataFromSocket = false;
    706                         break;
    707                     }
    708                     case OK: {
    709                         // We processed the entire packet successfully...
    710 
    711                         if (!engineHandshaking && isHandshaking(engineResult.getHandshakeStatus())
    712                             && isHandshakeFinished()) {
    713                             // The received packet is the beginning of a renegotiation handshake.
    714                             // Perform another handshake.
    715                             renegotiate();
    716                             return 0;
    717                         }
    718 
    719                         needMoreDataFromSocket = false;
    720                         break;
    721                     }
    722                     case CLOSED: {
    723                         // EOF
    724                         return -1;
    725                     }
    726                     default: {
    727                         // Anything else is an error.
    728                         throw new SSLException(
    729                                 "Unexpected engine result " + engineResult.getStatus());
    730                     }
    731                 }
    732 
    733                 if (!needMoreDataFromSocket && engineResult.bytesProduced() == 0) {
    734                     // Read successfully, but produced no data. Possibly part of a
    735                     // handshake.
    736                     return 0;
    737                 }
    738 
    739                 // Read more data from the socket.
    740                 if (needMoreDataFromSocket && readFromSocket() == -1) {
    741                     // Failed to read the next encrypted packet before reaching EOF.
    742                     return -1;
    743                 }
    744 
    745                 // Continue the loop and return the data from the engine buffer.
    746             }
    747         }
    748 
    749         private boolean isHandshakeFinished() {
    750             synchronized (stateLock) {
    751                 return state >= STATE_READY_HANDSHAKE_CUT_THROUGH;
    752             }
    753         }
    754 
    755         /**
    756          * Processes a renegotiation received from the remote peer.
    757          */
    758         private void renegotiate() throws IOException {
    759             synchronized (handshakeLock) {
    760                 doHandshake();
    761             }
    762         }
    763 
    764         private void init() throws IOException {
    765             if (socketInputStream == null) {
    766                 socketInputStream = getUnderlyingInputStream();
    767             }
    768         }
    769 
    770         private int readFromSocket() throws IOException {
    771             try {
    772                 // Read directly to the underlying array and increment the buffer position if
    773                 // appropriate.
    774                 int pos = fromSocket.position();
    775                 int lim = fromSocket.limit();
    776                 int read = socketInputStream.read(
    777                     fromSocket.array(), fromSocketArrayOffset + pos, lim - pos);
    778 
    779                 if (read > 0) {
    780                     fromSocket.position(pos + read);
    781                 }
    782                 return read;
    783             } catch (EOFException e) {
    784                 return -1;
    785             }
    786         }
    787     }
    788 }
    789