Blame lib/Net/DNS/RR/DS.pm

Packit Service f6e53a
package Net::DNS::RR::DS;
Packit Service f6e53a
Packit Service f6e53a
#
Packit Service f6e53a
# $Id: DS.pm 1597 2017-09-22 08:04:02Z willem $
Packit Service f6e53a
#
Packit Service f6e53a
our $VERSION = (qw$LastChangedRevision: 1597 $)[1];
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
use strict;
Packit Service f6e53a
use warnings;
Packit Service f6e53a
use base qw(Net::DNS::RR);
Packit Service f6e53a
Packit Service f6e53a
=head1 NAME
Packit Service f6e53a
Packit Service f6e53a
Net::DNS::RR::DS - DNS DS resource record
Packit Service f6e53a
Packit Service f6e53a
=cut
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
use integer;
Packit Service f6e53a
Packit Service f6e53a
use Carp;
Packit Service f6e53a
Packit Service f6e53a
use constant BABBLE => defined eval 'require Digest::BubbleBabble';
Packit Service f6e53a
Packit Service f6e53a
eval 'require Digest::SHA';		## optional for simple Net::DNS RR
Packit Service f6e53a
eval 'require Digest::GOST';
Packit Service f6e53a
eval 'require Digest::GOST::CryptoPro';
Packit Service f6e53a
Packit Service f6e53a
my %digest = (
Packit Service f6e53a
	'1' => ['Digest::SHA', 1],
Packit Service f6e53a
	'2' => ['Digest::SHA', 256],
Packit Service f6e53a
	'3' => ['Digest::GOST::CryptoPro'],
Packit Service f6e53a
	'4' => ['Digest::SHA', 384],
Packit Service f6e53a
	);
