Mail-GnuPG-0.19000755001750001750 012141170312 13542 5ustar00bremnerbremner000000000000Mail-GnuPG-0.19/SIGNATURE000644001750001750 434212141170312 15170 0ustar00bremnerbremner000000000000This file contains message digests of all files listed in MANIFEST, signed via the Module::Signature module, version 0.68. To verify the content in this distribution, first make sure you have Module::Signature installed, then type: % cpansign -v It will check each file's integrity, as well as the signature's validity. If "==> Signature verified OK! <==" is not displayed, the distribution may already have been compromised, and you should not run its Makefile.PL or Build.PL. -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 SHA1 2a0995e8f4ea107ac5740bb23f5602dc7b0216fa Build.PL SHA1 ef2347ad3e322e66476cf627bcf1e42ba7d4f36e Changes SHA1 715f00c27841c9e55587f86856b7dab59799a830 MANIFEST SHA1 31e74441f34fb0847f306d134b765334ca85a294 META.json SHA1 8d9f105187afe48498093e67e1071488e02b0ace META.yml SHA1 4bd99b7839619d627ad16d69d09772d3ef2e7784 README SHA1 95885d81413712ab28f4d15e1a8d585e7badba6e lib/Mail/GnuPG.pm SHA1 3ec6171779122b0bdc69937c283be11b2a15dd89 t/00.signature.t SHA1 269c6c48fbe5fd830479e83b2d7aae8ddca00133 t/05.load.t SHA1 2679e880c6c9f225dc97c1d7a462d3e43e2834b1 t/20.inline-verify.t SHA1 22d2700f00f149941964d96cabbb7c87aa908bfb t/25.multipart-verify.t SHA1 7bf3a408b7c981e84ef94a252319874c2009e81a t/30.inline-decrypt.t SHA1 27b2a825bb10243ff3db6fbc0ed46397993bb510 t/35.has-public-key.t SHA1 5a5966f563a4b6a4f7664c0b1251d3c1d2446c09 t/99.pod.t SHA1 c511c27d56aab293cd548ae2aee9159ff400a7be t/agent.t SHA1 782c0040382d4721f14f987a82e9ed34281e6781 t/base.t SHA1 58677c70dd194c09422dea0ad15ebfb9e3f04062 t/import_keys.pl SHA1 42f5e5ec614ad6e44a0f91c8aee0554b48b8445a t/msg/inline-encrypted-qp.eml SHA1 ea32c1f860eea29382f65acedb3ba3cd4c0ed9d7 t/msg/inline-signed-qp.eml SHA1 59b756891362972b3aa98207750f0dbcce52c3ec t/msg/multipart-signed-qp.eml SHA1 943ef9409156fef12c810738bb81c4d381f557e4 t/pubkeys.asc SHA1 5b89f061e6bb84e4fb73f36d737a36b4ad5fac7a t/round-trip.t SHA1 1932b1026feb122fedd16396d7cd069ba0330640 t/test-key.pgp -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iJwEAQECAAYFAlGE8L0ACgkQTiiN/0Um85ntxwP/WNRxl1NOco+86d/3AMibj0gU GGTqUPf88oqyzmFYN3pUFMDdybUbZ3zKBC8ot1rQG7nBjOG/EzwkBUC2ifKsSgcZ qEEuUejVUfrlFi60boh2gKmt6cGhYxrv6UOCoStvpttX0vn49w0ug391hOhRzIna ckmWuAFyMPwE9ywVHso= =B9b9 -----END PGP SIGNATURE----- Mail-GnuPG-0.19/Build.PL000444001750001750 123612141170275 15205 0ustar00bremnerbremner000000000000use strict; use warnings; use Module::Build; my $build = Module::Build->new ( module_name => 'Mail::GnuPG', dist_author => [ 'Robert Spier ', 'David Bremner '], (sign => 1), requires => { 'File::Spec' => 0, 'File::Temp' => 0, 'GnuPG::Interface' => 0, 'IO::Handle' => 0, 'MIME::Entity' => 0, 'MIME::Parser' => 0, 'Mail::Address' => 0, 'Test::More' => 0, 'Test::Pod' => 0, }, license => 'unknown', create_readme => 0, meta_merge => { resources => { homepage => 'http://pivot.cs.unb.ca/git/?p=mail-gnupg.git;a=summary' } } ); $build->create_build_script; Mail-GnuPG-0.19/README000444001750001750 444212141170275 14573 0ustar00bremnerbremner000000000000Mail/GnuPG version 0.15_1 ========================= Use GnuPG::Interface to process and/or create PGP signed or encrypted email. (See the inline documentation for more information) This is a development release. It works for me and at least four or five other people. It may not work for you. If it doesn't, patches are appreciated. There is a known issue where some messages may not verify properly because they use a fuzzy encoding like Quoted-Printable, and may decode slightly differently in different places. INSTALLATION To install this module type the following: perl Makefile.PL make make test make install DEPENDENCIES This module requires these other modules (and their dependencies): GnuPG::Interface IO::Handle MIME::Entity File::Temp MIME::Parser Mail::Address GnuPG cut(1) SUPPORT/REPORTING BUGS/PATCHES Please send all bugs/issues/patches to bug-Mail-GnuPG@rt.cpan.org COPYRIGHT AND LICENCE Copyright 2003 Best Practical Solutions, LLC This program is free software; you can redistribute it and/or modify it under the terms of either: a) the GNU General Public License as published by the Free Software Foundation; version 2 http://www.opensource.org/licenses/gpl-license.php b) the "Artistic License" http://www.opensource.org/licenses/artistic-license.php This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details. NOTES RFC1847 - Security Multiparts http://www.ietf.org/rfc/rfc1847.txt RFC2015 - MIME Security with PGP http://www.ietf.org/rfc/rfc2015.txt KNOWN ISSUES #2718 - https://rt.cpan.org/Ticket/Display.html?id=2718 Mail::GnuPG assumes the signature is calculated on the decoded MIME data (which is the only thing it can get from MIME::Entity). Jörn Reder is working on a solution. TODO - Get rid of 'cut' dependency. - Consider nicer/prettier interface - Use GnuPG::Interface's internal passphrase handling - Add tests - Use GnuPG::Handle->{direct} to pass files directly to gpg AUTHOR Robert Spier rspier at cpan.org MAINTAINER David Bremner ddb at cpan.org Large Contributions from: Jörn Reder joern at zyn.de Mail-GnuPG-0.19/META.json000444001750001750 226412141170275 15334 0ustar00bremnerbremner000000000000{ "abstract" : "Process email with GPG.", "author" : [ "Robert Spier ", "David Bremner " ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.38, CPAN::Meta::Converter version 2.120921", "license" : [ "unknown" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Mail-GnuPG", "prereqs" : { "configure" : { "requires" : { "Module::Build" : "0.38" } }, "runtime" : { "requires" : { "File::Spec" : "0", "File::Temp" : "0", "GnuPG::Interface" : "0", "IO::Handle" : "0", "MIME::Entity" : "0", "MIME::Parser" : "0", "Mail::Address" : "0", "Test::More" : "0", "Test::Pod" : "0" } } }, "provides" : { "Mail::GnuPG" : { "file" : "lib/Mail/GnuPG.pm", "version" : "0.19" } }, "release_status" : "stable", "resources" : { "homepage" : "http://pivot.cs.unb.ca/git/?p=mail-gnupg.git;a=summary" }, "version" : "0.19" } Mail-GnuPG-0.19/Changes000444001750001750 631012141170275 15202 0ustar00bremnerbremner000000000000Revision history for Perl extension Mail::GnuPG. 0.19 Sat May 4 2013 - [RT #83465] Update gnupg-agent support for GnuPG::Interface >= 0.46 0.18 Sat Jul 21 2012 - [RT #77070] Support non-default GPG key directory 0.17 Sun Dec 10 2011 - [RT #73036] Support trust-model = always-trust 0.16 Tue Dec 14 2010 - [RT #60280] Add support for gnupg-agent - [RT #60246] Use undecoded text for decode and get_decrypt_key of inline PGP - [RT #4388, #2718, #46168] Add test case for verify of encoded bodies 0.15 Sat Mar 8 19:51:55 PST 2008 This is the ntyni release, as he provided most of the fixes: - Fix roundtrip test by trusting test keyring. - New test to show blocking issues on large messages. - Switch to a non-blocking (select) based mechanism for interacting with gpg. 0.10 Mon Jul 9 15:12:10 PDT 2007 - Fixed "-1" result code from waitpid handling. (On OSX, it can mean 'reaped' not actually an error) 0.09 - MIME content type of signed portion will be same as content type of original message. 0.08 Sat Jul 17 19:11:06 PDT 2004 really tiny release for Paul's issue - https://rt.cpan.org/Ticket/Display.html?id=6968 IO::Handle::sync not implemented on all systems, can cause Mail::GnuPG to fail - cleanup some test warnings 0.07 Tue Dec 16 20:32:09 PST 2003 Lots o Documentation Updates (From Paul J. Schinder) - bugfix for encrypt without signing (For Jesse) - verify(): return uid/email on success - new methods: is_signed() and is_encrypted(), which are encapsulations of the simple tests for guessing whether something is signed or encrypted. - get_decrypt_key(): fix for gpg not in current path - decrypt(): return uid/email on successful decrypt of signed msg - verify() : fix tempfile creation location 0.06 Wed Jul 23 19:59:51 PDT 2003 (From Jörn Reder) - bugfix in decrypt(): with ASCII armor messages the first line of the cleartext was removed by MIME::Parser, if the cleartext was no entity but simple ASCII text. - new method get_decrypt_key() which returns a secret key and the corresponding mail address, which could be used to decrypt a given encrypted message. 0.05 Thu Jun 12 23:05:48 PDT 2003 (From Jörn Reder) - insecure temp file handling (still insecure, but not that much ;) - non portable temp directory handling - insecure temp file / MIME::Parser handling in decrypt() - broken signature verification on quoted printable ascii armor messages - broken MIME canonical conversion (was broken if single CR's or CR/LF sequences were already in the message) - removed line break mangling in mime_encrypt(). RFC3156 doesn't request it. new methods: clear_sign() - clearsign the body of an email message ascii_encrypt() - encrypt an email message body using ascii armor ascii_signencrypt() - encrypt and sign an email message body using ascii armor 0.04 Fri Apr 4 18:35:09 PST 2003 - Previous version didn't work. 0.03 Thu Mar 27 22:32:21 PST 2003 - Previous version didn't work. 0.02 Thu Mar 27 20:32:21 PST 2003 - Update Makefile.PL to set prereqs 0.01 Mon Jan 6 19:16:27 2003 - original version; created by h2xs 1.21 with options -X Mail::GnuPG Mail-GnuPG-0.19/META.yml000444001750001750 133612141170275 15163 0ustar00bremnerbremner000000000000--- abstract: 'Process email with GPG.' author: - 'Robert Spier ' - 'David Bremner ' build_requires: {} configure_requires: Module::Build: 0.38 dynamic_config: 1 generated_by: 'Module::Build version 0.38, CPAN::Meta::Converter version 2.120921' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Mail-GnuPG provides: Mail::GnuPG: file: lib/Mail/GnuPG.pm version: 0.19 requires: File::Spec: 0 File::Temp: 0 GnuPG::Interface: 0 IO::Handle: 0 MIME::Entity: 0 MIME::Parser: 0 Mail::Address: 0 Test::More: 0 Test::Pod: 0 resources: homepage: http://pivot.cs.unb.ca/git/?p=mail-gnupg.git;a=summary version: 0.19 Mail-GnuPG-0.19/MANIFEST000444001750001750 62712141170275 15025 0ustar00bremnerbremner000000000000Build.PL Changes lib/Mail/GnuPG.pm MANIFEST README t/00.signature.t t/05.load.t t/20.inline-verify.t t/25.multipart-verify.t t/30.inline-decrypt.t t/35.has-public-key.t t/99.pod.t t/agent.t t/base.t t/import_keys.pl t/msg/inline-encrypted-qp.eml t/msg/inline-signed-qp.eml t/msg/multipart-signed-qp.eml t/pubkeys.asc t/round-trip.t t/test-key.pgp META.yml META.json SIGNATURE Added here by Module::Build Mail-GnuPG-0.19/t000755001750001750 012141170275 14015 5ustar00bremnerbremner000000000000Mail-GnuPG-0.19/t/test-key.pgp000444001750001750 561112141170275 16432 0ustar00bremnerbremner000000000000gpg -a --export EFEA4EAD > test-key.pgp gpg -a --export-secret-keys EFEA4EAD >> test-key.pgp passcode is passcode -----BEGIN PGP PRIVATE KEY BLOCK----- Comment: Encryption is Good lQHhBD+ODYcRBACk5d777JxX4unmJLjy+SeexH1xYdDmcqH8VL125tyfpm9zIOtm bzCcur7c+WM6am7jsdVV7udX8RuYWnlpj3f0rtodjXsaxGUQSt3VN2/oec0Hr/PE 6T+64cHBCLsijgeYBFIP4Zoq2sK0vO9CIjqxveHbrfZx3UdpzofUTodKewCgzX4P KJjYzBfZQ+Y2C1kXWXOqGrkD/3INRfhmsZOUgQeJzcZLIi9vVeaJls4KV2LEpONv SqMJmsDsjzUOAMV81bj3GxdxSVtRmVPRgBw6bFvn5pPiVjF9V5dGAPJjrQx1shO6 4AP8xKNkiY7l1nDMbMvfqZEgu9Z7TB0OsRcEx0RSDt2dOyugmg7SdacdmkE4FNej nR0OA/9cXGi+alpfxCkLQgjPyjqDZqiuQXkOT7xwQg35YObaVcMa+c81d9h98K+l Ch8qv/J5mnxmglqMlf5JOGpjBBzOvgzSXVYAG2sd96vWlED9TlnK1uv0LO/5Jx1w neY6VpFWhkX8eKrbfMO644gTqnRT9rY8xdI+UsncuXb4aFSLnv4DAwJPq934lByD u2AYNlyjfh2/zag+ZQQ33rQhFyJjvkVw6zEP40NSmR/sNKkLCqXU6HMkgIipv0Sx pz2N9LQlTWFpbDo6R251UEcgVGVzdCBLZXkgPG1haWxAZ251cGcuZG9tPohZBBMR AgAZBQI/jg2HBAsHAwIDFQIDAxYCAQIeAQIXgAAKCRBJU51g7+pOrYqzAKCrIouc l6ksApGl3XEAwjiM9B0XNQCgzBU9MpPwXk+w4L6yb7QW1QLC31ydAVgEP44NiRAE AKlZnCUe3Bi8pWjt6eDQKH7LYeqU8Wnfa83rJJm+bXgk6JFFp6mxVTWEhI28PTtv u7JtNGRk8AeoZPPkA5ZDp4URZ9yiu1WK+7SbBLY++lSRaxS6xTFtMDnhFf+rO6lc oonnnyq1rYIBdcwcYKyjl8cGGzoqQJ3VOAOfqG65cHE3AAQNA/0SHN+H3n/x32qw kgO2ddy2x9dtFvnlIUS8a8ic7cdd96Sgz/dlHY+VYFIpuUMzASusxFaqcyQJHgNp fbqmckr2sf8LR+mdtLIsWNY4CVYNIO5FdXlKeIcLsq4F7QfBPYgfH4xqIXgmxF7d Lv9NQynbdbLKdF0QN43xsg3S3TBGtf4DAwJPq934lByDu2CEr/u9oT64AzSsq5ND whBR3rGGLCNBCPUVlNE+wnv3Afc/W6B1hR3NfUrKSb8uBS2bXeAAKCCFnQ+Bt+cr vYhGBBgRAgAGBQI/jg2JAAoJEElTnWDv6k6tMf8AoMxqTQCqbrUASBXA/KkEC9wK V+uBAJ92S0vFvgVqAUq+QdYVxyKhQbUvdQ== =VoD3 -----END PGP PRIVATE KEY BLOCK----- -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: Encryption is Good mQGiBD+ODYcRBACk5d777JxX4unmJLjy+SeexH1xYdDmcqH8VL125tyfpm9zIOtm bzCcur7c+WM6am7jsdVV7udX8RuYWnlpj3f0rtodjXsaxGUQSt3VN2/oec0Hr/PE 6T+64cHBCLsijgeYBFIP4Zoq2sK0vO9CIjqxveHbrfZx3UdpzofUTodKewCgzX4P KJjYzBfZQ+Y2C1kXWXOqGrkD/3INRfhmsZOUgQeJzcZLIi9vVeaJls4KV2LEpONv SqMJmsDsjzUOAMV81bj3GxdxSVtRmVPRgBw6bFvn5pPiVjF9V5dGAPJjrQx1shO6 4AP8xKNkiY7l1nDMbMvfqZEgu9Z7TB0OsRcEx0RSDt2dOyugmg7SdacdmkE4FNej nR0OA/9cXGi+alpfxCkLQgjPyjqDZqiuQXkOT7xwQg35YObaVcMa+c81d9h98K+l Ch8qv/J5mnxmglqMlf5JOGpjBBzOvgzSXVYAG2sd96vWlED9TlnK1uv0LO/5Jx1w neY6VpFWhkX8eKrbfMO644gTqnRT9rY8xdI+UsncuXb4aFSLnrQlTWFpbDo6R251 UEcgVGVzdCBLZXkgPG1haWxAZ251cGcuZG9tPohZBBMRAgAZBQI/jg2HBAsHAwID FQIDAxYCAQIeAQIXgAAKCRBJU51g7+pOrYqzAJwOT8usIZWPwyV+OBXtDJfdWvvO BACfac5uMGHjbOyWb7y9uKnQEyjYlPK5AQ0EP44NiRAEAKlZnCUe3Bi8pWjt6eDQ KH7LYeqU8Wnfa83rJJm+bXgk6JFFp6mxVTWEhI28PTtvu7JtNGRk8AeoZPPkA5ZD p4URZ9yiu1WK+7SbBLY++lSRaxS6xTFtMDnhFf+rO6lcoonnnyq1rYIBdcwcYKyj l8cGGzoqQJ3VOAOfqG65cHE3AAQNA/0SHN+H3n/x32qwkgO2ddy2x9dtFvnlIUS8 a8ic7cdd96Sgz/dlHY+VYFIpuUMzASusxFaqcyQJHgNpfbqmckr2sf8LR+mdtLIs WNY4CVYNIO5FdXlKeIcLsq4F7QfBPYgfH4xqIXgmxF7dLv9NQynbdbLKdF0QN43x sg3S3TBGtYhGBBgRAgAGBQI/jg2JAAoJEElTnWDv6k6tMf8AoMgSMnC2qbkS+7aG v3B/zy8zFcX4AKCWx0++nS0/Xx6J5aePGFZq1bPXAg== =53bw -----END PGP PUBLIC KEY BLOCK----- Mail-GnuPG-0.19/t/00.signature.t000444001750001750 172112141170275 16557 0ustar00bremnerbremner000000000000#!/usr/bin/perl use strict; use Test::More; if (!$ENV{TEST_SIGNATURE}) { plan skip_all => "Set the environment variable TEST_SIGNATURE to enable this test."; } elsif (!eval { require Module::Signature; 1 }) { plan skip_all => "Next time around, consider installing Module::Signature, ". "so you can verify the integrity of this distribution."; } elsif ( !-e 'SIGNATURE' ) { plan skip_all => "SIGNATURE not found"; } elsif ( -s 'SIGNATURE' == 0 ) { plan skip_all => "SIGNATURE file empty"; } elsif (!eval { require Socket; Socket::inet_aton('pool.sks-keyservers.net') }) { plan skip_all => "Cannot connect to the keyserver to check module ". "signature"; } else { plan tests => 1; } my $ret = Module::Signature::verify(); SKIP: { skip "Module::Signature cannot verify", 1 if $ret eq Module::Signature::CANNOT_VERIFY(); cmp_ok $ret, '==', Module::Signature::SIGNATURE_OK(), "Valid signature"; } Mail-GnuPG-0.19/t/base.t000444001750001750 15712141170275 15234 0ustar00bremnerbremner000000000000 print "1..1\n"; unless (eval 'require Mail::GnuPG') { print "not ok 1\n"; } else { print "ok 1\n"; } 1; Mail-GnuPG-0.19/t/agent.t000444001750001750 557612141170275 15452 0ustar00bremnerbremner000000000000# -*- perl -*- use Test::More; use File::Temp qw(tempdir); use Mail::GnuPG; use MIME::Entity; use strict; no warnings 'redefine'; # fix this later my $KEY = "EFEA4EAD"; # 49539D60EFEA4EAD my $WHO = "Mail::GnuPG Test Key "; unless ( 0 == system("gpg --version 2>&1 >/dev/null") && 0 == system("gpg-agent --version 2>&1 >/dev/null")) { plan skip_all => "gpg, gpg-agent in path required for testing agent"; goto end; } my $preset=$ENV{GPG_PRESET_PASSPHRASE} || "/usr/lib/gnupg2/gpg-preset-passphrase"; unless (0 == system("$preset --version 2>&1 >/dev/null")) { plan skip_all => "gpg-preset-passphrase not found; set GPG_PRESET_PASSPHRASE in environment to location of binary"; goto end; } my $tmpdir = tempdir( "mgtXXXXX", CLEANUP => 1); unless ( 0 == system("gpg --homedir $tmpdir --trusted-key 0x49539D60EFEA4EAD --import t/test-key.pgp 2>&1 >/dev/null")) { plan skip_all => "unable to import testing keys"; goto end; } unless (open AGENT, "gpg-agent --disable-scdaemon --allow-preset --daemon|") { plan skip_all =>"unable to start gpg-agent"; goto end; } my ($agent_pid,$agent_info); while (){ if (m/GPG_AGENT_INFO=([^;]*);/){ $agent_info=$1; $ENV{'GPG_AGENT_INFO'}=$agent_info; my @parts=split(':',$agent_info); $agent_pid=$parts[1]; } } # gpg-preset-passphrase uses the fingerprint of the subkey, rather than the id. unless ( 0 == system ("$preset --preset -P passphrase " . "576AE2D0BC6974C083705EE033A736779FE08E94") && 0 == system ("$preset --preset -P passphrase " . "8E136E6F34C0D4CD941A9DB749539D60EFEA4EAD") ){ plan skip_all =>"unable to cache passphrase"; goto end; } plan tests => 20; my $mg = new Mail::GnuPG( key => '49539D60EFEA4EAD', keydir => $tmpdir, use_agent => 1); isa_ok($mg,"Mail::GnuPG"); my $line = "x\n"; my $string = $line x 100000; my $copy; my $me = MIME::Entity->build(From => 'me@myhost.com', To => 'you@yourhost.com', Subject => "Hello, nurse!", Data => [$string]); # Test MIME Signing Round Trip $copy = $me->dup; is( 0, $mg->mime_sign( $copy ) ); my ($verify,$key,$who) = $mg->verify($copy); is( 0, $verify ); is( $KEY, $key ); is( $WHO, $who ); is( 1, $mg->is_signed($copy) ); is( 0, $mg->is_encrypted($copy) ); # Test Clear Signing Round Trip $copy = $me->dup; is( 0, $mg->clear_sign( $copy ) ); { my ($verify,$key,$who) = $mg->verify($copy); is( 0, $verify ); is( $KEY, $key ); is( $WHO, $who ); is( 1, $mg->is_signed($copy) ); is( 0, $mg->is_encrypted($copy) ); } # Test MIME Encryption Round Trip $copy = $me->dup; is( 0, $mg->ascii_encrypt( $copy, $KEY )); is( 0, $mg->is_signed($copy) ); is( 1, $mg->is_encrypted($copy) ); ($verify,$key,$who) = $mg->decrypt($copy); is( 0, $verify ); is( undef, $key ); is( undef, $who ); is_deeply($mg->{decrypted}->body,$me->body); end: kill 15,$agent_pid if (defined($agent_pid)); Mail-GnuPG-0.19/t/25.multipart-verify.t000444001750001750 134712141170275 20114 0ustar00bremnerbremner000000000000# -*- perl -*- use Test::More; use Mail::GnuPG; use MIME::Entity; use strict; require('t/import_keys.pl'); my $gpghome=import_keys('t/pubkeys.asc'); unless (defined($gpghome)){ plan skip_all => "failed to import GPG keys for testing"; goto end; } plan tests => 5; # Main program my $parser = new MIME::Parser; $parser->output_to_core(1); $parser->decode_bodies(0); my $entity= $parser->parse_open("t/msg/multipart-signed-qp.eml") ; isa_ok($entity,"MIME::Entity"); my $mg = new Mail::GnuPG( keydir=>$gpghome); isa_ok($mg,"Mail::GnuPG"); my ($return,$keyid,$uid) = $mg->verify($entity); is($return,0,"verify success"); is($keyid,'9456D16A',"verify keyid"); is($uid,'Mauricio Campiglia ',"verify uid"); end: Mail-GnuPG-0.19/t/99.pod.t000444001750001750 76712141170275 15353 0ustar00bremnerbremner000000000000# Thanks Andy! use Test::More; use File::Spec; use File::Find; use strict; eval { require Test::Pod; }; my $ok = !$@ && ($Test::Pod::VERSION >= '0.95'); if (!$ok) { plan skip_all => "Test::Pod v0.95 required for testing POD"; } else { Test::Pod->import; my @files; my $blib = File::Spec->catfile(qw(blib lib)); find( sub {push @files, $File::Find::name if /\.p(l|m|od)$/}, $blib); plan tests => scalar @files; foreach my $file (@files) { pod_file_ok($file); } } Mail-GnuPG-0.19/t/import_keys.pl000444001750001750 63612141170275 17041 0ustar00bremnerbremner000000000000sub import_keys($){ my $filename=shift; my $trusted = scalar(@_) ? "--trusted-key 0x".shift : ""; use File::Temp qw(tempdir); unless ( 0 == system("gpg --version 2>&1 >/dev/null") ) { return undef; } my $gpghome = tempdir( "mgtXXXXX", CLEANUP => 1); unless ( 0 == system("gpg --homedir $gpghome $trusted --import $filename 2>&1 >/dev/null")) { return undef; } return $gpghome; } 1; Mail-GnuPG-0.19/t/round-trip.t000444001750001750 314112141170275 16441 0ustar00bremnerbremner000000000000# -*- perl -*- use Test::More; use File::Temp qw(tempdir); use Mail::GnuPG; use MIME::Entity; use strict; my $FULL_KEY = "49539D60EFEA4EAD"; my $KEY = substr($FULL_KEY,-8,8); my $WHO = "Mail::GnuPG Test Key "; require('t/import_keys.pl'); my $gpghome=import_keys('t/test-key.pgp',$FULL_KEY); unless (defined($gpghome)){ plan skip_all => "failed to import GPG keys for testing"; goto end; } plan tests => 20; my $mg = new Mail::GnuPG( key => '49539D60EFEA4EAD', keydir => $gpghome, passphrase => 'passphrase'); isa_ok($mg,"Mail::GnuPG"); my $line = "x\n"; my $string = $line x 100000; my $copy; my $me = MIME::Entity->build(From => 'me@myhost.com', To => 'you@yourhost.com', Subject => "Hello, nurse!", Data => [$string]); # Test MIME Signing Round Trip $copy = $me->dup; is( $mg->mime_sign( $copy ), 0 ); my ($verify,$key,$who) = $mg->verify($copy); is( $verify, 0 ); is( $key, $KEY ); is( $who, $WHO ); is( $mg->is_signed($copy), 1 ); is( $mg->is_encrypted($copy), 0 ); # Test Clear Signing Round Trip $copy = $me->dup; is( $mg->clear_sign( $copy ), 0 ); { my ($verify,$key,$who) = $mg->verify($copy); is( 0, $verify ); is( $KEY, $key ); is( $WHO, $who ); is( 1, $mg->is_signed($copy) ); is( 0, $mg->is_encrypted($copy) ); } # Test MIME Encryption Round Trip $copy = $me->dup; is( $mg->ascii_encrypt( $copy, $KEY ), 0 ); is( $mg->is_signed($copy), 0 ); is( $mg->is_encrypted($copy), 1 ); ($verify,$key,$who) = $mg->decrypt($copy); is( $verify, 0 ); is( $key, undef ); is( $who, undef); is_deeply($mg->{decrypted}->body,$me->body); end: Mail-GnuPG-0.19/t/pubkeys.asc000444001750001750 13067112141170275 16374 0ustar00bremnerbremner000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Public Keys for testing Mail::GnuPG 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 AJ4+Xm0YBbMExYKbrP5irHm7W8fQfQ== =EGZo -----END PGP PUBLIC KEY BLOCK----- Mail-GnuPG-0.19/t/30.inline-decrypt.t000444001750001750 217412141170275 17512 0ustar00bremnerbremner000000000000# -*- perl -*- use Test::More; use Mail::GnuPG; use MIME::Entity; use File::Temp qw(tempdir); use strict; plan tests => 5; # Main program my $parser = new MIME::Parser; $parser->output_to_core(1); my $entity= $parser->parse_open("t/msg/inline-encrypted-qp.eml") ; isa_ok($entity,"MIME::Entity"); my $KEY = "EFEA4EAD"; # 49539D60EFEA4EAD my $WHO = "Mail::GnuPG Test Key "; unless ( 0 == system("gpg --version 2>&1 >/dev/null") ) { plan skip_all => "gpg in path required for testing round-trip"; goto end; } my $tmpdir = tempdir( "mgtXXXXX", CLEANUP => 1); unless ( 0 == system("gpg --homedir $tmpdir --trusted-key 0x49539D60EFEA4EAD --import t/test-key.pgp 2>&1 >/dev/null")) { plan skip_all => "unable to import testing keys"; goto end; } my $mg = new Mail::GnuPG( key => '49539D60EFEA4EAD', keydir => $tmpdir, passphrase => 'passphrase'); isa_ok($mg,"Mail::GnuPG"); my ($return,$keyid,$uid) = $mg->decrypt($entity); is($return,0,"decrypt success"); ok(!defined($keyid) && !defined($uid), "message unsigned"); is($mg->{decrypted}->as_string, " this is some 8-bit text: áëìóü ","plaintext"); end: Mail-GnuPG-0.19/t/05.load.t000444001750001750 6712141170275 15444 0ustar00bremnerbremner000000000000 use Test::More tests => 1; use_ok( 'Mail::GnuPG' ); Mail-GnuPG-0.19/t/35.has-public-key.t000444001750001750 74712141170275 17372 0ustar00bremnerbremner000000000000# -*- perl -*- use Test::More; use Mail::GnuPG; use strict; require('t/import_keys.pl'); my $gpghome=import_keys('t/test-key.pgp'); unless (defined($gpghome)){ plan skip_all => "failed to import GPG keys for testing"; goto end; } plan tests => 3; my $mg = new Mail::GnuPG( keydir => $gpghome ); isa_ok($mg, 'Mail::GnuPG'); is($mg->has_public_key('mail@gnupg.dom'), 1, 'public key exists'); is($mg->has_public_key('bogus@email.example.com'), 0, "bogus key doesn't exist"); end: Mail-GnuPG-0.19/t/20.inline-verify.t000444001750001750 130312141170275 17334 0ustar00bremnerbremner000000000000# -*- perl -*- use Test::More; use Mail::GnuPG; use MIME::Entity; use strict; require('t/import_keys.pl'); my $gpghome=import_keys('t/pubkeys.asc'); unless (defined($gpghome)){ plan skip_all => "failed to import GPG keys for testing"; goto end; } plan tests => 5; # Main program my $parser = new MIME::Parser; $parser->output_to_core(1); my $entity= $parser->parse_open("t/msg/inline-signed-qp.eml") ; isa_ok($entity,"MIME::Entity"); my $mg = new Mail::GnuPG( keydir =>$gpghome ); isa_ok($mg,"Mail::GnuPG"); my ($return,$keyid,$uid) = $mg->verify($entity); is($return,0,"verify success"); is($keyid,'4526F399',"verify keyid"); is($uid,'David Bremner ',"verify uid"); end: Mail-GnuPG-0.19/t/msg000755001750001750 012141170275 14603 5ustar00bremnerbremner000000000000Mail-GnuPG-0.19/t/msg/multipart-signed-qp.eml000444001750001750 1435112141170275 21371 0ustar00bremnerbremner000000000000From mauricio.campiglia@gmail.com Mon May 18 00:43:49 2009 Return-Path: X-Original-To: crhalpin@localhost Delivered-To: crhalpin@localhost.home.crhalpin.org Received: from spiff.home.crhalpin.org (localhost [127.0.0.1]) by spiff.home.crhalpin.org (Postfix) with ESMTP id A66261CC3C for ; Mon, 18 May 2009 00:43:46 -0500 (CDT) Received: from crimson.cs.wisc.edu [128.105.6.43] by spiff.home.crhalpin.org with IMAP (fetchmail-6.3.9) for (single-drop); Mon, 18 May 2009 00:43:46 -0500 (CDT) Received: from shale.cs.wisc.edu (shale.cs.wisc.edu [128.105.6.25]) by crimson.cs.wisc.edu (8.14.1/8.14.1) with ESMTP id n4I5fnVL000994 for ; Mon, 18 May 2009 00:41:49 -0500 Received: from sabe.cs.wisc.edu (sabe.cs.wisc.edu [128.105.6.20]) by shale.cs.wisc.edu (8.14.1/8.14.1) with ESMTP id n4I5fn3s007221 for ; Mon, 18 May 2009 00:41:49 -0500 Received: from spiff.home.crhalpin.org (eagleheights-105-18.resnet.wisc.edu [146.151.105.18]) (authenticated bits=0) by sabe.cs.wisc.edu (8.14.1/8.14.1) with ESMTP id n4I5fnhh030486 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 18 May 2009 00:41:49 -0500 Received: by spiff.home.crhalpin.org (Postfix, from userid 1001) id 7473A1CC3C; Mon, 18 May 2009 00:41:43 -0500 (CDT) X-Original-To: crhalpin@localhost Old-Delivered-To: crhalpin@localhost.home.crhalpin.org Received: from spiff.home.crhalpin.org (localhost [127.0.0.1]) by spiff.home.crhalpin.org (Postfix) with ESMTP id 47C2F1CC3B for ; Sun, 17 May 2009 22:34:32 -0500 (CDT) Received: from crimson.cs.wisc.edu [128.105.6.43] by spiff.home.crhalpin.org with IMAP (fetchmail-6.3.9) for (single-drop); Sun, 17 May 2009 22:34:32 -0500 (CDT) Received: from shale.cs.wisc.edu (shale.cs.wisc.edu [128.105.6.25]) by crimson.cs.wisc.edu (8.14.1/8.14.1) with ESMTP id n4I3YS9m007520 for ; Sun, 17 May 2009 22:34:28 -0500 Received: from silica.cs.wisc.edu (silica.cs.wisc.edu [128.105.6.34]) by shale.cs.wisc.edu (8.14.1/8.14.1) with ESMTP id n4I3YSPn003380 for ; Sun, 17 May 2009 22:34:28 -0500 Received: from yx-out-2324.google.com (yx-out-2324.google.com [74.125.44.29]) by silica.cs.wisc.edu (8.14.1/8.14.1) with ESMTP id n4I3YQqn025545 for ; Sun, 17 May 2009 22:34:27 -0500 Received: by yx-out-2324.google.com with SMTP id 8so1539394yxb.51 for ; Sun, 17 May 2009 20:34:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:sender:from:to:subject:date :user-agent:mime-version:content-type:content-transfer-encoding :message-id; bh=mrCnj+peIRZyFKKUom45vtHHHalEHjngUu8ydLdXIQI=; b=Nos28h4Ki/p8AmLuXUIXnY08sJVz5cZfP7iobo92FgBcAaISCSmb+j/226Ei+CM1cN E/379QNgPRWBM0YC7x6zP5U4BfI7HBYnZEjm5LVOrQZuMYavm62xesV8Yq/wMeRSmNiO wlhgPUBIWpJa25vLEGPFSAY+xeYhS45LTQj94= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:subject:date:user-agent:mime-version:content-type :content-transfer-encoding:message-id; b=G74tCLyIQKXgrQXPzZF94Mu3MBiPsEAYsLOz8YvF6tSVpv1DmfnBPJHznKvXtXt+vR vPizFC34icWwnEdzfLZ8q9qh3QWjpGRpfJnv7sa5bFOKMCnRH37Ev9zGWrphhgiOKvuv igizNl84V7Lb5mNiQc8hgdqbMPLIyVYRdli20= Received: by 10.90.86.10 with SMTP id j10mr5493898agb.59.1242617665125; Sun, 17 May 2009 20:34:25 -0700 (PDT) Received: from aldebaran.localnet (r190-64-27-81.dialup.adsl.anteldata.net.uy [190.64.27.81]) by mx.google.com with ESMTPS id 6sm12119406ywi.58.2009.05.17.20.34.23 (version=TLSv1/SSLv3 cipher=RC4-MD5); Sun, 17 May 2009 20:34:24 -0700 (PDT) Sender: Mauricio Campiglia From: Mauricio Campiglia To: chalpin@cs.wisc.edu Subject: Incorrect packet traversal path on your Netfilter page? Date: Mon, 18 May 2009 00:34:03 -0300 User-Agent: KMail/1.11.2 (Linux/2.6.26-2-686; KDE/4.2.2; i686; ; ) MIME-Version: 1.0 Content-Type: multipart/signed; boundary="nextPart2389499.aip7uZ08Kp"; protocol="application/pgp-signature"; micalg=pgp-sha1 Content-Transfer-Encoding: 7bit Message-Id: <200905180034.15041.mauricio@campiglia.org> (sfid-20090517_22343_E096A717) X-Seen-By: mailfromd 4.1 silica.cs.wisc.edu X-Virus-Status: No X-Virus-Checker-Version: clamassassin 1.2.4 with clamdscan / ClamAV 0.95.1/9365/Sat May 16 07:41:29 2009 X-CRM114-Version: 20090423-BlameSteveJobs ( TRE 0.7.5 (LGPL) ) MR-9B0B3C9E X-CRM114-CacheID: sfid-20090517_22343_E096A717 X-CRM114-Status: UNSURE ( 9.16 ) X-CRM114-Notice: Please train this message. X-TMDA-Confirm-Done: 1242617693.82104.1b4d37 X-TMDA-Released: Mon, 18 May 2009 00:41:42 -0500 X-RecFor-Recipient: chalpin@cs.wisc.edu --nextPart2389499.aip7uZ08Kp Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Corey, I have come across your Netfilter page [0]. Thanks for letting people=20 understand Netfilter in a simple and straightforward way. I have,=20 nevertheless, a couple of diferences on wich, afaik, are the correct=20 traversal of packets. Where you write: forwarded nat/PREROUTING -> filter/FORWARD -> nat/OUTPUT -> nat/POSTROUTING=20 outgoing filter/OUTPUT -> nat/PREROUTING -> nat/OUTPUT -> nat/POSTROUTING I think the correct flows are [1]: forwarded nat/PREROUTING -> filter/FORWARD -> nat/POSTROUTING=20 outgoing nat/OUTPUT -> filter/OUTPUT -> nat/POSTROUTING [0]http://pages.cs.wisc.edu/~chalpin/project/netfilter.html [1]http://pub1.zcjh.tpc.edu.tw:9100/computer/Lists/Discussion/Attachments/1= /PacketFlow.png Regards, Mauricio Campiglia =2D-=20 =C2=ABHistory is a vast early warning system.=C2=BB --Norman Cousins-- --nextPart2389499.aip7uZ08Kp Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEABECAAYFAkoQ1ywACgkQ++X8pZRW0Wq8CgCgoi4ET6UwUuqNkiJX2SUVCNq5 zs8AniaI78P46h9ZFiUc+pxfapI2s0mF =/yJS -----END PGP SIGNATURE----- --nextPart2389499.aip7uZ08Kp-- Mail-GnuPG-0.19/t/msg/inline-signed-qp.eml000444001750001750 146012141170275 20603 0ustar00bremnerbremner000000000000From: David Bremner To: ddb@cpan.org Subject: testing inline PGP User-Agent: Notmuch/0.4 (http://notmuchmail.org) Emacs/23.2.1 (x86_64-pc-linux-gnu) Date: Sun, 12 Dec 2010 15:26:43 -0400 Message-ID: <87bp4qrdvw.fsf@zancas.localnet> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Sender-Verified: bremner@unb.ca =2D----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 This message has tr=C3=A9s ex=C3=B6tic characters. =2D----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) iJwEAQECAAYFAk0FIfQACgkQTiiN/0Um85n1pAP9GG4DFyjdvhv6M77tf7dmhn+w QeWF3jhw2z5agg3m7N063lO8UrRn1+wap4XsuRGDAWYoIT+nR9UJccl3VV22WpW6 hMYhQZTKiOkHlKiNRoy+Zb+3P9ohpGguL0+VxqLKa7KibWC06gIkBOFTnxSaIakB xoSuXPvRiK0FYwxnqWo=3D =3DEDyV =2D----END PGP SIGNATURE----- Mail-GnuPG-0.19/t/msg/inline-encrypted-qp.eml000444001750001750 230712141170275 21330 0ustar00bremnerbremner000000000000From: David Bremner User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.15) Gecko/20101030 Icedove/3.0.10 MIME-Version: 1.0 To: mail@gnupg.dom Subject: testing encryption X-Enigmail-Version: 1.0.1 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Sender-Verified: ddb@cpan.org -----BEGIN PGP MESSAGE----- Charset: ISO-8859-1 Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ hQEOAwAAAAAAAAAAEAP/XtqY1rAIP5O3155UISmIXhUIbMZ4D2UYq6crO1m1a763 miPVrno2xXZ+3A86x47ozTivczg/hkbpFnoXuewSVOfAnJkS2P+Y5pfY3EggDbjt d1OCLadcyvfvxnPj5p6/RjgS5NPhgSl/sDqdqKDXByAW7rCK4tzeTnVUEAsorL0D /jJ0FTEx1rpDsjz5feZ+pJqoLaTXf/0Sa5SY0/S8Ss8o++c+pFcjfQqJzfBQy1// wX9A5rTGuUzthrU78aNbapp4mHN1kCWX2K6HNLFx6nH1scWigWf/fCx09NRkw+nu Fld8FaVkO+mSLhITRLW5meZTAIEuI7eALAoYznroVRFThIwDl+XMhKsBGIsBA/4i vDaV3e8LZV19BVrCyHP1BcF8kFemQG/KOvGMWl9zue/uszqwCHR32ImIUhEXKV1/ cOSTJfRG7todz6TijRWQLFjBVn4gBdZKT8z7t+M8VoeU65jKELEceQi6thDGioaV 1WzJo1mlGVnr3+OlTQr8RVJX/HOq2BNGp4UK8fHwqtJcAai6qLKLs2zFxu0DmZfy Our1TNz2e31HpiinhDcVHO3ZVcz+eZlziQGZa/SHt2lOFYbxFzQAxfW01Er7n8VU 4/Ak/e7pWzoUdEwlHTEpwGRgo4V70Dp0vqPIf3o=3D =3D2aPt -----END PGP MESSAGE----- Mail-GnuPG-0.19/lib000755001750001750 012141170275 14320 5ustar00bremnerbremner000000000000Mail-GnuPG-0.19/lib/Mail000755001750001750 012141170275 15202 5ustar00bremnerbremner000000000000Mail-GnuPG-0.19/lib/Mail/GnuPG.pm000444001750001750 7200512141170275 16701 0ustar00bremnerbremner000000000000package Mail::GnuPG; =head1 NAME Mail::GnuPG - Process email with GPG. =head1 SYNOPSIS use Mail::GnuPG; my $mg = new Mail::GnuPG( key => 'ABCDEFGH' ); $ret = $mg->mime_sign( $MIMEObj, 'you@my.dom' ); =head1 DESCRIPTION Use GnuPG::Interface to process or create PGP signed or encrypted email. =cut use 5.006; use strict; use warnings; our $VERSION = '0.19'; my $DEBUG = 0; use GnuPG::Interface; use File::Spec; use File::Temp; use IO::Handle; use MIME::Entity; use MIME::Parser; use Mail::Address; use IO::Select; use Errno qw(EPIPE); =head2 new Create a new Mail::GnuPG instance. Arguments: Paramhash... key => gpg key id keydir => gpg configuration/key directory passphrase => primary key password use_agent => use gpg-agent if non-zero always_trust => always trust a public key # FIXME: we need more things here, maybe primary key id. =cut sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = { key => undef, keydir => undef, passphrase => "", gpg_path => "gpg", use_agent => 0, @_ }; $self->{last_message} = []; $self->{plaintext} = []; bless ($self, $class); return $self; } sub _set_options { my ($self,$gnupg) = @_; $gnupg->options->meta_interactive( 0 ); $gnupg->options->hash_init( armor => 1, ( defined $self->{keydir} ? (homedir => $self->{keydir}) : () ), ( defined $self->{key} ? ( default_key => $self->{key} ) : () ), # ( defined $self->{passphrase} ? # ( passphrase => $self->{passphrase} ) : () ), ); if ($self->{use_agent}) { push @{$gnupg->options->extra_args}, '--use-agent'; } if (defined $self->{always_trust}) { $gnupg->options->always_trust($self->{always_trust}) } $gnupg->call( $self->{gpg_path} ) if defined $self->{gpg_path}; } =head2 decrypt Decrypt an encrypted message Input: MIME::Entity containing email message to decrypt. The message can either be in RFC compliant-ish multipart/encrypted format, or just a single part ascii armored message. Output: On Failure: Exit code of gpg. (0 on success) On Success: (just encrypted) (0, undef, undef) On success: (signed and encrypted) ( 0, keyid, # ABCDDCBA emailaddress # Foo Bar ) where the keyid is the key that signed it, and emailaddress is full name and email address of the primary uid $self->{last_message} => any errors from gpg $self->{plaintext} => plaintext output from gpg $self->{decrypted} => parsed output as MIME::Entity =cut sub decrypt { my ($self, $message) = @_; my $ciphertext = ""; $self->{last_message} = []; unless (ref $message && $message->isa("MIME::Entity")) { die "decrypt only knows about MIME::Entitys right now"; return 255; } my $armor_message = 0; if ($message->effective_type =~ m!multipart/encrypted!) { die "multipart/encrypted with more than two parts" if ($message->parts != 2); die "Content-Type not pgp-encrypted" unless $message->parts(0)->effective_type =~ m!application/pgp-encrypted!; $ciphertext = $message->parts(1)->stringify_body; } elsif ($message->bodyhandle->as_string =~ m!^-----BEGIN PGP MESSAGE-----!m ) { $ciphertext = $message->bodyhandle->as_string; $armor_message = 1; } else { die "Unknown Content-Type or no PGP message in body" } my $gnupg = GnuPG::Interface->new(); $self->_set_options($gnupg); # how we create some handles to interact with GnuPG # This time we'll catch the standard error for our perusing # as well as passing in the passphrase manually # as well as the status information given by GnuPG my ( $input, $output, $error, $passphrase_fh, $status_fh ) = ( new IO::Handle, new IO::Handle,new IO::Handle, new IO::Handle,new IO::Handle,); my $handles = GnuPG::Handles->new( stdin => $input, stdout => $output, stderr => $error, passphrase => $passphrase_fh, status => $status_fh, ); # this sets up the communication my $pid = $gnupg->decrypt( handles => $handles ); die "NO PASSPHRASE" unless defined $passphrase_fh; my $read = _communicate([$output, $error, $status_fh], [$input, $passphrase_fh], { $input => $ciphertext, $passphrase_fh => $self->{passphrase}} ); my @plaintext = split(/^/m, $read->{$output}); my @error_output = split(/^/m, $read->{$error}); my @status_info = split(/^/m, $read->{$status_fh}); waitpid $pid, 0; my $return = $?; $return = 0 if $return == -1; my $exit_value = $return >> 8; $self->{last_message} = \@error_output; $self->{plaintext} = \@plaintext; my $parser = new MIME::Parser; $parser->output_to_core(1); # for armor message (which usually contain no MIME entity) # and if the first line seems to be no header, add an empty # line at the top, otherwise the first line of a text message # will be removed by the parser. if ( $armor_message and $plaintext[0] and $plaintext[0] !~ /^[\w-]+:/ ) { unshift @plaintext, "\n"; } my $entity = $parser->parse_data(\@plaintext); $self->{decrypted} = $entity; return $exit_value if $exit_value; # failure # if the message was signed and encrypted, extract the signature # information and return it. In some theory or another, you can't # trust an unsigned encrypted message is from who it says signed it. # (Although I think it would have to go hand in hand at some point.) # FIXME: these regex are likely to break under non english locales. my $result = join "", @error_output; my ($keyid) = $result =~ /using \S+ key ID (.+)$/m; my ($pemail) = $result =~ /Good signature from "(.+)"$/m; return ($exit_value,$keyid,$pemail); } =head2 get_decrypt_key determines the decryption key (and corresponding mail) of a message Input: MIME::Entity containing email message to analyze. The message can either be in RFC compliant-ish multipart/signed format, or just a single part ascii armored message. Output: $key -- decryption key $mail -- corresponding mail address =cut sub get_decrypt_key { my ($self, $message) = @_; unless (ref $message && $message->isa("MIME::Entity")) { die "decrypt only knows about MIME::Entitys right now"; } my $ciphertext; if ($message->effective_type =~ m!multipart/encrypted!) { die "multipart/encrypted with more than two parts" if ($message->parts != 2); die "Content-Type not pgp-encrypted" unless $message->parts(0)->effective_type =~ m!application/pgp-encrypted!; $ciphertext = $message->parts(1)->stringify_body; } elsif ($message->bodyhandle->as_string =~ m!^-----BEGIN PGP MESSAGE-----!m ) { $ciphertext = $message->bodyhandle->as_string; } else { die "Unknown Content-Type or no PGP message in body" } my $gnupg = GnuPG::Interface->new(); # how we create some handles to interact with GnuPG # This time we'll catch the standard error for our perusing # as well as passing in the passphrase manually # as well as the status information given by GnuPG my ( $input, $output, $stderr ) = ( new IO::Handle, new IO::Handle, new IO::Handle ); my $handles = GnuPG::Handles->new( stdin => $input, stdout => $output, stderr => $stderr, ); # this sets up the communication my $pid = $gnupg->wrap_call( handles => $handles, commands => [ "--decrypt" ], command_args => [ "--batch", "--list-only", "--status-fd", "1" ], ); my $read = _communicate([$output], [$input], { $input => $ciphertext }); # reading the output my @result = split(/^/m, $read->{$output}); # clean up the finished GnuPG process waitpid $pid, 0; my $return = $?; $return = 0 if $return == -1; my $exit_value = $return >> 8; # set last_message $self->{last_message} = \@result; # grep ENC_TO and NO_SECKEY items my (@enc_to_keys, %no_sec_keys); for ( @result ) { push @enc_to_keys, $1 if /ENC_TO\s+([^\s]+)/; $no_sec_keys{$1} = 1 if /NO_SECKEY\s+([^\s]+)/; } # find first key we have the secret portion of my $key; foreach my $k ( @enc_to_keys ) { if ( not exists $no_sec_keys{$k} ) { $key = $k; last; } } return if not $key; # get mail address of this key die "Invalid Key Format: $key" unless $key =~ /^[0-9A-F]+$/i; my $cmd = $self->{gpg_path} . " --with-colons --list-keys $key 2>&1"; my $gpg_out = qx[ $cmd ]; ## FIXME: this should probably use open| instead. die "Couldn't find key $key in keyring" if $gpg_out !~ /\S/ or $?; my $mail = (split(":", $gpg_out))[9]; return ($mail, $key); } =head2 verify verify a signed message Input: MIME::Entity containing email message to verify. The message can either be in RFC compliant-ish multipart/signed format, or just a single part ascii armored message. Note that MIME-encoded data should be supplied unmodified inside the MIME::Entity input message, otherwise the signature will be broken. Since MIME-tools version 5.419, this can be achieved with the C method of MIME::Parser. See the MIME::Parser documentation for more information. Output: On error: Exit code of gpg. (0 on success) On success ( 0, keyid, # ABCDDCBA emailaddress # Foo Bar ) where the keyid is the key that signed it, and emailaddress is full name and email address of the primary uid $self->{last_message} => any errors from gpg =cut # Verify RFC2015/RFC3156 email sub verify { my ($self, $message) = @_; my $ciphertext = ""; my $sigtext = ""; $self->{last_message} = []; unless (ref $message && $message->isa("MIME::Entity")) { die "VerifyMessage only knows about MIME::Entitys right now"; return 255; } if ($message->effective_type =~ m!multipart/signed!) { die "multipart/signed with more than two parts" if ($message->parts != 2); die "Content-Type not pgp-signed" unless $message->parts(1)->effective_type =~ m!application/pgp-signature!; $ciphertext = $message->parts(0)->as_string; $sigtext = $message->parts(1)->stringify_body; } elsif ( $message->bodyhandle and $message->bodyhandle->as_string =~ m!^-----BEGIN PGP SIGNED MESSAGE-----!m ) { # don't use not $message->body_as_string here, because # the body isn't decoded in this case!!! # (which is evil for quoted-printable transfer encoding) # also the headers and stuff are not needed here $ciphertext = undef; $sigtext = $message->bodyhandle->as_string; # well, actually both } else { die "Unknown Content-Type or no PGP message in body" } my $gnupg = GnuPG::Interface->new(); $self->_set_options($gnupg); # how we create some handles to interact with GnuPG my $input = IO::Handle->new(); my $error = IO::Handle->new(); my $handles = GnuPG::Handles->new( stderr => $error, stdin => $input ); my ($sigfh, $sigfile) = File::Temp::tempfile('mgsXXXXXXXX', DIR => File::Spec->tmpdir, UNLINK => 1, ); print $sigfh $sigtext; close($sigfh); my ($datafh, $datafile) = File::Temp::tempfile('mgdXXXXXX', DIR => File::Spec->tmpdir, UNLINK => 1, ); # according to RFC3156 all line endings MUST be CR/LF if ( defined $ciphertext ) { $ciphertext =~ s/\x0A/\x0D\x0A/g; $ciphertext =~ s/\x0D+/\x0D/g; } # Read the (unencoded) body data: # as_string includes the header portion print $datafh $ciphertext if $ciphertext; close($datafh); my $pid = $gnupg->verify( handles => $handles, command_args => ( $ciphertext ? ["$sigfile", "$datafile"] : "$sigfile" ), ); my $read = _communicate([$error], [$input], {$input => ''}); my @result = split(/^/m, $read->{$error}); unlink $sigfile, $datafile; waitpid $pid, 0; my $return = $?; $return = 0 if $return == -1; my $exit_value = $return >> 8; $self->{last_message} = [@result]; return $exit_value if $exit_value; # failure # FIXME: these regex are likely to break under non english locales. my $result = join "", @result; my ($keyid) = $result =~ /using \S+ key ID (.+)$/m; my ($pemail) = $result =~ /Good signature from "(.+)"$/m; return ($exit_value,$keyid,$pemail); } # Should this go elsewhere? The Key handling stuff doesn't seem to # make sense in a Mail:: module. my %key_cache; my $key_cache_age = 0; my $key_cache_expire = 60*60*30; # 30 minutes sub _rebuild_key_cache { my $self = shift; local $_; %key_cache = (); my $gnupg = GnuPG::Interface->new(); $self->_set_options($gnupg); my @keys = $gnupg->get_public_keys(); foreach my $key (@keys) { foreach my $uid ($key->user_ids) { # M::A may not parse the gpg stuff properly. Cross fingers my ($a) = Mail::Address->parse($uid->as_string); # list context, please $key_cache{$a->address}=1 if ref $a; } } } =head2 has_public_key Does the keyring have a public key for the specified email address? FIXME: document better. talk about caching. maybe put a better interface in. =cut sub has_public_key { my ($self,$address) = @_; # cache aging is disabled until someone has enough time to test this if (0) { $self->_rebuild_key_cache() unless ($key_cache_age); if ( $key_cache_age && ( time() - $key_cache_expire > $key_cache_age )) { $self->_rebuild_key_cache(); } } $self->_rebuild_key_cache(); return 1 if exists $key_cache{$address}; return 0; } =head2 mime_sign sign an email message Input: MIME::Entity containing email message to sign Output: Exit code of gpg. (0 on success) $self->{last_message} => any errors from gpg The provided $entity will be signed. (i.e. it _will_ be modified.) =cut sub mime_sign { my ($self,$entity) = @_; die "Not a mime entity" unless $entity->isa("MIME::Entity"); $entity->make_multipart; my $workingentity = $entity; if ($entity->parts > 1) { $workingentity = MIME::Entity->build(Type => $entity->head->mime_attr("Content-Type")); $workingentity->add_part($_) for ($entity->parts); $entity->parts([]); $entity->add_part($workingentity); } my $gnupg = GnuPG::Interface->new(); $self->_set_options( $gnupg ); my ( $input, $output, $error, $passphrase_fh, $status_fh ) = ( new IO::Handle, new IO::Handle,new IO::Handle, new IO::Handle,new IO::Handle,); my $handles = GnuPG::Handles->new( stdin => $input, stdout => $output, stderr => $error, passphrase => $passphrase_fh, status => $status_fh, ); my $pid = $gnupg->detach_sign( handles => $handles ); die "NO PASSPHRASE" unless defined $passphrase_fh; # this passes in the plaintext my $plaintext; if ($workingentity eq $entity) { $plaintext = $entity->parts(0)->as_string; } else { $plaintext = $workingentity->as_string; } # according to RFC3156 all line endings MUST be CR/LF $plaintext =~ s/\x0A/\x0D\x0A/g; $plaintext =~ s/\x0D+/\x0D/g; # DEBUG: # print "SIGNING THIS STRING ----->\n"; # $plaintext =~ s/\n/-\n/gs; # warn("SIGNING:\n$plaintext<<<"); # warn($entity->as_string); # print STDERR $plaintext; # print "<----\n"; my $read = _communicate([$output, $error, $status_fh], [$input, $passphrase_fh], { $input => $plaintext, $passphrase_fh => $self->{passphrase}} ); my @signature = split(/^/m, $read->{$output}); my @error_output = split(/^/m, $read->{$error}); my @status_info = split(/^/m, $read->{$status_fh}); waitpid $pid, 0; my $return = $?; $return = 0 if $return == -1; my $exit_value = $return >> 8; $self->{last_message} = \@error_output; $entity->attach( Type => "application/pgp-signature", Disposition => "inline", Data => [@signature], Encoding => "7bit"); $entity->head->mime_attr("Content-Type","multipart/signed"); $entity->head->mime_attr("Content-Type.protocol","application/pgp-signature"); # $entity->head->mime_attr("Content-Type.micalg","pgp-md5"); # Richard Hirner notes that Thunderbird/Enigmail really wants a micalg # of pgp-sha1 (which will be GPG version dependent.. older versions # used md5. For now, until we can detect which type was used, the end # user should read the source code, notice this comment, and insert # the appropriate value themselves. return $exit_value; } =head2 clear_sign clearsign the body of an email message Input: MIME::Entity containing email message to sign. This entity MUST have a body. Output: Exit code of gpg. (0 on success) $self->{last_message} => any errors from gpg The provided $entity will be signed. (i.e. it _will_ be modified.) =cut sub clear_sign { my ($self, $entity) = @_; die "Not a mime entity" unless $entity->isa("MIME::Entity"); my $body = $entity->bodyhandle; die "Message has no body" unless defined $body; my $gnupg = GnuPG::Interface->new(); $self->_set_options( $gnupg ); $gnupg->passphrase ( $self->{passphrase} ); my ( $input, $output, $error ) = ( new IO::Handle, new IO::Handle, new IO::Handle); my $handles = GnuPG::Handles->new( stdin => $input, stdout => $output, stderr => $error, ); my $pid = $gnupg->clearsign ( handles => $handles ); my $plaintext = $body->as_string; $plaintext =~ s/\x0A/\x0D\x0A/g; $plaintext =~ s/\x0D+/\x0D/g; my $read = _communicate([$output, $error], [$input], { $input => $plaintext }); my @ciphertext = split(/^/m, $read->{$output}); my @error_output = split(/^/m, $read->{$error}); waitpid $pid, 0; my $return = $?; $return = 0 if $return == -1; my $exit_value = $return >> 8; $self->{last_message} = [@error_output]; my $io = $body->open ("w") or die "can't open entity body"; $io->print (join('',@ciphertext)); $io->close; return $exit_value; } =head2 ascii_encrypt encrypt an email message body using ascii armor Input: MIME::Entity containing email message to encrypt. This entity MUST have a body. list of recipients Output: Exit code of gpg. (0 on success) $self->{last_message} => any errors from gpg The provided $entity will be encrypted. (i.e. it _will_ be modified.) =head2 ascii_signencrypt encrypt and sign an email message body using ascii armor Input: MIME::Entity containing email message to encrypt. This entity MUST have a body. list of recipients Output: Exit code of gpg. (0 on success) $self->{last_message} => any errors from gpg The provided $entity will be encrypted. (i.e. it _will_ be modified.) =cut sub ascii_encrypt { my ($self, $entity, @recipients) = @_; $self->_ascii_encrypt($entity, 0, @recipients); } sub ascii_signencrypt { my ($self, $entity, @recipients) = @_; $self->_ascii_encrypt($entity, 1, @recipients); } sub _ascii_encrypt { my ($self, $entity, $sign, @recipients) = @_; die "Not a mime entity" unless $entity->isa("MIME::Entity"); my $body = $entity->bodyhandle; die "Message has no body" unless defined $body; my $plaintext = $body->as_string; my $gnupg = GnuPG::Interface->new(); $self->_set_options( $gnupg ); $gnupg->passphrase ( $self->{passphrase} ); $gnupg->options->push_recipients( $_ ) for @recipients; my ( $input, $output, $error ) = ( new IO::Handle, new IO::Handle, new IO::Handle); my $handles = GnuPG::Handles->new( stdin => $input, stdout => $output, stderr => $error, ); my $pid = do { if ( $sign ) { $gnupg->sign_and_encrypt ( handles => $handles ); } else { $gnupg->encrypt ( handles => $handles ); } }; my $read = _communicate([$output, $error], [$input], { $input => $plaintext }); my @ciphertext = split(/^/m, $read->{$output}); my @error_output = split(/^/m, $read->{$error}); waitpid $pid, 0; my $return = $?; $return = 0 if $return == -1; my $exit_value = $return >> 8; $self->{last_message} = [@error_output]; my $io = $body->open ("w") or die "can't open entity body"; $io->print (join('',@ciphertext)); $io->close; return $exit_value; } =head2 mime_encrypt encrypt an email message Input: MIME::Entity containing email message to encrypt list of email addresses to sign to Output: Exit code of gpg. (0 on success) $self->{last_message} => any errors from gpg The provided $entity will be encrypted. (i.e. it _will_ be modified.) =head2 mime_signencrypt sign and encrypt an email message Input: MIME::Entity containing email message to sign encrypt list of email addresses to sign to Output: Exit code of gpg. (0 on success) $self->{last_message} => any errors from gpg The provided $entity will be encrypted. (i.e. it _will_ be modified.) =cut sub mime_encrypt { my $self = shift; $self->_mime_encrypt(0,@_); } sub mime_signencrypt { my $self = shift; $self->_mime_encrypt(1,@_); } sub _mime_encrypt { my ($self,$sign,$entity,@recipients) = @_; die "Not a mime entity" unless $entity->isa("MIME::Entity"); my $workingentity = $entity; $entity->make_multipart; if ($entity->parts > 1) { $workingentity = MIME::Entity->build(Type => $entity->head->mime_attr("Content-Type")); $workingentity->add_part($_) for ($entity->parts); $entity->parts([]); $entity->add_part($workingentity); } my $gnupg = GnuPG::Interface->new(); $gnupg->options->push_recipients( $_ ) for @recipients; $self->_set_options($gnupg); my ( $input, $output, $error, $passphrase_fh, $status_fh ) = ( new IO::Handle, new IO::Handle,new IO::Handle, new IO::Handle,new IO::Handle,); my $handles = GnuPG::Handles->new( stdin => $input, stdout => $output, stderr => $error, passphrase => $passphrase_fh, status => $status_fh, ); my $pid = do { if ($sign) { $gnupg->sign_and_encrypt( handles => $handles ); } else { $gnupg->encrypt( handles => $handles ); } }; # this passes in the plaintext my $plaintext; if ($workingentity eq $entity) { $plaintext= $entity->parts(0)->as_string; } else { $plaintext=$workingentity->as_string; } # no need to mangle line endings for encryption (RFC3156) # $plaintext =~ s/\n/\x0D\x0A/sg; # should we store this back into the body? # DEBUG: #print "ENCRYPTING THIS STRING ----->\n"; # print $plaintext; # print "<----\n"; die "NO PASSPHRASE" unless defined $passphrase_fh; my $read = _communicate([$output, $error, $status_fh], [$input, $passphrase_fh], { $input => $plaintext, $passphrase_fh => $self->{passphrase}} ); my @plaintext = split(/^/m, $read->{$output}); my @ciphertext = split(/^/m, $read->{$output}); my @error_output = split(/^/m, $read->{$error}); my @status_info = split(/^/m, $read->{$status_fh}); waitpid $pid, 0; my $return = $?; $return = 0 if $return == -1; my $exit_value = $return >> 8; $self->{last_message} = [@error_output]; $entity->parts([]); # eliminate all parts $entity->attach(Type => "application/pgp-encrypted", Disposition => "inline", Filename => "msg.asc", Data => ["Version: 1",""], Encoding => "7bit"); $entity->attach(Type => "application/octet-stream", Disposition => "inline", Data => [@ciphertext], Encoding => "7bit"); $entity->head->mime_attr("Content-Type","multipart/encrypted"); $entity->head->mime_attr("Content-Type.protocol","application/pgp-encrypted"); $exit_value; } =head2 is_signed best guess as to whether a message is signed or not (by looking at the mime type and message content) Input: MIME::Entity containing email message to test Output: True or False value =head2 is_encrypted best guess as to whether a message is signed or not (by looking at the mime type and message content) Input: MIME::Entity containing email message to test Output: True or False value =cut sub is_signed { my ($self,$entity) = @_; return 1 if (($entity->effective_type =~ m!multipart/signed!) || ($entity->as_string =~ m!^-----BEGIN PGP SIGNED MESSAGE-----!m)); return 0; } sub is_encrypted { my ($self,$entity) = @_; return 1 if (($entity->effective_type =~ m!multipart/encrypted!) || ($entity->as_string =~ m!^-----BEGIN PGP MESSAGE-----!m)); return 0; } # interleave reads and writes # input parameters: # $rhandles - array ref with a list of file handles for reading # $whandles - array ref with a list of file handles for writing # $wbuf_of - hash ref indexed by the stringified handles # containing the data to write # return value: # $rbuf_of - hash ref indexed by the stringified handles # containing the data that has been read # # read and write errors due to EPIPE (gpg exit) are skipped silently on the # assumption that gpg will explain the problem on the error handle # # other errors cause a non-fatal warning, processing continues on the rest # of the file handles # # NOTE: all the handles get closed inside this function sub _communicate { my $blocksize = 2048; my ($rhandles, $whandles, $wbuf_of) = @_; my $rbuf_of = {}; # the current write offsets, again indexed by the stringified handle my $woffset_of; my $reader = IO::Select->new; for (@$rhandles) { $reader->add($_); $rbuf_of->{$_} = ''; } my $writer = IO::Select->new; for (@$whandles) { die("no data supplied for handle " . fileno($_)) if !exists $wbuf_of->{$_}; if ($wbuf_of->{$_}) { $writer->add($_); } else { # nothing to write close $_; } } # we'll handle EPIPE explicitly below local $SIG{PIPE} = 'IGNORE'; while ($reader->handles || $writer->handles) { my @ready = IO::Select->select($reader, $writer, undef, undef); if (!@ready) { die("error doing select: $!"); } my ($rready, $wready, $eready) = @ready; if (@$eready) { die("select returned an unexpected exception handle, this shouldn't happen"); } for my $rhandle (@$rready) { my $n = fileno($rhandle); my $count = sysread($rhandle, $rbuf_of->{$rhandle}, $blocksize, length($rbuf_of->{$rhandle})); warn("read $count bytes from handle $n") if $DEBUG; if (!defined $count) { # read error if ($!{EPIPE}) { warn("read failure (gpg exited?) from handle $n: $!") if $DEBUG; } else { warn("read failure from handle $n: $!"); } $reader->remove($rhandle); close $rhandle; next; } if ($count == 0) { # EOF warn("read done from handle $n") if $DEBUG; $reader->remove($rhandle); close $rhandle; next; } } for my $whandle (@$wready) { my $n = fileno($whandle); $woffset_of->{$whandle} = 0 if !exists $woffset_of->{$whandle}; my $count = syswrite($whandle, $wbuf_of->{$whandle}, $blocksize, $woffset_of->{$whandle}); if (!defined $count) { if ($!{EPIPE}) { # write error warn("write failure (gpg exited?) from handle $n: $!") if $DEBUG; } else { warn("write failure from handle $n: $!"); } $writer->remove($whandle); close $whandle; next; } warn("wrote $count bytes to handle $n") if $DEBUG; $woffset_of->{$whandle} += $count; if ($woffset_of->{$whandle} >= length($wbuf_of->{$whandle})) { warn("write done to handle $n") if $DEBUG; $writer->remove($whandle); close $whandle; next; } } } return $rbuf_of; } # FIXME: there's no reason why is_signed and is_encrypted couldn't be # static (class) methods, so maybe we should support that. # FIXME: will we properly deal with signed+encrypted stuff? probably not. # Autoload methods go after =cut, and are processed by the autosplit program. 1; __END__ =head1 LICENSE Copyright 2003 Best Practical Solutions, LLC This program is free software; you can redistribute it and/or modify it under the terms of either: a) the GNU General Public License as published by the Free Software Foundation; version 2 http://www.opensource.org/licenses/gpl-license.php b) the "Artistic License" http://www.opensource.org/licenses/artistic-license.php This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the Artistic License for more details. =head1 AUTHOR Robert Spier David Bremner =head1 BUGS/ISSUES/PATCHES Please send all bugs/issues/patches to bug-Mail-GnuPG@rt.cpan.org =head1 SEE ALSO L. GnuPG::Interface, MIME::Entity =cut