Ejemplo n.º 1
0
 protected virtual void HandleSupplementalData(global::System.Collections.IList serverSupplementalData)
 {
     mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
     mConnectionState = 3;
     mKeyExchange     = mTlsClient.GetKeyExchange();
     mKeyExchange.Init(Context);
 }
Ejemplo n.º 2
0
 protected virtual void HandleSupplementalData(IList serverSupplementalData)
 {
     this.mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
     base.mConnectionState = 3;
     this.mKeyExchange     = this.mTlsClient.GetKeyExchange();
     this.mKeyExchange.Init(this.Context);
 }
Ejemplo n.º 3
0
 protected override void CleanupHandshake()
 {
     base.CleanupHandshake();
     this.mKeyExchange        = null;
     this.mServerCredentials  = null;
     this.mCertificateRequest = null;
     this.mPrepareFinishHash  = null;
 }
Ejemplo n.º 4
0
        protected virtual void HandleSupplementalData(IList serverSupplementalData)
        {
            this.mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
            this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;

            this.mKeyExchange = mTlsClient.GetKeyExchange();
            this.mKeyExchange.Init(Context);
        }
Ejemplo n.º 5
0
 protected override void CleanupHandshake()
 {
     base.CleanupHandshake();
 
     this.mKeyExchange = null;
     this.mServerCredentials = null;
     this.mCertificateRequest = null;
     this.mPrepareFinishHash = null;
 }
Ejemplo n.º 6
0
 protected override void CleanupHandshake()
 {
     base.CleanupHandshake();
     mSelectedSessionID  = null;
     mKeyExchange        = null;
     mAuthentication     = null;
     mCertificateStatus  = null;
     mCertificateRequest = null;
 }
        protected override void CleanupHandshake()
        {
            base.CleanupHandshake();

            this.mSelectedSessionID = null;
            this.mKeyExchange = null;
            this.mAuthentication = null;
            this.mCertificateStatus = null;
            this.mCertificateRequest = null;
        }
        protected virtual void HandleSupplementalData(IList serverSupplementalData)
        {
            if (HTTPManager.Logger.Level <= Loglevels.All)
            {
                HTTPManager.Logger.Verbose("TlsClientProtocol", "HandleSupplementalData", this.LoggingContext);
            }

            this.mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
            this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;

            this.mKeyExchange = mTlsClient.GetKeyExchange();
            this.mKeyExchange.Init(Context);
        }
Ejemplo n.º 9
0
 protected internal static void EstablishMasterSecret(TlsContext context, TlsKeyExchange keyExchange)
 {
     byte[] array = keyExchange.GeneratePremasterSecret();
     try
     {
         context.SecurityParameters.masterSecret = TlsUtilities.CalculateMasterSecret(context, array);
     }
     finally
     {
         if (array != null)
         {
             Arrays.Fill(array, 0);
         }
     }
 }
        protected override void CleanupHandshake()
        {
            if (HTTPManager.Logger.Level <= Loglevels.All)
            {
                HTTPManager.Logger.Verbose("TlsClientProtocol", "CleanupHandshake", this.LoggingContext);
            }

            base.CleanupHandshake();

            this.mSelectedSessionID           = null;
            this.mKeyExchange                 = null;
            this.mAuthentication              = null;
            this.mTlsClient.CertificateStatus = null;
            this.mCertificateRequest          = null;
        }
Ejemplo n.º 11
0
        protected internal static void EstablishMasterSecret(TlsContext context, TlsKeyExchange keyExchange)
        {
            byte[] pre_master_secret = keyExchange.GeneratePremasterSecret();

            try
            {
                context.SecurityParameters.masterSecret = TlsUtilities.CalculateMasterSecret(context, pre_master_secret);
            }
            finally
            {
                // 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.
                 */
                if (pre_master_secret != null)
                {
                    Arrays.Fill(pre_master_secret, (byte)0);
                }
            }
        }
