Read() public method

Read data from the buffer.
public Read ( byte buf, int offset, int len, int skip ) : void
buf byte The buffer where the read data will be copied to.
offset int How many bytes to skip at the beginning of buf.
len int How many bytes to read at all.
skip int How many bytes from our data to skip.
return void
Exemplo n.º 1
0
        private void ProcessHandshake()
        {
            bool read;

            do
            {
                read = false;

                /*
                 * We need the first 4 bytes, they contain type and length of
                 * the message.
                 */
                if (handshakeQueue.Available >= 4)
                {
                    byte[] beginning = new byte[4];
                    handshakeQueue.Read(beginning, 0, 4, 0);
                    MemoryStream bis  = new MemoryStream(beginning, false);
                    short        type = TlsUtilities.ReadUint8(bis);
                    int          len  = TlsUtilities.ReadUint24(bis);

                    /*
                     * Check if we have enough bytes in the buffer to read
                     * the full message.
                     */
                    if (handshakeQueue.Available >= (len + 4))
                    {
                        /*
                         * Read the message.
                         */
                        byte[] buf = new byte[len];
                        handshakeQueue.Read(buf, 0, len, 4);
                        handshakeQueue.RemoveData(len + 4);

                        /*
                         * RFC 2246 7.4.9. "The value handshake_messages includes all
                         * handshake messages starting at client hello up to, but not
                         * including, this finished message. [..] Note: [Also,] Hello Request
                         * messages are omitted from handshake hashes."
                         */
                        switch (type)
                        {
                        case HP_HELLO_REQUEST:
                        case HP_FINISHED:
                            break;

                        default:
                            rs.UpdateHandshakeData(beginning, 0, 4);
                            rs.UpdateHandshakeData(buf, 0, len);
                            break;
                        }

                        /*
                         * Now, parse the message.
                         */
                        ProcessHandshakeMessage(type, buf);
                        read = true;
                    }
                }
            }while (read);
        }
Exemplo n.º 2
0
        private int ReceiveRecord(byte[] buf, int off, int len, int waitMillis)
        {
            if (mRecordQueue.Available > 0)
            {
                int length = 0;
                if (mRecordQueue.Available >= RECORD_HEADER_LENGTH)
                {
                    byte[] lengthBytes = new byte[2];
                    mRecordQueue.Read(lengthBytes, 0, 2, 11);
                    length = TlsUtilities.ReadUint16(lengthBytes, 0);
                }

                int received = System.Math.Min(mRecordQueue.Available, RECORD_HEADER_LENGTH + length);
                mRecordQueue.RemoveData(buf, off, received, 0);
                return(received);
            }

            {
                int received = mTransport.Receive(buf, off, len, waitMillis);
                if (received >= RECORD_HEADER_LENGTH)
                {
                    int fragmentLength = TlsUtilities.ReadUint16(buf, off + 11);
                    int recordLength   = RECORD_HEADER_LENGTH + fragmentLength;
                    if (received > recordLength)
                    {
                        mRecordQueue.AddData(buf, off + recordLength, received - recordLength);
                        received = recordLength;
                    }
                }
                return(received);
            }
        }
Exemplo n.º 3
0
        /**
         * This method is called, when a change cipher spec message is received.
         *
         * @throws IOException If the message has an invalid content or the
         *                     handshake is not in the correct state.
         */
        private void ProcessChangeCipherSpec()
        {
            while (changeCipherSpecQueue.Available > 0)
            {
                /*
                 * A change cipher spec message is only one byte with the value 1.
                 */
                byte[] b = new byte[1];
                changeCipherSpecQueue.Read(b, 0, 1, 0);
                changeCipherSpecQueue.RemoveData(1);
                if (b[0] != 1)
                {
                    /*
                     * This should never happen.
                     */
                    this.FailWithError(AL_fatal, AP_unexpected_message);
                }

                /*
                 * Check if we are in the correct connection state.
                 */
                if (this.connection_state != CS_CLIENT_FINISHED_SEND)
                {
                    this.FailWithError(AL_fatal, AP_handshake_failure);
                }

                rs.ServerClientSpecReceived();

                this.connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED;
            }
        }
