示例#1
0
        protected virtual void ProcessCertificateRequest(DtlsClientProtocol.ClientHandshakeState state, byte[] body)
        {
            if (state.authentication == null)
            {
                throw new TlsFatalAlert(40);
            }
            MemoryStream memoryStream = new MemoryStream(body, false);

            state.certificateRequest = CertificateRequest.Parse(state.clientContext, memoryStream);
            TlsProtocol.AssertEmpty(memoryStream);
            state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
        }
        protected virtual void ProcessCertificateRequest(ClientHandshakeState state, byte[] body)
        {
            //IL_0012: Unknown result type (might be due to invalid IL or missing references)
            //IL_0018: Expected O, but got Unknown
            if (state.authentication == null)
            {
                throw new TlsFatalAlert(40);
            }
            MemoryStream val = new MemoryStream(body, false);

            state.certificateRequest = CertificateRequest.Parse(state.clientContext, (Stream)(object)val);
            TlsProtocol.AssertEmpty(val);
            state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
        }
示例#3
0
        protected virtual void ProcessCertificateRequest(ClientHandshakeState state, byte[] body)
        {
            if (state.authentication == null)
            {
                /*
                 * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server to
                 * request client identification.
                 */
                throw new TlsFatalAlert(AlertDescription.handshake_failure);
            }

            MemoryStream buf = new MemoryStream(body, false);

            state.certificateRequest = CertificateRequest.Parse(state.clientContext, buf);

            TlsProtocol.AssertEmpty(buf);

            state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
        }