Ejemplo n.º 12
0
        protected override void HandleHandshakeMessage(byte type, byte[] data)
        {
            MemoryStream buf = new MemoryStream(data);

            switch (type)
            {
            case HandshakeType.client_hello:
            {
                switch (this.mConnectionState)
                {
                case CS_START:
                {
                    ReceiveClientHelloMessage(buf);
                    this.mConnectionState = CS_CLIENT_HELLO;

                    SendServerHelloMessage();
                    this.mConnectionState = CS_SERVER_HELLO;

                    mRecordStream.NotifyHelloComplete();

                    IList serverSupplementalData = mTlsServer.GetServerSupplementalData();
                    if (serverSupplementalData != null)
                    {
                        SendSupplementalDataMessage(serverSupplementalData);
                    }
                    this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;

                    this.mKeyExchange = mTlsServer.GetKeyExchange();
                    this.mKeyExchange.Init(Context);

                    this.mServerCredentials = mTlsServer.GetCredentials();

                    Certificate serverCertificate = null;

                    if (this.mServerCredentials == null)
                    {
                        this.mKeyExchange.SkipServerCredentials();
                    }
                    else
                    {
                        this.mKeyExchange.ProcessServerCredentials(this.mServerCredentials);

                        serverCertificate = this.mServerCredentials.Certificate;
                        SendCertificateMessage(serverCertificate);
                    }
                    this.mConnectionState = CS_SERVER_CERTIFICATE;

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

                    if (this.mAllowCertificateStatus)
                    {
                        CertificateStatus certificateStatus = mTlsServer.GetCertificateStatus();
                        if (certificateStatus != null)
                        {
                            SendCertificateStatusMessage(certificateStatus);
                        }
                    }

                    this.mConnectionState = CS_CERTIFICATE_STATUS;

                    byte[] serverKeyExchange = this.mKeyExchange.GenerateServerKeyExchange();
                    if (serverKeyExchange != null)
                    {
                        SendServerKeyExchangeMessage(serverKeyExchange);
                    }
                    this.mConnectionState = CS_SERVER_KEY_EXCHANGE;

                    if (this.mServerCredentials != null)
                    {
                        this.mCertificateRequest = mTlsServer.GetCertificateRequest();
                        if (this.mCertificateRequest != null)
                        {
                            this.mKeyExchange.ValidateCertificateRequest(mCertificateRequest);

                            SendCertificateRequestMessage(mCertificateRequest);

                            TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
                                this.mCertificateRequest.SupportedSignatureAlgorithms);
                        }
                    }
                    this.mConnectionState = CS_CERTIFICATE_REQUEST;

                    SendServerHelloDoneMessage();
                    this.mConnectionState = CS_SERVER_HELLO_DONE;

                    this.mRecordStream.HandshakeHash.SealHashAlgorithms();

                    break;
                }
                case CS_END:
                {
                    RefuseRenegotiation();
                    break;
                }
                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }
            case HandshakeType.supplemental_data:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO_DONE:
                {
                    mTlsServer.ProcessClientSupplementalData(ReadSupplementalDataMessage(buf));
                    this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
                    break;
                }
                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }
            case HandshakeType.certificate:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO_DONE:
                case CS_CLIENT_SUPPLEMENTAL_DATA:
                {
                    if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
                    {
                        mTlsServer.ProcessClientSupplementalData(null);
                    }

                    if (this.mCertificateRequest == null)
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);

                    ReceiveCertificateMessage(buf);
                    this.mConnectionState = CS_CLIENT_CERTIFICATE;
                    break;
                }
                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }
            case HandshakeType.client_key_exchange:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO_DONE:
                case CS_CLIENT_SUPPLEMENTAL_DATA:
                case CS_CLIENT_CERTIFICATE:
                {
                    if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
                    {
                        mTlsServer.ProcessClientSupplementalData(null);
                    }

                    if (mConnectionState < CS_CLIENT_CERTIFICATE)
                    {
                        if (this.mCertificateRequest == null)
                        {
                            this.mKeyExchange.SkipClientCredentials();
                        }
                        else
                        {
                            if (TlsUtilities.IsTlsV12(Context))
                            {
                                /*
                                 * 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.
                                 */
                                throw new TlsFatalAlert(AlertDescription.unexpected_message);
                            }
                            else if (TlsUtilities.IsSsl(Context))
                            {
                                if (this.mPeerCertificate == null)
                                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                            }
                            else
                            {
                                NotifyClientCertificate(Certificate.EmptyChain);
                            }
                        }
                    }

                    ReceiveClientKeyExchangeMessage(buf);
                    this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
                    break;
                }
                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }
            case HandshakeType.certificate_verify:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_KEY_EXCHANGE:
                {
                    /*
                     * RFC 5246 7.4.8 This message is only sent following a client certificate that has
                     * signing capability (i.e., all certificates except those containing fixed
                     * Diffie-Hellman parameters).
                     */
                    if (!ExpectCertificateVerifyMessage())
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);

                    ReceiveCertificateVerifyMessage(buf);
                    this.mConnectionState = CS_CERTIFICATE_VERIFY;

                    break;
                }
                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }
            case HandshakeType.finished:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_KEY_EXCHANGE:
                case CS_CERTIFICATE_VERIFY:
                {
                    if (mConnectionState < CS_CERTIFICATE_VERIFY && ExpectCertificateVerifyMessage())
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);

                    ProcessFinishedMessage(buf);
                    this.mConnectionState = CS_CLIENT_FINISHED;

                    if (this.mExpectSessionTicket)
                    {
                        SendNewSessionTicketMessage(mTlsServer.GetNewSessionTicket());
                        SendChangeCipherSpecMessage();
                    }
                    this.mConnectionState = CS_SERVER_SESSION_TICKET;

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

                    CompleteHandshake();
                    break;
                }
                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }
            case HandshakeType.hello_request:
            case HandshakeType.hello_verify_request:
            case HandshakeType.server_hello:
            case HandshakeType.server_key_exchange:
            case HandshakeType.certificate_request:
            case HandshakeType.server_hello_done:
            case HandshakeType.session_ticket:
            default:
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }
        }
