| 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__ |