#!/usr/bin/perl
#
# Copyright 2005-2014 SPARTA, Inc.  All rights reserved.  See the COPYING
# file distributed with this software for details.
#
#
# genkrf
#
#	This script generates a keyrec file.
#

use strict;

use Getopt::Long qw(:config no_ignore_case_always);
use Net::DNS::SEC::Tools::conf;
use Net::DNS::SEC::Tools::defaults;
use Net::DNS::SEC::Tools::keyrec;
use Net::DNS::SEC::Tools::tooloptions;

#
# Version information.
#
my $NAME   = "genkrf";
my $VERS   = "$NAME version: 2.1.0";
my $DTVERS = "DNSSEC-Tools Version: 2.1";

#######################################################################
#
# Constants
#
our $DEF_TOOLSCONF = $Net::DNS::SEC::Tools::conf::CONFFILE;

#
# A hash mapping algorithm numbers to algorithm names.
#
our %algos = (
	"001" => "rsa",
	"002" => "dh",
	"003" => "dsa",
	"005" => "rsasha1",
	"157" => "hmac_md5"
);

#
# Names of fields from bind-9.3.1/lib/dns/dst_parse.c.
# Private-key-format:  v1.2
# These help in finding the size of the key from the .private key file.
#
our %algofields = (
	"001" => "Modulus:",
	"002" => "Prime(p):",
	"003" => "Prime(p):",
	"005" => "Modulus:",
	"157" => "Key:"
);
		  
#
# Data required for command line options.
#
my $zone;				# Name of the zone.
my $kskcur;				# Name of current KSK.
my $zskcur;				# Name of current ZSK.
my $zskpub;				# Name of published ZSK.
my $zonefile;				# Name of the zone file.
my $signedfile;				# Name of the signed zone file.
my $kskcount;				# Count of KSKs to generate.
my $kskdir;				# Directory where the KSK resides.
my $zskdir;				# Directory where the ZSKs reside.
my $endtime;				# Endtime of signature validity.
my $random;				# The source of randomness.
my $krfile;				# Name of the keyrec file to generate.
my $ksklife;				# Lifespan of the KSK.
my $zsklife;				# Lifespan of the ZSK.
my $algo;				# The encryption algorithm.
my $ksksize;				# The KSK size.
my $zsksize;				# The ZSK size.
my $zskcount;				# Count of ZSKs to generate.

my $verbose;				# Verbose-output flag.

#
# Command-line options specifically for this program.
#
my @opts = (
		"kskcur=s",			# Specify the current KSK.
		"zskcur=s",			# Specify the current ZSK.
		"zskpub=s",			# Specify the published ZSK.
		"kskdir=s",			# Specify the KSK directory.
		"zskdir=s",			# Specify the ZSK directory.
		"Version",			# Display the version number.
	   );

#
# Data from the dnssec-tools.conf file.
#
my $keygen;					# The key-generation program.

#
# Standard paths.
#
my $MKDIR = "/bin/mkdir";
my $MV	  = "/bin/mv";

#
# Lists of KSKs and ZSKs.
#
my @ksklist = ();		# List of current KSKs.
my @curlist = ();		# List of current ZSKs.
my @publist = ();		# List of published ZSKs.

#######################################################################

my $ret;					# Return code from main().

$ret = main();
exit($ret);

#-----------------------------------------------------------------------------
# Routine:	main()
#
# Purpose:	Uses global variables in this file.
#
sub main()
{
	my $argc = @ARGV;		# Number of command line arguments.
	my $errors = 0;			# Total error count.
	my $retval;			# Return value.

	my $signset;			# Signing-set name prefix.
	my $curkey;			# Path to current ZSK.
	my $pubkey;			# Path to published ZSK.

	erraction(ERR_EXIT);

	#
	# Parse the command line options.
	#
	optsandargs();

	#
	# Build the signing-set name prefix.
	#
	$signset = keyrec_signset_prefix($zone);
	$signset =~ s/\-$//;

	#
	# Generate the keyrec file.
	#
	$retval = keyrec_creat($krfile);
	keyrec_read($krfile);

	#
	# Add the zone keyrec.
	#
	keyrec_add('zone', $zone, {
				     'keyrec_type'	=> "zone",
				     'zonefile'		=> $zonefile,
				     'signedzone'	=> $signedfile,
				     'endtime'		=> $endtime,
				     'kskcur'		=> "$signset-00001",
				     'kskcount'		=> $kskcount,
				     'kskdirectory'	=> $kskdir,
				     'zskcount'		=> $zskcount,
				     'zskdirectory'	=> $zskdir,
				     'zskcur'		=> "$signset-00002",
				     'zskpub'		=> "$signset-00003",
				     'lastset'		=> "$signset-00003",
				     'keyrec_signdate'	=> "",
				     'keyrec_signsecs'	=> "",
				  });

	#
	# Add the KSK set keyrec.
	#
	keyrec_add('set', "$signset-00001",
				{
				   'zonename'		=> $zone,
				   'set_type'		=> 'kskcur',
				   'keys'		=> "",
				   'keyrec_setdate'	=> "",
				   'keyrec_setsecs'	=> "",
				});

	#
	# Add the ZSKCUR set keyrec.
	#
	keyrec_add('set', "$signset-00002",
				{
				   'zonename'		=> $zone,
				   'set_type'		=> 'zskcur',
				   'keys'		=> "",
				   'keyrec_setdate'	=> "",
				   'keyrec_setsecs'	=> "",
				});

	#
	# Add the ZSKPUB set keyrec.
	#
	keyrec_add('set', "$signset-00003",
				{
				   'zonename'		=> $zone,
				   'set_type'		=> 'zskpub',
				   'keys'		=> "",
				   'keyrec_setdate'	=> "",
				   'keyrec_setsecs'	=> "",
				});

	#
	# Build all our KSKs and add them to the keyrec file.
	#
	if($kskcur)
	{
		#
		# Create the key and save its name.
		#
		addksk($kskcur);
		push @ksklist, $kskcur;
	}
	else
	{
		for(my $ind=0; $ind < $kskcount ; $ind++)
		{
			my $ksk;				# Name of KSK.

			#
			# Generate our KSK.
			#
			$ksk = genksk($kskdir);
			if(!$ksk)
			{
				print STDERR "unable to generate KSK.\nPlease check the $DEF_TOOLSCONF file for correctness\n";
				exit(1);
			}

			#
			# Add this KSK's keyrec to the keyrec file.
			#
			addksk($ksk);

			#
			# Save the name of this key.
			#
			push @ksklist, $ksk;
		}
	}

	#
	# Build all our current ZSKs and add them to the keyrec file.
	#
	if($zskcur)
	{
		#
		# Create the key and save its name.
		#
		addzsk("zskcur",$zskcur);
		push @curlist, $zskcur;
	}
	else
	{
		for(my $ind=0; $ind < $zskcount ; $ind++)
		{
			#
			# Generate our ZSK.
			#
			$zskcur = genzsk($zskdir);
			if(!$zskcur)
			{
				print STDERR "unable to generate current ZSK.\nPlease check the $DEF_TOOLSCONF file for correctness\n";
				exit(1);
			}

			#
			# Add this ZSK's keyrec to the keyrec file.
			#
			addzsk("zskcur",$zskcur);

			#
			# Save the name of this key.
			#
			push @curlist, $zskcur;
		}

	}

	#
	# Build all our published ZSKs and add them to the keyrec file.
	#
	if($zskpub)
	{
		#
		# Create the key and save its name.
		#
		addzsk("zskpub",$zskpub);
		push @publist, $zskpub;
	}
	else
	{
		for(my $ind=0; $ind < $zskcount ; $ind++)
		{
			#
			# Generate our ZSK.
			#
			$zskpub = genzsk($zskdir);
			if(!$zskpub)
			{
				print STDERR "unable to generate published ZSK.\nPlease check the $DEF_TOOLSCONF file for correctness\n";
				exit(1);
			}

			#
			# Add this ZSK's keyrec to the keyrec file.
			#
			addzsk("zskpub",$zskpub);

			#
			# Save the name of this key.
			#
			push @publist, $zskpub;
		}

	}

	#
	# Add all the keys to their respective signing sets.
	#
	foreach my $key (@ksklist)
	{
		keyrec_signset_addkey("$signset-00001",$key);
	}
	foreach my $key (@curlist)
	{
		keyrec_signset_addkey("$signset-00002",$key);
	}
	foreach my $key (@publist)
	{
		keyrec_signset_addkey("$signset-00003",$key);
	}

	#
	# Write the keyrec file.
	#
	keyrec_write();
	keyrec_close();

	print "genkrf:  keyrec file $krfile created successfully\n" if($verbose);
	return(0);
}