Ejemplo n.º 13
0
        protected override void HandleHandshakeMessage(byte type, byte[] data)
        {
            MemoryStream buf = new MemoryStream(data);

            switch (type)
            {
            case HandshakeType.client_hello:
            {
                switch (this.mConnectionState)
                {
                case CS_START:
                {
                    ReceiveClientHelloMessage(buf);
                    this.mConnectionState = CS_CLIENT_HELLO;

                    SendServerHelloMessage();
                    this.mConnectionState = CS_SERVER_HELLO;

                    mRecordStream.NotifyHelloComplete();

                    IList serverSupplementalData = mTlsServer.GetServerSupplementalData();
                    if (serverSupplementalData != null)
                    {
                        SendSupplementalDataMessage(serverSupplementalData);
                    }
                    this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;

                    this.mKeyExchange = mTlsServer.GetKeyExchange();
                    this.mKeyExchange.Init(Context);

                    this.mServerCredentials = mTlsServer.GetCredentials();

                    Certificate serverCertificate = null;

                    if (this.mServerCredentials == null)
                    {
                        this.mKeyExchange.SkipServerCredentials();
                    }
                    else
                    {
                        this.mKeyExchange.ProcessServerCredentials(this.mServerCredentials);

                        serverCertificate = this.mServerCredentials.Certificate;
                        SendCertificateMessage(serverCertificate);
                    }
                    this.mConnectionState = CS_SERVER_CERTIFICATE;

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

                    if (this.mAllowCertificateStatus)
                    {
                        CertificateStatus certificateStatus = mTlsServer.GetCertificateStatus();
                        if (certificateStatus != null)
                        {
                            SendCertificateStatusMessage(certificateStatus);
                        }
                    }

                    this.mConnectionState = CS_CERTIFICATE_STATUS;

                    byte[] serverKeyExchange = this.mKeyExchange.GenerateServerKeyExchange();
                    if (serverKeyExchange != null)
                    {
                        SendServerKeyExchangeMessage(serverKeyExchange);
                    }
                    this.mConnectionState = CS_SERVER_KEY_EXCHANGE;

                    if (this.mServerCredentials != null)
                    {
                        this.mCertificateRequest = mTlsServer.GetCertificateRequest();
                        if (this.mCertificateRequest != null)
                        {
                            this.mKeyExchange.ValidateCertificateRequest(mCertificateRequest);

                            SendCertificateRequestMessage(mCertificateRequest);

                            TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
                                                             this.mCertificateRequest.SupportedSignatureAlgorithms);
                        }
                    }
                    this.mConnectionState = CS_CERTIFICATE_REQUEST;

                    SendServerHelloDoneMessage();
                    this.mConnectionState = CS_SERVER_HELLO_DONE;

                    this.mRecordStream.HandshakeHash.SealHashAlgorithms();

                    break;
                }

                case CS_END:
                {
                    RefuseRenegotiation();
                    break;
                }

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

            case HandshakeType.supplemental_data:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO_DONE:
                {
                    mTlsServer.ProcessClientSupplementalData(ReadSupplementalDataMessage(buf));
                    this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
                    break;
                }

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

            case HandshakeType.certificate:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO_DONE:
                case CS_CLIENT_SUPPLEMENTAL_DATA:
                {
                    if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
                    {
                        mTlsServer.ProcessClientSupplementalData(null);
                    }

                    if (this.mCertificateRequest == null)
                    {
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    ReceiveCertificateMessage(buf);
                    this.mConnectionState = CS_CLIENT_CERTIFICATE;
                    break;
                }

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

            case HandshakeType.client_key_exchange:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO_DONE:
                case CS_CLIENT_SUPPLEMENTAL_DATA:
                case CS_CLIENT_CERTIFICATE:
                {
                    if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
                    {
                        mTlsServer.ProcessClientSupplementalData(null);
                    }

                    if (mConnectionState < CS_CLIENT_CERTIFICATE)
                    {
                        if (this.mCertificateRequest == null)
                        {
                            this.mKeyExchange.SkipClientCredentials();
                        }
                        else
                        {
                            if (TlsUtilities.IsTlsV12(Context))
                            {
                                /*
                                 * 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.
                                 */
                                throw new TlsFatalAlert(AlertDescription.unexpected_message);
                            }
                            else if (TlsUtilities.IsSsl(Context))
                            {
                                if (this.mPeerCertificate == null)
                                {
                                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                                }
                            }
                            else
                            {
                                NotifyClientCertificate(Certificate.EmptyChain);
                            }
                        }
                    }

                    ReceiveClientKeyExchangeMessage(buf);
                    this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
                    break;
                }

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

            case HandshakeType.certificate_verify:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_KEY_EXCHANGE:
                {
                    /*
                     * RFC 5246 7.4.8 This message is only sent following a client certificate that has
                     * signing capability (i.e., all certificates except those containing fixed
                     * Diffie-Hellman parameters).
                     */
                    if (!ExpectCertificateVerifyMessage())
                    {
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    ReceiveCertificateVerifyMessage(buf);
                    this.mConnectionState = CS_CERTIFICATE_VERIFY;

                    break;
                }

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

            case HandshakeType.finished:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_KEY_EXCHANGE:
                case CS_CERTIFICATE_VERIFY:
                {
                    if (mConnectionState < CS_CERTIFICATE_VERIFY && ExpectCertificateVerifyMessage())
                    {
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    ProcessFinishedMessage(buf);
                    this.mConnectionState = CS_CLIENT_FINISHED;

                    if (this.mExpectSessionTicket)
                    {
                        SendNewSessionTicketMessage(mTlsServer.GetNewSessionTicket());
                        SendChangeCipherSpecMessage();
                    }
                    this.mConnectionState = CS_SERVER_SESSION_TICKET;

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

                    CompleteHandshake();
                    break;
                }

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

            case HandshakeType.hello_request:
            case HandshakeType.hello_verify_request:
            case HandshakeType.server_hello:
            case HandshakeType.server_key_exchange:
            case HandshakeType.certificate_request:
            case HandshakeType.server_hello_done:
            case HandshakeType.session_ticket:
            default:
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }
        }
Ejemplo n.º 14
0
        private void ProcessHandshakeMessage(HandshakeType type, byte[] buf)
        {
            MemoryStream inStr = new MemoryStream(buf, false);

            /*
             * Check the type.
             */
            switch (type)
            {
            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.handshake_failure);
                    }

                    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, this);

                    /*
                     * 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.
                     */
                    CipherSuite selectedCipherSuite = (CipherSuite)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.
                     */
                    CompressionMethod selectedCompressionMethod = (CompressionMethod)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.
                     */

                    // ExtensionType -> 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)
                        {
                            ExtensionType extType  = (ExtensionType)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(emptybuf)))
                            {
                                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_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 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);
                    }

                    int numTypes = TlsUtilities.ReadUint8(inStr);
                    ClientCertificateType[] certificateTypes = new ClientCertificateType[numTypes];
                    for (int i = 0; i < numTypes; ++i)
                    {
                        certificateTypes[i] = (ClientCertificateType)TlsUtilities.ReadUint8(inStr);
                    }

                    byte[] authorities = TlsUtilities.ReadOpaque16(inStr);

                    AssertEmpty(inStr);

                    IList authorityDNs = Platform.CreateArrayList();

                    MemoryStream bis = new MemoryStream(authorities, false);
                    while (bis.Position < bis.Length)
                    {
                        byte[] dnBytes = TlsUtilities.ReadOpaque16(bis);
                        // TODO Switch to X500Name when available
                        authorityDNs.Add(X509Name.GetInstance(Asn1Object.FromByteArray(dnBytes)));
                    }

                    this.certificateRequest = new CertificateRequest(certificateTypes,
                                                                     authorityDNs);
                    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;
            }
        }
