Help on verifying email with GPG signature attached (RFC 3156)

171 views
Skip to first unread message

Leo Iannacone

unread,
May 16, 2014, 3:17:29 PM5/16/14
to python...@googlegroups.com

Hi, 


I'm trying to get signature verification from email multipart (with signature attached). But what I get is always a 'BAD signature from XXX'.

I guess I misunderstanding the format as described in: https://www.rfc-editor.org/rfc/rfc3156.txt

Do you have code-snip/tip/tricks about?


L.

Vinay Sajip

unread,
May 16, 2014, 3:27:39 PM5/16/14
to python...@googlegroups.com
It all depends on exactly what you are doing. python-gnupg is just a wrapper around GnuPG and has no knowledge of the internal structure of any data it's e.g. verifying. I would guess that you need to extract the payload and signature from the multipart message and then pass those parts to python-gnupg. That extraction should be straightforward from looking at the Python stdlib docs for email message functionality.

Regards,

Vinay Sajip

Leo Iannacone

unread,
May 17, 2014, 3:51:36 AM5/17/14
to python...@googlegroups.com

On Friday, May 16, 2014 9:27:39 PM UTC+2, Vinay Sajip wrote:
It all depends on exactly what you are doing. python-gnupg is just a wrapper around GnuPG and has no knowledge of the internal structure of any data it's e.g. verifying. I would guess that you need to extract the payload and signature from the multipart message and then pass those parts to python-gnupg. That extraction should be straightforward from looking at the Python stdlib docs for email message functionality.


Exaclty..

I'm able to get sign and body with this:

def get_signed_parts(message):
    ct = message.get_content_type()
    assert ct == 'multipart/signed', ct
    params = dict(message.get_params())
    assert params.get('protocol', None) == 'application/pgp-signature', params
    assert message.is_multipart(), message
    body = signature = None
    for part in message.get_payload():
        if part == message:
            continue
        ct = part.get_content_type()
        if ct == 'application/pgp-signature':
            if signature:
                raise ValueError('multiple application/pgp-signature parts')
            signature = part
        else:
            if body:
                raise ValueError('multiple non-signature parts')
            body = part
    if not body:
        raise ValueError('missing body part')
    if not signature:
        raise ValueError('missing application/pgp-signature part')
    return (body, signature)

 Then I try get a body flatten version with this:

def flatten(msg, to_unicode=False):
    """
    Produce flat text output from an email Message instance.
    """
    from email.generator import Generator
    from cStringIO import StringIO
    assert msg is not None
    fp = StringIO()
    g = Generator(fp, mangle_from_=False)
    g.flatten(msg)
    text = fp.getvalue()
    if to_unicode is True:
        encoding = msg.get_content_charset() or "utf-8"
        text = unicode(text, encoding=encoding)
    return text

Finally use python-gnupg in this way:

def verify(data):
    from gnupg import GPG
    from json import dumps as toJSON
    import email
    message = email.message_from_string(data)
    if message.get_content_type() == 'multipart/mixed':
        message = message.get_payload()[0]
    if message.get_content_type() == 'multipart/signed':
        body, signature = get_signed_parts(message)
        open('/tmp/t.asc', 'w').write(signature.get_payload(decode=True))
        verified = gpg.verify_data('/tmp/t.asc', flatten(body))
    else:
        verified = gpg.verified(data)
    verified = verified.__dict__
    del(verified['gpg'])
    return toJSON(verified, indent=4)

It works properly with inline signature, but return "status": "signature bad" for email with sign attached.

Any tip?

Leo Iannacone

unread,
May 17, 2014, 4:12:37 AM5/17/14
to python...@googlegroups.com
Awesome ... this code fixes my problem:



But I get this:

Exception in thread Thread-6:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/usr/lib/python2.7/dist-packages/gnupg.py", line 741, in _read_response
    result.handle_status(keyword, value)
  File "/usr/lib/python2.7/dist-packages/gnupg.py", line 275, in handle_status
    raise ValueError("Unknown status message: %r" % key)
ValueError: Unknown status message: u'NOTATION_NAME'


Is it a known problem?

Vinay Sajip

unread,
May 17, 2014, 4:27:16 AM5/17/14
to python...@googlegroups.com
I didn't know about it before, but I do know now ... I'll update the BitBucket repo soon. I'll comment on the issue you raised earlier, when I've addressed it.

Regards,

Vinay Sajip
Reply all
Reply to author
Forward
0 new messages