1 /* 2 * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 import java.io.*; 42 import java.nio.*; 43 import java.nio.channels.*; 44 import javax.net.ssl.*; 45 import javax.net.ssl.SSLEngineResult.*; 46 47 /** 48 * A helper class which performs I/O using the SSLEngine API. 49 * <P> 50 * Each connection has a SocketChannel and a SSLEngine that is 51 * used through the lifetime of the Channel. We allocate byte buffers 52 * for use as the outbound and inbound network buffers. 53 * 54 * <PRE> 55 * Application Data 56 * src requestBB 57 * | ^ 58 * | | | 59 * v | | 60 * +----+-----|-----+----+ 61 * | | | 62 * | SSL|Engine | 63 * wrap() | | | unwrap() 64 * | OUTBOUND | INBOUND | 65 * | | | 66 * +----+-----|-----+----+ 67 * | | ^ 68 * | | | 69 * v | 70 * outNetBB inNetBB 71 * Net data 72 * </PRE> 73 * 74 * These buffers handle all of the intermediary data for the SSL 75 * connection. To make things easy, we'll require outNetBB be 76 * completely flushed before trying to wrap any more data, but we 77 * could certainly remove that restriction by using larger buffers. 78 * <P> 79 * There are many, many ways to handle compute and I/O strategies. 80 * What follows is a relatively simple one. The reader is encouraged 81 * to develop the strategy that best fits the application. 82 * <P> 83 * In most of the non-blocking operations in this class, we let the 84 * Selector tell us when we're ready to attempt an I/O operation (by the 85 * application repeatedly calling our methods). Another option would be 86 * to attempt the operation and return from the method when no forward 87 * progress can be made. 88 * <P> 89 * There's lots of room for enhancements and improvement in this example. 90 * <P> 91 * We're checking for SSL/TLS end-of-stream truncation attacks via 92 * sslEngine.closeInbound(). When you reach the end of a input stream 93 * via a read() returning -1 or an IOException, we call 94 * sslEngine.closeInbound() to signal to the sslEngine that no more 95 * input will be available. If the peer's close_notify message has not 96 * yet been received, this could indicate a trucation attack, in which 97 * an attacker is trying to prematurely close the connection. The 98 * closeInbound() will throw an exception if this condition were 99 * present. 100 * 101 * @author Brad R. Wetmore 102 * @author Mark Reinhold 103 */ 104 class ChannelIOSecure extends ChannelIO { 105 106 private SSLEngine sslEngine = null; 107 108 private int appBBSize; 109 private int netBBSize; 110 111 /* 112 * All I/O goes through these buffers. 113 * <P> 114 * It might be nice to use a cache of ByteBuffers so we're 115 * not alloc/dealloc'ing ByteBuffer's for each new SSLEngine. 116 * <P> 117 * We use our superclass' requestBB for our application input buffer. 118 * Outbound application data is supplied to us by our callers. 119 */ 120 private ByteBuffer inNetBB; 121 private ByteBuffer outNetBB; 122 123 /* 124 * An empty ByteBuffer for use when one isn't available, say 125 * as a source buffer during initial handshake wraps or for close 126 * operations. 127 */ 128 private static ByteBuffer hsBB = ByteBuffer.allocate(0); 129 130 /* 131 * The FileChannel we're currently transferTo'ing (reading). 132 */ 133 private ByteBuffer fileChannelBB = null; 134 135 /* 136 * During our initial handshake, keep track of the next 137 * SSLEngine operation that needs to occur: 138 * 139 * NEED_WRAP/NEED_UNWRAP 140 * 141 * Once the initial handshake has completed, we can short circuit 142 * handshake checks with initialHSComplete. 143 */ 144 private HandshakeStatus initialHSStatus; 145 private boolean initialHSComplete; 146 147 /* 148 * We have received the shutdown request by our caller, and have 149 * closed our outbound side. 150 */ 151 private boolean shutdown = false; 152 153 /* 154 * Constructor for a secure ChannelIO variant. 155 */ ChannelIOSecure(SocketChannel sc, boolean blocking, SSLContext sslc)156 protected ChannelIOSecure(SocketChannel sc, boolean blocking, 157 SSLContext sslc) throws IOException { 158 super(sc, blocking); 159 160 /* 161 * We're a server, so no need to use host/port variant. 162 * 163 * The first call for a server is a NEED_UNWRAP. 164 */ 165 sslEngine = sslc.createSSLEngine(); 166 sslEngine.setUseClientMode(false); 167 initialHSStatus = HandshakeStatus.NEED_UNWRAP; 168 initialHSComplete = false; 169 170 // Create a buffer using the normal expected packet size we'll 171 // be getting. This may change, depending on the peer's 172 // SSL implementation. 173 netBBSize = sslEngine.getSession().getPacketBufferSize(); 174 inNetBB = ByteBuffer.allocate(netBBSize); 175 outNetBB = ByteBuffer.allocate(netBBSize); 176 outNetBB.position(0); 177 outNetBB.limit(0); 178 } 179 180 /* 181 * Static factory method for creating a secure ChannelIO object. 182 * <P> 183 * We need to allocate different sized application data buffers 184 * based on whether we're secure or not. We can't determine 185 * this until our sslEngine is created. 186 */ getInstance(SocketChannel sc, boolean blocking, SSLContext sslc)187 static ChannelIOSecure getInstance(SocketChannel sc, boolean blocking, 188 SSLContext sslc) throws IOException { 189 190 ChannelIOSecure cio = new ChannelIOSecure(sc, blocking, sslc); 191 192 // Create a buffer using the normal expected application size we'll 193 // be getting. This may change, depending on the peer's 194 // SSL implementation. 195 cio.appBBSize = cio.sslEngine.getSession().getApplicationBufferSize(); 196 cio.requestBB = ByteBuffer.allocate(cio.appBBSize); 197 198 return cio; 199 } 200 201 /* 202 * Calls up to the superclass to adjust the buffer size 203 * by an appropriate increment. 204 */ resizeRequestBB()205 protected void resizeRequestBB() { 206 resizeRequestBB(appBBSize); 207 } 208 209 /* 210 * Adjust the inbount network buffer to an appropriate size. 211 */ resizeResponseBB()212 private void resizeResponseBB() { 213 ByteBuffer bb = ByteBuffer.allocate(netBBSize); 214 inNetBB.flip(); 215 bb.put(inNetBB); 216 inNetBB = bb; 217 } 218 219 /* 220 * Writes bb to the SocketChannel. 221 * <P> 222 * Returns true when the ByteBuffer has no remaining data. 223 */ tryFlush(ByteBuffer bb)224 private boolean tryFlush(ByteBuffer bb) throws IOException { 225 super.write(bb); 226 return !bb.hasRemaining(); 227 } 228 229 /* 230 * Perform any handshaking processing. 231 * <P> 232 * This variant is for Servers without SelectionKeys (e.g. 233 * blocking). 234 */ doHandshake()235 boolean doHandshake() throws IOException { 236 return doHandshake(null); 237 } 238 239 /* 240 * Perform any handshaking processing. 241 * <P> 242 * If a SelectionKey is passed, register for selectable 243 * operations. 244 * <P> 245 * In the blocking case, our caller will keep calling us until 246 * we finish the handshake. Our reads/writes will block as expected. 247 * <P> 248 * In the non-blocking case, we just received the selection notification 249 * that this channel is ready for whatever the operation is, so give 250 * it a try. 251 * <P> 252 * return: 253 * true when handshake is done. 254 * false while handshake is in progress 255 */ doHandshake(SelectionKey sk)256 boolean doHandshake(SelectionKey sk) throws IOException { 257 258 SSLEngineResult result; 259 260 if (initialHSComplete) { 261 return initialHSComplete; 262 } 263 264 /* 265 * Flush out the outgoing buffer, if there's anything left in 266 * it. 267 */ 268 if (outNetBB.hasRemaining()) { 269 270 if (!tryFlush(outNetBB)) { 271 return false; 272 } 273 274 // See if we need to switch from write to read mode. 275 276 switch (initialHSStatus) { 277 278 /* 279 * Is this the last buffer? 280 */ 281 case FINISHED: 282 initialHSComplete = true; 283 // Fall-through to reregister need for a Read. 284 285 case NEED_UNWRAP: 286 if (sk != null) { 287 sk.interestOps(SelectionKey.OP_READ); 288 } 289 break; 290 } 291 292 return initialHSComplete; 293 } 294 295 296 switch (initialHSStatus) { 297 298 case NEED_UNWRAP: 299 if (sc.read(inNetBB) == -1) { 300 sslEngine.closeInbound(); 301 return initialHSComplete; 302 } 303 304 needIO: 305 while (initialHSStatus == HandshakeStatus.NEED_UNWRAP) { 306 resizeRequestBB(); // expected room for unwrap 307 inNetBB.flip(); 308 result = sslEngine.unwrap(inNetBB, requestBB); 309 inNetBB.compact(); 310 311 initialHSStatus = result.getHandshakeStatus(); 312 313 switch (result.getStatus()) { 314 315 case OK: 316 switch (initialHSStatus) { 317 case NOT_HANDSHAKING: 318 throw new IOException( 319 "Not handshaking during initial handshake"); 320 321 case NEED_TASK: 322 initialHSStatus = doTasks(); 323 break; 324 325 case FINISHED: 326 initialHSComplete = true; 327 break needIO; 328 } 329 330 break; 331 332 case BUFFER_UNDERFLOW: 333 // Resize buffer if needed. 334 netBBSize = sslEngine.getSession().getPacketBufferSize(); 335 if (netBBSize > inNetBB.capacity()) { 336 resizeResponseBB(); 337 } 338 339 /* 340 * Need to go reread the Channel for more data. 341 */ 342 if (sk != null) { 343 sk.interestOps(SelectionKey.OP_READ); 344 } 345 break needIO; 346 347 case BUFFER_OVERFLOW: 348 // Reset the application buffer size. 349 appBBSize = 350 sslEngine.getSession().getApplicationBufferSize(); 351 break; 352 353 default: //CLOSED: 354 throw new IOException("Received" + result.getStatus() + 355 "during initial handshaking"); 356 } 357 } // "needIO" block. 358 359 /* 360 * Just transitioned from read to write. 361 */ 362 if (initialHSStatus != HandshakeStatus.NEED_WRAP) { 363 break; 364 } 365 366 // Fall through and fill the write buffers. 367 368 case NEED_WRAP: 369 /* 370 * The flush above guarantees the out buffer to be empty 371 */ 372 outNetBB.clear(); 373 result = sslEngine.wrap(hsBB, outNetBB); 374 outNetBB.flip(); 375 376 initialHSStatus = result.getHandshakeStatus(); 377 378 switch (result.getStatus()) { 379 case OK: 380 381 if (initialHSStatus == HandshakeStatus.NEED_TASK) { 382 initialHSStatus = doTasks(); 383 } 384 385 if (sk != null) { 386 sk.interestOps(SelectionKey.OP_WRITE); 387 } 388 389 break; 390 391 default: // BUFFER_OVERFLOW/BUFFER_UNDERFLOW/CLOSED: 392 throw new IOException("Received" + result.getStatus() + 393 "during initial handshaking"); 394 } 395 break; 396 397 default: // NOT_HANDSHAKING/NEED_TASK/FINISHED 398 throw new RuntimeException("Invalid Handshaking State" + 399 initialHSStatus); 400 } // switch 401 402 return initialHSComplete; 403 } 404 405 /* 406 * Do all the outstanding handshake tasks in the current Thread. 407 */ doTasks()408 private SSLEngineResult.HandshakeStatus doTasks() { 409 410 Runnable runnable; 411 412 /* 413 * We could run this in a separate thread, but 414 * do in the current for now. 415 */ 416 while ((runnable = sslEngine.getDelegatedTask()) != null) { 417 runnable.run(); 418 } 419 return sslEngine.getHandshakeStatus(); 420 } 421 422 /* 423 * Read the channel for more information, then unwrap the 424 * (hopefully application) data we get. 425 * <P> 426 * If we run out of data, we'll return to our caller (possibly using 427 * a Selector) to get notification that more is available. 428 * <P> 429 * Each call to this method will perform at most one underlying read(). 430 */ read()431 int read() throws IOException { 432 SSLEngineResult result; 433 434 if (!initialHSComplete) { 435 throw new IllegalStateException(); 436 } 437 438 int pos = requestBB.position(); 439 440 if (sc.read(inNetBB) == -1) { 441 sslEngine.closeInbound(); // probably throws exception 442 return -1; 443 } 444 445 do { 446 resizeRequestBB(); // expected room for unwrap 447 inNetBB.flip(); 448 result = sslEngine.unwrap(inNetBB, requestBB); 449 inNetBB.compact(); 450 451 /* 452 * Could check here for a renegotation, but we're only 453 * doing a simple read/write, and won't have enough state 454 * transitions to do a complete handshake, so ignore that 455 * possibility. 456 */ 457 switch (result.getStatus()) { 458 459 case BUFFER_OVERFLOW: 460 // Reset the application buffer size. 461 appBBSize = sslEngine.getSession().getApplicationBufferSize(); 462 break; 463 464 case BUFFER_UNDERFLOW: 465 // Resize buffer if needed. 466 netBBSize = sslEngine.getSession().getPacketBufferSize(); 467 if (netBBSize > inNetBB.capacity()) { 468 resizeResponseBB(); 469 470 break; // break, next read will support larger buffer. 471 } 472 case OK: 473 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { 474 doTasks(); 475 } 476 break; 477 478 default: 479 throw new IOException("sslEngine error during data read: " + 480 result.getStatus()); 481 } 482 } while ((inNetBB.position() != 0) && 483 result.getStatus() != Status.BUFFER_UNDERFLOW); 484 485 return (requestBB.position() - pos); 486 } 487 488 /* 489 * Try to write out as much as possible from the src buffer. 490 */ write(ByteBuffer src)491 int write(ByteBuffer src) throws IOException { 492 493 if (!initialHSComplete) { 494 throw new IllegalStateException(); 495 } 496 497 return doWrite(src); 498 } 499 500 /* 501 * Try to flush out any existing outbound data, then try to wrap 502 * anything new contained in the src buffer. 503 * <P> 504 * Return the number of bytes actually consumed from the buffer, 505 * but the data may actually be still sitting in the output buffer, 506 * waiting to be flushed. 507 */ doWrite(ByteBuffer src)508 private int doWrite(ByteBuffer src) throws IOException { 509 int retValue = 0; 510 511 if (outNetBB.hasRemaining() && !tryFlush(outNetBB)) { 512 return retValue; 513 } 514 515 /* 516 * The data buffer is empty, we can reuse the entire buffer. 517 */ 518 outNetBB.clear(); 519 520 SSLEngineResult result = sslEngine.wrap(src, outNetBB); 521 retValue = result.bytesConsumed(); 522 523 outNetBB.flip(); 524 525 switch (result.getStatus()) { 526 527 case OK: 528 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { 529 doTasks(); 530 } 531 break; 532 533 default: 534 throw new IOException("sslEngine error during data write: " + 535 result.getStatus()); 536 } 537 538 /* 539 * Try to flush the data, regardless of whether or not 540 * it's been selected. Odds of a write buffer being full 541 * is less than a read buffer being empty. 542 */ 543 if (outNetBB.hasRemaining()) { 544 tryFlush(outNetBB); 545 } 546 547 return retValue; 548 } 549 550 /* 551 * Perform a FileChannel.TransferTo on the socket channel. 552 * <P> 553 * We have to copy the data into an intermediary app ByteBuffer 554 * first, then send it through the SSLEngine. 555 * <P> 556 * We return the number of bytes actually read out of the 557 * filechannel. However, the data may actually be stuck 558 * in the fileChannelBB or the outNetBB. The caller 559 * is responsible for making sure to call dataFlush() 560 * before shutting down. 561 */ transferTo(FileChannel fc, long pos, long len)562 long transferTo(FileChannel fc, long pos, long len) throws IOException { 563 564 if (!initialHSComplete) { 565 throw new IllegalStateException(); 566 } 567 568 if (fileChannelBB == null) { 569 fileChannelBB = ByteBuffer.allocate(appBBSize); 570 fileChannelBB.limit(0); 571 } 572 573 fileChannelBB.compact(); 574 int fileRead = fc.read(fileChannelBB); 575 fileChannelBB.flip(); 576 577 /* 578 * We ignore the return value here, we return the 579 * number of bytes actually consumed from the the file. 580 * We'll flush the output buffer before we start shutting down. 581 */ 582 doWrite(fileChannelBB); 583 584 return fileRead; 585 } 586 587 /* 588 * Flush any remaining data. 589 * <P> 590 * Return true when the fileChannelBB and outNetBB are empty. 591 */ dataFlush()592 boolean dataFlush() throws IOException { 593 boolean fileFlushed = true; 594 595 if ((fileChannelBB != null) && fileChannelBB.hasRemaining()) { 596 doWrite(fileChannelBB); 597 fileFlushed = !fileChannelBB.hasRemaining(); 598 } else if (outNetBB.hasRemaining()) { 599 tryFlush(outNetBB); 600 } 601 602 return (fileFlushed && !outNetBB.hasRemaining()); 603 } 604 605 /* 606 * Begin the shutdown process. 607 * <P> 608 * Close out the SSLEngine if not already done so, then 609 * wrap our outgoing close_notify message and try to send it on. 610 * <P> 611 * Return true when we're done passing the shutdown messsages. 612 */ shutdown()613 boolean shutdown() throws IOException { 614 615 if (!shutdown) { 616 sslEngine.closeOutbound(); 617 shutdown = true; 618 } 619 620 if (outNetBB.hasRemaining() && tryFlush(outNetBB)) { 621 return false; 622 } 623 624 /* 625 * By RFC 2616, we can "fire and forget" our close_notify 626 * message, so that's what we'll do here. 627 */ 628 outNetBB.clear(); 629 SSLEngineResult result = sslEngine.wrap(hsBB, outNetBB); 630 if (result.getStatus() != Status.CLOSED) { 631 throw new SSLException("Improper close state"); 632 } 633 outNetBB.flip(); 634 635 /* 636 * We won't wait for a select here, but if this doesn't work, 637 * we'll cycle back through on the next select. 638 */ 639 if (outNetBB.hasRemaining()) { 640 tryFlush(outNetBB); 641 } 642 643 return (!outNetBB.hasRemaining() && 644 (result.getHandshakeStatus() != HandshakeStatus.NEED_WRAP)); 645 } 646 647 /* 648 * close() is not overridden 649 */ 650 } 651