in lib/Mail/SpamAssassin/Plugin/DKIM.pm [1409:1510]
sub _wlcheck_list {
my ($self, $pms, $acceptable_sdid_tuples_ref) = @_;
my %any_match_by_wl;
my $any_match_at_all = 0;
my $verifier = $pms->{dkim_verifier};
my $minimum_key_bits = $pms->{conf}->{dkim_minimum_key_bits};
# walk through all signatures present in a message
foreach my $signature (@{$pms->{dkim_signatures}}) {
# old versions of Mail::DKIM would give undef for an invalid signature
next if !defined $signature;
my $sig_result_supported = $signature->UNIVERSAL::can("result_detail");
# test for empty selector (must not treat a selector "0" as missing!)
next if !defined $signature->selector || $signature->selector eq "";
my($info, $valid, $expired, $key_size_weak);
$valid =
($sig_result_supported ? $signature : $verifier)->result eq 'pass';
$info = $valid ? 'VALID' : 'FAILED';
if ($valid && $signature->UNIVERSAL::can("check_expiration")) {
$expired = !$signature->check_expiration;
$info .= ' EXPIRED' if $expired;
}
if ($valid && !$expired && $minimum_key_bits) {
my $key_size = $signature->{_spamassassin_key_size};
if ($key_size && $key_size < $minimum_key_bits) {
$info .= " WEAK($key_size)"; $key_size_weak = 1;
}
}
my ($sdid) = (defined $signature->identity)? $signature->identity =~ /\@(\S+)/ : ($signature->domain);
$sdid = lc $sdid if defined $sdid;
my %tried_authors;
foreach my $entry (@$acceptable_sdid_tuples_ref) {
my($author, $acceptable_sdid, $wl, $welcome_addr) = @$entry;
# $welcome_addr and $wl are here for logging purposes only, already checked.
# The $acceptable_sdid is a verifier-acceptable signing domain
# identifier (to be matched against a 'd' tag in signatures).
# When $acceptable_sdid is undef or an empty string it implies
# a check for Author Domain Signature.
local $1;
my $author_domain = $author !~ /\@([^\@]+)\z/s ? '' : lc $1;
$tried_authors{$author} = 1; # for logging purposes
my $matches = 0;
if (!defined $sdid) {
# don't bother, invalid signature with a missing 'd' or 'i' tag
} elsif (!defined $acceptable_sdid || $acceptable_sdid eq '') {
# An "Author Domain Signature" (sometimes called a first-party
# signature) is a Valid Signature in which the domain name of the
# DKIM signing entity, i.e., the d= tag in the DKIM-Signature header
# field, is the same as the domain name in the Author Address.
# Following [RFC5321], domain name comparisons are case insensitive.
# checking for Author Domain Signature
$matches = 1 if $sdid eq $author_domain;
} else { # checking for verifier-acceptable signature
# The second argument to a 'welcomelist_from_dkim' option is now (since
# version 3.3.0) supposed to be a signing domain (SDID), no longer an
# identity (AUID). Nevertheless, be prepared to accept the full e-mail
# address there for compatibility, and just ignore its local-part.
$acceptable_sdid = $1 if $acceptable_sdid =~ /\@([^\@]*)\z/s;
if ($acceptable_sdid =~ s/^\*?\.//s) {
$matches = 1 if $sdid =~ /\.\Q$acceptable_sdid\E\z/si;
} else {
$matches = 1 if $sdid eq lc $acceptable_sdid;
}
}
if ($matches) {
if (would_log("dbg","dkim")) {
if ($sdid eq $author_domain) {
dbg("dkim: %s author domain signature by %s, MATCHES %s %s",
$info, $sdid, $wl, $welcome_addr);
} else {
dbg("dkim: %s third-party signature by %s, author domain %s, ".
"MATCHES %s %s", $info, $sdid, $author_domain, $wl, $welcome_addr);
}
}
# a defined value indicates at least a match, not necessarily valid
# (this complication servers to preserve logging compatibility)
$any_match_by_wl{$wl} = '' if !exists $any_match_by_wl{$wl};
}
# only valid signature can cause welcomelisting
$matches = 0 if !$valid || $expired || $key_size_weak;
if ($matches) {
$any_match_at_all = 1;
$any_match_by_wl{$wl} = $sdid; # value used for debug logging
}
}
dbg("dkim: %s signature by %s, author %s, no valid matches",
$info, defined $sdid ? $sdid : '(undef)',
join(", ", keys %tried_authors)) if !$any_match_at_all;
}
return ($any_match_at_all, \%any_match_by_wl);
}