Beispiel #1
0
        internal virtual void CheckRecordHeader(byte[] recordHeader)
        {
            byte type = TlsUtilities.ReadUint8(recordHeader, TLS_HEADER_TYPE_OFFSET);

            /*
             * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an
             * unexpected_message alert.
             */
            CheckType(type, AlertDescription.unexpected_message);

            if (!mRestrictReadVersion)
            {
                int version = TlsUtilities.ReadVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET);
                if ((version & 0xffffff00) != 0x0300)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }
            }
            else
            {
                ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, TLS_HEADER_VERSION_OFFSET);
                if (mReadVersion == null)
                {
                    // Will be set later in 'readRecord'
                }
                else if (!version.Equals(mReadVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }
            }

            int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET);

            CheckLength(length, mCiphertextLimit, AlertDescription.record_overflow);
        }
Beispiel #2
0
        internal virtual bool ReadRecord()
        {
            byte[] buf = TlsUtilities.ReadAllOrNothing(5, this.mInput);
            if (buf == null)
            {
                return(false);
            }
            byte type = TlsUtilities.ReadUint8(buf, 0);

            CheckType(type, 10);
            if (!this.mRestrictReadVersion)
            {
                if ((TlsUtilities.ReadVersionRaw(buf, 1) & 0xffffff00L) != 0x300L)
                {
                    throw new TlsFatalAlert(0x2f);
                }
            }
            else
            {
                ProtocolVersion version = TlsUtilities.ReadVersion(buf, 1);
                if (this.mReadVersion == null)
                {
                    this.mReadVersion = version;
                }
                else if (!version.Equals(this.mReadVersion))
                {
                    throw new TlsFatalAlert(0x2f);
                }
            }
            int len = TlsUtilities.ReadUint16(buf, 3);

            byte[] buffer2 = this.DecodeAndVerify(type, this.mInput, len);
            this.mHandler.ProcessRecord(type, buffer2, 0, buffer2.Length);
            return(true);
        }
Beispiel #3
0
        protected virtual void ReportServerVersion(ClientHandshakeState state, ProtocolVersion server_version)
        {
            TlsClientContextImpl clientContext        = state.clientContext;
            ProtocolVersion      currentServerVersion = clientContext.ServerVersion;

            if (null == currentServerVersion)
            {
                clientContext.SetServerVersion(server_version);
                state.client.NotifyServerVersion(server_version);
            }
            else if (!currentServerVersion.Equals(server_version))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
        }
        protected virtual void ReportServerVersion(ClientHandshakeState state, ProtocolVersion server_version)
        {
            TlsClientContextImpl clientContext = state.clientContext;
            ProtocolVersion      serverVersion = clientContext.ServerVersion;

            if (serverVersion == null)
            {
                clientContext.SetServerVersion(server_version);
                state.client.NotifyServerVersion(server_version);
            }
            else if (!serverVersion.Equals(server_version))
            {
                throw new TlsFatalAlert(47);
            }
        }
Beispiel #5
0
        internal virtual bool ReadRecord()
        {
            byte[] recordHeader = TlsUtilities.ReadAllOrNothing(TLS_HEADER_SIZE, mInput);
            if (recordHeader == null)
            {
                return(false);
            }

            byte type = TlsUtilities.ReadUint8(recordHeader, TLS_HEADER_TYPE_OFFSET);

            /*
             * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an
             * unexpected_message alert.
             */
            CheckType(type, AlertDescription.unexpected_message);

            if (!mRestrictReadVersion)
            {
                int version = TlsUtilities.ReadVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET);
                if ((version & 0xffffff00) != 0x0300)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }
            }
            else
            {
                ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, TLS_HEADER_VERSION_OFFSET);
                if (mReadVersion == null)
                {
                    mReadVersion = version;
                }
                else if (!version.Equals(mReadVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }
            }

            int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET);

            CheckLength(length, mCiphertextLimit, AlertDescription.record_overflow);

            byte[] plaintext = DecodeAndVerify(type, mInput, length);
            mHandler.ProcessRecord(type, plaintext, 0, plaintext.Length);
            return(true);
        }
Beispiel #6
0
        internal virtual bool ReadRecord()
        {
            byte[] array = TlsUtilities.ReadAllOrNothing(5, this.mInput);
            if (array == null)
            {
                return(false);
            }
            byte b = TlsUtilities.ReadUint8(array, 0);

            RecordStream.CheckType(b, 10);
            if (!this.mRestrictReadVersion)
            {
                int num = TlsUtilities.ReadVersionRaw(array, 1);
                if (((long)num & (long)((ulong)-256)) != 768L)
                {
                    throw new TlsFatalAlert(47);
                }
            }
            else
            {
                ProtocolVersion protocolVersion = TlsUtilities.ReadVersion(array, 1);
                if (this.mReadVersion == null)
                {
                    this.mReadVersion = protocolVersion;
                }
                else if (!protocolVersion.Equals(this.mReadVersion))
                {
                    throw new TlsFatalAlert(47);
                }
            }
            int len = TlsUtilities.ReadUint16(array, 3);

            byte[] array2 = this.DecodeAndVerify(b, this.mInput, len);
            this.mHandler.ProcessRecord(b, array2, 0, array2.Length);
            return(true);
        }
