0

Is there a recipe for procmail that I can use to verify a pgp signature?Almost like gpg --verify. I have looked at pgpenvelope but I'm not needing to check this in any kind of mail client.

1 Answer 1

0

This solution worked great. Its a bit old but had no issues with it. https://www.w3.org/2004/07/pgp-whitelist.html

Requirements

To set up this whitelist system, you need:

a working procmail environment, set up to filter your incoming email on the same computer as procmail, an implementation of PGP; we assume it is gnupg from now on, but the system should be adaptable to other clients as well the set of keys of person you trust imported in your PGP environment; with gnupg, you would import a key using gpg --recv-key key_id, provided that you have a configured PGP server to get the keys from Set up

The system we're setting up does the following actions:

for any email it receives, it checks if the sender given in the From header is in our trusted list (.pgp-whitelist) if it is, it checks whether the mail is signed and if it is, whether it is correctly so (with the mailverify script) if it is, it adds a X-Whitelist: Yes header, after having made sure that the incoming mail didn't have such a header The mailverify script used to make the check can be downloaded from W3C CVS Public server. This is where you would need to change the call to your PGP client if it is not invoked as gpg.

The .pgp-whitelist is assumed to be in your home directory; change the path in the PGP_WHITELIST variable below if it isn't so. Its content is a list of email addresses (one per line) that you trust and want to be whitelisted if you receive properly signed mail from them.

The relevant procmail rules to add to your .procmailrc configuration file are below; they should be added before your set up for identifying spam if you do so using procmail too.

# .procmailrc - Check whitelist 

PGP_WHITELIST=$HOME/.pgp-whitelist

#looking from spam, but blessing sender from my white list
# by setting a X-Whitelist header

# First, removing fake headers
:0 fwh
* ^X-Whitelist
| formail -IX-Whitelist

# checking for people with a trusted PGP key
FROM=`formail -XFrom: | formail -r -xTo: | tr -d ' '`
PGP_OK=`$HOME/mailverify 1>/dev/null && echo 1`
:0
* ? egrep -q "$FROM" $PGP_WHITELIST
* ? test -n "$PGP_OK"
{
   :0 fwh
   | formail -a"X-Whitelist: Yes"
   :0:
   $MAILDIR/good/
}

:0 fwh
* !^X-Whitelist: Yes
{
        :0:
        $MAILDIR/bounce/
}

Perl script that is mailverify. Tweak MAILDIR folders accordingly.

#!/usr/bin/env perl
# File Name: mailverify
# Maintainer: Moshe Kaminsky <[email protected]>
# Original Date: September 30, 2003
# Last Update: September 30, 2003
# http://mirror.hamakor.org.il/archives/linux-il/att-5615/mailverify
###########################################################

use warnings;
use integer;

BEGIN {
    our $VERSION = 0.1;

    # analyze command line
    use Getopt::Long qw(:config gnu_getopt);
    use Pod::Usage;

    our $opt_help;
    our $opt_man;
    our $opt_version;
    our $Gpg;
    our $Tolerant;
    GetOptions('gpg=s' => \$Gpg,
               'tolerant!' => \$Tolerant,
               'help', 'version', 'man');
    pod2usage(1) if $opt_help;
    pod2usage(-verbose => 2) if $opt_man;
    print "$0 version $VERSION\n" and exit if $opt_version;
    $Gpg = '/usr/bin/gpg --batch --verify' unless $Gpg;
}

use File::Temp qw( tempfile );

my $PrevField = '';

# process the header
while (<>) {
    next if /^From /o;
    last if /^$/o;
    if (/^([\w-]+): (.*)$/o) {
        $Header{$1} = $2;
        $PrevField = $1;
    } else {
        $Header{$PrevField} .= $_;
    }
}

# check that the message is signed
$Str = $Header{'Content-Type'};
@Parts = split /;\s+/, $Str if $Str;
if (not $Str or $Parts[0] ne 'multipart/signed') {
    # the message is not multipart/signed, but might still be cleartext 
    # signed. Depending on --tolerant, we may pass the rest of the message to 
    # gpg directly
    print "Message not signed\n" and exit -1 unless $Tolerant;
    open GPG, "|$Gpg" or die "Can't open pipe to gpg ($Gpg): $!";
    print GPG <>;
    close GPG;
    exit $? >> 8;
}

# the boundary string signals the boundary between two attachments
$Boundary = $1 if $Parts[3] =~ /^boundary="(.*)"$/o;
# go to the start of the message
while (<>) {
    last if $_ eq "--$Boundary\n";
}

# read the message, excluding the last (empty) line
while (<>) {
    last if $_ eq "--$Boundary\n";
    push @Message, $_;
}
pop @Message;
# read the sig
while (<>) {
    last if /^-----BEGIN PGP SIGNATURE-----$/o;
}
{
do {
    push @Sig, $_;
    last if /^-----END PGP SIGNATURE-----$/o;
} while (<>);
};

# here comes the funny part: replace \n by \r\n
$_ = join '', @Message;
s/(?<!\r)\n/\r\n/g;

# write everything to files
my ($MsgFH, $MsgFile) = tempfile;
print $MsgFH $_;
my $SigFile = "$MsgFile.asc";
open SIGFH, ">$SigFile" or die "can't open $SigFile: $!";
print SIGFH @Sig;
close $MsgFH;
close SIGFH;

# run gpg
print `$Gpg $SigFile`;

# clean up
unlink $MsgFile, $SigFile;

# exit with the status of gpg
exit $? >> 8;

__DATA__

# start of POD

=head1 NAME

mailverify - verify the pgp signature of a mime signed mail message

=head1 SYNOPSIS

B<mailverify> B<--help>|B<--man>|B<--version>

B<mailverify> [B<--gpg=I<gpg command>>] [B<--(no)tolerant>] [I<mail file>]

=head1 OPTIONS

=over 4

=item B<--gpg=I<gpg command>>

The command to run to do the actual checking. The default is 
S<C</usr/local/bin/gpg --batch --verify>>. It is called with one argument, 
which is the name of the file containing the signature. If B<--tolerant> is 
used, it may also be called with the whole message on the standard input.

=item B<--(no)tolerant>

Normally (with B<--notolerant>), if the Content-Type is not 
C<multipart/signed>, B<mailverify> decides that the message is not signed, 
and exits with status -1. With this switch, the message is passed to I<gpg> 
(or whatever was specified with the B<--gpg> option) as is. This way, 
clearsigned messages can be verified with the same command.

=item B<--help>

Give a short usage message and exit with status 1

=item B<--man>

Give the full description and exit with status 1

=item B<--version>

Print a line with the program name and exit with status 0

=back

=head1 ARGUMENTS

If an argument is given, it is treated a file containing an e-mail message to 
verify, but more common is to read the message from stdin.

=head1 DESCRIPTION

This script verifies the pgp signature of files whose signature appears as an 
attachment (Content-Type C<multipart/signed>). If B<--tolerant> is used, it 
will also verify clearsigned messages. The usage is basically to pipe the 
mail to this program.

=head1 EXIT STATUS

If the message is not of type C<multipart/signed>, and B<--tolerant> is not 
given, the exit status is -1. In any other case, it is the exit status of the 
I<gpg> command.

=head1 SEE ALSO

I<gpg(1)>

=head1 BUGS

Probably plenty, since I don't read any RFCs. Works with all cases I checked, 
though.

=head1 AUTHOR

Moshe Kaminsky <[email protected]> - Copyright (c) 2003

=head1 LICENSE

This program is free software. You may copy or 
redistribute it under the same terms as Perl itself.

=cut

Kudos to Moshe.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .