wiktor-k / pysequoia

OpenPGP in Python using Sequoia PGP
https://pypi.org/project/pysequoia/
Apache License 2.0
9 stars 2 forks source link

RFE: support parsing signature bytes #27

Closed ktdreyer closed 4 months ago

ktdreyer commented 4 months ago

I have some GPG signature bytes from an RPM header. I can read the signature bytes with PGPy, but I don't think pysequoia exposes any method to read them. I'm interested in switching to pysequoia, and I wondered how difficult it would be to allow parsing a signature from bytes. (I'm mainly looking for the signer's key ID.)

import os
import tempfile
import rpm

# https://dl.fedoraproject.org/pub/fedora/linux/releases/39/Everything/x86_64/os/Packages/b/bash-devel-5.2.15-5.fc39.x86_64.rpm
filename = 'bash-devel-5.2.15-5.fc39.x86_64.rpm'

# Read RPM header values (bytes)
with tempfile.NamedTemporaryFile(prefix='rpmdb_') as temp:
    rpm.addMacro("_dbpath", temp.name)
    ts = rpm.TransactionSet()
    # We're operating on RPMs without rpmdb-trusted signatures:
    ts.setVSFlags((rpm._RPMVSF_NOSIGNATURES | rpm._RPMVSF_NODIGESTS))
    fd = os.open(filename, os.O_RDONLY)
    hdr = ts.hdrFromFdno(fd)
    os.close(fd)

# This is the RPM signature header (bytes):
signature_bytes = hdr[rpm.RPMTAG_RSAHEADER]
# b"\x89\x023\x04\x00\x01\x08\x00\x1d\x16!\x04\xe8\xf29\x96\xf22\x18d\x0c\xb4L\xbeu\xcfZ\xc4\x18\xb8\xe7L\x05\x02d\xb8'\xe9\x00\n\t\x10u\xcfZ\xc4\x18\xb8\xe7L\x1f\x9e\x10\x00\x86\xe5\x195\xcd\xcb\xa9n\x83\xfdv\xa2A\x1bU=\xbf\xda\x8d5\x9b\x8f\xde\xfb\xd5.\x8a\xef\xa5p\x88\x05\xb8j\x10\xcf\xb9oo\x8a\xae\xaas\xfd\xe4M\x11\x93\xbb\x8d\xf8\xdfu\xf7\xa6\x17\xca\xc8\xa6n;RUWz\xd2\x1f\xef\xb1\x9aJ\xff%\x80\x94\xe4\xb51\x91LE\x93\xc8\xe3N\x86\xd6\xa8S\xe9\xf7\xe3\xabWz\x82n\xd1\xf7\xae\xf6\xb1\x1f\x90\xe3\xa0bBh9\xa4\xa8V_\x8f\xfe\xe8i\xc30\x1b\xc8m\x00\x18\xab\x10zz\x874\xccD\xa9X\tX\x9b\x1d9Xn\xf0\xb0\x84\xd8\x83\x98\xe9*\x9d\xb2:\xec\xbb\x1c\x82\xd9\xf4{\x94\xd9C\x08\xe1\xbaA\xe8\xd7\x00%\x8a\xb2X\xbe!\x80\xe3\xcc`\xaa%`+\x8e\xcby\ni\x10/E\xd9\xedR\xc9\xf2\x8a\xfa\x93\xb6\x90\xd0L|\x96\xeb\xcf\x19\xd9\x05\x81\xe7\xd1\x1bBIh\xf8\xc9\xf8\r /\x9a\xd9\x00T\xa4\x90~m>\x16c\xd2\xc2\xa55D\x81\xb5\x99\x85\x1e\xd6\xd2T \xbc\xb9+\xf8n>\x15\xec\xf6\xfej\xf0\xe2\xdd@\xc1\xdc\xe4\x1b&\\\x87#31W\xa2D$V\r1\xdc$~Z\xce\x9cO,=\xf9F%G-&v\xfc0\xb8\x1f\x9e\xce]p\xdb\x88f\xd7\x91\xb5\xa4S\xd0.`\x1d\xfb\xe5m\x08P{7\x90\xfc\xde\x8c\xaa!:R\x1e9\x13\xb6[\xd7\xb3\xdb\xb1\xa8\xc8\xef\xfa\x08\x11\xb0+-\x1b_(\xdb\x02\xbf\x84\xb2rO\x9dj\xe2t\xf9,\x1d[\xb3\x92\xcak\xac6C\x00\xe0\xc6\xe5\xfe\xf5\xd9c~B\x08\x10O\xef\xae\x04Dps]\x8d4,c\x07L\xc5\t\x01\xe4\xdcQ\x9090r\xa4.\x97\xd8|\xafb+gT\xb8\xd7B\xfe\xd2\xdec\x97\xd7\x8b\x9c\xa2\x1b\xe5?(\xa7\x14\xbd\xaa\xcc \x85\xd7x\x83\xbad\xf6\xa0\x02\x14tI\xb5wq\xccaG\xa5.?\xed\x14\x93\xabh\x9a0v\xf3Uz@E\x12\tx,\xc8i\x8a\r\x8a\x8a\x80\x86Am\x9d\xc0\xc6\x06X\x98\xc1\x98\x08\x1e\x9c\x00R\xa3\x0b\tURl\x9d\x85"

# I can read the signature with https://pypi.org/project/PGPy/:
import pgpy
signature = pgpy.PGPSignature.from_blob(signature_bytes)
print(signature.signer)  # prints "75CF5AC418B8E74C", Fedora 39's signing key id
print(signature.created)  # prints "2023-07-19 18:14:01+00:00"

# but I cannot read it with pysequoia:
from pysequoia import Cert
signature = Cert.from_bytes(signature_bytes)
# RuntimeError: Malformed Cert: Unrecognized token `Signature Packet` found at 0:0
# Expected one of PUBLIC_KEY or SECRET_KEY
wiktor-k commented 4 months ago

It shouldn't be that difficult. Thanks for specifying exactly what you need! I'll take a look and report back.

I think you've already got familiar with maturin so you'd be able to test it when I file a PR 😁