Exemplo n.º 4
0
        /**
         * Read data from the network. The method will return immediately, if there is
         * still some data left in the buffer, or block until some application
         * data has been read from the network.
         *
         * @param buf    The buffer where the data will be copied to.
         * @param offset The position where the data will be placed in the buffer.
         * @param len    The maximum number of bytes to read.
         * @return The number of bytes read.
         * @throws IOException If something goes wrong during reading data.
         */
        internal int ReadApplicationData(byte[] buf, int offset, int len)
        {
            while (applicationDataQueue.Available == 0)
            {
                if (this.closed)
                {
                    /*
                     * We need to read some data.
                     */
                    if (this.failedWithError)
                    {
                        /*
                         * Something went terribly wrong, we should throw an IOException
                         */
                        throw new IOException(TLS_ERROR_MESSAGE);
                    }

                    /*
                     * Connection has been closed, there is no more data to read.
                     */
                    return(0);
                }

                SafeReadData();
            }
            len = System.Math.Min(len, applicationDataQueue.Available);
            applicationDataQueue.Read(buf, offset, len, 0);
            applicationDataQueue.RemoveData(len);
            return(len);
        }
Exemplo n.º 5
0
        public virtual int Peek(byte[] buf)
        {
            int num = Math.Min(buffer.Available, buf.Length);

            buffer.Read(buf, 0, num, 0);
            return(num);
        }
Exemplo n.º 6
0
        private int ReceiveRecord(byte[] buf, int off, int len, int waitMillis)
        {
            if (mRecordQueue.Available > 0)
            {
                int num = 0;
                if (mRecordQueue.Available >= 13)
                {
                    byte[] buf2 = new byte[2];
                    mRecordQueue.Read(buf2, 0, 2, 11);
                    num = TlsUtilities.ReadUint16(buf2, 0);
                }
                int num2 = Math.Min(mRecordQueue.Available, 13 + num);
                mRecordQueue.RemoveData(buf, off, num2, 0);
                return(num2);
            }
            int num3 = mTransport.Receive(buf, off, len, waitMillis);

            if (num3 >= 13)
            {
                int num4 = TlsUtilities.ReadUint16(buf, off + 11);
                int num5 = 13 + num4;
                if (num3 > num5)
                {
                    mRecordQueue.AddData(buf, off + num5, num3 - num5);
                    num3 = num5;
                }
            }
            return(num3);
        }
Exemplo n.º 7
0
        public virtual int Peek(byte[] buf)
        {
            int bytesToRead = System.Math.Min(buffer.Available, buf.Length);

            buffer.Read(buf, 0, bytesToRead, 0);
            return(bytesToRead);
        }
Exemplo n.º 8
0
        private void processAlert()
        {
            while (alertQueue.Available >= 2)
            {
                /*
                 * An alert is always 2 bytes. Read the alert.
                 */
                byte[] tmp = new byte[2];
                alertQueue.Read(tmp, 0, 2, 0);
                alertQueue.RemoveData(2);
                short level       = tmp[0];
                short description = tmp[1];
                if (level == AL_fatal)
                {
                    /*
                     * This is a fatal error.
                     */
                    this.failedWithError = true;
                    this.closed          = true;

                    /*
                     * Now try to Close the stream, ignore errors.
                     */
                    try
                    {
                        rs.Close();
                    }
                    catch (Exception)
                    {
                    }
                    throw new IOException(TLS_ERROR_MESSAGE);
                }
                else
                {
                    /*
                     * This is just a warning.
                     */
                    if (description == AP_close_notify)
                    {
                        /*
                         * Close notify
                         */
                        this.FailWithError(AL_warning, AP_close_notify);
                    }

                    /*
                     * If it is just a warning, we continue.
                     */
                }
            }
        }
Exemplo n.º 9
0
        private void ProcessHandshake()
        {
            bool flag;

            do
            {
                flag = false;
                if (mHandshakeQueue.Available >= 4)
                {
                    byte[] array = new byte[4];
                    mHandshakeQueue.Read(array, 0, 4, 0);
                    byte b   = TlsUtilities.ReadUint8(array, 0);
                    int  num = TlsUtilities.ReadUint24(array, 1);
                    if (mHandshakeQueue.Available >= num + 4)
                    {
                        byte[] array2 = mHandshakeQueue.RemoveData(num, 4);
                        CheckReceivedChangeCipherSpec(mConnectionState == 16 || b == 20);
                        switch (b)
                        {
                        default:
                        {
                            TlsContext context = Context;
                            if (b == 20 && mExpectedVerifyData == null && context.SecurityParameters.MasterSecret != null)
                            {
                                mExpectedVerifyData = CreateVerifyData(!context.IsServer);
                            }
                            mRecordStream.UpdateHandshakeData(array, 0, 4);
                            mRecordStream.UpdateHandshakeData(array2, 0, num);
                            break;
                        }

                        case 0:
                            break;
                        }
                        HandleHandshakeMessage(b, array2);
                        flag = true;
                    }
                }
            }while (flag);
        }
