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