Current File : //usr/share/perl5/vendor_perl/Mail/DKIM/Algorithm/Base.pm |
#!/usr/bin/perl
# Copyright 2005-2007 Messiah College. All rights reserved.
# Jason Long <jlong@messiah.edu>
# Copyright (c) 2004 Anthony D. Urso. All rights reserved.
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
use strict;
use warnings;
use Mail::DKIM::Canonicalization::nowsp;
use Mail::DKIM::Canonicalization::relaxed;
use Mail::DKIM::Canonicalization::simple;
package Mail::DKIM::Algorithm::Base;
use Carp;
use MIME::Base64;
sub new
{
my $class = shift;
my %args = @_;
my $self = bless \%args, $class;
$self->init;
return $self;
}
sub init
{
my $self = shift;
croak "no signature" unless $self->{Signature};
$self->{mode} = $self->{Signature}->signature ? "verify" : "sign";
# allows subclasses to set the header_digest and body_digest
# properties
$self->init_digests;
my ($header_method, $body_method)
= $self->{Signature}->canonicalization;
my $header_class = $self->get_canonicalization_class($header_method);
my $body_class = $self->get_canonicalization_class($body_method);
$self->{canon} = $header_class->new(
output_digest => $self->{header_digest},
Signature => $self->{Signature},
Debug_Canonicalization => $self->{Debug_Canonicalization});
$self->{body_canon} = $body_class->new(
output_digest => $self->{body_digest},
Signature => $self->{Signature},
Debug_Canonicalization => $self->{Debug_Canonicalization});
}
# override this method, please...
# this method should set the "header_digest" and "body_digest" properties
sub init_digests
{
die "not implemented";
}
# private method - DKIM-specific
sub get_canonicalization_class
{
my $self = shift;
croak "wrong number of arguments" unless (@_ == 1);
my ($method) = @_;
my $class = $method eq "nowsp" ? "Mail::DKIM::Canonicalization::nowsp" :
$method eq "relaxed" ? "Mail::DKIM::Canonicalization::relaxed" :
$method eq "simple" ? "Mail::DKIM::Canonicalization::simple" :
die "unknown method $method\n";
return $class;
}
=head1 NAME
Mail::DKIM::Algorithm::Base - base class for DKIM "algorithms"
=head1 SYNOPSIS
my $algorithm = new Mail::DKIM::Algorithm::rsa_sha1(
Signature => $dkim_signature
);
# add headers
$algorithm->add_header("Subject: this is the subject\015\012");
$algorithm->finish_header;
# add body
$algorithm->add_body("This is the body.\015\012");
$algorithm->add_body("Another line of the body.\015\012");
$algorithm->finish_body;
# now sign or verify...
# TODO...
=head1 CONSTRUCTOR
You should not create an object of this class directly. Instead, use one
of the DKIM algorithm implementation classes, such as rsa_sha1:
my $algorithm = new Mail::DKIM::Algorithm::rsa_sha1(
Signature => $dkim_signature
);
=head1 METHODS
=head2 add_body() - feeds part of the body into the algorithm/canonicalization
$algorithm->add_body("This is the body.\015\012");
$algorithm->add_body("Another line of the body.\015\012");
The body should be fed one "line" at a time.
=cut
sub add_body
{
my $self = shift;
my $canon = $self->{body_canon} || $self->{canon};
$canon->add_body(@_);
}
=head2 add_header() - feeds a header field into the algorithm/canonicalization
$algorithm->add_header("Subject: this is the subject\015\012");
The header must start with the header field name and continue through any
folded lines (including the embedded <CRLF> sequences). It terminates with
the <CRLF> at the end of the header field.
=cut
sub add_header
{
my $self = shift;
$self->{canon}->add_header(@_);
}
=head2 finish_body() - signals the end of the message body
$algorithm->finish_body
Call this method when all lines from the body have been submitted.
After calling this method, use sign() or verify() to get the results
from the algorithm.
=cut
sub finish_body
{
my $self = shift;
my $body_canon = $self->{body_canon} || $self->{canon};
$body_canon->finish_body;
$self->finish_message;
}
=head2 finish_header() - signals the end of the header field block
$algorithm->finish_header;
Call this method when all the headers have been submitted.
=cut
sub finish_header
{
my $self = shift;
$self->{canon}->finish_header(@_);
}
# checks the bh= tag of the signature to see if it has the same body
# hash as computed by canonicalizing/digesting the actual message body.
# If it doesn't match, a false value is returned, and the
# verification_details property is set to "body has been altered"
sub check_body_hash
{
my $self = shift;
# The body_hash value is set in finish_message(), if we're operating
# from a version of the DKIM spec that uses the bh= tag. Otherwise,
# the signature shouldn't have a bh= tag to check.
if ($self->{body_hash})
{
my $body_hash = $self->{body_hash};
my $expected = decode_base64($self->{Signature}->body_hash);
if ($body_hash ne $expected)
{
$self->{verification_details} = "body has been altered";
# print STDERR "I calculated "
# . encode_base64($body_hash, "") . "\n";
# print STDERR "signature has "
# . encode_base64($expected, "") . "\n";
return;
}
}
return 1;
}
sub finish_message
{
my $self = shift;
# DKIM requires the signature itself to be committed into the digest.
# But first, we need to set the bh= tag on the signature, then
# "prettify" it.
$self->{body_hash} = $self->{body_digest}->digest;
if ($self->{mode} eq "sign")
{
$self->{Signature}->body_hash(
encode_base64($self->{body_hash}, ""));
}
if ($self->{mode} eq "sign")
{
$self->{Signature}->prettify;
}
my $sig_line = $self->{Signature}->as_string_without_data;
my $canonicalized = $self->{canon}->canonicalize_header($sig_line);
$self->{canon}->output($canonicalized);
}
=head2 sign() - generates a signature using a private key
$base64 = $algorithm->sign($private_key);
=cut
# override this method, please...
sub sign
{
die "Not implemented";
}
=head2 signature() - get/set the signature worked on by this algorithm
my $old_signature = $algorithm->signature;
$algorithm->signature($new_signature);
=cut
sub signature
{
my $self = shift;
@_ and
$self->{Signature} = shift;
return $self->{Signature};
}
=head2 verify() - verifies a signature
$result = $algorithm->verify();
Must be called after finish_body().
The result is a true/false value: true indicates the signature data
is valid, false indicates it is invalid.
For an invalid signature, details may be obtained from
$algorithm->{verification_details} or $@.
=cut
# override this method, please...
sub verify
{
die "Not implemented";
}
1;
__END__
=head1 SEE ALSO
L<Mail::DKIM>
=head1 AUTHOR
Jason Long, E<lt>jlong@messiah.eduE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2005-2007 by Messiah College
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.6 or,
at your option, any later version of Perl 5 you may have available.
=cut