From 00d9217f1923a9e7fa8fca201393ff69e32a0105 Mon Sep 17 00:00:00 2001 From: J08nY Date: Fri, 4 Aug 2017 17:14:17 +0200 Subject: [PATCH] Parse partial length headers correctly. --- pgpy/types.py | 47 ++++++++++++++++++++++++---------------- tests/test_02_packets.py | 13 +++++------ 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/pgpy/types.py b/pgpy/types.py index eb5b6131..8a6f8aef 100644 --- a/pgpy/types.py +++ b/pgpy/types.py @@ -367,30 +367,39 @@ def length_int(self, val): @length.register(bytearray) def length_bin(self, val): def _new_len(b): - fo = b[0] + def _parse_len(a, offset=0): + # returns (the parsed length, size of length field, whether the length was of partial type) + fo = a[offset] - if 192 > fo: - self._len = self.bytes_to_int(b[:1]) - del b[:1] + if 192 > fo: + return (self.bytes_to_int(a[offset:offset + 1]), 1, False) - elif 224 > fo: # >= 192 is implied - dlen = self.bytes_to_int(b[:2]) - self._len = ((dlen - (192 << 8)) & 0xFF00) + ((dlen & 0xFF) + 192) - del b[:2] + elif 224 > fo: # >= 192 is implied + dlen = self.bytes_to_int(b[offset:offset + 2]) + return (((dlen - (192 << 8)) & 0xFF00) + ((dlen & 0xFF) + 192), 2, False) - elif 255 > fo: # pragma: no cover - # not testable until partial body lengths actually work - # >= 224 is implied - # this is a partial-length header - self._partial = True - self._len = 1 << (fo & 0x1f) + elif 255 > fo: # >= 224 is implied + # this is a partial-length header + return (1 << (fo & 0x1f), 1, True) - elif 255 == fo: - self._len = self.bytes_to_int(b[1:5]) - del b[:5] + elif 255 == fo: + return (self.bytes_to_int(b[offset + 1:offset + 5]), 5, False) - else: # pragma: no cover - raise ValueError("Malformed length: 0x{:02x}".format(fo)) + else: # pragma: no cover + raise ValueError("Malformed length: 0x{:02x}".format(fo)) + + part_len, size, partial = _parse_len(b) + del b[:size] + + if partial: + total = part_len + while partial: + part_len, size, partial = _parse_len(b, total) + del b[total:total+size] + total += part_len + self._len = total + else: + self._len = part_len def _old_len(b): if self.llen > 0: diff --git a/tests/test_02_packets.py b/tests/test_02_packets.py index bdf9ce56..0e31d641 100644 --- a/tests/test_02_packets.py +++ b/tests/test_02_packets.py @@ -40,16 +40,12 @@ def binload(f): return buf -skip_files = {'tests/testdata/packets/{:s}'.format(pkt) for pkt in ['11.partial.literal']} pktfiles = sorted(glob.glob('tests/testdata/packets/[0-9]*')) class TestPacket(object): @pytest.mark.parametrize('packet', pktfiles, ids=[os.path.basename(f) for f in pktfiles]) def test_load(self, packet): - if packet in skip_files: - pytest.skip("not implemented yet") - b = binload(packet) + _trailer _b = b[:] p = Packet(_b) @@ -59,11 +55,12 @@ def test_load(self, packet): # length is computed correctly assert p.header.length + len(p.header) == len(p) - assert len(p) == len(b) - len(_trailer) - assert len(p.__bytes__()) == len(b) - len(_trailer) + if packet not in ('tests/testdata/packets/11.partial.literal',): + assert len(p) == len(b) - len(_trailer) + assert len(p.__bytes__()) == len(b) - len(_trailer) - # __bytes__ output is correct - assert p.__bytes__() == b[:-len(_trailer)] + # __bytes__ output is correct + assert p.__bytes__() == b[:-len(_trailer)] # instantiated class is what we expected if hasattr(p.header, 'version') and (p.header.tag, p.header.version) in _pclasses: