diff --git a/bin/_makeDsSet.sh b/bin/_makeDsSet.sh deleted file mode 100755 index d0e3bc5..0000000 --- a/bin/_makeDsSet.sh +++ /dev/null @@ -1,27 +0,0 @@ -#! /bin/sh - -thisdir=`dirname $0` -basedir=`cd $thisdir/..; pwd` - -ulimit -n `ulimit -H -n` - -if [ x$JAVA_HOME = x ]; then - JAVA_HOME=/usr/local/jdk1.3 - export JAVA_HOME -fi - -LD_LIBRARY_PATH=${basedir}/obj:${LD_LIBRARY_PATH} -export LD_LIBRARY_PATH - -# set the classpath -CLASSPATH=\ -$JAVA_HOME/jre/lib/rt.jar:\ -$basedir/obj/classes:\ -$basedir/lib/dnsjava.jar:\ -$basedir/lib/protomatter-1.1.5.jar:\ -$basedir/lib/jdom-B6.jar:\ -$basedir/lib/jce1_2_1.jar - -export CLASSPATH - -exec $JAVA_HOME/bin/java -Xmx64m com.nsi.dnssec.cl.MakeDSSet "$@" diff --git a/bin/_makeKeySet.sh b/bin/_makeKeySet.sh deleted file mode 100755 index 7a69b50..0000000 --- a/bin/_makeKeySet.sh +++ /dev/null @@ -1,27 +0,0 @@ -#! /bin/sh - -thisdir=`dirname $0` -basedir=`cd $thisdir/..; pwd` - -ulimit -n `ulimit -H -n` - -if [ x$JAVA_HOME = x ]; then - JAVA_HOME=/usr/local/jdk1.3 - export JAVA_HOME -fi - -LD_LIBRARY_PATH=${basedir}/obj:${LD_LIBRARY_PATH} -export LD_LIBRARY_PATH - -# set the classpath -CLASSPATH=\ -$JAVA_HOME/jre/lib/rt.jar:\ -$basedir/obj/classes:\ -$basedir/lib/dnsjava.jar:\ -$basedir/lib/protomatter-1.1.5.jar:\ -$basedir/lib/jdom-B6.jar:\ -$basedir/lib/jce1_2_1.jar - -export CLASSPATH - -exec $JAVA_HOME/bin/java -Xmx64m com.nsi.dnssec.cl.MakeKeySet "$@" diff --git a/lib/dnsjava-1.5.2.jar b/lib/dnsjava-1.5.2.jar deleted file mode 100644 index 9abc126..0000000 Binary files a/lib/dnsjava-1.5.2.jar and /dev/null differ diff --git a/lib/dnsjava-2.0.0.jar b/lib/dnsjava-2.0.0.jar new file mode 100644 index 0000000..5af4715 Binary files /dev/null and b/lib/dnsjava-2.0.0.jar differ diff --git a/lib/jce1_2_2.jar b/lib/jce1_2_2.jar deleted file mode 100644 index 666a7e7..0000000 Binary files a/lib/jce1_2_2.jar and /dev/null differ diff --git a/src/com/verisignlabs/dnssec/cl/KeyGen.java b/src/com/verisignlabs/dnssec/cl/KeyGen.java index 6a195c1..faf66b3 100644 --- a/src/com/verisignlabs/dnssec/cl/KeyGen.java +++ b/src/com/verisignlabs/dnssec/cl/KeyGen.java @@ -1,4 +1,4 @@ -// $Id: KeyGen.java,v 1.2 2004/01/16 17:56:17 davidb Exp $ +// $Id$ // // Copyright (C) 2001-2003 VeriSign, Inc. // @@ -20,6 +20,8 @@ package com.verisignlabs.dnssec.cl; import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; import java.io.*; import java.text.SimpleDateFormat; import java.text.ParseException; @@ -32,66 +34,65 @@ import com.verisignlabs.dnssec.security.*; import org.apache.commons.cli.*; import org.apache.commons.cli.Options; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** This class forms the command line implementation of a DNSSEC key - * generator - * - * @author David Blacka (original) - * @author $Author: davidb $ - * @version $Revision: 1.2 $ +/** + * This class forms the command line implementation of a DNSSEC key generator + * + * @author David Blacka (original) + * @author $Author$ + * @version $Revision$ */ public class KeyGen { - private static Log log; - - /** This is a small inner class used to hold all of the command line - * option state. */ + private static Logger log; + + /** + * This is a small inner class used to hold all of the command line option + * state. + */ private static class CLIState { - public int algorithm = 5; - public int keylength = 1024; - public String outputfile = null; - public File keydir = null; - public boolean zoneKey = true; - public boolean kskFlag = false; - public String owner = null; - public long ttl = 86400; - - public CLIState() { } + private Options opts; + public int algorithm = 5; + public int keylength = 1024; + public String outputfile = null; + public File keydir = null; + public boolean zoneKey = true; + public boolean kskFlag = false; + public String owner = null; + public long ttl = 86400; - public void parseCommandLine(Options opts, String[] args) - throws org.apache.commons.cli.ParseException, ParseException, - IOException + public CLIState() + { + setupCLI(); + } + + public void parseCommandLine(String[] args) + throws org.apache.commons.cli.ParseException { CommandLineParser cli_parser = new PosixParser(); - CommandLine cli = cli_parser.parse(opts, args); + CommandLine cli = cli_parser.parse(opts, args); String optstr = null; - if (cli.hasOption('h')) usage(opts); - + if (cli.hasOption('h')) usage(); + if (cli.hasOption('v')) { - int value = parseInt(cli.getOptionValue('v'), 5); - - switch (value) - { - case 0: - System.setProperty("org.apache.commons.logging.simplelog.defaultlog", - "fatal"); - break; - case 5: - default: - System.setProperty("org.apache.commons.logging.simplelog.defaultlog", - "debug"); - break; - case 6: - System.setProperty("org.apache.commons.logging.simplelog.defaultlog", - "trace"); - break; - } + int value = parseInt(cli.getOptionValue('v'), 5); + Logger rootLogger = Logger.getLogger(""); + switch (value) + { + case 0 : + rootLogger.setLevel(Level.OFF); + break; + case 5 : + default : + rootLogger.setLevel(Level.FINE); + break; + case 6 : + rootLogger.setLevel(Level.ALL); + break; + } } if (cli.hasOption('k')) kskFlag = true; @@ -102,10 +103,10 @@ public class KeyGen { keydir = new File(optstr); } - + if ((optstr = cli.getOptionValue('n')) != null) { - if (! optstr.equalsIgnoreCase("ZONE")) + if (!optstr.equalsIgnoreCase("ZONE")) { zoneKey = false; } @@ -124,25 +125,104 @@ public class KeyGen { ttl = parseInt(optstr, 86400); } - + String[] cl_args = cli.getArgs(); if (cl_args.length < 1) { - System.err.println("error: missing key owner name"); - usage(opts); + System.err.println("error: missing key owner name"); + usage(); } owner = cl_args[0]; } + + /** + * Set up the command line options. + * + * @return a set of command line options. + */ + private void setupCLI() + { + opts = new Options(); + + // boolean options + opts.addOption("h", "help", false, "Print this message."); + opts.addOption("k", + "kskflag", + false, + "Key is a key-signing-key (sets the SEP flag)."); + + // Argument options + OptionBuilder.hasArg(); + OptionBuilder.withLongOpt("nametype"); + OptionBuilder.withArgName("type"); + OptionBuilder.withDescription("ZONE | OTHER (default ZONE)"); + opts.addOption(OptionBuilder.create('n')); + + OptionBuilder.hasOptionalArg(); + OptionBuilder.withLongOpt("verbose"); + OptionBuilder.withArgName("level"); + OptionBuilder.withDescription("verbosity level -- 0 is silence, " + + "5 is debug information, " + "6 is trace information.\n" + + "default is level 5."); + opts.addOption(OptionBuilder.create('v')); + + OptionBuilder.hasArg(); + OptionBuilder.withArgName("algorithm"); + OptionBuilder.withDescription("RSA | RSASHA1 | RSAMD5 | DH | DSA, " + + "RSASHA1 is default."); + opts.addOption(OptionBuilder.create('a')); + + OptionBuilder.hasArg(); + OptionBuilder.withArgName("size"); + OptionBuilder.withDescription("key size, in bits. (default = 1024)\n" + + "RSA|RSASHA1|RSAMD5: [512..4096]\n" + + "DSA: [512..1024]\n" + + "DH: [128..4096]"); + opts.addOption(OptionBuilder.create('b')); + + OptionBuilder.hasArg(); + OptionBuilder.withArgName("file"); + OptionBuilder.withLongOpt("output-file"); + OptionBuilder.withDescription("base filename for the public/private key files"); + opts.addOption(OptionBuilder.create('f')); + + OptionBuilder.hasArg(); + OptionBuilder.withLongOpt("keydir"); + OptionBuilder.withArgName("dir"); + OptionBuilder.withDescription("place generated key files in this directory"); + opts.addOption(OptionBuilder.create('d')); + } + + /** Print out the usage and help statements, then quit. */ + private void usage() + { + HelpFormatter f = new HelpFormatter(); + + PrintWriter out = new PrintWriter(System.err); + + // print our own usage statement: + f.printHelp(out, + 75, + "jdnssec-keygen [..options..] name", + null, + opts, + HelpFormatter.DEFAULT_LEFT_PAD, + HelpFormatter.DEFAULT_DESC_PAD, + null); + + out.flush(); + System.exit(64); + } } - /** This is just a convenience method for parsing integers from - * strings. - * - * @param s the string to parse. - * @param def the default value, if the string doesn't parse. - * @return the parsed integer, or the default. + /** + * This is just a convenience method for parsing integers from strings. + * + * @param s the string to parse. + * @param def the default value, if the string doesn't parse. + * @return the parsed integer, or the default. */ private static int parseInt(String s, int def) { @@ -161,7 +241,7 @@ public class KeyGen { int alg = parseInt(s, -1); if (alg > 0) return alg; - + s = s.toUpperCase(); if (s.equals("RSA")) @@ -188,109 +268,34 @@ public class KeyGen // default return DNSSEC.RSASHA1; } - - /** Set up the command line options. - * - * @return a set of command line options. - */ - private static Options setupCLI() - { - Options options = new Options(); - - // boolean options - options.addOption("h", "help", false, "Print this message."); - options.addOption("k", "kskflag", false, - "Key is a key-signing-key (sets the SEP flag)."); - // Argument options - options.addOption(OptionBuilder.hasArg() - .withLongOpt("nametype") - .withArgName("type") - .withDescription("ZONE | OTHER (default ZONE)") - .create('n')); - options.addOption(OptionBuilder.hasOptionalArg() - .withLongOpt("verbose") - .withArgName("level") - .withDescription("verbosity level -- 0 is silence, " + - "5 is debug information, " + - "6 is trace information.\n"+ - "default is level 5.") - .create('v')); - options.addOption(OptionBuilder.hasArg() - .withArgName("algorithm") - .withDescription("RSA | RSASHA1 | RSAMD5 | DH | DSA, " + - "RSASHA1 is default.") - .create('a')); - options.addOption(OptionBuilder.hasArg() - .withArgName("size") - .withDescription - ("key size, in bits. (default = 1024)\n" + - "RSA|RSASHA1|RSAMD5: [512..4096]\n" + - "DSA: [512..1024]\n" + - "DH: [128..4096]") - .create('b')); - options.addOption(OptionBuilder.hasArg() - .withArgName("file") - .withLongOpt("output-file") - .withDescription - ("base filename for the public/private key files") - .create('f')); - options.addOption(OptionBuilder.hasArg() - .withLongOpt("keydir") - .withArgName("dir") - .withDescription - ("place generated key files in this directory") - .create('d')); - - return options; - } - - /** Print out the usage and help statements, then quit. */ - private static void usage(Options opts) - { - HelpFormatter f = new HelpFormatter(); - - PrintWriter out = new PrintWriter(System.err); - - // print our own usage statement: - f.printHelp(out, 75, "keyGen.sh [..options..] name", null, opts, - HelpFormatter.DEFAULT_LEFT_PAD, - HelpFormatter.DEFAULT_DESC_PAD, null); - - out.flush(); - System.exit(64); - } - - - public static void execute(CLIState state, Options opts) - throws Exception + public static void execute(CLIState state) throws Exception { JCEDnsSecSigner signer = new JCEDnsSecSigner(); // Minor hack to make the owner name absolute. - if (! state.owner.endsWith(".")) + if (!state.owner.endsWith(".")) { state.owner = state.owner + "."; } - + Name owner_name = Name.fromString(state.owner); // Calculate our flags int flags = 0; - if (state.zoneKey) flags |= DNSKEYRecord.OWNER_ZONE; - if (state.kskFlag) flags |= DNSKEYRecord.FLAG_SEP; + if (state.zoneKey) flags |= DNSKEYRecord.Flags.ZONE_KEY; + if (state.kskFlag) flags |= DNSKEYRecord.Flags.SEP_KEY; + + log.fine("create key pair with (name = " + owner_name + ", ttl = " + + state.ttl + ", alg = " + state.algorithm + ", flags = " + flags + + ", length = " + state.keylength + ")"); - log.debug("create key pair with (name = " + owner_name + ", ttl = " + - state.ttl + ", alg = " + state.algorithm + ", flags = " + - flags + ", length = " + state.keylength + ")"); - - DnsKeyPair pair = signer.generateKey(owner_name, - state.ttl, - DClass.IN, - state.algorithm, - flags, - state.keylength); + state.ttl, + DClass.IN, + state.algorithm, + flags, + state.keylength); if (state.outputfile != null) { @@ -301,48 +306,39 @@ public class KeyGen BINDKeyUtils.writeKeyFiles(pair, state.keydir); } } - + public static void main(String[] args) { - // set up logging. - // For now, we force the commons logging to use the built-in - // SimpleLog. - System.setProperty("org.apache.commons.logging.Log", - "org.apache.commons.logging.impl.SimpleLog"); - - // set up the command line options - Options opts = setupCLI(); - - CLIState state = new CLIState(); + CLIState state = new CLIState(); try { - state.parseCommandLine(opts, args); + state.parseCommandLine(args); } catch (UnrecognizedOptionException e) { - System.err.println("error: unknown option encountered: " + - e.getMessage()); - usage(opts); + System.err.println("error: unknown option encountered: " + + e.getMessage()); + state.usage(); } catch (AlreadySelectedException e) { - System.err.println("error: mutually exclusive options have " + - "been selected:\n " + e.getMessage()); - usage(opts); + System.err.println("error: mutually exclusive options have " + + "been selected:\n " + e.getMessage()); + state.usage(); } catch (Exception e) { System.err.println("error: unknown command line parsing exception:"); e.printStackTrace(); - usage(opts); + state.usage(); } - log = LogFactory.getLog(KeyGen.class); + log = Logger.getLogger(KeyGen.class.toString()); try { - execute(state, opts); + execute(state); } catch (Exception e) { diff --git a/src/com/verisignlabs/dnssec/cl/SignZone.java b/src/com/verisignlabs/dnssec/cl/SignZone.java index 8884acb..667d237 100644 --- a/src/com/verisignlabs/dnssec/cl/SignZone.java +++ b/src/com/verisignlabs/dnssec/cl/SignZone.java @@ -1,4 +1,4 @@ -// $Id: SignZone.java,v 1.4 2004/01/16 17:57:47 davidb Exp $ +// $Id$ // // Copyright (C) 2001-2003 VeriSign, Inc. // @@ -19,37 +19,56 @@ package com.verisignlabs.dnssec.cl; -import java.util.*; -import java.io.*; -import java.text.SimpleDateFormat; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; import java.text.ParseException; -import java.security.GeneralSecurityException; - -import org.xbill.DNS.*; - -import com.verisignlabs.dnssec.security.*; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.TimeZone; +import java.util.logging.Logger; +import java.util.logging.Level; import org.apache.commons.cli.*; -import org.apache.commons.cli.Options; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.xbill.DNS.DNSKEYRecord; +import org.xbill.DNS.DNSSEC; +import org.xbill.DNS.Name; +import org.xbill.DNS.RRset; +import org.xbill.DNS.Record; +import org.xbill.DNS.TextParseException; -/** This class forms the command line implementation of a DNSSEC zone - * signer. - * - * @author David Blacka (original) - * @author $Author: davidb $ - * @version $Revision: 1.4 $ +import com.verisignlabs.dnssec.security.BINDKeyUtils; +import com.verisignlabs.dnssec.security.DnsKeyPair; +import com.verisignlabs.dnssec.security.DnsSecVerifier; +import com.verisignlabs.dnssec.security.JCEDnsSecSigner; +import com.verisignlabs.dnssec.security.SignUtils; +import com.verisignlabs.dnssec.security.ZoneUtils; + +/** + * This class forms the command line implementation of a DNSSEC zone signer. + * + * @author David Blacka (original) + * @author $Author$ + * @version $Revision$ */ public class SignZone { - private static Log log; - - /** This is a small inner class used to hold all of the command line - * option state. */ + private static Logger log; + + /** + * This is a small inner class used to hold all of the command line option + * state. + */ private static class CLIState { + private Options opts; private File keyDirectory = null; public File keysetDirectory = null; public String[] kskFiles = null; @@ -65,69 +84,70 @@ public class SignZone public boolean fullySignKeyset = false; public List includeNames = null; - public CLIState() { } + public CLIState() + { + setupCLI(); + } - public void parseCommandLine(Options opts, String[] args) - throws org.apache.commons.cli.ParseException, ParseException, - IOException + public void parseCommandLine(String[] args) + throws org.apache.commons.cli.ParseException, ParseException, + IOException { CommandLineParser cli_parser = new PosixParser(); CommandLine cli = cli_parser.parse(opts, args); String optstr = null; - if (cli.hasOption('h')) usage(opts); - + if (cli.hasOption('h')) usage(); + if (cli.hasOption('v')) { - int value = parseInt(cli.getOptionValue('v'), 5); + int value = parseInt(cli.getOptionValue('v'), 5); + Logger rootLogger = Logger.getLogger(""); - switch (value) - { - case 0: - System.setProperty("org.apache.commons.logging.simplelog.defaultlog", - "fatal"); - break; - case 5: - default: - System.setProperty("org.apache.commons.logging.simplelog.defaultlog", - "debug"); - break; - case 6: - System.setProperty("org.apache.commons.logging.simplelog.defaultlog", - "trace"); - break; - } + switch (value) + { + case 0 : + rootLogger.setLevel(Level.OFF); + break; + case 5 : + default : + rootLogger.setLevel(Level.FINE); + break; + case 6 : + rootLogger.setLevel(Level.ALL); + break; + } } if (cli.hasOption('a')) verifySigs = true; if (cli.hasOption('O')) useOptIn = true; if (cli.hasOption('C')) { - useOptIn = true; - optInConserve = true; + useOptIn = true; + optInConserve = true; } if (cli.hasOption('F')) fullySignKeyset = true; - + if ((optstr = cli.getOptionValue('d')) != null) { - keysetDirectory = new File(optstr); - if (! keysetDirectory.isDirectory()) - { + keysetDirectory = new File(optstr); + if (!keysetDirectory.isDirectory()) + { System.err.println("error: " + optstr + " is not a directory"); - usage(opts); + usage(); - } + } } - + if ((optstr = cli.getOptionValue('D')) != null) { keyDirectory = new File(optstr); - if (! keyDirectory.isDirectory()) + if (!keyDirectory.isDirectory()) { System.err.println("error: " + optstr + " is not a directory"); - usage(opts); + usage(); } } @@ -137,7 +157,7 @@ public class SignZone } else { - // default is now - 1 hour. + // default is now - 1 hour. start = new Date(System.currentTimeMillis() - (3600 * 1000)); } @@ -156,30 +176,134 @@ public class SignZone if ((optstr = cli.getOptionValue('I')) != null) { - File includeNamesFile = new File(optstr); - includeNames = getNameList(includeNamesFile); - } - + File includeNamesFile = new File(optstr); + includeNames = getNameList(includeNamesFile); + } + String[] files = cli.getArgs(); if (files.length < 2) { - System.err.println("error: missing zone file and/or key files"); - usage(opts); + System.err.println("error: missing zone file and/or key files"); + usage(); } zonefile = files[0]; keyFiles = new String[files.length - 1]; System.arraycopy(files, 1, keyFiles, 0, files.length - 1); } + + /** + * Set up the command line options. + * + * @return a set of command line options. + */ + private void setupCLI() + { + opts = new Options(); + + // boolean options + opts.addOption("h", "help", false, "Print this message."); + opts.addOption("a", false, "verify generated signatures>"); + opts.addOption("F", + "fully-sign-keyset", + false, + "sign the zone apex keyset with all " + + "available keys, instead of just key-signing-keys."); + + // Opt-In generation switches + OptionGroup opt_in_opts = new OptionGroup(); + opt_in_opts.addOption(new Option("O", "generate a fully Opt-In zone.")); + opt_in_opts.addOption(new Option("C", + "generate a conservative Opt-In zone.")); + opts.addOptionGroup(opt_in_opts); + + // Argument options + OptionBuilder.hasOptionalArg(); + OptionBuilder.withLongOpt("verbose"); + OptionBuilder.withArgName("level"); + OptionBuilder.withDescription("verbosity level -- 0 is silence, " + + "5 is debug information, " + + "6 is trace information. " + + "No argument means 5."); + opts.addOption(OptionBuilder.create('v')); + + OptionBuilder.hasArg(); + OptionBuilder.withArgName("dir"); + OptionBuilder.withLongOpt("keyset-directory"); + OptionBuilder.withDescription("directory to find keyset files (default '.')."); + opts.addOption(OptionBuilder.create('d')); + + OptionBuilder.hasArg(); + OptionBuilder.withArgName("dir"); + OptionBuilder.withLongOpt("key-directory"); + OptionBuilder.withDescription("directory to find key files (default '.')."); + opts.addOption(OptionBuilder.create('D')); + + OptionBuilder.hasArg(); + OptionBuilder.withArgName("time/offset"); + OptionBuilder.withLongOpt("start-time"); + OptionBuilder.withDescription("signature starting time (default is now - 1 hour)"); + opts.addOption(OptionBuilder.create('s')); + + OptionBuilder.hasArg(); + OptionBuilder.withArgName("time/offset"); + OptionBuilder.withLongOpt("expire-time"); + OptionBuilder.withDescription("signature expiration time (default is " + + "start-time + 30 days"); + opts.addOption(OptionBuilder.create('e')); + + OptionBuilder.hasArg(); + OptionBuilder.withArgName("outfile"); + OptionBuilder.withDescription("file the signed zone is written " + + "to (default is .signed)."); + opts.addOption(OptionBuilder.create('f')); + + OptionBuilder.hasArgs(); + OptionBuilder.withArgName("KSK file"); + OptionBuilder.withLongOpt("ksk-file"); + OptionBuilder.withDescription("this key is a key signing key " + + "(may repeat)"); + opts.addOption(OptionBuilder.create('k')); + + OptionBuilder.hasArg(); + OptionBuilder.withArgName("file"); + OptionBuilder.withLongOpt("include-file"); + OptionBuilder.withDescription("include names in this file " + + "in the NSEC chain"); + opts.addOption(OptionBuilder.create('I')); + } + + /** Print out the usage and help statements, then quit. */ + private void usage() + { + HelpFormatter f = new HelpFormatter(); + + PrintWriter out = new PrintWriter(System.err); + + // print our own usage statement: + out.println("usage: signZone.sh [..options..] zone_file [key_file ...] "); + f.printHelp(out, + 75, + "signZone.sh", + null, + opts, + HelpFormatter.DEFAULT_LEFT_PAD, + HelpFormatter.DEFAULT_DESC_PAD, + "\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n"); + + out.flush(); + System.exit(64); + } + } - /** This is just a convenience method for parsing integers from - * strings. - * - * @param s the string to parse. - * @param def the default value, if the string doesn't parse. - * @return the parsed integer, or the default. + /** + * This is just a convenience method for parsing integers from strings. + * + * @param s the string to parse. + * @param def the default value, if the string doesn't parse. + * @return the parsed integer, or the default. */ private static int parseInt(String s, int def) { @@ -194,21 +318,22 @@ public class SignZone } } - /** Verify the generated signatures. - * - * @param zonename the origin name of the zone. - * @param records a list of {@link org.xbill.DNS.Record}s. - * @param keypairs a list of keypairs used the sign the zone. - * @return true if all of the signatures validated. + /** + * Verify the generated signatures. + * + * @param zonename the origin name of the zone. + * @param records a list of {@link org.xbill.DNS.Record}s. + * @param keypairs a list of keypairs used the sign the zone. + * @return true if all of the signatures validated. */ private static boolean verifyZoneSigs(Name zonename, List records, - List keypairs) + List keypairs) { boolean secure = true; - + DnsSecVerifier verifier = new DnsSecVerifier(); - for (Iterator i = keypairs.iterator(); i.hasNext(); ) + for (Iterator i = keypairs.iterator(); i.hasNext();) { verifier.addTrustedKey((DnsKeyPair) i.next()); } @@ -217,39 +342,38 @@ public class SignZone List rrsets = SignUtils.assembleIntoRRsets(records); - for (Iterator i = rrsets.iterator(); i.hasNext(); ) + for (Iterator i = rrsets.iterator(); i.hasNext();) { RRset rrset = (RRset) i.next(); // skip unsigned rrsets. if (!rrset.sigs().hasNext()) continue; - - byte result = verifier.verify(rrset, null); + + int result = verifier.verify(rrset, null); if (result != DNSSEC.Secure) { - log.debug("Signatures did not verify for RRset: (" + result + "): " + - rrset); - secure = false; + log.fine("Signatures did not verify for RRset: (" + result + "): " + + rrset); + secure = false; } } return secure; } - /** Load the key pairs from the key files. - * - * @param keyfiles a string array containing the base names or - * paths of the keys to be loaded. - * @param start_index the starting index of keyfiles string array - * to use. This allows us to use the straight command line - * argument array. - * @param inDirectory the directory to look in (may be null). - * @return a list of keypair objects. + /** + * Load the key pairs from the key files. + * + * @param keyfiles a string array containing the base names or paths of the + * keys to be loaded. + * @param start_index the starting index of keyfiles string array to use. + * This allows us to use the straight command line argument array. + * @param inDirectory the directory to look in (may be null). + * @return a list of keypair objects. */ private static List getKeys(String[] keyfiles, int start_index, - File inDirectory) - throws IOException + File inDirectory) throws IOException { if (keyfiles == null) return null; @@ -267,55 +391,34 @@ public class SignZone return keys; } - /** Load a single key from a given keyfile. - * - * @param keyfile the keyfile. - * @param inDirectory the default directory to look in (may be - * null). - * @return a list containing one or zero keypair objects. + /** + * This is an implementation of a file filter used for finding BIND 9-style + * keyset-* files. */ - private static List getKeys(File keyfile, File inDirectory) - throws IOException - { - if (keyfile == null) return null; - - DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfile.getPath(), - inDirectory); - if (k != null) - { - ArrayList keys = new ArrayList(1); - keys.add(k); - return keys; - } - - return null; - } - - /** This is an implementation of a file filter used for finding BIND - * 9-style keyset-* files. */ private static class KeysetFileFilter implements FileFilter { public boolean accept(File pathname) { - if (! pathname.isFile()) return false; + if (!pathname.isFile()) return false; String name = pathname.getName(); if (name.startsWith("keyset-")) return true; return false; } } - /** Load keysets (which contain delegation point security info). - * - * @param inDirectory the directory to look for the keyset files - * (may be null, in which case it defaults to looking in the - * current working directory). - * @param zonename the name of the zone we are signing, so we can - * ignore keysets that do not belong in the zone. - * @return a list of {@link org.xbill.DNS.Record}s found in the - * keyset files. + /** + * Load keysets (which contain delegation point security info). + * + * @param inDirectory the directory to look for the keyset files (may be + * null, in which case it defaults to looking in the current + * working directory). + * @param zonename the name of the zone we are signing, so we can ignore + * keysets that do not belong in the zone. + * @return a list of {@link org.xbill.DNS.Record}s found in the keyset + * files. */ private static List getKeysets(File inDirectory, Name zonename) - throws IOException + throws IOException { if (inDirectory == null) { @@ -336,47 +439,47 @@ public class SignZone } // discard records that do not belong to the zone in question. - for (Iterator i = keysetRecords.iterator(); i.hasNext(); ) + for (Iterator i = keysetRecords.iterator(); i.hasNext();) { Record r = (Record) i.next(); if (!r.getName().subdomain(zonename)) { - i.remove(); + i.remove(); } } return keysetRecords; } - /** Load a list of DNS names from a file. - * - * @param nameListFile the path of a file containing a bare list of - * DNS names. - * @return a list of {@link org.xbill.DNS.Name} objects. + /** + * Load a list of DNS names from a file. + * + * @param nameListFile the path of a file containing a bare list of DNS + * names. + * @return a list of {@link org.xbill.DNS.Name} objects. */ - private static List getNameList(File nameListFile) - throws IOException + private static List getNameList(File nameListFile) throws IOException { BufferedReader br = new BufferedReader(new FileReader(nameListFile)); List res = new ArrayList(); String line = null; - while ( (line = br.readLine()) != null ) + while ((line = br.readLine()) != null) { try { - Name n = Name.fromString(line); - // force the name to be absolute. - // FIXME: we should probably get some fancy logic here to - // detect if the name needs the origin appended, or just the - // root. - if (! n.isAbsolute()) n = Name.concatenate(n, Name.root); - - res.add(n); + Name n = Name.fromString(line); + // force the name to be absolute. + // FIXME: we should probably get some fancy logic here to + // detect if the name needs the origin appended, or just the + // root. + if (!n.isAbsolute()) n = Name.concatenate(n, Name.root); + + res.add(n); } catch (TextParseException e) { - log.error("DNS Name parsing error", e); + log.severe("DNS Name parsing error:" + e); } } @@ -384,21 +487,22 @@ public class SignZone return res; } - /** Calculate a date/time from a command line time/offset duration string. - * - * @param start the start time to calculate offsets from. - * @param duration the time/offset string to parse. - * @return the calculated time. + /** + * Calculate a date/time from a command line time/offset duration string. + * + * @param start the start time to calculate offsets from. + * @param duration the time/offset string to parse. + * @return the calculated time. */ private static Date convertDuration(Date start, String duration) - throws ParseException + throws ParseException { if (start == null) start = new Date(); if (duration.startsWith("now")) { start = new Date(); if (duration.indexOf("+") < 0) return start; - + duration = duration.substring(3); } @@ -413,148 +517,55 @@ public class SignZone return dateFormatter.parse(duration); } - /** Determine if the given keypairs can be used to sign the zone. - * @param zonename the zone origin. - * @param keypairs a list of {@link DnsKeyPair} objects that will - * be used to sign the zone. - * @return true if the keypairs valid. - */ + /** + * Determine if the given keypairs can be used to sign the zone. + * + * @param zonename the zone origin. + * @param keypairs a list of {@link DnsKeyPair} objects that will be used to + * sign the zone. + * @return true if the keypairs valid. + */ private static boolean keyPairsValidForZone(Name zonename, List keypairs) { if (keypairs == null) return true; // technically true, I guess. - - for (Iterator i = keypairs.iterator(); i.hasNext(); ) + + for (Iterator i = keypairs.iterator(); i.hasNext();) { DnsKeyPair kp = (DnsKeyPair) i.next(); Name keyname = kp.getDNSKEYRecord().getName(); if (!keyname.equals(zonename)) { - return false; + return false; } } return true; } + - /** Set up the command line options. - * - * @return a set of command line options. - */ - private static Options setupCLI() - { - Options options = new Options(); - - // boolean options - options.addOption("h", "help", false, "Print this message."); - options.addOption("a", false, "verify generated signatures>"); - options.addOption("F", "fully-sign-keyset", false, - "sign the zone apex keyset with all " + - "available keys, instead of just key-signing-keys."); - - // Opt-In generation switches - OptionGroup opt_in_opts = new OptionGroup(); - opt_in_opts.addOption(new Option - ("O", "generate a fully Opt-In zone.")); - opt_in_opts.addOption(new Option - ("C", "generate a conservative Opt-In zone.")); - options.addOptionGroup(opt_in_opts); - - // Argument options - options.addOption(OptionBuilder.hasOptionalArg() - .withArgName("level") - .withDescription("verbosity level -- 0 is silence, " + - "5 is debug information, " + - "6 is trace information. " + - "No argument means 5.") - .create('v')); - options.addOption(OptionBuilder.hasArg() - .withArgName("dir") - .withLongOpt("keyset-directory") - .withDescription - ("directory to find keyset files (default '.').") - .create('d')); - options.addOption(OptionBuilder.hasArg() - .withArgName("dir") - .withLongOpt("key-directory") - .withDescription - ("directory to find key files (default '.').") - .create('D')); - options.addOption(OptionBuilder.hasArg() - .withArgName("time/offset") - .withLongOpt("start-time") - .withDescription - ("signature starting time (default is now - 1 hour)") - .create('s')); - options.addOption(OptionBuilder.hasArg() - .withArgName("time/offset") - .withLongOpt("expire-time") - .withDescription - ("signature expiration time (default is " + - "start-time + 30 days") - .create('e')); - options.addOption(OptionBuilder.hasArg() - .withArgName("outfile") - .withDescription("file the signed zone is written " + - "to (default is .signed).") - .create('f')); - options.addOption(OptionBuilder.hasArgs() - .withArgName("KSK file") - .withLongOpt("ksk-file") - .withDescription("this key is a key signing key " + - "(may repeat)") - .create('k')); - options.addOption(OptionBuilder.hasArg() - .withArgName("file") - .withLongOpt("include-file") - .withDescription("include names in this file " + - "in the NSEC chain") - .create('I')); - - return options; - } - - /** Print out the usage and help statements, then quit. */ - private static void usage(Options opts) - { - HelpFormatter f = new HelpFormatter(); - - PrintWriter out = new PrintWriter(System.err); - - // print our own usage statement: - out.println("usage: signZone.sh [..options..] zone_file [key_file ...] "); - f.printHelp(out, 75, "signZone.sh", null, opts, - HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD, - "\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n"); - - out.flush(); - System.exit(64); - } - - - public static void execute(CLIState state, Options opts) - throws Exception + public static void execute(CLIState state) throws Exception { // Load the key pairs. - + // FIXME: should we do what BIND 9.3.x snapshots do and look at // zone apex DNSKEY RRs, and from that be able to load all of the // keys? - - List keypairs = getKeys(state.keyFiles, 0, state.keyDirectory); - List kskpairs = getKeys(state.kskFiles, 0, state.keyDirectory); + + List keypairs = getKeys(state.keyFiles, 0, state.keyDirectory); + List kskpairs = getKeys(state.kskFiles, 0, state.keyDirectory); // If we don't have any KSKs, but we do have more than one zone // signing key (presumably), presume that the zone signing keys // are just not differentiated and try to figure out which keys // are actually ksks by looking at the SEP flag. - if ( (kskpairs == null || kskpairs.size() == 0) && - keypairs != null && keypairs.size() > 1) + if ((kskpairs == null || kskpairs.size() == 0) && keypairs != null + && keypairs.size() > 1) { - for (Iterator i = keypairs.iterator(); i.hasNext(); ) + for (Iterator i = keypairs.iterator(); i.hasNext();) { DnsKeyPair pair = (DnsKeyPair) i.next(); DNSKEYRecord kr = pair.getDNSKEYRecord(); - if ((kr.getFlags() & DNSKEYRecord.FLAG_SEP) != 0) + if ((kr.getFlags() & DNSKEYRecord.Flags.SEP_KEY) != 0) { if (kskpairs == null) kskpairs = new ArrayList(); kskpairs.add(pair); @@ -562,13 +573,13 @@ public class SignZone } } } - + // Read in the zone List records = ZoneUtils.readZoneFile(state.zonefile, null); if (records == null || records.size() == 0) { System.err.println("error: empty zone file"); - usage(opts); + state.usage(); } // calculate the zone name. @@ -576,7 +587,7 @@ public class SignZone if (zonename == null) { System.err.println("error: invalid zone file - no SOA"); - usage(opts); + state.usage(); } // default the output file, if not set. @@ -584,41 +595,39 @@ public class SignZone { if (zonename.isAbsolute()) { - state.outputfile = zonename + "signed"; + state.outputfile = zonename + "signed"; } else { - state.outputfile = zonename + ".signed"; + state.outputfile = zonename + ".signed"; } } - - // Verify that the keys can be in the zone. - List kpairs = keypairs; - if (!keyPairsValidForZone(zonename, keypairs) || - !keyPairsValidForZone(zonename, kskpairs)) + // Verify that the keys can be in the zone. + if (!keyPairsValidForZone(zonename, keypairs) + || !keyPairsValidForZone(zonename, kskpairs)) { - usage(opts); + state.usage(); } // We force the signing keys to be in the zone by just appending - // them to the zone here. Currently JCEDnsSecSigner.signZone + // them to the zone here. Currently JCEDnsSecSigner.signZone // removes duplicate records. if (kskpairs != null) { - for (Iterator i = kskpairs.iterator(); i.hasNext(); ) + for (Iterator i = kskpairs.iterator(); i.hasNext();) { - records.add( ((DnsKeyPair) i.next()).getDNSKEYRecord() ); + records.add(((DnsKeyPair) i.next()).getDNSKEYRecord()); } } if (keypairs != null) { - for (Iterator i = keypairs.iterator(); i.hasNext(); ) + for (Iterator i = keypairs.iterator(); i.hasNext();) { - records.add( ((DnsKeyPair) i.next()).getDNSKEYRecord() ); + records.add(((DnsKeyPair) i.next()).getDNSKEYRecord()); } } - + // read in the keysets, if any. List keysetrecs = getKeysets(state.keysetDirectory, zonename); if (keysetrecs != null) @@ -630,16 +639,16 @@ public class SignZone // Sign the zone. List signed_records = signer.signZone(zonename, - records, - kskpairs, - keypairs, - state.start, - state.expire, - state.useOptIn, - state.optInConserve, - state.fullySignKeyset, - state.includeNames); - + records, + kskpairs, + keypairs, + state.start, + state.expire, + state.useOptIn, + state.optInConserve, + state.fullySignKeyset, + state.includeNames); + // write out the signed zone // force multiline mode for now org.xbill.DNS.Options.set("multiline"); @@ -650,66 +659,57 @@ public class SignZone // FIXME: ugh. if (kskpairs != null) { - keypairs.addAll(kskpairs); + keypairs.addAll(kskpairs); } - - log.debug("verifying generated signatures"); + + log.fine("verifying generated signatures"); boolean res = verifyZoneSigs(zonename, signed_records, keypairs); if (res) { - System.out.println("Generated signatures verified"); - // log.info("Generated signatures verified"); + System.out.println("Generated signatures verified"); + // log.info("Generated signatures verified"); } else { - System.out.println("Generated signatures did not verify."); - // log.warn("Generated signatures did not verify."); + System.out.println("Generated signatures did not verify."); + // log.warn("Generated signatures did not verify."); } } } - + public static void main(String[] args) { - // set up logging. - // For now, we force the commons logging to use the built-in - // SimpleLog. - System.setProperty("org.apache.commons.logging.Log", - "org.apache.commons.logging.impl.SimpleLog"); - - // set up the command line options - Options opts = setupCLI(); - - CLIState state = new CLIState(); + CLIState state = new CLIState(); try { - state.parseCommandLine(opts, args); + state.parseCommandLine(args); } catch (UnrecognizedOptionException e) { - System.err.println("error: unknown option encountered: " + - e.getMessage()); - usage(opts); + System.err.println("error: unknown option encountered: " + + e.getMessage()); + state.usage(); } catch (AlreadySelectedException e) { - System.err.println("error: mutually exclusive options have " + - "been selected:\n " + e.getMessage()); - usage(opts); + System.err.println("error: mutually exclusive options have " + + "been selected:\n " + e.getMessage()); + state.usage(); } catch (Exception e) { System.err.println("error: unknown command line parsing exception:"); e.printStackTrace(); - usage(opts); + state.usage(); } - log = LogFactory.getLog(SignZone.class); + log = Logger.getLogger(SignZone.class.toString()); try { - execute(state, opts); + execute(state); } catch (Exception e) { diff --git a/src/com/verisignlabs/dnssec/cl/VerifyZone.java b/src/com/verisignlabs/dnssec/cl/VerifyZone.java index 7586ec7..d1a1088 100644 --- a/src/com/verisignlabs/dnssec/cl/VerifyZone.java +++ b/src/com/verisignlabs/dnssec/cl/VerifyZone.java @@ -1,4 +1,4 @@ -// $Id: VerifyZone.java,v 1.1 2004/01/16 17:57:59 davidb Exp $ +// $Id$ // // Copyright (C) 2001-2003 VeriSign, Inc. // @@ -19,75 +19,84 @@ package com.verisignlabs.dnssec.cl; -import java.util.*; -import java.io.*; -import java.text.SimpleDateFormat; -import java.text.ParseException; -import java.security.GeneralSecurityException; - -import org.xbill.DNS.*; - -import com.verisignlabs.dnssec.security.*; +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.commons.cli.*; -import org.apache.commons.cli.Options; +import org.xbill.DNS.DNSSEC; +import org.xbill.DNS.RRSIGRecord; +import org.xbill.DNS.RRset; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import com.verisignlabs.dnssec.security.BINDKeyUtils; +import com.verisignlabs.dnssec.security.DnsKeyPair; +import com.verisignlabs.dnssec.security.DnsSecVerifier; +import com.verisignlabs.dnssec.security.RecordComparator; +import com.verisignlabs.dnssec.security.SignUtils; +import com.verisignlabs.dnssec.security.ZoneUtils; -/** This class forms the command line implementation of a DNSSEC zone - * validator. - * @author David Blacka (original) - * @author $Author: davidb $ - * @version $Revision: 1.1 $ +/** + * This class forms the command line implementation of a DNSSEC zone + * validator. + * + * @author David Blacka (original) + * @author $Author$ + * @version $Revision$ */ public class VerifyZone { - private static Log log; - - /** This is a small inner class used to hold all of the command line - * option state. */ + private static Logger log; + + /** + * This is a small inner class used to hold all of the command line option + * state. + */ private static class CLIState { - - public boolean strict = false; - public File keydir = null; - public String zonefile = null; + private Options opts; + public boolean strict = false; + public File keydir = null; + public String zonefile = null; public String[] keyfiles = null; - - public CLIState() { } - public void parseCommandLine(Options opts, String[] args) - throws org.apache.commons.cli.ParseException, ParseException, - IOException + public CLIState() + { + setupCLI(); + } + + public void parseCommandLine(String[] args) + throws org.apache.commons.cli.ParseException { CommandLineParser cli_parser = new PosixParser(); - CommandLine cli = cli_parser.parse(opts, args); + CommandLine cli = cli_parser.parse(opts, args); String optstr = null; - if (cli.hasOption('h')) usage(opts); - + if (cli.hasOption('h')) usage(); + if (cli.hasOption('v')) { - int value = parseInt(cli.getOptionValue('v'), 5); - - switch (value) - { - case 0: - System.setProperty("org.apache.commons.logging.simplelog.defaultlog", - "fatal"); - break; - case 5: - default: - System.setProperty("org.apache.commons.logging.simplelog.defaultlog", - "debug"); - break; - case 6: - System.setProperty("org.apache.commons.logging.simplelog.defaultlog", - "trace"); - break; - } + int value = parseInt(cli.getOptionValue('v'), 5); + Logger rootLogger = Logger.getLogger(""); + switch (value) + { + case 0 : + rootLogger.setLevel(Level.OFF); + break; + case 5 : + default : + rootLogger.setLevel(Level.FINE); + break; + case 6 : + rootLogger.setLevel(Level.ALL); + break; + } } if (cli.hasOption('s')) strict = true; @@ -96,14 +105,13 @@ public class VerifyZone { keydir = new File(optstr); } - - + String[] cl_args = cli.getArgs(); if (cl_args.length < 1) { - System.err.println("error: missing zone file"); - usage(opts); + System.err.println("error: missing zone file"); + usage(); } zonefile = cl_args[0]; @@ -111,85 +119,90 @@ public class VerifyZone if (cl_args.length < 2) { System.err.println("error: at least one trusted key is required"); - usage(opts); + usage(); } - + keyfiles = new String[cl_args.length - 1]; System.arraycopy(cl_args, 1, keyfiles, 0, keyfiles.length); } - } - /** This is just a convenience method for parsing integers from - * strings. - * - * @param s the string to parse. - * @param def the default value, if the string doesn't parse. - * @return the parsed integer, or the default. - */ - private static int parseInt(String s, int def) - { - try + /** + * Set up the command line options. + * + * @return a set of command line options. + */ + private void setupCLI() { - int v = Integer.parseInt(s); - return v; + opts = new Options(); + + // boolean options + opts.addOption("h", "help", false, "Print this message."); + opts.addOption("s", + "strict", + false, + "Zone will only be considered valid if all " + + "signatures could be cryptographically verified"); + + // Argument options + OptionBuilder.hasArg(); + OptionBuilder.withLongOpt("keydir"); + OptionBuilder.withArgName("dir"); + OptionBuilder.withDescription("directory to find trusted key files"); + opts.addOption(OptionBuilder.create('d')); + + OptionBuilder.hasOptionalArg(); + OptionBuilder.withLongOpt("verbose"); + OptionBuilder.withArgName("level"); + OptionBuilder.withDescription("verbosity level -- 0 is silence, " + + "5 is debug information, 6 is trace information.\n" + + "default is level 5."); + opts.addOption(OptionBuilder.create('v')); + } - catch (NumberFormatException e) + + /** Print out the usage and help statements, then quit. */ + public void usage() { - return def; + HelpFormatter f = new HelpFormatter(); + + PrintWriter out = new PrintWriter(System.err); + + // print our own usage statement: + f.printHelp(out, + 75, + "verifyZone.sh [..options..] zonefile " + "keyfile [keyfile...]", + null, + opts, + HelpFormatter.DEFAULT_LEFT_PAD, + HelpFormatter.DEFAULT_DESC_PAD, + null); + + out.flush(); + System.exit(64); + } + + /** + * This is just a convenience method for parsing integers from strings. + * + * @param s the string to parse. + * @param def the default value, if the string doesn't parse. + * @return the parsed integer, or the default. + */ + private static int parseInt(String s, int def) + { + try + { + int v = Integer.parseInt(s); + return v; + } + catch (NumberFormatException e) + { + return def; + } + } + } - - /** Set up the command line options. - * - * @return a set of command line options. - */ - private static Options setupCLI() - { - Options options = new Options(); - - // boolean options - options.addOption("h", "help", false, "Print this message."); - options.addOption("s", "strict", false, - "Zone will only be considered valid if all " + - "signatures could be cryptographically verified"); - - // Argument options - options.addOption(OptionBuilder.hasArg() - .withLongOpt("keydir") - .withArgName("dir") - .withDescription("directory to find trusted key files") - .create('d')); - - options.addOption(OptionBuilder.hasOptionalArg() - .withLongOpt("verbose") - .withArgName("level") - .withDescription("verbosity level -- 0 is silence, " + - "5 is debug information, " + - "6 is trace information.\n" + - "default is level 5.") - .create('v')); - - return options; - } - - /** Print out the usage and help statements, then quit. */ - private static void usage(Options opts) - { - HelpFormatter f = new HelpFormatter(); - - PrintWriter out = new PrintWriter(System.err); - - // print our own usage statement: - f.printHelp(out, 75, - "verifyZone.sh [..options..] zonefile " + - "keyfile [keyfile...]", null, opts, - HelpFormatter.DEFAULT_LEFT_PAD, - HelpFormatter.DEFAULT_DESC_PAD, null); - - out.flush(); - System.exit(64); - } - private static byte verifyZoneSignatures(List records, List keypairs) { @@ -198,33 +211,34 @@ public class VerifyZone DnsSecVerifier verifier = new DnsSecVerifier(); - for (Iterator i = keypairs.iterator(); i.hasNext(); ) + for (Iterator i = keypairs.iterator(); i.hasNext();) { verifier.addTrustedKey((DnsKeyPair) i.next()); } List rrsets = SignUtils.assembleIntoRRsets(records); - - for (Iterator i = rrsets.iterator(); i.hasNext(); ) + + for (Iterator i = rrsets.iterator(); i.hasNext();) { RRset rrset = (RRset) i.next(); // We verify each signature separately so that we can report // which exact signature failed. - for (Iterator j = rrset.sigs(); j.hasNext(); ) + for (Iterator j = rrset.sigs(); j.hasNext();) { Object o = j.next(); - if (! (o instanceof RRSIGRecord)) + if (!(o instanceof RRSIGRecord)) { - log.debug("found " + o + " where expecting a RRSIG"); + log.fine("found " + o + " where expecting a RRSIG"); continue; } RRSIGRecord sigrec = (RRSIGRecord) o; - + byte res = verifier.verifySignature(rrset, sigrec, null); if (res != DNSSEC.Secure) { - log.info("Signature failed to verify RRset: " + rrset + "\nsig: " + sigrec); + log.info("Signature failed to verify RRset: " + rrset + "\nsig: " + + sigrec); } if (res < result) result = res; } @@ -234,7 +248,7 @@ public class VerifyZone } private static List getTrustedKeys(String[] keyfiles, File inDirectory) - throws IOException + throws IOException { if (keyfiles == null) return null; @@ -248,80 +262,70 @@ public class VerifyZone return keys; } - - public static void execute(CLIState state, Options opts) - throws Exception + + public static void execute(CLIState state) throws Exception { List keypairs = getTrustedKeys(state.keyfiles, state.keydir); - + List records = ZoneUtils.readZoneFile(state.zonefile, null); Collections.sort(records, new RecordComparator()); - log.debug("verifying signatures..."); + log.fine("verifying signatures..."); byte result = verifyZoneSignatures(records, keypairs); - log.debug("completed verification process."); + log.fine("completed verification process."); switch (result) { - case DNSSEC.Failed: - System.out.println("zone did not verify."); - System.exit(1); - break; - case DNSSEC.Insecure: - if (state.strict) - { + case DNSSEC.Failed : System.out.println("zone did not verify."); System.exit(1); - } - case DNSSEC.Secure: - System.out.println("zone verified."); - break; + break; + case DNSSEC.Insecure : + if (state.strict) + { + System.out.println("zone did not verify."); + System.exit(1); + } + case DNSSEC.Secure : + System.out.println("zone verified."); + break; } System.exit(0); } - + public static void main(String[] args) { - // set up logging. - // For now, we force the commons logging to use the built-in - // SimpleLog. - System.setProperty("org.apache.commons.logging.Log", - "org.apache.commons.logging.impl.SimpleLog"); - - // set up the command line options - Options opts = setupCLI(); - - CLIState state = new CLIState(); + CLIState state = new CLIState(); try { - state.parseCommandLine(opts, args); + state.parseCommandLine(args); } catch (UnrecognizedOptionException e) { - System.err.println("error: unknown option encountered: " + - e.getMessage()); - usage(opts); + System.err.println("error: unknown option encountered: " + + e.getMessage()); + state.usage(); } catch (AlreadySelectedException e) { - System.err.println("error: mutually exclusive options have " + - "been selected:\n " + e.getMessage()); - usage(opts); + System.err.println("error: mutually exclusive options have " + + "been selected:\n " + e.getMessage()); + state.usage(); } catch (Exception e) { System.err.println("error: unknown command line parsing exception:"); e.printStackTrace(); - usage(opts); + state.usage(); } - log = LogFactory.getLog(VerifyZone.class); + log = Logger.getLogger(VerifyZone.class.toString()); try { - execute(state, opts); + execute(state); } catch (Exception e) { diff --git a/src/com/verisignlabs/dnssec/security/BINDKeyUtils.java b/src/com/verisignlabs/dnssec/security/BINDKeyUtils.java index b04f956..2309973 100644 --- a/src/com/verisignlabs/dnssec/security/BINDKeyUtils.java +++ b/src/com/verisignlabs/dnssec/security/BINDKeyUtils.java @@ -1,4 +1,4 @@ -// $Id: BINDKeyUtils.java,v 1.5 2004/02/25 20:46:14 davidb Exp $ +// $Id$ // // Copyright (C) 2001-2003 VeriSign, Inc. // @@ -19,22 +19,35 @@ package com.verisignlabs.dnssec.security; -import java.io.*; -import java.security.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; import java.text.NumberFormat; -import org.xbill.DNS.*; +import org.xbill.DNS.DNSKEYRecord; +import org.xbill.DNS.Master; +import org.xbill.DNS.Name; +import org.xbill.DNS.RRset; +import org.xbill.DNS.Record; +import org.xbill.DNS.Type; 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: davidb $ - * @version $Revision: 1.5 $ +/** + * 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$ */ public class BINDKeyUtils { @@ -42,10 +55,11 @@ public class BINDKeyUtils private static NumberFormat mAlgNumberFormatter; private static NumberFormat mKeyIdNumberFormatter; - /** 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) + /** + * 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) { @@ -64,24 +78,22 @@ public class BINDKeyUtils keyid &= 0xFFFF; - String fn = "K" + signer + "+" + - mAlgNumberFormatter.format(algorithm) + - "+" + - mKeyIdNumberFormatter.format(keyid); + String fn = "K" + signer + "+" + mAlgNumberFormatter.format(algorithm) + + "+" + mKeyIdNumberFormatter.format(keyid); return fn; } - /** Reads in the KEYRecord from the public key file */ + /** 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 ) + while ((r = m.nextRecord()) != null) { if (r.getType() == Type.DNSKEY) { @@ -94,14 +106,14 @@ public class BINDKeyUtils /** Reads in the private key verbatim from the private key file */ private static String loadPrivateKeyFile(File privateKeyFile) - throws IOException + throws IOException { BufferedReader in = new BufferedReader(new FileReader(privateKeyFile)); - StringBuffer key_buf = new StringBuffer(); + StringBuffer key_buf = new StringBuffer(); String line; - while ( (line = in.readLine()) != null) + while ((line = in.readLine()) != null) { key_buf.append(line); key_buf.append('\n'); @@ -110,57 +122,56 @@ public class BINDKeyUtils return key_buf.toString().trim(); } - /** Given an actual path for one of the key files, return the base - * name */ + /** + * 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")) + if (basePath.endsWith(".key") || basePath.endsWith(".private")) { - basePath = basePath.substring - (0, basePath.lastIndexOf(".")); + basePath = basePath.substring(0, basePath.lastIndexOf(".")); } return basePath; } - /** 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. - * @param algorithm the DNSSEC algorithm of the key. - * @param keyid the DNSSEC key footprint. - * @param inDirectory 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. */ - public static DnsKeyPair loadKeyPair(Name signer, int algorithm, - int keyid, File inDirectory) - throws IOException + /** + * 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. + * @param algorithm the DNSSEC algorithm of the key. + * @param keyid the DNSSEC key footprint. + * @param inDirectory 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. + */ + public static DnsKeyPair loadKeyPair(Name signer, int algorithm, int keyid, + File inDirectory) throws IOException { String keyFileBase = getKeyFileBase(signer, algorithm, keyid); return loadKeyPair(keyFileBase, inDirectory); } - /** 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. - * @param inDirectory 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 */ + /** + * 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. + * @param inDirectory 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 + */ public static DnsKeyPair loadKeyPair(String keyFileBasePath, - File inDirectory) - throws IOException + File inDirectory) 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? - File publicKeyFile = new File(inDirectory, keyFileBasePath + ".key"); + File publicKeyFile = new File(inDirectory, keyFileBasePath + ".key"); File privateKeyFile = new File(inDirectory, keyFileBasePath + ".private"); DnsKeyPair kp = new DnsKeyPair(); @@ -174,23 +185,22 @@ public class BINDKeyUtils return kp; } - /** 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. - * @param inDirectory 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. + /** + * 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. + * @param inDirectory 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. */ public static DnsKeyPair loadKey(String keyFileBasePath, File inDirectory) - throws IOException + throws IOException { keyFileBasePath = fixKeyFileBasePath(keyFileBasePath); - File publicKeyFile = new File(inDirectory, keyFileBasePath + ".key"); + File publicKeyFile = new File(inDirectory, keyFileBasePath + ".key"); DnsKeyPair kp = new DnsKeyPair(); @@ -200,21 +210,19 @@ public class BINDKeyUtils return kp; } - /** 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. - * @param inDirectory 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. + /** + * 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. + * @param inDirectory 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. */ public static RRset loadKeySet(String keysetFileName, File inDirectory) - throws IOException + throws IOException { File keysetFile = new File(inDirectory, keysetFileName); @@ -222,7 +230,7 @@ public class BINDKeyUtils Record r; RRset keyset = new RRset(); - while ( (r = m.nextRecord()) != null ) + while ((r = m.nextRecord()) != null) { keyset.addRR(r); } @@ -230,11 +238,12 @@ public class BINDKeyUtils 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. - * @return the base name of the key files. + /** + * Calculate the key file base for this key pair. + * + * @param pair 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) { @@ -242,13 +251,14 @@ public class BINDKeyUtils if (keyrec == null) return null; return getKeyFileBase(keyrec.getName(), - keyrec.getAlgorithm(), - keyrec.getFootprint()); + keyrec.getAlgorithm(), + keyrec.getFootprint()); } - - /** @return a {@link java.io.File} object representing the BIND9 - * public key file. */ + /** + * @return a {@link java.io.File} object representing the BIND9 public key + * file. + */ public static File getPublicKeyFile(DnsKeyPair pair, File inDirectory) { String keyfilebase = keyFileBase(pair); @@ -257,8 +267,10 @@ public class BINDKeyUtils return new File(inDirectory, keyfilebase + ".key"); } - /** @return a {@link java.io.File} object representing the BIND9 - * private key file */ + /** + * @return a {@link java.io.File} object representing the BIND9 private key + * file + */ public static File getPrivateKeyFile(DnsKeyPair pair, File inDirectory) { String keyfilebase = keyFileBase(pair); @@ -267,11 +279,12 @@ public class BINDKeyUtils return new File(inDirectory, keyfilebase + ".private"); } - /** 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. - * @return a {@link java.security.PrivateKey} + /** + * 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. + * @return a {@link java.security.PrivateKey} */ public static PrivateKey convertPrivateKeyString(String privateKeyString) { @@ -296,24 +309,24 @@ public class BINDKeyUtils return null; } - /** Given a native private key, convert it into a BIND9 private key - * file format. - * @param priv the private key to convert. - * @param pub 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. + /** + * Given a native private key, convert it into a BIND9 private key file + * format. + * + * @param priv the private key to convert. + * @param pub 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) + int alg) { if (priv != null) { // debug // System.out.println("converting from privatekey to bind9 string"); DnsKeyConverter keyconv = new DnsKeyConverter(); - String priv_string - = keyconv.generatePrivateKeyString(priv, pub, alg); + String priv_string = keyconv.generatePrivateKeyString(priv, pub, alg); return priv_string; } @@ -321,11 +334,12 @@ public class BINDKeyUtils return null; } - - /** Convert the KEY record to the exact string format that the - * dnssec-* routines need. Currently, the DNSJAVA package uses a - * multiline mode for its record formatting. The BIND9 tools - * require everything on a single line. */ + /** + * Convert the KEY record to the exact string format that the dnssec-* + * 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(); @@ -343,34 +357,33 @@ public class BINDKeyUtils return buf.toString(); } - /** 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. - * @param pair the keypair in question. - * @param inDirectory the directory to write to (may be null). - * @throws IOException if there is a problem writing the files. + /** + * 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. + * @param pair the keypair in question. + * @param inDirectory the directory to write to (may be null). + * @throws IOException 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(); + DNSKEYRecord pub = pair.getDNSKEYRecord(); + String priv = pair.getPrivateKeyString(); if (priv == null) { - priv = convertPrivateKey(pair.getPrivate(), pair.getPublic(), - pair.getDNSKEYAlgorithm()); + priv = convertPrivateKey(pair.getPrivate(), + pair.getPublic(), + pair.getDNSKEYAlgorithm()); } if (pub == null || priv == null) return; // Write the public key file File pubkeyfile = new File(inDirectory, baseFileName + ".key"); - PrintWriter out - = new PrintWriter(new FileWriter(pubkeyfile)); + PrintWriter out = new PrintWriter(new FileWriter(pubkeyfile)); out.println(DNSKEYtoString(pub)); out.close(); @@ -382,14 +395,15 @@ 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. - * @param inDirectory the directory to write to (may be null). + /** + * This routine will write out the BIND9 dnssec-* tool compatible files to + * the standard file names. + * + * @param pair the key pair in question. + * @param inDirectory 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/com/verisignlabs/dnssec/security/ByteArrayComparator.java b/src/com/verisignlabs/dnssec/security/ByteArrayComparator.java index ca3a6ac..fa6df76 100644 --- a/src/com/verisignlabs/dnssec/security/ByteArrayComparator.java +++ b/src/com/verisignlabs/dnssec/security/ByteArrayComparator.java @@ -1,4 +1,4 @@ -// $Id: ByteArrayComparator.java,v 1.2 2004/02/25 20:46:14 davidb Exp $ +// $Id$ // // Copyright (C) 2001-2003 VeriSign, Inc. // @@ -18,31 +18,32 @@ package com.verisignlabs.dnssec.security; -import java.util.*; +import java.util.Comparator; - -/** This class implements a basic comparitor for byte arrays. It is - * primarily useful for comparing RDATA portions of DNS records in - * doing DNSSEC canonical ordering. - * - * @author David Blacka (original) - * @author $Author: davidb $ - * @version $Revision: 1.2 $ +/** + * This class implements a basic comparitor for byte arrays. It is primarily + * useful for comparing RDATA portions of DNS records in doing DNSSEC + * canonical ordering. + * + * @author David Blacka (original) + * @author $Author$ + * @version $Revision$ */ public class ByteArrayComparator implements Comparator { - private int mOffset = 0; - private boolean mDebug = false; - + private int mOffset = 0; + private boolean mDebug = false; + public ByteArrayComparator() - {} + { + } public ByteArrayComparator(int offset, boolean debug) { mOffset = offset; mDebug = debug; } - + public int compare(Object o1, Object o2) throws ClassCastException { byte[] b1 = (byte[]) o1; @@ -52,12 +53,12 @@ public class ByteArrayComparator implements Comparator { if (b1[i] != b2[i]) { - if (mDebug) - { - System.out.println("offset " + i + " differs (this is " + - (i - mOffset) +" bytes in from our offset.)"); - } - return (b1[i] & 0xFF) - (b2[i] & 0xFF); + if (mDebug) + { + System.out.println("offset " + i + " differs (this is " + + (i - mOffset) + " bytes in from our offset.)"); + } + return (b1[i] & 0xFF) - (b2[i] & 0xFF); } } diff --git a/src/com/verisignlabs/dnssec/security/DnsKeyConverter.java b/src/com/verisignlabs/dnssec/security/DnsKeyConverter.java index 2587f63..b2ea724 100644 --- a/src/com/verisignlabs/dnssec/security/DnsKeyConverter.java +++ b/src/com/verisignlabs/dnssec/security/DnsKeyConverter.java @@ -1,4 +1,4 @@ -// $Id: DnsKeyConverter.java,v 1.4 2004/02/23 15:06:15 davidb Exp $ +// $Id$ // // Copyright (C) 2001-2003 VeriSign, Inc. // @@ -18,33 +18,51 @@ package com.verisignlabs.dnssec.security; -import java.io.*; -import java.util.StringTokenizer; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.math.BigInteger; -import java.security.*; -import java.security.spec.*; -import javax.crypto.spec.DHPrivateKeySpec; -import javax.crypto.spec.DHParameterSpec; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.spec.DSAPrivateKeySpec; +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; import javax.crypto.interfaces.DHPublicKey; -import java.security.interfaces.*; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.DHPrivateKeySpec; -import org.xbill.DNS.*; +import org.xbill.DNS.DNSKEYRecord; +import org.xbill.DNS.DNSSEC; +import org.xbill.DNS.KEYRecord; +import org.xbill.DNS.Name; import org.xbill.DNS.security.KEYConverter; import org.xbill.DNS.utils.base64; -/** This class handles conversions between JCA key formats and DNSSEC - * and BIND9 key formats. - * - * @author David Blacka (original) - * @author $Author: davidb $ (latest) - * @version $Revision: 1.4 $ +/** + * This class handles conversions between JCA key formats and DNSSEC and BIND9 + * key formats. + * + * @author David Blacka (original) + * @author $Author$ (latest) + * @version $Revision$ */ public class DnsKeyConverter { - private KeyFactory mRSAKeyFactory; - private KeyFactory mDSAKeyFactory; - private KeyFactory mDHKeyFactory; + private KeyFactory mRSAKeyFactory; + private KeyFactory mDSAKeyFactory; + private KeyFactory mDHKeyFactory; public DnsKeyConverter() { @@ -54,35 +72,35 @@ public class DnsKeyConverter public PublicKey parseDNSKEYRecord(DNSKEYRecord pKeyRecord) { if (pKeyRecord.getKey() == null) return null; - + return KEYConverter.parseRecord(pKeyRecord); } - /** 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) + /** + * 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) { // FIXME: currenty org.xbill.DNS.security.KEYConverter will only // convert to KEYRecords, and even then, assume that an RSA // PublicKey means alg 1. - KEYRecord kr = KEYConverter.buildRecord(name, dclass, ttl, flags, - KEYRecord.PROTOCOL_DNSSEC, key); + KEYRecord kr = KEYConverter.buildRecord(name, + dclass, + ttl, + flags, + KEYRecord.PROTOCOL_DNSSEC, + key); return new DNSKEYRecord(name, dclass, ttl, flags, - DNSKEYRecord.Protocol.DNSSEC, alg, - kr.getKey()); + DNSKEYRecord.Protocol.DNSSEC, alg, kr.getKey()); } - // Private Key Specific Parsing routines - /** Convert a PKCS#8 encoded private key into a PrivateKey - * object. */ + /** + * Convert a PKCS#8 encoded private key into a PrivateKey object. + */ public PrivateKey convertEncodedPrivateKey(byte[] key, int algorithm) { PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(key); @@ -91,24 +109,24 @@ public class DnsKeyConverter { switch (algorithm) { - case DNSSEC.RSAMD5: - case DNSSEC.RSASHA1: - return mRSAKeyFactory.generatePrivate(spec); - case DNSSEC.DSA: - return mDSAKeyFactory.generatePrivate(spec); + case DNSSEC.RSAMD5 : + case DNSSEC.RSASHA1 : + return mRSAKeyFactory.generatePrivate(spec); + case DNSSEC.DSA : + return mDSAKeyFactory.generatePrivate(spec); } } catch (GeneralSecurityException e) - { - } - + {} + return null; } - /** @return a JCA private key, given a BIND9-style textual - * encoding */ - public PrivateKey parsePrivateKeyString(String key) - throws IOException, NoSuchAlgorithmException + /** + * @return a JCA private key, given a BIND9-style textual encoding + */ + public PrivateKey parsePrivateKeyString(String key) throws IOException, + NoSuchAlgorithmException { StringTokenizer lines = new StringTokenizer(key, "\n"); @@ -124,7 +142,7 @@ public class DnsKeyConverter if (line.startsWith("Private-key-format: ")) { - if (! val.equals("v1.2")) + if (!val.equals("v1.2")) { throw new IOException("unsupported private key format: " + val); } @@ -141,8 +159,10 @@ public class DnsKeyConverter return null; } - /** @return the value part of an "attribute:value" pair. The value - * is trimmed. */ + /** + * @return the value part of an "attribute:value" pair. The value is + * trimmed. + */ private String value(String av) { if (av == null) return null; @@ -155,41 +175,23 @@ public class DnsKeyConverter return av.substring(pos + 1).trim(); } - /** prints the bytes of an original byte array and the BigInteger - * copy */ - private void printBigIntCompare(byte[] orig, BigInteger copy) - { - byte[] copy_bytes = copy.toByteArray(); - - for (int i = 0; i < 10 && i < orig.length; i++) { - System.err.print((int) orig[i] & 0xFF); - System.err.print(" "); - } - System.err.println(); - - for (int i = 0; i < 10 && i < copy_bytes.length; i++) { - System.err.print((int) copy_bytes[i] & 0xFF); - System.err.print(" "); - } - System.err.println(); - } - - /** Given the rest of the RSA BIND9 string format private key, parse - * and translate into a JCA private key - * - * @throws NoSuchAlgorithmException if the RSA algorithm is not - * available. */ + /** + * Given the rest of the RSA BIND9 string format private key, parse and + * translate into a JCA private key + * + * @throws NoSuchAlgorithmException if the RSA algorithm is not available. + */ private PrivateKey parsePrivateRSA(StringTokenizer lines) - throws NoSuchAlgorithmException + throws NoSuchAlgorithmException { - BigInteger modulus = null; - BigInteger public_exponent = null; + BigInteger modulus = null; + BigInteger public_exponent = null; BigInteger private_exponent = null; - BigInteger prime_p = null; - BigInteger prime_q = null; + BigInteger prime_p = null; + BigInteger prime_q = null; BigInteger prime_p_exponent = null; BigInteger prime_q_exponent = null; - BigInteger coefficient = null; + BigInteger coefficient = null; while (lines.hasMoreTokens()) { @@ -203,26 +205,41 @@ public class DnsKeyConverter 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); } } @@ -230,9 +247,8 @@ public class DnsKeyConverter try { KeySpec spec = new RSAPrivateCrtKeySpec(modulus, public_exponent, - private_exponent, prime_p, - prime_q, prime_p_exponent, - prime_q_exponent, coefficient); + private_exponent, prime_p, prime_q, prime_p_exponent, + prime_q_exponent, coefficient); if (mRSAKeyFactory == null) { mRSAKeyFactory = KeyFactory.getInstance("RSA"); @@ -246,13 +262,14 @@ public class DnsKeyConverter } } - /** Given the remaining lines in a BIND9 style DH private key, parse - * the key info and translate it into a JCA private key. - * - * @throws NoSuchAlgorithmException if the DH algorithm is not - * available. */ + /** + * Given the remaining lines in a BIND9 style DH private key, parse the key + * info and translate it into a JCA private key. + * + * @throws NoSuchAlgorithmException if the DH algorithm is not available. + */ private PrivateKey parsePrivateDH(StringTokenizer lines) - throws NoSuchAlgorithmException + throws NoSuchAlgorithmException { BigInteger p = null; BigInteger x = null; @@ -270,11 +287,16 @@ public class DnsKeyConverter 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); } } @@ -295,13 +317,14 @@ public class DnsKeyConverter } } - /** Given the remaining lines in a BIND9 style DSA private key, - * parse the key info and translate it into a JCA private key. - * - * @throws NoSuchAlgorithmException if the DSA algorithm is not - * available. */ + /** + * Given the remaining lines in a BIND9 style DSA private key, parse the key + * info and translate it into a JCA private key. + * + * @throws NoSuchAlgorithmException if the DSA algorithm is not available. + */ private PrivateKey parsePrivateDSA(StringTokenizer lines) - throws NoSuchAlgorithmException + throws NoSuchAlgorithmException { BigInteger p = null; BigInteger q = null; @@ -320,13 +343,20 @@ public class DnsKeyConverter 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); } } @@ -347,22 +377,22 @@ public class DnsKeyConverter } } - /** Given a private key and public key, generate the BIND9 style - * private key format. */ + /** + * Given a private key and public key, generate the BIND9 style private key + * format. + */ public String generatePrivateKeyString(PrivateKey priv, PublicKey pub, - int alg) + 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); } - else if (priv instanceof DHPrivateKey && - pub instanceof DHPublicKey) + else if (priv instanceof DHPrivateKey && pub instanceof DHPublicKey) { return generatePrivateDH((DHPrivateKey) priv, (DHPublicKey) pub); } @@ -370,8 +400,9 @@ public class DnsKeyConverter return null; } - /** Convert from 'unsigned' big integer to original 'signed format' - * in Base64 */ + /** + * Convert from 'unsigned' big integer to original 'signed format' in Base64 + */ private String b64BigInt(BigInteger i) { byte[] orig_bytes = i.toByteArray(); @@ -387,8 +418,10 @@ public class DnsKeyConverter return base64.toString(signed_bytes); } - /** Given a RSA private key (in Crt format), return the BIND9-style - * text encoding. */ + /** + * Given a RSA private key (in Crt format), return the BIND9-style text + * encoding. + */ private String generatePrivateRSA(RSAPrivateCrtKey key, int algorithm) { StringWriter sw = new StringWriter(); diff --git a/src/com/verisignlabs/dnssec/security/DnsKeyPair.java b/src/com/verisignlabs/dnssec/security/DnsKeyPair.java index d477cd9..059c03c 100644 --- a/src/com/verisignlabs/dnssec/security/DnsKeyPair.java +++ b/src/com/verisignlabs/dnssec/security/DnsKeyPair.java @@ -1,4 +1,4 @@ -// $Id: DnsKeyPair.java,v 1.3 2004/01/16 21:07:09 davidb Exp $ +// $Id$ // // Copyright (C) 2001-2003 VeriSign, Inc. // @@ -20,73 +20,74 @@ package com.verisignlabs.dnssec.security; import java.security.*; import java.security.interfaces.*; +import java.util.logging.Logger; + import org.xbill.DNS.*; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** This class forms the basis for representing public/private key - * pairs in a DNSSEC context. It is possible to get a JCA public and - * private key from this object, as well as a KEYRecord encoding of - * the public key. This class is implemented as a UNION of all the - * functionality needed for handing native java, BIND, and possibly - * other underlying KEY engines. - * - * JCA == Java Cryptography Architecture. - * - * @author David Blacka (orig) - * @author $Author: davidb $ (latest) - * @version $Revision: 1.3 $ +/** + * This class forms the basis for representing public/private key pairs in a + * DNSSEC context. It is possible to get a JCA public and private key from + * this object, as well as a DNSKEYRecord encoding of the public key. This + * class is implemented as a UNION of all the functionality needed for handing + * native java, BIND, and possibly other underlying DNSKEY engines. + * + * JCA == Java Cryptography Architecture. + * + * @author David Blacka (orig) + * @author $Author$ (latest) + * @version $Revision$ */ -// FIXME: this class is not a generic DnsKeyPair at all. It is really -// a JCEDnsKeyPair. We probably need to reexamine the class design here. - // 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 { /** This is the real (base) encoding of the public key. */ - protected DNSKEYRecord mPublicKeyRecord; + protected DNSKEYRecord mPublicKeyRecord; - /** This is a precalcuated cache of the KEYRecord converted into a - * JCA public key. */ - private PublicKey mPublicKey; + /** + * This is a precalcuated cache of the KEYRecord converted into a JCA public + * key. + */ + 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; - - /** The private key in JCA format. This is the base encoding for - * instances were JCA private keys are used. */ - protected PrivateKey mPrivateKey; + /** + * 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; + + /** + * The private key in JCA format. This is the base encoding for instances + * were JCA private keys are used. + */ + protected PrivateKey mPrivateKey; /** The local key converter. */ protected DnsKeyConverter mKeyConverter; - /** a cached Signature used for signing (initialized with the - * private key) */ - protected Signature mSigner; + /** + * a cached Signature used for signing (initialized with the private key) + */ + protected Signature mSigner; - /** a caches Signature used for verifying (intialized with the - * public key) */ - protected Signature mVerifier; + /** + * a caches Signature used for verifying (intialized with the public key) + */ + protected Signature mVerifier; + private Logger log; - private Log log; - public DnsKeyPair() { - log = LogFactory.getLog(this.getClass()); + log = Logger.getLogger(this.getClass().toString()); } public DnsKeyPair(DNSKEYRecord keyRecord, PrivateKey privateKey) { this(); - + setDNSKEYRecord(keyRecord); setPrivate(privateKey); } @@ -94,19 +95,23 @@ public class DnsKeyPair public DnsKeyPair(DNSKEYRecord keyRecord, String privateKeyString) { this(); - + setDNSKEYRecord(keyRecord); setPrivateKeyString(privateKeyString); } - + 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); + DNSKEYRecord keyrec = conv.generateDNSKEYRecord(keyName, + DClass.IN, + 0, + 0, + algorithm, + publicKey); setDNSKEYRecord(keyrec); setPrivate(privateKey); } @@ -114,7 +119,7 @@ public class DnsKeyPair public DnsKeyPair(DnsKeyPair pair) { this(); - + setDNSKEYRecord(pair.getDNSKEYRecord()); setPrivate(pair.getPrivate()); setPrivateKeyString(pair.getPrivateKeyString()); @@ -130,7 +135,7 @@ public class DnsKeyPair return mKeyConverter; } - + /** @return the appropriate Signature object for this keypair. */ protected Signature getSignature() { @@ -143,30 +148,31 @@ public class DnsKeyPair { switch (getDNSKEYAlgorithm()) { - case DNSSEC.RSAMD5: - s = Signature.getInstance("MD5withRSA"); - break; - case DNSSEC.DSA: - s = Signature.getInstance("SHA1withDSA"); - break; - case DNSSEC.RSASHA1: - s = Signature.getInstance("SHA1withRSA"); - break; - case -1: - s = null; - break; + case DNSSEC.RSAMD5 : + s = Signature.getInstance("MD5withRSA"); + break; + case DNSSEC.DSA : + s = Signature.getInstance("SHA1withDSA"); + break; + case DNSSEC.RSASHA1 : + s = Signature.getInstance("SHA1withRSA"); + break; + case -1 : + s = null; + break; } } catch (NoSuchAlgorithmException e) { - log.error("error getting Signature object", e); + log.severe("error getting Signature object: " + e); } return s; } - /** @return the public key, translated from the KEYRecord, if - * necessary. */ + /** + * @return the public key, translated from the KEYRecord, if necessary. + */ public PublicKey getPublic() { if (mPublicKey == null && getDNSKEYRecord() != null) @@ -178,9 +184,9 @@ public class DnsKeyPair return mPublicKey; } - - /** sets the public key. This method is generally not used - * directly. */ + /** + * sets the public key. This method is generally not used directly. + */ protected void setPublic(PublicKey k) { mPublicKey = k; @@ -205,17 +211,19 @@ public class DnsKeyPair mPrivateKey = k; } - /** @return the opaque private key string, null if one doesn't - * exist. */ + /** + * @return the opaque private key string, null if one doesn't exist. + */ public String getPrivateKeyString() { if (mPrivateKeyString == null && mPrivateKey != null) { PublicKey pub = getPublic(); - mPrivateKeyString = BINDKeyUtils.convertPrivateKey(mPrivateKey, pub, - getDNSKEYAlgorithm()); + mPrivateKeyString = BINDKeyUtils.convertPrivateKey(mPrivateKey, + pub, + getDNSKEYAlgorithm()); } - + return mPrivateKeyString; } @@ -224,7 +232,7 @@ public class DnsKeyPair { mPrivateKeyString = p; } - + /** @return the private key in an encoded form (normally PKCS#8). */ public byte[] getEncodedPrivate() { @@ -233,11 +241,13 @@ public class DnsKeyPair return null; } - /** Sets the private key from the encoded form (PKCS#8). This - * routine requires that the public key already be assigned. - * Currently it can only handle DSA and RSA keys. */ + /** + * Sets the private key from the encoded form (PKCS#8). This routine + * requires that the public key already be assigned. Currently it can only + * handle DSA and RSA keys. + */ public void setEncodedPrivate(byte[] encoded) - { + { int alg = getDNSKEYAlgorithm(); if (alg >= 0) @@ -246,15 +256,17 @@ public class DnsKeyPair setPrivate(conv.convertEncodedPrivateKey(encoded, alg)); } } - + /** @return the public DNSKEY record */ public DNSKEYRecord getDNSKEYRecord() { return mPublicKeyRecord; } - /** @return a Signature object initialized for signing, or null if - * this key pair does not have a valid private key. */ + /** + * @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) @@ -263,27 +275,29 @@ public class DnsKeyPair PrivateKey priv = getPrivate(); if (mSigner != null && priv != null) { - try - { - mSigner.initSign(priv); - } - catch (InvalidKeyException e) - { - log.error("Signature error", e); - } + try + { + mSigner.initSign(priv); + } + catch (InvalidKeyException e) + { + log.severe("Signature error: " + e); + } } else { - // do not return an unitialized signer. - return null; + // do not return an unitialized signer. + return null; } } return mSigner; } - /** @return a Signature object initialized for verifying, or null if - * this key pair does not have a valid public key. */ + /** + * @return a Signature object initialized for verifying, or null if this key + * pair does not have a valid public key. + */ public Signature getVerifier() { if (mVerifier == null) @@ -292,16 +306,17 @@ public class DnsKeyPair PublicKey pk = getPublic(); if (mVerifier != null && pk != null) { - try - { - mVerifier.initVerify(pk); - } - catch (InvalidKeyException e) {} + try + { + mVerifier.initVerify(pk); + } + catch (InvalidKeyException e) + {} } else { - // do not return an unitialized verifier - return null; + // do not return an unitialized verifier + return null; } } @@ -313,10 +328,9 @@ public class DnsKeyPair { mPublicKeyRecord = r; // force the conversion to PublicKey: - mPublicKey = null; + mPublicKey = null; } - public Name getDNSKEYName() { DNSKEYRecord kr = getDNSKEYRecord(); @@ -343,7 +357,7 @@ public class DnsKeyPair if (priv instanceof RSAPrivateKey) return DNSSEC.RSASHA1; if (priv instanceof DSAPrivateKey) return DNSSEC.DSA; } - + return -1; } diff --git a/src/com/verisignlabs/dnssec/security/DnsSecVerifier.java b/src/com/verisignlabs/dnssec/security/DnsSecVerifier.java index c3012d5..43384b6 100644 --- a/src/com/verisignlabs/dnssec/security/DnsSecVerifier.java +++ b/src/com/verisignlabs/dnssec/security/DnsSecVerifier.java @@ -1,4 +1,4 @@ -// $Id: DnsSecVerifier.java,v 1.5 2004/02/25 20:46:14 davidb Exp $ +// $Id$ // // Copyright (C) 2001-2003 VeriSign, Inc. // @@ -19,23 +19,29 @@ package com.verisignlabs.dnssec.security; -import java.util.*; -import java.io.*; -import java.security.*; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +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.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** A class for performing basic DNSSEC verification. The DNSJAVA - * package contains a similar class. This differs (for the moment, - * anyway) by allowing timing "fudge" factors and logging more - * specifically why an RRset did not validate. - * - * @author David Blacka (original) - * @author $Author: davidb $ - * @version $Revision: 1.5 $ +/** + * A class for performing basic DNSSEC verification. The DNSJAVA package + * contains a similar class. This differs (for the moment, anyway) by allowing + * timing "fudge" factors and logging more specifically why an RRset did not + * validate. + * + * @author David Blacka (original) + * @author $Author$ + * @version $Revision$ */ public class DnsSecVerifier implements Verifier { @@ -58,8 +64,8 @@ public class DnsSecVerifier implements Verifier List l = (List) mKeyMap.get(n); if (l == null) { - l = new ArrayList(); - mKeyMap.put(n, l); + l = new ArrayList(); + mKeyMap.put(n, l); } l.add(pair); @@ -80,35 +86,35 @@ public class DnsSecVerifier implements Verifier public DnsKeyPair find(Name name, int algorithm, int keyid) { String n = name.toString().toLowerCase(); - List l = (List) mKeyMap.get(n); + List l = (List) mKeyMap.get(n); if (l == null) return null; // FIXME: this algorithm assumes that name+alg+footprint is // unique, which isn't necessarily true. - for (Iterator i = l.iterator(); i.hasNext(); ) + for (Iterator i = l.iterator(); i.hasNext();) { - DnsKeyPair p = (DnsKeyPair) i.next(); - if (p.getDNSKEYAlgorithm() == algorithm && - p.getDNSKEYFootprint() == keyid) - { - return p; - } + DnsKeyPair p = (DnsKeyPair) i.next(); + if (p.getDNSKEYAlgorithm() == algorithm + && p.getDNSKEYFootprint() == keyid) + { + return p; + } } return null; } } private TrustedKeyStore mKeyStore; - private int mStartFudge = 0; - private int mExpireFudge = 0; + private int mStartFudge = 0; + private int mExpireFudge = 0; private boolean mVerifyAllSigs = false; - private Log log; - + private Logger log; + public DnsSecVerifier() { - log = LogFactory.getLog(this.getClass()); - + log = Logger.getLogger(this.getClass().toString()); + mKeyStore = new TrustedKeyStore(); } @@ -146,24 +152,24 @@ public class DnsSecVerifier implements Verifier { mVerifyAllSigs = v; } - + private DnsKeyPair findCachedKey(Cache cache, Name name, int algorithm, - int footprint) + int footprint) { RRset[] keysets = cache.findAnyRecords(name, Type.KEY); if (keysets == null) return null; // look for the particular key // FIXME: this assumes that name+alg+footprint is unique. - for (Iterator i = keysets[0].rrs(); i.hasNext(); ) + for (Iterator i = keysets[0].rrs(); i.hasNext();) { Object o = i.next(); - if (! (o instanceof DNSKEYRecord)) continue; + if (!(o instanceof DNSKEYRecord)) continue; DNSKEYRecord keyrec = (DNSKEYRecord) o; - if (keyrec.getAlgorithm() == algorithm && - keyrec.getFootprint() == footprint) + if (keyrec.getAlgorithm() == algorithm + && keyrec.getFootprint() == footprint) { - return new DnsKeyPair(keyrec, (PrivateKey) null); + return new DnsKeyPair(keyrec, (PrivateKey) null); } } @@ -171,7 +177,7 @@ public class DnsSecVerifier implements Verifier } private DnsKeyPair findKey(Cache cache, Name name, int algorithm, - int footprint) + int footprint) { DnsKeyPair pair = mKeyStore.find(name, algorithm, footprint); if (pair == null && cache != null) @@ -185,7 +191,7 @@ public class DnsSecVerifier implements Verifier private byte validateSignature(RRset rrset, RRSIGRecord sigrec) { if (rrset == null || sigrec == null) return DNSSEC.Failed; - if (! rrset.getName().equals(sigrec.getName())) + if (!rrset.getName().equals(sigrec.getName())) { log.info("Signature name does not match RRset name"); return DNSSEC.Failed; @@ -203,12 +209,12 @@ public class DnsSecVerifier implements Verifier { if (mStartFudge > 0) { - start = new Date(start.getTime() - ((long) mStartFudge * 1000)); + start = new Date(start.getTime() - ((long) mStartFudge * 1000)); } if (now.before(start)) { - log.info("Signature is not yet valid"); - return DNSSEC.Failed; + log.info("Signature is not yet valid"); + return DNSSEC.Failed; } } @@ -216,34 +222,37 @@ public class DnsSecVerifier implements Verifier { if (mExpireFudge > 0) { - expire = new Date(expire.getTime() + ((long) mExpireFudge * 1000)); + expire = new Date(expire.getTime() + ((long) mExpireFudge * 1000)); } if (now.after(expire)) { - log.info("Signature has expired (now = " + now + - ", sig expires = " + expire); - return DNSSEC.Failed; + log.info("Signature has expired (now = " + now + ", sig expires = " + + expire); + return DNSSEC.Failed; } } return DNSSEC.Secure; } - /** Verify an RRset against a particular signature. - * - * @return DNSSEC.Secure if the signature verfied, DNSSEC.Failed if - * it did not verify (for any reason), and DNSSEC.Insecure if - * verification could not be completed (usually because the public - * key was not available). */ + /** + * Verify an RRset against a particular signature. + * + * @return DNSSEC.Secure if the signature verfied, DNSSEC.Failed if it did + * not verify (for any reason), and DNSSEC.Insecure if verification + * could not be completed (usually because the public key was not + * available). + */ public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache) { byte result = validateSignature(rrset, sigrec); if (result != DNSSEC.Secure) return result; - - DnsKeyPair keypair = findKey(cache, sigrec.getSigner(), - sigrec.getAlgorithm(), - sigrec.getFootprint()); - + + DnsKeyPair keypair = findKey(cache, + sigrec.getSigner(), + sigrec.getAlgorithm(), + sigrec.getFootprint()); + if (keypair == null) { log.info("could not find appropriate key"); @@ -260,41 +269,42 @@ public class DnsSecVerifier implements Verifier byte[] sig = sigrec.getSignature(); if (sigrec.getAlgorithm() == DNSSEC.DSA) { - sig = SignUtils.convertDSASignature(sig); + sig = SignUtils.convertDSASignature(sig); } if (!signer.verify(sig)) { - log.info("Signature failed to verify cryptographically"); - return DNSSEC.Failed; + log.info("Signature failed to verify cryptographically"); + return DNSSEC.Failed; } return DNSSEC.Secure; } catch (IOException e) { - log.error("I/O error", e); + log.severe("I/O error: " + e); } catch (GeneralSecurityException e) { - log.error("Security error", e); + log.severe("Security error: " + e); } - log.debug("Signature failed to verify due to exception"); + log.fine("Signature failed to verify due to exception"); return DNSSEC.Insecure; } - /** Verifies an RRset. This routine does not modify the RRset. - * - * @return DNSSEC.Secure if the set verified, DNSSEC.Failed if it - * did not, and DNSSEC.Insecure if verification could not - * complete. */ + /** + * Verifies an RRset. This routine does not modify the RRset. + * + * @return DNSSEC.Secure if the set verified, DNSSEC.Failed if it did not, + * and DNSSEC.Insecure if verification could not complete. + */ public int verify(RRset rrset, Cache cache) { - int result = mVerifyAllSigs ? DNSSEC.Secure: DNSSEC.Insecure; + int result = mVerifyAllSigs ? DNSSEC.Secure : DNSSEC.Insecure; Iterator i = rrset.sigs(); - if ( ! i.hasNext()) + if (!i.hasNext()) { log.info("RRset failed to verify due to lack of signatures"); return DNSSEC.Insecure; @@ -307,12 +317,12 @@ public class DnsSecVerifier implements Verifier byte res = verifySignature(rrset, sigrec, cache); if (!mVerifyAllSigs && res == DNSSEC.Secure) return res; - + if (!mVerifyAllSigs && res < result) result = res; - + if (mVerifyAllSigs && res != DNSSEC.Secure && res < result) { - result = res; + result = res; } } diff --git a/src/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java b/src/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java index 84eab56..c1e320b 100644 --- a/src/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java +++ b/src/com/verisignlabs/dnssec/security/JCEDnsSecSigner.java @@ -1,4 +1,4 @@ -// $Id: JCEDnsSecSigner.java,v 1.3 2004/02/25 20:46:14 davidb Exp $ +// $Id$ // // Copyright (C) 2001-2003 VeriSign, Inc. // @@ -16,24 +16,41 @@ // 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.*; -import java.io.*; -import java.security.*; -import java.security.interfaces.*; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.interfaces.DSAPublicKey; +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 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; -/** This class contains routines for signing DNS zones. - * - * In particular, it contains both an ability to sign an individual - * RRset and the ability to sign and entire zone. It primarily glues - * together the more basic primitives found in {@link SignUtils}. - * - * @author David Blacka (original) - * @author $Author: davidb $ - * @version $Revision: 1.3 $ +/** + * This class contains routines for signing DNS zones. + * + * In particular, it contains both an ability to sign an individual RRset and + * the ability to sign and entire zone. It primarily glues together the more + * basic primitives found in {@link SignUtils}. + * + * @author David Blacka (original) + * @author $Author$ + * @version $Revision$ */ public class JCEDnsSecSigner { @@ -42,24 +59,19 @@ public class JCEDnsSecSigner private KeyPairGenerator mRSAKeyGenerator; private KeyPairGenerator mDSAKeyGenerator; - - /** Cryptographically generate a new DNSSEC key. - * - * @param owner the KEY RR's owner name. - * @param ttl the KEY RR's TTL. - * @param dclass the KEY RR's DNS class. - * @param algorithm the DNSSEC algorithm (RSAMD5, RSASHA1, or DSA). - * @param flags any flags for the KEY RR. - * @param keysize the size of the key to generate. - * @return a DnsKeyPair with the public and private keys populated. + /** + * Cryptographically generate a new DNSSEC key. + * + * @param owner the KEY RR's owner name. + * @param ttl the KEY RR's TTL. + * @param dclass the KEY RR's DNS class. + * @param algorithm the DNSSEC algorithm (RSAMD5, RSASHA1, or DSA). + * @param flags any flags for the KEY RR. + * @param keysize the size of the key to generate. + * @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) - throws IOException, NoSuchAlgorithmException + public DnsKeyPair generateKey(Name owner, long ttl, int dclass, + int algorithm, int flags, int keysize) throws NoSuchAlgorithmException { KeyPair pair; @@ -67,25 +79,25 @@ public class JCEDnsSecSigner switch (algorithm) { - case DNSSEC.RSAMD5: - case DNSSEC.RSASHA1: - if (mRSAKeyGenerator == null) - { - mRSAKeyGenerator = KeyPairGenerator.getInstance("RSA"); - } - mRSAKeyGenerator.initialize(keysize); - pair = mRSAKeyGenerator.generateKeyPair(); - break; - case DNSSEC.DSA: - if (mDSAKeyGenerator == null) - { - mDSAKeyGenerator = KeyPairGenerator.getInstance("DSA"); - } - mDSAKeyGenerator.initialize(keysize); - pair = mDSAKeyGenerator.generateKeyPair(); - break; - default: - throw new NoSuchAlgorithmException("Alg " + algorithm); + case DNSSEC.RSAMD5 : + case DNSSEC.RSASHA1 : + if (mRSAKeyGenerator == null) + { + mRSAKeyGenerator = KeyPairGenerator.getInstance("RSA"); + } + mRSAKeyGenerator.initialize(keysize); + pair = mRSAKeyGenerator.generateKeyPair(); + break; + case DNSSEC.DSA : + if (mDSAKeyGenerator == null) + { + mDSAKeyGenerator = KeyPairGenerator.getInstance("DSA"); + } + mDSAKeyGenerator.initialize(keysize); + pair = mDSAKeyGenerator.generateKeyPair(); + break; + default : + throw new NoSuchAlgorithmException("Alg " + algorithm); } if (mKeyConverter == null) @@ -94,29 +106,30 @@ public class JCEDnsSecSigner } DNSKEYRecord keyrec = mKeyConverter.generateDNSKEYRecord(owner, - dclass, - ttl, - flags, - algorithm, - pair.getPublic()); + dclass, + ttl, + flags, + algorithm, + pair.getPublic()); DnsKeyPair dnspair = new DnsKeyPair(); dnspair.setDNSKEYRecord(keyrec); - dnspair.setPublic(pair.getPublic()); // keep from conv. the keyrec back. + dnspair.setPublic(pair.getPublic()); // keep from conv. the keyrec back. dnspair.setPrivate(pair.getPrivate()); return dnspair; } - /** Sign an RRset. - * - * @param rrset the RRset to sign -- any existing signatures are ignored. - * @param keypars a list of DnsKeyPair objects containing private keys. - * @param start the inception time for the resulting RRSIG records. - * @param expire the expiration time for the resulting RRSIG records. - * @return a list of RRSIGRecord objects. + /** + * Sign an RRset. + * + * @param rrset the RRset to sign -- any existing signatures are ignored. + * @param keypars a list of DnsKeyPair objects containing private keys. + * @param start the inception time for the resulting RRSIG records. + * @param expire 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 + throws IOException, GeneralSecurityException { if (rrset == null || keypairs == null) return null; @@ -131,28 +144,31 @@ public class JCEDnsSecSigner ArrayList sigs = new ArrayList(keypairs.size()); // for each keypair, sign the rrset. - for (Iterator i = keypairs.iterator(); i.hasNext(); ) + for (Iterator i = keypairs.iterator(); i.hasNext();) { DnsKeyPair pair = (DnsKeyPair) i.next(); DNSKEYRecord keyrec = pair.getDNSKEYRecord(); if (keyrec == null) continue; - RRSIGRecord presig = SignUtils.generatePreRRSIG(rrset, keyrec, start, - expire, rrset.getTTL()); + RRSIGRecord presig = SignUtils.generatePreRRSIG(rrset, + keyrec, + start, + expire, + rrset.getTTL()); byte[] sign_data = SignUtils.generateSigData(rrset_data, presig); Signature signer = pair.getSigner(); if (signer == null) { - // debug - System.out.println("missing private key that goes with:\n" + - pair.getDNSKEYRecord()); - throw new GeneralSecurityException - ("cannot sign without a valid Signer " + - "(probably missing private key)"); + // debug + System.out.println("missing private key that goes with:\n" + + pair.getDNSKEYRecord()); + throw new GeneralSecurityException( + "cannot sign without a valid Signer " + + "(probably missing private key)"); } - + // sign the data. signer.update(sign_data); byte[] sig = signer.sign(); @@ -160,8 +176,8 @@ public class JCEDnsSecSigner // Convert to RFC 2536 format, if necessary. if (pair.getDNSKEYAlgorithm() == DNSSEC.DSA) { - sig = SignUtils.convertDSASignature - (((DSAPublicKey)pair.getPublic()).getParams(), sig); + sig = SignUtils.convertDSASignature(((DSAPublicKey) pair.getPublic()).getParams(), + sig); } RRSIGRecord sigrec = SignUtils.generateRRSIG(sig, presig); sigs.add(sigrec); @@ -170,21 +186,22 @@ public class JCEDnsSecSigner return sigs; } - /** Create a completely self-signed KEY RRset. - * - * @param keypairs the public & private keypairs to use in the keyset. - * @param start the RRSIG inception time. - * @param expire the RRSIG expiration time. - * @return a signed RRset. + /** + * Create a completely self-signed KEY RRset. + * + * @param keypairs the public & private keypairs to use in the keyset. + * @param start the RRSIG inception time. + * @param expire the RRSIG expiration time. + * @return a signed RRset. */ public RRset makeKeySet(List keypairs, Date start, Date expire) - throws IOException, GeneralSecurityException + throws IOException, GeneralSecurityException { // Generate a KEY RR set to sign. - + RRset keyset = new RRset(); - for (Iterator i = keypairs.iterator(); i.hasNext(); ) + for (Iterator i = keypairs.iterator(); i.hasNext();) { DnsKeyPair pair = (DnsKeyPair) i.next(); keyset.addRR(pair.getDNSKEYRecord()); @@ -192,42 +209,44 @@ public class JCEDnsSecSigner List records = signRRset(keyset, keypairs, start, expire); - for (Iterator i = records.iterator(); i.hasNext(); ) + for (Iterator i = records.iterator(); i.hasNext();) { keyset.addRR((Record) i.next()); } - + return keyset; } - /** Conditionally sign an RRset and add it to the toList. - * - * @param toList the list to which we are adding the processed RRsets. - * @param zonename the zone apex name. - * @param rrset the rrset under consideration. - * @param keysigningkeypairs the List of KSKs.. - * @param zonekeypairs the List of zone keys. - * @param start the RRSIG inception time. - * @param expire the RRSIG expiration time. - * @param fullySignKeyset if true, sign the zone apex keyset with - * both KSKs and ZSKs. - * @param last_cut the name of the last delegation point encountered. - * @return the name of the new last_cut. + /** + * Conditionally sign an RRset and add it to the toList. + * + * @param toList the list to which we are adding the processed RRsets. + * @param zonename the zone apex name. + * @param rrset the rrset under consideration. + * @param keysigningkeypairs the List of KSKs.. + * @param zonekeypairs the List of zone keys. + * @param start the RRSIG inception time. + * @param expire the RRSIG expiration time. + * @param fullySignKeyset if true, sign the zone apex keyset with both KSKs + * and ZSKs. + * @param last_cut the name of the last delegation point encountered. + * @return the name of the new last_cut. */ private Name addRRset(List toList, Name zonename, RRset rrset, - List keysigningkeypairs, List zonekeypairs, - Date start, Date expire, boolean fullySignKeyset, - Name last_cut) - throws IOException, GeneralSecurityException + List keysigningkeypairs, List zonekeypairs, Date start, Date expire, + boolean fullySignKeyset, Name last_cut) throws IOException, + GeneralSecurityException { // add the records themselves - for (Iterator i = rrset.rrs(); i.hasNext(); ) + for (Iterator i = rrset.rrs(); i.hasNext();) { toList.add(i.next()); } - int type = SignUtils.recordSecType(zonename, rrset.getName(), - rrset.getType(), last_cut); + int type = SignUtils.recordSecType(zonename, + rrset.getName(), + rrset.getType(), + last_cut); // we don't sign non-normal sets (delegations, glue, invalid). // we also don't sign the zone key set unless we've been asked. @@ -247,11 +266,11 @@ public class JCEDnsSecSigner // otherwise we will just sign them with the zonesigning keys. if (keysigningkeypairs != null && keysigningkeypairs.size() > 0) { - List sigs = signRRset(rrset, keysigningkeypairs, start, expire); - toList.addAll(sigs); + List sigs = signRRset(rrset, keysigningkeypairs, 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 we aren't going to sign with all the keys, bail out now. + if (!fullySignKeyset) return last_cut; } } @@ -262,46 +281,39 @@ public class JCEDnsSecSigner return last_cut; } - /** Given a zone, sign it. - * - * @param zonename 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. - * @param keysigningkeypairs the key pairs that are designated as - * "key signing keys". - * @param zonekeypair this key pairs that are designated as "zone - * signing keys". - * @param start the RRSIG inception time. - * @param expire the RRSIG expiration time. - * @param useOptIn generate Opt-In style NXT records. It will - * consider any insecure delegation to be unsigned. To override - * this, include the name of the insecure delegation in the - * NXTIncludeNames list. - * @param useConservativeOptIn if true, Opt-In NXT records will - * only be generated if there are insecure, unsigned delegations in - * the span. Not effect if useOptIn is false. - * @param fullySignKeyset sign the zone apex keyset with all available keys. - * @param NXTIncludeNames names that are to be included in the NXT - * chain regardless. This may be null and is only used if useOptIn - * is true. - * - * @return an ordered list of {@link org.xbill.DNS.Record} objects, - * representing the signed zone. + /** + * Given a zone, sign it. + * + * @param zonename 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. + * @param keysigningkeypairs the key pairs that are designated as "key + * signing keys". + * @param zonekeypair this key pairs that are designated as "zone signing + * keys". + * @param start the RRSIG inception time. + * @param expire the RRSIG expiration time. + * @param useOptIn generate Opt-In style NXT records. It will consider any + * insecure delegation to be unsigned. To override this, include + * the name of the insecure delegation in the NXTIncludeNames list. + * @param useConservativeOptIn if true, Opt-In NXT records will only be + * generated if there are insecure, unsigned delegations in the + * span. Not effect if useOptIn is false. + * @param fullySignKeyset sign the zone apex keyset with all available keys. + * @param NXTIncludeNames names that are to be included in the NXT chain + * regardless. This may be null and is only used if useOptIn is + * true. + * + * @return an ordered list of {@link org.xbill.DNS.Record} objects, + * representing the signed zone. */ - public List signZone(Name zonename, - List records, - List keysigningkeypairs, - List zonekeypairs, - Date start, - Date expire, - boolean useOptIn, - boolean useConservativeOptIn, - boolean fullySignKeyset, - List NSECIncludeNames) - throws IOException, GeneralSecurityException + public List signZone(Name zonename, List records, List keysigningkeypairs, + List zonekeypairs, Date start, Date expire, boolean useOptIn, + boolean useConservativeOptIn, boolean fullySignKeyset, + List NSECIncludeNames) throws IOException, GeneralSecurityException { - + // Remove any existing DNSSEC records (NSEC, RRSIG) SignUtils.removeGeneratedRecords(zonename, records); // Sort the zone @@ -312,28 +324,28 @@ public class JCEDnsSecSigner // Generate DS records SignUtils.generateDSRecords(zonename, records); - + // Generate NXT records if (useOptIn) { - SignUtils.generateOptInNSECRecords(zonename, records, - NSECIncludeNames, - useConservativeOptIn); + SignUtils.generateOptInNSECRecords(zonename, + records, + NSECIncludeNames, + useConservativeOptIn); } else { SignUtils.generateNSECRecords(zonename, records); } - - // Assemble into RRsets and sign. - RRset rrset = new RRset(); - ArrayList signed_records = new ArrayList(); - Name last_cut = null; - for (ListIterator i = records.listIterator(); i.hasNext(); ) + // Assemble into RRsets and sign. + RRset rrset = new RRset(); + ArrayList signed_records = new ArrayList(); + Name last_cut = null; + + for (ListIterator i = records.listIterator(); i.hasNext();) { Record r = (Record) i.next(); - Name r_name = r.getName(); // First record if (rrset.getName() == null) @@ -343,9 +355,9 @@ public class JCEDnsSecSigner } // Current record is part of the current RRset. - if (rrset.getName().equals(r.getName()) && - rrset.getDClass() == r.getDClass() && - rrset.getType() == r.getType()) + if (rrset.getName().equals(r.getName()) + && rrset.getDClass() == r.getDClass() + && rrset.getType() == r.getType()) { rrset.addRR(r); continue; @@ -356,17 +368,30 @@ 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, keysigningkeypairs, - zonekeypairs, start, expire, fullySignKeyset, - last_cut); + last_cut = addRRset(signed_records, + zonename, + rrset, + keysigningkeypairs, + zonekeypairs, + start, + expire, + fullySignKeyset, + last_cut); rrset.clear(); rrset.addRR(r); } // add the last RR set - addRRset(signed_records, zonename, rrset, keysigningkeypairs, zonekeypairs, - start, expire, fullySignKeyset, last_cut); + addRRset(signed_records, + zonename, + rrset, + keysigningkeypairs, + zonekeypairs, + start, + expire, + fullySignKeyset, + last_cut); return signed_records; } diff --git a/src/com/verisignlabs/dnssec/security/RecordComparator.java b/src/com/verisignlabs/dnssec/security/RecordComparator.java index 7d398db..3f775d6 100644 --- a/src/com/verisignlabs/dnssec/security/RecordComparator.java +++ b/src/com/verisignlabs/dnssec/security/RecordComparator.java @@ -1,4 +1,4 @@ -// $Id: RecordComparator.java,v 1.2 2004/01/16 17:54:48 davidb Exp $ +// $Id$ // // Copyright (C) 2000-2003 Network Solutions, Inc. // @@ -19,26 +19,33 @@ package com.verisignlabs.dnssec.security; -import java.util.*; +import java.util.Comparator; -import org.xbill.DNS.*; +import org.xbill.DNS.RRSIGRecord; +import org.xbill.DNS.Record; +import org.xbill.DNS.Type; -/** This class implements a comparison operator for {@link - * org.xbill.DNS.Record} 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: davidb $ - * @version $Revision: 1.2 $ */ +/** + * This class implements a comparison operator for {@link + * org.xbill.DNS.Record} 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$ + */ public class RecordComparator implements Comparator { public RecordComparator() - {} + { + } - /** In general, types are compared numerically. However, SOA and NS - * are ordered before the rest. */ + /** + * In general, types are compared numerically. However, SOA and NS are + * ordered before the rest. + */ private int compareTypes(int a, int b) { if (a == b) return 0; @@ -53,8 +60,7 @@ public class RecordComparator implements Comparator return 1; } - public int compare(Object o1, Object o2) - throws ClassCastException + public int compare(Object o1, Object o2) throws ClassCastException { Record a = (Record) o1; Record b = (Record) o2; diff --git a/src/com/verisignlabs/dnssec/security/SignUtils.java b/src/com/verisignlabs/dnssec/security/SignUtils.java index 7e2eba7..fae5001 100644 --- a/src/com/verisignlabs/dnssec/security/SignUtils.java +++ b/src/com/verisignlabs/dnssec/security/SignUtils.java @@ -1,4 +1,4 @@ -// $Id: SignUtils.java,v 1.7 2004/03/23 17:53:57 davidb Exp $ +// $Id$ // // Copyright (C) 2001-2003 VeriSign, Inc. // @@ -19,118 +19,103 @@ package com.verisignlabs.dnssec.security; -import java.util.*; -import java.io.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.security.MessageDigest; -import java.security.interfaces.DSAParams; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; +import java.security.interfaces.DSAParams; +import java.util.*; +import java.util.logging.Logger; import org.xbill.DNS.*; -import org.xbill.DNS.utils.base64; // debug only +import org.xbill.DNS.utils.base64; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -/** This class contains a bunch of utility methods that are generally - * useful in signing zones. - * - * @author David Blacka (original) - * @author $Author: davidb $ - * @version $Revision: 1.7 $ +/** + * This class contains a bunch of utility methods that are generally useful in + * signing zones. + * + * @author David Blacka (original) + * @author $Author$ + * @version $Revision$ */ public class SignUtils { - private static final int DSA_SIGNATURE_LENGTH = 20; - 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; + private static final int ASN1_INT = 0x02; + private static final int ASN1_SEQ = 0x30; - private static Log log; + 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; - static { - log = LogFactory.getLog(SignUtils.class); + private static Logger log; + + static + { + log = Logger.getLogger(SignUtils.class.toString()); } - - public static void setLog(Log v) + + public static void setLog(Logger v) { log = v; } - /** Generate from some basic information a prototype SIG RR - * containing everything but the actual signature itself. - * - * @param rrset the RRset being signed. - * @param key the public KEY RR counterpart to the key being used - * to sign the RRset - * @param start the SIG inception time. - * @param expire the SIG expiration time. - * @param sig_ttl the TTL of the resulting SIG record. - * @return a prototype signature based on the RRset and key - * information. */ + + /** + * Generate from some basic information a prototype SIG RR containing + * everything but the actual signature itself. + * + * @param rrset the RRset being signed. + * @param key the public KEY RR counterpart to the key being used to sign + * the RRset + * @param start the SIG inception time. + * @param expire the SIG expiration time. + * @param sig_ttl the TTL of the resulting SIG 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) + Date start, Date 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); + return new RRSIGRecord(rrset.getName(), rrset.getDClass(), sig_ttl, + rrset.getType(), key.getAlgorithm(), (int) rrset.getTTL(), expire, + start, key.getFootprint(), key.getName(), null); } - /** Generate from some basic information a prototype SIG RR - * containing everything but the actual signature itself. - * + /** + * Generate from some basic information a prototype SIG RR containing + * everything but the actual signature itself. + * * @param rec the DNS record being signed (forming an entire RRset). - * @param key the public KEY RR counterpart to the key signing the - * record. + * @param key the public KEY RR counterpart to the key signing the record. * @param start the SIG inception time. * @param expire the SIG expiration time. * @param sig_ttl the TTL of the result SIG record. - * @return a prototype signature based on the Record and key - * information. */ + * @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) + Date start, Date 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); + return new RRSIGRecord(rec.getName(), rec.getDClass(), sig_ttl, + rec.getType(), key.getAlgorithm(), rec.getTTL(), expire, start, + key.getFootprint(), key.getName(), null); } - - /** Generate the binary image of the prototype SIG RR. - * - * @param presig the SIG RR prototype. - * @return the RDATA portion of the prototype SIG record. This - * forms the first part of the data to be signed. */ + /** + * Generate the binary image of the prototype SIG RR. + * + * @param presig the SIG RR prototype. + * @return the RDATA portion of the prototype SIG record. This forms the + * first part of the data to be signed. + */ private static byte[] generatePreSigRdata(RRSIGRecord presig) - throws IOException { // Generate the binary image; DNSOutput image = new DNSOutput(); // precalc some things - int start_time = (int) (presig.getTimeSigned().getTime() / 1000); + int start_time = (int) (presig.getTimeSigned().getTime() / 1000); int expire_time = (int) (presig.getExpire().getTime() / 1000); Name signer = presig.getSigner(); @@ -148,22 +133,23 @@ public class SignUtils return image.toByteArray(); } - /** Calculate the canonical wire line format of the RRset. - * - * @param rrset the RRset to convert. - * @return the canonical wire line format of the rrset. This is - * the second part of data to be signed.*/ + /** + * Calculate the canonical wire line format of the RRset. + * + * @param rrset the RRset to convert. + * @return the canonical wire line format of the rrset. This is the second + * part of data to be signed. + */ public static byte[] generateCanonicalRRsetData(RRset rrset) - throws IOException { DNSOutput image = new DNSOutput(); // now convert load 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(); ) + for (Iterator i = rrset.rrs(); i.hasNext();) { - Record r = (Record) i.next(); + Record r = (Record) i.next(); byte[] wire_fmt = r.toWireCanonical(); canonical_rrs.add(wire_fmt); } @@ -171,9 +157,9 @@ public class SignUtils // put the records into the correct ordering. // Caculate the offset where the RDATA begins (we have to skip // past the length byte) - + // FIXME: currently, draft-ietf-dnsext-dnssec-records-06 has us - // sorting by length first, then bytes. This can be accomplished + // sorting by length first, then bytes. This can be accomplished // by not skipping past the RDLENGTH field, I think. // FIXME update: I pointed this out as an error, and subsequent // versions should correct this, setting the standard back to @@ -181,10 +167,10 @@ public class SignUtils int offset = rrset.getName().toWireCanonical().length + 10; ByteArrayComparator bac = new ByteArrayComparator(offset, false); - + Collections.sort(canonical_rrs, bac); - for (Iterator i = canonical_rrs.iterator(); i.hasNext(); ) + for (Iterator i = canonical_rrs.iterator(); i.hasNext();) { byte[] wire_fmt_rec = (byte[]) i.next(); image.writeByteArray(wire_fmt_rec); @@ -193,37 +179,39 @@ public class SignUtils return image.toByteArray(); } - /** Given an RRset and the prototype signature, generate the - * canonical data that is to be signed. - * - * @param rrset the RRset to be signed. - * @param presig a prototype SIG RR created using the same RRset. - * @return a block of data ready to be signed. + /** + * Given an RRset and the prototype signature, generate the canonical data + * that is to be signed. + * + * @param rrset the RRset to be signed. + * @param presig 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); return generateSigData(rrset_data, presig); } - /** Given an RRset and the prototype signature, generate the - * canonical data that is to be signed. - * - * @param rrset_data 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. - * @return a block of data ready to be signed. + /** + * Given an RRset and the prototype signature, generate the canonical data + * that is to be signed. + * + * @param rrset_data 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. + * @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 + rrset_data.length); + ByteArrayOutputStream image = new ByteArrayOutputStream(sig_rdata.length + + rrset_data.length); image.write(sig_rdata); image.write(rrset_data); @@ -231,44 +219,41 @@ public class SignUtils return image.toByteArray(); } - /** Given the acutal signature an the prototype signature, combine - * them and return the fully formed SIGRecord. - * - * @param signature the cryptographic signature, in DNSSEC format. - * @param presig the prototype SIG RR to add the signature to. - * @return the fully formed SIG RR. + /** + * Given the acutal signature an the prototype signature, combine them and + * return the fully formed SIGRecord. + * + * @param signature the cryptographic signature, in DNSSEC format. + * @param presig the prototype SIG RR to add the signature to. + * @return the fully formed SIG RR. */ 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); + return new RRSIGRecord(presig.getName(), presig.getDClass(), + presig.getTTL(), presig.getTypeCovered(), presig.getAlgorithm(), + presig.getOrigTTL(), presig.getExpire(), presig.getTimeSigned(), + presig.getFootprint(), presig.getSigner(), signature); } - /** Converts from a RFC 2536 formatted DSA signature to a JCE - * (ASN.1) formatted signature. - * - *