Beispiel #7
0
        internal virtual bool ReadRecord()
        {
            byte[] array = TlsUtilities.ReadAllOrNothing(5, mInput);
            if (array == null)
            {
                return(false);
            }
            byte b = TlsUtilities.ReadUint8(array, 0);

            CheckType(b, 10);
            if (!mRestrictReadVersion)
            {
                int num = TlsUtilities.ReadVersionRaw(array, 1);
                if ((num & 4294967040u) != 768)
                {
                    throw new TlsFatalAlert(47);
                }
            }
            else
            {
                ProtocolVersion protocolVersion = TlsUtilities.ReadVersion(array, 1);
                if (mReadVersion == null)
                {
                    mReadVersion = protocolVersion;
                }
                else if (!protocolVersion.Equals(mReadVersion))
                {
                    throw new TlsFatalAlert(47);
                }
            }
            int len = TlsUtilities.ReadUint16(array, 3);

            byte[] array2 = DecodeAndVerify(b, mInput, len);
            mHandler.ProcessRecord(b, array2, 0, array2.Length);
            return(true);
        }
Beispiel #8
0
        protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
        {
            {
                ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
                if (server_version.IsDtls)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                // Check that this matches what the server is Sending in the record layer
                if (!server_version.Equals(this.mRecordStream.ReadVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                ProtocolVersion client_version = Context.ClientVersion;
                if (!server_version.IsEqualOrEarlierVersionOf(client_version))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                this.mRecordStream.SetWriteVersion(server_version);
                ContextAdmin.SetServerVersion(server_version);
                this.mTlsClient.NotifyServerVersion(server_version);
            }

            /*
             * Read the server random
             */
            this.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);

            this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
            if (this.mSelectedSessionID.Length > 32)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
            this.mResumedSession = this.mSelectedSessionID.Length > 0 && this.mTlsSession != null &&
                                   Arrays.AreEqual(this.mSelectedSessionID, this.mTlsSession.SessionID);

            /*
             * Find out which CipherSuite the server has chosen and check that it was one of the offered
             * ones, and is a valid selection for the negotiated version.
             */
            int selectedCipherSuite = TlsUtilities.ReadUint16(buf);

            if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite) ||
                selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite);

            /*
             * Find out which CompressionMethod the server has chosen and check that it was one of the
             * offered ones.
             */
            byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);

            if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            this.mTlsClient.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.
             */
            this.mServerExtensions = ReadExtensions(buf);

            /*
             * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
             * extended client hello message.
             *
             * However, see RFC 5746 exception below. We always include the SCSV, so an Extended Server
             * Hello is always allowed.
             */
            if (this.mServerExtensions != null)
            {
                foreach (int extType in this.mServerExtensions.Keys)
                {
                    /*
                     * RFC 5746 3.6. Note that Sending a "renegotiation_info" extension in response to a
                     * ClientHello containing only the SCSV is an explicit exception to the prohibition
                     * in RFC 5246, Section 7.4.1.4, on the server Sending unsolicited extensions and is
                     * only allowed because the client is signaling its willingness to receive the
                     * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
                     */
                    if (extType == ExtensionType.renegotiation_info)
                    {
                        continue;
                    }

                    /*
                     * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
                     * same extension type appeared in the corresponding ClientHello. If a client
                     * receives an extension type in ServerHello that it did not request in the
                     * associated ClientHello, it MUST abort the handshake with an unsupported_extension
                     * fatal alert.
                     */
                    if (null == TlsUtilities.GetExtensionData(this.mClientExtensions, extType))
                    {
                        throw new TlsFatalAlert(AlertDescription.unsupported_extension);
                    }

                    /*
                     * 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[.]
                     */
                    if (this.mResumedSession)
                    {
                        // TODO[compat-gnutls] GnuTLS test server Sends server extensions e.g. ec_point_formats
                        // TODO[compat-openssl] OpenSSL test server Sends server extensions e.g. ec_point_formats
                        // TODO[compat-polarssl] PolarSSL test server Sends server extensions e.g. ec_point_formats
                        //                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    }
                }
            }

            /*
             * RFC 5746 3.4. Client Behavior: Initial Handshake
             */
            {
                /*
                 * When a ServerHello is received, the client MUST check if it includes the
                 * "renegotiation_info" extension:
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
                if (renegExtData != null)
                {
                    /*
                     * 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).
                     */
                    this.mSecureRenegotiation = true;

                    if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                    {
                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
                    }
                }
            }

            // TODO[compat-gnutls] GnuTLS test server fails to Send renegotiation_info extension when resuming
            this.mTlsClient.NotifySecureRenegotiation(this.mSecureRenegotiation);

            IDictionary sessionClientExtensions = mClientExtensions, sessionServerExtensions = mServerExtensions;

            if (this.mResumedSession)
            {
                if (selectedCipherSuite != this.mSessionParameters.CipherSuite ||
                    selectedCompressionMethod != this.mSessionParameters.CompressionAlgorithm)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                sessionClientExtensions = null;
                sessionServerExtensions = this.mSessionParameters.ReadServerExtensions();
            }

            this.mSecurityParameters.cipherSuite          = selectedCipherSuite;
            this.mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;

            if (sessionServerExtensions != null)
            {
                {
                    /*
                     * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
                     * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
                     * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
                     * client.
                     */
                    bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
                    if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(selectedCipherSuite))
                    {
                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    }

                    this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
                }

                this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);

                this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
                                                                                               sessionServerExtensions, AlertDescription.illegal_parameter);

                this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);

                /*
                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
                 * a session resumption handshake.
                 */
                this.mAllowCertificateStatus = !this.mResumedSession &&
                                               TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
                                                                                          AlertDescription.illegal_parameter);

                this.mExpectSessionTicket = !this.mResumedSession &&
                                            TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
                                                                                       AlertDescription.illegal_parameter);
            }

            /*
             * TODO[session-hash]
             *
             * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
             * that do not use the extended master secret [..]. (and see 5.2, 5.3)
             */

            if (sessionClientExtensions != null)
            {
                this.mTlsClient.ProcessServerExtensions(sessionServerExtensions);
            }

            this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.CipherSuite);

            /*
             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify
             * verify_data_length has a verify_data_length equal to 12. This includes all
             * existing cipher suites.
             */
            this.mSecurityParameters.verifyDataLength = 12;
        }
