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