Files

134 lines
3.5 KiB
Plaintext
Raw Permalink Normal View History

#!/usr/bin/env perl
=pod
=head1 SUMMARY
This script verifies that the provided RRSIG signs the
the provided RRset by checking against the provided
DNSKEY.
=head1 SYNOPSIS
cat data-file | verify-rrset.pl
verify-rrset.pl --help
=head1 DATA FILE
Create a file with the entire RRset, the RRSIG record
and the matching DNSKEY record. The records must be
in that specific order.
=over 3
=item *
All records in an RRset must have the same type and the same
owner name.
=item *
There must be at least one record in the RRset, but there may
be multiple records. Some records such as NSEC must normally
not be more than one of in a RRset, but here that is permitted.
=item *
There must be exactly one RRSIG, and its owner name must be
the same as the RRset.
=item *
There must be exactly one DNSKEY.
=item *
Comment lines starting with "#" are permitted.
=back
=head1 EXAMPLE FILE
=begin text
err-mult-nsec-1.dnssec10.xa. 86400 IN NSEC ns1.err-mult-nsec-1.dnssec10.xa. NS SOA RRSIG NSEC DNSKEY TYPE65534
err-mult-nsec-1.dnssec10.xa. 86400 IN NSEC www.err-mult-nsec-1.dnssec10.xa. NS SOA RRSIG NSEC DNSKEY TYPE65534
err-mult-nsec-1.dnssec10.xa. 86400 IN RRSIG NSEC 13 3 86400 20320923032719 20240925135938 58097 err-mult-nsec-1.dnssec10.xa. loXyRdLZF9LWOOMLBl9Y8O4lRjoCiZVnnczuvlPxblX34Jy3tM+6IFmtHAUyU/6hLuoZ1H2BwYjN MSx2n95/lg==
err-mult-nsec-1.dnssec10.xa. 86400 IN DNSKEY 256 3 13 5H2z0t6sesAGCzY5ayLWpN5s2y7HUq/TWFeZ4tAEvAPhmX6rtM5AkEAm G3QnVSfQN3u5wirEC9/JDqm2G3wJkA==
=end text
=cut
use 5.16.0;
use warnings;
use Net::DNS::SEC 1.26;
use Net::DNS 1.47;
use Getopt::Long;
use Pod::Usage;
my ( $help );
GetOptions( 'help' => \$help
);
if ( $help ) {
pod2usage(-verbose => 99);
exit 0;
}
my ( $section ) = 'RRSET';
my ( $rrsig );
my ( @rrsetref );
my ( $keyrr );
my ( $rrsettype ) = '';
my ( $ownername ) = '';
my ( $rrsetfound ) = 0;
my ( $rrsigfound ) = 0;
my ( $keyrrfound ) = 0;
while( my $line = <> ) {
chomp ( $line );
next if $line =~ /^\s*$/;
next if $line =~ /^#/;
my $rr = Net::DNS::RR->new( $line );
# say "DEBUG: " . $rr->type;
if ( $rr->type eq 'RRSIG' ) {
die "ERROR: The RRset must be listed before the RRSIG.\n" unless $rrsetfound;
die "ERROR: Only one RRSIG may be included.\n" if $rrsigfound;
if ($rr->owner ne $ownername ) {
die "ERROR: RRSIG must have the same owner name as the RRset.\n";
}
$rrsig = $rr;
$rrsigfound = 1;
} elsif ( $rr->type eq 'DNSKEY' and $rrsigfound ) {
die "ERROR: Only one DNSKEY may be included.\n" if $keyrrfound;
$keyrr = $rr;
$keyrrfound = 1;
} elsif ($keyrrfound) {
die "ERROR: DNSKEY must be the last record.\n" if $keyrrfound;
} else {
if ( $rrsettype) {
if ($rr->type ne $rrsettype ) {
die "ERROR: All records in the RRset must have the same type.\n";
}
if ($rr->owner ne $ownername ) {
die "ERROR: All records in the RRset must have the same owner name.\n";
}
} else {
$rrsettype = $rr->type;
$ownername = $rr->owner;
$rrsetfound = 1;
};
push ( @rrsetref, $rr );
}
}
die "ERROR: Missing RRset\n" unless $rrsetfound;
die "ERROR: Missing RRSIG\n" unless $rrsigfound;
die "ERROR: Missing DNSKEY\n" unless $keyrrfound;
my $verify = $rrsig->verify( \@rrsetref, $keyrr );
if ($verify) {
say 'Verified.';
} else {
say 'Verify ERROR: ' . $rrsig->vrfyerrstr;
}