update to dnsjava-2.0.0; refactor command line parseing a bit; switch to java.util.logging
git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@16 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// $Id: KeyGen.java,v 1.2 2004/01/16 17:56:17 davidb Exp $
|
||||
// $Id$
|
||||
//
|
||||
// Copyright (C) 2001-2003 VeriSign, Inc.
|
||||
//
|
||||
@@ -20,6 +20,8 @@
|
||||
package com.verisignlabs.dnssec.cl;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.io.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.text.ParseException;
|
||||
@@ -32,66 +34,65 @@ import com.verisignlabs.dnssec.security.*;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.apache.commons.cli.Options;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/** This class forms the command line implementation of a DNSSEC key
|
||||
* generator
|
||||
*
|
||||
* @author David Blacka (original)
|
||||
* @author $Author: davidb $
|
||||
* @version $Revision: 1.2 $
|
||||
/**
|
||||
* This class forms the command line implementation of a DNSSEC key generator
|
||||
*
|
||||
* @author David Blacka (original)
|
||||
* @author $Author$
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class KeyGen
|
||||
{
|
||||
private static Log log;
|
||||
|
||||
/** This is a small inner class used to hold all of the command line
|
||||
* option state. */
|
||||
private static Logger log;
|
||||
|
||||
/**
|
||||
* This is a small inner class used to hold all of the command line option
|
||||
* state.
|
||||
*/
|
||||
private static class CLIState
|
||||
{
|
||||
public int algorithm = 5;
|
||||
public int keylength = 1024;
|
||||
public String outputfile = null;
|
||||
public File keydir = null;
|
||||
public boolean zoneKey = true;
|
||||
public boolean kskFlag = false;
|
||||
public String owner = null;
|
||||
public long ttl = 86400;
|
||||
|
||||
public CLIState() { }
|
||||
private Options opts;
|
||||
public int algorithm = 5;
|
||||
public int keylength = 1024;
|
||||
public String outputfile = null;
|
||||
public File keydir = null;
|
||||
public boolean zoneKey = true;
|
||||
public boolean kskFlag = false;
|
||||
public String owner = null;
|
||||
public long ttl = 86400;
|
||||
|
||||
public void parseCommandLine(Options opts, String[] args)
|
||||
throws org.apache.commons.cli.ParseException, ParseException,
|
||||
IOException
|
||||
public CLIState()
|
||||
{
|
||||
setupCLI();
|
||||
}
|
||||
|
||||
public void parseCommandLine(String[] args)
|
||||
throws org.apache.commons.cli.ParseException
|
||||
{
|
||||
CommandLineParser cli_parser = new PosixParser();
|
||||
CommandLine cli = cli_parser.parse(opts, args);
|
||||
CommandLine cli = cli_parser.parse(opts, args);
|
||||
|
||||
String optstr = null;
|
||||
|
||||
if (cli.hasOption('h')) usage(opts);
|
||||
|
||||
if (cli.hasOption('h')) usage();
|
||||
|
||||
if (cli.hasOption('v'))
|
||||
{
|
||||
int value = parseInt(cli.getOptionValue('v'), 5);
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
|
||||
"fatal");
|
||||
break;
|
||||
case 5:
|
||||
default:
|
||||
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
|
||||
"debug");
|
||||
break;
|
||||
case 6:
|
||||
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
|
||||
"trace");
|
||||
break;
|
||||
}
|
||||
int value = parseInt(cli.getOptionValue('v'), 5);
|
||||
Logger rootLogger = Logger.getLogger("");
|
||||
switch (value)
|
||||
{
|
||||
case 0 :
|
||||
rootLogger.setLevel(Level.OFF);
|
||||
break;
|
||||
case 5 :
|
||||
default :
|
||||
rootLogger.setLevel(Level.FINE);
|
||||
break;
|
||||
case 6 :
|
||||
rootLogger.setLevel(Level.ALL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cli.hasOption('k')) kskFlag = true;
|
||||
@@ -102,10 +103,10 @@ public class KeyGen
|
||||
{
|
||||
keydir = new File(optstr);
|
||||
}
|
||||
|
||||
|
||||
if ((optstr = cli.getOptionValue('n')) != null)
|
||||
{
|
||||
if (! optstr.equalsIgnoreCase("ZONE"))
|
||||
if (!optstr.equalsIgnoreCase("ZONE"))
|
||||
{
|
||||
zoneKey = false;
|
||||
}
|
||||
@@ -124,25 +125,104 @@ public class KeyGen
|
||||
{
|
||||
ttl = parseInt(optstr, 86400);
|
||||
}
|
||||
|
||||
|
||||
String[] cl_args = cli.getArgs();
|
||||
|
||||
if (cl_args.length < 1)
|
||||
{
|
||||
System.err.println("error: missing key owner name");
|
||||
usage(opts);
|
||||
System.err.println("error: missing key owner name");
|
||||
usage();
|
||||
}
|
||||
|
||||
owner = cl_args[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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("k",
|
||||
"kskflag",
|
||||
false,
|
||||
"Key is a key-signing-key (sets the SEP flag).");
|
||||
|
||||
// Argument options
|
||||
OptionBuilder.hasArg();
|
||||
OptionBuilder.withLongOpt("nametype");
|
||||
OptionBuilder.withArgName("type");
|
||||
OptionBuilder.withDescription("ZONE | OTHER (default ZONE)");
|
||||
opts.addOption(OptionBuilder.create('n'));
|
||||
|
||||
OptionBuilder.hasOptionalArg();
|
||||
OptionBuilder.withLongOpt("verbose");
|
||||
OptionBuilder.withArgName("level");
|
||||
OptionBuilder.withDescription("verbosity level -- 0 is silence, "
|
||||
+ "5 is debug information, " + "6 is trace information.\n"
|
||||
+ "default is level 5.");
|
||||
opts.addOption(OptionBuilder.create('v'));
|
||||
|
||||
OptionBuilder.hasArg();
|
||||
OptionBuilder.withArgName("algorithm");
|
||||
OptionBuilder.withDescription("RSA | RSASHA1 | RSAMD5 | DH | DSA, "
|
||||
+ "RSASHA1 is default.");
|
||||
opts.addOption(OptionBuilder.create('a'));
|
||||
|
||||
OptionBuilder.hasArg();
|
||||
OptionBuilder.withArgName("size");
|
||||
OptionBuilder.withDescription("key size, in bits. (default = 1024)\n"
|
||||
+ "RSA|RSASHA1|RSAMD5: [512..4096]\n"
|
||||
+ "DSA: [512..1024]\n"
|
||||
+ "DH: [128..4096]");
|
||||
opts.addOption(OptionBuilder.create('b'));
|
||||
|
||||
OptionBuilder.hasArg();
|
||||
OptionBuilder.withArgName("file");
|
||||
OptionBuilder.withLongOpt("output-file");
|
||||
OptionBuilder.withDescription("base filename for the public/private key files");
|
||||
opts.addOption(OptionBuilder.create('f'));
|
||||
|
||||
OptionBuilder.hasArg();
|
||||
OptionBuilder.withLongOpt("keydir");
|
||||
OptionBuilder.withArgName("dir");
|
||||
OptionBuilder.withDescription("place generated key files in this directory");
|
||||
opts.addOption(OptionBuilder.create('d'));
|
||||
}
|
||||
|
||||
/** 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-keygen [..options..] name",
|
||||
null,
|
||||
opts,
|
||||
HelpFormatter.DEFAULT_LEFT_PAD,
|
||||
HelpFormatter.DEFAULT_DESC_PAD,
|
||||
null);
|
||||
|
||||
out.flush();
|
||||
System.exit(64);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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.
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
@@ -161,7 +241,7 @@ public class KeyGen
|
||||
{
|
||||
int alg = parseInt(s, -1);
|
||||
if (alg > 0) return alg;
|
||||
|
||||
|
||||
s = s.toUpperCase();
|
||||
|
||||
if (s.equals("RSA"))
|
||||
@@ -188,109 +268,34 @@ public class KeyGen
|
||||
// default
|
||||
return DNSSEC.RSASHA1;
|
||||
}
|
||||
|
||||
/** Set up the command line options.
|
||||
*
|
||||
* @return a set of command line options.
|
||||
*/
|
||||
private static Options setupCLI()
|
||||
{
|
||||
Options options = new Options();
|
||||
|
||||
// boolean options
|
||||
options.addOption("h", "help", false, "Print this message.");
|
||||
options.addOption("k", "kskflag", false,
|
||||
"Key is a key-signing-key (sets the SEP flag).");
|
||||
|
||||
// Argument options
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withLongOpt("nametype")
|
||||
.withArgName("type")
|
||||
.withDescription("ZONE | OTHER (default ZONE)")
|
||||
.create('n'));
|
||||
options.addOption(OptionBuilder.hasOptionalArg()
|
||||
.withLongOpt("verbose")
|
||||
.withArgName("level")
|
||||
.withDescription("verbosity level -- 0 is silence, " +
|
||||
"5 is debug information, " +
|
||||
"6 is trace information.\n"+
|
||||
"default is level 5.")
|
||||
.create('v'));
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withArgName("algorithm")
|
||||
.withDescription("RSA | RSASHA1 | RSAMD5 | DH | DSA, " +
|
||||
"RSASHA1 is default.")
|
||||
.create('a'));
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withArgName("size")
|
||||
.withDescription
|
||||
("key size, in bits. (default = 1024)\n" +
|
||||
"RSA|RSASHA1|RSAMD5: [512..4096]\n" +
|
||||
"DSA: [512..1024]\n" +
|
||||
"DH: [128..4096]")
|
||||
.create('b'));
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withArgName("file")
|
||||
.withLongOpt("output-file")
|
||||
.withDescription
|
||||
("base filename for the public/private key files")
|
||||
.create('f'));
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withLongOpt("keydir")
|
||||
.withArgName("dir")
|
||||
.withDescription
|
||||
("place generated key files in this directory")
|
||||
.create('d'));
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/** Print out the usage and help statements, then quit. */
|
||||
private static void usage(Options opts)
|
||||
{
|
||||
HelpFormatter f = new HelpFormatter();
|
||||
|
||||
PrintWriter out = new PrintWriter(System.err);
|
||||
|
||||
// print our own usage statement:
|
||||
f.printHelp(out, 75, "keyGen.sh [..options..] name", null, opts,
|
||||
HelpFormatter.DEFAULT_LEFT_PAD,
|
||||
HelpFormatter.DEFAULT_DESC_PAD, null);
|
||||
|
||||
out.flush();
|
||||
System.exit(64);
|
||||
}
|
||||
|
||||
|
||||
public static void execute(CLIState state, Options opts)
|
||||
throws Exception
|
||||
public static void execute(CLIState state) throws Exception
|
||||
{
|
||||
JCEDnsSecSigner signer = new JCEDnsSecSigner();
|
||||
|
||||
// Minor hack to make the owner name absolute.
|
||||
if (! state.owner.endsWith("."))
|
||||
if (!state.owner.endsWith("."))
|
||||
{
|
||||
state.owner = state.owner + ".";
|
||||
}
|
||||
|
||||
|
||||
Name owner_name = Name.fromString(state.owner);
|
||||
|
||||
// Calculate our flags
|
||||
int flags = 0;
|
||||
if (state.zoneKey) flags |= DNSKEYRecord.OWNER_ZONE;
|
||||
if (state.kskFlag) flags |= DNSKEYRecord.FLAG_SEP;
|
||||
if (state.zoneKey) flags |= DNSKEYRecord.Flags.ZONE_KEY;
|
||||
if (state.kskFlag) flags |= DNSKEYRecord.Flags.SEP_KEY;
|
||||
|
||||
log.fine("create key pair with (name = " + owner_name + ", ttl = "
|
||||
+ state.ttl + ", alg = " + state.algorithm + ", flags = " + flags
|
||||
+ ", length = " + state.keylength + ")");
|
||||
|
||||
log.debug("create key pair with (name = " + owner_name + ", ttl = " +
|
||||
state.ttl + ", alg = " + state.algorithm + ", flags = " +
|
||||
flags + ", length = " + state.keylength + ")");
|
||||
|
||||
|
||||
DnsKeyPair pair = signer.generateKey(owner_name,
|
||||
state.ttl,
|
||||
DClass.IN,
|
||||
state.algorithm,
|
||||
flags,
|
||||
state.keylength);
|
||||
state.ttl,
|
||||
DClass.IN,
|
||||
state.algorithm,
|
||||
flags,
|
||||
state.keylength);
|
||||
|
||||
if (state.outputfile != null)
|
||||
{
|
||||
@@ -301,48 +306,39 @@ public class KeyGen
|
||||
BINDKeyUtils.writeKeyFiles(pair, state.keydir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
// set up logging.
|
||||
// For now, we force the commons logging to use the built-in
|
||||
// SimpleLog.
|
||||
System.setProperty("org.apache.commons.logging.Log",
|
||||
"org.apache.commons.logging.impl.SimpleLog");
|
||||
|
||||
// set up the command line options
|
||||
Options opts = setupCLI();
|
||||
|
||||
CLIState state = new CLIState();
|
||||
CLIState state = new CLIState();
|
||||
|
||||
try
|
||||
{
|
||||
state.parseCommandLine(opts, args);
|
||||
state.parseCommandLine(args);
|
||||
}
|
||||
catch (UnrecognizedOptionException e)
|
||||
{
|
||||
System.err.println("error: unknown option encountered: " +
|
||||
e.getMessage());
|
||||
usage(opts);
|
||||
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());
|
||||
usage(opts);
|
||||
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();
|
||||
usage(opts);
|
||||
state.usage();
|
||||
}
|
||||
|
||||
log = LogFactory.getLog(KeyGen.class);
|
||||
log = Logger.getLogger(KeyGen.class.toString());
|
||||
|
||||
try
|
||||
{
|
||||
execute(state, opts);
|
||||
execute(state);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// $Id: SignZone.java,v 1.4 2004/01/16 17:57:47 davidb Exp $
|
||||
// $Id$
|
||||
//
|
||||
// Copyright (C) 2001-2003 VeriSign, Inc.
|
||||
//
|
||||
@@ -19,37 +19,56 @@
|
||||
|
||||
package com.verisignlabs.dnssec.cl;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.ParseException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import org.xbill.DNS.*;
|
||||
|
||||
import com.verisignlabs.dnssec.security.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.apache.commons.cli.*;
|
||||
import org.apache.commons.cli.Options;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.xbill.DNS.DNSKEYRecord;
|
||||
import org.xbill.DNS.DNSSEC;
|
||||
import org.xbill.DNS.Name;
|
||||
import org.xbill.DNS.RRset;
|
||||
import org.xbill.DNS.Record;
|
||||
import org.xbill.DNS.TextParseException;
|
||||
|
||||
/** This class forms the command line implementation of a DNSSEC zone
|
||||
* signer.
|
||||
*
|
||||
* @author David Blacka (original)
|
||||
* @author $Author: davidb $
|
||||
* @version $Revision: 1.4 $
|
||||
import com.verisignlabs.dnssec.security.BINDKeyUtils;
|
||||
import com.verisignlabs.dnssec.security.DnsKeyPair;
|
||||
import com.verisignlabs.dnssec.security.DnsSecVerifier;
|
||||
import com.verisignlabs.dnssec.security.JCEDnsSecSigner;
|
||||
import com.verisignlabs.dnssec.security.SignUtils;
|
||||
import com.verisignlabs.dnssec.security.ZoneUtils;
|
||||
|
||||
/**
|
||||
* This class forms the command line implementation of a DNSSEC zone signer.
|
||||
*
|
||||
* @author David Blacka (original)
|
||||
* @author $Author$
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class SignZone
|
||||
{
|
||||
private static Log log;
|
||||
|
||||
/** This is a small inner class used to hold all of the command line
|
||||
* option state. */
|
||||
private static Logger log;
|
||||
|
||||
/**
|
||||
* This is a small inner class used to hold all of the command line option
|
||||
* state.
|
||||
*/
|
||||
private static class CLIState
|
||||
{
|
||||
private Options opts;
|
||||
private File keyDirectory = null;
|
||||
public File keysetDirectory = null;
|
||||
public String[] kskFiles = null;
|
||||
@@ -65,69 +84,70 @@ public class SignZone
|
||||
public boolean fullySignKeyset = false;
|
||||
public List includeNames = null;
|
||||
|
||||
public CLIState() { }
|
||||
public CLIState()
|
||||
{
|
||||
setupCLI();
|
||||
}
|
||||
|
||||
public void parseCommandLine(Options opts, String[] args)
|
||||
throws org.apache.commons.cli.ParseException, ParseException,
|
||||
IOException
|
||||
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(opts);
|
||||
|
||||
if (cli.hasOption('h')) usage();
|
||||
|
||||
if (cli.hasOption('v'))
|
||||
{
|
||||
int value = parseInt(cli.getOptionValue('v'), 5);
|
||||
int value = parseInt(cli.getOptionValue('v'), 5);
|
||||
Logger rootLogger = Logger.getLogger("");
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
|
||||
"fatal");
|
||||
break;
|
||||
case 5:
|
||||
default:
|
||||
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
|
||||
"debug");
|
||||
break;
|
||||
case 6:
|
||||
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
|
||||
"trace");
|
||||
break;
|
||||
}
|
||||
switch (value)
|
||||
{
|
||||
case 0 :
|
||||
rootLogger.setLevel(Level.OFF);
|
||||
break;
|
||||
case 5 :
|
||||
default :
|
||||
rootLogger.setLevel(Level.FINE);
|
||||
break;
|
||||
case 6 :
|
||||
rootLogger.setLevel(Level.ALL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cli.hasOption('a')) verifySigs = true;
|
||||
if (cli.hasOption('O')) useOptIn = true;
|
||||
if (cli.hasOption('C'))
|
||||
{
|
||||
useOptIn = true;
|
||||
optInConserve = true;
|
||||
useOptIn = true;
|
||||
optInConserve = true;
|
||||
}
|
||||
|
||||
if (cli.hasOption('F')) fullySignKeyset = true;
|
||||
|
||||
|
||||
if ((optstr = cli.getOptionValue('d')) != null)
|
||||
{
|
||||
keysetDirectory = new File(optstr);
|
||||
if (! keysetDirectory.isDirectory())
|
||||
{
|
||||
keysetDirectory = new File(optstr);
|
||||
if (!keysetDirectory.isDirectory())
|
||||
{
|
||||
System.err.println("error: " + optstr + " is not a directory");
|
||||
usage(opts);
|
||||
usage();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((optstr = cli.getOptionValue('D')) != null)
|
||||
{
|
||||
keyDirectory = new File(optstr);
|
||||
if (! keyDirectory.isDirectory())
|
||||
if (!keyDirectory.isDirectory())
|
||||
{
|
||||
System.err.println("error: " + optstr + " is not a directory");
|
||||
usage(opts);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +157,7 @@ public class SignZone
|
||||
}
|
||||
else
|
||||
{
|
||||
// default is now - 1 hour.
|
||||
// default is now - 1 hour.
|
||||
start = new Date(System.currentTimeMillis() - (3600 * 1000));
|
||||
}
|
||||
|
||||
@@ -156,30 +176,134 @@ public class SignZone
|
||||
|
||||
if ((optstr = cli.getOptionValue('I')) != null)
|
||||
{
|
||||
File includeNamesFile = new File(optstr);
|
||||
includeNames = getNameList(includeNamesFile);
|
||||
}
|
||||
|
||||
File includeNamesFile = new File(optstr);
|
||||
includeNames = getNameList(includeNamesFile);
|
||||
}
|
||||
|
||||
String[] files = cli.getArgs();
|
||||
|
||||
if (files.length < 2)
|
||||
{
|
||||
System.err.println("error: missing zone file and/or key files");
|
||||
usage(opts);
|
||||
System.err.println("error: missing zone file and/or key files");
|
||||
usage();
|
||||
}
|
||||
|
||||
zonefile = files[0];
|
||||
keyFiles = new String[files.length - 1];
|
||||
System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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", false, "verify generated signatures>");
|
||||
opts.addOption("F",
|
||||
"fully-sign-keyset",
|
||||
false,
|
||||
"sign the zone apex keyset with all "
|
||||
+ "available keys, instead of just key-signing-keys.");
|
||||
|
||||
// Opt-In generation switches
|
||||
OptionGroup opt_in_opts = new OptionGroup();
|
||||
opt_in_opts.addOption(new Option("O", "generate a fully Opt-In zone."));
|
||||
opt_in_opts.addOption(new Option("C",
|
||||
"generate a conservative Opt-In zone."));
|
||||
opts.addOptionGroup(opt_in_opts);
|
||||
|
||||
// Argument options
|
||||
OptionBuilder.hasOptionalArg();
|
||||
OptionBuilder.withLongOpt("verbose");
|
||||
OptionBuilder.withArgName("level");
|
||||
OptionBuilder.withDescription("verbosity level -- 0 is silence, "
|
||||
+ "5 is debug information, "
|
||||
+ "6 is trace information. "
|
||||
+ "No argument means 5.");
|
||||
opts.addOption(OptionBuilder.create('v'));
|
||||
|
||||
OptionBuilder.hasArg();
|
||||
OptionBuilder.withArgName("dir");
|
||||
OptionBuilder.withLongOpt("keyset-directory");
|
||||
OptionBuilder.withDescription("directory to find keyset files (default '.').");
|
||||
opts.addOption(OptionBuilder.create('d'));
|
||||
|
||||
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 zone is written "
|
||||
+ "to (default is <origin>.signed).");
|
||||
opts.addOption(OptionBuilder.create('f'));
|
||||
|
||||
OptionBuilder.hasArgs();
|
||||
OptionBuilder.withArgName("KSK file");
|
||||
OptionBuilder.withLongOpt("ksk-file");
|
||||
OptionBuilder.withDescription("this key is a key signing key "
|
||||
+ "(may repeat)");
|
||||
opts.addOption(OptionBuilder.create('k'));
|
||||
|
||||
OptionBuilder.hasArg();
|
||||
OptionBuilder.withArgName("file");
|
||||
OptionBuilder.withLongOpt("include-file");
|
||||
OptionBuilder.withDescription("include names in this file "
|
||||
+ "in the NSEC chain");
|
||||
opts.addOption(OptionBuilder.create('I'));
|
||||
}
|
||||
|
||||
/** 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:
|
||||
out.println("usage: signZone.sh [..options..] zone_file [key_file ...] ");
|
||||
f.printHelp(out,
|
||||
75,
|
||||
"signZone.sh",
|
||||
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.
|
||||
*
|
||||
* @param s the string to parse.
|
||||
* @param def the default value, if the string doesn't parse.
|
||||
* @return the parsed integer, or the default.
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
@@ -194,21 +318,22 @@ public class SignZone
|
||||
}
|
||||
}
|
||||
|
||||
/** 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.
|
||||
/**
|
||||
* 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 verifyZoneSigs(Name zonename, List records,
|
||||
List keypairs)
|
||||
List keypairs)
|
||||
{
|
||||
boolean secure = true;
|
||||
|
||||
|
||||
DnsSecVerifier verifier = new DnsSecVerifier();
|
||||
|
||||
for (Iterator i = keypairs.iterator(); i.hasNext(); )
|
||||
for (Iterator i = keypairs.iterator(); i.hasNext();)
|
||||
{
|
||||
verifier.addTrustedKey((DnsKeyPair) i.next());
|
||||
}
|
||||
@@ -217,39 +342,38 @@ public class SignZone
|
||||
|
||||
List rrsets = SignUtils.assembleIntoRRsets(records);
|
||||
|
||||
for (Iterator i = rrsets.iterator(); i.hasNext(); )
|
||||
for (Iterator i = rrsets.iterator(); i.hasNext();)
|
||||
{
|
||||
RRset rrset = (RRset) i.next();
|
||||
|
||||
// skip unsigned rrsets.
|
||||
if (!rrset.sigs().hasNext()) continue;
|
||||
|
||||
byte result = verifier.verify(rrset, null);
|
||||
|
||||
int result = verifier.verify(rrset, null);
|
||||
|
||||
if (result != DNSSEC.Secure)
|
||||
{
|
||||
log.debug("Signatures did not verify for RRset: (" + result + "): " +
|
||||
rrset);
|
||||
secure = false;
|
||||
log.fine("Signatures did not verify for RRset: (" + result + "): "
|
||||
+ rrset);
|
||||
secure = false;
|
||||
}
|
||||
}
|
||||
|
||||
return secure;
|
||||
}
|
||||
|
||||
/** Load the key pairs from the key files.
|
||||
*
|
||||
* @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.
|
||||
/**
|
||||
* Load the key pairs from the key files.
|
||||
*
|
||||
* @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
|
||||
File inDirectory) throws IOException
|
||||
{
|
||||
if (keyfiles == null) return null;
|
||||
|
||||
@@ -267,55 +391,34 @@ public class SignZone
|
||||
return keys;
|
||||
}
|
||||
|
||||
/** Load a single key from a given keyfile.
|
||||
*
|
||||
* @param keyfile the keyfile.
|
||||
* @param inDirectory the default directory to look in (may be
|
||||
* null).
|
||||
* @return a list containing one or zero keypair objects.
|
||||
/**
|
||||
* This is an implementation of a file filter used for finding BIND 9-style
|
||||
* keyset-* files.
|
||||
*/
|
||||
private static List getKeys(File keyfile, File inDirectory)
|
||||
throws IOException
|
||||
{
|
||||
if (keyfile == null) return null;
|
||||
|
||||
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfile.getPath(),
|
||||
inDirectory);
|
||||
if (k != null)
|
||||
{
|
||||
ArrayList keys = new ArrayList(1);
|
||||
keys.add(k);
|
||||
return keys;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** This is an implementation of a file filter used for finding BIND
|
||||
* 9-style keyset-* files. */
|
||||
private static class KeysetFileFilter implements FileFilter
|
||||
{
|
||||
public boolean accept(File pathname)
|
||||
{
|
||||
if (! pathname.isFile()) return false;
|
||||
if (!pathname.isFile()) return false;
|
||||
String name = pathname.getName();
|
||||
if (name.startsWith("keyset-")) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Load keysets (which contain delegation point security info).
|
||||
*
|
||||
* @param inDirectory the directory to look for the keyset files
|
||||
* (may be null, in which case it defaults to looking in the
|
||||
* current working directory).
|
||||
* @param zonename the name of the zone we are signing, so we can
|
||||
* ignore keysets that do not belong in the zone.
|
||||
* @return a list of {@link org.xbill.DNS.Record}s found in the
|
||||
* keyset files.
|
||||
/**
|
||||
* Load keysets (which contain delegation point security info).
|
||||
*
|
||||
* @param inDirectory the directory to look for the keyset files (may be
|
||||
* null, in which case it defaults to looking in the current
|
||||
* working directory).
|
||||
* @param zonename the name of the zone we are signing, so we can ignore
|
||||
* keysets that do not belong in the zone.
|
||||
* @return a list of {@link org.xbill.DNS.Record}s found in the keyset
|
||||
* files.
|
||||
*/
|
||||
private static List getKeysets(File inDirectory, Name zonename)
|
||||
throws IOException
|
||||
throws IOException
|
||||
{
|
||||
if (inDirectory == null)
|
||||
{
|
||||
@@ -336,47 +439,47 @@ public class SignZone
|
||||
}
|
||||
|
||||
// discard records that do not belong to the zone in question.
|
||||
for (Iterator i = keysetRecords.iterator(); i.hasNext(); )
|
||||
for (Iterator i = keysetRecords.iterator(); i.hasNext();)
|
||||
{
|
||||
Record r = (Record) i.next();
|
||||
if (!r.getName().subdomain(zonename))
|
||||
{
|
||||
i.remove();
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
return keysetRecords;
|
||||
}
|
||||
|
||||
/** Load a list of DNS names from a file.
|
||||
*
|
||||
* @param nameListFile the path of a file containing a bare list of
|
||||
* DNS names.
|
||||
* @return a list of {@link org.xbill.DNS.Name} objects.
|
||||
/**
|
||||
* Load a list of DNS names from a file.
|
||||
*
|
||||
* @param nameListFile the path of a file containing a bare list of DNS
|
||||
* names.
|
||||
* @return a list of {@link org.xbill.DNS.Name} objects.
|
||||
*/
|
||||
private static List getNameList(File nameListFile)
|
||||
throws IOException
|
||||
private static List getNameList(File nameListFile) throws IOException
|
||||
{
|
||||
BufferedReader br = new BufferedReader(new FileReader(nameListFile));
|
||||
List res = new ArrayList();
|
||||
|
||||
String line = null;
|
||||
while ( (line = br.readLine()) != null )
|
||||
while ((line = br.readLine()) != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Name n = Name.fromString(line);
|
||||
// force the name to be absolute.
|
||||
// FIXME: we should probably get some fancy logic here to
|
||||
// detect if the name needs the origin appended, or just the
|
||||
// root.
|
||||
if (! n.isAbsolute()) n = Name.concatenate(n, Name.root);
|
||||
|
||||
res.add(n);
|
||||
Name n = Name.fromString(line);
|
||||
// force the name to be absolute.
|
||||
// FIXME: we should probably get some fancy logic here to
|
||||
// detect if the name needs the origin appended, or just the
|
||||
// root.
|
||||
if (!n.isAbsolute()) n = Name.concatenate(n, Name.root);
|
||||
|
||||
res.add(n);
|
||||
}
|
||||
catch (TextParseException e)
|
||||
{
|
||||
log.error("DNS Name parsing error", e);
|
||||
log.severe("DNS Name parsing error:" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,21 +487,22 @@ public class SignZone
|
||||
return res;
|
||||
}
|
||||
|
||||
/** 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.
|
||||
/**
|
||||
* 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
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -413,148 +517,55 @@ public class SignZone
|
||||
return dateFormatter.parse(duration);
|
||||
}
|
||||
|
||||
/** Determine if the given keypairs can be used to sign the zone.
|
||||
* @param zonename the zone origin.
|
||||
* @param keypairs a list of {@link DnsKeyPair} objects that will
|
||||
* be used to sign the zone.
|
||||
* @return true if the keypairs valid.
|
||||
*/
|
||||
/**
|
||||
* Determine if the given keypairs can be used to sign the zone.
|
||||
*
|
||||
* @param zonename the zone origin.
|
||||
* @param keypairs a list of {@link DnsKeyPair} objects that will be used to
|
||||
* sign the zone.
|
||||
* @return true if the keypairs valid.
|
||||
*/
|
||||
private static boolean keyPairsValidForZone(Name zonename, List keypairs)
|
||||
{
|
||||
if (keypairs == null) return true; // technically true, I guess.
|
||||
|
||||
for (Iterator i = keypairs.iterator(); i.hasNext(); )
|
||||
|
||||
for (Iterator i = keypairs.iterator(); i.hasNext();)
|
||||
{
|
||||
DnsKeyPair kp = (DnsKeyPair) i.next();
|
||||
Name keyname = kp.getDNSKEYRecord().getName();
|
||||
if (!keyname.equals(zonename))
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Set up the command line options.
|
||||
*
|
||||
* @return a set of command line options.
|
||||
*/
|
||||
private static Options setupCLI()
|
||||
{
|
||||
Options options = new Options();
|
||||
|
||||
// boolean options
|
||||
options.addOption("h", "help", false, "Print this message.");
|
||||
options.addOption("a", false, "verify generated signatures>");
|
||||
options.addOption("F", "fully-sign-keyset", false,
|
||||
"sign the zone apex keyset with all " +
|
||||
"available keys, instead of just key-signing-keys.");
|
||||
|
||||
// Opt-In generation switches
|
||||
OptionGroup opt_in_opts = new OptionGroup();
|
||||
opt_in_opts.addOption(new Option
|
||||
("O", "generate a fully Opt-In zone."));
|
||||
opt_in_opts.addOption(new Option
|
||||
("C", "generate a conservative Opt-In zone."));
|
||||
options.addOptionGroup(opt_in_opts);
|
||||
|
||||
// Argument options
|
||||
options.addOption(OptionBuilder.hasOptionalArg()
|
||||
.withArgName("level")
|
||||
.withDescription("verbosity level -- 0 is silence, " +
|
||||
"5 is debug information, " +
|
||||
"6 is trace information. " +
|
||||
"No argument means 5.")
|
||||
.create('v'));
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withArgName("dir")
|
||||
.withLongOpt("keyset-directory")
|
||||
.withDescription
|
||||
("directory to find keyset files (default '.').")
|
||||
.create('d'));
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withArgName("dir")
|
||||
.withLongOpt("key-directory")
|
||||
.withDescription
|
||||
("directory to find key files (default '.').")
|
||||
.create('D'));
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withArgName("time/offset")
|
||||
.withLongOpt("start-time")
|
||||
.withDescription
|
||||
("signature starting time (default is now - 1 hour)")
|
||||
.create('s'));
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withArgName("time/offset")
|
||||
.withLongOpt("expire-time")
|
||||
.withDescription
|
||||
("signature expiration time (default is " +
|
||||
"start-time + 30 days")
|
||||
.create('e'));
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withArgName("outfile")
|
||||
.withDescription("file the signed zone is written " +
|
||||
"to (default is <origin>.signed).")
|
||||
.create('f'));
|
||||
options.addOption(OptionBuilder.hasArgs()
|
||||
.withArgName("KSK file")
|
||||
.withLongOpt("ksk-file")
|
||||
.withDescription("this key is a key signing key " +
|
||||
"(may repeat)")
|
||||
.create('k'));
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withArgName("file")
|
||||
.withLongOpt("include-file")
|
||||
.withDescription("include names in this file " +
|
||||
"in the NSEC chain")
|
||||
.create('I'));
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/** Print out the usage and help statements, then quit. */
|
||||
private static void usage(Options opts)
|
||||
{
|
||||
HelpFormatter f = new HelpFormatter();
|
||||
|
||||
PrintWriter out = new PrintWriter(System.err);
|
||||
|
||||
// print our own usage statement:
|
||||
out.println("usage: signZone.sh [..options..] zone_file [key_file ...] ");
|
||||
f.printHelp(out, 75, "signZone.sh", null, opts,
|
||||
HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD,
|
||||
"\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
|
||||
|
||||
out.flush();
|
||||
System.exit(64);
|
||||
}
|
||||
|
||||
|
||||
public static void execute(CLIState state, Options opts)
|
||||
throws Exception
|
||||
public static void execute(CLIState state) throws Exception
|
||||
{
|
||||
// Load the key pairs.
|
||||
|
||||
|
||||
// FIXME: should we do what BIND 9.3.x snapshots do and look at
|
||||
// zone apex DNSKEY RRs, and from that be able to load all of the
|
||||
// keys?
|
||||
|
||||
List keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);
|
||||
List kskpairs = getKeys(state.kskFiles, 0, state.keyDirectory);
|
||||
|
||||
List keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);
|
||||
List kskpairs = getKeys(state.kskFiles, 0, state.keyDirectory);
|
||||
|
||||
// If we don't have any KSKs, but we do have more than one zone
|
||||
// signing key (presumably), presume that the zone signing keys
|
||||
// are just not differentiated and try to figure out which keys
|
||||
// are actually ksks by looking at the SEP flag.
|
||||
if ( (kskpairs == null || kskpairs.size() == 0) &&
|
||||
keypairs != null && keypairs.size() > 1)
|
||||
if ((kskpairs == null || kskpairs.size() == 0) && keypairs != null
|
||||
&& keypairs.size() > 1)
|
||||
{
|
||||
for (Iterator i = keypairs.iterator(); i.hasNext(); )
|
||||
for (Iterator i = keypairs.iterator(); i.hasNext();)
|
||||
{
|
||||
DnsKeyPair pair = (DnsKeyPair) i.next();
|
||||
DNSKEYRecord kr = pair.getDNSKEYRecord();
|
||||
if ((kr.getFlags() & DNSKEYRecord.FLAG_SEP) != 0)
|
||||
if ((kr.getFlags() & DNSKEYRecord.Flags.SEP_KEY) != 0)
|
||||
{
|
||||
if (kskpairs == null) kskpairs = new ArrayList();
|
||||
kskpairs.add(pair);
|
||||
@@ -562,13 +573,13 @@ public class SignZone
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Read in the zone
|
||||
List records = ZoneUtils.readZoneFile(state.zonefile, null);
|
||||
if (records == null || records.size() == 0)
|
||||
{
|
||||
System.err.println("error: empty zone file");
|
||||
usage(opts);
|
||||
state.usage();
|
||||
}
|
||||
|
||||
// calculate the zone name.
|
||||
@@ -576,7 +587,7 @@ public class SignZone
|
||||
if (zonename == null)
|
||||
{
|
||||
System.err.println("error: invalid zone file - no SOA");
|
||||
usage(opts);
|
||||
state.usage();
|
||||
}
|
||||
|
||||
// default the output file, if not set.
|
||||
@@ -584,41 +595,39 @@ public class SignZone
|
||||
{
|
||||
if (zonename.isAbsolute())
|
||||
{
|
||||
state.outputfile = zonename + "signed";
|
||||
state.outputfile = zonename + "signed";
|
||||
}
|
||||
else
|
||||
{
|
||||
state.outputfile = zonename + ".signed";
|
||||
state.outputfile = zonename + ".signed";
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the keys can be in the zone.
|
||||
List kpairs = keypairs;
|
||||
|
||||
if (!keyPairsValidForZone(zonename, keypairs) ||
|
||||
!keyPairsValidForZone(zonename, kskpairs))
|
||||
// Verify that the keys can be in the zone.
|
||||
if (!keyPairsValidForZone(zonename, keypairs)
|
||||
|| !keyPairsValidForZone(zonename, kskpairs))
|
||||
{
|
||||
usage(opts);
|
||||
state.usage();
|
||||
}
|
||||
|
||||
// We force the signing keys to be in the zone by just appending
|
||||
// them to the zone here. Currently JCEDnsSecSigner.signZone
|
||||
// them to the zone here. Currently JCEDnsSecSigner.signZone
|
||||
// removes duplicate records.
|
||||
if (kskpairs != null)
|
||||
{
|
||||
for (Iterator i = kskpairs.iterator(); i.hasNext(); )
|
||||
for (Iterator i = kskpairs.iterator(); i.hasNext();)
|
||||
{
|
||||
records.add( ((DnsKeyPair) i.next()).getDNSKEYRecord() );
|
||||
records.add(((DnsKeyPair) i.next()).getDNSKEYRecord());
|
||||
}
|
||||
}
|
||||
if (keypairs != null)
|
||||
{
|
||||
for (Iterator i = keypairs.iterator(); i.hasNext(); )
|
||||
for (Iterator i = keypairs.iterator(); i.hasNext();)
|
||||
{
|
||||
records.add( ((DnsKeyPair) i.next()).getDNSKEYRecord() );
|
||||
records.add(((DnsKeyPair) i.next()).getDNSKEYRecord());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// read in the keysets, if any.
|
||||
List keysetrecs = getKeysets(state.keysetDirectory, zonename);
|
||||
if (keysetrecs != null)
|
||||
@@ -630,16 +639,16 @@ public class SignZone
|
||||
|
||||
// Sign the zone.
|
||||
List signed_records = signer.signZone(zonename,
|
||||
records,
|
||||
kskpairs,
|
||||
keypairs,
|
||||
state.start,
|
||||
state.expire,
|
||||
state.useOptIn,
|
||||
state.optInConserve,
|
||||
state.fullySignKeyset,
|
||||
state.includeNames);
|
||||
|
||||
records,
|
||||
kskpairs,
|
||||
keypairs,
|
||||
state.start,
|
||||
state.expire,
|
||||
state.useOptIn,
|
||||
state.optInConserve,
|
||||
state.fullySignKeyset,
|
||||
state.includeNames);
|
||||
|
||||
// write out the signed zone
|
||||
// force multiline mode for now
|
||||
org.xbill.DNS.Options.set("multiline");
|
||||
@@ -650,66 +659,57 @@ public class SignZone
|
||||
// FIXME: ugh.
|
||||
if (kskpairs != null)
|
||||
{
|
||||
keypairs.addAll(kskpairs);
|
||||
keypairs.addAll(kskpairs);
|
||||
}
|
||||
|
||||
log.debug("verifying generated signatures");
|
||||
|
||||
log.fine("verifying generated signatures");
|
||||
boolean res = verifyZoneSigs(zonename, signed_records, keypairs);
|
||||
|
||||
if (res)
|
||||
{
|
||||
System.out.println("Generated signatures verified");
|
||||
// log.info("Generated signatures verified");
|
||||
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.");
|
||||
System.out.println("Generated signatures did not verify.");
|
||||
// log.warn("Generated signatures did not verify.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
// set up logging.
|
||||
// For now, we force the commons logging to use the built-in
|
||||
// SimpleLog.
|
||||
System.setProperty("org.apache.commons.logging.Log",
|
||||
"org.apache.commons.logging.impl.SimpleLog");
|
||||
|
||||
// set up the command line options
|
||||
Options opts = setupCLI();
|
||||
|
||||
CLIState state = new CLIState();
|
||||
CLIState state = new CLIState();
|
||||
try
|
||||
{
|
||||
state.parseCommandLine(opts, args);
|
||||
state.parseCommandLine(args);
|
||||
}
|
||||
catch (UnrecognizedOptionException e)
|
||||
{
|
||||
System.err.println("error: unknown option encountered: " +
|
||||
e.getMessage());
|
||||
usage(opts);
|
||||
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());
|
||||
usage(opts);
|
||||
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();
|
||||
usage(opts);
|
||||
state.usage();
|
||||
}
|
||||
|
||||
log = LogFactory.getLog(SignZone.class);
|
||||
log = Logger.getLogger(SignZone.class.toString());
|
||||
|
||||
try
|
||||
{
|
||||
execute(state, opts);
|
||||
execute(state);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// $Id: VerifyZone.java,v 1.1 2004/01/16 17:57:59 davidb Exp $
|
||||
// $Id$
|
||||
//
|
||||
// Copyright (C) 2001-2003 VeriSign, Inc.
|
||||
//
|
||||
@@ -19,75 +19,84 @@
|
||||
|
||||
package com.verisignlabs.dnssec.cl;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import org.xbill.DNS.*;
|
||||
|
||||
import com.verisignlabs.dnssec.security.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.cli.*;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.xbill.DNS.DNSSEC;
|
||||
import org.xbill.DNS.RRSIGRecord;
|
||||
import org.xbill.DNS.RRset;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import com.verisignlabs.dnssec.security.BINDKeyUtils;
|
||||
import com.verisignlabs.dnssec.security.DnsKeyPair;
|
||||
import com.verisignlabs.dnssec.security.DnsSecVerifier;
|
||||
import com.verisignlabs.dnssec.security.RecordComparator;
|
||||
import com.verisignlabs.dnssec.security.SignUtils;
|
||||
import com.verisignlabs.dnssec.security.ZoneUtils;
|
||||
|
||||
/** This class forms the command line implementation of a DNSSEC zone
|
||||
* validator.
|
||||
* @author David Blacka (original)
|
||||
* @author $Author: davidb $
|
||||
* @version $Revision: 1.1 $
|
||||
/**
|
||||
* This class forms the command line implementation of a DNSSEC zone
|
||||
* validator.
|
||||
*
|
||||
* @author David Blacka (original)
|
||||
* @author $Author$
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class VerifyZone
|
||||
{
|
||||
private static Log log;
|
||||
|
||||
/** This is a small inner class used to hold all of the command line
|
||||
* option state. */
|
||||
private static Logger log;
|
||||
|
||||
/**
|
||||
* This is a small inner class used to hold all of the command line option
|
||||
* state.
|
||||
*/
|
||||
private static class CLIState
|
||||
{
|
||||
|
||||
public boolean strict = false;
|
||||
public File keydir = null;
|
||||
public String zonefile = null;
|
||||
private Options opts;
|
||||
public boolean strict = false;
|
||||
public File keydir = null;
|
||||
public String zonefile = null;
|
||||
public String[] keyfiles = null;
|
||||
|
||||
public CLIState() { }
|
||||
|
||||
public void parseCommandLine(Options opts, String[] args)
|
||||
throws org.apache.commons.cli.ParseException, ParseException,
|
||||
IOException
|
||||
public CLIState()
|
||||
{
|
||||
setupCLI();
|
||||
}
|
||||
|
||||
public void parseCommandLine(String[] args)
|
||||
throws org.apache.commons.cli.ParseException
|
||||
{
|
||||
CommandLineParser cli_parser = new PosixParser();
|
||||
CommandLine cli = cli_parser.parse(opts, args);
|
||||
CommandLine cli = cli_parser.parse(opts, args);
|
||||
|
||||
String optstr = null;
|
||||
|
||||
if (cli.hasOption('h')) usage(opts);
|
||||
|
||||
if (cli.hasOption('h')) usage();
|
||||
|
||||
if (cli.hasOption('v'))
|
||||
{
|
||||
int value = parseInt(cli.getOptionValue('v'), 5);
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
|
||||
"fatal");
|
||||
break;
|
||||
case 5:
|
||||
default:
|
||||
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
|
||||
"debug");
|
||||
break;
|
||||
case 6:
|
||||
System.setProperty("org.apache.commons.logging.simplelog.defaultlog",
|
||||
"trace");
|
||||
break;
|
||||
}
|
||||
int value = parseInt(cli.getOptionValue('v'), 5);
|
||||
Logger rootLogger = Logger.getLogger("");
|
||||
switch (value)
|
||||
{
|
||||
case 0 :
|
||||
rootLogger.setLevel(Level.OFF);
|
||||
break;
|
||||
case 5 :
|
||||
default :
|
||||
rootLogger.setLevel(Level.FINE);
|
||||
break;
|
||||
case 6 :
|
||||
rootLogger.setLevel(Level.ALL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cli.hasOption('s')) strict = true;
|
||||
@@ -96,14 +105,13 @@ public class VerifyZone
|
||||
{
|
||||
keydir = new File(optstr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
String[] cl_args = cli.getArgs();
|
||||
|
||||
if (cl_args.length < 1)
|
||||
{
|
||||
System.err.println("error: missing zone file");
|
||||
usage(opts);
|
||||
System.err.println("error: missing zone file");
|
||||
usage();
|
||||
}
|
||||
|
||||
zonefile = cl_args[0];
|
||||
@@ -111,85 +119,90 @@ public class VerifyZone
|
||||
if (cl_args.length < 2)
|
||||
{
|
||||
System.err.println("error: at least one trusted key is required");
|
||||
usage(opts);
|
||||
usage();
|
||||
}
|
||||
|
||||
|
||||
keyfiles = new String[cl_args.length - 1];
|
||||
System.arraycopy(cl_args, 1, keyfiles, 0, keyfiles.length);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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
|
||||
/**
|
||||
* Set up the command line options.
|
||||
*
|
||||
* @return a set of command line options.
|
||||
*/
|
||||
private void setupCLI()
|
||||
{
|
||||
int v = Integer.parseInt(s);
|
||||
return v;
|
||||
opts = new Options();
|
||||
|
||||
// boolean options
|
||||
opts.addOption("h", "help", false, "Print this message.");
|
||||
opts.addOption("s",
|
||||
"strict",
|
||||
false,
|
||||
"Zone will only be considered valid if all "
|
||||
+ "signatures could be cryptographically verified");
|
||||
|
||||
// Argument options
|
||||
OptionBuilder.hasArg();
|
||||
OptionBuilder.withLongOpt("keydir");
|
||||
OptionBuilder.withArgName("dir");
|
||||
OptionBuilder.withDescription("directory to find trusted key files");
|
||||
opts.addOption(OptionBuilder.create('d'));
|
||||
|
||||
OptionBuilder.hasOptionalArg();
|
||||
OptionBuilder.withLongOpt("verbose");
|
||||
OptionBuilder.withArgName("level");
|
||||
OptionBuilder.withDescription("verbosity level -- 0 is silence, "
|
||||
+ "5 is debug information, 6 is trace information.\n"
|
||||
+ "default is level 5.");
|
||||
opts.addOption(OptionBuilder.create('v'));
|
||||
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
|
||||
/** Print out the usage and help statements, then quit. */
|
||||
public void usage()
|
||||
{
|
||||
return def;
|
||||
HelpFormatter f = new HelpFormatter();
|
||||
|
||||
PrintWriter out = new PrintWriter(System.err);
|
||||
|
||||
// print our own usage statement:
|
||||
f.printHelp(out,
|
||||
75,
|
||||
"verifyZone.sh [..options..] zonefile " + "keyfile [keyfile...]",
|
||||
null,
|
||||
opts,
|
||||
HelpFormatter.DEFAULT_LEFT_PAD,
|
||||
HelpFormatter.DEFAULT_DESC_PAD,
|
||||
null);
|
||||
|
||||
out.flush();
|
||||
System.exit(64);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Set up the command line options.
|
||||
*
|
||||
* @return a set of command line options.
|
||||
*/
|
||||
private static Options setupCLI()
|
||||
{
|
||||
Options options = new Options();
|
||||
|
||||
// boolean options
|
||||
options.addOption("h", "help", false, "Print this message.");
|
||||
options.addOption("s", "strict", false,
|
||||
"Zone will only be considered valid if all " +
|
||||
"signatures could be cryptographically verified");
|
||||
|
||||
// Argument options
|
||||
options.addOption(OptionBuilder.hasArg()
|
||||
.withLongOpt("keydir")
|
||||
.withArgName("dir")
|
||||
.withDescription("directory to find trusted key files")
|
||||
.create('d'));
|
||||
|
||||
options.addOption(OptionBuilder.hasOptionalArg()
|
||||
.withLongOpt("verbose")
|
||||
.withArgName("level")
|
||||
.withDescription("verbosity level -- 0 is silence, " +
|
||||
"5 is debug information, " +
|
||||
"6 is trace information.\n" +
|
||||
"default is level 5.")
|
||||
.create('v'));
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/** Print out the usage and help statements, then quit. */
|
||||
private static void usage(Options opts)
|
||||
{
|
||||
HelpFormatter f = new HelpFormatter();
|
||||
|
||||
PrintWriter out = new PrintWriter(System.err);
|
||||
|
||||
// print our own usage statement:
|
||||
f.printHelp(out, 75,
|
||||
"verifyZone.sh [..options..] zonefile " +
|
||||
"keyfile [keyfile...]", null, opts,
|
||||
HelpFormatter.DEFAULT_LEFT_PAD,
|
||||
HelpFormatter.DEFAULT_DESC_PAD, null);
|
||||
|
||||
out.flush();
|
||||
System.exit(64);
|
||||
}
|
||||
|
||||
|
||||
private static byte verifyZoneSignatures(List records, List keypairs)
|
||||
{
|
||||
@@ -198,33 +211,34 @@ public class VerifyZone
|
||||
|
||||
DnsSecVerifier verifier = new DnsSecVerifier();
|
||||
|
||||
for (Iterator i = keypairs.iterator(); i.hasNext(); )
|
||||
for (Iterator i = keypairs.iterator(); i.hasNext();)
|
||||
{
|
||||
verifier.addTrustedKey((DnsKeyPair) i.next());
|
||||
}
|
||||
|
||||
List rrsets = SignUtils.assembleIntoRRsets(records);
|
||||
|
||||
for (Iterator i = rrsets.iterator(); i.hasNext(); )
|
||||
|
||||
for (Iterator i = rrsets.iterator(); i.hasNext();)
|
||||
{
|
||||
RRset rrset = (RRset) i.next();
|
||||
|
||||
// We verify each signature separately so that we can report
|
||||
// which exact signature failed.
|
||||
for (Iterator j = rrset.sigs(); j.hasNext(); )
|
||||
for (Iterator j = rrset.sigs(); j.hasNext();)
|
||||
{
|
||||
Object o = j.next();
|
||||
if (! (o instanceof RRSIGRecord))
|
||||
if (!(o instanceof RRSIGRecord))
|
||||
{
|
||||
log.debug("found " + o + " where expecting a RRSIG");
|
||||
log.fine("found " + o + " where expecting a RRSIG");
|
||||
continue;
|
||||
}
|
||||
RRSIGRecord sigrec = (RRSIGRecord) o;
|
||||
|
||||
|
||||
byte res = verifier.verifySignature(rrset, sigrec, null);
|
||||
if (res != DNSSEC.Secure)
|
||||
{
|
||||
log.info("Signature failed to verify RRset: " + rrset + "\nsig: " + sigrec);
|
||||
log.info("Signature failed to verify RRset: " + rrset + "\nsig: "
|
||||
+ sigrec);
|
||||
}
|
||||
if (res < result) result = res;
|
||||
}
|
||||
@@ -234,7 +248,7 @@ public class VerifyZone
|
||||
}
|
||||
|
||||
private static List getTrustedKeys(String[] keyfiles, File inDirectory)
|
||||
throws IOException
|
||||
throws IOException
|
||||
{
|
||||
if (keyfiles == null) return null;
|
||||
|
||||
@@ -248,80 +262,70 @@ public class VerifyZone
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
public static void execute(CLIState state, Options opts)
|
||||
throws Exception
|
||||
|
||||
public static void execute(CLIState state) throws Exception
|
||||
{
|
||||
|
||||
List keypairs = getTrustedKeys(state.keyfiles, state.keydir);
|
||||
|
||||
|
||||
List records = ZoneUtils.readZoneFile(state.zonefile, null);
|
||||
Collections.sort(records, new RecordComparator());
|
||||
|
||||
log.debug("verifying signatures...");
|
||||
log.fine("verifying signatures...");
|
||||
byte result = verifyZoneSignatures(records, keypairs);
|
||||
log.debug("completed verification process.");
|
||||
log.fine("completed verification process.");
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case DNSSEC.Failed:
|
||||
System.out.println("zone did not verify.");
|
||||
System.exit(1);
|
||||
break;
|
||||
case DNSSEC.Insecure:
|
||||
if (state.strict)
|
||||
{
|
||||
case DNSSEC.Failed :
|
||||
System.out.println("zone did not verify.");
|
||||
System.exit(1);
|
||||
}
|
||||
case DNSSEC.Secure:
|
||||
System.out.println("zone verified.");
|
||||
break;
|
||||
break;
|
||||
case DNSSEC.Insecure :
|
||||
if (state.strict)
|
||||
{
|
||||
System.out.println("zone did not verify.");
|
||||
System.exit(1);
|
||||
}
|
||||
case DNSSEC.Secure :
|
||||
System.out.println("zone verified.");
|
||||
break;
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
// set up logging.
|
||||
// For now, we force the commons logging to use the built-in
|
||||
// SimpleLog.
|
||||
System.setProperty("org.apache.commons.logging.Log",
|
||||
"org.apache.commons.logging.impl.SimpleLog");
|
||||
|
||||
// set up the command line options
|
||||
Options opts = setupCLI();
|
||||
|
||||
CLIState state = new CLIState();
|
||||
CLIState state = new CLIState();
|
||||
|
||||
try
|
||||
{
|
||||
state.parseCommandLine(opts, args);
|
||||
state.parseCommandLine(args);
|
||||
}
|
||||
catch (UnrecognizedOptionException e)
|
||||
{
|
||||
System.err.println("error: unknown option encountered: " +
|
||||
e.getMessage());
|
||||
usage(opts);
|
||||
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());
|
||||
usage(opts);
|
||||
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();
|
||||
usage(opts);
|
||||
state.usage();
|
||||
}
|
||||
|
||||
log = LogFactory.getLog(VerifyZone.class);
|
||||
log = Logger.getLogger(VerifyZone.class.toString());
|
||||
|
||||
try
|
||||
{
|
||||
execute(state, opts);
|
||||
execute(state);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user