示例#4
0
        protected override void HandleHandshakeMessage(byte type, byte[] data)
        {
            MemoryStream buf = new MemoryStream(data, false);

            if (this.mResumedSession)
            {
                if (type != HandshakeType.finished || this.mConnectionState != CS_SERVER_HELLO)
                {
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }

                ProcessFinishedMessage(buf);
                this.mConnectionState = CS_SERVER_FINISHED;

                SendFinishedMessage();
                this.mConnectionState = CS_CLIENT_FINISHED;
                this.mConnectionState = CS_END;

                return;
            }

            switch (type)
            {
            case HandshakeType.certificate:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO:
                case CS_SERVER_SUPPLEMENTAL_DATA:
                {
                    if (this.mConnectionState == CS_SERVER_HELLO)
                    {
                        HandleSupplementalData(null);
                    }

                    // Parse the Certificate message and Send to cipher suite

                    this.mPeerCertificate = Certificate.Parse(buf);

                    AssertEmpty(buf);

                    // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
                    if (this.mPeerCertificate == null || this.mPeerCertificate.IsEmpty)
                    {
                        this.mAllowCertificateStatus = false;
                    }

                    this.mKeyExchange.ProcessServerCertificate(this.mPeerCertificate);

                    this.mAuthentication = mTlsClient.GetAuthentication();
                    this.mAuthentication.NotifyServerCertificate(this.mPeerCertificate);

                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }

                this.mConnectionState = CS_SERVER_CERTIFICATE;
                break;
            }

            case HandshakeType.certificate_status:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_CERTIFICATE:
                {
                    if (!this.mAllowCertificateStatus)
                    {
                        /*
                         * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
                         * server MUST have included an extension of type "status_request" with empty
                         * "extension_data" in the extended server hello..
                         */
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    this.mCertificateStatus = CertificateStatus.Parse(buf);

                    AssertEmpty(buf);

                    // TODO[RFC 3546] Figure out how to provide this to the client/authentication.

                    this.mConnectionState = CS_CERTIFICATE_STATUS;
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.finished:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_FINISHED:
                case CS_SERVER_SESSION_TICKET:
                {
                    if (this.mConnectionState == CS_CLIENT_FINISHED && this.mExpectSessionTicket)
                    {
                        /*
                         * RFC 5077 3.3. This message MUST be sent if the server included a
                         * SessionTicket extension in the ServerHello.
                         */
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    ProcessFinishedMessage(buf);
                    this.mConnectionState = CS_SERVER_FINISHED;
                    this.mConnectionState = CS_END;
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.server_hello:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_HELLO:
                {
                    ReceiveServerHelloMessage(buf);
                    this.mConnectionState = CS_SERVER_HELLO;

                    this.mRecordStream.NotifyHelloComplete();

                    ApplyMaxFragmentLengthExtension();

                    if (this.mResumedSession)
                    {
                        this.mSecurityParameters.masterSecret = Arrays.Clone(this.mSessionParameters.MasterSecret);
                        this.mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());

                        SendChangeCipherSpecMessage();
                    }
                    else
                    {
                        InvalidateSession();

                        if (this.mSelectedSessionID.Length > 0)
                        {
                            this.mTlsSession = new TlsSessionImpl(this.mSelectedSessionID, null);
                        }
                    }

                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.supplemental_data:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO:
                {
                    HandleSupplementalData(ReadSupplementalDataMessage(buf));
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.server_hello_done:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO:
                case CS_SERVER_SUPPLEMENTAL_DATA:
                case CS_SERVER_CERTIFICATE:
                case CS_CERTIFICATE_STATUS:
                case CS_SERVER_KEY_EXCHANGE:
                case CS_CERTIFICATE_REQUEST:
                {
                    if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
                    {
                        HandleSupplementalData(null);
                    }

                    if (mConnectionState < CS_SERVER_CERTIFICATE)
                    {
                        // There was no server certificate message; check it's OK
                        this.mKeyExchange.SkipServerCredentials();
                        this.mAuthentication = null;
                    }

                    if (mConnectionState < CS_SERVER_KEY_EXCHANGE)
                    {
                        // There was no server key exchange message; check it's OK
                        this.mKeyExchange.SkipServerKeyExchange();
                    }

                    AssertEmpty(buf);

                    this.mConnectionState = CS_SERVER_HELLO_DONE;

                    this.mRecordStream.HandshakeHash.SealHashAlgorithms();

                    IList clientSupplementalData = mTlsClient.GetClientSupplementalData();
                    if (clientSupplementalData != null)
                    {
                        SendSupplementalDataMessage(clientSupplementalData);
                    }
                    this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;

                    TlsCredentials clientCreds = null;
                    if (mCertificateRequest == null)
                    {
                        this.mKeyExchange.SkipClientCredentials();
                    }
                    else
                    {
                        clientCreds = this.mAuthentication.GetClientCredentials(this.Context, mCertificateRequest);

                        if (clientCreds == null)
                        {
                            this.mKeyExchange.SkipClientCredentials();

                            /*
                             * RFC 5246 If no suitable certificate is available, the client MUST Send a
                             * certificate message containing no certificates.
                             *
                             * NOTE: In previous RFCs, this was SHOULD instead of MUST.
                             */
                            SendCertificateMessage(Certificate.EmptyChain);
                        }
                        else
                        {
                            this.mKeyExchange.ProcessClientCredentials(clientCreds);

                            SendCertificateMessage(clientCreds.Certificate);
                        }
                    }

                    this.mConnectionState = CS_CLIENT_CERTIFICATE;

                    /*
                     * Send the client key exchange message, depending on the key exchange we are using
                     * in our CipherSuite.
                     */
                    SendClientKeyExchangeMessage();
                    this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;

                    TlsHandshakeHash prepareFinishHash = mRecordStream.PrepareToFinish();
                    this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, prepareFinishHash, null);

                    EstablishMasterSecret(Context, mKeyExchange);
                    mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());

                    if (clientCreds != null && clientCreds is TlsSignerCredentials)
                    {
                        TlsSignerCredentials signerCredentials = (TlsSignerCredentials)clientCreds;

                        /*
                         * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
                         */
                        SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
                            Context, signerCredentials);

                        byte[] hash;
                        if (signatureAndHashAlgorithm == null)
                        {
                            hash = mSecurityParameters.SessionHash;
                        }
                        else
                        {
                            hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
                        }

                        byte[]          signature         = signerCredentials.GenerateCertificateSignature(hash);
                        DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
                        SendCertificateVerifyMessage(certificateVerify);

                        this.mConnectionState = CS_CERTIFICATE_VERIFY;
                    }

                    SendChangeCipherSpecMessage();
                    SendFinishedMessage();
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.handshake_failure);
                }

                this.mConnectionState = CS_CLIENT_FINISHED;
                break;
            }

            case HandshakeType.server_key_exchange:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO:
                case CS_SERVER_SUPPLEMENTAL_DATA:
                case CS_SERVER_CERTIFICATE:
                case CS_CERTIFICATE_STATUS:
                {
                    if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
                    {
                        HandleSupplementalData(null);
                    }

                    if (mConnectionState < CS_SERVER_CERTIFICATE)
                    {
                        // There was no server certificate message; check it's OK
                        this.mKeyExchange.SkipServerCredentials();
                        this.mAuthentication = null;
                    }

                    this.mKeyExchange.ProcessServerKeyExchange(buf);

                    AssertEmpty(buf);
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }

                this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
                break;
            }

            case HandshakeType.certificate_request:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_CERTIFICATE:
                case CS_CERTIFICATE_STATUS:
                case CS_SERVER_KEY_EXCHANGE:
                {
                    if (this.mConnectionState != CS_SERVER_KEY_EXCHANGE)
                    {
                        // There was no server key exchange message; check it's OK
                        this.mKeyExchange.SkipServerKeyExchange();
                    }

                    if (this.mAuthentication == null)
                    {
                        /*
                         * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server
                         * to request client identification.
                         */
                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
                    }

                    this.mCertificateRequest = CertificateRequest.Parse(Context, buf);

                    AssertEmpty(buf);

                    this.mKeyExchange.ValidateCertificateRequest(this.mCertificateRequest);

                    /*
                     * TODO Give the client a chance to immediately select the CertificateVerify hash
                     * algorithm here to avoid tracking the other hash algorithms unnecessarily?
                     */
                    TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
                                                     this.mCertificateRequest.SupportedSignatureAlgorithms);

                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }

                this.mConnectionState = CS_CERTIFICATE_REQUEST;
                break;
            }

            case HandshakeType.session_ticket:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_FINISHED:
                {
                    if (!this.mExpectSessionTicket)
                    {
                        /*
                         * RFC 5077 3.3. This message MUST NOT be sent if the server did not include a
                         * SessionTicket extension in the ServerHello.
                         */
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    /*
                     * RFC 5077 3.4. If the client receives a session ticket from the server, then it
                     * discards any Session ID that was sent in the ServerHello.
                     */
                    InvalidateSession();

                    ReceiveNewSessionTicketMessage(buf);
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }

                this.mConnectionState = CS_SERVER_SESSION_TICKET;
                break;
            }

            case HandshakeType.hello_request:
            {
                AssertEmpty(buf);

                /*
                 * RFC 2246 7.4.1.1 Hello request This message will be ignored by the client if the
                 * client is currently negotiating a session. This message may be ignored by the client
                 * if it does not wish to renegotiate a session, or the client may, if it wishes,
                 * respond with a no_renegotiation alert.
                 */
                if (this.mConnectionState == CS_END)
                {
                    RefuseRenegotiation();
                }
                break;
            }

            case HandshakeType.client_hello:
            case HandshakeType.client_key_exchange:
            case HandshakeType.certificate_verify:
            case HandshakeType.hello_verify_request:
            default:
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }
        }