Exemplo n.º 10
0
        private void processHandshake()
        {
            bool read;

            do
            {
                read = false;

                /*
                 * We need the first 4 bytes, they contain type and length of
                 * the message.
                 */
                if (handshakeQueue.Available >= 4)
                {
                    byte[] beginning = new byte[4];
                    handshakeQueue.Read(beginning, 0, 4, 0);
                    MemoryStream bis  = new MemoryStream(beginning, false);
                    short        type = TlsUtilities.ReadUint8(bis);
                    int          len  = TlsUtilities.ReadUint24(bis);

                    /*
                     * Check if we have enough bytes in the buffer to read
                     * the full message.
                     */
                    if (handshakeQueue.Available >= (len + 4))
                    {
                        /*
                         * Read the message.
                         */
                        byte[] buf = new byte[len];
                        handshakeQueue.Read(buf, 0, len, 4);
                        handshakeQueue.RemoveData(len + 4);

                        /*
                         * If it is not a finished message, update our hashes
                         * we prepare for the finish message.
                         */
                        if (type != HP_FINISHED)
                        {
                            rs.hash1.BlockUpdate(beginning, 0, 4);
                            rs.hash2.BlockUpdate(beginning, 0, 4);
                            rs.hash1.BlockUpdate(buf, 0, len);
                            rs.hash2.BlockUpdate(buf, 0, len);
                        }

                        /*
                         * Now, parse the message.
                         */
                        MemoryStream inStr = new MemoryStream(buf, false);

                        /*
                         * Check the type.
                         */
                        switch (type)
                        {
                        case HP_CERTIFICATE:
                        {
                            switch (connection_state)
                            {
                            case CS_SERVER_HELLO_RECEIVED:
                            {
                                /*
                                 * Parse the certificates.
                                 */
                                Certificate cert = Certificate.Parse(inStr);
                                AssertEmpty(inStr);

                                X509CertificateStructure x509Cert = cert.certs[0];
                                SubjectPublicKeyInfo     keyInfo  = x509Cert.SubjectPublicKeyInfo;

                                try
                                {
                                    this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
                                }
                                catch (Exception)
                                {
                                    this.FailWithError(AL_fatal, AP_unsupported_certificate);
                                }

                                // Sanity check the PublicKeyFactory
                                if (this.serverPublicKey.IsPrivate)
                                {
                                    this.FailWithError(AL_fatal, AP_internal_error);
                                }

                                /*
                                 * Perform various checks per RFC2246 7.4.2
                                 * TODO "Unless otherwise specified, the signing algorithm for the certificate
                                 * must be the same as the algorithm for the certificate key."
                                 */
                                switch (this.chosenCipherSuite.KeyExchangeAlgorithm)
                                {
                                case TlsCipherSuite.KE_RSA:
                                    if (!(this.serverPublicKey is RsaKeyParameters))
                                    {
                                        this.FailWithError(AL_fatal, AP_certificate_unknown);
                                    }
                                    validateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
                                    break;

                                case TlsCipherSuite.KE_DHE_RSA:
                                    if (!(this.serverPublicKey is RsaKeyParameters))
                                    {
                                        this.FailWithError(AL_fatal, AP_certificate_unknown);
                                    }
                                    validateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
                                    break;

                                case TlsCipherSuite.KE_DHE_DSS:
                                    if (!(this.serverPublicKey is DsaPublicKeyParameters))
                                    {
                                        this.FailWithError(AL_fatal, AP_certificate_unknown);
                                    }
                                    break;

                                default:
                                    this.FailWithError(AL_fatal, AP_unsupported_certificate);
                                    break;
                                }

                                /*
                                 * Verify them.
                                 */
                                if (!this.verifyer.IsValid(cert.GetCerts()))
                                {
                                    this.FailWithError(AL_fatal, AP_user_canceled);
                                }

                                break;
                            }

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }

                            connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
                            read             = true;
                            break;
                        }

                        case HP_FINISHED:
                            switch (connection_state)
                            {
                            case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:
                                /*
                                 * Read the checksum from the finished message,
                                 * it has always 12 bytes.
                                 */
                                byte[] receivedChecksum = new byte[12];
                                TlsUtilities.ReadFully(receivedChecksum, inStr);
                                AssertEmpty(inStr);

                                /*
                                 * Calculate our own checksum.
                                 */
                                byte[] checksum   = new byte[12];
                                byte[] md5andsha1 = new byte[16 + 20];
                                rs.hash2.DoFinal(md5andsha1, 0);
                                TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum);

                                /*
                                 * Compare both checksums.
                                 */
                                for (int i = 0; i < receivedChecksum.Length; i++)
                                {
                                    if (receivedChecksum[i] != checksum[i])
                                    {
                                        /*
                                         * Wrong checksum in the finished message.
                                         */
                                        this.FailWithError(AL_fatal, AP_handshake_failure);
                                    }
                                }

                                connection_state = CS_DONE;

                                /*
                                 * We are now ready to receive application data.
                                 */
                                this.appDataReady = true;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_SERVER_HELLO:
                            switch (connection_state)
                            {
                            case CS_CLIENT_HELLO_SEND:
                                /*
                                 * Read the server hello message
                                 */
                                TlsUtilities.CheckVersion(inStr, this);

                                /*
                                 * Read the server random
                                 */
                                this.serverRandom = new byte[32];
                                TlsUtilities.ReadFully(this.serverRandom, inStr);

                                /*
                                 * Currently, we don't support session ids
                                 */
                                short  sessionIdLength = TlsUtilities.ReadUint8(inStr);
                                byte[] sessionId       = new byte[sessionIdLength];
                                TlsUtilities.ReadFully(sessionId, inStr);

                                /*
                                 * Find out which ciphersuite the server has
                                 * chosen. If we don't support this ciphersuite,
                                 * the TlsCipherSuiteManager will throw an
                                 * exception.
                                 */
                                this.chosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite(
                                    TlsUtilities.ReadUint16(inStr), this);

                                /*
                                 * We support only the null compression which
                                 * means no compression.
                                 */
                                short compressionMethod = TlsUtilities.ReadUint8(inStr);
                                if (compressionMethod != 0)
                                {
                                    this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);
                                }
                                AssertEmpty(inStr);

                                connection_state = CS_SERVER_HELLO_RECEIVED;
                                read             = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_SERVER_HELLO_DONE:
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                            case CS_SERVER_KEY_EXCHANGE_RECEIVED:
                            case CS_CERTIFICATE_REQUEST_RECEIVED:

                                // NB: Original code used case label fall-through
                                if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
                                {
                                    /*
                                     * There was no server key exchange message, check
                                     * that we are doing RSA key exchange.
                                     */
                                    if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
                                    {
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                    }
                                }

                                AssertEmpty(inStr);
                                bool isCertReq = (connection_state == CS_CERTIFICATE_REQUEST_RECEIVED);
                                connection_state = CS_SERVER_HELLO_DONE_RECEIVED;

                                if (isCertReq)
                                {
                                    sendClientCertificate();
                                }

                                /*
                                 * Send the client key exchange message, depending
                                 * on the key exchange we are using in our
                                 * ciphersuite.
                                 */
                                switch (this.chosenCipherSuite.KeyExchangeAlgorithm)
                                {
                                case TlsCipherSuite.KE_RSA:
                                {
                                    /*
                                     * We are doing RSA key exchange. We will
                                     * choose a pre master secret and send it
                                     * rsa encrypted to the server.
                                     *
                                     * Prepare pre master secret.
                                     */
                                    pms    = new byte[48];
                                    pms[0] = 3;
                                    pms[1] = 1;
                                    random.NextBytes(pms, 2, 46);

                                    /*
                                     * Encode the pms and send it to the server.
                                     *
                                     * Prepare an Pkcs1Encoding with good random
                                     * padding.
                                     */
                                    RsaBlindedEngine rsa      = new RsaBlindedEngine();
                                    Pkcs1Encoding    encoding = new Pkcs1Encoding(rsa);
                                    encoding.Init(true, new ParametersWithRandom(this.serverPublicKey, this.random));
                                    byte[] encrypted = null;
                                    try
                                    {
                                        encrypted = encoding.ProcessBlock(pms, 0, pms.Length);
                                    }
                                    catch (InvalidCipherTextException)
                                    {
                                        /*
                                         * This should never happen, only during decryption.
                                         */
                                        this.FailWithError(AL_fatal, AP_internal_error);
                                    }

                                    /*
                                     * Send the encrypted pms.
                                     */
                                    sendClientKeyExchange(encrypted);
                                    break;
                                }

                                case TlsCipherSuite.KE_DHE_DSS:
                                case TlsCipherSuite.KE_DHE_RSA:
                                {
                                    /*
                                     * Send the Client Key Exchange message for
                                     * DHE key exchange.
                                     */
                                    byte[] YcByte = BigIntegers.AsUnsignedByteArray(this.Yc);

                                    sendClientKeyExchange(YcByte);

                                    break;
                                }

                                default:
                                    /*
                                     * Problem during handshake, we don't know
                                     * how to handle this key exchange method.
                                     */
                                    this.FailWithError(AL_fatal, AP_unexpected_message);
                                    break;
                                }

                                connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;

                                /*
                                 * Now, we send change cipher state
                                 */
                                byte[] cmessage = new byte[1];
                                cmessage[0] = 1;
                                rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length);

                                connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;

                                /*
                                 * Calculate the ms
                                 */
                                this.ms = new byte[48];
                                byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length];
                                Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length);
                                Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length);
                                TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms);

                                /*
                                 * Initialize our cipher suite
                                 */
                                rs.writeSuite = this.chosenCipherSuite;
                                rs.writeSuite.Init(this.ms, clientRandom, serverRandom);

                                /*
                                 * Send our finished message.
                                 */
                                byte[] checksum   = new byte[12];
                                byte[] md5andsha1 = new byte[16 + 20];
                                rs.hash1.DoFinal(md5andsha1, 0);
                                TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum);

                                MemoryStream bos2 = new MemoryStream();
                                TlsUtilities.WriteUint8(HP_FINISHED, bos2);
                                TlsUtilities.WriteUint24(12, bos2);
                                bos2.Write(checksum, 0, checksum.Length);
                                byte[] message2 = bos2.ToArray();

                                rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length);

                                this.connection_state = CS_CLIENT_FINISHED_SEND;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_handshake_failure);
                                break;
                            }
                            break;

                        case HP_SERVER_KEY_EXCHANGE:
                        {
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                            {
                                /*
                                 * Check that we are doing DHE key exchange
                                 */
                                switch (this.chosenCipherSuite.KeyExchangeAlgorithm)
                                {
                                case TlsCipherSuite.KE_DHE_RSA:
                                {
                                    processDHEKeyExchange(inStr, new TlsRsaSigner());
                                    break;
                                }

                                case TlsCipherSuite.KE_DHE_DSS:
                                {
                                    processDHEKeyExchange(inStr, new TlsDssSigner());
                                    break;
                                }

                                default:
                                    this.FailWithError(AL_fatal, AP_unexpected_message);
                                    break;
                                }
                                break;
                            }

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }

                            this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
                            read = true;
                            break;
                        }

                        case HP_CERTIFICATE_REQUEST:
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                            case CS_SERVER_KEY_EXCHANGE_RECEIVED:
                            {
                                // NB: Original code used case label fall-through
                                if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
                                {
                                    /*
                                     * There was no server key exchange message, check
                                     * that we are doing RSA key exchange.
                                     */
                                    if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
                                    {
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                    }
                                }

                                int    typesLength = TlsUtilities.ReadUint8(inStr);
                                byte[] types       = new byte[typesLength];
                                TlsUtilities.ReadFully(types, inStr);

                                int    authsLength = TlsUtilities.ReadUint16(inStr);
                                byte[] auths       = new byte[authsLength];
                                TlsUtilities.ReadFully(auths, inStr);

                                AssertEmpty(inStr);
                                break;
                            }

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }

                            this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED;
                            read = true;
                            break;

                        case HP_HELLO_REQUEST:
                        case HP_CLIENT_KEY_EXCHANGE:
                        case HP_CERTIFICATE_VERIFY:
                        case HP_CLIENT_HELLO:
                        default:
                            // We do not support this!
                            this.FailWithError(AL_fatal, AP_unexpected_message);
                            break;
                        }
                    }
                }
            }while (read);
        }
