1 package org.apache.tomcat.util.net; 2 3 import java.io.IOException ; 4 import java.nio.ByteBuffer ; 5 import java.nio.channels.SelectionKey ; 6 import java.nio.channels.SocketChannel ; 7 import javax.net.ssl.SSLEngine; 8 import javax.net.ssl.SSLEngineResult; 9 import javax.net.ssl.SSLEngineResult.HandshakeStatus; 10 import javax.net.ssl.SSLEngineResult.Status; 11 import java.nio.channels.Selector ; 12 13 19 20 public class SecureNioChannel extends NioChannel { 21 22 protected ByteBuffer netInBuffer; 23 protected ByteBuffer netOutBuffer; 24 25 protected SSLEngine sslEngine; 26 27 protected boolean initHandshakeComplete = false; 28 protected HandshakeStatus initHandshakeStatus; 30 protected boolean closed = false; 31 protected boolean closing = false; 32 33 protected NioSelectorPool pool; 34 35 public SecureNioChannel(SocketChannel channel, SSLEngine engine, 36 ApplicationBufferHandler bufHandler, NioSelectorPool pool) throws IOException { 37 super(channel,bufHandler); 38 this.sslEngine = engine; 39 int appBufSize = sslEngine.getSession().getApplicationBufferSize(); 40 int netBufSize = sslEngine.getSession().getPacketBufferSize(); 41 if ( netInBuffer == null ) netInBuffer = ByteBuffer.allocateDirect(netBufSize); 43 if ( netOutBuffer == null ) netOutBuffer = ByteBuffer.allocateDirect(netBufSize); 44 45 this.pool = pool; 47 48 bufHandler.expand(bufHandler.getReadBuffer(), appBufSize); 51 bufHandler.expand(bufHandler.getWriteBuffer(), appBufSize); 52 reset(); 53 } 54 55 public void reset(SSLEngine engine) throws IOException { 56 this.sslEngine = engine; 57 reset(); 58 } 59 public void reset() throws IOException { 60 super.reset(); 61 netOutBuffer.position(0); 62 netOutBuffer.limit(0); 63 netInBuffer.position(0); 64 netInBuffer.limit(0); 65 initHandshakeComplete = false; 66 closed = false; 67 closing = false; 68 sslEngine.beginHandshake(); 70 initHandshakeStatus = sslEngine.getHandshakeStatus(); 71 } 72 73 public int getBufferSize() { 74 int size = super.getBufferSize(); 75 size += netInBuffer!=null?netInBuffer.capacity():0; 76 size += netOutBuffer!=null?netOutBuffer.capacity():0; 77 return size; 78 } 79 80 81 89 public boolean flush(Selector s, long timeout) throws IOException { 90 pool.write(netOutBuffer,this,s,timeout); 91 return !netOutBuffer.hasRemaining(); 92 } 93 94 100 protected boolean flush(ByteBuffer buf) throws IOException { 101 int remaining = buf.remaining(); 102 if ( remaining > 0 ) { 103 int written = sc.write(buf); 104 return written >= remaining; 105 }else { 106 return true; 107 } 108 } 109 110 121 public int handshake(boolean read, boolean write) throws IOException { 122 if ( initHandshakeComplete ) return 0; 124 if (!flush(netOutBuffer)) return SelectionKey.OP_WRITE; 126 SSLEngineResult handshake = null; 127 128 while (!initHandshakeComplete) { 129 switch ( initHandshakeStatus ) { 130 case NOT_HANDSHAKING: { 131 throw new IOException ("NOT_HANDSHAKING during handshake"); 133 } 134 case FINISHED: { 135 initHandshakeComplete = !netOutBuffer.hasRemaining(); 137 return initHandshakeComplete?0:SelectionKey.OP_WRITE; 139 } 140 case NEED_WRAP: { 141 handshake = handshakeWrap(write); 143 if ( handshake.getStatus() == Status.OK ){ 144 if (initHandshakeStatus == HandshakeStatus.NEED_TASK) 145 initHandshakeStatus = tasks(); 146 } else { 147 throw new IOException ("Unexpected status:" + handshake.getStatus() + " during handshake WRAP."); 149 } 150 if ( initHandshakeStatus != HandshakeStatus.NEED_UNWRAP || (!flush(netOutBuffer)) ) { 151 return SelectionKey.OP_WRITE; 153 } 154 } 157 case NEED_UNWRAP: { 158 handshake = handshakeUnwrap(read); 160 if ( handshake.getStatus() == Status.OK ) { 161 if (initHandshakeStatus == HandshakeStatus.NEED_TASK) 162 initHandshakeStatus = tasks(); 163 } else if ( handshake.getStatus() == Status.BUFFER_UNDERFLOW ){ 164 return SelectionKey.OP_READ; 166 } else { 167 throw new IOException ("Invalid handshake status:"+initHandshakeStatus+" during handshake UNWRAP."); 168 } break; 170 } 171 case NEED_TASK: { 172 initHandshakeStatus = tasks(); 173 break; 174 } 175 default: throw new IllegalStateException ("Invalid handshake status:"+initHandshakeStatus); 176 } } return initHandshakeComplete?0:(SelectionKey.OP_WRITE|SelectionKey.OP_READ); 181 } 182 183 187 protected SSLEngineResult.HandshakeStatus tasks() { 188 Runnable r = null; 189 while ( (r = sslEngine.getDelegatedTask()) != null) { 190 r.run(); 191 } 192 return sslEngine.getHandshakeStatus(); 193 } 194 195 201 protected SSLEngineResult handshakeWrap(boolean doWrite) throws IOException { 202 netOutBuffer.clear(); 205 SSLEngineResult result = sslEngine.wrap(bufHandler.getWriteBuffer(), netOutBuffer); 207 netOutBuffer.flip(); 209 initHandshakeStatus = result.getHandshakeStatus(); 211 if ( doWrite ) flush(netOutBuffer); 213 return result; 214 } 215 216 222 protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException { 223 224 if (netInBuffer.position() == netInBuffer.limit()) { 225 netInBuffer.clear(); 227 } 228 if ( doread ) { 229 int read = sc.read(netInBuffer); 231 if (read == -1) throw new IOException ("EOF encountered during handshake."); 232 } 233 SSLEngineResult result; 234 boolean cont = false; 235 do { 237 netInBuffer.flip(); 239 result = sslEngine.unwrap(netInBuffer, bufHandler.getReadBuffer()); 241 netInBuffer.compact(); 243 initHandshakeStatus = result.getHandshakeStatus(); 245 if ( result.getStatus() == SSLEngineResult.Status.OK && 246 result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) { 247 initHandshakeStatus = tasks(); 249 } 250 cont = result.getStatus() == SSLEngineResult.Status.OK && 252 initHandshakeStatus == HandshakeStatus.NEED_UNWRAP; 253 }while ( cont ); 254 return result; 255 } 256 257 269 public void close() throws IOException { 270 if (closing) return; 271 closing = true; 272 sslEngine.closeOutbound(); 273 274 if (!flush(netOutBuffer)) { 275 throw new IOException ("Remaining data in the network buffer, can't send SSL close message, force a close with close(true) instead"); 276 } 277 netOutBuffer.clear(); 279 SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer); 281 if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) { 283 throw new IOException ("Invalid close state, will not send network data."); 284 } 285 netOutBuffer.flip(); 287 flush(netOutBuffer); 289 290 closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP)); 292 } 293 294 299 public void close(boolean force) throws IOException { 300 try { 301 close(); 302 }finally { 303 if ( force || closed ) { 304 closed = true; 305 sc.socket().close(); 306 sc.close(); 307 } 308 } 309 } 310 311 320 public int read(ByteBuffer dst) throws IOException { 321 if ( dst != bufHandler.getReadBuffer() ) throw new IllegalArgumentException ("You can only read using the application read buffer provided by the handler."); 323 if ( closing || closed) return -1; 325 if (!initHandshakeComplete) throw new IllegalStateException ("Handshake incomplete, you must complete handshake before reading data."); 327 328 int netread = sc.read(netInBuffer); 330 if (netread == -1) return -1; 332 333 int read = 0; 335 SSLEngineResult unwrap; 337 do { 338 netInBuffer.flip(); 340 unwrap = sslEngine.unwrap(netInBuffer, dst); 342 netInBuffer.compact(); 344 345 if ( unwrap.getStatus()==Status.OK || unwrap.getStatus()==Status.BUFFER_UNDERFLOW ) { 346 read += unwrap.bytesProduced(); 348 if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks(); 350 if ( unwrap.getStatus() == Status.BUFFER_UNDERFLOW ) break; 352 }else { 353 throw new IOException ("Unable to unwrap data, invalid status: " + unwrap.getStatus()); 357 } 358 } while ( (netInBuffer.position() != 0)); return (read); 360 } 361 362 370 public int write(ByteBuffer src) throws IOException { 371 if ( src != bufHandler.getWriteBuffer() ) throw new IllegalArgumentException ("You can only write using the application write buffer provided by the handler."); 373 if ( closing || closed) throw new IOException ("Channel is in closing state."); 375 376 int written = 0; 378 379 if (!flush(netOutBuffer)) { 380 return written; 382 } 383 384 387 netOutBuffer.clear(); 388 389 SSLEngineResult result = sslEngine.wrap(src, netOutBuffer); 390 written = result.bytesConsumed(); 391 netOutBuffer.flip(); 392 393 if (result.getStatus() == Status.OK) { 394 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks(); 395 } else { 396 throw new IOException ("Unable to wrap data, invalid engine state: " +result.getStatus()); 397 } 398 399 flush(netOutBuffer); 401 402 return written; 403 } 404 405 409 public static interface ApplicationBufferHandler { 410 public ByteBuffer expand(ByteBuffer buffer, int remaining); 411 public ByteBuffer getReadBuffer(); 412 public ByteBuffer getWriteBuffer(); 413 } 414 415 public ApplicationBufferHandler getBufHandler() { 416 return bufHandler; 417 } 418 419 public boolean isInitHandshakeComplete() { 420 return initHandshakeComplete; 421 } 422 423 public boolean isClosing() { 424 return closing; 425 } 426 427 public SSLEngine getSslEngine() { 428 return sslEngine; 429 } 430 431 public ByteBuffer getEmptyBuf() { 432 return emptyBuf; 433 } 434 435 public void setBufHandler(ApplicationBufferHandler bufHandler) { 436 this.bufHandler = bufHandler; 437 } 438 439 public SocketChannel getIOChannel() { 440 return sc; 441 } 442 443 } | Popular Tags |