Decrypt ciphertext using gpgsm if the user has indicated that it's ok. Signed-off-by: Daniel Kahn Gillmor <d...@fifthhorseman.net> --- debian/control | 1 + email-print-mime-structure | 31 +++++++++++++++++++++++++++++++ email-print-mime-structure.1.pod | 8 ++++---- 3 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/debian/control b/debian/control index 72b57c3..aa44863 100644 --- a/debian/control +++ b/debian/control @@ -46,6 +46,7 @@ Recommends: Suggests: gpg, gpg-agent, + gpgsm, Architecture: all Description: collection of scripts for manipulating e-mail on Debian This package provides a collection of scripts for manipulating e-mail diff --git a/email-print-mime-structure b/email-print-mime-structure index 27fb532..ab90976 100755 --- a/email-print-mime-structure +++ b/email-print-mime-structure @@ -81,6 +81,7 @@ class MimePrinter(object): cryptopayload:Optional[Message] = None ciphertext:Union[List[Message],str,bytes,None] = None try_pgp_decrypt:bool = self.args.pgpkey or self.args.use_gpg_agent + try_cms_decrypt:bool = self.args.use_gpg_agent if try_pgp_decrypt and \ (parent is not None) and \ @@ -99,6 +100,19 @@ class MimePrinter(object): logging.warning(f'Unable to decrypt') return + if try_cms_decrypt and \ + cryptopayload is None and \ + z.get_content_type().lower() == 'application/pkcs7-mime': + ciphertext = z.get_payload(decode=True) + if not isinstance(ciphertext, bytes): + logging.warning('encrypted part was not a leaf mime part somehow') + return + if self.args.use_gpg_agent: + cryptopayload = self.gpgsm_decrypt(ciphertext) + if cryptopayload is None: + logging.warning(f'Unable to decrypt') + return + if cryptopayload is not None: newprefix = prefix[:-3] + ' ' print(f'{newprefix}↧ (decrypts to)') @@ -134,6 +148,23 @@ class MimePrinter(object): return email.message_from_bytes(out.stdout) return None + def gpgsm_decrypt(self, ciphertext:bytes) -> Optional[Message]: + inp:int + outp:int + inp, outp = os.pipe() + with open(outp, 'wb') as outf: + outf.write(ciphertext) + try: + out:subprocess.CompletedProcess[bytes] = subprocess.run(['gpgsm', '--batch', '--decrypt'], + stdin=inp, + capture_output=True) + except Exception as e: + logging.warning(f'Failed to decrypt with gpgsm: {e}') + return None + if out.returncode == 0: + return email.message_from_bytes(out.stdout) + return None + def print_tree(self, z:Message, prefix:str, parent:Optional[Message], num:int) -> None: if (z.is_multipart()): self.print_part(z, prefix+'┬╴', parent, num) diff --git a/email-print-mime-structure.1.pod b/email-print-mime-structure.1.pod index d8545ad..f109997 100644 --- a/email-print-mime-structure.1.pod +++ b/email-print-mime-structure.1.pod @@ -35,8 +35,8 @@ do not interact with any local GnuPG keyring. =item B<--use-gpg-agent> If this flag is present, and B<email-print-mime-structure> encounters -a PGP/MIME-encrypted part, it will try to decrypt the part using the -secret keys found in the local installation of GnuPG. +a PGP/MIME- or S/MIME-encrypted part, it will try to decrypt the part +using the secret keys found in the local installation of GnuPG. If both B<--pgpkey=>I<KEYFILE> and B<--use-gpg-agent> are supplied, I<KEYFILE> arguments will be tried before falling back to @@ -49,8 +49,8 @@ stderr. =item B<--no-use-gpg-agent> -Don't try to decrypt PGP/MIME-encrypted parts using secret keys found -in the local installation of GnuPG. This is the default. +Don't try to decrypt PGP/MIME- or S/MIME-encrypted parts using secret +keys found in the local installation of GnuPG. This is the default. =item B<--help>, B<-h> -- 2.24.0