FileDocCategorySizeDatePackage
SSLEngineImpl.javaAPI DocAndroid 1.5 API30311Wed May 06 22:41:06 BST 2009org.apache.harmony.xnet.provider.jsse

SSLEngineImpl

public class SSLEngineImpl extends SSLEngine
Implementation of SSLEngine.
see
javax.net.ssl.SSLEngine class documentation for more information.

Fields Summary
private boolean
peer_mode_was_set
private boolean
handshake_started
private boolean
isInboundDone
private boolean
isOutboundDone
private boolean
close_notify_was_sent
private boolean
close_notify_was_received
private boolean
engine_was_closed
private boolean
engine_was_shutteddown
protected SSLRecordProtocol
recordProtocol
private SSLBufferedInput
recProtIS
private HandshakeProtocol
handshakeProtocol
private AlertProtocol
alertProtocol
private SSLEngineAppData
appData
private org.apache.harmony.xnet.provider.jsse.SSLEngineDataStream
dataStream
private org.apache.harmony.xnet.provider.jsse.SSLSessionImpl
session
protected SSLParameters
sslParameters
private byte[]
remaining_wrapped_data
private byte[]
remaining_hsh_data
private Logger.Stream
logger
Constructors Summary
protected SSLEngineImpl(SSLParameters sslParameters)
Ctor

param
sslParameters: SSLParameters


                
       
        super();
        this.sslParameters = sslParameters;
    
protected SSLEngineImpl(String host, int port, SSLParameters sslParameters)
Ctor

param
host: String
param
port: int
param
sslParameters: SSLParameters

        super(host, port);
        this.sslParameters = sslParameters;
    
Methods Summary
public voidbeginHandshake()
Starts the handshake.

throws
SSLException
see
javax.net.ssl.SSLEngine#beginHandshake() method documentation for more information

        if (engine_was_closed) {
            throw new SSLException("Engine has already been closed.");
        }
        if (!peer_mode_was_set) {
            throw new IllegalStateException("Client/Server mode was not set");
        }
        if (!handshake_started) {
            handshake_started = true;
            if (getUseClientMode()) {
                handshakeProtocol = new ClientHandshakeImpl(this);
            } else {
                handshakeProtocol = new ServerHandshakeImpl(this);
            }
            appData = new SSLEngineAppData();
            alertProtocol = new AlertProtocol();
            recProtIS = new SSLBufferedInput();
            recordProtocol = new SSLRecordProtocol(handshakeProtocol,
                    alertProtocol, recProtIS, appData);
        }
        handshakeProtocol.start();
    
public voidcloseInbound()
Closes inbound operations of this engine

throws
SSLException
see
javax.net.ssl.SSLEngine#closeInbound() method documentation for more information

        if (logger != null) {
            logger.println("closeInbound() "+isInboundDone);
        }
        if (isInboundDone) {
            return;
        }
        isInboundDone = true;
        engine_was_closed = true;
        if (handshake_started) {
            if (!close_notify_was_received) {
                if (session != null) {
                    session.invalidate();
                }
                alertProtocol.alert(AlertProtocol.FATAL,
                        AlertProtocol.INTERNAL_ERROR);
                throw new SSLException("Inbound is closed before close_notify "
                        + "alert has been received.");
            }
        } else {
            // engine is closing before initial handshake has been made
            shutdown();
        }
    
public voidcloseOutbound()
Closes outbound operations of this engine

see
javax.net.ssl.SSLEngine#closeOutbound() method documentation for more information

        if (logger != null) {
            logger.println("closeOutbound() "+isOutboundDone);
        }
        if (isOutboundDone) {
            return;
        }
        isOutboundDone = true;
        if (handshake_started) {
            // initial handshake had been started
            alertProtocol.alert(AlertProtocol.WARNING,
                    AlertProtocol.CLOSE_NOTIFY);
            close_notify_was_sent = true;
        } else {
            // engine is closing before initial handshake has been made
            shutdown();
        }
        engine_was_closed = true;
    
