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