FileDocCategorySizeDatePackage
SSLUtils.javaAPI DocGlassfish v2 API20115Wed Aug 08 00:24:12 BST 2007com.sun.enterprise.web.connector.grizzly.ssl

SSLUtils

public class SSLUtils extends Object
SSL over NIO utility class. The class handle the SSLEngine operations needed to support SSL over NIO. This class MUST be executed using an SSLWorkerThread as it rely on some SSLWorkerThread buffers and SSLEngine. TODO: Create an object that Wrap SSLEngine and its associated buffers.
author
Jeanfrancois Arcand

Fields Summary
public static final int
MAX_BB_SIZE
The maximum size a ByteBuffer can take.
protected static final ByteBuffer
hsBB
private static int
readTimeout
The time to wait before timing out when reading bytes
Constructors Summary
Methods Summary
public static java.nio.ByteBufferdoHandshake(java.nio.channels.SelectionKey key, java.nio.ByteBuffer byteBuffer, java.nio.ByteBuffer inputBB, java.nio.ByteBuffer outputBB, javax.net.ssl.SSLEngine sslEngine, javax.net.ssl.SSLEngineResult.HandshakeStatus handshakeStatus)
Perform an SSL handshake using the SSLEngine.

param
key the SelectionKey
param
byteBuffer The application ByteBuffer
param
inputBB The encrypted input ByteBuffer
param
outputBB The encrypted output ByteBuffer
param
sslEngine The SSLEngine used.
param
handshakeStatus The current handshake status
param
timeout The time the Selector will block waiting for bytes
return
byteBuffer the new ByteBuffer
throw
IOException if the handshake fail.

        return doHandshake(key,byteBuffer,inputBB,outputBB,sslEngine,
                           handshakeStatus,readTimeout);
    
public static java.nio.ByteBufferdoHandshake(java.nio.channels.SelectionKey key, java.nio.ByteBuffer byteBuffer, java.nio.ByteBuffer inputBB, java.nio.ByteBuffer outputBB, javax.net.ssl.SSLEngine sslEngine, javax.net.ssl.SSLEngineResult.HandshakeStatus handshakeStatus, int timeout)
Perform an SSL handshake using the SSLEngine.

param
key the SelectionKey
param
byteBuffer The application ByteBuffer
param
inputBB The encrypted input ByteBuffer
param
outputBB The encrypted output ByteBuffer
param
sslEngine The SSLEngine used.
param
handshakeStatus The current handshake status
return
byteBuffer the new ByteBuffer
throw
IOException if the handshake fail.

        
        SSLEngineResult result;
        int eof = timeout > 0 ? 0 : -1;
        while (handshakeStatus != HandshakeStatus.FINISHED){
            switch (handshakeStatus) {
               case NEED_UNWRAP:
                    if (doHandshakeRead(key,inputBB,sslEngine, timeout) <= eof) {
                        try{
                            sslEngine.closeInbound();
                        } catch (IOException ex){
                            Logger logger = SSLSelectorThread.logger();
                            if ( logger.isLoggable(Level.FINE) ){
                                logger.log(Level.FINE,"closeInbound",ex);
                            }
                        }
                        throw new EOFException("Connection closed");
                    }
                    
                    while (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
                        result = unwrap(byteBuffer,inputBB,sslEngine);
                        handshakeStatus = result.getHandshakeStatus();
                        
                        if (result.getStatus() == Status.BUFFER_UNDERFLOW){
                            break;
                        }
                        
                        switch (result.getStatus()) {
                            case OK:
                                switch (handshakeStatus) {
                                    case NOT_HANDSHAKING:
                                        throw new IOException("No Hanshake");

                                    case NEED_TASK:
                                        handshakeStatus = 
                                                executeDelegatedTask(sslEngine);
                                        break;                               

                                    case FINISHED:
                                       return byteBuffer;
                                }
                                break;
                            case BUFFER_OVERFLOW:
                                byteBuffer = reallocate(byteBuffer);     
                                break;
                            default: 
                                throw new IOException("Handshake exception: " + 
                                        result.getStatus());
                        }
                    }  

                    if (handshakeStatus != HandshakeStatus.NEED_WRAP) {
                        break;
                    }
                case NEED_WRAP:
                    result = wrap(hsBB,outputBB,sslEngine);
                    handshakeStatus = result.getHandshakeStatus();
                    switch (result.getStatus()) {
                        case OK:

                            if (handshakeStatus == HandshakeStatus.NEED_TASK) {
                                handshakeStatus = executeDelegatedTask(sslEngine);
                            }

                            // Flush all Server bytes to the client.
                            if (key != null) {
                                OutputWriter.flushChannel(
                                        (SocketChannel)key.channel(), outputBB);
                                outputBB.clear();
                            }
                            break;
                        default: 
                            throw new IOException("Handshaking error: " 
                                    + result.getStatus());
                        }
                        break;
                default: 
                    throw new RuntimeException("Invalid Handshaking State" +
                            handshakeStatus);
            } 
        }
        return byteBuffer;
    
