dnssec-keytool.pl
branchhs12
changeset 77 35905799cfd1
parent 76 7c48ae30987c
child 78 bb780a686eb6
equal deleted inserted replaced
76:7c48ae30987c 77:35905799cfd1
     1 #! /usr/bin/perl
       
     2 
       
     3 use v5.10;
       
     4 use warnings;
       
     5 use strict;
       
     6 use FindBin;
       
     7 use File::Temp;
       
     8 use Getopt::Long;
       
     9 use Pod::Usage;
       
    10 use File::Basename;
       
    11 use if $ENV{DEBUG} => "Smart::Comments";
       
    12 use DNStools::Config qw(get_config);
       
    13 
       
    14 my $ME = basename $0;
       
    15 
       
    16 sub read_conf(@);
       
    17 sub read_argv($);
       
    18 sub rm_keys($@);
       
    19 sub ck_zone($@);
       
    20 sub create_ksk($@);
       
    21 sub create_zsk($@);
       
    22 sub post_create($@);
       
    23 
       
    24 MAIN: {
       
    25     ### reading config
       
    26     my %conf = get_config("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf");
       
    27 
       
    28     my ($cmd, @zones) = read_argv($conf{master_dir});
       
    29 
       
    30     given ($cmd) {
       
    31         when ("rm") { rm_keys($conf{master_dir}, @zones); exit }
       
    32         when ("ck") { ck_zone($conf{master_dir}, @zones) }
       
    33         when ("ksk") { create_ksk($conf{master_dir}, @zones) }
       
    34     };
       
    35 
       
    36     create_zsk($conf{master_dir}, @zones);
       
    37     post_create($conf{master_dir}, @zones);
       
    38 }
       
    39 
       
    40 sub read_argv ($) {
       
    41     my ($master_dir) = @_;
       
    42     my ($cmd, @zones);    # return
       
    43 
       
    44     GetOptions(
       
    45         "zsk"      => sub { $cmd = "zsk" },
       
    46         "ksk"      => sub { $cmd = "ksk" },
       
    47         "rm"       => sub { $cmd = "rm" },
       
    48         "ck|check" => sub { $cmd = "ck" },
       
    49         "h|help" => sub { pod2usage(-exitvalue => 0, -verbose => 1) },
       
    50         "m|man"  => sub {
       
    51             pod2usage(
       
    52                 -exitvalue => 0,
       
    53                 -noperldoc => system("perldoc -V &>/dev/null"),
       
    54                 -verbose   => 2
       
    55             );
       
    56         },
       
    57       )
       
    58       and @ARGV
       
    59       or pod2usage;
       
    60 
       
    61     # checks the zones in argv if there are managed zones
       
    62     foreach (@ARGV) {
       
    63         chomp(my $zone = `idn --quiet "$_"`);
       
    64 
       
    65         die "zone $zone is not managed\n"
       
    66           if not -f "$master_dir/$zone/$zone";
       
    67 
       
    68         push @zones, $zone;
       
    69     }
       
    70     return ($cmd, @zones);
       
    71 }
       
    72 
       
    73 
       
    74 sub rm_keys ($@) {
       
    75 
       
    76     # deletes all the keys were handed over -rm in argv
       
    77     my ($master_dir, @zone) = @_;
       
    78 
       
    79     for (@zone) {
       
    80         my $zone = $_;
       
    81 
       
    82         my $zpf = "$master_dir/$zone";
       
    83         my $ep  = 0;
       
    84 
       
    85         if (-e "$zpf/$zone.signed") {
       
    86             unlink "$zpf/$zone.signed" and $ep = 1;
       
    87         }
       
    88         if (-e "$zpf/.keycounter") {
       
    89             unlink "$zpf/.keycounter" and $ep = 1;
       
    90         }
       
    91         if (-e "$zpf/.index.ksk") {
       
    92             unlink "$zpf/.index.ksk" and $ep = 1;
       
    93         }
       
    94         if (-e "$zpf/.index.zsk") {
       
    95             unlink "$zpf/.index.zsk" and $ep = 1;
       
    96         }
       
    97         if (-e "$zpf/dsset-$zone.") {
       
    98             unlink "$zpf/dsset-$zone." and $ep = 1;
       
    99         }
       
   100         if (-e "$zpf/keyset-$zone.") {
       
   101             unlink "$zpf/keyset-$zone." and $ep = 1;
       
   102         }
       
   103 
       
   104         for (glob("$zpf/K$zone*")) {
       
   105             chomp($_);
       
   106             unlink("$_");
       
   107         }
       
   108 
       
   109         if ($ep == 1) {
       
   110             print " * $zone: removed key-set\n";
       
   111         }
       
   112 
       
   113 	open(my $old, "$zpf/$zone") or die "$zpf/$zone: $!\n";
       
   114 	my $fh = File::Temp->new(DIR => $zpf) or die "Can't create tmpfile: $!\n";
       
   115 	print $fh grep { not /^\s*\$INCLUDE.*"K$zone.*\.key"/i } <$old>;
       
   116 	rename($fh->filename => "$zpf/$zone")
       
   117 	    or die "Can't rename " . $fh->filename . " to $zpf/$zone: $!\n";
       
   118     }
       
   119 }
       
   120 
       
   121 sub create_ksk ($@) {
       
   122     my ($master_dir, @zone) = @_;
       
   123     my @index;
       
   124     my $keyname;
       
   125 
       
   126     for (@zone) {
       
   127         my $zone = $_;
       
   128         my $zpf  = "$master_dir/$zone";
       
   129 
       
   130         $keyname =
       
   131           `cd $zpf && dnssec-keygen -a RSASHA1 -b 2048 -f KSK -n ZONE $zone`;
       
   132 
       
   133         unless (-f "$zpf/.index.ksk") { @index = (); }
       
   134         else {
       
   135             open(INDEX, "$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n";
       
   136             @index = <INDEX>;
       
   137             close(INDEX);
       
   138         }
       
   139 
       
   140         push @index, $keyname;
       
   141         if (@index > 2) { shift(@index); }
       
   142 
       
   143         {
       
   144             my $fh = File::Temp->new(DIR => "$zpf")
       
   145               or die "Can't create tmpdir: $!\n";
       
   146             print $fh join "" => @index, "";
       
   147             rename($fh->filename => "$zpf/.index.ksk")
       
   148               or die "Can't rename "
       
   149               . $fh->filename
       
   150               . " to $zpf/.index.ksk: $!\n";
       
   151         }
       
   152 
       
   153         chomp($keyname);
       
   154         print " * $zone: new KSK $keyname\n";
       
   155         print "!! THE KSK must be published !! \n";
       
   156 
       
   157     }
       
   158 }
       
   159 
       
   160 sub create_zsk ($@) {
       
   161     my ($master_dir, @zone) = @_;
       
   162     my @index;
       
   163     my $keyname;
       
   164 
       
   165     for (@zone) {
       
   166         my $zone = $_;
       
   167         my $zpf  = "$master_dir/$zone";
       
   168 
       
   169         $keyname = `cd $zpf && dnssec-keygen -a RSASHA1 -b 512 -n ZONE $zone`;
       
   170 
       
   171         unless (-f "$zpf/.index.zsk") {
       
   172             @index = ();
       
   173         }
       
   174         else {
       
   175             open(INDEX, "$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n";
       
   176             @index = <INDEX>;
       
   177             close(INDEX);
       
   178         }
       
   179 
       
   180         push @index, $keyname;
       
   181         if (@index > 2) { shift(@index); }
       
   182 
       
   183         {
       
   184             my $fh = File::Temp->new(DIR => "$zpf")
       
   185               or die "Can't create tmpdir: $!\n";
       
   186             print $fh join "" => @index, "";
       
   187             rename($fh->filename => "$zpf/.index.zsk")
       
   188               or die "Can't rename "
       
   189               . $fh->filename
       
   190               . " to $zpf/.index.zsk: $!\n";
       
   191         }
       
   192         chomp($keyname);
       
   193         print " * $zone: new ZSK $keyname\n";
       
   194 
       
   195         open(KC, ">$zpf/.keycounter") or die "$zpf/keycounter: $!\n";
       
   196         print KC "0";
       
   197         close(KC);
       
   198     }
       
   199 }
       
   200 
       
   201 sub ck_zone ($@) {
       
   202     my ($master_dir, @zone) = @_;
       
   203 
       
   204     for (@zone) {
       
   205         my $zone = $_;
       
   206         my $zpf  = "$master_dir/$zone";
       
   207         my $keyfile;
       
   208         my @content;
       
   209         my @keylist;
       
   210 
       
   211         for (<$zpf/*>) {
       
   212             if (m#(K$zone.*\.key)#) {
       
   213                 $keyfile = $1;
       
   214                 open(KEYFILE, "<", "$zpf/$keyfile")
       
   215                   or die "$zpf/$keyfile: $!\n";
       
   216                 @content = <KEYFILE>;
       
   217                 close(KEYFILE);
       
   218                 for (@content) {
       
   219                     if (m#DNSKEY.257#) {
       
   220                         push @keylist, $keyfile;
       
   221                     }
       
   222                 }
       
   223             }
       
   224         }
       
   225 
       
   226         open(INDEX, ">$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n";
       
   227         for (@keylist) {
       
   228             s#\.key##;
       
   229             print INDEX "$_\n";
       
   230         }
       
   231         close(INDEX);
       
   232 
       
   233         print " * $zone: new .index.ksk created\n";
       
   234         if (-f "$zpf/.index.zsk") {
       
   235             unlink("$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n";
       
   236         }
       
   237     }
       
   238 }
       
   239 
       
   240 sub post_create ($@) {
       
   241     my ($master_dir, @zone) = @_;
       
   242     for (@zone) {
       
   243         my $zone = $_;
       
   244         `touch $master_dir/$zone/$zone`;
       
   245         &kill_useless_keys($zone, $master_dir);
       
   246         &key_to_zonefile($zone, $master_dir);
       
   247     }
       
   248 }
       
   249 
       
   250 sub kill_useless_keys ($@) {
       
   251 
       
   252     # the function deletes all keys that are not available in the zone
       
   253 
       
   254     my $zone       = $_[0];
       
   255     my $master_dir = $_[1];
       
   256     my @keylist    = ();
       
   257     my $zpf        = "$master_dir/$zone";
       
   258 
       
   259     open(INDEX, "<$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n";
       
   260     @keylist = <INDEX>;
       
   261     close(INDEX);
       
   262     open(INDEX, "<$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n";
       
   263     push @keylist, <INDEX>;
       
   264 
       
   265     # shortened the key name from the index file on the id in order to
       
   266     # be able to compare
       
   267     for (@keylist) {
       
   268         chomp;
       
   269         s#K.*\+.*\+(.*)#$1#;
       
   270     }
       
   271 
       
   272     # reviewed every key file (KSK, ZSK), whether they are described in
       
   273     # the respective index file. if not they will be deleted.
       
   274     for (glob("$master_dir/$zone/K*")) {
       
   275         chomp;
       
   276         my $file     = $_;
       
   277         my $rm_count = 1;
       
   278         my $keyname;
       
   279         for (@keylist) {
       
   280             if ($file =~ /$_/) { $rm_count = 0; }
       
   281         }
       
   282         if ($rm_count == 1) {
       
   283             unlink "$file";
       
   284             if ($file =~ /$zpf\/(.*\.key)/) {
       
   285                 print " * $zone: Key $1 removed \n";
       
   286             }
       
   287         }
       
   288     }
       
   289 }
       
   290 
       
   291 sub key_to_zonefile ($@) {
       
   292 
       
   293     # the function added all keys to the indexfile
       
   294     my $zone       = $_[0];
       
   295     my $master_dir = $_[1];
       
   296     my $zpf        = "$master_dir/$zone";
       
   297     my @old_content;
       
   298     my @new_content = ();
       
   299 
       
   300     open(ZONEFILE, "<$zpf/$zone");
       
   301     @old_content = <ZONEFILE>;
       
   302     close(ZONEFILE);
       
   303 
       
   304     for (@old_content) {
       
   305         unless (m#INCLUDE.*key#) { push @new_content, $_; }
       
   306     }
       
   307 
       
   308     for (<$zpf/*>) {
       
   309         if (m#(.*\/)(K.*\.key)#) {
       
   310             push @new_content, "\$INCLUDE \"$2\"\n";
       
   311         }
       
   312     }
       
   313     open(ZONEFILE, ">$zpf/$zone") or die "$zpf/$zone: $!\n";
       
   314     print ZONEFILE @new_content;
       
   315     close(ZONEFILE);
       
   316 }
       
   317 
       
   318 __END__
       
   319 
       
   320 =pod
       
   321 
       
   322 =head1 NAME
       
   323 
       
   324 dnssec-keytool
       
   325 
       
   326 =head1 SYNOPSIS
       
   327 
       
   328 dnssec-keytool {-z|-k|-r|-c} zone
       
   329 
       
   330 =head1 DESCRIPTION
       
   331 
       
   332 Blabla.
       
   333 
       
   334 =head1 OPTIONS
       
   335 
       
   336 =over
       
   337 
       
   338 =item B<-z>  created a new ZSK
       
   339 
       
   340 =item B<-k>  created a new ZSK and KSK
       
   341 
       
   342 =item B<-r>  delete the key-set of a zone
       
   343 
       
   344 =item B<-c>  created configuration files for the dnstools and a new ZSK for an existing KSK
       
   345 
       
   346 =back
       
   347 
       
   348 =cut
       
   349 
       
   350 # vim:sts=4 sw=4 aw ai sm: