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