Add license header + SSL server config

This commit is contained in:
citronneur
2014-06-22 11:21:21 +02:00
parent e72c0da9d9
commit 063306c133
5 changed files with 205 additions and 78 deletions

View File

@@ -10,4 +10,10 @@ Remote Desktop Protocol in Twisted Python
* python-qt4 * python-qt4
* python-qt4reactor * python-qt4reactor
##Must be implemented before first release
* CreedSSP
* Packet redirection
* License
* Most common orders
this project is still in progress. this project is still in progress.

View File

@@ -7,9 +7,18 @@ import sys, os
sys.path.insert(1, os.path.join(sys.path[0], '../..')) sys.path.insert(1, os.path.join(sys.path[0], '../..'))
from rdpy.protocol.rdp import rdp from rdpy.protocol.rdp import rdp
from rdpy.network.layer import LayerMode
class TestServerFactory(rdp.ServerFactory):
def startedConnecting(self, connector):
pass
def clientConnectionLost(self, connector, reason):
pass
def clientConnectionFailed(self, connector, reason):
pass
if __name__ == '__main__': if __name__ == '__main__':
from twisted.internet import reactor from twisted.internet import reactor
reactor.listenTCP(33389, rdp.Factory(LayerMode.SERVER)) reactor.listenTCP(33389, TestServerFactory())
reactor.run() reactor.run()

View File

@@ -47,7 +47,7 @@ class ClientFactory(protocol.Factory):
''' '''
pduLayer = pdu.PDU(LayerMode.CLIENT) pduLayer = pdu.PDU(LayerMode.CLIENT)
pduLayer.getController().addObserver(self.buildObserver()) pduLayer.getController().addObserver(self.buildObserver())
return tpkt.TPKT(tpdu.TPDU(mcs.MCS(pduLayer))); return tpkt.TPKT(tpdu.createClient(mcs.MCS(pduLayer)));
def buildObserver(self): def buildObserver(self):
''' '''
@@ -55,6 +55,33 @@ class ClientFactory(protocol.Factory):
''' '''
pass pass
class ServerFactory(protocol.Factory):
'''
Factory of Serrve RDP protocol
'''
def __init__(self, privateKeyFileName, certificateFileName):
'''
ctor
@param privateKeyFileName: file contain server private key
@param certficiateFileName: file that contain publi key
'''
self._privateKeyFileName = privateKeyFileName
self._certificateFileName = certificateFileName
def buildProtocol(self, addr):
'''
Function call from twisted and build rdp protocol stack
@param addr: destination address
'''
pduLayer = pdu.PDU(LayerMode.SERVER)
#pduLayer.getController().addObserver(self.buildObserver())
return tpkt.TPKT(tpdu.createServer(mcs.MCS(pduLayer), self._privateKeyFileName, self._certificateFileName));
def buildObserver(self):
'''
build observer use for connection
'''
pass
class RDPClientObserver(object): class RDPClientObserver(object):
''' '''

View File

@@ -1,6 +1,29 @@
''' #
@author: sylvain # Copyright (c) 2014 Sylvain Peyrefitte
''' #
# This file is part of rdpy.
#
# rdpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""
Implement transport pdu layer
This layer have main goal to negociate ssl transport
RDP basic security is not supported by RDPY (because is not a true security layer...)
"""
from rdpy.network.layer import LayerAutomata, LayerMode from rdpy.network.layer import LayerAutomata, LayerMode
from rdpy.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof from rdpy.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof
from rdpy.network.error import InvalidExpectedDataException from rdpy.network.error import InvalidExpectedDataException
@@ -9,9 +32,9 @@ from rdpy.network.const import ConstAttributes, TypeAttributes
@ConstAttributes @ConstAttributes
@TypeAttributes(UInt8) @TypeAttributes(UInt8)
class MessageType(object): class MessageType(object):
''' """
message type message type
''' """
X224_TPDU_CONNECTION_REQUEST = 0xE0 X224_TPDU_CONNECTION_REQUEST = 0xE0
X224_TPDU_CONNECTION_CONFIRM = 0xD0 X224_TPDU_CONNECTION_CONFIRM = 0xD0
X224_TPDU_DISCONNECT_REQUEST = 0x80 X224_TPDU_DISCONNECT_REQUEST = 0x80
@@ -21,9 +44,9 @@ class MessageType(object):
@ConstAttributes @ConstAttributes
@TypeAttributes(UInt8) @TypeAttributes(UInt8)
class NegociationType(object): class NegociationType(object):
''' """
negotiation header negotiation header
''' """
TYPE_RDP_NEG_REQ = 0x01 TYPE_RDP_NEG_REQ = 0x01
TYPE_RDP_NEG_RSP = 0x02 TYPE_RDP_NEG_RSP = 0x02
TYPE_RDP_NEG_FAILURE = 0x03 TYPE_RDP_NEG_FAILURE = 0x03
@@ -31,9 +54,9 @@ class NegociationType(object):
@ConstAttributes @ConstAttributes
@TypeAttributes(UInt32Le) @TypeAttributes(UInt32Le)
class Protocols(object): class Protocols(object):
''' """
protocols available for TPDU layer protocols available for TPDU layer
''' """
PROTOCOL_RDP = 0x00000000 PROTOCOL_RDP = 0x00000000
PROTOCOL_SSL = 0x00000001 PROTOCOL_SSL = 0x00000001
PROTOCOL_HYBRID = 0x00000002 PROTOCOL_HYBRID = 0x00000002
@@ -42,9 +65,9 @@ class Protocols(object):
@ConstAttributes @ConstAttributes
@TypeAttributes(UInt32Le) @TypeAttributes(UInt32Le)
class NegotiationFailureCode(object): class NegotiationFailureCode(object):
''' """
protocol negotiation failure code protocol negotiation failure code
''' """
SSL_REQUIRED_BY_SERVER = 0x00000001 SSL_REQUIRED_BY_SERVER = 0x00000001
SSL_NOT_ALLOWED_BY_SERVER = 0x00000002 SSL_NOT_ALLOWED_BY_SERVER = 0x00000002
SSL_CERT_NOT_ON_SERVER = 0x00000003 SSL_CERT_NOT_ON_SERVER = 0x00000003
@@ -53,10 +76,13 @@ class NegotiationFailureCode(object):
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006 SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
class TPDUConnectMessage(CompositeType): class TPDUConnectMessage(CompositeType):
''' """
header of TPDU connection messages header of TPDU connection messages
''' """
def __init__(self, code): def __init__(self, code):
"""
@param code: MessageType
"""
CompositeType.__init__(self) CompositeType.__init__(self)
self.len = UInt8(lambda:sizeof(self) - 1) self.len = UInt8(lambda:sizeof(self) - 1)
self.code = UInt8(code.value, constant = True) self.code = UInt8(code.value, constant = True)
@@ -65,9 +91,9 @@ class TPDUConnectMessage(CompositeType):
self.protocolNeg = Negotiation(optional = True) self.protocolNeg = Negotiation(optional = True)
class TPDUDataHeader(CompositeType): class TPDUDataHeader(CompositeType):
''' """
header send when tpdu exchange application data header send when tpdu exchange application data
''' """
def __init__(self): def __init__(self):
CompositeType.__init__(self) CompositeType.__init__(self)
self.header = UInt8(2, constant = True) self.header = UInt8(2, constant = True)
@@ -75,12 +101,12 @@ class TPDUDataHeader(CompositeType):
self.separator = UInt8(0x80, constant = True) self.separator = UInt8(0x80, constant = True)
class Negotiation(CompositeType): class Negotiation(CompositeType):
''' """
negociation request message negociate request message
@see: request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx @see: request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx @see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx @see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
''' """
def __init__(self, optional = False): def __init__(self, optional = False):
CompositeType.__init__(self, optional = optional) CompositeType.__init__(self, optional = optional)
self.code = UInt8() self.code = UInt8()
@@ -91,16 +117,16 @@ class Negotiation(CompositeType):
self.failureCode = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_FAILURE) self.failureCode = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_FAILURE)
class TPDU(LayerAutomata): class TPDU(LayerAutomata):
''' """
TPDU layer management TPDU layer management
there is an connection automata there is an connection automata
''' """
def __init__(self, presentation): def __init__(self, mode, presentation):
''' """
Constructor @param mode: automata mode (client or server)
@param presentation: MCS layer @param presentation: upper layer, MCS layer in RDP case
''' """
LayerAutomata.__init__(self, presentation._mode, presentation) LayerAutomata.__init__(self, mode, presentation)
#default selectedProtocol is SSl because is the only supported #default selectedProtocol is SSl because is the only supported
#in this version of RDPY #in this version of RDPY
#client requested selectedProtocol #client requested selectedProtocol
@@ -108,25 +134,38 @@ class TPDU(LayerAutomata):
#server selected selectedProtocol #server selected selectedProtocol
self._selectedProtocol = Protocols.PROTOCOL_SSL self._selectedProtocol = Protocols.PROTOCOL_SSL
#Server mode informations for tls connexion
self._serverPrivateKeyFileName = None
self._serverCertificateFileName = None
def initTLSServerInfos(self, privateKeyFileName, certificateFileName):
"""
Init informations for ssl server connexion
@param privateKeyFileName: file contain server private key
@param certficiateFileName: file that contain publi key
"""
self._serverPrivateKeyFileName = privateKeyFileName
self._serverCertificateFileName = certificateFileName
def connect(self): def connect(self):
''' """
connection request connection request
for client send a connection request packet for client send a connection request packet
''' """
if self._mode == LayerMode.CLIENT: if self._mode == LayerMode.CLIENT:
self.sendConnectionRequest() self.sendConnectionRequest()
else: else:
self.setNextState(self.recvConnectionRequest) self.setNextState(self.recvConnectionRequest)
def recvConnectionConfirm(self, data): def recvConnectionConfirm(self, data):
''' """
recv connection confirm message receive connection confirm message
next state is recvData next state is recvData
call connect on presentation layer if all is good call connect on presentation layer if all is good
@param data: Stream that contain connection confirm @param data: Stream that contain connection confirm
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx @see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx @see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
''' """
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM) message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM)
data.readType(message) data.readType(message)
@@ -150,12 +189,12 @@ class TPDU(LayerAutomata):
LayerAutomata.connect(self) LayerAutomata.connect(self)
def recvConnectionRequest(self, data): def recvConnectionRequest(self, data):
''' """
read connection confirm packet read connection confirm packet
next state is send connection confirm next state is send connection confirm
@param data: stream @param data: Stream
@see : http://msdn.microsoft.com/en-us/library/cc240470.aspx @see : http://msdn.microsoft.com/en-us/library/cc240470.aspx
''' """
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST) message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST)
data.readType(message) data.readType(message)
@@ -177,21 +216,21 @@ class TPDU(LayerAutomata):
self.sendConnectionConfirm() self.sendConnectionConfirm()
def recvData(self, data): def recvData(self, data):
''' """
read data header from packet read data header from packet
and pass to presentation layer and pass to presentation layer
@param data: stream @param data: Stream
''' """
header = TPDUDataHeader() header = TPDUDataHeader()
data.readType(header) data.readType(header)
LayerAutomata.recv(self, data) LayerAutomata.recv(self, data)
def sendConnectionRequest(self): def sendConnectionRequest(self):
''' """
write connection request message write connection request message
next state is recvConnectionConfirm next state is recvConnectionConfirm
@see: http://msdn.microsoft.com/en-us/library/cc240500.aspx @see: http://msdn.microsoft.com/en-us/library/cc240500.aspx
''' """
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST) message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST)
message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ
message.protocolNeg.selectedProtocol = self._requestedProtocol message.protocolNeg.selectedProtocol = self._requestedProtocol
@@ -199,36 +238,53 @@ class TPDU(LayerAutomata):
self.setNextState(self.recvConnectionConfirm) self.setNextState(self.recvConnectionConfirm)
def sendConnectionConfirm(self): def sendConnectionConfirm(self):
''' """
write connection confirm message write connection confirm message
next state is recvData next state is recvData
@see : http://msdn.microsoft.com/en-us/library/cc240501.aspx @see : http://msdn.microsoft.com/en-us/library/cc240501.aspx
''' """
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM) message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM)
message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ
message.protocolNeg.selectedProtocol = self._selectedProtocol message.protocolNeg.selectedProtocol = self._selectedProtocol
self._transport.send(message) self._transport.send(message)
#_transport is TPKT and transport is TCP layer of twisted #_transport is TPKT and transport is TCP layer of twisted
self._transport.transport.startTLS(ServerTLSContext()) self._transport.transport.startTLS(ServerTLSContext(self._serverPrivateKeyFileName, self._serverCertificateFileName))
#connection is done send to presentation #connection is done send to presentation
LayerAutomata.connect(self) LayerAutomata.connect(self)
def send(self, message): def send(self, message):
''' """
write message packet for TPDU layer write message packet for TPDU layer
add TPDU header add TPDU header
''' @param message: network.Type message
"""
self._transport.send((TPDUDataHeader(), message)) self._transport.send((TPDUDataHeader(), message))
def createClient(presentation):
"""
Factory of TPDU layer in Client mode
@param presentation: presentation layer, in RDP mode is MCS layer
"""
return TPDU(LayerMode.CLIENT, presentation)
def createServer(presentation, privateKeyFileName, certificateFileName):
"""
Factory of TPDU layer in Server mode
@param privateKeyFileName: file contain server private key
@param certficiateFileName: file that contain publi key
"""
tpdu = TPDU(LayerMode.SERVER, presentation)
tpdu.initTLSServerInfos(privateKeyFileName, certificateFileName)
return tpdu
#open ssl needed #open ssl needed
from twisted.internet import ssl from twisted.internet import ssl
from OpenSSL import SSL from OpenSSL import SSL
class ClientTLSContext(ssl.ClientContextFactory): class ClientTLSContext(ssl.ClientContextFactory):
''' """
client context factory for open ssl client context factory for open ssl
''' """
def getContext(self): def getContext(self):
context = SSL.Context(SSL.TLSv1_METHOD) context = SSL.Context(SSL.TLSv1_METHOD)
context.set_options(0x00020000)#SSL_OP_NO_COMPRESSION context.set_options(0x00020000)#SSL_OP_NO_COMPRESSION
@@ -237,9 +293,10 @@ class ClientTLSContext(ssl.ClientContextFactory):
return context return context
class ServerTLSContext(ssl.DefaultOpenSSLContextFactory): class ServerTLSContext(ssl.DefaultOpenSSLContextFactory):
''' """
server context factory for open ssl server context factory for open ssl
''' @param privateKeyFileName: Name of a file containing a private key
def __init__(self, *args, **kw): @param certificateFileName: Name of a file containing a certificate
kw['sslmethod'] = SSL.TLSv1_METHOD """
ssl.DefaultOpenSSLContextFactory.__init__(self, *args, **kw) def __init__(self, privateKeyFileName, certificateFileName):
ssl.DefaultOpenSSLContextFactory.__init__(self, privateKeyFileName, certificateFileName, SSL.TLSv1_METHOD)

View File

@@ -1,22 +1,44 @@
''' #
@author: sylvain # Copyright (c) 2014 Sylvain Peyrefitte
''' #
# This file is part of rdpy.
#
# rdpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""
Transport packet layer implementation
Use to build correct size packet and handle slow path and fast path mode
"""
from rdpy.network.layer import RawLayer, LayerMode from rdpy.network.layer import RawLayer, LayerMode
from rdpy.network.type import UInt8, UInt16Be, sizeof from rdpy.network.type import UInt8, UInt16Be, sizeof
class TPKT(RawLayer): class TPKT(RawLayer):
''' """
TPKT layer in RDP protocol stack TPKT layer in RDP protocol stack
this layer only handle size of packet this layer only handle size of packet
and determine if is a fast path packet and determine if is a fast path packet
''' """
#first byte of classic tpkt header #first byte of classic tpkt header
TPKT_PACKET = UInt8(3) TPKT_PACKET = UInt8(3)
def __init__(self, presentation): def __init__(self, presentation):
''' """
Constructor Constructor
''' @param presentation: presentation layer, in RDP case is TPDU layer
"""
RawLayer.__init__(self, LayerMode.NONE, presentation) RawLayer.__init__(self, LayerMode.NONE, presentation)
#last packet version read from header #last packet version read from header
self._lastPacketVersion = UInt8() self._lastPacketVersion = UInt8()
@@ -24,10 +46,10 @@ class TPKT(RawLayer):
self._lastShortLength = UInt8() self._lastShortLength = UInt8()
def connect(self): def connect(self):
''' """
call when transport layer connection call when transport layer connection
is made (inherit from RawLayer) is made (inherit from RawLayer)
''' """
#header is on two bytes #header is on two bytes
self.expect(2, self.readHeader) self.expect(2, self.readHeader)
#no connection automata on this layer #no connection automata on this layer
@@ -35,9 +57,10 @@ class TPKT(RawLayer):
self._presentation.connect() self._presentation.connect()
def readHeader(self, data): def readHeader(self, data):
''' """
read header of TPKT packet read header of TPKT packet
''' @param data: Stream received from twisted layer
"""
#first read packet version #first read packet version
data.readType(self._lastPacketVersion) data.readType(self._lastPacketVersion)
#classic packet #classic packet
@@ -57,18 +80,20 @@ class TPKT(RawLayer):
def readExtendedHeader(self, data): def readExtendedHeader(self, data):
''' """
header may be on 4 bytes header may be on 4 bytes
''' @param data: Stream from twisted layer
"""
#next state is read data #next state is read data
size = UInt16Be() size = UInt16Be()
data.readType(size) data.readType(size)
self.expect(size.value - 4, self.readData) self.expect(size.value - 4, self.readData)
def readExtendedFastPathHeader(self, data): def readExtendedFastPathHeader(self, data):
''' """
fast ath header may be on 1 byte more fast path header may be on 1 byte more
''' @param data: Stream from twisted layer
"""
leftPart = UInt8() leftPart = UInt8()
data.readType(leftPart) data.readType(leftPart)
self._lastShortLength.value &= ~0x80 self._lastShortLength.value &= ~0x80
@@ -77,21 +102,24 @@ class TPKT(RawLayer):
self.expect(self._lastShortLength.value - 3, self.readFastPath) self.expect(self._lastShortLength.value - 3, self.readFastPath)
def readFastPath(self, data): def readFastPath(self, data):
''' """
fast path data fast path data
''' @param data: Stream from twisted layer
"""
pass pass
def readData(self, data): def readData(self, data):
''' """
read classic TPKT packet read classic TPKT packet, last state in tpkt automata
''' @param data: Stream with correct size
"""
#next state is pass to #next state is pass to
self._presentation.recv(data) self._presentation.recv(data)
self.expect(2, self.readHeader) self.expect(2, self.readHeader)
def send(self, message): def send(self, message):
''' """
send encapsuled data send encompassed data
''' @param message: network.Type message to send
"""
RawLayer.send(self, (TPKT.TPKT_PACKET, UInt8(0), UInt16Be(sizeof(message) + 4), message)) RawLayer.send(self, (TPKT.TPKT_PACKET, UInt8(0), UInt16Be(sizeof(message) + 4), message))