Beispiel #9
0
        public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
        {
            byte[] record = null;

            for (;;)
            {
                int receiveLimit = System.Math.Min(len, GetReceiveLimit()) + RECORD_HEADER_LENGTH;
                if (record == null || record.Length < receiveLimit)
                {
                    record = new byte[receiveLimit];
                }

                try
                {
                    if (mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > mRetransmitExpiry)
                    {
                        mRetransmit      = null;
                        mRetransmitEpoch = null;
                    }

                    int received = ReceiveRecord(record, 0, receiveLimit, waitMillis);
                    if (received < 0)
                    {
                        return(received);
                    }
                    if (received < RECORD_HEADER_LENGTH)
                    {
                        continue;
                    }
                    int length = TlsUtilities.ReadUint16(record, 11);
                    if (received != (length + RECORD_HEADER_LENGTH))
                    {
                        continue;
                    }

                    byte type = TlsUtilities.ReadUint8(record, 0);

                    // TODO Support user-specified custom protocols?
                    switch (type)
                    {
                    case ContentType.alert:
                    case ContentType.application_data:
                    case ContentType.change_cipher_spec:
                    case ContentType.handshake:
                    case ContentType.heartbeat:
                        break;

                    default:
                        // TODO Exception?
                        continue;
                    }

                    int epoch = TlsUtilities.ReadUint16(record, 3);

                    DtlsEpoch recordEpoch = null;
                    if (epoch == mReadEpoch.Epoch)
                    {
                        recordEpoch = mReadEpoch;
                    }
                    else if (type == ContentType.handshake && mRetransmitEpoch != null &&
                             epoch == mRetransmitEpoch.Epoch)
                    {
                        recordEpoch = mRetransmitEpoch;
                    }

                    if (recordEpoch == null)
                    {
                        continue;
                    }

                    long seq = TlsUtilities.ReadUint48(record, 5);
                    if (recordEpoch.ReplayWindow.ShouldDiscard(seq))
                    {
                        continue;
                    }

                    ProtocolVersion version = TlsUtilities.ReadVersion(record, 1);
                    if (!version.IsDtls)
                    {
                        continue;
                    }

                    if (mReadVersion != null && !mReadVersion.Equals(version))
                    {
                        continue;
                    }

                    byte[] plaintext = recordEpoch.Cipher.DecodeCiphertext(
                        GetMacSequenceNumber(recordEpoch.Epoch, seq), type, record, RECORD_HEADER_LENGTH,
                        received - RECORD_HEADER_LENGTH);

                    recordEpoch.ReplayWindow.ReportAuthenticated(seq);

                    if (plaintext.Length > this.mPlaintextLimit)
                    {
                        continue;
                    }

                    if (mReadVersion == null)
                    {
                        mReadVersion = version;
                    }

                    switch (type)
                    {
                    case ContentType.alert:
                    {
                        if (plaintext.Length == 2)
                        {
                            byte alertLevel       = plaintext[0];
                            byte alertDescription = plaintext[1];

                            mPeer.NotifyAlertReceived(alertLevel, alertDescription);

                            if (alertLevel == AlertLevel.fatal)
                            {
                                Failed();
                                throw new TlsFatalAlert(alertDescription);
                            }

                            // TODO Can close_notify be a fatal alert?
                            if (alertDescription == AlertDescription.close_notify)
                            {
                                CloseTransport();
                            }
                        }

                        continue;
                    }

                    case ContentType.application_data:
                    {
                        if (mInHandshake)
                        {
                            // TODO Consider buffering application data for new epoch that arrives
                            // out-of-order with the Finished message
                            continue;
                        }
                        break;
                    }

                    case ContentType.change_cipher_spec:
                    {
                        // Implicitly receive change_cipher_spec and change to pending cipher state

                        for (int i = 0; i < plaintext.Length; ++i)
                        {
                            byte message = TlsUtilities.ReadUint8(plaintext, i);
                            if (message != ChangeCipherSpec.change_cipher_spec)
                            {
                                continue;
                            }

                            if (mPendingEpoch != null)
                            {
                                mReadEpoch = mPendingEpoch;
                            }
                        }

                        continue;
                    }

                    case ContentType.handshake:
                    {
                        if (!mInHandshake)
                        {
                            if (mRetransmit != null)
                            {
                                mRetransmit.ReceivedHandshakeRecord(epoch, plaintext, 0, plaintext.Length);
                            }

                            // TODO Consider support for HelloRequest
                            continue;
                        }
                        break;
                    }

                    case ContentType.heartbeat:
                    {
                        // TODO[RFC 6520]
                        continue;
                    }
                    }

                    /*
                     * NOTE: If we receive any non-handshake data in the new epoch implies the peer has
                     * received our final flight.
                     */
                    if (!mInHandshake && mRetransmit != null)
                    {
                        this.mRetransmit      = null;
                        this.mRetransmitEpoch = null;
                    }

                    Array.Copy(plaintext, 0, buf, off, plaintext.Length);
                    return(plaintext.Length);
                }
                catch (IOException e)
                {
                    // NOTE: Assume this is a timeout for the moment
                    throw e;
                }
            }
        }
