File Coverage

blib/lib/Mail/DKIM/Algorithm/Base.pm
Criterion Covered Total %
statement 75 78 96.1
branch 19 24 79.1
condition 6 9 66.6
subroutine 18 21 85.7
pod 7 13 53.8
total 125 145 86.2


line stmt bran cond sub pod time code
1             package Mail::DKIM::Algorithm::Base;
2 14     14   121 use strict;
  14         32  
  14         426  
3 14     14   91 use warnings;
  14         49  
  14         677  
4             our $VERSION = '1.20230630'; # VERSION
5             # ABSTRACT: base class for DKIM "algorithms"
6              
7             # Copyright 2005-2007 Messiah College. All rights reserved.
8             # Jason Long
9              
10             # Copyright (c) 2004 Anthony D. Urso. All rights reserved.
11             # This program is free software; you can redistribute it and/or
12             # modify it under the same terms as Perl itself.
13              
14 14     14   10490 use Mail::DKIM::Canonicalization::nowsp;
  14         39  
  14         425  
15 14     14   6122 use Mail::DKIM::Canonicalization::relaxed;
  14         44  
  14         475  
16 14     14   5500 use Mail::DKIM::Canonicalization::simple;
  14         35  
  14         403  
17 14     14   5972 use Mail::DKIM::Canonicalization::seal;
  14         85  
  14         424  
18              
19 14     14   87 use Carp;
  14         24  
  14         831  
20 14     14   92 use MIME::Base64;
  14         26  
  14         15469  
21              
22             sub new {
23 481     481 0 912 my $class = shift;
24 481         1824 my %args = @_;
25 481         1006 my $self = bless \%args, $class;
26 481         1329 $self->init;
27 481         1187 return $self;
28             }
29              
30             sub init {
31 460     460 0 700 my $self = shift;
32              
33 460 50       1091 croak 'no signature' unless $self->{Signature};
34              
35 460 100       1092 $self->{mode} = $self->{Signature}->signature ? 'verify' : 'sign';
36              
37             # allows subclasses to set the header_digest and body_digest
38             # properties
39 460         1872 $self->init_digests;
40              
41 460         5104 my ( $header_method, $body_method ) = $self->{Signature}->canonicalization;
42              
43 460         1184 my $header_class = $self->get_canonicalization_class($header_method);
44 460         877 my $body_class = $self->get_canonicalization_class($body_method);
45             $self->{canon} = $header_class->new(
46             output_digest => $self->{header_digest},
47             Signature => $self->{Signature},
48             Debug_Canonicalization => $self->{Debug_Canonicalization}
49 460         1943 );
50             $self->{body_canon} = $body_class->new(
51             output_digest => $self->{body_digest},
52             Signature => $self->{Signature},
53             Debug_Canonicalization => $self->{Debug_Canonicalization}
54 460         1413 );
55             }
56              
57             # override this method, please...
58             # this method should set the "header_digest" and "body_digest" properties
59             sub init_digests {
60 0     0 0 0 die 'not implemented';
61             }
62              
63             # private method - DKIM-specific
64             sub get_canonicalization_class {
65 920     920 0 1336 my $self = shift;
66 920 50       1791 croak 'wrong number of arguments' unless ( @_ == 1 );
67 920         1494 my ($method) = @_;
68              
69 920 50       2470 my $class =
    100          
    100          
    50          
70             $method eq 'nowsp' ? 'Mail::DKIM::Canonicalization::nowsp'
71             : $method eq 'relaxed' ? 'Mail::DKIM::Canonicalization::relaxed'
72             : $method eq 'simple' ? 'Mail::DKIM::Canonicalization::simple'
73             : $method eq 'seal' ? 'Mail::DKIM::Canonicalization::seal'
74             : die "unknown method $method\n";
75 920         1522 return $class;
76             }
77              
78              
79             sub add_body {
80 458     458 1 738 my $self = shift;
81 458   66     1152 my $canon = $self->{body_canon} || $self->{canon};
82 458         1173 $canon->add_body(@_);
83             }
84              
85              
86             sub add_header {
87 6040     6040 1 8328 my $self = shift;
88 6040         12687 $self->{canon}->add_header(@_);
89             }
90              
91              
92             sub finish_body {
93 439     439 1 672 my $self = shift;
94 439   66     1064 my $body_canon = $self->{body_canon} || $self->{canon};
95 439         1291 $body_canon->finish_body;
96 439         951 $self->finish_message;
97             }
98              
99              
100             sub finish_header {
101 477     477 1 811 my $self = shift;
102 477         1458 $self->{canon}->finish_header(@_);
103             }
104              
105             # checks the bh= tag of the signature to see if it has the same body
106             # hash as computed by canonicalizing/digesting the actual message body.
107             # If it doesn't match, a false value is returned, and the
108             # verification_details property is set to "body has been altered"
109             sub check_body_hash {
110 259     259 0 445 my $self = shift;
111              
112             # The body_hash value is set in finish_message(), if we're operating
113             # from a version of the DKIM spec that uses the bh= tag. Otherwise,
114             # the signature shouldn't have a bh= tag to check.
115              
116 259         816 my $sighash = $self->{Signature}->body_hash();
117 259 100 66     1020 if ( $self->{body_hash} and $sighash ) {
118 149         286 my $body_hash = $self->{body_hash};
119 149         457 my $expected = decode_base64($sighash);
120 149 100       398 if ( $body_hash ne $expected ) {
121 6         22 $self->{verification_details} = 'body has been altered';
122              
123             # print STDERR "I calculated "
124             # . encode_base64($body_hash, "") . "\n";
125             # print STDERR "signature has "
126             # . encode_base64($expected, "") . "\n";
127 6         26 return;
128             }
129             }
130 253         913 return 1;
131             }
132              
133             sub finish_message {
134 418     418 0 615 my $self = shift;
135              
136             # DKIM requires the signature itself to be committed into the digest.
137             # But first, we need to set the bh= tag on the signature, then
138             # "prettify" it.
139              
140 418         3164 $self->{body_hash} = $self->{body_digest}->digest;
141 418 100       1272 if ( $self->{mode} eq 'sign' ) {
142             $self->{Signature}
143 58         329 ->body_hash( encode_base64( $self->{body_hash}, '' ) );
144             }
145              
146 418 100       881 if ( $self->{mode} eq 'sign' ) {
147 58         218 $self->{Signature}->prettify;
148             }
149              
150 418         1197 my $sig_line = $self->{Signature}->as_string_without_data;
151 418         1676 my $canonicalized = $self->{canon}->canonicalize_header($sig_line);
152              
153 418         1452 $self->{canon}->output($canonicalized);
154             }
155              
156              
157             # override this method, please...
158             sub sign {
159 0     0 1 0 die 'Not implemented';
160             }
161              
162              
163             sub signature {
164 2156     2156 1 3322 my $self = shift;
165             @_
166 2156 50       4255 and $self->{Signature} = shift;
167 2156         5403 return $self->{Signature};
168             }
169              
170              
171             # override this method, please...
172             sub verify {
173 0     0 1   die 'Not implemented';
174             }
175              
176             1;
177              
178             __END__