ASN.1 format = ASN1_SEQ . seq_length . ASN1_INT . Rlength . R - * . ANS1_INT . Slength . S

- * - * The integers R and S may have a leading null byte to force the - * integer positive. - * - * @param 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. - **/ + /** + * Converts from a RFC 2536 formatted DSA signature to a JCE (ASN.1) + * formatted signature. + * + *

+ * ASN.1 format = ASN1_SEQ . seq_length . ASN1_INT . Rlength . R . ANS1_INT . + * Slength . S + *

+ * + * The integers R and S may have a leading null byte to force the integer + * positive. + * + * @param 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. + */ public static byte[] convertDSASignature(byte[] signature) - throws SignatureException + throws SignatureException { if (signature.length != 41) throw new SignatureException("RFC 2536 signature not expected length."); @@ -277,14 +262,14 @@ public class SignUtils byte s_pad = 0; // handle initial null byte padding. - if (signature[1] < 0) r_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 // (SEQ, INT, INT). byte sig_length = (byte) (40 + r_pad + s_pad + 6); - + byte sig[] = new byte[sig_length]; byte pos = 0; @@ -295,7 +280,7 @@ public class SignUtils // copy the value of R, leaving a null byte if necessary if (r_pad == 1) sig[pos++] = 0; - + System.arraycopy(signature, 1, sig, pos, 20); pos += 20; @@ -309,46 +294,48 @@ public class SignUtils return sig; } - - /** Converts from a JCE (ASN.1) formatted DSA signature to a RFC - * 2536 compliant signature. - * - *

rfc2536 format = T . R . S

- * - * where T is a number between 0 and 8, which is based on the DSA - * key length, and R & S are formatted to be exactly 20 bytes each - * (no leading null bytes). - * - * @param params the DSA parameters associated with the DSA key - * used to generate the signature. - * @param 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. + /** + * Converts from a JCE (ASN.1) formatted DSA signature to a RFC 2536 + * compliant signature. + * + *

+ * rfc2536 format = T . R . S + *

+ * + * where T is a number between 0 and 8, which is based on the DSA key + * length, and R & S are formatted to be exactly 20 bytes each (no leading + * null bytes). + * + * @param params the DSA parameters associated with the DSA key used to + * generate the signature. + * @param 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. */ public static byte[] convertDSASignature(DSAParams params, byte[] signature) - throws SignatureException + throws SignatureException { if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT) { - throw new SignatureException - ("Invalid ASN.1 signature format: expected SEQ, 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) { - throw new SignatureException - ("Invalid ASN.1 signature format: expected SEQ, INT, INT"); + if (signature[24 + r_pad] != ASN1_INT) + { + throw new SignatureException( + "Invalid ASN.1 signature format: expected SEQ, INT, INT"); } - log.trace("(start) ASN.1 DSA Sig:\n" + base64.toString(signature)); + log.finer("(start) ASN.1 DSA Sig:\n" + base64.toString(signature)); byte s_pad = (byte) (signature[25 + r_pad] - 20); - + byte[] sig = new byte[41]; // all rfc2536 signatures are 41 bytes. - + // Calculate T: sig[0] = (byte) ((params.getP().bitLength() - 512) / 64); @@ -361,10 +348,10 @@ public class SignUtils { // 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); + Arrays.fill(sig, 1, 1 - r_pad, (byte) 0); System.arraycopy(signature, 4, sig, 1 - r_pad, 20 + r_pad); } - + // copy S value if (s_pad >= 0) { @@ -377,55 +364,57 @@ public class SignUtils 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) { - log.trace("(finish ***) RFC 2536 DSA Sig:\n" + base64.toString(sig)); + log.finer("(finish ***) RFC 2536 DSA Sig:\n" + base64.toString(sig)); } else { - log.trace("(finish) RFC 2536 DSA Sig:\n" + base64.toString(sig)); + log.finer("(finish) RFC 2536 DSA Sig:\n" + base64.toString(sig)); } - + return sig; } - - /** This is a convenience routine to help us classify records/RRsets. + + /** + * This is a convenience routine to help us classify records/RRsets. * - * It charaterizes a record/RRset as one of the following classes:
- *
- - *
NORMAL
This record/set is properly within the zone - * an subject to all NXT and SIG processing.
- - *
DELEGATION
This is a zone delegation point (or - * cut). It is used in NXT processing but is not signed.
- - *
GLUE
This is a glue record and therefore not - * properly within the zone. It is not included in NXT or SIG - * processing. Normally glue records are A records, but this - * routine calls anything that is below a zone delegation - * glue.
- - *
INVALID
This record doesn't even belong in the - * zone.
- - *

- - * This method must be called successively on records in the - * canonical name ordering, and the caller must maintain the - * last_cut parameter. - - * @param zonename the name of the zone that is being processed. - * @param name the name of the record/set under consideration. - * @param type 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. - */ + * It charaterizes a record/RRset as one of the following classes:
+ *
+ * + *
NORMAL
+ *
This record/set is properly within the zone an subject to all NXT + * and SIG processing.
+ * + *
DELEGATION
+ *
This is a zone delegation point (or cut). It is used in NXT + * processing but is not signed.
+ * + *
GLUE
+ *
This is a glue record and therefore not properly within the zone. It + * is not included in NXT or SIG processing. Normally glue records are A + * records, but this routine calls anything that is below a zone delegation + * glue.
+ * + *
INVALID
+ *
This record doesn't even belong in the zone.
+ * + *
+ *
+ * + * This method must be called successively on records in the canonical name + * ordering, and the caller must maintain the last_cut parameter. + * + * @param zonename the name of the zone that is being processed. + * @param name the name of the record/set under consideration. + * @param type 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. + */ public static int recordSecType(Name zonename, Name name, int type, - Name last_cut) + Name last_cut) { // records not even in the zone itself are invalid. if (!name.subdomain(zonename)) return RR_INVALID; @@ -442,10 +431,10 @@ public class SignUtils // NS record, then we either a DS record or glue. if (name.equals(last_cut)) { - if (type == Type.DS || type == Type.NXT || - type == Type.NSEC) return RR_NORMAL; - // actually, this is probably INVALID, but it could be glue. - return RR_GLUE; + if (type == Type.DS || type == Type.NXT || type == Type.NSEC) + return RR_NORMAL; + // actually, this is probably INVALID, but it could be glue. + return RR_GLUE; } // below the delegation, we are glue if (name.subdomain(last_cut)) return RR_GLUE; @@ -453,32 +442,32 @@ public class SignUtils return RR_NORMAL; } - - /** Given a canonical ordered list of records from a single zone, - * order the raw records into a list of RRsets. - * - * @param records a list of {@link org.xbill.DNS.Record} objects, - * in DNSSEC canonical order. - * @return a List of {@link org.xbill.DNS.RRset} objects. + + /** + * Given a canonical ordered list of records from a single zone, order the + * raw records into a list of RRsets. + * + * @param records 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) { - RRset rrset = new RRset(); - ArrayList rrsets = new ArrayList(); + RRset rrset = new RRset(); + ArrayList rrsets = new ArrayList(); - for (Iterator i = records.iterator(); i.hasNext(); ) + for (Iterator i = records.iterator(); i.hasNext();) { Object o = i.next(); - if (! (o instanceof Record)) + if (!(o instanceof Record)) { - log.warn("assembleIntoRRsets: a non-record object was " + - "encountered and skipped: " + o + " (" + o.getClass() + ")"); - continue; + log.warning("assembleIntoRRsets: a non-record object was " + + "encountered and skipped: " + o + " (" + o.getClass() + ")"); + continue; } Record r = (Record) o; - Name r_name = r.getName(); // First record if (rrset.getName() == null) @@ -488,11 +477,9 @@ 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())) + if (rrset.getName().equals(r.getName()) + && rrset.getDClass() == r.getDClass() + && ((r.getType() == Type.RRSIG && rrset.getType() == ((RRSIGRecord) r).getTypeCovered()) || rrset.getType() == r.getType())) { rrset.addRR(r); continue; @@ -508,13 +495,13 @@ public class SignUtils // add the last rrset. rrsets.add(rrset); - + return rrsets; } - - /** A little private class to hold information about a given - * node. */ + /** + * A little private class to hold information about a given node. + */ private static class NodeInfo { public Name name; @@ -525,28 +512,30 @@ public class SignUtils public boolean isSecureNode; // opt-in support. public boolean hasOptInSpan; // opt-in support. public int nsecIndex; - + public NodeInfo(Record r) { - this.name = r.getName(); - this.type = r.getType(); - this.ttl = r.getTTL(); - this.dclass = r.getDClass(); - this.typemap = new HashSet(); + this.name = r.getName(); + this.type = r.getType(); + this.ttl = r.getTTL(); + this.dclass = r.getDClass(); + this.typemap = new HashSet(); this.isSecureNode = false; this.hasOptInSpan = false; addType(type); } + public void addType(int type) { this.typemap.add(new Integer(type)); // Opt-In support. if (type != Type.NS && type != Type.NSEC && type != Type.RRSIG) - { - isSecureNode = true; + { + isSecureNode = true; } } + public String toString() { StringBuffer sb = new StringBuffer(name.toString()); @@ -557,9 +546,9 @@ public class SignUtils public int[] getTypes() { - Object[] a = typemap.toArray(); - int[] res = new int[a.length]; - + Object[] a = typemap.toArray(); + int[] res = new int[a.length]; + for (int i = 0; i < a.length; i++) { res[i] = ((Integer) a[i]).intValue(); @@ -568,33 +557,34 @@ public class SignUtils } } - /** Given a canonical (by name) ordered list of records in a zone, - * generate the NXT records in place. - * - * Note that the list that the records are stored in must support - * the listIterator.add() operation. - * - * @param zonename 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. + /** + * Given a canonical (by name) ordered list of records in a zone, generate + * the NXT records in place. + * + * Note that the list that the records are stored in must support the + * listIterator.add() operation. + * + * @param zonename 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. */ public static void generateNSECRecords(Name zonename, List records) { - // This works by iterating over a known sorted list of records. + // This works by iterating over a known sorted list of records. - NodeInfo last_node = null; + NodeInfo last_node = null; NodeInfo current_node = null; - + Name last_cut = null; - int backup; - - for (ListIterator i = records.listIterator(); i.hasNext(); ) + int backup; + + for (ListIterator i = records.listIterator(); i.hasNext();) { - Record r = (Record) i.next(); - Name r_name = r.getName(); - int r_type = r.getType(); - int r_sectype = recordSecType(zonename, r_name, r_type, last_cut); + Record r = (Record) i.next(); + Name r_name = r.getName(); + int r_type = r.getType(); + int r_sectype = recordSecType(zonename, r_name, r_type, last_cut); // skip irrelevant records if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue; @@ -605,37 +595,38 @@ public class SignUtils // first node -- initialize if (current_node == null) { - current_node = new NodeInfo(r); - current_node.addType(Type.RRSIG); - current_node.addType(Type.NSEC); - continue; + current_node = new NodeInfo(r); + current_node.addType(Type.RRSIG); + current_node.addType(Type.NSEC); + continue; } // record name hasn't changed, so we are still on the same node. if (r_name.equals(current_node.name)) { - current_node.addType(r_type); - continue; + current_node.addType(r_type); + continue; } - + if (last_node != null) { - NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, - last_node.ttl, 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. - backup = i.nextIndex() - last_node.nsecIndex; - for (int j = 0; j < backup; j++) i.previous(); - i.add(nsec); - for (int j = 0; j < backup; j++) i.next(); + NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, + last_node.ttl, 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. + backup = i.nextIndex() - last_node.nsecIndex; + for (int j = 0; j < backup; j++) + i.previous(); + i.add(nsec); + for (int j = 0; j < backup; j++) + i.next(); - log.trace("Generated: " + nsec); + log.finer("Generated: " + nsec); } last_node = current_node; - + current_node.nsecIndex = i.previousIndex(); current_node = new NodeInfo(r); current_node.addType(Type.RRSIG); @@ -646,63 +637,58 @@ public class SignUtils if (last_node != null) { NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, - last_node.ttl, current_node.name, - last_node.getTypes()); + last_node.ttl, current_node.name, last_node.getTypes()); records.add(last_node.nsecIndex - 1, nsec); - log.trace("Generated: " + nsec); + log.finer("Generated: " + nsec); } - + // Generate last NSEC NSECRecord nsec = new NSECRecord(current_node.name, current_node.dclass, - current_node.ttl, zonename, - current_node.getTypes()); + current_node.ttl, zonename, current_node.getTypes()); records.add(nsec); - log.trace("Generated: " + nsec); + log.finer("Generated: " + nsec); } - - /** Given a canonical (by name) ordered list of records in a zone, - * generate the NXT records in place. - * - * Note thatthe list that the records are stored in must support - * the listIterator.add operation. - * - * @param zonename 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. - * @param includeNames 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. + /** + * Given a canonical (by name) ordered list of records in a zone, generate + * the NXT records in place. + * + * Note thatthe list that the records are stored in must support the + * listIterator.add operation. + * + * @param zonename 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. + * @param includeNames 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. */ - public static void generateOptInNSECRecords(Name zonename, - List records, - List includeNames, - boolean beConservative) + public static void generateOptInNSECRecords(Name zonename, List records, + List includeNames, boolean beConservative) { - // This works by iterating over a known sorted list of records. + // This works by iterating over a known sorted list of records. - NodeInfo last_node = null; + NodeInfo last_node = null; NodeInfo current_node = null; - - Name last_cut = null; - int backup; + + Name last_cut = null; + int backup; HashSet includeSet = null; - + if (includeNames != null) { includeSet = new HashSet(includeNames); } - - for (ListIterator i = records.listIterator(); i.hasNext(); ) + + for (ListIterator i = records.listIterator(); i.hasNext();) { - Record r = (Record) i.next(); - Name r_name = r.getName(); - int r_type = r.getType(); - int r_sectype = recordSecType(zonename, r_name, r_type, last_cut); + Record r = (Record) i.next(); + Name r_name = r.getName(); + int r_type = r.getType(); + int r_sectype = recordSecType(zonename, r_name, r_type, last_cut); // skip irrelevant records if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue; @@ -713,58 +699,59 @@ public class SignUtils // first node -- initialize if (current_node == null) { - current_node = new NodeInfo(r); - current_node.addType(Type.RRSIG); - continue; + current_node = new NodeInfo(r); + 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)) { - current_node.addType(r_type); - continue; + 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)) { - current_node.isSecureNode = true; + current_node.isSecureNode = true; } if (last_node != null && current_node.isSecureNode) { - // generate a NSEC record. - 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()); - // Note: we have to add this through the iterator, otherwise - // the next access via the iterator will generate a - // ConcurrencyModificationException. - backup = i.nextIndex() - last_node.nsecIndex; - for (int j = 0; j < backup; j++) i.previous(); - i.add(nsec); - for (int j = 0; j < backup; j++) i.next(); - - log.trace("Generated: " + nsec); + // generate a NSEC record. + 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()); + // Note: we have to add this through the iterator, otherwise + // the next access via the iterator will generate a + // ConcurrencyModificationException. + backup = i.nextIndex() - last_node.nsecIndex; + for (int j = 0; j < backup; j++) + i.previous(); + i.add(nsec); + for (int j = 0; j < backup; j++) + i.next(); + + log.finer("Generated: " + nsec); } if (current_node.isSecureNode) { - last_node = current_node; + last_node = current_node; } 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. - last_node.hasOptInSpan = true; + // 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. + last_node.hasOptInSpan = true; } - + current_node.nsecIndex = i.previousIndex(); current_node = new NodeInfo(r); current_node.addType(Type.RRSIG); @@ -776,26 +763,24 @@ public class SignUtils // generate a NSEC record. if (beConservative && !last_node.hasOptInSpan) { - last_node.addType(Type.NSEC); + last_node.addType(Type.NSEC); } NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, - last_node.ttl, current_node.name, - last_node.getTypes()); + last_node.ttl, current_node.name, last_node.getTypes()); records.add(last_node.nsecIndex - 1, nsec); - log.trace("Generated: " + nsec); + log.finer("Generated: " + nsec); } - + // Generate last NSEC NSECRecord nsec; if (current_node.isSecureNode) { if (beConservative) { - current_node.addType(Type.NSEC); + current_node.addType(Type.NSEC); } nsec = new NSECRecord(current_node.name, current_node.dclass, - current_node.ttl, zonename, - current_node.getTypes()); + current_node.ttl, zonename, current_node.getTypes()); // we can just tack this on the end as we are working on the // last node. records.add(nsec); @@ -803,28 +788,27 @@ public class SignUtils else { nsec = new NSECRecord(last_node.name, last_node.dclass, last_node.ttl, - zonename, last_node.getTypes()); + zonename, 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); } - - log.trace("Generated: " + nsec); + + log.finer("Generated: " + nsec); } - - /** Given a zone with DNSKEY records at delegation points, convert - * those KEY 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. - * @param records a list of {@link org.xbill.DNS.Record} objects. + /** + * Given a zone with DNSKEY records at delegation points, convert those KEY + * 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. + * @param records a list of {@link org.xbill.DNS.Record} objects. */ public static void generateDSRecords(Name zonename, List records) - throws IOException { - for (ListIterator i = records.listIterator(); i.hasNext(); ) + for (ListIterator i = records.listIterator(); i.hasNext();) { Record r = (Record) i.next(); if (r == null) continue; // this should never be true. @@ -835,73 +819,74 @@ public class SignUtils // Convert non-zone level KEY records into DS records. if (r.getType() == Type.DNSKEY && !r_name.equals(zonename)) { - DSRecord ds = calculateDSRecord((DNSKEYRecord) r, r.getTTL()); + DSRecord ds = calculateDSRecord((DNSKEYRecord) r, r.getTTL()); - i.set(ds); + i.set(ds); } } } - /** Given a zone, remove all records that are generated. - * - * @param zonename the name of the zone. - * @param records a list of {@link org.xbill.DNS.Record} objects. + /** + * Given a zone, remove all records that are generated. + * + * @param zonename the name of the zone. + * @param records a list of {@link org.xbill.DNS.Record} objects. */ public static void removeGeneratedRecords(Name zonename, List records) { - for (Iterator i = records.iterator(); i.hasNext(); ) + for (Iterator i = records.iterator(); i.hasNext();) { Record r = (Record) i.next(); - if (r.getType() == Type.RRSIG || - r.getType() == Type.NSEC) + if (r.getType() == Type.RRSIG || r.getType() == Type.NSEC) { - i.remove(); + i.remove(); } - } + } } - /** Remove duplicate records from a list of records. This routine - * presumes the list of records is in a canonical sorted order, at - * least on name and RR type. - * - * @param records a list of {@link org.xbill.DNS.Record} object, in - * sorted order. + /** + * Remove duplicate records from a list of records. This routine presumes + * the list of records is in a canonical sorted order, at least on name and + * RR type. + * + * @param records a list of {@link org.xbill.DNS.Record} object, in sorted + * order. */ 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 = (Record) i.next(); if (lastrec == null) { - lastrec = r; - continue; + lastrec = r; + continue; } if (lastrec.equals(r)) { - i.remove(); - continue; + i.remove(); + continue; } lastrec = r; } } - /** Given a DNSKEY record, generate the DS record from it. - * - * @param keyrec the KEY record in question. - * @param ttl 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} - */ + /** + * Given a DNSKEY record, generate the DS record from it. + * + * @param keyrec the KEY record in question. + * @param ttl 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, long ttl) - throws IOException { if (keyrec == null) return null; if (ttl <= 0) ttl = keyrec.getTTL(); - + DNSOutput os = new DNSOutput(); os.writeByteArray(keyrec.getName().toWireCanonical()); @@ -914,13 +899,13 @@ public class SignUtils byte[] digest = md.digest(os.toByteArray()); return new DSRecord(keyrec.getName(), keyrec.getDClass(), ttl, - keyrec.getFootprint(), keyrec.getAlgorithm(), - DSRecord.SHA1_DIGEST_ID, digest); + keyrec.getFootprint(), keyrec.getAlgorithm(), + DSRecord.SHA1_DIGEST_ID, digest); } catch (NoSuchAlgorithmException e) { - log.error("", e); + log.severe(e.toString()); return null; } } diff --git a/src/com/verisignlabs/dnssec/security/TypeMap.java b/src/com/verisignlabs/dnssec/security/TypeMap.java index 756a66f..9989563 100644 --- a/src/com/verisignlabs/dnssec/security/TypeMap.java +++ b/src/com/verisignlabs/dnssec/security/TypeMap.java @@ -1,24 +1,28 @@ -// $Id: TypeMap.java,v 1.5 2004/03/23 17:53:57 davidb Exp $ +// $Id$ // // Copyright (C) 2004 Verisign, Inc. package com.verisignlabs.dnssec.security; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; -import org.xbill.DNS.Type; import org.xbill.DNS.DNSOutput; +import org.xbill.DNS.Type; -/** This class represents the multiple type maps of the NSEC - * record. Currently it is just used to convert the wire format type - * map to the int array that org.xbill.DNS.NSECRecord uses. */ +/** + * This class represents the multiple type maps of the NSEC record. Currently + * it is just used to convert the wire format type map to the int array that + * org.xbill.DNS.NSECRecord uses. + */ public class TypeMap { private static final Integer[] integerArray = new Integer[0]; - private Set typeSet; - + private Set typeSet; + public TypeMap() { this.typeSet = new HashSet(); @@ -41,7 +45,6 @@ public class TypeMap { return typeSet.contains(new Integer(type)); } - public static TypeMap fromTypes(int[] types) { @@ -53,27 +56,29 @@ public class TypeMap return m; } - - /** Given an array of bytes representing a wire-format type map, - * construct the TypeMap object. */ + + /** + * Given an array of bytes representing a wire-format type map, construct + * the TypeMap object. + */ public static TypeMap fromBytes(byte[] map) { - int m = 0; + int m = 0; TypeMap typemap = new TypeMap(); - + int map_number; int byte_length; - + while (m < map.length) { - map_number = map[m++]; + map_number = 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 ) + if ((map[m + i] & (1 << (7 - j))) != 0) { typemap.set(map_number * 8 + j); } @@ -84,15 +89,15 @@ public class TypeMap return typemap; } - + /** @return the normal string representation of the typemap. */ public String toString() { int[] types = getTypes(); Arrays.sort(types); - + StringBuffer sb = new StringBuffer(); - + for (int i = 0; i < types.length; i++) { sb.append(" "); @@ -102,8 +107,8 @@ public class TypeMap 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. @@ -121,7 +126,7 @@ public class TypeMap // for each type in our sub-array, set its corresponding bit in the map. for (int i = start; i < end; i++) { - map[ (types[i] & 0xFF) / 8 ] |= ( 1 << (7 - types[i] % 8) ); + map[(types[i] & 0xFF) / 8] |= (1 << (7 - types[i] % 8)); } // write out the resulting binary bitmap. for (int i = 0; i < map.length; i++) @@ -129,7 +134,7 @@ public class TypeMap out.writeU8(map[i]); } } - + public byte[] toWire() { int[] types = getTypes(); @@ -140,7 +145,7 @@ public class TypeMap int mapstart = -1; DNSOutput out = new DNSOutput(); - + for (int i = 0; i < types.length; i++) { int base = types[i] >> 8; @@ -156,13 +161,14 @@ public class TypeMap return out.toByteArray(); } - + 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(); } @@ -178,5 +184,5 @@ public class TypeMap { return TypeMap.fromTypes(types).toWire(); } - + } diff --git a/src/com/verisignlabs/dnssec/security/ZoneUtils.java b/src/com/verisignlabs/dnssec/security/ZoneUtils.java index 12338a6..30810ea 100644 --- a/src/com/verisignlabs/dnssec/security/ZoneUtils.java +++ b/src/com/verisignlabs/dnssec/security/ZoneUtils.java @@ -1,4 +1,4 @@ -// $Id: ZoneUtils.java,v 1.3 2004/01/15 17:32:18 davidb Exp $ +// $Id$ // // Copyright (C) 2003 VeriSign, Inc. // @@ -19,51 +19,50 @@ package com.verisignlabs.dnssec.security; -import java.util.*; -import java.io.*; +import java.io.BufferedWriter; +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.*; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.xbill.DNS.Master; +import org.xbill.DNS.Name; +import org.xbill.DNS.RRset; +import org.xbill.DNS.Record; +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: davidb $ - * @version $Revision: 1.3 $ +/** + * This class contains a bunch of utility methods that are generally useful in + * manipulating zones. + * + * @author David Blacka (original) + * @author $Author$ + * @version $Revision$ */ public class ZoneUtils { - - private static Log log; - - static { - log = LogFactory.getLog(ZoneUtils.class); - } - - /** Load a zone file. - * - * @param zonefile 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). - * @return a {@link java.util.List} of {@link org.xbill.DNS.Record} - * objects. - * @throws IOException if something goes wrong reading the zone - * file. + /** + * Load a zone file. + * + * @param zonefile 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). + * @return a {@link java.util.List} of {@link org.xbill.DNS.Record} objects. + * @throws IOException if something goes wrong reading the zone file. */ public static List readZoneFile(String zonefile, Name origin) - throws IOException + throws IOException { ArrayList records = new ArrayList(); Master m = new Master(zonefile, origin); Record r = null; - while ( (r = m.nextRecord()) != null ) + while ((r = m.nextRecord()) != null) { records.add(r); } @@ -71,15 +70,16 @@ public class ZoneUtils return records; } - /** 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. - * @param zonefile the file to write to. If null or equal to "-", - * System.out is used. + /** + * 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. + * @param zonefile the file to write to. If null or equal to "-", System.out + * is used. */ public static void writeZoneFile(List records, String zonefile) - throws IOException + throws IOException { PrintWriter out = null; @@ -92,8 +92,7 @@ public class ZoneUtils out = new PrintWriter(new BufferedWriter(new FileWriter(zonefile))); } - - for (Iterator i = records.iterator(); i.hasNext(); ) + for (Iterator i = records.iterator(); i.hasNext();) { out.println(i.next()); } @@ -101,38 +100,38 @@ public class ZoneUtils out.close(); } - /** Given just the list of records, determine the zone name - * (origin). - * - * @param records a list of {@link org.xbill.DNS.Record} or {@link - * org.xbill.DNS.RRset} objects. - * @return the zone name, if found. null if one couldn't be found.q + /** + * Given just the list of records, determine the zone name (origin). + * + * @param records a list of {@link org.xbill.DNS.Record} or {@link + * org.xbill.DNS.RRset} objects. + * @return the zone name, if found. null if one couldn't be found.q */ public static Name findZoneName(List records) { - for (Iterator i = records.iterator(); i.hasNext(); ) + for (Iterator i = records.iterator(); i.hasNext();) { - int type = 0; - Name n = null; - + int type = 0; + Name n = null; + Object o = i.next(); - + if (o instanceof Record) { - Record r = (Record) o; - type = r.getType(); - n = r.getName(); + Record r = (Record) o; + type = r.getType(); + n = r.getName(); } else if (o instanceof RRset) { - RRset r = (RRset) o; - type = r.getType(); - n = r.getName(); + RRset r = (RRset) o; + type = r.getType(); + n = r.getName(); } if (type == Type.SOA) return n; } - + return null; } }