Add PGPPacket._old_format_packet_lengths
authorW. Trevor King <wking@tremily.us>
Thu, 19 Dec 2013 04:05:25 +0000 (20:05 -0800)
committerW. Trevor King <wking@tremily.us>
Thu, 19 Dec 2013 04:39:58 +0000 (20:39 -0800)
From RFC 4880 [1]:

   The meaning of the length-type in old format packets is:

   0 - The packet has a one-octet length.  The header is 2 octets long.

   1 - The packet has a two-octet length.  The header is 3 octets long.

   2 - The packet has a four-octet length.  The header is 5 octets long.

   3 - The packet is of indeterminate length.  The header is 1 octet
       long, and the implementation must determine how long the packet
       is.  If the packet is in a file, this means that the packet
       extends until the end of the file.  In general, an implementation
       SHOULD NOT use indeterminate-length packets except where the end
       of the data will be clear from the context, and even then it is
       better to use a definite length, or a new format header.  The new
       format headers described below have a mechanism for precisely
       encoding data of indeterminate length.

The struct format characters are [2]:

  Format   C Type           Python type   Standard size   Notes
  B        unsigned char    integer       1               (3)
  H        unsigned short   integer       2               (3)
  I        unsigned int     integer       4               (3)

  3. When attempting to pack a non-integer using any of the integer
     conversion codes, if the non-integer has a __index__() method
     then that method is called to convert the argument to an integer
     before packing.

     Changed in version 3.2: Use of the __index__() method for
     non-integers is new in 3.2.

[1]: http://tools.ietf.org/search/rfc4880#section-4.2.1
[2]: http://docs.python.org/3/library/struct.html#format-characters

gpg-migrate.py

index 1eb09be90fabd506622a8743f843447e84342ed7..b836926d70ebbed403f710e8ecdc36dacdefc202 100755 (executable)
@@ -18,6 +18,13 @@ def _get_stdout(args, stdin=None):
 
 class PGPPacket (dict):
     # http://tools.ietf.org/search/rfc4880
+    _old_format_packet_length_type = {  # type: (bytes, struct type)
+        0: (1, 'B'),  # 1-byte unsigned integer
+        1: (2, 'H'),  # 2-byte unsigned integer
+        2: (4, 'I'),  # 4-byte unsigned integer
+        3: (None, None),
+        }
+
     def from_bytes(self, data):
         packet_tag = data[0]
         always_one = packet_tag & 1 << 7
@@ -26,9 +33,15 @@ class PGPPacket (dict):
         self['new-format'] = packet_tag & 1 << 6
         if self['new-format']:
             self['packet-tag'] = packet_tag & 0b111111
+            raise NotImplementedError('new-format packet length')
         else:
             self['packet-tag'] = packet_tag >> 2 & 0b1111
             self['length-type'] = packet_tag & 0b11
+            length_bytes, length_type = self._old_format_packet_length_type[
+                self['length-type']]
+            if not length_bytes:
+                raise NotImplementedError(
+                    'old-format packet of indeterminate length')
 
     def to_bytes(self):
         pass