#!/usr/bin/perl -w ################################################################# # # @(#) dns-tsig-gen (c) 19. May 2004 (hoz) # # Generate a HMAC-MD5 TSIG key and create a file with a # named.conf key section. # The file name will be "keyname.secret". # # (M1) 06. Jun 2011 # Algorithm changed to HMAC-SHA1 with a default # key size of 160 bits # ################################################################# use POSIX; use integer; my $kname = ""; my $kfile = ""; # (M1) my $algorithm = "HMAC-SHA1"; my $algnr = 161; # 157 for HMAC-MD5 my $bits = 160; # 256 for HMAC-MD5 ################################################################# # usage ################################################################# sub usage { my ($mesg) = shift @_; print STDERR "usage: $progname [-b bits] -n keyname | -k keyfile ...\n"; print STDERR "\t-b bits \tsize of key (1..160, defaults to $bits)\n"; print STDERR "\t-n keyname\tGenerate new key with keyname to identify the key\n"; print STDERR "\t-k keyfile\tUse existent \"K*+$algnr+*.key\" keyfile to generate key section\n"; print STDERR "illegal argument: $mesg \n" if defined $mesg; exit (1); } ################################################################# # parseopts ################################################################# sub parseopts { my (@args) = @_; my ($option); while ( $option = shift @args ) { if ( $option eq "-b" ) { $bits = shift @args; } elsif ( $option eq "-n" ) { $kname = shift @args; } elsif ( $option eq "-k" ) { $kfile = shift @args; } elsif ( $option eq "--" ) { last; } elsif ( $option =~ /^-.*/ ) { usage $option; } else { unshift @args, $option; last; } } return @args; } ################################################################# # error ($format, ....) ################################################################# sub error { my ($frmt) = shift @_; my (@pars) = @_; printf (STDERR "$progname: $frmt\n", @pars); } ################################################################# # fatal ($format, ....) ################################################################# sub fatal { error (@_); exit (1); } ################################################################# # get_secret_from_file ($kfile) ################################################################# sub get_secret_from_file { my ($file) = shift @_; my ($name, $class, $type, $flags, $proto, $algo, $secret); open (IN, "< $file") or fatal "Can't open $file for reading"; while ( ) { chomp; next if /^;/; # skip comment lines next if /^\s*$/; # skip empty lines ($name, $class, $type, $flags, $proto, $algo, $secret) = split (" ", $_, 7); last if $type eq "DNSKEY"; } close (IN); fatal ("$file: $name is not a key for dnssec\n") if $proto != 3; fatal ("$file: key algorithm must be $algorithm\n") if $algo != $algnr; return ($secret); } ################################################################# # print_keysection ################################################################# sub print_keysection { my ($fh) = shift @_; my ($name, $secret, $keytag, $date) = @_; # print the record in "keys" section syntax print $fh "\n"; printf $fh "key \"%s\" {\n", $name; print $fh "\talgorithm hmac-sha1;\n"; printf $fh "\tsecret \"%s\";\n", $secret; printf $fh "}; # keyid = %s (%s)\n", $keytag, $date; } ################################################################# # add_file ################################################################# sub add_file { my ($file) = shift @_; local *OUT; # get name and tag from kfile name $file =~ /K(.*)\+$algnr\+(\d+)\.key/; my $name = $1; my $keytag = $2; # get last modification time of keyfile my @fatt = stat ($kfile); my @tm = localtime ($fatt[9]); # get time struct my $fdate = POSIX::strftime ("%d. %b %Y %H:%M:%S %Z", @tm); # get secret from file.key my $secret = get_secret_from_file ($file); # check if key is already there $file = $name . "secret"; # filename is "name.secret" if ( -f $file ) # file does exist ? { my $rc = 0xffff & system ("grep \"# keyid = $keytag \" $file > /dev/null"); if ( $rc == 0 ) { printf STDERR "Key with keytag $keytag already in file $file\n"; return; } } # now write the output file open (OUT, "> $file") or die "Can't create \"$file\"\n"; # write file header @tm = localtime (time()); # get time struct my $date = POSIX::strftime ("%d. %b %Y %H:%M:%S %Z", @tm); print OUT "#\n"; print OUT "#\t@(#)\t$file $date\n"; print OUT "#\n"; print OUT "#\t!! Don't edit this file by hand !!\n"; print OUT "#\n"; print OUT "#\tThis file is generated by $progname (c) May 2004 - Jun 2011 (hoz)\n"; print OUT "#\tInclude it into named.conf via\n"; print OUT "#\t\tinclude \"$file\";\n"; print OUT "#\n"; print_keysection (\*OUT, $name, $secret, $keytag, $fdate); close (OUT); } ################################################################# # main ################################################################# local ($progname) = $0; $progname =~ s|.*/||; parseopts @ARGV; # check options usage "specify at least -n or -k\n" if $kname eq "" && $kfile eq ""; usage "specify one of -n or -k but not both\n" if $kname ne "" && $kfile ne ""; usage "arg to -b should be between 1 and 160\n" if $bits < 1 || $bits > 160; if ( $kname ) # generate new keyfile if there is a key name { $kfile = `dnssec-keygen -a HMAC-SHA1 -b $bits -n HOST $kname`; chomp ($kfile); } else # canonify key file name { $kfile =~ s/\.private$//; $kfile =~ s/\.key$//; $kfile =~ s/\.$//; } $kfile .= ".key"; add_file ($kfile);