diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..00a51af --- /dev/null +++ b/.gitattributes @@ -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 + diff --git a/.gitignore b/.gitignore index 74a743a..463da61 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build +bin/main .classpath .project .gradle @@ -6,4 +7,4 @@ jdnssec-tools*.tar.gz docs test-zones settings.json -.settings \ No newline at end of file +.settings diff --git a/README.TODO.md b/README.TODO.md new file mode 100644 index 0000000..e78ec7c --- /dev/null +++ b/README.TODO.md @@ -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. diff --git a/README.md b/README.md index 7b812a4..d4ceb96 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # jdnssec-tools -* 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 (), the Jakarta Commons CLI and Logging libraries (), slf4j (), 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 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: --- diff --git a/VERSION b/VERSION index 3e88108..a12c194 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -version=0.16.1 +version=0.17 diff --git a/build.gradle b/build.gradle index 34de45e..6c2351c 100644 --- a/build.gradle +++ b/build.gradle @@ -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') diff --git a/build.xml b/build.xml index 3e38ac9..7e30180 100644 --- a/build.xml +++ b/build.xml @@ -47,8 +47,8 @@ deprecation="true" includeantruntime="false" includes="com/verisignlabs/dnssec/" - source="1.7" - target="1.7" /> + source="8" + target="8" /> diff --git a/lib/commons-cli-1.2.jar b/lib/commons-cli-1.2.jar deleted file mode 100644 index ce4b9ff..0000000 Binary files a/lib/commons-cli-1.2.jar and /dev/null differ diff --git a/lib/commons-cli-1.5.0.jar b/lib/commons-cli-1.5.0.jar new file mode 100644 index 0000000..e036456 Binary files /dev/null and b/lib/commons-cli-1.5.0.jar differ diff --git a/lib/dnsjava-2.1.9-vrsn-1.jar b/lib/dnsjava-2.1.9-vrsn-1.jar deleted file mode 100644 index 3cbf6fb..0000000 Binary files a/lib/dnsjava-2.1.9-vrsn-1.jar and /dev/null differ diff --git a/lib/dnsjava-3.5.1.jar b/lib/dnsjava-3.5.1.jar new file mode 100644 index 0000000..6333f86 Binary files /dev/null and b/lib/dnsjava-3.5.1.jar differ diff --git a/lib/slf4j-api-1.7.36.jar b/lib/slf4j-api-1.7.36.jar new file mode 100644 index 0000000..7d3ce68 Binary files /dev/null and b/lib/slf4j-api-1.7.36.jar differ diff --git a/lib/slf4j-simple-1.7.36.jar b/lib/slf4j-simple-1.7.36.jar new file mode 100644 index 0000000..ef831a8 Binary files /dev/null and b/lib/slf4j-simple-1.7.36.jar differ diff --git a/licenses/slf4j-LICENSE.txt b/licenses/slf4j-LICENSE.txt new file mode 100644 index 0000000..c8e72c2 --- /dev/null +++ b/licenses/slf4j-LICENSE.txt @@ -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. diff --git a/src/main/java/com/verisignlabs/dnssec/cl/CLBase.java b/src/main/java/com/verisignlabs/dnssec/cl/CLBase.java index 765c2ff..03ff1c0 100644 --- a/src/main/java/com/verisignlabs/dnssec/cl/CLBase.java +++ b/src/main/java/com/verisignlabs/dnssec/cl/CLBase.java @@ -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); } diff --git a/src/main/java/com/verisignlabs/dnssec/cl/DSTool.java b/src/main/java/com/verisignlabs/dnssec/cl/DSTool.java index 444af8e..3054555 100644 --- a/src/main/java/com/verisignlabs/dnssec/cl/DSTool.java +++ b/src/main/java/com/verisignlabs/dnssec/cl/DSTool.java @@ -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(); diff --git a/src/main/java/com/verisignlabs/dnssec/cl/KeyGen.java b/src/main/java/com/verisignlabs/dnssec/cl/KeyGen.java index 25e6e0e..eed0dd4 100644 --- a/src/main/java/com/verisignlabs/dnssec/cl/KeyGen.java +++ b/src/main/java/com/verisignlabs/dnssec/cl/KeyGen.java @@ -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(); diff --git a/src/main/java/com/verisignlabs/dnssec/cl/KeyInfoTool.java b/src/main/java/com/verisignlabs/dnssec/cl/KeyInfoTool.java index 3eead2a..25df385 100644 --- a/src/main/java/com/verisignlabs/dnssec/cl/KeyInfoTool.java +++ b/src/main/java/com/verisignlabs/dnssec/cl/KeyInfoTool.java @@ -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(); diff --git a/src/main/java/com/verisignlabs/dnssec/cl/SignKeyset.java b/src/main/java/com/verisignlabs/dnssec/cl/SignKeyset.java index bdc395d..fdc2f4f 100644 --- a/src/main/java/com/verisignlabs/dnssec/cl/SignKeyset.java +++ b/src/main/java/com/verisignlabs/dnssec/cl/SignKeyset.java @@ -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 records, - List keypairs) - { + private static boolean verifySigs(List records, + List 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 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 getKeys(String[] keyfiles, int start_index, - File inDirectory) throws IOException - { - if (keyfiles == null) return null; + private static List 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 keys = new ArrayList(len); + ArrayList 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 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 keys = new ArrayList(); - for (int i = 0; i < files.length; i++) - { + ArrayList 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 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 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 signed_records = new ArrayList(); - for (Iterator i = keyset.rrs(); i.hasNext();) - { - signed_records.add(i.next()); + List signedRecords = new ArrayList<>(); + for (Record r : keyset.rrs()) { + signedRecords.add(r); } - for (Iterator 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(); diff --git a/src/main/java/com/verisignlabs/dnssec/cl/SignRRset.java b/src/main/java/com/verisignlabs/dnssec/cl/SignRRset.java index 23d4938..69cefd6 100644 --- a/src/main/java/com/verisignlabs/dnssec/cl/SignRRset.java +++ b/src/main/java/com/verisignlabs/dnssec/cl/SignRRset.java @@ -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 records, List keypairs) - { + private static boolean verifySigs(List records, List 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 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 getKeys(String[] keyfiles, int start_index, - File inDirectory) throws IOException - { - if (keyfiles == null) return null; + private static List 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 keys = new ArrayList(len); + ArrayList 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 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 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 signed_records = new ArrayList(); - for (Iterator i = rrset.rrs(); i.hasNext();) - { - signed_records.add(i.next()); + List signedRecords = new ArrayList<>(); + for (Record r : rrset.rrs()) { + signedRecords.add(r); } - for (Iterator 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(); diff --git a/src/main/java/com/verisignlabs/dnssec/cl/SignZone.java b/src/main/java/com/verisignlabs/dnssec/cl/SignZone.java index a08df40..293446c 100644 --- a/src/main/java/com/verisignlabs/dnssec/cl/SignZone.java +++ b/src/main/java/com/verisignlabs/dnssec/cl/SignZone.java @@ -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 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 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 .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 ").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 getNameList(File nameListFile) throws IOException { + try (BufferedReader br = new BufferedReader(new FileReader(nameListFile))) { + List 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 records, - List keypairs) - { + private static boolean verifyZoneSigs(List records, + List 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 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 getKeys(String[] keyfiles, int start_index, - File inDirectory) throws IOException - { - if (keyfiles == null) return null; + private static List 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 keys = new ArrayList(len); + ArrayList 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 getKeys(List dnskeyrrs, File inDirectory) - throws IOException - { - List res = new ArrayList(); - for (Record r : dnskeyrrs) - { - if (r.getType() != Type.DNSKEY) continue; + throws IOException { + List 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 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 keys = new ArrayList(); - for (int i = 0; i < files.length; i++) - { + ArrayList 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 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 keysetRecords = new ArrayList(); - for (int i = 0; i < files.length; i++) - { + ArrayList keysetRecords = new ArrayList<>(); + for (int i = 0; i < files.length; i++) { List l = ZoneUtils.readZoneFile(files[i].getAbsolutePath(), zonename); keysetRecords.addAll(l); } // discard records that do not belong to the zone in question. - for (Iterator i = keysetRecords.iterator(); i.hasNext();) - { + for (Iterator i = keysetRecords.iterator(); i.hasNext();) { Record r = 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 getNameList(File nameListFile) throws IOException - { - BufferedReader br = new BufferedReader(new FileReader(nameListFile)); - List 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) - { - 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 keypairs) - { - if (keypairs == null) return true; // technically true, I guess. + private static boolean keyPairsValidForZone(Name zonename, List 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 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 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 i = keypairs.iterator(); i.hasNext();) - { + if ((kskpairs == null || kskpairs.isEmpty()) && keypairs != null + && keypairs.size() > 1) { + for (Iterator 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(); + 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 keysetrecs = getKeysets(state.keysetDirectory, zonename); - if (keysetrecs != null) - { + if (keysetrecs != null) { records.addAll(keysetrecs); } JCEDnsSecSigner signer = new JCEDnsSecSigner(state.verboseSigning); // Sign the zone. - List signed_records; + List 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(); diff --git a/src/main/java/com/verisignlabs/dnssec/cl/VerifyZone.java b/src/main/java/com/verisignlabs/dnssec/cl/VerifyZone.java index 01394a1..40ece56 100644 --- a/src/main/java/com/verisignlabs/dnssec/cl/VerifyZone.java +++ b/src/main/java/com/verisignlabs/dnssec/cl/VerifyZone.java @@ -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); } } diff --git a/src/main/java/com/verisignlabs/dnssec/cl/ZoneFormat.java b/src/main/java/com/verisignlabs/dnssec/cl/ZoneFormat.java index 887df26..96ff79e 100644 --- a/src/main/java/com/verisignlabs/dnssec/cl/ZoneFormat.java +++ b/src/main/java/com/verisignlabs/dnssec/cl/ZoneFormat.java @@ -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 readZoneFile(String filename) throws IOException - { - Master master = new Master(filename); + private static List readZoneFile(String filename) throws IOException { + try (Master master = new Master(filename)) { + List res = new ArrayList<>(); + Record r = null; - List res = new ArrayList(); - 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 zone) - { - // Put the zone into a consistent (name and RR type) order. - RecordComparator cmp = new RecordComparator(); + private static void formatZone(List zone) { - Collections.sort(zone, cmp); - for (Record r : zone) - { + for (Record r : zone) { System.out.println(r.toString()); } } private static void determineNSEC3Owners(List 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 map = new HashMap(); + HashMap 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 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 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(); diff --git a/src/main/java/com/verisignlabs/dnssec/security/BINDKeyUtils.java b/src/main/java/com/verisignlabs/dnssec/security/BINDKeyUtils.java index 2551ba6..450f8d4 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/BINDKeyUtils.java +++ b/src/main/java/com/verisignlabs/dnssec/security/BINDKeyUtils.java @@ -1,6 +1,4 @@ -// $Id$ -// -// Copyright (C) 2001-2003 VeriSign, Inc. +// Copyright (C) 2001-2003, 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 @@ -28,7 +26,6 @@ import java.io.PrintWriter; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; -import java.text.NumberFormat; import org.xbill.DNS.DNSKEYRecord; import org.xbill.DNS.Master; @@ -41,62 +38,35 @@ import org.xbill.DNS.utils.base64; /** * This class contains a series of static methods used for manipulating BIND * 9.x.x-style DNSSEC key files. - * + * * In this class, the "base" key path or name is the file name without the * trailing ".key" or ".private". - * - * @author David Blacka (original) - * @author $Author$ - * @version $Revision$ + * + * @author David Blacka */ -public class BINDKeyUtils -{ - // formatters used to generated the BIND key file names - private static NumberFormat mAlgNumberFormatter; - private static NumberFormat mKeyIdNumberFormatter; +public class BINDKeyUtils { + + private BINDKeyUtils() { } /** * Calculate the BIND9 key file base name (i.e., without the ".key" or * ".private" extensions) */ - private static String getKeyFileBase(Name signer, int algorithm, int keyid) - { - if (mAlgNumberFormatter == null) - { - mAlgNumberFormatter = NumberFormat.getNumberInstance(); - mAlgNumberFormatter.setMaximumIntegerDigits(3); - mAlgNumberFormatter.setMinimumIntegerDigits(3); - } - if (mKeyIdNumberFormatter == null) - { - mKeyIdNumberFormatter = NumberFormat.getNumberInstance(); - mKeyIdNumberFormatter.setMaximumIntegerDigits(5); - mKeyIdNumberFormatter.setMinimumIntegerDigits(5); - mKeyIdNumberFormatter.setGroupingUsed(false); - - } - + private static String getKeyFileBase(Name signer, int algorithm, int keyid) { keyid &= 0xFFFF; - - String fn = "K" + signer + "+" + mAlgNumberFormatter.format(algorithm) - + "+" + mKeyIdNumberFormatter.format(keyid); - - return fn; + return String.format("K%1$s+%2$03d+%3$05d", signer, algorithm, keyid); } /** Reads in the DNSKEYRecord from the public key file */ private static DNSKEYRecord loadPublicKeyFile(File publicKeyFile) - throws IOException - { + throws IOException { Master m = new Master(publicKeyFile.getAbsolutePath(), null, 600); Record r; DNSKEYRecord result = null; - while ((r = m.nextRecord()) != null) - { - if (r.getType() == Type.DNSKEY) - { + while ((r = m.nextRecord()) != null) { + if (r.getType() == Type.DNSKEY) { result = (DNSKEYRecord) r; } } @@ -106,31 +76,26 @@ public class BINDKeyUtils /** Reads in the private key verbatim from the private key file */ private static String loadPrivateKeyFile(File privateKeyFile) - throws IOException - { - BufferedReader in = new BufferedReader(new FileReader(privateKeyFile)); - StringBuffer key_buf = new StringBuffer(); + throws IOException { + try (BufferedReader in = new BufferedReader(new FileReader(privateKeyFile))) { + StringBuilder keybuf = new StringBuilder(); + String line; - String line; - - while ((line = in.readLine()) != null) - { - key_buf.append(line); - key_buf.append('\n'); + while ((line = in.readLine()) != null) { + keybuf.append(line); + keybuf.append('\n'); + } + return keybuf.toString().trim(); } - in.close(); - - return key_buf.toString().trim(); } /** * Given an actual path for one of the key files, return the base name */ - private static String fixKeyFileBasePath(String basePath) - { - if (basePath == null) throw new IllegalArgumentException(); - if (basePath.endsWith(".key") || basePath.endsWith(".private")) - { + private static String fixKeyFileBasePath(String basePath) { + if (basePath == null) + throw new IllegalArgumentException(); + if (basePath.endsWith(".key") || basePath.endsWith(".private")) { basePath = basePath.substring(0, basePath.lastIndexOf(".")); } @@ -140,22 +105,21 @@ public class BINDKeyUtils /** * Given the information necessary to construct the path to a BIND9 generated * key pair, load the key pair. - * + * * @param signer - * the DNS name of the key. + * the DNS name of the key. * @param algorithm - * the DNSSEC algorithm of the key. + * the DNSSEC algorithm of the key. * @param keyid - * the DNSSEC key footprint. + * the DNSSEC key footprint. * @param inDirectory - * the directory to look for the files (may be null). + * the directory to look for the files (may be null). * @return the loaded key pair. * @throws IOException - * if there was a problem reading the BIND9 files. + * if there was a problem reading the BIND9 files. */ public static DnsKeyPair loadKeyPair(Name signer, int algorithm, int keyid, - File inDirectory) throws IOException - { + File inDirectory) throws IOException { String keyFileBase = getKeyFileBase(signer, algorithm, keyid); return loadKeyPair(keyFileBase, inDirectory); @@ -163,19 +127,20 @@ public class BINDKeyUtils /** * Given a base path to a BIND9 key pair, load the key pair. - * + * * @param keyFileBasePath - * the base filename (or real filename for either the public or - * private key) of the key. + * the base filename (or real filename for either the + * public or + * private key) of the key. * @param inDirectory - * the directory to look in, if the keyFileBasePath is relative. + * the directory to look in, if the keyFileBasePath is + * relative. * @return the loaded key pair. * @throws IOException - * if there was a problem reading the files + * if there was a problem reading the files */ public static DnsKeyPair loadKeyPair(String keyFileBasePath, File inDirectory) - throws IOException - { + throws IOException { keyFileBasePath = fixKeyFileBasePath(keyFileBasePath); // FIXME: should we throw the IOException when one of the files // cannot be found, or just when both cannot be found? @@ -196,18 +161,19 @@ public class BINDKeyUtils /** * Given a base path to a BIND9 key pair, load the public part (only) of the * key pair - * + * * @param keyFileBasePath - * the base or real path to the public part of a key pair. + * the base or real path to the public part of a key + * pair. * @param inDirectory - * the directory to look in if the path is relative (may be null). + * the directory to look in if the path is relative (may + * be null). * @return a {@link DnsKeyPair} containing just the public key information. * @throws IOException - * if there was a problem reading the public key file. + * if there was a problem reading the public key file. */ public static DnsKeyPair loadKey(String keyFileBasePath, File inDirectory) - throws IOException - { + throws IOException { keyFileBasePath = fixKeyFileBasePath(keyFileBasePath); File publicKeyFile = new File(inDirectory, keyFileBasePath + ".key"); @@ -223,57 +189,56 @@ public class BINDKeyUtils * Load a BIND keyset file. The BIND 9 dnssec tools typically call these files * "keyset-[signer]." where [signer] is the DNS owner name of the key. The * keyset may be signed, but doesn't have to be. - * + * * @param keysetFileName - * the name of the keyset file. + * the name of the keyset file. * @param inDirectory - * the directory to look in if the path is relative (may be null, - * defaults to the current working directory). + * the directory to look in if the path is relative (may + * be null, + * defaults to the current working directory). * @return a RRset contain the KEY records and any associated SIG records. * @throws IOException - * if there was a problem reading the keyset file. + * if there was a problem reading the keyset file. */ public static RRset loadKeySet(String keysetFileName, File inDirectory) - throws IOException - { + throws IOException { File keysetFile = new File(inDirectory, keysetFileName); - Master m = new Master(keysetFile.getAbsolutePath()); + try (Master m = new Master(keysetFile.getAbsolutePath())) { + Record r; + RRset keyset = new RRset(); + while ((r = m.nextRecord()) != null) { + keyset.addRR(r); + } - Record r; - RRset keyset = new RRset(); - while ((r = m.nextRecord()) != null) - { - keyset.addRR(r); + return keyset; } - - return keyset; } /** * Calculate the key file base for this key pair. - * + * * @param pair - * the {@link DnsKeyPair} to work from. It only needs a public key. + * the {@link DnsKeyPair} to work from. It only needs a public key. * @return the base name of the key files. */ - public static String keyFileBase(DnsKeyPair pair) - { + public static String keyFileBase(DnsKeyPair pair) { DNSKEYRecord keyrec = pair.getDNSKEYRecord(); - if (keyrec == null) return null; + if (keyrec == null) + return null; return getKeyFileBase(keyrec.getName(), keyrec.getAlgorithm(), - keyrec.getFootprint()); + keyrec.getFootprint()); } /** * @return a {@link java.io.File} object representing the BIND9 public key * file. */ - public static File getPublicKeyFile(DnsKeyPair pair, File inDirectory) - { + public static File getPublicKeyFile(DnsKeyPair pair, File inDirectory) { String keyfilebase = keyFileBase(pair); - if (keyfilebase == null) return null; + if (keyfilebase == null) + return null; return new File(inDirectory, keyfilebase + ".key"); } @@ -282,10 +247,10 @@ public class BINDKeyUtils * @return a {@link java.io.File} object representing the BIND9 private key * file */ - public static File getPrivateKeyFile(DnsKeyPair pair, File inDirectory) - { + public static File getPrivateKeyFile(DnsKeyPair pair, File inDirectory) { String keyfilebase = keyFileBase(pair); - if (keyfilebase == null) return null; + if (keyfilebase == null) + return null; return new File(inDirectory, keyfilebase + ".private"); } @@ -293,28 +258,21 @@ public class BINDKeyUtils /** * Given a the contents of a BIND9 private key file, convert it into a native * {@link java.security.PrivateKey} object. - * + * * @param privateKeyString - * the contents of a BIND9 key file in string form. + * the contents of a BIND9 key file in string form. * @return a {@link java.security.PrivateKey} */ - public static PrivateKey convertPrivateKeyString(String privateKeyString) - { - if (privateKeyString == null) return null; + public static PrivateKey convertPrivateKeyString(String privateKeyString) { + if (privateKeyString == null) + return null; // FIXME: should this swallow exceptions or actually propagate // them? - try - { + try { DnsKeyConverter conv = new DnsKeyConverter(); return conv.parsePrivateKeyString(privateKeyString); - } - catch (IOException e) - { - e.printStackTrace(); - } - catch (NoSuchAlgorithmException e) - { + } catch (IOException|NoSuchAlgorithmException e) { e.printStackTrace(); } @@ -324,22 +282,18 @@ public class BINDKeyUtils /** * Given a native private key, convert it into a BIND9 private key file * format. - * + * * @param priv - * the private key to convert. + * the private key to convert. * @param pub - * the private key's corresponding public key. Some algorithms - * require information from both. + * the private key's corresponding public key. Some algorithms + * require information from both. * @return a string containing the contents of a BIND9 private key file. */ - public static String convertPrivateKey(PrivateKey priv, PublicKey pub, int alg) - { - if (priv != null) - { + public static String convertPrivateKey(PrivateKey priv, PublicKey pub, int alg) { + if (priv != null) { DnsKeyConverter keyconv = new DnsKeyConverter(); - String priv_string = keyconv.generatePrivateKeyString(priv, pub, alg); - - return priv_string; + return keyconv.generatePrivateKeyString(priv, pub, alg); } return null; @@ -350,13 +304,14 @@ public class BINDKeyUtils * routines need. Currently, the DNSJAVA package uses a multiline mode for its * record formatting. The BIND9 tools require everything on a single line. */ - private static String DNSKEYtoString(DNSKEYRecord rec) - { - StringBuffer buf = new StringBuffer(); + private static String DNSKEYtoString(DNSKEYRecord rec) { + StringBuilder buf = new StringBuilder(); buf.append(rec.getName()); - buf.append(" "); - buf.append(rec.getTTL()); + if (rec.getTTL() > 0) { + buf.append(" "); + buf.append(rec.getTTL()); + } buf.append(" IN DNSKEY "); buf.append(rec.getFlags() & 0xFFFF); buf.append(" "); @@ -371,30 +326,30 @@ public class BINDKeyUtils /** * This routine will write out the BIND9 dnssec-* tool compatible files. - * + * * @param baseFileName - * use this base file name. If null, the standard BIND9 base file - * name will be computed. + * use this base file name. If null, the standard BIND9 base + * file + * name will be computed. * @param pair - * the keypair in question. + * the keypair in question. * @param inDirectory - * the directory to write to (may be null). + * the directory to write to (may be null). * @throws IOException - * if there is a problem writing the files. + * if there is a problem writing the files. */ public static void writeKeyFiles(String baseFileName, DnsKeyPair pair, - File inDirectory) throws IOException - { + File inDirectory) throws IOException { DNSKEYRecord pub = pair.getDNSKEYRecord(); String priv = pair.getPrivateKeyString(); - if (priv == null) - { + if (priv == null) { priv = convertPrivateKey(pair.getPrivate(), pair.getPublic(), - pair.getDNSKEYAlgorithm()); + pair.getDNSKEYAlgorithm()); } - if (pub == null || priv == null) return; + if (pub == null || priv == null) + return; // Write the public key file File pubkeyfile = new File(inDirectory, baseFileName + ".key"); @@ -413,15 +368,14 @@ public class BINDKeyUtils /** * This routine will write out the BIND9 dnssec-* tool compatible files to the * standard file names. - * + * * @param pair - * the key pair in question. + * the key pair in question. * @param inDirectory - * the directory to write to (may be null). + * the directory to write to (may be null). */ public static void writeKeyFiles(DnsKeyPair pair, File inDirectory) - throws IOException - { + throws IOException { String base = keyFileBase(pair); writeKeyFiles(base, pair, inDirectory); } diff --git a/src/main/java/com/verisignlabs/dnssec/security/ByteArrayComparator.java b/src/main/java/com/verisignlabs/dnssec/security/ByteArrayComparator.java index f8d5a1d..84082f1 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/ByteArrayComparator.java +++ b/src/main/java/com/verisignlabs/dnssec/security/ByteArrayComparator.java @@ -1,6 +1,4 @@ -// $Id$ -// -// Copyright (C) 2001-2003 VeriSign, Inc. +// Copyright (C) 2001-2003, 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 @@ -26,34 +24,25 @@ import java.util.logging.Logger; * useful for comparing RDATA portions of DNS records in doing DNSSEC canonical * ordering. * - * @author David Blacka (original) - * @author $Author$ - * @version $Revision$ + * @author David Blacka */ -public class ByteArrayComparator implements Comparator -{ - private int mOffset = 0; - private boolean mDebug = false; +public class ByteArrayComparator implements Comparator { + private int mOffset = 0; + private boolean mDebug = false; private Logger log; - public ByteArrayComparator() - { + public ByteArrayComparator() { } - public ByteArrayComparator(int offset, boolean debug) - { + public ByteArrayComparator(int offset, boolean debug) { mOffset = offset; mDebug = debug; } - public int compare(byte[] b1, byte[] b2) - { - for (int i = mOffset; i < b1.length && i < b2.length; i++) - { - if (b1[i] != b2[i]) - { - if (mDebug) - { + public int compare(byte[] b1, byte[] b2) { + for (int i = mOffset; i < b1.length && i < b2.length; i++) { + if (b1[i] != b2[i]) { + if (mDebug) { log.info("offset " + i + " differs (this is " + (i - mOffset) + " bytes in from our offset.)"); } diff --git a/src/main/java/com/verisignlabs/dnssec/security/DnsKeyAlgorithm.java b/src/main/java/com/verisignlabs/dnssec/security/DnsKeyAlgorithm.java index 17e8c86..dc9a971 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/DnsKeyAlgorithm.java +++ b/src/main/java/com/verisignlabs/dnssec/security/DnsKeyAlgorithm.java @@ -1,7 +1,5 @@ /* - * $Id$ - * - * Copyright (c) 2006 VeriSign. All rights reserved. + * Copyright (c) 2006, 2022 Verisign. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,8 +28,22 @@ package com.verisignlabs.dnssec.security; import java.math.BigInteger; -import java.security.*; -import java.security.spec.*; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.spec.ECFieldFp; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.EllipticCurve; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.RSAKeyGenParameterSpec; import java.util.Arrays; import java.util.HashMap; import java.util.Set; @@ -39,10 +51,11 @@ import java.util.logging.Logger; import org.xbill.DNS.DNSSEC; +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; // for now, we need to import the EdDSA parameter spec classes // because they have no generic form in java.security.spec.* // sadly, this will currently fail if you don't have the lib. -import net.i2p.crypto.eddsa.spec.*; +import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec; /** * This class handles translating DNS signing algorithm identifiers into various @@ -53,57 +66,48 @@ import net.i2p.crypto.eddsa.spec.*; * aliasing -- that is, defining a new algorithm identifier to be equivalent to * an existing identifier. * - * @author David Blacka (orig) - * @author $Author: davidb $ (latest) - * @version $Revision: 2098 $ + * @author David Blacka */ -public class DnsKeyAlgorithm -{ +public class DnsKeyAlgorithm { // Our base algorithm numbers. This is a normalization of the DNSSEC // algorithms (which are really signature algorithms). Thus RSASHA1, // RSASHA256, etc. all boil down to 'RSA' here. - public static final int UNKNOWN = -1; - public static final int RSA = 1; - public static final int DH = 2; - public static final int DSA = 3; - public static final int ECC_GOST = 4; - public static final int ECDSA = 5; - public static final int EDDSA = 6; + public static final int UNKNOWN = -1; + public static final int RSA = 1; + public static final int DH = 2; + public static final int DSA = 3; + public static final int ECC_GOST = 4; + public static final int ECDSA = 5; + public static final int EDDSA = 6; - private static class AlgEntry - { - public int dnssecAlgorithm; + private static class AlgEntry { + public int dnssecAlgorithm; public String sigName; - public int baseType; + public int baseType; - public AlgEntry(int algorithm, String sigName, int baseType) - { + public AlgEntry(int algorithm, String sigName, int baseType) { this.dnssecAlgorithm = algorithm; - this.sigName = sigName; - this.baseType = baseType; + this.sigName = sigName; + this.baseType = baseType; } } - private static class ECAlgEntry extends AlgEntry - { - public ECParameterSpec ec_spec; + private static class ECAlgEntry extends AlgEntry { + public ECParameterSpec ecSpec; - public ECAlgEntry(int algorithm, String sigName, int baseType, ECParameterSpec spec) - { + public ECAlgEntry(int algorithm, String sigName, int baseType, ECParameterSpec spec) { super(algorithm, sigName, baseType); - this.ec_spec = spec; + this.ecSpec = spec; } } - private static class EdAlgEntry extends AlgEntry - { - public EdDSAParameterSpec ed_spec; + private static class EdAlgEntry extends AlgEntry { + public EdDSAParameterSpec edSpec; - public EdAlgEntry(int algorithm, String sigName, int baseType, EdDSAParameterSpec spec) - { + public EdAlgEntry(int algorithm, String sigName, int baseType, EdDSAParameterSpec spec) { super(algorithm, sigName, baseType); - this.ed_spec = spec; + this.edSpec = spec; } } @@ -111,7 +115,7 @@ public class DnsKeyAlgorithm * This is a mapping of algorithm identifier to Entry. The Entry contains the * data needed to map the algorithm to the various crypto implementations. */ - private HashMap mAlgorithmMap; + private HashMap mAlgorithmMap; /** * This is a mapping of algorithm mnemonics to algorithm identifiers. */ @@ -123,53 +127,50 @@ public class DnsKeyAlgorithm private HashMap mIdToMnemonicMap; /** This is a cached key pair generator for RSA keys. */ - private KeyPairGenerator mRSAKeyGenerator; + private KeyPairGenerator mRSAKeyGenerator; /** This is a cached key pair generator for DSA keys. */ - private KeyPairGenerator mDSAKeyGenerator; + private KeyPairGenerator mDSAKeyGenerator; /** This is a cached key pair generator for ECC GOST keys. */ - private KeyPairGenerator mECGOSTKeyGenerator; + private KeyPairGenerator mECGOSTKeyGenerator; /** This is a cached key pair generator for ECDSA_P256 keys. */ - private KeyPairGenerator mECKeyGenerator; + private KeyPairGenerator mECKeyGenerator; /** This is a cached key pair generator for EdDSA keys. */ - private KeyPairGenerator mEdKeyGenerator; + private KeyPairGenerator mEdKeyGenerator; - private Logger log = Logger.getLogger(this.getClass().toString()); + private Logger log = Logger.getLogger(this.getClass().toString()); /** This is the global instance for this class. */ - private static DnsKeyAlgorithm mInstance = null; + private static DnsKeyAlgorithm mInstance = null; - public DnsKeyAlgorithm() - { + public DnsKeyAlgorithm() { // Attempt to add the bouncycastle provider. // This is so we can use this provider if it is available, but not require // the user to add it as one of the java.security providers. - try - { + try { Class bc_provider_class = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider"); - Provider bc_provider = (Provider) bc_provider_class.newInstance(); + // Provider bc_provider = (Provider) bc_provider_class.newInstance(); + Provider bc_provider = (Provider) bc_provider_class.getDeclaredConstructor().newInstance(); Security.addProvider(bc_provider); + } catch (ReflectiveOperationException e) { } - catch (ReflectiveOperationException e) { } // Attempt to add the EdDSA-Java provider. - try - { + try { Class eddsa_provider_class = Class.forName("net.i2p.crypto.eddsa.EdDSASecurityProvider"); - Provider eddsa_provider = (Provider) eddsa_provider_class.newInstance(); + // Provider eddsa_provider = (Provider) eddsa_provider_class.newInstance(); + Provider eddsa_provider = (Provider) eddsa_provider_class.getDeclaredConstructor().newInstance(); Security.addProvider(eddsa_provider); - } - catch (ReflectiveOperationException e) { + } catch (ReflectiveOperationException e) { log.warning("Unable to load EdDSA provider"); } initialize(); } - private void initialize() - { - mAlgorithmMap = new HashMap(); - mMnemonicToIdMap = new HashMap(); - mIdToMnemonicMap = new HashMap(); + private void initialize() { + mAlgorithmMap = new HashMap<>(); + mMnemonicToIdMap = new HashMap<>(); + mIdToMnemonicMap = new HashMap<>(); // Load the standard DNSSEC algorithms. addAlgorithm(DNSSEC.Algorithm.RSAMD5, "MD5withRSA", RSA); @@ -216,25 +217,24 @@ public class DnsKeyAlgorithm addMnemonic("ECDSA-P384", DNSSEC.Algorithm.ECDSAP384SHA384); // EdDSA is not supported by either the Java 1.8 Sun crypto - // provider or bouncycastle. It is added by the Ed25519-Java - // library. We don't have a corresponding constant in + // provider or bouncycastle. It is added by the Ed25519-Java + // library. We don't have a corresponding constant in // org.xbill.DNS.DNSSEC yet, though. addAlgorithm(15, "NONEwithEdDSA", EDDSA, "Ed25519"); addMnemonic("ED25519", 15); } - private void addAlgorithm(int algorithm, String sigName, int baseType) - { + private void addAlgorithm(int algorithm, String sigName, int baseType) { mAlgorithmMap.put(algorithm, new AlgEntry(algorithm, sigName, baseType)); } - private void addAlgorithm(int algorithm, String sigName, int baseType, String curveName) - { - if (baseType == ECDSA) - { - ECParameterSpec ec_spec = ECSpecFromAlgorithm(algorithm); - if (ec_spec == null) ec_spec = ECSpecFromName(curveName); - if (ec_spec == null) return; + private void addAlgorithm(int algorithm, String sigName, int baseType, String curveName) { + if (baseType == ECDSA) { + ECParameterSpec ecSpec = ECSpecFromAlgorithm(algorithm); + if (ecSpec == null) + ecSpec = ECSpecFromName(curveName); + if (ecSpec == null) + return; // Check to see if we can get a Signature object for this algorithm. try { @@ -245,13 +245,12 @@ public class DnsKeyAlgorithm // If not, do not add the algorithm. return; } - ECAlgEntry entry = new ECAlgEntry(algorithm, sigName, baseType, ec_spec); + ECAlgEntry entry = new ECAlgEntry(algorithm, sigName, baseType, ecSpec); mAlgorithmMap.put(algorithm, entry); - } - else if (baseType == EDDSA) - { - EdDSAParameterSpec ed_spec = EdDSASpecFromName(curveName); - if (ed_spec == null) return; + } else if (baseType == EDDSA) { + EdDSAParameterSpec edSpec = EdDSASpecFromName(curveName); + if (edSpec == null) + return; // Check to see if we can get a Signature object for this algorithm. try { @@ -262,35 +261,29 @@ public class DnsKeyAlgorithm // If not, do not add the algorithm. return; } - EdAlgEntry entry = new EdAlgEntry(algorithm, sigName, baseType, ed_spec); + EdAlgEntry entry = new EdAlgEntry(algorithm, sigName, baseType, edSpec); mAlgorithmMap.put(algorithm, entry); } - } - private void addMnemonic(String m, int alg) - { - // Do not add mnemonics for algorithms that ended up not actually being supported. - if (!mAlgorithmMap.containsKey(alg)) return; + private void addMnemonic(String m, int alg) { + // Do not add mnemonics for algorithms that ended up not actually being + // supported. + if (!mAlgorithmMap.containsKey(alg)) + return; mMnemonicToIdMap.put(m.toUpperCase(), alg); - if (!mIdToMnemonicMap.containsKey(alg)) - { - mIdToMnemonicMap.put(alg, m); - } + mIdToMnemonicMap.computeIfAbsent(alg, k -> m); } - public void addAlias(int alias, String mnemonic, int original_algorithm) - { - if (mAlgorithmMap.containsKey(alias)) - { + public void addAlias(int alias, String mnemonic, int original_algorithm) { + if (mAlgorithmMap.containsKey(alias)) { log.warning("Unable to alias algorithm " + alias + " because it already exists."); return; } - if (!mAlgorithmMap.containsKey(original_algorithm)) - { + if (!mAlgorithmMap.containsKey(original_algorithm)) { log.warning("Unable to alias algorithm " + alias + " to unknown algorithm identifier " + original_algorithm); return; @@ -298,33 +291,28 @@ public class DnsKeyAlgorithm mAlgorithmMap.put(alias, mAlgorithmMap.get(original_algorithm)); - if (mnemonic != null) - { + if (mnemonic != null) { addMnemonic(mnemonic, alias); } } - private AlgEntry getEntry(int alg) - { + private AlgEntry getEntry(int alg) { return mAlgorithmMap.get(alg); } // For curves where we don't (or can't) get the parameters from a standard // name, we can construct the parameters here. For now, we only do this for // the ECC-GOST curve. - private ECParameterSpec ECSpecFromAlgorithm(int algorithm) - { - switch (algorithm) - { - case DNSSEC.Algorithm.ECC_GOST: - { + private ECParameterSpec ECSpecFromAlgorithm(int algorithm) { + switch (algorithm) { + case DNSSEC.Algorithm.ECC_GOST: { // From RFC 4357 Section 11.4 - BigInteger p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", 16); - BigInteger a = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94", 16); - BigInteger b = new BigInteger("A6", 16); + BigInteger p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", 16); + BigInteger a = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94", 16); + BigInteger b = new BigInteger("A6", 16); BigInteger gx = new BigInteger("1", 16); BigInteger gy = new BigInteger("8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14", 16); - BigInteger n = new BigInteger( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893", 16); + BigInteger n = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893", 16); EllipticCurve curve = new EllipticCurve(new ECFieldFp(p), a, b); return new ECParameterSpec(curve, new ECPoint(gx, gy), n, 1); @@ -335,35 +323,31 @@ public class DnsKeyAlgorithm } // Fetch the curve parameters from a named ECDSA curve. - private ECParameterSpec ECSpecFromName(String stdName) - { - try - { + private ECParameterSpec ECSpecFromName(String stdName) { + try { AlgorithmParameters ap = AlgorithmParameters.getInstance("EC"); ECGenParameterSpec ecg_spec = new ECGenParameterSpec(stdName); ap.init(ecg_spec); return ap.getParameterSpec(ECParameterSpec.class); - } - catch (NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { log.info("Elliptic Curve not supported by any crypto provider: " + e.getMessage()); - } - catch (InvalidParameterSpecException e) { + } catch (InvalidParameterSpecException e) { log.info("Elliptic Curve " + stdName + " not supported"); } return null; } // Fetch the curve parameters from a named EdDSA curve. - private EdDSAParameterSpec EdDSASpecFromName(String stdName) - { - try - { + private EdDSAParameterSpec EdDSASpecFromName(String stdName) { + try { EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(stdName); - if (spec != null) return spec; + if (spec != null) + return spec; throw new InvalidParameterSpecException("Edwards Curve " + stdName + " not found."); } // catch (NoSuchAlgorithmException e) { - // log.info("Edwards Curve not supported by any crypto provider: " + e.getMessage()); + // log.info("Edwards Curve not supported by any crypto provider: " + + // e.getMessage()); // } catch (InvalidParameterSpecException e) { log.info("Edwards Curve " + stdName + " not supported"); @@ -371,15 +355,13 @@ public class DnsKeyAlgorithm return null; } - public String[] supportedAlgMnemonics() - { + public String[] supportedAlgMnemonics() { Set keyset = mAlgorithmMap.keySet(); Integer[] algs = keyset.toArray(new Integer[keyset.size()]); Arrays.sort(algs); String[] result = new String[algs.length]; - for (int i = 0; i < algs.length; i++) - { + for (int i = 0; i < algs.length; i++) { result[i] = mIdToMnemonicMap.get(algs[i]); } @@ -388,22 +370,20 @@ public class DnsKeyAlgorithm /** * Return a Signature object for the specified DNSSEC algorithm. + * * @param algorithm The DNSSEC algorithm (by number). * @return a Signature object. */ - public Signature getSignature(int algorithm) - { + public Signature getSignature(int algorithm) { AlgEntry entry = getEntry(algorithm); - if (entry == null) return null; + if (entry == null) + return null; Signature s = null; - try - { + try { s = Signature.getInstance(entry.sigName); - } - catch (NoSuchAlgorithmException e) - { + } catch (NoSuchAlgorithmException e) { log.severe("Unable to get signature implementation for algorithm " + algorithm + ": " + e); } @@ -416,36 +396,39 @@ public class DnsKeyAlgorithm * the elliptic curve parameters. * * @param algorithm - * The DNSSEC algorithm number. + * The DNSSEC algorithm number. * @return The calculated JCA ECParameterSpec for that DNSSEC algorithm, or * null if not a recognized/supported EC algorithm. */ - public ECParameterSpec getEllipticCurveParams(int algorithm) - { + public ECParameterSpec getEllipticCurveParams(int algorithm) { AlgEntry entry = getEntry(algorithm); - if (entry == null) return null; - if (!(entry instanceof ECAlgEntry)) return null; + if (entry == null) + return null; + if (!(entry instanceof ECAlgEntry)) + return null; ECAlgEntry ec_entry = (ECAlgEntry) entry; - return ec_entry.ec_spec; + return ec_entry.ecSpec; } - /** Given one of the EdDSA algorithms (Ed25519, Ed448) return the + /** + * Given one of the EdDSA algorithms (Ed25519, Ed448) return the * elliptic curve parameters. * * @param algorithm - * The DNSSEC algorithm number. + * The DNSSEC algorithm number. * @return The stored EdDSAParameterSpec for that algorithm, or * null if not a recognized/supported EdDSA algorithm. */ - public EdDSAParameterSpec getEdwardsCurveParams(int algorithm) - { + public EdDSAParameterSpec getEdwardsCurveParams(int algorithm) { AlgEntry entry = getEntry(algorithm); - if (entry == null) return null; - if (!(entry instanceof EdAlgEntry)) return null; + if (entry == null) + return null; + if (!(entry instanceof EdAlgEntry)) + return null; EdAlgEntry ed_entry = (EdAlgEntry) entry; - return ed_entry.ed_spec; + return ed_entry.edSpec; } /** @@ -453,14 +436,14 @@ public class DnsKeyAlgorithm * number * * @param algorithm - * a DNSSEC algorithm that may be an alias. + * a DNSSEC algorithm that may be an alias. * @return -1 if the algorithm isn't recognised, the orignal algorithm number * if it is. */ - public int originalAlgorithm(int algorithm) - { + public int originalAlgorithm(int algorithm) { AlgEntry entry = getEntry(algorithm); - if (entry == null) return -1; + if (entry == null) + return -1; return entry.dnssecAlgorithm; } @@ -468,11 +451,12 @@ public class DnsKeyAlgorithm * Test if a given algorithm is supported. * * @param algorithm The DNSSEC algorithm number. - * @return true if the algorithm is a recognized and supported algorithm or alias. + * @return true if the algorithm is a recognized and supported algorithm or + * alias. */ - public boolean supportedAlgorithm(int algorithm) - { - if (mAlgorithmMap.containsKey(algorithm)) return true; + public boolean supportedAlgorithm(int algorithm) { + if (mAlgorithmMap.containsKey(algorithm)) + return true; return false; } @@ -485,10 +469,10 @@ public class DnsKeyAlgorithm * @return -1 if the mnemonic isn't recognized or supported, the algorithm * number if it is. */ - public int stringToAlgorithm(String s) - { + public int stringToAlgorithm(String s) { Integer alg = mMnemonicToIdMap.get(s.toUpperCase()); - if (alg != null) return alg.intValue(); + if (alg != null) + return alg.intValue(); return -1; } @@ -496,55 +480,43 @@ public class DnsKeyAlgorithm * Given a DNSSEC algorithm number, return the "preferred" mnemonic. * * @param algorithm - * A DNSSEC algorithm number. + * A DNSSEC algorithm number. * @return The preferred mnemonic string, or null if not supported or * recognized. */ - public String algToString(int algorithm) - { + public String algToString(int algorithm) { return mIdToMnemonicMap.get(algorithm); } - public int baseType(int algorithm) - { + public int baseType(int algorithm) { AlgEntry entry = getEntry(algorithm); - if (entry != null) return entry.baseType; + if (entry != null) + return entry.baseType; return UNKNOWN; } - public boolean isDSA(int algorithm) - { + public boolean isDSA(int algorithm) { return (baseType(algorithm) == DSA); } public KeyPair generateKeyPair(int algorithm, int keysize, boolean useLargeExp) - throws NoSuchAlgorithmException - { + throws NoSuchAlgorithmException { KeyPair pair = null; - switch (baseType(algorithm)) - { - case RSA: - { - if (mRSAKeyGenerator == null) - { + switch (baseType(algorithm)) { + case RSA: { + if (mRSAKeyGenerator == null) { mRSAKeyGenerator = KeyPairGenerator.getInstance("RSA"); } RSAKeyGenParameterSpec rsa_spec; - if (useLargeExp) - { + if (useLargeExp) { rsa_spec = new RSAKeyGenParameterSpec(keysize, RSAKeyGenParameterSpec.F4); - } - else - { + } else { rsa_spec = new RSAKeyGenParameterSpec(keysize, RSAKeyGenParameterSpec.F0); } - try - { + try { mRSAKeyGenerator.initialize(rsa_spec); - } - catch (InvalidAlgorithmParameterException e) - { + } catch (InvalidAlgorithmParameterException e) { // Fold the InvalidAlgorithmParameterException into our existing // thrown exception. Ugly, but requires less code change. throw new NoSuchAlgorithmException("invalid key parameter spec"); @@ -553,30 +525,23 @@ public class DnsKeyAlgorithm pair = mRSAKeyGenerator.generateKeyPair(); break; } - case DSA: - { - if (mDSAKeyGenerator == null) - { + case DSA: { + if (mDSAKeyGenerator == null) { mDSAKeyGenerator = KeyPairGenerator.getInstance("DSA"); } mDSAKeyGenerator.initialize(keysize); pair = mDSAKeyGenerator.generateKeyPair(); break; } - case ECC_GOST: - { - if (mECGOSTKeyGenerator == null) - { + case ECC_GOST: { + if (mECGOSTKeyGenerator == null) { mECGOSTKeyGenerator = KeyPairGenerator.getInstance("ECGOST3410"); } - ECParameterSpec ec_spec = getEllipticCurveParams(algorithm); - try - { - mECGOSTKeyGenerator.initialize(ec_spec); - } - catch (InvalidAlgorithmParameterException e) - { + ECParameterSpec ecSpec = getEllipticCurveParams(algorithm); + try { + mECGOSTKeyGenerator.initialize(ecSpec); + } catch (InvalidAlgorithmParameterException e) { // Fold the InvalidAlgorithmParameterException into our existing // thrown exception. Ugly, but requires less code change. throw new NoSuchAlgorithmException("invalid key parameter spec"); @@ -584,20 +549,15 @@ public class DnsKeyAlgorithm pair = mECGOSTKeyGenerator.generateKeyPair(); break; } - case ECDSA: - { - if (mECKeyGenerator == null) - { + case ECDSA: { + if (mECKeyGenerator == null) { mECKeyGenerator = KeyPairGenerator.getInstance("EC"); } - ECParameterSpec ec_spec = getEllipticCurveParams(algorithm); - try - { - mECKeyGenerator.initialize(ec_spec); - } - catch (InvalidAlgorithmParameterException e) - { + ECParameterSpec ecSpec = getEllipticCurveParams(algorithm); + try { + mECKeyGenerator.initialize(ecSpec); + } catch (InvalidAlgorithmParameterException e) { // Fold the InvalidAlgorithmParameterException into our existing // thrown exception. Ugly, but requires less code change. throw new NoSuchAlgorithmException("invalid key parameter spec"); @@ -605,20 +565,15 @@ public class DnsKeyAlgorithm pair = mECKeyGenerator.generateKeyPair(); break; } - case EDDSA: - { - if (mEdKeyGenerator == null) - { + case EDDSA: { + if (mEdKeyGenerator == null) { mEdKeyGenerator = KeyPairGenerator.getInstance("EdDSA"); } - EdDSAParameterSpec ed_spec = getEdwardsCurveParams(algorithm); - try - { - mEdKeyGenerator.initialize(ed_spec, new SecureRandom()); - } - catch (InvalidAlgorithmParameterException e) - { + EdDSAParameterSpec edSpec = getEdwardsCurveParams(algorithm); + try { + mEdKeyGenerator.initialize(edSpec, new SecureRandom()); + } catch (InvalidAlgorithmParameterException e) { // Fold the InvalidAlgorithmParameterException into our existing // thrown exception. Ugly, but requires less code change. throw new NoSuchAlgorithmException("invalid key parameter spec"); @@ -626,22 +581,21 @@ public class DnsKeyAlgorithm pair = mEdKeyGenerator.generateKeyPair(); break; } - default: - throw new NoSuchAlgorithmException("Alg " + algorithm); + default: + throw new NoSuchAlgorithmException("Alg " + algorithm); } return pair; } public KeyPair generateKeyPair(int algorithm, int keysize) - throws NoSuchAlgorithmException - { + throws NoSuchAlgorithmException { return generateKeyPair(algorithm, keysize, false); } - public static DnsKeyAlgorithm getInstance() - { - if (mInstance == null) mInstance = new DnsKeyAlgorithm(); + public static DnsKeyAlgorithm getInstance() { + if (mInstance == null) + mInstance = new DnsKeyAlgorithm(); return mInstance; } } diff --git a/src/main/java/com/verisignlabs/dnssec/security/DnsKeyConverter.java b/src/main/java/com/verisignlabs/dnssec/security/DnsKeyConverter.java index 25fda27..bf65af2 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/DnsKeyConverter.java +++ b/src/main/java/com/verisignlabs/dnssec/security/DnsKeyConverter.java @@ -1,6 +1,4 @@ -// $Id$ -// -// Copyright (C) 2001-2003 VeriSign, Inc. +// Copyright (C) 2001-2003, 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 @@ -27,8 +25,19 @@ import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; -import java.security.interfaces.*; -import java.security.spec.*; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; import java.util.StringTokenizer; import javax.crypto.interfaces.DHPrivateKey; @@ -36,27 +45,25 @@ import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import javax.crypto.spec.DHPrivateKeySpec; -// For now, just import the native EdDSA classes -import net.i2p.crypto.eddsa.EdDSAPublicKey; -import net.i2p.crypto.eddsa.EdDSAPrivateKey; -import net.i2p.crypto.eddsa.spec.*; - import org.xbill.DNS.DNSKEYRecord; -import org.xbill.DNS.DNSSEC; import org.xbill.DNS.DNSSEC.DNSSECException; import org.xbill.DNS.Name; import org.xbill.DNS.utils.base64; +import net.i2p.crypto.eddsa.EdDSAPrivateKey; +// For now, just import the native EdDSA classes +import net.i2p.crypto.eddsa.EdDSAPublicKey; +import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec; +import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec; +import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; + /** * This class handles conversions between JCA key formats and DNSSEC and BIND9 * key formats. * - * @author David Blacka (original) - * @author $Author$ (latest) - * @version $Revision$ + * @author David Blacka */ -public class DnsKeyConverter -{ +public class DnsKeyConverter { private KeyFactory mRSAKeyFactory; private KeyFactory mDSAKeyFactory; private KeyFactory mDHKeyFactory; @@ -64,8 +71,7 @@ public class DnsKeyConverter private KeyFactory mEdKeyFactory; private DnsKeyAlgorithm mAlgorithms; - public DnsKeyConverter() - { + public DnsKeyConverter() { mAlgorithms = DnsKeyAlgorithm.getInstance(); } @@ -75,29 +81,28 @@ public class DnsKeyConverter * @throws NoSuchAlgorithmException */ public PublicKey parseDNSKEYRecord(DNSKEYRecord pKeyRecord) - throws NoSuchAlgorithmException - { - if (pKeyRecord.getKey() == null) return null; + throws NoSuchAlgorithmException { + if (pKeyRecord.getKey() == null) + return null; // Because we have arbitrarily aliased algorithms, we need to possibly // translate the aliased algorithm back to the actual algorithm. int originalAlgorithm = mAlgorithms.originalAlgorithm(pKeyRecord.getAlgorithm()); - if (originalAlgorithm <= 0) throw new NoSuchAlgorithmException("DNSKEY algorithm " - + pKeyRecord.getAlgorithm() + " is unrecognized"); + if (originalAlgorithm <= 0) + throw new NoSuchAlgorithmException("DNSKEY algorithm " + + pKeyRecord.getAlgorithm() + " is unrecognized"); - if (pKeyRecord.getAlgorithm() != originalAlgorithm) - { + if (pKeyRecord.getAlgorithm() != originalAlgorithm) { pKeyRecord = new DNSKEYRecord(pKeyRecord.getName(), pKeyRecord.getDClass(), - pKeyRecord.getTTL(), pKeyRecord.getFlags(), - pKeyRecord.getProtocol(), originalAlgorithm, - pKeyRecord.getKey()); + pKeyRecord.getTTL(), pKeyRecord.getFlags(), + pKeyRecord.getProtocol(), originalAlgorithm, + pKeyRecord.getKey()); } // do not rely on DNSJava's method for EdDSA for now. - if (mAlgorithms.baseType(originalAlgorithm) == DnsKeyAlgorithm.EDDSA) - { + if (mAlgorithms.baseType(originalAlgorithm) == DnsKeyAlgorithm.EDDSA) { try { return parseEdDSADNSKEYRecord(pKeyRecord); } catch (InvalidKeySpecException e) { @@ -106,26 +111,24 @@ public class DnsKeyConverter } } - try - { + try { // This uses DNSJava's DNSSEC.toPublicKey() method. return pKeyRecord.getPublicKey(); - } - catch (DNSSECException e) - { + } catch (DNSSECException e) { throw new NoSuchAlgorithmException(e); } } - /** Since we don't (yet) have support in DNSJava for parsing the - newer EdDSA algorithms, here is a local version. */ + /** + * Since we don't (yet) have support in DNSJava for parsing the + * newer EdDSA algorithms, here is a local version. + */ private PublicKey parseEdDSADNSKEYRecord(DNSKEYRecord pKeyRecord) - throws IllegalArgumentException, NoSuchAlgorithmException, InvalidKeySpecException - { + throws IllegalArgumentException, NoSuchAlgorithmException, InvalidKeySpecException { byte[] seed = pKeyRecord.getKey(); - EdDSAPublicKeySpec spec = new EdDSAPublicKeySpec - (seed, mAlgorithms.getEdwardsCurveParams(pKeyRecord.getAlgorithm())); + EdDSAPublicKeySpec spec = new EdDSAPublicKeySpec(seed, + mAlgorithms.getEdwardsCurveParams(pKeyRecord.getAlgorithm())); KeyFactory factory = KeyFactory.getInstance("EdDSA"); return factory.generatePublic(spec); @@ -135,52 +138,44 @@ public class DnsKeyConverter * Given a JCA public key and the ancillary data, generate a DNSKEY record. */ public DNSKEYRecord generateDNSKEYRecord(Name name, int dclass, long ttl, - int flags, int alg, PublicKey key) - { - try - { + int flags, int alg, PublicKey key) { + try { if (mAlgorithms.baseType(alg) == DnsKeyAlgorithm.EDDSA) { return generateEdDSADNSKEYRecord(name, dclass, ttl, flags, alg, key); } return new DNSKEYRecord(name, dclass, ttl, flags, DNSKEYRecord.Protocol.DNSSEC, alg, - key); - } - catch (DNSSECException e) - { - // FIXME: this mimics the behavior of KEYConverter.buildRecord(), which would return null if the algorithm was unknown. + key); + } catch (DNSSECException e) { + // FIXME: this mimics the behavior of KEYConverter.buildRecord(), which would + // return null if the algorithm was unknown. return null; } } - private DNSKEYRecord generateEdDSADNSKEYRecord(Name name, int dclass, long ttl, - int flags, int alg, PublicKey key) - { + int flags, int alg, PublicKey key) { EdDSAPublicKey ed_key = (EdDSAPublicKey) key; byte[] key_data = ed_key.getAbyte(); return new DNSKEYRecord(name, dclass, ttl, flags, DNSKEYRecord.Protocol.DNSSEC, alg, - key_data); + key_data); } // Private Key Specific Parsing routines /** * Convert a PKCS#8 encoded private key into a PrivateKey object. */ - public PrivateKey convertEncodedPrivateKey(byte[] key, int algorithm) - { + public PrivateKey convertEncodedPrivateKey(byte[] key, int algorithm) { PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(key); - try - { - switch (mAlgorithms.baseType(algorithm)) - { + try { + switch (mAlgorithms.baseType(algorithm)) { case DnsKeyAlgorithm.RSA: return mRSAKeyFactory.generatePrivate(spec); case DnsKeyAlgorithm.DSA: return mDSAKeyFactory.generatePrivate(spec); + default: + return null; } - } - catch (GeneralSecurityException e) - { + } catch (GeneralSecurityException e) { e.printStackTrace(); } @@ -191,14 +186,10 @@ public class DnsKeyConverter * A simple wrapper for parsing integers; parse failures result in the * supplied default. */ - private static int parseInt(String s, int def) - { - try - { + private static int parseInt(String s, int def) { + try { return Integer.parseInt(s); - } - catch (NumberFormatException e) - { + } catch (NumberFormatException e) { return def; } } @@ -207,37 +198,33 @@ public class DnsKeyConverter * @return a JCA private key, given a BIND9-style textual encoding */ public PrivateKey parsePrivateKeyString(String key) - throws IOException, NoSuchAlgorithmException - { + throws IOException, NoSuchAlgorithmException { StringTokenizer lines = new StringTokenizer(key, "\n"); - while (lines.hasMoreTokens()) - { + while (lines.hasMoreTokens()) { String line = lines.nextToken(); - if (line == null) continue; + if (line == null) + continue; - if (line.startsWith("#")) continue; + if (line.startsWith("#")) + continue; String val = value(line); - if (val == null) continue; + if (val == null) + continue; - if (line.startsWith("Private-key-format: ")) - { - if (!val.equals("v1.2") && !val.equals("v1.3")) - { + if (line.startsWith("Private-key-format: ")) { + if (!val.equals("v1.2") && !val.equals("v1.3")) { throw new IOException("unsupported private key format: " + val); } - } - else if (line.startsWith("Algorithm: ")) - { + } else if (line.startsWith("Algorithm: ")) { // here we assume that the value looks like # (MNEM) or just the // number. String[] toks = val.split("\\s", 2); val = toks[0]; int alg = parseInt(val, -1); - switch (mAlgorithms.baseType(alg)) - { + switch (mAlgorithms.baseType(alg)) { case DnsKeyAlgorithm.RSA: return parsePrivateRSA(lines); case DnsKeyAlgorithm.DSA: @@ -261,14 +248,16 @@ public class DnsKeyConverter /** * @return the value part of an "attribute:value" pair. The value is trimmed. */ - private static String value(String av) - { - if (av == null) return null; + private static String value(String av) { + if (av == null) + return null; int pos = av.indexOf(':'); - if (pos < 0) return av; + if (pos < 0) + return av; - if (pos >= av.length()) return null; + if (pos >= av.length()) + return null; return av.substring(pos + 1).trim(); } @@ -278,11 +267,10 @@ public class DnsKeyConverter * translate into a JCA private key * * @throws NoSuchAlgorithmException - * if the RSA algorithm is not available. + * if the RSA algorithm is not available. */ private PrivateKey parsePrivateRSA(StringTokenizer lines) - throws NoSuchAlgorithmException - { + throws NoSuchAlgorithmException { BigInteger modulus = null; BigInteger public_exponent = null; BigInteger private_exponent = null; @@ -292,71 +280,54 @@ public class DnsKeyConverter BigInteger prime_q_exponent = null; BigInteger coefficient = null; - while (lines.hasMoreTokens()) - { + while (lines.hasMoreTokens()) { String line = lines.nextToken(); - if (line == null) continue; + if (line == null) + continue; - if (line.startsWith("#")) continue; + if (line.startsWith("#")) + continue; String val = value(line); - if (val == null) continue; + if (val == null) + continue; byte[] data = base64.fromString(val); - if (line.startsWith("Modulus: ")) - { + if (line.startsWith("Modulus: ")) { modulus = new BigInteger(1, data); // printBigIntCompare(data, modulus); - } - else if (line.startsWith("PublicExponent: ")) - { + } else if (line.startsWith("PublicExponent: ")) { public_exponent = new BigInteger(1, data); // printBigIntCompare(data, public_exponent); - } - else if (line.startsWith("PrivateExponent: ")) - { + } else if (line.startsWith("PrivateExponent: ")) { private_exponent = new BigInteger(1, data); // printBigIntCompare(data, private_exponent); - } - else if (line.startsWith("Prime1: ")) - { + } else if (line.startsWith("Prime1: ")) { prime_p = new BigInteger(1, data); // printBigIntCompare(data, prime_p); - } - else if (line.startsWith("Prime2: ")) - { + } else if (line.startsWith("Prime2: ")) { prime_q = new BigInteger(1, data); // printBigIntCompare(data, prime_q); - } - else if (line.startsWith("Exponent1: ")) - { + } else if (line.startsWith("Exponent1: ")) { prime_p_exponent = new BigInteger(1, data); - } - else if (line.startsWith("Exponent2: ")) - { + } else if (line.startsWith("Exponent2: ")) { prime_q_exponent = new BigInteger(1, data); - } - else if (line.startsWith("Coefficient: ")) - { + } else if (line.startsWith("Coefficient: ")) { coefficient = new BigInteger(1, data); } } - try - { + try { KeySpec spec = new RSAPrivateCrtKeySpec(modulus, public_exponent, - private_exponent, prime_p, - prime_q, prime_p_exponent, - prime_q_exponent, coefficient); - if (mRSAKeyFactory == null) - { + private_exponent, prime_p, + prime_q, prime_p_exponent, + prime_q_exponent, coefficient); + if (mRSAKeyFactory == null) { mRSAKeyFactory = KeyFactory.getInstance("RSA"); } return mRSAKeyFactory.generatePrivate(spec); - } - catch (InvalidKeySpecException e) - { + } catch (InvalidKeySpecException e) { e.printStackTrace(); return null; } @@ -367,52 +338,44 @@ public class DnsKeyConverter * info and translate it into a JCA private key. * * @throws NoSuchAlgorithmException - * if the DH algorithm is not available. + * if the DH algorithm is not available. */ private PrivateKey parsePrivateDH(StringTokenizer lines) - throws NoSuchAlgorithmException - { + throws NoSuchAlgorithmException { BigInteger p = null; BigInteger x = null; BigInteger g = null; - while (lines.hasMoreTokens()) - { + while (lines.hasMoreTokens()) { String line = lines.nextToken(); - if (line == null) continue; + if (line == null) + continue; - if (line.startsWith("#")) continue; + if (line.startsWith("#")) + continue; String val = value(line); - if (val == null) continue; + if (val == null) + continue; byte[] data = base64.fromString(val); - if (line.startsWith("Prime(p): ")) - { + if (line.startsWith("Prime(p): ")) { p = new BigInteger(1, data); - } - else if (line.startsWith("Generator(g): ")) - { + } else if (line.startsWith("Generator(g): ")) { g = new BigInteger(1, data); - } - else if (line.startsWith("Private_value(x): ")) - { + } else if (line.startsWith("Private_value(x): ")) { x = new BigInteger(1, data); } } - try - { + try { KeySpec spec = new DHPrivateKeySpec(x, p, g); - if (mDHKeyFactory == null) - { + if (mDHKeyFactory == null) { mDHKeyFactory = KeyFactory.getInstance("DH"); } return mDHKeyFactory.generatePrivate(spec); - } - catch (InvalidKeySpecException e) - { + } catch (InvalidKeySpecException e) { e.printStackTrace(); return null; } @@ -423,57 +386,47 @@ public class DnsKeyConverter * info and translate it into a JCA private key. * * @throws NoSuchAlgorithmException - * if the DSA algorithm is not available. + * if the DSA algorithm is not available. */ private PrivateKey parsePrivateDSA(StringTokenizer lines) - throws NoSuchAlgorithmException - { + throws NoSuchAlgorithmException { BigInteger p = null; BigInteger q = null; BigInteger g = null; BigInteger x = null; - while (lines.hasMoreTokens()) - { + while (lines.hasMoreTokens()) { String line = lines.nextToken(); - if (line == null) continue; + if (line == null) + continue; - if (line.startsWith("#")) continue; + if (line.startsWith("#")) + continue; String val = value(line); - if (val == null) continue; + if (val == null) + continue; byte[] data = base64.fromString(val); - if (line.startsWith("Prime(p): ")) - { + if (line.startsWith("Prime(p): ")) { p = new BigInteger(1, data); - } - else if (line.startsWith("Subprime(q): ")) - { + } else if (line.startsWith("Subprime(q): ")) { q = new BigInteger(1, data); - } - else if (line.startsWith("Base(g): ")) - { + } else if (line.startsWith("Base(g): ")) { g = new BigInteger(1, data); - } - else if (line.startsWith("Private_value(x): ")) - { + } else if (line.startsWith("Private_value(x): ")) { x = new BigInteger(1, data); } } - try - { + try { KeySpec spec = new DSAPrivateKeySpec(x, p, q, g); - if (mDSAKeyFactory == null) - { + if (mDSAKeyFactory == null) { mDSAKeyFactory = KeyFactory.getInstance("DSA"); } return mDSAKeyFactory.generatePrivate(spec); - } - catch (InvalidKeySpecException e) - { + } catch (InvalidKeySpecException e) { e.printStackTrace(); return null; } @@ -482,52 +435,48 @@ public class DnsKeyConverter /** * Given the remaining lines in a BIND9-style ECDSA private key, parse the key * info and translate it into a JCA private key object. + * * @param lines The remaining lines in a private key file (after * @throws NoSuchAlgorithmException - * If elliptic curve is not available. + * If elliptic curve is not available. */ private PrivateKey parsePrivateECDSA(StringTokenizer lines, int algorithm) - throws NoSuchAlgorithmException - { + throws NoSuchAlgorithmException { BigInteger s = null; - while (lines.hasMoreTokens()) - { + while (lines.hasMoreTokens()) { String line = lines.nextToken(); - if (line == null) continue; + if (line == null) + continue; - if (line.startsWith("#")) continue; + if (line.startsWith("#")) + continue; String val = value(line); - if (val == null) continue; + if (val == null) + continue; byte[] data = base64.fromString(val); - if (line.startsWith("PrivateKey: ")) - { + if (line.startsWith("PrivateKey: ")) { s = new BigInteger(1, data); } } - if (mECKeyFactory == null) - { + if (mECKeyFactory == null) { mECKeyFactory = KeyFactory.getInstance("EC"); } ECParameterSpec ec_spec = mAlgorithms.getEllipticCurveParams(algorithm); - if (ec_spec == null) - { + if (ec_spec == null) { throw new NoSuchAlgorithmException("DNSSEC algorithm " + algorithm + - " is not a recognized Elliptic Curve algorithm"); + " is not a recognized Elliptic Curve algorithm"); } KeySpec spec = new ECPrivateKeySpec(s, ec_spec); - try - { + try { return mECKeyFactory.generatePrivate(spec); - } - catch (InvalidKeySpecException e) - { + } catch (InvalidKeySpecException e) { e.printStackTrace(); return null; } @@ -536,52 +485,48 @@ public class DnsKeyConverter /** * Given the remaining lines in a BIND9-style ECDSA private key, parse the key * info and translate it into a JCA private key object. + * * @param lines The remaining lines in a private key file (after * @throws NoSuchAlgorithmException - * If elliptic curve is not available. + * If elliptic curve is not available. */ private PrivateKey parsePrivateEdDSA(StringTokenizer lines, int algorithm) - throws NoSuchAlgorithmException - { + throws NoSuchAlgorithmException { byte[] seed = null; - while (lines.hasMoreTokens()) - { + while (lines.hasMoreTokens()) { String line = lines.nextToken(); - if (line == null) continue; + if (line == null) + continue; - if (line.startsWith("#")) continue; + if (line.startsWith("#")) + continue; String val = value(line); - if (val == null) continue; + if (val == null) + continue; byte[] data = base64.fromString(val); - if (line.startsWith("PrivateKey: ")) - { + if (line.startsWith("PrivateKey: ")) { seed = data; } } - if (mEdKeyFactory == null) - { + if (mEdKeyFactory == null) { mEdKeyFactory = KeyFactory.getInstance("EdDSA"); } EdDSAParameterSpec ed_spec = mAlgorithms.getEdwardsCurveParams(algorithm); - if (ed_spec == null) - { + if (ed_spec == null) { throw new NoSuchAlgorithmException("DNSSEC algorithm " + algorithm + - " is not a recognized Edwards Curve algorithm"); + " is not a recognized Edwards Curve algorithm"); } KeySpec spec = new EdDSAPrivateKeySpec(seed, ed_spec); - try - { + try { return mEdKeyFactory.generatePrivate(spec); - } - catch (InvalidKeySpecException e) - { + } catch (InvalidKeySpecException e) { e.printStackTrace(); return null; } @@ -591,26 +536,16 @@ public class DnsKeyConverter * Given a private key and public key, generate the BIND9 style private key * format. */ - public String generatePrivateKeyString(PrivateKey priv, PublicKey pub, int alg) - { - if (priv instanceof RSAPrivateCrtKey) - { + public String generatePrivateKeyString(PrivateKey priv, PublicKey pub, int alg) { + if (priv instanceof RSAPrivateCrtKey) { return generatePrivateRSA((RSAPrivateCrtKey) priv, alg); - } - else if (priv instanceof DSAPrivateKey && pub instanceof DSAPublicKey) - { + } else if (priv instanceof DSAPrivateKey && pub instanceof DSAPublicKey) { return generatePrivateDSA((DSAPrivateKey) priv, (DSAPublicKey) pub, alg); - } - else if (priv instanceof DHPrivateKey && pub instanceof DHPublicKey) - { + } else if (priv instanceof DHPrivateKey && pub instanceof DHPublicKey) { return generatePrivateDH((DHPrivateKey) priv, (DHPublicKey) pub, alg); - } - else if (priv instanceof ECPrivateKey && pub instanceof ECPublicKey) - { + } else if (priv instanceof ECPrivateKey && pub instanceof ECPublicKey) { return generatePrivateEC((ECPrivateKey) priv, (ECPublicKey) pub, alg); - } - else if (priv instanceof EdDSAPrivateKey && pub instanceof EdDSAPublicKey) - { + } else if (priv instanceof EdDSAPrivateKey && pub instanceof EdDSAPublicKey) { return generatePrivateED((EdDSAPrivateKey) priv, (EdDSAPublicKey) pub, alg); } @@ -620,12 +555,10 @@ public class DnsKeyConverter /** * Convert from 'unsigned' big integer to original 'signed format' in Base64 */ - private static String b64BigInt(BigInteger i) - { + private static String b64BigInt(BigInteger i) { byte[] orig_bytes = i.toByteArray(); - if (orig_bytes[0] != 0 || orig_bytes.length == 1) - { + if (orig_bytes[0] != 0 || orig_bytes.length == 1) { return base64.toString(orig_bytes); } @@ -639,8 +572,7 @@ public class DnsKeyConverter * Given a RSA private key (in Crt format), return the BIND9-style text * encoding. */ - private String generatePrivateRSA(RSAPrivateCrtKey key, int algorithm) - { + private String generatePrivateRSA(RSAPrivateCrtKey key, int algorithm) { StringWriter sw = new StringWriter(); PrintWriter out = new PrintWriter(sw); @@ -669,8 +601,7 @@ public class DnsKeyConverter /** Given a DH key pair, return the BIND9-style text encoding */ private String generatePrivateDH(DHPrivateKey key, DHPublicKey pub, - int algorithm) - { + int algorithm) { StringWriter sw = new StringWriter(); PrintWriter out = new PrintWriter(sw); @@ -693,8 +624,7 @@ public class DnsKeyConverter /** Given a DSA key pair, return the BIND9-style text encoding */ private String generatePrivateDSA(DSAPrivateKey key, DSAPublicKey pub, - int algorithm) - { + int algorithm) { StringWriter sw = new StringWriter(); PrintWriter out = new PrintWriter(sw); @@ -721,8 +651,7 @@ public class DnsKeyConverter * Given an elliptic curve key pair, and the actual algorithm (which will * describe the curve used), return the BIND9-style text encoding. */ - private String generatePrivateEC(ECPrivateKey priv, ECPublicKey pub, int alg) - { + private String generatePrivateEC(ECPrivateKey priv, ECPublicKey pub, int alg) { StringWriter sw = new StringWriter(); PrintWriter out = new PrintWriter(sw); @@ -739,8 +668,7 @@ public class DnsKeyConverter * Given an edwards curve key pair, and the actual algorithm (which will * describe the curve used), return the BIND9-style text encoding. */ - private String generatePrivateED(EdDSAPrivateKey priv, EdDSAPublicKey pub, int alg) - { + private String generatePrivateED(EdDSAPrivateKey priv, EdDSAPublicKey pub, int alg) { StringWriter sw = new StringWriter(); PrintWriter out = new PrintWriter(sw); diff --git a/src/main/java/com/verisignlabs/dnssec/security/DnsKeyPair.java b/src/main/java/com/verisignlabs/dnssec/security/DnsKeyPair.java index 0b94970..ba6d5e7 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/DnsKeyPair.java +++ b/src/main/java/com/verisignlabs/dnssec/security/DnsKeyPair.java @@ -1,6 +1,4 @@ -// $Id$ -// -// Copyright (C) 2001-2003 VeriSign, Inc. +// Copyright (C) 2001-2003, 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 @@ -18,11 +16,21 @@ package com.verisignlabs.dnssec.security; -import java.security.*; -import java.security.interfaces.*; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; import java.util.logging.Logger; -import org.xbill.DNS.*; +import org.xbill.DNS.DClass; +import org.xbill.DNS.DNSKEYRecord; +import org.xbill.DNS.DNSSEC; +import org.xbill.DNS.Name; /** * This class forms the basis for representing public/private key pairs in a @@ -33,36 +41,33 @@ import org.xbill.DNS.*; * * JCA == Java Cryptography Architecture. * - * @author David Blacka (orig) - * @author $Author$ (latest) - * @version $Revision$ + * @author David Blacka */ // NOTE: this class is designed to do "lazy" evaluation of it's // various cached objects and format conversions, so methods should // avoid direct access to the member variables. -public class DnsKeyPair -{ +public class DnsKeyPair { /** This is the real (base) encoding of the public key. */ - protected DNSKEYRecord mPublicKeyRecord; + protected DNSKEYRecord mPublicKeyRecord; /** * This is a pre-calculated cache of the DNSKEYRecord converted into a JCA * public key. */ - private PublicKey mPublicKey; + private PublicKey mPublicKey; /** * The private key in Base64 encoded format. This version is presumed to be * opaque, so no attempts will be made to convert it to a JCA private key. */ - protected String mPrivateKeyString; + protected String mPrivateKeyString; /** * The private key in JCA format. This is the base encoding for instances where * JCA private keys are used. */ - protected PrivateKey mPrivateKey; + protected PrivateKey mPrivateKey; /** The local key converter. */ protected DnsKeyConverter mKeyConverter; @@ -70,57 +75,51 @@ public class DnsKeyPair /** * a cached Signature used for signing (initialized with the private key) */ - protected Signature mSigner; + protected Signature mSigner; /** * a caches Signature used for verifying (initialized with the public key) */ - protected Signature mVerifier; + protected Signature mVerifier; - private Logger log; + private Logger log; - public DnsKeyPair() - { + public DnsKeyPair() { log = Logger.getLogger(this.getClass().toString()); } - public DnsKeyPair(DNSKEYRecord keyRecord, PrivateKey privateKey) - { + public DnsKeyPair(DNSKEYRecord keyRecord, PrivateKey privateKey) { this(); setDNSKEYRecord(keyRecord); setPrivate(privateKey); } - public DnsKeyPair(DNSKEYRecord keyRecord, String privateKeyString) - { + public DnsKeyPair(DNSKEYRecord keyRecord, String privateKeyString) { this(); setDNSKEYRecord(keyRecord); setPrivateKeyString(privateKeyString); } - public DnsKeyPair(DNSKEYRecord keyRecord) - { + public DnsKeyPair(DNSKEYRecord keyRecord) { this(); setDNSKEYRecord(keyRecord); setPrivateKeyString(null); } public DnsKeyPair(Name keyName, int algorithm, PublicKey publicKey, - PrivateKey privateKey) - { + PrivateKey privateKey) { this(); DnsKeyConverter conv = new DnsKeyConverter(); DNSKEYRecord keyrec = conv.generateDNSKEYRecord(keyName, DClass.IN, 0, 0, - algorithm, publicKey); + algorithm, publicKey); setDNSKEYRecord(keyrec); setPrivate(privateKey); } - public DnsKeyPair(DnsKeyPair pair) - { + public DnsKeyPair(DnsKeyPair pair) { this(); setDNSKEYRecord(pair.getDNSKEYRecord()); @@ -129,10 +128,8 @@ public class DnsKeyPair } /** @return cached DnsKeyConverter object. */ - protected DnsKeyConverter getKeyConverter() - { - if (mKeyConverter == null) - { + protected DnsKeyConverter getKeyConverter() { + if (mKeyConverter == null) { mKeyConverter = new DnsKeyConverter(); } @@ -140,8 +137,7 @@ public class DnsKeyPair } /** @return the appropriate Signature object for this keypair. */ - protected Signature getSignature() - { + protected Signature getSignature() { DnsKeyAlgorithm algorithms = DnsKeyAlgorithm.getInstance(); return algorithms.getSignature(getDNSKEYAlgorithm()); } @@ -149,17 +145,12 @@ public class DnsKeyPair /** * @return the public key, translated from the KEYRecord, if necessary. */ - public PublicKey getPublic() - { - if (mPublicKey == null && getDNSKEYRecord() != null) - { - try - { + public PublicKey getPublic() { + if (mPublicKey == null && getDNSKEYRecord() != null) { + try { DnsKeyConverter conv = getKeyConverter(); setPublic(conv.parseDNSKEYRecord(getDNSKEYRecord())); - } - catch (NoSuchAlgorithmException e) - { + } catch (NoSuchAlgorithmException e) { log.severe(e.toString()); return null; } @@ -171,18 +162,15 @@ public class DnsKeyPair /** * sets the public key. This method is generally not used directly. */ - protected void setPublic(PublicKey k) - { + protected void setPublic(PublicKey k) { mPublicKey = k; } /** @return the private key. */ - public PrivateKey getPrivate() - { + public PrivateKey getPrivate() { // attempt to convert the private key string format into a JCA // private key. - if (mPrivateKey == null && mPrivateKeyString != null) - { + if (mPrivateKey == null && mPrivateKeyString != null) { mPrivateKey = BINDKeyUtils.convertPrivateKeyString(mPrivateKeyString); } @@ -190,8 +178,7 @@ public class DnsKeyPair } /** sets the private key */ - public void setPrivate(PrivateKey k) - { + public void setPrivate(PrivateKey k) { mPrivateKey = k; } @@ -199,30 +186,27 @@ public class DnsKeyPair * @return the opaque private key string, null if one doesn't exist. * @throws NoSuchAlgorithmException */ - public String getPrivateKeyString() - { - if (mPrivateKeyString == null && mPrivateKey != null) - { + public String getPrivateKeyString() { + if (mPrivateKeyString == null && mPrivateKey != null) { PublicKey pub = getPublic(); mPrivateKeyString = BINDKeyUtils.convertPrivateKey(mPrivateKey, pub, - getDNSKEYAlgorithm()); + getDNSKEYAlgorithm()); } return mPrivateKeyString; } /** sets the opaque private key string. */ - public void setPrivateKeyString(String p) - { + public void setPrivateKeyString(String p) { mPrivateKeyString = p; } /** @return the private key in an encoded form (normally PKCS#8). */ - public byte[] getEncodedPrivate() - { + public byte[] getEncodedPrivate() { PrivateKey priv = getPrivate(); - if (priv != null) return priv.getEncoded(); - return null; + if (priv != null) + return priv.getEncoded(); + return new byte[0]; } /** @@ -230,20 +214,17 @@ public class DnsKeyPair * that the public key already be assigned. Currently it can only handle DSA * and RSA keys. */ - public void setEncodedPrivate(byte[] encoded) - { + public void setEncodedPrivate(byte[] encoded) { int alg = getDNSKEYAlgorithm(); - if (alg >= 0) - { + if (alg >= 0) { DnsKeyConverter conv = getKeyConverter(); setPrivate(conv.convertEncodedPrivateKey(encoded, alg)); } } /** @return the public DNSKEY record */ - public DNSKEYRecord getDNSKEYRecord() - { + public DNSKEYRecord getDNSKEYRecord() { return mPublicKeyRecord; } @@ -251,25 +232,17 @@ public class DnsKeyPair * @return a Signature object initialized for signing, or null if this key * pair does not have a valid private key. */ - public Signature getSigner() - { - if (mSigner == null) - { + public Signature getSigner() { + if (mSigner == null) { mSigner = getSignature(); PrivateKey priv = getPrivate(); - if (mSigner != null && priv != null) - { - try - { + if (mSigner != null && priv != null) { + try { mSigner.initSign(priv); - } - catch (InvalidKeyException e) - { + } catch (InvalidKeyException e) { log.severe("Signature error: " + e); } - } - else - { + } else { // do not return an uninitialized signer. return null; } @@ -283,24 +256,16 @@ public class DnsKeyPair * pair does not have a valid public key. * @throws NoSuchAlgorithmException */ - public Signature getVerifier() - { - if (mVerifier == null) - { + public Signature getVerifier() { + if (mVerifier == null) { mVerifier = getSignature(); PublicKey pk = getPublic(); - if (mVerifier != null && pk != null) - { - try - { + if (mVerifier != null && pk != null) { + try { mVerifier.initVerify(pk); + } catch (InvalidKeyException e) { } - catch (InvalidKeyException e) - { - } - } - else - { + } else { // do not return an uninitialized verifier return null; } @@ -310,47 +275,48 @@ public class DnsKeyPair } /** sets the public key record */ - public void setDNSKEYRecord(DNSKEYRecord r) - { + public void setDNSKEYRecord(DNSKEYRecord r) { mPublicKeyRecord = r; // force the conversion to PublicKey: mPublicKey = null; } - public Name getDNSKEYName() - { + public Name getDNSKEYName() { DNSKEYRecord kr = getDNSKEYRecord(); - if (kr != null) return kr.getName(); + if (kr != null) + return kr.getName(); return null; } - public int getDNSKEYAlgorithm() - { + public int getDNSKEYAlgorithm() { DNSKEYRecord kr = getDNSKEYRecord(); - if (kr != null) return kr.getAlgorithm(); + if (kr != null) + return kr.getAlgorithm(); PublicKey pk = getPublic(); - if (pk != null) - { + if (pk != null) { // currently, alg 5 is the default over alg 1 (RSASHA1). - if (pk instanceof RSAPublicKey) return DNSSEC.Algorithm.RSASHA1; - if (pk instanceof DSAPublicKey) return DNSSEC.Algorithm.DSA; + if (pk instanceof RSAPublicKey) + return DNSSEC.Algorithm.RSASHA1; + if (pk instanceof DSAPublicKey) + return DNSSEC.Algorithm.DSA; } PrivateKey priv = getPrivate(); - if (priv != null) - { - if (priv instanceof RSAPrivateKey) return DNSSEC.Algorithm.RSASHA1; - if (priv instanceof DSAPrivateKey) return DNSSEC.Algorithm.DSA; + if (priv != null) { + if (priv instanceof RSAPrivateKey) + return DNSSEC.Algorithm.RSASHA1; + if (priv instanceof DSAPrivateKey) + return DNSSEC.Algorithm.DSA; } return -1; } - public int getDNSKEYFootprint() - { + public int getDNSKEYFootprint() { DNSKEYRecord kr = getDNSKEYRecord(); - if (kr != null) return kr.getFootprint(); + if (kr != null) + return kr.getFootprint(); return -1; } } diff --git a/src/main/java/com/verisignlabs/dnssec/security/DnsSecVerifier.java b/src/main/java/com/verisignlabs/dnssec/security/DnsSecVerifier.java index 150a068..1a9994e 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/DnsSecVerifier.java +++ b/src/main/java/com/verisignlabs/dnssec/security/DnsSecVerifier.java @@ -1,6 +1,4 @@ -// $Id$ -// -// Copyright (C) 2001-2003 VeriSign, Inc. +// Copyright (C) 2001-2003, 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 @@ -24,14 +22,17 @@ import java.security.GeneralSecurityException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; +import java.time.Instant; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.logging.Logger; -import org.xbill.DNS.*; +import org.xbill.DNS.DNSKEYRecord; +import org.xbill.DNS.DNSSEC; +import org.xbill.DNS.Name; +import org.xbill.DNS.RRSIGRecord; +import org.xbill.DNS.RRset; /** * A class for performing basic DNSSEC verification. The DNSJAVA package @@ -39,62 +40,46 @@ import org.xbill.DNS.*; * timing "fudge" factors and logging more specifically why an RRset did not * validate. * - * @author David Blacka (original) - * @author $Author$ - * @version $Revision$ + * @author David Blacka */ -public class DnsSecVerifier -{ +public class DnsSecVerifier { - private class TrustedKeyStore - { + private class TrustedKeyStore { // for now, this is implemented as a hash table of lists of // DnsKeyPair objects (obviously, all of them will not have // private keys). private HashMap> mKeyMap; - public TrustedKeyStore() - { - mKeyMap = new HashMap>(); + public TrustedKeyStore() { + mKeyMap = new HashMap<>(); } - public void add(DnsKeyPair pair) - { + public void add(DnsKeyPair pair) { String n = pair.getDNSKEYName().toString().toLowerCase(); - List l = mKeyMap.get(n); - if (l == null) - { - l = new ArrayList(); - mKeyMap.put(n, l); - } - + List l = mKeyMap.computeIfAbsent(n, k -> new ArrayList<>()); l.add(pair); } - public void add(DNSKEYRecord keyrec) - { + public void add(DNSKEYRecord keyrec) { DnsKeyPair pair = new DnsKeyPair(keyrec, (PrivateKey) null); add(pair); } - public void add(Name name, int algorithm, PublicKey key) - { + public void add(Name name, int algorithm, PublicKey key) { DnsKeyPair pair = new DnsKeyPair(name, algorithm, key, null); add(pair); } - public DnsKeyPair find(Name name, int algorithm, int keyid) - { + public DnsKeyPair find(Name name, int algorithm, int keyid) { String n = name.toString().toLowerCase(); List l = mKeyMap.get(n); - if (l == null) return null; + if (l == null) + return null; // FIXME: this algorithm assumes that name+alg+footprint is // unique, which isn't necessarily true. - for (DnsKeyPair p : l) - { - if (p.getDNSKEYAlgorithm() == algorithm && p.getDNSKEYFootprint() == keyid) - { + for (DnsKeyPair p : l) { + if (p.getDNSKEYAlgorithm() == algorithm && p.getDNSKEYFootprint() == keyid) { return p; } } @@ -103,126 +88,112 @@ public class DnsSecVerifier } private TrustedKeyStore mKeyStore; - private int mStartFudge = 0; - private int mExpireFudge = 0; - private boolean mVerifyAllSigs = false; - private boolean mIgnoreTime = false; + private int mStartFudge = 0; + private int mExpireFudge = 0; + private boolean mVerifyAllSigs = false; + private boolean mIgnoreTime = false; - private Logger log; + private Logger log; - public DnsSecVerifier() - { + public DnsSecVerifier() { log = Logger.getLogger(this.getClass().toString()); mKeyStore = new TrustedKeyStore(); } - public void addTrustedKey(DNSKEYRecord keyrec) - { + public void addTrustedKey(DNSKEYRecord keyrec) { mKeyStore.add(keyrec); } - public void addTrustedKey(DnsKeyPair pair) - { + public void addTrustedKey(DnsKeyPair pair) { mKeyStore.add(pair); } - public void addTrustedKey(Name name, int algorithm, PublicKey key) - { + public void addTrustedKey(Name name, int algorithm, PublicKey key) { mKeyStore.add(name, algorithm, key); } - public void addTrustedKey(Name name, PublicKey key) - { + public void addTrustedKey(Name name, PublicKey key) { mKeyStore.add(name, 0, key); } - public void setExpireFudge(int fudge) - { + public void setExpireFudge(int fudge) { mExpireFudge = fudge; } - public void setStartFudge(int fudge) - { + public void setStartFudge(int fudge) { mStartFudge = fudge; } - public void setVerifyAllSigs(boolean v) - { + public void setVerifyAllSigs(boolean v) { mVerifyAllSigs = v; } - public void setIgnoreTime(boolean v) - { + public void setIgnoreTime(boolean v) { mIgnoreTime = v; } - private DnsKeyPair findKey(Name name, int algorithm, int footprint) - { + private DnsKeyPair findKey(Name name, int algorithm, int footprint) { return mKeyStore.find(name, algorithm, footprint); } - private boolean validateSignature(RRset rrset, RRSIGRecord sigrec, List reasons) - { - if (rrset == null || sigrec == null) return false; - if (!rrset.getName().equals(sigrec.getName())) - { + private boolean validateSignature(RRset rrset, RRSIGRecord sigrec, List reasons) { + if (rrset == null || sigrec == null) + return false; + if (!rrset.getName().equals(sigrec.getName())) { log.fine("Signature name does not match RRset name"); - if (reasons != null) reasons.add("Signature name does not match RRset name"); + if (reasons != null) + reasons.add("Signature name does not match RRset name"); return false; } - if (rrset.getType() != sigrec.getTypeCovered()) - { + if (rrset.getType() != sigrec.getTypeCovered()) { log.fine("Signature type does not match RRset type"); - if (reasons != null) reasons.add("Signature type does not match RRset type"); + if (reasons != null) + reasons.add("Signature type does not match RRset type"); } - if (mIgnoreTime) return true; + if (mIgnoreTime) + return true; - Date now = new Date(); - Date start = sigrec.getTimeSigned(); - Date expire = sigrec.getExpire(); + Instant now = Instant.now(); + Instant start = sigrec.getTimeSigned(); + Instant expire = sigrec.getExpire(); - if (mStartFudge >= 0) - { - if (mStartFudge > 0) - { - start = new Date(start.getTime() - ((long) mStartFudge * 1000)); + if (mStartFudge >= 0) { + if (mStartFudge > 0) { + start = start.minusSeconds(mStartFudge); } - if (now.before(start)) - { + if (now.isBefore(start)) { log.fine("Signature is not yet valid"); - if (reasons != null) reasons.add("Signature not yet valid"); + if (reasons != null) + reasons.add("Signature not yet valid"); return false; } } - if (mExpireFudge >= 0) - { - if (mExpireFudge > 0) - { - expire = new Date(expire.getTime() + ((long) mExpireFudge * 1000)); + if (mExpireFudge >= 0) { + if (mExpireFudge > 0) { + expire = expire.plusSeconds(mExpireFudge); } - if (now.after(expire)) - { + if (now.isAfter(expire)) { log.fine("Signature has expired (now = " + now + ", sig expires = " + expire); - if (reasons != null) reasons.add("Signature has expired."); + if (reasons != null) + reasons.add("Signature has expired."); return false; } } - if (rrset.getTTL() > sigrec.getOrigTTL()) - { + if (rrset.getTTL() > sigrec.getOrigTTL()) { log.fine("RRset's TTL is greater than the Signature's orignal TTL"); - if (reasons != null) reasons.add("RRset TTL greater than RRSIG origTTL"); + if (reasons != null) + reasons.add("RRset TTL greater than RRSIG origTTL"); return false; } return true; } - public boolean verifySignature(RRset rrset, RRSIGRecord sigrec) - { + public boolean verifySignature(RRset rrset, RRSIGRecord sigrec) { return verifySignature(rrset, sigrec, null); } @@ -232,23 +203,22 @@ public class DnsSecVerifier * @return true if the signature verified, false if it did * not verify (for any reason, including not finding the DNSKEY.) */ - public boolean verifySignature(RRset rrset, RRSIGRecord sigrec, List reasons) - { + public boolean verifySignature(RRset rrset, RRSIGRecord sigrec, List reasons) { boolean result = validateSignature(rrset, sigrec, reasons); - if (!result) return result; + if (!result) + return result; DnsKeyPair keypair = findKey(sigrec.getSigner(), sigrec.getAlgorithm(), - sigrec.getFootprint()); + sigrec.getFootprint()); - if (keypair == null) - { - if (reasons != null) reasons.add("Could not find matching trusted key"); + if (keypair == null) { + if (reasons != null) + reasons.add("Could not find matching trusted key"); log.fine("could not find matching trusted key"); return false; } - try - { + try { byte[] data = SignUtils.generateSigData(rrset, sigrec); DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance(); @@ -258,35 +228,30 @@ public class DnsSecVerifier byte[] sig = sigrec.getSignature(); - if (algs.baseType(sigrec.getAlgorithm()) == DnsKeyAlgorithm.DSA) - { + if (algs.baseType(sigrec.getAlgorithm()) == DnsKeyAlgorithm.DSA) { sig = SignUtils.convertDSASignature(sig); } - if (sigrec.getAlgorithm() == DNSSEC.Algorithm.ECDSAP256SHA256 || - sigrec.getAlgorithm() == DNSSEC.Algorithm.ECDSAP384SHA384) - { + if (sigrec.getAlgorithm() == DNSSEC.Algorithm.ECDSAP256SHA256 || + sigrec.getAlgorithm() == DNSSEC.Algorithm.ECDSAP384SHA384) { sig = SignUtils.convertECDSASignature(sig); } - if (!signer.verify(sig)) - { - if (reasons != null) reasons.add("Signature failed to verify cryptographically"); + if (!signer.verify(sig)) { + if (reasons != null) + reasons.add("Signature failed to verify cryptographically"); log.fine("Signature failed to verify cryptographically"); return false; } return true; - } - catch (IOException e) - { + } catch (IOException e) { log.severe("I/O error: " + e); - } - catch (GeneralSecurityException e) - { + } catch (GeneralSecurityException e) { log.severe("Security error: " + e); } - if (reasons != null) reasons.add("Signature failed to verify due to exception"); + if (reasons != null) + reasons.add("Signature failed to verify due to exception"); log.fine("Signature failed to verify due to exception"); return false; } @@ -296,30 +261,24 @@ public class DnsSecVerifier * * @return true if the set verified, false if it did not. */ - public boolean verify(RRset rrset) - { + public boolean verify(RRset rrset) { boolean result = mVerifyAllSigs ? true : false; - Iterator i = rrset.sigs(); - - if (!i.hasNext()) - { + if (rrset.sigs().isEmpty()) { log.fine("RRset failed to verify due to lack of signatures"); return false; } - - while (i.hasNext()) - { - RRSIGRecord sigrec = (RRSIGRecord) i.next(); + for (RRSIGRecord sigrec : rrset.sigs()) { boolean res = verifySignature(rrset, sigrec); - // If not requiring all signature to validate, then any successful validation is sufficient. - if (!mVerifyAllSigs && res) return res; + // If not requiring all signature to validate, then any successful validation is + // sufficient. + if (!mVerifyAllSigs && res) + return res; // Otherwise, note if a signature failed to validate. - if (mVerifyAllSigs && !res) - { + if (mVerifyAllSigs && !res) { result = res; } } diff --git a/src/main/java/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java b/src/main/java/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java index ebf5dc6..34b36b8 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java +++ b/src/main/java/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java @@ -1,6 +1,4 @@ -// $Id$ -// -// Copyright (C) 2001-2003, 2009 VeriSign, Inc. +// Copyright (C) 2001-2003, 2009, 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 @@ -25,15 +23,20 @@ import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.Signature; import java.security.interfaces.DSAPublicKey; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; -import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.logging.Logger; -import org.xbill.DNS.*; +import org.xbill.DNS.DNSKEYRecord; +import org.xbill.DNS.DNSSEC; +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 org.xbill.DNS.utils.hexdump; /** @@ -43,26 +46,21 @@ import org.xbill.DNS.utils.hexdump; * the ability to sign an entire zone. It primarily glues together the more * basic primitives found in {@link SignUtils}. * - * @author David Blacka (original) - * @author $Author$ - * @version $Revision$ + * @author David Blacka */ -public class JCEDnsSecSigner -{ +public class JCEDnsSecSigner { private DnsKeyConverter mKeyConverter; - private boolean mVerboseSigning = false; + private boolean mVerboseSigning = false; - private Logger log = Logger.getLogger(this.getClass().toString()); + private Logger log = Logger.getLogger(this.getClass().toString()); - public JCEDnsSecSigner() - { + public JCEDnsSecSigner() { this.mKeyConverter = null; this.mVerboseSigning = false; } - public JCEDnsSecSigner(boolean verboseSigning) - { + public JCEDnsSecSigner(boolean verboseSigning) { this.mKeyConverter = null; this.mVerboseSigning = verboseSigning; } @@ -71,38 +69,38 @@ public class JCEDnsSecSigner * Cryptographically generate a new DNSSEC key. * * @param owner - * the KEY RR's owner name. + * the KEY RR's owner name. * @param ttl - * the KEY RR's TTL. + * the KEY RR's TTL. * @param dclass - * the KEY RR's DNS class. + * the KEY RR's DNS class. * @param algorithm - * the DNSSEC algorithm (RSAMD5, RSASHA1, or DSA). + * the DNSSEC algorithm (RSASHA258, RSASHA512, + * ECDSAP256, etc.) * @param flags - * any flags for the KEY RR. + * any flags for the KEY RR. * @param keysize - * the size of the key to generate. + * the size of the key to generate. * @param useLargeExponent - * if generating an RSA key, use the large exponent. + * if generating an RSA key, use the large exponent. * @return a DnsKeyPair with the public and private keys populated. */ public DnsKeyPair generateKey(Name owner, long ttl, int dclass, int algorithm, - int flags, int keysize, boolean useLargeExponent) - throws NoSuchAlgorithmException - { + int flags, int keysize, boolean useLargeExponent) + throws NoSuchAlgorithmException { DnsKeyAlgorithm algorithms = DnsKeyAlgorithm.getInstance(); - if (ttl < 0) ttl = 86400; // set to a reasonable default. + if (ttl < 0) + ttl = 86400; // set to a reasonable default. KeyPair pair = algorithms.generateKeyPair(algorithm, keysize, useLargeExponent); - if (mKeyConverter == null) - { + if (mKeyConverter == null) { mKeyConverter = new DnsKeyConverter(); } DNSKEYRecord keyrec = mKeyConverter.generateDNSKEYRecord(owner, dclass, ttl, flags, - algorithm, pair.getPublic()); + algorithm, pair.getPublic()); DnsKeyPair dnspair = new DnsKeyPair(); dnspair.setDNSKEYRecord(keyrec); @@ -116,28 +114,30 @@ public class JCEDnsSecSigner * Sign an RRset. * * @param rrset - * the RRset to sign -- any existing signatures are ignored. + * the RRset to sign -- any existing signatures are ignored. * @param keypars - * a list of DnsKeyPair objects containing private keys. + * a list of DnsKeyPair objects containing private keys. * @param start - * the inception time for the resulting RRSIG records. + * the inception time for the resulting RRSIG records. * @param expire - * the expiration time for the resulting RRSIG records. + * the expiration time for the resulting RRSIG records. * @return a list of RRSIGRecord objects. */ - public List signRRset(RRset rrset, List keypairs, Date start, - Date expire) throws IOException, - GeneralSecurityException - { - if (rrset == null || keypairs == null) return null; + public List signRRset(RRset rrset, List keypairs, Instant start, + Instant expire) throws IOException, + GeneralSecurityException { + if (rrset == null || keypairs == null) + return null; // default start to now, expire to start + 1 second. - if (start == null) start = new Date(); - if (expire == null) expire = new Date(start.getTime() + 1000L); - if (keypairs.size() == 0) return null; + if (start == null) + start = Instant.now(); + if (expire == null) + expire = start.plusSeconds(1); + if (keypairs.size() == 0) + return null; - if (mVerboseSigning) - { + if (mVerboseSigning) { log.info("Signing RRset:"); log.info(ZoneUtils.rrsetToString(rrset, false)); } @@ -148,17 +148,16 @@ public class JCEDnsSecSigner ArrayList sigs = new ArrayList(keypairs.size()); // for each keypair, sign the RRset. - for (DnsKeyPair pair : keypairs) - { + for (DnsKeyPair pair : keypairs) { DNSKEYRecord keyrec = pair.getDNSKEYRecord(); - if (keyrec == null) continue; + if (keyrec == null) + continue; RRSIGRecord presig = SignUtils.generatePreRRSIG(rrset, keyrec, start, expire, - rrset.getTTL()); + rrset.getTTL()); byte[] sign_data = SignUtils.generateSigData(rrset_data, presig); - if (mVerboseSigning) - { + if (mVerboseSigning) { log.info("Canonical pre-signature data to sign with key " + keyrec.getName().toString() + "/" + keyrec.getAlgorithm() + "/" + keyrec.getFootprint() + ":"); @@ -167,8 +166,7 @@ public class JCEDnsSecSigner Signature signer = pair.getSigner(); - if (signer == null) - { + if (signer == null) { // debug log.fine("missing private key that goes with:\n" + pair.getDNSKEYRecord()); throw new GeneralSecurityException("cannot sign without a valid Signer " @@ -179,28 +177,24 @@ public class JCEDnsSecSigner signer.update(sign_data); byte[] sig = signer.sign(); - if (mVerboseSigning) - { + if (mVerboseSigning) { log.info("Raw Signature:"); log.info(hexdump.dump(null, sig)); } DnsKeyAlgorithm algs = DnsKeyAlgorithm.getInstance(); // Convert to RFC 2536 format, if necessary. - if (algs.baseType(pair.getDNSKEYAlgorithm()) == DnsKeyAlgorithm.DSA) - { + if (algs.baseType(pair.getDNSKEYAlgorithm()) == DnsKeyAlgorithm.DSA) { DSAPublicKey pk = (DSAPublicKey) pair.getPublic(); sig = SignUtils.convertDSASignature(pk.getParams(), sig); } // Convert to RFC 6605, etc format if (pair.getDNSKEYAlgorithm() == DNSSEC.Algorithm.ECDSAP256SHA256 || - pair.getDNSKEYAlgorithm() == DNSSEC.Algorithm.ECDSAP384SHA384) - { + pair.getDNSKEYAlgorithm() == DNSSEC.Algorithm.ECDSAP384SHA384) { sig = SignUtils.convertECDSASignature(pair.getDNSKEYAlgorithm(), sig); } RRSIGRecord sigrec = SignUtils.generateRRSIG(sig, presig); - if (mVerboseSigning) - { + if (mVerboseSigning) { log.info("RRSIG:\n" + sigrec); } sigs.add(sigrec); @@ -213,29 +207,26 @@ public class JCEDnsSecSigner * Create a completely self-signed DNSKEY RRset. * * @param keypairs - * the public & private keypairs to use in the keyset. + * the public & private keypairs to use in the keyset. * @param start - * the RRSIG inception time. + * the RRSIG inception time. * @param expire - * the RRSIG expiration time. + * the RRSIG expiration time. * @return a signed RRset. */ - public RRset makeKeySet(List keypairs, Date start, Date expire) - throws IOException, GeneralSecurityException - { + public RRset makeKeySet(List keypairs, Instant start, Instant expire) + throws IOException, GeneralSecurityException { // Generate a KEY RR set to sign. RRset keyset = new RRset(); - for (DnsKeyPair pair : keypairs) - { + for (DnsKeyPair pair : keypairs) { keyset.addRR(pair.getDNSKEYRecord()); } List records = signRRset(keyset, keypairs, start, expire); - for (RRSIGRecord r : records) - { + for (RRSIGRecord r : records) { keyset.addRR(r); } @@ -246,63 +237,58 @@ public class JCEDnsSecSigner * Conditionally sign an RRset and add it to the toList. * * @param toList - * the list to which we are adding the processed RRsets. + * the list to which we are adding the processed RRsets. * @param zonename - * the zone apex name. + * the zone apex name. * @param rrset - * the RRset under consideration. + * the RRset under consideration. * @param kskpairs - * the List of KSKs.. + * the List of KSKs.. * @param zskpairs - * the List of zone keys. + * the List of zone keys. * @param start - * the RRSIG inception time. + * the RRSIG inception time. * @param expire - * the RRSIG expiration time. + * the RRSIG expiration time. * @param fullySignKeyset - * if true, sign the zone apex keyset with both KSKs and ZSKs. + * if true, sign the zone apex keyset with both KSKs and + * ZSKs. * @param last_cut - * the name of the last delegation point encountered. + * the name of the last delegation point encountered. * * @return the name of the new last_cut. */ - @SuppressWarnings("unchecked") private Name addRRset(List toList, Name zonename, RRset rrset, - List kskpairs, List zskpairs, Date start, - Date expire, boolean fullySignKeyset, Name last_cut, - Name last_dname) throws IOException, GeneralSecurityException - { + List kskpairs, List zskpairs, Instant start, + Instant expire, boolean fullySignKeyset, Name last_cut, + Name last_dname) throws IOException, GeneralSecurityException { // add the records themselves - for (Iterator i = rrset.rrs(); i.hasNext();) - { - toList.add(i.next()); - } + rrset.rrs().forEach(record -> { + toList.add(record); + }); int type = SignUtils.recordSecType(zonename, rrset.getName(), rrset.getType(), - last_cut, last_dname); + last_cut, last_dname); // we don't sign non-normal sets (delegations, glue, invalid). - if (type == SignUtils.RR_DELEGATION) - { + if (type == SignUtils.RR_DELEGATION) { return rrset.getName(); } - if (type == SignUtils.RR_GLUE || type == SignUtils.RR_INVALID) - { + if (type == SignUtils.RR_GLUE || type == SignUtils.RR_INVALID) { return last_cut; } // check for the zone apex keyset. - if (rrset.getName().equals(zonename) && rrset.getType() == Type.DNSKEY) - { + if (rrset.getName().equals(zonename) && rrset.getType() == Type.DNSKEY) { // if we have ksks, sign the keyset with them, otherwise we will just sign // them with the zsks. - if (kskpairs != null && kskpairs.size() > 0) - { + if (kskpairs != null && kskpairs.size() > 0) { List sigs = signRRset(rrset, kskpairs, start, expire); toList.addAll(sigs); // If we aren't going to sign with all the keys, bail out now. - if (!fullySignKeyset) return last_cut; + if (!fullySignKeyset) + return last_cut; } } @@ -314,10 +300,10 @@ public class JCEDnsSecSigner } // Various NSEC/NSEC3 generation modes - private static final int NSEC_MODE = 0; - private static final int NSEC3_MODE = 1; + private static final int NSEC_MODE = 0; + private static final int NSEC3_MODE = 1; private static final int NSEC3_OPTOUT_MODE = 2; - private static final int NSEC_EXP_OPT_IN = 3; + private static final int NSEC_EXP_OPT_IN = 3; /** * Master zone signing method. This method handles all of the different zone @@ -326,41 +312,48 @@ public class JCEDnsSecSigner * appropriate public signZone* methods instead of this. * * @param zonename - * The name of the zone + * The name of the zone * @param records - * The records comprising the zone. They do not have to be in any - * particular order, as this method will order them as necessary. + * The records comprising the zone. They do not have to + * be in any + * particular order, as this method will order them as + * necessary. * @param kskpairs - * The key pairs designated as "key signing keys" + * The key pairs designated as "key signing keys" * @param zskpairs - * The key pairs designated as "zone signing keys" + * The key pairs designated as "zone signing keys" * @param start - * The RRSIG inception time + * The RRSIG inception time * @param expire - * The RRSIG expiration time + * The RRSIG expiration time * @param fullySignKeyset - * If true, all keys (ksk or zsk) will sign the DNSKEY RRset. If - * false, only the ksks will sign it. + * If true, all keys (ksk or zsk) will sign the DNSKEY + * RRset. If + * false, only the ksks will sign it. * @param ds_digest_alg - * The hash algorithm to use for generating DS records - * (DSRecord.SHA1_DIGEST_ID, e.g.) + * The hash algorithm to use for generating DS records + * (DSRecord.SHA1_DIGEST_ID, e.g.) * @param mode - * The NSEC/NSEC3 generation mode: NSEC_MODE, NSEC3_MODE, - * NSEC3_OPTOUT_MODE, etc. + * The NSEC/NSEC3 generation mode: NSEC_MODE, NSEC3_MODE, + * NSEC3_OPTOUT_MODE, etc. * @param includedNames - * When using an Opt-In/Opt-Out mode, the names listed here will be - * included in the NSEC/NSEC3 chain regardless + * When using an Opt-In/Opt-Out mode, the names listed + * here will be + * included in the NSEC/NSEC3 chain regardless * @param salt - * When using an NSEC3 mode, use this salt. + * When using an NSEC3 mode, use this salt. * @param iterations - * When using an NSEC3 mode, use this number of iterations + * When using an NSEC3 mode, use this number of + * iterations * @param beConservative - * If true, then only turn on the Opt-In flag when there are insecure - * delegations in the span. Currently this only works for - * NSEC_EXP_OPT_IN mode. + * If true, then only turn on the Opt-In flag when there + * are insecure + * delegations in the span. Currently this only works for + * NSEC_EXP_OPT_IN mode. * @param nsec3paramttl - * The TTL to use for the generated NSEC3PARAM record. Negative - * values will use the SOA TTL. + * The TTL to use for the generated NSEC3PARAM record. + * Negative + * values will use the SOA TTL. * @return an ordered list of {@link org.xbill.DNS.Record} objects, * representing the signed zone. * @@ -368,13 +361,12 @@ public class JCEDnsSecSigner * @throws GeneralSecurityException */ private List signZone(Name zonename, List records, - List kskpairs, List zskpairs, - Date start, Date expire, boolean fullySignKeyset, - int ds_digest_alg, int mode, List includedNames, - byte[] salt, int iterations, long nsec3paramttl, - boolean beConservative) throws IOException, - GeneralSecurityException - { + List kskpairs, List zskpairs, + Instant start, Instant expire, boolean fullySignKeyset, + int ds_digest_alg, int mode, List includedNames, + byte[] salt, int iterations, long nsec3paramttl, + boolean beConservative) throws IOException, + GeneralSecurityException { // Remove any existing generated DNSSEC records (NSEC, NSEC3, NSEC3PARAM, // RRSIG) SignUtils.removeGeneratedRecords(zonename, records); @@ -391,8 +383,7 @@ public class JCEDnsSecSigner SignUtils.generateDSRecords(zonename, records, ds_digest_alg); // Generate the NSEC or NSEC3 records based on 'mode' - switch (mode) - { + switch (mode) { case NSEC_MODE: SignUtils.generateNSECRecords(zonename, records); break; @@ -401,11 +392,11 @@ public class JCEDnsSecSigner break; case NSEC3_OPTOUT_MODE: SignUtils.generateOptOutNSEC3Records(zonename, records, includedNames, salt, - iterations, nsec3paramttl); + iterations, nsec3paramttl); break; case NSEC_EXP_OPT_IN: SignUtils.generateOptInNSECRecords(zonename, records, includedNames, - beConservative); + beConservative); break; } @@ -418,21 +409,18 @@ public class JCEDnsSecSigner Name last_cut = null; Name last_dname = null; - for (ListIterator i = records.listIterator(); i.hasNext();) - { + for (ListIterator i = records.listIterator(); i.hasNext();) { Record r = i.next(); // First record - if (rrset.size() == 0) - { + if (rrset.size() == 0) { rrset.addRR(r); continue; } // Current record is part of the current RRset. if (rrset.getName().equals(r.getName()) && rrset.getDClass() == r.getDClass() - && rrset.getType() == r.getType()) - { + && rrset.getType() == r.getType()) { rrset.addRR(r); continue; } @@ -443,8 +431,9 @@ public class JCEDnsSecSigner // add the RRset to the list of signed_records, regardless of // whether or not we actually end up signing the set. last_cut = addRRset(signed_records, zonename, rrset, kskpairs, zskpairs, start, - expire, fullySignKeyset, last_cut, last_dname); - if (rrset.getType() == Type.DNAME) last_dname = rrset.getName(); + expire, fullySignKeyset, last_cut, last_dname); + if (rrset.getType() == Type.DNAME) + last_dname = rrset.getName(); rrset.clear(); rrset.addRR(r); @@ -452,7 +441,7 @@ public class JCEDnsSecSigner // add the last RR set addRRset(signed_records, zonename, rrset, kskpairs, zskpairs, start, expire, - fullySignKeyset, last_cut, last_dname); + fullySignKeyset, last_cut, last_dname); return signed_records; } @@ -461,72 +450,88 @@ public class JCEDnsSecSigner * Given a zone, sign it using standard NSEC records. * * @param zonename - * The name of the zone. + * The name of the zone. * @param records - * The records comprising the zone. They do not have to be in any - * particular order, as this method will order them as necessary. + * The records comprising the zone. They do not have to + * be in any + * particular order, as this method will order them as + * necessary. * @param kskpairs - * The key pairs that are designated as "key signing keys". + * The key pairs that are designated as "key signing + * keys". * @param zskpairs - * This key pairs that are designated as "zone signing keys". + * This key pairs that are designated as "zone signing + * keys". * @param start - * The RRSIG inception time. + * The RRSIG inception time. * @param expire - * The RRSIG expiration time. + * The RRSIG expiration time. * @param fullySignKeyset - * Sign the zone apex keyset with all available keys (instead of just - * the key signing keys). + * Sign the zone apex keyset with all available keys + * (instead of just + * the key signing keys). * @param ds_digest_alg - * The digest algorithm to use when generating DS records. + * The digest algorithm to use when generating DS + * records. * * @return an ordered list of {@link org.xbill.DNS.Record} objects, * representing the signed zone. */ public List signZone(Name zonename, List records, - List kskpairs, List zskpairs, - Date start, Date expire, boolean fullySignKeyset, - int ds_digest_alg) throws IOException, - GeneralSecurityException - { + List kskpairs, List zskpairs, + Instant start, Instant expire, boolean fullySignKeyset, + int ds_digest_alg) throws IOException, + GeneralSecurityException { return signZone(zonename, records, kskpairs, zskpairs, start, expire, - fullySignKeyset, ds_digest_alg, NSEC_MODE, null, null, 0, 0, false); + fullySignKeyset, ds_digest_alg, NSEC_MODE, null, null, 0, 0, false); } /** * Given a zone, sign it using NSEC3 records. * * @param signer - * A signer (utility) object used to actually sign stuff. + * A signer (utility) object used to actually sign stuff. * @param zonename - * The name of the zone being signed. + * The name of the zone being signed. * @param records - * The records comprising the zone. They do not have to be in any - * particular order, as this method will order them as necessary. + * The records comprising the zone. They do not have to + * be in any + * particular order, as this method will order them as + * necessary. * @param kskpairs - * The key pairs that are designated as "key signing keys". + * The key pairs that are designated as "key signing + * keys". * @param zskpairs - * This key pairs that are designated as "zone signing keys". + * This key pairs that are designated as "zone signing + * keys". * @param start - * The RRSIG inception time. + * The RRSIG inception time. * @param expire - * The RRSIG expiration time. + * The RRSIG expiration time. * @param fullySignKeyset - * If true then the DNSKEY RRset will be signed by all available - * keys, if false, only the key signing keys. + * If true then the DNSKEY RRset will be signed by all + * available + * keys, if false, only the key signing keys. * @param useOptOut - * If true, insecure delegations will be omitted from the NSEC3 - * chain, and all NSEC3 records will have the Opt-Out flag set. + * If true, insecure delegations will be omitted from the + * NSEC3 + * chain, and all NSEC3 records will have the Opt-Out + * flag set. * @param includedNames - * A list of names to include in the NSEC3 chain regardless. + * A list of names to include in the NSEC3 chain + * regardless. * @param salt - * The salt to use for the NSEC3 hashing. null means no salt. + * The salt to use for the NSEC3 hashing. null means no + * salt. * @param iterations - * The number of iterations to use for the NSEC3 hashing. + * The number of iterations to use for the NSEC3 hashing. * @param ds_digest_alg - * The digest algorithm to use when generating DS records. + * The digest algorithm to use when generating DS + * records. * @param nsec3paramttl - * The TTL to use for the generated NSEC3PARAM record. Negative - * values will use the SOA TTL. + * The TTL to use for the generated NSEC3PARAM record. + * Negative + * values will use the SOA TTL. * @return an ordered list of {@link org.xbill.DNS.Record} objects, * representing the signed zone. * @@ -534,24 +539,20 @@ public class JCEDnsSecSigner * @throws GeneralSecurityException */ public List signZoneNSEC3(Name zonename, List records, - List kskpairs, List zskpairs, - Date start, Date expire, boolean fullySignKeyset, - boolean useOptOut, List includedNames, - byte[] salt, int iterations, int ds_digest_alg, - long nsec3paramttl) throws IOException, - GeneralSecurityException - { - if (useOptOut) - { + List kskpairs, List zskpairs, + Instant start, Instant expire, boolean fullySignKeyset, + boolean useOptOut, List includedNames, + byte[] salt, int iterations, int ds_digest_alg, + long nsec3paramttl) throws IOException, + GeneralSecurityException { + if (useOptOut) { return signZone(zonename, records, kskpairs, zskpairs, start, expire, - fullySignKeyset, ds_digest_alg, NSEC3_OPTOUT_MODE, includedNames, - salt, iterations, nsec3paramttl, false); - } - else - { + fullySignKeyset, ds_digest_alg, NSEC3_OPTOUT_MODE, includedNames, + salt, iterations, nsec3paramttl, false); + } else { return signZone(zonename, records, kskpairs, zskpairs, start, expire, - fullySignKeyset, ds_digest_alg, NSEC3_MODE, null, salt, iterations, - nsec3paramttl, false); + fullySignKeyset, ds_digest_alg, NSEC3_MODE, null, salt, iterations, + nsec3paramttl, false); } } @@ -560,42 +561,49 @@ public class JCEDnsSecSigner * 4956). * * @param zonename - * the name of the zone. + * the name of the zone. * @param records - * the records comprising the zone. They do not have to be in any - * particular order, as this method will order them as necessary. + * the records comprising the zone. They do not have + * to be in any + * particular order, as this method will order them + * as necessary. * @param kskpairs - * the key pairs that are designated as "key signing keys". + * the key pairs that are designated as "key signing + * keys". * @param zskpairs - * this key pairs that are designated as "zone signing keys". + * this key pairs that are designated as "zone + * signing keys". * @param start - * the RRSIG inception time. + * the RRSIG inception time. * @param expire - * the RRSIG expiration time. + * the RRSIG expiration time. * @param useConservativeOptIn - * if true, Opt-In NSEC records will only be generated if there are - * insecure, unsigned delegations in the span. + * if true, Opt-In NSEC records will only be + * generated if there are + * insecure, unsigned delegations in the span. * @param fullySignKeyset - * sign the zone apex keyset with all available keys. + * sign the zone apex keyset with all available + * keys. * @param ds_digest_alg - * The digest algorithm to use when generating DS records. + * The digest algorithm to use when generating DS + * records. * @param NSECIncludeNames - * names that are to be included in the NSEC chain regardless. This - * may be null. + * names that are to be included in the NSEC chain + * regardless. This + * may be null. * @return an ordered list of {@link org.xbill.DNS.Record} objects, * representing the signed zone. */ public List signZoneOptIn(Name zonename, List records, - List kskpairs, List zskpairs, - Date start, Date expire, - boolean useConservativeOptIn, - boolean fullySignKeyset, List NSECIncludeNames, - int ds_digest_alg) throws IOException, - GeneralSecurityException - { + List kskpairs, List zskpairs, + Instant start, Instant expire, + boolean useConservativeOptIn, + boolean fullySignKeyset, List NSECIncludeNames, + int ds_digest_alg) throws IOException, + GeneralSecurityException { return signZone(zonename, records, kskpairs, zskpairs, start, expire, - fullySignKeyset, ds_digest_alg, NSEC_EXP_OPT_IN, NSECIncludeNames, - null, 0, 0, useConservativeOptIn); + fullySignKeyset, ds_digest_alg, NSEC_EXP_OPT_IN, NSECIncludeNames, + null, 0, 0, useConservativeOptIn); } } diff --git a/src/main/java/com/verisignlabs/dnssec/security/ProtoNSEC3.java b/src/main/java/com/verisignlabs/dnssec/security/ProtoNSEC3.java index 9e67469..10b24c3 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/ProtoNSEC3.java +++ b/src/main/java/com/verisignlabs/dnssec/security/ProtoNSEC3.java @@ -1,11 +1,9 @@ /* - * $Id$ - * - * Copyright (c) 2005 VeriSign. All rights reserved. - * + * Copyright (c) 2005, 2022 Verisign. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. 2. Redistributions in * binary form must reproduce the above copyright notice, this list of @@ -13,7 +11,7 @@ * materials provided with the distribution. 3. The name of the author may not * be used to endorse or promote products derived from this software without * specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN @@ -24,12 +22,15 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * */ package com.verisignlabs.dnssec.security; -import org.xbill.DNS.*; +import org.xbill.DNS.DClass; +import org.xbill.DNS.NSEC3Record; +import org.xbill.DNS.Name; +import org.xbill.DNS.TextParseException; import org.xbill.DNS.utils.base16; import org.xbill.DNS.utils.base32; @@ -37,25 +38,22 @@ import org.xbill.DNS.utils.base32; * This is a class representing a "prototype NSEC3" resource record. These are * used as an intermediate stage (in zone signing) between determining the list * of NSEC3 records and forming them into a viable chain. - * - * @author David Blacka (original) - * @author $Author: davidb $ - * @version $Revision: 183 $ + * + * @author David Blacka */ -public class ProtoNSEC3 -{ - private Name originalOwner; - private int hashAlg; - private byte flags; - private int iterations; - private byte[] salt; - private byte[] next; - private byte[] owner; // cached numerical owner value. - private TypeMap typemap; - private Name zone; - private Name name; - private int dclass; - private long ttl; +public class ProtoNSEC3 { + private Name originalOwner; + private int hashAlg; + private byte flags; + private int iterations; + private byte[] salt; + private byte[] next; + private byte[] owner; // cached numerical owner value. + private TypeMap typemap; + private Name zone; + private Name name; + private int dclass; + private long ttl; private static final base32 b32 = new base32(base32.Alphabet.BASE32HEX, false, false); @@ -63,9 +61,8 @@ public class ProtoNSEC3 * Creates an NSEC3 Record from the given data. */ public ProtoNSEC3(byte[] owner, Name originalOwner, Name zone, int dclass, long ttl, - int hashAlg, byte flags, int iterations, byte[] salt, byte[] next, - TypeMap typemap) - { + int hashAlg, byte flags, int iterations, byte[] salt, byte[] next, + TypeMap typemap) { this.zone = zone; this.owner = owner; this.dclass = dclass; @@ -80,29 +77,23 @@ public class ProtoNSEC3 } public ProtoNSEC3(byte[] owner, Name originalOwner, Name zone, int dclass, long ttl, - int hashAlg, byte flags, int iterations, byte[] salt, byte[] next, - int[] types) - { + int hashAlg, byte flags, int iterations, byte[] salt, byte[] next, + int[] types) { this(owner, originalOwner, zone, dclass, ttl, hashAlg, flags, iterations, salt, next, - TypeMap.fromTypes(types)); + TypeMap.fromTypes(types)); } - private String hashToString(byte[] hash) - { - if (hash == null) return null; + private String hashToString(byte[] hash) { + if (hash == null) + return null; return b32.toString(hash); } - public Name getName() - { - if (name == null) - { - try - { + public Name getName() { + if (name == null) { + try { name = new Name(hashToString(owner), zone); - } - catch (TextParseException e) - { + } catch (TextParseException e) { // This isn't going to happen. } } @@ -110,122 +101,104 @@ public class ProtoNSEC3 return name; } - public byte[] getNext() - { + public Name getOriginalOwnerName() { + return this.originalOwner; + } + + public byte[] getNext() { return next; } - public void setNext(byte[] next) - { + public void setNext(byte[] next) { this.next = next; } - public byte getFlags() - { + public byte getFlags() { return flags; } - public boolean getOptOutFlag() - { + public boolean getOptOutFlag() { return (flags & NSEC3Record.Flags.OPT_OUT) != 0; } - public void setOptOutFlag(boolean optOutFlag) - { + public void setOptOutFlag(boolean optOutFlag) { if (optOutFlag) this.flags |= NSEC3Record.Flags.OPT_OUT; else this.flags &= ~NSEC3Record.Flags.OPT_OUT; } - public long getTTL() - { + public long getTTL() { return ttl; } - public void setTTL(long ttl) - { + public void setTTL(long ttl) { this.ttl = ttl; } - public TypeMap getTypemap() - { + public TypeMap getTypemap() { return typemap; } - public int[] getTypes() - { + public int[] getTypes() { return typemap.getTypes(); } - public void setTypemap(TypeMap typemap) - { + public void setTypemap(TypeMap typemap) { this.typemap = typemap; } - public int getDClass() - { + public int getDClass() { return dclass; } - public int getHashAlgorithm() - { + public int getHashAlgorithm() { return hashAlg; } - public int getIterations() - { + public int getIterations() { return iterations; } - public byte[] getOwner() - { + public byte[] getOwner() { return owner; } - public byte[] getSalt() - { + public byte[] getSalt() { return salt; } - public Name getZone() - { + public Name getZone() { return zone; } - public NSEC3Record getNSEC3Record() - { - String comment = (originalOwner == null) ? "(unknown original ownername)" - : originalOwner.toString(); - return new NSEC3Record(getName(), dclass, ttl, hashAlg, flags, iterations, salt, - next, getTypes(), comment); + public NSEC3Record getNSEC3Record() { + return new NSEC3Record(getName(), dclass, ttl, hashAlg, flags, iterations, salt, next, getTypes()); } - public void mergeTypes(TypeMap new_types) - { - int[] nt = new_types.getTypes(); - for (int i = 0; i < nt.length; i++) - { - if (!typemap.get(nt[i])) typemap.set(nt[i]); + public void mergeTypes(TypeMap newTypes) { + int[] nt = newTypes.getTypes(); + for (int i = 0; i < nt.length; i++) { + if (!typemap.get(nt[i])) + typemap.set(nt[i]); } } - public int compareTo(ProtoNSEC3 o) - { - if (o == null) return 1; - byte[] o_owner = o.getOwner(); - int len = owner.length < o_owner.length ? o_owner.length : owner.length; - for (int i = 0; i < len; i++) - { - int d = ((owner[i] & 0xFF) - (o_owner[i] & 0xFF)); - if (d != 0) return d; + public int compareTo(ProtoNSEC3 o) { + if (o == null) + return 1; + byte[] origOwner = o.getOwner(); + int len = owner.length < origOwner.length ? origOwner.length : owner.length; + for (int i = 0; i < len; i++) { + int d = ((owner[i] & 0xFF) - (origOwner[i] & 0xFF)); + if (d != 0) + return d; } - return owner.length - o_owner.length; + return owner.length - origOwner.length; } - public String toString() - { - StringBuffer sb = new StringBuffer(); + public String toString() { + StringBuilder sb = new StringBuilder(); sb.append(getName()); sb.append(' '); sb.append(ttl); @@ -248,10 +221,8 @@ public class ProtoNSEC3 return sb.toString(); } - public static class Comparator implements java.util.Comparator - { - public int compare(ProtoNSEC3 a, ProtoNSEC3 b) - { + public static class Comparator implements java.util.Comparator { + public int compare(ProtoNSEC3 a, ProtoNSEC3 b) { return a.compareTo(b); } diff --git a/src/main/java/com/verisignlabs/dnssec/security/RecordComparator.java b/src/main/java/com/verisignlabs/dnssec/security/RecordComparator.java index 049f5a1..9f6b312 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/RecordComparator.java +++ b/src/main/java/com/verisignlabs/dnssec/security/RecordComparator.java @@ -1,6 +1,4 @@ -// $Id$ -// -// Copyright (C) 2000-2003 Network Solutions, Inc. +// Copyright (C) 2000-2003 Network Solutions, Inc., 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 @@ -30,79 +28,87 @@ import org.xbill.DNS.Type; * objects. It imposes a canonical order consistent with DNSSEC. It does not put * records within a RRset into canonical order: see {@link ByteArrayComparator}. * - * @author David Blacka (original) - * @author $Author$ - * @version $Revision$ + * @author David Blacka */ -public class RecordComparator implements Comparator -{ - public RecordComparator() - { +public class RecordComparator implements Comparator { + public RecordComparator() { } /** - * In general, types are compared numerically. However, SOA, NS, and DNAME are ordered + * In general, types are compared numerically. However, SOA, NS, and DNAME are + * ordered * before the rest. */ - private int compareTypes(int a, int b) - { - if (a == b) return 0; - if (a == Type.SOA) return -1; - if (b == Type.SOA) return 1; + private int compareTypes(int a, int b) { + if (a == b) + return 0; + if (a == Type.SOA) + return -1; + if (b == Type.SOA) + return 1; - if (a == Type.NS) return -1; - if (b == Type.NS) return 1; + if (a == Type.NS) + return -1; + if (b == Type.NS) + return 1; - if (a == Type.DNAME) return -1; - if (b == Type.DNAME) return 1; - - if (a < b) return -1; + if (a == Type.DNAME) + return -1; + if (b == Type.DNAME) + return 1; + + if (a < b) + return -1; return 1; } - private int compareRDATA(Record a, Record b) - { + private int compareRDATA(Record a, Record b) { byte[] a_rdata = a.rdataToWireCanonical(); byte[] b_rdata = b.rdataToWireCanonical(); - for (int i = 0; i < a_rdata.length && i < b_rdata.length; i++) - { + for (int i = 0; i < a_rdata.length && i < b_rdata.length; i++) { int n = (a_rdata[i] & 0xFF) - (b_rdata[i] & 0xFF); - if (n != 0) return n; + if (n != 0) + return n; } return (a_rdata.length - b_rdata.length); } - public int compare(Record a, Record b) - { - if (a == null && b == null) return 0; - if (a == null) return 1; - if (b == null) return -1; + public int compare(Record a, Record b) { + if (a == null && b == null) + return 0; + if (a == null) + return 1; + if (b == null) + return -1; int res = a.getName().compareTo(b.getName()); - if (res != 0) return res; + if (res != 0) + return res; int a_type = a.getType(); int b_type = b.getType(); int sig_type = 0; - if (a_type == Type.RRSIG) - { + if (a_type == Type.RRSIG) { a_type = ((RRSIGRecord) a).getTypeCovered(); - if (b_type != Type.RRSIG) sig_type = 1; + if (b_type != Type.RRSIG) + sig_type = 1; } - if (b_type == Type.RRSIG) - { + if (b_type == Type.RRSIG) { b_type = ((RRSIGRecord) b).getTypeCovered(); - if (a.getType() != Type.RRSIG) sig_type = -1; + if (a.getType() != Type.RRSIG) + sig_type = -1; } res = compareTypes(a_type, b_type); - if (res != 0) return res; + if (res != 0) + return res; - if (sig_type != 0) return sig_type; + if (sig_type != 0) + return sig_type; return compareRDATA(a, b); } diff --git a/src/main/java/com/verisignlabs/dnssec/security/SignUtils.java b/src/main/java/com/verisignlabs/dnssec/security/SignUtils.java index 35be19d..384ee2c 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/SignUtils.java +++ b/src/main/java/com/verisignlabs/dnssec/security/SignUtils.java @@ -1,6 +1,4 @@ -// $Id$ -// -// Copyright (C) 2001-2003 VeriSign, Inc. +// Copyright (C) 2001-2003, 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 @@ -25,41 +23,57 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.interfaces.DSAParams; -import java.util.*; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; import java.util.logging.Logger; -import org.xbill.DNS.*; +import org.xbill.DNS.DClass; +import org.xbill.DNS.DNSKEYRecord; +import org.xbill.DNS.DNSOutput; +import org.xbill.DNS.DNSSEC; +import org.xbill.DNS.DSRecord; +import org.xbill.DNS.NSEC3PARAMRecord; +import org.xbill.DNS.NSEC3Record; +import org.xbill.DNS.NSECRecord; +import org.xbill.DNS.Name; +import org.xbill.DNS.RRSIGRecord; +import org.xbill.DNS.RRset; +import org.xbill.DNS.Record; +import org.xbill.DNS.SOARecord; +import org.xbill.DNS.Type; import org.xbill.DNS.utils.base64; /** * This class contains a bunch of utility methods that are generally useful in * signing zones. * - * @author David Blacka (original) - * @author $Author$ - * @version $Revision$ + * @author David Blacka */ -public class SignUtils -{ - private static final int ASN1_INT = 0x02; - private static final int ASN1_SEQ = 0x30; +public class SignUtils { + private static final int ASN1_INT = 0x02; + private static final int ASN1_SEQ = 0x30; - public static final int RR_NORMAL = 0; - public static final int RR_DELEGATION = 1; - public static final int RR_GLUE = 2; - public static final int RR_INVALID = 3; - public static final int RR_DNAME = 4; + public static final int RR_NORMAL = 0; + public static final int RR_DELEGATION = 1; + public static final int RR_GLUE = 2; + public static final int RR_INVALID = 3; + public static final int RR_DNAME = 4; - private static Logger log; + private static Logger log; - static - { + static { log = Logger.getLogger(SignUtils.class.toString()); } - public static void setLog(Logger v) - { + public static void setLog(Logger v) { log = v; } @@ -68,25 +82,25 @@ public class SignUtils * everything but the actual signature itself. * * @param rrset - * the RRset being signed. + * the RRset being signed. * @param key - * the public DNSKEY RR counterpart to the key being used to sign the - * RRset + * the public DNSKEY RR counterpart to the key being used to sign + * the + * RRset * @param start - * the RRSIG inception time. + * the RRSIG inception time. * @param expire - * the RRSIG expiration time. + * the RRSIG expiration time. * @param sig_ttl - * the TTL of the resulting RRSIG record. + * the TTL of the resulting RRSIG record. * * @return a prototype signature based on the RRset and key information. */ - public static RRSIGRecord generatePreRRSIG(RRset rrset, DNSKEYRecord key, Date start, - Date expire, long sig_ttl) - { + public static RRSIGRecord generatePreRRSIG(RRset rrset, DNSKEYRecord key, Instant start, + Instant expire, long sig_ttl) { return new RRSIGRecord(rrset.getName(), rrset.getDClass(), sig_ttl, rrset.getType(), - key.getAlgorithm(), (int) rrset.getTTL(), expire, start, - key.getFootprint(), key.getName(), null); + key.getAlgorithm(), (int) rrset.getTTL(), expire, start, + key.getFootprint(), key.getName(), null); } /** @@ -94,42 +108,41 @@ public class SignUtils * everything but the actual signature itself. * * @param rec - * the DNS record being signed (forming an entire RRset). + * the DNS record being signed (forming an entire RRset). * @param key - * the public DNSKEY RR counterpart to the key signing the record. + * the public DNSKEY RR counterpart to the key signing the + * record. * @param start - * the RRSIG inception time. + * the RRSIG inception time. * @param expire - * the RRSIG expiration time. + * the RRSIG expiration time. * @param sig_ttl - * the TTL of the result RRSIG record. + * the TTL of the result RRSIG record. * * @return a prototype signature based on the Record and key information. */ - public static RRSIGRecord generatePreRRSIG(Record rec, DNSKEYRecord key, Date start, - Date expire, long sig_ttl) - { + public static RRSIGRecord generatePreRRSIG(Record rec, DNSKEYRecord key, Instant start, + Instant expire, long sig_ttl) { return new RRSIGRecord(rec.getName(), rec.getDClass(), sig_ttl, rec.getType(), - key.getAlgorithm(), rec.getTTL(), expire, start, - key.getFootprint(), key.getName(), null); + key.getAlgorithm(), rec.getTTL(), expire, start, + key.getFootprint(), key.getName(), null); } /** * Generate the binary image of the prototype RRSIG RR. * * @param presig - * the RRSIG RR prototype. + * the RRSIG RR prototype. * @return the RDATA portion of the prototype RRSIG record. This forms the * first part of the data to be signed. */ - private static byte[] generatePreSigRdata(RRSIGRecord presig) - { + private static byte[] generatePreSigRdata(RRSIGRecord presig) { // Generate the binary image; DNSOutput image = new DNSOutput(); // precalc some things - int start_time = (int) (presig.getTimeSigned().getTime() / 1000); - int expire_time = (int) (presig.getExpire().getTime() / 1000); + long start_time = presig.getTimeSigned().getEpochSecond(); + long expire_time = presig.getExpire().getEpochSecond(); Name signer = presig.getSigner(); // first write out the partial SIG record (this is the SIG RDATA @@ -150,35 +163,32 @@ public class SignUtils * Calculate the canonical wire line format of the RRset. * * @param rrset - * the RRset to convert. + * the RRset to convert. * @param ttl - * the TTL to use when canonicalizing -- this is generally the - * TTL of the signature if there is a pre-existing signature. If - * not it is just the ttl of the rrset itself. + * the TTL to use when canonicalizing -- this is generally the + * TTL of the signature if there is a pre-existing signature. If + * not it is just the ttl of the rrset itself. * @param labels - * the labels field of the signature, or 0. + * the labels field of the signature, or 0. * @return the canonical wire line format of the rrset. This is the second * part of data to be signed. */ - @SuppressWarnings("unchecked") - public static byte[] generateCanonicalRRsetData(RRset rrset, long ttl, int labels) - { + public static byte[] generateCanonicalRRsetData(RRset rrset, long ttl, int labels) { DNSOutput image = new DNSOutput(); - if (ttl == 0) ttl = rrset.getTTL(); - Name n = rrset.getName(); - if (labels == 0) - { - labels = n.labels(); + if (ttl == 0) { + ttl = rrset.getTTL(); } - else - { + + Name n = rrset.getName(); + if (labels == 0) { + labels = n.labels(); + } else { // correct for Name()'s conception of label count. labels++; } boolean wildcardName = false; - if (n.labels() != labels) - { + if (n.labels() != labels) { n = n.wild(n.labels() - labels); wildcardName = true; log.fine("Detected wildcard expansion: " + rrset.getName() + " changed to " + n); @@ -187,11 +197,8 @@ public class SignUtils // now convert the wire format records in the RRset into a // list of byte arrays. ArrayList canonical_rrs = new ArrayList(); - for (Iterator i = rrset.rrs(); i.hasNext();) - { - Record r = i.next(); - if (r.getTTL() != ttl || wildcardName) - { + for (Record r : rrset.rrs()) { + if (r.getTTL() != ttl || wildcardName) { // If necessary, we need to create a new record with a new ttl // or ownername. // In the TTL case, this avoids changing the ttl in the @@ -211,8 +218,7 @@ public class SignUtils Collections.sort(canonical_rrs, bac); - for (byte[] wire_fmt_rec : canonical_rrs) - { + for (byte[] wire_fmt_rec : canonical_rrs) { image.writeByteArray(wire_fmt_rec); } @@ -224,16 +230,15 @@ public class SignUtils * that is to be signed. * * @param rrset - * the RRset to be signed. + * the RRset to be signed. * @param presig - * a prototype SIG RR created using the same RRset. + * a prototype SIG RR created using the same RRset. * @return a block of data ready to be signed. */ public static byte[] generateSigData(RRset rrset, RRSIGRecord presig) - throws IOException - { + throws IOException { byte[] rrset_data = generateCanonicalRRsetData(rrset, presig.getOrigTTL(), - presig.getLabels()); + presig.getLabels()); return generateSigData(rrset_data, presig); } @@ -243,16 +248,17 @@ public class SignUtils * that is to be signed. * * @param rrset_data - * the RRset converted into canonical wire line format (as per the - * canonicalization rules in RFC 2535). + * the RRset converted into canonical wire line format (as per + * the + * canonicalization rules in RFC 2535). * @param presig - * the prototype signature based on the same RRset represented in - * rrset_data. + * the prototype signature based on the same RRset represented + * in + * rrset_data. * @return a block of data ready to be signed. */ public static byte[] generateSigData(byte[] rrset_data, RRSIGRecord presig) - throws IOException - { + throws IOException { byte[] sig_rdata = generatePreSigRdata(presig); ByteArrayOutputStream image = new ByteArrayOutputStream(sig_rdata.length @@ -269,18 +275,17 @@ public class SignUtils * return the fully formed RRSIGRecord. * * @param signature - * the cryptographic signature, in DNSSEC format. + * the cryptographic signature, in DNSSEC format. * @param presig - * the prototype RRSIG RR to add the signature to. + * the prototype RRSIG RR to add the signature to. * @return the fully formed RRSIG RR. */ - public static RRSIGRecord generateRRSIG(byte[] signature, RRSIGRecord presig) - { + public static RRSIGRecord generateRRSIG(byte[] signature, RRSIGRecord presig) { return new RRSIGRecord(presig.getName(), presig.getDClass(), presig.getTTL(), - presig.getTypeCovered(), presig.getAlgorithm(), - presig.getOrigTTL(), presig.getExpire(), - presig.getTimeSigned(), presig.getFootprint(), - presig.getSigner(), signature); + presig.getTypeCovered(), presig.getAlgorithm(), + presig.getOrigTTL(), presig.getExpire(), + presig.getTimeSigned(), presig.getFootprint(), + presig.getSigner(), signature); } /** @@ -296,14 +301,14 @@ public class SignUtils * positive. * * @param signature - * the RFC 2536 formatted DSA signature. + * the RFC 2536 formatted DSA signature. * @return The ASN.1 formatted DSA signature. * @throws SignatureException - * if there was something wrong with the RFC 2536 formatted - * signature. + * if there was something wrong with the RFC 2536 + * formatted + * signature. */ - public static byte[] convertDSASignature(byte[] signature) throws SignatureException - { + public static byte[] convertDSASignature(byte[] signature) throws SignatureException { if (signature.length != 41) throw new SignatureException("RFC 2536 signature not expected length."); @@ -311,8 +316,10 @@ public class SignUtils byte s_pad = 0; // handle initial null byte padding. - if (signature[1] < 0) r_pad++; - if (signature[21] < 0) s_pad++; + if (signature[1] < 0) + r_pad++; + if (signature[21] < 0) + s_pad++; // ASN.1 length = R length + S length + (2 + 2 + 2), where each 2 // is for a ASN.1 type-length byte pair of which there are three @@ -328,7 +335,8 @@ public class SignUtils sig[pos++] = (byte) (20 + r_pad); // copy the value of R, leaving a null byte if necessary - if (r_pad == 1) sig[pos++] = 0; + if (r_pad == 1) + sig[pos++] = 0; System.arraycopy(signature, 1, sig, pos, 20); pos += 20; @@ -337,7 +345,8 @@ public class SignUtils sig[pos++] = (byte) (20 + s_pad); // copy the value of S, leaving a null byte if necessary - if (s_pad == 1) sig[pos++] = 0; + if (s_pad == 1) + sig[pos++] = 0; System.arraycopy(signature, 21, sig, pos, 20); @@ -357,28 +366,26 @@ public class SignUtils * bytes). * * @param params - * the DSA parameters associated with the DSA key used to generate - * the signature. + * the DSA parameters associated with the DSA key used to + * generate + * the signature. * @param signature - * the ASN.1 formatted DSA signature. + * the ASN.1 formatted DSA signature. * @return a RFC 2536 formatted DSA signature. * @throws SignatureException - * if something is wrong with the ASN.1 format. + * if something is wrong with the ASN.1 format. */ public static byte[] convertDSASignature(DSAParams params, byte[] signature) - throws SignatureException - { - if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT) - { + throws SignatureException { + if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT) { throw new SignatureException("Invalid ASN.1 signature format: expected SEQ, INT"); } byte r_pad = (byte) (signature[3] - 20); - if (signature[24 + r_pad] != ASN1_INT) - { + if (signature[24 + r_pad] != ASN1_INT) { throw new SignatureException( - "Invalid ASN.1 signature format: expected SEQ, INT, INT"); + "Invalid ASN.1 signature format: expected SEQ, INT, INT"); } log.finer("(start) ASN.1 DSA Sig:\n" + base64.toString(signature)); @@ -391,12 +398,9 @@ public class SignUtils sig[0] = (byte) ((params.getP().bitLength() - 512) / 64); // copy R value - if (r_pad >= 0) - { + if (r_pad >= 0) { System.arraycopy(signature, 4 + r_pad, sig, 1, 20); - } - else - { + } else { // R is shorter than 20 bytes, so right justify the number // (r_pad is negative here, remember?). Arrays.fill(sig, 1, 1 - r_pad, (byte) 0); @@ -404,25 +408,19 @@ public class SignUtils } // copy S value - if (s_pad >= 0) - { + if (s_pad >= 0) { System.arraycopy(signature, 26 + r_pad + s_pad, sig, 21, 20); - } - else - { + } else { // S is shorter than 20 bytes, so right justify the number // (s_pad is negative here). Arrays.fill(sig, 21, 21 - s_pad, (byte) 0); System.arraycopy(signature, 26 + r_pad, sig, 21 - s_pad, 20 + s_pad); } - if (r_pad < 0 || s_pad < 0) - { + if (r_pad < 0 || s_pad < 0) { log.finer("(finish ***) RFC 2536 DSA Sig:\n" + base64.toString(sig)); - } - else - { + } else { log.finer("(finish) RFC 2536 DSA Sig:\n" + base64.toString(sig)); } @@ -431,15 +429,15 @@ public class SignUtils // Given one of the ECDSA algorithms determine the "length", which is the // length, in bytes, of both 'r' and 's' in the ECDSA signature. - private static int ecdsaLength(int algorithm) throws SignatureException - { - switch (algorithm) - { - case DNSSEC.Algorithm.ECDSAP256SHA256: return 32; - case DNSSEC.Algorithm.ECDSAP384SHA384: return 48; + private static int ecdsaLength(int algorithm) throws SignatureException { + switch (algorithm) { + case DNSSEC.Algorithm.ECDSAP256SHA256: + return 32; + case DNSSEC.Algorithm.ECDSAP384SHA384: + return 48; default: - throw new SignatureException("Algorithm " + algorithm + - " is not a supported ECDSA signature algorithm."); + throw new SignatureException("Algorithm " + algorithm + + " is not a supported ECDSA signature algorithm."); } } @@ -458,25 +456,22 @@ public class SignUtils * exactly "length" bytes. * * @param signature - * The output of a ECDSA signature object. + * The output of a ECDSA signature object. * @return signature data formatted for use in DNSSEC. * @throws SignatureException if the ASN.1 encoding appears to be corrupt. */ - public static byte[] convertECDSASignature(int algorithm, byte[] signature) - throws SignatureException - { + public static byte[] convertECDSASignature(int algorithm, byte[] signature) + throws SignatureException { int exp_length = ecdsaLength(algorithm); byte[] sig = new byte[exp_length * 2]; - if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT) - { + if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT) { throw new SignatureException("Invalid ASN.1 signature format: expected SEQ, INT"); } int r_len = signature[3]; int r_pos = 4; - - if (signature[r_pos + r_len] != ASN1_INT) - { + + if (signature[r_pos + r_len] != ASN1_INT) { throw new SignatureException("Invalid ASN.1 signature format: expected SEQ, INT, INT"); } int s_pos = r_pos + r_len + 2; @@ -513,33 +508,40 @@ public class SignUtils * exactly "length" bytes. * * @param signature - * The binary signature data from an RRSIG record. + * The binary signature data from an RRSIG record. * @return signature data that may be used in a JCE Signature object for * verification purposes. */ - public static byte[] convertECDSASignature(byte[] signature) - { + public static byte[] convertECDSASignature(byte[] signature) { byte r_src_pos, r_src_len, r_pad, s_src_pos, s_src_len, s_pad, len; r_src_len = s_src_len = (byte) (signature.length / 2); - r_src_pos = 0; r_pad = 0; - s_src_pos = (byte) (r_src_pos + r_src_len); s_pad = 0; + r_src_pos = 0; + r_pad = 0; + s_src_pos = (byte) (r_src_pos + r_src_len); + s_pad = 0; len = (byte) (6 + r_src_len + s_src_len); // leading zeroes are forbidden while (signature[r_src_pos] == 0 && r_src_len > 0) { - r_src_pos++; r_src_len--; len--; + r_src_pos++; + r_src_len--; + len--; } while (signature[s_src_pos] == 0 && s_src_len > 0) { - s_src_pos++; s_src_len--; len--; + s_src_pos++; + s_src_len--; + len--; } // except when they are mandatory if (r_src_len > 0 && signature[r_src_pos] < 0) { - r_pad = 1; len++; + r_pad = 1; + len++; } if (s_src_len > 0 && signature[s_src_pos] < 0) { - s_pad = 1; len++; + s_pad = 1; + len++; } byte[] sig = new byte[len]; byte pos = 0; @@ -589,52 +591,51 @@ public class SignUtils * ordering, and the caller must maintain the last_cut parameter. * * @param zonename - * the name of the zone that is being processed. + * the name of the zone that is being processed. * @param name - * the name of the record/set under consideration. + * the name of the record/set under consideration. * @param type - * the type of the record/set under consideration. + * the type of the record/set under consideration. * @param last_cut - * the name of the last DELEGATION record/set that was encountered - * while iterating over the zone in canonical order. + * the name of the last DELEGATION record/set that was + * encountered + * while iterating over the zone in canonical order. */ public static int recordSecType(Name zonename, Name name, int type, Name last_cut, - Name last_dname) - { + Name last_dname) { // records not even in the zone itself are invalid. - if (!name.subdomain(zonename)) return RR_INVALID; + if (!name.subdomain(zonename)) + return RR_INVALID; // all records a the zone apex are normal, by definition. - if (name.equals(zonename)) return RR_NORMAL; + if (name.equals(zonename)) + return RR_NORMAL; - if (last_cut != null && name.subdomain(last_cut)) - { - // if we are at the same level as a delegation point, but not one of a set of types allowed at + if (last_cut != null && name.subdomain(last_cut)) { + // if we are at the same level as a delegation point, but not one of a set of + // types allowed at // a delegation point (NS, DS, NSEC), this is glue. - if (name.equals(last_cut)) - { - if (type != Type.NS && type != Type.DS && type != Type.NXT && type != Type.NSEC) - { + if (name.equals(last_cut)) { + if (type != Type.NS && type != Type.DS && type != Type.NXT && type != Type.NSEC) { return RR_GLUE; } } // if we are below the delegation point, this is glue. - else - { + else { return RR_GLUE; } } - // if we are below a DNAME, then the RR is invalid. + // if we are below a DNAME, then the RR is invalid. if (last_dname != null && name.subdomain(last_dname) - && name.labels() > last_dname.labels()) - { + && name.labels() > last_dname.labels()) { return RR_INVALID; } // since we are not at zone level, any NS records are delegations - if (type == Type.NS) return RR_DELEGATION; + if (type == Type.NS) + return RR_DELEGATION; // and everything else is normal return RR_NORMAL; @@ -645,20 +646,17 @@ public class SignUtils * records into a list of RRsets. * * @param records - * a list of {@link org.xbill.DNS.Record} objects, in DNSSEC - * canonical order. + * a list of {@link org.xbill.DNS.Record} objects, in DNSSEC + * canonical order. * @return a List of {@link org.xbill.DNS.RRset} objects. */ - public static List assembleIntoRRsets(List records) - { + public static List assembleIntoRRsets(List records) { RRset rrset = new RRset(); ArrayList rrsets = new ArrayList(); - for (Record r : records) - { + for (Record r : records) { // First record - if (rrset.size() == 0) - { + if (rrset.size() == 0) { rrset.addRR(r); continue; } @@ -666,8 +664,8 @@ public class SignUtils // Current record is part of the current RRset. if (rrset.getName().equals(r.getName()) && rrset.getDClass() == r.getDClass() - && ((r.getType() == Type.RRSIG && rrset.getType() == ((RRSIGRecord) r).getTypeCovered()) || rrset.getType() == r.getType())) - { + && ((r.getType() == Type.RRSIG && rrset.getType() == ((RRSIGRecord) r).getTypeCovered()) + || rrset.getType() == r.getType())) { rrset.addRR(r); continue; } @@ -689,19 +687,17 @@ public class SignUtils /** * A little private class to hold information about a given node. */ - private static class NodeInfo - { - public Name name; - public int type; - public long ttl; - public int dclass; + private static class NodeInfo { + public Name name; + public int type; + public long ttl; + public int dclass; public Set typemap; - public boolean isSecureNode; // opt-in support. - public boolean hasOptInSpan; // opt-in support. - public int nsecIndex; + public boolean isSecureNode; // opt-in support. + public boolean hasOptInSpan; // opt-in support. + public int nsecIndex; - public NodeInfo(Record r, int nodeType) - { + public NodeInfo(Record r, int nodeType) { this.name = r.getName(); this.type = nodeType; this.ttl = r.getTTL(); @@ -712,38 +708,34 @@ public class SignUtils addType(r.getType()); } - public void addType(int type) - { - this.typemap.add(new Integer(type)); + public void addType(int type) { + this.typemap.add(Integer.valueOf(type)); // Opt-In support. if (type != Type.NS && type != Type.NSEC && type != Type.RRSIG - && type != Type.NSEC3) - { + && type != Type.NSEC3) { isSecureNode = true; } } - public boolean hasType(int type) - { + public boolean hasType(int type) { return this.typemap.contains(type); } - public String toString() - { + public String toString() { StringBuffer sb = new StringBuffer(name.toString()); - if (isSecureNode) sb.append("(S)"); - if (hasOptInSpan) sb.append("(O)"); + if (isSecureNode) + sb.append("(S)"); + if (hasOptInSpan) + sb.append("(O)"); return sb.toString(); } - public int[] getTypes() - { + public int[] getTypes() { Object[] a = typemap.toArray(); int[] res = new int[a.length]; - for (int i = 0; i < a.length; i++) - { + for (int i = 0; i < a.length; i++) { res[i] = ((Integer) a[i]).intValue(); } return res; @@ -758,14 +750,15 @@ public class SignUtils * listIterator.add() operation. * * @param zonename - * the name of the zone (used to distinguish between zone apex NS - * RRsets and delegations). + * the name of the zone (used to distinguish between zone apex + * NS + * RRsets and delegations). * @param records - * a list of {@link org.xbill.DNS.Record} objects in DNSSEC canonical - * order. + * a list of {@link org.xbill.DNS.Record} objects in DNSSEC + * canonical + * order. */ - public static void generateNSECRecords(Name zonename, List records) - { + public static void generateNSECRecords(Name zonename, List records) { // This works by iterating over a known sorted list of records. NodeInfo last_node = null; @@ -778,40 +771,38 @@ public class SignUtils // First find the SOA record -- it should be near the beginning -- and get // the soa minimum - for (Record r : records) - { - if (r.getType() == Type.SOA) - { + for (Record r : records) { + if (r.getType() == Type.SOA) { SOARecord soa = (SOARecord) r; - nsec_ttl = soa.getMinimum(); + nsec_ttl = Math.min(soa.getMinimum(), soa.getTTL()); break; } } - if (nsec_ttl == 0) - { + if (nsec_ttl == 0) { throw new IllegalArgumentException("Zone did not contain a SOA record"); } - for (ListIterator i = records.listIterator(); i.hasNext();) - { + for (ListIterator i = records.listIterator(); i.hasNext();) { Record r = i.next(); Name r_name = r.getName(); int r_type = r.getType(); int r_sectype = recordSecType(zonename, r_name, r_type, last_cut, last_dname); // skip irrelevant records - if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue; + if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) + continue; // note our last delegation point so we can recognize glue. - if (r_sectype == RR_DELEGATION) last_cut = r_name; + if (r_sectype == RR_DELEGATION) + last_cut = r_name; // if this is a DNAME, note it so we can recognize junk - if (r_type == Type.DNAME) last_dname = r_name; + if (r_type == Type.DNAME) + last_dname = r_name; // first node -- initialize - if (current_node == null) - { + if (current_node == null) { current_node = new NodeInfo(r, r_sectype); current_node.addType(Type.RRSIG); current_node.addType(Type.NSEC); @@ -819,16 +810,14 @@ public class SignUtils } // record name hasn't changed, so we are still on the same node. - if (r_name.equals(current_node.name)) - { + if (r_name.equals(current_node.name)) { current_node.addType(r_type); continue; } - if (last_node != null) - { + if (last_node != null) { NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, nsec_ttl, - current_node.name, last_node.getTypes()); + current_node.name, last_node.getTypes()); // Note: we have to add this through the iterator, otherwise // the next access via the iterator will generate a // ConcurrencyModificationException. @@ -851,17 +840,16 @@ public class SignUtils } // Generate next to last NSEC - if (last_node != null) - { + if (last_node != null) { NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, nsec_ttl, - current_node.name, last_node.getTypes()); + current_node.name, last_node.getTypes()); records.add(last_node.nsecIndex - 1, nsec); log.finer("Generated: " + nsec); } // Generate last NSEC NSECRecord nsec = new NSECRecord(current_node.name, current_node.dclass, nsec_ttl, - zonename, current_node.getTypes()); + zonename, current_node.getTypes()); records.add(nsec); log.finer("Generated: " + nsec); @@ -875,24 +863,27 @@ public class SignUtils * listIterator.add() operation. * * @param zonename - * the name of the zone (used to distinguish between zone apex NS - * RRsets and delegations). + * the name of the zone (used to distinguish between zone + * apex NS + * RRsets and delegations). * @param records - * a list of {@link org.xbill.DNS.Record} objects in DNSSEC canonical - * order. + * a list of {@link org.xbill.DNS.Record} objects in + * DNSSEC canonical + * order. * @param salt - * The NSEC3 salt to use (may be null or empty for no salt). + * The NSEC3 salt to use (may be null or empty for no + * salt). * @param iterations - * The number of hash iterations to use. + * The number of hash iterations to use. * @param nsec3param_ttl - * The TTL to use for the generated NSEC3PARAM records (NSEC3 records - * will use the SOA minimum) + * The TTL to use for the generated NSEC3PARAM records + * (NSEC3 records + * will use the SOA minimum) * @throws NoSuchAlgorithmException */ public static void generateNSEC3Records(Name zonename, List records, - byte[] salt, int iterations, long nsec3param_ttl) - throws NoSuchAlgorithmException - { + byte[] salt, int iterations, long nsec3param_ttl) + throws NoSuchAlgorithmException { List proto_nsec3s = new ArrayList(); NodeInfo current_node = null; NodeInfo last_node = null; @@ -903,8 +894,7 @@ public class SignUtils long nsec3_ttl = 0; - for (Record r : records) - { + for (Record r : records) { Name r_name = r.getName(); int r_type = r.getType(); @@ -912,34 +902,33 @@ public class SignUtils int r_sectype = recordSecType(zonename, r_name, r_type, last_cut, last_dname); // skip irrelevant records - if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue; + if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) + continue; // note our last delegation point so we can recognize glue. - if (r_sectype == RR_DELEGATION) last_cut = r_name; + if (r_sectype == RR_DELEGATION) + last_cut = r_name; // note our last DNAME point, so we can recognize junk. - if (r_type == Type.DNAME) last_dname = r_name; + if (r_type == Type.DNAME) + last_dname = r_name; - if (r_type == Type.SOA) - { + if (r_type == Type.SOA) { SOARecord soa = (SOARecord) r; - nsec3_ttl = soa.getMinimum(); - if (nsec3param_ttl < 0) - { - nsec3param_ttl = soa.getTTL(); + nsec3_ttl = Math.min(soa.getMinimum(), soa.getTTL()); + if (nsec3param_ttl < 0) { + nsec3param_ttl = nsec3_ttl; } } // For the first iteration, we create our current node. - if (current_node == null) - { + if (current_node == null) { current_node = new NodeInfo(r, r_sectype); continue; } // If we are at the same name, we are on the same node. - if (r_name.equals(current_node.name)) - { + if (r_name.equals(current_node.name)) { current_node.addType(r_type); continue; } @@ -962,9 +951,9 @@ public class SignUtils records.addAll(nsec3s); NSEC3PARAMRecord nsec3param = new NSEC3PARAMRecord(zonename, DClass.IN, - nsec3param_ttl, - NSEC3Record.SHA1_DIGEST_ID, - (byte) 0, iterations, salt); + nsec3param_ttl, + NSEC3Record.SHA1_DIGEST_ID, + (byte) 0, iterations, salt); records.add(nsec3param); } @@ -979,29 +968,33 @@ public class SignUtils * listIterator.add() operation. * * @param zonename - * the name of the zone (used to distinguish between zone apex NS - * RRsets and delegations). + * the name of the zone (used to distinguish between zone + * apex NS + * RRsets and delegations). * @param records - * a list of {@link org.xbill.DNS.Record} objects in DNSSEC canonical - * order. + * a list of {@link org.xbill.DNS.Record} objects in + * DNSSEC canonical + * order. * @param includedNames - * A list of {@link org.xbill.DNS.Name} objects. These names will be - * included in the NSEC3 chain (if they exist in the zone) - * regardless. + * A list of {@link org.xbill.DNS.Name} objects. These + * names will be + * included in the NSEC3 chain (if they exist in the zone) + * regardless. * @param salt - * The NSEC3 salt to use (may be null or empty for no salt). + * The NSEC3 salt to use (may be null or empty for no + * salt). * @param iterations - * The number of hash iterations to use. + * The number of hash iterations to use. * @param nsec3param_ttl - * The TTL to use for the generated NSEC3PARAM records (NSEC3 records - * will use the SOA minimum) + * The TTL to use for the generated NSEC3PARAM records + * (NSEC3 records + * will use the SOA minimum) * @throws NoSuchAlgorithmException */ public static void generateOptOutNSEC3Records(Name zonename, List records, - List includedNames, byte[] salt, - int iterations, long nsec3param_ttl) - throws NoSuchAlgorithmException - { + List includedNames, byte[] salt, + int iterations, long nsec3param_ttl) + throws NoSuchAlgorithmException { List proto_nsec3s = new ArrayList(); NodeInfo current_node = null; NodeInfo last_node = null; @@ -1013,13 +1006,11 @@ public class SignUtils long nsec3_ttl = 0; HashSet includeSet = null; - if (includedNames != null) - { + if (includedNames != null) { includeSet = new HashSet(includedNames); } - for (Record r : records) - { + for (Record r : records) { Name r_name = r.getName(); int r_type = r.getType(); @@ -1027,39 +1018,37 @@ public class SignUtils int r_sectype = recordSecType(zonename, r_name, r_type, last_cut, last_dname); // skip irrelevant records - if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue; + if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) + continue; // note our last delegation point so we can recognize glue. - if (r_sectype == RR_DELEGATION) last_cut = r_name; + if (r_sectype == RR_DELEGATION) + last_cut = r_name; - if (r_type == Type.DNAME) last_dname = r_name; + if (r_type == Type.DNAME) + last_dname = r_name; - if (r_type == Type.SOA) - { + if (r_type == Type.SOA) { SOARecord soa = (SOARecord) r; - nsec3_ttl = soa.getMinimum(); - if (nsec3param_ttl < 0) - { - nsec3param_ttl = soa.getTTL(); + nsec3_ttl = Math.min(soa.getMinimum(), soa.getTTL()); + if (nsec3param_ttl < 0) { + nsec3param_ttl = nsec3_ttl; } } // For the first iteration, we create our current node. - if (current_node == null) - { + if (current_node == null) { current_node = new NodeInfo(r, r_sectype); continue; } // If we are at the same name, we are on the same node. - if (r_name.equals(current_node.name)) - { + if (r_name.equals(current_node.name)) { current_node.addType(r_type); continue; } - if (includeSet != null && includeSet.contains(current_node.name)) - { + if (includeSet != null && includeSet.contains(current_node.name)) { current_node.isSecureNode = true; } @@ -1068,12 +1057,9 @@ public class SignUtils // But first, we need to do something with the last node. generateNSEC3ForNode(last_node, zonename, salt, iterations, true, proto_nsec3s); - if (current_node.isSecureNode) - { + if (current_node.isSecureNode) { last_node = current_node; - } - else - { + } else { last_node.hasOptInSpan = true; } @@ -1088,9 +1074,9 @@ public class SignUtils records.addAll(nsec3s); NSEC3PARAMRecord nsec3param = new NSEC3PARAMRecord(zonename, DClass.IN, - nsec3param_ttl, - NSEC3Record.SHA1_DIGEST_ID, - (byte) 0, iterations, salt); + nsec3param_ttl, + NSEC3Record.SHA1_DIGEST_ID, + (byte) 0, iterations, salt); records.add(nsec3param); } @@ -1100,47 +1086,47 @@ public class SignUtils * the node itself, and for any potential empty non-terminals. * * @param node - * The node in question. + * The node in question. * @param zonename - * The zonename. + * The zonename. * @param salt - * The salt to use for the NSEC3 RRs + * The salt to use for the NSEC3 RRs * @param iterations - * The iterations to use for the NSEC3 RRs. + * The iterations to use for the NSEC3 RRs. * @param optIn - * If true, the NSEC3 will have the Opt-Out flag set. + * If true, the NSEC3 will have the Opt-Out flag set. * @param nsec3s - * The current list of NSEC3s -- this will be updated. + * The current list of NSEC3s -- this will be updated. * @throws NoSuchAlgorithmException */ private static void generateNSEC3ForNode(NodeInfo node, Name zonename, byte[] salt, - int iterations, boolean optIn, List nsec3s) - throws NoSuchAlgorithmException - { - if (node == null) return; - if (optIn && !node.isSecureNode) return; + int iterations, boolean optIn, List nsec3s) + throws NoSuchAlgorithmException { + if (node == null) + return; + if (optIn && !node.isSecureNode) + return; // Add our default types. - if (node.type == RR_NORMAL || (node.type == RR_DELEGATION && node.hasType(Type.DS))) - { + if (node.type == RR_NORMAL || (node.type == RR_DELEGATION && node.hasType(Type.DS))) { node.addType(Type.RRSIG); } - if (node.name.equals(zonename)) node.addType(Type.NSEC3PARAM); + if (node.name.equals(zonename)) + node.addType(Type.NSEC3PARAM); // Check for ENTs -- note this will generate duplicate ENTs because it // doesn't use any context. int ldiff = node.name.labels() - zonename.labels(); - for (int i = 1; i < ldiff; i++) - { + for (int i = 1; i < ldiff; i++) { Name n = new Name(node.name, i); log.fine("Generating ENT NSEC3 for " + n); ProtoNSEC3 nsec3 = generateNSEC3(n, zonename, node.ttl, salt, iterations, optIn, - null); + null); nsec3s.add(nsec3); } ProtoNSEC3 nsec3 = generateNSEC3(node.name, zonename, node.ttl, salt, iterations, - optIn, node.getTypes()); + optIn, node.getTypes()); nsec3s.add(nsec3); } @@ -1148,33 +1134,32 @@ public class SignUtils * Create a "prototype" NSEC3 record. Basically, a mutable NSEC3 record. * * @param name - * The original ownername to use. + * The original ownername to use. * @param zonename - * The zonename to use. + * The zonename to use. * @param ttl - * The TTL to use. + * The TTL to use. * @param salt - * The salt to use. + * The salt to use. * @param iterations - * The number of hash iterations to use. + * The number of hash iterations to use. * @param optIn - * The value of the Opt-Out flag. + * The value of the Opt-Out flag. * @param types - * The typecodes present at this name. + * The typecodes present at this name. * @return A mutable NSEC3 record. * * @throws NoSuchAlgorithmException */ private static ProtoNSEC3 generateNSEC3(Name name, Name zonename, long ttl, - byte[] salt, int iterations, boolean optIn, - int[] types) throws NoSuchAlgorithmException - { + byte[] salt, int iterations, boolean optIn, + int[] types) throws NoSuchAlgorithmException { byte[] hash = nsec3hash(name, NSEC3Record.SHA1_DIGEST_ID, iterations, salt); byte flags = (byte) (optIn ? 0x01 : 0x00); - + ProtoNSEC3 r = new ProtoNSEC3(hash, name, zonename, DClass.IN, ttl, - NSEC3Record.SHA1_DIGEST_ID, flags, iterations, salt, - null, types); + NSEC3Record.SHA1_DIGEST_ID, flags, iterations, salt, + null, types); log.finer("Generated: " + r); return r; @@ -1186,29 +1171,28 @@ public class SignUtils * will remove duplicates and finalize the records. * * @param nsec3s - * The list of ProtoNSEC3 objects + * The list of ProtoNSEC3 objects * @param ttl - * The TTL to assign to the finished NSEC3 records. In general, this - * should match the SOA minimum value for the zone. + * The TTL to assign to the finished NSEC3 records. In general, + * this + * should match the SOA minimum value for the zone. * @return The list of {@link org.xbill.DNS.NSEC3Record} objects. */ - private static List finishNSEC3s(List nsec3s, long ttl) - { - if (nsec3s == null) return null; + private static List finishNSEC3s(List nsec3s, long ttl) { + if (nsec3s == null) + return null; Collections.sort(nsec3s, new ProtoNSEC3.Comparator()); ProtoNSEC3 prev_nsec3 = null; ProtoNSEC3 cur_nsec3 = null; byte[] first_nsec3_hash = null; - for (ListIterator i = nsec3s.listIterator(); i.hasNext();) - { + for (ListIterator i = nsec3s.listIterator(); i.hasNext();) { cur_nsec3 = i.next(); // check to see if cur is a duplicate (by name) if (prev_nsec3 != null - && Arrays.equals(prev_nsec3.getOwner(), cur_nsec3.getOwner())) - { + && Arrays.equals(prev_nsec3.getOwner(), cur_nsec3.getOwner())) { log.fine("found duplicate NSEC3 (by name) -- merging type maps: " + prev_nsec3.getTypemap() + " and " + cur_nsec3.getTypemap()); i.remove(); @@ -1219,8 +1203,7 @@ public class SignUtils byte[] next = cur_nsec3.getOwner(); - if (prev_nsec3 == null) - { + if (prev_nsec3 == null) { prev_nsec3 = cur_nsec3; first_nsec3_hash = next; continue; @@ -1231,22 +1214,18 @@ public class SignUtils } // Handle last NSEC3. - if (prev_nsec3.getNext() == null) - { + if (prev_nsec3.getNext() == null) { // if prev_nsec3's next field hasn't been set, then it is the last // record (i.e., all remaining records were duplicates.) prev_nsec3.setNext(first_nsec3_hash); - } - else - { + } else { // otherwise, cur_nsec3 is the last record. cur_nsec3.setNext(first_nsec3_hash); } // Convert our ProtoNSEC3s to actual (immutable) NSEC3Record objects. List res = new ArrayList(nsec3s.size()); - for (ProtoNSEC3 p : nsec3s) - { + for (ProtoNSEC3 p : nsec3s) { p.setTTL(ttl); res.add(p.getNSEC3Record()); } @@ -1262,21 +1241,23 @@ public class SignUtils * listIterator.add operation. * * @param zonename - * the name of the zone apex, used to distinguish between - * authoritative and delegation NS RRsets. + * the name of the zone apex, used to distinguish between + * authoritative and delegation NS RRsets. * @param records - * a list of {@link org.xbill.DNS.Record}s in DNSSEC canonical order. + * a list of {@link org.xbill.DNS.Record}s in DNSSEC + * canonical order. * @param includeNames - * a list of names that should be in the NXT chain regardless. This - * may be null. + * a list of names that should be in the NXT chain + * regardless. This + * may be null. * @param beConservative - * if true, then Opt-In NXTs will only be generated where there is - * actually a span of insecure delegations. + * if true, then Opt-In NXTs will only be generated where + * there is + * actually a span of insecure delegations. */ public static void generateOptInNSECRecords(Name zonename, List records, - List includeNames, - boolean beConservative) - { + List includeNames, + boolean beConservative) { // This works by iterating over a known sorted list of records. NodeInfo last_node = null; @@ -1288,57 +1269,53 @@ public class SignUtils int backup; HashSet includeSet = null; - if (includeNames != null) - { + if (includeNames != null) { includeSet = new HashSet(includeNames); } - for (ListIterator i = records.listIterator(); i.hasNext();) - { + for (ListIterator i = records.listIterator(); i.hasNext();) { Record r = i.next(); Name r_name = r.getName(); int r_type = r.getType(); int r_sectype = recordSecType(zonename, r_name, r_type, last_cut, last_dname); // skip irrelevant records - if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue; + if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) + continue; // note our last delegation point so we can recognize glue. - if (r_sectype == RR_DELEGATION) last_cut = r_name; + if (r_sectype == RR_DELEGATION) + last_cut = r_name; - if (r_type == Type.DNAME) last_dname = r_name; + if (r_type == Type.DNAME) + last_dname = r_name; // first node -- initialize - if (current_node == null) - { + if (current_node == null) { current_node = new NodeInfo(r, r_sectype); current_node.addType(Type.RRSIG); continue; } // record name hasn't changed, so we are still on the same node. - if (r_name.equals(current_node.name)) - { + if (r_name.equals(current_node.name)) { current_node.addType(r_type); continue; } // If the name is in the set of included names, mark it as // secure. - if (includeSet != null && includeSet.contains(current_node.name)) - { + if (includeSet != null && includeSet.contains(current_node.name)) { current_node.isSecureNode = true; } - if (last_node != null && current_node.isSecureNode) - { + if (last_node != null && current_node.isSecureNode) { // generate a NSEC record. - if (beConservative && !last_node.hasOptInSpan) - { + if (beConservative && !last_node.hasOptInSpan) { last_node.addType(Type.NSEC); } NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, last_node.ttl, - current_node.name, last_node.getTypes()); + current_node.name, last_node.getTypes()); // Note: we have to add this through the iterator, otherwise // the next access via the iterator will generate a // ConcurrencyModificationException. @@ -1352,12 +1329,9 @@ public class SignUtils log.finer("Generated: " + nsec); } - if (current_node.isSecureNode) - { + if (current_node.isSecureNode) { last_node = current_node; - } - else if (last_node != null) - { + } else if (last_node != null) { // last_node does not change -- last_node is essentially the // last *secure* node, and current_node is not secure. // However, we need to note the passing of the insecure node. @@ -1370,37 +1344,31 @@ public class SignUtils } // Generate next to last NSEC - if (last_node != null && current_node.isSecureNode) - { + if (last_node != null && current_node.isSecureNode) { // generate a NSEC record. - if (beConservative && !last_node.hasOptInSpan) - { + if (beConservative && !last_node.hasOptInSpan) { last_node.addType(Type.NSEC); } NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, last_node.ttl, - current_node.name, last_node.getTypes()); + current_node.name, last_node.getTypes()); records.add(last_node.nsecIndex - 1, nsec); log.finer("Generated: " + nsec); } // Generate last NSEC NSECRecord nsec; - if (current_node.isSecureNode) - { - if (beConservative) - { + if (current_node.isSecureNode) { + if (beConservative) { current_node.addType(Type.NSEC); } nsec = new NSECRecord(current_node.name, current_node.dclass, current_node.ttl, - zonename, current_node.getTypes()); + zonename, current_node.getTypes()); // we can just tack this on the end as we are working on the // last node. records.add(nsec); - } - else - { + } else { nsec = new NSECRecord(last_node.name, last_node.dclass, last_node.ttl, zonename, - last_node.getTypes()); + last_node.getTypes()); // We need to tack this on after the last secure node, not the // end of the whole list. records.add(last_node.nsecIndex, nsec); @@ -1414,27 +1382,27 @@ public class SignUtils * records into their corresponding DS records in place. * * @param zonename - * the name of the zone, used to reliably distinguish the zone apex - * from other records. + * the name of the zone, used to reliably distinguish the zone + * apex + * from other records. * @param records - * a list of {@link org.xbill.DNS.Record} objects. + * a list of {@link org.xbill.DNS.Record} objects. * @param digest_alg - * The digest algorithm to use. + * The digest algorithm to use. */ - public static void generateDSRecords(Name zonename, List records, int digest_alg) - { + public static void generateDSRecords(Name zonename, List records, int digest_alg) { - for (ListIterator i = records.listIterator(); i.hasNext();) - { + for (ListIterator i = records.listIterator(); i.hasNext();) { Record r = i.next(); - if (r == null) continue; // this should never be true. + if (r == null) + continue; // this should never be true. Name r_name = r.getName(); - if (r_name == null) continue; // this should never be true. + if (r_name == null) + continue; // this should never be true. // Convert non-zone level KEY records into DS records. - if (r.getType() == Type.DNSKEY && !r_name.equals(zonename)) - { + if (r.getType() == Type.DNSKEY && !r_name.equals(zonename)) { DSRecord ds = calculateDSRecord((DNSKEYRecord) r, digest_alg, r.getTTL()); i.set(ds); @@ -1446,19 +1414,16 @@ public class SignUtils * Given a zone, remove all records that are generated. * * @param zonename - * the name of the zone. + * the name of the zone. * @param records - * a list of {@link org.xbill.DNS.Record} objects. + * a list of {@link org.xbill.DNS.Record} objects. */ - public static void removeGeneratedRecords(Name zonename, List records) - { - for (Iterator i = records.iterator(); i.hasNext();) - { + public static void removeGeneratedRecords(Name zonename, List records) { + for (Iterator i = records.iterator(); i.hasNext();) { Record r = (Record) i.next(); if (r.getType() == Type.RRSIG || r.getType() == Type.NSEC - || r.getType() == Type.NSEC3 || r.getType() == Type.NSEC3PARAM) - { + || r.getType() == Type.NSEC3 || r.getType() == Type.NSEC3PARAM) { i.remove(); } } @@ -1470,21 +1435,18 @@ public class SignUtils * type. * * @param records - * a list of {@link org.xbill.DNS.Record} object, in sorted order. + * a list of {@link org.xbill.DNS.Record} object, in sorted + * order. */ - public static void removeDuplicateRecords(List records) - { + public static void removeDuplicateRecords(List records) { Record lastrec = null; - for (Iterator i = records.iterator(); i.hasNext();) - { + for (Iterator i = records.iterator(); i.hasNext();) { Record r = i.next(); - if (lastrec == null) - { + if (lastrec == null) { lastrec = r; continue; } - if (lastrec.equals(r)) - { + if (lastrec.equals(r)) { i.remove(); continue; } @@ -1496,37 +1458,37 @@ public class SignUtils * Given a DNSKEY record, generate the DS record from it. * * @param keyrec - * the KEY record in question. + * the KEY record in question. * @param digest_alg - * The digest algorithm (SHA-1, SHA-256, etc.). + * The digest algorithm (SHA-1, SHA-256, etc.). * @param ttl - * the desired TTL for the generated DS record. If zero, or negative, - * the original KEY RR's TTL will be used. + * the desired TTL for the generated DS record. If zero, or + * negative, + * the original KEY RR's TTL will be used. * @return the corresponding {@link org.xbill.DNS.DSRecord} */ - public static DSRecord calculateDSRecord(DNSKEYRecord keyrec, int digest_alg, long ttl) - { - if (keyrec == null) return null; + public static DSRecord calculateDSRecord(DNSKEYRecord keyrec, int digest_alg, long ttl) { + if (keyrec == null) + return null; - if (ttl <= 0) ttl = keyrec.getTTL(); + if (ttl <= 0) + ttl = keyrec.getTTL(); DNSOutput os = new DNSOutput(); os.writeByteArray(keyrec.getName().toWireCanonical()); os.writeByteArray(keyrec.rdataToWireCanonical()); - try - { + try { byte[] digest; MessageDigest md; - switch (digest_alg) - { - case DSRecord.SHA1_DIGEST_ID: + switch (digest_alg) { + case DNSSEC.Digest.SHA1: md = MessageDigest.getInstance("SHA"); digest = md.digest(os.toByteArray()); break; - case DSRecord.SHA256_DIGEST_ID: + case DNSSEC.Digest.SHA256: md = MessageDigest.getInstance("SHA-256"); digest = md.digest(os.toByteArray()); break; @@ -1535,12 +1497,10 @@ public class SignUtils } return new DSRecord(keyrec.getName(), keyrec.getDClass(), ttl, - keyrec.getFootprint(), keyrec.getAlgorithm(), digest_alg, - digest); + keyrec.getFootprint(), keyrec.getAlgorithm(), digest_alg, + digest); - } - catch (NoSuchAlgorithmException e) - { + } catch (NoSuchAlgorithmException e) { log.severe(e.toString()); return null; } @@ -1550,24 +1510,22 @@ public class SignUtils * Calculate an NSEC3 hash based on a DNS name and NSEC3 hash parameters. * * @param n - * The name to hash. + * The name to hash. * @param hash_algorithm - * The hash algorithm to use. + * The hash algorithm to use. * @param iterations - * The number of iterations to do. + * The number of iterations to do. * @param salt - * The salt to use. + * The salt to use. * @return The calculated hash as a byte array. * @throws NoSuchAlgorithmException - * If the hash algorithm is unrecognized. + * If the hash algorithm is unrecognized. */ public static byte[] nsec3hash(Name n, int hash_algorithm, int iterations, byte[] salt) - throws NoSuchAlgorithmException - { + throws NoSuchAlgorithmException { MessageDigest md; - switch (hash_algorithm) - { + switch (hash_algorithm) { case NSEC3Record.SHA1_DIGEST_ID: md = MessageDigest.getInstance("SHA1"); break; @@ -1579,11 +1537,9 @@ public class SignUtils // Construct our wire form. byte[] wire_name = n.toWireCanonical(); byte[] res = wire_name; // for the first iteration. - for (int i = 0; i <= iterations; i++) - { + for (int i = 0; i <= iterations; i++) { // Concatenate the salt, if it exists. - if (salt != null) - { + if (salt != null) { byte[] concat = new byte[res.length + salt.length]; System.arraycopy(res, 0, concat, 0, res.length); System.arraycopy(salt, 0, concat, res.length, salt.length); diff --git a/src/main/java/com/verisignlabs/dnssec/security/TypeMap.java b/src/main/java/com/verisignlabs/dnssec/security/TypeMap.java index 5003d9b..84542cd 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/TypeMap.java +++ b/src/main/java/com/verisignlabs/dnssec/security/TypeMap.java @@ -1,7 +1,19 @@ -// $Id$ +// Copyright (C) 2004, 2022 Verisign, Inc. // -// Copyright (C) 2004 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.security; import java.util.Arrays; @@ -18,45 +30,39 @@ import org.xbill.DNS.Type; * DNSjava: {@link org.xbill.DNS.TypeBitmap}. */ -public class TypeMap -{ +public class TypeMap { private static final Integer[] integerArray = new Integer[0]; private static final byte[] emptyBitmap = new byte[0]; - private Set typeSet; + private Set typeSet; - public TypeMap() - { + public TypeMap() { this.typeSet = new HashSet(); } /** Add the given type to the typemap. */ - public void set(int type) - { + public void set(int type) { typeSet.add(type); } /** Remove the given type from the type map. */ - public void clear(int type) - { + public void clear(int type) { typeSet.remove(type); } /** @return true if the given type is present in the type map. */ - public boolean get(int type) - { + public boolean get(int type) { return typeSet.contains(type); } /** * Given an array of DNS type code, construct a TypeMap object. */ - public static TypeMap fromTypes(int[] types) - { + public static TypeMap fromTypes(int[] types) { TypeMap m = new TypeMap(); - if (types == null) return m; - for (int i = 0; i < types.length; i++) - { + if (types == null) + return m; + for (int i = 0; i < types.length; i++) { m.set(types[i]); } @@ -67,25 +73,20 @@ public class TypeMap * Given an array of bytes representing a wire-format type map, construct the * TypeMap object. */ - public static TypeMap fromBytes(byte[] map) - { + public static TypeMap fromBytes(byte[] map) { int m = 0; TypeMap typemap = new TypeMap(); int page; int byte_length; - while (m < map.length) - { + while (m < map.length) { page = map[m++]; byte_length = map[m++]; - for (int i = 0; i < byte_length; i++) - { - for (int j = 0; j < 8; j++) - { - if ((map[m + i] & (1 << (7 - j))) != 0) - { + for (int i = 0; i < byte_length; i++) { + for (int j = 0; j < 8; j++) { + if ((map[m + i] & (1 << (7 - j))) != 0) { typemap.set((page << 8) + (i * 8) + j); } } @@ -99,12 +100,10 @@ public class TypeMap /** * Given list of type mnemonics, construct a TypeMap object. */ - public static TypeMap fromString(String types) - { + public static TypeMap fromString(String types) { TypeMap typemap = new TypeMap(); - for (String type : types.split("\\s+")) - { + for (String type : types.split("\\s+")) { typemap.set(Type.value(type)); } @@ -112,24 +111,22 @@ public class TypeMap } /** @return the normal string representation of the typemap. */ - public String toString() - { + public String toString() { int[] types = getTypes(); Arrays.sort(types); StringBuffer sb = new StringBuffer(); - for (int i = 0; i < types.length; i++) - { - if (i > 0) sb.append(" "); + for (int i = 0; i < types.length; i++) { + if (i > 0) + sb.append(" "); sb.append(Type.string(types[i])); } return sb.toString(); } - protected static void mapToWire(DNSOutput out, int[] types, int base, int start, int end) - { + protected static void mapToWire(DNSOutput out, int[] types, int base, int start, int end) { // calculate the length of this map by looking at the largest // typecode in this section. int max_type = types[end - 1] & 0xFF; @@ -144,22 +141,20 @@ public class TypeMap byte[] map = new byte[map_length]; // for each type in our sub-array, set its corresponding bit in the map. - for (int i = start; i < end; i++) - { + for (int i = start; i < end; i++) { map[(types[i] & 0xFF) / 8] |= (1 << (7 - types[i] % 8)); } // write out the resulting binary bitmap. - for (int i = 0; i < map.length; i++) - { + for (int i = 0; i < map.length; i++) { out.writeU8(map[i]); } } - public byte[] toWire() - { + public byte[] toWire() { int[] types = getTypes(); - if (types.length == 0) return emptyBitmap; + if (types.length == 0) + return emptyBitmap; Arrays.sort(types); @@ -168,12 +163,11 @@ public class TypeMap DNSOutput out = new DNSOutput(); - for (int i = 0; i < types.length; i++) - { + for (int i = 0; i < types.length; i++) { int base = (types[i] >> 8) & 0xFF; - if (base == mapbase) continue; - if (mapstart >= 0) - { + if (base == mapbase) + continue; + if (mapstart >= 0) { mapToWire(out, types, mapbase, mapstart, i); } mapbase = base; @@ -184,26 +178,22 @@ public class TypeMap return out.toByteArray(); } - public int[] getTypes() - { + public int[] getTypes() { Integer[] a = (Integer[]) typeSet.toArray(integerArray); int[] res = new int[a.length]; - for (int i = 0; i < res.length; i++) - { + for (int i = 0; i < res.length; i++) { res[i] = a[i].intValue(); } return res; } - public static int[] fromWireToTypes(byte[] wire_fmt) - { + public static int[] fromWireToTypes(byte[] wire_fmt) { return TypeMap.fromBytes(wire_fmt).getTypes(); } - public static byte[] fromTypesToWire(int[] types) - { + public static byte[] fromTypesToWire(int[] types) { return TypeMap.fromTypes(types).toWire(); } diff --git a/src/main/java/com/verisignlabs/dnssec/security/ZoneUtils.java b/src/main/java/com/verisignlabs/dnssec/security/ZoneUtils.java index 02cb2e2..209c27d 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/ZoneUtils.java +++ b/src/main/java/com/verisignlabs/dnssec/security/ZoneUtils.java @@ -1,6 +1,4 @@ -// $Id$ -// -// Copyright (C) 2003 VeriSign, Inc. +// Copyright (C) 2003, 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 @@ -24,11 +22,11 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import org.xbill.DNS.Master; 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; @@ -36,44 +34,42 @@ import org.xbill.DNS.Type; /** * This class contains a bunch of utility methods that are generally useful in * manipulating zones. - * - * @author David Blacka (original) - * @author $Author$ - * @version $Revision$ + * + * @author David Blacka */ -public class ZoneUtils -{ +public class ZoneUtils { /** * Load a zone file. - * + * * @param zonefile - * the filename/path of the zonefile to read. + * the filename/path of the zonefile to read. * @param origin - * the origin to use for the zonefile (may be null if the origin is - * specified in the zone file itself). + * the origin to use for the zonefile (may be null if the origin + * is + * specified in the zone file itself). * @return a {@link java.util.List} of {@link org.xbill.DNS.Record} objects. * @throws IOException - * if something goes wrong reading the zone file. + * if something goes wrong reading the zone file. */ - public static List readZoneFile(String zonefile, Name origin) throws IOException - { + public static List readZoneFile(String zonefile, Name origin) throws IOException { ArrayList records = new ArrayList(); Master m; - if (zonefile.equals("-")) - { - m = new Master(System.in); - } - else - { - m = new Master(zonefile, origin); - } + try { + if (zonefile.equals("-")) { + m = new Master(System.in); + } else { + m = new Master(zonefile, origin); + } - Record r = null; + Record r = null; - while ((r = m.nextRecord()) != null) - { - records.add(r); + while ((r = m.nextRecord()) != null) { + + records.add(r); + } + } catch (IOException e) { + e.printStackTrace(); } return records; @@ -81,28 +77,25 @@ public class ZoneUtils /** * Write the records out into a zone file. - * + * * @param records - * a {@link java.util.List} of {@link org.xbill.DNS.Record} objects - * forming a zone. + * a {@link java.util.List} of {@link org.xbill.DNS.Record} + * objects + * forming a zone. * @param zonefile - * the file to write to. If null or equal to "-", System.out is used. + * the file to write to. If null or equal to "-", System.out is + * used. */ - public static void writeZoneFile(List records, String zonefile) throws IOException - { + public static void writeZoneFile(List records, String zonefile) throws IOException { PrintWriter out = null; - if (zonefile == null || zonefile.equals("-")) - { + if (zonefile == null || zonefile.equals("-")) { out = new PrintWriter(System.out); - } - else - { + } else { out = new PrintWriter(new BufferedWriter(new FileWriter(zonefile))); } - for (Record r : records) - { + for (Record r : records) { out.println(r); } @@ -111,56 +104,43 @@ public class ZoneUtils /** * Given just the list of records, determine the zone name (origin). - * + * * @param records - * a list of {@link org.xbill.DNS.Record} objects. + * a list of {@link org.xbill.DNS.Record} objects. * @return the zone name, if found. null if one couldn't be found. */ - public static Name findZoneName(List records) - { - for (Record r : records) - { - int type = r.getType(); - - if (type == Type.SOA) return r.getName(); + public static Name findZoneName(List records) { + for (Record r : records) { + if (r.getType() == Type.SOA) { + return r.getName(); + } } return null; } - public static List findRRs(List records, Name name, int type) - { + public static List findRRs(List records, Name name, int type) { List res = new ArrayList(); - for (Record r : records) - { - if (r.getName().equals(name) && r.getType() == type) - { + for (Record r : records) { + if (r.getName().equals(name) && r.getType() == type) { res.add(r); } } - return res; } /** This is an alternate way to format an RRset into a string */ - @SuppressWarnings("unchecked") - public static String rrsetToString(RRset rrset, boolean includeSigs) - { + public static String rrsetToString(RRset rrset, boolean includeSigs) { StringBuilder out = new StringBuilder(); - for (Iterator i = rrset.rrs(false); i.hasNext();) - { - Record r = i.next(); + for (Record r : rrset.rrs(false)) { out.append(r.toString()); out.append("\n"); } - if (includeSigs) - { - for (Iterator i = rrset.sigs(); i.hasNext();) - { - Record r = i.next(); - out.append(r.toString()); + if (includeSigs) { + for (RRSIGRecord s : rrset.sigs()) { + out.append(s.toString()); out.append("\n"); } } diff --git a/src/main/java/com/verisignlabs/dnssec/security/ZoneVerifier.java b/src/main/java/com/verisignlabs/dnssec/security/ZoneVerifier.java index fb49d56..079d0ea 100644 --- a/src/main/java/com/verisignlabs/dnssec/security/ZoneVerifier.java +++ b/src/main/java/com/verisignlabs/dnssec/security/ZoneVerifier.java @@ -1,6 +1,4 @@ -// $Id: DnsSecVerifier.java 172 2009-08-23 19:13:42Z davidb $ -// -// Copyright (C) 2010 Verisign, Inc. +// Copyright (C) 2010, 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 @@ -49,62 +47,53 @@ import org.xbill.DNS.utils.base32; * verifying signatures, this class will also detect invalid NSEC and NSEC3 * chains. * - * @author David Blacka (original) - * @author $Author: davidb $ - * @version $Revision: 172 $ + * @author David Blacka */ -public class ZoneVerifier -{ +public class ZoneVerifier { private SortedMap> mNodeMap; - private HashMap mRRsetMap; - private SortedMap mNSECMap; - private SortedMap mNSEC3Map; - private Name mZoneName; - private DNSSECType mDNSSECType; - private NSEC3PARAMRecord mNSEC3params; - private boolean mIgnoreDuplicateRRs; + private HashMap mRRsetMap; + private SortedMap mNSECMap; + private SortedMap mNSEC3Map; + private Name mZoneName; + private DNSSECType mDNSSECType; + private NSEC3PARAMRecord mNSEC3params; + private boolean mIgnoreDuplicateRRs; - private DnsSecVerifier mVerifier; - private base32 mBase32; - private ByteArrayComparator mBAcmp; + private DnsSecVerifier mVerifier; + private base32 mBase32; + private ByteArrayComparator mBAcmp; - private Logger log = Logger.getLogger("ZoneVerifier"); + private Logger log = Logger.getLogger("ZoneVerifier"); // The various types of signed zones. - enum DNSSECType - { + enum DNSSECType { UNSIGNED, NSEC, NSEC3, NSEC3_OPTOUT; } // The types of nodes (a node consists of all RRs with the same name). - enum NodeType - { + enum NodeType { NORMAL, DELEGATION, GLUE; } /** * This is a subclass of {@link org.xbill.DNS.RRset} that adds a "mark". */ - private class MarkRRset extends RRset - { + private class MarkRRset extends RRset { private static final long serialVersionUID = 1L; - private boolean mIsMarked = false; + private boolean mIsMarked = false; - boolean getMark() - { + boolean getMark() { return mIsMarked; } - void setMark(boolean value) - { + void setMark(boolean value) { mIsMarked = value; } } - public ZoneVerifier() - { + public ZoneVerifier() { mVerifier = new DnsSecVerifier(); mBase32 = new base32(base32.Alphabet.BASE32HEX, false, true); mBAcmp = new ByteArrayComparator(); @@ -112,94 +101,78 @@ public class ZoneVerifier } /** @return the DnsSecVerifier object used to verify individual RRsets. */ - public DnsSecVerifier getVerifier() - { + public DnsSecVerifier getVerifier() { return mVerifier; } - public void setIgnoreDuplicateRRs(boolean value) - { + public void setIgnoreDuplicateRRs(boolean value) { mIgnoreDuplicateRRs = value; } - private static String key(Name n, int type) - { + private static String key(Name n, int type) { return n.toString() + ':' + type; } - @SuppressWarnings("rawtypes") - private boolean addRRtoRRset(RRset rrset, Record rr) - { - if (mIgnoreDuplicateRRs) - { + private boolean addRRtoRRset(RRset rrset, Record rr) { + if (mIgnoreDuplicateRRs) { rrset.addRR(rr); return true; } - Iterator i = (rr instanceof RRSIGRecord) ? rrset.sigs() : rrset.rrs(); - for ( ; i.hasNext(); ) - { - Record record = (Record) i.next(); - if (rr.equals(record)) return false; + if (rr instanceof RRSIGRecord) { + for (RRSIGRecord sigrec : rrset.sigs()) { + if (rr.equals(sigrec)) { + return false; + } + } + } else { + for (Record rec : rrset.rrs()) { + if (rr.equals(rec)) { + return false; + } + } } + rrset.addRR(rr); return true; } /** * Add a record to the various maps. + * * @return TODO */ - private boolean addRR(Record r) - { - Name r_name = r.getName(); - int r_type = r.getType(); - if (r_type == Type.RRSIG) r_type = ((RRSIGRecord) r).getTypeCovered(); + private boolean addRR(Record r) { + Name n = r.getName(); + int t = r.getType(); + if (t == Type.RRSIG) + t = ((RRSIGRecord) r).getTypeCovered(); // Add NSEC and NSEC3 RRs to their respective maps - if (r_type == Type.NSEC) - { - if (mNSECMap == null) mNSECMap = new TreeMap(); - MarkRRset rrset = mNSECMap.get(r_name); - if (rrset == null) - { - rrset = new MarkRRset(); - mNSECMap.put(r_name, rrset); + if (t == Type.NSEC) { + if (mNSECMap == null) { + mNSECMap = new TreeMap<>(); } - + MarkRRset rrset = mNSECMap.computeIfAbsent(n, k -> new MarkRRset()); return addRRtoRRset(rrset, r); } - if (r_type == Type.NSEC3) - { - if (mNSEC3Map == null) mNSEC3Map = new TreeMap(); - MarkRRset rrset = mNSEC3Map.get(r_name); - if (rrset == null) - { - rrset = new MarkRRset(); - mNSEC3Map.put(r_name, rrset); + if (t == Type.NSEC3) { + if (mNSEC3Map == null) { + mNSEC3Map = new TreeMap<>(); } + MarkRRset rrset = mNSECMap.computeIfAbsent(n, k -> new MarkRRset()); return addRRtoRRset(rrset, r); } // Add the name and type to the node map - Set typeset = mNodeMap.get(r_name); - if (typeset == null) - { - typeset = new HashSet(); - mNodeMap.put(r_name, typeset); - } + Set typeset = mNodeMap.computeIfAbsent(n, k -> new HashSet<>()); typeset.add(r.getType()); // add the original type // Add the record to the RRset map - String k = key(r_name, r_type); - RRset rrset = mRRsetMap.get(k); - if (rrset == null) - { - rrset = new RRset(); - mRRsetMap.put(k, rrset); - } + String k = key(n, t); + RRset rrset = mRRsetMap.computeIfAbsent(k, k2 -> new RRset()); return addRRtoRRset(rrset, r); } @@ -207,14 +180,12 @@ public class ZoneVerifier * Given a record, determine the DNSSEC signing type. If the record doesn't * determine that, DNSSECType.UNSIGNED is returned */ - private DNSSECType determineDNSSECType(Record r) - { - if (r.getType() == Type.NSEC) return DNSSECType.NSEC; - if (r.getType() == Type.NSEC3) - { + private DNSSECType determineDNSSECType(Record r) { + if (r.getType() == Type.NSEC) + return DNSSECType.NSEC; + if (r.getType() == Type.NSEC3) { NSEC3Record nsec3 = (NSEC3Record) r; - if ((nsec3.getFlags() & NSEC3Record.Flags.OPT_OUT) == NSEC3Record.Flags.OPT_OUT) - { + if ((nsec3.getFlags() & NSEC3Record.Flags.OPT_OUT) == NSEC3Record.Flags.OPT_OUT) { return DNSSECType.NSEC3_OPTOUT; } return DNSSECType.NSEC3; @@ -230,39 +201,39 @@ public class ZoneVerifier * @param records * @return TODO */ - private int calculateNodes(List records) - { - mNodeMap = new TreeMap>(); - mRRsetMap = new HashMap(); + private int calculateNodes(List records) { + mNodeMap = new TreeMap<>(); + mRRsetMap = new HashMap<>(); // The zone is unsigned until we get a clue otherwise. mDNSSECType = DNSSECType.UNSIGNED; int errors = 0; - for (Record r : records) - { - Name r_name = r.getName(); - int r_type = r.getType(); + for (Record r : records) { + Name n = r.getName(); + int t = r.getType(); // Add the record to the various maps. boolean res = addRR(r); - if (!res) - { + if (!res) { log.warning("Record '" + r + "' detected as a duplicate"); errors++; } // Learn some things about the zone as we do this pass. - if (r_type == Type.SOA) mZoneName = r_name; - if (r_type == Type.NSEC3PARAM) mNSEC3params = (NSEC3PARAMRecord) r; - if (r_type == Type.DNSKEY) { + if (t == Type.SOA) + mZoneName = n; + if (t == Type.NSEC3PARAM) + mNSEC3params = (NSEC3PARAMRecord) r; + if (t == Type.DNSKEY) { DNSKEYRecord dnskey = (DNSKEYRecord) r; mVerifier.addTrustedKey(dnskey); log.info("Adding trusted key: " + dnskey + " ; keytag = " - + dnskey.getFootprint()); + + dnskey.getFootprint()); } - if (mDNSSECType == DNSSECType.UNSIGNED) mDNSSECType = determineDNSSECType(r); + if (mDNSSECType == DNSSECType.UNSIGNED) + mDNSSECType = determineDNSSECType(r); } return errors; @@ -272,37 +243,40 @@ public class ZoneVerifier * Given a name, typeset, and name of the last zone cut, determine the node * type. */ - private NodeType determineNodeType(Name n, Set typeset, Name last_cut) - { + private NodeType determineNodeType(Name n, Set typeset, Name last_cut) { // All RRs at the zone apex are normal - if (n.equals(mZoneName)) return NodeType.NORMAL; + if (n.equals(mZoneName)) + return NodeType.NORMAL; - // If the node is not below the zone itself, we will treat it as glue (it is really junk). - if (!n.subdomain(mZoneName)) - { + // If the node is not below the zone itself, we will treat it as glue (it is + // really junk). + if (!n.subdomain(mZoneName)) { return NodeType.GLUE; } // If the node is below a zone cut (either a delegation or DNAME), it is // glue. - if (last_cut != null && n.subdomain(last_cut) && !n.equals(last_cut)) - { + if (last_cut != null && n.subdomain(last_cut) && !n.equals(last_cut)) { return NodeType.GLUE; } // If the node has a NS record it is a delegation. - if (typeset.contains(new Integer(Type.NS))) return NodeType.DELEGATION; + if (typeset.contains(Integer.valueOf(Type.NS))) + return NodeType.DELEGATION; return NodeType.NORMAL; } - private Set cleanupDelegationTypeset(Set typeset) - { - Set t = new HashSet(); - if (typeset.contains(Type.NS)) t.add(Type.NS); - if (typeset.contains(Type.DS)) t.add(Type.DS); - if (typeset.contains(Type.RRSIG)) t.add(Type.RRSIG); + private Set cleanupDelegationTypeset(Set typeset) { + Set t = new HashSet<>(); + if (typeset.contains(Type.NS)) + t.add(Type.NS); + if (typeset.contains(Type.DS)) + t.add(Type.DS); + if (typeset.contains(Type.RRSIG)) + t.add(Type.RRSIG); - if (!typeset.equals(t)) return t; + if (!typeset.equals(t)) + return t; return typeset; } @@ -310,13 +284,11 @@ public class ZoneVerifier * For each node, determine which RRsets should be signed, verify those, and * determine which nodes get NSEC or NSEC3 RRs and verify those. */ - private int processNodes() throws NoSuchAlgorithmException, TextParseException - { + private int processNodes() throws NoSuchAlgorithmException, TextParseException { int errors = 0; Name last_cut = null; - for (Map.Entry> entry : mNodeMap.entrySet()) - { + for (Map.Entry> entry : mNodeMap.entrySet()) { Name n = entry.getKey(); Set typeset = entry.getValue(); @@ -324,21 +296,22 @@ public class ZoneVerifier log.finest("Node " + n + " is type " + ntype); // we can ignore glue/invalid RRs. - if (ntype == NodeType.GLUE) continue; + if (ntype == NodeType.GLUE) + continue; // record the last zone cut if this node is a zone cut. - if (ntype == NodeType.DELEGATION || typeset.contains(Type.DNAME)) - { + if (ntype == NodeType.DELEGATION || typeset.contains(Type.DNAME)) { last_cut = n; } // check all of the RRsets that should be signed - for (int type : typeset) - { - if (type == Type.RRSIG) continue; + for (int type : typeset) { + if (type == Type.RRSIG) + continue; // at delegation points, only DS RRs are signed (and NSEC, but those are // checked separately) - if (ntype == NodeType.DELEGATION && type != Type.DS) continue; + if (ntype == NodeType.DELEGATION && type != Type.DS) + continue; // otherwise, verify the RRset. String k = key(n, type); RRset rrset = mRRsetMap.get(k); @@ -348,13 +321,11 @@ public class ZoneVerifier // cleanup the typesets of delegation nodes. // the only types that should be there are NS, DS and RRSIG. - if (ntype == NodeType.DELEGATION) - { + if (ntype == NodeType.DELEGATION) { typeset = cleanupDelegationTypeset(typeset); } - switch (mDNSSECType) - { + switch (mDNSSECType) { case NSEC: // all nodes with NSEC records have NSEC and RRSIG types typeset.add(Type.NSEC); @@ -366,8 +337,7 @@ public class ZoneVerifier break; case NSEC3_OPTOUT: if (ntype == NodeType.NORMAL - || (ntype == NodeType.DELEGATION && typeset.contains(Type.DS))) - { + || (ntype == NodeType.DELEGATION && typeset.contains(Type.DS))) { errors += processNSEC3(n, typeset, ntype); } break; @@ -378,99 +348,87 @@ public class ZoneVerifier return errors; } - private static String reasonListToString(List reasons) - { - if (reasons == null) return ""; - StringBuffer out = new StringBuffer(); - for (Iterator i = reasons.iterator(); i.hasNext();) - { + private static String reasonListToString(List reasons) { + if (reasons == null) + return ""; + StringBuilder out = new StringBuilder(); + for (Iterator i = reasons.iterator(); i.hasNext();) { out.append("Reason: "); out.append(i.next()); - if (i.hasNext()) out.append("\n"); + if (i.hasNext()) + out.append("\n"); } return out.toString(); } - @SuppressWarnings("unchecked") - private int processRRset(RRset rrset) - { - List reasons = new ArrayList(); + private int processRRset(RRset rrset) { + List reasons = new ArrayList<>(); boolean result = false; - for (Iterator i = rrset.sigs(); i.hasNext();) - { - RRSIGRecord sigrec = (RRSIGRecord) i.next(); + for (RRSIGRecord sigrec : rrset.sigs()) { boolean res = mVerifier.verifySignature(rrset, sigrec, reasons); - if (!res) - { + if (!res) { log.warning("Signature failed to verify RRset:\n rr: " + ZoneUtils.rrsetToString(rrset, false) + "\n sig: " + sigrec + "\n" + reasonListToString(reasons)); } - if (res) result = res; + if (res) + result = res; } String rrsetname = rrset.getName() + "/" + Type.string(rrset.getType()); - if (result) - { + if (result) { log.fine("RRset " + rrsetname + " verified."); - } - else - { + } else { log.warning("RRset " + rrsetname + " did not verify."); } return result ? 0 : 1; } - private String typesToString(int[] types) - { + private String typesToString(int[] types) { StringBuilder sb = new StringBuilder(); Arrays.sort(types); - for (int i = 0; i < types.length; ++i) - { - if (i != 0) sb.append(' '); + for (int i = 0; i < types.length; ++i) { + if (i != 0) + sb.append(' '); sb.append(Type.string(types[i])); } return sb.toString(); } - private String typesetToString(Set typeset) - { - if (typeset == null) return ""; + private String typesetToString(Set typeset) { + if (typeset == null) + return ""; int[] types = new int[typeset.size()]; int i = 0; - for (int type : typeset) - { + for (int type : typeset) { types[i++] = type; } return typesToString(types); } - private boolean checkTypeMap(Set typeset, int[] types) - { + private boolean checkTypeMap(Set typeset, int[] types) { // a null typeset means that we are expecting the typemap of an ENT, which // should be empty. - if (typeset == null) return types.length == 0; + if (typeset == null) + return types.length == 0; - Set compareTypeset = new HashSet(); - for (int i = 0; i < types.length; ++i) - { + Set compareTypeset = new HashSet<>(); + for (int i = 0; i < types.length; ++i) { compareTypeset.add(types[i]); } return typeset.equals(compareTypeset); } - private int processNSEC(Name n, Set typeset) - { + private int processNSEC(Name n, Set typeset) { MarkRRset rrset = mNSECMap.get(n); - if (n == null) - { + if (n == null) { log.warning("Missing NSEC for " + n); return 1; } @@ -482,8 +440,7 @@ public class ZoneVerifier NSECRecord nsec = (NSECRecord) rrset.first(); // check typemap - if (!checkTypeMap(typeset, nsec.getTypes())) - { + if (!checkTypeMap(typeset, nsec.getTypes())) { log.warning("Typemap for NSEC RR " + n + " did not match what was expected. Expected '" + typesetToString(typeset) + "', got '" + typesToString(nsec.getTypes())); @@ -496,32 +453,27 @@ public class ZoneVerifier return errors; } - private boolean shouldCheckENTs(Name n, Set typeset, NodeType ntype) - { + private boolean shouldCheckENTs(Name n, Set typeset, NodeType ntype) { // if we are just one (or zero) labels longer than the zonename, the node // can't create a ENT - if (n.labels() <= mZoneName.labels() + 1) return false; + if (n.labels() <= mZoneName.labels() + 1) + return false; // we probably won't ever get called for a GLUE node - if (ntype == NodeType.GLUE) return false; + if (ntype == NodeType.GLUE) + return false; // if we aren't doing opt-out, then all possible ENTs must be checked. - if (mDNSSECType == DNSSECType.NSEC3) return true; + if (mDNSSECType == DNSSECType.NSEC3) + return true; // if we are opt-out, and the node is an insecure delegation, don't check // ENTs. - if (ntype == NodeType.DELEGATION && !typeset.contains(Type.DS)) - { - return false; - } - - // otherwise, check ENTs. - return true; + return !(ntype == NodeType.DELEGATION && !typeset.contains(Type.DS)); } private int processNSEC3(Name n, Set typeset, NodeType ntype) - throws NoSuchAlgorithmException, TextParseException - { + throws NoSuchAlgorithmException, TextParseException { // calculate the NSEC3 RR name byte[] hash = mNSEC3params.hashName(n); @@ -529,8 +481,7 @@ public class ZoneVerifier Name hashname = new Name(hashstr, mZoneName); MarkRRset rrset = mNSEC3Map.get(hashname); - if (rrset == null) - { + if (rrset == null) { log.warning("Missing NSEC3 for " + hashname + " corresponding to " + n); return 1; } @@ -542,8 +493,7 @@ public class ZoneVerifier NSEC3Record nsec3 = (NSEC3Record) rrset.first(); // check typemap - if (!checkTypeMap(typeset, nsec3.getTypes())) - { + if (!checkTypeMap(typeset, nsec3.getTypes())) { log.warning("Typemap for NSEC3 RR " + hashname + " for " + n + " did not match what was expected. Expected '" + typesetToString(typeset) + "', got '" + typesToString(nsec3.getTypes()) + "'"); @@ -555,11 +505,9 @@ public class ZoneVerifier // check NSEC3 RRs for empty non-terminals. // this is recursive. - if (shouldCheckENTs(n, typeset, ntype)) - { + if (shouldCheckENTs(n, typeset, ntype)) { Name ent = new Name(n, 1); - if (mNodeMap.get(ent) == null) - { + if (mNodeMap.get(ent) == null) { errors += processNSEC3(ent, null, NodeType.NORMAL); } } @@ -567,24 +515,18 @@ public class ZoneVerifier return errors; } - private int processNSECChain() - { + private int processNSECChain() { int errors = 0; NSECRecord lastNSEC = null; - for (Iterator> i = mNSECMap.entrySet().iterator(); i.hasNext();) - { + for (Iterator> i = mNSECMap.entrySet().iterator(); i.hasNext();) { // check the internal ordering of the previous NSEC record. This avoids // looking at the last one, // which is different. - if (lastNSEC != null) - { - if (lastNSEC.getName().compareTo(lastNSEC.getNext()) >= 0) - { - log.warning("NSEC for " + lastNSEC.getName() - + " has next name >= owner but is not the last NSEC in the chain."); - errors++; - } + if (lastNSEC != null && lastNSEC.getName().compareTo(lastNSEC.getNext()) >= 0) { + log.warning("NSEC for " + lastNSEC.getName() + + " has next name >= owner but is not the last NSEC in the chain."); + errors++; } Map.Entry entry = i.next(); @@ -593,8 +535,7 @@ public class ZoneVerifier // check to see if the NSEC is marked. If not, it was not correlated to a // signed node. - if (!rrset.getMark()) - { + if (!rrset.getMark()) { log.warning("NSEC RR for " + n + " appears to be extra."); errors++; } @@ -604,30 +545,24 @@ public class ZoneVerifier // This is just a sanity check. If this isn't true, we are constructing // the // nsec map incorrectly. - if (!n.equals(nsec.getName())) - { + if (!n.equals(nsec.getName())) { log.warning("The NSEC in the map for name " + n + " has name " + nsec.getName()); errors++; } // If this is the first row, ensure that the owner name equals the zone // name - if (lastNSEC == null && !n.equals(mZoneName)) - { + if (lastNSEC == null && !n.equals(mZoneName)) { log.warning("The first NSEC in the chain does not match the zone name: name = " + n + " zonename = " + mZoneName); errors++; } // Check that the prior NSEC's next name equals this rows owner name. - if (lastNSEC != null) - { - if (!lastNSEC.getNext().equals(nsec.getName())) - { - log.warning("NSEC for " + lastNSEC.getName() - + " does not point to the next NSEC in the chain: " + n); - errors++; - } + if (lastNSEC != null && !lastNSEC.getNext().equals(nsec.getName())) { + log.warning("NSEC for " + lastNSEC.getName() + + " does not point to the next NSEC in the chain: " + n); + errors++; } lastNSEC = nsec; @@ -635,16 +570,14 @@ public class ZoneVerifier // check the internal ordering of the last NSEC in the chain // the ownername should be >= next name. - if (lastNSEC.getName().compareTo(lastNSEC.getNext()) < 0) - { + if (lastNSEC.getName().compareTo(lastNSEC.getNext()) < 0) { log.warning("The last NSEC RR in the chain did not have an owner >= next: owner = " + lastNSEC.getName() + " next = " + lastNSEC.getNext()); errors++; } // check to make sure it links to the first NSEC in the chain - if (!lastNSEC.getNext().equals(mZoneName)) - { + if (!lastNSEC.getNext().equals(mZoneName)) { log.warning("The last NSEC RR in the chain did not link to the first NSEC"); errors++; } @@ -652,8 +585,7 @@ public class ZoneVerifier return errors; } - private int compareNSEC3Hashes(Name owner, byte[] hash) - { + private int compareNSEC3Hashes(Name owner, byte[] hash) { // we will compare the binary images String ownerhashstr = owner.getLabelString(0); byte[] ownerhash = mBase32.fromString(ownerhashstr); @@ -661,25 +593,19 @@ public class ZoneVerifier return mBAcmp.compare(ownerhash, hash); } - private int processNSEC3Chain() - { + private int processNSEC3Chain() { int errors = 0; NSEC3Record lastNSEC3 = null; NSEC3Record firstNSEC3 = null; - for (Iterator> i = mNSEC3Map.entrySet().iterator(); i.hasNext();) - { + for (Iterator> i = mNSEC3Map.entrySet().iterator(); i.hasNext();) { // check the internal ordering of the previous NSEC3 record. This avoids // looking at the last one, // which is different. - if (lastNSEC3 != null) - { - if (compareNSEC3Hashes(lastNSEC3.getName(), lastNSEC3.getNext()) >= 0) - { - log.warning("NSEC3 for " + lastNSEC3.getName() - + " has next name >= owner but is not the last NSEC3 in the chain."); - errors++; - } + if (lastNSEC3 != null && compareNSEC3Hashes(lastNSEC3.getName(), lastNSEC3.getNext()) >= 0) { + log.warning("NSEC3 for " + lastNSEC3.getName() + + " has next name >= owner but is not the last NSEC3 in the chain."); + errors++; } Map.Entry entry = i.next(); @@ -688,8 +614,7 @@ public class ZoneVerifier // check to see if the NSEC is marked. If not, it was not correlated to a // signed node. - if (!rrset.getMark()) - { + if (!rrset.getMark()) { log.warning("NSEC3 RR for " + n + " appears to be extra."); errors++; } @@ -699,23 +624,19 @@ public class ZoneVerifier // This is just a sanity check. If this isn't true, we are constructing // the // nsec3 map incorrectly. - if (!n.equals(nsec3.getName())) - { + if (!n.equals(nsec3.getName())) { log.severe("The NSEC3 in the map for name " + n + " has name " + nsec3.getName()); errors++; } // note the first NSEC3 in the chain. - if (lastNSEC3 == null) - { + if (lastNSEC3 == null) { firstNSEC3 = nsec3; - } - else + } else // Check that the prior NSEC3's next hashed name equals this row's hashed // owner name. { - if (compareNSEC3Hashes(nsec3.getName(), lastNSEC3.getNext()) != 0) - { + if (compareNSEC3Hashes(nsec3.getName(), lastNSEC3.getNext()) != 0) { String nextstr = mBase32.toString(lastNSEC3.getNext()); log.warning("NSEC3 for " + lastNSEC3.getName() + " does not point to the next NSEC3 in the chain: " + nsec3.getName() @@ -729,8 +650,7 @@ public class ZoneVerifier // check the internal ordering of the last NSEC in the chain // the ownername should be >= next name. - if (compareNSEC3Hashes(lastNSEC3.getName(), lastNSEC3.getNext()) < 0) - { + if (compareNSEC3Hashes(lastNSEC3.getName(), lastNSEC3.getNext()) < 0) { String nextstr = mBase32.toString(lastNSEC3.getNext()); log.warning("The last NSEC3 RR in the chain did not have an owner >= next: owner = " + lastNSEC3.getName() + " next = " + nextstr); @@ -738,8 +658,7 @@ public class ZoneVerifier } // check to make sure it links to the first NSEC in the chain - if (compareNSEC3Hashes(firstNSEC3.getName(), lastNSEC3.getNext()) != 0) - { + if (compareNSEC3Hashes(firstNSEC3.getName(), lastNSEC3.getNext()) != 0) { log.warning("The last NSEC3 RR in the chain did not link to the first NSEC3"); errors++; } @@ -747,29 +666,22 @@ public class ZoneVerifier return errors; } - public int verifyZone(List records) throws NoSuchAlgorithmException, TextParseException - { + public int verifyZone(List records) throws NoSuchAlgorithmException, TextParseException { int errors = 0; errors += calculateNodes(records); errors += processNodes(); - if (mDNSSECType == DNSSECType.NSEC) - { + if (mDNSSECType == DNSSECType.NSEC) { errors += processNSECChain(); - } - else if (mDNSSECType == DNSSECType.NSEC3 || mDNSSECType == DNSSECType.NSEC3_OPTOUT) - { + } else if (mDNSSECType == DNSSECType.NSEC3 || mDNSSECType == DNSSECType.NSEC3_OPTOUT) { errors += processNSEC3Chain(); } - if (errors > 0) - { + if (errors > 0) { log.info("Zone " + mZoneName + " failed verification with " + errors + " errors"); - } - else - { + } else { log.info("Zone " + mZoneName + " verified with 0 errors"); }