From f3a3ad8ac3a9bf8d8acd830245c78c3684040957 Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Wed, 10 Dec 2014 18:32:10 +0100 Subject: [PATCH] finish 128 bit basic rdp security layer --- rdpy/protocol/rdp/gcc.py | 26 +++++----- rdpy/protocol/rdp/lic.py | 5 +- rdpy/protocol/rdp/pdu/caps.py | 5 +- rdpy/protocol/rdp/pdu/layer.py | 46 ++++++++---------- rdpy/protocol/rdp/rc4.py | 7 +-- rdpy/protocol/rdp/rdp.py | 5 +- rdpy/protocol/rdp/sec.py | 87 ++++++++++++++++++++++++++++------ rdpy/protocol/rdp/tpkt.py | 71 ++++++++++++++++++++------- rdpy/protocol/rdp/x224.py | 2 +- setup.py | 1 + 10 files changed, 175 insertions(+), 80 deletions(-) diff --git a/rdpy/protocol/rdp/gcc.py b/rdpy/protocol/rdp/gcc.py index 5c7ecdd..1479b13 100644 --- a/rdpy/protocol/rdp/gcc.py +++ b/rdpy/protocol/rdp/gcc.py @@ -34,7 +34,7 @@ h221_sc_key = "McDn"; class MessageType(object): """ - Server to Client block + @summary: Server to Client block GCC conference messages @see: http://msdn.microsoft.com/en-us/library/cc240509.aspx """ @@ -52,7 +52,7 @@ class MessageType(object): class ColorDepth(object): """ - Depth color + @summary: Depth color @see: http://msdn.microsoft.com/en-us/library/cc240510.aspx """ RNS_UD_COLOR_8BPP = 0xCA01 @@ -62,7 +62,7 @@ class ColorDepth(object): class HighColor(object): """ - High color of client + @summary: High color of client @see: http://msdn.microsoft.com/en-us/library/cc240510.aspx """ HIGH_COLOR_4BPP = 0x0004 @@ -73,7 +73,7 @@ class HighColor(object): class Support(object): """ - Supported depth flag + @summary: Supported depth flag @see: http://msdn.microsoft.com/en-us/library/cc240510.aspx """ RNS_UD_24BPP_SUPPORT = 0x0001 @@ -83,7 +83,7 @@ class Support(object): class CapabilityFlags(object): """ - For more details on each flags click above + @summary: For more details on each flags click above @see: http://msdn.microsoft.com/en-us/library/cc240510.aspx """ RNS_UD_CS_SUPPORT_ERRINFO_PDU = 0x0001 @@ -100,7 +100,7 @@ class CapabilityFlags(object): class ConnectionType(object): """ - This information is correct if + @summary: This information is correct if RNS_UD_CS_VALID_CONNECTION_TYPE flag is set on capabilityFlag @see: http://msdn.microsoft.com/en-us/library/cc240510.aspx """ @@ -114,7 +114,7 @@ class ConnectionType(object): class Version(object): """ - Supported version of RDP + @summary: Supported version of RDP @see: http://msdn.microsoft.com/en-us/library/cc240510.aspx """ RDP_VERSION_4 = 0x00080001 @@ -125,7 +125,7 @@ class Sequence(object): class Encryption(object): """ - Encryption methods supported + @summary: Encryption methods supported @see: http://msdn.microsoft.com/en-us/library/cc240511.aspx """ ENCRYPTION_FLAG_40BIT = 0x00000001 @@ -135,7 +135,7 @@ class Encryption(object): class ChannelOptions(object): """ - Channel options + @summary: Channel options @see: http://msdn.microsoft.com/en-us/library/cc240513.aspx """ CHANNEL_OPTION_INITIALIZED = 0x80000000 @@ -152,8 +152,8 @@ class ChannelOptions(object): class KeyboardType(object): """ - Keyboard type - IBM_101_102_KEYS is the most common keyboard type + @summary: Keyboard type + @see: IBM_101_102_KEYS is the most common keyboard type """ IBM_PC_XT_83_KEY = 0x00000001 OLIVETTI = 0x00000002 @@ -165,7 +165,7 @@ class KeyboardType(object): class KeyboardLayout(object): """ - Keyboard layout definition + @summary: Keyboard layout definition @see: http://technet.microsoft.com/en-us/library/cc766503%28WS.10%29.aspx """ ARABIC = 0x00000401 @@ -197,7 +197,7 @@ class CertificateType(object): class DataBlock(CompositeType): """ - Block settings + @summary: Block settings """ def __init__(self, dataBlock = None): CompositeType.__init__(self) diff --git a/rdpy/protocol/rdp/lic.py b/rdpy/protocol/rdp/lic.py index 8b572d0..cac38fc 100644 --- a/rdpy/protocol/rdp/lic.py +++ b/rdpy/protocol/rdp/lic.py @@ -275,6 +275,7 @@ class LicenseManager(object): sessionKeyBlob = sec.generateMicrosoftKeyABBCCC(masterSecret, self._serverRandom, self._clientRandom) self._macSalt = sessionKeyBlob[:16] self._licenseKey = sec.finalHash(sessionKeyBlob[16:32], self._clientRandom, self._serverRandom) + self._rc4LicenseKey = rc4.RC4Key(self._licenseKey) def recv(self, s): """ @@ -324,7 +325,7 @@ class LicenseManager(object): """ #decrypt server challenge #it should be TEST word in unicode format - serverChallenge = rc4.crypt(self._licenseKey, self._serverEncryptedChallenge) + serverChallenge = rc4.crypt(self._rc4LicenseKey, self._serverEncryptedChallenge) #generate hwid s = Stream() @@ -333,7 +334,7 @@ class LicenseManager(object): message = ClientPLatformChallengeResponse() message.encryptedPlatformChallengeResponse.blobData.value = self._serverEncryptedChallenge - message.encryptedHWID.blobData.value = rc4.crypt(self._licenseKey, hwid) + message.encryptedHWID.blobData.value = rc4.crypt(self._rc4LicenseKey, hwid) message.MACData.value = sec.macData(self._macSalt, serverChallenge + hwid) self._transport.sendFlagged(sec.SecurityFlag.SEC_LICENSE_PKT, LicPacket(message)) \ No newline at end of file diff --git a/rdpy/protocol/rdp/pdu/caps.py b/rdpy/protocol/rdp/pdu/caps.py index f328d16..f06989d 100644 --- a/rdpy/protocol/rdp/pdu/caps.py +++ b/rdpy/protocol/rdp/pdu/caps.py @@ -362,8 +362,9 @@ class PointerCapability(CompositeType): def __init__(self, readLen = None): CompositeType.__init__(self, readLen = readLen) self.colorPointerFlag = UInt16Le() - self.colorPointerCacheSize = UInt16Le() - self.pointerCacheSize = UInt16Le() + self.colorPointerCacheSize = UInt16Le(20) + #old version of rdp doesn't support ... + #self.pointerCacheSize = UInt16Le() class InputCapability(CompositeType): """ diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index d3cfcc5..3bee01a 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -24,8 +24,7 @@ In this layer are managed all mains bitmap update orders end user inputs """ from rdpy.core.layer import LayerAutomata -from rdpy.core.error import InvalidExpectedDataException, CallPureVirtualFuntion -from rdpy.core.type import UInt16Le +from rdpy.core.error import CallPureVirtualFuntion import rdpy.core.log as log import rdpy.protocol.rdp.gcc as gcc import rdpy.protocol.rdp.tpkt as tpkt @@ -71,7 +70,7 @@ class PDUServerListener(object): """ raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onSlowPathInput", "PDUServerListener")) -class PDULayer(LayerAutomata): +class PDULayer(LayerAutomata, tpkt.IFastPathListener): """ @summary: Global channel for MCS that handle session identification user, licensing management, and capabilities exchange @@ -106,6 +105,15 @@ class PDULayer(LayerAutomata): } #share id between client and server self._shareId = 0x103EA + #enable or not fast path + self._fastPathSender = None + + def setFastPathSender(self, fastPathSender): + """ + @param fastPathSender: {tpkt.FastPathSender} + @note: implement tpkt.IFastPathListener + """ + self._fastPathSender = fastPathSender def sendPDU(self, pduMessage): """ @@ -121,7 +129,7 @@ class PDULayer(LayerAutomata): """ self.sendPDU(data.DataPDU(pduData, self._shareId)) -class Client(PDULayer, tpkt.IFastPathListener): +class Client(PDULayer): """ @summary: Client automata of PDU layer """ @@ -131,8 +139,6 @@ class Client(PDULayer, tpkt.IFastPathListener): """ PDULayer.__init__(self) self._listener = listener - #enable or not fast path - self._fastPathSender = None def connect(self): """ @@ -149,13 +155,6 @@ class Client(PDULayer, tpkt.IFastPathListener): """ self._transport.close() #self.sendDataPDU(data.ShutdownRequestPDU()) - - def setFastPathSender(self, fastPathSender): - """ - @param fastPathSender: tpkt.FastPathSender - @note: implement tpkt.IFastPathListener - """ - self._fastPathSender = fastPathSender def recvDemandActivePDU(self, s): """ @@ -267,11 +266,12 @@ class Client(PDULayer, tpkt.IFastPathListener): #http://msdn.microsoft.com/en-us/library/cc240454.aspx self.setNextState(self.recvDemandActivePDU) - def recvFastPath(self, fastPathS): + def recvFastPath(self, secFlag, fastPathS): """ @summary: Implement IFastPathListener interface Fast path is needed by RDP 8.0 - @param fastPathS: Stream that contain fast path data + @param fastPathS: {Stream} that contain fast path data + @param secFlag: {SecFlags} """ fastPathPDU = data.FastPathUpdatePDU() fastPathS.readType(fastPathPDU) @@ -343,7 +343,7 @@ class Client(PDULayer, tpkt.IFastPathListener): def sendClientFinalizeSynchronizePDU(self): """ - send a synchronize PDU from client to server + @summary: send a synchronize PDU from client to server """ synchronizePDU = data.SynchronizeDataPDU(self._transport._transport.getChannelId()) self.sendDataPDU(synchronizePDU) @@ -371,7 +371,7 @@ class Client(PDULayer, tpkt.IFastPathListener): pdu.slowPathInputEvents._array = [data.SlowPathInputEvent(x) for x in pointerEvents] self.sendDataPDU(pdu) -class Server(PDULayer, tpkt.IFastPathListener): +class Server(PDULayer): """ Server Automata of PDU layer """ @@ -389,14 +389,7 @@ class Server(PDULayer, tpkt.IFastPathListener): Connect message for server automata """ self.sendDemandActivePDU() - self.setNextState(self.recvConfirmActivePDU) - - def setFastPathSender(self, fastPathSender): - """ - @param fastPathSender: tpkt.FastPathSender - @note: implement tpkt.IFastPathListener - """ - self._fastPathSender = fastPathSender + self.setNextState(self.recvConfirmActivePDU) def recvConfirmActivePDU(self, s): """ @@ -588,7 +581,8 @@ class Server(PDULayer, tpkt.IFastPathListener): #fast path case fastPathUpdateDataPDU = data.FastPathBitmapUpdateDataPDU() fastPathUpdateDataPDU.rectangles._array = bitmapDatas - self._fastPathSender.sendFastPath(data.FastPathUpdatePDU(fastPathUpdateDataPDU)) + self._fastPathSender.sendFastPath(0, data.FastPathUpdatePDU(fastPathUpdateDataPDU)) + else: #slow path case updateDataPDU = data.BitmapUpdateDataPDU() diff --git a/rdpy/protocol/rdp/rc4.py b/rdpy/protocol/rdp/rc4.py index 476bfa3..5802cb1 100644 --- a/rdpy/protocol/rdp/rc4.py +++ b/rdpy/protocol/rdp/rc4.py @@ -50,7 +50,8 @@ def RC4(key): S = KSA(key) return PRGA(S) -def crypt(key, plaintext): - keystream = RC4([ord(c) for c in key]) - +def RC4Key(key): + return RC4([ord(c) for c in key]) + +def crypt(keystream, plaintext): return "".join([chr(ord(c) ^ keystream.next()) for c in plaintext]) \ No newline at end of file diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index c4d675c..9d33e2f 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -45,7 +45,10 @@ class RDPClientController(pdu.layer.PDUClientListener): #transport pdu layer self._x224Layer = x224.Client(self._mcsLayer) #transport packet (protocol layer) - self._tpktLayer = tpkt.TPKT(self._x224Layer, self._pduLayer) + self._tpktLayer = tpkt.TPKT(self._x224Layer) + #fastpath stack + self._pduLayer.initFastPath(self._secLayer) + self._secLayer.initFastPath(self._tpktLayer) #is pdu layer is ready to send self._isReady = False diff --git a/rdpy/protocol/rdp/sec.py b/rdpy/protocol/rdp/sec.py index 4fa49fd..17de239 100644 --- a/rdpy/protocol/rdp/sec.py +++ b/rdpy/protocol/rdp/sec.py @@ -21,7 +21,8 @@ Some use full methods for security in RDP """ -import sha, md5, rsa, gcc, rc4, lic +import sha, md5, rsa, rc4 +import gcc, lic, tpkt from rdpy.core.type import CompositeType, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8 from rdpy.core.layer import LayerAutomata, IStreamSender from rdpy.core.error import InvalidExpectedDataException @@ -238,7 +239,7 @@ class RDPExtendedInfo(CompositeType): self.clientSessionId = UInt32Le() self.performanceFlags = UInt32Le() -class SecLayer(LayerAutomata, IStreamSender): +class SecLayer(LayerAutomata, IStreamSender, tpkt.IFastPathListener, tpkt.IFastPathSender): """ @summary: Basic RDP security manager This layer is Transparent as possible for upper layer @@ -248,10 +249,25 @@ class SecLayer(LayerAutomata, IStreamSender): @param presentation: Layer (generally pdu layer) """ LayerAutomata.__init__(self, presentation) + #thios layer is like a fastpath proxy + self._fastPathTransport = None + self._fastPathPresentation = None + + #credentials self._info = RDPInfo(extendedInfoConditional = lambda:(self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_CORE).rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS)) + + #True if classic encryption is enable self._enableEncryption = False + + #crypto random + self._clientRandom = None + self._serverRandom = None + #initialise decrypt and encrypt keys self._decryt = None self._encrypt = None + #current rc4 map key + self._decryptRc4 = None + self._encryptRc4 = None def generateKeys(self): """ @@ -273,7 +289,12 @@ class SecLayer(LayerAutomata, IStreamSender): signature = String(readLen = UInt8(8)) encryptedPayload = String() s.readType((signature, encryptedPayload)) - return Stream(rc4.crypt(self._decrypt, encryptedPayload.value)) + decrypted = rc4.crypt(self._decryptRc4, encryptedPayload.value) + #ckeck signature + if macData(self._macKey128, decrypted)[:8] != signature.value: + raise InvalidExpectedDataException("Bad packet signature") + + return Stream(decrypted) def writeEncryptedPayload(self, data): """ @@ -283,7 +304,7 @@ class SecLayer(LayerAutomata, IStreamSender): """ s = Stream() s.writeType(data) - return (String(macData(self._macKey128, s.getvalue())[:8]), String(rc4.crypt(self._encrypt, s.getvalue()))) + return (String(macData(self._macKey128, s.getvalue())[:8]), String(rc4.crypt(self._encryptRc4, s.getvalue()))) def recv(self, data): """ @@ -301,7 +322,7 @@ class SecLayer(LayerAutomata, IStreamSender): if securityFlag.value & SecurityFlag.SEC_ENCRYPT: data = self.readEncryptedPayload(data) - + self._presentation.recv(data) def send(self, data): @@ -324,16 +345,44 @@ class SecLayer(LayerAutomata, IStreamSender): @param flag: {integer} security flag @param data: {Type | Tuple} """ - if self._enableEncryption: - flag |= SecurityFlag.SEC_ENCRYPT + if flag & SecurityFlag.SEC_ENCRYPT: data = self.writeEncryptedPayload(data) - self.__sendFlagged__(flag, data) - - def __sendFlagged__(self, flag, data): - """ - @summary: format basic message of security layer - """ self._transport.send((UInt16Le(flag), UInt16Le(), data)) + + def recvFastPath(self, secFlag, fastPathS): + """ + @summary: Call when fast path packet is received + @param secFlag: {SecFlags} + @param fastPathS: {Stream} + """ + if self._enableEncryption and secFlag & tpkt.SecFlags.FASTPATH_OUTPUT_ENCRYPTED: + fastPathS = self.readEncryptedPayload(fastPathS) + + self._fastPathPresentation.recvFastPath(secFlag, fastPathS) + + def setFastPathListener(self, fastPathListener): + """ + @param fastPathListener : {IFastPathListener} + """ + self._fastPathPresentation = fastPathListener + + def sendFastPath(self, secFlag, fastPathS): + """ + @summary: Send fastPathS Type as fast path packet + @param secFlag: {SecFlags} + @param fastPathS: {Stream} type transform to stream and send as fastpath + """ + if self._enableEncryption: + secFlag |= tpkt.SecFlags.FASTPATH_OUTPUT_ENCRYPTED + fastPathS = self.writeEncryptedPayload(fastPathS) + + self._fastPathTransport.sendFastPath(secFlag, fastPathS) + + def setFastPathSender(self, fastPathSender): + """ + @param fastPathSender: {tpkt.FastPathSender} + """ + self._fastPathTransport = fastPathSender class Client(SecLayer): """ @@ -352,19 +401,27 @@ class Client(SecLayer): self._clientRandom = rsa.randnum.read_random_bits(256) self._serverRandom = self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_SECURITY).serverRandom.value self._decrypt, self._encrypt = self.generateKeys() + self._decryptRc4 = rc4.RC4Key(self._decrypt) + self._encryptRc4 = rc4.RC4Key(self._encrypt) #send client random encrypted with certificate = self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_SECURITY).serverCertificate.certData + #reverse because bignum in little endian serverPublicKey = rsa.PublicKey(bin2bn(certificate.PublicKeyBlob.modulus.value[::-1]), certificate.PublicKeyBlob.pubExp.value) message = ClientSecurityExchangePDU() + #reverse because bignum in little endian message.encryptedClientRandom.value = rsa.encrypt(self._clientRandom[::-1], serverPublicKey)[::-1] self.sendFlagged(SecurityFlag.SEC_EXCHANGE_PKT, message) #now all messages must be encrypted self._enableEncryption = True - - self.sendFlagged(SecurityFlag.SEC_INFO_PKT, self._info) + + secFlag = SecurityFlag.SEC_INFO_PKT + if self._enableEncryption: + secFlag |= SecurityFlag.SEC_ENCRYPT + self.sendFlagged(secFlag, self._info) + self.setNextState(self.recvLicenceInfo) def recvLicenceInfo(self, s): diff --git a/rdpy/protocol/rdp/tpkt.py b/rdpy/protocol/rdp/tpkt.py index 6d54492..14d42d3 100644 --- a/rdpy/protocol/rdp/tpkt.py +++ b/rdpy/protocol/rdp/tpkt.py @@ -33,36 +33,67 @@ class Action(object): """ FASTPATH_ACTION_FASTPATH = 0x0 FASTPATH_ACTION_X224 = 0x3 + +class SecFlags(object): + """ + @see: http://msdn.microsoft.com/en-us/library/cc240621.aspx + """ + #hihi 'secure' checksum but private key is public !!! + FASTPATH_OUTPUT_SECURE_CHECKSUM = 0x1 + FASTPATH_OUTPUT_ENCRYPTED = 0x2 class IFastPathListener(object): """ @summary: Fast path packet listener Usually X224 layer """ - def recvFastPath(self, fastPathS): + def recvFastPath(self, secFlag, fastPathS): """ @summary: Call when fast path packet is received - @param fastPathS: Stream + @param secFlag: {SecFlags} + @param fastPathS: {Stream} """ - raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recvFastPath", "recvFastPath")) + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recvFastPath", "IFastPathListener")) + + def initFastPath(self, fastPathSender): + """ + @summary: initialize stack + @param fastPathSender: {IFastPathSender} + """ + self.setFastPathSender(fastPathSender) + fastPathSender.setFastPathListener(self) def setFastPathSender(self, fastPathSender): """ - @summary: Call to set a fast path sender to listener - @param fastPathSender: IFastPathSender + @param fastPathSender : {IFastPathSender} """ - raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathSender", "recvFastPath")) - + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathSender", "IFastPathListener")) + class IFastPathSender(object): """ @summary: Fast path send capability """ - def sendFastPath(self, fastPathS): + def sendFastPath(self, secFlag, fastPathS): """ @summary: Send fastPathS Type as fast path packet + @param secFlag: {SecFlags} @param fastPathS: type transform to stream and send as fastpath """ raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendFastPath", "IFastPathSender")) + + def initFastPath(self, fastPathListener): + """ + @summary: initialize stack + @param fastPathListener: {IFastPathListener} + """ + self.setFastPathListener(fastPathListener) + fastPathListener.setFastPathSender(self) + + def setFastPathListener(self, fastPathListener): + """ + @param fastPathListener: {IFastPathListener} + """ + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathListener", "IFastPathSender")) class TPKT(RawLayer, IFastPathSender): """ @@ -70,21 +101,25 @@ class TPKT(RawLayer, IFastPathSender): represent the Raw Layer in stack (first layer) This layer only handle size of packet and determine if is a fast path packet """ - def __init__(self, presentation, fastPathListener = None): + def __init__(self, presentation): """ @param presentation: presentation layer, in RDP case is x224 layer - @param fastPathListener: IFastPathListener """ RawLayer.__init__(self, presentation) #length may be coded on more than 1 bytes self._lastShortLength = UInt8() #fast path listener + self._fastPathListener = None + #last secure flag + self._secFlag = 0 + + def setFastPathListener(self, fastPathListener): + """ + @param fastPathListener : {IFastPathListener} + @note: implement IFastPathSender + """ self._fastPathListener = fastPathListener - if not fastPathListener is None: - #set me as fast path sender - fastPathListener.setFastPathSender(self) - def connect(self): """ @summary: Call when transport layer connection @@ -112,6 +147,7 @@ class TPKT(RawLayer, IFastPathSender): self.expect(2, self.readExtendedHeader) else: #is fast path packet + self._secFlag = version.value >> 6 data.readType(self._lastShortLength) if self._lastShortLength.value & 0x80: #size is 1 byte more @@ -147,7 +183,7 @@ class TPKT(RawLayer, IFastPathSender): Fast path data @param data: Stream from twisted layer """ - self._fastPathListener.recvFastPath(data) + self._fastPathListener.recvFastPath(self._secFlag, data) self.expect(2, self.readHeader) def readData(self, data): @@ -166,8 +202,9 @@ class TPKT(RawLayer, IFastPathSender): """ RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_X224), UInt8(0), UInt16Be(sizeof(message) + 4), message)) - def sendFastPath(self, fastPathS): + def sendFastPath(self, secFlag, fastPathS): """ @param fastPathS: type transform to stream and send as fastpath + @param secFlag: {SecFlags} """ - RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_FASTPATH), UInt16Be((sizeof(fastPathS) + 3) | 0x8000), fastPathS)) \ No newline at end of file + RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_FASTPATH | secFlag), UInt16Be((sizeof(fastPathS) + 3) | 0x8000), fastPathS)) \ No newline at end of file diff --git a/rdpy/protocol/rdp/x224.py b/rdpy/protocol/rdp/x224.py index 89cbbc9..3b1fdb5 100644 --- a/rdpy/protocol/rdp/x224.py +++ b/rdpy/protocol/rdp/x224.py @@ -132,7 +132,7 @@ class X224Layer(LayerAutomata, IStreamSender): LayerAutomata.__init__(self, presentation) #default selectedProtocol is SSl #client requested selectedProtocol - self._requestedProtocol = Protocols.PROTOCOL_RDP + self._requestedProtocol = Protocols.PROTOCOL_RDP | Protocols.PROTOCOL_SSL #server selected selectedProtocol self._selectedProtocol = Protocols.PROTOCOL_SSL diff --git a/setup.py b/setup.py index 8e552a6..d11a432 100644 --- a/setup.py +++ b/setup.py @@ -35,5 +35,6 @@ setup(name='rdpy', 'pyopenssl', 'service_identity', 'qt4reactor', + 'rsa', ], )