Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  //
  //  ========================================================================
  //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
  //  ------------------------------------------------------------------------
  //  All rights reserved. This program and the accompanying materials
  //  are made available under the terms of the Eclipse Public License v1.0
  //  and Apache License v2.0 which accompanies this distribution.
  //
  //      The Eclipse Public License is available at
 //      http://www.eclipse.org/legal/epl-v10.html
 //
 //      The Apache License v2.0 is available at
 //      http://www.opensource.org/licenses/apache2.0.php
 //
 //  You may elect to redistribute this code under either of these licenses.
 //  ========================================================================
 //
 
 package org.eclipse.jetty.io.nio;
 
 
 
 /* ------------------------------------------------------------ */
SSL Connection. An AysyncConnection that acts as an interceptor between and EndPoint and another Connection, that implements TLS encryption using an javax.net.ssl.SSLEngine.

The connector uses an org.eclipse.jetty.io.AsyncEndPoint (like SelectChannelEndPoint) as it's source/sink of encrypted data. It then provides getSslEndPoint() to expose a source/sink of unencrypted data to another connection (eg HttpConnection).

 
 public class SslConnection extends AbstractConnection implements AsyncConnection
 {
     private final Logger _logger = Log.getLogger("org.eclipse.jetty.io.nio.ssl");
 
     private static final NIOBuffer __ZERO_BUFFER=new IndirectNIOBuffer(0);
 
     private static final ThreadLocal<SslBuffers__buffers = new ThreadLocal<SslBuffers>();
     private final SSLEngine _engine;
     private final SSLSession _session;
     private AsyncConnection _connection;
     private final SslEndPoint _sslEndPoint;
     private int _allocations;
     private SslBuffers _buffers;
     private NIOBuffer _inbound;
     private NIOBuffer _unwrapBuf;
     private NIOBuffer _outbound;
     private AsyncEndPoint _aEndp;
     private boolean _allowRenegotiate=true;
     private boolean _handshook;
     private boolean _ishut;
     private boolean _oshut;
     private final AtomicBoolean _progressed = new AtomicBoolean();
 
     /* ------------------------------------------------------------ */
     /* this is a half baked buffer pool
      */
     private static class SslBuffers
     {
         final NIOBuffer _in;
         final NIOBuffer _out;
         final NIOBuffer _unwrap;
 
         SslBuffers(int packetSizeint appSize)
         {
             =new IndirectNIOBuffer(packetSize);
             =new IndirectNIOBuffer(packetSize);
             =new IndirectNIOBuffer(appSize);
         }
     }
 
     /* ------------------------------------------------------------ */
     public SslConnection(SSLEngine engine,EndPoint endp)
     {
         this(engine,endp,System.currentTimeMillis());
     }
 
     /* ------------------------------------------------------------ */
     public SslConnection(SSLEngine engine,EndPoint endplong timeStamp)
     {
         super(endp,timeStamp);
         =engine;
         =.getSession();
        =(AsyncEndPoint)endp;
         = newSslEndPoint();
    }
    /* ------------------------------------------------------------ */
    protected SslEndPoint newSslEndPoint()
    {
        return new SslEndPoint();
    }
    /* ------------------------------------------------------------ */
    

Returns:
True if SSL re-negotiation is allowed (default false)
    public boolean isAllowRenegotiate()
    {
        return ;
    }
    /* ------------------------------------------------------------ */
    
Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered a vulnerability in SSL/TLS with re-negotiation. If your JVM does not have CVE-2009-3555 fixed, then re-negotiation should not be allowed. CVE-2009-3555 was fixed in Sun java 1.6 with a ban of renegotiates in u19 and with RFC5746 in u22.

Parameters:
allowRenegotiate true if re-negotiation is allowed (default false)
    public void setAllowRenegotiate(boolean allowRenegotiate)
    {
         = allowRenegotiate;
    }
    /* ------------------------------------------------------------ */
    private void allocateBuffers()
    {
        synchronized (this)
        {
            if (++==0)
            {
                if (==null)
                {
                    =.get();
                    if (==null)
                        =new SslBuffers(.getPacketBufferSize()*2,.getApplicationBufferSize()*2);
                    =.;
                    =.;
                    =.;
                    .set(null);
                }
            }
        }
    }
    /* ------------------------------------------------------------ */
    private void releaseBuffers()
    {
        synchronized (this)
        {
            if (--==0)
            {
                if (!=null &&
                    .length()==0 &&
                    .length()==0 &&
                    .length()==0)
                {
                    =null;
                    =null;
                    =null;
                    .set();
                    =null;
                }
            }
        }
    }
    /* ------------------------------------------------------------ */
    public Connection handle() throws IOException
    {
        try
        {
            allocateBuffers();
            boolean progress=true;
            while (progress)
            {
                progress=false;
                // If we are handshook let the delegate connection
                if (.getHandshakeStatus()!=.)
                    progress=process(null,null);
                // handle the delegate connection
                AsyncConnection next = (AsyncConnection).handle();
                if (next!= && next!=null)
                {
                    =next;
                    progress=true;
                }
                .debug("{} handle {} progress={}"thisprogress);
            }
        }
        finally
        {
            releaseBuffers();
            if (! && .isInputShutdown() && .isOpen())
            {
                =true;
                try
                {
                    .onInputShutdown();
                }
                catch(Throwable x)
                {
                    .warn("onInputShutdown failed"x);
                    try{.close();}
                    catch(IOException e2){
                        .ignore(e2);}
                }
            }
        }
        return this;
    }
    /* ------------------------------------------------------------ */
    public boolean isIdle()
    {
        return false;
    }
    /* ------------------------------------------------------------ */
    public boolean isSuspended()
    {
        return false;
    }
    /* ------------------------------------------------------------ */
    public void onClose()
    {
        Connection connection = .getConnection();
        if (connection != null && connection != this)
            connection.onClose();
    }
    /* ------------------------------------------------------------ */
    @Override
    public void onIdleExpired(long idleForMs)
    {
        try
        {
            .debug("onIdleExpired {}ms on {}",idleForMs,this);
            if (.isOutputShutdown())
                .close();
            else
                .shutdownOutput();
        }
        catch (IOException e)
        {
            .warn(e);
            super.onIdleExpired(idleForMs);
        }
    }
    /* ------------------------------------------------------------ */
    public void onInputShutdown() throws IOException
    {
    }
    /* ------------------------------------------------------------ */
    private synchronized boolean process(Buffer toFillBuffer toFlushthrows IOException
    {
        boolean some_progress=false;
        try
        {
            // We need buffers to progress
            allocateBuffers();
            // if we don't have a buffer to put received data into
            if (toFill==null)
            {
                // use the unwrapbuffer to hold received data.
                .compact();
                toFill=;
            }
            // Else if the fill buffer is too small for the SSL session
            else if (toFill.capacity()<.getApplicationBufferSize())
            {
                // fill to the temporary unwrapBuffer
                boolean progress=process(null,toFlush);
                // if we received any data,
                if (!=null && .hasContent())
                {
                    // transfer from temp buffer to fill buffer
                    .skip(toFill.put());
                    return true;
                }
                else
                    // return progress from recursive call
                    return progress;
            }
            // Else if there is some temporary data
            else if (!=null && .hasContent())
            {
                // transfer from temp buffer to fill buffer
                .skip(toFill.put());
                return true;
            }
            // If we are here, we have a buffer ready into which we can put some read data.
            // If we have no data to flush, flush the empty buffer
            if (toFlush==null)
                toFlush=;
            // While we are making progress processing SSL engine
            boolean progress=true;
            while (progress)
            {
                progress=false;
                // Do any real IO
                int filled=0,flushed=0;
                try
                {
                    // Read any available data
                    if (.space()>0 && (filled=.fill())>0)
                        progress = true;
                    // flush any output data
                    if (.hasContent() && (flushed=.flush())>0)
                        progress = true;
                }
                catch (IOException e)
                {
                    .close();
                    throw e;
                }
                finally
                {
                    .debug("{} {} {} filled={}/{} flushed={}/{}",,this,.getHandshakeStatus(),filled,.length(),flushed,.length());
                }
                // handle the current hand share status
                switch(.getHandshakeStatus())
                {
                    case :
                        throw new IllegalStateException();
                    case :
                    {
                        // Try unwrapping some application data
                        if (toFill.space()>0 && .hasContent() && unwrap(toFill))
                            progress=true;
                        // Try wrapping some application data
                        if (toFlush.hasContent() && .space()>0 && wrap(toFlush))
                            progress=true;
                    }
                    break;
                    case :
                    {
                        // A task needs to be run, so run it!
                        Runnable task;
                        while ((task=.getDelegatedTask())!=null)
                        {
                            progress=true;
                            task.run();
                        }
                    }
                    break;
                    case :
                    {
                        // The SSL needs to send some handshake data to the other side
                        if ( && !)
                            .close();
                        else if (wrap(toFlush))
                            progress=true;
                    }
                    break;
                    case :
                    {
                        // The SSL needs to receive some handshake data from the other side
                        if ( && !)
                            .close();
                        else if (!.hasContent()&&filled==-1)
                        {
                            // No more input coming
                            .shutdownInput();
                        }
                        else if (unwrap(toFill))
                            progress=true;
                    }
                    break;
                }
                // pass on ishut/oshut state
                if (.isOpen() && .isInputShutdown() && !.hasContent())
                    closeInbound();
                if (.isOpen() && .isOutboundDone() && !.hasContent())
                    .shutdownOutput();
                // remember if any progress has been made
                some_progress|=progress;
            }
            // If we are reading into the temp buffer and it has some content, then we should be dispatched.
            if (toFill== && .hasContent() && !.isSuspended())
                .dispatch();
        }
        finally
        {
            releaseBuffers();
            if (some_progress)
                .set(true);
        }
        return some_progress;
    }
    private void closeInbound()
    {
        try
        {
            .closeInbound();
        }
        catch (SSLException x)
        {
            .debug(x);
        }
    }
    private synchronized boolean wrap(final Buffer bufferthrows IOException
    {
        ByteBuffer bbuf=extractByteBuffer(buffer);
        final SSLEngineResult result;
        synchronized(bbuf)
        {
            .compact();
            ByteBuffer out_buffer=.getByteBuffer();
            synchronized(out_buffer)
            {
                try
                {
                    bbuf.position(buffer.getIndex());
                    bbuf.limit(buffer.putIndex());
                    out_buffer.position(.putIndex());
                    out_buffer.limit(out_buffer.capacity());
                    result=.wrap(bbuf,out_buffer);
                    if (.isDebugEnabled())
                        .debug("{} wrap {} {} consumed={} produced={}",
                            ,
                            result.getStatus(),
                            result.getHandshakeStatus(),
                            result.bytesConsumed(),
                            result.bytesProduced());
                    buffer.skip(result.bytesConsumed());
                    .setPutIndex(.putIndex()+result.bytesProduced());
                }
                catch(SSLException e)
                {
                    .debug(String.valueOf(), e);
                    .close();
                    throw e;
                }
                finally
                {
                    out_buffer.position(0);
                    out_buffer.limit(out_buffer.capacity());
                    bbuf.position(0);
                    bbuf.limit(bbuf.capacity());
                }
            }
        }
        switch(result.getStatus())
        {
            case :
                throw new IllegalStateException();
            case :
                break;
            case :
                if (result.getHandshakeStatus()==.)
                    =true;
                break;
            case :
                .debug("wrap CLOSE {} {}",this,result);
                if (result.getHandshakeStatus()==.)
                    .close();
                break;
            default:
                .debug("{} wrap default {}",,result);
            throw new IOException(result.toString());
        }
        return result.bytesConsumed()>0 || result.bytesProduced()>0;
    }
    private synchronized boolean unwrap(final Buffer bufferthrows IOException
    {
        if (!.hasContent())
            return false;
        ByteBuffer bbuf=extractByteBuffer(buffer);
        final SSLEngineResult result;
        synchronized(bbuf)
        {
            ByteBuffer in_buffer=.getByteBuffer();
            synchronized(in_buffer)
            {
                try
                {
                    bbuf.position(buffer.putIndex());
                    bbuf.limit(buffer.capacity());
                    in_buffer.position(.getIndex());
                    in_buffer.limit(.putIndex());
                    result=.unwrap(in_buffer,bbuf);
                    if (.isDebugEnabled())
                        .debug("{} unwrap {} {} consumed={} produced={}",
                            ,
                            result.getStatus(),
                            result.getHandshakeStatus(),
                            result.bytesConsumed(),
                            result.bytesProduced());
                    .skip(result.bytesConsumed());
                    .compact();
                    buffer.setPutIndex(buffer.putIndex()+result.bytesProduced());
                }
                catch(SSLException e)
                {
                    .debug(String.valueOf(), e);
                    .close();
                    throw e;
                }
                finally
                {
                    in_buffer.position(0);
                    in_buffer.limit(in_buffer.capacity());
                    bbuf.position(0);
                    bbuf.limit(bbuf.capacity());
                }
            }
        }
        switch(result.getStatus())
        {
            case :
                if (.isInputShutdown())
                    .clear();
                break;
            case :
                if (.isDebugEnabled()) .debug("{} unwrap {} {}->{}",,result.getStatus(),.toDetailString(),buffer.toDetailString());
                break;
            case :
                if (result.getHandshakeStatus()==.)
                    =true;
                break;
            case :
                .debug("unwrap CLOSE {} {}",this,result);
                if (result.getHandshakeStatus()==.)
                    .close();
                break;
            default:
                .debug("{} wrap default {}",,result);
            throw new IOException(result.toString());
        }
        //if (LOG.isDebugEnabled() && result.bytesProduced()>0)
        //    LOG.debug("{} unwrapped '{}'",_session,buffer);
        return result.bytesConsumed()>0 || result.bytesProduced()>0;
    }
    /* ------------------------------------------------------------ */
    private ByteBuffer extractByteBuffer(Buffer buffer)
    {
        if (buffer.buffer() instanceof NIOBuffer)
            return ((NIOBuffer)buffer.buffer()).getByteBuffer();
        return ByteBuffer.wrap(buffer.array());
    }
    /* ------------------------------------------------------------ */
    public AsyncEndPoint getSslEndPoint()
    {
        return ;
    }
    /* ------------------------------------------------------------ */
    public String toString()
    {
        return String.format("%s %s"super.toString(), );
    }
    /* ------------------------------------------------------------ */
    /* ------------------------------------------------------------ */
    public class SslEndPoint implements AsyncEndPoint
    {
        public SSLEngine getSslEngine()
        {
            return ;
        }
        public AsyncEndPoint getEndpoint()
        {
            return ;
        }
        public void shutdownOutput() throws IOException
        {
            synchronized (SslConnection.this)
            {
                .debug("{} ssl endp.oshut {}",,this);
                .closeOutbound();
                =true;
            }
            flush();
        }
        public boolean isOutputShutdown()
        {
            synchronized (SslConnection.this)
            {
                return ||!isOpen()||.isOutboundDone();
            }
        }
        public void shutdownInput() throws IOException
        {
            .debug("{} ssl endp.ishut!",);
            // We do not do a closeInput here, as SSL does not support half close.
            // isInputShutdown works it out itself from buffer state and underlying endpoint state.
        }
        public boolean isInputShutdown()
        {
            synchronized (SslConnection.this)
            {
                return .isInputShutdown() &&
                !(!=null&&.hasContent()) &&
                !(!=null&&.hasContent());
            }
        }
        public void close() throws IOException
        {
            .debug("{} ssl endp.close",);
            .close();
        }
        public int fill(Buffer bufferthrows IOException
        {
            int size=buffer.length();
            process(buffernull);
            int filled=buffer.length()-size;
            if (filled==0 && isInputShutdown())
                return -1;
            return filled;
        }
        public int flush(Buffer bufferthrows IOException
        {
            int size = buffer.length();
            process(nullbuffer);
            return size-buffer.length();
        }
        public int flush(Buffer headerBuffer bufferBuffer trailerthrows IOException
        {
            if (header!=null && header.hasContent())
                return flush(header);
            if (buffer!=null && buffer.hasContent())
                return flush(buffer);
            if (trailer!=null && trailer.hasContent())
                return flush(trailer);
            return 0;
        }
        public boolean blockReadable(long millisecsthrows IOException
        {
            long now = System.currentTimeMillis();
            long end=millisecs>0?(now+millisecs):.;
            while (now<end)
            {
                if (process(null,null))
                    break;
                .blockReadable(end-now);
                now = System.currentTimeMillis();
            }
            return now<end;
        }
        public boolean blockWritable(long millisecsthrows IOException
        {
            return .blockWritable(millisecs);
        }
        public boolean isOpen()
        {
            return .isOpen();
        }
        public Object getTransport()
        {
            return ;
        }
        public void flush() throws IOException
        {
            process(nullnull);
        }
        public void dispatch()
        {
            .dispatch();
        }
        public void asyncDispatch()
        {
            .asyncDispatch();
        }
        public void scheduleWrite()
        {
            .scheduleWrite();
        }
        public void onIdleExpired(long idleForMs)
        {
            .onIdleExpired(idleForMs);
        }
        public void setCheckForIdle(boolean check)
        {
            .setCheckForIdle(check);
        }
        public boolean isCheckForIdle()
        {
            return .isCheckForIdle();
        }
        public void scheduleTimeout(Task tasklong timeoutMs)
        {
            .scheduleTimeout(task,timeoutMs);
        }
        public void cancelTimeout(Task task)
        {
            .cancelTimeout(task);
        }
        public boolean isWritable()
        {
            return .isWritable();
        }
        public boolean hasProgressed()
        {
            return .getAndSet(false);
        }
        public String getLocalAddr()
        {
            return .getLocalAddr();
        }
        public String getLocalHost()
        {
            return .getLocalHost();
        }
        public int getLocalPort()
        {
            return .getLocalPort();
        }
        public String getRemoteAddr()
        {
            return .getRemoteAddr();
        }
        public String getRemoteHost()
        {
            return .getRemoteHost();
        }
        public int getRemotePort()
        {
            return .getRemotePort();
        }
        public boolean isBlocking()
        {
            return false;
        }
        public int getMaxIdleTime()
        {
            return .getMaxIdleTime();
        }
        public void setMaxIdleTime(int timeMsthrows IOException
        {
            .setMaxIdleTime(timeMs);
        }
        public Connection getConnection()
        {
            return ;
        }
        public void setConnection(Connection connection)
        {
            =(AsyncConnection)connection;
        }
        public String toString()
        {
            // Do NOT use synchronized (SslConnection.this)
            // because it's very easy to deadlock when debugging is enabled.
            // We do a best effort to print the right toString() and that's it.
            Buffer inbound = ;
            Buffer outbound = ;
            Buffer unwrap = ;
            int i = inbound == null? -1 : inbound.length();
            int o = outbound == null ? -1 : outbound.length();
            int u = unwrap == null ? -1 : unwrap.length();
            return String.format("SSL %s i/o/u=%d/%d/%d ishut=%b oshut=%b {%s}",
                    .getHandshakeStatus(),
                    iou,
                    ,
                    );
        }
    }
New to GrepCode? Check out our FAQ X