protected boolean handleSSLHandshake2() throws IOException { // We need to make sure the handshake process finished as a whole // boolean proceed = false; SSLEngineResult engineResult = null; isHanshakeDone = false; while (true) { switch (engine.getHandshakeStatus()) { case NOT_HANDSHAKING: case FINISHED: isHanshakeDone = true; return true; case NEED_TASK: Executor exec = Executors.newSingleThreadExecutor(); Runnable task; while ((task = engine.getDelegatedTask()) != null) { exec.execute(task); } continue; case NEED_WRAP: // We need to call a wrap on the engine appSendBuffer.flip(); engineResult = engine.wrap(appSendBuffer, netSendBuffer); appSendBuffer.compact(); if (engineResult.getStatus() == Status.BUFFER_OVERFLOW || engineResult.getStatus() == Status .OK) { // The enigne sys we need to flush the current buffer into the network // So just set the selector to the write mode channel.register(selector, SelectionKey.OP_WRITE); selector.wakeup(); // System.out.println("Handshake wants to do a write "); return false; } else if (engineResult.getStatus() == Status.CLOSED) { throw new IOException("Connection closed"); } else { continue; } case NEED_UNWRAP: // We need to call unwarap method of the engine netRecvBuffer.flip(); engineResult = engine.unwrap(netRecvBuffer, appRecvBuffer); netRecvBuffer.compact(); // System.out.println(engine.isInboundDone()); if (engineResult.getStatus() == Status.BUFFER_UNDERFLOW) { if (!engine.isInboundDone()) { channel.register(selector, SelectionKey.OP_READ); selector.wakeup(); // System.out.println("Handshake wants to do a read "); return false; } else continue; } else if (engineResult.getStatus() == Status.CLOSED) { throw new IOException("Connection closed"); } else { continue; } } } }
private void handleRenegotiation(HandshakeStatus handshakeStatus) { if (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING || handshakeStatus == HandshakeStatus.FINISHED) { // Not handshaking return; } if (!handshaken) { // Not renegotiation return; } final boolean renegotiate; synchronized (handshakeLock) { if (handshaking) { // Renegotiation in progress or failed already. // i.e. Renegotiation check has been done already below. return; } if (engine.isInboundDone() || engine.isOutboundDone()) { // Not handshaking but closing. return; } if (isEnableRenegotiation()) { // Continue renegotiation. renegotiate = true; } else { // Do not renegotiate. renegotiate = false; // Prevent reentrance of this method. handshaking = true; } } if (renegotiate) { // Renegotiate. handshake(); } else { // Raise an exception. fireExceptionCaught( ctx, new SSLException("renegotiation attempted by peer; " + "closing the connection")); // Close the connection to stop renegotiation. Channels.close(ctx, succeededFuture(ctx.getChannel())); } }
private void closeOutboundAndChannel( final ChannelHandlerContext context, final ChannelStateEvent e) throws SSLException { if (!e.getChannel().isConnected()) { context.sendDownstream(e); return; } unwrap(context, e.getChannel(), ChannelBuffers.EMPTY_BUFFER, 0, 0); if (!engine.isInboundDone()) { if (sentCloseNotify.compareAndSet(false, true)) { engine.closeOutbound(); ChannelFuture closeNotifyFuture = wrapNonAppData(context, e.getChannel()); closeNotifyFuture.addListener(new ClosingChannelFutureListener(context, e)); return; } } context.sendDownstream(e); }
/** * Close engines by sending "close outbound" message from one SSLEngine to another. * * @param fromEngine - Sending engine. * @param toEngine - Receiving engine. * @throws SSLException - thrown on engine errors. */ public static void closeEngines(SSLEngine fromEngine, SSLEngine toEngine) throws SSLException { String from = null; String to = null; ByteBuffer app; if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) { from = "Client"; to = "Server"; } else if (toEngine.getUseClientMode() && !fromEngine.getUseClientMode()) { from = "Server"; to = "Client"; } else { throw new Error("Both engines are in the same mode"); } System.out.println("============================================="); System.out.println("Trying to close engines from " + from + " to " + to); // Sending close outbound request to peer fromEngine.closeOutbound(); app = ByteBuffer.allocate(fromEngine.getSession().getApplicationBufferSize()); net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED); doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED); app = ByteBuffer.allocate(fromEngine.getSession().getApplicationBufferSize()); net = doWrap(toEngine, to, 0, app, SSLEngineResult.Status.CLOSED); doUnWrap(fromEngine, from, net, SSLEngineResult.Status.CLOSED); if (!toEngine.isInboundDone()) { throw new AssertionError( from + " sent close request to " + to + ", but " + to + "did not close inbound."); } // Executing close inbound fromEngine.closeInbound(); app = ByteBuffer.allocate(fromEngine.getSession().getApplicationBufferSize()); net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED); doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED); if (!toEngine.isOutboundDone()) { throw new AssertionError( from + "sent close request to " + to + ", but " + to + "did not close outbound."); } System.out.println("Successful closing from " + from + " to " + to); }
private ChannelBuffer unwrap( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, int offset, int length) throws SSLException { ByteBuffer inNetBuf = buffer.toByteBuffer(offset, length); ByteBuffer outAppBuf = bufferPool.acquire(); try { boolean needsWrap = false; loop: for (; ; ) { SSLEngineResult result; synchronized (handshakeLock) { if (!handshaken && !handshaking && !engine.getUseClientMode() && !engine.isInboundDone() && !engine.isOutboundDone()) { handshake(); } try { result = engine.unwrap(inNetBuf, outAppBuf); } catch (SSLException e) { throw e; } final HandshakeStatus handshakeStatus = result.getHandshakeStatus(); handleRenegotiation(handshakeStatus); switch (handshakeStatus) { case NEED_UNWRAP: if (inNetBuf.hasRemaining() && !engine.isInboundDone()) { break; } else { break loop; } case NEED_WRAP: wrapNonAppData(ctx, channel); break; case NEED_TASK: runDelegatedTasks(); break; case FINISHED: setHandshakeSuccess(channel); needsWrap = true; break loop; case NOT_HANDSHAKING: needsWrap = true; break loop; default: throw new IllegalStateException("Unknown handshake status: " + handshakeStatus); } } } if (needsWrap) { // wrap() acquires pendingUnencryptedWrites first and then // handshakeLock. If handshakeLock is already hold by the // current thread, calling wrap() will lead to a dead lock // i.e. pendingUnencryptedWrites -> handshakeLock vs. // handshakeLock -> pendingUnencryptedLock -> handshakeLock // // There is also a same issue between pendingEncryptedWrites // and pendingUnencryptedWrites. if (!Thread.holdsLock(handshakeLock) && !pendingEncryptedWritesLock.isHeldByCurrentThread()) { wrap(ctx, channel); } } outAppBuf.flip(); if (outAppBuf.hasRemaining()) { ChannelBuffer frame = ChannelBuffers.buffer(outAppBuf.remaining()); frame.writeBytes(outAppBuf.array(), 0, frame.capacity()); return frame; } else { return null; } } catch (SSLException e) { setHandshakeFailure(channel, e); throw e; } finally { bufferPool.release(outAppBuf); } }
private static boolean isEngineClosed(SSLEngine engine) { return (engine.isOutboundDone() && engine.isInboundDone()); }