eclipse reformatting.
git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@242 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
parent
faae654a23
commit
453bf283ba
@ -59,447 +59,504 @@ import com.verisignlabs.dnssec.security.*;
|
|||||||
* @author $Author: davidb $
|
* @author $Author: davidb $
|
||||||
* @version $Revision: 2235 $
|
* @version $Revision: 2235 $
|
||||||
*/
|
*/
|
||||||
public class SignKeyset {
|
public class SignKeyset
|
||||||
private static Logger log;
|
{
|
||||||
|
private static Logger log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an inner class used to hold all of the command line option state.
|
* This is an inner class used to hold all of the command line option state.
|
||||||
*/
|
*/
|
||||||
private static class CLIState {
|
private static class CLIState
|
||||||
private Options opts;
|
{
|
||||||
private File keyDirectory = null;
|
private Options opts;
|
||||||
public String[] keyFiles = null;
|
private File keyDirectory = null;
|
||||||
public Date start = null;
|
public String[] keyFiles = null;
|
||||||
public Date expire = null;
|
public Date start = null;
|
||||||
public String inputfile = null;
|
public Date expire = null;
|
||||||
public String outputfile = null;
|
public String inputfile = null;
|
||||||
public boolean verifySigs = false;
|
public String outputfile = null;
|
||||||
|
public boolean verifySigs = false;
|
||||||
|
|
||||||
public CLIState() {
|
public CLIState()
|
||||||
setupCLI();
|
{
|
||||||
}
|
setupCLI();
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the command line options.
|
|
||||||
*
|
|
||||||
* @return a set of command line options.
|
|
||||||
*/
|
|
||||||
private void setupCLI() {
|
|
||||||
opts = new Options();
|
|
||||||
|
|
||||||
// boolean options
|
|
||||||
opts.addOption("h", "help", false, "Print this message.");
|
|
||||||
opts.addOption("a", "verify", false, "verify generated signatures>");
|
|
||||||
|
|
||||||
OptionBuilder.hasOptionalArg();
|
|
||||||
OptionBuilder.withLongOpt("verbose");
|
|
||||||
OptionBuilder.withArgName("level");
|
|
||||||
OptionBuilder.withDescription("verbosity level.");
|
|
||||||
// Argument options
|
|
||||||
opts.addOption(OptionBuilder.create('v'));
|
|
||||||
|
|
||||||
OptionBuilder.hasArg();
|
|
||||||
OptionBuilder.withArgName("dir");
|
|
||||||
OptionBuilder.withLongOpt("key-directory");
|
|
||||||
OptionBuilder.withDescription("directory to find key files (default '.').");
|
|
||||||
opts.addOption(OptionBuilder.create('D'));
|
|
||||||
|
|
||||||
OptionBuilder.hasArg();
|
|
||||||
OptionBuilder.withArgName("time/offset");
|
|
||||||
OptionBuilder.withLongOpt("start-time");
|
|
||||||
OptionBuilder.withDescription("signature starting time (default is now - 1 hour)");
|
|
||||||
opts.addOption(OptionBuilder.create('s'));
|
|
||||||
|
|
||||||
OptionBuilder.hasArg();
|
|
||||||
OptionBuilder.withArgName("time/offset");
|
|
||||||
OptionBuilder.withLongOpt("expire-time");
|
|
||||||
OptionBuilder.withDescription("signature expiration time (default is start-time + 30 days).");
|
|
||||||
opts.addOption(OptionBuilder.create('e'));
|
|
||||||
|
|
||||||
OptionBuilder.hasArg();
|
|
||||||
OptionBuilder.withArgName("outfile");
|
|
||||||
OptionBuilder.withDescription("file the signed keyset is written to.");
|
|
||||||
opts.addOption(OptionBuilder.create('f'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void parseCommandLine(String[] args)
|
|
||||||
throws org.apache.commons.cli.ParseException, ParseException,
|
|
||||||
IOException {
|
|
||||||
CommandLineParser cli_parser = new PosixParser();
|
|
||||||
CommandLine cli = cli_parser.parse(opts, args);
|
|
||||||
|
|
||||||
String optstr = null;
|
|
||||||
if (cli.hasOption('h')) usage();
|
|
||||||
|
|
||||||
Logger rootLogger = Logger.getLogger("");
|
|
||||||
if (cli.hasOption('v'))
|
|
||||||
{
|
|
||||||
int value = parseInt(cli.getOptionValue('v'), -1);
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
rootLogger.setLevel(Level.OFF);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
rootLogger.setLevel(Level.SEVERE);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
default:
|
|
||||||
rootLogger.setLevel(Level.WARNING);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
rootLogger.setLevel(Level.INFO);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
rootLogger.setLevel(Level.CONFIG);
|
|
||||||
case 5:
|
|
||||||
rootLogger.setLevel(Level.FINE);
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
rootLogger.setLevel(Level.ALL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// I hate java.util.logging, btw.
|
|
||||||
for (Handler h : rootLogger.getHandlers())
|
|
||||||
{
|
|
||||||
h.setLevel(rootLogger.getLevel());
|
|
||||||
h.setFormatter(new BareLogFormatter());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cli.hasOption('a')) verifySigs = true;
|
|
||||||
|
|
||||||
if ((optstr = cli.getOptionValue('D')) != null) {
|
|
||||||
keyDirectory = new File(optstr);
|
|
||||||
if (!keyDirectory.isDirectory()) {
|
|
||||||
System.err.println("error: " + optstr
|
|
||||||
+ " is not a directory");
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((optstr = cli.getOptionValue('s')) != null) {
|
|
||||||
start = convertDuration(null, optstr);
|
|
||||||
} else {
|
|
||||||
// default is now - 1 hour.
|
|
||||||
start = new Date(System.currentTimeMillis() - (3600 * 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((optstr = cli.getOptionValue('e')) != null) {
|
|
||||||
expire = convertDuration(start, optstr);
|
|
||||||
} else {
|
|
||||||
expire = convertDuration(start, "+2592000"); // 30 days
|
|
||||||
}
|
|
||||||
|
|
||||||
outputfile = cli.getOptionValue('f');
|
|
||||||
|
|
||||||
String[] files = cli.getArgs();
|
|
||||||
|
|
||||||
if (files.length < 1) {
|
|
||||||
System.err.println("error: missing zone file and/or key files");
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
inputfile = files[0];
|
|
||||||
if (files.length > 1) {
|
|
||||||
keyFiles = new String[files.length - 1];
|
|
||||||
System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Print out the usage and help statements, then quit. */
|
|
||||||
private void usage() {
|
|
||||||
HelpFormatter f = new HelpFormatter();
|
|
||||||
|
|
||||||
PrintWriter out = new PrintWriter(System.err);
|
|
||||||
|
|
||||||
// print our own usage statement:
|
|
||||||
f.printHelp(out, 75, "jdnssec-signkeyset [..options..] "
|
|
||||||
+ "dnskeyset_file [key_file ...]", null, opts,
|
|
||||||
HelpFormatter.DEFAULT_LEFT_PAD,
|
|
||||||
HelpFormatter.DEFAULT_DESC_PAD,
|
|
||||||
"\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
|
|
||||||
|
|
||||||
out.flush();
|
|
||||||
System.exit(64);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is just a convenience method for parsing integers from strings.
|
* Set up the command line options.
|
||||||
*
|
*
|
||||||
* @param s
|
* @return a set of command line options.
|
||||||
* the string to parse.
|
|
||||||
* @param def
|
|
||||||
* the default value, if the string doesn't parse.
|
|
||||||
* @return the parsed integer, or the default.
|
|
||||||
*/
|
*/
|
||||||
private static int parseInt(String s, int def) {
|
private void setupCLI()
|
||||||
try {
|
{
|
||||||
int v = Integer.parseInt(s);
|
opts = new Options();
|
||||||
return v;
|
|
||||||
} catch (NumberFormatException e) {
|
// boolean options
|
||||||
return def;
|
opts.addOption("h", "help", false, "Print this message.");
|
||||||
}
|
opts.addOption("a", "verify", false, "verify generated signatures>");
|
||||||
|
|
||||||
|
OptionBuilder.hasOptionalArg();
|
||||||
|
OptionBuilder.withLongOpt("verbose");
|
||||||
|
OptionBuilder.withArgName("level");
|
||||||
|
OptionBuilder.withDescription("verbosity level.");
|
||||||
|
// Argument options
|
||||||
|
opts.addOption(OptionBuilder.create('v'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("dir");
|
||||||
|
OptionBuilder.withLongOpt("key-directory");
|
||||||
|
OptionBuilder.withDescription("directory to find key files (default '.').");
|
||||||
|
opts.addOption(OptionBuilder.create('D'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("time/offset");
|
||||||
|
OptionBuilder.withLongOpt("start-time");
|
||||||
|
OptionBuilder.withDescription("signature starting time (default is now - 1 hour)");
|
||||||
|
opts.addOption(OptionBuilder.create('s'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("time/offset");
|
||||||
|
OptionBuilder.withLongOpt("expire-time");
|
||||||
|
OptionBuilder.withDescription("signature expiration time (default is start-time + 30 days).");
|
||||||
|
opts.addOption(OptionBuilder.create('e'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("outfile");
|
||||||
|
OptionBuilder.withDescription("file the signed keyset is written to.");
|
||||||
|
opts.addOption(OptionBuilder.create('f'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void parseCommandLine(String[] args)
|
||||||
* Verify the generated signatures.
|
throws org.apache.commons.cli.ParseException, ParseException, IOException
|
||||||
*
|
{
|
||||||
* @param zonename
|
CommandLineParser cli_parser = new PosixParser();
|
||||||
* the origin name of the zone.
|
CommandLine cli = cli_parser.parse(opts, args);
|
||||||
* @param records
|
|
||||||
* a list of {@link org.xbill.DNS.Record}s.
|
|
||||||
* @param keypairs
|
|
||||||
* a list of keypairs used the sign the zone.
|
|
||||||
* @return true if all of the signatures validated.
|
|
||||||
*/
|
|
||||||
private static boolean verifySigs(Name zonename, List records, List keypairs) {
|
|
||||||
boolean secure = true;
|
|
||||||
|
|
||||||
DnsSecVerifier verifier = new DnsSecVerifier();
|
String optstr = null;
|
||||||
|
if (cli.hasOption('h')) usage();
|
||||||
|
|
||||||
for (Iterator i = keypairs.iterator(); i.hasNext();) {
|
Logger rootLogger = Logger.getLogger("");
|
||||||
verifier.addTrustedKey((DnsKeyPair) i.next());
|
if (cli.hasOption('v'))
|
||||||
|
{
|
||||||
|
int value = parseInt(cli.getOptionValue('v'), -1);
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
rootLogger.setLevel(Level.OFF);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rootLogger.setLevel(Level.SEVERE);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
default:
|
||||||
|
rootLogger.setLevel(Level.WARNING);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rootLogger.setLevel(Level.INFO);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
rootLogger.setLevel(Level.CONFIG);
|
||||||
|
case 5:
|
||||||
|
rootLogger.setLevel(Level.FINE);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
rootLogger.setLevel(Level.ALL);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// I hate java.util.logging, btw.
|
||||||
|
for (Handler h : rootLogger.getHandlers())
|
||||||
|
{
|
||||||
|
h.setLevel(rootLogger.getLevel());
|
||||||
|
h.setFormatter(new BareLogFormatter());
|
||||||
|
}
|
||||||
|
|
||||||
verifier.setVerifyAllSigs(true);
|
if (cli.hasOption('a')) verifySigs = true;
|
||||||
|
|
||||||
List rrsets = SignUtils.assembleIntoRRsets(records);
|
if ((optstr = cli.getOptionValue('D')) != null)
|
||||||
|
{
|
||||||
for (Iterator i = rrsets.iterator(); i.hasNext();) {
|
keyDirectory = new File(optstr);
|
||||||
RRset rrset = (RRset) i.next();
|
if (!keyDirectory.isDirectory())
|
||||||
|
{
|
||||||
// skip unsigned rrsets.
|
System.err.println("error: " + optstr + " is not a directory");
|
||||||
if (!rrset.sigs().hasNext()) continue;
|
usage();
|
||||||
|
|
||||||
int result = verifier.verify(rrset, null);
|
|
||||||
|
|
||||||
if (result != DNSSEC.Secure) {
|
|
||||||
log.fine("Signatures did not verify for RRset: (" + result
|
|
||||||
+ "): " + rrset);
|
|
||||||
secure = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return secure;
|
if ((optstr = cli.getOptionValue('s')) != null)
|
||||||
|
{
|
||||||
|
start = convertDuration(null, optstr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// default is now - 1 hour.
|
||||||
|
start = new Date(System.currentTimeMillis() - (3600 * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((optstr = cli.getOptionValue('e')) != null)
|
||||||
|
{
|
||||||
|
expire = convertDuration(start, optstr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expire = convertDuration(start, "+2592000"); // 30 days
|
||||||
|
}
|
||||||
|
|
||||||
|
outputfile = cli.getOptionValue('f');
|
||||||
|
|
||||||
|
String[] files = cli.getArgs();
|
||||||
|
|
||||||
|
if (files.length < 1)
|
||||||
|
{
|
||||||
|
System.err.println("error: missing zone file and/or key files");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
inputfile = files[0];
|
||||||
|
if (files.length > 1)
|
||||||
|
{
|
||||||
|
keyFiles = new String[files.length - 1];
|
||||||
|
System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Print out the usage and help statements, then quit. */
|
||||||
* Load the key pairs from the key files.
|
private void usage()
|
||||||
*
|
{
|
||||||
* @param keyfiles
|
HelpFormatter f = new HelpFormatter();
|
||||||
* a string array containing the base names or paths of the keys
|
|
||||||
* to be loaded.
|
|
||||||
* @param start_index
|
|
||||||
* the starting index of keyfiles string array to use. This
|
|
||||||
* allows us to use the straight command line argument array.
|
|
||||||
* @param inDirectory
|
|
||||||
* the directory to look in (may be null).
|
|
||||||
* @return a list of keypair objects.
|
|
||||||
*/
|
|
||||||
private static List getKeys(String[] keyfiles, int start_index,
|
|
||||||
File inDirectory) throws IOException {
|
|
||||||
if (keyfiles == null) return null;
|
|
||||||
|
|
||||||
int len = keyfiles.length - start_index;
|
PrintWriter out = new PrintWriter(System.err);
|
||||||
if (len <= 0) return null;
|
|
||||||
|
|
||||||
ArrayList keys = new ArrayList(len);
|
// print our own usage statement:
|
||||||
|
f.printHelp(out, 75, "jdnssec-signkeyset [..options..] "
|
||||||
|
+ "dnskeyset_file [key_file ...]", null, opts,
|
||||||
|
HelpFormatter.DEFAULT_LEFT_PAD,
|
||||||
|
HelpFormatter.DEFAULT_DESC_PAD,
|
||||||
|
"\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
|
||||||
|
|
||||||
for (int i = start_index; i < keyfiles.length; i++) {
|
out.flush();
|
||||||
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
|
System.exit(64);
|
||||||
if (k != null) keys.add(k);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return keys;
|
/**
|
||||||
|
* This is just a convenience method for parsing integers from strings.
|
||||||
|
*
|
||||||
|
* @param s
|
||||||
|
* the string to parse.
|
||||||
|
* @param def
|
||||||
|
* the default value, if the string doesn't parse.
|
||||||
|
* @return the parsed integer, or the default.
|
||||||
|
*/
|
||||||
|
private static int parseInt(String s, int def)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int v = Integer.parseInt(s);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e)
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the generated signatures.
|
||||||
|
*
|
||||||
|
* @param zonename
|
||||||
|
* the origin name of the zone.
|
||||||
|
* @param records
|
||||||
|
* a list of {@link org.xbill.DNS.Record}s.
|
||||||
|
* @param keypairs
|
||||||
|
* a list of keypairs used the sign the zone.
|
||||||
|
* @return true if all of the signatures validated.
|
||||||
|
*/
|
||||||
|
private static boolean verifySigs(Name zonename, List records, List keypairs)
|
||||||
|
{
|
||||||
|
boolean secure = true;
|
||||||
|
|
||||||
|
DnsSecVerifier verifier = new DnsSecVerifier();
|
||||||
|
|
||||||
|
for (Iterator i = keypairs.iterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
verifier.addTrustedKey((DnsKeyPair) i.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class KeyFileFilter implements FileFilter {
|
verifier.setVerifyAllSigs(true);
|
||||||
private String prefix;
|
|
||||||
|
|
||||||
public KeyFileFilter(Name origin) {
|
List rrsets = SignUtils.assembleIntoRRsets(records);
|
||||||
prefix = "K" + origin.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean accept(File pathname) {
|
for (Iterator i = rrsets.iterator(); i.hasNext();)
|
||||||
if (!pathname.isFile()) return false;
|
{
|
||||||
String name = pathname.getName();
|
RRset rrset = (RRset) i.next();
|
||||||
if (name.startsWith(prefix) && name.endsWith(".private"))
|
|
||||||
return true;
|
// skip unsigned rrsets.
|
||||||
return false;
|
if (!rrset.sigs().hasNext()) continue;
|
||||||
}
|
|
||||||
|
int result = verifier.verify(rrset, null);
|
||||||
|
|
||||||
|
if (result != DNSSEC.Secure)
|
||||||
|
{
|
||||||
|
log.fine("Signatures did not verify for RRset: (" + result + "): " + rrset);
|
||||||
|
secure = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List findZoneKeys(File inDirectory, Name zonename)
|
return secure;
|
||||||
throws IOException {
|
}
|
||||||
if (inDirectory == null) {
|
|
||||||
inDirectory = new File(".");
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the list of "K<zone>.*.private files.
|
/**
|
||||||
FileFilter filter = new KeyFileFilter(zonename);
|
* Load the key pairs from the key files.
|
||||||
File[] files = inDirectory.listFiles(filter);
|
*
|
||||||
|
* @param keyfiles
|
||||||
|
* a string array containing the base names or paths of the keys
|
||||||
|
* to be loaded.
|
||||||
|
* @param start_index
|
||||||
|
* the starting index of keyfiles string array to use. This
|
||||||
|
* allows us to use the straight command line argument array.
|
||||||
|
* @param inDirectory
|
||||||
|
* the directory to look in (may be null).
|
||||||
|
* @return a list of keypair objects.
|
||||||
|
*/
|
||||||
|
private static List getKeys(String[] keyfiles, int start_index, File inDirectory)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
if (keyfiles == null) return null;
|
||||||
|
|
||||||
// read in all of the records
|
int len = keyfiles.length - start_index;
|
||||||
ArrayList keys = new ArrayList();
|
if (len <= 0) return null;
|
||||||
for (int i = 0; i < files.length; i++) {
|
|
||||||
DnsKeyPair p = BINDKeyUtils.loadKeyPair(files[i].getName(),
|
|
||||||
inDirectory);
|
|
||||||
keys.add(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keys.size() > 0) return keys;
|
ArrayList keys = new ArrayList(len);
|
||||||
return null;
|
|
||||||
|
for (int i = start_index; i < keyfiles.length; i++)
|
||||||
|
{
|
||||||
|
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
|
||||||
|
if (k != null) keys.add(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return keys;
|
||||||
* Calculate a date/time from a command line time/offset duration string.
|
}
|
||||||
*
|
|
||||||
* @param start
|
|
||||||
* the start time to calculate offsets from.
|
|
||||||
* @param duration
|
|
||||||
* the time/offset string to parse.
|
|
||||||
* @return the calculated time.
|
|
||||||
*/
|
|
||||||
private static Date convertDuration(Date start, String duration)
|
|
||||||
throws ParseException {
|
|
||||||
if (start == null) start = new Date();
|
|
||||||
if (duration.startsWith("now")) {
|
|
||||||
start = new Date();
|
|
||||||
if (duration.indexOf("+") < 0) return start;
|
|
||||||
|
|
||||||
duration = duration.substring(3);
|
private static class KeyFileFilter implements FileFilter
|
||||||
}
|
{
|
||||||
|
private String prefix;
|
||||||
|
|
||||||
if (duration.startsWith("+")) {
|
public KeyFileFilter(Name origin)
|
||||||
long offset = (long) parseInt(duration.substring(1), 0) * 1000;
|
{
|
||||||
return new Date(start.getTime() + offset);
|
prefix = "K" + origin.toString();
|
||||||
}
|
|
||||||
|
|
||||||
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
|
|
||||||
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
||||||
return dateFormatter.parse(duration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void execute(CLIState state) throws Exception {
|
public boolean accept(File pathname)
|
||||||
// Read in the zone
|
{
|
||||||
List records = ZoneUtils.readZoneFile(state.inputfile, null);
|
if (!pathname.isFile()) return false;
|
||||||
if (records == null || records.size() == 0) {
|
String name = pathname.getName();
|
||||||
System.err.println("error: empty keyset file");
|
if (name.startsWith(prefix) && name.endsWith(".private")) return true;
|
||||||
state.usage();
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Make sure that all records are DNSKEYs with the same name.
|
|
||||||
Name keysetName = null;
|
|
||||||
RRset keyset = new RRset();
|
|
||||||
for (Iterator i = records.iterator(); i.hasNext();) {
|
|
||||||
Record r = (Record) i.next();
|
|
||||||
if (r.getType() != Type.DNSKEY) {
|
|
||||||
System.err.println("error: Non DNSKEY RR found in keyset: " + r);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (keysetName == null) {
|
|
||||||
keysetName = r.getName();
|
|
||||||
}
|
|
||||||
if (!r.getName().equals(keysetName)) {
|
|
||||||
System.err.println("error: DNSKEY with a different name found!");
|
|
||||||
state.usage();
|
|
||||||
}
|
|
||||||
keyset.addRR(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyset.size() == 0) {
|
|
||||||
System.err.println("error: No DNSKEYs found in keyset file");
|
|
||||||
state.usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the key pairs.
|
|
||||||
List keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);
|
|
||||||
|
|
||||||
// If we *still* don't have any key pairs, look for keys the key
|
|
||||||
// directory
|
|
||||||
// that match
|
|
||||||
if (keypairs == null) {
|
|
||||||
keypairs = findZoneKeys(state.keyDirectory, keysetName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there *still* aren't any ZSKs defined, bail.
|
|
||||||
if (keypairs == null || keypairs.size() == 0) {
|
|
||||||
System.err.println("error: No signing keys could be determined.");
|
|
||||||
state.usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// default the output file, if not set.
|
|
||||||
if (state.outputfile == null) {
|
|
||||||
if (keysetName.isAbsolute()) {
|
|
||||||
state.outputfile = keysetName + "signed_keyset";
|
|
||||||
} else {
|
|
||||||
state.outputfile = keysetName + ".signed_keyset";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JCEDnsSecSigner signer = new JCEDnsSecSigner();
|
|
||||||
|
|
||||||
List sigs = signer.signRRset(keyset, keypairs, state.start,
|
|
||||||
state.expire);
|
|
||||||
for (Iterator i = sigs.iterator(); i.hasNext();) {
|
|
||||||
keyset.addRR((Record) i.next());
|
|
||||||
}
|
|
||||||
|
|
||||||
// write out the signed RRset
|
|
||||||
List signed_records = new ArrayList();
|
|
||||||
for (Iterator i = keyset.rrs(); i.hasNext();) {
|
|
||||||
signed_records.add(i.next());
|
|
||||||
}
|
|
||||||
for (Iterator i = keyset.sigs(); i.hasNext();) {
|
|
||||||
signed_records.add(i.next());
|
|
||||||
}
|
|
||||||
|
|
||||||
// write out the signed zone
|
|
||||||
// force multiline mode for now
|
|
||||||
org.xbill.DNS.Options.set("multiline");
|
|
||||||
ZoneUtils.writeZoneFile(signed_records, state.outputfile);
|
|
||||||
|
|
||||||
if (state.verifySigs) {
|
|
||||||
log.fine("verifying generated signatures");
|
|
||||||
boolean res = verifySigs(keysetName, signed_records, keypairs);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
System.out.println("Generated signatures verified");
|
|
||||||
// log.info("Generated signatures verified");
|
|
||||||
} else {
|
|
||||||
System.out.println("Generated signatures did not verify.");
|
|
||||||
// log.warn("Generated signatures did not verify.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private static List findZoneKeys(File inDirectory, Name zonename) throws IOException
|
||||||
|
{
|
||||||
|
if (inDirectory == null)
|
||||||
|
{
|
||||||
|
inDirectory = new File(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
// get the list of "K<zone>.*.private files.
|
||||||
CLIState state = new CLIState();
|
FileFilter filter = new KeyFileFilter(zonename);
|
||||||
try {
|
File[] files = inDirectory.listFiles(filter);
|
||||||
state.parseCommandLine(args);
|
|
||||||
} catch (UnrecognizedOptionException e) {
|
|
||||||
System.err.println("error: unknown option encountered: "
|
|
||||||
+ e.getMessage());
|
|
||||||
state.usage();
|
|
||||||
} catch (AlreadySelectedException e) {
|
|
||||||
System.err.println("error: mutually exclusive options have "
|
|
||||||
+ "been selected:\n " + e.getMessage());
|
|
||||||
state.usage();
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println("error: unknown command line parsing exception:");
|
|
||||||
e.printStackTrace();
|
|
||||||
state.usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
log = Logger.getLogger(SignKeyset.class.toString());
|
// read in all of the records
|
||||||
|
ArrayList keys = new ArrayList();
|
||||||
try {
|
for (int i = 0; i < files.length; i++)
|
||||||
execute(state);
|
{
|
||||||
} catch (Exception e) {
|
DnsKeyPair p = BINDKeyUtils.loadKeyPair(files[i].getName(), inDirectory);
|
||||||
e.printStackTrace();
|
keys.add(p);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (keys.size() > 0) return keys;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate a date/time from a command line time/offset duration string.
|
||||||
|
*
|
||||||
|
* @param start
|
||||||
|
* the start time to calculate offsets from.
|
||||||
|
* @param duration
|
||||||
|
* the time/offset string to parse.
|
||||||
|
* @return the calculated time.
|
||||||
|
*/
|
||||||
|
private static Date convertDuration(Date start, String duration) throws ParseException
|
||||||
|
{
|
||||||
|
if (start == null) start = new Date();
|
||||||
|
if (duration.startsWith("now"))
|
||||||
|
{
|
||||||
|
start = new Date();
|
||||||
|
if (duration.indexOf("+") < 0) return start;
|
||||||
|
|
||||||
|
duration = duration.substring(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duration.startsWith("+"))
|
||||||
|
{
|
||||||
|
long offset = (long) parseInt(duration.substring(1), 0) * 1000;
|
||||||
|
return new Date(start.getTime() + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||||
|
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
|
return dateFormatter.parse(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void execute(CLIState state) throws Exception
|
||||||
|
{
|
||||||
|
// Read in the zone
|
||||||
|
List records = ZoneUtils.readZoneFile(state.inputfile, null);
|
||||||
|
if (records == null || records.size() == 0)
|
||||||
|
{
|
||||||
|
System.err.println("error: empty keyset file");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure that all records are DNSKEYs with the same name.
|
||||||
|
Name keysetName = null;
|
||||||
|
RRset keyset = new RRset();
|
||||||
|
for (Iterator i = records.iterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
Record r = (Record) i.next();
|
||||||
|
if (r.getType() != Type.DNSKEY)
|
||||||
|
{
|
||||||
|
System.err.println("error: Non DNSKEY RR found in keyset: " + r);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (keysetName == null)
|
||||||
|
{
|
||||||
|
keysetName = r.getName();
|
||||||
|
}
|
||||||
|
if (!r.getName().equals(keysetName))
|
||||||
|
{
|
||||||
|
System.err.println("error: DNSKEY with a different name found!");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
keyset.addRR(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyset.size() == 0)
|
||||||
|
{
|
||||||
|
System.err.println("error: No DNSKEYs found in keyset file");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the key pairs.
|
||||||
|
List keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);
|
||||||
|
|
||||||
|
// If we *still* don't have any key pairs, look for keys the key
|
||||||
|
// directory
|
||||||
|
// that match
|
||||||
|
if (keypairs == null)
|
||||||
|
{
|
||||||
|
keypairs = findZoneKeys(state.keyDirectory, keysetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there *still* aren't any ZSKs defined, bail.
|
||||||
|
if (keypairs == null || keypairs.size() == 0)
|
||||||
|
{
|
||||||
|
System.err.println("error: No signing keys could be determined.");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// default the output file, if not set.
|
||||||
|
if (state.outputfile == null)
|
||||||
|
{
|
||||||
|
if (keysetName.isAbsolute())
|
||||||
|
{
|
||||||
|
state.outputfile = keysetName + "signed_keyset";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.outputfile = keysetName + ".signed_keyset";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JCEDnsSecSigner signer = new JCEDnsSecSigner();
|
||||||
|
|
||||||
|
List sigs = signer.signRRset(keyset, keypairs, state.start, state.expire);
|
||||||
|
for (Iterator i = sigs.iterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
keyset.addRR((Record) i.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
// write out the signed RRset
|
||||||
|
List signed_records = new ArrayList();
|
||||||
|
for (Iterator i = keyset.rrs(); i.hasNext();)
|
||||||
|
{
|
||||||
|
signed_records.add(i.next());
|
||||||
|
}
|
||||||
|
for (Iterator i = keyset.sigs(); i.hasNext();)
|
||||||
|
{
|
||||||
|
signed_records.add(i.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
// write out the signed zone
|
||||||
|
// force multiline mode for now
|
||||||
|
org.xbill.DNS.Options.set("multiline");
|
||||||
|
ZoneUtils.writeZoneFile(signed_records, state.outputfile);
|
||||||
|
|
||||||
|
if (state.verifySigs)
|
||||||
|
{
|
||||||
|
log.fine("verifying generated signatures");
|
||||||
|
boolean res = verifySigs(keysetName, signed_records, keypairs);
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
System.out.println("Generated signatures verified");
|
||||||
|
// log.info("Generated signatures verified");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.out.println("Generated signatures did not verify.");
|
||||||
|
// log.warn("Generated signatures did not verify.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
CLIState state = new CLIState();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
state.parseCommandLine(args);
|
||||||
|
}
|
||||||
|
catch (UnrecognizedOptionException e)
|
||||||
|
{
|
||||||
|
System.err.println("error: unknown option encountered: " + e.getMessage());
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
catch (AlreadySelectedException e)
|
||||||
|
{
|
||||||
|
System.err.println("error: mutually exclusive options have "
|
||||||
|
+ "been selected:\n " + e.getMessage());
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
System.err.println("error: unknown command line parsing exception:");
|
||||||
|
e.printStackTrace();
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
log = Logger.getLogger(SignKeyset.class.toString());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
execute(state);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,423 +60,474 @@ import com.verisignlabs.dnssec.security.*;
|
|||||||
* @author $Author: davidb $
|
* @author $Author: davidb $
|
||||||
* @version $Revision: 2235 $
|
* @version $Revision: 2235 $
|
||||||
*/
|
*/
|
||||||
public class SignRRset {
|
public class SignRRset
|
||||||
private static Logger log;
|
{
|
||||||
|
private static Logger log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an inner class used to hold all of the command line option state.
|
* This is an inner class used to hold all of the command line option state.
|
||||||
*/
|
*/
|
||||||
private static class CLIState {
|
private static class CLIState
|
||||||
private Options opts;
|
{
|
||||||
private File keyDirectory = null;
|
private Options opts;
|
||||||
public String[] keyFiles = null;
|
private File keyDirectory = null;
|
||||||
public Date start = null;
|
public String[] keyFiles = null;
|
||||||
public Date expire = null;
|
public Date start = null;
|
||||||
public String inputfile = null;
|
public Date expire = null;
|
||||||
public String outputfile = null;
|
public String inputfile = null;
|
||||||
public boolean verifySigs = false;
|
public String outputfile = null;
|
||||||
|
public boolean verifySigs = false;
|
||||||
|
|
||||||
public CLIState() {
|
public CLIState()
|
||||||
setupCLI();
|
{
|
||||||
}
|
setupCLI();
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the command line options.
|
|
||||||
*
|
|
||||||
* @return a set of command line options.
|
|
||||||
*/
|
|
||||||
private void setupCLI() {
|
|
||||||
opts = new Options();
|
|
||||||
|
|
||||||
// boolean options
|
|
||||||
opts.addOption("h", "help", false, "Print this message.");
|
|
||||||
opts.addOption("a", "verify", false, "verify generated signatures>");
|
|
||||||
opts.addOption("m", "multiline", false, "Use a multiline format");
|
|
||||||
|
|
||||||
OptionBuilder.hasOptionalArg();
|
|
||||||
OptionBuilder.withLongOpt("verbose");
|
|
||||||
OptionBuilder.withArgName("level");
|
|
||||||
OptionBuilder.withDescription("verbosity level.");
|
|
||||||
// Argument options
|
|
||||||
opts.addOption(OptionBuilder.create('v'));
|
|
||||||
|
|
||||||
OptionBuilder.hasArg();
|
|
||||||
OptionBuilder.withArgName("dir");
|
|
||||||
OptionBuilder.withLongOpt("key-directory");
|
|
||||||
OptionBuilder.withDescription("directory to find key files (default '.').");
|
|
||||||
opts.addOption(OptionBuilder.create('D'));
|
|
||||||
|
|
||||||
OptionBuilder.hasArg();
|
|
||||||
OptionBuilder.withArgName("time/offset");
|
|
||||||
OptionBuilder.withLongOpt("start-time");
|
|
||||||
OptionBuilder.withDescription("signature starting time (default is now - 1 hour)");
|
|
||||||
opts.addOption(OptionBuilder.create('s'));
|
|
||||||
|
|
||||||
OptionBuilder.hasArg();
|
|
||||||
OptionBuilder.withArgName("time/offset");
|
|
||||||
OptionBuilder.withLongOpt("expire-time");
|
|
||||||
OptionBuilder.withDescription("signature expiration time (default is start-time + 30 days).");
|
|
||||||
opts.addOption(OptionBuilder.create('e'));
|
|
||||||
|
|
||||||
OptionBuilder.hasArg();
|
|
||||||
OptionBuilder.withArgName("outfile");
|
|
||||||
OptionBuilder.withDescription("file the signed rrset is written to.");
|
|
||||||
opts.addOption(OptionBuilder.create('f'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void parseCommandLine(String[] args)
|
|
||||||
throws org.apache.commons.cli.ParseException, ParseException,
|
|
||||||
IOException {
|
|
||||||
CommandLineParser cli_parser = new PosixParser();
|
|
||||||
CommandLine cli = cli_parser.parse(opts, args);
|
|
||||||
|
|
||||||
String optstr = null;
|
|
||||||
if (cli.hasOption('h')) usage();
|
|
||||||
|
|
||||||
Logger rootLogger = Logger.getLogger("");
|
|
||||||
if (cli.hasOption('v'))
|
|
||||||
{
|
|
||||||
int value = parseInt(cli.getOptionValue('v'), -1);
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
rootLogger.setLevel(Level.OFF);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
rootLogger.setLevel(Level.SEVERE);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
default:
|
|
||||||
rootLogger.setLevel(Level.WARNING);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
rootLogger.setLevel(Level.INFO);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
rootLogger.setLevel(Level.CONFIG);
|
|
||||||
case 5:
|
|
||||||
rootLogger.setLevel(Level.FINE);
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
rootLogger.setLevel(Level.ALL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// I hate java.util.logging, btw.
|
|
||||||
for (Handler h : rootLogger.getHandlers())
|
|
||||||
{
|
|
||||||
h.setLevel(rootLogger.getLevel());
|
|
||||||
h.setFormatter(new BareLogFormatter());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cli.hasOption('a')) verifySigs = true;
|
|
||||||
if (cli.hasOption('m')) org.xbill.DNS.Options.set("multiline");
|
|
||||||
|
|
||||||
if ((optstr = cli.getOptionValue('D')) != null) {
|
|
||||||
keyDirectory = new File(optstr);
|
|
||||||
if (!keyDirectory.isDirectory()) {
|
|
||||||
System.err.println("error: " + optstr
|
|
||||||
+ " is not a directory");
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((optstr = cli.getOptionValue('s')) != null) {
|
|
||||||
start = convertDuration(null, optstr);
|
|
||||||
} else {
|
|
||||||
// default is now - 1 hour.
|
|
||||||
start = new Date(System.currentTimeMillis() - (3600 * 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((optstr = cli.getOptionValue('e')) != null) {
|
|
||||||
expire = convertDuration(start, optstr);
|
|
||||||
} else {
|
|
||||||
expire = convertDuration(start, "+2592000"); // 30 days
|
|
||||||
}
|
|
||||||
|
|
||||||
outputfile = cli.getOptionValue('f');
|
|
||||||
|
|
||||||
String[] files = cli.getArgs();
|
|
||||||
|
|
||||||
if (files.length < 1) {
|
|
||||||
System.err.println("error: missing zone file and/or key files");
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
inputfile = files[0];
|
|
||||||
if (files.length > 1) {
|
|
||||||
keyFiles = new String[files.length - 1];
|
|
||||||
System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Print out the usage and help statements, then quit. */
|
|
||||||
private void usage() {
|
|
||||||
HelpFormatter f = new HelpFormatter();
|
|
||||||
|
|
||||||
PrintWriter out = new PrintWriter(System.err);
|
|
||||||
|
|
||||||
// print our own usage statement:
|
|
||||||
f.printHelp(out, 75, "jdnssec-signrrset [..options..] "
|
|
||||||
+ "rrset_file key_file [key_file ...]", null, opts,
|
|
||||||
HelpFormatter.DEFAULT_LEFT_PAD,
|
|
||||||
HelpFormatter.DEFAULT_DESC_PAD,
|
|
||||||
"\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
|
|
||||||
|
|
||||||
out.flush();
|
|
||||||
System.exit(64);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is just a convenience method for parsing integers from strings.
|
* Set up the command line options.
|
||||||
*
|
*
|
||||||
* @param s
|
* @return a set of command line options.
|
||||||
* the string to parse.
|
|
||||||
* @param def
|
|
||||||
* the default value, if the string doesn't parse.
|
|
||||||
* @return the parsed integer, or the default.
|
|
||||||
*/
|
*/
|
||||||
private static int parseInt(String s, int def) {
|
private void setupCLI()
|
||||||
try {
|
{
|
||||||
int v = Integer.parseInt(s);
|
opts = new Options();
|
||||||
return v;
|
|
||||||
} catch (NumberFormatException e) {
|
// boolean options
|
||||||
return def;
|
opts.addOption("h", "help", false, "Print this message.");
|
||||||
}
|
opts.addOption("a", "verify", false, "verify generated signatures>");
|
||||||
|
opts.addOption("m", "multiline", false, "Use a multiline format");
|
||||||
|
|
||||||
|
OptionBuilder.hasOptionalArg();
|
||||||
|
OptionBuilder.withLongOpt("verbose");
|
||||||
|
OptionBuilder.withArgName("level");
|
||||||
|
OptionBuilder.withDescription("verbosity level.");
|
||||||
|
// Argument options
|
||||||
|
opts.addOption(OptionBuilder.create('v'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("dir");
|
||||||
|
OptionBuilder.withLongOpt("key-directory");
|
||||||
|
OptionBuilder.withDescription("directory to find key files (default '.').");
|
||||||
|
opts.addOption(OptionBuilder.create('D'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("time/offset");
|
||||||
|
OptionBuilder.withLongOpt("start-time");
|
||||||
|
OptionBuilder.withDescription("signature starting time (default is now - 1 hour)");
|
||||||
|
opts.addOption(OptionBuilder.create('s'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("time/offset");
|
||||||
|
OptionBuilder.withLongOpt("expire-time");
|
||||||
|
OptionBuilder.withDescription("signature expiration time (default is start-time + 30 days).");
|
||||||
|
opts.addOption(OptionBuilder.create('e'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("outfile");
|
||||||
|
OptionBuilder.withDescription("file the signed rrset is written to.");
|
||||||
|
opts.addOption(OptionBuilder.create('f'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void parseCommandLine(String[] args)
|
||||||
* Verify the generated signatures.
|
throws org.apache.commons.cli.ParseException, ParseException, IOException
|
||||||
*
|
{
|
||||||
* @param zonename
|
CommandLineParser cli_parser = new PosixParser();
|
||||||
* the origin name of the zone.
|
CommandLine cli = cli_parser.parse(opts, args);
|
||||||
* @param records
|
|
||||||
* a list of {@link org.xbill.DNS.Record}s.
|
|
||||||
* @param keypairs
|
|
||||||
* a list of keypairs used the sign the zone.
|
|
||||||
* @return true if all of the signatures validated.
|
|
||||||
*/
|
|
||||||
private static boolean verifySigs(Name zonename, List records, List keypairs) {
|
|
||||||
boolean secure = true;
|
|
||||||
|
|
||||||
DnsSecVerifier verifier = new DnsSecVerifier();
|
String optstr = null;
|
||||||
|
if (cli.hasOption('h')) usage();
|
||||||
|
|
||||||
for (Iterator i = keypairs.iterator(); i.hasNext();) {
|
Logger rootLogger = Logger.getLogger("");
|
||||||
verifier.addTrustedKey((DnsKeyPair) i.next());
|
if (cli.hasOption('v'))
|
||||||
|
{
|
||||||
|
int value = parseInt(cli.getOptionValue('v'), -1);
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
rootLogger.setLevel(Level.OFF);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rootLogger.setLevel(Level.SEVERE);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
default:
|
||||||
|
rootLogger.setLevel(Level.WARNING);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rootLogger.setLevel(Level.INFO);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
rootLogger.setLevel(Level.CONFIG);
|
||||||
|
case 5:
|
||||||
|
rootLogger.setLevel(Level.FINE);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
rootLogger.setLevel(Level.ALL);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// I hate java.util.logging, btw.
|
||||||
|
for (Handler h : rootLogger.getHandlers())
|
||||||
|
{
|
||||||
|
h.setLevel(rootLogger.getLevel());
|
||||||
|
h.setFormatter(new BareLogFormatter());
|
||||||
|
}
|
||||||
|
|
||||||
verifier.setVerifyAllSigs(true);
|
if (cli.hasOption('a')) verifySigs = true;
|
||||||
|
if (cli.hasOption('m')) org.xbill.DNS.Options.set("multiline");
|
||||||
|
|
||||||
List rrsets = SignUtils.assembleIntoRRsets(records);
|
if ((optstr = cli.getOptionValue('D')) != null)
|
||||||
|
{
|
||||||
for (Iterator i = rrsets.iterator(); i.hasNext();) {
|
keyDirectory = new File(optstr);
|
||||||
RRset rrset = (RRset) i.next();
|
if (!keyDirectory.isDirectory())
|
||||||
|
{
|
||||||
// skip unsigned rrsets.
|
System.err.println("error: " + optstr + " is not a directory");
|
||||||
if (!rrset.sigs().hasNext()) continue;
|
usage();
|
||||||
|
|
||||||
int result = verifier.verify(rrset, null);
|
|
||||||
|
|
||||||
if (result != DNSSEC.Secure) {
|
|
||||||
log.fine("Signatures did not verify for RRset: (" + result
|
|
||||||
+ "): " + rrset);
|
|
||||||
secure = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return secure;
|
if ((optstr = cli.getOptionValue('s')) != null)
|
||||||
|
{
|
||||||
|
start = convertDuration(null, optstr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// default is now - 1 hour.
|
||||||
|
start = new Date(System.currentTimeMillis() - (3600 * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((optstr = cli.getOptionValue('e')) != null)
|
||||||
|
{
|
||||||
|
expire = convertDuration(start, optstr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expire = convertDuration(start, "+2592000"); // 30 days
|
||||||
|
}
|
||||||
|
|
||||||
|
outputfile = cli.getOptionValue('f');
|
||||||
|
|
||||||
|
String[] files = cli.getArgs();
|
||||||
|
|
||||||
|
if (files.length < 1)
|
||||||
|
{
|
||||||
|
System.err.println("error: missing zone file and/or key files");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
inputfile = files[0];
|
||||||
|
if (files.length > 1)
|
||||||
|
{
|
||||||
|
keyFiles = new String[files.length - 1];
|
||||||
|
System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Print out the usage and help statements, then quit. */
|
||||||
* Load the key pairs from the key files.
|
private void usage()
|
||||||
*
|
{
|
||||||
* @param keyfiles
|
HelpFormatter f = new HelpFormatter();
|
||||||
* a string array containing the base names or paths of the keys
|
|
||||||
* to be loaded.
|
|
||||||
* @param start_index
|
|
||||||
* the starting index of keyfiles string array to use. This
|
|
||||||
* allows us to use the straight command line argument array.
|
|
||||||
* @param inDirectory
|
|
||||||
* the directory to look in (may be null).
|
|
||||||
* @return a list of keypair objects.
|
|
||||||
*/
|
|
||||||
private static List<DnsKeyPair> getKeys(String[] keyfiles, int start_index,
|
|
||||||
File inDirectory)
|
|
||||||
throws IOException {
|
|
||||||
if (keyfiles == null) return null;
|
|
||||||
|
|
||||||
int len = keyfiles.length - start_index;
|
PrintWriter out = new PrintWriter(System.err);
|
||||||
if (len <= 0) return null;
|
|
||||||
|
|
||||||
ArrayList<DnsKeyPair> keys = new ArrayList<DnsKeyPair>(len);
|
// print our own usage statement:
|
||||||
|
f.printHelp(out, 75, "jdnssec-signrrset [..options..] "
|
||||||
|
+ "rrset_file key_file [key_file ...]", null, opts,
|
||||||
|
HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD,
|
||||||
|
"\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
|
||||||
|
|
||||||
for (int i = start_index; i < keyfiles.length; i++) {
|
out.flush();
|
||||||
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
|
System.exit(64);
|
||||||
if (k != null) keys.add(k);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return keys;
|
/**
|
||||||
|
* This is just a convenience method for parsing integers from strings.
|
||||||
|
*
|
||||||
|
* @param s
|
||||||
|
* the string to parse.
|
||||||
|
* @param def
|
||||||
|
* the default value, if the string doesn't parse.
|
||||||
|
* @return the parsed integer, or the default.
|
||||||
|
*/
|
||||||
|
private static int parseInt(String s, int def)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int v = Integer.parseInt(s);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e)
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the generated signatures.
|
||||||
|
*
|
||||||
|
* @param zonename
|
||||||
|
* the origin name of the zone.
|
||||||
|
* @param records
|
||||||
|
* a list of {@link org.xbill.DNS.Record}s.
|
||||||
|
* @param keypairs
|
||||||
|
* a list of keypairs used the sign the zone.
|
||||||
|
* @return true if all of the signatures validated.
|
||||||
|
*/
|
||||||
|
private static boolean verifySigs(Name zonename, List records, List keypairs)
|
||||||
|
{
|
||||||
|
boolean secure = true;
|
||||||
|
|
||||||
|
DnsSecVerifier verifier = new DnsSecVerifier();
|
||||||
|
|
||||||
|
for (Iterator i = keypairs.iterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
verifier.addTrustedKey((DnsKeyPair) i.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
verifier.setVerifyAllSigs(true);
|
||||||
* Calculate a date/time from a command line time/offset duration string.
|
|
||||||
*
|
|
||||||
* @param start
|
|
||||||
* the start time to calculate offsets from.
|
|
||||||
* @param duration
|
|
||||||
* the time/offset string to parse.
|
|
||||||
* @return the calculated time.
|
|
||||||
*/
|
|
||||||
private static Date convertDuration(Date start, String duration)
|
|
||||||
throws ParseException {
|
|
||||||
if (start == null) start = new Date();
|
|
||||||
if (duration.startsWith("now")) {
|
|
||||||
start = new Date();
|
|
||||||
if (duration.indexOf("+") < 0) return start;
|
|
||||||
|
|
||||||
duration = duration.substring(3);
|
List rrsets = SignUtils.assembleIntoRRsets(records);
|
||||||
}
|
|
||||||
|
|
||||||
if (duration.startsWith("+")) {
|
for (Iterator i = rrsets.iterator(); i.hasNext();)
|
||||||
long offset = (long) parseInt(duration.substring(1), 0) * 1000;
|
{
|
||||||
return new Date(start.getTime() + offset);
|
RRset rrset = (RRset) i.next();
|
||||||
}
|
|
||||||
|
|
||||||
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
|
// skip unsigned rrsets.
|
||||||
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
|
if (!rrset.sigs().hasNext()) continue;
|
||||||
return dateFormatter.parse(duration);
|
|
||||||
|
int result = verifier.verify(rrset, null);
|
||||||
|
|
||||||
|
if (result != DNSSEC.Secure)
|
||||||
|
{
|
||||||
|
log.fine("Signatures did not verify for RRset: (" + result + "): " + rrset);
|
||||||
|
secure = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void execute(CLIState state) throws Exception {
|
return secure;
|
||||||
// Read in the zone
|
}
|
||||||
List records = ZoneUtils.readZoneFile(state.inputfile, null);
|
|
||||||
if (records == null || records.size() == 0) {
|
|
||||||
System.err.println("error: empty RRset file");
|
|
||||||
state.usage();
|
|
||||||
}
|
|
||||||
// Construct the RRset. Complain if the records in the input file
|
|
||||||
// consist of more than one RRset.
|
|
||||||
RRset rrset = null;
|
|
||||||
for (Iterator i = records.iterator(); i.hasNext();) {
|
|
||||||
Record r = (Record) i.next();
|
|
||||||
|
|
||||||
// skip RRSIGs
|
/**
|
||||||
if (r.getType() == Type.RRSIG || r.getType() == Type.SIG) {
|
* Load the key pairs from the key files.
|
||||||
continue;
|
*
|
||||||
}
|
* @param keyfiles
|
||||||
|
* a string array containing the base names or paths of the keys
|
||||||
// Handle the first record.
|
* to be loaded.
|
||||||
if (rrset == null) {
|
* @param start_index
|
||||||
rrset = new RRset();
|
* the starting index of keyfiles string array to use. This
|
||||||
rrset.addRR(r);
|
* allows us to use the straight command line argument array.
|
||||||
continue;
|
* @param inDirectory
|
||||||
}
|
* the directory to look in (may be null).
|
||||||
// Ensure that the remaining records all belong to the same rrset.
|
* @return a list of keypair objects.
|
||||||
if (rrset.getName().equals(r.getName())
|
*/
|
||||||
&& rrset.getType() == r.getType()
|
private static List<DnsKeyPair> getKeys(String[] keyfiles, int start_index,
|
||||||
&& rrset.getDClass() == r.getDClass()) {
|
File inDirectory) throws IOException
|
||||||
rrset.addRR(r);
|
{
|
||||||
} else {
|
if (keyfiles == null) return null;
|
||||||
System.err.println("Records do not all belong to the same RRset.");
|
|
||||||
state.usage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rrset.size() == 0) {
|
int len = keyfiles.length - start_index;
|
||||||
System.err.println("No records found in inputfile.");
|
if (len <= 0) return null;
|
||||||
state.usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the key pairs.
|
ArrayList<DnsKeyPair> keys = new ArrayList<DnsKeyPair>(len);
|
||||||
|
|
||||||
if (state.keyFiles.length == 0) {
|
|
||||||
System.err.println("error: at least one keyfile must be specified");
|
|
||||||
state.usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<DnsKeyPair> keypairs = getKeys(state.keyFiles, 0,
|
|
||||||
state.keyDirectory);
|
|
||||||
|
|
||||||
// Make sure that all the keypairs have the same name.
|
|
||||||
// This will be used as the zone name, too.
|
|
||||||
|
|
||||||
Name keysetName = null;
|
|
||||||
for (DnsKeyPair pair : keypairs) {
|
|
||||||
if (keysetName == null) {
|
|
||||||
keysetName = pair.getDNSKEYName();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!pair.getDNSKEYName().equals(keysetName)) {
|
|
||||||
System.err.println("Keys do not all have the same name.");
|
|
||||||
state.usage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// default the output file, if not set.
|
|
||||||
if (state.outputfile == null && !state.inputfile.equals("-")) {
|
|
||||||
state.outputfile = state.inputfile + ".signed";
|
|
||||||
}
|
|
||||||
|
|
||||||
JCEDnsSecSigner signer = new JCEDnsSecSigner();
|
|
||||||
|
|
||||||
List sigs = signer.signRRset(rrset, keypairs, state.start,
|
|
||||||
state.expire);
|
|
||||||
for (Iterator i = sigs.iterator(); i.hasNext();) {
|
|
||||||
rrset.addRR((Record) i.next());
|
|
||||||
}
|
|
||||||
|
|
||||||
// write out the signed RRset
|
|
||||||
List signed_records = new ArrayList();
|
|
||||||
for (Iterator i = rrset.rrs(); i.hasNext();) {
|
|
||||||
signed_records.add(i.next());
|
|
||||||
}
|
|
||||||
for (Iterator i = rrset.sigs(); i.hasNext();) {
|
|
||||||
signed_records.add(i.next());
|
|
||||||
}
|
|
||||||
|
|
||||||
// write out the signed zone
|
|
||||||
ZoneUtils.writeZoneFile(signed_records, state.outputfile);
|
|
||||||
|
|
||||||
if (state.verifySigs) {
|
|
||||||
log.fine("verifying generated signatures");
|
|
||||||
boolean res = verifySigs(keysetName, signed_records, keypairs);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
System.out.println("Generated signatures verified");
|
|
||||||
// log.info("Generated signatures verified");
|
|
||||||
} else {
|
|
||||||
System.out.println("Generated signatures did not verify.");
|
|
||||||
// log.warn("Generated signatures did not verify.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (int i = start_index; i < keyfiles.length; i++)
|
||||||
|
{
|
||||||
|
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
|
||||||
|
if (k != null) keys.add(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
return keys;
|
||||||
CLIState state = new CLIState();
|
}
|
||||||
try {
|
|
||||||
state.parseCommandLine(args);
|
|
||||||
} catch (UnrecognizedOptionException e) {
|
|
||||||
System.err.println("error: unknown option encountered: "
|
|
||||||
+ e.getMessage());
|
|
||||||
state.usage();
|
|
||||||
} catch (AlreadySelectedException e) {
|
|
||||||
System.err.println("error: mutually exclusive options have "
|
|
||||||
+ "been selected:\n " + e.getMessage());
|
|
||||||
state.usage();
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println("error: unknown command line parsing exception:");
|
|
||||||
e.printStackTrace();
|
|
||||||
state.usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
log = Logger.getLogger(SignRRset.class.toString());
|
/**
|
||||||
|
* Calculate a date/time from a command line time/offset duration string.
|
||||||
|
*
|
||||||
|
* @param start
|
||||||
|
* the start time to calculate offsets from.
|
||||||
|
* @param duration
|
||||||
|
* the time/offset string to parse.
|
||||||
|
* @return the calculated time.
|
||||||
|
*/
|
||||||
|
private static Date convertDuration(Date start, String duration) throws ParseException
|
||||||
|
{
|
||||||
|
if (start == null) start = new Date();
|
||||||
|
if (duration.startsWith("now"))
|
||||||
|
{
|
||||||
|
start = new Date();
|
||||||
|
if (duration.indexOf("+") < 0) return start;
|
||||||
|
|
||||||
try {
|
duration = duration.substring(3);
|
||||||
execute(state);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (duration.startsWith("+"))
|
||||||
|
{
|
||||||
|
long offset = (long) parseInt(duration.substring(1), 0) * 1000;
|
||||||
|
return new Date(start.getTime() + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||||
|
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
|
return dateFormatter.parse(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void execute(CLIState state) throws Exception
|
||||||
|
{
|
||||||
|
// Read in the zone
|
||||||
|
List records = ZoneUtils.readZoneFile(state.inputfile, null);
|
||||||
|
if (records == null || records.size() == 0)
|
||||||
|
{
|
||||||
|
System.err.println("error: empty RRset file");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
// Construct the RRset. Complain if the records in the input file
|
||||||
|
// consist of more than one RRset.
|
||||||
|
RRset rrset = null;
|
||||||
|
for (Iterator i = records.iterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
Record r = (Record) i.next();
|
||||||
|
|
||||||
|
// skip RRSIGs
|
||||||
|
if (r.getType() == Type.RRSIG || r.getType() == Type.SIG)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the first record.
|
||||||
|
if (rrset == null)
|
||||||
|
{
|
||||||
|
rrset = new RRset();
|
||||||
|
rrset.addRR(r);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Ensure that the remaining records all belong to the same rrset.
|
||||||
|
if (rrset.getName().equals(r.getName()) && rrset.getType() == r.getType()
|
||||||
|
&& rrset.getDClass() == r.getDClass())
|
||||||
|
{
|
||||||
|
rrset.addRR(r);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("Records do not all belong to the same RRset.");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rrset.size() == 0)
|
||||||
|
{
|
||||||
|
System.err.println("No records found in inputfile.");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the key pairs.
|
||||||
|
|
||||||
|
if (state.keyFiles.length == 0)
|
||||||
|
{
|
||||||
|
System.err.println("error: at least one keyfile must be specified");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<DnsKeyPair> keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);
|
||||||
|
|
||||||
|
// Make sure that all the keypairs have the same name.
|
||||||
|
// This will be used as the zone name, too.
|
||||||
|
|
||||||
|
Name keysetName = null;
|
||||||
|
for (DnsKeyPair pair : keypairs)
|
||||||
|
{
|
||||||
|
if (keysetName == null)
|
||||||
|
{
|
||||||
|
keysetName = pair.getDNSKEYName();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!pair.getDNSKEYName().equals(keysetName))
|
||||||
|
{
|
||||||
|
System.err.println("Keys do not all have the same name.");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default the output file, if not set.
|
||||||
|
if (state.outputfile == null && !state.inputfile.equals("-"))
|
||||||
|
{
|
||||||
|
state.outputfile = state.inputfile + ".signed";
|
||||||
|
}
|
||||||
|
|
||||||
|
JCEDnsSecSigner signer = new JCEDnsSecSigner();
|
||||||
|
|
||||||
|
List sigs = signer.signRRset(rrset, keypairs, state.start, state.expire);
|
||||||
|
for (Iterator i = sigs.iterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
rrset.addRR((Record) i.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
// write out the signed RRset
|
||||||
|
List signed_records = new ArrayList();
|
||||||
|
for (Iterator i = rrset.rrs(); i.hasNext();)
|
||||||
|
{
|
||||||
|
signed_records.add(i.next());
|
||||||
|
}
|
||||||
|
for (Iterator i = rrset.sigs(); i.hasNext();)
|
||||||
|
{
|
||||||
|
signed_records.add(i.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
// write out the signed zone
|
||||||
|
ZoneUtils.writeZoneFile(signed_records, state.outputfile);
|
||||||
|
|
||||||
|
if (state.verifySigs)
|
||||||
|
{
|
||||||
|
log.fine("verifying generated signatures");
|
||||||
|
boolean res = verifySigs(keysetName, signed_records, keypairs);
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
System.out.println("Generated signatures verified");
|
||||||
|
// log.info("Generated signatures verified");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.out.println("Generated signatures did not verify.");
|
||||||
|
// log.warn("Generated signatures did not verify.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
CLIState state = new CLIState();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
state.parseCommandLine(args);
|
||||||
|
}
|
||||||
|
catch (UnrecognizedOptionException e)
|
||||||
|
{
|
||||||
|
System.err.println("error: unknown option encountered: " + e.getMessage());
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
catch (AlreadySelectedException e)
|
||||||
|
{
|
||||||
|
System.err.println("error: mutually exclusive options have "
|
||||||
|
+ "been selected:\n " + e.getMessage());
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
System.err.println("error: unknown command line parsing exception:");
|
||||||
|
e.printStackTrace();
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
log = Logger.getLogger(SignRRset.class.toString());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
execute(state);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user