Maintain the important parameters of the session during RDPBCGR transport, including the main sent or received PDUs, Channel Manager, the selected Encryption Algorithm etc.
상속: IDisposable
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="context"></param>
        public Rdpbcgr_DVCServerTransport(RdpbcgrServerSessionContext context)
        {
            this.sessionContext = context;

            if (sessionContext.SVCManager == null)
            {
                throw new NotSupportedException("Cannot get SVC from RDPBCGR connection for RDPEDYC, this transport must be created after RDPBCGR connection established.");
            }

            channel = sessionContext.SVCManager.GetChannelByName(StaticVirtualChannelName.RDPEDYC);
            if (channel == null)
            {
                throw new NotSupportedException("Cannot get SVC from RDPBCGR connection for RDPEDYC, the static virtual channel is not created.");
            }

            channel.Received += ReceivedBytes;

            if (!sessionContext.SVCManager.IsRunning)
            {
                // Better start the SVC manager here, so as to make sure the first packet of RDPEDYC can be processed
                // it is not same restrict as client, since the first packet is sent by server
                sessionContext.SVCManager.Start();
            }

            decoder = new ServerDecodingPduBuilder();
            pduBuilder = new PduBuilder();
        }
 /// <summary>
 /// Wait for connection.
 /// </summary>
 public void Accept()
 {
     this.rdpbcgrAdapter = Site.GetAdapter<IRdpbcgrAdapter>();
     this.rdpbcgrServerStack = this.rdpbcgrAdapter.ServerStack;
     this.rdpbcgrSessionContext = this.rdpbcgrAdapter.SessionContext;
     this.rdpbcgrAdapter.TS_FRAME_ACKNOWLEDGE_PDUReceived += new TS_FRAME_ACKNOWLEDGE_PDUHandler(this.VerifyTS_FRAME_ACKNOWLEDGE_PDU);
 }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="server"></param>
        /// <param name="context"></param>
        public RdpedycServer(RdpbcgrServer server, RdpbcgrServerSessionContext context, bool autoCloseChannel = true)
        {
            this.rdpbcgrServer = server;
            this.sessionContext = context;
            transportDic = new Dictionary<DynamicVC_TransportType, IDVCTransport>();
            unprocessedDVCPacketBuffer = new List<UnprocessedDVCPDUInfo>();
            Rdpbcgr_DVCServerTransport transport = new Rdpbcgr_DVCServerTransport(context);

            channelDicbyId = new Dictionary<uint, DynamicVirtualChannel>();

            pduBuilder = new PduBuilder();

            transport.Received += ProcessPacketFromTCP;
            transportDic.Add(DynamicVC_TransportType.RDP_TCP, transport);

            this.autoCloseChannel = autoCloseChannel;
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="connectedRdpServer"></param>
        /// <param name="context"></param>
        /// <param name="transportType"></param>
        public Rdpemt_DVCServerTransport(RdpbcgrServer connectedRdpServer, RdpbcgrServerSessionContext context, DynamicVC_TransportType transportType)
        {
            this.serverSessionContext = context;
            this.rdpbcgrServer = connectedRdpServer;
            this.transportProtocol = Multitransport_Protocol_value.INITITATE_REQUEST_PROTOCOL_UDPFECR;
            if (transportType == DynamicVC_TransportType.RDP_UDP_Lossy)
            {
                this.transportProtocol = Multitransport_Protocol_value.INITITATE_REQUEST_PROTOCOL_UDPFECL;
            }

            if (!serverSessionContext.IsClientMultitransportChannelDataRecieved)
            {
                throw new NotSupportedException("This RDP connection doesn't support multiple transport!");
            }

            EstablishTransportConnection();

            decoder = new ServerDecodingPduBuilder();
            pduBuilder = new PduBuilder();
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="context"></param>
        public ServerStaticVirtualChannelManager(RdpbcgrServerSessionContext context)
        {
            this.context = context;
            this.channelDicById = new Dictionary<ushort, StaticVirtualChannel>();
            this.channelDicByName = new Dictionary<string, StaticVirtualChannel>();
            ushort[] virtualChannelIds = context.VirtualChannelIdStore;
            CHANNEL_DEF[] virtualChannelDefines = context.VirtualChannelDefines;
            if (virtualChannelIds != null && virtualChannelDefines != null
                && virtualChannelIds.Length == virtualChannelDefines.Length)
            {
                CompressionType compressType = context.VirtualChannelSCCompressionType;
                if (context.CompressionTypeSupported == CompressionType.PACKET_COMPR_TYPE_NONE)
                {
                    compressType = CompressionType.PACKET_COMPR_TYPE_NONE;
                }
                else if (context.CompressionTypeSupported == CompressionType.PACKET_COMPR_TYPE_RDP6 ||
                      context.CompressionTypeSupported == CompressionType.PACKET_COMPR_TYPE_RDP62)
                {
                    compressType = CompressionType.PACKET_COMPR_TYPE_64K;
                }

                for (int i = 0; i < virtualChannelIds.Length; ++i)
                {
                    string name = virtualChannelDefines[i].name;
                    if (name != null)
                    {
                        name = name.Replace("\0", string.Empty).ToUpper();
                    }
                    StaticVirtualChannel channel = new ServerStaticVirtualChannel(virtualChannelIds[i],
                                                                name,
                                                                virtualChannelDefines[i].options,
                                                                context.VCChunkSize,
                                                                compressType,
                                                                context.VirtualChannelCSCompressionType,
                                                                SendPacket);
                    channelDicById.Add(virtualChannelIds[i], channel);
                    channelDicByName.Add(name, channel);
                }
            }
        }
        /// <summary>
        /// Parse TS_SECURITY_PACKET
        /// (parser index is updated according to parsed length)
        /// </summary>
        /// <param name="serverSessionContext">the server session context</param>
        /// <param name="data">data to be parsed</param>
        /// <param name="currentIndex">current parser index</param>
        /// <returns>TS_SECURITY_PACKET</returns>
        private TS_SECURITY_PACKET ParseSecurityExchange(
            RdpbcgrServerSessionContext serverSessionContext,
            byte[] data,
            ref int currentIndex)
        {
            TS_SECURITY_PACKET secExchangeData = new TS_SECURITY_PACKET();
            secExchangeData.length = ParseUInt32(data, ref currentIndex, false);

            byte[] encryptedRandom = GetBytes(data, ref currentIndex, (int)secExchangeData.length);

            byte[] decryptedRandom = RdpbcgrUtility.DecryptClientRandom(
                encryptedRandom,
                serverSessionContext.ServerPrivateExponent,
                serverSessionContext.ServerModulus);

            if (decryptedRandom.Length != ConstValue.CLIENT_RANDOM_NUMBER_SIZE)
            {
                Array.Resize<byte>(ref decryptedRandom, ConstValue.CLIENT_RANDOM_NUMBER_SIZE);
            }

            int startIndex = 0;
            //secExchangeData.clientRandom =
            //    GetBytes(decryptedRandom, ref startIndex, (int)secExchangeData.length - 40);
            secExchangeData.clientRandom =
                GetBytes(decryptedRandom, ref startIndex, decryptedRandom.Length);

            return secExchangeData;
        }
        /// <summary>
        /// Get Security Header Type by Server Context
        /// </summary>
        /// <returns>Security Header Type</returns>
        private SecurityHeaderType GetSecurityHeaderTypeByContext(RdpbcgrServerSessionContext serverSessionContext)
        {
            SecurityHeaderType securityHeaderType;
            switch (serverSessionContext.RdpEncryptionLevel)
            {
                case EncryptionLevel.ENCRYPTION_LEVEL_NONE:
                    securityHeaderType = SecurityHeaderType.None;
                    break;

                case EncryptionLevel.ENCRYPTION_LEVEL_LOW:
                    //securityHeaderType = SecurityHeaderType.Basic;
                    //break;

                case EncryptionLevel.ENCRYPTION_LEVEL_CLIENT_COMPATIBLE:
                case EncryptionLevel.ENCRYPTION_LEVEL_HIGH:
                case EncryptionLevel.ENCRYPTION_LEVEL_FIPS:
                default: //To enable invalid encryption level test.
                    // The following logic is implemented according to actual situation observed,
                    if (serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_40BIT
                        || serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_56BIT
                        || serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_128BIT)
                    {
                        securityHeaderType = SecurityHeaderType.NonFips;
                    }
                    else if (serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS)
                    {
                        securityHeaderType = SecurityHeaderType.Fips;
                    }
                    else
                    {
                        securityHeaderType = SecurityHeaderType.None;
                    }
                    break;
            }
            return securityHeaderType;
        }
예제 #8
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="serverSessionContext">Specify the session context.</param>
 public Server_Status_Info_Pdu(RdpbcgrServerSessionContext serverSessionContext)
     : base(serverSessionContext)
 {
 }
        /// <summary>
        /// Add session context to server context.
        /// </summary>
        /// <param name="sessionContext">Add session context.</param>
        internal void AddSession(RdpbcgrServerSessionContext sessionContext)
        {
            lock (this.sessions)
            {
                if (this.sessions.Contains(sessionContext))
                {
                    throw new InvalidOperationException(
                        "the sessionContext is exists in the sessionContext collection, can not add duplicate sessionContext");
                }

                this.sessions.Add(sessionContext);
            }
        }
예제 #10
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="serverSessionContext">Specify the session context.</param>
 public Server_Set_Keyboard_IME_Status_Pdu(RdpbcgrServerSessionContext serverSessionContext)
     : base(serverSessionContext)
 {
 }
        /// <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>
 /// For Standard Redirection PDU type, an encryption is needed. 
 /// So if there's encryptionLevel is ENCRYPTION_LEVEL_LOW, update the securityHeaderType according to TD.
 /// </summary>
 /// <param name="securityHeaderType">security header type</param>
 private void UpdateSecurityHeaderType(RdpbcgrServerSessionContext serverSessionContext, ref SecurityHeaderType securityHeaderType)
 {
     // Redirection PDU need to decrypt
     if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_LOW)
     {
         if (serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_40BIT
             || serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_56BIT
             || serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_128BIT)
         {
             securityHeaderType = SecurityHeaderType.NonFips;
         }
         else if (serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS)
         {
             securityHeaderType = SecurityHeaderType.Fips;
         }
         else
         {
             securityHeaderType = SecurityHeaderType.None;
         }
     }
 }
예제 #13
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="clientContext">Specify the context.</param>
 public Virtual_Channel_RAW_Server_Pdu(RdpbcgrServerSessionContext serverSessionContext)
     : base(serverSessionContext)
 {
 }
예제 #14
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="serverSessionContext">Specify the session context.</param>
 public TS_MONITOR_LAYOUT_PDU(RdpbcgrServerSessionContext serverSessionContext)
     : base(serverSessionContext)
 {
 }
예제 #15
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="serverSessionContext">Specify the session context.</param>
 public TS_FP_UPDATE_PDU(RdpbcgrServerSessionContext serverSessionContext)
     : base(serverSessionContext)
 {
 }
예제 #16
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="serverSessionContext">Specify the session context.</param>
 public SlowPathOutputPdu(RdpbcgrServerSessionContext serverSessionContext)
     : base(serverSessionContext)
 {
 }
예제 #17
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="serverSessionContext"></param>
 public Server_X_224_Negotiate_Failure_Pdu(RdpbcgrServerSessionContext serverSessionContext)
     : base(serverSessionContext)
 {
 }
예제 #18
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="serverSessionContext"></param>
 public Server_X_224_Connection_Confirm_Pdu(RdpbcgrServerSessionContext serverSessionContext)
     : base(serverSessionContext)
 {
 }
예제 #19
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="serverSessionContext">Specify the session context.</param>
 public Server_Synchronize_Pdu(RdpbcgrServerSessionContext serverSessionContext)
     : base(serverSessionContext)
 {
 }
        /// <summary>
        /// Switch Decode MCS Domain PDU
        /// </summary>
        /// <param name="serverSessionContext">the server session context</param>
        /// <param name="data">data to be parsed</param>
        /// <returns>decoded MCS Domain PDU</returns>
        private StackPacket SwitchDecodeMcsDomainPDU(RdpbcgrServerSessionContext serverSessionContext, byte[] data)
        {
            // Skip TpktHeader and X224Data
            int tempIndex = ConstValue.TPKT_HEADER_AND_X224_DATA_LENGTH;

            // Decode Domain MCS PDU
            DomainMCSPDU domainPdu = ParseMcsDomainPdu(data, ref tempIndex);

            // Switch decoders by pdu element name
            StackPacket pdu = null;
            switch (domainPdu.ElemName)
            {
                // Erect Domain Request PDU
                case ConstValue.MCS_DOMAIN_PDU_NAME_ERECT_DOMAIN_REQUEST:
                    pdu = DecodeMcsErectDomainRequestPDU(data);
                    break;

                // Attach User Request PDU
                case ConstValue.MCS_DOMAIN_PDU_NAME_ATTACH_USER_REQUEST:
                    pdu = DecodeMcsAttachUserRequestPDU(data);
                    break;

                // Channel Join Request PDU
                case ConstValue.MCS_DOMAIN_PDU_NAME_CHANNEL_JOIN_REQUEST:
                    pdu = DecodeMcsChannelJoinRequestPDU(data);
                    break;

                // Send Data Request PDU
                case ConstValue.MCS_DOMAIN_PDU_NAME_SEND_DATA_REQUEST:
                    pdu = DecodeMcsSendDataRequestPDU(serverSessionContext, data, domainPdu);
                    break;

                // Disconnect Provider Ultimatum PDU
                case ConstValue.MCS_DOMAIN_PDU_NAME_DISCONNECT_PROVIDER_ULTIMATUM:
                    pdu = DecodeDisconnectProviderUltimatumPDU(data);
                    break;

                default:
                    throw new FormatException(ConstValue.ERROR_MESSAGE_ENUM_UNRECOGNIZED);
            }
            return pdu;
        }
        /// <summary>
        /// Switch Decode MCS PDU
        /// </summary>
        /// <param name="serverSessionContext">the server session context</param>
        /// <param name="data">data to be parsed</param>
        /// <returns>decode MCS PDU</returns>
        private StackPacket SwitchDecodeMcsPDU(RdpbcgrServerSessionContext serverSessionContext, byte[] data)
        {
            // Check data length
            if (ConstValue.MCS_CONNECT_INITIAL_PDU_INDICATOR_INDEX >= data.Length)
            {
                throw new FormatException(ConstValue.ERROR_MESSAGE_DATA_INDEX_OUT_OF_RANGE);
            }

            // Decode by MCS PDU Type
            StackPacket pdu = null;
            byte mcsPduType = data[ConstValue.MCS_CONNECT_INITIAL_PDU_INDICATOR_INDEX];
            if (ConstValue.MCS_CONNECT_INITIAL_PDU_INDICATOR_VALUE == mcsPduType)
            {
                // Decode MCS Connect Response PDU
                pdu = DecodeMcsConnectInitialPDU(data);
            }
            else
            {
                // Decode MCS Domain PDU
                pdu = SwitchDecodeMcsDomainPDU(serverSessionContext, data);
            }
            return pdu;
        }
        /// <summary>
        /// Creates a new Socket for a newly created connection and  a new thread to receive packet in the loop.
        /// </summary>
        private void AcceptLoop()
        {
            while (!exitLoop)
            {
                if (this.receivingStreams.Count >= config.MaxConnections)
                {
                    // not listen untill the current connections are less than the max value.
                    // the interval to query is 1 seconds:
                    Thread.Sleep(1000);
                    continue;
                }

                Socket socket = null;
                try
                {
                    socket = this.listenSock.Accept();
                }
                catch (SocketException)
                {
                    exitLoop = true;
                    continue;
                }

                TransportEvent connectEvent;

                Stream receiveStream = null;
                Stream baseStream = new NetworkStream(socket);
                switch (streamType)
                {
                    case SecurityStreamType.None:
                        receiveStream = baseStream;
                        break;
                    case SecurityStreamType.Ssl:
                        receiveStream = new SslStream(
                            new ETWStream(
                            baseStream),
                            false
                            );
                        ((SslStream)receiveStream).AuthenticateAsServer(cert);
                        break;
                    case SecurityStreamType.CredSsp:
                        string targetSPN = ConstValue.CREDSSP_SERVER_NAME_PREFIX + config.LocalIpAddress;
                        RdpbcgrServerCredSspStream credSspStream = new RdpbcgrServerCredSspStream(new ETWStream(baseStream), targetSPN);
                        credSspStream.Authenticate(cert);
                        receiveStream = credSspStream;
                        break;
                    default:
                        receiveStream = baseStream;
                        break;
                }

                RdpbcgrReceiveThread receiveThread = new RdpbcgrReceiveThread(
                    socket.RemoteEndPoint,
                    this.packetQueue,
                    this.decoder,
                    receiveStream,
                    this.config.BufferSize,
                    this.rdpbcgrServer);

                connectEvent = new TransportEvent(EventType.Connected, socket.RemoteEndPoint, null);

                RdpbcgrServerSessionContext session = new RdpbcgrServerSessionContext();
                session.Identity = connectEvent.EndPoint;
                session.Server = this.rdpbcgrServer;
                session.LocalIdentity = socket.LocalEndPoint;
                session.IsClientToServerEncrypted = this.rdpbcgrServer.IsClientToServerEncrypted;
                this.rdpbcgrServer.ServerContext.AddSession(session);

                this.packetQueue.AddObject(connectEvent);

                lock (this.receivingStreams)
                {
                    this.receivingStreams.Add(socket, receiveThread);
                }

                receiveThread.Start();
            }
        }
        /// <summary>
        /// Decode PDU 
        /// (entrance method for decoders)
        /// </summary>
        /// <param name="serverSessionContext">the server session context</param>
        /// <param name="data">data to be parsed</param>
        /// <returns>decoded PDU</returns>
        public StackPacket DecodePdu(RdpbcgrServerSessionContext serverSessionContext, byte[] data)
        {
            // Check data length
            if (null == data)
            {
                throw new FormatException(ConstValue.ERROR_MESSAGE_DATA_NULL_REF);
            }
            if (0 == data.Length)
            {
                throw new FormatException(ConstValue.ERROR_MESSAGE_DATA_INDEX_OUT_OF_RANGE);
            }

            // Check slow-path/fast-path type
            StackPacket pdu = null;
            if (ConstValue.SLOW_PATH_PDU_INDICATOR_VALUE == data[ConstValue.SLOW_PATH_PDU_INDICATOR_INDEX])
            {
                // Slow-Path Situation
                if (data.Length <= ConstValue.X224_TPDU_TYPE_INDICATOR_INDEX)
                {
                    throw new FormatException(ConstValue.ERROR_MESSAGE_DATA_INDEX_OUT_OF_RANGE);
                }

                X224_TPDU_TYPE x224Type = (X224_TPDU_TYPE)data[ConstValue.X224_TPDU_TYPE_INDICATOR_INDEX];
                switch (x224Type)
                {
                    // X224 Connection Confirm PDU
                    case X224_TPDU_TYPE.ConnectionRequest:
                        pdu = DecodeX224ConnectionRequestPDU(data);
                        break;

                    // MCS PDU
                    case X224_TPDU_TYPE.Data:
                        pdu = SwitchDecodeMcsPDU(serverSessionContext, data);
                        break;

                    default:
                        throw new FormatException(ConstValue.ERROR_MESSAGE_ENUM_UNRECOGNIZED);
                }
            }
            else
            {
                // Fast-Path Situation
                pdu = DecodeTsFpInputPDU(serverSessionContext, data);
            }

            return pdu;
        }
예제 #24
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="serverSessionContext">Specify the session context.</param>
 public Server_Set_Keyboard_Indicators_Pdu(RdpbcgrServerSessionContext severSessionContext)
     : base(severSessionContext)
 {
 }
        /// <summary>
        /// Decode Fast-path Update PDU
        /// </summary>
        /// <param name="serverSessionContext">server session context</param>
        /// <param name="data">data to be parsed</param>
        /// <returns>decoded Fast-path Update PDU</returns>
        public StackPacket DecodeTsFpInputPDU(RdpbcgrServerSessionContext serverSessionContext, byte[] data)
        {
            int currentIndex = 0;
            TS_FP_INPUT_PDU pdu = new TS_FP_INPUT_PDU();

            pdu.fpInputHeader.actionCode = ParseByte(data, ref currentIndex);
            nested_TS_FP_UPDATE_PDU_fpOutputHeader_actionCode_Values actionCode;
            byte numberEvents;
            encryptionFlagsChgd_Values encryptionFlags;
            GetFpInputHeaderInfo(pdu.fpInputHeader.actionCode, out actionCode, out numberEvents, out encryptionFlags);

            pdu.length1 = ParseByte(data, ref currentIndex);

            if ((ConstValue.MOST_SIGNIFICANT_BIT_FILTER & pdu.length1) != pdu.length1)
            {
                // length2 is present (since the most significant bit of length1 is set)
                pdu.length2 = ParseByte(data, ref currentIndex);
            }

            // TS_FP_UPDATE_PDU: fipsInformation
            if (EncryptionLevel.ENCRYPTION_LEVEL_FIPS == serverSessionContext.RdpEncryptionLevel)
            {
                pdu.fipsInformation = ParseTsFpFipsInfo(data, ref currentIndex);
            }

            // TS_FP_UPDATE_PDU: dataSignature
            if (IsFlagExist((byte)encryptionFlags, (byte)encryptionFlagsChgd_Values.FASTPATH_OUTPUT_ENCRYPTED))
            {
                // pdu were encrypted, data signature exists
                pdu.dataSignature = GetBytes(data, ref currentIndex,
                    ConstValue.TS_FP_UPDATE_PDU_DATA_SIGNATURE_LENGTH);
            }
            else
            {
                pdu.dataSignature = null;
            }

            // Decryption
            bool isSalted = IsFlagExist((byte)encryptionFlags,
                (byte)encryptionFlagsChgd_Values.FASTPATH_OUTPUT_SECURE_CHECKSUM);
            byte[] remainData = GetBytes(data, ref currentIndex, (data.Length - currentIndex));
            byte[] decryptedData = DecryptFastPathInputData(serverSessionContext, remainData, pdu.dataSignature, isSalted);

            // Decrypted data index
            int decryptedDataIndex = 0;

            //[yunzed]
            if( numberEvents == 0 )
            {
                Console.WriteLine("numberEvents is 0, so parse the additional numberEvents");
                pdu.numberEvents = ParseByte(decryptedData, ref decryptedDataIndex);
            }

            // TS_FP_UPDATE_PDU: fpOutputUpdates
            pdu.fpInputEvents= ParseTsFpInputEvents(decryptedData, ref decryptedDataIndex);

            // ETW Provider Dump Message
            if (pdu.dataSignature != null)
            {
                // Fast-Path encrypted
                string messageName = "RDPBCGR:" + pdu.GetType().Name;
                ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer3, pdu.GetType().Name, decryptedData);
            }

            // Check if data length exceeded expectation
            VerifyDataLength(decryptedData.Length, decryptedDataIndex, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return pdu;
        }
 /// <summary>
 /// Decrypt Fast-path Update Data
 /// </summary>
 /// <param name="remainData">data to be decrypted</param>
 /// <param name="signatureData">signature data</param>
 /// <param name="isSalted">if the MAC signature was created by "salted MAC generation"</param>
 /// <returns>decrypted Fast-path Update Data</returns>
 private byte[] DecryptFastPathInputData(RdpbcgrServerSessionContext serverSessionContext, byte[] remainData, byte[] signatureData, bool isSalted)
 {
     if (null == signatureData)
     {
         // No need to decrypt, return directly
         return remainData;
     }
     else
     {
         // Decryption
         byte[] decryptedData = null;
         if (!serverSessionContext.ServerDecrypt(remainData, signatureData, isSalted, out decryptedData))
         {
             // Decryptioin failed
             throw new FormatException(ConstValue.ERROR_MESSAGE_DECRYPTION_FAILED);
         }
         return decryptedData;
     }
 }
 /// <summary>
 /// Remove session context from server context. If connection does not exists, do nothing.
 /// </summary>
 /// <param name="sessionContext">Add session context.</param>
 internal void RemoveSession(RdpbcgrServerSessionContext sessionContext)
 {
     lock (this.sessions)
     {
         if (this.SessionContexts.Contains(sessionContext))
         {
             this.sessions.Remove(sessionContext);
         }
     }
 }
        /// <summary>
        /// Decrypt Send Data Request
        /// </summary>
        /// <param name="userData">user data</param>
        /// <param name="securityHeaderType">security header type</param>
        /// <returns>decrypted user data</returns>
        private byte[] DecryptSendDataRequest(RdpbcgrServerSessionContext serverSessionContext, byte[] userData, SecurityHeaderType securityHeaderType)
        {
            // Parse security header
            int index = 0;
            TS_SECURITY_HEADER header = ParseTsSecurityHeader(userData, ref index, securityHeaderType);

            // If header is absent, data is not encrypted, return directly
            if (null == header)
            {
                return userData;
            }

            // Get remain data with security header removed
            int remainLength = userData.Length - index;
            byte[] remainData = GetBytes(userData, ref index, remainLength);

            // Header is present, but still data is not encrypted, return directly
            bool isEncryptFlagExist = IsFlagExist((UInt16)header.flags,
                (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_ENCRYPT);
            bool isRedirectFlagExist = IsFlagExist((UInt16)header.flags,
                (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_REDIRECTION_PKT);
            if ((!isEncryptFlagExist) && (!isRedirectFlagExist))
            {
                return remainData;
            }

            // Get data signature (Fips/NonFips only)
            byte[] signature = null;
            switch (securityHeaderType)
            {
                case SecurityHeaderType.NonFips:
                    TS_SECURITY_HEADER1 nonFipsHeader = (TS_SECURITY_HEADER1)header;
                    signature = nonFipsHeader.dataSignature;
                    break;

                case SecurityHeaderType.Fips:
                    TS_SECURITY_HEADER2 fipsHeader = (TS_SECURITY_HEADER2)header;
                    signature = fipsHeader.dataSignature;
                    break;

                case SecurityHeaderType.None:
                    signature = null;
                    break;

                case SecurityHeaderType.Basic:
                    signature = null;
                    break;

                default:
                    throw new FormatException(ConstValue.ERROR_MESSAGE_ENUM_UNRECOGNIZED);
            }

            // Check if "Salted MAC Generation" was used in PDU generation
            bool isSalted = IsFlagExist((UInt16)header.flags,
                (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_SECURE_CHECKSUM);

            // Decryption
            byte[] decryptedData = null;
            if (!serverSessionContext.ServerDecrypt(remainData, signature, isSalted, out decryptedData))
            {
                // If decryption failed
                throw new FormatException(ConstValue.ERROR_MESSAGE_DECRYPTION_FAILED);
            }
            return decryptedData;
        }
        /// <summary>
        /// Decode MCS Send Data Request PDU
        /// </summary>
        /// <param name="serverSessionContext">the server session context</param>
        /// <param name="data">data to be parsed</param>
        /// <param name="domainPdu">Mcs Domain PDU</param>
        /// <returns>decoded MCS Send Data Request PDU</returns>
        private StackPacket DecodeMcsSendDataRequestPDU(RdpbcgrServerSessionContext serverSessionContext, byte[] data, DomainMCSPDU domainPdu)
        {
            SendDataRequest indication = (SendDataRequest)domainPdu.GetData();
            byte[] userData = indication.userData.ByteArrayValue;

            bool isSecurityExchange;
            bool isClientInfo;
            bool isAutoDetectResponsePDU;
            bool isMultitransportErrorPDU;

            // Get Security Header Type
            SecurityHeaderType securityHeaderType = GetSecurityHeaderTypeByContext(serverSessionContext);

            int i = 0;
            if (userData.Length == ParseUInt16(userData, ref i, false)
                || (securityHeaderType == SecurityHeaderType.None && serverSessionContext.IOChannelId != indication.channelId.Value && serverSessionContext.McsMsgChannelId != indication.channelId.Value))
            {
                // the packet not transmitted in IO Channel cannot be Security Exchange PDU or Client Info PDU, so set all to false.
                isSecurityExchange = false;
                isClientInfo = false;
                isAutoDetectResponsePDU = false;
                isMultitransportErrorPDU = false;
            }
            else
            {
                int tempIndex = 0;
                TS_SECURITY_HEADER header = ParseTsSecurityHeader(userData, ref tempIndex, SecurityHeaderType.Basic);

                // Check if PDU is Security Exchange PDU
                isSecurityExchange = IsFlagExist((UInt16)header.flags,
                    (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_EXCHANGE_PKT);

                //Check if PDU is Client Info PDU
                isClientInfo = IsFlagExist((UInt16)header.flags, (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_INFO_PKT);

                //check if PDU is Auto Detect Response PDU
                isAutoDetectResponsePDU = IsFlagExist((UInt16)header.flags, (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_AUTODETECT_RSP);

                //check if PDU is Client Initiate Multitransport Error PDU
                isMultitransportErrorPDU = IsFlagExist((UInt16)header.flags, (UInt16)TS_SECURITY_HEADER_flags_Values.SEC_TRANSPORT_RSP);
            }

            if (isSecurityExchange)
            {
                securityHeaderType = SecurityHeaderType.Basic;
                byte[] decryptedUserData = DecryptSendDataRequest(serverSessionContext, userData, securityHeaderType);
                return DecodeSecurityExchangePdu(serverSessionContext, data, decryptedUserData, securityHeaderType);
            }
            else if (isClientInfo)
            {
                if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_NONE &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_NONE)
                {
                    securityHeaderType = SecurityHeaderType.Basic;
                }
                else if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_FIPS &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS)
                {
                    securityHeaderType = SecurityHeaderType.Fips;
                }
                else
                {
                    securityHeaderType = SecurityHeaderType.NonFips;
                }
                byte[] decryptedUserData = DecryptSendDataRequest(serverSessionContext, userData, securityHeaderType);
                return DecodeClientInfoPdu(data, decryptedUserData, securityHeaderType);
            }
            else if (isAutoDetectResponsePDU)
            {
                if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_NONE &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_NONE)
                {
                    securityHeaderType = SecurityHeaderType.Basic;
                }
                else if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_FIPS &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS)
                {
                    securityHeaderType = SecurityHeaderType.Fips;
                }
                else
                {
                    securityHeaderType = SecurityHeaderType.NonFips;
                }
                byte[] decryptedUserData = DecryptSendDataRequest(serverSessionContext, userData, securityHeaderType);
                return DecodeClientAutoDetectResponsePDU(data, decryptedUserData, securityHeaderType);
            }
            else if (isMultitransportErrorPDU)
            {
                if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_NONE &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_NONE)
                {
                    securityHeaderType = SecurityHeaderType.Basic;
                }
                else if (serverSessionContext.RdpEncryptionLevel == EncryptionLevel.ENCRYPTION_LEVEL_FIPS &&
                    serverSessionContext.RdpEncryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS)
                {
                    securityHeaderType = SecurityHeaderType.Fips;
                }
                else
                {
                    securityHeaderType = SecurityHeaderType.NonFips;
                }
                byte[] decryptedUserData = DecryptSendDataRequest(serverSessionContext, userData, securityHeaderType);
                return DecodeClientInitiateMultitransportResponsePDU(data, decryptedUserData, securityHeaderType);
            }
            else
            {
                if(!serverSessionContext.IsClientToServerEncrypted)
                    securityHeaderType = SecurityHeaderType.Basic;
                // Get decrypted user data
                byte[] decryptedUserData = DecryptSendDataRequest(serverSessionContext, userData, securityHeaderType);

                // Check channel ID (IO Channel ID/Virual Channel ID)
                if (serverSessionContext.IOChannelId != indication.channelId.Value)
                {
                    // Decode Virtual Channel PDU
                    return DecodeVirtualChannelPDU(data, decryptedUserData, securityHeaderType);
                }

                else
                {
                    // Decode other Send Data Indication PDUs
                    return SwitchDecodeMcsSendDataRequestPDU(data, decryptedUserData, securityHeaderType);
                }
            }
        }
예제 #30
0
 /// <summary>
 /// The constructor of the class.
 /// </summary>
 /// <param name="serverSessionContext">Specify the session context.</param>
 public Server_Shutdown_Request_Denied_Pdu(RdpbcgrServerSessionContext serverSessionContext)
     : base(serverSessionContext)
 {
 }