Exemplo n.º 11
0
        private void processHandshake()
        {
            bool read;

            do
            {
                read = false;

                /*
                 * We need the first 4 bytes, they contain type and length of
                 * the message.
                 */
                if (handshakeQueue.Available >= 4)
                {
                    byte[] beginning = new byte[4];
                    handshakeQueue.Read(beginning, 0, 4, 0);
                    MemoryStream bis  = new MemoryStream(beginning, false);
                    short        type = TlsUtilities.ReadUint8(bis);
                    int          len  = TlsUtilities.ReadUint24(bis);

                    /*
                     * Check if we have enough bytes in the buffer to read
                     * the full message.
                     */
                    if (handshakeQueue.Available >= (len + 4))
                    {
                        /*
                         * Read the message.
                         */
                        byte[] buf = new byte[len];
                        handshakeQueue.Read(buf, 0, len, 4);
                        handshakeQueue.RemoveData(len + 4);

                        /*
                         * If it is not a finished message, update our hashes
                         * we prepare for the finish message.
                         */
                        if (type != HP_FINISHED)
                        {
                            rs.hash1.BlockUpdate(beginning, 0, 4);
                            rs.hash2.BlockUpdate(beginning, 0, 4);
                            rs.hash1.BlockUpdate(buf, 0, len);
                            rs.hash2.BlockUpdate(buf, 0, len);
                        }

                        /*
                         * Now, parse the message.
                         */
                        MemoryStream inStr = new MemoryStream(buf, false);

                        /*
                         * Check the type.
                         */
                        switch (type)
                        {
                        case HP_CERTIFICATE:
                            switch (connection_state)
                            {
                            case CS_SERVER_HELLO_RECEIVED:
                                /*
                                 * Parse the certificates.
                                 */
                                Certificate cert = Certificate.Parse(inStr);
                                AssertEmpty(inStr);

                                /*
                                 * Verify them.
                                 */
                                if (!this.verifyer.IsValid(cert.GetCerts()))
                                {
                                    this.FailWithError(AL_fatal, AP_user_canceled);
                                }

                                /*
                                 * We only support RSA certificates. Lets hope
                                 * this is one.
                                 */
                                RsaPublicKeyStructure rsaKey = null;
                                try
                                {
                                    rsaKey = RsaPublicKeyStructure.GetInstance(
                                        cert.certs[0].TbsCertificate.SubjectPublicKeyInfo.GetPublicKey());
                                }
                                catch (Exception)
                                {
                                    /*
                                     * Sorry, we have to fail ;-(
                                     */
                                    this.FailWithError(AL_fatal, AP_unsupported_certificate);
                                }

                                /*
                                 * Parse the servers public RSA key.
                                 */
                                this.serverRsaKey = new RsaKeyParameters(
                                    false,
                                    rsaKey.Modulus,
                                    rsaKey.PublicExponent);

                                connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
                                read             = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_FINISHED:
                            switch (connection_state)
                            {
                            case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:
                                /*
                                 * Read the checksum from the finished message,
                                 * it has always 12 bytes.
                                 */
                                byte[] receivedChecksum = new byte[12];
                                TlsUtilities.ReadFully(receivedChecksum, inStr);
                                AssertEmpty(inStr);

                                /*
                                 * Calculate our owne checksum.
                                 */
                                byte[] checksum   = new byte[12];
                                byte[] md5andsha1 = new byte[16 + 20];
                                rs.hash2.DoFinal(md5andsha1, 0);
                                TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum);

                                /*
                                 * Compare both checksums.
                                 */
                                for (int i = 0; i < receivedChecksum.Length; i++)
                                {
                                    if (receivedChecksum[i] != checksum[i])
                                    {
                                        /*
                                         * Wrong checksum in the finished message.
                                         */
                                        this.FailWithError(AL_fatal, AP_handshake_failure);
                                    }
                                }

                                connection_state = CS_DONE;

                                /*
                                 * We are now ready to receive application data.
                                 */
                                this.appDataReady = true;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_SERVER_HELLO:
                            switch (connection_state)
                            {
                            case CS_CLIENT_HELLO_SEND:
                                /*
                                 * Read the server hello message
                                 */
                                TlsUtilities.CheckVersion(inStr, this);

                                /*
                                 * Read the server random
                                 */
                                this.serverRandom = new byte[32];
                                TlsUtilities.ReadFully(this.serverRandom, inStr);

                                /*
                                 * Currenty, we don't support session ids
                                 */
                                short  sessionIdLength = TlsUtilities.ReadUint8(inStr);
                                byte[] sessionId       = new byte[sessionIdLength];
                                TlsUtilities.ReadFully(sessionId, inStr);

                                /*
                                 * Find out which ciphersuite the server has
                                 * choosen. If we don't support this ciphersuite,
                                 * the TlsCipherSuiteManager will throw an
                                 * exception.
                                 */
                                this.choosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite(
                                    TlsUtilities.ReadUint16(inStr), this);

                                /*
                                 * We support only the null compression which
                                 * means no compression.
                                 */
                                short compressionMethod = TlsUtilities.ReadUint8(inStr);
                                if (compressionMethod != 0)
                                {
                                    this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);
                                }
                                AssertEmpty(inStr);

                                connection_state = CS_SERVER_HELLO_RECEIVED;
                                read             = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_SERVER_HELLO_DONE:
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                            case CS_SERVER_KEY_EXCHANGE_RECEIVED:

                                // NB: Original code used case label fall-through
                                if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
                                {
                                    /*
                                     * There was no server key exchange message, check
                                     * that we are doing RSA key exchange.
                                     */
                                    if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
                                    {
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                    }
                                }

                                AssertEmpty(inStr);
                                connection_state = CS_SERVER_HELLO_DONE_RECEIVED;

                                /*
                                 * Send the client key exchange message, depending
                                 * on the key exchange we are using in our
                                 * ciphersuite.
                                 */
                                short ke = this.choosenCipherSuite.KeyExchangeAlgorithm;

                                switch (ke)
                                {
                                case TlsCipherSuite.KE_RSA:
                                    /*
                                     * We are doing RSA key exchange. We will
                                     * choose a pre master secret and send it
                                     * rsa encrypted to the server.
                                     *
                                     * Prepare pre master secret.
                                     */
                                    pms    = new byte[48];
                                    pms[0] = 3;
                                    pms[1] = 1;
                                    random.NextBytes(pms, 2, 46);

                                    /*
                                     * Encode the pms and send it to the server.
                                     *
                                     * Prepare an Pkcs1Encoding with good random
                                     * padding.
                                     */
                                    RsaBlindedEngine rsa      = new RsaBlindedEngine();
                                    Pkcs1Encoding    encoding = new Pkcs1Encoding(rsa);
                                    encoding.Init(true, new ParametersWithRandom(this.serverRsaKey, this.random));
                                    byte[] encrypted = null;
                                    try
                                    {
                                        encrypted = encoding.ProcessBlock(pms, 0, pms.Length);
                                    }
                                    catch (InvalidCipherTextException)
                                    {
                                        /*
                                         * This should never happen, only during decryption.
                                         */
                                        this.FailWithError(AL_fatal, AP_internal_error);
                                    }

                                    /*
                                     * Send the encrypted pms.
                                     */
                                    MemoryStream bos = new MemoryStream();
                                    TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, bos);
                                    TlsUtilities.WriteUint24(encrypted.Length + 2, bos);
                                    TlsUtilities.WriteUint16(encrypted.Length, bos);
                                    bos.Write(encrypted, 0, encrypted.Length);
                                    byte[] message = bos.ToArray();

                                    rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length);
                                    break;

                                case TlsCipherSuite.KE_DHE_RSA:
                                    /*
                                     * Send the Client Key Exchange message for
                                     * DHE key exchange.
                                     */
                                    byte[]       YcByte = this.Yc.ToByteArray();
                                    MemoryStream DHbos  = new MemoryStream();
                                    TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, DHbos);
                                    TlsUtilities.WriteUint24(YcByte.Length + 2, DHbos);
                                    TlsUtilities.WriteUint16(YcByte.Length, DHbos);
                                    DHbos.Write(YcByte, 0, YcByte.Length);
                                    byte[] DHmessage = DHbos.ToArray();

                                    rs.WriteMessage((short)RL_HANDSHAKE, DHmessage, 0, DHmessage.Length);

                                    break;

                                default:
                                    /*
                                     * Proble during handshake, we don't know
                                     * how to thandle this key exchange method.
                                     */
                                    this.FailWithError(AL_fatal, AP_unexpected_message);
                                    break;
                                }

                                connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;

                                /*
                                 * Now, we send change cipher state
                                 */
                                byte[] cmessage = new byte[1];
                                cmessage[0] = 1;
                                rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length);

                                connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;

                                /*
                                 * Calculate the ms
                                 */
                                this.ms = new byte[48];
                                byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length];
                                Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length);
                                Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length);
                                TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms);

                                /*
                                 * Initialize our cipher suite
                                 */
                                rs.writeSuite = this.choosenCipherSuite;
                                rs.writeSuite.Init(this.ms, clientRandom, serverRandom);

                                /*
                                 * Send our finished message.
                                 */
                                byte[] checksum   = new byte[12];
                                byte[] md5andsha1 = new byte[16 + 20];
                                rs.hash1.DoFinal(md5andsha1, 0);
                                TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum);

                                MemoryStream bos2 = new MemoryStream();
                                TlsUtilities.WriteUint8(HP_FINISHED, bos2);
                                TlsUtilities.WriteUint24(12, bos2);
                                bos2.Write(checksum, 0, checksum.Length);
                                byte[] message2 = bos2.ToArray();

                                rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length);

                                this.connection_state = CS_CLIENT_FINISHED_SEND;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_handshake_failure);
                                break;
                            }
                            break;

                        case HP_SERVER_KEY_EXCHANGE:
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                                /*
                                 * Check that we are doing DHE key exchange
                                 */
                                if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_DHE_RSA)
                                {
                                    this.FailWithError(AL_fatal, AP_unexpected_message);
                                }

                                /*
                                 * Parse the Structure
                                 */
                                int    pLength = TlsUtilities.ReadUint16(inStr);
                                byte[] pByte   = new byte[pLength];
                                TlsUtilities.ReadFully(pByte, inStr);

                                int    gLength = TlsUtilities.ReadUint16(inStr);
                                byte[] gByte   = new byte[gLength];
                                TlsUtilities.ReadFully(gByte, inStr);

                                int    YsLength = TlsUtilities.ReadUint16(inStr);
                                byte[] YsByte   = new byte[YsLength];
                                TlsUtilities.ReadFully(YsByte, inStr);

                                int    sigLength = TlsUtilities.ReadUint16(inStr);
                                byte[] sigByte   = new byte[sigLength];
                                TlsUtilities.ReadFully(sigByte, inStr);

                                this.AssertEmpty(inStr);

                                /*
                                 * Verify the Signature.
                                 *
                                 * First, calculate the hash.
                                 */
                                CombinedHash sigDigest  = new CombinedHash();
                                MemoryStream signedData = new MemoryStream();
                                TlsUtilities.WriteUint16(pLength, signedData);
                                signedData.Write(pByte, 0, pByte.Length);
                                TlsUtilities.WriteUint16(gLength, signedData);
                                signedData.Write(gByte, 0, gByte.Length);
                                TlsUtilities.WriteUint16(YsLength, signedData);
                                signedData.Write(YsByte, 0, YsByte.Length);
                                byte[] signed = signedData.ToArray();

                                sigDigest.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length);
                                sigDigest.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length);
                                sigDigest.BlockUpdate(signed, 0, signed.Length);
                                byte[] hash = new byte[sigDigest.GetDigestSize()];
                                sigDigest.DoFinal(hash, 0);

                                /*
                                 * Now, do the RSA operation
                                 */
                                RsaBlindedEngine rsa      = new RsaBlindedEngine();
                                Pkcs1Encoding    encoding = new Pkcs1Encoding(rsa);
                                encoding.Init(false, this.serverRsaKey);

                                /*
                                 * The data which was signed
                                 */
                                byte[] sigHash = null;

                                try
                                {
                                    sigHash = encoding.ProcessBlock(sigByte, 0, sigByte.Length);
                                }
                                catch (InvalidCipherTextException)
                                {
                                    this.FailWithError(AL_fatal, AP_bad_certificate);
                                }

                                /*
                                 * Check if the data which was signed is equal to
                                 * the hash we calculated.
                                 */
                                if (sigHash.Length != hash.Length)
                                {
                                    this.FailWithError(AL_fatal, AP_bad_certificate);
                                }

                                for (int i = 0; i < sigHash.Length; i++)
                                {
                                    if (sigHash[i] != hash[i])
                                    {
                                        this.FailWithError(AL_fatal, AP_bad_certificate);
                                    }
                                }

                                /*
                                 * OK, Signature was correct.
                                 *
                                 * Do the DH calculation.
                                 */
                                BigInteger p  = new BigInteger(1, pByte);
                                BigInteger g  = new BigInteger(1, gByte);
                                BigInteger Ys = new BigInteger(1, YsByte);
                                BigInteger x  = new BigInteger(p.BitLength - 1, this.random);
                                Yc       = g.ModPow(x, p);
                                this.pms = (Ys.ModPow(x, p)).ToByteArray();

                                /*
                                 * Remove leading zero byte, if present.
                                 */
                                if (this.pms[0] == 0)
                                {
                                    byte[] tmp = new byte[this.pms.Length - 1];
                                    Array.Copy(this.pms, 1, tmp, 0, tmp.Length);
                                    this.pms = tmp;
                                }

                                this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_HELLO_REQUEST:
                        case HP_CLIENT_KEY_EXCHANGE:
                        case HP_CERTIFICATE_REQUEST:
                        case HP_CERTIFICATE_VERIFY:
                        case HP_CLIENT_HELLO:
                        default:
                            // We do not support this!
                            this.FailWithError(AL_fatal, AP_unexpected_message);
                            break;
                        }
                    }
                }
            }while (read);
        }