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-qt4reactor
##Must be implemented before first release
* CreedSSP
* Packet redirection
* License
* Most common orders
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], '../..'))
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__':
from twisted.internet import reactor
reactor.listenTCP(33389, rdp.Factory(LayerMode.SERVER))
reactor.listenTCP(33389, TestServerFactory())
reactor.run()

View File

@@ -47,7 +47,7 @@ class ClientFactory(protocol.Factory):
'''
pduLayer = pdu.PDU(LayerMode.CLIENT)
pduLayer.getController().addObserver(self.buildObserver())
return tpkt.TPKT(tpdu.TPDU(mcs.MCS(pduLayer)));
return tpkt.TPKT(tpdu.createClient(mcs.MCS(pduLayer)));
def buildObserver(self):
'''
@@ -55,6 +55,33 @@ class ClientFactory(protocol.Factory):
'''
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):
'''

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.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof
from rdpy.network.error import InvalidExpectedDataException
@@ -9,9 +32,9 @@ from rdpy.network.const import ConstAttributes, TypeAttributes
@ConstAttributes
@TypeAttributes(UInt8)
class MessageType(object):
'''
"""
message type
'''
"""
X224_TPDU_CONNECTION_REQUEST = 0xE0
X224_TPDU_CONNECTION_CONFIRM = 0xD0
X224_TPDU_DISCONNECT_REQUEST = 0x80
@@ -21,9 +44,9 @@ class MessageType(object):
@ConstAttributes
@TypeAttributes(UInt8)
class NegociationType(object):
'''
"""
negotiation header
'''
"""
TYPE_RDP_NEG_REQ = 0x01
TYPE_RDP_NEG_RSP = 0x02
TYPE_RDP_NEG_FAILURE = 0x03
@@ -31,9 +54,9 @@ class NegociationType(object):
@ConstAttributes
@TypeAttributes(UInt32Le)
class Protocols(object):
'''
"""
protocols available for TPDU layer
'''
"""
PROTOCOL_RDP = 0x00000000
PROTOCOL_SSL = 0x00000001
PROTOCOL_HYBRID = 0x00000002
@@ -42,9 +65,9 @@ class Protocols(object):
@ConstAttributes
@TypeAttributes(UInt32Le)
class NegotiationFailureCode(object):
'''
"""
protocol negotiation failure code
'''
"""
SSL_REQUIRED_BY_SERVER = 0x00000001
SSL_NOT_ALLOWED_BY_SERVER = 0x00000002
SSL_CERT_NOT_ON_SERVER = 0x00000003
@@ -53,10 +76,13 @@ class NegotiationFailureCode(object):
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
class TPDUConnectMessage(CompositeType):
'''
"""
header of TPDU connection messages
'''
"""
def __init__(self, code):
"""
@param code: MessageType
"""
CompositeType.__init__(self)
self.len = UInt8(lambda:sizeof(self) - 1)
self.code = UInt8(code.value, constant = True)
@@ -65,9 +91,9 @@ class TPDUConnectMessage(CompositeType):
self.protocolNeg = Negotiation(optional = True)
class TPDUDataHeader(CompositeType):
'''
"""
header send when tpdu exchange application data
'''
"""
def __init__(self):
CompositeType.__init__(self)
self.header = UInt8(2, constant = True)
@@ -75,12 +101,12 @@ class TPDUDataHeader(CompositeType):
self.separator = UInt8(0x80, constant = True)
class Negotiation(CompositeType):
'''
negociation request message
"""
negociate request message
@see: request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
'''
"""
def __init__(self, optional = False):
CompositeType.__init__(self, optional = optional)
self.code = UInt8()
@@ -91,16 +117,16 @@ class Negotiation(CompositeType):
self.failureCode = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_FAILURE)
class TPDU(LayerAutomata):
'''
"""
TPDU layer management
there is an connection automata
'''
def __init__(self, presentation):
'''
Constructor
@param presentation: MCS layer
'''
LayerAutomata.__init__(self, presentation._mode, presentation)
"""
def __init__(self, mode, presentation):
"""
@param mode: automata mode (client or server)
@param presentation: upper layer, MCS layer in RDP case
"""
LayerAutomata.__init__(self, mode, presentation)
#default selectedProtocol is SSl because is the only supported
#in this version of RDPY
#client requested selectedProtocol
@@ -108,25 +134,38 @@ class TPDU(LayerAutomata):
#server selected selectedProtocol
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):
'''
"""
connection request
for client send a connection request packet
'''
"""
if self._mode == LayerMode.CLIENT:
self.sendConnectionRequest()
else:
self.setNextState(self.recvConnectionRequest)
def recvConnectionConfirm(self, data):
'''
recv connection confirm message
"""
receive connection confirm message
next state is recvData
call connect on presentation layer if all is good
@param data: Stream that contain connection confirm
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
'''
"""
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM)
data.readType(message)
@@ -150,12 +189,12 @@ class TPDU(LayerAutomata):
LayerAutomata.connect(self)
def recvConnectionRequest(self, data):
'''
"""
read connection confirm packet
next state is send connection confirm
@param data: stream
@param data: Stream
@see : http://msdn.microsoft.com/en-us/library/cc240470.aspx
'''
"""
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST)
data.readType(message)
@@ -177,21 +216,21 @@ class TPDU(LayerAutomata):
self.sendConnectionConfirm()
def recvData(self, data):
'''
"""
read data header from packet
and pass to presentation layer
@param data: stream
'''
@param data: Stream
"""
header = TPDUDataHeader()
data.readType(header)
LayerAutomata.recv(self, data)
def sendConnectionRequest(self):
'''
"""
write connection request message
next state is recvConnectionConfirm
@see: http://msdn.microsoft.com/en-us/library/cc240500.aspx
'''
"""
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_REQUEST)
message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ
message.protocolNeg.selectedProtocol = self._requestedProtocol
@@ -199,36 +238,53 @@ class TPDU(LayerAutomata):
self.setNextState(self.recvConnectionConfirm)
def sendConnectionConfirm(self):
'''
"""
write connection confirm message
next state is recvData
@see : http://msdn.microsoft.com/en-us/library/cc240501.aspx
'''
"""
message = TPDUConnectMessage(MessageType.X224_TPDU_CONNECTION_CONFIRM)
message.protocolNeg.code = NegociationType.TYPE_RDP_NEG_REQ
message.protocolNeg.selectedProtocol = self._selectedProtocol
self._transport.send(message)
#_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
LayerAutomata.connect(self)
def send(self, message):
'''
"""
write message packet for TPDU layer
add TPDU header
'''
@param message: network.Type 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
from twisted.internet import ssl
from OpenSSL import SSL
class ClientTLSContext(ssl.ClientContextFactory):
'''
"""
client context factory for open ssl
'''
"""
def getContext(self):
context = SSL.Context(SSL.TLSv1_METHOD)
context.set_options(0x00020000)#SSL_OP_NO_COMPRESSION
@@ -237,9 +293,10 @@ class ClientTLSContext(ssl.ClientContextFactory):
return context
class ServerTLSContext(ssl.DefaultOpenSSLContextFactory):
'''
"""
server context factory for open ssl
'''
def __init__(self, *args, **kw):
kw['sslmethod'] = SSL.TLSv1_METHOD
ssl.DefaultOpenSSLContextFactory.__init__(self, *args, **kw)
@param privateKeyFileName: Name of a file containing a private key
@param certificateFileName: Name of a file containing a certificate
"""
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.type import UInt8, UInt16Be, sizeof
class TPKT(RawLayer):
'''
"""
TPKT layer in RDP protocol stack
this layer only handle size of packet
and determine if is a fast path packet
'''
"""
#first byte of classic tpkt header
TPKT_PACKET = UInt8(3)
def __init__(self, presentation):
'''
"""
Constructor
'''
@param presentation: presentation layer, in RDP case is TPDU layer
"""
RawLayer.__init__(self, LayerMode.NONE, presentation)
#last packet version read from header
self._lastPacketVersion = UInt8()
@@ -24,10 +46,10 @@ class TPKT(RawLayer):
self._lastShortLength = UInt8()
def connect(self):
'''
"""
call when transport layer connection
is made (inherit from RawLayer)
'''
"""
#header is on two bytes
self.expect(2, self.readHeader)
#no connection automata on this layer
@@ -35,9 +57,10 @@ class TPKT(RawLayer):
self._presentation.connect()
def readHeader(self, data):
'''
"""
read header of TPKT packet
'''
@param data: Stream received from twisted layer
"""
#first read packet version
data.readType(self._lastPacketVersion)
#classic packet
@@ -57,18 +80,20 @@ class TPKT(RawLayer):
def readExtendedHeader(self, data):
'''
"""
header may be on 4 bytes
'''
@param data: Stream from twisted layer
"""
#next state is read data
size = UInt16Be()
data.readType(size)
self.expect(size.value - 4, self.readData)
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()
data.readType(leftPart)
self._lastShortLength.value &= ~0x80
@@ -77,21 +102,24 @@ class TPKT(RawLayer):
self.expect(self._lastShortLength.value - 3, self.readFastPath)
def readFastPath(self, data):
'''
"""
fast path data
'''
@param data: Stream from twisted layer
"""
pass
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
self._presentation.recv(data)
self.expect(2, self.readHeader)
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))