use strict; use warnings; use feature 'say'; # verify a message use Mail::DKIM::Verifier; use Mail::DKIM::ARC::Verifier; use Time::Piece; use Time::Seconds; my $separator = "_______________________________\n"; my $indent = " "; # create a verifier object my $dkim = Mail::DKIM::Verifier->new(); my $arc = Mail::DKIM::ARC::Verifier->new(); my $filename = shift or die "$0 FILENAME\n"; open FILE, '<', $filename or die "$!\n"; while () { # remove local line terminators chomp; s/\015$//; # use SMTP line terminators $dkim->PRINT("$_\015\012"); } $dkim->CLOSE; open FILE, '<', $filename or die "Could not open '$filename'\n"; while () { # remove local line terminators chomp; s/\015$//; # use SMTP line terminators $arc->PRINT("$_\015\012"); } $arc->CLOSE; my $email = $dkim->message_originator->address; say "$separator"; say "From $email"; say ""; # what is the result of the DKIM verify? my $dkim_result = $dkim->result_detail; say "DKIM result = $dkim_result"; say "$separator"; open FILE, '<', $filename or die "Could not open '$filename'\n"; my $header = ""; my $dkim_string = ""; my $found_dkim = 0; my $found_domkey = 0; my $finite_loop = 20; my $loop_counter = 0; my $substr = ""; my $substr2 = ""; my $tstring = ""; my $xstring = ""; my $sstring = ""; my $time_t = ""; my $time_x = ""; my $slength = 0; my $time_diff = ""; my $found_t = 0; my $found_x = 0; my @all_signatures = $dkim->signatures; # there might be multiple signatures, what is the result per signature? foreach my $signature ($dkim->signatures) { say 'DKIM signature identity: ' . $signature->identity; say 'DKIM verify result: ' . $signature->result_detail; say ""; while (my $line = ) { chomp $line; $line =~ tr/\t/ /; $line =~ s/^\s+//; # left trim $line =~ s/\s+$//; # right trim $dkim_string = ""; if ($line =~ /^DKIM-Signature:/i) { $loop_counter = 0; $found_dkim = 1; while (1) { $substr = "bh="; if (index($line, $substr) != -1) { $dkim_string = $dkim_string . $line; last; } $substr = "b="; if (index($line, $substr) != -1) { $dkim_string = $dkim_string . $line; last; } $dkim_string = $dkim_string . $line; $line = ; chomp $line; $line =~ tr/\t/ /; $line =~ s/^\s+//; # left trim $line =~ s/\s+$//; # right trim $loop_counter++; if ($loop_counter == $finite_loop) { warn "Finite loop count of $finite_loop reached!"; say "$dkim_string"; last; } } } if ($line =~ /^DomainKey-Signature:/i) { $loop_counter = 0; $found_domkey = 1; while (1) { $substr = "bh="; if (index($line, $substr) != -1) { $dkim_string = $dkim_string . $line; last; } $substr = "b="; if (index($line, $substr) != -1) { $dkim_string = $dkim_string . $line; last; } $dkim_string = $dkim_string . $line; $line = ; chomp $line; $line =~ tr/\t/ /; $line =~ s/^\s+//; # left trim $line =~ s/\s+$//; # right trim $loop_counter++; if ($loop_counter == $finite_loop) { warn "Finite loop count of $finite_loop reached!"; say "$dkim_string"; last; } } } if ($found_domkey == 1) { $header = "DomainKey"; parse_file_for ($header); } if ($found_domkey == 1) { $found_domkey = 0; say "$separator"; last; } if ($found_dkim == 1) { $header = "DKIM"; parse_file_for ($header); } if ($found_dkim == 1) { $found_dkim = 0; say "$separator"; last; } } } # what is the result of the ARC verify? my $arc_result = $arc->result_detail; say "ARC result = $arc_result"; my @all_arc_signatures = $arc->signatures; # there might be multiple signatures, what is the result per signature? foreach my $signature ($arc->signatures) { say ""; say $signature->prefix() . ' v=' . $signature->instance . ' ' . $signature->result_detail; } say "$separator"; foreach my $policy ($dkim->policies) { my $policy_name = $policy->name; my $policy_result = $policy->apply($dkim); say "$policy_name policy result: $policy_result"; } say "$separator"; sub parse_file_for { my $header = shift; if ($dkim_string =~ /d=[^ ]+;/) { $substr = "d="; $substr2 = ";"; if (index($dkim_string, $substr) != -1) { $sstring=(substr($dkim_string,index($dkim_string, $substr)+2)); $slength=index($sstring, $substr2); $sstring=substr($sstring,0,$slength); say $indent.$header." domain $substr$sstring"; } } if ($dkim_string =~ /s=[^ ]+;/) { $substr = "s="; $substr2 = ";"; if (index($dkim_string, $substr) != -1) { $sstring=(substr($dkim_string,index($dkim_string, $substr)+2)); $slength=index($sstring, $substr2); $sstring=substr($sstring,0,$slength); say $indent.$header." selector $substr$sstring"; } } if ($dkim_string =~ /t=[0123456789]+;/) { $substr = "t="; if (index($dkim_string, $substr) != -1) { $tstring=(substr($dkim_string,index($dkim_string, $substr)+2,10)); $time_t = Time::Piece->gmtime($tstring); say $indent.$header." Timestamp $substr$tstring -> " . $time_t->strftime(); $found_t = 1; } } if ($dkim_string =~ /x=[0123456789]+;/) { $substr = "x="; if (index($dkim_string, $substr) != -1) { $xstring=(substr($dkim_string,index($dkim_string, $substr)+2,10)); $time_x = Time::Piece->gmtime($xstring); say $indent.$header." Expiry $substr$xstring -> " . $time_x->strftime(); $found_x = 1; } } if ($found_t == 1 && $found_x == 1) { $time_diff = $time_x - $time_t; say "\n".$indent."The time difference is " . $time_diff->pretty(); $found_t = 0; $found_x = 0; } return 0; } close FILE