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