@SuppressWarnings("unchecked") @Override public SMTPClientFuture<FutureResult<me.normanmaurer.niosmtp.transport.FutureResult.Void>> startTLS() { if (!isEncrypted()) { final SMTPClientFutureImpl<FutureResult<me.normanmaurer.niosmtp.transport.FutureResult.Void>> future = new SMTPClientFutureImpl< FutureResult<me.normanmaurer.niosmtp.transport.FutureResult.Void>>(false); SslHandler sslHandler = new SslHandler(engine, false); channel.getPipeline().addFirst(SSL_HANDLER_KEY, sslHandler); sslHandler .handshake() .addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture cfuture) throws Exception { if (cfuture.isSuccess()) { future.setResult(FutureResult.createVoid()); } else { future.setResult(FutureResult.create(cfuture.getCause())); } } }); return future; } else { return new ReadySMTPClientFuture< FutureResult<me.normanmaurer.niosmtp.transport.FutureResult.Void>>( this, FutureResult.create(STARTTLS_EXCEPTION)); } }
@Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Get the SslHandler in the current pipeline. // We added it in SecureChatPipelineFactory. final SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class); // Get notified when SSL handshake is done. ChannelFuture handshakeFuture = sslHandler.handshake(); handshakeFuture.addListener(new SslLister(sslHandler)); }
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())); } }
@Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { final NioSocketChannel ch = (NioSocketChannel) e.getChannel(); NioWorker worker = ch.getWorker(); // Choose a handler final HandlerHolder handler = handlerManager.chooseHandler(worker); if (handler == null) { // Ignore return; } if (tcpHelper.isSSL()) { SslHandler sslHandler = (SslHandler) ch.getPipeline().get("ssl"); ChannelFuture fut = sslHandler.handshake(); fut.addListener( new ChannelFutureListener() { public void operationComplete(ChannelFuture channelFuture) throws Exception { if (channelFuture.isSuccess()) { connected(ch, handler); } else { log.error( "Client from origin " + ch.getRemoteAddress() + " failed to connect over ssl"); } } }); } else { connected(ch, handler); } }
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); } }