Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for parsing smartcard/HSM related fields (mode 1002, gnu-divert-to-card S2K) #12

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions pgpdump/packet.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from datetime import datetime, timedelta
import hashlib
import re
import binascii

from .utils import (PgpdumpException, get_int2, get_int4, get_mpi,
get_key_id, get_int_bytes)
Expand Down Expand Up @@ -334,6 +335,7 @@ def __init__(self, *args, **kwargs):
self.group_order = None
self.group_gen = None
self.key_value = None
self.serial = None
super(PublicKeyPacket, self).__init__(*args, **kwargs)

def parse(self):
Expand Down Expand Up @@ -375,22 +377,25 @@ def parse(self):
self.pubkey_version)
self.fingerprint = md5.hexdigest().upper().encode('ascii')
elif self.pubkey_version == 4:
self.raw_pub_algorithm = self.data[offset+4]
# This trickery with afterkey_offset is to avoid confusion from
# special parameters that are present e.g. for card readers.
# Fingerprint/key_id would be screwed if the special params were
# used in hash computation.
afterkey_offset = self.parse_key_material(offset+5)

sha1 = hashlib.sha1()
seed_bytes = (0x99, (self.length >> 8) & 0xff, self.length & 0xff)
seed_bytes = (0x99, (afterkey_offset >> 8) & 0xff, afterkey_offset & 0xff)
sha1.update(bytearray(seed_bytes))
sha1.update(self.data)
sha1.update(self.data[:afterkey_offset])
self.fingerprint = sha1.hexdigest().upper().encode('ascii')
self.key_id = self.fingerprint[24:]

self.raw_creation_time = get_int4(self.data, offset)
self.creation_time = datetime.utcfromtimestamp(
self.raw_creation_time)
offset += 4

self.raw_pub_algorithm = self.data[offset]
offset += 1

offset = self.parse_key_material(offset)
offset = afterkey_offset
else:
raise PgpdumpException("Unsupported public key packet, version %d" %
self.pubkey_version)
Expand Down Expand Up @@ -543,6 +548,26 @@ def parse(self):
offset += 1
if mode == 1001:
has_iv = False
elif mode == 1002:
# gnu-divert-to-card S2K - divert to HSM or card reader
serial_len = self.data[offset]

# This is not a real IV, even though gnupg stores it in
# IV structure internally
has_iv = False

# This guessing of hash length is ugly, but it's taken from
# gnupg 2.0.19's g10/parse-packet.c line 1945 -
# self.lookup_sym_algorithm_iv may not work in this case.
if serial_len > 16:
serial_len = 16
offset += 1
s2k_length += 1

# Keys tied to tokens and smart cards have token serial ID
# stored here.
serial_bin = self.data[offset:offset + serial_len]
self.serial = binascii.hexlify(serial_bin).upper()
else:
# TODO implement other modes?
raise PgpdumpException(
Expand Down