#! /usr/bin/perl -w $ID = q$Id$; # # run-tests -- Test signcontrol and pgpverify. # # Written by Russ Allbery # This work is hereby placed in the public domain by its author. use strict; use vars qw($ID); ############################################################################## # Test suite preparation ############################################################################## # Find a program on the user's path. sub find_program { my ($program) = @_; my @path = split (/:/, $ENV{PATH}); for (@path) { return "$_/$program" if -x "$_/$program"; } return $program; } # Given the path to the PGP program to use, generate a fixed version of # pgpverify in the current directory. Takes care of a few other things, like # making sure that there's a temporary directory for it to put its files. # Expects to find normal pgpverify up one directory. sub fix_pgpverify { my ($path) = @_; my $gpg = ($path =~ /gpgv$/); mkdir ('tmp', 0755); open (BASIC, "../pgpverify") or die "Can't open ../pgpverify: $!\n"; open (FIXED, "> pgpverify") or die "Can't create pgpverify: $!\n"; while () { s%^\# \$gpgv = \'.*%\$gpgv = '$path';% if $gpg; s%^\$pgp = \'.*%\$pgp = '$path';% unless $gpg; s%^\# \$keyring = \'.*%\$keyring = './keyring';%; s%^\$tmpdir = \".*%\$tmpdir = './tmp';%; s%^\$syslog_method = \'.*%\$syslog_method = '';%; print FIXED; } close BASIC; close FIXED; chmod (0755, 'pgpverify'); } # Given the path to the PGP program to use, generate a fixed version of # signcontrol in the current directory. It also sets up signcontrol to sign # example.* control messages with the testing key. Expects to find the normal # signcontrol up one level. sub fix_signcontrol { my ($path) = @_; open (BASIC, "../signcontrol") or die "Can't open ../signcontrol: $!\n"; open (FIXED, "> signcontrol") or die "Can't create signcontrol: $!\n"; while () { s/INSERT_YOUR_PGP_USERID/testing/; s%^\$pgppassfile = \'.*%\$pgppassfile = 'keyring/passphrase';%; s/^\$pgp = \".*/\$pgp = '$path';/; s%^\$pgplock = .*%\$pgplock = 'keyring/passphrase';%; s/YOUR_ADDRESS_AND_NAME/Test Signer /; s/ADDRESS_FOR_Approved_HEADER/test\@example.com/; s/FULL_HOST_NAME/example.com/; s/HIERARCHIES/example/; print FIXED; } close BASIC; close FIXED; chmod (0755, 'signcontrol'); } ############################################################################## # Individual tests ############################################################################## # Run pgpverify on a given file, expecting the given signer. Warn if # something goes wrong and return true on success and false on failure. sub pgpverify { my ($file, $expected) = @_; my $signer = `./pgpverify < $file`; chomp $signer; if ($? == 0 && $signer eq $expected) { return 1; } else { print "pgpverify exited with status ", ($? >> 8), "\n" if $? != 0; print "pgpverify said the signer was $signer\n" if $signer; return 0; } } # Run pgpverify on a given file, expecting failure with the provided status # code. Warn if we succeed and return true on success of the test and false # on failure. sub pgpverify_fail { my ($file, $status) = @_; my $signer = `./pgpverify < $file 2> /dev/null`; chomp $signer; if (($? >> 8) == $status && !$signer) { return 1; } else { print "pgpverify exited with status ", ($? >> 8), "\n"; print "pgpverify said the signer was $signer\n" if $signer; return 0; } } ############################################################################## # Test suite ############################################################################## # Running totals. my $tests = 0; my $failed = 0; # Tell signcontrol where to find the PGP keyrings. $ENV{PGPPATH} = './keyring'; $ENV{GNUPGHOME} = './keyring'; # Set up pgpverify to use PGP first. my $pgp = find_program ('pgp'); fix_pgpverify ($pgp); # Check the signature on sample.control. if (pgpverify ('../sample.control', 'news.announce.newgroups')) { print "PASS: pgpverify-pgp\n"; } else { print "FAIL: pgpverify-pgp\n"; $failed++; } $tests++; # Now, try with GnuPG. my $gpgv = find_program ('gpgv'); fix_pgpverify ($gpgv); # Check the signature on sample.control. if (pgpverify ('../sample.control', 'news.announce.newgroups')) { print "PASS: pgpverify-gpg\n"; } else { print "FAIL: pgpverify-gpg\n"; $failed++; } $tests++; # Convert sample.control to wire format and then check its signature. open (SAMPLE, '../sample.control') or die "Can't open ../sample.control: $!\n"; open (WIRE, '> signed') or die "Can't create signed: $!\n"; while () { s/\n\z/\r\n/; s/^\./../; print WIRE; } print WIRE ".\r\n"; close SAMPLE; close WIRE; if (pgpverify ('signed', 'news.announce.newgroups')) { print "PASS: pgpverify-wire\n"; } else { print "FAIL: pgpverify-wire\n"; $failed++; } $tests++; # Sign a message with signcontrol. fix_signcontrol ($pgp); my $status = system ('./signcontrol < ./messages/newgroup > signed'); if ($? == 0) { print "PASS: signcontrol-pgp\n"; } else { print "signcontrol exited with status ", ($? >> 8), "\n"; print "FAIL: signcontrol-pgp\n"; $failed++; } $tests++; # We still have a GnuPG pgpverify, so check cross-compatibility. if (pgpverify ('./signed', 'testing')) { print "PASS: signcontrol-pgp-gpg\n"; } else { print "FAIL: signcontrol-pgp-gpg\n"; $failed++; } $tests++; # Switch to a PGP pgpverify and check again. fix_pgpverify ($pgp); if (pgpverify ('./signed', 'testing')) { print "PASS: signcontrol-pgp-pgp\n"; } else { print "FAIL: signcontrol-pgp-pgp\n"; $failed++; } $tests++; # Check with an old copy of pgpverify to make sure that the generated # signatures still verify properly with a pgpverify that uses attached # signatures. my $signer = `./pgpverify-old $pgp < ./signed`; chomp $signer; if ($? == 0 && $signer eq 'testing') { print "PASS: signcontrol-pgp-old\n"; } else { print "pgpverify exited with status ", ($? >> 8), "\n" if $? != 0; print "pgpverify said the signer was $signer\n" if $signer; print "FAIL: signcontrol-pgp-old\n"; $failed++; } $tests++; # Switch to a GnuPG signcontrol and try again. my $gpg = find_program ('gpg'); fix_signcontrol ($gpg); $status = system ('./signcontrol < ./messages/newgroup > signed'); if ($? == 0) { print "PASS: signcontrol-gpg\n"; } else { print "signcontrol exited with status ", ($? >> 8), "\n"; print "FAIL: signcontrol-gpg\n"; $failed++; } $tests++; # This will only verify with a GnuPG pgpverify. fix_pgpverify ($gpgv); if (pgpverify ('./signed', 'testing')) { print "PASS: signcontrol-gpg-gpg\n"; } else { print "FAIL: signcontrol-gpg-gpg\n"; $failed++; } $tests++; # Generate signed messages with News::Article. system ('./sign-newsart', './messages/newgroup'); # Verify both with the GnuPG pgpverify. if (pgpverify ('./signed.pgp', 'testing')) { print "PASS: news-article-pgp-gpg\n"; } else { print "FAIL: news-article-pgp-gpg\n"; $failed++; } $tests++; if (pgpverify ('./signed.gpg', 'testing')) { print "PASS: news-article-gpg-gpg\n"; } else { print "FAIL: news-article-gpg-gpg\n"; $failed++; } $tests++; # Switch to the PGP pgpverify and verify just the PGP one. fix_pgpverify ($pgp); if (pgpverify ('./signed.pgp', 'testing')) { print "PASS: news-article-pgp-pgp\n"; } else { print "FAIL: news-article-pgp-pgp\n"; $failed++; } $tests++; # Check the return status for a truncated signature. if (pgpverify_fail ('./messages/bad-syntax', 255)) { print "PASS: pgpverify-pgp-syntax\n"; } else { print "FAIL: pgpverify-pgp-syntax\n"; $failed++; } $tests++; # Check the return status for a bad signature. if (pgpverify_fail ('./messages/bad-corrupt', 3)) { print "PASS: pgpverify-pgp-bad\n"; } else { print "FAIL: pgpverify-pgp-bad\n"; $failed++; } $tests++; # Switch to GnuPG and check the return status for a truncated signature. fix_pgpverify ($gpgv); if (pgpverify_fail ('./messages/bad-syntax', 255)) { print "PASS: pgpverify-gpg-syntax\n"; } else { print "FAIL: pgpverify-gpg-syntax\n"; $failed++; } $tests++; # Check the return status for a bad signature. if (pgpverify_fail ('./messages/bad-corrupt', 3)) { print "PASS: pgpverify-gpg-bad\n"; } else { print "FAIL: pgpverify-gpg-bad\n"; $failed++; } $tests++; # Check the return status for an unknown signer. if (pgpverify_fail ('./messages/gnu', 2)) { print "PASS: pgpverify-gpg-unknown\n"; } else { print "FAIL: pgpverify-gpg-unknown\n"; $failed++; } $tests++; # Print out a summary of the tests. unlink ('pgpverify', 'signcontrol', 'signed', 'signed.pgp', 'signed.gpg') unless $failed > 0; if ($failed == 0) { print "All $tests tests passed\n"; } else { print "Failed $failed tests out of $tests total\n"; exit 1; }