1 /* 2 * Copyright (c) 1996, 2020, 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.EOFException; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.OutputStream; 32 import java.nio.ByteBuffer; 33 import java.security.GeneralSecurityException; 34 import java.util.ArrayList; 35 import javax.crypto.BadPaddingException; 36 import javax.net.ssl.SSLException; 37 import javax.net.ssl.SSLHandshakeException; 38 import javax.net.ssl.SSLProtocolException; 39 40 import sun.security.ssl.SSLCipher.SSLReadCipher; 41 42 /** 43 * {@code InputRecord} implementation for {@code SSLSocket}. 44 * 45 * @author David Brownell 46 */ 47 final class SSLSocketInputRecord extends InputRecord implements SSLRecord { 48 private InputStream is = null; 49 private OutputStream os = null; 50 private final byte[] temporary = new byte[1024]; 51 52 private boolean formatVerified = false; // SSLv2 ruled out? 53 54 // Cache for incomplete handshake messages. 55 private ByteBuffer handshakeBuffer = null; 56 57 private boolean hasHeader = false; // Had read the record header 58 59 SSLSocketInputRecord(HandshakeHash handshakeHash) { 60 super(handshakeHash, SSLReadCipher.nullTlsReadCipher()); 61 } 62 63 @Override 64 int bytesInCompletePacket() throws IOException { 65 if (!hasHeader) { 66 // read exactly one record 67 try { 68 int really = read(is, temporary, 0, headerSize); 69 if (really < 0) { 70 // EOF: peer shut down incorrectly 71 return -1; 72 } 73 } catch (EOFException eofe) { 74 // The caller will handle EOF. 75 return -1; 76 } 77 hasHeader = true; 78 } 79 80 byte byteZero = temporary[0]; 81 int len = 0; 82 83 /* 84 * If we have already verified previous packets, we can 85 * ignore the verifications steps, and jump right to the 86 * determination. Otherwise, try one last heuristic to 87 * see if it's SSL/TLS. 88 */ 89 if (formatVerified || 90 (byteZero == ContentType.HANDSHAKE.id) || 91 (byteZero == ContentType.ALERT.id)) { 92 /* 93 * Last sanity check that it's not a wild record 94 */ 95 if (!ProtocolVersion.isNegotiable( 96 temporary[1], temporary[2], false)) { 97 throw new SSLException("Unrecognized record version " + 98 ProtocolVersion.nameOf(temporary[1], temporary[2]) + 99 " , plaintext connection?"); 100 } 101 102 /* 103 * Reasonably sure this is a V3, disable further checks. 104 * We can't do the same in the v2 check below, because 105 * read still needs to parse/handle the v2 clientHello. 106 */ 107 formatVerified = true; 108 109 /* 110 * One of the SSLv3/TLS message types. 111 */ 112 len = ((temporary[3] & 0xFF) << 8) + 113 (temporary[4] & 0xFF) + headerSize; 114 } else { 115 /* 116 * Must be SSLv2 or something unknown. 117 * Check if it's short (2 bytes) or 118 * long (3) header. 119 * 120 * Internals can warn about unsupported SSLv2 121 */ 122 boolean isShort = ((byteZero & 0x80) != 0); 123 124 if (isShort && ((temporary[2] == 1) || (temporary[2] == 4))) { 125 if (!ProtocolVersion.isNegotiable( 126 temporary[3], temporary[4], false)) { 127 throw new SSLException("Unrecognized record version " + 128 ProtocolVersion.nameOf(temporary[3], temporary[4]) + 129 " , plaintext connection?"); 130 } 131 132 /* 133 * Client or Server Hello 134 */ 135 // 136 // Short header is using here. We reverse the code here 137 // in case it is used in the future. 138 // 139 // int mask = (isShort ? 0x7F : 0x3F); 140 // len = ((byteZero & mask) << 8) + 141 // (temporary[1] & 0xFF) + (isShort ? 2 : 3); 142 // 143 len = ((byteZero & 0x7F) << 8) + (temporary[1] & 0xFF) + 2; 144 } else { 145 // Gobblygook! 146 throw new SSLException( 147 "Unrecognized SSL message, plaintext connection?"); 148 } 149 } 150 151 return len; 152 } 153 154 // Note that the input arguments are not used actually. 155 @Override 156 Plaintext[] decode(ByteBuffer[] srcs, int srcsOffset, 157 int srcsLength) throws IOException, BadPaddingException { 158 159 if (isClosed) { 160 return null; 161 } 162 163 if (!hasHeader) { 164 // read exactly one record 165 int really = read(is, temporary, 0, headerSize); 166 if (really < 0) { 167 throw new EOFException("SSL peer shut down incorrectly"); 168 } 169 hasHeader = true; 170 } 171 172 Plaintext plaintext = null; 173 if (!formatVerified) { 174 formatVerified = true; 175 176 /* 177 * The first record must either be a handshake record or an 178 * alert message. If it's not, it is either invalid or an 179 * SSLv2 message. 180 */ 181 if ((temporary[0] != ContentType.HANDSHAKE.id) && 182 (temporary[0] != ContentType.ALERT.id)) { 183 hasHeader = false; 184 return handleUnknownRecord(temporary); 185 } 186 } 187 188 // The record header should has consumed. 189 hasHeader = false; 190 return decodeInputRecord(temporary); 191 } 192 193 @Override 194 void setReceiverStream(InputStream inputStream) { 195 this.is = inputStream; 196 } 197 198 @Override 199 void setDeliverStream(OutputStream outputStream) { 200 this.os = outputStream; 201 } 202 203 // Note that destination may be null 204 private Plaintext[] decodeInputRecord( 205 byte[] header) throws IOException, BadPaddingException { 206 byte contentType = header[0]; // pos: 0 207 byte majorVersion = header[1]; // pos: 1 208 byte minorVersion = header[2]; // pos: 2 209 int contentLen = ((header[3] & 0xFF) << 8) + 210 (header[4] & 0xFF); // pos: 3, 4 211 212 if (SSLLogger.isOn && SSLLogger.isOn("record")) { 213 SSLLogger.fine( 214 "READ: " + 215 ProtocolVersion.nameOf(majorVersion, minorVersion) + 216 " " + ContentType.nameOf(contentType) + ", length = " + 217 contentLen); 218 } 219 220 // 221 // Check for upper bound. 222 // 223 // Note: May check packetSize limit in the future. 224 if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) { 225 throw new SSLProtocolException( 226 "Bad input record size, TLSCiphertext.length = " + contentLen); 227 } 228 229 // 230 // Read a complete record. 231 // 232 ByteBuffer destination = ByteBuffer.allocate(headerSize + contentLen); 233 int dstPos = destination.position(); 234 destination.put(temporary, 0, headerSize); 235 while (contentLen > 0) { 236 int howmuch = Math.min(temporary.length, contentLen); 237 int really = read(is, temporary, 0, howmuch); 238 if (really < 0) { 239 throw new EOFException("SSL peer shut down incorrectly"); 240 } 241 242 destination.put(temporary, 0, howmuch); 243 contentLen -= howmuch; 244 } 245 destination.flip(); 246 destination.position(dstPos + headerSize); 247 248 if (SSLLogger.isOn && SSLLogger.isOn("record")) { 249 SSLLogger.fine( 250 "READ: " + 251 ProtocolVersion.nameOf(majorVersion, minorVersion) + 252 " " + ContentType.nameOf(contentType) + ", length = " + 253 destination.remaining()); 254 } 255 256 // 257 // Decrypt the fragment 258 // 259 ByteBuffer fragment; 260 try { 261 Plaintext plaintext = 262 readCipher.decrypt(contentType, destination, null); 263 fragment = plaintext.fragment; 264 contentType = plaintext.contentType; 265 } catch (BadPaddingException bpe) { 266 throw bpe; 267 } catch (GeneralSecurityException gse) { 268 throw (SSLProtocolException)(new SSLProtocolException( 269 "Unexpected exception")).initCause(gse); 270 } 271 272 if (contentType != ContentType.HANDSHAKE.id && 273 handshakeBuffer != null && handshakeBuffer.hasRemaining()) { 274 throw new SSLProtocolException( 275 "Expecting a handshake fragment, but received " + 276 ContentType.nameOf(contentType)); 277 } 278 279 // 280 // parse handshake messages 281 // 282 if (contentType == ContentType.HANDSHAKE.id) { 283 ByteBuffer handshakeFrag = fragment; 284 if ((handshakeBuffer != null) && 285 (handshakeBuffer.remaining() != 0)) { 286 ByteBuffer bb = ByteBuffer.wrap(new byte[ 287 handshakeBuffer.remaining() + fragment.remaining()]); 288 bb.put(handshakeBuffer); 289 bb.put(fragment); 290 handshakeFrag = (ByteBuffer)bb.rewind(); 291 handshakeBuffer = null; 292 } 293 294 ArrayList<Plaintext> plaintexts = new ArrayList<>(5); 295 while (handshakeFrag.hasRemaining()) { 296 int remaining = handshakeFrag.remaining(); 297 if (remaining < handshakeHeaderSize) { 298 handshakeBuffer = ByteBuffer.wrap(new byte[remaining]); 299 handshakeBuffer.put(handshakeFrag); 300 handshakeBuffer.rewind(); 301 break; 302 } 303 304 handshakeFrag.mark(); 305 // skip the first byte: handshake type 306 byte handshakeType = handshakeFrag.get(); 307 int handshakeBodyLen = Record.getInt24(handshakeFrag); 308 if (handshakeBodyLen > SSLConfiguration.maxHandshakeMessageSize) { 309 throw new SSLProtocolException( 310 "The size of the handshake message (" 311 + handshakeBodyLen 312 + ") exceeds the maximum allowed size (" 313 + SSLConfiguration.maxHandshakeMessageSize 314 + ")"); 315 } 316 317 handshakeFrag.reset(); 318 int handshakeMessageLen = 319 handshakeHeaderSize + handshakeBodyLen; 320 if (remaining < handshakeMessageLen) { 321 handshakeBuffer = ByteBuffer.wrap(new byte[remaining]); 322 handshakeBuffer.put(handshakeFrag); 323 handshakeBuffer.rewind(); 324 break; 325 } if (remaining == handshakeMessageLen) { 326 if (handshakeHash.isHashable(handshakeType)) { 327 handshakeHash.receive(handshakeFrag); 328 } 329 330 plaintexts.add( 331 new Plaintext(contentType, 332 majorVersion, minorVersion, -1, -1L, handshakeFrag) 333 ); 334 break; 335 } else { 336 int fragPos = handshakeFrag.position(); 337 int fragLim = handshakeFrag.limit(); 338 int nextPos = fragPos + handshakeMessageLen; 339 handshakeFrag.limit(nextPos); 340 341 if (handshakeHash.isHashable(handshakeType)) { 342 handshakeHash.receive(handshakeFrag); 343 } 344 345 plaintexts.add( 346 new Plaintext(contentType, majorVersion, minorVersion, 347 -1, -1L, handshakeFrag.slice()) 348 ); 349 350 handshakeFrag.position(nextPos); 351 handshakeFrag.limit(fragLim); 352 } 353 } 354 355 return plaintexts.toArray(new Plaintext[0]); 356 } 357 358 return new Plaintext[] { 359 new Plaintext(contentType, 360 majorVersion, minorVersion, -1, -1L, fragment) 361 }; 362 } 363 364 private Plaintext[] handleUnknownRecord( 365 byte[] header) throws IOException, BadPaddingException { 366 byte firstByte = header[0]; 367 byte thirdByte = header[2]; 368 369 // Does it look like a Version 2 client hello (V2ClientHello)? 370 if (((firstByte & 0x80) != 0) && (thirdByte == 1)) { 371 /* 372 * If SSLv2Hello is not enabled, throw an exception. 373 */ 374 if (helloVersion != ProtocolVersion.SSL20Hello) { 375 throw new SSLHandshakeException("SSLv2Hello is not enabled"); 376 } 377 378 byte majorVersion = header[3]; 379 byte minorVersion = header[4]; 380 381 if ((majorVersion == ProtocolVersion.SSL20Hello.major) && 382 (minorVersion == ProtocolVersion.SSL20Hello.minor)) { 383 384 /* 385 * Looks like a V2 client hello, but not one saying 386 * "let's talk SSLv3". So we need to send an SSLv2 387 * error message, one that's treated as fatal by 388 * clients (Otherwise we'll hang.) 389 */ 390 os.write(SSLRecord.v2NoCipher); // SSLv2Hello 391 392 if (SSLLogger.isOn) { 393 if (SSLLogger.isOn("record")) { 394 SSLLogger.fine( 395 "Requested to negotiate unsupported SSLv2!"); 396 } 397 398 if (SSLLogger.isOn("packet")) { 399 SSLLogger.fine("Raw write", SSLRecord.v2NoCipher); 400 } 401 } 402 403 throw new SSLException("Unsupported SSL v2.0 ClientHello"); 404 } 405 406 int msgLen = ((header[0] & 0x7F) << 8) | (header[1] & 0xFF); 407 408 ByteBuffer destination = ByteBuffer.allocate(headerSize + msgLen); 409 destination.put(temporary, 0, headerSize); 410 msgLen -= 3; // had read 3 bytes of content as header 411 while (msgLen > 0) { 412 int howmuch = Math.min(temporary.length, msgLen); 413 int really = read(is, temporary, 0, howmuch); 414 if (really < 0) { 415 throw new EOFException("SSL peer shut down incorrectly"); 416 } 417 418 destination.put(temporary, 0, howmuch); 419 msgLen -= howmuch; 420 } 421 destination.flip(); 422 423 /* 424 * If we can map this into a V3 ClientHello, read and 425 * hash the rest of the V2 handshake, turn it into a 426 * V3 ClientHello message, and pass it up. 427 */ 428 destination.position(2); // exclude the header 429 handshakeHash.receive(destination); 430 destination.position(0); 431 432 ByteBuffer converted = convertToClientHello(destination); 433 434 if (SSLLogger.isOn && SSLLogger.isOn("packet")) { 435 SSLLogger.fine( 436 "[Converted] ClientHello", converted); 437 } 438 439 return new Plaintext[] { 440 new Plaintext(ContentType.HANDSHAKE.id, 441 majorVersion, minorVersion, -1, -1L, converted) 442 }; 443 } else { 444 if (((firstByte & 0x80) != 0) && (thirdByte == 4)) { 445 throw new SSLException("SSL V2.0 servers are not supported."); 446 } 447 448 throw new SSLException("Unsupported or unrecognized SSL message"); 449 } 450 } 451 452 // Read the exact bytes of data, otherwise, return -1. 453 private static int read(InputStream is, 454 byte[] buffer, int offset, int len) throws IOException { 455 int n = 0; 456 while (n < len) { 457 int readLen = is.read(buffer, offset + n, len - n); 458 if (readLen < 0) { 459 if (SSLLogger.isOn && SSLLogger.isOn("packet")) { 460 SSLLogger.fine("Raw read: EOF"); 461 } 462 return -1; 463 } 464 465 if (SSLLogger.isOn && SSLLogger.isOn("packet")) { 466 ByteBuffer bb = ByteBuffer.wrap(buffer, offset + n, readLen); 467 SSLLogger.fine("Raw read", bb); 468 } 469 470 n += readLen; 471 } 472 473 return n; 474 } 475 }