1 /*
   2  * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   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
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package sun.security.ssl;
  28 
  29 import java.io.*;
  30 import java.nio.*;
  31 
  32 import javax.crypto.BadPaddingException;
  33 
  34 import javax.net.ssl.*;
  35 
  36 import sun.misc.HexDumpEncoder;
  37 
  38 
  39 /**
  40  * SSL 3.0 records, as pulled off a TCP stream.  Input records are
  41  * basically buffers tied to a particular input stream ... a layer
  42  * above this must map these records into the model of a continuous
  43  * stream of data.
  44  *
  45  * Since this returns SSL 3.0 records, it's the layer that needs to
  46  * map SSL 2.0 style handshake records into SSL 3.0 ones for those
  47  * "old" clients that interop with both V2 and V3 servers.  Not as
  48  * pretty as might be desired.
  49  *
  50  * NOTE:  During handshaking, each message must be hashed to support
  51  * verification that the handshake process wasn't compromised.
  52  *
  53  * @author David Brownell
  54  */
  55 class InputRecord extends ByteArrayInputStream implements Record {
  56 
  57     private HandshakeHash       handshakeHash;
  58     private int                 lastHashed;
  59     boolean                     formatVerified = true;  // SSLv2 ruled out?
  60     private boolean             isClosed;
  61     private boolean             appDataValid;
  62 
  63     // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
  64     // and the first message we read is a ClientHello in V2 format, we convert
  65     // it to V3. Otherwise we throw an exception when encountering a V2 hello.
  66     private ProtocolVersion     helloVersion;
  67 
  68     /* Class and subclass dynamic debugging support */
  69     static final Debug debug = Debug.getInstance("ssl");
  70 
  71     /* The existing record length */
  72     private int exlen;
  73 
  74     /* V2 handshake message */
  75     private byte v2Buf[];
  76 
  77     /*
  78      * Construct the record to hold the maximum sized input record.
  79      * Data will be filled in separately.
  80      *
  81      * The structure of the byte buffer looks like:
  82      *
  83      *     |--------+---------+---------------------------------|
  84      *     | header |   IV    | content, MAC/TAG, padding, etc. |
  85      *     | headerPlusIVSize |
  86      *
  87      * header: the header of an SSL records
  88      * IV:     the optional IV/nonce field, it is only required for block
  89      *         (TLS 1.1 or later) and AEAD cipher suites.
  90      *
  91      */
  92     InputRecord() {
  93         super(new byte[maxRecordSize]);
  94         setHelloVersion(ProtocolVersion.DEFAULT_HELLO);
  95         pos = headerSize;
  96         count = headerSize;
  97         lastHashed = count;
  98         exlen = 0;
  99         v2Buf = null;
 100     }
 101 
 102     void setHelloVersion(ProtocolVersion helloVersion) {
 103         this.helloVersion = helloVersion;
 104     }
 105 
 106     ProtocolVersion getHelloVersion() {
 107         return helloVersion;
 108     }
 109 
 110     /*
 111      * Enable format checks if initial handshaking hasn't completed
 112      */
 113     void enableFormatChecks() {
 114         formatVerified = false;
 115     }
 116 
 117     // return whether the data in this record is valid, decrypted data
 118     boolean isAppDataValid() {
 119         return appDataValid;
 120     }
 121 
 122     void setAppDataValid(boolean value) {
 123         appDataValid = value;
 124     }
 125 
 126     /*
 127      * Return the content type of the record.
 128      */
 129     byte contentType() {
 130         return buf[0];
 131     }
 132 
 133     /*
 134      * For handshaking, we need to be able to hash every byte above the
 135      * record marking layer.  This is where we're guaranteed to see those
 136      * bytes, so this is where we can hash them ... especially in the
 137      * case of hashing the initial V2 message!
 138      */
 139     void setHandshakeHash(HandshakeHash handshakeHash) {
 140         this.handshakeHash = handshakeHash;
 141     }
 142 
 143     HandshakeHash getHandshakeHash() {
 144         return handshakeHash;
 145     }
 146 
 147     void decrypt(Authenticator authenticator,
 148             CipherBox box) throws BadPaddingException {
 149         BadPaddingException reservedBPE = null;
 150         int tagLen =
 151             (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
 152         int cipheredLength = count - headerSize;
 153 
 154         if (!box.isNullCipher()) {
 155             try {
 156                 // apply explicit nonce for AEAD/CBC cipher suites if needed
 157                 int nonceSize = box.applyExplicitNonce(authenticator,
 158                         contentType(), buf, headerSize, cipheredLength);
 159                 pos = headerSize + nonceSize;
 160                 lastHashed = pos;   // don't digest the explicit nonce
 161 
 162                 // decrypt the content
 163                 int offset = headerSize;
 164                 if (box.isAEADMode()) {
 165                     // DON'T encrypt the nonce_explicit for AEAD mode
 166                     offset += nonceSize;
 167                 }   // The explicit IV for CBC mode can be decrypted.
 168 
 169                 // Note that the CipherBox.decrypt() does not change
 170                 // the capacity of the buffer.
 171                 count = offset +
 172                     box.decrypt(buf, offset, count - offset, tagLen);
 173 
 174                 // Note that we don't remove the nonce from the buffer.
 175             } catch (BadPaddingException bpe) {
 176                 // RFC 2246 states that decryption_failed should be used
 177                 // for this purpose. However, that allows certain attacks,
 178                 // so we just send bad record MAC. We also need to make
 179                 // sure to always check the MAC to avoid a timing attack
 180                 // for the same issue. See paper by Vaudenay et al and the
 181                 // update in RFC 4346/5246.
 182                 //
 183                 // Failover to message authentication code checking.
 184                 reservedBPE = bpe;
 185             }
 186         }
 187 
 188         // Requires message authentication code for null, stream and block
 189         // cipher suites.
 190         if (authenticator instanceof MAC && tagLen != 0) {
 191             MAC signer = (MAC)authenticator;
 192             int macOffset = count - tagLen;
 193             int contentLen = macOffset - pos;
 194 
 195             // Note that although it is not necessary, we run the same MAC
 196             // computation and comparison on the payload for both stream
 197             // cipher and CBC block cipher.
 198             if (contentLen < 0) {
 199                 // negative data length, something is wrong
 200                 if (reservedBPE == null) {
 201                     reservedBPE = new BadPaddingException("bad record");
 202                 }
 203 
 204                 // set offset of the dummy MAC
 205                 macOffset = headerSize + cipheredLength - tagLen;
 206                 contentLen = macOffset - headerSize;
 207             }
 208 
 209             count -= tagLen;  // Set the count before any MAC checking
 210                               // exception occurs, so that the following
 211                               // process can read the actual decrypted
 212                               // content (minus the MAC) in the fragment
 213                               // if necessary.
 214 
 215             // Run MAC computation and comparison on the payload.
 216             if (checkMacTags(contentType(),
 217                     buf, pos, contentLen, signer, false)) {
 218                 if (reservedBPE == null) {
 219                     reservedBPE = new BadPaddingException("bad record MAC");
 220                 }
 221             }
 222 
 223             // Run MAC computation and comparison on the remainder.
 224             //
 225             // It is only necessary for CBC block cipher.  It is used to get a
 226             // constant time of MAC computation and comparison on each record.
 227             if (box.isCBCMode()) {
 228                 int remainingLen = calculateRemainingLen(
 229                                         signer, cipheredLength, contentLen);
 230 
 231                 // NOTE: remainingLen may be bigger (less than 1 block of the
 232                 // hash algorithm of the MAC) than the cipheredLength. However,
 233                 // We won't need to worry about it because we always use a
 234                 // maximum buffer for every record.  We need a change here if
 235                 // we use small buffer size in the future.
 236                 if (remainingLen > buf.length) {
 237                     // unlikely to happen, just a placehold
 238                     throw new RuntimeException(
 239                         "Internal buffer capacity error");
 240                 }
 241 
 242                 // Won't need to worry about the result on the remainder. And
 243                 // then we won't need to worry about what's actual data to
 244                 // check MAC tag on.  We start the check from the header of the
 245                 // buffer so that we don't need to construct a new byte buffer.
 246                 checkMacTags(contentType(), buf, 0, remainingLen, signer, true);
 247             }
 248         }
 249 
 250         // Is it a failover?
 251         if (reservedBPE != null) {
 252             throw reservedBPE;
 253         }
 254     }
 255 
 256     /*
 257      * Run MAC computation and comparison
 258      *
 259      * Please DON'T change the content of the byte buffer parameter!
 260      */
 261     static boolean checkMacTags(byte contentType, byte[] buffer,
 262             int offset, int contentLen, MAC signer, boolean isSimulated) {
 263 
 264         int tagLen = signer.MAClen();
 265         byte[] hash = signer.compute(
 266                 contentType, buffer, offset, contentLen, isSimulated);
 267         if (hash == null || tagLen != hash.length) {
 268             // Something is wrong with MAC implementation.
 269             throw new RuntimeException("Internal MAC error");
 270         }
 271 
 272         int[] results = compareMacTags(buffer, offset + contentLen, hash);
 273         return (results[0] != 0);
 274     }
 275 
 276     /*
 277      * A constant-time comparison of the MAC tags.
 278      *
 279      * Please DON'T change the content of the byte buffer parameter!
 280      */
 281     private static int[] compareMacTags(
 282             byte[] buffer, int offset, byte[] tag) {
 283 
 284         // An array of hits is used to prevent Hotspot optimization for
 285         // the purpose of a constant-time check.
 286         int[] results = {0, 0};    // {missed #, matched #}
 287 
 288         // The caller ensures there are enough bytes available in the buffer.
 289         // So we won't need to check the length of the buffer.
 290         for (int i = 0; i < tag.length; i++) {
 291             if (buffer[offset + i] != tag[i]) {
 292                 results[0]++;       // mismatched bytes
 293             } else {
 294                 results[1]++;       // matched bytes
 295             }
 296         }
 297 
 298         return results;
 299     }
 300 
 301     /*
 302      * Calculate the length of a dummy buffer to run MAC computation
 303      * and comparison on the remainder.
 304      *
 305      * The caller MUST ensure that the fullLen is not less than usedLen.
 306      */
 307     static int calculateRemainingLen(
 308             MAC signer, int fullLen, int usedLen) {
 309 
 310         int blockLen = signer.hashBlockLen();
 311         int minimalPaddingLen = signer.minimalPaddingLen();
 312 
 313         // (blockLen - minimalPaddingLen) is the maximum message size of
 314         // the last block of hash function operation. See FIPS 180-4, or
 315         // MD5 specification.
 316         fullLen += 13 - (blockLen - minimalPaddingLen);
 317         usedLen += 13 - (blockLen - minimalPaddingLen);
 318 
 319         // Note: fullLen is always not less than usedLen, and blockLen
 320         // is always bigger than minimalPaddingLen, so we don't worry
 321         // about negative values. 0x01 is added to the result to ensure
 322         // that the return value is positive.  The extra one byte does
 323         // not impact the overall MAC compression function evaluations.
 324         return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) -
 325                 Math.ceil(usedLen/(1.0d * blockLen))) * signer.hashBlockLen();
 326     }
 327 
 328     /*
 329      * Well ... hello_request messages are _never_ hashed since we can't
 330      * know when they'd appear in the sequence.
 331      */
 332     void ignore(int bytes) {
 333         if (bytes > 0) {
 334             pos += bytes;
 335             lastHashed = pos;
 336         }
 337     }
 338 
 339     /*
 340      * We hash the (plaintext) we've processed, but only on demand.
 341      *
 342      * There is one place where we want to access the hash in the middle
 343      * of a record:  client cert message gets hashed, and part of the
 344      * same record is the client cert verify message which uses that hash.
 345      * So we track how much we've read and hashed.
 346      */
 347     void doHashes() {
 348         int len = pos - lastHashed;
 349 
 350         if (len > 0) {
 351             hashInternal(buf, lastHashed, len);
 352             lastHashed = pos;
 353         }
 354     }
 355 
 356     /*
 357      * Need a helper function so we can hash the V2 hello correctly
 358      */
 359     private void hashInternal(byte databuf [], int offset, int len) {
 360         if (debug != null && Debug.isOn("data")) {
 361             try {
 362                 HexDumpEncoder hd = new HexDumpEncoder();
 363 
 364                 System.out.println("[read] MD5 and SHA1 hashes:  len = "
 365                     + len);
 366                 hd.encodeBuffer(new ByteArrayInputStream(databuf, offset, len),
 367                     System.out);
 368             } catch (IOException e) { }
 369         }
 370         handshakeHash.update(databuf, offset, len);
 371     }
 372 
 373 
 374     /*
 375      * Handshake messages may cross record boundaries.  We "queue"
 376      * these in big buffers if we need to cope with this problem.
 377      * This is not anticipated to be a common case; if this turns
 378      * out to be wrong, this can readily be sped up.
 379      */
 380     void queueHandshake(InputRecord r) throws IOException {
 381         int len;
 382 
 383         /*
 384          * Hash any data that's read but unhashed.
 385          */
 386         doHashes();
 387 
 388         /*
 389          * Move any unread data to the front of the buffer,
 390          * flagging it all as unhashed.
 391          */
 392         if (pos > headerSize) {
 393             len = count - pos;
 394             if (len != 0) {
 395                 System.arraycopy(buf, pos, buf, headerSize, len);
 396             }
 397             pos = headerSize;
 398             lastHashed = pos;
 399             count = headerSize + len;
 400         }
 401 
 402         /*
 403          * Grow "buf" if needed
 404          */
 405         len = r.available() + count;
 406         if (buf.length < len) {
 407             byte        newbuf [];
 408 
 409             newbuf = new byte [len];
 410             System.arraycopy(buf, 0, newbuf, 0, count);
 411             buf = newbuf;
 412         }
 413 
 414         /*
 415          * Append the new buffer to this one.
 416          */
 417         System.arraycopy(r.buf, r.pos, buf, count, len - count);
 418         count = len;
 419 
 420         /*
 421          * Adjust lastHashed; important for now with clients which
 422          * send SSL V2 client hellos.  This will go away eventually,
 423          * by buffer code cleanup.
 424          */
 425         len = r.lastHashed - r.pos;
 426         if (pos == headerSize) {
 427             lastHashed += len;
 428         } else {
 429             throw new SSLProtocolException("?? confused buffer hashing ??");
 430         }
 431         // we've read the record, advance the pointers
 432         r.pos = r.count;
 433     }
 434 
 435 
 436     /**
 437      * Prevent any more data from being read into this record,
 438      * and flag the record as holding no data.
 439      */
 440     @Override
 441     public void close() {
 442         appDataValid = false;
 443         isClosed = true;
 444         mark = 0;
 445         pos = 0;
 446         count = 0;
 447     }
 448 
 449 
 450     /*
 451      * We may need to send this SSL v2 "No Cipher" message back, if we
 452      * are faced with an SSLv2 "hello" that's not saying "I talk v3".
 453      * It's the only one documented in the V2 spec as a fatal error.
 454      */
 455     private static final byte[] v2NoCipher = {
 456         (byte)0x80, (byte)0x03, // unpadded 3 byte record
 457         (byte)0x00,             // ... error message
 458         (byte)0x00, (byte)0x01  // ... NO_CIPHER error
 459     };
 460 
 461     private int readFully(InputStream s, byte b[], int off, int len)
 462             throws IOException {
 463         int n = 0;
 464         while (n < len) {
 465             int readLen = s.read(b, off + n, len - n);
 466             if (readLen < 0) {
 467                 return readLen;
 468             }
 469 
 470             if (debug != null && Debug.isOn("packet")) {
 471                 try {
 472                     HexDumpEncoder hd = new HexDumpEncoder();
 473                     ByteBuffer bb = ByteBuffer.wrap(b, off + n, readLen);
 474 
 475                     System.out.println("[Raw read]: length = " +
 476                         bb.remaining());
 477                     hd.encodeBuffer(bb, System.out);
 478                 } catch (IOException e) { }
 479             }
 480 
 481             n += readLen;
 482             exlen += readLen;
 483         }
 484 
 485         return n;
 486     }
 487 
 488     /*
 489      * Read the SSL V3 record ... first time around, check to see if it
 490      * really IS a V3 record.  Handle SSL V2 clients which can talk V3.0,
 491      * as well as real V3 record format; otherwise report an error.
 492      */
 493     void read(InputStream s, OutputStream o) throws IOException {
 494         if (isClosed) {
 495             return;
 496         }
 497 
 498         /*
 499          * For SSL it really _is_ an error if the other end went away
 500          * so ungracefully as to not shut down cleanly.
 501          */
 502         if(exlen < headerSize) {
 503             int really = readFully(s, buf, exlen, headerSize - exlen);
 504             if (really < 0) {
 505                 throw new EOFException("SSL peer shut down incorrectly");
 506             }
 507 
 508             pos = headerSize;
 509             count = headerSize;
 510             lastHashed = pos;
 511         }
 512 
 513         /*
 514          * The first record might use some other record marking convention,
 515          * typically SSL v2 header.  (PCT could also be detected here.)
 516          * This case is currently common -- Navigator 3.0 usually works
 517          * this way, as do IE 3.0 and other products.
 518          */
 519         if (!formatVerified) {
 520             formatVerified = true;
 521             /*
 522              * The first record must either be a handshake record or an
 523              * alert message. If it's not, it is either invalid or an
 524              * SSLv2 message.
 525              */
 526             if (buf[0] != ct_handshake && buf[0] != ct_alert) {
 527                 handleUnknownRecord(s, o);
 528             } else {
 529                 readV3Record(s, o);
 530             }
 531         } else { // formatVerified == true
 532             readV3Record(s, o);
 533         }
 534     }
 535 
 536     /**
 537      * Return true if the specified record protocol version is out of the
 538      * range of the possible supported versions.
 539      */
 540     static void checkRecordVersion(ProtocolVersion version,
 541             boolean allowSSL20Hello) throws SSLException {
 542         // Check if the record version is too old (currently not possible)
 543         // or if the major version does not match.
 544         //
 545         // The actual version negotiation is in the handshaker classes
 546         if ((version.v < ProtocolVersion.MIN.v) ||
 547             ((version.major & 0xFF) > (ProtocolVersion.MAX.major & 0xFF))) {
 548 
 549             // if it's not SSLv2, we're out of here.
 550             if (!allowSSL20Hello ||
 551                     (version.v != ProtocolVersion.SSL20Hello.v)) {
 552                 throw new SSLException("Unsupported record version " + version);
 553             }
 554         }
 555     }
 556 
 557     /**
 558      * Read a SSL/TLS record. Throw an IOException if the format is invalid.
 559      */
 560     private void readV3Record(InputStream s, OutputStream o)
 561             throws IOException {
 562         ProtocolVersion recordVersion = ProtocolVersion.valueOf(buf[1], buf[2]);
 563 
 564         // check the record version
 565         checkRecordVersion(recordVersion, false);
 566 
 567         /*
 568          * Get and check length, then the data.
 569          */
 570         int contentLen = ((buf[3] & 0x0ff) << 8) + (buf[4] & 0xff);
 571 
 572         /*
 573          * Check for upper bound.
 574          */
 575         if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) {
 576             throw new SSLProtocolException("Bad InputRecord size"
 577                 + ", count = " + contentLen
 578                 + ", buf.length = " + buf.length);
 579         }
 580 
 581         /*
 582          * Grow "buf" if needed. Since buf is maxRecordSize by default,
 583          * this only occurs when we receive records which violate the
 584          * SSL specification. This is a workaround for a Microsoft SSL bug.
 585          */
 586         if (contentLen > buf.length - headerSize) {
 587             byte[] newbuf = new byte[contentLen + headerSize];
 588             System.arraycopy(buf, 0, newbuf, 0, headerSize);
 589             buf = newbuf;
 590         }
 591 
 592         if (exlen < contentLen + headerSize) {
 593             int really = readFully(
 594                 s, buf, exlen, contentLen + headerSize - exlen);
 595             if (really < 0) {
 596                 throw new SSLException("SSL peer shut down incorrectly");
 597             }
 598         }
 599 
 600         // now we've got a complete record.
 601         count = contentLen + headerSize;
 602         exlen = 0;
 603 
 604         if (debug != null && Debug.isOn("record")) {
 605             if (count < 0 || count > (maxRecordSize - headerSize)) {
 606                 System.out.println(Thread.currentThread().getName()
 607                     + ", Bad InputRecord size" + ", count = " + count);
 608             }
 609             System.out.println(Thread.currentThread().getName()
 610                 + ", READ: " + recordVersion + " "
 611                 + contentName(contentType()) + ", length = " + available());
 612         }
 613         /*
 614          * then caller decrypts, verifies, and uncompresses
 615          */
 616     }
 617 
 618     /**
 619      * Deal with unknown records. Called if the first data we read on this
 620      * connection does not look like an SSL/TLS record. It could a SSLv2
 621      * message, or just garbage.
 622      */
 623     private void handleUnknownRecord(InputStream s, OutputStream o)
 624             throws IOException {
 625         /*
 626          * No?  Oh well; does it look like a V2 "ClientHello"?
 627          * That'd be an unpadded handshake message; we don't
 628          * bother checking length just now.
 629          */
 630         if (((buf[0] & 0x080) != 0) && buf[2] == 1) {
 631             /*
 632              * if the user has disabled SSLv2Hello (using
 633              * setEnabledProtocol) then throw an
 634              * exception
 635              */
 636             if (helloVersion != ProtocolVersion.SSL20Hello) {
 637                 throw new SSLHandshakeException("SSLv2Hello is disabled");
 638             }
 639 
 640             ProtocolVersion recordVersion =
 641                                 ProtocolVersion.valueOf(buf[3], buf[4]);
 642 
 643             if (recordVersion == ProtocolVersion.SSL20Hello) {
 644                 /*
 645                  * Looks like a V2 client hello, but not one saying
 646                  * "let's talk SSLv3".  So we send an SSLv2 error
 647                  * message, one that's treated as fatal by clients.
 648                  * (Otherwise we'll hang.)
 649                  */
 650                 try {
 651                     writeBuffer(o, v2NoCipher, 0, v2NoCipher.length);
 652                 } catch (Exception e) {
 653                     /* NOTHING */
 654                 }
 655                 throw new SSLException("Unsupported SSL v2.0 ClientHello");
 656             }
 657 
 658             /*
 659              * If we can map this into a V3 ClientHello, read and
 660              * hash the rest of the V2 handshake, turn it into a
 661              * V3 ClientHello message, and pass it up.
 662              */
 663             int len = ((buf[0] & 0x7f) << 8) +
 664                 (buf[1] & 0xff) - 3;
 665             if (v2Buf == null) {
 666                 v2Buf = new byte[len];
 667             }
 668             if (exlen < len + headerSize) {
 669                 int really = readFully(
 670                         s, v2Buf, exlen - headerSize, len + headerSize - exlen);
 671                 if (really < 0) {
 672                     throw new EOFException("SSL peer shut down incorrectly");
 673                 }
 674             }
 675 
 676             // now we've got a complete record.
 677             exlen = 0;
 678 
 679             hashInternal(buf, 2, 3);
 680             hashInternal(v2Buf, 0, len);
 681             V2toV3ClientHello(v2Buf);
 682             v2Buf = null;
 683             lastHashed = count;
 684 
 685             if (debug != null && Debug.isOn("record"))  {
 686                 System.out.println(
 687                     Thread.currentThread().getName()
 688                     + ", READ:  SSL v2, contentType = "
 689                     + contentName(contentType())
 690                     + ", translated length = " + available());
 691             }
 692             return;
 693 
 694         } else {
 695             /*
 696              * Does it look like a V2 "ServerHello"?
 697              */
 698             if (((buf [0] & 0x080) != 0) && buf [2] == 4) {
 699                 throw new SSLException(
 700                     "SSL V2.0 servers are not supported.");
 701             }
 702 
 703             /*
 704              * If this is a V2 NoCipher message then this means
 705              * the other server doesn't support V3. Otherwise, we just
 706              * don't understand what it's saying.
 707              */
 708             for (int i = 0; i < v2NoCipher.length; i++) {
 709                 if (buf[i] != v2NoCipher[i]) {
 710                     throw new SSLException(
 711                         "Unrecognized SSL message, plaintext connection?");
 712                 }
 713             }
 714 
 715             throw new SSLException("SSL V2.0 servers are not supported.");
 716         }
 717     }
 718 
 719     /*
 720      * Actually do the write here.  For SSLEngine's HS data,
 721      * we'll override this method and let it take the appropriate
 722      * action.
 723      */
 724     void writeBuffer(OutputStream s, byte [] buf, int off, int len)
 725             throws IOException {
 726         s.write(buf, 0, len);
 727         s.flush();
 728     }
 729 
 730     /*
 731      * Support "old" clients which are capable of SSL V3.0 protocol ... for
 732      * example, Navigator 3.0 clients.  The V2 message is in the header and
 733      * the bytes passed as parameter.  This routine translates the V2 message
 734      * into an equivalent V3 one.
 735      */
 736     private void V2toV3ClientHello(byte v2Msg []) throws SSLException
 737     {
 738         int i;
 739 
 740         /*
 741          * Build the first part of the V3 record header from the V2 one
 742          * that's now buffered up.  (Lengths are fixed up later).
 743          */
 744         buf [0] = ct_handshake;
 745         buf [1] = buf [3];      // V3.x
 746         buf[2] = buf[4];
 747         // header [3..4] for handshake message length
 748         // count = 5;
 749 
 750         /*
 751          * Store the generic V3 handshake header:  4 bytes
 752          */
 753         buf [5] = 1;    // HandshakeMessage.ht_client_hello
 754         // buf [6..8] for length of ClientHello (int24)
 755         // count += 4;
 756 
 757         /*
 758          * ClientHello header starts with SSL version
 759          */
 760         buf [9] = buf [1];
 761         buf [10] = buf [2];
 762         // count += 2;
 763         count = 11;
 764 
 765         /*
 766          * Start parsing the V2 message ...
 767          */
 768         int      cipherSpecLen, sessionIdLen, nonceLen;
 769 
 770         cipherSpecLen = ((v2Msg [0] & 0xff) << 8) + (v2Msg [1] & 0xff);
 771         sessionIdLen  = ((v2Msg [2] & 0xff) << 8) + (v2Msg [3] & 0xff);
 772         nonceLen   = ((v2Msg [4] & 0xff) << 8) + (v2Msg [5] & 0xff);
 773 
 774         /*
 775          * Copy Random value/nonce ... if less than the 32 bytes of
 776          * a V3 "Random", right justify and zero pad to the left.  Else
 777          * just take the last 32 bytes.
 778          */
 779         int      offset = 6 + cipherSpecLen + sessionIdLen;
 780 
 781         if (nonceLen < 32) {
 782             for (i = 0; i < (32 - nonceLen); i++)
 783                 buf [count++] = 0;
 784             System.arraycopy(v2Msg, offset, buf, count, nonceLen);
 785             count += nonceLen;
 786         } else {
 787             System.arraycopy(v2Msg, offset + (nonceLen - 32),
 788                     buf, count, 32);
 789             count += 32;
 790         }
 791 
 792         /*
 793          * Copy Session ID (only one byte length!)
 794          */
 795         offset -= sessionIdLen;
 796         buf [count++] = (byte) sessionIdLen;
 797 
 798         System.arraycopy(v2Msg, offset, buf, count, sessionIdLen);
 799         count += sessionIdLen;
 800 
 801         /*
 802          * Copy and translate cipher suites ... V2 specs with first byte zero
 803          * are really V3 specs (in the last 2 bytes), just copy those and drop
 804          * the other ones.  Preference order remains unchanged.
 805          *
 806          * Example:  Netscape Navigator 3.0 (exportable) says:
 807          *
 808          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
 809          * 0/6,     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
 810          *
 811          * Microsoft Internet Explorer 3.0 (exportable) supports only
 812          *
 813          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
 814          */
 815         int j;
 816 
 817         offset -= cipherSpecLen;
 818         j = count + 2;
 819 
 820         for (i = 0; i < cipherSpecLen; i += 3) {
 821             if (v2Msg [offset + i] != 0)
 822                 continue;
 823             buf [j++] = v2Msg [offset + i + 1];
 824             buf [j++] = v2Msg [offset + i + 2];
 825         }
 826 
 827         j -= count + 2;
 828         buf [count++] = (byte) (j >>> 8);
 829         buf [count++] = (byte) j;
 830         count += j;
 831 
 832         /*
 833          * Append compression methods (default/null only)
 834          */
 835         buf [count++] = 1;
 836         buf [count++] = 0;      // Session.compression_null
 837 
 838         /*
 839          * Fill in lengths of the messages we synthesized (nested:
 840          * V3 handshake message within V3 record) and then return
 841          */
 842         buf [3] = (byte) (count - headerSize);
 843         buf [4] = (byte) ((count - headerSize) >>> 8);
 844 
 845         buf [headerSize + 1] = 0;
 846         buf [headerSize + 2] = (byte) (((count - headerSize) - 4) >>> 8);
 847         buf [headerSize + 3] = (byte) ((count - headerSize) - 4);
 848 
 849         pos = headerSize;
 850     }
 851 
 852     /**
 853      * Return a description for the given content type. This method should be
 854      * in Record, but since that is an interface this is not possible.
 855      * Called from InputRecord and OutputRecord.
 856      */
 857     static String contentName(int contentType) {
 858         switch (contentType) {
 859         case ct_change_cipher_spec:
 860             return "Change Cipher Spec";
 861         case ct_alert:
 862             return "Alert";
 863         case ct_handshake:
 864             return "Handshake";
 865         case ct_application_data:
 866             return "Application Data";
 867         default:
 868             return "contentType = " + contentType;
 869         }
 870     }
 871 
 872 }