From c7ee05593feeddedba66749632ad80999b6c3778 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 23 Dec 2013 11:55:56 -0800 Subject: [PATCH] Add PGPPacket.copy and pull out PGPPacket._serialize_body Use these with _serialize_signature_packet_target to compute key fingerprints in _parse_generic_public_key_packet. I'd previously been hashing over the whole (sub)key packet, but RFC 4880 says the hash should just be over the public-key part of the packet, even for secret keys [1]: A V4 fingerprint is the 160-bit SHA-1 hash of the octet 0x99, followed by the two-octet packet length, followed by the entire Public-Key packet starting with the version field. I've added the fingerprint_target stuff so I don't hash the secret-key-specific fields. [1]: http://tools.ietf.org/search/rfc4880#section-12.2 --- gpg-migrate.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/gpg-migrate.py b/gpg-migrate.py index 0a7d116..3a3c7e9 100755 --- a/gpg-migrate.py +++ b/gpg-migrate.py @@ -309,6 +309,11 @@ class PGPPacket (dict): """ return [k for k,v in dict.items() if v == value][0] + def copy(self): + packet = PGPPacket(key=self.key) + packet.update(self) + return packet + def __str__(self): method_name = '_str_{}'.format(self._clean_type()) method = getattr(self, method_name, None) @@ -566,9 +571,12 @@ class PGPPacket (dict): 'algorithm-specific key fields for {}'.format( self['public-key-algorithm'])) fingerprint = _hashlib.sha1() - fingerprint.update(b'\x99') - fingerprint.update(_struct.pack('>H', len(data))) - fingerprint.update(data) + fingerprint_target = self + if self['type'] != 'public-key packet': + fingerprint_target = self.copy() + fingerprint_target['type'] = 'public-key packet' + fingerprint.update( + self._serialize_signature_packet_target(target=fingerprint_target)) self['fingerprint'] = fingerprint.hexdigest() return offset @@ -801,12 +809,9 @@ class PGPPacket (dict): self['user'] = str(data, 'utf-8') def to_bytes(self): - method_name = '_serialize_{}'.format(self._clean_type()) - method = getattr(self, method_name, None) - if not method: - raise NotImplementedError( - 'cannot serialize packet type {!r}'.format(self['type'])) - body = method() + body = self._serialize_body() + if body is None: + raise ValueError(method) self['length'] = len(body) return b''.join([ self._serialize_header(), @@ -832,6 +837,14 @@ class PGPPacket (dict): length_data, ]) + def _serialize_body(self): + method_name = '_serialize_{}'.format(self._clean_type()) + method = getattr(self, method_name, None) + if not method: + raise NotImplementedError( + 'cannot serialize packet type {!r}'.format(self['type'])) + return method() + @staticmethod def _serialize_multiprecision_integer(integer): r"""Serialize RFC 4880's multipricision integers -- 2.26.2