diff --git a/.travis.yml b/.travis.yml index 3dda419..95b7787 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,5 +16,5 @@ install: - scons -C rdpy/core install script: - - python -m unittest discover -s test + - python -m unittest discover -s test -v diff --git a/rdpy/protocol/rdp/per.py b/rdpy/protocol/rdp/per.py index e9f843d..b92527d 100644 --- a/rdpy/protocol/rdp/per.py +++ b/rdpy/protocol/rdp/per.py @@ -1,16 +1,35 @@ -''' -@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 . +# + +""" +Per encoded function +""" from rdpy.network.type import UInt8, UInt16Be, UInt32Be, String from rdpy.base.error import InvalidValue, InvalidExpectedDataException def readLength(s): - ''' - read length use in per specification + """ + @summary: read length use in per specification @param s: Stream @return: int python - ''' + """ byte = UInt8() s.readType(byte) size = 0 @@ -24,95 +43,95 @@ def readLength(s): return size def writeLength(value): - ''' - write length as expected in per specification + """ + @summary: write length as expected in per specification @param value: int or long python @return: UInt8, UInt16Be depend on value - ''' + """ if value > 0x7f: return UInt16Be(value | 0x8000) else: return UInt8(value) def readChoice(s): - ''' - read per choice format + """ + @summary: read per choice format @param s: Stream @return: int that represent choice - ''' + """ choice = UInt8() s.readType(choice) return choice.value def writeChoice(choice): - ''' - read per choice structure + """ + @summary: read per choice structure @param choice: int choice value @return: UInt8 - ''' + """ return UInt8(choice) def readSelection(s): - ''' - read per selection format + """ + @summary: read per selection format @param s: Stream @return: int that represent selection - ''' + """ choice = UInt8() s.readType(choice) return choice.value def writeSelection(selection): - ''' - read per selection structure + """ + @summary: read per selection structure @param selection: int selection value @return: UInt8 - ''' + """ return UInt8(selection) def readNumberOfSet(s): - ''' - read per numberOfSet format + """ + @summary: read per numberOfSet format @param s: Stream @return: int that represent numberOfSet - ''' + """ choice = UInt8() s.readType(choice) return choice.value def writeNumberOfSet(numberOfSet): - ''' - read per numberOfSet structure + """ + @summary: read per numberOfSet structure @param numberOfSet: int numberOfSet value @return: UInt8 - ''' + """ return UInt8(numberOfSet) def readEnumerates(s): - ''' - read per enumerate format + """ + @summary: read per enumerate format @param s: Stream @return: int that represent enumerate - ''' + """ choice = UInt8() s.readType(choice) return choice.value def writeEnumerates(enumer): - ''' - read per enumerate structure + """ + @summary: read per enumerate structure @param enumer: int enumerate value @return: UInt8 - ''' + """ return UInt8(enumer) def readInteger(s): - ''' - read interger per format from stream + """ + @summary: read interger per format from stream @param s: Stream @return: python int or long @raise InvalidValue: if size of integer is not correct - ''' + """ result = None size = readLength(s) if size == 1: @@ -127,11 +146,11 @@ def readInteger(s): return result.value def writeInteger(value): - ''' - write python long or int into per integer format + """ + @summary: write python long or int into per integer format @param value: int or long python value @return: UInt8, UInt16Be or UInt32Be - ''' + """ if value <= 0xff: return (writeLength(1), UInt8(value)) elif value < 0xffff: @@ -140,32 +159,32 @@ def writeInteger(value): return (writeLength(4), UInt32Be(value)) def readInteger16(s, minimum = 0): - ''' - read UInt16Be from stream s and add minimum + """ + @summary: read UInt16Be from stream s and add minimum @param s: Stream @param minimum: minimum added to real value @return: int or long python value - ''' + """ result = UInt16Be() s.readType(result) return result.value + minimum def writeInteger16(value, minimum = 0): - ''' - write UInt16Be minus minimum + """ + @summary: write UInt16Be minus minimum @param value: value to write @param minimum: value subtracted to real value @return: UInt16Be - ''' + """ return UInt16Be(value - minimum) def readObjectIdentifier(s, oid): - ''' - read object identifier + """ + @summary: read object identifier @param oid: must be a tuple of 6 elements @param s: Stream @return: true if oid is same as in stream - ''' + """ size = readLength(s) if size != 5: raise InvalidValue("size of stream oid is wrong %d != 5"%size) @@ -188,7 +207,7 @@ def readObjectIdentifier(s, oid): def writeObjectIdentifier(oid): """ - Create tuple of 6 UInt8 with oid values + @summary: Create tuple of 6 UInt8 with oid values @param oid: tuple of 6 int @return: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) """ @@ -196,7 +215,7 @@ def writeObjectIdentifier(oid): def readNumericString(s, minValue): """ - Read numeric string + @summary: Read numeric string @param s: Stream @param minValue: offset """ @@ -205,12 +224,12 @@ def readNumericString(s, minValue): s.read(length) def writeNumericString(nStr, minValue): - ''' - write string in per format + """ + @summary: write string in per format @param str: python string to write @param min: min value @return: String type that contain str encoded in per format - ''' + """ length = len(nStr) mlength = minValue if length - minValue >= 0: @@ -232,29 +251,29 @@ def writeNumericString(nStr, minValue): return (writeLength(mlength), tuple(result)) def readPadding(s, length): - ''' - read length byte in stream + """ + @summary: read length byte in stream @param s: Stream @param length: length of passing in bytes - ''' + """ s.read(length) def writePadding(length): - ''' - create string with null char * length + """ + @summary: create string with null char * length @param length: length of padding @return: String with \x00 * length - ''' + """ return String("\x00"*length) def readOctetStream(s, octetStream, minValue = 0): - ''' - read string as octet stream and compare with octetStream + """ + @summary: read string as octet stream and compare with octetStream @param octetStream: compare stream @param s: Stream @param minValue: min value @return: if stream read from s is equal to octetStream - ''' + """ size = readLength(s) + minValue if size != len(octetStream): raise InvalidValue("incompatible size %d != %d"(len(octetStream), size)) @@ -267,12 +286,12 @@ def readOctetStream(s, octetStream, minValue = 0): return True def writeOctetStream(oStr, minValue = 0): - ''' - write string as octet stream with per header + """ + @summary: write string as octet stream with per header @param oStr: octet stream to convert @param minValue: min length value @return: per header follow by tuple of UInt8 - ''' + """ length = len(oStr) mlength = minValue diff --git a/test/test_protocol_rdp_ber.py b/test/test_protocol_rdp_ber.py new file mode 100644 index 0000000..f50bac9 --- /dev/null +++ b/test/test_protocol_rdp_ber.py @@ -0,0 +1,80 @@ +# +# 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 . +# + +""" +unit test for rdpy.protocol.rdp.ber module +""" + +import os, sys +# Change path so we find rdpy +sys.path.insert(1, os.path.join(sys.path[0], '..')) + +import unittest +import rdpy.protocol.rdp.ber as ber +import rdpy.network.type as type +import rdpy.base.error as error + +class BERCase(unittest.TestCase): + """ + @summary: test case for ber layer (RDP) + """ + + def test_ber_readLength(self): + """ + @summary: test readLength function in ber module + """ + s1 = type.Stream() + s1.writeType(type.UInt8(0x1a)) + s1.pos = 0 + + l1 = ber.readLength(s1) + + self.assertTrue(l1 == 0x1a, "readLength fail in small format") + + s2 = type.Stream() + s2.writeType((type.UInt8(0x81),type.UInt8(0xab))) + s2.pos = 0 + + l2 = ber.readLength(s2) + + self.assertTrue(l2 == 0xab, "readLength fail in big format of size 1") + + s3 = type.Stream() + s3.writeType((type.UInt8(0x82),type.UInt16Be(0xabab))) + s3.pos = 0 + + l3 = ber.readLength(s3) + + self.assertTrue(l3 == 0xabab, "readLength fail in big format of size 2") + + def test_ber_writeLength(self): + """ + @summary: test writeLength function in ber module + """ + l1 = ber.writeLength(0x1a) + self.assertTrue(isinstance(l1, type.UInt8), "bad write length type in small case") + + l2 = ber.writeLength(0x7f) + self.assertTrue(isinstance(l2, type.UInt8), "bad write length type in small case limit") + + (h3, l3) = ber.writeLength(0x80) + self.assertTrue(h3.value == 0x82 and isinstance(l3, type.UInt16Be), "bad write length type in large case limit") + + (h4, l4) = ber.writeLength(0xab) + self.assertTrue(h4.value == 0x82 and isinstance(l4, type.UInt16Be), "bad write length type in large case") \ No newline at end of file diff --git a/test/test_protocol_rdp_per.py b/test/test_protocol_rdp_per.py new file mode 100644 index 0000000..e1e65c4 --- /dev/null +++ b/test/test_protocol_rdp_per.py @@ -0,0 +1,107 @@ +# +# 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 . +# + +""" +unit test for rdpy.protocol.rdp.per module +""" + +import os, sys +# Change path so we find rdpy +sys.path.insert(1, os.path.join(sys.path[0], '..')) + +import unittest +import rdpy.protocol.rdp.per as per +import rdpy.network.type as type +import rdpy.base.error as error + +class PERCase(unittest.TestCase): + """ + @summary: test case for per layer (RDP) + """ + + def test_per_readLength(self): + """ + @summary: test readLength function in per module + """ + s1 = type.Stream() + s1.writeType(type.UInt8(0x1a)) + s1.pos = 0 + + l1 = per.readLength(s1) + + self.assertTrue(l1 == 0x1a, "readLength fail in small format") + + s2 = type.Stream() + s2.writeType(type.UInt16Be(0x1abc | 0x8000)) + s2.pos = 0 + + l2 = per.readLength(s2) + + self.assertTrue(l2 == 0x1abc, "readLength fail in big format") + + def test_per_writeLength(self): + """ + @summary: test writeLength function in per module + """ + l1 = per.writeLength(0x1a) + self.assertTrue(isinstance(l1, type.UInt8), "bad write length type in small case") + + l2 = per.writeLength(0x7f) + self.assertTrue(isinstance(l2, type.UInt8), "bad write length type in small case limit") + + l3 = per.writeLength(0x80) + self.assertTrue(isinstance(l3, type.UInt16Be), "bad write length type in large case limit") + + l4 = per.writeLength(0xab) + self.assertTrue(isinstance(l4, type.UInt16Be), "bad write length type in large case") + + def test_per_readInteger(self): + """ + @summary: test readInteger function in per module + """ + for t in [type.UInt8, type.UInt16Be, type.UInt32Be]: + v = t(3) + s = type.Stream() + s.writeType((per.writeLength(type.sizeof(v)), v)) + s.pos = 0 + + self.assertTrue(per.readInteger(s) == 3, "invalid readLength for type %s"%t) + + #error case + for l in [0, 3, 5]: + s = type.Stream() + s.writeType(per.writeLength(l)) + s.pos = 0 + + self.assertRaises(error.InvalidValue, per.readInteger, s) + + def test_per_writeInteger(self): + """ + @summary: test writeInteger function in per module + """ + (s, i) = per.writeInteger(0xaf) + self.assertTrue(s.value == 1 and isinstance(i, type.UInt8), "invalid writeLength output in case of size 1") + + (s, i) = per.writeInteger(0xaff) + self.assertTrue(s.value == 2 and isinstance(i, type.UInt16Be), "invalid writeLength output in case of size 2") + + (s, i) = per.writeInteger(0xaffff) + self.assertTrue(s.value == 4 and isinstance(i, type.UInt32Be), "invalid writeLength output in case of size 4") + + \ No newline at end of file