public java.lang.RunnablegetDelegatedTask()
Returns handshake's delegated tasks to be run

return
the delegated task to be executed.
see
javax.net.ssl.SSLEngine#getDelegatedTask() method documentation for more information

        return handshakeProtocol.getTask();
    
public booleangetEnableSessionCreation()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#getEnableSessionCreation() method documentation for more information

        return sslParameters.getEnableSessionCreation();
    
public java.lang.String[]getEnabledCipherSuites()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#getEnabledCipherSuites() method documentation for more information

        return sslParameters.getEnabledCipherSuites();
    
public java.lang.String[]getEnabledProtocols()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#getEnabledProtocols() method documentation for more information

        return sslParameters.getEnabledProtocols();
    
private javax.net.ssl.SSLEngineResult$StatusgetEngineStatus()

        return (engine_was_closed)
            ? SSLEngineResult.Status.CLOSED
            : SSLEngineResult.Status.OK;
    
public javax.net.ssl.SSLEngineResult$HandshakeStatusgetHandshakeStatus()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#getHandshakeStatus() method documentation for more information

        if (!handshake_started || engine_was_shutteddown) {
            // initial handshake has not been started yet
            return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
        }
        if (alertProtocol.hasAlert()) {
            // need to send an alert
            return SSLEngineResult.HandshakeStatus.NEED_WRAP;
        }
        if (close_notify_was_sent && !close_notify_was_received) {
            // waiting for "close_notify" response
            return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
        }
        return handshakeProtocol.getStatus();
    
public booleangetNeedClientAuth()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#getNeedClientAuth() method documentation for more information

        return sslParameters.getNeedClientAuth();
    
public javax.net.ssl.SSLSessiongetSession()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#getSession() method documentation for more information

        if (session != null) {
            return session;
        } else {
            return SSLSessionImpl.NULL_SESSION;
        }
    
public java.lang.String[]getSupportedCipherSuites()
Returns names of supported cipher suites.

return
array of strings containing the names of supported cipher suites
see
javax.net.ssl.SSLEngine#getSupportedCipherSuites() method documentation for more information

        return CipherSuite.getSupportedCipherSuiteNames();
    
public java.lang.String[]getSupportedProtocols()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#getSupportedProtocols() method documentation for more information

        return (String[]) ProtocolVersion.supportedProtocols.clone();
    
public booleangetUseClientMode()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#getUseClientMode() method documentation for more information

        return sslParameters.getUseClientMode();
    
public booleangetWantClientAuth()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#getWantClientAuth() method documentation for more information

        return sslParameters.getWantClientAuth();
    
public booleanisInboundDone()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#isInboundDone() method documentation for more information

        return isInboundDone || engine_was_closed;
    
public booleanisOutboundDone()
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#isOutboundDone() method documentation for more information

        return isOutboundDone;
    
public voidsetEnableSessionCreation(boolean flag)
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#setEnableSessionCreation(boolean) method documentation for more information

        sslParameters.setEnableSessionCreation(flag);
    
public voidsetEnabledCipherSuites(java.lang.String[] suites)
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#setEnabledCipherSuites(String[]) method documentation for more information

        sslParameters.setEnabledCipherSuites(suites);
    
public voidsetEnabledProtocols(java.lang.String[] protocols)
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#setEnabledProtocols(String[]) method documentation for more information

        sslParameters.setEnabledProtocols(protocols);
    
public voidsetNeedClientAuth(boolean need)
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#setNeedClientAuth(boolean) method documentation for more information

        sslParameters.setNeedClientAuth(need);
    
public voidsetUseClientMode(boolean mode)
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#setUseClientMode(boolean) method documentation for more information

        if (handshake_started) {
            throw new IllegalArgumentException(
            "Could not change the mode after the initial handshake has begun.");
        }
        sslParameters.setUseClientMode(mode);
        peer_mode_was_set = true;
    
public voidsetWantClientAuth(boolean want)
This method works according to the specification of implemented class.

see
javax.net.ssl.SSLEngine#setWantClientAuth(boolean) method documentation for more information

        sslParameters.setWantClientAuth(want);
    
