On 1/15/25 11:25 PM, [email protected] wrote:
Author: fkento
Date: Wed Jan 15 22:25:42 2025
New Revision: 1923158

URL: http://svn.apache.org/viewvc?rev=1923158&view=rev
Log:
Bug 8262: Process ARC independently from DKIM

Modified:
     spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm

[...]
@@ -741,6 +741,20 @@ sub _dkim_load_modules {
          info("dkim: Mail::DKIM $version is older than the required ".
               "minimal version 0.31, suggested upgrade to 0.37 or later!");
        }
+      if (version->parse($version) >= version->parse(0.40)) {
+        my $edns = $self->{main}->{conf}->{dns_options}->{edns};
+        if ($edns && $edns >= 1024) {
+          # Let Mail::DKIM use our interface to Net::DNS::Resolver.
+          # Only do so if EDNS0 provides a reasonably-sized UDP payload size,
+          # as our interface does not provide a DNS fallback to TCP, unlike
+          # the Net::DNS::Resolver::send which does provide it.
+          # See also Bug 7265 regarding a choice of a resolver.
+          # my $res = $self->{main}->{resolver}->get_resolver;
+          my $res = $self->{main}->{resolver};
+          dbg("dkim: providing our own resolver: %s", ref $res);
+          Mail::DKIM::DNS::resolver($res);
+        }
+      }

Our DNS resolver does TCP fallback, since version 4.0.1.
Relevant commit:
https://github.com/apache/spamassassin/commit/da18247314241f2e391dab2130212bc4cb7d9240

 Regards
  Giovanni

        $self->{service_available} = 1;
