From 15ed2184e61e40a35e56921aa57a49726f56b5c2 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Mon, 25 Nov 2019 16:45:49 -0500 Subject: email-print-mime-structure: decrypt S/MIME parts with OpenSSL If the user supplies a secret key like the ones found in https://www.ietf.org/id/draft-dkg-lamps-samples-01.html, then email-print-mime-structure will try to use that for decryption of CMS-encrypted (S/MIME) message parts. Signed-off-by: Daniel Kahn Gillmor Acked-by: Sean Whitton --- debian/control | 2 ++ email-print-mime-structure | 12 ++++++++++-- email-print-mime-structure.1.pod | 17 ++++++++++++++--- tests/email-print-mime-structure.sh | 6 ++++++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/debian/control b/debian/control index f04ce79..d2e07da 100644 --- a/debian/control +++ b/debian/control @@ -12,6 +12,7 @@ Build-Depends: gpg-agent , gpgsm , mypy , + openssl , perl, python3 , python3-argcomplete, @@ -54,6 +55,7 @@ Suggests: gpg, gpg-agent, gpgsm, + openssl, 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 e82d56e..4de0789 100755 --- a/email-print-mime-structure +++ b/email-print-mime-structure @@ -83,7 +83,7 @@ class MimePrinter(object): print(f'{prefix}{z.get_content_type()}{cset}{disposition}{fname} {nbytes:d} bytes') cryptopayload:Optional[Message] = None try_pgp_decrypt:bool = self.args.pgpkey or self.args.use_gpg_agent - try_cms_decrypt:bool = self.args.use_gpg_agent + try_cms_decrypt:bool = self.args.cmskey or self.args.use_gpg_agent if try_pgp_decrypt and \ (parent is not None) and \ @@ -116,6 +116,12 @@ class MimePrinter(object): if cryptopayload is None and self.args.use_gpg_agent: cryptopayload = self.pipe_decrypt(ciphertext, ['gpg', '--batch', '--decrypt']) elif flavor == EncType.SMIME: + if self.args.cmskey: + for keyname in self.args.cmskey: + cmd = ['openssl', 'smime', '-decrypt', '-inform', 'DER', '-inkey', keyname] + cryptopayload = self.pipe_decrypt(ciphertext, cmd) + if cryptopayload: + return cryptopayload if self.args.use_gpg_agent: cryptopayload = self.pipe_decrypt(ciphertext, ['gpgsm', '--batch', '--decrypt']) if cryptopayload is None: @@ -175,7 +181,9 @@ def main() -> None: parser:ArgumentParser = ArgumentParser(description='Read RFC2822 MIME message from stdin and emit a tree diagram to stdout.', epilog="Example: email-print-mime-structure are used ephemerally, and do not interact with any local GnuPG keyring. +=item B<--cmskey=>I + +I should name a PEM- or DER-encoded X.509 private key that is +not password-protected. If an S/MIME-encrypted message that uses CMS +is found on standard input, this key will be tried for decryption. +May be used multiple times if you want to try decrypting with more +than one such key. + +X.509 private keys listed in B<--cmskey=> are used ephemerally, and do +not interact with any local GnuPG keyring. + =item B<--use-gpg-agent> If this flag is present, and B encounters 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 and B<--use-gpg-agent> are -supplied, I arguments will be tried before falling back to -GnuPG. +If B<--use-gpg-agent> is supplied along with either +B<--pgpkey=>I or B<--cmskey=>I arguments, the +I arguments will be tried before falling back to GnuPG. If B has been asked to decrypt parts with either B<--pgpkey=>I or with B<--use-gpg-agent>, and it diff --git a/tests/email-print-mime-structure.sh b/tests/email-print-mime-structure.sh index 6e510ca..b45294e 100755 --- a/tests/email-print-mime-structure.sh +++ b/tests/email-print-mime-structure.sh @@ -22,6 +22,12 @@ for eml in tests/email-print-mime-structure/*.eml; do GNUPGHOME="$testgpghome" test_eml "$base" --use-gpg-agent rm -rf "$testgpghome" elif [ -e "$p12key" ]; then + printf "Testing %s (OpenSSL)\n" "${eml##*/}" + grep -v ^- < "$p12key" | base64 -d | \ + openssl pkcs12 -nocerts -nodes -passin pass: -passout pass: -out "$base.pemkey" + test_eml "$base" --cmskey "$base.pemkey" + rm -f "$base.pemkey" + testgpghome=$(mktemp -d) printf "Testing %s (GnuPG S/MIME)\n" "${eml##*/}" gpgsm --pinentry-mode=loopback --passphrase-fd 4 4<<<'' --homedir="$testgpghome" --batch --quiet --import <"$p12key" -- cgit v1.2.3