The Security Exchange PDU is a Standard RDP Connection Sequence PDU sent from client to server during the RDP Security Commencement phase (see section ). It MAY be sent after receiving all requested MCS Channel Join Confirm PDUs.
file:///C:/ts_dev/TestSuites/MS-RDPBCGR/TestSuite/Src/TD/latest_XMLS_16may/RDPBCGR/_rfc_ms-rdpbcgr2_1_1_10.xml
Inheritance: RdpbcgrClientPdu
        /// <summary>
        /// Clear all the members except the reconnection relative members.
        /// </summary>
        internal void ClearForReconnect()
        {
            lock (contextLock)
            {
                x224ConnectionRequestPdu = null;
                x224ConnectionConfirmPdu = null;
                x224NegotiateFailurePdu = null;
                mcsConnectInitialPdu = null;
                mcsConnectResponsePdu = null;
                userChannelId = 0;
                ioChannelId = 0;
                serverChannelId = 0;
                clientInfo = null;
                securityExchangePdu = null;
                licenseErrorPdu = null;
                demandActivePdu = null;
                comfirmActivePdu = null;
                logonInfoV1 = new TS_LOGON_INFO();
                logonInfoV2 = new TS_LOGON_INFO_VERSION_2();
                logonErrorsInfo = null;
                encryptionCount = 0;
                decryptionCount = 0;

                if (encryptionAlgorithm != null)
                {
                    encryptionAlgorithm.Dispose();
                    encryptionAlgorithm = null;
                }

                if (ioDecompressor != null)
                {
                    ioDecompressor.Dispose();
                    ioDecompressor = null;
                }

                if (ioCompressor != null)
                {
                    ioCompressor.Dispose();
                    ioCompressor = null;
                }
            }
        }
        /// <summary>
        /// Update some members of context with the specified pdu.
        /// </summary>
        /// <param name="pdu">The sending or receiving pdu.</param>
        public void UpdateContext(StackPacket pdu)
        {
            lock (contextLock)
            {
                if (!isSwitchOn)
                {
                    // Don't update context but wait for upper layer TSD to do so.
                    return;
                }

                if (pdu.GetType() == typeof(Client_X_224_Connection_Request_Pdu))
                {
                    x224ConnectionRequestPdu = (Client_X_224_Connection_Request_Pdu)pdu.Clone();
                }
                else if (pdu.GetType() == typeof(Server_X_224_Connection_Confirm_Pdu))
                {
                    x224ConnectionConfirmPdu = ((Server_X_224_Connection_Confirm_Pdu)pdu.Clone()).rdpNegData;
                }
                else if (pdu.GetType() == typeof(Server_X_224_Negotiate_Failure_Pdu))
                {
                    x224NegotiateFailurePdu = ((Server_X_224_Negotiate_Failure_Pdu)pdu.Clone()).rdpNegFailure;
                }
                else if (pdu.GetType() == typeof(Client_MCS_Connect_Initial_Pdu_with_GCC_Conference_Create_Request))
                {
                    mcsConnectInitialPdu = ((Client_MCS_Connect_Initial_Pdu_with_GCC_Conference_Create_Request)
                        pdu.Clone()).mcsCi;
                }
                else if (pdu is Server_MCS_Connect_Response_Pdu_with_GCC_Conference_Create_Response)
                {
                    mcsConnectResponsePdu = (Server_MCS_Connect_Response_Pdu_with_GCC_Conference_Create_Response)
                        pdu.Clone();
                    serverRandom = RdpbcgrUtility.CloneByteArray(mcsConnectResponsePdu.mcsCrsp.gccPdu.serverSecurityData.serverRandom);
                    ioChannelId = mcsConnectResponsePdu.mcsCrsp.gccPdu.serverNetworkData.MCSChannelId;
                    if(mcsConnectResponsePdu.mcsCrsp.gccPdu.serverMessageChannelData != null)
                        mcsMsgChannelId = mcsConnectResponsePdu.mcsCrsp.gccPdu.serverMessageChannelData.MCSChannelID;
                    encryptionAlgorithm = new EncryptionAlgorithm(RdpEncryptionMethod);
                }
                else if (pdu.GetType() == typeof(Server_MCS_Attach_User_Confirm_Pdu))
                {
                    if (((Server_MCS_Attach_User_Confirm_Pdu)pdu).attachUserConfirm.initiator != null)
                    {
                        userChannelId = (ushort)((Server_MCS_Attach_User_Confirm_Pdu)pdu).attachUserConfirm.initiator.Value;
                    }
                }
                else if (pdu.GetType() == typeof(Client_Security_Exchange_Pdu))
                {
                    securityExchangePdu = (Client_Security_Exchange_Pdu)pdu.Clone();
                    clientRandom = RdpbcgrUtility.CloneByteArray(
                        ((Client_Security_Exchange_Pdu)pdu).securityExchangePduData.clientRandom);
                    GenerateSessionKey();
                }
                else if (pdu.GetType() == typeof(Client_Info_Pdu))
                {
                    clientInfo = ((Client_Info_Pdu)pdu.Clone()).infoPacket;
                    if (clientInfo != null
                        && (clientInfo.flags & flags_Values.INFO_COMPRESSION) == flags_Values.INFO_COMPRESSION)
                    {
                        ioDecompressor = new Decompressor(SlidingWindowSize.EightKB);
                        ioCompressor = new Compressor(SlidingWindowSize.EightKB);
                    }
                    isWaitingLicenseErrorPdu = true;
                }
                else if (pdu.GetType() == typeof(Server_Auto_Detect_Request_PDU))
                {

                    NETWORK_DETECTION_REQUEST requestData = ((Server_Auto_Detect_Request_PDU)pdu).autoDetectReqData.Clone();
                    if (requestData.requestType == AUTO_DETECT_REQUEST_TYPE.RDP_RTT_REQUEST_IN_CONNECTTIME || requestData.requestType == AUTO_DETECT_REQUEST_TYPE.RDP_RTT_REQUEST_AFTER_CONNECTTIME)
                    {
                        RDP_RTT_REQUEST rttRequest = (RDP_RTT_REQUEST)requestData;
                        rttRequest.sendTime = DateTime.Now;
                        this.serverAutoDetectRequestData.Add(rttRequest.sequenceNumber, rttRequest);
                    }
                }
                else if (pdu.GetType() == typeof(Client_Auto_Detect_Response_PDU))
                {
                    clientAutoDetectResponsePdu = (Client_Auto_Detect_Response_PDU)pdu.Clone();
                    NETWORK_DETECTION_RESPONSE responseData = clientAutoDetectResponsePdu.autodetectRspPduData;
                    if (responseData.responseType == AUTO_DETECT_RESPONSE_TYPE.RDP_RTT_RESPONSE)
                    {
                        RDP_RTT_REQUEST rttRequest = (RDP_RTT_REQUEST)serverAutoDetectRequestData[responseData.sequenceNumber];
                        if (rttRequest != null)
                        {
                            TimeSpan interval = DateTime.Now -  rttRequest.sendTime;
                            this.autoDetectedRTTList.Add((uint)interval.TotalMilliseconds);
                            serverAutoDetectRequestData.Remove(responseData.sequenceNumber);
                        }
                    }
                    else if (responseData.responseType == AUTO_DETECT_RESPONSE_TYPE.RDP_BW_RESULTS_AFTER_CONNECT || responseData.responseType == AUTO_DETECT_RESPONSE_TYPE.RDP_BW_RESULTS_DURING_CONNECT)
                    {
                        RDP_BW_RESULTS bwResult = (RDP_BW_RESULTS)responseData;
                        if(bwResult.timeDelta != 0)
                            this.autoDetectedBandwidth = (uint)(bwResult.byteCount / bwResult.timeDelta);
                    }
                    else if (responseData.responseType == AUTO_DETECT_RESPONSE_TYPE.RDP_NETCHAR_SYNC)
                    {
                        RDP_NETCHAR_SYNC netSync = (RDP_NETCHAR_SYNC)responseData;
                        this.autoDetectedRTTList.Add(netSync.rtt);
                        this.autoDetectedBandwidth = netSync.bandwidth;
                    }
                }
                else if (pdu.GetType() == typeof(Server_License_Error_Pdu_Valid_Client))
                {
                    licenseErrorPdu = (Server_License_Error_Pdu_Valid_Client)pdu.Clone();
                    serverChannelId = licenseErrorPdu.commonHeader.initiator;
                }
                else if (pdu.GetType() == typeof(Server_Initiate_Multitransport_Request_PDU))
                {
                    Server_Initiate_Multitransport_Request_PDU requestPDU = (Server_Initiate_Multitransport_Request_PDU)pdu;
                    serverInitiateMultitransportRequestPduDictionary.Add(requestPDU.requestId, requestPDU);
                }
                else if (pdu.GetType() == typeof(Client_Initiate_Multitransport_Response_PDU))
                {
                    clientInitiateMultitransportResponsePdu = (Client_Initiate_Multitransport_Response_PDU)pdu;
                }
                else if (pdu.GetType() == typeof(Server_Demand_Active_Pdu))
                {
                    serverChannelId = ((Server_Demand_Active_Pdu)pdu.Clone()).commonHeader.initiator;
                    demandActivePdu = ((Server_Demand_Active_Pdu)pdu.Clone()).demandActivePduData;

                }
                else if (pdu.GetType() == typeof(Client_Confirm_Active_Pdu))
                {
                    comfirmActivePdu = ((Client_Confirm_Active_Pdu)pdu.Clone()).confirmActivePduData;
                    if (channelManager == null)
                    {
                        channelManager = new ServerStaticVirtualChannelManager(this);
                    }
                }
                else if (pdu.GetType() == typeof(MCS_Disconnect_Provider_Ultimatum_Server_Pdu))
                {
                    lastDisconnectReason = (int)((MCS_Disconnect_Provider_Ultimatum_Server_Pdu)
                        pdu).disconnectProvider.reason.Value;
                }
                else if (pdu.GetType() == typeof(MCS_Disconnect_Provider_Ultimatum_Pdu))
                {
                    lastDisconnectReason = (int)((MCS_Disconnect_Provider_Ultimatum_Pdu)
                        pdu).disconnectProvider.reason.Value;
                }
                else if (pdu.GetType() == typeof(Server_Set_Error_Info_Pdu))
                {
                    lastErrorInfo = ((Server_Set_Error_Info_Pdu)pdu).errorInfoPduData.errorInfo;
                }
                else if (pdu.GetType() == typeof(Server_Status_Info_Pdu))
                {
                    lastStatusInfo = ((Server_Status_Info_Pdu)pdu).statusCode;
                }
                else if (pdu.GetType() == typeof(Server_Save_Session_Info_Pdu))
                {
                    Server_Save_Session_Info_Pdu saveSessionInfoPdu = (Server_Save_Session_Info_Pdu)pdu.Clone();

                    switch (saveSessionInfoPdu.saveSessionInfoPduData.infoType)
                    {
                        case infoType_Values.INFOTYPE_LOGON:
                            logonInfoV1 = (TS_LOGON_INFO)saveSessionInfoPdu.saveSessionInfoPduData.infoData;
                            break;

                        case infoType_Values.INFOTYPE_LOGON_LONG:
                            logonInfoV2 = (TS_LOGON_INFO_VERSION_2)saveSessionInfoPdu.saveSessionInfoPduData.infoData;
                            break;

                        case infoType_Values.INFOTYPE_LOGON_EXTENDED_INF:
                            TS_LOGON_INFO_EXTENDED infoExtended =
                                (TS_LOGON_INFO_EXTENDED)saveSessionInfoPdu.saveSessionInfoPduData.infoData;
                            switch (infoExtended.FieldsPresent)
                            {
                                case FieldsPresent_Values.LOGON_EX_AUTORECONNECTCOOKIE
                                   | FieldsPresent_Values.LOGON_EX_LOGONERRORS:
                                    autoReconnectCookie = (ARC_SC_PRIVATE_PACKET)infoExtended.LogonFields[0].FieldData;
                                    logonErrorsInfo = (TS_LOGON_ERRORS_INFO)infoExtended.LogonFields[1].FieldData;
                                    break;

                                case FieldsPresent_Values.LOGON_EX_AUTORECONNECTCOOKIE:
                                    autoReconnectCookie = (ARC_SC_PRIVATE_PACKET)infoExtended.LogonFields[0].FieldData;
                                    break;

                                case FieldsPresent_Values.LOGON_EX_LOGONERRORS:
                                    logonErrorsInfo = (TS_LOGON_ERRORS_INFO)infoExtended.LogonFields[0].FieldData;
                                    break;

                                default:
                                    break;
                            }
                            break;

                        default:
                            break;
                    }
                }
            }
        }
 /// <summary>
 /// 2.2.1.10
 /// </summary>
 /// <param name="securityPdu"></param>
 public void VerifyPdu(Client_Security_Exchange_Pdu securityPdu)
 {
     //<?>
     CaptureRequirement(securityPdu.securityExchangePduData.length != 0, 407);
 }
        /// <summary>
        /// Decode Security Exchange PDU
        /// </summary>
        /// <param name="serverSessionContext">the server session context</param>
        /// <param name="data">data to be parsed</param>
        /// <param name="decryptedUserData">decrypted user data</param>
        /// <param name="type">the security header type</param>
        /// <returns>Decoded Security Exchange PDU</returns>
        public StackPacket DecodeSecurityExchangePdu(
            RdpbcgrServerSessionContext serverSessionContext,
            byte[] data,
            byte[] decryptedUserData,
            SecurityHeaderType type)
        {
            int currentIndex = 0;
            Client_Security_Exchange_Pdu pdu = new Client_Security_Exchange_Pdu();
            pdu.commonHeader = ParseMcsCommonHeader(data, ref currentIndex, type);

            int userDataIndex = 0;
            pdu.securityExchangePduData = ParseSecurityExchange(
                serverSessionContext,
                decryptedUserData,
                ref userDataIndex);

            // ETW Provider Dump Message
            if (pdu.commonHeader.securityHeader != null)
            {
                // RDP Standard Security
                string messageName = "RDPBCGR:" + pdu.GetType().Name;
                ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer3, pdu.GetType().Name, decryptedUserData);
            }

            // Check if data length exceeded expectation
            VerifyDataLength(decryptedUserData.Length, userDataIndex, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return pdu;
        }
        /// <summary>
        /// Create an instance of the class that is identical to the current PDU. 
        /// </summary>
        /// <returns>The new instance.</returns>
        public override StackPacket Clone()
        {
            Client_Security_Exchange_Pdu cloneSecurityPdu = new Client_Security_Exchange_Pdu(context);

            cloneSecurityPdu.commonHeader = commonHeader.Clone();
            cloneSecurityPdu.securityExchangePduData = securityExchangePduData;
            cloneSecurityPdu.securityExchangePduData.clientRandom =
                RdpbcgrUtility.CloneByteArray(securityExchangePduData.clientRandom);

            return cloneSecurityPdu;
        }
        /// <summary>
        /// 2.2.1.10
        /// </summary>
        /// <param name="securityPdu"></param>
        public void VerifyPdu(Client_Security_Exchange_Pdu securityPdu)
        {
            //<?>
            CaptureRequirement(securityPdu.securityExchangePduData.length != 0, 407);
            //Refer to test suite bug #8341151
            //site.CaptureRequirementIfIsTrue((securityPdu.commonHeader.securityHeader.flags & TS_SECURITY_HEADER_flags_Values.SEC_EXCHANGE_PKT) == TS_SECURITY_HEADER_flags_Values.SEC_EXCHANGE_PKT, 411,
            //  "In Security Exchange PDU Data (TS_SECURITY_PACKET) the flags field of the security header MUST contain the SEC_EXCHANGE_PKT flag (0x0001).");

            //following capture is wrong, as after decoding the length would changed
            //site.CaptureRequirementIfAreEqual<uint>((uint)securityPdu.securityExchangePduData.clientRandom.Length, securityPdu.securityExchangePduData.length, 413,
            //"In Security Exchange PDU Data (TS_SECURITY_PACKET) the length field indicates the size in bytes of the buffer containing the encrypted client random value, not including the header length.");
        }