Ejemplo n.º 15
0
        protected override void HandleHandshakeMessage(byte type, byte[] data)
        {
            //IL_0001: Unknown result type (might be due to invalid IL or missing references)
            //IL_0007: Expected O, but got Unknown
            MemoryStream val = new MemoryStream(data);

            switch (type)
            {
            case 1:
                switch (mConnectionState)
                {
                case 0:
                {
                    ReceiveClientHelloMessage(val);
                    mConnectionState = 1;
                    SendServerHelloMessage();
                    mConnectionState = 2;
                    mRecordStream.NotifyHelloComplete();
                    global::System.Collections.IList serverSupplementalData = mTlsServer.GetServerSupplementalData();
                    if (serverSupplementalData != null)
                    {
                        SendSupplementalDataMessage(serverSupplementalData);
                    }
                    mConnectionState = 3;
                    mKeyExchange     = mTlsServer.GetKeyExchange();
                    mKeyExchange.Init(Context);
                    mServerCredentials = mTlsServer.GetCredentials();
                    Certificate certificate = null;
                    if (mServerCredentials == null)
                    {
                        mKeyExchange.SkipServerCredentials();
                    }
                    else
                    {
                        mKeyExchange.ProcessServerCredentials(mServerCredentials);
                        certificate = mServerCredentials.Certificate;
                        SendCertificateMessage(certificate);
                    }
                    mConnectionState = 4;
                    if (certificate == null || certificate.IsEmpty)
                    {
                        mAllowCertificateStatus = false;
                    }
                    if (mAllowCertificateStatus)
                    {
                        CertificateStatus certificateStatus = mTlsServer.GetCertificateStatus();
                        if (certificateStatus != null)
                        {
                            SendCertificateStatusMessage(certificateStatus);
                        }
                    }
                    mConnectionState = 5;
                    byte[] array = mKeyExchange.GenerateServerKeyExchange();
                    if (array != null)
                    {
                        SendServerKeyExchangeMessage(array);
                    }
                    mConnectionState = 6;
                    if (mServerCredentials != null)
                    {
                        mCertificateRequest = mTlsServer.GetCertificateRequest();
                        if (mCertificateRequest != null)
                        {
                            if (TlsUtilities.IsTlsV12(Context) != (mCertificateRequest.SupportedSignatureAlgorithms != null))
                            {
                                throw new TlsFatalAlert(80);
                            }
                            mKeyExchange.ValidateCertificateRequest(mCertificateRequest);
                            SendCertificateRequestMessage(mCertificateRequest);
                            TlsUtilities.TrackHashAlgorithms(mRecordStream.HandshakeHash, mCertificateRequest.SupportedSignatureAlgorithms);
                        }
                    }
                    mConnectionState = 7;
                    SendServerHelloDoneMessage();
                    mConnectionState = 8;
                    mRecordStream.HandshakeHash.SealHashAlgorithms();
                    break;
                }

                case 16:
                    RefuseRenegotiation();
                    break;

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

            case 23:
            {
                short num = mConnectionState;
                if (num == 8)
                {
                    mTlsServer.ProcessClientSupplementalData(TlsProtocol.ReadSupplementalDataMessage(val));
                    mConnectionState = 9;
                    break;
                }
                throw new TlsFatalAlert(10);
            }

            case 11:
                switch (mConnectionState)
                {
                case 8:
                case 9:
                    if (mConnectionState < 9)
                    {
                        mTlsServer.ProcessClientSupplementalData(null);
                    }
                    if (mCertificateRequest == null)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    ReceiveCertificateMessage(val);
                    mConnectionState = 10;
                    break;

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

            case 16:
                switch (mConnectionState)
                {
                case 8:
                case 9:
                case 10:
                    if (mConnectionState < 9)
                    {
                        mTlsServer.ProcessClientSupplementalData(null);
                    }
                    if (mConnectionState < 10)
                    {
                        if (mCertificateRequest == null)
                        {
                            mKeyExchange.SkipClientCredentials();
                        }
                        else
                        {
                            if (TlsUtilities.IsTlsV12(Context))
                            {
                                throw new TlsFatalAlert(10);
                            }
                            if (TlsUtilities.IsSsl(Context))
                            {
                                if (mPeerCertificate == null)
                                {
                                    throw new TlsFatalAlert(10);
                                }
                            }
                            else
                            {
                                NotifyClientCertificate(Certificate.EmptyChain);
                            }
                        }
                    }
                    ReceiveClientKeyExchangeMessage(val);
                    mConnectionState = 11;
                    break;

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

            case 15:
            {
                short num = mConnectionState;
                if (num == 11)
                {
                    if (!ExpectCertificateVerifyMessage())
                    {
                        throw new TlsFatalAlert(10);
                    }
                    ReceiveCertificateVerifyMessage(val);
                    mConnectionState = 12;
                    break;
                }
                throw new TlsFatalAlert(10);
            }

            case 20:
                switch (mConnectionState)
                {
                case 11:
                case 12:
                    if (mConnectionState < 12 && ExpectCertificateVerifyMessage())
                    {
                        throw new TlsFatalAlert(10);
                    }
                    ProcessFinishedMessage(val);
                    mConnectionState = 13;
                    if (mExpectSessionTicket)
                    {
                        SendNewSessionTicketMessage(mTlsServer.GetNewSessionTicket());
                        SendChangeCipherSpecMessage();
                    }
                    mConnectionState = 14;
                    SendFinishedMessage();
                    mConnectionState = 15;
                    mConnectionState = 16;
                    CompleteHandshake();
                    break;

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

            default:
                throw new TlsFatalAlert(10);
            }
        }
Ejemplo n.º 16
0
		private void ProcessHandshakeMessage(short type, byte[] buf)
		{
			MemoryStream inStr = new MemoryStream(buf, false);

			/*
			* Check the type.
			*/
			switch (type)
			{
				case HP_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);

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

					connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
					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[] 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(AL_fatal, AP_handshake_failure);
							}

							connection_state = CS_DONE;

							/*
							* We are now ready to receive application data.
							*/
							this.appDataReady = 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
							 */
							securityParameters.serverRandom = new byte[32];
							TlsUtilities.ReadFully(securityParameters.serverRandom, inStr);

							/*
							 * Currently, we don't support session ids
							 */
							byte[] sessionID = TlsUtilities.ReadOpaque8(inStr);
							if (sessionID.Length > 32)
							{
								this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_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 (!WasCipherSuiteOffered(selectedCipherSuite))
							{
								this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);
							}

							this.tlsClient.NotifySelectedCipherSuite(selectedCipherSuite);

							/*
							 * 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);
							}

	                        /*
	                         * RFC4366 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.
	                         */
	                        if (extendedClientHello)
	                        {
	                            // Integer -> byte[]
	                            Hashtable serverExtensions = new Hashtable();

	                            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);

	                                    serverExtensions.Add(extType, extValue);
	                                }
	                            }

								// TODO[RFC 5746] If renegotiation_info was sent in client hello, check here

	                            tlsClient.ProcessServerExtensions(serverExtensions);
	                        }

							AssertEmpty(inStr);

	                        this.keyExchange = tlsClient.CreateKeyExchange();

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

							AssertEmpty(inStr);

							bool isClientCertificateRequested = (connection_state == CS_CERTIFICATE_REQUEST_RECEIVED);

							connection_state = CS_SERVER_HELLO_DONE_RECEIVED;

							if (isClientCertificateRequested)
							{
								SendClientCertificate(tlsClient.GetCertificate());
							}

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

							connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;

							if (isClientCertificateRequested)
							{
								byte[] clientCertificateSignature = tlsClient.GenerateCertificateSignature(rs.GetCurrentHash());
								if (clientCertificateSignature != null)
								{
									SendCertificateVerify(clientCertificateSignature);

									connection_state = CS_CERTIFICATE_VERIFY_SEND;
								}
							}

							/*
							* Now, we send change cipher state
							*/
							byte[] cmessage = new byte[1];
							cmessage[0] = 1;
							rs.WriteMessage(RL_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.CreateCipher(securityParameters));

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

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

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

							this.connection_state = CS_CLIENT_FINISHED_SEND;
							break;
						default:
							this.FailWithError(AL_fatal, AP_handshake_failure);
							break;
					}
					break;
				case HP_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.keyExchange.ProcessServerKeyExchange(inStr, securityParameters);

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

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

							byte[] types = TlsUtilities.ReadOpaque8(inStr);
							byte[] authorities = TlsUtilities.ReadOpaque16(inStr);

							AssertEmpty(inStr);

							ArrayList authorityDNs = new ArrayList();

							MemoryStream bis = new MemoryStream(authorities, false);
							while (bis.Position < bis.Length)
							{
								byte[] dnBytes = TlsUtilities.ReadOpaque16(bis);
								authorityDNs.Add(X509Name.GetInstance(Asn1Object.FromByteArray(dnBytes)));
							}

							this.tlsClient.ProcessServerCertificateRequest(types, authorityDNs);

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

					this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED;
					break;
				case HP_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(AL_warning, AP_no_renegotiation);
					}
					break;
				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;
			}
		}
