1#!@PERL@
2#
3# Copyright (C) 2010, 2012, 2014  Internet Systems Consortium, Inc. ("ISC")
4#
5# Permission to use, copy, modify, and/or distribute this software for any
6# purpose with or without fee is hereby granted, provided that the above
7# copyright notice and this permission notice appear in all copies.
8#
9# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15# PERFORMANCE OF THIS SOFTWARE.
16
17# Id: check-secure-delegation.pl.in,v 1.2 2010/12/21 02:32:21 marka Exp
18
19use warnings;
20use FileHandle;
21use IPC::Open2;
22use POSIX qw/strftime/;
23
24#
25# We only compare keyid / DNSSEC algorithm pairs.  If this succeeds then
26# the crypto will likely succeed.  If it fails then the crypto will definitely
27# fail.
28#
29$prefix = "@prefix@";
30$dig = "$prefix/bin/dig +cd +dnssec +noall +answer";
31$dsfromkey = "$prefix/sbin/dnssec-dsfromkey -1 -A -f /dev/stdin";
32
33# Get "now" in a RRSIG datestamp format.
34$now = strftime "%Y%m%d%H%M%S", gmtime;
35
36foreach $zone (@ARGV) {
37	my %algorithms = ();
38	my %dnskeygood = ();
39	my %dnskeyalg = ();
40	my %dnskey = ();
41	my %dsgood = ();
42	my %ds = ();
43
44	# Read the DS records and extract the key id, algorithm pairs
45	open(DS, "$dig -t DS -q $zone|") || die("dig DS failed");
46	while(<DS>) {
47		@words = split;
48		if ($words[3] eq "RRSIG" && $words[4] eq "DS") {
49			next if ($words[8] >= $now && $words[9] <= $now);
50			print "BAD SIG DATES: $_";
51		}
52		next if ($words[3] ne "DS");
53		$ds{"$words[4] $words[5]"} = 1;
54		$algorithms{"$words[5]"} = 1;
55	}
56	close(DS);
57
58	# Read the RRSIG(DNSKEY) records and extract the key id,
59	# algorithm pairs.  Set good if we have a match against the DS
60	# records.  DNSKEY records should be before the RRSIG records.
61	open(DNSKEY, "$dig -t DNSKEY -q $zone|") || die("dig DNSKEY failed");
62	while (<DNSKEY>) {
63		@words = split;
64		if ($words[3] eq "DNSKEY") {
65			$dnskeyalg{"$words[6]"} = 1;
66			next if (! -e "/dev/stdin");
67			# get the key id ($dswords[3]).
68			$pid = open2(*Reader, *Writer, "$dsfromkey $zone");
69			die("dsfromkey failed") if ($pid == -1);
70			print Writer "$_";
71			close(Writer);
72			$line = <Reader>;
73			close(Reader);
74			@dswords = split /\s/, $line;
75			$dnskey{"$dswords[3] $dswords[4]"} = 1;
76			next;
77		}
78		next if ($words[3] ne "RRSIG" || $words[4] ne "DNSKEY");
79		if ($words[8] >= $now && $words[9] <= $now) {
80			# If we don't have /dev/stdin then just check for the
81			# RRSIG otherwise check for both the DNSKEY and
82			# RRSIG.
83			$dsgood{"$words[5]"} = 1
84				if (! -e "/dev/stdin" &&
85				    exists($ds{"$words[10] $words[5]"}));
86			$dsgood{"$words[5]"} = 1
87				if (exists($ds{"$words[10] $words[5]"}) &&
88				    exists($dnskey{"$words[10] $words[5]"}));
89			$dnskeygood{"$words[5]"} = 1
90				if (! -e "/dev/stdin");
91			$dnskeygood{"$words[5]"} = 1
92				if (exists($dnskey{"$words[10] $words[5]"}));
93		} else {
94			$dnskeygood{"$words[5]"} = 1;
95			print "BAD SIG DATES: $_";
96		}
97	}
98	close(DNSKEY);
99
100	# Do we have signatures for all DNSKEY algorithms?
101	foreach $alg ( keys %dnskeyalg ) {
102		print "Missing $zone DNSKEY RRSIG for algorithm $alg\n"
103			if (!exists($dnskeygood{$alg}));
104	}
105
106	# Do we have a matching self signed DNSKEY for all DNSSEC algorithms
107	# in the DS records.
108	$count = 0;
109	foreach $alg ( keys %algorithms ) {
110		if (exists($dsgood{$alg})) {
111			print "$zone algorithm $alg good " .
112			      "(found DS / self signed DNSKEY pair)\n";
113		} else {
114			print "$zone algorithm $alg bad " .
115			      "(no DS / self signed DNSKEY pair found)\n";
116		}
117		$count++;
118	}
119	print "$zone has no secure delegation records\n"
120		if (! $count);
121}
122