File Coverage

blib/lib/Mail/DKIM/Canonicalization/seal.pm
Criterion Covered Total %
statement 33 33 100.0
branch 7 8 87.5
condition 3 3 100.0
subroutine 8 8 100.0
pod 2 3 66.6
total 53 55 96.3


line stmt bran cond sub pod time code
1             package Mail::DKIM::Canonicalization::seal;
2 14     14   92 use strict;
  14         27  
  14         404  
3 14     14   70 use warnings;
  14         28  
  14         687  
4             our $VERSION = '1.20230630'; # VERSION
5             # ABSTRACT: arc seal canonicalization
6              
7             # Copyright 2017 FastMail Pty Ltd. All Rights Reserved.
8             # Bron Gondwana
9              
10             # This program is free software; you can redistribute it and/or
11             # modify it under the same terms as Perl itself.
12              
13             # This canonicalization is for the ARC-Seal header from
14             # https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-06
15             # Rather than having a 'h' property, it processes the headers in
16             # a pre-defined way.
17             #
18             # 5.1.1.3. Deterministic (Implicit) 'h' Tag Value for ARC-Seal
19             #
20             # In this section, the term "scope" is used to indicate those header
21             # fields signed by an ARC-Seal header field. A number in parentheses
22             # indicates the instance of that field, starting at 1. The suffix "-
23             # no-b" is used with an ARC-Seal field to indicate that its "b" field
24             # is empty at the time the signature is computed, as described in
25             # Section 3.5 of [RFC6376]. "AAR" refers to ARC-Authentication-
26             # Results, "AMS" to ARC-Message-Signature, "AS" to ARC-Seal, and "ASB"
27             # to an ARC-Seal with an empty "b" tag.
28             #
29             # Generally, the scope of an ARC set for a message containing "n" ARC
30             # sets is the concatenation of the following, for x (instance number)
31             # from 1 to n:
32             #
33             # o AAR(x);
34             #
35             # o AMS(x);
36             #
37             # o ASB(x) if x = n, else AS(x)
38             #
39             # Thus for a message with no seals (i.e., upon injection), the scope of
40             # the first ARC set is AAR(1):AMS(1):ASB(1). The ARC set thus
41             # generated would produce a first ARC-Seal with a "b" value. The next
42             # ARC set would include in its signed content the prior scope, so it
43             # would have a scope of AAR(1):AMS(1):AS(1):AAR(2):AMS(2):ASB(2).
44             #
45             # Note: Typically header field sets appear within the header in
46             # descending instance order.
47              
48 14     14   78 use base 'Mail::DKIM::Canonicalization::relaxed';
  14         24  
  14         1393  
49 14     14   93 use Carp;
  14         29  
  14         6137  
50              
51             sub init {
52 396     396 0 634 my $self = shift;
53 396         924 $self->SUPER::init;
54             }
55              
56             sub _output_indexed_header {
57 501     501   1044 my ( $self, $headers, $h, $i ) = @_;
58 501         963 foreach my $hdr (@$headers) {
59              
60             # this ugly pattern matches header: field; field; ... i=N
61 3093 100 100     76350 next unless $hdr =~ m/^$h:\s*(?:[^;]*;\s*)*i=(\d+)/i and $1 == $i;
62 481         1959 $hdr =~ s/\015\012\z//s;
63 481         1606 $self->output( $self->canonicalize_header($hdr) . "\015\012" );
64 481         1655 return;
65             }
66             }
67              
68             sub finish_header {
69 196     196 1 305 my $self = shift;
70 196         580 my %args = @_;
71              
72 196         625 my $i = $self->{Signature}->identity();
73 196 100       784 return unless $i =~ m{^\d+$}; # don't waste time if i= is bogus
74              
75 192         362 my $chain = $args{Chain};
76 192 50       410 $chain = $self->{Signature}->chain() if ! defined $chain;
77              
78             # we include the seal for everything else
79             # if the previous status was pass
80 192 100       530 if ( $chain eq 'pass' ) {
81 176         549 foreach my $n ( 1 .. ( $i - 1 ) ) {
82             $self->_output_indexed_header( $args{Headers},
83 39         124 'ARC-Authentication-Results', $n );
84             $self->_output_indexed_header( $args{Headers},
85 39         116 'ARC-Message-Signature', $n );
86 39         121 $self->_output_indexed_header( $args{Headers}, 'ARC-Seal', $n );
87             }
88             }
89              
90             # always include this header set
91             $self->_output_indexed_header( $args{Headers},
92 192         570 'ARC-Authentication-Results', $i );
93 192         513 $self->_output_indexed_header( $args{Headers}, 'ARC-Message-Signature',
94             $i );
95              
96             # we don't add ARC-Seal at our index, because that is this signature, and it's
97             # formed with standard DKIM style, so automatically appeneded
98             }
99              
100       179 1   sub add_body {
101              
102             # no body add
103             }
104              
105             1;
106              
107             __END__