private voidshutdown()

        engine_was_closed = true;
        engine_was_shutteddown = true;
        isOutboundDone = true;
        isInboundDone = true;
        if (handshake_started) {
            alertProtocol.shutdown();
            alertProtocol = null;
            handshakeProtocol.shutdown();
            handshakeProtocol = null;
            recordProtocol.shutdown();
            recordProtocol = null;
        }
    
public javax.net.ssl.SSLEngineResultunwrap(java.nio.ByteBuffer src, java.nio.ByteBuffer[] dsts, int offset, int length)
Decodes one complete SSL/TLS record provided in the source buffer. If decoded record contained application data, this data will be placed in the destination buffers. For more information about TLS record fragmentation see TLS v 1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 6.2.

param
src source buffer containing SSL/TLS record.
param
dsts destination buffers to place received application data.
see
javax.net.ssl.SSLEngine#unwrap(ByteBuffer,ByteBuffer[],int,int) method documentation for more information

        if (engine_was_shutteddown) {
            return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
                    SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 0, 0);
        }
        if ((src == null) || (dsts == null)) {
            throw new IllegalStateException(
                    "Some of the input parameters are null");
        }

        if (!handshake_started) {
            beginHandshake();
        }

        SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus();
        // If is is initial handshake or connection closure stage,
        // check if this call was made in spite of handshake status
        if ((session == null || engine_was_closed) && (
                    handshakeStatus.equals(
                        SSLEngineResult.HandshakeStatus.NEED_WRAP) ||
                    handshakeStatus.equals(
                        SSLEngineResult.HandshakeStatus.NEED_TASK))) {
            return new SSLEngineResult(
                    getEngineStatus(), handshakeStatus, 0, 0);
        }

        if (src.remaining() < recordProtocol.getMinRecordSize()) {
            return new SSLEngineResult(
                    SSLEngineResult.Status.BUFFER_UNDERFLOW,
                    getHandshakeStatus(), 0, 0);
        }

        try {
            src.mark();
            // check the destination buffers and count their capacity
            int capacity = 0;
            for (int i=offset; i<offset+length; i++) {
                if (dsts[i] == null) {
                    throw new IllegalStateException(
                            "Some of the input parameters are null");
                }
                if (dsts[i].isReadOnly()) {
                    throw new ReadOnlyBufferException();
                }
                capacity += dsts[i].remaining();
            }
            if (capacity < recordProtocol.getDataSize(src.remaining())) {
                return new SSLEngineResult(
                        SSLEngineResult.Status.BUFFER_OVERFLOW,
                        getHandshakeStatus(), 0, 0);
            }
            recProtIS.setSourceBuffer(src);
            // unwrap the record contained in source buffer, pass it
            // to appropriate client protocol (alert, handshake, or app)
            // and retrieve the type of unwrapped data
            int type = recordProtocol.unwrap();
            // process the data and return the result
            switch (type) {
                case ContentType.HANDSHAKE:
                case ContentType.CHANGE_CIPHER_SPEC:
                    if (handshakeProtocol.getStatus().equals(
                            SSLEngineResult.HandshakeStatus.FINISHED)) {
                        session = recordProtocol.getSession();
                    }
                    break;
                case ContentType.APPLICATION_DATA:
                    break;
                case ContentType.ALERT:
                    if (alertProtocol.isFatalAlert()) {
                        alertProtocol.setProcessed();
                        if (session != null) {
                            session.invalidate();
                        }
                        String description = "Fatal alert received "
                            + alertProtocol.getAlertDescription();
                        shutdown();
                        throw new SSLException(description);
                    } else {
                        if (logger != null) {
                            logger.println("Warning allert has been received: "
                                + alertProtocol.getAlertDescription());
                        }
                        switch(alertProtocol.getDescriptionCode()) {
                            case AlertProtocol.CLOSE_NOTIFY:
                                alertProtocol.setProcessed();
                                close_notify_was_received = true;
                                if (!close_notify_was_sent) {
                                    closeOutbound();
                                    closeInbound();
                                } else {
                                    closeInbound();
                                    shutdown();
                                }
                                break;
                            case AlertProtocol.NO_RENEGOTIATION:
                                alertProtocol.setProcessed();
                                if (session == null) {
                                    // message received during the initial 
                                    // handshake
                                    throw new AlertException(
                                        AlertProtocol.HANDSHAKE_FAILURE,
                                        new SSLHandshakeException(
                                            "Received no_renegotiation "
                                            + "during the initial handshake"));
                                } else {
                                    // just stop the handshake
                                    handshakeProtocol.stop();
                                }
                                break;
                            default:
                                alertProtocol.setProcessed();
                        }
                    }
                    break;
            }
            return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(),
                    recProtIS.consumed(), 
                    // place the app. data (if any) into the dest. buffers 
                    // and get the number of produced bytes:
                    appData.placeTo(dsts, offset, length));
        } catch (BufferUnderflowException e) {
            // there was not enought data ource buffer to make complete packet
            src.reset();
            return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW,
                    getHandshakeStatus(), 0, 0);
        } catch (AlertException e) {
            // fatal alert occured
            alertProtocol.alert(AlertProtocol.FATAL, e.getDescriptionCode());
            engine_was_closed = true;
            src.reset();
            if (session != null) {
                session.invalidate();
            }
            // shutdown work will be made after the alert will be sent
            // to another peer (by wrap method)
            throw e.getReason();
        } catch (SSLException e) {
            throw e;
        } catch (IOException e) {
            alertProtocol.alert(AlertProtocol.FATAL,
                    AlertProtocol.INTERNAL_ERROR);
            engine_was_closed = true;
            // shutdown work will be made after the alert will be sent
            // to another peer (by wrap method)
            throw new SSLException(e.getMessage());
        }
    
