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.util.Arrays; 32 33 import javax.net.ssl.SSLException; 34 import sun.misc.HexDumpEncoder; 35 36 37 /** 38 * SSL 3.0 records, as written to a TCP stream. 39 * 40 * Each record has a message area that starts out with data supplied by the 41 * application. It may grow/shrink due to compression and will be modified 42 * in place for mac-ing and encryption. 43 * 44 * Handshake records have additional needs, notably accumulation of a set 45 * of hashes which are used to establish that handshaking was done right. 46 * Handshake records usually have several handshake messages each, and we 47 * need message-level control over what's hashed. 48 * 49 * @author David Brownell 50 */ 51 class OutputRecord extends ByteArrayOutputStream implements Record { 52 53 private HandshakeHash handshakeHash; 54 private int lastHashed; 55 private boolean firstMessage; 56 final private byte contentType; 57 private int headerOffset; 58 59 // current protocol version, sent as record version 60 ProtocolVersion protocolVersion; 61 62 // version for the ClientHello message. Only relevant if this is a 63 // client handshake record. If set to ProtocolVersion.SSL20Hello, 64 // the V3 client hello is converted to V2 format. 65 private ProtocolVersion helloVersion; 66 67 /* Class and subclass dynamic debugging support */ 68 static final Debug debug = Debug.getInstance("ssl"); 69 70 /* 71 * Default constructor makes a record supporting the maximum 72 * SSL record size. It allocates the header bytes directly. 73 * 74 * The structure of the byte buffer looks like: 75 * 76 * |---------+--------+-------+---------------------------------| 77 * | unused | header | IV | content, MAC/TAG, padding, etc. | 78 * | headerPlusMaxIVSize | 79 * 80 * unused: unused part of the buffer of size 81 * 82 * headerPlusMaxIVSize - header size - IV size 83 * 84 * When this object is created, we don't know the protocol 85 * version number, IV length, etc., so reserve space in front 86 * to avoid extra data movement (copies). 87 * header: the header of an SSL record 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 * @param type the content type for the record 92 */ 93 OutputRecord(byte type, int size) { 94 super(size); 95 this.protocolVersion = ProtocolVersion.DEFAULT; 96 this.helloVersion = ProtocolVersion.DEFAULT_HELLO; 97 firstMessage = true; 98 count = headerPlusMaxIVSize; 99 contentType = type; 100 lastHashed = count; 101 headerOffset = headerPlusMaxIVSize - headerSize; 102 } 103 104 OutputRecord(byte type) { 105 this(type, recordSize(type)); 106 } 107 108 /** 109 * Get the size of the buffer we need for records of the specified 110 * type. 111 */ 112 private static int recordSize(byte type) { 113 if ((type == ct_change_cipher_spec) || (type == ct_alert)) { 114 return maxAlertRecordSize; 115 } else { 116 return maxRecordSize; 117 } 118 } 119 120 /* 121 * Updates the SSL version of this record. 122 */ 123 synchronized void setVersion(ProtocolVersion protocolVersion) { 124 this.protocolVersion = protocolVersion; 125 } 126 127 /* 128 * Updates helloVersion of this record. 129 */ 130 synchronized void setHelloVersion(ProtocolVersion helloVersion) { 131 this.helloVersion = helloVersion; 132 } 133 134 /* 135 * Reset the record so that it can be refilled, starting 136 * immediately after the header. 137 */ 138 @Override 139 public synchronized void reset() { 140 super.reset(); 141 count = headerPlusMaxIVSize; 142 lastHashed = count; 143 headerOffset = headerPlusMaxIVSize - headerSize; 144 } 145 146 /* 147 * For handshaking, we need to be able to hash every byte above the 148 * record marking layer. This is where we're guaranteed to see those 149 * bytes, so this is where we can hash them. 150 */ 151 void setHandshakeHash(HandshakeHash handshakeHash) { 152 assert(contentType == ct_handshake); 153 this.handshakeHash = handshakeHash; 154 } 155 156 /* 157 * We hash (the plaintext) on demand. There is one place where 158 * we want to access the hash in the middle of a record: client 159 * cert message gets hashed, and part of the same record is the 160 * client cert verify message which uses that hash. So we track 161 * how much of each record we've hashed so far. 162 */ 163 void doHashes() { 164 int len = count - lastHashed; 165 166 if (len > 0) { 167 hashInternal(buf, lastHashed, len); 168 lastHashed = count; 169 } 170 } 171 172 /* 173 * Need a helper function so we can hash the V2 hello correctly 174 */ 175 private void hashInternal(byte buf [], int offset, int len) { 176 if (debug != null && Debug.isOn("data")) { 177 try { 178 HexDumpEncoder hd = new HexDumpEncoder(); 179 180 System.out.println("[write] MD5 and SHA1 hashes: len = " 181 + len); 182 hd.encodeBuffer(new ByteArrayInputStream(buf, 183 lastHashed, len), System.out); 184 } catch (IOException e) { } 185 } 186 187 handshakeHash.update(buf, lastHashed, len); 188 lastHashed = count; 189 } 190 191 /* 192 * Return true iff the record is empty -- to avoid doing the work 193 * of sending empty records over the network. 194 */ 195 boolean isEmpty() { 196 return count == headerPlusMaxIVSize; 197 } 198 199 /* 200 * Return true if the record is of an alert of the given description. 201 * 202 * Per SSL/TLS specifications, alert messages convey the severity of the 203 * message (warning or fatal) and a description of the alert. An alert 204 * is defined with a two bytes struct, {byte level, byte description}, 205 * following after the header bytes. 206 */ 207 boolean isAlert(byte description) { 208 if ((count > (headerPlusMaxIVSize + 1)) && (contentType == ct_alert)) { 209 return buf[headerPlusMaxIVSize + 1] == description; 210 } 211 212 return false; 213 } 214 215 /* 216 * Encrypt ... length may grow due to block cipher padding, or 217 * message authentication code or tag. 218 */ 219 void encrypt(Authenticator authenticator, CipherBox box) 220 throws IOException { 221 222 // In case we are automatically flushing a handshake stream, make 223 // sure we have hashed the message first. 224 // 225 // when we support compression, hashing can't go here 226 // since it'll need to be done on the uncompressed data, 227 // and the MAC applies to the compressed data. 228 if (contentType == ct_handshake) { 229 doHashes(); 230 } 231 232 // Requires message authentication code for stream and block 233 // cipher suites. 234 if (authenticator instanceof MAC) { 235 MAC signer = (MAC)authenticator; 236 if (signer.MAClen() != 0) { 237 byte[] hash = signer.compute(contentType, buf, 238 headerPlusMaxIVSize, count - headerPlusMaxIVSize, false); 239 write(hash); 240 } 241 } 242 243 if (!box.isNullCipher()) { 244 // Requires explicit IV/nonce for CBC/AEAD cipher suites for 245 // TLS 1.1 or later. 246 if ((protocolVersion.v >= ProtocolVersion.TLS11.v) && 247 (box.isCBCMode() || box.isAEADMode())) { 248 byte[] nonce = box.createExplicitNonce(authenticator, 249 contentType, count - headerPlusMaxIVSize); 250 int offset = headerPlusMaxIVSize - nonce.length; 251 System.arraycopy(nonce, 0, buf, offset, nonce.length); 252 headerOffset = offset - headerSize; 253 } else { 254 headerOffset = headerPlusMaxIVSize - headerSize; 255 } 256 257 // encrypt the content 258 int offset = headerPlusMaxIVSize; 259 if (!box.isAEADMode()) { 260 // The explicit IV can be encrypted. 261 offset = headerOffset + headerSize; 262 } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode 263 264 count = offset + box.encrypt(buf, offset, count - offset); 265 } 266 } 267 268 /* 269 * Tell how full the buffer is ... for filling it with application or 270 * handshake data. 271 */ 272 final int availableDataBytes() { 273 int dataSize = count - headerPlusMaxIVSize; 274 return maxDataSize - dataSize; 275 } 276 277 /* 278 * Increases the capacity if necessary to ensure that it can hold 279 * at least the number of elements specified by the minimum 280 * capacity argument. 281 * 282 * Note that the increased capacity is only can be used for held 283 * record buffer. Please DO NOT update the availableDataBytes() 284 * according to the expended buffer capacity. 285 * 286 * @see availableDataBytes() 287 */ 288 private void ensureCapacity(int minCapacity) { 289 // overflow-conscious code 290 if (minCapacity > buf.length) { 291 buf = Arrays.copyOf(buf, minCapacity); 292 } 293 } 294 295 /* 296 * Return the type of SSL record that's buffered here. 297 */ 298 final byte contentType() { 299 return contentType; 300 } 301 302 /* 303 * Write the record out on the stream. Note that you must have (in 304 * order) compressed the data, appended the MAC, and encrypted it in 305 * order for the record to be understood by the other end. (Some of 306 * those steps will be null early in handshaking.) 307 * 308 * Note that this does no locking for the connection, it's required 309 * that synchronization be done elsewhere. Also, this does its work 310 * in a single low level write, for efficiency. 311 */ 312 void write(OutputStream s, boolean holdRecord, 313 ByteArrayOutputStream heldRecordBuffer) throws IOException { 314 315 /* 316 * Don't emit content-free records. (Even change cipher spec 317 * messages have a byte of data!) 318 */ 319 if (count == headerPlusMaxIVSize) { 320 return; 321 } 322 323 int length = count - headerOffset - headerSize; 324 // "should" really never write more than about 14 Kb... 325 if (length < 0) { 326 throw new SSLException("output record size too small: " 327 + length); 328 } 329 330 if (debug != null 331 && (Debug.isOn("record") || Debug.isOn("handshake"))) { 332 if ((debug != null && Debug.isOn("record")) 333 || contentType() == ct_change_cipher_spec) 334 System.out.println(Thread.currentThread().getName() 335 // v3.0/v3.1 ... 336 + ", WRITE: " + protocolVersion 337 + " " + InputRecord.contentName(contentType()) 338 + ", length = " + length); 339 } 340 341 /* 342 * If this is the initial ClientHello on this connection and 343 * we're not trying to resume a (V3) session then send a V2 344 * ClientHello instead so we can detect V2 servers cleanly. 345 */ 346 if (firstMessage && useV2Hello()) { 347 byte[] v3Msg = new byte[length - 4]; 348 System.arraycopy(buf, headerPlusMaxIVSize + 4, 349 v3Msg, 0, v3Msg.length); 350 headerOffset = 0; // reset the header offset 351 V3toV2ClientHello(v3Msg); 352 handshakeHash.reset(); 353 lastHashed = 2; 354 doHashes(); 355 if (debug != null && Debug.isOn("record")) { 356 System.out.println( 357 Thread.currentThread().getName() 358 + ", WRITE: SSLv2 client hello message" 359 + ", length = " + (count - 2)); // 2 byte SSLv2 header 360 } 361 } else { 362 /* 363 * Fill out the header, write it and the message. 364 */ 365 buf[headerOffset + 0] = contentType; 366 buf[headerOffset + 1] = protocolVersion.major; 367 buf[headerOffset + 2] = protocolVersion.minor; 368 buf[headerOffset + 3] = (byte)(length >> 8); 369 buf[headerOffset + 4] = (byte)(length); 370 } 371 firstMessage = false; 372 373 /* 374 * The upper levels may want us to delay sending this packet so 375 * multiple TLS Records can be sent in one (or more) TCP packets. 376 * If so, add this packet to the heldRecordBuffer. 377 * 378 * NOTE: all writes have been synchronized by upper levels. 379 */ 380 int debugOffset = 0; 381 if (holdRecord) { 382 /* 383 * If holdRecord is true, we must have a heldRecordBuffer. 384 * 385 * Don't worry about the override of writeBuffer(), because 386 * when holdRecord is true, the implementation in this class 387 * will be used. 388 */ 389 writeBuffer(heldRecordBuffer, 390 buf, headerOffset, count - headerOffset, debugOffset); 391 } else { 392 // It's time to send, do we have buffered data? 393 // May or may not have a heldRecordBuffer. 394 if (heldRecordBuffer != null && heldRecordBuffer.size() > 0) { 395 int heldLen = heldRecordBuffer.size(); 396 397 // Ensure the capacity of this buffer. 398 int newCount = count + heldLen - headerOffset; 399 ensureCapacity(newCount); 400 401 // Slide everything in the buffer to the right. 402 System.arraycopy(buf, headerOffset, 403 buf, heldLen, count - headerOffset); 404 405 // Prepend the held record to the buffer. 406 System.arraycopy( 407 heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen); 408 count = newCount; 409 headerOffset = 0; 410 411 // Clear the held buffer. 412 heldRecordBuffer.reset(); 413 414 // The held buffer has been dumped, set the debug dump offset. 415 debugOffset = heldLen; 416 } 417 writeBuffer(s, buf, headerOffset, 418 count - headerOffset, debugOffset); 419 } 420 421 reset(); 422 } 423 424 /* 425 * Actually do the write here. For SSLEngine's HS data, 426 * we'll override this method and let it take the appropriate 427 * action. 428 */ 429 void writeBuffer(OutputStream s, byte [] buf, int off, int len, 430 int debugOffset) throws IOException { 431 s.write(buf, off, len); 432 s.flush(); 433 434 // Output only the record from the specified debug offset. 435 if (debug != null && Debug.isOn("packet")) { 436 try { 437 HexDumpEncoder hd = new HexDumpEncoder(); 438 439 System.out.println("[Raw write]: length = " + 440 (len - debugOffset)); 441 hd.encodeBuffer(new ByteArrayInputStream(buf, 442 off + debugOffset, len - debugOffset), System.out); 443 } catch (IOException e) { } 444 } 445 } 446 447 /* 448 * Return whether the buffer contains a ClientHello message that should 449 * be converted to V2 format. 450 */ 451 private boolean useV2Hello() { 452 return firstMessage 453 && (helloVersion == ProtocolVersion.SSL20Hello) 454 && (contentType == ct_handshake) 455 && (buf[headerOffset + 5] == HandshakeMessage.ht_client_hello) 456 // 5: recode header size 457 && (buf[headerPlusMaxIVSize + 4 + 2 + 32] == 0); 458 // V3 session ID is empty 459 // 4: handshake header size 460 // 2: client_version in ClientHello 461 // 32: random in ClientHello 462 } 463 464 /* 465 * Detect "old" servers which are capable of SSL V2.0 protocol ... for 466 * example, Netscape Commerce 1.0 servers. The V3 message is in the 467 * header and the bytes passed as parameter. This routine translates 468 * the V3 message into an equivalent V2 one. 469 * 470 * Note that the translation will strip off all hello extensions as 471 * SSL V2.0 does not support hello extension. 472 */ 473 private void V3toV2ClientHello(byte v3Msg []) throws SSLException { 474 int v3SessionIdLenOffset = 2 + 32; // version + nonce 475 int v3SessionIdLen = v3Msg[v3SessionIdLenOffset]; 476 int v3CipherSpecLenOffset = v3SessionIdLenOffset + 1 + v3SessionIdLen; 477 int v3CipherSpecLen = ((v3Msg[v3CipherSpecLenOffset] & 0xff) << 8) + 478 (v3Msg[v3CipherSpecLenOffset + 1] & 0xff); 479 int cipherSpecs = v3CipherSpecLen / 2; // 2 bytes each in V3 480 481 /* 482 * Copy over the cipher specs. We don't care about actually translating 483 * them for use with an actual V2 server since we only talk V3. 484 * Therefore, just copy over the V3 cipher spec values with a leading 485 * 0. 486 */ 487 int v3CipherSpecOffset = v3CipherSpecLenOffset + 2; // skip length 488 int v2CipherSpecLen = 0; 489 count = 11; 490 boolean containsRenegoInfoSCSV = false; 491 for (int i = 0; i < cipherSpecs; i++) { 492 byte byte1, byte2; 493 494 byte1 = v3Msg[v3CipherSpecOffset++]; 495 byte2 = v3Msg[v3CipherSpecOffset++]; 496 v2CipherSpecLen += V3toV2CipherSuite(byte1, byte2); 497 if (!containsRenegoInfoSCSV && 498 byte1 == (byte)0x00 && byte2 == (byte)0xFF) { 499 containsRenegoInfoSCSV = true; 500 } 501 } 502 503 if (!containsRenegoInfoSCSV) { 504 v2CipherSpecLen += V3toV2CipherSuite((byte)0x00, (byte)0xFF); 505 } 506 507 /* 508 * Build the first part of the V3 record header from the V2 one 509 * that's now buffered up. (Lengths are fixed up later). 510 */ 511 buf[2] = HandshakeMessage.ht_client_hello; 512 buf[3] = v3Msg[0]; // major version 513 buf[4] = v3Msg[1]; // minor version 514 buf[5] = (byte)(v2CipherSpecLen >>> 8); 515 buf[6] = (byte)v2CipherSpecLen; 516 buf[7] = 0; 517 buf[8] = 0; // always no session 518 buf[9] = 0; 519 buf[10] = 32; // nonce length (always 32 in V3) 520 521 /* 522 * Copy in the nonce. 523 */ 524 System.arraycopy(v3Msg, 2, buf, count, 32); 525 count += 32; 526 527 /* 528 * Set the length of the message. 529 */ 530 count -= 2; // don't include length field itself 531 buf[0] = (byte)(count >>> 8); 532 buf[0] |= 0x80; 533 buf[1] = (byte)(count); 534 count += 2; 535 } 536 537 /* 538 * Mappings from V3 cipher suite encodings to their pure V2 equivalents. 539 * This is taken from the SSL V3 specification, Appendix E. 540 */ 541 private static int[] V3toV2CipherMap1 = 542 {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07}; 543 private static int[] V3toV2CipherMap3 = 544 {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0}; 545 546 /* 547 * See which matching pure-V2 cipher specs we need to include. 548 * We are including these not because we are actually prepared 549 * to talk V2 but because the Oracle Web Server insists on receiving 550 * at least 1 "pure V2" cipher suite that it supports and returns an 551 * illegal_parameter alert unless one is present. Rather than mindlessly 552 * claiming to implement all documented pure V2 cipher suites the code below 553 * just claims to implement the V2 cipher suite that is "equivalent" 554 * in terms of cipher algorithm & exportability with the actual V3 cipher 555 * suite that we do support. 556 */ 557 private int V3toV2CipherSuite(byte byte1, byte byte2) { 558 buf[count++] = 0; 559 buf[count++] = byte1; 560 buf[count++] = byte2; 561 562 if (((byte2 & 0xff) > 0xA) || 563 (V3toV2CipherMap1[byte2] == -1)) { 564 return 3; 565 } 566 567 buf[count++] = (byte)V3toV2CipherMap1[byte2]; 568 buf[count++] = 0; 569 buf[count++] = (byte)V3toV2CipherMap3[byte2]; 570 571 return 6; 572 } 573 }