Packit Service f6e53a
Packit Service f6e53a
#
Packit Service f6e53a
# source: http://www.iana.org/assignments/dns-sec-alg-numbers
Packit Service f6e53a
#
Packit Service f6e53a
{
Packit Service f6e53a
	my @algbyname = (
Packit Service f6e53a
		'DELETE'	     => 0,			# [RFC4034][RFC4398][RFC8078]
Packit Service f6e53a
		'RSAMD5'	     => 1,			# [RFC3110][RFC4034]
Packit Service f6e53a
		'DH'		     => 2,			# [RFC2539]
Packit Service f6e53a
		'DSA'		     => 3,			# [RFC3755][RFC2536]
Packit Service f6e53a
					## Reserved	=> 4,	# [RFC6725]
Packit Service f6e53a
		'RSASHA1'	     => 5,			# [RFC3110][RFC4034]
Packit Service f6e53a
		'DSA-NSEC3-SHA1'     => 6,			# [RFC5155]
Packit Service f6e53a
		'RSASHA1-NSEC3-SHA1' => 7,			# [RFC5155]
Packit Service f6e53a
		'RSASHA256'	     => 8,			# [RFC5702]
Packit Service f6e53a
					## Reserved	=> 9,	# [RFC6725]
Packit Service f6e53a
		'RSASHA512'	     => 10,			# [RFC5702]
Packit Service f6e53a
					## Reserved	=> 11,	# [RFC6725]
Packit Service f6e53a
		'ECC-GOST'	     => 12,			# [RFC5933]
Packit Service f6e53a
		'ECDSAP256SHA256'    => 13,			# [RFC6605]
Packit Service f6e53a
		'ECDSAP384SHA384'    => 14,			# [RFC6605]
Packit Service f6e53a
		'ED25519'	     => 15,			# [RFC8080]
Packit Service f6e53a
		'ED448'		     => 16,			# [RFC8080]
Packit Service f6e53a
Packit Service f6e53a
		'INDIRECT'   => 252,				# [RFC4034]
Packit Service f6e53a
		'PRIVATEDNS' => 253,				# [RFC4034]
Packit Service f6e53a
		'PRIVATEOID' => 254,				# [RFC4034]
Packit Service f6e53a
					## Reserved	=> 255,	# [RFC4034]
Packit Service f6e53a
		);
Packit Service f6e53a
Packit Service f6e53a
	my %algbyval = reverse @algbyname;
Packit Service f6e53a
Packit Service f6e53a
	my @algrehash = map /^\d/ ? ($_) x 3 : do { s/[\W_]//g; uc($_) }, @algbyname;
Packit Service f6e53a
	my %algbyname = @algrehash;    # work around broken cperl
Packit Service f6e53a
Packit Service f6e53a
	sub _algbyname {
Packit Service f6e53a
		my $arg = shift;
Packit Service f6e53a
		my $key = uc $arg;				# synthetic key
Packit Service f6e53a
		$key =~ s/[\W_]//g;				# strip non-alphanumerics
Packit Service f6e53a
		my $val = $algbyname{$key};
Packit Service f6e53a
		return $val if defined $val;
Packit Service f6e53a
		return $key =~ /^\d/ ? $arg : croak "unknown algorithm $arg";
Packit Service f6e53a
	}
Packit Service f6e53a
Packit Service f6e53a
	sub _algbyval {
Packit Service f6e53a
		my $value = shift;
Packit Service f6e53a
		$algbyval{$value} || return $value;
Packit Service f6e53a
	}
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
#
Packit Service f6e53a
# source: http://www.iana.org/assignments/ds-rr-types
Packit Service f6e53a
#
Packit Service f6e53a
{
Packit Service f6e53a
	my @digestbyname = (
Packit Service f6e53a
		'SHA-1'		  => 1,				# RFC3658
Packit Service f6e53a
		'SHA-256'	  => 2,				# RFC4509
Packit Service f6e53a
		'GOST-R-34.11-94' => 3,				# RFC5933
Packit Service f6e53a
		'SHA-384'	  => 4,				# RFC6605
Packit Service f6e53a
		);
Packit Service f6e53a
Packit Service f6e53a
	my @digestalias = (
Packit Service f6e53a
		'SHA'  => 1,
Packit Service f6e53a
		'GOST' => 3,
Packit Service f6e53a
		);
Packit Service f6e53a
Packit Service f6e53a
	my %digestbyval = reverse @digestbyname;
Packit Service f6e53a
Packit Service f6e53a
	my @digestrehash = map /^\d/ ? ($_) x 3 : do { s/[\W_]//g; uc($_) }, @digestbyname;
Packit Service f6e53a
	my %digestbyname = ( @digestalias, @digestrehash );	# work around broken cperl
Packit Service f6e53a
Packit Service f6e53a
	sub _digestbyname {
Packit Service f6e53a
		my $arg = shift;
Packit Service f6e53a
		my $key = uc $arg;				# synthetic key
Packit Service f6e53a
		$key =~ s/[\W_]//g;				# strip non-alphanumerics
Packit Service f6e53a
		my $val = $digestbyname{$key};
Packit Service f6e53a
		return $val if defined $val;
Packit Service f6e53a
		return $key =~ /^\d/ ? $arg : croak "unknown digest type $arg";
Packit Service f6e53a
	}
Packit Service f6e53a
Packit Service f6e53a
	sub _digestbyval {
Packit Service f6e53a
		my $value = shift;
Packit Service f6e53a
		$digestbyval{$value} || return $value;
Packit Service f6e53a
	}
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub _decode_rdata {			## decode rdata from wire-format octet string
Packit Service f6e53a
	my $self = shift;
Packit Service f6e53a
	my ( $data, $offset ) = @_;
Packit Service f6e53a
Packit Service f6e53a
	my $rdata = substr $$data, $offset, $self->{rdlength};
Packit Service f6e53a
	$self->{digestbin} = unpack '@4 a*', $rdata;
Packit Service f6e53a
	@{$self}{qw(keytag algorithm digtype)} = unpack 'n C*', $rdata;
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub _encode_rdata {			## encode rdata as wire-format octet string
Packit Service f6e53a
	my $self = shift;
Packit Service f6e53a
Packit Service f6e53a
	pack 'n C2 a*', @{$self}{qw(keytag algorithm digtype digestbin)};
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub _format_rdata {			## format rdata portion of RR string.
Packit Service f6e53a
	my $self = shift;
Packit Service f6e53a
Packit Service f6e53a
	$self->_annotation( $self->babble ) if BABBLE && $self->{algorithm};
Packit Service f6e53a
	my @digest = split /(\S{64})/, $self->digest || '-';
Packit Service f6e53a
	my @rdata = ( @{$self}{qw(keytag algorithm digtype)}, @digest );
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub _parse_rdata {			## populate RR from rdata in argument list
Packit Service f6e53a
	my $self = shift;
Packit Service f6e53a
Packit Service f6e53a
	my $keytag = shift;		## avoid destruction by CDS algorithm(0)
Packit Service f6e53a
	$self->algorithm(shift);
Packit Service f6e53a
	$self->keytag($keytag);
Packit Service f6e53a
	$self->digtype(shift);
Packit Service f6e53a
	$self->digest(@_);
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub keytag {
Packit Service f6e53a
	my $self = shift;
Packit Service f6e53a
Packit Service f6e53a
	$self->{keytag} = 0 + shift if scalar @_;
Packit Service f6e53a
	$self->{keytag} || 0;
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub algorithm {
Packit Service f6e53a
	my ( $self, $arg ) = @_;
Packit Service f6e53a
Packit Service f6e53a
	unless ( ref($self) ) {		## class method or simple function
Packit Service f6e53a
		my $argn = pop;
Packit Service f6e53a
		return $argn =~ /[^0-9]/ ? _algbyname($argn) : _algbyval($argn);
Packit Service f6e53a
	}
Packit Service f6e53a
Packit Service f6e53a
	return $self->{algorithm} unless defined $arg;
Packit Service f6e53a
	return _algbyval( $self->{algorithm} ) if uc($arg) eq 'MNEMONIC';
Packit Service f6e53a
	$self->{algorithm} = _algbyname($arg) || die _algbyname('')    # disallow algorithm(0)
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub digtype {
Packit Service f6e53a
	my ( $self, $arg ) = @_;
Packit Service f6e53a
Packit Service f6e53a
	unless ( ref($self) ) {		## class method or simple function
Packit Service f6e53a
		my $argn = pop;
Packit Service f6e53a
		return $argn =~ /[^0-9]/ ? _digestbyname($argn) : _digestbyval($argn);
Packit Service f6e53a
	}
Packit Service f6e53a
Packit Service f6e53a
	return $self->{digtype} unless defined $arg;
Packit Service f6e53a
	return _digestbyval( $self->{digtype} ) if uc($arg) eq 'MNEMONIC';
Packit Service f6e53a
	$self->{digtype} = _digestbyname($arg) || die _digestbyname('')	   # disallow digtype(0)
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub digest {
Packit Service f6e53a
	my $self = shift;
Packit Service f6e53a
	return unpack "H*", $self->digestbin() unless scalar @_;
Packit Service f6e53a
	$self->digestbin( pack "H*", map /[^\dA-F]/i ? croak "corrupt hex" : $_, join "", @_ );
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub digestbin {
Packit Service f6e53a
	my $self = shift;
Packit Service f6e53a
Packit Service f6e53a
	$self->{digestbin} = shift if scalar @_;
Packit Service f6e53a
	$self->{digestbin} || "";
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub babble {
Packit Service f6e53a
	return BABBLE ? Digest::BubbleBabble::bubblebabble( Digest => shift->digestbin ) : '';
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub create {
Packit Service f6e53a
	my $class = shift;
Packit Service f6e53a
	my $keyrr = shift;
Packit Service f6e53a
	my %args  = $keyrr->ttl ? ( ttl => $keyrr->ttl, @_ ) : (@_);
Packit Service f6e53a
Packit Service f6e53a
	my ($type) = reverse split '::', $class;
Packit Service f6e53a
Packit Service f6e53a
	my $kname = $keyrr->name;
Packit Service f6e53a
	my $flags = $keyrr->flags;
Packit Service f6e53a
	croak "Unable to create $type record for non-DNSSEC key" unless $keyrr->protocol == 3;
Packit Service f6e53a
	croak "Unable to create $type record for non-authentication key" if $flags & 0x8000;
Packit Service f6e53a
	croak "Unable to create $type record for non-ZONE key" unless ( $flags & 0x300 ) == 0x100;
Packit Service f6e53a
Packit Service f6e53a
	my $self = new Net::DNS::RR(
Packit Service f6e53a
		name	  => $kname,				# per definition, same as keyrr
Packit Service f6e53a
		type	  => $type,
Packit Service f6e53a
		class	  => $keyrr->class,
Packit Service f6e53a
		keytag	  => $keyrr->keytag,
Packit Service f6e53a
		algorithm => $keyrr->algorithm,
Packit Service f6e53a
		digtype	  => 1,					# SHA1 by default
Packit Service f6e53a
		%args
Packit Service f6e53a
		);
Packit Service f6e53a
Packit Service f6e53a
	my $owner = $self->{owner}->encode();
Packit Service f6e53a
	my $data = pack 'a* a*', $owner, $keyrr->_encode_rdata;
Packit Service f6e53a
Packit Service f6e53a
	my $arglist = $digest{$self->digtype};
Packit Service f6e53a
	croak join ' ', 'digtype', $self->digtype('MNEMONIC'), 'not supported' unless $arglist;
Packit Service f6e53a
	my ( $object, @argument ) = @$arglist;
Packit Service f6e53a
	my $hash = $object->new(@argument);
Packit Service f6e53a
	$hash->add($data);
Packit Service f6e53a
	$self->digestbin( $hash->digest );
Packit Service f6e53a
Packit Service f6e53a
	return $self;
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
sub verify {
Packit Service f6e53a
	my ( $self, $key ) = @_;
Packit Service f6e53a
	my $verify = create Net::DNS::RR::DS( $key, ( digtype => $self->digtype ) );
Packit Service f6e53a
	return $verify->digestbin eq $self->digestbin;
Packit Service f6e53a
}
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
1;
Packit Service f6e53a
__END__
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
=head1 SYNOPSIS
Packit Service f6e53a
Packit Service f6e53a
    use Net::DNS;
Packit Service f6e53a
    $rr = new Net::DNS::RR('name DS keytag algorithm digtype digest');
Packit Service f6e53a
Packit Service f6e53a
    use Net::DNS::SEC;
Packit Service f6e53a
    $ds = create Net::DNS::RR::DS(
Packit Service f6e53a
	$dnskeyrr,
Packit Service f6e53a
	digtype => 'SHA256',
Packit Service f6e53a
	ttl	=> 3600
Packit Service f6e53a
	);
Packit Service f6e53a
Packit Service f6e53a
=head1 DESCRIPTION
Packit Service f6e53a
Packit Service f6e53a
Class for DNS Delegation Signer (DS) resource record.
Packit Service f6e53a
Packit Service f6e53a
=head1 METHODS
Packit Service f6e53a
Packit Service f6e53a
The available methods are those inherited from the base class augmented
Packit Service f6e53a
by the type-specific methods defined in this package.
Packit Service f6e53a
Packit Service f6e53a
Use of undocumented package features or direct access to internal data
Packit Service f6e53a
structures is discouraged and could result in program termination or
Packit Service f6e53a
other unpredictable behaviour.
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
=head2 keytag
Packit Service f6e53a
Packit Service f6e53a
    $keytag = $rr->keytag;
Packit Service f6e53a
    $rr->keytag( $keytag );
Packit Service f6e53a
Packit Service f6e53a
The 16-bit numerical key tag of the key. (RFC2535 4.1.6)
Packit Service f6e53a
Packit Service f6e53a
=head2 algorithm
Packit Service f6e53a
Packit Service f6e53a
    $algorithm = $rr->algorithm;
Packit Service f6e53a
    $rr->algorithm( $algorithm );
Packit Service f6e53a
Packit Service f6e53a
Decimal representation of the 8-bit algorithm field.
Packit Service f6e53a
Packit Service f6e53a
algorithm() may also be invoked as a class method or simple function
Packit Service f6e53a
to perform mnemonic and numeric code translation.
Packit Service f6e53a
Packit Service f6e53a
=head2 digtype
Packit Service f6e53a
Packit Service f6e53a
    $digtype = $rr->digtype;
Packit Service f6e53a
    $rr->digtype( $digtype );
Packit Service f6e53a
Packit Service f6e53a
Decimal representation of the 8-bit digest type field.
Packit Service f6e53a
Packit Service f6e53a
digtype() may also be invoked as a class method or simple function
Packit Service f6e53a
to perform mnemonic and numeric code translation.
Packit Service f6e53a
Packit Service f6e53a
=head2 digest
Packit Service f6e53a
Packit Service f6e53a
    $digest = $rr->digest;
Packit Service f6e53a
    $rr->digest( $digest );
Packit Service f6e53a
Packit Service f6e53a
Hexadecimal representation of the digest over the label and key.
Packit Service f6e53a
Packit Service f6e53a
=head2 digestbin
Packit Service f6e53a
Packit Service f6e53a
    $digestbin = $rr->digestbin;
Packit Service f6e53a
    $rr->digestbin( $digestbin );
Packit Service f6e53a
Packit Service f6e53a
Binary representation of the digest over the label and key.
Packit Service f6e53a
Packit Service f6e53a
=head2 babble
Packit Service f6e53a
Packit Service f6e53a
    print $rr->babble;
Packit Service f6e53a
Packit Service f6e53a
The babble() method returns the 'BubbleBabble' representation of the
Packit Service f6e53a
digest if the Digest::BubbleBabble package is available, otherwise
Packit Service f6e53a
an empty string is returned.
Packit Service f6e53a
Packit Service f6e53a
BubbleBabble represents a message digest as a string of plausible
Packit Service f6e53a
words, to make the digest easier to verify.  The "words" are not
Packit Service f6e53a
necessarily real words, but they look more like words than a string
Packit Service f6e53a
of hex characters.
Packit Service f6e53a
Packit Service f6e53a
The 'BubbleBabble' string is appended as a comment when the string
Packit Service f6e53a
method is called.
Packit Service f6e53a
Packit Service f6e53a
=head2 create
Packit Service f6e53a
Packit Service f6e53a
    use Net::DNS::SEC;
Packit Service f6e53a
Packit Service f6e53a
    $dsrr = create Net::DNS::RR::DS($keyrr, digtype => 'SHA-256' );
Packit Service f6e53a
    $keyrr->print;
Packit Service f6e53a
    $dsrr->print;
Packit Service f6e53a
Packit Service f6e53a
This constructor takes a key object as argument and will return the
Packit Service f6e53a
corresponding DS RR object.
Packit Service f6e53a
Packit Service f6e53a
The digest type defaults to SHA-1.
Packit Service f6e53a
Packit Service f6e53a
=head2 verify
Packit Service f6e53a
Packit Service f6e53a
    $verify = $dsrr->verify($keyrr);
Packit Service f6e53a
Packit Service f6e53a
The boolean verify method will return true if the hash over the key
Packit Service f6e53a
RR provided as the argument conforms to the data in the DS itself
Packit Service f6e53a
i.e. the DS points to the DNSKEY from the argument.
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
=head1 COPYRIGHT
Packit Service f6e53a
Packit Service f6e53a
Copyright (c)2001-2005 RIPE NCC.  Author Olaf M. Kolkman
Packit Service f6e53a
Packit Service f6e53a
Portions Copyright (c)2013 Dick Franks.
Packit Service f6e53a
Packit Service f6e53a
All rights reserved.
Packit Service f6e53a
Packit Service f6e53a
Package template (c)2009,2012 O.M.Kolkman and R.W.Franks.
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
=head1 LICENSE
Packit Service f6e53a
Packit Service f6e53a
Permission to use, copy, modify, and distribute this software and its
Packit Service f6e53a
documentation for any purpose and without fee is hereby granted, provided
Packit Service f6e53a
that the above copyright notice appear in all copies and that both that
Packit Service f6e53a
copyright notice and this permission notice appear in supporting
Packit Service f6e53a
documentation, and that the name of the author not be used in advertising
Packit Service f6e53a
or publicity pertaining to distribution of the software without specific
Packit Service f6e53a
prior written permission.
Packit Service f6e53a
Packit Service f6e53a
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit Service f6e53a
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit Service f6e53a
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Packit Service f6e53a
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit Service f6e53a
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit Service f6e53a
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Packit Service f6e53a
DEALINGS IN THE SOFTWARE.
Packit Service f6e53a
Packit Service f6e53a
Packit Service f6e53a
=head1 SEE ALSO
Packit Service f6e53a
Packit Service f6e53a
L<perl>, L<Net::DNS>, L<Net::DNS::RR>, RFC4034, RFC3658
Packit Service f6e53a
Packit Service f6e53a
L<Algorithm Numbers|http://www.iana.org/assignments/dns-sec-alg-numbers>,
Packit Service f6e53a
L<Digest Types|http://www.iana.org/assignments/ds-rr-types>
Packit Service f6e53a
Packit Service f6e53a
=cut