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:
David Blacka 2022-09-21 14:24:42 -04:00 committed by GitHub
parent ce1189703f
commit e322186112
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 2627 additions and 3332 deletions

6
.gitattributes vendored Normal file
View File

@ -0,0 +1,6 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
build
bin/main
.classpath
.project
.gradle
@ -6,4 +7,4 @@ jdnssec-tools*.tar.gz
docs
test-zones
settings.json
.settings
.settings

15
README.TODO.md Normal file
View File

@ -0,0 +1,15 @@
# jdnssec-tools TODO List
This bit of code has been around since approximately 2005, and has been in "minimal maintenance" mode for much of that time. But that doesn't mean there aren't features that we *want* to do, if we could arrange time and attention. Here is a partial list:
* More feature parity with the current BIND 9 tools
* Support the "v1.3" private key format. This basically means supporting the timing parameters that BiND 9 added.
* Have `jdnssec-signzone` support incremental signing, including key rollovers
* Rewrite `jdnssec-signzone` to use a "TreeMap" and arrange the data into a map of RRsets, rather than a sorted list of Record objects. This wouldn't be more efficient, but might be easier to understand.
* Allow `jdnssec-signzone` to scale by either:
* Allowing for pre-sorted zone data, and/or
* allowing for an external sort once the data is shown to be larger than X, and/or
* allowing for a memory-constrained internal sort that uses disk, and/or,
* figuring out how to let the JVM use *a lot* of memory.
* Add support for algorithm 16, perhaps refactor algorithm 15 support using bouncycastle.
* Note that our current dnsjava version, 3.5.1 has some support, although it isn't clear if it has sign/verify support.

View File

@ -1,12 +1,12 @@
# jdnssec-tools
* https://github.com/dblacka/jdnssec-tools/wiki
* <https://github.com/dblacka/jdnssec-tools/wiki>
Author: David Blacka (davidb@verisign.com)
This is a collection of DNSSEC tools written in Java. They are intended to be an addition or replacement for the DNSSEC tools that are part of BIND 9.
These tools depend upon DNSjava (https://github.com/dnsjava/dnsjava), the Jakarta Commons CLI and Logging libraries (https://commons.apache.org/proper/commons-cli), and Sun's Java Cryptography extensions. A copy of each of these libraries is included in the distribution. Currently, these tools use a custom version of the DNSjava library with minor modifications, which is provided.
These tools depend upon DNSjava (<https://github.com/dnsjava/dnsjava>), the Jakarta Commons CLI and Logging libraries (<https://commons.apache.org/proper/commons-cli>), slf4j (<https://www.slf4j.org>), and Sun's Java Cryptography extensions. A copy of each of these libraries is included in the distribution.
See the "licenses" directory for the licensing information of this package and the other packages that are distributed with it.
@ -21,7 +21,6 @@ Getting started:
cd java-dnssec-tools-x.x.x
./bin/jdnssec-signzone -h
Building from source:
1. Unpack the source distribution, preferably into the same directory that the binary distribution was unpacked.
@ -29,7 +28,7 @@ Building from source:
tar zxvf java-dnssec-tools-x.x.x-src.tar.gz
2. Edit the build.properties file to suit your environment.
3. Run Ant (see http://ant.apache.org for information about the Ant build tool).
3. Run Ant (see <http://ant.apache.org> for information about the Ant build tool).
ant
@ -42,9 +41,7 @@ Building from source:
The resulting jar file gets generated in build/libs.
The source for this project is available in git on github: https://github.com/dblacka/jdnssec-tools
Source for the modified DNSjava library can be found on github as well: https://github.com/dblacka/jdnssec-dnsjava
The source for this project is available in git on github: <https://github.com/dblacka/jdnssec-tools>
---

View File

@ -1 +1 @@
version=0.16.1
version=0.17

View File

@ -10,15 +10,15 @@ apply plugin: 'idea'
jar {
baseName = 'jdnssec-tools'
version = '0.16'
version = '0.17'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.7
targetCompatibility = 1.7
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile fileTree(dir: 'lib', include: '*.jar')

View File

@ -47,8 +47,8 @@
deprecation="true"
includeantruntime="false"
includes="com/verisignlabs/dnssec/"
source="1.7"
target="1.7" />
source="8"
target="8" />
</target>
<target name="sectools-jar" depends="usage,sectools">

Binary file not shown.

BIN
lib/commons-cli-1.5.0.jar Normal file

Binary file not shown.

Binary file not shown.

BIN
lib/dnsjava-3.5.1.jar Normal file

Binary file not shown.

BIN
lib/slf4j-api-1.7.36.jar Normal file

Binary file not shown.

BIN
lib/slf4j-simple-1.7.36.jar Normal file

Binary file not shown.

View File

@ -0,0 +1,21 @@
Copyright (c) 2004-2017 QOS.ch
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

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() {