diff -r 7c48ae30987c -r 35905799cfd1 bin/dnssec-keytool --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/dnssec-keytool Thu Jan 13 00:20:26 2011 +0100 @@ -0,0 +1,350 @@ +#! /usr/bin/perl + +use v5.10; +use warnings; +use strict; +use FindBin; +use File::Temp; +use Getopt::Long; +use Pod::Usage; +use File::Basename; +use if $ENV{DEBUG} => "Smart::Comments"; +use DNStools::Config qw(get_config); + +my $ME = basename $0; + +sub read_conf(@); +sub read_argv($); +sub rm_keys($@); +sub ck_zone($@); +sub create_ksk($@); +sub create_zsk($@); +sub post_create($@); + +MAIN: { + ### reading config + my %conf = get_config("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf"); + + my ($cmd, @zones) = read_argv($conf{master_dir}); + + given ($cmd) { + when ("rm") { rm_keys($conf{master_dir}, @zones); exit } + when ("ck") { ck_zone($conf{master_dir}, @zones) } + when ("ksk") { create_ksk($conf{master_dir}, @zones) } + }; + + create_zsk($conf{master_dir}, @zones); + post_create($conf{master_dir}, @zones); +} + +sub read_argv ($) { + my ($master_dir) = @_; + my ($cmd, @zones); # return + + GetOptions( + "zsk" => sub { $cmd = "zsk" }, + "ksk" => sub { $cmd = "ksk" }, + "rm" => sub { $cmd = "rm" }, + "ck|check" => sub { $cmd = "ck" }, + "h|help" => sub { pod2usage(-exitvalue => 0, -verbose => 1) }, + "m|man" => sub { + pod2usage( + -exitvalue => 0, + -noperldoc => system("perldoc -V &>/dev/null"), + -verbose => 2 + ); + }, + ) + and @ARGV + or pod2usage; + + # checks the zones in argv if there are managed zones + foreach (@ARGV) { + chomp(my $zone = `idn --quiet "$_"`); + + die "zone $zone is not managed\n" + if not -f "$master_dir/$zone/$zone"; + + push @zones, $zone; + } + return ($cmd, @zones); +} + + +sub rm_keys ($@) { + + # deletes all the keys were handed over -rm in argv + my ($master_dir, @zone) = @_; + + for (@zone) { + my $zone = $_; + + my $zpf = "$master_dir/$zone"; + my $ep = 0; + + if (-e "$zpf/$zone.signed") { + unlink "$zpf/$zone.signed" and $ep = 1; + } + if (-e "$zpf/.keycounter") { + unlink "$zpf/.keycounter" and $ep = 1; + } + if (-e "$zpf/.index.ksk") { + unlink "$zpf/.index.ksk" and $ep = 1; + } + if (-e "$zpf/.index.zsk") { + unlink "$zpf/.index.zsk" and $ep = 1; + } + if (-e "$zpf/dsset-$zone.") { + unlink "$zpf/dsset-$zone." and $ep = 1; + } + if (-e "$zpf/keyset-$zone.") { + unlink "$zpf/keyset-$zone." and $ep = 1; + } + + for (glob("$zpf/K$zone*")) { + chomp($_); + unlink("$_"); + } + + if ($ep == 1) { + print " * $zone: removed key-set\n"; + } + + open(my $old, "$zpf/$zone") or die "$zpf/$zone: $!\n"; + my $fh = File::Temp->new(DIR => $zpf) or die "Can't create tmpfile: $!\n"; + print $fh grep { not /^\s*\$INCLUDE.*"K$zone.*\.key"/i } <$old>; + rename($fh->filename => "$zpf/$zone") + or die "Can't rename " . $fh->filename . " to $zpf/$zone: $!\n"; + } +} + +sub create_ksk ($@) { + my ($master_dir, @zone) = @_; + my @index; + my $keyname; + + for (@zone) { + my $zone = $_; + my $zpf = "$master_dir/$zone"; + + $keyname = + `cd $zpf && dnssec-keygen -a RSASHA1 -b 2048 -f KSK -n ZONE $zone`; + + unless (-f "$zpf/.index.ksk") { @index = (); } + else { + open(INDEX, "$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n"; + @index = ; + close(INDEX); + } + + push @index, $keyname; + if (@index > 2) { shift(@index); } + + { + my $fh = File::Temp->new(DIR => "$zpf") + or die "Can't create tmpdir: $!\n"; + print $fh join "" => @index, ""; + rename($fh->filename => "$zpf/.index.ksk") + or die "Can't rename " + . $fh->filename + . " to $zpf/.index.ksk: $!\n"; + } + + chomp($keyname); + print " * $zone: new KSK $keyname\n"; + print "!! THE KSK must be published !! \n"; + + } +} + +sub create_zsk ($@) { + my ($master_dir, @zone) = @_; + my @index; + my $keyname; + + for (@zone) { + my $zone = $_; + my $zpf = "$master_dir/$zone"; + + $keyname = `cd $zpf && dnssec-keygen -a RSASHA1 -b 512 -n ZONE $zone`; + + unless (-f "$zpf/.index.zsk") { + @index = (); + } + else { + open(INDEX, "$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n"; + @index = ; + close(INDEX); + } + + push @index, $keyname; + if (@index > 2) { shift(@index); } + + { + my $fh = File::Temp->new(DIR => "$zpf") + or die "Can't create tmpdir: $!\n"; + print $fh join "" => @index, ""; + rename($fh->filename => "$zpf/.index.zsk") + or die "Can't rename " + . $fh->filename + . " to $zpf/.index.zsk: $!\n"; + } + chomp($keyname); + print " * $zone: new ZSK $keyname\n"; + + open(KC, ">$zpf/.keycounter") or die "$zpf/keycounter: $!\n"; + print KC "0"; + close(KC); + } +} + +sub ck_zone ($@) { + my ($master_dir, @zone) = @_; + + for (@zone) { + my $zone = $_; + my $zpf = "$master_dir/$zone"; + my $keyfile; + my @content; + my @keylist; + + for (<$zpf/*>) { + if (m#(K$zone.*\.key)#) { + $keyfile = $1; + open(KEYFILE, "<", "$zpf/$keyfile") + or die "$zpf/$keyfile: $!\n"; + @content = ; + close(KEYFILE); + for (@content) { + if (m#DNSKEY.257#) { + push @keylist, $keyfile; + } + } + } + } + + open(INDEX, ">$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n"; + for (@keylist) { + s#\.key##; + print INDEX "$_\n"; + } + close(INDEX); + + print " * $zone: new .index.ksk created\n"; + if (-f "$zpf/.index.zsk") { + unlink("$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n"; + } + } +} + +sub post_create ($@) { + my ($master_dir, @zone) = @_; + for (@zone) { + my $zone = $_; + `touch $master_dir/$zone/$zone`; + &kill_useless_keys($zone, $master_dir); + &key_to_zonefile($zone, $master_dir); + } +} + +sub kill_useless_keys ($@) { + + # the function deletes all keys that are not available in the zone + + my $zone = $_[0]; + my $master_dir = $_[1]; + my @keylist = (); + my $zpf = "$master_dir/$zone"; + + open(INDEX, "<$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n"; + @keylist = ; + close(INDEX); + open(INDEX, "<$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n"; + push @keylist, ; + + # shortened the key name from the index file on the id in order to + # be able to compare + for (@keylist) { + chomp; + s#K.*\+.*\+(.*)#$1#; + } + + # reviewed every key file (KSK, ZSK), whether they are described in + # the respective index file. if not they will be deleted. + for (glob("$master_dir/$zone/K*")) { + chomp; + my $file = $_; + my $rm_count = 1; + my $keyname; + for (@keylist) { + if ($file =~ /$_/) { $rm_count = 0; } + } + if ($rm_count == 1) { + unlink "$file"; + if ($file =~ /$zpf\/(.*\.key)/) { + print " * $zone: Key $1 removed \n"; + } + } + } +} + +sub key_to_zonefile ($@) { + + # the function added all keys to the indexfile + my $zone = $_[0]; + my $master_dir = $_[1]; + my $zpf = "$master_dir/$zone"; + my @old_content; + my @new_content = (); + + open(ZONEFILE, "<$zpf/$zone"); + @old_content = ; + close(ZONEFILE); + + for (@old_content) { + unless (m#INCLUDE.*key#) { push @new_content, $_; } + } + + for (<$zpf/*>) { + if (m#(.*\/)(K.*\.key)#) { + push @new_content, "\$INCLUDE \"$2\"\n"; + } + } + open(ZONEFILE, ">$zpf/$zone") or die "$zpf/$zone: $!\n"; + print ZONEFILE @new_content; + close(ZONEFILE); +} + +__END__ + +=pod + +=head1 NAME + +dnssec-keytool + +=head1 SYNOPSIS + +dnssec-keytool {-z|-k|-r|-c} zone + +=head1 DESCRIPTION + +Blabla. + +=head1 OPTIONS + +=over + +=item B<-z> created a new ZSK + +=item B<-k> created a new ZSK and KSK + +=item B<-r> delete the key-set of a zone + +=item B<-c> created configuration files for the dnstools and a new ZSK for an existing KSK + +=back + +=cut + +# vim:sts=4 sw=4 aw ai sm: