update to dnsjava-2.0.0; refactor command line parseing a bit; switch to java.util.logging

git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@16 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
David Blacka 2005-08-14 02:08:48 +00:00
parent 0d5aed62b6
commit 4b84bbf4db
18 changed files with 1899 additions and 1860 deletions

View File

@ -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 "$@"

View File

@ -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 "$@"

Binary file not shown.

BIN
lib/dnsjava-2.0.0.jar Normal file

Binary file not shown.

Binary file not shown.

View File

@ -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. // Copyright (C) 2001-2003 VeriSign, Inc.
// //
@ -20,6 +20,8 @@
package com.verisignlabs.dnssec.cl; package com.verisignlabs.dnssec.cl;
import java.util.*; import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.*; import java.io.*;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.text.ParseException; import java.text.ParseException;
@ -32,24 +34,24 @@ import com.verisignlabs.dnssec.security.*;
import org.apache.commons.cli.*; import org.apache.commons.cli.*;
import org.apache.commons.cli.Options; 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
/** This class forms the command line implementation of a DNSSEC key
* generator
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author$
* @version $Revision: 1.2 $ * @version $Revision$
*/ */
public class KeyGen public class KeyGen
{ {
private static Log log; private static Logger log;
/** This is a small inner class used to hold all of the command line /**
* option state. */ * This is a small inner class used to hold all of the command line option
* state.
*/
private static class CLIState private static class CLIState
{ {
private Options opts;
public int algorithm = 5; public int algorithm = 5;
public int keylength = 1024; public int keylength = 1024;
public String outputfile = null; public String outputfile = null;
@ -59,37 +61,36 @@ public class KeyGen
public String owner = null; public String owner = null;
public long ttl = 86400; public long ttl = 86400;
public CLIState() { } public CLIState()
{
setupCLI();
}
public void parseCommandLine(Options opts, String[] args) public void parseCommandLine(String[] args)
throws org.apache.commons.cli.ParseException, ParseException, throws org.apache.commons.cli.ParseException
IOException
{ {
CommandLineParser cli_parser = new PosixParser(); CommandLineParser cli_parser = new PosixParser();
CommandLine cli = cli_parser.parse(opts, args); CommandLine cli = cli_parser.parse(opts, args);
String optstr = null; String optstr = null;
if (cli.hasOption('h')) usage(opts); if (cli.hasOption('h')) usage();
if (cli.hasOption('v')) if (cli.hasOption('v'))
{ {
int value = parseInt(cli.getOptionValue('v'), 5); int value = parseInt(cli.getOptionValue('v'), 5);
Logger rootLogger = Logger.getLogger("");
switch (value) switch (value)
{ {
case 0: case 0 :
System.setProperty("org.apache.commons.logging.simplelog.defaultlog", rootLogger.setLevel(Level.OFF);
"fatal");
break; break;
case 5: case 5 :
default: default :
System.setProperty("org.apache.commons.logging.simplelog.defaultlog", rootLogger.setLevel(Level.FINE);
"debug");
break; break;
case 6: case 6 :
System.setProperty("org.apache.commons.logging.simplelog.defaultlog", rootLogger.setLevel(Level.ALL);
"trace");
break; break;
} }
} }
@ -105,7 +106,7 @@ public class KeyGen
if ((optstr = cli.getOptionValue('n')) != null) if ((optstr = cli.getOptionValue('n')) != null)
{ {
if (! optstr.equalsIgnoreCase("ZONE")) if (!optstr.equalsIgnoreCase("ZONE"))
{ {
zoneKey = false; zoneKey = false;
} }
@ -130,15 +131,94 @@ public class KeyGen
if (cl_args.length < 1) if (cl_args.length < 1)
{ {
System.err.println("error: missing key owner name"); System.err.println("error: missing key owner name");
usage(opts); usage();
} }
owner = cl_args[0]; 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'));
} }
/** This is just a convenience method for parsing integers from /** Print out the usage and help statements, then quit. */
* strings. 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 s the string to parse.
* @param def the default value, if the string doesn't parse. * @param def the default value, if the string doesn't parse.
@ -189,86 +269,12 @@ public class KeyGen
return DNSSEC.RSASHA1; return DNSSEC.RSASHA1;
} }
/** Set up the command line options. public static void execute(CLIState state) throws Exception
*
* @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
{ {
JCEDnsSecSigner signer = new JCEDnsSecSigner(); JCEDnsSecSigner signer = new JCEDnsSecSigner();
// Minor hack to make the owner name absolute. // Minor hack to make the owner name absolute.
if (! state.owner.endsWith(".")) if (!state.owner.endsWith("."))
{ {
state.owner = state.owner + "."; state.owner = state.owner + ".";
} }
@ -277,13 +283,12 @@ public class KeyGen
// Calculate our flags // Calculate our flags
int flags = 0; int flags = 0;
if (state.zoneKey) flags |= DNSKEYRecord.OWNER_ZONE; if (state.zoneKey) flags |= DNSKEYRecord.Flags.ZONE_KEY;
if (state.kskFlag) flags |= DNSKEYRecord.FLAG_SEP; if (state.kskFlag) flags |= DNSKEYRecord.Flags.SEP_KEY;
log.debug("create key pair with (name = " + owner_name + ", ttl = " +
state.ttl + ", alg = " + state.algorithm + ", flags = " +
flags + ", length = " + state.keylength + ")");
log.fine("create key pair with (name = " + owner_name + ", ttl = "
+ state.ttl + ", alg = " + state.algorithm + ", flags = " + flags
+ ", length = " + state.keylength + ")");
DnsKeyPair pair = signer.generateKey(owner_name, DnsKeyPair pair = signer.generateKey(owner_name,
state.ttl, state.ttl,
@ -304,45 +309,36 @@ public class KeyGen
public static void main(String[] args) 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 try
{ {
state.parseCommandLine(opts, args); state.parseCommandLine(args);
} }
catch (UnrecognizedOptionException e) catch (UnrecognizedOptionException e)
{ {
System.err.println("error: unknown option encountered: " + System.err.println("error: unknown option encountered: "
e.getMessage()); + e.getMessage());
usage(opts); state.usage();
} }
catch (AlreadySelectedException e) catch (AlreadySelectedException e)
{ {
System.err.println("error: mutually exclusive options have " + System.err.println("error: mutually exclusive options have "
"been selected:\n " + e.getMessage()); + "been selected:\n " + e.getMessage());
usage(opts); state.usage();
} }
catch (Exception e) catch (Exception e)
{ {
System.err.println("error: unknown command line parsing exception:"); System.err.println("error: unknown command line parsing exception:");
e.printStackTrace(); e.printStackTrace();
usage(opts); state.usage();
} }
log = LogFactory.getLog(KeyGen.class); log = Logger.getLogger(KeyGen.class.toString());
try try
{ {
execute(state, opts); execute(state);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -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. // Copyright (C) 2001-2003 VeriSign, Inc.
// //
@ -19,37 +19,56 @@
package com.verisignlabs.dnssec.cl; package com.verisignlabs.dnssec.cl;
import java.util.*; import java.io.BufferedReader;
import java.io.*; import java.io.File;
import java.text.SimpleDateFormat; import java.io.FileFilter;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.ParseException; import java.text.ParseException;
import java.security.GeneralSecurityException; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import org.xbill.DNS.*; import java.util.Date;
import java.util.Iterator;
import com.verisignlabs.dnssec.security.*; 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.*;
import org.apache.commons.cli.Options;
import org.apache.commons.logging.Log; import org.xbill.DNS.DNSKEYRecord;
import org.apache.commons.logging.LogFactory; 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 import com.verisignlabs.dnssec.security.BINDKeyUtils;
* signer. 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 David Blacka (original)
* @author $Author: davidb $ * @author $Author$
* @version $Revision: 1.4 $ * @version $Revision$
*/ */
public class SignZone public class SignZone
{ {
private static Log log; private static Logger log;
/** This is a small inner class used to hold all of the command line /**
* option state. */ * This is a small inner class used to hold all of the command line option
* state.
*/
private static class CLIState private static class CLIState
{ {
private Options opts;
private File keyDirectory = null; private File keyDirectory = null;
public File keysetDirectory = null; public File keysetDirectory = null;
public String[] kskFiles = null; public String[] kskFiles = null;
@ -65,9 +84,12 @@ public class SignZone
public boolean fullySignKeyset = false; public boolean fullySignKeyset = false;
public List includeNames = null; public List includeNames = null;
public CLIState() { } public CLIState()
{
setupCLI();
}
public void parseCommandLine(Options opts, String[] args) public void parseCommandLine(String[] args)
throws org.apache.commons.cli.ParseException, ParseException, throws org.apache.commons.cli.ParseException, ParseException,
IOException IOException
{ {
@ -76,26 +98,24 @@ public class SignZone
String optstr = null; String optstr = null;
if (cli.hasOption('h')) usage(opts); if (cli.hasOption('h')) usage();
if (cli.hasOption('v')) if (cli.hasOption('v'))
{ {
int value = parseInt(cli.getOptionValue('v'), 5); int value = parseInt(cli.getOptionValue('v'), 5);
Logger rootLogger = Logger.getLogger("");
switch (value) switch (value)
{ {
case 0: case 0 :
System.setProperty("org.apache.commons.logging.simplelog.defaultlog", rootLogger.setLevel(Level.OFF);
"fatal");
break; break;
case 5: case 5 :
default: default :
System.setProperty("org.apache.commons.logging.simplelog.defaultlog", rootLogger.setLevel(Level.FINE);
"debug");
break; break;
case 6: case 6 :
System.setProperty("org.apache.commons.logging.simplelog.defaultlog", rootLogger.setLevel(Level.ALL);
"trace");
break; break;
} }
} }
@ -113,10 +133,10 @@ public class SignZone
if ((optstr = cli.getOptionValue('d')) != null) if ((optstr = cli.getOptionValue('d')) != null)
{ {
keysetDirectory = new File(optstr); keysetDirectory = new File(optstr);
if (! keysetDirectory.isDirectory()) if (!keysetDirectory.isDirectory())
{ {
System.err.println("error: " + optstr + " is not a directory"); System.err.println("error: " + optstr + " is not a directory");
usage(opts); usage();
} }
} }
@ -124,10 +144,10 @@ public class SignZone
if ((optstr = cli.getOptionValue('D')) != null) if ((optstr = cli.getOptionValue('D')) != null)
{ {
keyDirectory = new File(optstr); keyDirectory = new File(optstr);
if (! keyDirectory.isDirectory()) if (!keyDirectory.isDirectory())
{ {
System.err.println("error: " + optstr + " is not a directory"); System.err.println("error: " + optstr + " is not a directory");
usage(opts); usage();
} }
} }
@ -165,17 +185,121 @@ public class SignZone
if (files.length < 2) if (files.length < 2)
{ {
System.err.println("error: missing zone file and/or key files"); System.err.println("error: missing zone file and/or key files");
usage(opts); usage();
} }
zonefile = files[0]; zonefile = files[0];
keyFiles = new String[files.length - 1]; keyFiles = new String[files.length - 1];
System.arraycopy(files, 1, keyFiles, 0, files.length - 1); System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
} }
/**
* Set up the command line options.
*
* @return a set of command line options.
*/
private void setupCLI()
{
opts = new Options();
// boolean options
opts.addOption("h", "help", false, "Print this message.");
opts.addOption("a", false, "verify generated signatures>");
opts.addOption("F",
"fully-sign-keyset",
false,
"sign the zone apex keyset with all "
+ "available keys, instead of just key-signing-keys.");
// Opt-In generation switches
OptionGroup opt_in_opts = new OptionGroup();
opt_in_opts.addOption(new Option("O", "generate a fully Opt-In zone."));
opt_in_opts.addOption(new Option("C",
"generate a conservative Opt-In zone."));
opts.addOptionGroup(opt_in_opts);
// Argument options
OptionBuilder.hasOptionalArg();
OptionBuilder.withLongOpt("verbose");
OptionBuilder.withArgName("level");
OptionBuilder.withDescription("verbosity level -- 0 is silence, "
+ "5 is debug information, "
+ "6 is trace information. "
+ "No argument means 5.");
opts.addOption(OptionBuilder.create('v'));
OptionBuilder.hasArg();
OptionBuilder.withArgName("dir");
OptionBuilder.withLongOpt("keyset-directory");
OptionBuilder.withDescription("directory to find keyset files (default '.').");
opts.addOption(OptionBuilder.create('d'));
OptionBuilder.hasArg();
OptionBuilder.withArgName("dir");
OptionBuilder.withLongOpt("key-directory");
OptionBuilder.withDescription("directory to find key files (default '.').");
opts.addOption(OptionBuilder.create('D'));
OptionBuilder.hasArg();
OptionBuilder.withArgName("time/offset");
OptionBuilder.withLongOpt("start-time");
OptionBuilder.withDescription("signature starting time (default is now - 1 hour)");
opts.addOption(OptionBuilder.create('s'));
OptionBuilder.hasArg();
OptionBuilder.withArgName("time/offset");
OptionBuilder.withLongOpt("expire-time");
OptionBuilder.withDescription("signature expiration time (default is "
+ "start-time + 30 days");
opts.addOption(OptionBuilder.create('e'));
OptionBuilder.hasArg();
OptionBuilder.withArgName("outfile");
OptionBuilder.withDescription("file the signed zone is written "
+ "to (default is <origin>.signed).");
opts.addOption(OptionBuilder.create('f'));
OptionBuilder.hasArgs();
OptionBuilder.withArgName("KSK file");
OptionBuilder.withLongOpt("ksk-file");
OptionBuilder.withDescription("this key is a key signing key "
+ "(may repeat)");
opts.addOption(OptionBuilder.create('k'));
OptionBuilder.hasArg();
OptionBuilder.withArgName("file");
OptionBuilder.withLongOpt("include-file");
OptionBuilder.withDescription("include names in this file "
+ "in the NSEC chain");
opts.addOption(OptionBuilder.create('I'));
} }
/** This is just a convenience method for parsing integers from /** Print out the usage and help statements, then quit. */
* strings. 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 s the string to parse.
* @param def the default value, if the string doesn't parse. * @param def the default value, if the string doesn't parse.
@ -194,7 +318,8 @@ public class SignZone
} }
} }
/** Verify the generated signatures. /**
* Verify the generated signatures.
* *
* @param zonename the origin name of the zone. * @param zonename the origin name of the zone.
* @param records a list of {@link org.xbill.DNS.Record}s. * @param records a list of {@link org.xbill.DNS.Record}s.
@ -208,7 +333,7 @@ public class SignZone
DnsSecVerifier verifier = new DnsSecVerifier(); DnsSecVerifier verifier = new DnsSecVerifier();
for (Iterator i = keypairs.iterator(); i.hasNext(); ) for (Iterator i = keypairs.iterator(); i.hasNext();)
{ {
verifier.addTrustedKey((DnsKeyPair) i.next()); verifier.addTrustedKey((DnsKeyPair) i.next());
} }
@ -217,19 +342,19 @@ public class SignZone
List rrsets = SignUtils.assembleIntoRRsets(records); List rrsets = SignUtils.assembleIntoRRsets(records);
for (Iterator i = rrsets.iterator(); i.hasNext(); ) for (Iterator i = rrsets.iterator(); i.hasNext();)
{ {
RRset rrset = (RRset) i.next(); RRset rrset = (RRset) i.next();
// skip unsigned rrsets. // skip unsigned rrsets.
if (!rrset.sigs().hasNext()) continue; if (!rrset.sigs().hasNext()) continue;
byte result = verifier.verify(rrset, null); int result = verifier.verify(rrset, null);
if (result != DNSSEC.Secure) if (result != DNSSEC.Secure)
{ {
log.debug("Signatures did not verify for RRset: (" + result + "): " + log.fine("Signatures did not verify for RRset: (" + result + "): "
rrset); + rrset);
secure = false; secure = false;
} }
} }
@ -237,19 +362,18 @@ public class SignZone
return secure; return secure;
} }
/** Load the key pairs from the key files. /**
* Load the key pairs from the key files.
* *
* @param keyfiles a string array containing the base names or * @param keyfiles a string array containing the base names or paths of the
* paths of the keys to be loaded. * keys to be loaded.
* @param start_index the starting index of keyfiles string array * @param start_index the starting index of keyfiles string array to use.
* to use. This allows us to use the straight command line * This allows us to use the straight command line argument array.
* argument array.
* @param inDirectory the directory to look in (may be null). * @param inDirectory the directory to look in (may be null).
* @return a list of keypair objects. * @return a list of keypair objects.
*/ */
private static List getKeys(String[] keyfiles, int start_index, private static List getKeys(String[] keyfiles, int start_index,
File inDirectory) File inDirectory) throws IOException
throws IOException
{ {
if (keyfiles == null) return null; if (keyfiles == null) return null;
@ -267,52 +391,31 @@ public class SignZone
return keys; return keys;
} }
/** Load a single key from a given keyfile. /**
* * This is an implementation of a file filter used for finding BIND 9-style
* @param keyfile the keyfile. * keyset-* files.
* @param inDirectory the default directory to look in (may be
* null).
* @return a list containing one or zero keypair objects.
*/ */
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 private static class KeysetFileFilter implements FileFilter
{ {
public boolean accept(File pathname) public boolean accept(File pathname)
{ {
if (! pathname.isFile()) return false; if (!pathname.isFile()) return false;
String name = pathname.getName(); String name = pathname.getName();
if (name.startsWith("keyset-")) return true; if (name.startsWith("keyset-")) return true;
return false; return false;
} }
} }
/** Load keysets (which contain delegation point security info). /**
* Load keysets (which contain delegation point security info).
* *
* @param inDirectory the directory to look for the keyset files * @param inDirectory the directory to look for the keyset files (may be
* (may be null, in which case it defaults to looking in the * null, in which case it defaults to looking in the current
* current working directory). * working directory).
* @param zonename the name of the zone we are signing, so we can * @param zonename the name of the zone we are signing, so we can ignore
* ignore keysets that do not belong in the zone. * keysets that do not belong in the zone.
* @return a list of {@link org.xbill.DNS.Record}s found in the * @return a list of {@link org.xbill.DNS.Record}s found in the keyset
* keyset files. * files.
*/ */
private static List getKeysets(File inDirectory, Name zonename) private static List getKeysets(File inDirectory, Name zonename)
throws IOException throws IOException
@ -336,7 +439,7 @@ public class SignZone
} }
// discard records that do not belong to the zone in question. // 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(); Record r = (Record) i.next();
if (!r.getName().subdomain(zonename)) if (!r.getName().subdomain(zonename))
@ -348,20 +451,20 @@ public class SignZone
return keysetRecords; return keysetRecords;
} }
/** Load a list of DNS names from a file. /**
* Load a list of DNS names from a file.
* *
* @param nameListFile the path of a file containing a bare list of * @param nameListFile the path of a file containing a bare list of DNS
* DNS names. * names.
* @return a list of {@link org.xbill.DNS.Name} objects. * @return a list of {@link org.xbill.DNS.Name} objects.
*/ */
private static List getNameList(File nameListFile) private static List getNameList(File nameListFile) throws IOException
throws IOException
{ {
BufferedReader br = new BufferedReader(new FileReader(nameListFile)); BufferedReader br = new BufferedReader(new FileReader(nameListFile));
List res = new ArrayList(); List res = new ArrayList();
String line = null; String line = null;
while ( (line = br.readLine()) != null ) while ((line = br.readLine()) != null)
{ {
try try
{ {
@ -370,13 +473,13 @@ public class SignZone
// FIXME: we should probably get some fancy logic here to // FIXME: we should probably get some fancy logic here to
// detect if the name needs the origin appended, or just the // detect if the name needs the origin appended, or just the
// root. // root.
if (! n.isAbsolute()) n = Name.concatenate(n, Name.root); if (!n.isAbsolute()) n = Name.concatenate(n, Name.root);
res.add(n); res.add(n);
} }
catch (TextParseException e) catch (TextParseException e)
{ {
log.error("DNS Name parsing error", e); log.severe("DNS Name parsing error:" + e);
} }
} }
@ -384,7 +487,8 @@ public class SignZone
return res; return res;
} }
/** Calculate a date/time from a command line time/offset duration string. /**
* Calculate a date/time from a command line time/offset duration string.
* *
* @param start the start time to calculate offsets from. * @param start the start time to calculate offsets from.
* @param duration the time/offset string to parse. * @param duration the time/offset string to parse.
@ -413,17 +517,19 @@ public class SignZone
return dateFormatter.parse(duration); return dateFormatter.parse(duration);
} }
/** Determine if the given keypairs can be used to sign the zone. /**
* Determine if the given keypairs can be used to sign the zone.
*
* @param zonename the zone origin. * @param zonename the zone origin.
* @param keypairs a list of {@link DnsKeyPair} objects that will * @param keypairs a list of {@link DnsKeyPair} objects that will be used to
* be used to sign the zone. * sign the zone.
* @return true if the keypairs valid. * @return true if the keypairs valid.
*/ */
private static boolean keyPairsValidForZone(Name zonename, List keypairs) private static boolean keyPairsValidForZone(Name zonename, List keypairs)
{ {
if (keypairs == null) return true; // technically true, I guess. 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(); DnsKeyPair kp = (DnsKeyPair) i.next();
Name keyname = kp.getDNSKEYRecord().getName(); Name keyname = kp.getDNSKEYRecord().getName();
@ -436,103 +542,8 @@ public class SignZone
return true; 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 public static void execute(CLIState state) throws Exception
options.addOption("h", "help", false, "Print this message.");
options.addOption("a", false, "verify generated signatures>");
options.addOption("F", "fully-sign-keyset", false,
"sign the zone apex keyset with all " +
"available keys, instead of just key-signing-keys.");
// Opt-In generation switches
OptionGroup opt_in_opts = new OptionGroup();
opt_in_opts.addOption(new Option
("O", "generate a fully Opt-In zone."));
opt_in_opts.addOption(new Option
("C", "generate a conservative Opt-In zone."));
options.addOptionGroup(opt_in_opts);
// Argument options
options.addOption(OptionBuilder.hasOptionalArg()
.withArgName("level")
.withDescription("verbosity level -- 0 is silence, " +
"5 is debug information, " +
"6 is trace information. " +
"No argument means 5.")
.create('v'));
options.addOption(OptionBuilder.hasArg()
.withArgName("dir")
.withLongOpt("keyset-directory")
.withDescription
("directory to find keyset files (default '.').")
.create('d'));
options.addOption(OptionBuilder.hasArg()
.withArgName("dir")
.withLongOpt("key-directory")
.withDescription
("directory to find key files (default '.').")
.create('D'));
options.addOption(OptionBuilder.hasArg()
.withArgName("time/offset")
.withLongOpt("start-time")
.withDescription
("signature starting time (default is now - 1 hour)")
.create('s'));
options.addOption(OptionBuilder.hasArg()
.withArgName("time/offset")
.withLongOpt("expire-time")
.withDescription
("signature expiration time (default is " +
"start-time + 30 days")
.create('e'));
options.addOption(OptionBuilder.hasArg()
.withArgName("outfile")
.withDescription("file the signed zone is written " +
"to (default is <origin>.signed).")
.create('f'));
options.addOption(OptionBuilder.hasArgs()
.withArgName("KSK file")
.withLongOpt("ksk-file")
.withDescription("this key is a key signing key " +
"(may repeat)")
.create('k'));
options.addOption(OptionBuilder.hasArg()
.withArgName("file")
.withLongOpt("include-file")
.withDescription("include names in this file " +
"in the NSEC chain")
.create('I'));
return options;
}
/** Print out the usage and help statements, then quit. */
private static void usage(Options opts)
{
HelpFormatter f = new HelpFormatter();
PrintWriter out = new PrintWriter(System.err);
// print our own usage statement:
out.println("usage: signZone.sh [..options..] zone_file [key_file ...] ");
f.printHelp(out, 75, "signZone.sh", null, opts,
HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD,
"\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
out.flush();
System.exit(64);
}
public static void execute(CLIState state, Options opts)
throws Exception
{ {
// Load the key pairs. // Load the key pairs.
@ -547,14 +558,14 @@ public class SignZone
// signing key (presumably), presume that the zone signing keys // signing key (presumably), presume that the zone signing keys
// are just not differentiated and try to figure out which keys // are just not differentiated and try to figure out which keys
// are actually ksks by looking at the SEP flag. // are actually ksks by looking at the SEP flag.
if ( (kskpairs == null || kskpairs.size() == 0) && if ((kskpairs == null || kskpairs.size() == 0) && keypairs != null
keypairs != null && keypairs.size() > 1) && keypairs.size() > 1)
{ {
for (Iterator i = keypairs.iterator(); i.hasNext(); ) for (Iterator i = keypairs.iterator(); i.hasNext();)
{ {
DnsKeyPair pair = (DnsKeyPair) i.next(); DnsKeyPair pair = (DnsKeyPair) i.next();
DNSKEYRecord kr = pair.getDNSKEYRecord(); 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(); if (kskpairs == null) kskpairs = new ArrayList();
kskpairs.add(pair); kskpairs.add(pair);
@ -568,7 +579,7 @@ public class SignZone
if (records == null || records.size() == 0) if (records == null || records.size() == 0)
{ {
System.err.println("error: empty zone file"); System.err.println("error: empty zone file");
usage(opts); state.usage();
} }
// calculate the zone name. // calculate the zone name.
@ -576,7 +587,7 @@ public class SignZone
if (zonename == null) if (zonename == null)
{ {
System.err.println("error: invalid zone file - no SOA"); System.err.println("error: invalid zone file - no SOA");
usage(opts); state.usage();
} }
// default the output file, if not set. // default the output file, if not set.
@ -593,12 +604,10 @@ public class SignZone
} }
// Verify that the keys can be in the zone. // Verify that the keys can be in the zone.
List kpairs = keypairs; if (!keyPairsValidForZone(zonename, keypairs)
|| !keyPairsValidForZone(zonename, kskpairs))
if (!keyPairsValidForZone(zonename, keypairs) ||
!keyPairsValidForZone(zonename, kskpairs))
{ {
usage(opts); state.usage();
} }
// We force the signing keys to be in the zone by just appending // We force the signing keys to be in the zone by just appending
@ -606,16 +615,16 @@ public class SignZone
// removes duplicate records. // removes duplicate records.
if (kskpairs != null) 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) 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());
} }
} }
@ -653,7 +662,7 @@ public class SignZone
keypairs.addAll(kskpairs); keypairs.addAll(kskpairs);
} }
log.debug("verifying generated signatures"); log.fine("verifying generated signatures");
boolean res = verifyZoneSigs(zonename, signed_records, keypairs); boolean res = verifyZoneSigs(zonename, signed_records, keypairs);
if (res) if (res)
@ -672,44 +681,35 @@ public class SignZone
public static void main(String[] args) 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 try
{ {
state.parseCommandLine(opts, args); state.parseCommandLine(args);
} }
catch (UnrecognizedOptionException e) catch (UnrecognizedOptionException e)
{ {
System.err.println("error: unknown option encountered: " + System.err.println("error: unknown option encountered: "
e.getMessage()); + e.getMessage());
usage(opts); state.usage();
} }
catch (AlreadySelectedException e) catch (AlreadySelectedException e)
{ {
System.err.println("error: mutually exclusive options have " + System.err.println("error: mutually exclusive options have "
"been selected:\n " + e.getMessage()); + "been selected:\n " + e.getMessage());
usage(opts); state.usage();
} }
catch (Exception e) catch (Exception e)
{ {
System.err.println("error: unknown command line parsing exception:"); System.err.println("error: unknown command line parsing exception:");
e.printStackTrace(); e.printStackTrace();
usage(opts); state.usage();
} }
log = LogFactory.getLog(SignZone.class); log = Logger.getLogger(SignZone.class.toString());
try try
{ {
execute(state, opts); execute(state);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -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. // Copyright (C) 2001-2003 VeriSign, Inc.
// //
@ -19,73 +19,82 @@
package com.verisignlabs.dnssec.cl; package com.verisignlabs.dnssec.cl;
import java.util.*; import java.io.File;
import java.io.*; import java.io.IOException;
import java.text.SimpleDateFormat; import java.io.PrintWriter;
import java.text.ParseException; import java.util.ArrayList;
import java.security.GeneralSecurityException; import java.util.Collections;
import java.util.Iterator;
import org.xbill.DNS.*; import java.util.List;
import java.util.logging.Level;
import com.verisignlabs.dnssec.security.*; import java.util.logging.Logger;
import org.apache.commons.cli.*; 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 com.verisignlabs.dnssec.security.BINDKeyUtils;
import org.apache.commons.logging.LogFactory; 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 /**
* This class forms the command line implementation of a DNSSEC zone
* validator. * validator.
*
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author$
* @version $Revision: 1.1 $ * @version $Revision$
*/ */
public class VerifyZone public class VerifyZone
{ {
private static Log log; private static Logger log;
/** This is a small inner class used to hold all of the command line /**
* option state. */ * This is a small inner class used to hold all of the command line option
* state.
*/
private static class CLIState private static class CLIState
{ {
private Options opts;
public boolean strict = false; public boolean strict = false;
public File keydir = null; public File keydir = null;
public String zonefile = null; public String zonefile = null;
public String[] keyfiles = null; public String[] keyfiles = null;
public CLIState() { } public CLIState()
{
setupCLI();
}
public void parseCommandLine(Options opts, String[] args) public void parseCommandLine(String[] args)
throws org.apache.commons.cli.ParseException, ParseException, throws org.apache.commons.cli.ParseException
IOException
{ {
CommandLineParser cli_parser = new PosixParser(); CommandLineParser cli_parser = new PosixParser();
CommandLine cli = cli_parser.parse(opts, args); CommandLine cli = cli_parser.parse(opts, args);
String optstr = null; String optstr = null;
if (cli.hasOption('h')) usage(opts); if (cli.hasOption('h')) usage();
if (cli.hasOption('v')) if (cli.hasOption('v'))
{ {
int value = parseInt(cli.getOptionValue('v'), 5); int value = parseInt(cli.getOptionValue('v'), 5);
Logger rootLogger = Logger.getLogger("");
switch (value) switch (value)
{ {
case 0: case 0 :
System.setProperty("org.apache.commons.logging.simplelog.defaultlog", rootLogger.setLevel(Level.OFF);
"fatal");
break; break;
case 5: case 5 :
default: default :
System.setProperty("org.apache.commons.logging.simplelog.defaultlog", rootLogger.setLevel(Level.FINE);
"debug");
break; break;
case 6: case 6 :
System.setProperty("org.apache.commons.logging.simplelog.defaultlog", rootLogger.setLevel(Level.ALL);
"trace");
break; break;
} }
} }
@ -97,13 +106,12 @@ public class VerifyZone
keydir = new File(optstr); keydir = new File(optstr);
} }
String[] cl_args = cli.getArgs(); String[] cl_args = cli.getArgs();
if (cl_args.length < 1) if (cl_args.length < 1)
{ {
System.err.println("error: missing zone file"); System.err.println("error: missing zone file");
usage(opts); usage();
} }
zonefile = cl_args[0]; zonefile = cl_args[0];
@ -111,16 +119,71 @@ public class VerifyZone
if (cl_args.length < 2) if (cl_args.length < 2)
{ {
System.err.println("error: at least one trusted key is required"); System.err.println("error: at least one trusted key is required");
usage(opts); usage();
} }
keyfiles = new String[cl_args.length - 1]; keyfiles = new String[cl_args.length - 1];
System.arraycopy(cl_args, 1, keyfiles, 0, keyfiles.length); System.arraycopy(cl_args, 1, keyfiles, 0, keyfiles.length);
} }
/**
* 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("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'));
} }
/** This is just a convenience method for parsing integers from /** Print out the usage and help statements, then quit. */
* strings. public void usage()
{
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 s the string to parse.
* @param def the default value, if the string doesn't parse. * @param def the default value, if the string doesn't parse.
@ -139,58 +202,8 @@ public class VerifyZone
} }
} }
/** 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) private static byte verifyZoneSignatures(List records, List keypairs)
{ {
// Zone is secure until proven otherwise. // Zone is secure until proven otherwise.
@ -198,25 +211,25 @@ public class VerifyZone
DnsSecVerifier verifier = new DnsSecVerifier(); DnsSecVerifier verifier = new DnsSecVerifier();
for (Iterator i = keypairs.iterator(); i.hasNext(); ) for (Iterator i = keypairs.iterator(); i.hasNext();)
{ {
verifier.addTrustedKey((DnsKeyPair) i.next()); verifier.addTrustedKey((DnsKeyPair) i.next());
} }
List rrsets = SignUtils.assembleIntoRRsets(records); List rrsets = SignUtils.assembleIntoRRsets(records);
for (Iterator i = rrsets.iterator(); i.hasNext(); ) for (Iterator i = rrsets.iterator(); i.hasNext();)
{ {
RRset rrset = (RRset) i.next(); RRset rrset = (RRset) i.next();
// We verify each signature separately so that we can report // We verify each signature separately so that we can report
// which exact signature failed. // which exact signature failed.
for (Iterator j = rrset.sigs(); j.hasNext(); ) for (Iterator j = rrset.sigs(); j.hasNext();)
{ {
Object o = j.next(); 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; continue;
} }
RRSIGRecord sigrec = (RRSIGRecord) o; RRSIGRecord sigrec = (RRSIGRecord) o;
@ -224,7 +237,8 @@ public class VerifyZone
byte res = verifier.verifySignature(rrset, sigrec, null); byte res = verifier.verifySignature(rrset, sigrec, null);
if (res != DNSSEC.Secure) 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; if (res < result) result = res;
} }
@ -249,8 +263,7 @@ public class VerifyZone
return keys; return keys;
} }
public static void execute(CLIState state, Options opts) public static void execute(CLIState state) throws Exception
throws Exception
{ {
List keypairs = getTrustedKeys(state.keyfiles, state.keydir); List keypairs = getTrustedKeys(state.keyfiles, state.keydir);
@ -258,23 +271,23 @@ public class VerifyZone
List records = ZoneUtils.readZoneFile(state.zonefile, null); List records = ZoneUtils.readZoneFile(state.zonefile, null);
Collections.sort(records, new RecordComparator()); Collections.sort(records, new RecordComparator());
log.debug("verifying signatures..."); log.fine("verifying signatures...");
byte result = verifyZoneSignatures(records, keypairs); byte result = verifyZoneSignatures(records, keypairs);
log.debug("completed verification process."); log.fine("completed verification process.");
switch (result) switch (result)
{ {
case DNSSEC.Failed: case DNSSEC.Failed :
System.out.println("zone did not verify."); System.out.println("zone did not verify.");
System.exit(1); System.exit(1);
break; break;
case DNSSEC.Insecure: case DNSSEC.Insecure :
if (state.strict) if (state.strict)
{ {
System.out.println("zone did not verify."); System.out.println("zone did not verify.");
System.exit(1); System.exit(1);
} }
case DNSSEC.Secure: case DNSSEC.Secure :
System.out.println("zone verified."); System.out.println("zone verified.");
break; break;
} }
@ -283,45 +296,36 @@ public class VerifyZone
public static void main(String[] args) 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 try
{ {
state.parseCommandLine(opts, args); state.parseCommandLine(args);
} }
catch (UnrecognizedOptionException e) catch (UnrecognizedOptionException e)
{ {
System.err.println("error: unknown option encountered: " + System.err.println("error: unknown option encountered: "
e.getMessage()); + e.getMessage());
usage(opts); state.usage();
} }
catch (AlreadySelectedException e) catch (AlreadySelectedException e)
{ {
System.err.println("error: mutually exclusive options have " + System.err.println("error: mutually exclusive options have "
"been selected:\n " + e.getMessage()); + "been selected:\n " + e.getMessage());
usage(opts); state.usage();
} }
catch (Exception e) catch (Exception e)
{ {
System.err.println("error: unknown command line parsing exception:"); System.err.println("error: unknown command line parsing exception:");
e.printStackTrace(); e.printStackTrace();
usage(opts); state.usage();
} }
log = LogFactory.getLog(VerifyZone.class); log = Logger.getLogger(VerifyZone.class.toString());
try try
{ {
execute(state, opts); execute(state);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -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. // Copyright (C) 2001-2003 VeriSign, Inc.
// //
@ -19,22 +19,35 @@
package com.verisignlabs.dnssec.security; package com.verisignlabs.dnssec.security;
import java.io.*; import java.io.BufferedReader;
import java.security.*; 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 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; 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. * 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 * In this class, the "base" key path or name is the file name without the
* without the trailing ".key" or ".private". * trailing ".key" or ".private".
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author$
* @version $Revision: 1.5 $ * @version $Revision$
*/ */
public class BINDKeyUtils public class BINDKeyUtils
{ {
@ -42,10 +55,11 @@ public class BINDKeyUtils
private static NumberFormat mAlgNumberFormatter; private static NumberFormat mAlgNumberFormatter;
private static NumberFormat mKeyIdNumberFormatter; private static NumberFormat mKeyIdNumberFormatter;
/** Calculate the BIND9 key file base name (i.e., without the ".key" /**
* or ".private" extensions) */ * Calculate the BIND9 key file base name (i.e., without the ".key" or
private static String getKeyFileBase(Name signer, int algorithm, * ".private" extensions)
int keyid) */
private static String getKeyFileBase(Name signer, int algorithm, int keyid)
{ {
if (mAlgNumberFormatter == null) if (mAlgNumberFormatter == null)
{ {
@ -64,15 +78,13 @@ public class BINDKeyUtils
keyid &= 0xFFFF; keyid &= 0xFFFF;
String fn = "K" + signer + "+" + String fn = "K" + signer + "+" + mAlgNumberFormatter.format(algorithm)
mAlgNumberFormatter.format(algorithm) + + "+" + mKeyIdNumberFormatter.format(keyid);
"+" +
mKeyIdNumberFormatter.format(keyid);
return fn; 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) private static DNSKEYRecord loadPublicKeyFile(File publicKeyFile)
throws IOException throws IOException
{ {
@ -81,7 +93,7 @@ public class BINDKeyUtils
Record r; Record r;
DNSKEYRecord result = null; DNSKEYRecord result = null;
while ( (r = m.nextRecord()) != null ) while ((r = m.nextRecord()) != null)
{ {
if (r.getType() == Type.DNSKEY) if (r.getType() == Type.DNSKEY)
{ {
@ -101,7 +113,7 @@ public class BINDKeyUtils
String line; String line;
while ( (line = in.readLine()) != null) while ((line = in.readLine()) != null)
{ {
key_buf.append(line); key_buf.append(line);
key_buf.append('\n'); key_buf.append('\n');
@ -110,52 +122,51 @@ public class BINDKeyUtils
return key_buf.toString().trim(); 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) private static String fixKeyFileBasePath(String basePath)
{ {
if (basePath == null) throw new IllegalArgumentException(); if (basePath == null) throw new IllegalArgumentException();
if (basePath.endsWith(".key") || if (basePath.endsWith(".key") || basePath.endsWith(".private"))
basePath.endsWith(".private"))
{ {
basePath = basePath.substring basePath = basePath.substring(0, basePath.lastIndexOf("."));
(0, basePath.lastIndexOf("."));
} }
return basePath; return basePath;
} }
/** Given the information necessary to construct the path to a BIND9 /**
* Given the information necessary to construct the path to a BIND9
* generated key pair, load the key pair. * generated key pair, load the key pair.
* *
* @param signer the DNS name of the key. * @param signer the DNS name of the key.
* @param algorithm the DNSSEC algorithm of the key. * @param algorithm the DNSSEC algorithm of the key.
* @param keyid the DNSSEC key footprint. * @param keyid the DNSSEC key footprint.
* @param inDirectory the directory to look for the files (may be * @param inDirectory the directory to look for the files (may be null).
* null).
* @return the loaded key pair. * @return the loaded key pair.
* @throws IOException if there was a problem reading the BIND9 * @throws IOException if there was a problem reading the BIND9 files.
* files. */ */
public static DnsKeyPair loadKeyPair(Name signer, int algorithm, public static DnsKeyPair loadKeyPair(Name signer, int algorithm, int keyid,
int keyid, File inDirectory) File inDirectory) throws IOException
throws IOException
{ {
String keyFileBase = getKeyFileBase(signer, algorithm, keyid); String keyFileBase = getKeyFileBase(signer, algorithm, keyid);
return loadKeyPair(keyFileBase, inDirectory); return loadKeyPair(keyFileBase, inDirectory);
} }
/** Given a base path to a BIND9 key pair, load the key pair. /**
* Given a base path to a BIND9 key pair, load the key pair.
* *
* @param keyFileBasePath the base filename (or real filename for * @param keyFileBasePath the base filename (or real filename for either the
* either the public or private key) of the key. * public or private key) of the key.
* @param inDirectory the directory to look in, if the * @param inDirectory the directory to look in, if the keyFileBasePath is
* keyFileBasePath is relative. * relative.
* @return the loaded key pair. * @return the loaded key pair.
* @throws IOException if there was a problem reading the files */ * @throws IOException if there was a problem reading the files
*/
public static DnsKeyPair loadKeyPair(String keyFileBasePath, public static DnsKeyPair loadKeyPair(String keyFileBasePath,
File inDirectory) File inDirectory) throws IOException
throws IOException
{ {
keyFileBasePath = fixKeyFileBasePath(keyFileBasePath); keyFileBasePath = fixKeyFileBasePath(keyFileBasePath);
// FIXME: should we throw the IOException when one of the files // FIXME: should we throw the IOException when one of the files
@ -174,17 +185,16 @@ public class BINDKeyUtils
return kp; return kp;
} }
/** Given a base path to a BIND9 key pair, load the public part /**
* (only) of the key pair * 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 * @param keyFileBasePath the base or real path to the public part of a key
* of a key pair. * pair.
* @param inDirectory the directory to look in if the path is * @param inDirectory the directory to look in if the path is relative (may
* relative (may be null). * be null).
* @return a {@link DnsKeyPair} containing just the public key * @return a {@link DnsKeyPair} containing just the public key information.
* information. * @throws IOException if there was a problem reading the public key file.
* @throws IOException if there was a problem reading the public
* key file.
*/ */
public static DnsKeyPair loadKey(String keyFileBasePath, File inDirectory) public static DnsKeyPair loadKey(String keyFileBasePath, File inDirectory)
throws IOException throws IOException
@ -200,18 +210,16 @@ public class BINDKeyUtils
return kp; return kp;
} }
/** Load a BIND keyset file. The BIND 9 dnssec tools typically call /**
* these files "keyset-[signer]." where [signer] is the DNS owner * Load a BIND keyset file. The BIND 9 dnssec tools typically call these
* name of the key. The keyset may be signed, but doesn't have to * files "keyset-[signer]." where [signer] is the DNS owner name of the key.
* be. * The keyset may be signed, but doesn't have to be.
* *
* @param keysetFileName the name of the keyset file. * @param keysetFileName the name of the keyset file.
* @param inDirectory the directory to look in if the path is * @param inDirectory the directory to look in if the path is relative (may
* relative (may be null, defaults to the current working * be null, defaults to the current working directory).
* directory).
* @return a RRset contain the KEY records and any associated SIG records. * @return a RRset contain the KEY records and any associated SIG records.
* @throws IOException if there was a problem reading the keyset * @throws IOException if there was a problem reading the keyset file.
* file.
*/ */
public static RRset loadKeySet(String keysetFileName, File inDirectory) public static RRset loadKeySet(String keysetFileName, File inDirectory)
throws IOException throws IOException
@ -222,7 +230,7 @@ public class BINDKeyUtils
Record r; Record r;
RRset keyset = new RRset(); RRset keyset = new RRset();
while ( (r = m.nextRecord()) != null ) while ((r = m.nextRecord()) != null)
{ {
keyset.addRR(r); keyset.addRR(r);
} }
@ -230,7 +238,8 @@ public class BINDKeyUtils
return keyset; return keyset;
} }
/** Calculate the key file base for this key pair. /**
* Calculate the key file base for this key pair.
* *
* @param pair the {@link DnsKeyPair} to work from. It only needs a public * @param pair the {@link DnsKeyPair} to work from. It only needs a public
* key. * key.
@ -246,9 +255,10 @@ public class BINDKeyUtils
keyrec.getFootprint()); keyrec.getFootprint());
} }
/**
/** @return a {@link java.io.File} object representing the BIND9 * @return a {@link java.io.File} object representing the BIND9 public key
* public key file. */ * file.
*/
public static File getPublicKeyFile(DnsKeyPair pair, File inDirectory) public static File getPublicKeyFile(DnsKeyPair pair, File inDirectory)
{ {
String keyfilebase = keyFileBase(pair); String keyfilebase = keyFileBase(pair);
@ -257,8 +267,10 @@ public class BINDKeyUtils
return new File(inDirectory, keyfilebase + ".key"); 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) public static File getPrivateKeyFile(DnsKeyPair pair, File inDirectory)
{ {
String keyfilebase = keyFileBase(pair); String keyfilebase = keyFileBase(pair);
@ -267,10 +279,11 @@ public class BINDKeyUtils
return new File(inDirectory, keyfilebase + ".private"); 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. * Given a the contents of a BIND9 private key file, convert it into a
* @param privateKeyString the contents of a BIND9 key file in * native {@link java.security.PrivateKey} object.
* string form. *
* @param privateKeyString the contents of a BIND9 key file in string form.
* @return a {@link java.security.PrivateKey} * @return a {@link java.security.PrivateKey}
*/ */
public static PrivateKey convertPrivateKeyString(String privateKeyString) public static PrivateKey convertPrivateKeyString(String privateKeyString)
@ -296,13 +309,14 @@ public class BINDKeyUtils
return null; return null;
} }
/** Given a native private key, convert it into a BIND9 private key /**
* file format. * Given a native private key, convert it into a BIND9 private key file
* format.
*
* @param priv the private key to convert. * @param priv the private key to convert.
* @param pub the private key's corresponding public key. Some * @param pub the private key's corresponding public key. Some algorithms
* algorithms require information from both. * require information from both.
* @return a string containing the contents of a BIND9 private key * @return a string containing the contents of a BIND9 private key file.
* file.
*/ */
public static String convertPrivateKey(PrivateKey priv, PublicKey pub, public static String convertPrivateKey(PrivateKey priv, PublicKey pub,
int alg) int alg)
@ -312,8 +326,7 @@ public class BINDKeyUtils
// debug // debug
// System.out.println("converting from privatekey to bind9 string"); // System.out.println("converting from privatekey to bind9 string");
DnsKeyConverter keyconv = new DnsKeyConverter(); DnsKeyConverter keyconv = new DnsKeyConverter();
String priv_string String priv_string = keyconv.generatePrivateKeyString(priv, pub, alg);
= keyconv.generatePrivateKeyString(priv, pub, alg);
return priv_string; return priv_string;
} }
@ -321,11 +334,12 @@ public class BINDKeyUtils
return null; return null;
} }
/**
/** Convert the KEY record to the exact string format that the * Convert the KEY record to the exact string format that the dnssec-*
* dnssec-* routines need. Currently, the DNSJAVA package uses a * routines need. Currently, the DNSJAVA package uses a multiline mode for
* multiline mode for its record formatting. The BIND9 tools * its record formatting. The BIND9 tools require everything on a single
* require everything on a single line. */ * line.
*/
private static String DNSKEYtoString(DNSKEYRecord rec) private static String DNSKEYtoString(DNSKEYRecord rec)
{ {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
@ -343,25 +357,25 @@ public class BINDKeyUtils
return buf.toString(); return buf.toString();
} }
/** This routine will write out the BIND9 dnssec-* tool compatible /**
* files. * This routine will write out the BIND9 dnssec-* tool compatible files.
* *
* @param baseFileName use this base file name. If null, the * @param baseFileName use this base file name. If null, the standard BIND9
* standard BIND9 base file name will be computed. * base file name will be computed.
* @param pair the keypair in question. * @param pair the keypair in question.
* @param inDirectory the directory to write to (may be null). * @param inDirectory the directory to write to (may be null).
* @throws IOException if there is a problem writing the files. * @throws IOException if there is a problem writing the files.
*/ */
public static void writeKeyFiles(String baseFileName, DnsKeyPair pair, public static void writeKeyFiles(String baseFileName, DnsKeyPair pair,
File inDirectory) File inDirectory) throws IOException
throws IOException
{ {
DNSKEYRecord pub = pair.getDNSKEYRecord(); DNSKEYRecord pub = pair.getDNSKEYRecord();
String priv = pair.getPrivateKeyString(); String priv = pair.getPrivateKeyString();
if (priv == null) if (priv == null)
{ {
priv = convertPrivateKey(pair.getPrivate(), pair.getPublic(), priv = convertPrivateKey(pair.getPrivate(),
pair.getPublic(),
pair.getDNSKEYAlgorithm()); pair.getDNSKEYAlgorithm());
} }
@ -369,8 +383,7 @@ public class BINDKeyUtils
// Write the public key file // Write the public key file
File pubkeyfile = new File(inDirectory, baseFileName + ".key"); File pubkeyfile = new File(inDirectory, baseFileName + ".key");
PrintWriter out PrintWriter out = new PrintWriter(new FileWriter(pubkeyfile));
= new PrintWriter(new FileWriter(pubkeyfile));
out.println(DNSKEYtoString(pub)); out.println(DNSKEYtoString(pub));
out.close(); out.close();
@ -382,8 +395,9 @@ public class BINDKeyUtils
} }
/** This routine will write out the BIND9 dnssec-* tool compatible /**
* files to the standard file names. * This routine will write out the BIND9 dnssec-* tool compatible files to
* the standard file names.
* *
* @param pair the key pair in question. * @param pair the key pair in question.
* @param inDirectory the directory to write to (may be null). * @param inDirectory the directory to write to (may be null).

View File

@ -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. // Copyright (C) 2001-2003 VeriSign, Inc.
// //
@ -18,16 +18,16 @@
package com.verisignlabs.dnssec.security; package com.verisignlabs.dnssec.security;
import java.util.*; import java.util.Comparator;
/**
/** This class implements a basic comparitor for byte arrays. It is * This class implements a basic comparitor for byte arrays. It is primarily
* primarily useful for comparing RDATA portions of DNS records in * useful for comparing RDATA portions of DNS records in doing DNSSEC
* doing DNSSEC canonical ordering. * canonical ordering.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author$
* @version $Revision: 1.2 $ * @version $Revision$
*/ */
public class ByteArrayComparator implements Comparator public class ByteArrayComparator implements Comparator
{ {
@ -35,7 +35,8 @@ public class ByteArrayComparator implements Comparator
private boolean mDebug = false; private boolean mDebug = false;
public ByteArrayComparator() public ByteArrayComparator()
{} {
}
public ByteArrayComparator(int offset, boolean debug) public ByteArrayComparator(int offset, boolean debug)
{ {
@ -54,8 +55,8 @@ public class ByteArrayComparator implements Comparator
{ {
if (mDebug) if (mDebug)
{ {
System.out.println("offset " + i + " differs (this is " + System.out.println("offset " + i + " differs (this is "
(i - mOffset) +" bytes in from our offset.)"); + (i - mOffset) + " bytes in from our offset.)");
} }
return (b1[i] & 0xFF) - (b2[i] & 0xFF); return (b1[i] & 0xFF) - (b2[i] & 0xFF);
} }

View File

@ -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. // Copyright (C) 2001-2003 VeriSign, Inc.
// //
@ -18,27 +18,45 @@
package com.verisignlabs.dnssec.security; package com.verisignlabs.dnssec.security;
import java.io.*; import java.io.IOException;
import java.util.StringTokenizer; import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger; import java.math.BigInteger;
import java.security.*; import java.security.GeneralSecurityException;
import java.security.spec.*; import java.security.KeyFactory;
import javax.crypto.spec.DHPrivateKeySpec; import java.security.NoSuchAlgorithmException;
import javax.crypto.spec.DHParameterSpec; 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.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey; 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.security.KEYConverter;
import org.xbill.DNS.utils.base64; import org.xbill.DNS.utils.base64;
/** This class handles conversions between JCA key formats and DNSSEC /**
* and BIND9 key formats. * This class handles conversions between JCA key formats and DNSSEC and BIND9
* key formats.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ (latest) * @author $Author$ (latest)
* @version $Revision: 1.4 $ * @version $Revision$
*/ */
public class DnsKeyConverter public class DnsKeyConverter
{ {
@ -58,31 +76,31 @@ public class DnsKeyConverter
return KEYConverter.parseRecord(pKeyRecord); return KEYConverter.parseRecord(pKeyRecord);
} }
/** Given a JCA public key and the ancillary data, generate a DNSKEY /**
* record. */ * Given a JCA public key and the ancillary data, generate a DNSKEY record.
public DNSKEYRecord generateDNSKEYRecord(Name name, */
int dclass, public DNSKEYRecord generateDNSKEYRecord(Name name, int dclass, long ttl,
long ttl, int flags, int alg, PublicKey key)
int flags,
int alg,
PublicKey key)
{ {
// FIXME: currenty org.xbill.DNS.security.KEYConverter will only // FIXME: currenty org.xbill.DNS.security.KEYConverter will only
// convert to KEYRecords, and even then, assume that an RSA // convert to KEYRecords, and even then, assume that an RSA
// PublicKey means alg 1. // PublicKey means alg 1.
KEYRecord kr = KEYConverter.buildRecord(name, dclass, ttl, flags, KEYRecord kr = KEYConverter.buildRecord(name,
KEYRecord.PROTOCOL_DNSSEC, key); dclass,
ttl,
flags,
KEYRecord.PROTOCOL_DNSSEC,
key);
return new DNSKEYRecord(name, dclass, ttl, flags, return new DNSKEYRecord(name, dclass, ttl, flags,
DNSKEYRecord.Protocol.DNSSEC, alg, DNSKEYRecord.Protocol.DNSSEC, alg, kr.getKey());
kr.getKey());
} }
// Private Key Specific Parsing routines // 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) public PrivateKey convertEncodedPrivateKey(byte[] key, int algorithm)
{ {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(key); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(key);
@ -91,24 +109,24 @@ public class DnsKeyConverter
{ {
switch (algorithm) switch (algorithm)
{ {
case DNSSEC.RSAMD5: case DNSSEC.RSAMD5 :
case DNSSEC.RSASHA1: case DNSSEC.RSASHA1 :
return mRSAKeyFactory.generatePrivate(spec); return mRSAKeyFactory.generatePrivate(spec);
case DNSSEC.DSA: case DNSSEC.DSA :
return mDSAKeyFactory.generatePrivate(spec); return mDSAKeyFactory.generatePrivate(spec);
} }
} }
catch (GeneralSecurityException e) catch (GeneralSecurityException e)
{ {}
}
return null; return null;
} }
/** @return a JCA private key, given a BIND9-style textual /**
* encoding */ * @return a JCA private key, given a BIND9-style textual encoding
public PrivateKey parsePrivateKeyString(String key) */
throws IOException, NoSuchAlgorithmException public PrivateKey parsePrivateKeyString(String key) throws IOException,
NoSuchAlgorithmException
{ {
StringTokenizer lines = new StringTokenizer(key, "\n"); StringTokenizer lines = new StringTokenizer(key, "\n");
@ -124,7 +142,7 @@ public class DnsKeyConverter
if (line.startsWith("Private-key-format: ")) if (line.startsWith("Private-key-format: "))
{ {
if (! val.equals("v1.2")) if (!val.equals("v1.2"))
{ {
throw new IOException("unsupported private key format: " + val); throw new IOException("unsupported private key format: " + val);
} }
@ -141,8 +159,10 @@ public class DnsKeyConverter
return null; 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) private String value(String av)
{ {
if (av == null) return null; if (av == null) return null;
@ -155,30 +175,12 @@ public class DnsKeyConverter
return av.substring(pos + 1).trim(); return av.substring(pos + 1).trim();
} }
/** prints the bytes of an original byte array and the BigInteger /**
* copy */ * Given the rest of the RSA BIND9 string format private key, parse and
private void printBigIntCompare(byte[] orig, BigInteger copy) * translate into a JCA private key
{
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 * @throws NoSuchAlgorithmException if the RSA algorithm is not available.
* available. */ */
private PrivateKey parsePrivateRSA(StringTokenizer lines) private PrivateKey parsePrivateRSA(StringTokenizer lines)
throws NoSuchAlgorithmException throws NoSuchAlgorithmException
{ {
@ -203,26 +205,41 @@ public class DnsKeyConverter
byte[] data = base64.fromString(val); byte[] data = base64.fromString(val);
if (line.startsWith("Modulus: ")) { if (line.startsWith("Modulus: "))
{
modulus = new BigInteger(1, data); modulus = new BigInteger(1, data);
// printBigIntCompare(data, modulus); // printBigIntCompare(data, modulus);
} else if (line.startsWith("PublicExponent: ")) { }
else if (line.startsWith("PublicExponent: "))
{
public_exponent = new BigInteger(1, data); public_exponent = new BigInteger(1, data);
// printBigIntCompare(data, public_exponent); // printBigIntCompare(data, public_exponent);
} else if (line.startsWith("PrivateExponent: ")) { }
else if (line.startsWith("PrivateExponent: "))
{
private_exponent = new BigInteger(1, data); private_exponent = new BigInteger(1, data);
// printBigIntCompare(data, private_exponent); // printBigIntCompare(data, private_exponent);
} else if (line.startsWith("Prime1: ")) { }
else if (line.startsWith("Prime1: "))
{
prime_p = new BigInteger(1, data); prime_p = new BigInteger(1, data);
// printBigIntCompare(data, prime_p); // printBigIntCompare(data, prime_p);
} else if (line.startsWith("Prime2: ")) { }
else if (line.startsWith("Prime2: "))
{
prime_q = new BigInteger(1, data); prime_q = new BigInteger(1, data);
// printBigIntCompare(data, prime_q); // printBigIntCompare(data, prime_q);
} else if (line.startsWith("Exponent1: ")) { }
else if (line.startsWith("Exponent1: "))
{
prime_p_exponent = new BigInteger(1, data); prime_p_exponent = new BigInteger(1, data);
} else if (line.startsWith("Exponent2: ")) { }
else if (line.startsWith("Exponent2: "))
{
prime_q_exponent = new BigInteger(1, data); prime_q_exponent = new BigInteger(1, data);
} else if (line.startsWith("Coefficient: ")) { }
else if (line.startsWith("Coefficient: "))
{
coefficient = new BigInteger(1, data); coefficient = new BigInteger(1, data);
} }
} }
@ -230,8 +247,7 @@ public class DnsKeyConverter
try try
{ {
KeySpec spec = new RSAPrivateCrtKeySpec(modulus, public_exponent, KeySpec spec = new RSAPrivateCrtKeySpec(modulus, public_exponent,
private_exponent, prime_p, private_exponent, prime_p, prime_q, prime_p_exponent,
prime_q, prime_p_exponent,
prime_q_exponent, coefficient); prime_q_exponent, coefficient);
if (mRSAKeyFactory == null) if (mRSAKeyFactory == null)
{ {
@ -246,11 +262,12 @@ 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. * 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 * @throws NoSuchAlgorithmException if the DH algorithm is not available.
* available. */ */
private PrivateKey parsePrivateDH(StringTokenizer lines) private PrivateKey parsePrivateDH(StringTokenizer lines)
throws NoSuchAlgorithmException throws NoSuchAlgorithmException
{ {
@ -270,11 +287,16 @@ public class DnsKeyConverter
byte[] data = base64.fromString(val); byte[] data = base64.fromString(val);
if (line.startsWith("Prime(p): ")) { if (line.startsWith("Prime(p): "))
{
p = new BigInteger(1, data); p = new BigInteger(1, data);
} else if (line.startsWith("Generator(g): ")) { }
else if (line.startsWith("Generator(g): "))
{
g = new BigInteger(1, data); g = new BigInteger(1, data);
} else if (line.startsWith("Private_value(x): ")) { }
else if (line.startsWith("Private_value(x): "))
{
x = new BigInteger(1, data); x = new BigInteger(1, data);
} }
} }
@ -295,11 +317,12 @@ 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. * 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 * @throws NoSuchAlgorithmException if the DSA algorithm is not available.
* available. */ */
private PrivateKey parsePrivateDSA(StringTokenizer lines) private PrivateKey parsePrivateDSA(StringTokenizer lines)
throws NoSuchAlgorithmException throws NoSuchAlgorithmException
{ {
@ -320,13 +343,20 @@ public class DnsKeyConverter
byte[] data = base64.fromString(val); byte[] data = base64.fromString(val);
if (line.startsWith("Prime(p): ")) { if (line.startsWith("Prime(p): "))
{
p = new BigInteger(1, data); p = new BigInteger(1, data);
} else if (line.startsWith("Subprime(q): ")) { }
else if (line.startsWith("Subprime(q): "))
{
q = new BigInteger(1, data); q = new BigInteger(1, data);
} else if (line.startsWith("Base(g): ")) { }
else if (line.startsWith("Base(g): "))
{
g = new BigInteger(1, data); g = new BigInteger(1, data);
} else if (line.startsWith("Private_value(x): ")) { }
else if (line.startsWith("Private_value(x): "))
{
x = new BigInteger(1, data); x = new BigInteger(1, data);
} }
} }
@ -347,8 +377,10 @@ 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, public String generatePrivateKeyString(PrivateKey priv, PublicKey pub,
int alg) int alg)
{ {
@ -356,13 +388,11 @@ public class DnsKeyConverter
{ {
return generatePrivateRSA((RSAPrivateCrtKey) priv, alg); return generatePrivateRSA((RSAPrivateCrtKey) priv, alg);
} }
else if (priv instanceof DSAPrivateKey && else if (priv instanceof DSAPrivateKey && pub instanceof DSAPublicKey)
pub instanceof DSAPublicKey)
{ {
return generatePrivateDSA((DSAPrivateKey) priv, (DSAPublicKey) pub); return generatePrivateDSA((DSAPrivateKey) priv, (DSAPublicKey) pub);
} }
else if (priv instanceof DHPrivateKey && else if (priv instanceof DHPrivateKey && pub instanceof DHPublicKey)
pub instanceof DHPublicKey)
{ {
return generatePrivateDH((DHPrivateKey) priv, (DHPublicKey) pub); return generatePrivateDH((DHPrivateKey) priv, (DHPublicKey) pub);
} }
@ -370,8 +400,9 @@ public class DnsKeyConverter
return null; 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) private String b64BigInt(BigInteger i)
{ {
byte[] orig_bytes = i.toByteArray(); byte[] orig_bytes = i.toByteArray();
@ -387,8 +418,10 @@ public class DnsKeyConverter
return base64.toString(signed_bytes); 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) private String generatePrivateRSA(RSAPrivateCrtKey key, int algorithm)
{ {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();

View File

@ -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. // Copyright (C) 2001-2003 VeriSign, Inc.
// //
@ -20,67 +20,68 @@ package com.verisignlabs.dnssec.security;
import java.security.*; import java.security.*;
import java.security.interfaces.*; import java.security.interfaces.*;
import java.util.logging.Logger;
import org.xbill.DNS.*; 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 class forms the basis for representing public/private key * this object, as well as a DNSKEYRecord encoding of the public key. This
* pairs in a DNSSEC context. It is possible to get a JCA public and * class is implemented as a UNION of all the functionality needed for handing
* private key from this object, as well as a KEYRecord encoding of * native java, BIND, and possibly other underlying DNSKEY engines.
* 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. * JCA == Java Cryptography Architecture.
* *
* @author David Blacka (orig) * @author David Blacka (orig)
* @author $Author: davidb $ (latest) * @author $Author$ (latest)
* @version $Revision: 1.3 $ * @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 // NOTE: this class is designed to do "lazy" evaluation of it's
// various cached objects and format conversions, so methods should // various cached objects and format conversions, so methods should
// avoid direct access to the member variables. // avoid direct access to the member variables.
public class DnsKeyPair public class DnsKeyPair
{ {
/** This is the real (base) encoding of the public key. */ /** 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. */ * This is a precalcuated cache of the KEYRecord converted into a JCA public
* key.
*/
private PublicKey mPublicKey; private PublicKey mPublicKey;
/** The private key in Base64 encoded format. This version is /**
* presumed to be opaque, so no attempts will be made to convert it * The private key in Base64 encoded format. This version is presumed to be
* to a JCA private key. */ * opaque, so no attempts will be made to convert it to a JCA private key.
*/
protected String mPrivateKeyString; protected String mPrivateKeyString;
/** The private key in JCA format. This is the base encoding for /**
* instances were JCA private keys are used. */ * The private key in JCA format. This is the base encoding for instances
* were JCA private keys are used.
*/
protected PrivateKey mPrivateKey; protected PrivateKey mPrivateKey;
/** The local key converter. */ /** The local key converter. */
protected DnsKeyConverter mKeyConverter; protected DnsKeyConverter mKeyConverter;
/** a cached Signature used for signing (initialized with the /**
* private key) */ * a cached Signature used for signing (initialized with the private key)
*/
protected Signature mSigner; protected Signature mSigner;
/** a caches Signature used for verifying (intialized with the /**
* public key) */ * a caches Signature used for verifying (intialized with the public key)
*/
protected Signature mVerifier; protected Signature mVerifier;
private Logger log;
private Log log;
public DnsKeyPair() public DnsKeyPair()
{ {
log = LogFactory.getLog(this.getClass()); log = Logger.getLogger(this.getClass().toString());
} }
public DnsKeyPair(DNSKEYRecord keyRecord, PrivateKey privateKey) public DnsKeyPair(DNSKEYRecord keyRecord, PrivateKey privateKey)
@ -105,8 +106,12 @@ public class DnsKeyPair
this(); this();
DnsKeyConverter conv = new DnsKeyConverter(); DnsKeyConverter conv = new DnsKeyConverter();
DNSKEYRecord keyrec = conv.generateDNSKEYRecord(keyName, DClass.IN, 0, 0, DNSKEYRecord keyrec = conv.generateDNSKEYRecord(keyName,
algorithm, publicKey); DClass.IN,
0,
0,
algorithm,
publicKey);
setDNSKEYRecord(keyrec); setDNSKEYRecord(keyrec);
setPrivate(privateKey); setPrivate(privateKey);
} }
@ -143,30 +148,31 @@ public class DnsKeyPair
{ {
switch (getDNSKEYAlgorithm()) switch (getDNSKEYAlgorithm())
{ {
case DNSSEC.RSAMD5: case DNSSEC.RSAMD5 :
s = Signature.getInstance("MD5withRSA"); s = Signature.getInstance("MD5withRSA");
break; break;
case DNSSEC.DSA: case DNSSEC.DSA :
s = Signature.getInstance("SHA1withDSA"); s = Signature.getInstance("SHA1withDSA");
break; break;
case DNSSEC.RSASHA1: case DNSSEC.RSASHA1 :
s = Signature.getInstance("SHA1withRSA"); s = Signature.getInstance("SHA1withRSA");
break; break;
case -1: case -1 :
s = null; s = null;
break; break;
} }
} }
catch (NoSuchAlgorithmException e) catch (NoSuchAlgorithmException e)
{ {
log.error("error getting Signature object", e); log.severe("error getting Signature object: " + e);
} }
return s; 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() public PublicKey getPublic()
{ {
if (mPublicKey == null && getDNSKEYRecord() != null) if (mPublicKey == null && getDNSKEYRecord() != null)
@ -178,9 +184,9 @@ public class DnsKeyPair
return mPublicKey; return mPublicKey;
} }
/**
/** sets the public key. This method is generally not used * sets the public key. This method is generally not used directly.
* directly. */ */
protected void setPublic(PublicKey k) protected void setPublic(PublicKey k)
{ {
mPublicKey = k; mPublicKey = k;
@ -205,14 +211,16 @@ public class DnsKeyPair
mPrivateKey = k; 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() public String getPrivateKeyString()
{ {
if (mPrivateKeyString == null && mPrivateKey != null) if (mPrivateKeyString == null && mPrivateKey != null)
{ {
PublicKey pub = getPublic(); PublicKey pub = getPublic();
mPrivateKeyString = BINDKeyUtils.convertPrivateKey(mPrivateKey, pub, mPrivateKeyString = BINDKeyUtils.convertPrivateKey(mPrivateKey,
pub,
getDNSKEYAlgorithm()); getDNSKEYAlgorithm());
} }
@ -233,9 +241,11 @@ public class DnsKeyPair
return null; return null;
} }
/** Sets the private key from the encoded form (PKCS#8). This /**
* routine requires that the public key already be assigned. * Sets the private key from the encoded form (PKCS#8). This routine
* Currently it can only handle DSA and RSA keys. */ * requires that the public key already be assigned. Currently it can only
* handle DSA and RSA keys.
*/
public void setEncodedPrivate(byte[] encoded) public void setEncodedPrivate(byte[] encoded)
{ {
int alg = getDNSKEYAlgorithm(); int alg = getDNSKEYAlgorithm();
@ -253,8 +263,10 @@ public class DnsKeyPair
return mPublicKeyRecord; 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() public Signature getSigner()
{ {
if (mSigner == null) if (mSigner == null)
@ -269,7 +281,7 @@ public class DnsKeyPair
} }
catch (InvalidKeyException e) catch (InvalidKeyException e)
{ {
log.error("Signature error", e); log.severe("Signature error: " + e);
} }
} }
else else
@ -282,8 +294,10 @@ public class DnsKeyPair
return mSigner; 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() public Signature getVerifier()
{ {
if (mVerifier == null) if (mVerifier == null)
@ -296,7 +310,8 @@ public class DnsKeyPair
{ {
mVerifier.initVerify(pk); mVerifier.initVerify(pk);
} }
catch (InvalidKeyException e) {} catch (InvalidKeyException e)
{}
} }
else else
{ {
@ -316,7 +331,6 @@ public class DnsKeyPair
mPublicKey = null; mPublicKey = null;
} }
public Name getDNSKEYName() public Name getDNSKEYName()
{ {
DNSKEYRecord kr = getDNSKEYRecord(); DNSKEYRecord kr = getDNSKEYRecord();

View File

@ -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. // Copyright (C) 2001-2003 VeriSign, Inc.
// //
@ -19,23 +19,29 @@
package com.verisignlabs.dnssec.security; package com.verisignlabs.dnssec.security;
import java.util.*; import java.io.IOException;
import java.io.*; import java.security.GeneralSecurityException;
import java.security.*; 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.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
/** A class for performing basic DNSSEC verification. The DNSJAVA * timing "fudge" factors and logging more specifically why an RRset did not
* package contains a similar class. This differs (for the moment, * validate.
* anyway) by allowing timing "fudge" factors and logging more
* specifically why an RRset did not validate.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author$
* @version $Revision: 1.5 $ * @version $Revision$
*/ */
public class DnsSecVerifier implements Verifier public class DnsSecVerifier implements Verifier
{ {
@ -85,11 +91,11 @@ public class DnsSecVerifier implements Verifier
// FIXME: this algorithm assumes that name+alg+footprint is // FIXME: this algorithm assumes that name+alg+footprint is
// unique, which isn't necessarily true. // 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(); DnsKeyPair p = (DnsKeyPair) i.next();
if (p.getDNSKEYAlgorithm() == algorithm && if (p.getDNSKEYAlgorithm() == algorithm
p.getDNSKEYFootprint() == keyid) && p.getDNSKEYFootprint() == keyid)
{ {
return p; return p;
} }
@ -103,11 +109,11 @@ public class DnsSecVerifier implements Verifier
private int mExpireFudge = 0; private int mExpireFudge = 0;
private boolean mVerifyAllSigs = false; private boolean mVerifyAllSigs = false;
private Log log; private Logger log;
public DnsSecVerifier() public DnsSecVerifier()
{ {
log = LogFactory.getLog(this.getClass()); log = Logger.getLogger(this.getClass().toString());
mKeyStore = new TrustedKeyStore(); mKeyStore = new TrustedKeyStore();
} }
@ -155,13 +161,13 @@ public class DnsSecVerifier implements Verifier
// look for the particular key // look for the particular key
// FIXME: this assumes that name+alg+footprint is unique. // 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(); Object o = i.next();
if (! (o instanceof DNSKEYRecord)) continue; if (!(o instanceof DNSKEYRecord)) continue;
DNSKEYRecord keyrec = (DNSKEYRecord) o; DNSKEYRecord keyrec = (DNSKEYRecord) o;
if (keyrec.getAlgorithm() == algorithm && if (keyrec.getAlgorithm() == algorithm
keyrec.getFootprint() == footprint) && keyrec.getFootprint() == footprint)
{ {
return new DnsKeyPair(keyrec, (PrivateKey) null); return new DnsKeyPair(keyrec, (PrivateKey) null);
} }
@ -185,7 +191,7 @@ public class DnsSecVerifier implements Verifier
private byte validateSignature(RRset rrset, RRSIGRecord sigrec) private byte validateSignature(RRset rrset, RRSIGRecord sigrec)
{ {
if (rrset == null || sigrec == null) return DNSSEC.Failed; 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"); log.info("Signature name does not match RRset name");
return DNSSEC.Failed; return DNSSEC.Failed;
@ -220,8 +226,8 @@ public class DnsSecVerifier implements Verifier
} }
if (now.after(expire)) if (now.after(expire))
{ {
log.info("Signature has expired (now = " + now + log.info("Signature has expired (now = " + now + ", sig expires = "
", sig expires = " + expire); + expire);
return DNSSEC.Failed; return DNSSEC.Failed;
} }
} }
@ -229,18 +235,21 @@ public class DnsSecVerifier implements Verifier
return DNSSEC.Secure; return DNSSEC.Secure;
} }
/** Verify an RRset against a particular signature. /**
* Verify an RRset against a particular signature.
* *
* @return DNSSEC.Secure if the signature verfied, DNSSEC.Failed if * @return DNSSEC.Secure if the signature verfied, DNSSEC.Failed if it did
* it did not verify (for any reason), and DNSSEC.Insecure if * not verify (for any reason), and DNSSEC.Insecure if verification
* verification could not be completed (usually because the public * could not be completed (usually because the public key was not
* key was not available). */ * available).
*/
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache) public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache)
{ {
byte result = validateSignature(rrset, sigrec); byte result = validateSignature(rrset, sigrec);
if (result != DNSSEC.Secure) return result; if (result != DNSSEC.Secure) return result;
DnsKeyPair keypair = findKey(cache, sigrec.getSigner(), DnsKeyPair keypair = findKey(cache,
sigrec.getSigner(),
sigrec.getAlgorithm(), sigrec.getAlgorithm(),
sigrec.getFootprint()); sigrec.getFootprint());
@ -272,29 +281,30 @@ public class DnsSecVerifier implements Verifier
} }
catch (IOException e) catch (IOException e)
{ {
log.error("I/O error", e); log.severe("I/O error: " + e);
} }
catch (GeneralSecurityException 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; return DNSSEC.Insecure;
} }
/** Verifies an RRset. This routine does not modify the RRset. /**
* Verifies an RRset. This routine does not modify the RRset.
* *
* @return DNSSEC.Secure if the set verified, DNSSEC.Failed if it * @return DNSSEC.Secure if the set verified, DNSSEC.Failed if it did not,
* did not, and DNSSEC.Insecure if verification could not * and DNSSEC.Insecure if verification could not complete.
* complete. */ */
public int verify(RRset rrset, Cache cache) 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(); Iterator i = rrset.sigs();
if ( ! i.hasNext()) if (!i.hasNext())
{ {
log.info("RRset failed to verify due to lack of signatures"); log.info("RRset failed to verify due to lack of signatures");
return DNSSEC.Insecure; return DNSSEC.Insecure;

View File

@ -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. // Copyright (C) 2001-2003 VeriSign, Inc.
// //
@ -16,24 +16,41 @@
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA // USA
package com.verisignlabs.dnssec.security; package com.verisignlabs.dnssec.security;
import java.util.*; import java.io.IOException;
import java.io.*; import java.security.GeneralSecurityException;
import java.security.*; import java.security.KeyPair;
import java.security.interfaces.*; 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. /**
* This class contains routines for signing DNS zones.
* *
* In particular, it contains both an ability to sign an individual * In particular, it contains both an ability to sign an individual RRset and
* RRset and the ability to sign and entire zone. It primarily glues * the ability to sign and entire zone. It primarily glues together the more
* together the more basic primitives found in {@link SignUtils}. * basic primitives found in {@link SignUtils}.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author$
* @version $Revision: 1.3 $ * @version $Revision$
*/ */
public class JCEDnsSecSigner public class JCEDnsSecSigner
{ {
@ -42,8 +59,8 @@ public class JCEDnsSecSigner
private KeyPairGenerator mRSAKeyGenerator; private KeyPairGenerator mRSAKeyGenerator;
private KeyPairGenerator mDSAKeyGenerator; private KeyPairGenerator mDSAKeyGenerator;
/**
/** Cryptographically generate a new DNSSEC key. * Cryptographically generate a new DNSSEC key.
* *
* @param owner the KEY RR's owner name. * @param owner the KEY RR's owner name.
* @param ttl the KEY RR's TTL. * @param ttl the KEY RR's TTL.
@ -53,13 +70,8 @@ public class JCEDnsSecSigner
* @param keysize the size of the key to generate. * @param keysize the size of the key to generate.
* @return a DnsKeyPair with the public and private keys populated. * @return a DnsKeyPair with the public and private keys populated.
*/ */
public DnsKeyPair generateKey(Name owner, public DnsKeyPair generateKey(Name owner, long ttl, int dclass,
long ttl, int algorithm, int flags, int keysize) throws NoSuchAlgorithmException
int dclass,
int algorithm,
int flags,
int keysize)
throws IOException, NoSuchAlgorithmException
{ {
KeyPair pair; KeyPair pair;
@ -67,8 +79,8 @@ public class JCEDnsSecSigner
switch (algorithm) switch (algorithm)
{ {
case DNSSEC.RSAMD5: case DNSSEC.RSAMD5 :
case DNSSEC.RSASHA1: case DNSSEC.RSASHA1 :
if (mRSAKeyGenerator == null) if (mRSAKeyGenerator == null)
{ {
mRSAKeyGenerator = KeyPairGenerator.getInstance("RSA"); mRSAKeyGenerator = KeyPairGenerator.getInstance("RSA");
@ -76,7 +88,7 @@ public class JCEDnsSecSigner
mRSAKeyGenerator.initialize(keysize); mRSAKeyGenerator.initialize(keysize);
pair = mRSAKeyGenerator.generateKeyPair(); pair = mRSAKeyGenerator.generateKeyPair();
break; break;
case DNSSEC.DSA: case DNSSEC.DSA :
if (mDSAKeyGenerator == null) if (mDSAKeyGenerator == null)
{ {
mDSAKeyGenerator = KeyPairGenerator.getInstance("DSA"); mDSAKeyGenerator = KeyPairGenerator.getInstance("DSA");
@ -84,7 +96,7 @@ public class JCEDnsSecSigner
mDSAKeyGenerator.initialize(keysize); mDSAKeyGenerator.initialize(keysize);
pair = mDSAKeyGenerator.generateKeyPair(); pair = mDSAKeyGenerator.generateKeyPair();
break; break;
default: default :
throw new NoSuchAlgorithmException("Alg " + algorithm); throw new NoSuchAlgorithmException("Alg " + algorithm);
} }
@ -107,7 +119,8 @@ public class JCEDnsSecSigner
return dnspair; return dnspair;
} }
/** Sign an RRset. /**
* Sign an RRset.
* *
* @param rrset the RRset to sign -- any existing signatures are ignored. * @param rrset the RRset to sign -- any existing signatures are ignored.
* @param keypars a list of DnsKeyPair objects containing private keys. * @param keypars a list of DnsKeyPair objects containing private keys.
@ -131,14 +144,17 @@ public class JCEDnsSecSigner
ArrayList sigs = new ArrayList(keypairs.size()); ArrayList sigs = new ArrayList(keypairs.size());
// for each keypair, sign the rrset. // 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(); DnsKeyPair pair = (DnsKeyPair) i.next();
DNSKEYRecord keyrec = pair.getDNSKEYRecord(); DNSKEYRecord keyrec = pair.getDNSKEYRecord();
if (keyrec == null) continue; if (keyrec == null) continue;
RRSIGRecord presig = SignUtils.generatePreRRSIG(rrset, keyrec, start, RRSIGRecord presig = SignUtils.generatePreRRSIG(rrset,
expire, rrset.getTTL()); keyrec,
start,
expire,
rrset.getTTL());
byte[] sign_data = SignUtils.generateSigData(rrset_data, presig); byte[] sign_data = SignUtils.generateSigData(rrset_data, presig);
Signature signer = pair.getSigner(); Signature signer = pair.getSigner();
@ -146,11 +162,11 @@ public class JCEDnsSecSigner
if (signer == null) if (signer == null)
{ {
// debug // debug
System.out.println("missing private key that goes with:\n" + System.out.println("missing private key that goes with:\n"
pair.getDNSKEYRecord()); + pair.getDNSKEYRecord());
throw new GeneralSecurityException throw new GeneralSecurityException(
("cannot sign without a valid Signer " + "cannot sign without a valid Signer "
"(probably missing private key)"); + "(probably missing private key)");
} }
// sign the data. // sign the data.
@ -160,8 +176,8 @@ public class JCEDnsSecSigner
// Convert to RFC 2536 format, if necessary. // Convert to RFC 2536 format, if necessary.
if (pair.getDNSKEYAlgorithm() == DNSSEC.DSA) if (pair.getDNSKEYAlgorithm() == DNSSEC.DSA)
{ {
sig = SignUtils.convertDSASignature sig = SignUtils.convertDSASignature(((DSAPublicKey) pair.getPublic()).getParams(),
(((DSAPublicKey)pair.getPublic()).getParams(), sig); sig);
} }
RRSIGRecord sigrec = SignUtils.generateRRSIG(sig, presig); RRSIGRecord sigrec = SignUtils.generateRRSIG(sig, presig);
sigs.add(sigrec); sigs.add(sigrec);
@ -170,7 +186,8 @@ public class JCEDnsSecSigner
return sigs; return sigs;
} }
/** Create a completely self-signed KEY RRset. /**
* Create a completely self-signed KEY RRset.
* *
* @param keypairs the public & private keypairs to use in the keyset. * @param keypairs the public & private keypairs to use in the keyset.
* @param start the RRSIG inception time. * @param start the RRSIG inception time.
@ -184,7 +201,7 @@ public class JCEDnsSecSigner
RRset keyset = new RRset(); RRset keyset = new RRset();
for (Iterator i = keypairs.iterator(); i.hasNext(); ) for (Iterator i = keypairs.iterator(); i.hasNext();)
{ {
DnsKeyPair pair = (DnsKeyPair) i.next(); DnsKeyPair pair = (DnsKeyPair) i.next();
keyset.addRR(pair.getDNSKEYRecord()); keyset.addRR(pair.getDNSKEYRecord());
@ -192,7 +209,7 @@ public class JCEDnsSecSigner
List records = signRRset(keyset, keypairs, start, expire); 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()); keyset.addRR((Record) i.next());
} }
@ -200,7 +217,8 @@ public class JCEDnsSecSigner
return keyset; return keyset;
} }
/** Conditionally sign an RRset and add it to the toList. /**
* Conditionally sign an RRset and add it to the toList.
* *
* @param toList the list to which we are adding the processed RRsets. * @param toList the list to which we are adding the processed RRsets.
* @param zonename the zone apex name. * @param zonename the zone apex name.
@ -209,25 +227,26 @@ public class JCEDnsSecSigner
* @param zonekeypairs the List of zone keys. * @param zonekeypairs the List of zone keys.
* @param start the RRSIG inception time. * @param start the RRSIG inception time.
* @param expire the RRSIG expiration time. * @param expire the RRSIG expiration time.
* @param fullySignKeyset if true, sign the zone apex keyset with * @param fullySignKeyset if true, sign the zone apex keyset with both KSKs
* both KSKs and ZSKs. * and ZSKs.
* @param last_cut the name of the last delegation point encountered. * @param last_cut the name of the last delegation point encountered.
* @return the name of the new last_cut. * @return the name of the new last_cut.
*/ */
private Name addRRset(List toList, Name zonename, RRset rrset, private Name addRRset(List toList, Name zonename, RRset rrset,
List keysigningkeypairs, List zonekeypairs, List keysigningkeypairs, List zonekeypairs, Date start, Date expire,
Date start, Date expire, boolean fullySignKeyset, boolean fullySignKeyset, Name last_cut) throws IOException,
Name last_cut) GeneralSecurityException
throws IOException, GeneralSecurityException
{ {
// add the records themselves // add the records themselves
for (Iterator i = rrset.rrs(); i.hasNext(); ) for (Iterator i = rrset.rrs(); i.hasNext();)
{ {
toList.add(i.next()); toList.add(i.next());
} }
int type = SignUtils.recordSecType(zonename, rrset.getName(), int type = SignUtils.recordSecType(zonename,
rrset.getType(), last_cut); rrset.getName(),
rrset.getType(),
last_cut);
// we don't sign non-normal sets (delegations, glue, invalid). // we don't sign non-normal sets (delegations, glue, invalid).
// we also don't sign the zone key set unless we've been asked. // we also don't sign the zone key set unless we've been asked.
@ -262,44 +281,37 @@ public class JCEDnsSecSigner
return last_cut; return last_cut;
} }
/** Given a zone, sign it. /**
* Given a zone, sign it.
* *
* @param zonename the name of the zone. * @param zonename the name of the zone.
* @param records the records comprising the zone. They do not * @param records the records comprising the zone. They do not have to be in
* have to be in any particular order, as this method will order * any particular order, as this method will order them as
* them as necessary. * necessary.
* @param keysigningkeypairs the key pairs that are designated as * @param keysigningkeypairs the key pairs that are designated as "key
* "key signing keys".
* @param zonekeypair this key pairs that are designated as "zone
* signing keys". * signing keys".
* @param zonekeypair this key pairs that are designated as "zone signing
* keys".
* @param start the RRSIG inception time. * @param start the RRSIG inception time.
* @param expire the RRSIG expiration time. * @param expire the RRSIG expiration time.
* @param useOptIn generate Opt-In style NXT records. It will * @param useOptIn generate Opt-In style NXT records. It will consider any
* consider any insecure delegation to be unsigned. To override * insecure delegation to be unsigned. To override this, include
* this, include the name of the insecure delegation in the * the name of the insecure delegation in the NXTIncludeNames list.
* NXTIncludeNames list. * @param useConservativeOptIn if true, Opt-In NXT records will only be
* @param useConservativeOptIn if true, Opt-In NXT records will * generated if there are insecure, unsigned delegations in the
* only be generated if there are insecure, unsigned delegations in * span. Not effect if useOptIn is false.
* the span. Not effect if useOptIn is false.
* @param fullySignKeyset sign the zone apex keyset with all available keys. * @param fullySignKeyset sign the zone apex keyset with all available keys.
* @param NXTIncludeNames names that are to be included in the NXT * @param NXTIncludeNames names that are to be included in the NXT chain
* chain regardless. This may be null and is only used if useOptIn * regardless. This may be null and is only used if useOptIn is
* is true. * true.
* *
* @return an ordered list of {@link org.xbill.DNS.Record} objects, * @return an ordered list of {@link org.xbill.DNS.Record} objects,
* representing the signed zone. * representing the signed zone.
*/ */
public List signZone(Name zonename, public List signZone(Name zonename, List records, List keysigningkeypairs,
List records, List zonekeypairs, Date start, Date expire, boolean useOptIn,
List keysigningkeypairs, boolean useConservativeOptIn, boolean fullySignKeyset,
List zonekeypairs, List NSECIncludeNames) throws IOException, GeneralSecurityException
Date start,
Date expire,
boolean useOptIn,
boolean useConservativeOptIn,
boolean fullySignKeyset,
List NSECIncludeNames)
throws IOException, GeneralSecurityException
{ {
// Remove any existing DNSSEC records (NSEC, RRSIG) // Remove any existing DNSSEC records (NSEC, RRSIG)
@ -316,7 +328,8 @@ public class JCEDnsSecSigner
// Generate NXT records // Generate NXT records
if (useOptIn) if (useOptIn)
{ {
SignUtils.generateOptInNSECRecords(zonename, records, SignUtils.generateOptInNSECRecords(zonename,
records,
NSECIncludeNames, NSECIncludeNames,
useConservativeOptIn); useConservativeOptIn);
} }
@ -330,10 +343,9 @@ public class JCEDnsSecSigner
ArrayList signed_records = new ArrayList(); ArrayList signed_records = new ArrayList();
Name last_cut = null; Name last_cut = null;
for (ListIterator i = records.listIterator(); i.hasNext(); ) for (ListIterator i = records.listIterator(); i.hasNext();)
{ {
Record r = (Record) i.next(); Record r = (Record) i.next();
Name r_name = r.getName();
// First record // First record
if (rrset.getName() == null) if (rrset.getName() == null)
@ -343,9 +355,9 @@ public class JCEDnsSecSigner
} }
// Current record is part of the current RRset. // Current record is part of the current RRset.
if (rrset.getName().equals(r.getName()) && if (rrset.getName().equals(r.getName())
rrset.getDClass() == r.getDClass() && && rrset.getDClass() == r.getDClass()
rrset.getType() == r.getType()) && rrset.getType() == r.getType())
{ {
rrset.addRR(r); rrset.addRR(r);
continue; continue;
@ -356,8 +368,14 @@ public class JCEDnsSecSigner
// add the RRset to the list of signed_records, regardless of // add the RRset to the list of signed_records, regardless of
// whether or not we actually end up signing the set. // whether or not we actually end up signing the set.
last_cut = addRRset(signed_records, zonename, rrset, keysigningkeypairs, last_cut = addRRset(signed_records,
zonekeypairs, start, expire, fullySignKeyset, zonename,
rrset,
keysigningkeypairs,
zonekeypairs,
start,
expire,
fullySignKeyset,
last_cut); last_cut);
rrset.clear(); rrset.clear();
@ -365,8 +383,15 @@ public class JCEDnsSecSigner
} }
// add the last RR set // add the last RR set
addRRset(signed_records, zonename, rrset, keysigningkeypairs, zonekeypairs, addRRset(signed_records,
start, expire, fullySignKeyset, last_cut); zonename,
rrset,
keysigningkeypairs,
zonekeypairs,
start,
expire,
fullySignKeyset,
last_cut);
return signed_records; return signed_records;
} }

View File

@ -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. // Copyright (C) 2000-2003 Network Solutions, Inc.
// //
@ -19,26 +19,33 @@
package com.verisignlabs.dnssec.security; 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 * This class implements a comparison operator for {@link
* consistent with DNSSEC. It does not put records within a RRset * org.xbill.DNS.Record} objects. It imposes a canonical order consistent with
* into canonical order: see {@link ByteArrayComparator}. * DNSSEC. It does not put records within a RRset into canonical order: see
* {@link ByteArrayComparator}.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author$
* @version $Revision: 1.2 $ */ * @version $Revision$
*/
public class RecordComparator implements Comparator public class RecordComparator implements Comparator
{ {
public RecordComparator() 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) private int compareTypes(int a, int b)
{ {
if (a == b) return 0; if (a == b) return 0;
@ -53,8 +60,7 @@ public class RecordComparator implements Comparator
return 1; return 1;
} }
public int compare(Object o1, Object o2) public int compare(Object o1, Object o2) throws ClassCastException
throws ClassCastException
{ {
Record a = (Record) o1; Record a = (Record) o1;
Record b = (Record) o2; Record b = (Record) o2;

View File

@ -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. // Copyright (C) 2001-2003 VeriSign, Inc.
// //
@ -19,30 +19,30 @@
package com.verisignlabs.dnssec.security; package com.verisignlabs.dnssec.security;
import java.util.*; import java.io.ByteArrayOutputStream;
import java.io.*; import java.io.IOException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.interfaces.DSAParams;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SignatureException; 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.*;
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. * This class contains a bunch of utility methods that are generally useful in
* signing zones.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author$
* @version $Revision: 1.7 $ * @version $Revision$
*/ */
public class SignUtils public class SignUtils
{ {
private static final int DSA_SIGNATURE_LENGTH = 20;
private static final int ASN1_INT = 0x02; private static final int ASN1_INT = 0x02;
private static final int ASN1_SEQ = 0x30; private static final int ASN1_SEQ = 0x30;
@ -51,80 +51,65 @@ public class SignUtils
public static final int RR_GLUE = 2; public static final int RR_GLUE = 2;
public static final int RR_INVALID = 3; public static final int RR_INVALID = 3;
private static Log log; private static Logger log;
static { static
log = LogFactory.getLog(SignUtils.class); {
log = Logger.getLogger(SignUtils.class.toString());
} }
public static void setLog(Log v) public static void setLog(Logger v)
{ {
log = v; log = v;
} }
/** 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 rrset the RRset being signed. * @param rrset the RRset being signed.
* @param key the public KEY RR counterpart to the key being used * @param key the public KEY RR counterpart to the key being used to sign
* to sign the RRset * the RRset
* @param start the SIG inception time. * @param start the SIG inception time.
* @param expire the SIG expiration time. * @param expire the SIG expiration time.
* @param sig_ttl the TTL of the resulting SIG record. * @param sig_ttl the TTL of the resulting SIG record.
* @return a prototype signature based on the RRset and key * @return a prototype signature based on the RRset and key information.
* information. */ */
public static RRSIGRecord generatePreRRSIG(RRset rrset, DNSKEYRecord key, public static RRSIGRecord generatePreRRSIG(RRset rrset, DNSKEYRecord key,
Date start, Date expire, Date start, Date expire, long sig_ttl)
long sig_ttl)
{ {
return new RRSIGRecord(rrset.getName(), return new RRSIGRecord(rrset.getName(), rrset.getDClass(), sig_ttl,
rrset.getDClass(), rrset.getType(), key.getAlgorithm(), (int) rrset.getTTL(), expire,
sig_ttl, start, key.getFootprint(), key.getName(), null);
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 rec the DNS record being signed (forming an entire RRset).
* @param key the public KEY RR counterpart to the key signing the * @param key the public KEY RR counterpart to the key signing the record.
* record.
* @param start the SIG inception time. * @param start the SIG inception time.
* @param expire the SIG expiration time. * @param expire the SIG expiration time.
* @param sig_ttl the TTL of the result SIG record. * @param sig_ttl the TTL of the result SIG record.
* @return a prototype signature based on the Record and key * @return a prototype signature based on the Record and key information.
* information. */ */
public static RRSIGRecord generatePreRRSIG(Record rec, DNSKEYRecord key, public static RRSIGRecord generatePreRRSIG(Record rec, DNSKEYRecord key,
Date start, Date expire, Date start, Date expire, long sig_ttl)
long sig_ttl)
{ {
return new RRSIGRecord(rec.getName(), return new RRSIGRecord(rec.getName(), rec.getDClass(), sig_ttl,
rec.getDClass(), rec.getType(), key.getAlgorithm(), rec.getTTL(), expire, start,
sig_ttl, key.getFootprint(), key.getName(), null);
rec.getType(),
key.getAlgorithm(),
rec.getTTL(),
expire,
start,
key.getFootprint(),
key.getName(),
null);
} }
/**
/** Generate the binary image of the prototype SIG RR. * Generate the binary image of the prototype SIG RR.
* *
* @param presig the SIG RR prototype. * @param presig the SIG RR prototype.
* @return the RDATA portion of the prototype SIG record. This * @return the RDATA portion of the prototype SIG record. This forms the
* forms the first part of the data to be signed. */ * first part of the data to be signed.
*/
private static byte[] generatePreSigRdata(RRSIGRecord presig) private static byte[] generatePreSigRdata(RRSIGRecord presig)
throws IOException
{ {
// Generate the binary image; // Generate the binary image;
DNSOutput image = new DNSOutput(); DNSOutput image = new DNSOutput();
@ -148,20 +133,21 @@ public class SignUtils
return image.toByteArray(); return image.toByteArray();
} }
/** Calculate the canonical wire line format of the RRset. /**
* Calculate the canonical wire line format of the RRset.
* *
* @param rrset the RRset to convert. * @param rrset the RRset to convert.
* @return the canonical wire line format of the rrset. This is * @return the canonical wire line format of the rrset. This is the second
* the second part of data to be signed.*/ * part of data to be signed.
*/
public static byte[] generateCanonicalRRsetData(RRset rrset) public static byte[] generateCanonicalRRsetData(RRset rrset)
throws IOException
{ {
DNSOutput image = new DNSOutput(); DNSOutput image = new DNSOutput();
// now convert load the wire format records in the RRset into a // now convert load the wire format records in the RRset into a
// list of byte arrays. // list of byte arrays.
ArrayList canonical_rrs = new ArrayList(); 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(); byte[] wire_fmt = r.toWireCanonical();
@ -184,7 +170,7 @@ public class SignUtils
Collections.sort(canonical_rrs, bac); 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(); byte[] wire_fmt_rec = (byte[]) i.next();
image.writeByteArray(wire_fmt_rec); image.writeByteArray(wire_fmt_rec);
@ -193,8 +179,9 @@ public class SignUtils
return image.toByteArray(); return image.toByteArray();
} }
/** Given an RRset and the prototype signature, generate the /**
* canonical data that is 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 rrset the RRset to be signed.
* @param presig a prototype SIG RR created using the same RRset. * @param presig a prototype SIG RR created using the same RRset.
@ -208,13 +195,14 @@ public class SignUtils
return generateSigData(rrset_data, presig); return generateSigData(rrset_data, presig);
} }
/** Given an RRset and the prototype signature, generate the /**
* canonical data that is 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 * @param rrset_data the RRset converted into canonical wire line format (as
* format (as per the canonicalization rules in RFC 2535). * per the canonicalization rules in RFC 2535).
* @param presig the prototype signature based on the same RRset * @param presig the prototype signature based on the same RRset represented
* represented in <code>rrset_data</code>. * in <code>rrset_data</code>.
* @return a block of data ready to be signed. * @return a block of data ready to be signed.
*/ */
public static byte[] generateSigData(byte[] rrset_data, RRSIGRecord presig) public static byte[] generateSigData(byte[] rrset_data, RRSIGRecord presig)
@ -222,8 +210,8 @@ public class SignUtils
{ {
byte[] sig_rdata = generatePreSigRdata(presig); byte[] sig_rdata = generatePreSigRdata(presig);
ByteArrayOutputStream image ByteArrayOutputStream image = new ByteArrayOutputStream(sig_rdata.length
= new ByteArrayOutputStream(sig_rdata.length + rrset_data.length); + rrset_data.length);
image.write(sig_rdata); image.write(sig_rdata);
image.write(rrset_data); image.write(rrset_data);
@ -231,8 +219,9 @@ public class SignUtils
return image.toByteArray(); return image.toByteArray();
} }
/** Given the acutal signature an the prototype signature, combine /**
* them and return the fully formed SIGRecord. * 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 signature the cryptographic signature, in DNSSEC format.
* @param presig the prototype SIG RR to add the signature to. * @param presig the prototype SIG RR to add the signature to.
@ -240,33 +229,29 @@ public class SignUtils
*/ */
public static RRSIGRecord generateRRSIG(byte[] signature, RRSIGRecord presig) public static RRSIGRecord generateRRSIG(byte[] signature, RRSIGRecord presig)
{ {
return new RRSIGRecord(presig.getName(), return new RRSIGRecord(presig.getName(), presig.getDClass(),
presig.getDClass(), presig.getTTL(), presig.getTypeCovered(), presig.getAlgorithm(),
presig.getTTL(), presig.getOrigTTL(), presig.getExpire(), presig.getTimeSigned(),
presig.getTypeCovered(), presig.getFootprint(), presig.getSigner(), signature);
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. * Converts from a RFC 2536 formatted DSA signature to a JCE (ASN.1)
* formatted signature.
* *
* <p>ASN.1 format = ASN1_SEQ . seq_length . ASN1_INT . Rlength . R * <p>
* . ANS1_INT . Slength . S</p> * ASN.1 format = ASN1_SEQ . seq_length . ASN1_INT . Rlength . R . ANS1_INT .
* Slength . S
* </p>
* *
* The integers R and S may have a leading null byte to force the * The integers R and S may have a leading null byte to force the integer
* integer positive. * positive.
* *
* @param signature the RFC 2536 formatted DSA signature. * @param signature the RFC 2536 formatted DSA signature.
* @return The ASN.1 formatted DSA signature. * @return The ASN.1 formatted DSA signature.
* @throws SignatureException if there was something wrong with the * @throws SignatureException if there was something wrong with the RFC 2536
* RFC 2536 formatted signature. * formatted signature.
**/ */
public static byte[] convertDSASignature(byte[] signature) public static byte[] convertDSASignature(byte[] signature)
throws SignatureException throws SignatureException
{ {
@ -310,40 +295,42 @@ public class SignUtils
return sig; return sig;
} }
/**
/** Converts from a JCE (ASN.1) formatted DSA signature to a RFC * Converts from a JCE (ASN.1) formatted DSA signature to a RFC 2536
* 2536 compliant signature. * compliant signature.
* *
* <p>rfc2536 format = T . R . S</p> * <p>
* rfc2536 format = T . R . S
* </p>
* *
* where T is a number between 0 and 8, which is based on the DSA * where T is a number between 0 and 8, which is based on the DSA key
* key length, and R & S are formatted to be exactly 20 bytes each * length, and R & S are formatted to be exactly 20 bytes each (no leading
* (no leading null bytes). * null bytes).
* *
* @param params the DSA parameters associated with the DSA key * @param params the DSA parameters associated with the DSA key used to
* used to generate the signature. * generate the signature.
* @param signature the ASN.1 formatted DSA signature. * @param signature the ASN.1 formatted DSA signature.
* @return a RFC 2536 formatted DSA signature. * @return a RFC 2536 formatted DSA signature.
* @throws SignatureException if something is wrong with the ASN.1 * @throws SignatureException if something is wrong with the ASN.1 format.
* format.
*/ */
public static byte[] convertDSASignature(DSAParams params, byte[] signature) public static byte[] convertDSASignature(DSAParams params, byte[] signature)
throws SignatureException throws SignatureException
{ {
if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT) if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT)
{ {
throw new SignatureException throw new SignatureException(
("Invalid ASN.1 signature format: expected SEQ, INT"); "Invalid ASN.1 signature format: expected SEQ, INT");
} }
byte r_pad = (byte) (signature[3] - 20); byte r_pad = (byte) (signature[3] - 20);
if (signature[24 + r_pad] != ASN1_INT) { if (signature[24 + r_pad] != ASN1_INT)
throw new SignatureException {
("Invalid ASN.1 signature format: expected SEQ, INT, INT"); 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 s_pad = (byte) (signature[25 + r_pad] - 20);
@ -361,7 +348,7 @@ public class SignUtils
{ {
// R is shorter than 20 bytes, so right justify the number // R is shorter than 20 bytes, so right justify the number
// (r_pad is negative here, remember?). // (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); System.arraycopy(signature, 4, sig, 1 - r_pad, 20 + r_pad);
} }
@ -380,49 +367,51 @@ public class SignUtils
if (r_pad < 0 || s_pad < 0) 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 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; 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:<br/> * It charaterizes a record/RRset as one of the following classes:<br/>
* <dl> * <dl>
*
* <dt>NORMAL</dt><dd>This record/set is properly within the zone * <dt>NORMAL</dt>
* an subject to all NXT and SIG processing.</dd> * <dd>This record/set is properly within the zone an subject to all NXT
* and SIG processing.</dd>
* <dt>DELEGATION</dt><dd>This is a zone delegation point (or *
* cut). It is used in NXT processing but is not signed.</dd> * <dt>DELEGATION</dt>
* <dd>This is a zone delegation point (or cut). It is used in NXT
* <dt>GLUE</dt><dd>This is a glue record and therefore not * processing but is not signed.</dd>
* properly within the zone. It is not included in NXT or SIG *
* processing. Normally glue records are A records, but this * <dt>GLUE</dt>
* routine calls anything that is below a zone delegation * <dd>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.</dd> * glue.</dd>
*
* <dt>INVALID</dt><dd>This record doesn't even belong in the * <dt>INVALID</dt>
* zone.</dd> * <dd>This record doesn't even belong in the zone.</dd>
*
* </dl><br/> * </dl>
* <br/>
* This method must be called successively on records in the *
* canonical name ordering, and the caller must maintain the * This method must be called successively on records in the canonical name
* last_cut parameter. * ordering, and the caller must maintain the last_cut parameter.
*
* @param zonename the name of the zone that is being processed. * @param zonename the name of the zone that is being processed.
* @param name the name of the record/set under consideration. * @param name the name of the record/set under consideration.
* @param type the type 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 * @param last_cut the name of the last DELEGATION record/set that was
* was encountered while iterating over the zone in canonical * encountered while iterating over the zone in canonical order.
* order.
*/ */
public static int recordSecType(Name zonename, Name name, int type, public static int recordSecType(Name zonename, Name name, int type,
Name last_cut) Name last_cut)
@ -442,8 +431,8 @@ public class SignUtils
// NS record, then we either a DS record or glue. // NS record, then we either a DS record or glue.
if (name.equals(last_cut)) if (name.equals(last_cut))
{ {
if (type == Type.DS || type == Type.NXT || if (type == Type.DS || type == Type.NXT || type == Type.NSEC)
type == Type.NSEC) return RR_NORMAL; return RR_NORMAL;
// actually, this is probably INVALID, but it could be glue. // actually, this is probably INVALID, but it could be glue.
return RR_GLUE; return RR_GLUE;
} }
@ -454,11 +443,12 @@ public class SignUtils
return RR_NORMAL; return RR_NORMAL;
} }
/** Given a canonical ordered list of records from a single zone, /**
* order the raw records into a list of RRsets. * 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, * @param records a list of {@link org.xbill.DNS.Record} objects, in DNSSEC
* in DNSSEC canonical order. * canonical order.
* @return a List of {@link org.xbill.DNS.RRset} objects. * @return a List of {@link org.xbill.DNS.RRset} objects.
*/ */
public static List assembleIntoRRsets(List records) public static List assembleIntoRRsets(List records)
@ -466,19 +456,18 @@ public class SignUtils
RRset rrset = new RRset(); RRset rrset = new RRset();
ArrayList rrsets = new ArrayList(); ArrayList rrsets = new ArrayList();
for (Iterator i = records.iterator(); i.hasNext(); ) for (Iterator i = records.iterator(); i.hasNext();)
{ {
Object o = i.next(); Object o = i.next();
if (! (o instanceof Record)) if (!(o instanceof Record))
{ {
log.warn("assembleIntoRRsets: a non-record object was " + log.warning("assembleIntoRRsets: a non-record object was "
"encountered and skipped: " + o + " (" + o.getClass() + ")"); + "encountered and skipped: " + o + " (" + o.getClass() + ")");
continue; continue;
} }
Record r = (Record) o; Record r = (Record) o;
Name r_name = r.getName();
// First record // First record
if (rrset.getName() == null) if (rrset.getName() == null)
@ -488,11 +477,9 @@ public class SignUtils
} }
// Current record is part of the current RRset. // Current record is part of the current RRset.
if (rrset.getName().equals(r.getName()) && if (rrset.getName().equals(r.getName())
rrset.getDClass() == r.getDClass() && && rrset.getDClass() == r.getDClass()
((r.getType() == Type.RRSIG && && ((r.getType() == Type.RRSIG && rrset.getType() == ((RRSIGRecord) r).getTypeCovered()) || rrset.getType() == r.getType()))
rrset.getType() == ((RRSIGRecord)r).getTypeCovered()) ||
rrset.getType() == r.getType()))
{ {
rrset.addRR(r); rrset.addRR(r);
continue; continue;
@ -512,9 +499,9 @@ public class SignUtils
return rrsets; return rrsets;
} }
/**
/** A little private class to hold information about a given * A little private class to hold information about a given node.
* node. */ */
private static class NodeInfo private static class NodeInfo
{ {
public Name name; public Name name;
@ -537,6 +524,7 @@ public class SignUtils
this.hasOptInSpan = false; this.hasOptInSpan = false;
addType(type); addType(type);
} }
public void addType(int type) public void addType(int type)
{ {
this.typemap.add(new Integer(type)); this.typemap.add(new Integer(type));
@ -547,6 +535,7 @@ public class SignUtils
isSecureNode = true; isSecureNode = true;
} }
} }
public String toString() public String toString()
{ {
StringBuffer sb = new StringBuffer(name.toString()); StringBuffer sb = new StringBuffer(name.toString());
@ -568,16 +557,17 @@ public class SignUtils
} }
} }
/** Given a canonical (by name) ordered list of records in a zone, /**
* generate the NXT records in place. * 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 * Note that the list that the records are stored in must support the
* the listIterator.add() operation. * listIterator.add() operation.
* *
* @param zonename the name of the zone (used to distinguish * @param zonename the name of the zone (used to distinguish between zone
* between zone apex NS RRsets and delegations). * apex NS RRsets and delegations).
* @param records a list of {@link org.xbill.DNS.Record} objects in * @param records a list of {@link org.xbill.DNS.Record} objects in DNSSEC
* DNSSEC canonical order. * canonical order.
*/ */
public static void generateNSECRecords(Name zonename, List records) public static void generateNSECRecords(Name zonename, List records)
{ {
@ -589,7 +579,7 @@ public class SignUtils
Name last_cut = null; Name last_cut = null;
int backup; int backup;
for (ListIterator i = records.listIterator(); i.hasNext(); ) for (ListIterator i = records.listIterator(); i.hasNext();)
{ {
Record r = (Record) i.next(); Record r = (Record) i.next();
Name r_name = r.getName(); Name r_name = r.getName();
@ -621,17 +611,18 @@ public class SignUtils
if (last_node != null) if (last_node != null)
{ {
NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass,
last_node.ttl, current_node.name, last_node.ttl, current_node.name, last_node.getTypes());
last_node.getTypes());
// Note: we have to add this through the iterator, otherwise // Note: we have to add this through the iterator, otherwise
// the next access via the iterator will generate a // the next access via the iterator will generate a
// ConcurrencyModificationException. // ConcurrencyModificationException.
backup = i.nextIndex() - last_node.nsecIndex; backup = i.nextIndex() - last_node.nsecIndex;
for (int j = 0; j < backup; j++) i.previous(); for (int j = 0; j < backup; j++)
i.previous();
i.add(nsec); i.add(nsec);
for (int j = 0; j < backup; j++) i.next(); for (int j = 0; j < backup; j++)
i.next();
log.trace("Generated: " + nsec); log.finer("Generated: " + nsec);
} }
last_node = current_node; last_node = current_node;
@ -646,42 +637,37 @@ public class SignUtils
if (last_node != null) if (last_node != null)
{ {
NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass,
last_node.ttl, current_node.name, last_node.ttl, current_node.name, last_node.getTypes());
last_node.getTypes());
records.add(last_node.nsecIndex - 1, nsec); records.add(last_node.nsecIndex - 1, nsec);
log.trace("Generated: " + nsec); log.finer("Generated: " + nsec);
} }
// Generate last NSEC // Generate last NSEC
NSECRecord nsec = new NSECRecord(current_node.name, current_node.dclass, NSECRecord nsec = new NSECRecord(current_node.name, current_node.dclass,
current_node.ttl, zonename, current_node.ttl, zonename, current_node.getTypes());
current_node.getTypes());
records.add(nsec); records.add(nsec);
log.trace("Generated: " + nsec); log.finer("Generated: " + nsec);
} }
/**
/** Given a canonical (by name) ordered list of records in a zone, * Given a canonical (by name) ordered list of records in a zone, generate
* generate the NXT records in place. * the NXT records in place.
* *
* Note thatthe list that the records are stored in must support * Note thatthe list that the records are stored in must support the
* the <code>listIterator.add</code> operation. * <code>listIterator.add</code> operation.
* *
* @param zonename the name of the zone apex, used to distinguish * @param zonename the name of the zone apex, used to distinguish between
* between authoritative and delegation NS RRsets. * authoritative and delegation NS RRsets.
* @param records a list of {@link org.xbill.DNS.Record}s in DNSSEC * @param records a list of {@link org.xbill.DNS.Record}s in DNSSEC
* canonical order. * canonical order.
* @param includeNames a list of names that should be in the NXT * @param includeNames a list of names that should be in the NXT chain
* chain regardless. This may be null. * regardless. This may be null.
* @param beConservative if true, then Opt-In NXTs will only be * @param beConservative if true, then Opt-In NXTs will only be generated
* generated where there is actually a span of insecure * where there is actually a span of insecure delegations.
* delegations.
*/ */
public static void generateOptInNSECRecords(Name zonename, public static void generateOptInNSECRecords(Name zonename, List records,
List records, List includeNames, boolean beConservative)
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.
@ -697,7 +683,7 @@ public class SignUtils
includeSet = new HashSet(includeNames); includeSet = new HashSet(includeNames);
} }
for (ListIterator i = records.listIterator(); i.hasNext(); ) for (ListIterator i = records.listIterator(); i.hasNext();)
{ {
Record r = (Record) i.next(); Record r = (Record) i.next();
Name r_name = r.getName(); Name r_name = r.getName();
@ -740,17 +726,18 @@ public class SignUtils
last_node.addType(Type.NSEC); last_node.addType(Type.NSEC);
} }
NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass,
last_node.ttl, current_node.name, last_node.ttl, current_node.name, last_node.getTypes());
last_node.getTypes());
// Note: we have to add this through the iterator, otherwise // Note: we have to add this through the iterator, otherwise
// the next access via the iterator will generate a // the next access via the iterator will generate a
// ConcurrencyModificationException. // ConcurrencyModificationException.
backup = i.nextIndex() - last_node.nsecIndex; backup = i.nextIndex() - last_node.nsecIndex;
for (int j = 0; j < backup; j++) i.previous(); for (int j = 0; j < backup; j++)
i.previous();
i.add(nsec); i.add(nsec);
for (int j = 0; j < backup; j++) i.next(); for (int j = 0; j < backup; j++)
i.next();
log.trace("Generated: " + nsec); log.finer("Generated: " + nsec);
} }
if (current_node.isSecureNode) if (current_node.isSecureNode)
@ -779,10 +766,9 @@ public class SignUtils
last_node.addType(Type.NSEC); last_node.addType(Type.NSEC);
} }
NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass, NSECRecord nsec = new NSECRecord(last_node.name, last_node.dclass,
last_node.ttl, current_node.name, last_node.ttl, current_node.name, last_node.getTypes());
last_node.getTypes());
records.add(last_node.nsecIndex - 1, nsec); records.add(last_node.nsecIndex - 1, nsec);
log.trace("Generated: " + nsec); log.finer("Generated: " + nsec);
} }
// Generate last NSEC // Generate last NSEC
@ -794,8 +780,7 @@ public class SignUtils
current_node.addType(Type.NSEC); current_node.addType(Type.NSEC);
} }
nsec = new NSECRecord(current_node.name, current_node.dclass, nsec = new NSECRecord(current_node.name, current_node.dclass,
current_node.ttl, zonename, current_node.ttl, zonename, current_node.getTypes());
current_node.getTypes());
// we can just tack this on the end as we are working on the // we can just tack this on the end as we are working on the
// last node. // last node.
records.add(nsec); records.add(nsec);
@ -809,22 +794,21 @@ public class SignUtils
records.add(last_node.nsecIndex, nsec); records.add(last_node.nsecIndex, nsec);
} }
log.trace("Generated: " + nsec); log.finer("Generated: " + nsec);
} }
/**
/** Given a zone with DNSKEY records at delegation points, convert * Given a zone with DNSKEY records at delegation points, convert those KEY
* those KEY records into their corresponding DS records in place. * records into their corresponding DS records in place.
* *
* @param zonename the name of the zone, used to reliably * @param zonename the name of the zone, used to reliably distinguish the
* distinguish the zone apex from other records. * zone apex from other records.
* @param records a list of {@link org.xbill.DNS.Record} objects. * @param records a list of {@link org.xbill.DNS.Record} objects.
*/ */
public static void generateDSRecords(Name zonename, List records) 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(); Record r = (Record) i.next();
if (r == null) continue; // this should never be true. if (r == null) continue; // this should never be true.
@ -842,36 +826,37 @@ public class SignUtils
} }
} }
/** Given a zone, remove all records that are generated. /**
* Given a zone, remove all records that are generated.
* *
* @param zonename the name of the zone. * @param zonename the name of the zone.
* @param records a list of {@link org.xbill.DNS.Record} objects. * @param records a list of {@link org.xbill.DNS.Record} objects.
*/ */
public static void removeGeneratedRecords(Name zonename, List records) 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(); Record r = (Record) i.next();
if (r.getType() == Type.RRSIG || if (r.getType() == Type.RRSIG || r.getType() == Type.NSEC)
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 * Remove duplicate records from a list of records. This routine presumes
* least on name and RR type. * 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 * @param records a list of {@link org.xbill.DNS.Record} object, in sorted
* sorted order. * order.
*/ */
public static void removeDuplicateRecords(List records) public static void removeDuplicateRecords(List records)
{ {
Record lastrec = null; Record lastrec = null;
for (Iterator i = records.iterator(); i.hasNext(); ) for (Iterator i = records.iterator(); i.hasNext();)
{ {
Record r = (Record) i.next(); Record r = (Record) i.next();
if (lastrec == null) if (lastrec == null)
@ -888,15 +873,15 @@ public class SignUtils
} }
} }
/** Given a DNSKEY record, generate the DS record from it. /**
* Given a DNSKEY record, generate the DS record from it.
* *
* @param keyrec the KEY record in question. * @param keyrec the KEY record in question.
* @param ttl the desired TTL for the generated DS record. If * @param ttl the desired TTL for the generated DS record. If zero, or
* zero, or negative, the original KEY RR's TTL will be used. * negative, the original KEY RR's TTL will be used.
* @return the corresponding {@link org.xbill.DNS.DSRecord} * @return the corresponding {@link org.xbill.DNS.DSRecord}
*/ */
public static DSRecord calculateDSRecord(DNSKEYRecord keyrec, long ttl) public static DSRecord calculateDSRecord(DNSKEYRecord keyrec, long ttl)
throws IOException
{ {
if (keyrec == null) return null; if (keyrec == null) return null;
@ -920,7 +905,7 @@ public class SignUtils
} }
catch (NoSuchAlgorithmException e) catch (NoSuchAlgorithmException e)
{ {
log.error("", e); log.severe(e.toString());
return null; return null;
} }
} }

View File

@ -1,17 +1,21 @@
// $Id: TypeMap.java,v 1.5 2004/03/23 17:53:57 davidb Exp $ // $Id$
// //
// Copyright (C) 2004 Verisign, Inc. // Copyright (C) 2004 Verisign, Inc.
package com.verisignlabs.dnssec.security; 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.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 * This class represents the multiple type maps of the NSEC record. Currently
* map to the int array that org.xbill.DNS.NSECRecord uses. */ * it is just used to convert the wire format type map to the int array that
* org.xbill.DNS.NSECRecord uses.
*/
public class TypeMap public class TypeMap
{ {
@ -42,7 +46,6 @@ public class TypeMap
return typeSet.contains(new Integer(type)); return typeSet.contains(new Integer(type));
} }
public static TypeMap fromTypes(int[] types) public static TypeMap fromTypes(int[] types)
{ {
TypeMap m = new TypeMap(); TypeMap m = new TypeMap();
@ -54,8 +57,10 @@ public class TypeMap
return m; 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) public static TypeMap fromBytes(byte[] map)
{ {
int m = 0; int m = 0;
@ -73,7 +78,7 @@ public class TypeMap
{ {
for (int j = 0; j < 8; j++) 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); typemap.set(map_number * 8 + j);
} }
@ -102,8 +107,8 @@ public class TypeMap
return sb.toString(); return sb.toString();
} }
protected static void mapToWire(DNSOutput out, int[] types, protected static void mapToWire(DNSOutput out, int[] types, int base,
int base, int start, int end) int start, int end)
{ {
// calculate the length of this map by looking at the largest // calculate the length of this map by looking at the largest
// typecode in this section. // 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 each type in our sub-array, set its corresponding bit in the map.
for (int i = start; i < end; i++) for (int i = start; i < end; i++)
{ {
map[ (types[i] & 0xFF) / 8 ] |= ( 1 << (7 - types[i] % 8) ); map[(types[i] & 0xFF) / 8] |= (1 << (7 - types[i] % 8));
} }
// write out the resulting binary bitmap. // write out the resulting binary bitmap.
for (int i = 0; i < map.length; i++) for (int i = 0; i < map.length; i++)
@ -162,7 +167,8 @@ public class TypeMap
Integer[] a = (Integer[]) typeSet.toArray(integerArray); Integer[] a = (Integer[]) typeSet.toArray(integerArray);
int[] res = new int[a.length]; 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(); res[i] = a[i].intValue();
} }

View File

@ -1,4 +1,4 @@
// $Id: ZoneUtils.java,v 1.3 2004/01/15 17:32:18 davidb Exp $ // $Id$
// //
// Copyright (C) 2003 VeriSign, Inc. // Copyright (C) 2003 VeriSign, Inc.
// //
@ -19,41 +19,40 @@
package com.verisignlabs.dnssec.security; package com.verisignlabs.dnssec.security;
import java.util.*; import java.io.BufferedWriter;
import java.io.*; 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.xbill.DNS.Master;
import org.xbill.DNS.Name;
import org.apache.commons.logging.Log; import org.xbill.DNS.RRset;
import org.apache.commons.logging.LogFactory; 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. * This class contains a bunch of utility methods that are generally useful in
* manipulating zones.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author$
* @version $Revision: 1.3 $ * @version $Revision$
*/ */
public class ZoneUtils public class ZoneUtils
{ {
/**
private static Log log; * Load a zone file.
static {
log = LogFactory.getLog(ZoneUtils.class);
}
/** Load a zone file.
* *
* @param zonefile the filename/path of the zonefile to read. * @param zonefile the filename/path of the zonefile to read.
* @param origin the origin to use for the zonefile (may be null if * @param origin the origin to use for the zonefile (may be null if the
* the origin is specified in the zone file itself). * origin is specified in the zone file itself).
* @return a {@link java.util.List} of {@link org.xbill.DNS.Record} * @return a {@link java.util.List} of {@link org.xbill.DNS.Record} objects.
* objects. * @throws IOException if something goes wrong reading the zone file.
* @throws IOException if something goes wrong reading the zone
* file.
*/ */
public static List readZoneFile(String zonefile, Name origin) public static List readZoneFile(String zonefile, Name origin)
throws IOException throws IOException
@ -63,7 +62,7 @@ public class ZoneUtils
Record r = null; Record r = null;
while ( (r = m.nextRecord()) != null ) while ((r = m.nextRecord()) != null)
{ {
records.add(r); records.add(r);
} }
@ -71,12 +70,13 @@ public class ZoneUtils
return records; return records;
} }
/** Write the records out into a zone file. /**
* Write the records out into a zone file.
* *
* @param records a {@link java.util.List} of {@link * @param records a {@link java.util.List} of {@link org.xbill.DNS.Record}
* org.xbill.DNS.Record} objects forming a zone. * objects forming a zone.
* @param zonefile the file to write to. If null or equal to "-", * @param zonefile the file to write to. If null or equal to "-", System.out
* System.out is used. * is used.
*/ */
public static void writeZoneFile(List records, String zonefile) public static void writeZoneFile(List records, String zonefile)
throws IOException throws IOException
@ -92,8 +92,7 @@ public class ZoneUtils
out = new PrintWriter(new BufferedWriter(new FileWriter(zonefile))); 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()); out.println(i.next());
} }
@ -101,8 +100,8 @@ public class ZoneUtils
out.close(); out.close();
} }
/** Given just the list of records, determine the zone name /**
* (origin). * Given just the list of records, determine the zone name (origin).
* *
* @param records a list of {@link org.xbill.DNS.Record} or {@link * @param records a list of {@link org.xbill.DNS.Record} or {@link
* org.xbill.DNS.RRset} objects. * org.xbill.DNS.RRset} objects.
@ -110,7 +109,7 @@ public class ZoneUtils
*/ */
public static Name findZoneName(List records) public static Name findZoneName(List records)
{ {
for (Iterator i = records.iterator(); i.hasNext(); ) for (Iterator i = records.iterator(); i.hasNext();)
{ {
int type = 0; int type = 0;
Name n = null; Name n = null;