The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Net::DNS::RR::SSHFP;
#
# $Id: SSHFP.pm 932 2011-10-26 12:40:48Z willem $
#
use strict;
BEGIN {
    eval { require bytes; }
}
use vars qw(@ISA $VERSION $HasBabble);

BEGIN {
	eval {
		require Digest::BubbleBabble;
		Digest::BubbleBabble->import(qw(bubblebabble))
	};

	$HasBabble = $@ ? 0 : 1;

}

$VERSION = (qw$LastChangedRevision: 932 $)[1];

@ISA = qw(Net::DNS::RR);

my %algtype = (
	RSA => 1,
	DSA => 2,
);

my %fingerprinttype = (
	'SHA-1' => 1,
);

my %fingerprinttypebyval = reverse %fingerprinttype;
my %algtypebyval	     = reverse %algtype;


sub new {
    my ($class, $self, $data, $offset) = @_;

	if ($self->{'rdlength'} > 0) {
		my $offsettoalg    = $offset;
		my $offsettofptype = $offset+1;
		my $offsettofp     = $offset+2;
		my $fplength       = 20;   # This will need to change if other fingerprint types
								   # are being deployed.


		$self->{'algorithm'} = unpack('C', substr($$data, $offsettoalg, 1));
		$self->{'fptype'}    = unpack('C', substr($$data, $offsettofptype, 1));

		unless (defined $fingerprinttypebyval{$self->{'fptype'}}){
		  warn "This fingerprint type $self->{'fptype'} has not yet been implemented, creation of SSHFP failed\n." ;
		  return undef;
		}


		# All this is SHA-1 dependend
		$self->{'fpbin'} = substr($$data,$offsettofp, $fplength); # SHA1 digest 20 bytes long

		$self->{'fingerprint'} = uc unpack('H*', $self->{'fpbin'});
    }


    return bless $self, $class;
}


sub new_from_string {
	my ($class, $self, $string) = @_;

	if ($string) {
		$string =~ tr/()//d;
		$string =~ s/;.*$//mg;
		$string =~ s/\n//g;

		@{$self}{qw(algorithm fptype fingerprint)} = split(m/\s+/, $string, 3);

		# We allow spaces in the fingerprint.
		$self->{'fingerprint'} =~ s/\s//g;
    }

	return bless $self, $class;
}



sub rdatastr {
	my $self     = shift;
	my $rdatastr = '';

	if (exists $self->{"algorithm"}) {
		$rdatastr = join('  ', @{$self}{qw(algorithm fptype fingerprint)})
					.' ; ' . $self->babble;
	}

	return $rdatastr;
}

sub rr_rdata {
    my $self = shift;

    if (exists $self->{"algorithm"}) {
    	return pack('C2',  @{$self}{qw(algorithm fptype)}) . $self->fpbin;
    }

    return '';

}



sub babble {
    my $self = shift;

    if ($HasBabble) {
		return bubblebabble(Digest => $self->fpbin);
    } else {
		return "";
    }
}


sub fpbin {
	my ($self) = @_;

	return $self->{'fpbin'} ||= pack('H*', $self->{'fingerprint'});
}


1;


=head1 NAME

Net::DNS::RR::SSHFP - DNS SSHFP resource record

=head1 SYNOPSIS

C<use Net::DNS::RR>;

=head1 DESCRIPTION

Class for Delegation signer (SSHFP) resource records.

=head1 METHODS

In addition to the regular methods


=head2 algorithm

    print "algorithm" = ", $rr->algorithm, "\n";

Returns the RR's algorithm field in decimal representation

    1 = RSA
    2 = DSS


=head2 fingerprint

    print "fingerprint" = ", $rr->fingerprint, "\n";

Returns the SHA1 fingerprint over the label and key in hexadecimal
representation.


=head2 fpbin

    $fpbin = $rr->fpbin;

Returns the fingerprint as binary material.


=head2 fptype

   print "fingerprint type" . " = " . $rr->fptype ."\n";

Returns the fingerprint type of the SSHFP RR.

=head2 babble

   print $rr->babble;

If Digest::BubbleBabble is available on the sytem this method returns the
'BabbleBubble' representation of the fingerprint. The 'BabbleBubble'
string may be handy for telephone confirmation.

The 'BabbleBubble' string returned as a comment behind the RDATA when
the string method is called.

The method returns an empty string if Digest::BubbleBable is not installed.

=head1 TODO

=head1 ACKNOWLEDGEMENT

Jakob Schlyter for code review and supplying patches.

=head1 COPYRIGHT

Copyright (c) 2004 RIPE NCC, Olaf Kolkman.

"All rights reserved, This program is free software; you may redistribute it
and/or modify it under the same terms as Perl itself.

=head1 SEE ALSO

L<perl(1)>, L<Net::DNS>, L<Net::DNS::Resolver>, L<Net::DNS::Packet>,
L<Net::DNS::Header>, L<Net::DNS::Question>, L<Net::DNS::RR>,
draft-ietf-dnssext-delegation-signer

=cut