You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by do...@apache.org on 2006/12/08 22:43:35 UTC

svn commit: r484798 - /spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm

Author: dos
Date: Fri Dec  8 13:43:34 2006
New Revision: 484798

URL: http://svn.apache.org/viewvc?view=rev&rev=484798
Log:
bug 5140: improvements to DomainKeys support, thanks to Mark Martinec <Mark.Martinec /at/ ijs.si>

  - improve debugging
  - avoid fetching DK policy when the signature is valid (verifies), as
    required by draft-delany-domainkeys-base-06
  - avoid sanitizing header (stripping away trailing header fields likely to
    be inserted by LDA or MUA) when signature header contains a h tag, which
    explicitly lists header fields which were included in signature calculation

  - fix parsing of DK tags, tags are case-sensitive, and whitespace may appear
    before and after tag name and value
  - let DK_POLICY_TESTING be true if t=y appears in a public key, even when
    policy record is not fetched

Modified:
    spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm

Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm?view=diff&rev=484798&r1=484797&r2=484798
==============================================================================
--- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm (original)
+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DomainKeys.pm Fri Dec  8 13:43:34 2006
@@ -23,7 +23,26 @@
 
  loadplugin Mail::SpamAssassin::Plugin::DomainKeys [/path/to/DomainKeys.pm]
 
- full DOMAINKEY_DOMAIN eval:check_domainkeys_verified()
+Signature:
+ header DK_SIGNED                eval:check_domainkeys_signed()
+ header DK_VERIFIED              eval:check_domainkeys_verified()
+
+Policy:
+   Note that DK policy record is only fetched if DK_VERIFIED is false
+   to save signing domain from unnecessary DNS queries,
+   as recommended (SHOULD) by draft-delany-domainkeys-base.
+   Rules DK_POLICY_* should preferably not be relied upon when DK_VERIFIED
+   is true, although they will return false in current implementation
+   when a policy record is not fetched, except for DK_POLICY_TESTING,
+   which is true if t=y appears in a public key record OR in a policy
+   record (when available).
+ header DK_POLICY_TESTING        eval:check_domainkeys_testing()
+ header DK_POLICY_SIGNSOME       eval:check_domainkeys_signsome()
+ header DK_POLICY_SIGNALL        eval:check_domainkeys_signall()
+
+Whitelisting based on verified signature:
+ header USER_IN_DK_WHITELIST     eval:check_for_dk_whitelist_from()
+ header USER_IN_DEF_DK_WL        eval:check_for_def_dk_whitelist_from()
 
 =head1 DESCRIPTION
 
@@ -241,8 +260,11 @@
 
   my $header = $scan->{msg}->get_pristine_header();
   my $body = $scan->{msg}->get_body();
+  my $dksighdr = $scan->{msg}->get_header("DomainKey-Signature");
+  dbg("dk: signature: $dksighdr")  if defined $dksighdr;
 
-  $self->sanitize_header_for_dk(\$header);
+  $self->sanitize_header_for_dk(\$header)
+    if defined $dksighdr && $dksighdr !~ /(?:^|;)[ \t]*h=/;  # case sensitive
 
   my $message = Mail::DomainKeys::Message->load(HeadString => $header,
 						 BodyReference => $body);
@@ -315,20 +337,30 @@
       $scan->{domainkeys_verified} = 1;
     }
   }
-
-  my $policy = Mail::DomainKeys::Policy->fetch(Protocol => 'dns',
-					       Domain => $domain);
-
+  # testing flag in signature
+  if ($message->testing()) {
+    $scan->{domainkeys_testing} = 1;
+    dbg("dk: testing flag found in signature");
+  }
+  my $policy;
+  if (!$scan->{domainkeys_verified}) {
+    # Recipient systems SHOULD not retrieve a policy TXT record
+    # for email that successfully verifies.
+    $policy = Mail::DomainKeys::Policy->fetch(Protocol => 'dns',
+					      Domain => $domain);
+    my($fetched_policy) = $policy ? $policy->as_string : 'NONE';
+    $fetched_policy = ''  if !defined $fetched_policy;
+    dbg ("dk: fetched policy for domain $domain: $fetched_policy");
+  }
   return unless $policy;
-  dbg ("dk: fetched policy");
 
   # not signed and domain doesn't sign all
   if ($policy->signsome()) {
     $scan->{domainkeys_signsome} = 1;
   }
 
-  # domain or key testing
-  if ($message->testing() || $policy->testing()) {
+  # testing flag in policy
+  if ($policy->testing()) {
     $scan->{domainkeys_testing} = 1;
   }
 
@@ -346,10 +378,15 @@
   my ($self, $message) = @_;
   # try to use the signature() API if it exists (post-0.80)
   if ($message->can("signature")) {
+    my($sts,$msg);
     if (!$message->signed) {
-      return "no signature";
+      $sts = "no signature";
+    } else {
+      $sts = $message->signature->status;
+      $msg = $message->signature->errorstr;
     }
-    return $message->signature->status;
+    dbg("dk: $sts" . (defined $msg ? " ($msg)" : ''));
+    return $sts;
   } else {
     return $message->header->value;
   }
@@ -366,7 +403,8 @@
     return $message->signature->domain;
   } else {
     # otherwise parse it ourself
-    if ($scan->{msg}->get_header("DomainKey-Signature") =~ /d=(\S+);/) {
+    if ($scan->{msg}->get_header("DomainKey-Signature") =~
+        /(?: ^|; ) [ \t]* d= [ \t]* ([^;]*?) [ \t]* (?: ;|$ )/x) {
       return $1;
     }
     return undef;
@@ -376,6 +414,7 @@
 sub sanitize_header_for_dk {
   my ($self, $ref) = @_;
 
+  dbg("dk: sanitizing header, no \"h\" tag in signature");
   # remove folding, in a HTML-escape data-preserving style, so we can
   # strip headers easily
   $$ref =~ s/!/!ex;/gs;