Ejemplo n.º 17
0
        protected override void HandleHandshakeMessage(byte type, byte[] data)
        {
            MemoryStream memoryStream = new MemoryStream(data);

            switch (type)
            {
            case 1:
            {
                short mConnectionState = this.mConnectionState;
                if (mConnectionState == 0)
                {
                    this.ReceiveClientHelloMessage(memoryStream);
                    this.mConnectionState = 1;
                    this.SendServerHelloMessage();
                    this.mConnectionState = 2;
                    this.mRecordStream.NotifyHelloComplete();
                    IList serverSupplementalData = this.mTlsServer.GetServerSupplementalData();
                    if (serverSupplementalData != null)
                    {
                        this.SendSupplementalDataMessage(serverSupplementalData);
                    }
                    this.mConnectionState = 3;
                    this.mKeyExchange     = this.mTlsServer.GetKeyExchange();
                    this.mKeyExchange.Init(this.Context);
                    this.mServerCredentials = this.mTlsServer.GetCredentials();
                    Certificate certificate = null;
                    if (this.mServerCredentials == null)
                    {
                        this.mKeyExchange.SkipServerCredentials();
                    }
                    else
                    {
                        this.mKeyExchange.ProcessServerCredentials(this.mServerCredentials);
                        certificate = this.mServerCredentials.Certificate;
                        this.SendCertificateMessage(certificate);
                    }
                    this.mConnectionState = 4;
                    if (certificate == null || certificate.IsEmpty)
                    {
                        this.mAllowCertificateStatus = false;
                    }
                    if (this.mAllowCertificateStatus)
                    {
                        CertificateStatus certificateStatus = this.mTlsServer.GetCertificateStatus();
                        if (certificateStatus != null)
                        {
                            this.SendCertificateStatusMessage(certificateStatus);
                        }
                    }
                    this.mConnectionState = 5;
                    byte[] array = this.mKeyExchange.GenerateServerKeyExchange();
                    if (array != null)
                    {
                        this.SendServerKeyExchangeMessage(array);
                    }
                    this.mConnectionState = 6;
                    if (this.mServerCredentials != null)
                    {
                        this.mCertificateRequest = this.mTlsServer.GetCertificateRequest();
                        if (this.mCertificateRequest != null)
                        {
                            this.mKeyExchange.ValidateCertificateRequest(this.mCertificateRequest);
                            this.SendCertificateRequestMessage(this.mCertificateRequest);
                            TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash, this.mCertificateRequest.SupportedSignatureAlgorithms);
                        }
                    }
                    this.mConnectionState = 7;
                    this.SendServerHelloDoneMessage();
                    this.mConnectionState = 8;
                    this.mRecordStream.HandshakeHash.SealHashAlgorithms();
                    return;
                }
                if (mConnectionState != 16)
                {
                    throw new TlsFatalAlert(10);
                }
                this.RefuseRenegotiation();
                return;
            }

            case 11:
                switch (this.mConnectionState)
                {
                case 8:
                case 9:
                    if (this.mConnectionState < 9)
                    {
                        this.mTlsServer.ProcessClientSupplementalData(null);
                    }
                    if (this.mCertificateRequest == null)
                    {
                        throw new TlsFatalAlert(10);
                    }
                    this.ReceiveCertificateMessage(memoryStream);
                    this.mConnectionState = 10;
                    return;

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

            case 15:
            {
                short mConnectionState2 = this.mConnectionState;
                if (mConnectionState2 != 11)
                {
                    throw new TlsFatalAlert(10);
                }
                if (!this.ExpectCertificateVerifyMessage())
                {
                    throw new TlsFatalAlert(10);
                }
                this.ReceiveCertificateVerifyMessage(memoryStream);
                this.mConnectionState = 12;
                return;
            }

            case 16:
                switch (this.mConnectionState)
                {
                case 8:
                case 9:
                case 10:
                    if (this.mConnectionState < 9)
                    {
                        this.mTlsServer.ProcessClientSupplementalData(null);
                    }
                    if (this.mConnectionState < 10)
                    {
                        if (this.mCertificateRequest == null)
                        {
                            this.mKeyExchange.SkipClientCredentials();
                        }
                        else
                        {
                            if (TlsUtilities.IsTlsV12(this.Context))
                            {
                                throw new TlsFatalAlert(10);
                            }
                            if (TlsUtilities.IsSsl(this.Context))
                            {
                                if (this.mPeerCertificate == null)
                                {
                                    throw new TlsFatalAlert(10);
                                }
                            }
                            else
                            {
                                this.NotifyClientCertificate(Certificate.EmptyChain);
                            }
                        }
                    }
                    this.ReceiveClientKeyExchangeMessage(memoryStream);
                    this.mConnectionState = 11;
                    return;

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

            case 20:
                switch (this.mConnectionState)
                {
                case 11:
                case 12:
                    if (this.mConnectionState < 12 && this.ExpectCertificateVerifyMessage())
                    {
                        throw new TlsFatalAlert(10);
                    }
                    this.ProcessFinishedMessage(memoryStream);
                    this.mConnectionState = 13;
                    if (this.mExpectSessionTicket)
                    {
                        this.SendNewSessionTicketMessage(this.mTlsServer.GetNewSessionTicket());
                        this.SendChangeCipherSpecMessage();
                    }
                    this.mConnectionState = 14;
                    this.SendFinishedMessage();
                    this.mConnectionState = 15;
                    this.mConnectionState = 16;
                    return;

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

            case 23:
            {
                short mConnectionState3 = this.mConnectionState;
                if (mConnectionState3 == 8)
                {
                    this.mTlsServer.ProcessClientSupplementalData(TlsProtocol.ReadSupplementalDataMessage(memoryStream));
                    this.mConnectionState = 9;
                    return;
                }
                throw new TlsFatalAlert(10);
            }
            }
            throw new TlsFatalAlert(10);
        }
        protected virtual void HandleSupplementalData(IList serverSupplementalData)
        {
            this.mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
            this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;

            this.mKeyExchange = mTlsClient.GetKeyExchange();
            this.mKeyExchange.Init(Context);
        }
Ejemplo n.º 19
0
		private void ProcessHandshakeMessage(HandshakeType type, byte[] buf)
		{
			MemoryStream inStr = new MemoryStream(buf, false);

			/*
			* Check the type.
			*/
			switch (type)
			{
				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.handshake_failure);
							}

							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, this);

							/*
							 * 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.
							 */
							CipherSuite selectedCipherSuite = (CipherSuite)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.
                             */
                            CompressionMethod selectedCompressionMethod = (CompressionMethod)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.
							 */

							// ExtensionType -> 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)
								{
                                    ExtensionType extType = (ExtensionType)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(emptybuf)))
									{
										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_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 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);
							}

                            int numTypes = TlsUtilities.ReadUint8(inStr);
                            ClientCertificateType[] certificateTypes = new ClientCertificateType[numTypes];
                            for (int i = 0; i < numTypes; ++i)
                            {
                                certificateTypes[i] = (ClientCertificateType)TlsUtilities.ReadUint8(inStr);
                            }

                            byte[] authorities = TlsUtilities.ReadOpaque16(inStr);

							AssertEmpty(inStr);

                            IList authorityDNs = Platform.CreateArrayList();

							MemoryStream bis = new MemoryStream(authorities, false);
							while (bis.Position < bis.Length)
							{
								byte[] dnBytes = TlsUtilities.ReadOpaque16(bis);
								// TODO Switch to X500Name when available
								authorityDNs.Add(X509Name.GetInstance(Asn1Object.FromByteArray(dnBytes)));
							}

							this.certificateRequest = new CertificateRequest(certificateTypes,
								authorityDNs);
							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 internal static void EstablishMasterSecret(TlsContext context, TlsKeyExchange keyExchange)
        {
            byte[] pre_master_secret = keyExchange.GeneratePremasterSecret();

            try
            {
                context.SecurityParameters.masterSecret = TlsUtilities.CalculateMasterSecret(context, pre_master_secret);
            }
            finally
            {
                // 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.
                 */
                if (pre_master_secret != null)
                {
                    Arrays.Fill(pre_master_secret, (byte)0);
                }
            }
        }
