Port to DNSJava 3.5.1, Java 8, linter fixes (#13)

* Initial port to dnsjava 3.5.1

* java.util.Date -> java.time.Instant
* for (Iterator ..) to for ( Object : List )
* DSRecord.<digest type> -> DNSSEC.Digest.<type>
* source to java 8

* formatting overhaul; copyright; author

* add slf4j jars for dnsjava 3.5.1

* NSEC/NSEC3 ttls are now min(soa.min, soa.ttl)

* Upgrade to commons-cli-1.5; some linter fixes

* Add CDS support of jdnssec-dstool

* linter suggestions

* add a TODO list

* Add a TODO list
This commit is contained in:
2022-09-21 14:24:42 -04:00
committed by GitHub
parent ce1189703f
commit e322186112
36 changed files with 2627 additions and 3332 deletions

View File

@@ -1,7 +1,25 @@
// Copyright (C) 2022 Verisign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.cl;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.TimeZone;
import java.util.logging.Formatter;
@@ -13,11 +31,11 @@ import java.util.logging.Logger;
import org.apache.commons.cli.AlreadySelectedException;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.cli.UnrecognizedOptionException;
import com.verisignlabs.dnssec.security.DnsKeyAlgorithm;
@@ -29,19 +47,17 @@ import com.verisignlabs.dnssec.security.DnsKeyAlgorithm;
* Subclasses also have their own main() methods, which should just create the
* subclass variant of the CLIState and call run().
*/
public abstract class CLBase
{
protected static Logger log;
public abstract class CLBase {
protected static Logger staticLog = Logger.getLogger(CLBase.class.getName());
protected Logger log;
/**
* This is a very simple log formatter that simply outputs the log level and
* log string.
*/
public static class BareLogFormatter extends Formatter
{
@Override
public String format(LogRecord arg0)
{
public static class BareLogFormatter extends Formatter {
public String format(LogRecord arg0) {
StringBuilder out = new StringBuilder();
String lvl = arg0.getLevel().getName();
@@ -58,47 +74,39 @@ public abstract class CLBase
* This is a base class for command line parsing state. Subclasses should
* override setupOptions and processOptions.
*/
public static class CLIStateBase
{
public static class CLIStateBase {
protected Options opts;
protected String usageStr;
protected String usageStr;
/**
* The base constructor. This will setup the command line options.
*
* @param usage
* The command line usage string (e.g.,
* "jdnssec-foo [..options..] zonefile")
* The command line usage string (e.g.,
* "jdnssec-foo [..options..] zonefile")
*/
public CLIStateBase(String usage)
{
public CLIStateBase(String usage) {
usageStr = usage;
setup();
}
/** This is the base set of command line options provided to all subclasses. */
private void setup()
{
// Set up the standard set of options that all jdnssec command line tools will implement.
private void setup() {
// Set up the standard set of options that all jdnssec command line tools will
// implement.
opts = new Options();
// boolean options
opts.addOption("h", "help", false, "Print this message.");
opts.addOption("m", "multiline", false,
"Output DNS records using 'multiline' format");
"Output DNS records using 'multiline' format");
OptionBuilder.hasOptionalArg();
OptionBuilder.withLongOpt("verbose");
OptionBuilder.withArgName("level");
OptionBuilder.withDescription("verbosity level -- 0 is silence, 3 is info, "
+ "5 is debug information, 6 is trace information. default is level 2 (warning)");
opts.addOption(OptionBuilder.create('v'));
opts.addOption(Option.builder("v").longOpt("verbose").argName("level").optionalArg(true).desc(
"verbosity level -- 0 is silence, 3 is info, 5 is debug information, 6 is trace information. default is level 2 (warning)")
.build());
OptionBuilder.hasArg();
OptionBuilder.withArgName("alias:original:mnemonic");
OptionBuilder.withLongOpt("alg-alias");
OptionBuilder.withDescription("Define an alias for an algorithm");
opts.addOption(OptionBuilder.create('A'));
opts.addOption(Option.builder("A").hasArg().argName("alias:original:mnemonic").longOpt("alg-alias")
.desc("Define an alias for an algorithm").build());
setupOptions(opts);
}
@@ -108,11 +116,10 @@ public abstract class CLBase
* line options.
*
* @param opts
* the options object to add (via OptionBuilder, typically) new
* options to.
* the options object to add (via OptionBuilder, typically) new
* options to.
*/
protected void setupOptions(Options opts)
{
protected void setupOptions(Options opts) {
// Subclasses generally override this.
}
@@ -123,21 +130,21 @@ public abstract class CLBase
* options.
*
* @param args
* The command line arguments.
* The command line arguments.
* @throws ParseException
*/
public void parseCommandLine(String args[]) throws ParseException
{
CommandLineParser cli_parser = new PosixParser();
CommandLine cli = cli_parser.parse(opts, args);
public void parseCommandLine(String[] args) throws ParseException {
CommandLineParser parser = new DefaultParser();
CommandLine cli = parser.parse(opts, args);
if (cli.hasOption('h')) usage();
if (cli.hasOption('h')) {
usage();
}
Logger rootLogger = Logger.getLogger("");
int value = parseInt(cli.getOptionValue('v'), -1);
switch (value)
{
switch (value) {
case 0:
rootLogger.setLevel(Level.OFF);
break;
@@ -162,22 +169,18 @@ public abstract class CLBase
}
// I hate java.util.logging, btw.
for (Handler h : rootLogger.getHandlers())
{
for (Handler h : rootLogger.getHandlers()) {
h.setLevel(rootLogger.getLevel());
h.setFormatter(new BareLogFormatter());
}
if (cli.hasOption('m'))
{
if (cli.hasOption('m')) {
org.xbill.DNS.Options.set("multiline");
}
String[] optstrs = null;
if ((optstrs = cli.getOptionValues('A')) != null)
{
for (int i = 0; i < optstrs.length; i++)
{
if ((optstrs = cli.getOptionValues('A')) != null) {
for (int i = 0; i < optstrs.length; i++) {
addArgAlias(optstrs[i]);
}
}
@@ -190,72 +193,64 @@ public abstract class CLBase
* this.
*
* @param cli
* The {@link CommandLine} object containing the parsed command
* line state.
* The {@link CommandLine} object containing the parsed command
* line state.
*/
protected void processOptions(CommandLine cli) throws ParseException
{
protected void processOptions(CommandLine cli) throws ParseException {
// Subclasses generally override this.
}
/** Print out the usage and help statements, then quit. */
public void usage()
{
public void usage() {
HelpFormatter f = new HelpFormatter();
PrintWriter out = new PrintWriter(System.err);
// print our own usage statement:
f.printHelp(out, 75, usageStr, null, opts, HelpFormatter.DEFAULT_LEFT_PAD,
HelpFormatter.DEFAULT_DESC_PAD, null);
HelpFormatter.DEFAULT_DESC_PAD, null);
out.flush();
System.exit(64);
}
protected void addArgAlias(String s)
{
if (s == null) return;
protected void addArgAlias(String s) {
if (s == null)
return;
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
String[] v = s.split(":");
if (v.length < 2) return;
if (v.length < 2)
return;
int alias = parseInt(v[0], -1);
if (alias <= 0) return;
if (alias <= 0)
return;
int orig = parseInt(v[1], -1);
if (orig <= 0) return;
if (orig <= 0)
return;
String mn = null;
if (v.length > 2) mn = v[2];
if (v.length > 2)
mn = v[2];
algs.addAlias(alias, mn, orig);
}
}
public static int parseInt(String s, int def)
{
try
{
int v = Integer.parseInt(s);
return v;
}
catch (NumberFormatException e)
{
public static int parseInt(String s, int def) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return def;
}
}
public static long parseLong(String s, long def)
{
try
{
long v = Long.parseLong(s);
return v;
}
catch (NumberFormatException e)
{
public static long parseLong(String s, long def) {
try {
return Long.parseLong(s);
} catch (NumberFormatException e) {
return def;
}
}
@@ -264,66 +259,59 @@ public abstract class CLBase
* Calculate a date/time from a command line time/offset duration string.
*
* @param start
* the start time to calculate offsets from.
* the start time to calculate offsets from.
* @param duration
* the time/offset string to parse.
* the time/offset string to parse.
* @return the calculated time.
*/
public 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;
public static Instant convertDuration(Instant start, String duration) throws ParseException {
if (start == null) {
start = Instant.now();
}
if (duration.startsWith("now")) {
start = Instant.now();
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);
if (duration.startsWith("+")) {
long offset = parseLong(duration.substring(1), 0);
return start.plusSeconds(offset);
}
if (duration.length() <= 10)
{
long epoch = parseLong(duration, 0) * 1000;
return new Date(epoch);
// This is a heuristic to distinguish UNIX epoch times from the zone file
// format standard (which is length == 14)
if (duration.length() <= 10) {
long epoch = parseLong(duration, 0);
return Instant.ofEpochSecond(epoch);
}
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
try
{
return dateFormatter.parse(duration);
}
catch (java.text.ParseException e)
{
try {
Date parsedDate = dateFormatter.parse(duration);
return parsedDate.toInstant();
} catch (java.text.ParseException e) {
throw new ParseException(e.getMessage());
}
}
public abstract void execute() throws Exception;
public void run(CLIStateBase state, String[] args)
{
try
{
public void run(CLIStateBase state, String[] args) {
try {
state.parseCommandLine(args);
}
catch (UnrecognizedOptionException e)
{
} catch (UnrecognizedOptionException e) {
System.err.println("error: unknown option encountered: " + e.getMessage());
state.usage();
}
catch (AlreadySelectedException e)
{
} catch (AlreadySelectedException e) {
System.err.println("error: mutually exclusive options have "
+ "been selected:\n " + e.getMessage());
state.usage();
}
catch (Exception e)
{
} catch (Exception e) {
System.err.println("error: unknown command line parsing exception:");
e.printStackTrace();
state.usage();
@@ -331,12 +319,9 @@ public abstract class CLBase
log = Logger.getLogger(this.getClass().toString());
try
{
try {
execute();
}
catch (Exception e)
{
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003, 2011 VeriSign, Inc.
// Copyright (C) 2001-2003, 2011, 2022 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -20,36 +20,45 @@ package com.verisignlabs.dnssec.cl;
import java.io.FileWriter;
import java.io.PrintWriter;
import org.apache.commons.cli.*;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.xbill.DNS.CDSRecord;
import org.xbill.DNS.DLVRecord;
import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.DSRecord;
import org.xbill.DNS.Record;
import com.verisignlabs.dnssec.security.*;
import com.verisignlabs.dnssec.security.BINDKeyUtils;
import com.verisignlabs.dnssec.security.DnsKeyPair;
import com.verisignlabs.dnssec.security.SignUtils;
/**
* This class forms the command line implementation of a DNSSEC DS/DLV generator
*
* @author David Blacka
*/
public class DSTool extends CLBase
{
public class DSTool extends CLBase {
private CLIState state;
/** There are several records that are based on DS. */
protected enum dsType {
DS, CDS, DLV;
}
/**
* This is a small inner class used to hold all of the command line option
* state.
*/
protected static class CLIState extends CLIStateBase
{
public boolean createDLV = false;
public String outputfile = null;
public String keyname = null;
public int digest_id = DSRecord.SHA1_DIGEST_ID;
public CLIState()
{
protected static class CLIState extends CLIStateBase {
public dsType createType = dsType.DS;
public String outputfile = null;
public String keyname = null;
public int digestId = DNSSEC.Digest.SHA1;
public CLIState() {
super("jdnssec-dstool [..options..] keyfile");
}
@@ -58,76 +67,72 @@ public class DSTool extends CLBase
*
* @return a set of command line options.
*/
protected void setupOptions(Options opts)
{
OptionBuilder.withLongOpt("dlv");
OptionBuilder.withDescription("Generate a DLV record instead.");
opts.addOption(OptionBuilder.create());
OptionBuilder.hasArg();
OptionBuilder.withLongOpt("digest");
OptionBuilder.withArgName("id");
OptionBuilder.withDescription("The Digest ID to use (numerically): either 1 for SHA1 or 2 for SHA256");
opts.addOption(OptionBuilder.create('d'));
@Override
protected void setupOptions(Options opts) {
opts.addOption(Option.builder("D").longOpt("dlv").desc("Generate a DLV record instead.").build());
opts.addOption(Option.builder("C").longOpt("cds").desc("Generate a CDS record instead").build());
opts.addOption(Option.builder("d").hasArg().argName("id").longOpt("digest").desc("The digest algorithm to use").build());
opts.addOption(Option.builder("f").hasArg().argName("file").longOpt("output").desc("output to file").build());
}
@Override
protected void processOptions(CommandLine cli)
throws org.apache.commons.cli.ParseException
{
throws org.apache.commons.cli.ParseException {
outputfile = cli.getOptionValue('f');
createDLV = cli.hasOption("dlv");
if (cli.hasOption("dlv")) {
createType = dsType.DLV;
} else if (cli.hasOption("cds")) {
createType = dsType.CDS;
}
String optstr = cli.getOptionValue('d');
if (optstr != null) digest_id = parseInt(optstr, digest_id);
if (optstr != null)
digestId = DNSSEC.Digest.value(optstr);
String[] cl_args = cli.getArgs();
String[] args = cli.getArgs();
if (cl_args.length < 1)
{
if (args.length < 1) {
System.err.println("error: missing key file ");
usage();
}
keyname = cl_args[0];
keyname = args[0];
}
}
public void execute() throws Exception
{
public void execute() throws Exception {
DnsKeyPair key = BINDKeyUtils.loadKey(state.keyname, null);
DNSKEYRecord dnskey = key.getDNSKEYRecord();
if ((dnskey.getFlags() & DNSKEYRecord.Flags.SEP_KEY) == 0)
{
if ((dnskey.getFlags() & DNSKEYRecord.Flags.SEP_KEY) == 0) {
log.warning("DNSKEY is not an SEP-flagged key.");
}
DSRecord ds = SignUtils.calculateDSRecord(dnskey, state.digest_id, dnskey.getTTL());
DSRecord ds = SignUtils.calculateDSRecord(dnskey, state.digestId, dnskey.getTTL());
Record res = ds;
if (state.createDLV)
{
if (state.createType == dsType.DLV) {
log.fine("creating DLV.");
DLVRecord dlv = new DLVRecord(ds.getName(), ds.getDClass(), ds.getTTL(),
ds.getFootprint(), ds.getAlgorithm(),
ds.getDigestID(), ds.getDigest());
DLVRecord dlv = new DLVRecord(ds.getName(), ds.getDClass(), ds.getTTL(), ds.getFootprint(), ds.getAlgorithm(),
ds.getDigestID(), ds.getDigest());
res = dlv;
} else if (state.createType == dsType.CDS) {
log.fine("creating CDS.");
CDSRecord cds = new CDSRecord(ds.getName(), ds.getDClass(), ds.getTTL(), ds.getFootprint(), ds.getAlgorithm(),
ds.getDClass(), ds.getDigest());
res = cds;
}
if (state.outputfile != null)
{
PrintWriter out = new PrintWriter(new FileWriter(state.outputfile));
out.println(res);
out.close();
}
else
{
if (state.outputfile != null && !state.outputfile.equals("-")) {
try (PrintWriter out = new PrintWriter(new FileWriter(state.outputfile))) {
out.println(res);
}
} else {
System.out.println(res);
}
}
public static void main(String[] args)
{
public static void main(String[] args) {
DSTool tool = new DSTool();
tool.state = new CLIState();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003, 2011 VeriSign, Inc.
// Copyright (C) 2001-2003, 2011, 2022 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -19,205 +19,178 @@ package com.verisignlabs.dnssec.cl;
import java.io.File;
import org.apache.commons.cli.*;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.xbill.DNS.DClass;
import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.Name;
import com.verisignlabs.dnssec.security.*;
import com.verisignlabs.dnssec.security.BINDKeyUtils;
import com.verisignlabs.dnssec.security.DnsKeyAlgorithm;
import com.verisignlabs.dnssec.security.DnsKeyPair;
import com.verisignlabs.dnssec.security.JCEDnsSecSigner;
/**
* This class forms the command line implementation of a DNSSEC key generator
*
*
* @author David Blacka
*/
public class KeyGen extends CLBase
{
public class KeyGen extends CLBase {
private CLIState state;
/**
* This is a small inner class used to hold all of the command line option
* state.
*/
protected static class CLIState extends CLIStateBase
{
public int algorithm = 8;
public int keylength = 1024;
public boolean useLargeE = true;
public String outputfile = null;
public File keydir = null;
public boolean zoneKey = true;
public boolean kskFlag = false;
public String owner = null;
public long ttl = 86400;
protected static class CLIState extends CLIStateBase {
public int algorithm = 8;
public int keylength = 1024;
public boolean useLargeE = true;
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()
{
public CLIState() {
super("jdnssec-keygen [..options..] name");
}
/**
* Set up the command line options.
*/
protected void setupOptions(Options opts)
{
@Override
protected void setupOptions(Options opts) {
// boolean options
opts.addOption("k", "kskflag", false,
"Key is a key-signing-key (sets the SEP flag).");
"Key is a key-signing-key (sets the SEP flag).");
opts.addOption("e", "large-exponent", false, "Use large RSA exponent (default)");
opts.addOption("E", "small-exponent", false, "Use small RSA exponent");
// Argument options
OptionBuilder.hasArg();
OptionBuilder.withLongOpt("nametype");
OptionBuilder.withArgName("type");
OptionBuilder.withDescription("ZONE | OTHER (default ZONE)");
opts.addOption(OptionBuilder.create('n'));
opts.addOption(
Option.builder("n").longOpt("nametype").hasArg().argName("type").desc("ZONE | OTHER (default ZONE)").build());
String[] algStrings = DnsKeyAlgorithm.getInstance().supportedAlgMnemonics();
OptionBuilder.hasArg();
OptionBuilder.withArgName("algorithm");
OptionBuilder.withDescription(String.join(" | ", algStrings) +
" | alias, RSASHA256 is default.");
opts.addOption(OptionBuilder.create('a'));
String algStringSet = String.join(" | ", algStrings);
opts.addOption(Option.builder("a").hasArg().argName("algorithm")
.desc(algStringSet + " | alias, RSASHA256 is default.").build());
OptionBuilder.hasArg();
OptionBuilder.withArgName("size");
OptionBuilder.withDescription("key size, in bits. default is 1024. "
+ "RSA: [512..4096], DSA: [512..1024], DH: [128..4096], "
+ "ECDSA: ignored");
opts.addOption(OptionBuilder.create('b'));
opts.addOption(Option.builder("b").hasArg().argName("size").desc(
"key size, in bits (default 1024). RSA: [512..4096], DSA: [512..1024], DH: [128..4096], ECDSA: ignored, EdDSA: ignored")
.build());
opts.addOption(Option.builder("f").hasArg().argName("file").longOpt("output-file")
.desc("base filename from the public/private key files").build());
opts.addOption(Option.builder("d").hasArg().argName("dir").longOpt("keydir")
.desc("generated keyfiles are written to this directory").build());
opts.addOption(Option.builder("T").hasArg().argName("ttl").longOpt("ttl")
.desc("use this TTL for the generated DNSKEY records (default: 86400").build());
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'));
}
@Override
protected void processOptions(CommandLine cli)
throws org.apache.commons.cli.ParseException
{
throws org.apache.commons.cli.ParseException {
String optstr = null;
String[] optstrs = null;
if (cli.hasOption('k')) kskFlag = true;
if (cli.hasOption('e')) useLargeE = true;
if (cli.hasOption('k'))
kskFlag = true;
if (cli.hasOption('e'))
useLargeE = true;
outputfile = cli.getOptionValue('f');
if ((optstr = cli.getOptionValue('d')) != null)
{
if ((optstr = cli.getOptionValue('d')) != null) {
keydir = new File(optstr);
}
if ((optstr = cli.getOptionValue('n')) != null)
{
if (!optstr.equalsIgnoreCase("ZONE"))
{
zoneKey = false;
}
if ((optstr = cli.getOptionValue('n')) != null && !optstr.equalsIgnoreCase("ZONE")) {
zoneKey = false;
}
if ((optstrs = cli.getOptionValues('A')) != null)
{
for (int i = 0; i < optstrs.length; i++)
{
if ((optstrs = cli.getOptionValues('A')) != null) {
for (int i = 0; i < optstrs.length; i++) {
addArgAlias(optstrs[i]);
}
}
if ((optstr = cli.getOptionValue('a')) != null)
{
algorithm = parseAlg(optstr);
if (algorithm < 0)
{
if ((optstr = cli.getOptionValue('a')) != null) {
algorithm = CLIState.parseAlg(optstr);
if (algorithm < 0) {
System.err.println("DNSSEC algorithm " + optstr + " is not supported");
usage();
}
}
if ((optstr = cli.getOptionValue('b')) != null)
{
if ((optstr = cli.getOptionValue('b')) != null) {
keylength = parseInt(optstr, 1024);
}
if ((optstr = cli.getOptionValue("ttl")) != null)
{
if ((optstr = cli.getOptionValue("ttl")) != null) {
ttl = parseInt(optstr, 86400);
}
String[] cl_args = cli.getArgs();
String[] args = cli.getArgs();
if (cl_args.length < 1)
{
if (args.length < 1) {
System.err.println("error: missing key owner name");
usage();
}
owner = cl_args[0];
owner = args[0];
}
private static int parseAlg(String s) {
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
int alg = parseInt(s, -1);
if (alg > 0) {
if (algs.supportedAlgorithm(alg))
return alg;
return -1;
}
return algs.stringToAlgorithm(s);
}
}
private static int parseAlg(String s)
{
DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance();
int alg = parseInt(s, -1);
if (alg > 0)
{
if (algs.supportedAlgorithm(alg)) return alg;
return -1;
}
return algs.stringToAlgorithm(s);
}
public void execute() throws Exception
{
public void execute() 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);
Name ownerName = Name.fromString(state.owner);
// Calculate our flags
int flags = 0;
if (state.zoneKey) flags |= DNSKEYRecord.Flags.ZONE_KEY;
if (state.kskFlag) flags |= DNSKEYRecord.Flags.SEP_KEY;
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
log.fine("create key pair with (name = " + ownerName + ", 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.useLargeE);
DnsKeyPair pair = signer.generateKey(ownerName, state.ttl, DClass.IN,
state.algorithm, flags, state.keylength,
state.useLargeE);
if (state.outputfile != null)
{
if (state.outputfile != null) {
BINDKeyUtils.writeKeyFiles(state.outputfile, pair, state.keydir);
}
else
{
} else {
BINDKeyUtils.writeKeyFiles(pair, state.keydir);
System.out.println(BINDKeyUtils.keyFileBase(pair));
}
}
public static void main(String[] args)
{
public static void main(String[] args) {
KeyGen tool = new KeyGen();
tool.state = new CLIState();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003, 2011 VeriSign, Inc.
// Copyright (C) 2001-2003, 2011, 2022 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -20,60 +20,58 @@ package com.verisignlabs.dnssec.cl;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPublicKey;
import org.apache.commons.cli.*;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.xbill.DNS.DNSKEYRecord;
import com.verisignlabs.dnssec.security.*;
import com.verisignlabs.dnssec.security.BINDKeyUtils;
import com.verisignlabs.dnssec.security.DnsKeyAlgorithm;
import com.verisignlabs.dnssec.security.DnsKeyPair;
/**
* This class forms the command line implementation of a key introspection tool.
*
*
* @author David Blacka
*/
public class KeyInfoTool extends CLBase
{
public class KeyInfoTool extends CLBase {
private CLIState state;
/**
* This is a small inner class used to hold all of the command line option
* state.
*/
protected static class CLIState extends CLIStateBase
{
protected static class CLIState extends CLIStateBase {
public String[] keynames = null;
public CLIState()
{
public CLIState() {
super("jdnssec-keyinfo [..options..] keyfile");
}
/**
* Set up the command line options.
*/
protected void setupOptions(Options opts)
{
@Override
protected void setupOptions(Options opts) {
// no special options at the moment.
}
protected void processOptions(CommandLine cli) throws ParseException
{
@Override
protected void processOptions(CommandLine cli) throws ParseException {
keynames = cli.getArgs();
if (keynames.length < 1)
{
if (keynames.length < 1) {
System.err.println("error: missing key file ");
usage();
}
}
}
public void execute() throws Exception
{
for (int i = 0; i < state.keynames.length; ++i)
{
String keyname = state.keynames[i];
DnsKeyPair key = BINDKeyUtils.loadKey(keyname, null);
DNSKEYRecord dnskey = key.getDNSKEYRecord();
public void execute() throws Exception {
for (int i = 0; i < state.keynames.length; ++i) {
String keyname = state.keynames[i];
DnsKeyPair key = BINDKeyUtils.loadKey(keyname, null);
DNSKEYRecord dnskey = key.getDNSKEYRecord();
DnsKeyAlgorithm dnskeyalg = DnsKeyAlgorithm.getInstance();
boolean isSEP = (dnskey.getFlags() & DNSKEYRecord.Flags.SEP_KEY) != 0;
@@ -87,32 +85,25 @@ public class KeyInfoTool extends CLBase
System.out.println("ID: " + dnskey.getFootprint());
System.out.println("KeyFileBase: " + BINDKeyUtils.keyFileBase(key));
int basetype = dnskeyalg.baseType(dnskey.getAlgorithm());
switch (basetype)
{
case DnsKeyAlgorithm.RSA: {
RSAPublicKey pub = (RSAPublicKey) key.getPublic();
System.out.println("RSA Public Exponent: " + pub.getPublicExponent());
System.out.println("RSA Modulus: " + pub.getModulus());
break;
}
case DnsKeyAlgorithm.DSA: {
DSAPublicKey pub = (DSAPublicKey) key.getPublic();
System.out.println("DSA base (G): " + pub.getParams().getG());
System.out.println("DSA prime (P): " + pub.getParams().getP());
System.out.println("DSA subprime (Q): " + pub.getParams().getQ());
System.out.println("DSA public (Y): " + pub.getY());
break;
}
if (basetype == DnsKeyAlgorithm.RSA) {
RSAPublicKey pub = (RSAPublicKey) key.getPublic();
System.out.println("RSA Public Exponent: " + pub.getPublicExponent());
System.out.println("RSA Modulus: " + pub.getModulus());
} else if (basetype == DnsKeyAlgorithm.DSA) {
DSAPublicKey pub = (DSAPublicKey) key.getPublic();
System.out.println("DSA base (G): " + pub.getParams().getG());
System.out.println("DSA prime (P): " + pub.getParams().getP());
System.out.println("DSA subprime (Q): " + pub.getParams().getQ());
System.out.println("DSA public (Y): " + pub.getY());
}
if (state.keynames.length - i > 1)
{
if (state.keynames.length - i > 1) {
System.out.println();
}
}
}
public static void main(String[] args)
{
public static void main(String[] args) {
KeyInfoTool tool = new KeyInfoTool();
tool.state = new CLIState();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003, 2011 VeriSign, Inc.
// Copyright (C) 2001-2003, 2011, 2022 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -20,13 +20,13 @@ package com.verisignlabs.dnssec.cl;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Collections;
import java.util.List;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.xbill.DNS.Name;
import org.xbill.DNS.RRSIGRecord;
@@ -34,7 +34,12 @@ import org.xbill.DNS.RRset;
import org.xbill.DNS.Record;
import org.xbill.DNS.Type;
import com.verisignlabs.dnssec.security.*;
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 keyset signer.
@@ -43,94 +48,66 @@ import com.verisignlabs.dnssec.security.*;
*
* @author David Blacka
*/
public class SignKeyset extends CLBase
{
public class SignKeyset extends CLBase {
private CLIState state;
/**
* This is an inner class used to hold all of the command line option state.
*/
protected static class CLIState extends CLIStateBase
{
public File keyDirectory = null;
public String[] keyFiles = null;
public Date start = null;
public Date expire = null;
public String inputfile = null;
public String outputfile = null;
public boolean verifySigs = false;
protected static class CLIState extends CLIStateBase {
public File keyDirectory = null;
public String[] keyFiles = null;
public Instant start = null;
public Instant expire = null;
public String inputfile = null;
public String outputfile = null;
public boolean verifySigs = false;
public CLIState()
{
public CLIState() {
super("jdnssec-signkeyset [..options..] dnskeyset_file [key_file ...]");
}
/**
* Set up the command line options.
*/
protected void setupOptions(Options opts)
{
@Override
protected void setupOptions(Options opts) {
// boolean options
opts.addOption("a", "verify", false, "verify generated signatures>");
// Argument options
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'));
opts.addOption(Option.builder("D").hasArg().argName("dir").longOpt("key-directory").desc("directory where key files are found (default '.').").build());
opts.addOption(Option.builder("s").hasArg().argName("time/offset").longOpt("start-time").desc("signature starting time (default is now - 1 hour)").build());
opts.addOption(Option.builder("e").hasArg().argName("time/offset").longOpt("expire-time").desc("signature expiration time (default is start-time + 30 days)").build());
opts.addOption(Option.builder("f").hasArg().argName("outfile").desc("file the signed keyset is written to").build());
}
@Override
protected void processOptions(CommandLine cli)
throws org.apache.commons.cli.ParseException
{
throws org.apache.commons.cli.ParseException {
String optstr = null;
if (cli.hasOption('a')) verifySigs = true;
if (cli.hasOption('a'))
verifySigs = true;
if ((optstr = cli.getOptionValue('D')) != null)
{
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();
}
}
if ((optstr = cli.getOptionValue('s')) != null)
{
if ((optstr = cli.getOptionValue('s')) != null) {
start = convertDuration(null, optstr);
}
else
{
} else {
// default is now - 1 hour.
start = new Date(System.currentTimeMillis() - (3600 * 1000));
start = Instant.now().minusSeconds(3600);
}
if ((optstr = cli.getOptionValue('e')) != null)
{
if ((optstr = cli.getOptionValue('e')) != null) {
expire = convertDuration(start, optstr);
}
else
{
} else {
expire = convertDuration(start, "+2592000"); // 30 days
}
@@ -138,15 +115,13 @@ public class SignKeyset extends CLBase
String[] files = cli.getArgs();
if (files.length < 1)
{
if (files.length < 1) {
System.err.println("error: missing zone file and/or key files");
usage();
}
inputfile = files[0];
if (files.length > 1)
{
if (files.length > 1) {
keyFiles = new String[files.length - 1];
System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
}
@@ -156,23 +131,19 @@ public class SignKeyset extends CLBase
/**
* Verify the generated signatures.
*
* @param zonename
* the origin name of the zone.
* @param records
* a list of {@link org.xbill.DNS.Record}s.
* a list of {@link org.xbill.DNS.Record}s.
* @param keypairs
* a list of keypairs used the sign the zone.
* a list of keypairs used the sign the zone.
* @return true if all of the signatures validated.
*/
private static boolean verifySigs(Name zonename, List<Record> records,
List<DnsKeyPair> keypairs)
{
private static boolean verifySigs(List<Record> records,
List<DnsKeyPair> keypairs) {
boolean secure = true;
DnsSecVerifier verifier = new DnsSecVerifier();
for (DnsKeyPair pair : keypairs)
{
for (DnsKeyPair pair : keypairs) {
verifier.addTrustedKey(pair);
}
@@ -180,16 +151,15 @@ public class SignKeyset extends CLBase
List<RRset> rrsets = SignUtils.assembleIntoRRsets(records);
for (RRset rrset : rrsets)
{
for (RRset rrset : rrsets) {
// skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue;
if (rrset.sigs().isEmpty())
continue;
boolean result = verifier.verify(rrset);
if (!result)
{
log.fine("Signatures did not verify for RRset: " + rrset);
if (!result) {
staticLog.fine("Signatures did not verify for RRset: " + rrset);
secure = false;
}
}
@@ -201,57 +171,54 @@ public class SignKeyset extends CLBase
* 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.
* a string array containing the base names or paths of the
* keys
* to be loaded.
* @param startIndex
* 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).
* 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;
private static List<DnsKeyPair> getKeys(String[] keyfiles, int startIndex,
File inDirectory) throws IOException {
if (keyfiles == null)
return Collections.emptyList();
int len = keyfiles.length - start_index;
if (len <= 0) return null;
int len = keyfiles.length - startIndex;
if (len <= 0)
return Collections.emptyList();
ArrayList<DnsKeyPair> keys = new ArrayList<DnsKeyPair>(len);
ArrayList<DnsKeyPair> keys = new ArrayList<>(len);
for (int i = start_index; i < keyfiles.length; i++)
{
for (int i = startIndex; i < keyfiles.length; i++) {
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
if (k != null) keys.add(k);
if (k != null)
keys.add(k);
}
return keys;
}
private static class KeyFileFilter implements FileFilter
{
private static class KeyFileFilter implements FileFilter {
private String prefix;
public KeyFileFilter(Name origin)
{
public KeyFileFilter(Name origin) {
prefix = "K" + origin.toString();
}
public boolean accept(File pathname)
{
if (!pathname.isFile()) return false;
public boolean accept(File pathname) {
if (!pathname.isFile())
return false;
String name = pathname.getName();
if (name.startsWith(prefix) && name.endsWith(".private")) return true;
return false;
return (name.startsWith(prefix) && name.endsWith(".private"));
}
}
private static List<DnsKeyPair> findZoneKeys(File inDirectory, Name zonename)
throws IOException
{
if (inDirectory == null)
{
throws IOException {
if (inDirectory == null) {
inDirectory = new File(".");
}
@@ -260,53 +227,43 @@ public class SignKeyset extends CLBase
File[] files = inDirectory.listFiles(filter);
// read in all of the records
ArrayList<DnsKeyPair> keys = new ArrayList<DnsKeyPair>();
for (int i = 0; i < files.length; i++)
{
ArrayList<DnsKeyPair> keys = new ArrayList<>();
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;
return null;
return keys;
}
@SuppressWarnings("unchecked")
public void execute() throws Exception
{
public void execute() throws Exception {
// Read in the zone
List<Record> records = ZoneUtils.readZoneFile(state.inputfile, null);
if (records == null || records.size() == 0)
{
if (records == null || records.isEmpty()) {
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();
Name keysetName = null;
RRset keyset = new RRset();
for (Record r : records)
{
if (r.getType() != Type.DNSKEY)
{
for (Record r : records) {
if (r.getType() != Type.DNSKEY) {
System.err.println("error: Non DNSKEY RR found in keyset: " + r);
continue;
}
if (keysetName == null)
{
if (keysetName == null) {
keysetName = r.getName();
}
if (!r.getName().equals(keysetName))
{
if (!r.getName().equals(keysetName)) {
System.err.println("error: DNSKEY with a different name found!");
state.usage();
}
keyset.addRR(r);
}
if (keyset.size() == 0)
{
if (keyset.size() == 0) {
System.err.println("error: No DNSKEYs found in keyset file");
state.usage();
}
@@ -317,27 +274,22 @@ public class SignKeyset extends CLBase
// If we *still* don't have any key pairs, look for keys the key
// directory
// that match
if (keypairs == null)
{
if (keypairs == null) {
keypairs = findZoneKeys(state.keyDirectory, keysetName);
}
// If there *still* aren't any ZSKs defined, bail.
if (keypairs == null || keypairs.size() == 0)
{
if (keypairs == null || keypairs.isEmpty() || keysetName == null) {
System.err.println("error: No signing keys could be determined.");
state.usage();
return;
}
// default the output file, if not set.
if (state.outputfile == null)
{
if (keysetName.isAbsolute())
{
if (state.outputfile == null) {
if (keysetName.isAbsolute()) {
state.outputfile = keysetName + "signed_keyset";
}
else
{
} else {
state.outputfile = keysetName + ".signed_keyset";
}
}
@@ -345,46 +297,36 @@ public class SignKeyset extends CLBase
JCEDnsSecSigner signer = new JCEDnsSecSigner();
List<RRSIGRecord> sigs = signer.signRRset(keyset, keypairs, state.start, state.expire);
for (RRSIGRecord s : sigs)
{
for (RRSIGRecord s : sigs) {
keyset.addRR(s);
}
// write out the signed RRset
List<Record> signed_records = new ArrayList<Record>();
for (Iterator<Record> i = keyset.rrs(); i.hasNext();)
{
signed_records.add(i.next());
List<Record> signedRecords = new ArrayList<>();
for (Record r : keyset.rrs()) {
signedRecords.add(r);
}
for (Iterator<Record> i = keyset.sigs(); i.hasNext();)
{
signed_records.add(i.next());
for (RRSIGRecord s : keyset.sigs()) {
signedRecords.add(s);
}
// write out the signed zone
ZoneUtils.writeZoneFile(signed_records, state.outputfile);
ZoneUtils.writeZoneFile(signedRecords, state.outputfile);
if (state.verifySigs)
{
if (state.verifySigs) {
log.fine("verifying generated signatures");
boolean res = verifySigs(keysetName, signed_records, keypairs);
boolean res = verifySigs(signedRecords, keypairs);
if (res)
{
if (res) {
System.out.println("Generated signatures verified");
// log.info("Generated signatures verified");
}
else
{
} else {
System.out.println("Generated signatures did not verify.");
// log.warn("Generated signatures did not verify.");
}
}
}
public static void main(String[] args)
{
public static void main(String[] args) {
SignKeyset tool = new SignKeyset();
tool.state = new CLIState();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003, 2011 VeriSign, Inc.
// Copyright (C) 2001-2003, 2011, 2022 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -19,22 +19,26 @@ package com.verisignlabs.dnssec.cl;
import java.io.File;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Collections;
import java.util.List;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.xbill.DNS.Name;
import org.xbill.DNS.RRSIGRecord;
import org.xbill.DNS.RRset;
import org.xbill.DNS.Record;
import org.xbill.DNS.Type;
import com.verisignlabs.dnssec.security.*;
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 RRset signer.
@@ -45,95 +49,72 @@ import com.verisignlabs.dnssec.security.*;
*
* @author David Blacka
*/
public class SignRRset extends CLBase
{
public class SignRRset extends CLBase {
private CLIState state;
/**
* This is an inner class used to hold all of the command line option state.
*/
protected static class CLIState extends CLIStateBase
{
private File keyDirectory = null;
public String[] keyFiles = null;
public Date start = null;
public Date expire = null;
public String inputfile = null;
public String outputfile = null;
public boolean verifySigs = false;
public boolean verboseSigning = false;
protected static class CLIState extends CLIStateBase {
private File keyDirectory = null;
public String[] keyFiles = null;
public Instant start = null;
public Instant expire = null;
public String inputfile = null;
public String outputfile = null;
public boolean verifySigs = false;
public boolean verboseSigning = false;
public CLIState()
{
public CLIState() {
super("jdnssec-signrrset [..options..] rrset_file key_file [key_file ...]");
}
/**
* Set up the command line options.
*/
protected void setupOptions(Options opts)
{
@Override
protected void setupOptions(Options opts) {
// boolean options
opts.addOption("a", "verify", false, "verify generated signatures>");
opts.addOption("V", "verbose-signing", false, "Display verbose signing activity.");
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'));
opts.addOption(Option.builder("D").hasArg().argName("dir").longOpt("key-directory")
.desc("directory to find key files (default '.'").build());
opts.addOption(Option.builder("s").hasArg().argName("time/offset").longOpt("start-time")
.desc("signature starting time (default is now - 1 hour)").build());
opts.addOption(Option.builder("e").hasArg().argName("time/offset").longOpt("expire-time")
.desc("signature expiration time (default is start-time + 30 days)").build());
opts.addOption(
Option.builder("f").hasArg().argName("outfile").desc("file the the signed rrset is written to").build());
}
protected void processOptions(CommandLine cli) throws org.apache.commons.cli.ParseException
{
@Override
protected void processOptions(CommandLine cli) throws org.apache.commons.cli.ParseException {
String optstr = null;
if (cli.hasOption('a')) verifySigs = true;
if (cli.hasOption('V')) verboseSigning = true;
if (cli.hasOption('a'))
verifySigs = true;
if (cli.hasOption('V'))
verboseSigning = true;
if ((optstr = cli.getOptionValue('D')) != null)
{
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();
}
}
if ((optstr = cli.getOptionValue('s')) != null)
{
if ((optstr = cli.getOptionValue('s')) != null) {
start = convertDuration(null, optstr);
}
else
{
} else {
// default is now - 1 hour.
start = new Date(System.currentTimeMillis() - (3600 * 1000));
start = Instant.now().minusSeconds(3600);
}
if ((optstr = cli.getOptionValue('e')) != null)
{
if ((optstr = cli.getOptionValue('e')) != null) {
expire = convertDuration(start, optstr);
}
else
{
} else {
expire = convertDuration(start, "+2592000"); // 30 days
}
@@ -141,15 +122,13 @@ public class SignRRset extends CLBase
String[] files = cli.getArgs();
if (files.length < 1)
{
if (files.length < 1) {
System.err.println("error: missing zone file and/or key files");
usage();
}
inputfile = files[0];
if (files.length > 1)
{
if (files.length > 1) {
keyFiles = new String[files.length - 1];
System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
}
@@ -159,22 +138,18 @@ public class SignRRset extends CLBase
/**
* Verify the generated signatures.
*
* @param zonename
* the origin name of the zone.
* @param records
* a list of {@link org.xbill.DNS.Record}s.
* a list of {@link org.xbill.DNS.Record}s.
* @param keypairs
* a list of keypairs used the sign the zone.
* a list of keypairs used the sign the zone.
* @return true if all of the signatures validated.
*/
private static boolean verifySigs(Name zonename, List<Record> records, List<DnsKeyPair> keypairs)
{
private static boolean verifySigs(List<Record> records, List<DnsKeyPair> keypairs) {
boolean secure = true;
DnsSecVerifier verifier = new DnsSecVerifier();
for (DnsKeyPair pair : keypairs)
{
for (DnsKeyPair pair : keypairs) {
verifier.addTrustedKey(pair);
}
@@ -182,16 +157,16 @@ public class SignRRset extends CLBase
List<RRset> rrsets = SignUtils.assembleIntoRRsets(records);
for (RRset rrset : rrsets)
{
for (RRset rrset : rrsets) {
// skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue;
if (rrset.sigs().isEmpty()) {
continue;
}
boolean result = verifier.verify(rrset);
if (!result)
{
log.fine("Signatures did not verify for RRset: " + rrset);
if (!result) {
staticLog.fine("Signatures did not verify for RRset: " + rrset);
secure = false;
}
}
@@ -203,41 +178,40 @@ public class SignRRset extends CLBase
* 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.
* a string array containing the base names or paths of the
* keys
* to be loaded.
* @param startIndex
* 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).
* 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;
private static List<DnsKeyPair> getKeys(String[] keyfiles, int startIndex,
File inDirectory) throws IOException {
if (keyfiles == null)
return Collections.emptyList();
int len = keyfiles.length - start_index;
if (len <= 0) return null;
int len = keyfiles.length - startIndex;
if (len <= 0)
return Collections.emptyList();
ArrayList<DnsKeyPair> keys = new ArrayList<DnsKeyPair>(len);
ArrayList<DnsKeyPair> keys = new ArrayList<>(len);
for (int i = start_index; i < keyfiles.length; i++)
{
for (int i = startIndex; i < keyfiles.length; i++) {
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
if (k != null) keys.add(k);
if (k != null)
keys.add(k);
}
return keys;
}
@SuppressWarnings("unchecked")
public void execute() throws Exception
{
public void execute() throws Exception {
// Read in the zone
List<Record> records = ZoneUtils.readZoneFile(state.inputfile, null);
if (records == null || records.size() == 0)
{
if (records == null || records.isEmpty()) {
System.err.println("error: empty RRset file");
state.usage();
}
@@ -245,44 +219,37 @@ public class SignRRset extends CLBase
// consist of more than one RRset.
RRset rrset = null;
for (Record r : records)
{
for (Record r : records) {
// skip RRSIGs
if (r.getType() == Type.RRSIG || r.getType() == Type.SIG)
{
if (r.getType() == Type.RRSIG || r.getType() == Type.SIG) {
continue;
}
// Handle the first record.
if (rrset == null)
{
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.getDClass() == r.getDClass()) {
rrset.addRR(r);
}
else
{
} else {
System.err.println("Records do not all belong to the same RRset.");
state.usage();
}
}
if (rrset.size() == 0)
{
if (rrset == null || rrset.size() == 0) {
System.err.println("No records found in inputfile.");
state.usage();
return;
}
// Load the key pairs.
if (state.keyFiles.length == 0)
{
if (state.keyFiles.length == 0) {
System.err.println("error: at least one keyfile must be specified");
state.usage();
}
@@ -293,69 +260,55 @@ public class SignRRset extends CLBase
// This will be used as the zone name, too.
Name keysetName = null;
for (DnsKeyPair pair : keypairs)
{
if (keysetName == null)
{
for (DnsKeyPair pair : keypairs) {
if (keysetName == null) {
keysetName = pair.getDNSKEYName();
continue;
}
if (!pair.getDNSKEYName().equals(keysetName))
{
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("-"))
{
if (state.outputfile == null && !state.inputfile.equals("-")) {
state.outputfile = state.inputfile + ".signed";
}
JCEDnsSecSigner signer = new JCEDnsSecSigner(state.verboseSigning);
List<RRSIGRecord> sigs = signer.signRRset(rrset, keypairs, state.start, state.expire);
for (RRSIGRecord s : sigs)
{
for (RRSIGRecord s : sigs) {
rrset.addRR(s);
}
// write out the signed RRset
List<Record> signed_records = new ArrayList<Record>();
for (Iterator<Record> i = rrset.rrs(); i.hasNext();)
{
signed_records.add(i.next());
List<Record> signedRecords = new ArrayList<>();
for (Record r : rrset.rrs()) {
signedRecords.add(r);
}
for (Iterator<Record> i = rrset.sigs(); i.hasNext();)
{
signed_records.add(i.next());
for (RRSIGRecord sigrec : rrset.sigs()) {
signedRecords.add(sigrec);
}
// write out the signed zone
ZoneUtils.writeZoneFile(signed_records, state.outputfile);
ZoneUtils.writeZoneFile(signedRecords, state.outputfile);
if (state.verifySigs)
{
if (state.verifySigs) {
log.fine("verifying generated signatures");
boolean res = verifySigs(keysetName, signed_records, keypairs);
boolean res = verifySigs(signedRecords, keypairs);
if (res)
{
if (res) {
System.out.println("Generated signatures verified");
// log.info("Generated signatures verified");
}
else
{
} else {
System.out.println("Generated signatures did not verify.");
// log.warn("Generated signatures did not verify.");
}
}
}
public static void main(String[] args)
{
public static void main(String[] args) {
SignRRset tool = new SignRRset();
tool.state = new CLIState();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2001-2003, 2011 VeriSign, Inc.
// Copyright (C) 2001-2003, 2011, 2022 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -22,19 +22,19 @@ import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.xbill.DNS.DNSKEYRecord;
import org.xbill.DNS.DSRecord;
import org.xbill.DNS.DNSSEC;
import org.xbill.DNS.Name;
import org.xbill.DNS.RRset;
import org.xbill.DNS.Record;
@@ -51,182 +51,127 @@ import com.verisignlabs.dnssec.security.ZoneUtils;
/**
* This class forms the command line implementation of a DNSSEC zone signer.
*
*
* @author David Blacka
*/
public class SignZone extends CLBase
{
public class SignZone extends CLBase {
private CLIState state;
/**
* This is an inner class used to hold all of the command line option state.
*/
private static class CLIState extends CLIStateBase
{
public File keyDirectory = null;
public File keysetDirectory = null;
public String[] kskFiles = null;
public String[] keyFiles = null;
public String zonefile = null;
public Date start = null;
public Date expire = null;
public String outputfile = null;
public boolean verifySigs = false;
public boolean useOptOut = false;
public boolean fullySignKeyset = false;
public List<Name> includeNames = null;
public boolean useNsec3 = false;
public byte[] salt = null;
public int iterations = 0;
public int digest_id = DSRecord.SHA1_DIGEST_ID;
public long nsec3paramttl = -1;
public boolean verboseSigning = false;
private static class CLIState extends CLIStateBase {
public File keyDirectory = null;
public File keysetDirectory = null;
public String[] kskFiles = null;
public String[] keyFiles = null;
public String zonefile = null;
public Instant start = null;
public Instant expire = null;
public String outputfile = null;
public boolean verifySigs = false;
public boolean useOptOut = false;
public boolean fullySignKeyset = false;
public List<Name> includeNames = null;
public boolean useNsec3 = false;
public byte[] salt = null;
public int iterations = 0;
public int digestId = DNSSEC.Digest.SHA1;
public long nsec3paramttl = -1;
public boolean verboseSigning = false;
public CLIState()
{
public CLIState() {
super("jdnssec-signzone [..options..] zone_file [key_file ...]");
}
protected void setupOptions(Options opts)
{
@Override
protected void setupOptions(Options opts) {
// boolean options
opts.addOption("a", "verify", false, "verify generated signatures>");
opts.addOption("F", "fully-sign-keyset", false,
"sign the zone apex keyset with all available keys.");
"sign the zone apex keyset with all available keys.");
opts.addOption("V", "verbose-signing", false, "Display verbose signing activity.");
// Argument options
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/NSEC3 chain.");
opts.addOption(OptionBuilder.create('I'));
opts.addOption(Option.builder("d").hasArg().argName("dir").longOpt("keyset-directory")
.desc("directory to find keyset files (default '.')").build());
opts.addOption(Option.builder("D").hasArg().argName("dir").longOpt("key-directory")
.desc("directory to find key files (default '.'").build());
opts.addOption(Option.builder("s").hasArg().argName("time/offset").longOpt("start-time")
.desc("signature starting time (default is now - 1 hour)").build());
opts.addOption(Option.builder("e").hasArg().argName("time/offset").longOpt("expire-time")
.desc("signature expiration time (default is start-time + 30 days)").build());
opts.addOption(
Option.builder("f").hasArg().argName("outfile").desc("file the the signed rrset is written to").build());
opts.addOption(Option.builder("k").hasArgs().argName("KSK file").longOpt("ksk-file")
.desc("This key is a Key-Signing Key (may repeat)").build());
opts.addOption(Option.builder("I").hasArg().argName("file").longOpt("include-file")
.desc("include names in the file in the NSEC/NSEC3 chain").build());
// NSEC3 options
opts.addOption("3", "use-nsec3", false, "use NSEC3 instead of NSEC");
opts.addOption("O", "use-opt-out", false,
"generate a fully Opt-Out zone (only valid with NSEC3).");
"generate a fully Opt-Out zone (only valid with NSEC3).");
opts.addOption(
Option.builder("S").hasArg().argName("hex value").longOpt("salt").desc("Supply a salt value").build());
opts.addOption(Option.builder("R").hasArg().argName("length").longOpt("random-salt")
.desc("Generate a random salt of <length>").build());
opts.addOption(Option.builder("H").hasArg().argName("count").longOpt("iterations")
.desc("Use this many addtional iterations in NSEC3 (default 0)").build());
opts.addOption(Option.builder().hasArg().longOpt("nsec3paramttl").argName("ttl")
.desc("Use this TTL for the NSEC3PARAM record (default is min(soa.min, soa.ttl))").build());
opts.addOption(Option.builder().hasArg().argName("id").longOpt("ds-digest")
.desc("Digest algorithm to use for generated DS records").build());
OptionBuilder.hasArg();
OptionBuilder.withLongOpt("salt");
OptionBuilder.withArgName("hex value");
OptionBuilder.withDescription("supply a salt value.");
opts.addOption(OptionBuilder.create('S'));
OptionBuilder.hasArg();
OptionBuilder.withLongOpt("random-salt");
OptionBuilder.withArgName("length");
OptionBuilder.withDescription("generate a random salt.");
opts.addOption(OptionBuilder.create('R'));
OptionBuilder.hasArg();
OptionBuilder.withLongOpt("iterations");
OptionBuilder.withArgName("value");
OptionBuilder.withDescription("use this value for the iterations in NSEC3.");
opts.addOption(OptionBuilder.create());
OptionBuilder.hasArg();
OptionBuilder.withLongOpt("nsec3paramttl");
OptionBuilder.withArgName("ttl");
OptionBuilder.withDescription("use this value for the NSEC3PARAM RR ttl");
opts.addOption(OptionBuilder.create());
OptionBuilder.hasArg();
OptionBuilder.withArgName("id");
OptionBuilder.withLongOpt("ds-digest");
OptionBuilder.withDescription("Digest algorithm to use for generated DSs");
opts.addOption(OptionBuilder.create());
}
protected void processOptions(CommandLine cli) throws ParseException
{
@Override
protected void processOptions(CommandLine cli) throws ParseException {
String optstr = null;
if (cli.hasOption('a')) verifySigs = true;
if (cli.hasOption('3')) useNsec3 = true;
if (cli.hasOption('O')) useOptOut = true;
if (cli.hasOption('V')) verboseSigning = true;
if (cli.hasOption('a'))
verifySigs = true;
if (cli.hasOption('3'))
useNsec3 = true;
if (cli.hasOption('O'))
useOptOut = true;
if (cli.hasOption('V'))
verboseSigning = true;
if (useOptOut && !useNsec3)
{
if (useOptOut && !useNsec3) {
System.err.println("Opt-Out not supported without NSEC3 -- ignored.");
useOptOut = false;
}
if (cli.hasOption('F')) fullySignKeyset = true;
if (cli.hasOption('F'))
fullySignKeyset = true;
if ((optstr = cli.getOptionValue('d')) != null)
{
if ((optstr = cli.getOptionValue('d')) != null) {
keysetDirectory = new File(optstr);
if (!keysetDirectory.isDirectory())
{
if (!keysetDirectory.isDirectory()) {
System.err.println("error: " + optstr + " is not a directory");
usage();
}
}
if ((optstr = cli.getOptionValue('D')) != null)
{
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();
}
}
if ((optstr = cli.getOptionValue('s')) != null)
{
if ((optstr = cli.getOptionValue('s')) != null) {
start = CLBase.convertDuration(null, optstr);
}
else
{
} else {
// default is now - 1 hour.
start = new Date(System.currentTimeMillis() - (3600 * 1000));
start = Instant.now().minusSeconds(3600);
}
if ((optstr = cli.getOptionValue('e')) != null)
{
if ((optstr = cli.getOptionValue('e')) != null) {
expire = CLBase.convertDuration(start, optstr);
}
else
{
} else {
expire = CLBase.convertDuration(start, "+2592000"); // 30 days
}
@@ -234,102 +179,115 @@ public class SignZone extends CLBase
kskFiles = cli.getOptionValues('k');
if ((optstr = cli.getOptionValue('I')) != null)
{
if ((optstr = cli.getOptionValue('I')) != null) {
File includeNamesFile = new File(optstr);
try
{
includeNames = getNameList(includeNamesFile);
}
catch (IOException e)
{
try {
includeNames = CLIState.getNameList(includeNamesFile);
} catch (IOException e) {
throw new ParseException(e.getMessage());
}
}
if ((optstr = cli.getOptionValue('S')) != null)
{
if ((optstr = cli.getOptionValue('S')) != null) {
salt = base16.fromString(optstr);
if (salt == null && !optstr.equals("-"))
{
if (salt == null && !optstr.equals("-")) {
System.err.println("error: salt is not valid hexidecimal.");
usage();
}
}
if ((optstr = cli.getOptionValue('R')) != null)
{
if ((optstr = cli.getOptionValue('R')) != null) {
int length = parseInt(optstr, 0);
if (length > 0 && length <= 255)
{
if (length > 0 && length <= 255) {
Random random = new Random();
salt = new byte[length];
random.nextBytes(salt);
}
}
if ((optstr = cli.getOptionValue("iterations")) != null)
{
if ((optstr = cli.getOptionValue("iterations")) != null) {
iterations = parseInt(optstr, iterations);
if (iterations < 0 || iterations > 8388607)
{
if (iterations < 0 || iterations > 8388607) {
System.err.println("error: iterations value is invalid");
usage();
}
}
if ((optstr = cli.getOptionValue("ds-digest")) != null)
{
digest_id = parseInt(optstr, -1);
if (digest_id < 0)
{
if ((optstr = cli.getOptionValue("ds-digest")) != null) {
digestId = parseInt(optstr, -1);
if (digestId < 0) {
System.err.println("error: DS digest ID is not a valid identifier");
usage();
}
}
if ((optstr = cli.getOptionValue("nsec3paramttl")) != null)
{
if ((optstr = cli.getOptionValue("nsec3paramttl")) != null) {
nsec3paramttl = parseInt(optstr, -1);
}
String[] files = cli.getArgs();
if (files.length < 1)
{
if (files.length < 1) {
System.err.println("error: missing zone file and/or key files");
usage();
}
zonefile = files[0];
if (files.length > 1)
{
if (files.length > 1) {
keyFiles = new String[files.length - 1];
System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
}
}
/**
* 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<Name> getNameList(File nameListFile) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(nameListFile))) {
List<Name> res = new ArrayList<>();
String line = 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);
} catch (TextParseException e) {
staticLog.severe("DNS Name parsing error:" + e);
}
}
return res;
}
}
}
/**
* Verify the generated signatures.
*
* @param zonename
* the origin name of the zone.
*
* @param records
* a list of {@link org.xbill.DNS.Record}s.
* a list of {@link org.xbill.DNS.Record}s.
* @param keypairs
* a list of keypairs used the sign the zone.
* a list of keypairs used the sign the zone.
* @return true if all of the signatures validated.
*/
private static boolean verifyZoneSigs(Name zonename, List<Record> records,
List<DnsKeyPair> keypairs)
{
private static boolean verifyZoneSigs(List<Record> records,
List<DnsKeyPair> keypairs) {
boolean secure = true;
DnsSecVerifier verifier = new DnsSecVerifier();
for (DnsKeyPair pair : keypairs)
{
for (DnsKeyPair pair : keypairs) {
verifier.addTrustedKey(pair);
}
@@ -337,16 +295,16 @@ public class SignZone extends CLBase
List<RRset> rrsets = SignUtils.assembleIntoRRsets(records);
for (RRset rrset : rrsets)
{
for (RRset rrset : rrsets) {
// skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue;
if (rrset.sigs().isEmpty()) {
continue;
}
boolean result = verifier.verify(rrset);
if (!result)
{
log.fine("Signatures did not verify for RRset: " + rrset);
if (!result) {
staticLog.fine("Signatures did not verify for RRset: " + rrset);
secure = false;
}
}
@@ -356,83 +314,78 @@ public class SignZone extends CLBase
/**
* 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.
* a string array containing the base names or paths of the
* keys to
* be loaded.
* @param startIndex
* 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).
* 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;
private static List<DnsKeyPair> getKeys(String[] keyfiles, int startIndex,
File inDirectory) throws IOException {
if (keyfiles == null)
return Collections.emptyList();
int len = keyfiles.length - start_index;
if (len <= 0) return null;
int len = keyfiles.length - startIndex;
if (len <= 0)
return Collections.emptyList();
ArrayList<DnsKeyPair> keys = new ArrayList<DnsKeyPair>(len);
ArrayList<DnsKeyPair> keys = new ArrayList<>(len);
for (int i = start_index; i < keyfiles.length; i++)
{
for (int i = startIndex; i < keyfiles.length; i++) {
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
if (k != null) keys.add(k);
if (k != null) {
keys.add(k);
}
}
return keys;
}
private static List<DnsKeyPair> getKeys(List<Record> dnskeyrrs, File inDirectory)
throws IOException
{
List<DnsKeyPair> res = new ArrayList<DnsKeyPair>();
for (Record r : dnskeyrrs)
{
if (r.getType() != Type.DNSKEY) continue;
throws IOException {
List<DnsKeyPair> res = new ArrayList<>();
for (Record r : dnskeyrrs) {
if (r.getType() != Type.DNSKEY)
continue;
// Construct a public-key-only DnsKeyPair just so we can calculate the
// base name.
DnsKeyPair pub = new DnsKeyPair((DNSKEYRecord) r);
DnsKeyPair pair = BINDKeyUtils.loadKeyPair(BINDKeyUtils.keyFileBase(pub),
inDirectory);
if (pair != null)
{
inDirectory);
if (pair != null) {
res.add(pair);
}
}
if (res.size() > 0) return res;
return null;
return res;
}
private static class KeyFileFilter implements FileFilter
{
private static class KeyFileFilter implements FileFilter {
private String prefix;
public KeyFileFilter(Name origin)
{
public KeyFileFilter(Name origin) {
prefix = "K" + origin.toString();
}
public boolean accept(File pathname)
{
if (!pathname.isFile()) return false;
public boolean accept(File pathname) {
if (!pathname.isFile())
return false;
String name = pathname.getName();
if (name.startsWith(prefix) && name.endsWith(".private")) return true;
return false;
return (name.startsWith(prefix) && name.endsWith(".private"));
}
}
private static List<DnsKeyPair> findZoneKeys(File inDirectory, Name zonename)
throws IOException
{
if (inDirectory == null)
{
throws IOException {
if (inDirectory == null) {
inDirectory = new File(".");
}
@@ -441,51 +394,48 @@ public class SignZone extends CLBase
File[] files = inDirectory.listFiles(filter);
// read in all of the records
ArrayList<DnsKeyPair> keys = new ArrayList<DnsKeyPair>();
for (int i = 0; i < files.length; i++)
{
ArrayList<DnsKeyPair> keys = new ArrayList<>();
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;
return null;
return keys;
}
/**
* 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;
private static class KeysetFileFilter implements FileFilter {
public boolean accept(File pathname) {
if (!pathname.isFile())
return false;
String name = pathname.getName();
if (name.startsWith("keyset-")) return true;
return false;
return (name.startsWith("keyset-"));
}
}
/**
* 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).
* 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.
* 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<Record> getKeysets(File inDirectory, Name zonename)
throws IOException
{
if (inDirectory == null)
{
throws IOException {
if (inDirectory == null) {
inDirectory = new File(".");
}
@@ -494,19 +444,16 @@ public class SignZone extends CLBase
File[] files = inDirectory.listFiles(filter);
// read in all of the records
ArrayList<Record> keysetRecords = new ArrayList<Record>();
for (int i = 0; i < files.length; i++)
{
ArrayList<Record> keysetRecords = new ArrayList<>();
for (int i = 0; i < files.length; i++) {
List<Record> l = ZoneUtils.readZoneFile(files[i].getAbsolutePath(), zonename);
keysetRecords.addAll(l);
}
// discard records that do not belong to the zone in question.
for (Iterator<Record> i = keysetRecords.iterator(); i.hasNext();)
{
for (Iterator<Record> i = keysetRecords.iterator(); i.hasNext();) {
Record r = i.next();
if (!r.getName().subdomain(zonename))
{
if (!r.getName().subdomain(zonename)) {
i.remove();
}
}
@@ -514,63 +461,25 @@ public class SignZone extends CLBase
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.
*/
private static List<Name> getNameList(File nameListFile) throws IOException
{
BufferedReader br = new BufferedReader(new FileReader(nameListFile));
List<Name> res = new ArrayList<Name>();
String line = 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);
}
catch (TextParseException e)
{
log.severe("DNS Name parsing error:" + e);
}
}
br.close();
if (res.size() == 0) return null;
return res;
}
/**
* Determine if the given keypairs can be used to sign the zone.
*
*
* @param zonename
* the zone origin.
* the zone origin.
* @param keypairs
* a list of {@link DnsKeyPair} objects that will be used to sign
* the
* zone.
* 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<DnsKeyPair> keypairs)
{
if (keypairs == null) return true; // technically true, I guess.
private static boolean keyPairsValidForZone(Name zonename, List<DnsKeyPair> keypairs) {
if (keypairs == null)
return true; // technically true, I guess.
for (DnsKeyPair kp : keypairs)
{
for (DnsKeyPair kp : keypairs) {
Name keyname = kp.getDNSKEYRecord().getName();
if (!keyname.equals(zonename))
{
if (!keyname.equals(zonename)) {
return false;
}
}
@@ -578,22 +487,21 @@ public class SignZone extends CLBase
return true;
}
public void execute() throws Exception
{
public void execute() throws Exception {
// Read in the zone
List<Record> records = ZoneUtils.readZoneFile(state.zonefile, null);
if (records == null || records.size() == 0)
{
if (records == null || records.isEmpty()) {
System.err.println("error: empty zone file");
state.usage();
return;
}
// calculate the zone name.
Name zonename = ZoneUtils.findZoneName(records);
if (zonename == null)
{
if (zonename == null) {
System.err.println("error: invalid zone file - no SOA");
state.usage();
return;
}
// Load the key pairs.
@@ -603,16 +511,14 @@ public class SignZone extends CLBase
// If we didn't get any keys on the command line, look at the zone apex for
// any public keys.
if (keypairs == null && kskpairs == null)
{
if (keypairs == null && kskpairs == null) {
List<Record> dnskeys = ZoneUtils.findRRs(records, zonename, Type.DNSKEY);
keypairs = getKeys(dnskeys, state.keyDirectory);
}
// If we *still* don't have any key pairs, look for keys the key directory
// that match
if (keypairs == null && kskpairs == null)
{
if (keypairs == null && kskpairs == null) {
keypairs = findZoneKeys(state.keyDirectory, zonename);
}
@@ -620,16 +526,14 @@ public class SignZone extends CLBase
// 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)
{
for (Iterator<DnsKeyPair> i = keypairs.iterator(); i.hasNext();)
{
if ((kskpairs == null || kskpairs.isEmpty()) && keypairs != null
&& keypairs.size() > 1) {
for (Iterator<DnsKeyPair> i = keypairs.iterator(); i.hasNext();) {
DnsKeyPair pair = i.next();
DNSKEYRecord kr = pair.getDNSKEYRecord();
if ((kr.getFlags() & DNSKEYRecord.Flags.SEP_KEY) != 0)
{
if (kskpairs == null) kskpairs = new ArrayList<DnsKeyPair>();
if ((kr.getFlags() & DNSKEYRecord.Flags.SEP_KEY) != 0) {
if (kskpairs == null)
kskpairs = new ArrayList<>();
kskpairs.add(pair);
i.remove();
}
@@ -638,35 +542,29 @@ public class SignZone extends CLBase
// If there are no ZSKs defined at this point (yet there are KSKs
// provided), all KSKs will be treated as ZSKs, as well.
if (keypairs == null || keypairs.size() == 0)
{
if (keypairs == null || keypairs.isEmpty()) {
keypairs = kskpairs;
}
// If there *still* aren't any ZSKs defined, bail.
if (keypairs == null || keypairs.size() == 0)
{
if (keypairs == null || keypairs.isEmpty()) {
System.err.println("No zone signing keys could be determined.");
state.usage();
return;
}
// default the output file, if not set.
if (state.outputfile == null && !state.zonefile.equals("-"))
{
if (zonename.isAbsolute())
{
if (state.outputfile == null && !state.zonefile.equals("-")) {
if (zonename.isAbsolute()) {
state.outputfile = zonename + "signed";
}
else
{
} else {
state.outputfile = zonename + ".signed";
}
}
// Verify that the keys can be in the zone.
if (!keyPairsValidForZone(zonename, keypairs)
|| !keyPairsValidForZone(zonename, kskpairs))
{
|| !keyPairsValidForZone(zonename, kskpairs)) {
System.err.println("error: specified keypairs are not valid for the zone.");
state.usage();
}
@@ -674,79 +572,63 @@ public class SignZone extends CLBase
// We force the signing keys to be in the zone by just appending
// them to the zone here. Currently JCEDnsSecSigner.signZone
// removes duplicate records.
if (kskpairs != null)
{
for (DnsKeyPair pair : kskpairs)
{
if (kskpairs != null) {
for (DnsKeyPair pair : kskpairs) {
records.add(pair.getDNSKEYRecord());
}
}
if (keypairs != null)
{
for (DnsKeyPair pair : keypairs)
{
if (keypairs != null) {
for (DnsKeyPair pair : keypairs) {
records.add(pair.getDNSKEYRecord());
}
}
// read in the keysets, if any.
List<Record> keysetrecs = getKeysets(state.keysetDirectory, zonename);
if (keysetrecs != null)
{
if (keysetrecs != null) {
records.addAll(keysetrecs);
}
JCEDnsSecSigner signer = new JCEDnsSecSigner(state.verboseSigning);
// Sign the zone.
List<Record> signed_records;
List<Record> signedRecords;
if (state.useNsec3)
{
signed_records = signer.signZoneNSEC3(zonename, records, kskpairs, keypairs,
state.start, state.expire,
state.fullySignKeyset, state.useOptOut,
state.includeNames, state.salt,
state.iterations, state.digest_id,
state.nsec3paramttl);
}
else
{
signed_records = signer.signZone(zonename, records, kskpairs, keypairs,
state.start, state.expire, state.fullySignKeyset,
state.digest_id);
if (state.useNsec3) {
signedRecords = signer.signZoneNSEC3(zonename, records, kskpairs, keypairs,
state.start, state.expire,
state.fullySignKeyset, state.useOptOut,
state.includeNames, state.salt,
state.iterations, state.digestId,
state.nsec3paramttl);
} else {
signedRecords = signer.signZone(zonename, records, kskpairs, keypairs,
state.start, state.expire, state.fullySignKeyset,
state.digestId);
}
// write out the signed zone
ZoneUtils.writeZoneFile(signed_records, state.outputfile);
ZoneUtils.writeZoneFile(signedRecords, state.outputfile);
if (state.verifySigs)
{
if (state.verifySigs) {
// FIXME: ugh.
if (kskpairs != null)
{
if (kskpairs != null) {
keypairs.addAll(kskpairs);
}
log.fine("verifying generated signatures");
boolean res = verifyZoneSigs(zonename, signed_records, keypairs);
boolean res = verifyZoneSigs(signedRecords, keypairs);
if (res)
{
if (res) {
System.out.println("Generated signatures verified");
// log.info("Generated signatures verified");
}
else
{
} else {
System.out.println("Generated signatures did not verify.");
// log.warn("Generated signatures did not verify.");
}
}
}
public static void main(String[] args)
{
public static void main(String[] args) {
SignZone tool = new SignZone();
tool.state = new CLIState();

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2011 VeriSign, Inc.
// Copyright (C) 2011, 2022 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -20,8 +20,8 @@ package com.verisignlabs.dnssec.cl;
import java.util.List;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.Option;
import org.xbill.DNS.Record;
import com.verisignlabs.dnssec.security.ZoneUtils;
@@ -32,106 +32,80 @@ import com.verisignlabs.dnssec.security.ZoneVerifier;
*
* @author David Blacka
*/
public class VerifyZone extends CLBase
{
public class VerifyZone extends CLBase {
private CLIState state;
/**
* This is a small inner class used to hold all of the command line option
* state.
*/
protected static class CLIState extends CLIStateBase
{
public String zonefile = null;
public String[] keyfiles = null;
public int startfudge = 0;
public int expirefudge = 0;
public boolean ignoreTime = false;
public boolean ignoreDups = false;
protected static class CLIState extends CLIStateBase {
public String zonefile = null;
public String[] keyfiles = null;
public int startfudge = 0;
public int expirefudge = 0;
public boolean ignoreTime = false;
public boolean ignoreDups = false;
public CLIState()
{
public CLIState() {
super("jdnssec-verifyzone [..options..] zonefile");
}
protected void setupOptions(Options opts)
{
OptionBuilder.hasOptionalArg();
OptionBuilder.withLongOpt("sig-start-fudge");
OptionBuilder.withArgName("seconds");
OptionBuilder.withDescription("'fudge' RRSIG inception times by 'seconds' seconds.");
opts.addOption(OptionBuilder.create('S'));
OptionBuilder.hasOptionalArg();
OptionBuilder.withLongOpt("sig-expire-fudge");
OptionBuilder.withArgName("seconds");
OptionBuilder.withDescription("'fudge' RRSIG expiration times by 'seconds' seconds.");
opts.addOption(OptionBuilder.create('E'));
OptionBuilder.withLongOpt("ignore-time");
OptionBuilder.withDescription("Ignore RRSIG inception and expiration time errors.");
opts.addOption(OptionBuilder.create());
OptionBuilder.withLongOpt("ignore-duplicate-rrs");
OptionBuilder.withDescription("Ignore duplicate record errors.");
opts.addOption(OptionBuilder.create());
@Override
protected void setupOptions(Options opts) {
opts.addOption(Option.builder("S").optionalArg(true).argName("seconds").longOpt("sig-start-fudge")
.desc("'fudge' RRSIG inception ties by 'seconds'").build());
opts.addOption(Option.builder("E").optionalArg(true).argName("seconds").longOpt("sig-expire-fudge")
.desc("'fudge' RRSIG expiration times by 'seconds'").build());
opts.addOption(
Option.builder().longOpt("ignore-time").desc("Ignore RRSIG inception and expiration time errors.").build());
opts.addOption(Option.builder().longOpt("ignore-duplicate-rrs").desc("Ignore duplicate record errors.").build());
}
protected void processOptions(CommandLine cli)
{
if (cli.hasOption("ignore-time"))
{
@Override
protected void processOptions(CommandLine cli) {
if (cli.hasOption("ignore-time")) {
ignoreTime = true;
}
if (cli.hasOption("ignore-duplicate-rrs"))
{
if (cli.hasOption("ignore-duplicate-rrs")) {
ignoreDups = true;
}
String optstr = null;
if ((optstr = cli.getOptionValue('S')) != null)
{
if ((optstr = cli.getOptionValue('S')) != null) {
startfudge = parseInt(optstr, 0);
}
if ((optstr = cli.getOptionValue('E')) != null)
{
if ((optstr = cli.getOptionValue('E')) != null) {
expirefudge = parseInt(optstr, 0);
}
String[] optstrs = null;
if ((optstrs = cli.getOptionValues('A')) != null)
{
for (int i = 0; i < optstrs.length; i++)
{
if ((optstrs = cli.getOptionValues('A')) != null) {
for (int i = 0; i < optstrs.length; i++) {
addArgAlias(optstrs[i]);
}
}
String[] cl_args = cli.getArgs();
String[] args = cli.getArgs();
if (cl_args.length < 1)
{
if (args.length < 1) {
System.err.println("error: missing zone file");
usage();
}
zonefile = cl_args[0];
zonefile = args[0];
if (cl_args.length >= 2)
{
keyfiles = new String[cl_args.length - 1];
System.arraycopy(cl_args, 1, keyfiles, 0, keyfiles.length);
if (args.length >= 2) {
keyfiles = new String[args.length - 1];
System.arraycopy(args, 1, keyfiles, 0, keyfiles.length);
}
}
}
public void execute() throws Exception
{
public void execute() throws Exception {
ZoneVerifier zoneverifier = new ZoneVerifier();
zoneverifier.getVerifier().setStartFudge(state.startfudge);
zoneverifier.getVerifier().setExpireFudge(state.expirefudge);
@@ -144,23 +118,19 @@ public class VerifyZone extends CLBase
int errors = zoneverifier.verifyZone(records);
log.fine("completed verification process.");
if (errors > 0)
{
if (errors > 0) {
System.out.println("zone did not verify.");
System.exit(1);
}
else
{
} else {
System.out.println("zone verified.");
System.exit(0);
}
}
public static void main(String[] args)
{
public static void main(String[] args) {
VerifyZone tool = new VerifyZone();
tool.state = new CLIState();
tool.run(tool.state, args);
}
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2011 VeriSign, Inc.
// Copyright (C) 2011, 2022 VeriSign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
@@ -43,168 +42,150 @@ import com.verisignlabs.dnssec.security.RecordComparator;
* This class forms the command line implementation of a zone file normalizer.
* That is, a tool to rewrite zones in a consistent, comparable format.
*
* @author David Blacka (original)
* @author $Author: davidb $
* @version $Revision: 2218 $
* @author David Blacka
*/
public class ZoneFormat extends CLBase
{
public class ZoneFormat extends CLBase {
private CLIState state;
/**
* This is a small inner class used to hold all of the command line option
* state.
*/
protected static class CLIState extends CLIStateBase
{
public String file;
protected static class CLIState extends CLIStateBase {
public String file;
public boolean assignNSEC3;
public CLIState()
{
public CLIState() {
super("jdnssec-zoneformat [..options..] zonefile");
}
protected void setupOptions(Options opts)
{
@Override
protected void setupOptions(Options opts) {
opts.addOption("N", "nsec3", false,
"attempt to determine the original ownernames for NSEC3 RRs.");
"attempt to determine the original ownernames for NSEC3 RRs.");
}
protected void processOptions(CommandLine cli) throws ParseException
{
if (cli.hasOption('N')) assignNSEC3 = true;
@Override
protected void processOptions(CommandLine cli) throws ParseException {
if (cli.hasOption('N'))
assignNSEC3 = true;
String[] cl_args = cli.getArgs();
String[] args = cli.getArgs();
if (cl_args.length < 1)
{
if (args.length < 1) {
System.err.println("error: must specify a zone file");
usage();
}
file = cl_args[0];
file = args[0];
}
}
private static List<Record> readZoneFile(String filename) throws IOException
{
Master master = new Master(filename);
private static List<Record> readZoneFile(String filename) throws IOException {
try (Master master = new Master(filename)) {
List<Record> res = new ArrayList<>();
Record r = null;
List<Record> res = new ArrayList<Record>();
Record r = null;
while ((r = master.nextRecord()) != null) {
// Normalize each record by round-tripping it through canonical wire line
// format. Mostly this just lowercases names that are subject to it.
byte[] wire = r.toWireCanonical();
Record canonRec = Record.fromWire(wire, Section.ANSWER);
res.add(canonRec);
}
while ((r = master.nextRecord()) != null)
{
// Normalize each record by round-tripping it through canonical wire line
// format. Mostly this just lowercases names that are subject to it.
byte[] wire = r.toWireCanonical();
Record canon_record = Record.fromWire(wire, Section.ANSWER);
res.add(canon_record);
return res;
}
return res;
}
private static void formatZone(List<Record> zone)
{
// Put the zone into a consistent (name and RR type) order.
RecordComparator cmp = new RecordComparator();
private static void formatZone(List<Record> zone) {
Collections.sort(zone, cmp);
for (Record r : zone)
{
for (Record r : zone) {
System.out.println(r.toString());
}
}
private static void determineNSEC3Owners(List<Record> zone)
throws NoSuchAlgorithmException
{
// Put the zone into a consistent (name and RR type) order.
Collections.sort(zone, new RecordComparator());
throws NoSuchAlgorithmException {
// first, find the NSEC3PARAM record -- this is an inefficient linear
// search, although it should be near the head of the list.
NSEC3PARAMRecord nsec3param = null;
HashMap<String, String> map = new HashMap<String, String>();
HashMap<String, String> map = new HashMap<>();
base32 b32 = new base32(base32.Alphabet.BASE32HEX, false, true);
Name zonename = null;
for (Record r : zone)
{
if (r.getType() == Type.SOA)
{
for (Record r : zone) {
if (r.getType() == Type.SOA) {
zonename = r.getName();
continue;
}
if (r.getType() == Type.NSEC3PARAM)
{
if (r.getType() == Type.NSEC3PARAM) {
nsec3param = (NSEC3PARAMRecord) r;
break;
}
}
// If we couldn't determine a zone name, we have an issue.
if (zonename == null) return;
// If there wasn't one, we have nothing to do.
if (nsec3param == null) return;
if (zonename == null || nsec3param == null) {
formatZone(zone);
return;
}
// Next pass, calculate a mapping between ownernames and hashnames
Name last_name = null;
for (Record r : zone)
{
if (r.getName().equals(last_name)) continue;
if (r.getType() == Type.NSEC3) continue;
Name lastName = null;
for (Record r : zone) {
if (r.getName().equals(lastName))
continue;
if (r.getType() == Type.NSEC3)
continue;
Name n = r.getName();
byte[] hash = nsec3param.hashName(n);
String hashname = b32.toString(hash);
map.put(hashname, n.toString().toLowerCase());
last_name = n;
lastName = n;
// inefficiently create hashes for the possible ancestor ENTs
for (int i = zonename.labels() + 1; i < n.labels(); ++i)
{
for (int i = zonename.labels() + 1; i < n.labels(); ++i) {
Name parent = new Name(n, n.labels() - i);
byte[] parent_hash = nsec3param.hashName(parent);
String parent_hashname = b32.toString(parent_hash);
if (!map.containsKey(parent_hashname))
{
map.put(parent_hashname, parent.toString().toLowerCase());
byte[] parentHash = nsec3param.hashName(parent);
String parentHashName = b32.toString(parentHash);
if (!map.containsKey(parentHashName)) {
map.put(parentHashName, parent.toString().toLowerCase());
}
}
}
// Final pass, assign the names if we can
for (ListIterator<Record> i = zone.listIterator(); i.hasNext();)
{
Record r = i.next();
if (r.getType() != Type.NSEC3) continue;
// Final pass, output the zone with added comments for the NSEC3 records
for (Record r : zone) {
if (r.getType() != Type.NSEC3) {
System.out.println(r.toString());
continue;
}
NSEC3Record nsec3 = (NSEC3Record) r;
String hashname = nsec3.getName().getLabelString(0).toLowerCase();
String ownername = (String) map.get(hashname);
NSEC3Record new_nsec3 = new NSEC3Record(nsec3.getName(), nsec3.getDClass(),
nsec3.getTTL(), nsec3.getHashAlgorithm(),
nsec3.getFlags(), nsec3.getIterations(),
nsec3.getSalt(), nsec3.getNext(),
nsec3.getTypes(), ownername);
i.set(new_nsec3);
String ownername = map.get(hashname);
System.out.println(r.toString() + " ; " + ownername);
}
}
public void execute() throws IOException, NoSuchAlgorithmException
{
public void execute() throws IOException, NoSuchAlgorithmException {
List<Record> z = readZoneFile(state.file);
if (state.assignNSEC3) determineNSEC3Owners(z);
formatZone(z);
// Put the zone into a consistent (name and RR type) order.
Collections.sort(z, new RecordComparator());
if (state.assignNSEC3) {
determineNSEC3Owners(z);
} else {
formatZone(z);
}
}
public static void main(String[] args)
{
public static void main(String[] args) {
ZoneFormat tool = new ZoneFormat();
tool.state = new CLIState();