We need to know what we're signing. From RFC 4880 [1]:
The concatenation of the data being signed and the signature data
from the version number through the hashed subpacket data
(inclusive) is hashed. The resulting hash value is what is signed.
It's not always clear what the target bytes should be. RFC 4880 is
clear for some types, and ambiguous for others. For example, it's
clear that a standalone signature has no target [2]:
0x02: Standalone signature.
This signature is a signature of only its own subpacket contents.
It is calculated identically to a signature over a zero-length
binary document.
It is less clear how to serialize the targets for a
user-id-and-public-key signature [2]:
0x10: Generic certification of a User ID and Public-Key packet.
The issuer of this certification does not make any particular
assertion as to how well the certifier has checked that the owner
of the key is in fact the person described by the User ID.
There is a bit more guidance later on, showing that the key packet
should indeed come before the user id packet [3]:
When a signature is made over a key, the hash data starts with the
octet 0x99, followed by a two-octet length of the key, and then body
of the key packet. (Note that this is an old-style packet header
for a key packet with two-octet length.) A subkey binding signature
(type 0x18) or primary key binding signature (type 0x19) then hashes
the subkey using the same format as the main key (also using 0x99 as
the first octet). Key revocation signatures (types 0x20 and 0x28)
hash only the key being revoked.
A certification signature (type 0x10 through 0x13) hashes the User
ID being bound to the key into the hash context after the above
data. A V3 certification hashes the contents of the User ID or
attribute packet packet, without any header. A V4 certification
hashes the constant 0xB4 for User ID certifications or the constant
0xD1 for User Attribute certifications, followed by a four-octet
number giving the length of the User ID or User Attribute data, and
then the User ID or User Attribute data.
...
V4 signatures also hash in a final trailer of six octets: the
version of the Signature packet, i.e., 0x04; 0xFF; and a four-octet,
big-endian number that is the length of the hashed data from the
Signature packet (note that this number does not include these final
six octets).
After all this has been hashed in a single hash context, the
resulting hash field is used in the signature algorithm and placed
at the end of the Signature packet.
[1]: http://tools.ietf.org/search/rfc4880#section-5.2.3
[2]: http://tools.ietf.org/search/rfc4880#section-5.2.1
[3]: http://tools.ietf.org/search/rfc4880#section-5.2.4
self['signed-hash-word'] = data[offset: offset + 2]
offset += 2
self['signature'] = data[offset:]
+ if self['signature-type'] == 'standalone':
+ self['target'] = None
+ elif self['signature-type'].endswith(' user id and public-key packet'):
+ self['target'] = [
+ [p for p in self.key.public_packets if p['type'] == 'public-key packet'][-1],
+ [p for p in self.key.public_packets if p['type'] == 'user id packet'][-1],
+ ]
+ else:
+ raise NotImplementedError(
+ 'target for {}'.format(self['signature-type']))
def _parse_signature_creation_time_signature_subpacket(
self, data, subpacket):