public static intdoHandshakeRead(java.nio.channels.SelectionKey key, java.nio.ByteBuffer inputBB, javax.net.ssl.SSLEngine sslEngine, int timeout)
Read encrypted bytes using an SSLEngine.

param
key The SelectionKey
param
inputBB The byteBuffer to store encrypted bytes
param
sslEngine The SSLEngine uses to manage the SSL operations.
param
timeout The Selector.select() timeout value. A value of 0 will be exectuted as a Selector.selectNow();
return
the bytes read.

 
        
        if (key == null) return -1;

    	SSLEngineResult result = null;
        int count = 1;
        int byteRead = 0;
        int preReadInputBBPos = inputBB.position();
        Selector readSelector = null;
        SelectionKey tmpKey = null;
        try{
            SocketChannel socketChannel = (SocketChannel)key.channel();
            while (count > 0){
                count = socketChannel.read(inputBB);
                
                if (count == -1) {
                    try{
                        sslEngine.closeInbound();  
                    } catch (IOException ex){
                        ;//
                    }
                    return -1;
                }
                byteRead += count;
            }            
            
            if (byteRead == 0 && inputBB.position() == preReadInputBBPos){
                readSelector = SelectorFactory.getSelector();

                if (readSelector == null){
                    return 0;
                }
                count = 1;
                tmpKey = socketChannel
                           .register(readSelector,SelectionKey.OP_READ);               
                tmpKey.interestOps(tmpKey.interestOps() | SelectionKey.OP_READ);
                
                int code = 0;
                if (timeout > 0) {
                    code = readSelector.select(timeout);
                } else {
                    code = readSelector.selectNow();
                }
                tmpKey.interestOps(
                    tmpKey.interestOps() & (~SelectionKey.OP_READ));

                if (code == 0){
                    return 0; // Return on the main Selector and try again.
                }

                while (count > 0){
                    count = socketChannel.read(inputBB);
                                                    
                    if (count == -1) {
                        try{
                            sslEngine.closeInbound();  
                        } catch (IOException ex){
                            ;//
                        }
                        return -1;
                    }
                    byteRead += count;                    
                }
            } else if (byteRead == 0 && inputBB.position() != preReadInputBBPos) {
                byteRead += (inputBB.position() - preReadInputBBPos);
            }
        } catch (Throwable t){
            Logger logger = SSLSelectorThread.logger();
            if ( logger.isLoggable(Level.FINEST) ){
                logger.log(Level.FINEST,"doRead",t);
            }            
            return -1;
        } finally {
            if (tmpKey != null)
                tmpKey.cancel();

            if (readSelector != null){
                // Bug 6403933
                try{
                    readSelector.selectNow();
                } catch (IOException ex){
                    ;
                }
                SelectorFactory.returnSelector(readSelector);
            }
        }
        return byteRead;
    
public static intdoRead(java.nio.channels.SelectionKey key, java.nio.ByteBuffer inputBB, javax.net.ssl.SSLEngine sslEngine, int timeout)
Read encrypted bytes using an SSLEngine.

param
key The SelectionKey
param
inputBB The byteBuffer to store encrypted bytes
param
sslEngine The SSLEngine uses to manage the SSL operations.
param
timeout The Selector.select() timeout value. A value of 0 will be exectuted as a Selector.selectNow();
return
the bytes read.

    
    
    
                                                                        
           
                
        
        if (key == null) return -1;

    	SSLEngineResult result = null;
        int count = 1;
        int byteRead = 0;
        Selector readSelector = null;
        SelectionKey tmpKey = null;
        try{
            SocketChannel socketChannel = (SocketChannel)key.channel();
            while (count > 0){
                count = socketChannel.read(inputBB);
                
                if (count == -1) {
                    try{
                        sslEngine.closeInbound();  
                    } catch (IOException ex){
                        ;//
                    }
                    return -1;
                }
                byteRead += count;
            }            
            
            if (byteRead == 0 && inputBB.position() == 0){
                readSelector = SelectorFactory.getSelector();

                if (readSelector == null){
                    return 0;
                }
                count = 1;
                tmpKey = socketChannel
                           .register(readSelector,SelectionKey.OP_READ);               
                tmpKey.interestOps(tmpKey.interestOps() | SelectionKey.OP_READ);
                
                int code = 0;
                if (timeout > 0) {
                    code = readSelector.select(timeout);
                } else {
                    code = readSelector.selectNow();
                }
                tmpKey.interestOps(
                    tmpKey.interestOps() & (~SelectionKey.OP_READ));

                if (code == 0){
                    return 0; // Return on the main Selector and try again.
                }

                while (count > 0){
                    count = socketChannel.read(inputBB);
                                                    
                    if (count == -1) {
                        try{
                            sslEngine.closeInbound();  
                        } catch (IOException ex){
                            ;//
                        }
                        return -1;
                    }
                    byteRead += count;                    
                }
            } else if (byteRead == 0) {
                byteRead += inputBB.position();
            }
        } catch (Throwable t){
            Logger logger = SSLSelectorThread.logger();
            if ( logger.isLoggable(Level.FINEST) ){
                logger.log(Level.FINEST,"doRead",t);
            }            
            return -1;
        } finally {
            if (tmpKey != null)
                tmpKey.cancel();

            if (readSelector != null){
                // Bug 6403933
                try{
                    readSelector.selectNow();
                } catch (IOException ex){
                    ;
                }
                SelectorFactory.returnSelector(readSelector);
            }
        }
        return byteRead;
    