public javax.net.ssl.SSLEngineResultwrap(java.nio.ByteBuffer[] srcs, int offset, int len, java.nio.ByteBuffer dst)
Encodes the application data into SSL/TLS record. If handshake status of the engine differs from NOT_HANDSHAKING the operation can work without consuming of the source data. For more information about TLS record fragmentation see TLS v 1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 6.2.

param
srcs the source buffers with application data to be encoded into SSL/TLS record.
param
offset the offset in the destination buffers array pointing to the first buffer with the source data.
param
len specifies the maximum number of buffers to be procesed.
param
dst the destination buffer where encoded data will be placed.
see
javax.net.ssl.SSLEngine#wrap(ByteBuffer[],int,int,ByteBuffer) method documentation for more information

        if (engine_was_shutteddown) {
            return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
                    SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 0, 0);
        }
        if ((srcs == null) || (dst == null)) {
            throw new IllegalStateException(
                    "Some of the input parameters are null");
        }
        if (dst.isReadOnly()) {
            throw new ReadOnlyBufferException();
        }

        if (!handshake_started) {
            beginHandshake();
        }

        SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus();
        // If it is an initial handshake or connection closure stage,
        // check if this call was made in spite of handshake status
        if ((session == null || engine_was_closed) && (
                handshakeStatus.equals(
                        SSLEngineResult.HandshakeStatus.NEED_UNWRAP) ||
                handshakeStatus.equals(
                        SSLEngineResult.HandshakeStatus.NEED_TASK))) {
            return new SSLEngineResult(
                    getEngineStatus(), handshakeStatus, 0, 0);
        }

        int capacity = dst.remaining();
        int produced = 0;

        if (alertProtocol.hasAlert()) {
            // we have an alert to be sent
            if (capacity < recordProtocol.getRecordSize(2)) {
                return new SSLEngineResult(
                        SSLEngineResult.Status.BUFFER_OVERFLOW,
                        handshakeStatus, 0, 0);
            }
            byte[] alert_data = alertProtocol.wrap();
            // place the alert record into destination
            dst.put(alert_data);
            if (alertProtocol.isFatalAlert()) {
                alertProtocol.setProcessed();
                if (session != null) {
                    session.invalidate();
                }
                // fatal alert has been sent, so shut down the engine
                shutdown();
                return new SSLEngineResult(
                        SSLEngineResult.Status.CLOSED,
                        SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING,
                        0, alert_data.length);
            } else {
                alertProtocol.setProcessed();
                // check if the works on this engine have been done
                if (close_notify_was_sent && close_notify_was_received) {
                    shutdown();
                    return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
                            SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING,
                            0, alert_data.length);
                }
                return new SSLEngineResult(
                        getEngineStatus(),
                        getHandshakeStatus(),
                        0, alert_data.length);
            }
        }

        if (capacity < recordProtocol.getMinRecordSize()) {
            if (logger != null) {
                logger.println("Capacity of the destination("
                        +capacity+") < MIN_PACKET_SIZE("
                        +recordProtocol.getMinRecordSize()+")");
            }
            return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW,
                        handshakeStatus, 0, 0);
        }

        try {
            if (!handshakeStatus.equals(
                        SSLEngineResult.HandshakeStatus.NEED_WRAP)) {
                // so we wraps application data
                dataStream.setSourceBuffers(srcs, offset, len);
                if ((capacity < SSLRecordProtocol.MAX_SSL_PACKET_SIZE) &&
                    (capacity < recordProtocol.getRecordSize(
                                                 dataStream.available()))) {
                    if (logger != null) {
                        logger.println("The destination buffer("
                                +capacity+") can not take the resulting packet("
                                + recordProtocol.getRecordSize(
                                    dataStream.available())+")");
                    }
                    return new SSLEngineResult(
                            SSLEngineResult.Status.BUFFER_OVERFLOW,
                            handshakeStatus, 0, 0);
                }
                if (remaining_wrapped_data == null) {
                    remaining_wrapped_data =
                        recordProtocol.wrap(ContentType.APPLICATION_DATA,
                                dataStream);
                }
                if (capacity < remaining_wrapped_data.length) {
                    // It should newer happen because we checked the destination
                    // buffer size, but there is a possibility
                    // (if dest buffer was filled outside)
                    // so we just remember the data into remaining_wrapped_data
                    // and will enclose it during the the next call
                    return new SSLEngineResult(
                            SSLEngineResult.Status.BUFFER_OVERFLOW,
                            handshakeStatus, dataStream.consumed(), 0);
                } else {
                    dst.put(remaining_wrapped_data);
                    produced = remaining_wrapped_data.length;
                    remaining_wrapped_data = null;
                    return new SSLEngineResult(getEngineStatus(), 
                            handshakeStatus, dataStream.consumed(), produced);
                }
            } else {
                if (remaining_hsh_data == null) {
                    remaining_hsh_data = handshakeProtocol.wrap();
                }
                if (capacity < remaining_hsh_data.length) {
                    // It should newer happen because we checked the destination
                    // buffer size, but there is a possibility
                    // (if dest buffer was filled outside)
                    // so we just remember the data into remaining_hsh_data
                    // and will enclose it during the the next call
                    return new SSLEngineResult(
                            SSLEngineResult.Status.BUFFER_OVERFLOW,
                            handshakeStatus, 0, 0);
                } else {
                    dst.put(remaining_hsh_data);
                    produced = remaining_hsh_data.length;
                    remaining_hsh_data = null;

                    handshakeStatus = handshakeProtocol.getStatus();
                    if (handshakeStatus.equals(
                            SSLEngineResult.HandshakeStatus.FINISHED)) {
                        session = recordProtocol.getSession();
                    }
                }
                return new SSLEngineResult(
                        getEngineStatus(), getHandshakeStatus(), 0, produced);
            }
        } catch (AlertException e) {
            // fatal alert occured
            alertProtocol.alert(AlertProtocol.FATAL, e.getDescriptionCode());
            engine_was_closed = true;
            if (session != null) {
                session.invalidate();
            }
            // shutdown work will be made after the alert will be sent
            // to another peer (by wrap method)
            throw e.getReason();
        }