#-----------------------------------------------------------------------------
# Routine:	optsandargs()
#
# Purpose:	Parse the command line for options and arguments.
#
sub optsandargs
{
	my $ropts;				# Reference to options hash.
	my %opts = ();				# Options hash.

	#
	# Slurp up the options.
	#
	opts_onerr(1);
	$ropts = opts_cmdopts(@opts);
	%opts = %$ropts 	if($ropts != undef);

	#
	# Get the option values.  If these weren't given on the command
	# line, they'll be taken from the config file or the defaults.
	#
	$kskcur	  = $opts{'kskcur'};
	$zskcur	  = $opts{'zskcur'};
	$zskpub	  = $opts{'zskpub'};

	$kskcount = $opts{'kskcount'}	|| dnssec_tools_default("kskcount");
	$kskdir	  = $opts{'kskdir'}	|| dnssec_tools_default("kskdir");
	$ksklife  = $opts{'ksklife'}	|| dnssec_tools_default("ksklife");
	$ksksize  = $opts{'ksklength'}	|| dnssec_tools_default("ksklength");
	$zskcount = $opts{'zskcount'}	|| dnssec_tools_default("zskcount");
	$zskdir	  = $opts{'zskdir'}	|| dnssec_tools_default("zskdir");
	$zsklife  = $opts{'zsklife'}	|| dnssec_tools_default("zsklife");
	$zsksize  = $opts{'zsklength'}	|| dnssec_tools_default("zsklength");

	$algo	  = $opts{'algorithm'}	|| dnssec_tools_default("algorithm");
	$endtime  = $opts{'endtime'}	|| dnssec_tools_default("enddate");
	$random	  = $opts{'random'}	|| dnssec_tools_default("random");

	$keygen	  = $opts{'keygen'}	|| dnssec_tools_default("bind-keygen");

	$verbose  = $opts{'verbose'};

	version() if(defined($opts{'Version'}));

	#
	# Give usage message in a few situations.
	#
	usage() if($#ARGV < 0);
	usage() if(defined($opts{'help'}));

	#
	# Get the zone file and signed filename.
	#
	$zonefile   = $ARGV[0];
	if($#ARGV > 0)
	{
		$signedfile = $ARGV[1];
	}
	else
	{
		$signedfile = $zonefile . ".signed";
	}

	#
	# Get the keyrec's zone and strip off a terminal ".".
	#
	$zone = $opts{'zone'} || $zonefile;
	$zone =~ s/^(.*)\.$/$1/;

	#
	# Set the output filename.
	#
	$krfile = $opts{'krfile'} || "$zone.krf";

	#
	# Default to the current directory if the KSK or ZSK directories
	# aren't given.
	#
	$kskdir = "." if(!$kskdir);
	$zskdir = "." if(!$zskdir);

	#
	# Ensure the KSK count is valid.
	#
	if($kskcount < 1)
	{
		print STDERR "invalid KSK count:  \"$kskcount\"\n";
		exit(10);
	}

	#
	# Ensure the ZSK count is valid.
	#
	if($zskcount < 1)
	{
		print STDERR "invalid ZSK count:  \"$zskcount\"\n";
		exit(10);
	}

	#
	# If the verbose flag was given, show all the values.
	#
	verbose() if($verbose);

}

#-----------------------------------------------------------------------------
# Routine:      getkeyalgo()
#
# Purpose:      This routine takes the identification string of the key
#               generated by dnssec-keygen as a parameter and returns the name
#               of the algorithm for that key.
#
#               The identification string of the key has the following format:
#
#			Knnnn.+aaa+iiiii
#
#               where:
#
#			nnnn is the key name
#			aaa  is the numeric representation of the algorithm
#			iiiii is the key identifier (or footprint)
#
sub getkeyalgo
{
	my $key = shift;
	my $algonum = $key;

	$algonum =~ s/^[^\+]*\+([^+]*)\+.*$/$1/g;
	return($algos{$algonum});
}

#-----------------------------------------------------------------------------
# Routine:      getkeysize()
#
# Purpose:      This routine takes the identification string of the key
#               and an optional key directory as parameters and returns
#               the size of the key.  If the directory is not specified
#               it defaults to the current directory.
#
sub getkeysize
{
	my $keytype = shift;			# Type of key to create.
	my $key	= shift;			# Name of key.
	my $keydir = shift;			# Key's directory.

	my $algofield;
	my $algonum;				# Algorithm number from key.
	my $keypath;
	my $keysize = 0;			# Key length.

	#
	# If the key's size field is set, we'll use it instead of
	# calculating things.
	#
	if($keytype eq "kskcur")
	{
		return($ksksize) if($ksksize > -1);
	}
	else
	{
		return($zsksize) if($zsksize > -1);
	}

	#
	# Get the path to the key.
	#
	$keydir = "." if(!$keydir);
	$keypath = $keydir . "/" . $key . ".private";

	#
	# Determine the algorithm field.
	#
	$algonum = $key;
	$algonum =~ s/^[^\+]*\+([^+]*)\+.*$/$1/g;
	$algofield = $algofields{$algonum};

	#
	# Open the key's file.
	#
	open(KF, "< $keypath") or return "";

	#
	# Get the algorithm line from the key file and calculate the
	# key's size.
	#
	while(<KF>)
	{
		my $line = $_;

		#
		# Skip any lines that don't hold the specified algorithm.
		#
		next if($line !~ /^$algofield/);

		#
		# Extract the value of the field.
		#
		$line =~ s/^$algofield(.*)$/$1/;
		$line =~ s/\s//g;

		#
		# The value is encoded in Base64, hence the following
		# algorithm for finding the keysize.
		#
		$keysize = length($line);
		$keysize = ($keysize / 4) * 3;

		#
		# Adjust the keysize a bit.
		#
		if($line =~ /==$/)
		{
			$keysize -= 2;
		}
		elsif($line =~ /=$/)
		{
			$keysize -= 1;
		}

		#
		# And one more minor tweak...
		#
		$keysize *= 8;
		last;
	}

	#
	# Close the key file and return the calculated key size.
	#
	close(KF);
	return($keysize);
}

#-----------------------------------------------------------------------------
# Routine:      genksk()
#
# Purpose:      Generate a new Key Signing Key (KSK.)
#
sub genksk
{
	my $cmdopts = "-r $random -a $algo -b $ksksize";
	my $ksk;

	#
	# Generate a new key.
	#
# print "genksk:  <$keygen $cmdopts -n zone -f KSK $zone>\n";
	$ksk = `$keygen $cmdopts -n zone -f KSK $zone`;
	chomp $ksk;

	#
	# Put the key files in their place.
	#
	if($kskdir ne ".")
	{
		`$MKDIR -p $kskdir && $MV $ksk* $kskdir`;
	}

	return($ksk || "");
}


#-----------------------------------------------------------------------------
# Routine:      genzsk()
#
# Purpose:      Generate a new Zone Signing Key (ZSK.)
#
sub genzsk
{
	my $cmdopts = "-r $random -a $algo -b $zsksize";
	my $zsk;

	#
	# Generate a new key.
	#
# print "genzsk:  <$keygen $cmdopts -n zone $zone>\n";
	$zsk = `$keygen $cmdopts -n zone $zone`;
	chomp $zsk;

	#
	# Put the key files in their place.
	#
	if($zskdir ne ".")
	{
		`$MKDIR -p $zskdir && $MV $zsk* $zskdir`;
	}

	return($zsk || "");
}

#----------------------------------------------------------------------
# Routine:	addksk()
#
# Purpose:	Add the KSK's keyrec to the keyrec file.
#
sub addksk
{
	my $keyname = shift;				# KSK's name.

	my $keypath;						# Path to KSK.
	my $alg = getkeyalgo($keyname);				# Key algorithm.
	my $len = getkeysize('kskcur',$keyname,$kskdir);	# Key length.

	#
	# Build the path to the KSK.
	#
	$keypath = "$kskdir/$keyname.key";

	#
	# Add the KSK keyrec.
	#
	keyrec_add('key', $keyname, {
				      'zonename'	=> $zone,
				      'keyrec_type'	=> "kskcur",
				      'algorithm'	=> $alg,
				      'random'		=> $random,
				      'ksklength'	=> $len,
				      'ksklife'		=> $ksklife,
				      'keypath'		=> "$keypath",
				      'keyrec_gendate'	=> "",
				      'keyrec_gensecs'	=> "",
				    });
};

#----------------------------------------------------------------------
# Routine:	addzsk()
#
# Purpose:	Add the ZSK's keyrec to the keyrec file.
#
sub addzsk
{
	my $keytype = shift;				# Type of ZSK.
	my $keyname = shift;				# ZSK's name.

	my $keypath;					# Path to ZSK.
	my $alg = getkeyalgo($keyname);			# Key algorithm.
	my $len = getkeysize('zsk',$keyname,$zskdir);	# Key length.

	#
	# Build the path to the ZSK.
	#
	$keypath = "$zskdir/$keyname.key";

	#
	# Add the ZSK keyrec.
	#
	keyrec_add('key', $keyname, {
				      'zonename'	=> $zone,
				      'keyrec_type'	=> "$keytype",
				      'algorithm'	=> $alg,
				      'random'		=> $random,
				      'zsklength'	=> $len,
				      'zsklife'		=> $zsklife,
				      'keypath'		=> "$keypath",
				      'keyrec_gendate'	=> "",
				      'keyrec_gensecs'	=> "",
				    });
};

#----------------------------------------------------------------------
# Routine:	version()
#
# Purpose:	Print the version number(s) and exit.
#
sub version
{
	print STDERR "$VERS\n";
	print STDERR "$DTVERS\n";

	exit(0);
}

#----------------------------------------------------------------------
# Routine:	verbose()
#
# Purpose:	Print the argument info.
#
sub verbose
{
	print "zonefile    - \"$zonefile\"\n";
	print "signedfile  - \"$signedfile\"\n";
	print "zone        - \"$zone\"\n";
	print "keyrec file - \"$krfile\"\n\n";

	print "algorithm   - \"$algo\"\n";
	print "endtime     - \"$endtime\"\n";
	print "random      - \"$random\"\n\n";

	print "kskcur      - \"$kskcur\"\n" if($kskcur ne "");
	print "kskcount    - \"$kskcount\"\n";
	print "kskdir      - \"$kskdir\"\n";
	print "ksksize     - \"$ksksize\"\n";
	print "ksklife     - \"$ksklife\"\n\n";

	print "zskcur      - \"$zskcur\"\n" if($zskcur ne "");
	print "zskpub      - \"$zskpub\"\n" if($zskpub ne "");
	print "zskcount    - \"$zskcount\"\n";
	print "zskdir      - \"$zskdir\"\n";
	print "zsksize     - \"$zsksize\"\n";
	print "zsklife     - \"$zsklife\"\n\n";
}

#-----------------------------------------------------------------------------
# Routine:	usage()
#
# Purpose:      This routine prints the usage and exits.
#
sub usage
{
	print STDERR "usage: genkrf [options] <zone-file> [signed-zone-file]\n";

	print STDERR "\n\t<zone-file>                     name of the zone file\n";
	print STDERR "\t[signed-zone-file]              name of the signed zone file\n";

	print STDERR "\n\toptions:\n";
	print STDERR "\t\t-zone ZONE              name of the zone\n";
	print STDERR "\t\t-krfile KEYREC          zone's keyrec file\n";
	print STDERR "\t\t-algorithm ALGORITHM    encryption algorithm\n";
	print STDERR "\t\t-endtime ENDTIME        end time of signature\n";
	print STDERR "\t\t-random RANDOMDEV       source of randomness\n\n";

	print STDERR "\t\t-kskcur KSK             name of the KSK\n";
	print STDERR "\t\t-kskcount COUNT         count of KSKs\n";
	print STDERR "\t\t-kskdir PATH            KSK directory\n";
	print STDERR "\t\t-ksklength KEYLEN       KSK length\n";
	print STDERR "\t\t-ksklife LIFESPAN       KSK lifespan\n\n";

	print STDERR "\t\t-zskcur ZSKCUR          name of the current ZSK\n";
	print STDERR "\t\t-zskpub ZSKPUB          name of the published ZSK\n";
	print STDERR "\t\t-zskcount COUNT         count of ZSKs\n";
	print STDERR "\t\t-zskdir PATH            ZSK directory\n";
	print STDERR "\t\t-zsklength KEYLEN       ZSK length\n";
	print STDERR "\t\t-zsklife LIFESPAN       ZSK lifespan\n\n";

	print STDERR "\t\t-verbose                verbose output\n";
	print STDERR "\t\t-Version                display version number\n";
	print STDERR "\t\t-help                   help message\n";

	exit(0);
}

1;

##############################################################################
#

=pod

=head1 NAME

genkrf - Generate a I<keyrec> file from Key Signing Key (KSK)
and/or Zone Signing Key (ZSK) files

=head1 SYNOPSIS

  genkrf [options] <zone-file> [<signed-zone-file>]

=head1 DESCRIPTION

B<genkrf> generates a I<keyrec> file from KSK and/or ZSK files.  It
generates new KSK and ZSK keys if needed.

The name of the I<keyrec> file to be generated is given by the B<-krfile>
option.  If this option is not specified, B<zone-name.krf> is used as the name
of the I<keyrec> file.  If the I<keyrec> file already exists, it will be
overwritten with new I<keyrec> definitions.

The I<zone-file> argument is required.  It specifies the name of the zone file
from which the signed zone file was created.  The optional I<signed-zone-file>
argument specifies the name of the signed zone file.  If it is not given, then
it defaults to B<zone-file.signed>.  The signed zone file field is, in effect,
a dummy field as the zone file is not actually signed.

=head1 OPTIONS

B<genkrf> has a number of options that assist in creation of the I<keyrec>
file.  These options will be set to the first value found from this search
path:

    command line options
    DNSSEC-Tools configuration file
    DNSSEC-Tools defaults

See I<tooloptions.pm(3)> for more details.
Exceptions to this are given in the option descriptions.

The B<genkrf> options are described below.

=head2 General B<genkrf> Options

=over 4

=item B<-zone zone-name>

This option specifies the name of the zone.  If it is not given then
I<zone-file> will be used as the name of the zone.

=item B<-krfile keyrec-file>

This option specifies the name of the I<keyrec> file to be generated.
If it is not given, then B<zone-name.krf> will be used.

=item B<-algorithm algorithm>

This option specifies the algorithm used to generate encryption keys.

=item B<-endtime endtime>

This option specifies the time that the signature on the zone expires,
measured in seconds.

=item B<-random random-device>

Source of randomness used to generate the zone's keys. See the man
page for B<dnssec-signzone> for the valid format of this field.

=item B<-verbose>

Display additional messages during processing.  If this option is given at
least once, then a message will be displayed indicating the successful
generation of the I<keyrec> file.  If it is given twice, then the values of
all options will also be displayed.

=item B<-Version>

Displays the version information for B<genkrf> and the DNSSEC-Tools package.

=item B<-help>

Display a usage message.

=back

=head2 KSK-related Options

=over 4

=item B<-kskcur KSK-name>

This option specifies the Current KSK's key file being used to sign the zone.
If this option is not given, a new KSK will be created.

=item B<-kskcount KSK-count>

This option specifies the number of KSK keys that will be generated.  If this
option is not given, the default given in the DNSSEC-Tools configuration file
will be used.

=item B<-kskdir KSK-directory>

This option specifies the absolute or relative path of the directory
where the KSK resides.  If this option is not given, it defaults to
the current directory ".".

=item B<-ksklength KSK-length>

This option specifies the length of the KSK encryption key.

=item B<-ksklife KSK-lifespan>

This option specifies the lifespan of the KSK encryption key.  This lifespan
is B<not> inherent to the key itself.  It is B<only> used to determine when
the KSK must be rolled over.

=back

=head2 ZSK-related Options

=over 4

=item B<-zskcur ZSK-name>

This option specifies the current ZSK being used to sign the zone.
If this option is not given, a new ZSK will be created.

=item B<-zskpub ZSK-name>

This option specifies the published ZSK for the zone.  If this option
is not given, a new ZSK will be created.

=item B<-zskcount ZSK-count>

This option specifies the number of current and published ZSK keys that will
be generated.  If this option is not given, the default given in the
DNSSEC-Tools configuration file will be used.

=item B<-zskdir ZSK-directory>

This option specifies the absolute or relative path of the directory
where the ZSKs reside.  If this option is not given, it defaults to
the current directory ".".

=item B<-zsklength ZSK-length>

This option specifies the length of the ZSK encryption key.

=item B<-zsklife ZSK-lifespan>

This option specifies the lifespan of the ZSK encryption key.  This lifespan
is B<not> inherent to the key itself.  It is B<only> used to determine when
the ZSK must be rolled over.

=back

=head1 COPYRIGHT

Copyright 2005-2014 SPARTA, Inc.  All rights reserved.
See the COPYING file included with the DNSSEC-Tools package for details.

=head1 AUTHOR

Wayne Morrison, tewok@tislabs.com

=head1 SEE ALSO

B<dnssec-keygen(8)>,
B<dnssec-signzone(8)>,
B<zonesigner(8)>

B<Net::DNS::SEC::Tools::conf.pm(3)>,
B<Net::DNS::SEC::Tools::defaults.pm(3)>,
B<Net::DNS::SEC::Tools::keyrec.pm(3)>

B<conf(5)>,
B<keyrec(5)>

=cut

