/** * Encrypt provided buffer. Encrypted data returned by getOutNetBuffer(). * * @param src * data to encrypt * @throws SSLException * on errors */ /* no qualifier */void encrypt(ByteBuffer src) throws SSLException { if (!handshakeComplete) { throw new IllegalStateException(); } if (!src.hasRemaining()) { if (outNetBuffer == null) { outNetBuffer = emptyBuffer; } return; } createOutNetBuffer(src.remaining()); // Loop until there is no more data in src while (src.hasRemaining()) { SSLEngineResult result = sslEngine.wrap(src, outNetBuffer.buf()); if (result.getStatus() == SSLEngineResult.Status.OK) { if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) { doTasks(); } } else if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) { outNetBuffer.capacity(outNetBuffer.capacity() << 1); outNetBuffer.limit(outNetBuffer.capacity()); } else { throw new SSLException("SSLEngine error during encrypt: " + result.getStatus() + " src: " + src + "outNetBuffer: " + outNetBuffer); } } outNetBuffer.flip(); }
/** * Start SSL shutdown process. * * @return <tt>true</tt> if shutdown process is started. <tt>false</tt> if * shutdown process is already finished. * @throws SSLException * on errors */ /* no qualifier */boolean closeOutbound() throws SSLException { if (sslEngine == null || sslEngine.isOutboundDone()) { return false; } sslEngine.closeOutbound(); createOutNetBuffer(0); SSLEngineResult result; for (;;) { result = sslEngine.wrap(emptyBuffer.buf(), outNetBuffer.buf()); if (result.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) { outNetBuffer.capacity(outNetBuffer.capacity() << 1); outNetBuffer.limit(outNetBuffer.capacity()); } else { break; } } if (result.getStatus() != SSLEngineResult.Status.CLOSED) { throw new SSLException("Improper close state: " + result); } outNetBuffer.flip(); return true; }
/** * @param res * @throws SSLException */ private void checkStatus(SSLEngineResult res) throws SSLException { SSLEngineResult.Status status = res.getStatus(); /* * The status may be: * OK - Normal operation * OVERFLOW - Should never happen since the application buffer is sized to hold the maximum * packet size. * UNDERFLOW - Need to read more data from the socket. It's normal. * CLOSED - The other peer closed the socket. Also normal. */ if (status == SSLEngineResult.Status.BUFFER_OVERFLOW) { throw new SSLException("SSLEngine error during decrypt: " + status + " inNetBuffer: " + inNetBuffer + "appBuffer: " + appBuffer); } }
private void checkResult(SSLEngineResult result, boolean wrap) throws SSLException { handshakeStatus = result.getHandshakeStatus(); resultStatus = result.getStatus(); if (resultStatus != Status.OK && (wrap || resultStatus != Status.BUFFER_UNDERFLOW)) { throw new SSLException("TODO"); } if (wrap && result.bytesConsumed() != 0) { throw new SSLException("TODO"); } if (!wrap && result.bytesProduced() != 0) { throw new SSLException("TODO"); } }
/** * Sends a SSL close message, will not physically close the connection here.<br> * To close the connection, you could do something like * <pre><code> * close(); * while (isOpen() && !myTimeoutFunction()) Thread.sleep(25); * if ( isOpen() ) close(true); //forces a close if you timed out * </code></pre> * @throws IOException if an I/O error occurs * @throws IOException if there is data on the outgoing network buffer and we are unable to flush it * TODO Implement this java.io.Closeable method */ @Override public void close() throws IOException { if (closing) return; closing = true; sslEngine.closeOutbound(); if (!flush(netOutBuffer)) { throw new IOException("Remaining data in the network buffer, can't send SSL close message, force a close with close(true) instead"); } //prep the buffer for the close message netOutBuffer.clear(); //perform the close, since we called sslEngine.closeOutbound SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer); //we should be in a close state if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) { throw new IOException("Invalid close state, will not send network data."); } //prepare the buffer for writing netOutBuffer.flip(); //if there is data to be written flush(netOutBuffer); //is the channel closed? closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP)); }
public SSLSocketChannel2( SocketChannel channel , SSLEngine sslEngine , ExecutorService exec , SelectionKey key ) throws IOException { if( channel == null || sslEngine == null || exec == null ) throw new IllegalArgumentException( "parameter must not be null" ); this.socketChannel = channel; this.sslEngine = sslEngine; this.exec = exec; readEngineResult = writeEngineResult = new SSLEngineResult( Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0 ); // init to prevent NPEs tasks = new ArrayList<Future<?>>( 3 ); if( key != null ) { key.interestOps( key.interestOps() | SelectionKey.OP_WRITE ); this.selectionKey = key; } createBuffers( sslEngine.getSession() ); // kick off handshake socketChannel.write( wrap( emptybuffer ) );// initializes res processHandshake(); }
public SSLSocketChannel2(SocketChannel channel, SSLEngine sslEngine, ExecutorService exec, SelectionKey key) throws IOException { if (channel == null || sslEngine == null || exec == null) { throw new IllegalArgumentException("parameter must not be null"); } this.socketChannel = channel; this.sslEngine = sslEngine; this.exec = exec; readEngineResult = writeEngineResult = new SSLEngineResult(Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0); // init to prevent NPEs tasks = new ArrayList<Future<?>>(3); if (key != null) { key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); this.selectionKey = key; } createBuffers(sslEngine.getSession()); // kick off handshake socketChannel.write(wrap(emptybuffer));// initializes res processHandshake(); }
public int write(ByteBuffer src) throws IOException { if (!isHandShakeComplete()) { processHandshake(); return 0; } // assert ( bufferallocations > 1 ); //see #190 //if( bufferallocations <= 1 ) { // createBuffers( sslEngine.getSession() ); //} int num = socketChannel.write(wrap(src)); if (writeEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) { throw new EOFException("Connection is closed"); } return num; }
/** * {@link #read(ByteBuffer)} may not be to leave all buffers(inData, * inCrypt) * */ private int readRemaining(ByteBuffer dst) throws SSLException { if (inData.hasRemaining()) { return transfereTo(inData, dst); } if (!inData.hasRemaining()) { inData.clear(); } // test if some bytes left from last read (e.g. BUFFER_UNDERFLOW) if (inCrypt.hasRemaining()) { unwrap(); int amount = transfereTo(inData, dst); if (readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) { return -1; } if (amount > 0) { return amount; } } return 0; }
/** * Performs the WRAP function * @param doWrite boolean * @return SSLEngineResult * @throws IOException */ private SSLEngineResult handshakeWrap(boolean doWrite) throws IOException { log.trace("SSLHandshake handshakeWrap {}", channelId); if (netWriteBuffer.hasRemaining()) throw new IllegalStateException("handshakeWrap called with netWriteBuffer not empty"); //this should never be called with a network buffer that contains data //so we can clear it here. netWriteBuffer.clear(); SSLEngineResult result = sslEngine.wrap(emptyBuf, netWriteBuffer); //prepare the results to be written netWriteBuffer.flip(); handshakeStatus = result.getHandshakeStatus(); if (result.getStatus() == SSLEngineResult.Status.OK && result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { handshakeStatus = runDelegatedTasks(); } if (doWrite) flush(netWriteBuffer); return result; }
/** * Perform handshake unwrap * @param doRead boolean * @return SSLEngineResult * @throws IOException */ private SSLEngineResult handshakeUnwrap(boolean doRead) throws IOException { log.trace("SSLHandshake handshakeUnwrap {}", channelId); SSLEngineResult result; if (doRead) { int read = socketChannel.read(netReadBuffer); if (read == -1) throw new EOFException("EOF during handshake."); } boolean cont; do { //prepare the buffer with the incoming data netReadBuffer.flip(); result = sslEngine.unwrap(netReadBuffer, appReadBuffer); netReadBuffer.compact(); handshakeStatus = result.getHandshakeStatus(); if (result.getStatus() == SSLEngineResult.Status.OK && result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { handshakeStatus = runDelegatedTasks(); } cont = result.getStatus() == SSLEngineResult.Status.OK && handshakeStatus == HandshakeStatus.NEED_UNWRAP; log.trace("SSLHandshake handshakeUnwrap: handshakeStatus {} status {}", handshakeStatus, result.getStatus()); } while (netReadBuffer.position() != 0 && cont); return result; }
/** * send the data in the given ByteBuffer. If a handshake is needed * then this is handled within this method. When this call returns, * all of the given user data has been sent and any handshake has been * completed. Caller should check if engine has been closed. */ WrapperResult sendData (ByteBuffer[] src, int offset, int len) throws IOException { WrapperResult r = WrapperResult.createOK(); while (countBytes(src, offset, len) > 0) { r = wrapper.wrapAndSend(src, offset, len, false); Status status = r.result.getStatus(); if (status == Status.CLOSED) { doClosure (); return r; } HandshakeStatus hs_status = r.result.getHandshakeStatus(); if (hs_status != HandshakeStatus.FINISHED && hs_status != HandshakeStatus.NOT_HANDSHAKING) { doHandshake(hs_status); } } return r; }
/** * read data thru the engine into the given ByteBuffer. If the * given buffer was not large enough, a new one is allocated * and returned. This call handles handshaking automatically. * Caller should check if engine has been closed. */ WrapperResult recvData (ByteBuffer dst) throws IOException { /* we wait until some user data arrives */ int mark = dst.position(); WrapperResult r = null; int pos = dst.position(); while (dst.position() == pos) { r = wrapper.recvAndUnwrap (dst); dst = (r.buf != dst) ? r.buf: dst; Status status = r.result.getStatus(); if (status == Status.CLOSED) { doClosure (); return r; } HandshakeStatus hs_status = r.result.getHandshakeStatus(); if (hs_status != HandshakeStatus.FINISHED && hs_status != HandshakeStatus.NOT_HANDSHAKING) { doHandshake (hs_status); } } Utils.flipToMark(dst, mark); return r; }
public SSLSocketChannel2( SocketChannel channel , SSLEngine sslEngine , ExecutorService exec , SelectionKey key ) throws IOException { if( channel == null || sslEngine == null || exec == null ) throw new IllegalArgumentException( "parameter must not be null" ); this.socketChannel = channel; this.sslEngine = sslEngine; this.exec = exec; readEngineResult = writeEngineResult = new SSLEngineResult( Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0 ); // init to prevent NPEs tasks = new ArrayList<Future<?>>( 3 ); if( key != null ) { key.interestOps( key.interestOps() | SelectionKey.OP_WRITE ); this.selectionKey = key; } createBuffers( sslEngine.getSession() ); // kick off request socketChannel.write( wrap( emptybuffer ) );// initializes res processHandshake(); }
/** * performs the unwrap operation by unwrapping from {@link #inCrypt} to {@link #inData} **/ private synchronized ByteBuffer unwrap() throws SSLException { int rem; //There are some ssl test suites, which get around the selector.select() call, which cause an infinite unwrap and 100% cpu usage (see #459 and #458) if(readEngineResult.getStatus() == Status.CLOSED && sslEngine.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING){ try { close(); } catch (IOException e) { //Not really interesting } } do { rem = inData.remaining(); readEngineResult = sslEngine.unwrap( inCrypt, inData ); } while ( readEngineResult.getStatus() == Status.OK && ( rem != inData.remaining() || sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP ) ); inData.flip(); return inData; }
public int write( ByteBuffer src ) throws IOException { if( !isHandShakeComplete() ) { processHandshake(); return 0; } // assert ( bufferallocations > 1 ); //see #190 //if( bufferallocations <= 1 ) { // createBuffers( sslEngine.getSession() ); //} int num = socketChannel.write( wrap( src ) ); if (writeEngineResult.getStatus() == Status.CLOSED) { throw new EOFException("Connection is closed"); } return num; }
/** * {@link #read(ByteBuffer)} may not be to leave all buffers(inData, inCrypt) **/ private int readRemaining( ByteBuffer dst ) throws SSLException { if( inData.hasRemaining() ) { return transfereTo( inData, dst ); } if( !inData.hasRemaining() ) inData.clear(); // test if some bytes left from last read (e.key. BUFFER_UNDERFLOW) if( inCrypt.hasRemaining() ) { unwrap(); int amount = transfereTo( inData, dst ); if (readEngineResult.getStatus() == Status.CLOSED) { return -1; } if( amount > 0 ) return amount; } return 0; }
public SSLSocketChannel(SocketChannel channel, SSLEngine sslEngine, ExecutorService exec, SelectionKey key) throws IOException { if(channel == null || sslEngine == null || exec == null) throw new IllegalArgumentException("parameter must not be null"); this.socketChannel = channel; this.sslEngine = sslEngine; this.exec = exec; readEngineResult = writeEngineResult = new SSLEngineResult(Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0); // init to prevent NPEs tasks = new ArrayList<Future<?>>(3); if(key != null) { key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); this.selectionKey = key; } createBuffers(sslEngine.getSession()); socketChannel.write(wrap(emptybuffer)); processHandshake(); }
private int readRemaining(ByteBuffer dst) throws SSLException { if(inData.hasRemaining()) { return transfereTo(inData, dst); } if(!inData.hasRemaining()) inData.clear(); if(inCrypt.hasRemaining()) { unwrap(); int amount = transfereTo(inData, dst); if (readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) { return -1; } if(amount > 0) return amount; } return 0; }
public int write( ByteBuffer src ) throws IOException { if( !isHandShakeComplete() ) { processHandshake(); return 0; } // assert ( bufferallocations > 1 ); //see #190 //if( bufferallocations <= 1 ) { // createBuffers( sslEngine.getSession() ); //} int num = socketChannel.write( wrap( src ) ); if (writeEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) { throw new EOFException("Connection is closed"); } return num; }
/** * {@link #read(ByteBuffer)} may not be to leave all buffers(inData, inCrypt) **/ private int readRemaining( ByteBuffer dst ) throws SSLException { if( inData.hasRemaining() ) { return transfereTo( inData, dst ); } if( !inData.hasRemaining() ) inData.clear(); // test if some bytes left from last read (e.g. BUFFER_UNDERFLOW) if( inCrypt.hasRemaining() ) { unwrap(); int amount = transfereTo( inData, dst ); if (readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) { return -1; } if( amount > 0 ) return amount; } return 0; }
public SSLSocketChannel2(SocketChannel channel, SSLEngine sslEngine, ExecutorService exec, SelectionKey key) throws IOException { if (channel == null || sslEngine == null || exec == null) throw new IllegalArgumentException("parameter must not be null"); this.socketChannel = channel; this.sslEngine = sslEngine; this.exec = exec; readEngineResult = writeEngineResult = new SSLEngineResult(Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0); // init to prevent NPEs tasks = new ArrayList<Future<?>>(3); if (key != null) { key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); this.selectionKey = key; } createBuffers(sslEngine.getSession()); // kick off handshake socketChannel.write(wrap(emptybuffer));// initializes res processHandshake(); }
/** * {@link #read(ByteBuffer)} may not be to leave all buffers(inData, inCrypt) **/ private int readRemaining(ByteBuffer dst) throws SSLException { if (inData.hasRemaining()) { return transfereTo(inData, dst); } if (!inData.hasRemaining()) inData.clear(); // test if some bytes left from last read (e.g. BUFFER_UNDERFLOW) if (inCrypt.hasRemaining()) { unwrap(); int amount = transfereTo(inData, dst); if (readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) { return -1; } if (amount > 0) return amount; } return 0; }
/** * Performs raw unwrap from network read buffer. * * @return Result. * @throws SSLException If SSL exception occurs. */ private SSLEngineResult unwrap0() throws SSLException { SSLEngineResult res; do { res = sslEngine.unwrap(inNetBuf, appBuf); if (log.isDebugEnabled()) log.debug("Unwrapped raw data [status=" + res.getStatus() + ", handshakeStatus=" + res.getHandshakeStatus() + ']'); if (res.getStatus() == Status.BUFFER_OVERFLOW) appBuf = expandBuffer(appBuf, appBuf.capacity() * 2); } while ((res.getStatus() == OK || res.getStatus() == Status.BUFFER_OVERFLOW) && (handshakeFinished && res.getHandshakeStatus() == NOT_HANDSHAKING || res.getHandshakeStatus() == NEED_UNWRAP)); return res; }
protected SSLEngineResult doCallbackIncreaseBufferProcess(HandshakeCallback callback, HandshakeBuffer hb) throws SSLException, WebSocketException { SSLEngineResult res = null; do { res = callback.execute(hb); if (log.isLoggable(Level.FINER)) { log.finer("res: \n" + res); log.finer("buffer: " + hb); } if (res.getStatus() == Status.BUFFER_OVERFLOW) { increaseBuffer(hb, hb.localBuffer); } else if (res.getStatus() == Status.BUFFER_UNDERFLOW) { increaseBuffer(hb, hb.netBuffer); } if (res.getStatus() != Status.BUFFER_OVERFLOW) { break; } } while (true); return res; }
private int wrapClose(final Buffer pool, final int offset, final int length) throws SSLException { int encLength = 0; initWrap(); SSLEngineResult res; do { res = sslEngine.wrap(localAppData, localNetDataForPeer); LOG.log("--CLOSE-- wrap " + res); switch (res.getStatus()) { case CLOSED: case OK: { encLength += fillBuffer(localNetDataForPeer, pool); localNetDataForPeer.compact(); break; } case BUFFER_OVERFLOW: { localNetDataForPeer = handleBufferOverFlow(sslEngine.getSession().getPacketBufferSize(), localNetDataForPeer); break; } case BUFFER_UNDERFLOW: { throw new RuntimeException("NOT EXPECTING THIS BUFFER_UNDERFLOW"); } } } while (res.getStatus() == Status.BUFFER_OVERFLOW || !sslEngine.isOutboundDone()); return encLength; }
/** * Returns the current status for this TLSHandler. * * @return the current TLSStatus */ public TLSStatus getStatus() { if (tlsEngineResult != null && tlsEngineResult.getStatus() == Status.BUFFER_UNDERFLOW) { return TLSStatus.UNDERFLOW; } else { if (tlsEngineResult != null && tlsEngineResult.getStatus() == Status.CLOSED) { return TLSStatus.CLOSED; } else { switch (tlsEngine.getHandshakeStatus()) { case NEED_WRAP: return TLSStatus.NEED_WRITE; case NEED_UNWRAP: return TLSStatus.NEED_READ; default: return TLSStatus.OK; } } } }