public static javax.net.ssl.SSLEngineResult.HandshakeStatusexecuteDelegatedTask(javax.net.ssl.SSLEngine sslEngine)
Complete hanshakes operations.

param
sslEngine The SSLEngine used to manage the SSL operations.
return
SSLEngineResult.HandshakeStatus


        Runnable runnable;
        while ((runnable = sslEngine.getDelegatedTask()) != null) {
            runnable.run();
        }
        return sslEngine.getHandshakeStatus();
    
public static intgetReadTimeout()

        return readTimeout;
    
private static java.nio.ByteBufferreallocate(java.nio.ByteBuffer byteBuffer)
Resize a ByteBuffer.

        
        if (byteBuffer.capacity() > MAX_BB_SIZE){
            throw new IOException("Unwrap error: BUFFER_OVERFLOW");
        }
        ByteBuffer tmp = ByteBuffer.allocate(byteBuffer.capacity() * 2);
        byteBuffer.flip();
        tmp.put(byteBuffer);
        byteBuffer = tmp;
        return byteBuffer;
    
public static voidsetReadTimeout(int aReadTimeout)

        readTimeout = aReadTimeout;
    
public static javax.net.ssl.SSLEngineResultunwrap(java.nio.ByteBuffer byteBuffer, java.nio.ByteBuffer inputBB, javax.net.ssl.SSLEngine sslEngine)
Unwrap available encrypted bytes from inputBB to byteBuffer using the SSLEngine

param
byteBuffer the decrypted ByteBuffer
param
inputBB the encrypted ByteBuffer
param
sslEngine The SSLEngine used to manage the SSL operations.
return
SSLEngineResult of the SSLEngine.unwrap operation.


        inputBB.flip();
        SSLEngineResult result = sslEngine.unwrap(inputBB, byteBuffer);
        inputBB.compact();
        return result;
    
public static java.nio.ByteBufferunwrapAll(java.nio.ByteBuffer byteBuffer, java.nio.ByteBuffer inputBB, javax.net.ssl.SSLEngine sslEngine)
Unwrap all encrypted bytes from inputBB to byteBuffer using the SSLEngine

param
byteBuffer the decrypted ByteBuffer
param
inputBB the encrypted ByteBuffer
param
sslEngine The SSLEngine used to manage the SSL operations.
return
the decrypted ByteBuffer

        
        SSLEngineResult result = null;
        do{
            try{
               result = unwrap(byteBuffer,inputBB,sslEngine);
            } catch (Throwable ex){
                Logger logger = SSLSelectorThread.logger();
                if ( logger.isLoggable(Level.FINE) ){
                    logger.log(Level.FINE,"unwrap",ex);
                }
                inputBB.compact();
            }

            if (result != null){
                switch (result.getStatus()) {

                    case BUFFER_UNDERFLOW:
                        // Need more data.
                        break;
                    case OK:
                        if (result.getHandshakeStatus() 
                                == HandshakeStatus.NEED_TASK) {
                            executeDelegatedTask(sslEngine);
                        }
                        break;
                    case BUFFER_OVERFLOW:
                         byteBuffer = reallocate(byteBuffer);
                         break;
                    default:                       
                        throw new 
                             IOException("Unwrap error: "+ result.getStatus());
                 }   
             }
        } while ((inputBB.position() != 0) && result!= null &&
                result.getStatus() != Status.BUFFER_UNDERFLOW);
        return byteBuffer;
    
public static javax.net.ssl.SSLEngineResultwrap(java.nio.ByteBuffer byteBuffer, java.nio.ByteBuffer outputBB, javax.net.ssl.SSLEngine sslEngine)
Encrypt bytes.

param
byteBuffer the decrypted ByteBuffer
param
outputBB the encrypted ByteBuffer
param
sslEngine The SSLEngine used to manage the SSL operations.
return
SSLEngineResult of the SSLEngine.wrap operation.

        
        
        outputBB.clear();   
        SSLEngineResult result = sslEngine.wrap(byteBuffer, outputBB);
        outputBB.flip();
        return result;