/// <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; }
/// <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); } }
/// <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; } } }
/// <summary> /// The constructor of the class. /// </summary> /// <param name="clientContext">Specify the context.</param> public Virtual_Channel_RAW_Server_Pdu(RdpbcgrServerSessionContext serverSessionContext) : base(serverSessionContext) { }
/// <summary> /// The constructor of the class. /// </summary> /// <param name="serverSessionContext">Specify the session context.</param> public TS_MONITOR_LAYOUT_PDU(RdpbcgrServerSessionContext serverSessionContext) : base(serverSessionContext) { }
/// <summary> /// The constructor of the class. /// </summary> /// <param name="serverSessionContext">Specify the session context.</param> public TS_FP_UPDATE_PDU(RdpbcgrServerSessionContext serverSessionContext) : base(serverSessionContext) { }
/// <summary> /// The constructor of the class. /// </summary> /// <param name="serverSessionContext">Specify the session context.</param> public SlowPathOutputPdu(RdpbcgrServerSessionContext serverSessionContext) : base(serverSessionContext) { }
/// <summary> /// The constructor of the class. /// </summary> /// <param name="serverSessionContext"></param> public Server_X_224_Negotiate_Failure_Pdu(RdpbcgrServerSessionContext serverSessionContext) : base(serverSessionContext) { }
/// <summary> /// The constructor of the class. /// </summary> /// <param name="serverSessionContext"></param> public Server_X_224_Connection_Confirm_Pdu(RdpbcgrServerSessionContext serverSessionContext) : base(serverSessionContext) { }
/// <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; }
/// <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); } } }
/// <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) { }