mailpipe: don't bail if a message is signed by a subkey.
authorW. Trevor King <wking@tremily.us>
Thu, 20 Sep 2012 16:35:00 +0000 (12:35 -0400)
committerW. Trevor King <wking@tremily.us>
Thu, 20 Sep 2012 16:49:27 +0000 (12:49 -0400)
Also strips off a leading '0x' before matching fingerprint tails.

You should normally be using primary keys in the `pgp_key` field of
the course configuration file.  Before this commit, messages signed by
a subkey would raise WrongSignatureMessage (i.e. we were looking for a
signature by your primary key, but we only got a signature from your
subkey).  Now we look for the listed signature not only in the signing
keys but also in their primaries.

This requires pgp-mime commit:

  commit eab8b88fe3f4940a9f8285cfb8b88070cd5c0050
  Author: W. Trevor King <wking@tremily.us>
  Date:   Thu Sep 20 12:24:27 2012 -0400

    key: add pgp_mime.key wrapping gpgme-tool's KEYLIST command.

pygrader/mailpipe.py

index 1a0bd6e49a38055c29cb79b2dcb6bcd1b5935364..281839b03c8dfe9f9266c74be953a555d9a07d14 100644 (file)
@@ -26,6 +26,7 @@ import re as _re
 import sys as _sys
 
 import pgp_mime as _pgp_mime
+import pgp_mime.key as _pgp_mime_key
 
 from . import LOG as _LOG
 from .email import construct_email as _construct_email
@@ -76,13 +77,14 @@ class AmbiguousAddress (_InvalidMessage):
 
 
 class WrongSignatureMessage (_InsecureMessage):
-    def __init__(self, pgp_key=None, signatures=None, decrypted=None,
-                 **kwargs):
+    def __init__(self, pgp_key=None, signatures=None, fingerprints=None,
+                 decrypted=None, **kwargs):
         if 'error' not in kwargs:
             kwargs['error'] = 'not signed by the expected key'
         super(WrongSignatureMessage, self).__init__(**kwargs)
         self.pgp_key = pgp_key
         self.signatures = signatures
+        self.fingerprints = fingerprints
         self.decrypted = decrypted
 
 
@@ -939,11 +941,22 @@ def _get_verified_message(message, pgp_key):
     for signature in signatures:
         _LOG.debug(signature.dumps())
     match = None
-    matches = [s for s in signatures if s.fingerprint.endswith(pgp_key)]
+    fingerprints = dict((s.fingerprint, s) for s in signatures)
+    for s in signatures:
+        for key in _pgp_mime_key.lookup_keys([s.fingerprint]):
+            if key.fingerprint != s.fingerprint:
+                # the signature was made with a subkey.  Add the primary.
+                fingerprints[key.fingerprint] = s
+    if pgp_key.startswith('0x'):
+        key_tail = pgp_key[len('0x'):]
+    else:
+        key_tail = pgp_key
+    matches = [fingerprints[f] for f in fingerprints.keys()
+               if f.endswith(key_tail)]
     if len(matches) == 0:
         raise WrongSignatureMessage(
             message=message, pgp_key=pgp_key, signatures=signatures,
-            decrypted=decrypted)
+            fingerprints=fingerprints, decrypted=decrypted)
     signature = matches[0]
     if not verified:
         if signature.get_summary() != 0: