1 /* 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. 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 package sun.security.ssl; 27 28 import java.io.ByteArrayOutputStream; 29 import java.io.Closeable; 30 import java.io.IOException; 31 import java.io.OutputStream; 32 import java.nio.ByteBuffer; 33 import sun.security.ssl.SSLCipher.SSLWriteCipher; 34 35 /** 36 * {@code OutputRecord} takes care of the management of SSL/(D)TLS 37 * output records, including buffering, encryption, handshake 38 * messages marshal, etc. 39 * 40 * @author David Brownell 41 */ 42 abstract class OutputRecord 43 extends ByteArrayOutputStream implements Record, Closeable { 44 SSLWriteCipher writeCipher; 45 // Needed for KeyUpdate, used after Handshake.Finished 46 TransportContext tc; 47 48 final HandshakeHash handshakeHash; 49 boolean firstMessage; 50 51 // current protocol version, sent as record version 52 ProtocolVersion protocolVersion; 53 54 // version for the ClientHello message. Only relevant if this is a 55 // client handshake record. If set to ProtocolVersion.SSL20Hello, 56 // the V3 client hello is converted to V2 format. 57 ProtocolVersion helloVersion; 58 59 // Is it the first application record to write? 60 boolean isFirstAppOutputRecord = true; 61 62 // packet size 63 int packetSize; 64 65 // fragment size 66 int fragmentSize; 67 68 // closed or not? 69 volatile boolean isClosed; 70 71 /* 72 * Mappings from V3 cipher suite encodings to their pure V2 equivalents. 73 * This is taken from the SSL V3 specification, Appendix E. 74 */ 75 private static final int[] V3toV2CipherMap1 = 76 {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07}; 77 private static final int[] V3toV2CipherMap3 = 78 {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0}; 79 private static final byte[] HANDSHAKE_MESSAGE_KEY_UPDATE = 80 {SSLHandshake.KEY_UPDATE.id, 0x00, 0x00, 0x01, 0x00}; 81 OutputRecord(HandshakeHash handshakeHash, SSLWriteCipher writeCipher)82 OutputRecord(HandshakeHash handshakeHash, SSLWriteCipher writeCipher) { 83 this.writeCipher = writeCipher; 84 this.firstMessage = true; 85 this.fragmentSize = Record.maxDataSize; 86 87 this.handshakeHash = handshakeHash; 88 89 // Please set packetSize and protocolVersion in the implementation. 90 } 91 setVersion(ProtocolVersion protocolVersion)92 synchronized void setVersion(ProtocolVersion protocolVersion) { 93 this.protocolVersion = protocolVersion; 94 } 95 96 /* 97 * Updates helloVersion of this record. 98 */ setHelloVersion(ProtocolVersion helloVersion)99 synchronized void setHelloVersion(ProtocolVersion helloVersion) { 100 this.helloVersion = helloVersion; 101 } 102 103 /* 104 * Return true iff the record is empty -- to avoid doing the work 105 * of sending empty records over the network. 106 */ isEmpty()107 boolean isEmpty() { 108 return false; 109 } 110 seqNumIsHuge()111 synchronized boolean seqNumIsHuge() { 112 return (writeCipher.authenticator != null) && 113 writeCipher.authenticator.seqNumIsHuge(); 114 } 115 116 // SSLEngine and SSLSocket encodeAlert(byte level, byte description)117 abstract void encodeAlert(byte level, byte description) throws IOException; 118 119 // SSLEngine and SSLSocket encodeHandshake(byte[] buffer, int offset, int length)120 abstract void encodeHandshake(byte[] buffer, 121 int offset, int length) throws IOException; 122 123 // SSLEngine and SSLSocket encodeChangeCipherSpec()124 abstract void encodeChangeCipherSpec() throws IOException; 125 126 // apply to SSLEngine only encode( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength)127 Ciphertext encode( 128 ByteBuffer[] srcs, int srcsOffset, int srcsLength, 129 ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException { 130 131 throw new UnsupportedOperationException(); 132 } 133 134 // apply to SSLEngine only encodeV2NoCipher()135 void encodeV2NoCipher() throws IOException { 136 throw new UnsupportedOperationException(); 137 } 138 139 // apply to SSLSocket only deliver( byte[] source, int offset, int length)140 void deliver( 141 byte[] source, int offset, int length) throws IOException { 142 throw new UnsupportedOperationException(); 143 } 144 145 // apply to SSLSocket only setDeliverStream(OutputStream outputStream)146 void setDeliverStream(OutputStream outputStream) { 147 throw new UnsupportedOperationException(); 148 } 149 150 // Change write ciphers, may use change_cipher_spec record. changeWriteCiphers(SSLWriteCipher writeCipher, boolean useChangeCipherSpec)151 synchronized void changeWriteCiphers(SSLWriteCipher writeCipher, 152 boolean useChangeCipherSpec) throws IOException { 153 if (isClosed()) { 154 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 155 SSLLogger.warning("outbound has closed, ignore outbound " + 156 "change_cipher_spec message"); 157 } 158 return; 159 } 160 161 if (useChangeCipherSpec) { 162 encodeChangeCipherSpec(); 163 } 164 165 /* 166 * Dispose of any intermediate state in the underlying cipher. 167 * For PKCS11 ciphers, this will release any attached sessions, 168 * and thus make finalization faster. 169 * 170 * Since MAC's doFinal() is called for every SSL/TLS packet, it's 171 * not necessary to do the same with MAC's. 172 */ 173 writeCipher.dispose(); 174 175 this.writeCipher = writeCipher; 176 this.isFirstAppOutputRecord = true; 177 } 178 179 // Change write ciphers using key_update handshake message. changeWriteCiphers(SSLWriteCipher writeCipher, byte keyUpdateRequest)180 synchronized void changeWriteCiphers(SSLWriteCipher writeCipher, 181 byte keyUpdateRequest) throws IOException { 182 if (isClosed()) { 183 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 184 SSLLogger.warning("outbound has closed, ignore outbound " + 185 "key_update handshake message"); 186 } 187 return; 188 } 189 190 // encode the handshake message, KeyUpdate 191 byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone(); 192 hm[hm.length - 1] = keyUpdateRequest; 193 encodeHandshake(hm, 0, hm.length); 194 flush(); 195 196 // Dispose of any intermediate state in the underlying cipher. 197 writeCipher.dispose(); 198 199 this.writeCipher = writeCipher; 200 this.isFirstAppOutputRecord = true; 201 } 202 changePacketSize(int packetSize)203 synchronized void changePacketSize(int packetSize) { 204 this.packetSize = packetSize; 205 } 206 changeFragmentSize(int fragmentSize)207 synchronized void changeFragmentSize(int fragmentSize) { 208 this.fragmentSize = fragmentSize; 209 } 210 getMaxPacketSize()211 synchronized int getMaxPacketSize() { 212 return packetSize; 213 } 214 215 // apply to DTLS SSLEngine initHandshaker()216 void initHandshaker() { 217 // blank 218 } 219 220 // apply to DTLS SSLEngine finishHandshake()221 void finishHandshake() { 222 // blank 223 } 224 225 // apply to DTLS SSLEngine launchRetransmission()226 void launchRetransmission() { 227 // blank 228 } 229 230 @Override close()231 public synchronized void close() throws IOException { 232 if (isClosed) { 233 return; 234 } 235 236 isClosed = true; 237 writeCipher.dispose(); 238 } 239 isClosed()240 boolean isClosed() { 241 return isClosed; 242 } 243 244 // 245 // shared helpers 246 // 247 248 // Encrypt a fragment and wrap up a record. 249 // 250 // To be consistent with the spec of SSLEngine.wrap() methods, the 251 // destination ByteBuffer's position is updated to reflect the amount 252 // of data produced. The limit remains the same. encrypt( SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, int headerOffset, int dstLim, int headerSize, ProtocolVersion protocolVersion)253 static long encrypt( 254 SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, 255 int headerOffset, int dstLim, int headerSize, 256 ProtocolVersion protocolVersion) { 257 boolean isDTLS = protocolVersion.isDTLS; 258 if (isDTLS) { 259 if (protocolVersion.useTLS13PlusSpec()) { 260 return d13Encrypt(encCipher, 261 contentType, destination, headerOffset, 262 dstLim, headerSize, protocolVersion); 263 } else { 264 return d10Encrypt(encCipher, 265 contentType, destination, headerOffset, 266 dstLim, headerSize, protocolVersion); 267 } 268 } else { 269 if (protocolVersion.useTLS13PlusSpec()) { 270 return t13Encrypt(encCipher, 271 contentType, destination, headerOffset, 272 dstLim, headerSize, protocolVersion); 273 } else { 274 return t10Encrypt(encCipher, 275 contentType, destination, headerOffset, 276 dstLim, headerSize, protocolVersion); 277 } 278 } 279 } 280 d13Encrypt( SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, int headerOffset, int dstLim, int headerSize, ProtocolVersion protocolVersion)281 private static long d13Encrypt( 282 SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, 283 int headerOffset, int dstLim, int headerSize, 284 ProtocolVersion protocolVersion) { 285 throw new UnsupportedOperationException("Not supported yet."); 286 } 287 d10Encrypt( SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, int headerOffset, int dstLim, int headerSize, ProtocolVersion protocolVersion)288 private static long d10Encrypt( 289 SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, 290 int headerOffset, int dstLim, int headerSize, 291 ProtocolVersion protocolVersion) { 292 byte[] sequenceNumber = encCipher.authenticator.sequenceNumber(); 293 encCipher.encrypt(contentType, destination); 294 295 // Finish out the record header. 296 int fragLen = destination.limit() - headerOffset - headerSize; 297 298 destination.put(headerOffset, contentType); // content type 299 destination.put(headerOffset + 1, protocolVersion.major); 300 destination.put(headerOffset + 2, protocolVersion.minor); 301 302 // epoch and sequence_number 303 destination.put(headerOffset + 3, sequenceNumber[0]); 304 destination.put(headerOffset + 4, sequenceNumber[1]); 305 destination.put(headerOffset + 5, sequenceNumber[2]); 306 destination.put(headerOffset + 6, sequenceNumber[3]); 307 destination.put(headerOffset + 7, sequenceNumber[4]); 308 destination.put(headerOffset + 8, sequenceNumber[5]); 309 destination.put(headerOffset + 9, sequenceNumber[6]); 310 destination.put(headerOffset + 10, sequenceNumber[7]); 311 312 // fragment length 313 destination.put(headerOffset + 11, (byte)(fragLen >> 8)); 314 destination.put(headerOffset + 12, (byte)fragLen); 315 316 // Update destination position to reflect the amount of data produced. 317 destination.position(destination.limit()); 318 319 return Authenticator.toLong(sequenceNumber); 320 } 321 t13Encrypt( SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, int headerOffset, int dstLim, int headerSize, ProtocolVersion protocolVersion)322 private static long t13Encrypt( 323 SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, 324 int headerOffset, int dstLim, int headerSize, 325 ProtocolVersion protocolVersion) { 326 if (!encCipher.isNullCipher()) { 327 // inner plaintext, using zero length padding. 328 int endOfPt = destination.limit(); 329 destination.limit(endOfPt + 1); 330 destination.put(endOfPt, contentType); 331 } 332 333 // use the right TLSCiphertext.opaque_type and legacy_record_version 334 ProtocolVersion pv = protocolVersion; 335 if (!encCipher.isNullCipher()) { 336 pv = ProtocolVersion.TLS12; 337 contentType = ContentType.APPLICATION_DATA.id; 338 } else if (protocolVersion.useTLS13PlusSpec()) { 339 pv = ProtocolVersion.TLS12; 340 } 341 342 byte[] sequenceNumber = encCipher.authenticator.sequenceNumber(); 343 encCipher.encrypt(contentType, destination); 344 345 // Finish out the record header. 346 int fragLen = destination.limit() - headerOffset - headerSize; 347 destination.put(headerOffset, contentType); 348 destination.put(headerOffset + 1, pv.major); 349 destination.put(headerOffset + 2, pv.minor); 350 351 // fragment length 352 destination.put(headerOffset + 3, (byte)(fragLen >> 8)); 353 destination.put(headerOffset + 4, (byte)fragLen); 354 355 // Update destination position to reflect the amount of data produced. 356 destination.position(destination.limit()); 357 358 return Authenticator.toLong(sequenceNumber); 359 } 360 t10Encrypt( SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, int headerOffset, int dstLim, int headerSize, ProtocolVersion protocolVersion)361 private static long t10Encrypt( 362 SSLWriteCipher encCipher, byte contentType, ByteBuffer destination, 363 int headerOffset, int dstLim, int headerSize, 364 ProtocolVersion protocolVersion) { 365 byte[] sequenceNumber = encCipher.authenticator.sequenceNumber(); 366 encCipher.encrypt(contentType, destination); 367 368 // Finish out the record header. 369 int fragLen = destination.limit() - headerOffset - headerSize; 370 371 destination.put(headerOffset, contentType); // content type 372 destination.put(headerOffset + 1, protocolVersion.major); 373 destination.put(headerOffset + 2, protocolVersion.minor); 374 375 // fragment length 376 destination.put(headerOffset + 3, (byte)(fragLen >> 8)); 377 destination.put(headerOffset + 4, (byte)fragLen); 378 379 // Update destination position to reflect the amount of data produced. 380 destination.position(destination.limit()); 381 382 return Authenticator.toLong(sequenceNumber); 383 } 384 385 // Encrypt a fragment and wrap up a record. 386 // 387 // Uses the internal expandable buf variable and the current 388 // protocolVersion variable. encrypt( SSLWriteCipher encCipher, byte contentType, int headerSize)389 long encrypt( 390 SSLWriteCipher encCipher, byte contentType, int headerSize) { 391 if (protocolVersion.useTLS13PlusSpec()) { 392 return t13Encrypt(encCipher, contentType, headerSize); 393 } else { 394 return t10Encrypt(encCipher, contentType, headerSize); 395 } 396 } 397 398 private static final class T13PaddingHolder { 399 private static final byte[] zeros = new byte[16]; 400 } 401 t13Encrypt( SSLWriteCipher encCipher, byte contentType, int headerSize)402 private long t13Encrypt( 403 SSLWriteCipher encCipher, byte contentType, int headerSize) { 404 if (!encCipher.isNullCipher()) { 405 // inner plaintext 406 write(contentType); 407 write(T13PaddingHolder.zeros, 0, T13PaddingHolder.zeros.length); 408 } 409 410 byte[] sequenceNumber = encCipher.authenticator.sequenceNumber(); 411 int position = headerSize; 412 int contentLen = count - position; 413 414 // ensure the capacity 415 int requiredPacketSize = 416 encCipher.calculatePacketSize(contentLen, headerSize); 417 if (requiredPacketSize > buf.length) { 418 byte[] newBuf = new byte[requiredPacketSize]; 419 System.arraycopy(buf, 0, newBuf, 0, count); 420 buf = newBuf; 421 } 422 423 // use the right TLSCiphertext.opaque_type and legacy_record_version 424 ProtocolVersion pv = protocolVersion; 425 if (!encCipher.isNullCipher()) { 426 pv = ProtocolVersion.TLS12; 427 contentType = ContentType.APPLICATION_DATA.id; 428 } else { 429 pv = ProtocolVersion.TLS12; 430 } 431 432 ByteBuffer destination = ByteBuffer.wrap(buf, position, contentLen); 433 count = headerSize + encCipher.encrypt(contentType, destination); 434 435 // Fill out the header, write it and the message. 436 int fragLen = count - headerSize; 437 438 buf[0] = contentType; 439 buf[1] = pv.major; 440 buf[2] = pv.minor; 441 buf[3] = (byte)((fragLen >> 8) & 0xFF); 442 buf[4] = (byte)(fragLen & 0xFF); 443 444 return Authenticator.toLong(sequenceNumber); 445 } 446 t10Encrypt( SSLWriteCipher encCipher, byte contentType, int headerSize)447 private long t10Encrypt( 448 SSLWriteCipher encCipher, byte contentType, int headerSize) { 449 byte[] sequenceNumber = encCipher.authenticator.sequenceNumber(); 450 int position = headerSize + writeCipher.getExplicitNonceSize(); 451 int contentLen = count - position; 452 453 // ensure the capacity 454 int requiredPacketSize = 455 encCipher.calculatePacketSize(contentLen, headerSize); 456 if (requiredPacketSize > buf.length) { 457 byte[] newBuf = new byte[requiredPacketSize]; 458 System.arraycopy(buf, 0, newBuf, 0, count); 459 buf = newBuf; 460 } 461 ByteBuffer destination = ByteBuffer.wrap(buf, position, contentLen); 462 count = headerSize + encCipher.encrypt(contentType, destination); 463 464 // Fill out the header, write it and the message. 465 int fragLen = count - headerSize; 466 buf[0] = contentType; 467 buf[1] = protocolVersion.major; 468 buf[2] = protocolVersion.minor; 469 buf[3] = (byte)((fragLen >> 8) & 0xFF); 470 buf[4] = (byte)(fragLen & 0xFF); 471 472 return Authenticator.toLong(sequenceNumber); 473 } 474 encodeV2ClientHello( byte[] fragment, int offset, int length)475 static ByteBuffer encodeV2ClientHello( 476 byte[] fragment, int offset, int length) throws IOException { 477 int v3SessIdLenOffset = offset + 34; // 2: client_version 478 // 32: random 479 480 int v3SessIdLen = fragment[v3SessIdLenOffset]; 481 int v3CSLenOffset = v3SessIdLenOffset + 1 + v3SessIdLen; 482 int v3CSLen = ((fragment[v3CSLenOffset] & 0xff) << 8) + 483 (fragment[v3CSLenOffset + 1] & 0xff); 484 int cipherSpecs = v3CSLen / 2; // 2: cipher spec size 485 486 // Estimate the max V2ClientHello message length 487 // 488 // 11: header size 489 // (cipherSpecs * 6): cipher_specs 490 // 6: one cipher suite may need 6 bytes, see V3toV2CipherSuite. 491 // 3: placeholder for the TLS_EMPTY_RENEGOTIATION_INFO_SCSV 492 // signaling cipher suite 493 // 32: challenge size 494 int v2MaxMsgLen = 11 + (cipherSpecs * 6) + 3 + 32; 495 496 // Create a ByteBuffer backed by an accessible byte array. 497 byte[] dstBytes = new byte[v2MaxMsgLen]; 498 ByteBuffer dstBuf = ByteBuffer.wrap(dstBytes); 499 500 /* 501 * Copy over the cipher specs. We don't care about actually 502 * translating them for use with an actual V2 server since 503 * we only talk V3. Therefore, just copy over the V3 cipher 504 * spec values with a leading 0. 505 */ 506 int v3CSOffset = v3CSLenOffset + 2; // skip length field 507 int v2CSLen = 0; 508 509 dstBuf.position(11); 510 boolean containsRenegoInfoSCSV = false; 511 for (int i = 0; i < cipherSpecs; i++) { 512 byte byte1, byte2; 513 514 byte1 = fragment[v3CSOffset++]; 515 byte2 = fragment[v3CSOffset++]; 516 v2CSLen += V3toV2CipherSuite(dstBuf, byte1, byte2); 517 if (!containsRenegoInfoSCSV && 518 byte1 == (byte)0x00 && byte2 == (byte)0xFF) { 519 containsRenegoInfoSCSV = true; 520 } 521 } 522 523 if (!containsRenegoInfoSCSV) { 524 v2CSLen += V3toV2CipherSuite(dstBuf, (byte)0x00, (byte)0xFF); 525 } 526 527 /* 528 * Copy in the nonce. 529 */ 530 dstBuf.put(fragment, (offset + 2), 32); 531 532 /* 533 * Build the first part of the V3 record header from the V2 one 534 * that's now buffered up. (Lengths are fixed up later). 535 */ 536 int msgLen = dstBuf.position() - 2; // Exclude the legth field itself 537 dstBuf.position(0); 538 dstBuf.put((byte)(0x80 | ((msgLen >>> 8) & 0xFF))); // pos: 0 539 dstBuf.put((byte)(msgLen & 0xFF)); // pos: 1 540 dstBuf.put(SSLHandshake.CLIENT_HELLO.id); // pos: 2 541 dstBuf.put(fragment[offset]); // major version, pos: 3 542 dstBuf.put(fragment[offset + 1]); // minor version, pos: 4 543 dstBuf.put((byte)(v2CSLen >>> 8)); // pos: 5 544 dstBuf.put((byte)(v2CSLen & 0xFF)); // pos: 6 545 dstBuf.put((byte)0x00); // session_id_length, pos: 7 546 dstBuf.put((byte)0x00); // pos: 8 547 dstBuf.put((byte)0x00); // challenge_length, pos: 9 548 dstBuf.put((byte)32); // pos: 10 549 550 dstBuf.position(0); 551 dstBuf.limit(msgLen + 2); 552 553 return dstBuf; 554 } 555 V3toV2CipherSuite(ByteBuffer dstBuf, byte byte1, byte byte2)556 private static int V3toV2CipherSuite(ByteBuffer dstBuf, 557 byte byte1, byte byte2) { 558 dstBuf.put((byte)0); 559 dstBuf.put(byte1); 560 dstBuf.put(byte2); 561 562 if (((byte2 & 0xff) > 0xA) || (V3toV2CipherMap1[byte2] == -1)) { 563 return 3; 564 } 565 566 dstBuf.put((byte)V3toV2CipherMap1[byte2]); 567 dstBuf.put((byte)0); 568 dstBuf.put((byte)V3toV2CipherMap3[byte2]); 569 570 return 6; 571 } 572 } 573