Ejemplo n.º 21
0
        private void ProcessHandshakeMessage(short type, byte[] buf)
        {
            MemoryStream inStr = new MemoryStream(buf, false);

            /*
             * Check the type.
             */
            switch (type)
            {
            case HP_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);

                    break;
                }

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

                connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
                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[] 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(AL_fatal, AP_handshake_failure);
                    }

                    connection_state = CS_DONE;

                    /*
                     * We are now ready to receive application data.
                     */
                    this.appDataReady = 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
                     */
                    securityParameters.serverRandom = new byte[32];
                    TlsUtilities.ReadFully(securityParameters.serverRandom, inStr);

                    /*
                     * Currently, we don't support session ids
                     */
                    byte[] sessionID = TlsUtilities.ReadOpaque8(inStr);
                    if (sessionID.Length > 32)
                    {
                        this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_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 (!WasCipherSuiteOffered(selectedCipherSuite))
                    {
                        this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);
                    }

                    this.tlsClient.NotifySelectedCipherSuite(selectedCipherSuite);

                    /*
                     * 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);
                    }

                    /*
                     * RFC4366 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.
                     */
                    if (extendedClientHello)
                    {
                        // Integer -> byte[]
                        Hashtable serverExtensions = new Hashtable();

                        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);

                                serverExtensions.Add(extType, extValue);
                            }
                        }

                        // TODO[RFC 5746] If renegotiation_info was sent in client hello, check here

                        tlsClient.ProcessServerExtensions(serverExtensions);
                    }

                    AssertEmpty(inStr);

                    this.keyExchange = tlsClient.CreateKeyExchange();

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

                    AssertEmpty(inStr);

                    bool isClientCertificateRequested = (connection_state == CS_CERTIFICATE_REQUEST_RECEIVED);

                    connection_state = CS_SERVER_HELLO_DONE_RECEIVED;

                    if (isClientCertificateRequested)
                    {
                        SendClientCertificate(tlsClient.GetCertificate());
                    }

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

                    connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;

                    if (isClientCertificateRequested)
                    {
                        byte[] clientCertificateSignature = tlsClient.GenerateCertificateSignature(rs.GetCurrentHash());
                        if (clientCertificateSignature != null)
                        {
                            SendCertificateVerify(clientCertificateSignature);

                            connection_state = CS_CERTIFICATE_VERIFY_SEND;
                        }
                    }

                    /*
                     * Now, we send change cipher state
                     */
                    byte[] cmessage = new byte[1];
                    cmessage[0] = 1;
                    rs.WriteMessage(RL_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.CreateCipher(securityParameters));

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

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

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

                    this.connection_state = CS_CLIENT_FINISHED_SEND;
                    break;

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

            case HP_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.keyExchange.ProcessServerKeyExchange(inStr, securityParameters);

                    AssertEmpty(inStr);
                    break;
                }

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

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

                    byte[] types       = TlsUtilities.ReadOpaque8(inStr);
                    byte[] authorities = TlsUtilities.ReadOpaque16(inStr);

                    AssertEmpty(inStr);

                    ArrayList authorityDNs = new ArrayList();

                    MemoryStream bis = new MemoryStream(authorities, false);
                    while (bis.Position < bis.Length)
                    {
                        byte[] dnBytes = TlsUtilities.ReadOpaque16(bis);
                        authorityDNs.Add(X509Name.GetInstance(Asn1Object.FromByteArray(dnBytes)));
                    }

                    this.tlsClient.ProcessServerCertificateRequest(types, authorityDNs);

                    break;
                }

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

                this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED;
                break;

            case HP_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(AL_warning, AP_no_renegotiation);
                }
                break;

            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;
            }
        }