src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java
branchJDK-8145252-TLS13-branch
changeset 56542 56aaa6cb3693
parent 47216 71c04702a3d5
child 56694 aa54a1f8e426
equal deleted inserted replaced
56541:92cbbfc996f3 56542:56aaa6cb3693
     1 /*
     1 /*
     2  * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    25 
    25 
    26 package sun.security.ssl;
    26 package sun.security.ssl;
    27 
    27 
    28 import java.io.*;
    28 import java.io.*;
    29 import java.nio.*;
    29 import java.nio.*;
    30 
    30 import java.security.GeneralSecurityException;
       
    31 import java.util.ArrayList;
    31 import javax.crypto.BadPaddingException;
    32 import javax.crypto.BadPaddingException;
    32 
       
    33 import javax.net.ssl.*;
    33 import javax.net.ssl.*;
    34 
    34 import sun.security.ssl.SSLCipher.SSLReadCipher;
    35 import sun.security.util.HexDumpEncoder;
       
    36 
       
    37 
    35 
    38 /**
    36 /**
    39  * {@code InputRecord} implementation for {@code SSLSocket}.
    37  * {@code InputRecord} implementation for {@code SSLSocket}.
    40  *
    38  *
    41  * @author David Brownell
    39  * @author David Brownell
    42  */
    40  */
    43 final class SSLSocketInputRecord extends InputRecord implements SSLRecord {
    41 final class SSLSocketInputRecord extends InputRecord implements SSLRecord {
    44     private OutputStream deliverStream = null;
    42     private InputStream is = null;
    45     private byte[] temporary = new byte[1024];
    43     private OutputStream os = null;
       
    44     private final byte[] temporary = new byte[1024];
    46 
    45 
    47     // used by handshake hash computation for handshake fragment
    46     // used by handshake hash computation for handshake fragment
    48     private byte prevType = -1;
    47     private byte prevType = -1;
    49     private int hsMsgOff = 0;
    48     private int hsMsgOff = 0;
    50     private int hsMsgLen = 0;
    49     private int hsMsgLen = 0;
    51 
    50 
    52     private boolean formatVerified = false;     // SSLv2 ruled out?
    51     private boolean formatVerified = false;     // SSLv2 ruled out?
    53 
    52 
       
    53     // Cache for incomplete handshake messages.
       
    54     private ByteBuffer handshakeBuffer = null;
       
    55 
    54     private boolean hasHeader = false;          // Had read the record header
    56     private boolean hasHeader = false;          // Had read the record header
    55 
    57 
    56     SSLSocketInputRecord() {
    58     SSLSocketInputRecord(HandshakeHash handshakeHash) {
    57         this.readAuthenticator = MAC.TLS_NULL;
    59         super(handshakeHash, SSLReadCipher.nullTlsReadCipher());
    58     }
    60     }
    59 
    61 
    60     @Override
    62     @Override
    61     int bytesInCompletePacket(InputStream is) throws IOException {
    63     int bytesInCompletePacket() throws IOException {
    62 
    64 
    63         if (!hasHeader) {
    65         if (!hasHeader) {
    64             // read exactly one record
    66             // read exactly one record
    65             int really = read(is, temporary, 0, headerSize);
    67             int really = read(is, temporary, 0, headerSize);
    66             if (really < 0) {
    68             if (really < 0) {
    67                 throw new EOFException("SSL peer shut down incorrectly");
    69                 // EOF: peer shut down incorrectly
       
    70                 return -1;
    68             }
    71             }
    69             hasHeader = true;
    72             hasHeader = true;
    70         }
    73         }
    71 
    74 
    72         byte byteZero = temporary[0];
    75         byte byteZero = temporary[0];
    77          * ignore the verifications steps, and jump right to the
    80          * ignore the verifications steps, and jump right to the
    78          * determination.  Otherwise, try one last hueristic to
    81          * determination.  Otherwise, try one last hueristic to
    79          * see if it's SSL/TLS.
    82          * see if it's SSL/TLS.
    80          */
    83          */
    81         if (formatVerified ||
    84         if (formatVerified ||
    82                 (byteZero == ct_handshake) || (byteZero == ct_alert)) {
    85                 (byteZero == ContentType.HANDSHAKE.id) ||
       
    86                 (byteZero == ContentType.ALERT.id)) {
    83             /*
    87             /*
    84              * Last sanity check that it's not a wild record
    88              * Last sanity check that it's not a wild record
    85              */
    89              */
    86             ProtocolVersion recordVersion =
    90             if (!ProtocolVersion.isNegotiable(
    87                     ProtocolVersion.valueOf(temporary[1], temporary[2]);
    91                     temporary[1], temporary[2], false, false)) {
    88 
    92                 throw new SSLException("Unrecognized record version " +
    89             // check the record version
    93                         ProtocolVersion.nameOf(temporary[1], temporary[2]) +
    90             checkRecordVersion(recordVersion, false);
    94                         " , plaintext connection?");
       
    95             }
    91 
    96 
    92             /*
    97             /*
    93              * Reasonably sure this is a V3, disable further checks.
    98              * Reasonably sure this is a V3, disable further checks.
    94              * We can't do the same in the v2 check below, because
    99              * We can't do the same in the v2 check below, because
    95              * read still needs to parse/handle the v2 clientHello.
   100              * read still needs to parse/handle the v2 clientHello.
   110              * Internals can warn about unsupported SSLv2
   115              * Internals can warn about unsupported SSLv2
   111              */
   116              */
   112             boolean isShort = ((byteZero & 0x80) != 0);
   117             boolean isShort = ((byteZero & 0x80) != 0);
   113 
   118 
   114             if (isShort && ((temporary[2] == 1) || (temporary[2] == 4))) {
   119             if (isShort && ((temporary[2] == 1) || (temporary[2] == 4))) {
   115                 ProtocolVersion recordVersion =
   120                 if (!ProtocolVersion.isNegotiable(
   116                         ProtocolVersion.valueOf(temporary[3], temporary[4]);
   121                         temporary[3], temporary[4], false, false)) {
   117 
   122                     throw new SSLException("Unrecognized record version " +
   118                 // check the record version
   123                             ProtocolVersion.nameOf(temporary[3], temporary[4]) +
   119                 checkRecordVersion(recordVersion, true);
   124                             " , plaintext connection?");
       
   125                 }
   120 
   126 
   121                 /*
   127                 /*
   122                  * Client or Server Hello
   128                  * Client or Server Hello
   123                  */
   129                  */
   124                 //
   130                 //
   138         }
   144         }
   139 
   145 
   140         return len;
   146         return len;
   141     }
   147     }
   142 
   148 
   143     // destination.position() is zero.
   149     // Note that the input arguments are not used actually.
   144     @Override
   150     @Override
   145     Plaintext decode(InputStream is, ByteBuffer destination)
   151     Plaintext[] decode(ByteBuffer[] srcs, int srcsOffset,
   146             throws IOException, BadPaddingException {
   152             int srcsLength) throws IOException, BadPaddingException {
   147 
   153 
   148         if (isClosed) {
   154         if (isClosed) {
   149             return null;
   155             return null;
   150         }
   156         }
   151 
   157 
   165             /*
   171             /*
   166              * The first record must either be a handshake record or an
   172              * The first record must either be a handshake record or an
   167              * alert message. If it's not, it is either invalid or an
   173              * alert message. If it's not, it is either invalid or an
   168              * SSLv2 message.
   174              * SSLv2 message.
   169              */
   175              */
   170             if ((temporary[0] != ct_handshake) &&
   176             if ((temporary[0] != ContentType.HANDSHAKE.id) &&
   171                 (temporary[0] != ct_alert)) {
   177                 (temporary[0] != ContentType.ALERT.id)) {
   172 
   178                 hasHeader = false;
   173                 plaintext = handleUnknownRecord(is, temporary, destination);
   179                 return handleUnknownRecord(temporary);
   174             }
   180             }
   175         }
       
   176 
       
   177         if (plaintext == null) {
       
   178             plaintext = decodeInputRecord(is, temporary, destination);
       
   179         }
   181         }
   180 
   182 
   181         // The record header should has comsumed.
   183         // The record header should has comsumed.
   182         hasHeader = false;
   184         hasHeader = false;
   183 
   185         return decodeInputRecord(temporary);
   184         return plaintext;
   186     }
       
   187 
       
   188     @Override
       
   189     void setReceiverStream(InputStream inputStream) {
       
   190         this.is = inputStream;
   185     }
   191     }
   186 
   192 
   187     @Override
   193     @Override
   188     void setDeliverStream(OutputStream outputStream) {
   194     void setDeliverStream(OutputStream outputStream) {
   189         this.deliverStream = outputStream;
   195         this.os = outputStream;
   190     }
   196     }
   191 
   197 
   192     // Note that destination may be null
   198     // Note that destination may be null
   193     private Plaintext decodeInputRecord(InputStream is, byte[] header,
   199     private Plaintext[] decodeInputRecord(
   194             ByteBuffer destination) throws IOException, BadPaddingException {
   200             byte[] header) throws IOException, BadPaddingException {
   195 
   201         byte contentType = header[0];                   // pos: 0
   196         byte contentType = header[0];
   202         byte majorVersion = header[1];                  // pos: 1
   197         byte majorVersion = header[1];
   203         byte minorVersion = header[2];                  // pos: 2
   198         byte minorVersion = header[2];
   204         int contentLen = ((header[3] & 0xFF) << 8) +
   199         int contentLen = ((header[3] & 0xFF) << 8) + (header[4] & 0xFF);
   205                            (header[4] & 0xFF);          // pos: 3, 4
       
   206 
       
   207         if (SSLLogger.isOn && SSLLogger.isOn("record")) {
       
   208             SSLLogger.fine(
       
   209                     "READ: " +
       
   210                     ProtocolVersion.nameOf(majorVersion, minorVersion) +
       
   211                     " " + ContentType.nameOf(contentType) + ", length = " +
       
   212                     contentLen);
       
   213         }
   200 
   214 
   201         //
   215         //
   202         // Check for upper bound.
   216         // Check for upper bound.
   203         //
   217         //
   204         // Note: May check packetSize limit in the future.
   218         // Note: May check packetSize limit in the future.
   208         }
   222         }
   209 
   223 
   210         //
   224         //
   211         // Read a complete record.
   225         // Read a complete record.
   212         //
   226         //
   213         if (destination == null) {
   227         ByteBuffer destination = ByteBuffer.allocate(headerSize + contentLen);
   214             destination = ByteBuffer.allocate(headerSize + contentLen);
       
   215         }  // Otherwise, the destination buffer should have enough room.
       
   216 
       
   217         int dstPos = destination.position();
   228         int dstPos = destination.position();
   218         destination.put(temporary, 0, headerSize);
   229         destination.put(temporary, 0, headerSize);
   219         while (contentLen > 0) {
   230         while (contentLen > 0) {
   220             int howmuch = Math.min(temporary.length, contentLen);
   231             int howmuch = Math.min(temporary.length, contentLen);
   221             int really = read(is, temporary, 0, howmuch);
   232             int really = read(is, temporary, 0, howmuch);
   227             contentLen -= howmuch;
   238             contentLen -= howmuch;
   228         }
   239         }
   229         destination.flip();
   240         destination.flip();
   230         destination.position(dstPos + headerSize);
   241         destination.position(dstPos + headerSize);
   231 
   242 
   232         if (debug != null && Debug.isOn("record")) {
   243         if (SSLLogger.isOn && SSLLogger.isOn("record")) {
   233              System.out.println(Thread.currentThread().getName() +
   244             SSLLogger.fine(
   234                     ", READ: " +
   245                     "READ: " +
   235                     ProtocolVersion.valueOf(majorVersion, minorVersion) +
   246                     ProtocolVersion.nameOf(majorVersion, minorVersion) +
   236                     " " + Record.contentName(contentType) + ", length = " +
   247                     " " + ContentType.nameOf(contentType) + ", length = " +
   237                     destination.remaining());
   248                     destination.remaining());
   238         }
   249         }
   239 
   250 
   240         //
   251         //
   241         // Decrypt the fragment
   252         // Decrypt the fragment
   242         //
   253         //
   243         ByteBuffer plaintext =
   254         ByteBuffer fragment;
   244             decrypt(readAuthenticator, readCipher, contentType, destination);
   255         try {
   245 
   256             Plaintext plaintext =
   246         if ((contentType != ct_handshake) && (hsMsgOff != hsMsgLen)) {
   257                     readCipher.decrypt(contentType, destination, null);
       
   258             fragment = plaintext.fragment;
       
   259             contentType = plaintext.contentType;
       
   260         } catch (BadPaddingException bpe) {
       
   261             throw bpe;
       
   262         } catch (GeneralSecurityException gse) {
       
   263             throw (SSLProtocolException)(new SSLProtocolException(
       
   264                     "Unexpected exception")).initCause(gse);
       
   265         }
       
   266         if (contentType != ContentType.HANDSHAKE.id && hsMsgOff != hsMsgLen) {
   247             throw new SSLProtocolException(
   267             throw new SSLProtocolException(
   248                     "Expected to get a handshake fragment");
   268                     "Expected to get a handshake fragment");
   249         }
   269         }
   250 
   270 
   251         //
   271         //
   252         // handshake hashing
   272         // parse handshake messages
   253         //
   273         //
   254         if (contentType == ct_handshake) {
   274         if (contentType == ContentType.HANDSHAKE.id) {
   255             int pltPos = plaintext.position();
   275             ByteBuffer handshakeFrag = fragment;
   256             int pltLim = plaintext.limit();
   276             if ((handshakeBuffer != null) &&
   257             int frgPos = pltPos;
   277                     (handshakeBuffer.remaining() != 0)) {
   258             for (int remains = plaintext.remaining(); remains > 0;) {
   278                 ByteBuffer bb = ByteBuffer.wrap(new byte[
   259                 int howmuch;
   279                         handshakeBuffer.remaining() + fragment.remaining()]);
   260                 byte handshakeType;
   280                 bb.put(handshakeBuffer);
   261                 if (hsMsgOff < hsMsgLen) {
   281                 bb.put(fragment);
   262                     // a fragment of the handshake message
   282                 handshakeFrag = bb.rewind();
   263                     howmuch = Math.min((hsMsgLen - hsMsgOff), remains);
   283                 handshakeBuffer = null;
   264                     handshakeType = prevType;
   284             }
   265 
   285 
   266                     hsMsgOff += howmuch;
   286             ArrayList<Plaintext> plaintexts = new ArrayList<>(5);
   267                     if (hsMsgOff == hsMsgLen) {
   287             while (handshakeFrag.hasRemaining()) {
   268                         // Now is a complete handshake message.
   288                 int remaining = handshakeFrag.remaining();
   269                         hsMsgOff = 0;
   289                 if (remaining < handshakeHeaderSize) {
   270                         hsMsgLen = 0;
   290                     handshakeBuffer = ByteBuffer.wrap(new byte[remaining]);
       
   291                     handshakeBuffer.put(handshakeFrag);
       
   292                     handshakeBuffer.rewind();
       
   293                     break;
       
   294                 }
       
   295 
       
   296                 handshakeFrag.mark();
       
   297                 // skip the first byte: handshake type
       
   298                 byte handshakeType = handshakeFrag.get();
       
   299                 int handshakeBodyLen = Record.getInt24(handshakeFrag);
       
   300                 handshakeFrag.reset();
       
   301                 int handshakeMessageLen =
       
   302                         handshakeHeaderSize + handshakeBodyLen;
       
   303                 if (remaining < handshakeMessageLen) {
       
   304                     handshakeBuffer = ByteBuffer.wrap(new byte[remaining]);
       
   305                     handshakeBuffer.put(handshakeFrag);
       
   306                     handshakeBuffer.rewind();
       
   307                     break;
       
   308                 } if (remaining == handshakeMessageLen) {
       
   309                     if (handshakeHash.isHashable(handshakeType)) {
       
   310                         handshakeHash.receive(handshakeFrag);
   271                     }
   311                     }
   272                 } else {    // hsMsgOff == hsMsgLen, a new handshake message
   312 
   273                     handshakeType = plaintext.get();
   313                     plaintexts.add(
   274                     int handshakeLen = ((plaintext.get() & 0xFF) << 16) |
   314                         new Plaintext(contentType,
   275                                        ((plaintext.get() & 0xFF) << 8) |
   315                             majorVersion, minorVersion, -1, -1L, handshakeFrag)
   276                                         (plaintext.get() & 0xFF);
   316                     );
   277                     plaintext.position(frgPos);
   317                     break;
   278                     if (remains < (handshakeLen + 1)) { // 1: handshake type
   318                 } else {
   279                         // This handshake message is fragmented.
   319                     int fragPos = handshakeFrag.position();
   280                         prevType = handshakeType;
   320                     int fragLim = handshakeFrag.limit();
   281                         hsMsgOff = remains - 4;         // 4: handshake header
   321                     int nextPos = fragPos + handshakeMessageLen;
   282                         hsMsgLen = handshakeLen;
   322                     handshakeFrag.limit(nextPos);
       
   323 
       
   324                     if (handshakeHash.isHashable(handshakeType)) {
       
   325                         handshakeHash.receive(handshakeFrag);
   283                     }
   326                     }
   284 
   327 
   285                     howmuch = Math.min(handshakeLen + 4, remains);
   328                     plaintexts.add(
   286                 }
   329                         new Plaintext(contentType, majorVersion, minorVersion,
   287 
   330                             -1, -1L, handshakeFrag.slice())
   288                 plaintext.limit(frgPos + howmuch);
   331                     );
   289 
   332 
   290                 if (handshakeType == HandshakeMessage.ht_hello_request) {
   333                     handshakeFrag.position(nextPos);
   291                     // omitted from handshake hash computation
   334                     handshakeFrag.limit(fragLim);
   292                 } else if ((handshakeType != HandshakeMessage.ht_finished) &&
   335                 }
   293                     (handshakeType != HandshakeMessage.ht_certificate_verify)) {
   336             }
   294 
   337 
   295                     if (handshakeHash == null) {
   338             return plaintexts.toArray(new Plaintext[0]);
   296                         // used for cache only
   339         }
   297                         handshakeHash = new HandshakeHash(false);
   340 
   298                     }
   341         return new Plaintext[] {
   299                     handshakeHash.update(plaintext);
   342                 new Plaintext(contentType,
   300                 } else {
   343                     majorVersion, minorVersion, -1, -1L, fragment)
   301                     // Reserve until this handshake message has been processed.
   344                     // recordEpoch, recordSeq, plaintext);
   302                     if (handshakeHash == null) {
   345             };
   303                         // used for cache only
   346     }
   304                         handshakeHash = new HandshakeHash(false);
   347 
   305                     }
   348     private Plaintext[] handleUnknownRecord(
   306                     handshakeHash.reserve(plaintext);
   349             byte[] header) throws IOException, BadPaddingException {
   307                 }
       
   308 
       
   309                 plaintext.position(frgPos + howmuch);
       
   310                 plaintext.limit(pltLim);
       
   311 
       
   312                 frgPos += howmuch;
       
   313                 remains -= howmuch;
       
   314             }
       
   315             plaintext.position(pltPos);
       
   316         }
       
   317 
       
   318         return new Plaintext(contentType,
       
   319                 majorVersion, minorVersion, -1, -1L, plaintext);
       
   320                 // recordEpoch, recordSeq, plaintext);
       
   321     }
       
   322 
       
   323     private Plaintext handleUnknownRecord(InputStream is, byte[] header,
       
   324             ByteBuffer destination) throws IOException, BadPaddingException {
       
   325 
       
   326         byte firstByte = header[0];
   350         byte firstByte = header[0];
   327         byte thirdByte = header[2];
   351         byte thirdByte = header[2];
   328 
   352 
   329         // Does it look like a Version 2 client hello (V2ClientHello)?
   353         // Does it look like a Version 2 client hello (V2ClientHello)?
   330         if (((firstByte & 0x80) != 0) && (thirdByte == 1)) {
   354         if (((firstByte & 0x80) != 0) && (thirdByte == 1)) {
   345                  * Looks like a V2 client hello, but not one saying
   369                  * Looks like a V2 client hello, but not one saying
   346                  * "let's talk SSLv3".  So we need to send an SSLv2
   370                  * "let's talk SSLv3".  So we need to send an SSLv2
   347                  * error message, one that's treated as fatal by
   371                  * error message, one that's treated as fatal by
   348                  * clients (Otherwise we'll hang.)
   372                  * clients (Otherwise we'll hang.)
   349                  */
   373                  */
   350                 deliverStream.write(SSLRecord.v2NoCipher);      // SSLv2Hello
   374                 os.write(SSLRecord.v2NoCipher);      // SSLv2Hello
   351 
   375 
   352                 if (debug != null) {
   376                 if (SSLLogger.isOn) {
   353                     if (Debug.isOn("record")) {
   377                     if (SSLLogger.isOn("record")) {
   354                          System.out.println(Thread.currentThread().getName() +
   378                          SSLLogger.fine(
   355                                 "Requested to negotiate unsupported SSLv2!");
   379                                 "Requested to negotiate unsupported SSLv2!");
   356                     }
   380                     }
   357 
   381 
   358                     if (Debug.isOn("packet")) {
   382                     if (SSLLogger.isOn("packet")) {
   359                         Debug.printHex(
   383                         SSLLogger.fine("Raw write", SSLRecord.v2NoCipher);
   360                                 "[Raw write]: length = " +
       
   361                                 SSLRecord.v2NoCipher.length,
       
   362                                 SSLRecord.v2NoCipher);
       
   363                     }
   384                     }
   364                 }
   385                 }
   365 
   386 
   366                 throw new SSLException("Unsupported SSL v2.0 ClientHello");
   387                 throw new SSLException("Unsupported SSL v2.0 ClientHello");
   367             }
   388             }
   368 
   389 
   369             int msgLen = ((header[0] & 0x7F) << 8) | (header[1] & 0xFF);
   390             int msgLen = ((header[0] & 0x7F) << 8) | (header[1] & 0xFF);
   370 
   391 
   371             if (destination == null) {
   392             ByteBuffer destination = ByteBuffer.allocate(headerSize + msgLen);
   372                 destination = ByteBuffer.allocate(headerSize + msgLen);
       
   373             }
       
   374             destination.put(temporary, 0, headerSize);
   393             destination.put(temporary, 0, headerSize);
   375             msgLen -= 3;            // had read 3 bytes of content as header
   394             msgLen -= 3;            // had read 3 bytes of content as header
   376             while (msgLen > 0) {
   395             while (msgLen > 0) {
   377                 int howmuch = Math.min(temporary.length, msgLen);
   396                 int howmuch = Math.min(temporary.length, msgLen);
   378                 int really = read(is, temporary, 0, howmuch);
   397                 int really = read(is, temporary, 0, howmuch);
   389              * If we can map this into a V3 ClientHello, read and
   408              * If we can map this into a V3 ClientHello, read and
   390              * hash the rest of the V2 handshake, turn it into a
   409              * hash the rest of the V2 handshake, turn it into a
   391              * V3 ClientHello message, and pass it up.
   410              * V3 ClientHello message, and pass it up.
   392              */
   411              */
   393             destination.position(2);     // exclude the header
   412             destination.position(2);     // exclude the header
   394 
   413             handshakeHash.receive(destination);
   395             if (handshakeHash == null) {
       
   396                 // used for cache only
       
   397                 handshakeHash = new HandshakeHash(false);
       
   398             }
       
   399             handshakeHash.update(destination);
       
   400             destination.position(0);
   414             destination.position(0);
   401 
   415 
   402             ByteBuffer converted = convertToClientHello(destination);
   416             ByteBuffer converted = convertToClientHello(destination);
   403 
   417 
   404             if (debug != null && Debug.isOn("packet")) {
   418             if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
   405                  Debug.printHex(
   419                 SSLLogger.fine(
   406                         "[Converted] ClientHello", converted);
   420                         "[Converted] ClientHello", converted);
   407             }
   421             }
   408 
   422 
   409             return new Plaintext(ct_handshake,
   423             return new Plaintext[] {
   410                 majorVersion, minorVersion, -1, -1L, converted);
   424                     new Plaintext(ContentType.HANDSHAKE.id,
       
   425                     majorVersion, minorVersion, -1, -1L, converted)
       
   426                 };
   411         } else {
   427         } else {
   412             if (((firstByte & 0x80) != 0) && (thirdByte == 4)) {
   428             if (((firstByte & 0x80) != 0) && (thirdByte == 4)) {
   413                 throw new SSLException("SSL V2.0 servers are not supported.");
   429                 throw new SSLException("SSL V2.0 servers are not supported.");
   414             }
   430             }
   415 
   431 
   422             byte[] buffer, int offset, int len) throws IOException {
   438             byte[] buffer, int offset, int len) throws IOException {
   423         int n = 0;
   439         int n = 0;
   424         while (n < len) {
   440         while (n < len) {
   425             int readLen = is.read(buffer, offset + n, len - n);
   441             int readLen = is.read(buffer, offset + n, len - n);
   426             if (readLen < 0) {
   442             if (readLen < 0) {
       
   443                 if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
       
   444                     SSLLogger.fine("Raw read: EOF");
       
   445                 }
   427                 return -1;
   446                 return -1;
   428             }
   447             }
   429 
   448 
   430             if (debug != null && Debug.isOn("packet")) {
   449             if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
   431                  Debug.printHex(
   450                 ByteBuffer bb = ByteBuffer.wrap(buffer, offset + n, readLen);
   432                         "[Raw read]: length = " + readLen,
   451                 SSLLogger.fine("Raw read", bb);
   433                         buffer, offset + n, readLen);
       
   434             }
   452             }
   435 
   453 
   436             n += readLen;
   454             n += readLen;
   437         }
   455         }
   438 
   456