my $adsp_avail =
@@ -827,11 +841,9 @@ sub _get_authors {
  sub _check_dkim_signature {
    my ($self, $pms) = @_;
- my $conf = $pms->{conf};
-  my($verifier, $arc_verifier, @signatures, @arc_signatures, 
@valid_signatures, @arc_valid_signatures);
+  my(@signatures, @valid_signatures);
$pms->{dkim_checked_signature} = 1; # has this sub already been invoked?
-  $pms->{arc_checked_signature} = 1;  # has this sub already been invoked?
    $pms->{dkim_signatures_ready} = 0;  # have we obtained & verified 
signatures?
    $pms->{dkim_signatures_dependable} = 0;
    # dkim_signatures_dependable =
@@ -840,12 +852,8 @@ sub _check_dkim_signature {
    #     (no signatures, or message was not truncated) )
    $pms->{dkim_signatures} = \@signatures;
    $pms->{dkim_valid_signatures} = \@valid_signatures;
-  $pms->{arc_signatures} = \@arc_signatures;
-  $pms->{arc_valid_signatures} = \@arc_valid_signatures;
    $pms->{dkim_signed} = 0;
-  $pms->{arc_signed} = 0;
    $pms->{dkim_valid} = 0;
-  $pms->{arc_valid} = 0;
    $pms->{dkim_key_testing} = 0;
    # the following hashes are keyed by a signing domain (SDID):
    $pms->{dkim_author_sig_tempfailed} = {}; # DNS timeout verifying author 
sign.
@@ -856,51 +864,72 @@ sub _check_dkim_signature {
    if (defined $suppl_attrib && exists $suppl_attrib->{dkim_signatures}) {
      # caller of SpamAssassin already supplied DKIM signature objects
      my $provided_signatures = $suppl_attrib->{dkim_signatures};
-    @signatures = @$provided_signatures  if ref $provided_signatures;
-    $pms->{dkim_signatures_ready} = 1;
-    $pms->{dkim_signatures_dependable} = 1;
-    dbg("dkim: DKIM signatures provided by the caller, %d signatures",
-        scalar(@signatures));
+    if (ref $provided_signatures) {
+      @signatures = @$provided_signatures;
+      $pms->{dkim_signatures_ready} = 1;
+      $pms->{dkim_signatures_dependable} = 1;
+      dbg("dkim: DKIM signatures provided by the caller, %d signatures",
+          scalar(@signatures));
+    }
    }
+
+  if ($pms->{dkim_signatures_ready}) {
+    # signatures already available and verified
+    _check_valid_signature($self, $pms, 'DKIM', \@signatures);
+  } elsif (!$pms->is_dns_available()) {
+    dbg("dkim: signature verification disabled, DNS resolving not available");
+  } elsif (!$self->_dkim_load_modules()) {
+    # Mail::DKIM module not available
+  } else {
+    # signature objects not provided by the caller, must verify for ourselves
+    my $timemethod = $self->{main}->time_method("check_dkim_signature");
+    my $verifier = Mail::DKIM::Verifier->new;
+    _check_signature($self, $pms, $verifier, 'DKIM', \@signatures);
+  }
+}
+
+sub _check_arc_signature {
+  my ($self, $pms) = @_;
+
+  my(@arc_signatures, @arc_valid_signatures);
+
+  $pms->{arc_checked_signature} = 1;  # has this sub already been invoked?
+  $pms->{arc_signatures_ready} = 0;  # have we obtained & verified signatures?
+  $pms->{arc_signatures_dependable} = 0;
+  # arc_signatures_dependable =
+  #   (signatures supplied by a caller) or
+  #   ( (signatures obtained by this plugin) and
+  #     (no signatures, or message was not truncated) )
+  $pms->{arc_signatures} = \@arc_signatures;
+  $pms->{arc_valid_signatures} = \@arc_valid_signatures;
+  $pms->{arc_signed} = 0;
+  $pms->{arc_valid} = 0;
+
+  my $suppl_attrib = $pms->{msg}->{suppl_attrib};
    if (defined $suppl_attrib && exists $suppl_attrib->{arc_signatures}) {
      # caller of SpamAssassin already supplied ARC signature objects
      my $provided_arc_signatures = $suppl_attrib->{arc_signatures};
-    @arc_signatures = @$provided_arc_signatures  if ref 
$provided_arc_signatures;
-    $pms->{arc_signatures_ready} = 1;
-    $pms->{arc_signatures_dependable} = 1;
-    dbg("dkim: ARC signatures provided by the caller, %d signatures",
-        scalar(@arc_signatures));
+    if (ref $provided_arc_signatures) {
+      @arc_signatures = @$provided_arc_signatures;
+      $pms->{arc_signatures_ready} = 1;
+      $pms->{arc_signatures_dependable} = 1;
+      dbg("dkim: ARC signatures provided by the caller, %d signatures",
+          scalar(@arc_signatures));
+    }
    }
- if ($pms->{dkim_signatures_ready} or $pms->{arc_signatures_ready}) {
+  if ($pms->{arc_signatures_ready}) {
      # signatures already available and verified
-    _check_valid_signature($self, $pms, $verifier, 'DKIM', \@signatures) if 
$self->{service_available};
-    _check_valid_signature($self, $pms, $arc_verifier, 'ARC', \@arc_signatures) 
if $self->{arc_available};
+    _check_valid_signature($self, $pms, 'ARC', \@arc_signatures);
    } elsif (!$pms->is_dns_available()) {
      dbg("dkim: signature verification disabled, DNS resolving not available");
-  } elsif (!$self->_dkim_load_modules()) {
-    # Mail::DKIM module not available
+  } elsif (!$self->_dkim_load_modules() || !$self->{arc_available}) {
+    # Mail::DKIM::ARC module not available
    } else {
      # signature objects not provided by the caller, must verify for ourselves
-    my $timemethod = $self->{main}->time_method("check_dkim_signature");
-    if (version->parse(Mail::DKIM::Verifier->VERSION) >= version->parse(0.40)) 
{
-      my $edns = $conf->{dns_options}->{edns};
-      if ($edns && $edns >= 1024) {
-        # Let Mail::DKIM use our interface to Net::DNS::Resolver.
-        # Only do so if EDNS0 provides a reasonably-sized UDP payload size,
-        # as our interface does not provide a DNS fallback to TCP, unlike
-        # the Net::DNS::Resolver::send which does provide it.
-        # See also Bug 7265 regarding a choice of a resolver.
-      # my $res = $self->{main}->{resolver}->get_resolver;
-        my $res = $self->{main}->{resolver};
-        dbg("dkim: providing our own resolver: %s", ref $res);
-        Mail::DKIM::DNS::resolver($res);
-      }
-    }
-    $verifier = Mail::DKIM::Verifier->new if $self->{service_available};
-    _check_signature($self, $pms, $verifier, 'DKIM', \@signatures) if 
$self->{service_available};
-    $arc_verifier = Mail::DKIM::ARC::Verifier->new if $self->{arc_available};
-    _check_signature($self, $pms, $arc_verifier, 'ARC', \@arc_signatures) if 
$self->{arc_available};
+    my $timemethod = $self->{main}->time_method("check_arc_signature");
+    my $arc_verifier = Mail::DKIM::ARC::Verifier->new;
+    _check_signature($self, $pms, $arc_verifier, 'ARC', \@arc_signatures);
    }
  }
@@ -988,18 +1017,18 @@ sub _check_signature {
      if (!@$signatures || !$pms->{tests_already_hit}->{'__TRUNCATED'}) {
        $pms->{dkim_signatures_dependable} = 1;
      }
-    _check_valid_signature($self, $pms, $verifier, 'DKIM', \@$signatures) if 
$self->{service_available};
+    _check_valid_signature($self, $pms, 'DKIM', \@$signatures);
    } elsif ($type eq 'ARC') {
      $pms->{arc_signatures_ready} = 1;
      if (!@$signatures || !$pms->{tests_already_hit}->{'__TRUNCATED'}) {
        $pms->{arc_signatures_dependable} = 1;
      }
-    _check_valid_signature($self, $pms, $verifier, 'ARC', \@$signatures) if 
$self->{arc_available};
+    _check_valid_signature($self, $pms, 'ARC', \@$signatures);
    }
  }
sub _check_valid_signature {
-  my($self, $pms, $verifier, $type, $signatures) = @_;
+  my($self, $pms, $type, $signatures) = @_;
my $sig_type = lc $type;
    $self->_get_authors($pms)  if !$pms->{"dkim_author_addresses"};
@@ -1014,13 +1043,11 @@ sub _check_valid_signature {
      foreach my $signature (@$signatures) {
        # old versions of Mail::DKIM would give undef for an invalid signature
        next if !defined $signature;
-      $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);
-      $valid =
-        ($sig_result_supported ? $signature : $verifier)->result eq 'pass';
+      $valid = $signature->result eq 'pass';
        $info = $valid ? 'VALID' : 'FAILED';
        if ($valid && $signature->UNIVERSAL::can("check_expiration")) {
          $expired = !$signature->check_expiration;
@@ -1048,8 +1075,7 @@ sub _check_valid_signature {
            if ($valid && !$expired &&
                $key_size && $key_size >= $minimum_key_bits) {
              $pms->{"${sig_type}_has_valid_author_sig"}->{$d} = 1;
-          } elsif ( ($sig_result_supported ? $signature
-                                           : $verifier)->result_detail
+          } elsif ( $signature->result_detail
                     =~ /\b(?:timed out|SERVFAIL)\b/i) {
              $pms->{"${sig_type}_author_sig_tempfailed"}->{$d} = 1;
            }
@@ -1064,7 +1090,7 @@ sub _check_valid_signature {
                $signature->identity, $d, $signature->selector,
                $signature->algorithm, scalar($signature->canonicalization),
                $key_size ? "key_bits=$key_size" : "unknown key size",
-              ($sig_result_supported ? $signature : $verifier)->result ),
+              $signature->result ),
              defined $d && $pms->{dkim_author_domains}->{$d}
                ? 'matches author domain'
                : 'does not match author domain',
@@ -1079,7 +1105,7 @@ sub _check_valid_signature {
                $signature->identity, $d, $signature->selector,
                $signature->algorithm, scalar($signature->canonicalization),
                $key_size ? "key_bits=$key_size" : "unknown key size",
-              ($sig_result_supported ? $signature : $verifier)->result ),
+              $signature->result ),
              defined $d && $pms->{dkim_author_domains}->{$d}
                ? 'matches author domain'
                : 'does not match author domain',
@@ -1113,7 +1139,7 @@ sub _check_valid_signature {
        }
        # let the result stand out more clearly in the log, use uppercase
        my $sig = $valid_signatures[0];
-      my $sig_res = ($sig_result_supported ? $sig : $verifier)->result_detail;
+      my $sig_res = $sig->result_detail;
        dbg("dkim: $type signature verification result: %s", uc($sig_res));
} elsif (@$signatures) {
@@ -1123,7 +1149,7 @@ sub _check_valid_signature {
          $pms->{arc_signed} = 1;
        }
        my $sig = @$signatures[0];
-      my $sig_res = ($sig_result_supported ? $sig : $verifier)->result_detail;
+      my $sig_res = $sig->result_detail;
        dbg("dkim: $type signature verification result: %s", uc($sig_res));
} else {



Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature

Reply via email to