/** * Creates a new <code>TLSWrapper</code> instance. * * @param sslc * @param eventHandler * @param clientMode */ public TLSWrapper( SSLContext sslc, TLSEventHandler eventHandler, String[] sslProtocols, boolean clientMode) { tlsEngine = sslc.createSSLEngine(); tlsEngine.setUseClientMode(clientMode); if (tls_jdk_nss_workaround) { // Workaround for TLS/SSL bug in new JDK used with new version of // nss library see also: // http://stackoverflow.com/q/10687200/427545 // http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=b509d9cb5d8164d90e6731f5fc44?bug_id=6928796 tlsEngine.setEnabledCipherSuites(tls_workaround_ciphers); } if (sslProtocols != null) { tlsEngine.setEnabledProtocols(sslProtocols); } netBuffSize = tlsEngine.getSession().getPacketBufferSize(); appBuffSize = tlsEngine.getSession().getApplicationBufferSize(); this.eventHandler = eventHandler; if (!clientMode) { tlsEngine.setWantClientAuth(true); } }
protected SSLEngine createSSLEngine(String sniHostName, List<Cipher> clientRequestedCiphers) { SSLHostConfig sslHostConfig = getSSLHostConfig(sniHostName); SSLHostConfigCertificate certificate = selectCertificate(sslHostConfig, clientRequestedCiphers); SSLContextWrapper sslContextWrapper = certificate.getSslContextWrapper(); if (sslContextWrapper == null) { throw new IllegalStateException(sm.getString("endpoint.jsse.noSslContext", sniHostName)); } SSLEngine engine = sslContextWrapper.getSSLContext().createSSLEngine(); switch (sslHostConfig.getCertificateVerification()) { case NONE: engine.setNeedClientAuth(false); engine.setWantClientAuth(false); break; case OPTIONAL: case OPTIONAL_NO_CA: engine.setWantClientAuth(true); break; case REQUIRED: engine.setNeedClientAuth(true); break; } engine.setUseClientMode(false); engine.setEnabledCipherSuites(sslContextWrapper.getEnabledCiphers()); engine.setEnabledProtocols(sslContextWrapper.getEnabledProtocols()); SSLParameters sslParameters = engine.getSSLParameters(); sslParameters.setUseCipherSuitesOrder(sslHostConfig.getHonorCipherOrder()); // In case the getter returns a defensive copy engine.setSSLParameters(sslParameters); return engine; }
/** Notify all the handshake futures about the failure during the handshake. */ private void setHandshakeFailure(Throwable cause) { // Release all resources such as internal buffers that SSLEngine // is managing. engine.closeOutbound(); try { engine.closeInbound(); } catch (SSLException e) { // only log in debug mode as it most likely harmless and latest chrome still trigger // this all the time. // // See https://github.com/netty/netty/issues/1340 String msg = e.getMessage(); if (msg == null || !msg.contains("possible truncation attack")) { logger.debug("SSLEngine.closeInbound() raised an exception.", e); } } notifyHandshakeFailure(cause); for (; ; ) { PendingWrite write = pendingUnencryptedWrites.poll(); if (write == null) { break; } write.failAndRecycle(cause); } }
private void wrap(ByteBuffer data) throws IOException { SSLEngineResult result; do { result = engine.wrap(data, outToken); switch (result.getStatus()) { case BUFFER_UNDERFLOW: throw new RuntimeException(); case BUFFER_OVERFLOW: ByteBuffer buffer = ByteBuffer.allocate(outToken.capacity() + engine.getSession().getPacketBufferSize()); outToken.flip(); buffer.put(outToken); outToken = buffer; break; case OK: if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) { subject = createSubject(); } break; case CLOSED: throw new EOFException(); } } while (result.getStatus() != SSLEngineResult.Status.OK); if (data.hasRemaining()) { throw new RuntimeException("SSLEngine did not wrap all data."); } }
public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); // Add SSL handler first to encrypt and decrypt everything. // In this example, we use a bogus certificate in the server side // and accept any invalid certificates in the client side. // You will need something more complicated to identify both // and server in the real world. // // Read SecureChatSslContextFactory // if you need client certificate authentication. SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); engine.setUseClientMode(false); pipeline.addLast("ssl", new SslHandler(engine)); // On top of the SSL handler, add the text line codec. pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); // and then business logic. pipeline.addLast("handler", new SecureChatServerHandler()); return pipeline; }
/** * Method description * * @param app * @param net * @throws SSLException */ public void wrap(ByteBuffer app, ByteBuffer net) throws SSLException { tlsEngineResult = tlsEngine.wrap(app, net); if (log.isLoggable(Level.FINEST)) { log.log( Level.FINEST, "{0}, tlsEngineRsult.getStatus() = {1}, tlsEngineRsult.getHandshakeStatus() = {2}", new Object[] { debugId, tlsEngineResult.getStatus(), tlsEngineResult.getHandshakeStatus() }); } if (tlsEngineResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) { if (eventHandler != null) { eventHandler.handshakeCompleted(this); } } if (tlsEngineResult.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { doTasks(); if (log.isLoggable(Level.FINEST)) { log.log( Level.FINEST, "doTasks(): {0}, {1}", new Object[] {tlsEngine.getHandshakeStatus(), debugId}); } } }
public SSLSession getSSLSession() { SSLEngine e = connection.getSSLEngine(); if (e == null) { return null; } return e.getSession(); }
/* * Begin the shutdown process. * <P> * Close out the SSLEngine if not already done so, then * wrap our outgoing close_notify message and try to send it on. * <P> * Return true when we're done passing the shutdown messsages. */ boolean shutdown() throws IOException { if (!shutdown) { sslEngine.closeOutbound(); shutdown = true; } if (outNetBB.hasRemaining() && tryFlush(outNetBB)) { return false; } /* * By RFC 2616, we can "fire and forget" our close_notify * message, so that's what we'll do here. */ outNetBB.clear(); SSLEngineResult result = sslEngine.wrap(hsBB, outNetBB); if (result.getStatus() != Status.CLOSED) { throw new SSLException("Improper close state"); } outNetBB.flip(); /* * We won't wait for a select here, but if this doesn't work, * we'll cycle back through on the next select. */ if (outNetBB.hasRemaining()) { tryFlush(outNetBB); } return (!outNetBB.hasRemaining() && (result.getHandshakeStatus() != HandshakeStatus.NEED_WRAP)); }
/** Notify all the handshake futures about the failure during the handshake. */ private void setHandshakeFailure(Throwable cause) { // Release all resources such as internal buffers that SSLEngine // is managing. engine.closeOutbound(); try { engine.closeInbound(); } catch (SSLException e) { if (logger.isDebugEnabled()) { logger.debug( "SSLEngine.closeInbound() raised an exception after " + "a handshake failure.", e); } } if (cause == null) { cause = new ClosedChannelException(); } for (; ; ) { ChannelFuture f = handshakeFutures.poll(); if (f == null) { break; } f.setFailure(cause); } flush0(ctx, 0, cause); }
/** * Wraps data with the specified engine. * * @param engine - SSLEngine that wraps data. * @param wrapper - Set wrapper id, e.g. "server" of "client". Used for logging only. * @param maxPacketSize - Max packet size to check that MFLN extension works or zero for no check. * @param app - Buffer with data to wrap. * @param wantedStatus - Specifies expected result status of wrapping. * @param result - Array which first element will be used to output wrap result object. * @return - Buffer with wrapped data. * @throws SSLException - thrown on engine errors. */ public static ByteBuffer doWrap( SSLEngine engine, String wrapper, int maxPacketSize, ByteBuffer app, SSLEngineResult.Status wantedStatus, SSLEngineResult[] result) throws SSLException { ByteBuffer net = ByteBuffer.allocate(engine.getSession().getPacketBufferSize()); SSLEngineResult r = engine.wrap(app, net); net.flip(); int length = net.remaining(); System.out.println(wrapper + " wrapped " + length + " bytes."); System.out.println(wrapper + " handshake status is " + engine.getHandshakeStatus()); if (maxPacketSize < length && maxPacketSize != 0) { throw new AssertionError( "Handshake wrapped net buffer length " + length + " exceeds maximum packet size " + maxPacketSize); } checkResult(r, wantedStatus); if (result != null && result.length > 0) { result[0] = r; } return net; }
public ChannelPipeline getPipeline() throws Exception { log.debug("Creating client channel pipeline"); ChannelPipeline pipeline = Channels.pipeline(); SSLEngine engine = sslContext.createSSLEngine(); engine.setUseClientMode(true); SslHandler sslHandler = new SslHandler(engine); sslHandler.setCloseOnSSLException(true); pipeline.addLast("ssl", sslHandler); pipeline.addLast("chunker", new ChunkedWriteHandler()); pipeline.addLast( "framer", new DelimiterBasedFrameDecoder(protocol.maxHeaderLength(), protocol.headerDelimiter())); pipeline.addLast("stringDecoder", new StringDecoder(protocol.headerCharset())); pipeline.addLast("stringEncoder", new StringEncoder(protocol.headerCharset())); HeaderCodec headerCodec = new HeaderCodec(protocol); pipeline.addLast("headerDecoder", headerCodec.decoder()); pipeline.addLast("headerEncoder", headerCodec.encoder()); pipeline.addLast("client", new ClientHandler(store)); return pipeline; }
@Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Make sure the handshake future is notified when a connection has // been closed during handshake. synchronized (handshakeLock) { if (handshaking) { handshakeFuture.setFailure(new ClosedChannelException()); } } try { super.channelDisconnected(ctx, e); } finally { unwrap(ctx, e.getChannel(), ChannelBuffers.EMPTY_BUFFER, 0, 0); engine.closeOutbound(); if (!sentCloseNotify.get() && handshaken) { try { engine.closeInbound(); } catch (SSLException ex) { logger.debug("Failed to clean up SSLEngine.", ex); } } } }
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; } } } }
/** {@inheritDoc} */ @Override public Collection<String> getEnabledSSLProtocols() { final SSLEngine engine = sslEngine; if (engine != null) { return Arrays.asList(engine.getEnabledProtocols()); } return super.getEnabledSSLProtocols(); }
public Channel createChannel(SocketChannel sc, SelectorThread st, ChannelListener l) throws IOException, SSLException { log.info("Creating SecureChannel. Client mode: " + clientMode); SSLEngine engine = sslContext.createSSLEngine(); engine.setUseClientMode(clientMode); engine.setNeedClientAuth(true); return new SSLChannel(st, sc, l, engine); }
/** * Perform tasks, if any, during the handshake phase * * @return The handshake status ( {@link javax.net.ssl.SSLEngineResult.HandshakeStatus}) */ private SSLEngineResult.HandshakeStatus tasks() { Runnable task = null; while ((task = sslEngine.getDelegatedTask()) != null) { // Run the task in blocking mode task.run(); } return sslEngine.getHandshakeStatus(); }
void close(boolean properly) { _engine.closeOutbound(); try { if (properly) { wrap(null); // sends a TLS close_notify alert } _engine.closeInbound(); } catch (SSLException ignore) { } }
public SSLHandler(SSLEngine engine, SocketChannel channle, Selector selector) throws SSLException { this.engine = engine; this.channel = channle; this.selector = selector; this.appSendBuffer = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); this.netSendBuffer = ByteBuffer.allocate(engine.getSession().getPacketBufferSize()); this.appRecvBuffer = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize()); this.netRecvBuffer = ByteBuffer.allocate(engine.getSession().getPacketBufferSize()); engine.beginHandshake(); }
private static void runDelegatedTasks(SSLEngine engine) { Runnable runnable; System.out.println("Running delegated tasks..."); while ((runnable = engine.getDelegatedTask()) != null) { runnable.run(); } HandshakeStatus hs = engine.getHandshakeStatus(); if (hs == HandshakeStatus.NEED_TASK) { throw new Error("Handshake shouldn't need additional tasks."); } }
@Override protected Connection newConnection(SelectableChannel channel, EndPoint endpoint) { SSLEngine engine = __sslCtxFactory.newSSLEngine(); engine.setUseClientMode(false); SslConnection sslConnection = new SslConnection(__byteBufferPool, _threadPool, endpoint, engine); sslConnection.setRenegotiationAllowed(__sslCtxFactory.isRenegotiationAllowed()); Connection appConnection = super.newConnection(channel, sslConnection.getDecryptedEndPoint()); sslConnection.getDecryptedEndPoint().setConnection(appConnection); return sslConnection; }
@Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); SSLContext sslContext = Utils.createSSLContext(); SSLEngine engine = sslContext.createSSLEngine(); engine.setUseClientMode(true); pipeline.addLast("ssl", new SslHandler(engine)); pipeline.addLast("framer", new LineBasedFrameDecoder(1000 * 1000 * 10, true, false)); pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast("handler", connection); }
protected void decode(ChannelHandlerContext context, ByteBuf buffer) throws Exception { ChannelPipeline pipeline = context.pipeline(); if (detectSsl && SslHandler.isEncrypted(buffer)) { SSLEngine engine = SSL_SERVER_CONTEXT.getValue().createSSLEngine(); engine.setUseClientMode(false); pipeline.addLast( new SslHandler(engine), new ChunkedWriteHandler(), new PortUnificationServerHandler(delegatingHttpRequestHandler, false, detectGzip)); } else { int magic1 = buffer.getUnsignedByte(buffer.readerIndex()); int magic2 = buffer.getUnsignedByte(buffer.readerIndex() + 1); if (detectGzip && magic1 == 31 && magic2 == 139) { pipeline.addLast( new JZlibEncoder(ZlibWrapper.GZIP), new JdkZlibDecoder(ZlibWrapper.GZIP), new PortUnificationServerHandler(delegatingHttpRequestHandler, detectSsl, false)); } else if (isHttp(magic1, magic2)) { NettyUtil.initHttpHandlers(pipeline); pipeline.addLast(delegatingHttpRequestHandler); if (BuiltInServer.LOG.isDebugEnabled()) { pipeline.addLast( new ChannelOutboundHandlerAdapter() { @Override public void write( ChannelHandlerContext context, Object message, ChannelPromise promise) throws Exception { if (message instanceof HttpResponse) { // BuiltInServer.LOG.debug("OUT HTTP:\n" + message); HttpResponse response = (HttpResponse) message; BuiltInServer.LOG.debug( "OUT HTTP: " + response.getStatus().code() + " " + response.headers().get("Content-type")); } super.write(context, message, promise); } }); } } else if (magic1 == 'C' && magic2 == 'H') { buffer.skipBytes(2); pipeline.addLast(new CustomHandlerDelegator()); } else { BuiltInServer.LOG.warn("unknown request, first two bytes " + magic1 + " " + magic2); context.close(); } } // must be after new channels handlers addition (netty bug?) ensureThatExceptionHandlerIsLast(pipeline); pipeline.remove(this); context.fireChannelRead(buffer); }
/* * Read the channel for more information, then unwrap the * (hopefully application) data we get. * <P> * If we run out of data, we'll return to our caller (possibly using * a Selector) to get notification that more is available. * <P> * Each call to this method will perform at most one underlying read(). */ int read() throws IOException { SSLEngineResult result; if (!initialHSComplete) { throw new IllegalStateException(); } int pos = requestBB.position(); if (sc.read(inNetBB) == -1) { sslEngine.closeInbound(); // probably throws exception return -1; } do { resizeRequestBB(); // expected room for unwrap inNetBB.flip(); result = sslEngine.unwrap(inNetBB, requestBB); inNetBB.compact(); /* * Could check here for a renegotation, but we're only * doing a simple read/write, and won't have enough state * transitions to do a complete handshake, so ignore that * possibility. */ switch (result.getStatus()) { case BUFFER_OVERFLOW: // Reset the application buffer size. appBBSize = sslEngine.getSession().getApplicationBufferSize(); break; case BUFFER_UNDERFLOW: // Resize buffer if needed. netBBSize = sslEngine.getSession().getPacketBufferSize(); if (netBBSize > inNetBB.capacity()) { resizeResponseBB(); break; // break, next read will support larger buffer. } case OK: if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { doTasks(); } break; default: throw new IOException("sslEngine error during data read: " + result.getStatus()); } } while ((inNetBB.position() != 0) && result.getStatus() != Status.BUFFER_UNDERFLOW); return (requestBB.position() - pos); }
/** {@inheritDoc} */ @Override public <T> T getOption(final Option<T> option) throws IOException { if (option == Options.SSL_CLIENT_AUTH_MODE) { return option.cast( engine.getNeedClientAuth() ? SslClientAuthMode.REQUIRED : engine.getWantClientAuth() ? SslClientAuthMode.REQUESTED : SslClientAuthMode.NOT_REQUESTED); } else { return option == Options.SECURE ? (T) Boolean.TRUE : delegate.getOption(option); } }
private SSLEngine makeSSLEngine(TLSParams p, SSLContext ctx) { SSLEngine eng = ctx.createSSLEngine(); if (p.getCiphers() != null) { eng.setEnabledCipherSuites(p.getCiphers().toArray(new String[p.getCiphers().size()])); } if (p.isClientAuthRequired()) { eng.setNeedClientAuth(true); } else if (p.isClientAuthRequested()) { eng.setWantClientAuth(true); } eng.setUseClientMode(false); return eng; }
public SSLSocketChannelWrapper(SSLContext sslContext, SocketChannel sc, boolean client) throws Exception { super(sc); sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(client); sslEngine.setEnableSessionCreation(true); SSLSession session = sslEngine.getSession(); in = ByteBuffer.allocate(64 * 1024); emptyBuffer = ByteBuffer.allocate(0); int netBufferMax = session.getPacketBufferSize(); netOutBuffer = ByteBuffer.allocate(netBufferMax); netInBuffer = ByteBuffer.allocate(netBufferMax); }
/* * Do all the outstanding handshake tasks in the current Thread. */ private SSLEngineResult.HandshakeStatus doTasks() { Runnable runnable; /* * We could run this in a separate thread, but * do in the current for now. */ while ((runnable = sslEngine.getDelegatedTask()) != null) { runnable.run(); } return sslEngine.getHandshakeStatus(); }
private SSLEngineConfigurator createSSLEngineConfigurator(HTTPConnectionHandlerCfg config) throws DirectoryException { if (!config.isUseSSL()) { return null; } try { SSLContext sslContext = createSSLContext(config); SSLEngineConfigurator configurator = new SSLEngineConfigurator(sslContext); configurator.setClientMode(false); // configure with defaults from the JVM final SSLEngine defaults = sslContext.createSSLEngine(); configurator.setEnabledProtocols(defaults.getEnabledProtocols()); configurator.setEnabledCipherSuites(defaults.getEnabledCipherSuites()); final Set<String> protocols = config.getSSLProtocol(); if (!protocols.isEmpty()) { configurator.setEnabledProtocols(protocols.toArray(new String[protocols.size()])); } final Set<String> ciphers = config.getSSLCipherSuite(); if (!ciphers.isEmpty()) { configurator.setEnabledCipherSuites(ciphers.toArray(new String[ciphers.size()])); } switch (config.getSSLClientAuthPolicy()) { case DISABLED: configurator.setNeedClientAuth(false); configurator.setWantClientAuth(false); break; case REQUIRED: configurator.setNeedClientAuth(true); configurator.setWantClientAuth(true); break; case OPTIONAL: default: configurator.setNeedClientAuth(false); configurator.setWantClientAuth(true); break; } return configurator; } catch (Exception e) { logger.traceException(e); ResultCode resCode = DirectoryServer.getServerErrorResultCode(); throw new DirectoryException( resCode, ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE.get(getExceptionMessage(e)), e); } }
/** * Returns client ssl engine. * * @param context - SSLContext to get SSLEngine from. * @param useSNI - flag used to enable or disable using SNI extension. Needed for Kerberos. */ public static SSLEngine getClientSSLEngine(SSLContext context, boolean useSNI) { SSLEngine clientEngine = context.createSSLEngine(HOST, 80); clientEngine.setUseClientMode(true); if (useSNI) { SNIHostName serverName = new SNIHostName(SERVER_NAME); List<SNIServerName> serverNames = new ArrayList<>(); serverNames.add(serverName); SSLParameters params = clientEngine.getSSLParameters(); params.setServerNames(serverNames); clientEngine.setSSLParameters(params); } return clientEngine; }
/** * Returns server ssl engine. * * @param context - SSLContext to get SSLEngine from. * @param useSNI - flag used to enable or disable using SNI extension. Needed for Kerberos. */ public static SSLEngine getServerSSLEngine(SSLContext context, boolean useSNI) { SSLEngine serverEngine = context.createSSLEngine(); serverEngine.setUseClientMode(false); if (useSNI) { SNIMatcher matcher = SNIHostName.createSNIMatcher(SNI_PATTERN); List<SNIMatcher> matchers = new ArrayList<>(); matchers.add(matcher); SSLParameters params = serverEngine.getSSLParameters(); params.setSNIMatchers(matchers); serverEngine.setSSLParameters(params); } return serverEngine; }