示例#5
0
        private void ProcessHandshakeMessage(byte handshakeType, byte[] buf)
        {
            MemoryStream inStr = new MemoryStream(buf, false);

            /*
             * Check the type.
             */
            switch (handshakeType)
            {
            case HandshakeType.certificate:
            {
                switch (connection_state)
                {
                case CS_SERVER_HELLO_RECEIVED:
                {
                    // Parse the Certificate message and send to cipher suite

                    Certificate serverCertificate = Certificate.Parse(inStr);

                    AssertEmpty(inStr);

                    this.keyExchange.ProcessServerCertificate(serverCertificate);

                    this.authentication = tlsClient.GetAuthentication();
                    this.authentication.NotifyServerCertificate(serverCertificate);

                    break;
                }

                default:
                    this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
                    break;
                }

                connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
                break;
            }

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

                    AssertEmpty(inStr);

                    /*
                     * Calculate our own checksum.
                     */
                    byte[] expectedServerVerifyData = TlsUtilities.PRF(
                        securityParameters.masterSecret, "server finished",
                        rs.GetCurrentHash(), 12);

                    /*
                     * Compare both checksums.
                     */
                    if (!Arrays.ConstantTimeAreEqual(expectedServerVerifyData, serverVerifyData))
                    {
                        /*
                         * Wrong checksum in the finished message.
                         */
                        this.FailWithError(AlertLevel.fatal, AlertDescription.decrypt_error);
                    }

                    connection_state = CS_DONE;

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

                default:
                    this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
                    break;
                }
                break;

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

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

                    byte[] sessionID = TlsUtilities.ReadOpaque8(inStr);
                    if (sessionID.Length > 32)
                    {
                        this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
                    }

                    this.tlsClient.NotifySessionID(sessionID);

                    /*
                     * Find out which CipherSuite the server has chosen and check that
                     * it was one of the offered ones.
                     */
                    int selectedCipherSuite = TlsUtilities.ReadUint16(inStr);
                    if (!ArrayContains(offeredCipherSuites, selectedCipherSuite) ||
                        selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
                    {
                        this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
                    }

                    this.tlsClient.NotifySelectedCipherSuite(selectedCipherSuite);

                    /*
                     * Find out which CompressionMethod the server has chosen and check that
                     * it was one of the offered ones.
                     */
                    byte selectedCompressionMethod = TlsUtilities.ReadUint8(inStr);
                    if (!ArrayContains(offeredCompressionMethods, selectedCompressionMethod))
                    {
                        this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
                    }

                    this.tlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);

                    /*
                     * RFC3546 2.2 The extended server hello message format MAY be
                     * sent in place of the server hello message when the client has
                     * requested extended functionality via the extended client hello
                     * message specified in Section 2.1.
                     * ...
                     * Note that the extended server hello message is only sent in response
                     * to an extended client hello message.  This prevents the possibility
                     * that the extended server hello message could "break" existing TLS 1.0
                     * clients.
                     */

                    /*
                     * TODO RFC 3546 2.3
                     * If [...] the older session is resumed, then the server MUST ignore
                     * extensions appearing in the client hello, and send a server hello
                     * containing no extensions.
                     */

                    // Int32 -> byte[]
                    IDictionary serverExtensions = Platform.CreateHashtable();

                    if (inStr.Position < inStr.Length)
                    {
                        // Process extensions from extended server hello
                        byte[] extBytes = TlsUtilities.ReadOpaque16(inStr);

                        MemoryStream ext = new MemoryStream(extBytes, false);
                        while (ext.Position < ext.Length)
                        {
                            int    extType  = TlsUtilities.ReadUint16(ext);
                            byte[] extValue = TlsUtilities.ReadOpaque16(ext);

                            // Note: RFC 5746 makes a special case for EXT_RenegotiationInfo
                            if (extType != ExtensionType.renegotiation_info &&
                                !clientExtensions.Contains(extType))
                            {
                                /*
                                 * RFC 3546 2.3
                                 * Note that for all extension types (including those defined in
                                 * future), the extension type MUST NOT appear in the extended server
                                 * hello unless the same extension type appeared in the corresponding
                                 * client hello.  Thus clients MUST abort the handshake if they receive
                                 * an extension type in the extended server hello that they did not
                                 * request in the associated (extended) client hello.
                                 */
                                this.FailWithError(AlertLevel.fatal, AlertDescription.unsupported_extension);
                            }

                            if (serverExtensions.Contains(extType))
                            {
                                /*
                                 * RFC 3546 2.3
                                 * Also note that when multiple extensions of different types are
                                 * present in the extended client hello or the extended server hello,
                                 * the extensions may appear in any order. There MUST NOT be more than
                                 * one extension of the same type.
                                 */
                                this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
                            }

                            serverExtensions.Add(extType, extValue);
                        }
                    }

                    AssertEmpty(inStr);

                    /*
                     * RFC 5746 3.4. When a ServerHello is received, the client MUST check if it
                     * includes the "renegotiation_info" extension:
                     */
                    {
                        bool secure_negotiation = serverExtensions.Contains(ExtensionType.renegotiation_info);

                        /*
                         * If the extension is present, set the secure_renegotiation flag
                         * to TRUE.  The client MUST then verify that the length of the
                         * "renegotiated_connection" field is zero, and if it is not, MUST
                         * abort the handshake (by sending a fatal handshake_failure
                         * alert).
                         */
                        if (secure_negotiation)
                        {
                            byte[] renegExtValue = (byte[])serverExtensions[ExtensionType.renegotiation_info];

                            if (!Arrays.ConstantTimeAreEqual(renegExtValue,
                                                             CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                            {
                                this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
                            }
                        }

                        tlsClient.NotifySecureRenegotiation(secure_negotiation);
                    }

                    if (clientExtensions != null)
                    {
                        tlsClient.ProcessServerExtensions(serverExtensions);
                    }

                    this.keyExchange = tlsClient.GetKeyExchange();

                    connection_state = CS_SERVER_HELLO_RECEIVED;
                    break;

                default:
                    this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
                    break;
                }
                break;

            case HandshakeType.server_hello_done:
                switch (connection_state)
                {
                case CS_SERVER_HELLO_RECEIVED:
                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_HELLO_RECEIVED)
                    {
                        // There was no server certificate message; check it's OK
                        this.keyExchange.SkipServerCertificate();
                        this.authentication = null;

                        // There was no server key exchange message; check it's OK
                        this.keyExchange.SkipServerKeyExchange();
                    }
                    else if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
                    {
                        // There was no server key exchange message; check it's OK
                        this.keyExchange.SkipServerKeyExchange();
                    }

                    AssertEmpty(inStr);

                    connection_state = CS_SERVER_HELLO_DONE_RECEIVED;

                    TlsCredentials clientCreds = null;
                    if (certificateRequest == null)
                    {
                        this.keyExchange.SkipClientCredentials();
                    }
                    else
                    {
                        clientCreds = this.authentication.GetClientCredentials(certificateRequest);

                        Certificate clientCert;
                        if (clientCreds == null)
                        {
                            this.keyExchange.SkipClientCredentials();
                            clientCert = Certificate.EmptyChain;
                        }
                        else
                        {
                            this.keyExchange.ProcessClientCredentials(clientCreds);
                            clientCert = clientCreds.Certificate;
                        }

                        SendClientCertificate(clientCert);
                    }

                    /*
                     * Send the client key exchange message, depending on the key
                     * exchange we are using in our CipherSuite.
                     */
                    SendClientKeyExchange();

                    connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;

                    if (clientCreds != null && clientCreds is TlsSignerCredentials)
                    {
                        TlsSignerCredentials signerCreds = (TlsSignerCredentials)clientCreds;
                        byte[] md5andsha1 = rs.GetCurrentHash();
                        byte[] clientCertificateSignature = signerCreds.GenerateCertificateSignature(
                            md5andsha1);
                        SendCertificateVerify(clientCertificateSignature);

                        connection_state = CS_CERTIFICATE_VERIFY_SEND;
                    }

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

                    connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;

                    /*
                     * Calculate the master_secret
                     */
                    byte[] pms = this.keyExchange.GeneratePremasterSecret();

                    securityParameters.masterSecret = TlsUtilities.PRF(pms, "master secret",
                                                                       TlsUtilities.Concat(securityParameters.clientRandom, securityParameters.serverRandom),
                                                                       48);

                    // TODO Is there a way to ensure the data is really overwritten?

                    /*
                     * RFC 2246 8.1. The pre_master_secret should be deleted from
                     * memory once the master_secret has been computed.
                     */
                    Array.Clear(pms, 0, pms.Length);

                    /*
                     * Initialize our cipher suite
                     */
                    rs.ClientCipherSpecDecided(tlsClient.GetCompression(), tlsClient.GetCipher());

                    /*
                     * Send our finished message.
                     */
                    byte[] clientVerifyData = TlsUtilities.PRF(securityParameters.masterSecret,
                                                               "client finished", rs.GetCurrentHash(), 12);

                    MemoryStream bos = new MemoryStream();
                    TlsUtilities.WriteUint8((byte)HandshakeType.finished, bos);
                    TlsUtilities.WriteOpaque24(clientVerifyData, bos);
                    byte[] message = bos.ToArray();

                    rs.WriteMessage(ContentType.handshake, message, 0, message.Length);

                    this.connection_state = CS_CLIENT_FINISHED_SEND;
                    break;

                default:
                    this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
                    break;
                }
                break;

            case HandshakeType.server_key_exchange:
            {
                switch (connection_state)
                {
                case CS_SERVER_HELLO_RECEIVED:
                case CS_SERVER_CERTIFICATE_RECEIVED:
                {
                    // NB: Original code used case label fall-through
                    if (connection_state == CS_SERVER_HELLO_RECEIVED)
                    {
                        // There was no server certificate message; check it's OK
                        this.keyExchange.SkipServerCertificate();
                        this.authentication = null;
                    }

                    this.keyExchange.ProcessServerKeyExchange(inStr);

                    AssertEmpty(inStr);
                    break;
                }

                default:
                    this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
                    break;
                }

                this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
                break;
            }

            case HandshakeType.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 it's OK
                        this.keyExchange.SkipServerKeyExchange();
                    }

                    if (this.authentication == null)
                    {
                        /*
                         * RFC 2246 7.4.4. It is a fatal handshake_failure alert
                         * for an anonymous server to request client identification.
                         */
                        this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
                    }

                    this.certificateRequest = CertificateRequest.Parse(        //getContext(),
                        inStr);

                    AssertEmpty(inStr);

                    this.keyExchange.ValidateCertificateRequest(this.certificateRequest);

                    break;
                }

                default:
                    this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
                    break;
                }

                this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED;
                break;

            case HandshakeType.hello_request:
                /*
                 * RFC 2246 7.4.1.1 Hello request
                 * This message will be ignored by the client if the client is currently
                 * negotiating a session. This message may be ignored by the client if it
                 * does not wish to renegotiate a session, or the client may, if it wishes,
                 * respond with a no_renegotiation alert.
                 */
                if (connection_state == CS_DONE)
                {
                    // Renegotiation not supported yet
                    SendAlert(AlertLevel.warning, AlertDescription.no_renegotiation);
                }
                break;

            case HandshakeType.client_key_exchange:
            case HandshakeType.certificate_verify:
            case HandshakeType.client_hello:
            default:
                // We do not support this!
                this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
                break;
            }
        }
        protected override void HandleHandshakeMessage(byte type, byte[] data)
        {
            //IL_0002: Unknown result type (might be due to invalid IL or missing references)
            //IL_0008: Expected O, but got Unknown
            MemoryStream val = new MemoryStream(data, false);

            if (mResumedSession)
            {
                if (type != 20 || mConnectionState != 2)
                {
                    throw new TlsFatalAlert(10);
                }
                ProcessFinishedMessage(val);
                mConnectionState = 15;
                SendFinishedMessage();
                mConnectionState = 13;
                mConnectionState = 16;
                CompleteHandshake();
                return;
            }
            switch (type)
            {
            case 11:
                switch (mConnectionState)
                {
                case 2:
                case 3:
                    if (mConnectionState == 2)
                    {
                        HandleSupplementalData(null);
                    }
                    mPeerCertificate = Certificate.Parse((Stream)(object)val);
                    TlsProtocol.AssertEmpty(val);
                    if (mPeerCertificate == null || mPeerCertificate.IsEmpty)
                    {
                        mAllowCertificateStatus = false;
                    }
                    mKeyExchange.ProcessServerCertificate(mPeerCertificate);
                    mAuthentication = mTlsClient.GetAuthentication();
                    mAuthentication.NotifyServerCertificate(mPeerCertificate);
                    mConnectionState = 4;
                    break;

                default:
                    throw new TlsFatalAlert(10);
                }
                break;

            case 22:
            {
                short num = mConnectionState;
                if (num == 4)
                {
                    if (!mAllowCertificateStatus)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    mCertificateStatus = CertificateStatus.Parse((Stream)(object)val);
                    TlsProtocol.AssertEmpty(val);
                    mConnectionState = 5;
                    break;
                }
                throw new TlsFatalAlert(10);
            }

            case 20:
                switch (mConnectionState)
                {
                case 13:
                case 14:
                    if (mConnectionState == 13 && mExpectSessionTicket)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    ProcessFinishedMessage(val);
                    mConnectionState = 15;
                    mConnectionState = 16;
                    CompleteHandshake();
                    break;

                default:
                    throw new TlsFatalAlert(10);
                }
                break;

            case 2:
            {
                short num = mConnectionState;
                if (num == 1)
                {
                    ReceiveServerHelloMessage(val);
                    mConnectionState = 2;
                    mRecordStream.NotifyHelloComplete();
                    ApplyMaxFragmentLengthExtension();
                    if (mResumedSession)
                    {
                        mSecurityParameters.masterSecret = Arrays.Clone(mSessionParameters.MasterSecret);
                        mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
                        SendChangeCipherSpecMessage();
                        break;
                    }
                    InvalidateSession();
                    if (mSelectedSessionID.Length > 0)
                    {
                        mTlsSession = new TlsSessionImpl(mSelectedSessionID, null);
                    }
                    break;
                }
                throw new TlsFatalAlert(10);
            }

            case 23:
            {
                short num = mConnectionState;
                if (num == 2)
                {
                    HandleSupplementalData(TlsProtocol.ReadSupplementalDataMessage(val));
                    break;
                }
                throw new TlsFatalAlert(10);
            }

            case 14:
                switch (mConnectionState)
                {
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                {
                    if (mConnectionState < 3)
                    {
                        HandleSupplementalData(null);
                    }
                    if (mConnectionState < 4)
                    {
                        mKeyExchange.SkipServerCredentials();
                        mAuthentication = null;
                    }
                    if (mConnectionState < 6)
                    {
                        mKeyExchange.SkipServerKeyExchange();
                    }
                    TlsProtocol.AssertEmpty(val);
                    mConnectionState = 8;
                    mRecordStream.HandshakeHash.SealHashAlgorithms();
                    global::System.Collections.IList clientSupplementalData = mTlsClient.GetClientSupplementalData();
                    if (clientSupplementalData != null)
                    {
                        SendSupplementalDataMessage(clientSupplementalData);
                    }
                    mConnectionState = 9;
                    TlsCredentials tlsCredentials = null;
                    if (mCertificateRequest == null)
                    {
                        mKeyExchange.SkipClientCredentials();
                    }
                    else
                    {
                        tlsCredentials = mAuthentication.GetClientCredentials(mCertificateRequest);
                        if (tlsCredentials == null)
                        {
                            mKeyExchange.SkipClientCredentials();
                            SendCertificateMessage(Certificate.EmptyChain);
                        }
                        else
                        {
                            mKeyExchange.ProcessClientCredentials(tlsCredentials);
                            SendCertificateMessage(tlsCredentials.Certificate);
                        }
                    }
                    mConnectionState = 10;
                    SendClientKeyExchangeMessage();
                    mConnectionState = 11;
                    TlsHandshakeHash tlsHandshakeHash = mRecordStream.PrepareToFinish();
                    mSecurityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(Context, tlsHandshakeHash, null);
                    TlsProtocol.EstablishMasterSecret(Context, mKeyExchange);
                    mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
                    if (tlsCredentials != null && tlsCredentials is TlsSignerCredentials)
                    {
                        TlsSignerCredentials      tlsSignerCredentials      = (TlsSignerCredentials)tlsCredentials;
                        SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(Context, tlsSignerCredentials);
                        byte[]          hash              = ((signatureAndHashAlgorithm != null) ? tlsHandshakeHash.GetFinalHash(signatureAndHashAlgorithm.Hash) : mSecurityParameters.SessionHash);
                        byte[]          signature         = tlsSignerCredentials.GenerateCertificateSignature(hash);
                        DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
                        SendCertificateVerifyMessage(certificateVerify);
                        mConnectionState = 12;
                    }
                    SendChangeCipherSpecMessage();
                    SendFinishedMessage();
                    mConnectionState = 13;
                    break;
                }

                default:
                    throw new TlsFatalAlert(40);
                }
                break;

            case 12:
                switch (mConnectionState)
                {
                case 2:
                case 3:
                case 4:
                case 5:
                    if (mConnectionState < 3)
                    {
                        HandleSupplementalData(null);
                    }
                    if (mConnectionState < 4)
                    {
                        mKeyExchange.SkipServerCredentials();
                        mAuthentication = null;
                    }
                    mKeyExchange.ProcessServerKeyExchange((Stream)(object)val);
                    TlsProtocol.AssertEmpty(val);
                    mConnectionState = 6;
                    break;

                default:
                    throw new TlsFatalAlert(10);
                }
                break;

            case 13:
                switch (mConnectionState)
                {
                case 4:
                case 5:
                case 6:
                    if (mConnectionState != 6)
                    {
                        mKeyExchange.SkipServerKeyExchange();
                    }
                    if (mAuthentication == null)
                    {
                        throw new TlsFatalAlert(40);
                    }
                    mCertificateRequest = CertificateRequest.Parse(Context, (Stream)(object)val);
                    TlsProtocol.AssertEmpty(val);
                    mKeyExchange.ValidateCertificateRequest(mCertificateRequest);
                    TlsUtilities.TrackHashAlgorithms(mRecordStream.HandshakeHash, mCertificateRequest.SupportedSignatureAlgorithms);
                    mConnectionState = 7;
                    break;

                default:
                    throw new TlsFatalAlert(10);
                }
                break;

            case 4:
            {
                short num = mConnectionState;
                if (num == 13)
                {
                    if (!mExpectSessionTicket)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    InvalidateSession();
                    ReceiveNewSessionTicketMessage(val);
                    mConnectionState = 14;
                    break;
                }
                throw new TlsFatalAlert(10);
            }

            case 0:
                TlsProtocol.AssertEmpty(val);
                if (mConnectionState == 16)
                {
                    RefuseRenegotiation();
                }
                break;

            default:
                throw new TlsFatalAlert(10);
            }
        }
        protected override void HandleHandshakeMessage(byte type, byte[] data)
        {
            MemoryStream buf = new MemoryStream(data, false);

            if (base.mResumedSession)
            {
                if ((type != 20) || (base.mConnectionState != 2))
                {
                    throw new TlsFatalAlert(10);
                }
                this.ProcessFinishedMessage(buf);
                base.mConnectionState = 15;
                this.SendFinishedMessage();
                base.mConnectionState = 13;
                base.mConnectionState = 0x10;
                this.CompleteHandshake();
            }
            else
            {
                switch (type)
                {
                case 0:
                    TlsProtocol.AssertEmpty(buf);
                    if (base.mConnectionState == 0x10)
                    {
                        this.RefuseRenegotiation();
                    }
                    return;

                case 2:
                    if (base.mConnectionState != 1)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    this.ReceiveServerHelloMessage(buf);
                    base.mConnectionState = 2;
                    base.mRecordStream.NotifyHelloComplete();
                    this.ApplyMaxFragmentLengthExtension();
                    if (base.mResumedSession)
                    {
                        base.mSecurityParameters.masterSecret = Arrays.Clone(base.mSessionParameters.MasterSecret);
                        base.mRecordStream.SetPendingConnectionState(this.Peer.GetCompression(), this.Peer.GetCipher());
                        this.SendChangeCipherSpecMessage();
                    }
                    else
                    {
                        this.InvalidateSession();
                        if (this.mSelectedSessionID.Length > 0)
                        {
                            base.mTlsSession = new TlsSessionImpl(this.mSelectedSessionID, null);
                        }
                    }
                    return;

                case 4:
                    if (base.mConnectionState != 13)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    if (!base.mExpectSessionTicket)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    this.InvalidateSession();
                    this.ReceiveNewSessionTicketMessage(buf);
                    base.mConnectionState = 14;
                    return;

                case 11:
                    switch (base.mConnectionState)
                    {
                    case 2:
                    case 3:
                        if (base.mConnectionState == 2)
                        {
                            this.HandleSupplementalData(null);
                        }
                        base.mPeerCertificate = Certificate.Parse(buf);
                        TlsProtocol.AssertEmpty(buf);
                        if ((base.mPeerCertificate == null) || base.mPeerCertificate.IsEmpty)
                        {
                            base.mAllowCertificateStatus = false;
                        }
                        this.mKeyExchange.ProcessServerCertificate(base.mPeerCertificate);
                        this.mAuthentication = this.mTlsClient.GetAuthentication();
                        this.mAuthentication.NotifyServerCertificate(base.mPeerCertificate);
                        base.mConnectionState = 4;
                        return;
                    }
                    throw new TlsFatalAlert(10);

                case 12:
                    switch (base.mConnectionState)
                    {
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                        if (base.mConnectionState < 3)
                        {
                            this.HandleSupplementalData(null);
                        }
                        if (base.mConnectionState < 4)
                        {
                            this.mKeyExchange.SkipServerCredentials();
                            this.mAuthentication = null;
                        }
                        this.mKeyExchange.ProcessServerKeyExchange(buf);
                        TlsProtocol.AssertEmpty(buf);
                        base.mConnectionState = 6;
                        return;
                    }
                    throw new TlsFatalAlert(10);

                case 13:
                    switch (base.mConnectionState)
                    {
                    case 4:
                    case 5:
                    case 6:
                        if (base.mConnectionState != 6)
                        {
                            this.mKeyExchange.SkipServerKeyExchange();
                        }
                        if (this.mAuthentication == null)
                        {
                            throw new TlsFatalAlert(40);
                        }
                        this.mCertificateRequest = CertificateRequest.Parse(this.Context, buf);
                        TlsProtocol.AssertEmpty(buf);
                        this.mKeyExchange.ValidateCertificateRequest(this.mCertificateRequest);
                        TlsUtilities.TrackHashAlgorithms(base.mRecordStream.HandshakeHash, this.mCertificateRequest.SupportedSignatureAlgorithms);
                        base.mConnectionState = 7;
                        return;
                    }
                    throw new TlsFatalAlert(10);

                case 14:
                    switch (base.mConnectionState)
                    {
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                    case 7:
                    {
                        if (base.mConnectionState < 3)
                        {
                            this.HandleSupplementalData(null);
                        }
                        if (base.mConnectionState < 4)
                        {
                            this.mKeyExchange.SkipServerCredentials();
                            this.mAuthentication = null;
                        }
                        if (base.mConnectionState < 6)
                        {
                            this.mKeyExchange.SkipServerKeyExchange();
                        }
                        TlsProtocol.AssertEmpty(buf);
                        base.mConnectionState = 8;
                        base.mRecordStream.HandshakeHash.SealHashAlgorithms();
                        IList clientSupplementalData = this.mTlsClient.GetClientSupplementalData();
                        if (clientSupplementalData != null)
                        {
                            this.SendSupplementalDataMessage(clientSupplementalData);
                        }
                        base.mConnectionState = 9;
                        TlsCredentials clientCredentials = null;
                        if (this.mCertificateRequest == null)
                        {
                            this.mKeyExchange.SkipClientCredentials();
                        }
                        else
                        {
                            clientCredentials = this.mAuthentication.GetClientCredentials(this.Context, this.mCertificateRequest);
                            if (clientCredentials == null)
                            {
                                this.mKeyExchange.SkipClientCredentials();
                                this.SendCertificateMessage(Certificate.EmptyChain);
                            }
                            else
                            {
                                this.mKeyExchange.ProcessClientCredentials(clientCredentials);
                                this.SendCertificateMessage(clientCredentials.Certificate);
                            }
                        }
                        base.mConnectionState = 10;
                        this.SendClientKeyExchangeMessage();
                        base.mConnectionState = 11;
                        TlsHandshakeHash handshakeHash = base.mRecordStream.PrepareToFinish();
                        base.mSecurityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(this.Context, handshakeHash, null);
                        TlsProtocol.EstablishMasterSecret(this.Context, this.mKeyExchange);
                        base.mRecordStream.SetPendingConnectionState(this.Peer.GetCompression(), this.Peer.GetCipher());
                        if ((clientCredentials != null) && (clientCredentials is TlsSignerCredentials))
                        {
                            byte[] sessionHash;
                            TlsSignerCredentials      signerCredentials         = (TlsSignerCredentials)clientCredentials;
                            SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(this.Context, signerCredentials);
                            if (signatureAndHashAlgorithm == null)
                            {
                                sessionHash = base.mSecurityParameters.SessionHash;
                            }
                            else
                            {
                                sessionHash = handshakeHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
                            }
                            byte[]          signature         = signerCredentials.GenerateCertificateSignature(sessionHash);
                            DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
                            this.SendCertificateVerifyMessage(certificateVerify);
                            base.mConnectionState = 12;
                        }
                        this.SendChangeCipherSpecMessage();
                        this.SendFinishedMessage();
                        base.mConnectionState = 13;
                        return;
                    }
                    }
                    throw new TlsFatalAlert(40);

                case 20:
                    switch (base.mConnectionState)
                    {
                    case 13:
                    case 14:
                        if ((base.mConnectionState == 13) && base.mExpectSessionTicket)
                        {
                            throw new TlsFatalAlert(10);
                        }
                        this.ProcessFinishedMessage(buf);
                        base.mConnectionState = 15;
                        base.mConnectionState = 0x10;
                        this.CompleteHandshake();
                        return;
                    }
                    throw new TlsFatalAlert(10);

                case 0x16:
                    if (base.mConnectionState != 4)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    if (!base.mAllowCertificateStatus)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    this.mCertificateStatus = CertificateStatus.Parse(buf);
                    TlsProtocol.AssertEmpty(buf);
                    base.mConnectionState = 5;
                    return;

                case 0x17:
                    if (base.mConnectionState != 2)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    this.HandleSupplementalData(TlsProtocol.ReadSupplementalDataMessage(buf));
                    return;
                }
                throw new TlsFatalAlert(10);
            }
        }