Beispiel #10
0
        private int ProcessRecord(int received, byte[] record, byte[] buf, int off)
        {
            // NOTE: received < 0 (timeout) is covered by this first case
            if (received < RECORD_HEADER_LENGTH)
            {
                return(-1);
            }
            int length = TlsUtilities.ReadUint16(record, 11);

            if (received != (length + RECORD_HEADER_LENGTH))
            {
                return(-1);
            }

            byte type = TlsUtilities.ReadUint8(record, 0);

            switch (type)
            {
            case ContentType.alert:
            case ContentType.application_data:
            case ContentType.change_cipher_spec:
            case ContentType.handshake:
            case ContentType.heartbeat:
                break;

            default:
                return(-1);
            }

            int epoch = TlsUtilities.ReadUint16(record, 3);

            DtlsEpoch recordEpoch = null;

            if (epoch == mReadEpoch.Epoch)
            {
                recordEpoch = mReadEpoch;
            }
            else if (type == ContentType.handshake && mRetransmitEpoch != null &&
                     epoch == mRetransmitEpoch.Epoch)
            {
                recordEpoch = mRetransmitEpoch;
            }

            if (recordEpoch == null)
            {
                return(-1);
            }

            long seq = TlsUtilities.ReadUint48(record, 5);

            if (recordEpoch.ReplayWindow.ShouldDiscard(seq))
            {
                return(-1);
            }

            ProtocolVersion version = TlsUtilities.ReadVersion(record, 1);

            if (!version.IsDtls)
            {
                return(-1);
            }

            if (mReadVersion != null && !mReadVersion.Equals(version))
            {
                return(-1);
            }

            byte[] plaintext = recordEpoch.Cipher.DecodeCiphertext(
                GetMacSequenceNumber(recordEpoch.Epoch, seq), type, record, RECORD_HEADER_LENGTH,
                received - RECORD_HEADER_LENGTH);

            recordEpoch.ReplayWindow.ReportAuthenticated(seq);

            if (plaintext.Length > this.mPlaintextLimit)
            {
                return(-1);
            }

            if (mReadVersion == null)
            {
                mReadVersion = version;
            }

            switch (type)
            {
            case ContentType.alert:
            {
                if (plaintext.Length == 2)
                {
                    byte alertLevel       = plaintext[0];
                    byte alertDescription = plaintext[1];

                    mPeer.NotifyAlertReceived(alertLevel, alertDescription);

                    if (alertLevel == AlertLevel.fatal)
                    {
                        Failed();
                        throw new TlsFatalAlert(alertDescription);
                    }

                    // TODO Can close_notify be a fatal alert?
                    if (alertDescription == AlertDescription.close_notify)
                    {
                        CloseTransport();
                    }
                }

                return(-1);
            }

            case ContentType.application_data:
            {
                if (mInHandshake)
                {
                    // TODO Consider buffering application data for new epoch that arrives
                    // out-of-order with the Finished message
                    return(-1);
                }
                break;
            }

            case ContentType.change_cipher_spec:
            {
                // Implicitly receive change_cipher_spec and change to pending cipher state

                for (int i = 0; i < plaintext.Length; ++i)
                {
                    byte message = TlsUtilities.ReadUint8(plaintext, i);
                    if (message != ChangeCipherSpec.change_cipher_spec)
                    {
                        continue;
                    }

                    if (mPendingEpoch != null)
                    {
                        mReadEpoch = mPendingEpoch;
                    }
                }

                return(-1);
            }

            case ContentType.handshake:
            {
                if (!mInHandshake)
                {
                    if (mRetransmit != null)
                    {
                        mRetransmit.ReceivedHandshakeRecord(epoch, plaintext, 0, plaintext.Length);
                    }

                    // TODO Consider support for HelloRequest
                    return(-1);
                }
                break;
            }

            case ContentType.heartbeat:
            {
                // TODO[RFC 6520]
                return(-1);
            }
            }

            /*
             * NOTE: If we receive any non-handshake data in the new epoch implies the peer has
             * received our final flight.
             */
            if (!mInHandshake && mRetransmit != null)
            {
                this.mRetransmit        = null;
                this.mRetransmitEpoch   = null;
                this.mRetransmitTimeout = null;
            }

            Array.Copy(plaintext, 0, buf, off, plaintext.Length);
            return(plaintext.Length);
        }
        public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
        {
            //IL_02c8: Expected O, but got Unknown
            byte[] array = null;
            while (true)
            {
                int num = Math.Min(len, GetReceiveLimit()) + 13;
                if (array == null || array.Length < num)
                {
                    array = new byte[num];
                }
                try
                {
                    if (mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > mRetransmitExpiry)
                    {
                        mRetransmit      = null;
                        mRetransmitEpoch = null;
                    }
                    int num2 = ReceiveRecord(array, 0, num, waitMillis);
                    if (num2 < 0)
                    {
                        return(num2);
                    }
                    if (num2 < 13)
                    {
                        continue;
                    }
                    int num3 = TlsUtilities.ReadUint16(array, 11);
                    if (num2 != num3 + 13)
                    {
                        continue;
                    }
                    byte b = TlsUtilities.ReadUint8(array, 0);
                    switch (b)
                    {
                    case 20:
                    case 21:
                    case 22:
                    case 23:
                    case 24:
                    {
                        int       num4      = TlsUtilities.ReadUint16(array, 3);
                        DtlsEpoch dtlsEpoch = null;
                        if (num4 == mReadEpoch.Epoch)
                        {
                            dtlsEpoch = mReadEpoch;
                        }
                        else if (b == 22 && mRetransmitEpoch != null && num4 == mRetransmitEpoch.Epoch)
                        {
                            dtlsEpoch = mRetransmitEpoch;
                        }
                        if (dtlsEpoch == null)
                        {
                            break;
                        }
                        long num5 = TlsUtilities.ReadUint48(array, 5);
                        if (dtlsEpoch.ReplayWindow.ShouldDiscard(num5))
                        {
                            break;
                        }
                        ProtocolVersion protocolVersion = TlsUtilities.ReadVersion(array, 1);
                        if (!protocolVersion.IsDtls || (mReadVersion != null && !mReadVersion.Equals(protocolVersion)))
                        {
                            break;
                        }
                        byte[] array2 = dtlsEpoch.Cipher.DecodeCiphertext(GetMacSequenceNumber(dtlsEpoch.Epoch, num5), b, array, 13, num2 - 13);
                        dtlsEpoch.ReplayWindow.ReportAuthenticated(num5);
                        if (array2.Length > mPlaintextLimit)
                        {
                            break;
                        }
                        if (mReadVersion == null)
                        {
                            mReadVersion = protocolVersion;
                        }
                        switch (b)
                        {
                        case 21:
                            if (array2.Length == 2)
                            {
                                byte b2 = array2[0];
                                byte b3 = array2[1];
                                mPeer.NotifyAlertReceived(b2, b3);
                                if (b2 == 2)
                                {
                                    Fail(b3);
                                    throw new TlsFatalAlert(b3);
                                }
                                if (b3 == 0)
                                {
                                    CloseTransport();
                                }
                            }
                            goto end_IL_0022;

                        case 23:
                            if (!mInHandshake)
                            {
                                break;
                            }
                            goto end_IL_0022;

                        case 20:
                        {
                            for (int i = 0; i < array2.Length; i++)
                            {
                                byte b4 = TlsUtilities.ReadUint8(array2, i);
                                if (b4 == 1 && mPendingEpoch != null)
                                {
                                    mReadEpoch = mPendingEpoch;
                                }
                            }
                            goto end_IL_0022;
                        }

                        case 22:
                            if (mInHandshake)
                            {
                                break;
                            }
                            if (mRetransmit != null)
                            {
                                mRetransmit.ReceivedHandshakeRecord(num4, array2, 0, array2.Length);
                            }
                            goto end_IL_0022;

                        case 24:
                            goto end_IL_0022;
                        }
                        if (!mInHandshake && mRetransmit != null)
                        {
                            mRetransmit      = null;
                            mRetransmitEpoch = null;
                        }
                        global::System.Array.Copy((global::System.Array)array2, 0, (global::System.Array)buf, off, array2.Length);
                        return(array2.Length);
                    }
                    }
                    end_IL_0022 :;
                }
                catch (IOException val)
                {
                    IOException val2 = val;
                    throw val2;
                }
            }
        }
        protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
        {
            ProtocolVersion protocolVersion = TlsUtilities.ReadVersion((Stream)(object)buf);

            if (protocolVersion.IsDtls)
            {
                throw new TlsFatalAlert(47);
            }
            if (!protocolVersion.Equals(mRecordStream.ReadVersion))
            {
                throw new TlsFatalAlert(47);
            }
            ProtocolVersion clientVersion = Context.ClientVersion;

            if (!protocolVersion.IsEqualOrEarlierVersionOf(clientVersion))
            {
                throw new TlsFatalAlert(47);
            }
            mRecordStream.SetWriteVersion(protocolVersion);
            ContextAdmin.SetServerVersion(protocolVersion);
            mTlsClient.NotifyServerVersion(protocolVersion);
            mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, (Stream)(object)buf);
            mSelectedSessionID = TlsUtilities.ReadOpaque8((Stream)(object)buf);
            if (mSelectedSessionID.Length > 32)
            {
                throw new TlsFatalAlert(47);
            }
            mTlsClient.NotifySessionID(mSelectedSessionID);
            mResumedSession = mSelectedSessionID.Length > 0 && mTlsSession != null && Arrays.AreEqual(mSelectedSessionID, mTlsSession.SessionID);
            int num = TlsUtilities.ReadUint16((Stream)(object)buf);

            if (!Arrays.Contains(mOfferedCipherSuites, num) || num == 0 || CipherSuite.IsScsv(num) || !TlsUtilities.IsValidCipherSuiteForVersion(num, Context.ServerVersion))
            {
                throw new TlsFatalAlert(47);
            }
            mTlsClient.NotifySelectedCipherSuite(num);
            byte b = TlsUtilities.ReadUint8((Stream)(object)buf);

            if (!Arrays.Contains(mOfferedCompressionMethods, b))
            {
                throw new TlsFatalAlert(47);
            }
            mTlsClient.NotifySelectedCompressionMethod(b);
            mServerExtensions = TlsProtocol.ReadExtensions(buf);
            if (mServerExtensions != null)
            {
                {
                    global::System.Collections.IEnumerator enumerator = ((global::System.Collections.IEnumerable)mServerExtensions.get_Keys()).GetEnumerator();
                    try
                    {
                        while (enumerator.MoveNext())
                        {
                            int num2 = (int)enumerator.get_Current();
                            if (num2 != 65281)
                            {
                                if (TlsUtilities.GetExtensionData(mClientExtensions, num2) == null)
                                {
                                    throw new TlsFatalAlert(110);
                                }
                                _ = mResumedSession;
                            }
                        }
                    }
                    finally
                    {
                        global::System.IDisposable disposable = enumerator as global::System.IDisposable;
                        if (disposable != null)
                        {
                            disposable.Dispose();
                        }
                    }
                }
            }
            byte[] extensionData = TlsUtilities.GetExtensionData(mServerExtensions, 65281);
            if (extensionData != null)
            {
                mSecureRenegotiation = true;
                if (!Arrays.ConstantTimeAreEqual(extensionData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                {
                    throw new TlsFatalAlert(40);
                }
            }
            mTlsClient.NotifySecureRenegotiation(mSecureRenegotiation);
            IDictionary val  = mClientExtensions;
            IDictionary val2 = mServerExtensions;

            if (mResumedSession)
            {
                if (num != mSessionParameters.CipherSuite || b != mSessionParameters.CompressionAlgorithm)
                {
                    throw new TlsFatalAlert(47);
                }
                val  = null;
                val2 = mSessionParameters.ReadServerExtensions();
            }
            mSecurityParameters.cipherSuite          = num;
            mSecurityParameters.compressionAlgorithm = b;
            if (val2 != null)
            {
                bool flag = TlsExtensionsUtilities.HasEncryptThenMacExtension(val2);
                if (flag && !TlsUtilities.IsBlockCipherSuite(num))
                {
                    throw new TlsFatalAlert(47);
                }
                mSecurityParameters.encryptThenMac       = flag;
                mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(val2);
                mSecurityParameters.maxFragmentLength    = ProcessMaxFragmentLengthExtension(val, val2, 47);
                mSecurityParameters.truncatedHMac        = TlsExtensionsUtilities.HasTruncatedHMacExtension(val2);
                mAllowCertificateStatus = !mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(val2, 5, 47);
                mExpectSessionTicket    = !mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(val2, 35, 47);
            }
            if (val != null)
            {
                mTlsClient.ProcessServerExtensions(val2);
            }
            mSecurityParameters.prfAlgorithm     = TlsProtocol.GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
            mSecurityParameters.verifyDataLength = 12;
        }
        protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
        {
            ProtocolVersion protocolVersion = TlsUtilities.ReadVersion(buf);

            if (protocolVersion.IsDtls)
            {
                throw new TlsFatalAlert(47);
            }
            if (!protocolVersion.Equals(mRecordStream.ReadVersion))
            {
                throw new TlsFatalAlert(47);
            }
            ProtocolVersion clientVersion = Context.ClientVersion;

            if (!protocolVersion.IsEqualOrEarlierVersionOf(clientVersion))
            {
                throw new TlsFatalAlert(47);
            }
            mRecordStream.SetWriteVersion(protocolVersion);
            ContextAdmin.SetServerVersion(protocolVersion);
            mTlsClient.NotifyServerVersion(protocolVersion);
            mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
            mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
            if (mSelectedSessionID.Length > 32)
            {
                throw new TlsFatalAlert(47);
            }
            mTlsClient.NotifySessionID(mSelectedSessionID);
            mResumedSession = (mSelectedSessionID.Length > 0 && mTlsSession != null && Arrays.AreEqual(mSelectedSessionID, mTlsSession.SessionID));
            int num = TlsUtilities.ReadUint16(buf);

            if (!Arrays.Contains(mOfferedCipherSuites, num) || num == 0 || CipherSuite.IsScsv(num) || !TlsUtilities.IsValidCipherSuiteForVersion(num, Context.ServerVersion))
            {
                throw new TlsFatalAlert(47);
            }
            mTlsClient.NotifySelectedCipherSuite(num);
            byte b = TlsUtilities.ReadUint8(buf);

            if (!Arrays.Contains(mOfferedCompressionMethods, b))
            {
                throw new TlsFatalAlert(47);
            }
            mTlsClient.NotifySelectedCompressionMethod(b);
            mServerExtensions = TlsProtocol.ReadExtensions(buf);
            if (mServerExtensions != null)
            {
                foreach (int key in mServerExtensions.Keys)
                {
                    if (key != 65281)
                    {
                        if (TlsUtilities.GetExtensionData(mClientExtensions, key) == null)
                        {
                            throw new TlsFatalAlert(110);
                        }
                        if (!mResumedSession)
                        {
                        }
                    }
                }
            }
            byte[] extensionData = TlsUtilities.GetExtensionData(mServerExtensions, 65281);
            if (extensionData != null)
            {
                mSecureRenegotiation = true;
                if (!Arrays.ConstantTimeAreEqual(extensionData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                {
                    throw new TlsFatalAlert(40);
                }
            }
            mTlsClient.NotifySecureRenegotiation(mSecureRenegotiation);
            IDictionary dictionary  = mClientExtensions;
            IDictionary dictionary2 = mServerExtensions;

            if (mResumedSession)
            {
                if (num != mSessionParameters.CipherSuite || b != mSessionParameters.CompressionAlgorithm)
                {
                    throw new TlsFatalAlert(47);
                }
                dictionary  = null;
                dictionary2 = mSessionParameters.ReadServerExtensions();
            }
            mSecurityParameters.cipherSuite          = num;
            mSecurityParameters.compressionAlgorithm = b;
            if (dictionary2 != null)
            {
                bool flag = TlsExtensionsUtilities.HasEncryptThenMacExtension(dictionary2);
                if (flag && !TlsUtilities.IsBlockCipherSuite(num))
                {
                    throw new TlsFatalAlert(47);
                }
                mSecurityParameters.encryptThenMac       = flag;
                mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(dictionary2);
                mSecurityParameters.maxFragmentLength    = ProcessMaxFragmentLengthExtension(dictionary, dictionary2, 47);
                mSecurityParameters.truncatedHMac        = TlsExtensionsUtilities.HasTruncatedHMacExtension(dictionary2);
                mAllowCertificateStatus = (!mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(dictionary2, 5, 47));
                mExpectSessionTicket    = (!mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(dictionary2, 35, 47));
            }
            if (dictionary != null)
            {
                mTlsClient.ProcessServerExtensions(dictionary2);
            }
            mSecurityParameters.prfAlgorithm     = TlsProtocol.GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
            mSecurityParameters.verifyDataLength = 12;
        }
        protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
        {
            ProtocolVersion writeVersion = TlsUtilities.ReadVersion(buf);

            if (writeVersion.IsDtls)
            {
                throw new TlsFatalAlert(0x2f);
            }
            if (!writeVersion.Equals(base.mRecordStream.ReadVersion))
            {
                throw new TlsFatalAlert(0x2f);
            }
            ProtocolVersion clientVersion = this.Context.ClientVersion;

            if (!writeVersion.IsEqualOrEarlierVersionOf(clientVersion))
            {
                throw new TlsFatalAlert(0x2f);
            }
            base.mRecordStream.SetWriteVersion(writeVersion);
            this.ContextAdmin.SetServerVersion(writeVersion);
            this.mTlsClient.NotifyServerVersion(writeVersion);
            base.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(0x20, buf);
            this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
            if (this.mSelectedSessionID.Length > 0x20)
            {
                throw new TlsFatalAlert(0x2f);
            }
            this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
            base.mResumedSession = ((this.mSelectedSessionID.Length > 0) && (base.mTlsSession != null)) && Arrays.AreEqual(this.mSelectedSessionID, base.mTlsSession.SessionID);
            int n = TlsUtilities.ReadUint16(buf);

            if ((!Arrays.Contains(base.mOfferedCipherSuites, n) || (n == 0)) || (CipherSuite.IsScsv(n) || !TlsUtilities.IsValidCipherSuiteForVersion(n, this.Context.ServerVersion)))
            {
                throw new TlsFatalAlert(0x2f);
            }
            this.mTlsClient.NotifySelectedCipherSuite(n);
            byte num2 = TlsUtilities.ReadUint8(buf);

            if (!Arrays.Contains(base.mOfferedCompressionMethods, num2))
            {
                throw new TlsFatalAlert(0x2f);
            }
            this.mTlsClient.NotifySelectedCompressionMethod(num2);
            base.mServerExtensions = TlsProtocol.ReadExtensions(buf);
            if (base.mServerExtensions != null)
            {
                IEnumerator enumerator = base.mServerExtensions.Keys.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        int current = (int)enumerator.Current;
                        if (current != 0xff01)
                        {
                            if (TlsUtilities.GetExtensionData(base.mClientExtensions, current) == null)
                            {
                                throw new TlsFatalAlert(110);
                            }
                            if (base.mResumedSession)
                            {
                            }
                        }
                    }
                }
                finally
                {
                    if (enumerator is IDisposable disposable)
                    {
                        IDisposable disposable;
                        disposable.Dispose();
                    }
                }
            }
            byte[] extensionData = TlsUtilities.GetExtensionData(base.mServerExtensions, 0xff01);
            if (extensionData != null)
            {
                base.mSecureRenegotiation = true;
                if (!Arrays.ConstantTimeAreEqual(extensionData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                {
                    throw new TlsFatalAlert(40);
                }
            }
            this.mTlsClient.NotifySecureRenegotiation(base.mSecureRenegotiation);
            IDictionary mClientExtensions = base.mClientExtensions;
            IDictionary mServerExtensions = base.mServerExtensions;

            if (base.mResumedSession)
            {
                if ((n != base.mSessionParameters.CipherSuite) || (num2 != base.mSessionParameters.CompressionAlgorithm))
                {
                    throw new TlsFatalAlert(0x2f);
                }
                mClientExtensions = null;
                mServerExtensions = base.mSessionParameters.ReadServerExtensions();
            }
            base.mSecurityParameters.cipherSuite          = n;
            base.mSecurityParameters.compressionAlgorithm = num2;
            if (mServerExtensions != null)
            {
                bool flag = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);
                if (flag && !TlsUtilities.IsBlockCipherSuite(n))
                {
                    throw new TlsFatalAlert(0x2f);
                }
                base.mSecurityParameters.encryptThenMac       = flag;
                base.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mServerExtensions);
                base.mSecurityParameters.maxFragmentLength    = this.ProcessMaxFragmentLengthExtension(mClientExtensions, mServerExtensions, 0x2f);
                base.mSecurityParameters.truncatedHMac        = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions);
                base.mAllowCertificateStatus = !base.mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, 5, 0x2f);
                base.mExpectSessionTicket    = !base.mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, 0x23, 0x2f);
            }
            if (mClientExtensions != null)
            {
                this.mTlsClient.ProcessServerExtensions(mServerExtensions);
            }
            base.mSecurityParameters.prfAlgorithm     = TlsProtocol.GetPrfAlgorithm(this.Context, base.mSecurityParameters.CipherSuite);
            base.mSecurityParameters.verifyDataLength = 12;
        }