NioSslEngine implements NioFilter { @Override public synchronized ByteBuffer unwrap(ByteBuffer wrappedBuffer) throws IOException { checkClosed(); peerAppData.limit(peerAppData.capacity()); while (wrappedBuffer.hasRemaining()) { SSLEngineResult unwrapResult = engine.unwrap(wrappedBuffer, peerAppData); switch (unwrapResult.getStatus()) { case BUFFER_OVERFLOW: int newCapacity = (peerAppData.capacity() - peerAppData.position()) * 2 + peerAppData.position(); newCapacity = Math.max(newCapacity, peerAppData.capacity() / 2 * 3); peerAppData = bufferPool.expandWriteBufferIfNeeded(TRACKED_RECEIVER, peerAppData, newCapacity); peerAppData.limit(peerAppData.capacity()); break; case BUFFER_UNDERFLOW: wrappedBuffer.compact(); return peerAppData; case OK: break; default: throw new SSLException("Error decrypting data: " + unwrapResult); } } wrappedBuffer.clear(); return peerAppData; } NioSslEngine(SSLEngine engine, BufferPool bufferPool); boolean handshake(SocketChannel socketChannel, int timeout,
      ByteBuffer peerNetData); @Override synchronized ByteBuffer wrap(ByteBuffer appData); @Override synchronized ByteBuffer unwrap(ByteBuffer wrappedBuffer); @Override ByteBuffer ensureWrappedCapacity(int amount, ByteBuffer wrappedBuffer,
      BufferType bufferType); @Override ByteBuffer readAtLeast(SocketChannel channel, int bytes,
      ByteBuffer wrappedBuffer); @Override ByteBuffer getUnwrappedBuffer(ByteBuffer wrappedBuffer); ByteBuffer ensureUnwrappedCapacity(int amount); @Override void doneReadingDirectAck(ByteBuffer unwrappedBuffer); @Override synchronized void close(SocketChannel socketChannel);  }
@Test public void unwrapWithBufferOverflow() throws Exception { int originalPeerAppDataCapacity = nioSslEngine.peerAppData.capacity(); int originalPeerAppDataPosition = originalPeerAppDataCapacity / 2; nioSslEngine.peerAppData.position(originalPeerAppDataPosition); ByteBuffer wrappedData = ByteBuffer.allocate(originalPeerAppDataCapacity + 100); byte[] netBytes = new byte[wrappedData.capacity()]; Arrays.fill(netBytes, (byte) 0x1F); wrappedData.put(netBytes); wrappedData.flip(); TestSSLEngine testEngine = new TestSSLEngine(); spyNioSslEngine.engine = testEngine; testEngine.addReturnResult( new SSLEngineResult(BUFFER_OVERFLOW, NEED_UNWRAP, 0, 0), new SSLEngineResult(BUFFER_OVERFLOW, NEED_UNWRAP, 0, 0), new SSLEngineResult(BUFFER_OVERFLOW, NEED_UNWRAP, 0, 0), new SSLEngineResult(OK, FINISHED, netBytes.length, netBytes.length)); int expectedCapacity = 2 * originalPeerAppDataCapacity - originalPeerAppDataPosition; expectedCapacity = 2 * (expectedCapacity - originalPeerAppDataPosition) + originalPeerAppDataPosition; expectedCapacity = 2 * (expectedCapacity - originalPeerAppDataPosition) + originalPeerAppDataPosition; ByteBuffer unwrappedBuffer = spyNioSslEngine.unwrap(wrappedData); unwrappedBuffer.flip(); assertThat(unwrappedBuffer.capacity()).isEqualTo(expectedCapacity); }
@Test public void unwrapWithBufferUnderflow() throws Exception { ByteBuffer wrappedData = ByteBuffer.allocate(nioSslEngine.peerAppData.capacity()); byte[] netBytes = new byte[wrappedData.capacity() / 2]; Arrays.fill(netBytes, (byte) 0x1F); wrappedData.put(netBytes); wrappedData.flip(); TestSSLEngine testEngine = new TestSSLEngine(); testEngine.addReturnResult(new SSLEngineResult(BUFFER_UNDERFLOW, NEED_TASK, 0, 0)); spyNioSslEngine.engine = testEngine; ByteBuffer unwrappedBuffer = spyNioSslEngine.unwrap(wrappedData); unwrappedBuffer.flip(); assertThat(unwrappedBuffer.remaining()).isEqualTo(0); assertThat(wrappedData.position()).isEqualTo(netBytes.length); }
@Test public void unwrapWithDecryptionError() { ByteBuffer wrappedData = ByteBuffer.allocate(nioSslEngine.peerAppData.capacity()); byte[] netBytes = new byte[wrappedData.capacity() / 2]; Arrays.fill(netBytes, (byte) 0x1F); wrappedData.put(netBytes); wrappedData.flip(); TestSSLEngine testEngine = new TestSSLEngine(); testEngine.addReturnResult(new SSLEngineResult(CLOSED, FINISHED, 0, 0)); spyNioSslEngine.engine = testEngine; assertThatThrownBy(() -> spyNioSslEngine.unwrap(wrappedData)).isInstanceOf(SSLException.class) .hasMessageContaining("Error decrypting data"); }