Merge changes from experimental branch 2255:2273.
git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@172 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
parent
dec1b802e2
commit
8b1203c243
34
ChangeLog
34
ChangeLog
@ -1,3 +1,37 @@
|
|||||||
|
2009-08-23 David Blacka <davidb@verisignlabs.com>
|
||||||
|
|
||||||
|
* Released version 0.9.4
|
||||||
|
|
||||||
|
2009-07-15 David Blacka <davidb@verisignlabs.com>
|
||||||
|
|
||||||
|
* SignUtils: Fix major issue where the code that generates that
|
||||||
|
canonical RRset given signature data wasn't obeying the "Orig TTL"
|
||||||
|
and "Labels" fields. This is a major issue with verification,
|
||||||
|
although it doesn't affect signature generation.
|
||||||
|
|
||||||
|
* VerifyZone: Fix bug where the whole-zone security status was
|
||||||
|
still wrong: unsigned RRsets shouldn't make the zone Bogus.
|
||||||
|
|
||||||
|
2009-06-12 David Blacka <davidb@verisignlabs.com>
|
||||||
|
|
||||||
|
* VerifyZone: Fix bug in verification logic so that RRsets that
|
||||||
|
never find a valid signature (i.e., only have signatures by keys
|
||||||
|
that aren't in the zone) are considered Bogus. Note that
|
||||||
|
VerifyZone still can't tell if a RRset that should be signed
|
||||||
|
wasn't (or vice versa).
|
||||||
|
|
||||||
|
* dnsjava: Update local copy of dnsjava library. This version
|
||||||
|
adds NSEC3 agorithms to DNSSECVerifier and KEYConverter, emulates
|
||||||
|
DiG's "OPT PSEUDOSECTION" formatting in Message.toString(), and
|
||||||
|
adds a minimal DHCIDRecord type. Note that the DNSjava trunk has
|
||||||
|
a different (although functional similar) version of this type.
|
||||||
|
|
||||||
|
2009-06-09 David Blacka <davidb@verisignlabs.com>
|
||||||
|
|
||||||
|
* VerifyZone: Improve the output.
|
||||||
|
|
||||||
|
* SignKeyset: Add a command line tool for just signing DNSKEY RRsets.
|
||||||
|
|
||||||
2009-02-10 David Blacka <davidb@verisignlabs.com>
|
2009-02-10 David Blacka <davidb@verisignlabs.com>
|
||||||
|
|
||||||
* Released version 0.9.0
|
* Released version 0.9.0
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
thisdir=`dirname $0`
|
thisdir=`dirname $0`
|
||||||
basedir=`cd $thisdir/..; pwd`
|
basedir=`cd $thisdir/..; pwd`
|
||||||
|
|
||||||
ulimit -n `ulimit -H -n`
|
ulimit_max=`ulimit -H -n`
|
||||||
|
if [ $ulimit_max != "unlimited" ]; then
|
||||||
|
ulimit -n $ulimit_max
|
||||||
|
fi
|
||||||
|
|
||||||
# set the classpath
|
# set the classpath
|
||||||
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
thisdir=`dirname $0`
|
thisdir=`dirname $0`
|
||||||
basedir=`cd $thisdir/..; pwd`
|
basedir=`cd $thisdir/..; pwd`
|
||||||
|
|
||||||
ulimit -n `ulimit -H -n`
|
ulimit_max=`ulimit -H -n`
|
||||||
|
if [ $ulimit_max != "unlimited" ]; then
|
||||||
|
ulimit -n $ulimit_max
|
||||||
|
fi
|
||||||
|
|
||||||
# set the classpath
|
# set the classpath
|
||||||
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
thisdir=`dirname $0`
|
thisdir=`dirname $0`
|
||||||
basedir=`cd $thisdir/..; pwd`
|
basedir=`cd $thisdir/..; pwd`
|
||||||
|
|
||||||
ulimit -n `ulimit -H -n`
|
ulimit_max=`ulimit -H -n`
|
||||||
|
if [ $ulimit_max != "unlimited" ]; then
|
||||||
|
ulimit -n $ulimit_max
|
||||||
|
fi
|
||||||
|
|
||||||
# set the classpath
|
# set the classpath
|
||||||
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
||||||
|
19
bin/_jdnssec-signkeyset
Executable file
19
bin/_jdnssec-signkeyset
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
thisdir=`dirname $0`
|
||||||
|
basedir=`cd $thisdir/..; pwd`
|
||||||
|
|
||||||
|
ulimit_max=`ulimit -H -n`
|
||||||
|
if [ $ulimit_max != "unlimited" ]; then
|
||||||
|
ulimit -n $ulimit_max
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set the classpath
|
||||||
|
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
||||||
|
|
||||||
|
for i in $basedir/lib/*.jar $basedir/lib/*.zip; do
|
||||||
|
CLASSPATH="$CLASSPATH":"$i"
|
||||||
|
done
|
||||||
|
export CLASSPATH
|
||||||
|
|
||||||
|
exec java com.verisignlabs.dnssec.cl.SignKeyset "$@"
|
@ -3,7 +3,10 @@
|
|||||||
thisdir=`dirname $0`
|
thisdir=`dirname $0`
|
||||||
basedir=`cd $thisdir/..; pwd`
|
basedir=`cd $thisdir/..; pwd`
|
||||||
|
|
||||||
ulimit -n `ulimit -H -n`
|
ulimit_max=`ulimit -H -n`
|
||||||
|
if [ $ulimit_max != "unlimited" ]; then
|
||||||
|
ulimit -n $ulimit_max
|
||||||
|
fi
|
||||||
|
|
||||||
# set the classpath
|
# set the classpath
|
||||||
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
thisdir=`dirname $0`
|
thisdir=`dirname $0`
|
||||||
basedir=`cd $thisdir/..; pwd`
|
basedir=`cd $thisdir/..; pwd`
|
||||||
|
|
||||||
ulimit -n `ulimit -H -n`
|
ulimit_max=`ulimit -H -n`
|
||||||
|
if [ $ulimit_max != "unlimited" ]; then
|
||||||
|
ulimit -n $ulimit_max
|
||||||
|
fi
|
||||||
|
|
||||||
# set the classpath
|
# set the classpath
|
||||||
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
thisdir=`dirname $0`
|
thisdir=`dirname $0`
|
||||||
basedir=`cd $thisdir/..; pwd`
|
basedir=`cd $thisdir/..; pwd`
|
||||||
|
|
||||||
ulimit -n `ulimit -H -n`
|
ulimit_max=`ulimit -H -n`
|
||||||
|
if [ $ulimit_max != "unlimited" ]; then
|
||||||
|
ulimit -n $ulimit_max
|
||||||
|
fi
|
||||||
|
|
||||||
# set the classpath
|
# set the classpath
|
||||||
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
CLASSPATH=$CLASSPATH:$basedir/build/classes
|
||||||
|
12
bin/jdnssec-signkeyset
Executable file
12
bin/jdnssec-signkeyset
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
thisdir=`dirname $0`
|
||||||
|
basedir=`cd $thisdir/..; pwd`
|
||||||
|
|
||||||
|
# set the classpath
|
||||||
|
for i in $basedir/lib/*.jar $basedir/lib/*.zip $basedir/build/lib/*.jar; do
|
||||||
|
CLASSPATH="$CLASSPATH":"$i"
|
||||||
|
done
|
||||||
|
export CLASSPATH
|
||||||
|
|
||||||
|
exec java com.verisignlabs.dnssec.cl.SignKeyset "$@"
|
Binary file not shown.
BIN
lib/dnsjava-2.0.6-vrsn-4.jar
Normal file
BIN
lib/dnsjava-2.0.6-vrsn-4.jar
Normal file
Binary file not shown.
500
src/com/verisignlabs/dnssec/cl/SignKeyset.java
Normal file
500
src/com/verisignlabs/dnssec/cl/SignKeyset.java
Normal file
@ -0,0 +1,500 @@
|
|||||||
|
// $Id: SignZone.java 2235 2009-02-07 20:37:29Z davidb $
|
||||||
|
//
|
||||||
|
// Copyright (C) 2001-2003, 2009 VeriSign, Inc.
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
// USA
|
||||||
|
|
||||||
|
package com.verisignlabs.dnssec.cl;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.logging.Handler;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.apache.commons.cli.AlreadySelectedException;
|
||||||
|
import org.apache.commons.cli.CommandLine;
|
||||||
|
import org.apache.commons.cli.CommandLineParser;
|
||||||
|
import org.apache.commons.cli.HelpFormatter;
|
||||||
|
import org.apache.commons.cli.OptionBuilder;
|
||||||
|
import org.apache.commons.cli.Options;
|
||||||
|
import org.apache.commons.cli.PosixParser;
|
||||||
|
import org.apache.commons.cli.UnrecognizedOptionException;
|
||||||
|
import org.xbill.DNS.DNSSEC;
|
||||||
|
import org.xbill.DNS.Name;
|
||||||
|
import org.xbill.DNS.RRset;
|
||||||
|
import org.xbill.DNS.Record;
|
||||||
|
import org.xbill.DNS.Type;
|
||||||
|
|
||||||
|
import com.verisignlabs.dnssec.security.BINDKeyUtils;
|
||||||
|
import com.verisignlabs.dnssec.security.DnsKeyPair;
|
||||||
|
import com.verisignlabs.dnssec.security.DnsSecVerifier;
|
||||||
|
import com.verisignlabs.dnssec.security.JCEDnsSecSigner;
|
||||||
|
import com.verisignlabs.dnssec.security.SignUtils;
|
||||||
|
import com.verisignlabs.dnssec.security.ZoneUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class forms the command line implementation of a DNSSEC keyset signer.
|
||||||
|
* Instead of being able to sign an entire zone, it will just sign a given
|
||||||
|
* DNSKEY RRset.
|
||||||
|
*
|
||||||
|
* @author David Blacka (original)
|
||||||
|
* @author $Author: davidb $
|
||||||
|
* @version $Revision: 2235 $
|
||||||
|
*/
|
||||||
|
public class SignKeyset {
|
||||||
|
private static Logger log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an inner class used to hold all of the command line option state.
|
||||||
|
*/
|
||||||
|
private static class CLIState {
|
||||||
|
private Options opts;
|
||||||
|
private File keyDirectory = null;
|
||||||
|
public String[] keyFiles = null;
|
||||||
|
public String keysetFile = null;
|
||||||
|
public Date start = null;
|
||||||
|
public Date expire = null;
|
||||||
|
public String inputfile = null;
|
||||||
|
public String outputfile = null;
|
||||||
|
public boolean verifySigs = false;
|
||||||
|
|
||||||
|
public CLIState() {
|
||||||
|
setupCLI();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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", "verify", false, "verify generated signatures>");
|
||||||
|
|
||||||
|
OptionBuilder.hasOptionalArg();
|
||||||
|
OptionBuilder.withLongOpt("verbose");
|
||||||
|
OptionBuilder.withArgName("level");
|
||||||
|
OptionBuilder.withDescription("verbosity level.");
|
||||||
|
// Argument options
|
||||||
|
opts.addOption(OptionBuilder.create('v'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("dir");
|
||||||
|
OptionBuilder.withLongOpt("key-directory");
|
||||||
|
OptionBuilder.withDescription("directory to find key files (default '.').");
|
||||||
|
opts.addOption(OptionBuilder.create('D'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("time/offset");
|
||||||
|
OptionBuilder.withLongOpt("start-time");
|
||||||
|
OptionBuilder.withDescription("signature starting time (default is now - 1 hour)");
|
||||||
|
opts.addOption(OptionBuilder.create('s'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("time/offset");
|
||||||
|
OptionBuilder.withLongOpt("expire-time");
|
||||||
|
OptionBuilder.withDescription("signature expiration time (default is start-time + 30 days).");
|
||||||
|
opts.addOption(OptionBuilder.create('e'));
|
||||||
|
|
||||||
|
OptionBuilder.hasArg();
|
||||||
|
OptionBuilder.withArgName("outfile");
|
||||||
|
OptionBuilder.withDescription("file the signed keyset is written to.");
|
||||||
|
opts.addOption(OptionBuilder.create('f'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parseCommandLine(String[] args)
|
||||||
|
throws org.apache.commons.cli.ParseException, ParseException,
|
||||||
|
IOException {
|
||||||
|
CommandLineParser cli_parser = new PosixParser();
|
||||||
|
CommandLine cli = cli_parser.parse(opts, args);
|
||||||
|
|
||||||
|
String optstr = null;
|
||||||
|
if (cli.hasOption('h')) usage();
|
||||||
|
|
||||||
|
if (cli.hasOption('v')) {
|
||||||
|
int value = parseInt(cli.getOptionValue('v'), 5);
|
||||||
|
Logger rootLogger = Logger.getLogger("");
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
rootLogger.setLevel(Level.OFF);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
default:
|
||||||
|
rootLogger.setLevel(Level.INFO);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
rootLogger.setLevel(Level.FINE);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
rootLogger.setLevel(Level.ALL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Handler[] handlers = rootLogger.getHandlers();
|
||||||
|
for (int i = 0; i < handlers.length; i++)
|
||||||
|
handlers[i].setLevel(rootLogger.getLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cli.hasOption('a')) verifySigs = true;
|
||||||
|
|
||||||
|
if ((optstr = cli.getOptionValue('D')) != null) {
|
||||||
|
keyDirectory = new File(optstr);
|
||||||
|
if (!keyDirectory.isDirectory()) {
|
||||||
|
System.err.println("error: " + optstr
|
||||||
|
+ " is not a directory");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((optstr = cli.getOptionValue('s')) != null) {
|
||||||
|
start = convertDuration(null, optstr);
|
||||||
|
} else {
|
||||||
|
// default is now - 1 hour.
|
||||||
|
start = new Date(System.currentTimeMillis() - (3600 * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((optstr = cli.getOptionValue('e')) != null) {
|
||||||
|
expire = convertDuration(start, optstr);
|
||||||
|
} else {
|
||||||
|
expire = convertDuration(start, "+2592000"); // 30 days
|
||||||
|
}
|
||||||
|
|
||||||
|
outputfile = cli.getOptionValue('f');
|
||||||
|
|
||||||
|
String[] files = cli.getArgs();
|
||||||
|
|
||||||
|
if (files.length < 1) {
|
||||||
|
System.err.println("error: missing zone file and/or key files");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
inputfile = files[0];
|
||||||
|
if (files.length > 1) {
|
||||||
|
keyFiles = new String[files.length - 1];
|
||||||
|
System.arraycopy(files, 1, keyFiles, 0, files.length - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Print out the usage and help statements, then quit. */
|
||||||
|
private void usage() {
|
||||||
|
HelpFormatter f = new HelpFormatter();
|
||||||
|
|
||||||
|
PrintWriter out = new PrintWriter(System.err);
|
||||||
|
|
||||||
|
// print our own usage statement:
|
||||||
|
out.println("usage: jdnssec-signkeyset [..options..] "
|
||||||
|
+ "dnskeyset_file [key_file ...] ");
|
||||||
|
f.printHelp(out, 75, "signZone.sh", null, opts,
|
||||||
|
HelpFormatter.DEFAULT_LEFT_PAD,
|
||||||
|
HelpFormatter.DEFAULT_DESC_PAD,
|
||||||
|
"\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
|
||||||
|
|
||||||
|
out.flush();
|
||||||
|
System.exit(64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is just a convenience method for parsing integers from strings.
|
||||||
|
*
|
||||||
|
* @param s
|
||||||
|
* the string to parse.
|
||||||
|
* @param def
|
||||||
|
* the default value, if the string doesn't parse.
|
||||||
|
* @return the parsed integer, or the default.
|
||||||
|
*/
|
||||||
|
private static int parseInt(String s, int def) {
|
||||||
|
try {
|
||||||
|
int v = Integer.parseInt(s);
|
||||||
|
return v;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the generated signatures.
|
||||||
|
*
|
||||||
|
* @param zonename
|
||||||
|
* the origin name of the zone.
|
||||||
|
* @param records
|
||||||
|
* a list of {@link org.xbill.DNS.Record}s.
|
||||||
|
* @param keypairs
|
||||||
|
* a list of keypairs used the sign the zone.
|
||||||
|
* @return true if all of the signatures validated.
|
||||||
|
*/
|
||||||
|
private static boolean verifySigs(Name zonename, List records, List keypairs) {
|
||||||
|
boolean secure = true;
|
||||||
|
|
||||||
|
DnsSecVerifier verifier = new DnsSecVerifier();
|
||||||
|
|
||||||
|
for (Iterator i = keypairs.iterator(); i.hasNext();) {
|
||||||
|
verifier.addTrustedKey((DnsKeyPair) i.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
verifier.setVerifyAllSigs(true);
|
||||||
|
|
||||||
|
List rrsets = SignUtils.assembleIntoRRsets(records);
|
||||||
|
|
||||||
|
for (Iterator i = rrsets.iterator(); i.hasNext();) {
|
||||||
|
RRset rrset = (RRset) i.next();
|
||||||
|
|
||||||
|
// skip unsigned rrsets.
|
||||||
|
if (!rrset.sigs().hasNext()) continue;
|
||||||
|
|
||||||
|
int result = verifier.verify(rrset, null);
|
||||||
|
|
||||||
|
if (result != DNSSEC.Secure) {
|
||||||
|
log.fine("Signatures did not verify for RRset: (" + result
|
||||||
|
+ "): " + rrset);
|
||||||
|
secure = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return secure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the key pairs from the key files.
|
||||||
|
*
|
||||||
|
* @param keyfiles
|
||||||
|
* a string array containing the base names or paths of the keys
|
||||||
|
* to be loaded.
|
||||||
|
* @param start_index
|
||||||
|
* the starting index of keyfiles string array to use. This
|
||||||
|
* allows us to use the straight command line argument array.
|
||||||
|
* @param inDirectory
|
||||||
|
* the directory to look in (may be null).
|
||||||
|
* @return a list of keypair objects.
|
||||||
|
*/
|
||||||
|
private static List getKeys(String[] keyfiles, int start_index,
|
||||||
|
File inDirectory) throws IOException {
|
||||||
|
if (keyfiles == null) return null;
|
||||||
|
|
||||||
|
int len = keyfiles.length - start_index;
|
||||||
|
if (len <= 0) return null;
|
||||||
|
|
||||||
|
ArrayList keys = new ArrayList(len);
|
||||||
|
|
||||||
|
for (int i = start_index; i < keyfiles.length; i++) {
|
||||||
|
DnsKeyPair k = BINDKeyUtils.loadKeyPair(keyfiles[i], inDirectory);
|
||||||
|
if (k != null) keys.add(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class KeyFileFilter implements FileFilter {
|
||||||
|
private String prefix;
|
||||||
|
|
||||||
|
public KeyFileFilter(Name origin) {
|
||||||
|
prefix = "K" + origin.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean accept(File pathname) {
|
||||||
|
if (!pathname.isFile()) return false;
|
||||||
|
String name = pathname.getName();
|
||||||
|
if (name.startsWith(prefix) && name.endsWith(".private"))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List findZoneKeys(File inDirectory, Name zonename)
|
||||||
|
throws IOException {
|
||||||
|
if (inDirectory == null) {
|
||||||
|
inDirectory = new File(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the list of "K<zone>.*.private files.
|
||||||
|
FileFilter filter = new KeyFileFilter(zonename);
|
||||||
|
File[] files = inDirectory.listFiles(filter);
|
||||||
|
|
||||||
|
// read in all of the records
|
||||||
|
ArrayList keys = new ArrayList();
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
DnsKeyPair p = BINDKeyUtils.loadKeyPair(files[i].getName(),
|
||||||
|
inDirectory);
|
||||||
|
keys.add(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys.size() > 0) return keys;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate a date/time from a command line time/offset duration string.
|
||||||
|
*
|
||||||
|
* @param start
|
||||||
|
* the start time to calculate offsets from.
|
||||||
|
* @param duration
|
||||||
|
* the time/offset string to parse.
|
||||||
|
* @return the calculated time.
|
||||||
|
*/
|
||||||
|
private static Date convertDuration(Date start, String duration)
|
||||||
|
throws ParseException {
|
||||||
|
if (start == null) start = new Date();
|
||||||
|
if (duration.startsWith("now")) {
|
||||||
|
start = new Date();
|
||||||
|
if (duration.indexOf("+") < 0) return start;
|
||||||
|
|
||||||
|
duration = duration.substring(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duration.startsWith("+")) {
|
||||||
|
long offset = (long) parseInt(duration.substring(1), 0) * 1000;
|
||||||
|
return new Date(start.getTime() + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||||
|
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
|
return dateFormatter.parse(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void execute(CLIState state) throws Exception {
|
||||||
|
// Read in the zone
|
||||||
|
List records = ZoneUtils.readZoneFile(state.inputfile, null);
|
||||||
|
if (records == null || records.size() == 0) {
|
||||||
|
System.err.println("error: empty keyset file");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure that all records are DNSKEYs with the same name.
|
||||||
|
Name keysetName = null;
|
||||||
|
RRset keyset = new RRset();
|
||||||
|
for (Iterator i = records.iterator(); i.hasNext();) {
|
||||||
|
Record r = (Record) i.next();
|
||||||
|
if (r.getType() != Type.DNSKEY) {
|
||||||
|
System.err.println("error: Non DNSKEY RR found in keyset: " + r);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (keysetName == null) {
|
||||||
|
keysetName = r.getName();
|
||||||
|
}
|
||||||
|
if (!r.getName().equals(keysetName)) {
|
||||||
|
System.err.println("error: DNSKEY with a different name found!");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
keyset.addRR(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyset.size() == 0) {
|
||||||
|
System.err.println("error: No DNSKEYs found in keyset file");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the key pairs.
|
||||||
|
List keypairs = getKeys(state.keyFiles, 0, state.keyDirectory);
|
||||||
|
|
||||||
|
// If we *still* don't have any key pairs, look for keys the key
|
||||||
|
// directory
|
||||||
|
// that match
|
||||||
|
if (keypairs == null) {
|
||||||
|
keypairs = findZoneKeys(state.keyDirectory, keysetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there *still* aren't any ZSKs defined, bail.
|
||||||
|
if (keypairs == null || keypairs.size() == 0) {
|
||||||
|
System.err.println("error: No signing keys could be determined.");
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// default the output file, if not set.
|
||||||
|
if (state.outputfile == null) {
|
||||||
|
if (keysetName.isAbsolute()) {
|
||||||
|
state.outputfile = keysetName + "signed_keyset";
|
||||||
|
} else {
|
||||||
|
state.outputfile = keysetName + ".signed_keyset";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JCEDnsSecSigner signer = new JCEDnsSecSigner();
|
||||||
|
|
||||||
|
List sigs = signer.signRRset(keyset, keypairs, state.start,
|
||||||
|
state.expire);
|
||||||
|
for (Iterator i = sigs.iterator(); i.hasNext();) {
|
||||||
|
keyset.addRR((Record) i.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
// write out the signed RRset
|
||||||
|
List signed_records = new ArrayList();
|
||||||
|
for (Iterator i = keyset.rrs(); i.hasNext();) {
|
||||||
|
signed_records.add(i.next());
|
||||||
|
}
|
||||||
|
for (Iterator i = keyset.sigs(); i.hasNext();) {
|
||||||
|
signed_records.add(i.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
// write out the signed zone
|
||||||
|
// force multiline mode for now
|
||||||
|
org.xbill.DNS.Options.set("multiline");
|
||||||
|
ZoneUtils.writeZoneFile(signed_records, state.outputfile);
|
||||||
|
|
||||||
|
if (state.verifySigs) {
|
||||||
|
log.fine("verifying generated signatures");
|
||||||
|
boolean res = verifySigs(keysetName, signed_records, keypairs);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
System.out.println("Generated signatures verified");
|
||||||
|
// log.info("Generated signatures verified");
|
||||||
|
} else {
|
||||||
|
System.out.println("Generated signatures did not verify.");
|
||||||
|
// log.warn("Generated signatures did not verify.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
CLIState state = new CLIState();
|
||||||
|
try {
|
||||||
|
state.parseCommandLine(args);
|
||||||
|
} catch (UnrecognizedOptionException e) {
|
||||||
|
System.err.println("error: unknown option encountered: "
|
||||||
|
+ e.getMessage());
|
||||||
|
state.usage();
|
||||||
|
} catch (AlreadySelectedException e) {
|
||||||
|
System.err.println("error: mutually exclusive options have "
|
||||||
|
+ "been selected:\n " + e.getMessage());
|
||||||
|
state.usage();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("error: unknown command line parsing exception:");
|
||||||
|
e.printStackTrace();
|
||||||
|
state.usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
log = Logger.getLogger(SignKeyset.class.toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
execute(state);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -75,8 +75,10 @@ public class VerifyZone
|
|||||||
// boolean options
|
// boolean options
|
||||||
opts.addOption("h", "help", false, "Print this message.");
|
opts.addOption("h", "help", false, "Print this message.");
|
||||||
opts.addOption("s", "strict", false,
|
opts.addOption("s", "strict", false,
|
||||||
"Zone will only be considered valid if all "
|
"Zone will only be considered valid if all "
|
||||||
+ "signatures could be cryptographically verified");
|
+ "signatures could be cryptographically verified");
|
||||||
|
opts.addOption("m", "multiline", false,
|
||||||
|
"log DNS records using 'multiline' format");
|
||||||
|
|
||||||
// Argument options
|
// Argument options
|
||||||
OptionBuilder.hasArg();
|
OptionBuilder.hasArg();
|
||||||
@ -112,25 +114,33 @@ public class VerifyZone
|
|||||||
|
|
||||||
if (cli.hasOption('v'))
|
if (cli.hasOption('v'))
|
||||||
{
|
{
|
||||||
int value = parseInt(cli.getOptionValue('v'), 5);
|
int value = parseInt(cli.getOptionValue('v'), 1);
|
||||||
Logger rootLogger = Logger.getLogger("");
|
Logger rootLogger = Logger.getLogger("");
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
rootLogger.setLevel(Level.OFF);
|
rootLogger.setLevel(Level.OFF);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 1:
|
||||||
default:
|
rootLogger.setLevel(Level.INFO);
|
||||||
rootLogger.setLevel(Level.FINE);
|
break;
|
||||||
break;
|
case 5:
|
||||||
case 6:
|
default:
|
||||||
rootLogger.setLevel(Level.ALL);
|
rootLogger.setLevel(Level.FINE);
|
||||||
break;
|
break;
|
||||||
|
case 6:
|
||||||
|
rootLogger.setLevel(Level.ALL);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cli.hasOption('s')) strict = true;
|
if (cli.hasOption('s')) strict = true;
|
||||||
|
|
||||||
|
if (cli.hasOption('m'))
|
||||||
|
{
|
||||||
|
org.xbill.DNS.Options.set("multiline");
|
||||||
|
}
|
||||||
|
|
||||||
if ((optstr = cli.getOptionValue('d')) != null)
|
if ((optstr = cli.getOptionValue('d')) != null)
|
||||||
{
|
{
|
||||||
keydir = new File(optstr);
|
keydir = new File(optstr);
|
||||||
@ -191,8 +201,7 @@ public class VerifyZone
|
|||||||
// print our own usage statement:
|
// print our own usage statement:
|
||||||
f.printHelp(out, 75, "jdnssec-verifyzone [..options..] zonefile "
|
f.printHelp(out, 75, "jdnssec-verifyzone [..options..] zonefile "
|
||||||
+ "[keyfile [keyfile...]]", null, opts,
|
+ "[keyfile [keyfile...]]", null, opts,
|
||||||
HelpFormatter.DEFAULT_LEFT_PAD,
|
HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD, null);
|
||||||
HelpFormatter.DEFAULT_DESC_PAD, null);
|
|
||||||
|
|
||||||
out.flush();
|
out.flush();
|
||||||
System.exit(64);
|
System.exit(64);
|
||||||
@ -223,6 +232,19 @@ public class VerifyZone
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String reasonListToString(List reasons)
|
||||||
|
{
|
||||||
|
if (reasons == null) return "";
|
||||||
|
StringBuffer out = new StringBuffer();
|
||||||
|
for (Iterator i = reasons.iterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
out.append("Reason: ");
|
||||||
|
out.append((String) i.next());
|
||||||
|
if (i.hasNext()) out.append("\n");
|
||||||
|
}
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
|
|
||||||
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.
|
||||||
@ -234,18 +256,24 @@ public class VerifyZone
|
|||||||
{
|
{
|
||||||
DnsKeyPair pair = (DnsKeyPair) i.next();
|
DnsKeyPair pair = (DnsKeyPair) i.next();
|
||||||
if (pair.getPublic() == null) continue;
|
if (pair.getPublic() == null) continue;
|
||||||
|
log.info("Adding trusted key: " + pair.getDNSKEYRecord() + " ; keytag = "
|
||||||
|
+ pair.getDNSKEYFootprint());
|
||||||
verifier.addTrustedKey(pair);
|
verifier.addTrustedKey(pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
List rrsets = SignUtils.assembleIntoRRsets(records);
|
List rrsets = SignUtils.assembleIntoRRsets(records);
|
||||||
|
|
||||||
|
List reasons = new ArrayList();
|
||||||
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();)
|
Iterator j = rrset.sigs();
|
||||||
|
// Set the default result based on whether or not this was a signed RRset.
|
||||||
|
byte rrset_result = (byte) (j.hasNext() ? DNSSEC.Failed : DNSSEC.Secure);
|
||||||
|
while (j.hasNext())
|
||||||
{
|
{
|
||||||
Object o = j.next();
|
Object o = j.next();
|
||||||
if (!(o instanceof RRSIGRecord))
|
if (!(o instanceof RRSIGRecord))
|
||||||
@ -255,14 +283,18 @@ public class VerifyZone
|
|||||||
}
|
}
|
||||||
RRSIGRecord sigrec = (RRSIGRecord) o;
|
RRSIGRecord sigrec = (RRSIGRecord) o;
|
||||||
|
|
||||||
byte res = verifier.verifySignature(rrset, sigrec, null);
|
reasons.clear();
|
||||||
|
byte res = verifier.verifySignature(rrset, sigrec, null, reasons);
|
||||||
if (res != DNSSEC.Secure)
|
if (res != DNSSEC.Secure)
|
||||||
{
|
{
|
||||||
log.info("Signature failed to verify RRset: " + rrset + "\nsig: "
|
log.info("Signature failed to verify RRset:\n rr: "
|
||||||
+ sigrec);
|
+ ZoneUtils.rrsetToString(rrset, false) + "\n sig: " + sigrec
|
||||||
|
+ "\n" + reasonListToString(reasons));
|
||||||
}
|
}
|
||||||
if (res < result) result = res;
|
if (res > rrset_result) rrset_result = res;
|
||||||
}
|
}
|
||||||
|
if (rrset_result != DNSSEC.Secure) result = DNSSEC.Failed;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -327,19 +359,19 @@ public class VerifyZone
|
|||||||
|
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case DNSSEC.Failed:
|
case DNSSEC.Failed:
|
||||||
|
System.out.println("zone did not verify.");
|
||||||
|
System.exit(1);
|
||||||
|
break;
|
||||||
|
case DNSSEC.Insecure:
|
||||||
|
if (state.strict)
|
||||||
|
{
|
||||||
System.out.println("zone did not verify.");
|
System.out.println("zone did not verify.");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
break;
|
}
|
||||||
case DNSSEC.Insecure:
|
case DNSSEC.Secure:
|
||||||
if (state.strict)
|
System.out.println("zone verified.");
|
||||||
{
|
break;
|
||||||
System.out.println("zone did not verify.");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
case DNSSEC.Secure:
|
|
||||||
System.out.println("zone verified.");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
@ -354,7 +386,8 @@ public class VerifyZone
|
|||||||
}
|
}
|
||||||
catch (UnrecognizedOptionException e)
|
catch (UnrecognizedOptionException e)
|
||||||
{
|
{
|
||||||
System.err.println("error: unknown option encountered: " + e.getMessage());
|
System.err
|
||||||
|
.println("error: unknown option encountered: " + e.getMessage());
|
||||||
state.usage();
|
state.usage();
|
||||||
}
|
}
|
||||||
catch (AlreadySelectedException e)
|
catch (AlreadySelectedException e)
|
||||||
|
@ -95,7 +95,10 @@ public class DnsSecVerifier implements Verifier
|
|||||||
{
|
{
|
||||||
DnsKeyPair p = (DnsKeyPair) i.next();
|
DnsKeyPair p = (DnsKeyPair) i.next();
|
||||||
if (p.getDNSKEYAlgorithm() == algorithm
|
if (p.getDNSKEYAlgorithm() == algorithm
|
||||||
&& p.getDNSKEYFootprint() == keyid) { return p; }
|
&& p.getDNSKEYFootprint() == keyid)
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -164,8 +167,10 @@ public class DnsSecVerifier implements Verifier
|
|||||||
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) { return new DnsKeyPair(
|
&& keyrec.getFootprint() == footprint)
|
||||||
keyrec, (PrivateKey) null); }
|
{
|
||||||
|
return new DnsKeyPair(keyrec, (PrivateKey) null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -183,17 +188,21 @@ public class DnsSecVerifier implements Verifier
|
|||||||
return pair;
|
return pair;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte validateSignature(RRset rrset, RRSIGRecord sigrec)
|
private byte validateSignature(RRset rrset, RRSIGRecord sigrec, List reasons)
|
||||||
{
|
{
|
||||||
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.fine("Signature name does not match RRset name");
|
||||||
|
if (reasons != null)
|
||||||
|
reasons.add("Signature name does not match RRset name");
|
||||||
return DNSSEC.Failed;
|
return DNSSEC.Failed;
|
||||||
}
|
}
|
||||||
if (rrset.getType() != sigrec.getTypeCovered())
|
if (rrset.getType() != sigrec.getTypeCovered())
|
||||||
{
|
{
|
||||||
log.info("Signature type does not match RRset type");
|
log.fine("Signature type does not match RRset type");
|
||||||
|
if (reasons != null)
|
||||||
|
reasons.add("Signature type does not match RRset type");
|
||||||
}
|
}
|
||||||
|
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
@ -208,7 +217,8 @@ public class DnsSecVerifier implements Verifier
|
|||||||
}
|
}
|
||||||
if (now.before(start))
|
if (now.before(start))
|
||||||
{
|
{
|
||||||
log.info("Signature is not yet valid");
|
log.fine("Signature is not yet valid");
|
||||||
|
if (reasons != null) reasons.add("Signature not yet valid");
|
||||||
return DNSSEC.Failed;
|
return DNSSEC.Failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,8 +231,9 @@ public class DnsSecVerifier implements Verifier
|
|||||||
}
|
}
|
||||||
if (now.after(expire))
|
if (now.after(expire))
|
||||||
{
|
{
|
||||||
log.info("Signature has expired (now = " + now + ", sig expires = "
|
log.fine("Signature has expired (now = " + now + ", sig expires = "
|
||||||
+ expire);
|
+ expire);
|
||||||
|
if (reasons != null) reasons.add("Signature has expired.");
|
||||||
return DNSSEC.Failed;
|
return DNSSEC.Failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,25 +241,32 @@ public class DnsSecVerifier implements Verifier
|
|||||||
return DNSSEC.Secure;
|
return DNSSEC.Secure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache)
|
||||||
|
{
|
||||||
|
return verifySignature(rrset, sigrec, cache, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify an RRset against a particular signature.
|
* Verify an RRset against a particular signature.
|
||||||
*
|
*
|
||||||
* @return DNSSEC.Secure if the signature verfied, DNSSEC.Failed if it did not
|
* @return DNSSEC.Secure if the signature verified, DNSSEC.Failed if it did
|
||||||
* verify (for any reason), and DNSSEC.Insecure if verification could
|
* not verify (for any reason), and DNSSEC.Insecure if verification
|
||||||
* not be completed (usually because the public key was not
|
* could not be completed (usually because the public key was not
|
||||||
* available).
|
* available).
|
||||||
*/
|
*/
|
||||||
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache)
|
public byte verifySignature(RRset rrset, RRSIGRecord sigrec, Cache cache,
|
||||||
|
List reasons)
|
||||||
{
|
{
|
||||||
byte result = validateSignature(rrset, sigrec);
|
byte result = validateSignature(rrset, sigrec, reasons);
|
||||||
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
|
||||||
sigrec.getAlgorithm(), sigrec.getFootprint());
|
.getAlgorithm(), sigrec.getFootprint());
|
||||||
|
|
||||||
if (keypair == null)
|
if (keypair == null)
|
||||||
{
|
{
|
||||||
log.info("could not find appropriate key");
|
if (reasons != null) reasons.add("Could not find matching trusted key");
|
||||||
|
log.fine("could not find matching trusted key");
|
||||||
return DNSSEC.Insecure;
|
return DNSSEC.Insecure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +288,9 @@ public class DnsSecVerifier implements Verifier
|
|||||||
|
|
||||||
if (!signer.verify(sig))
|
if (!signer.verify(sig))
|
||||||
{
|
{
|
||||||
log.info("Signature failed to verify cryptographically");
|
if (reasons != null)
|
||||||
|
reasons.add("Signature failed to verify cryptographically");
|
||||||
|
log.fine("Signature failed to verify cryptographically");
|
||||||
return DNSSEC.Failed;
|
return DNSSEC.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +304,8 @@ public class DnsSecVerifier implements Verifier
|
|||||||
{
|
{
|
||||||
log.severe("Security error: " + e);
|
log.severe("Security error: " + e);
|
||||||
}
|
}
|
||||||
|
if (reasons != null)
|
||||||
|
reasons.add("Signature failed to verify due to exception");
|
||||||
log.fine("Signature failed to verify due to exception");
|
log.fine("Signature failed to verify due to exception");
|
||||||
return DNSSEC.Insecure;
|
return DNSSEC.Insecure;
|
||||||
}
|
}
|
||||||
@ -303,7 +324,7 @@ public class DnsSecVerifier implements Verifier
|
|||||||
|
|
||||||
if (!i.hasNext())
|
if (!i.hasNext())
|
||||||
{
|
{
|
||||||
log.info("RRset failed to verify due to lack of signatures");
|
log.fine("RRset failed to verify due to lack of signatures");
|
||||||
return DNSSEC.Insecure;
|
return DNSSEC.Insecure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ public class JCEDnsSecSigner
|
|||||||
if (keypairs.size() == 0) return null;
|
if (keypairs.size() == 0) return null;
|
||||||
|
|
||||||
// first, pre-calculate the RRset bytes.
|
// first, pre-calculate the RRset bytes.
|
||||||
byte[] rrset_data = SignUtils.generateCanonicalRRsetData(rrset);
|
byte[] rrset_data = SignUtils.generateCanonicalRRsetData(rrset, 0, 0);
|
||||||
|
|
||||||
ArrayList sigs = new ArrayList(keypairs.size());
|
ArrayList sigs = new ArrayList(keypairs.size());
|
||||||
|
|
||||||
|
@ -149,24 +149,61 @@ 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
|
* @param rrset
|
||||||
* the RRset to convert.
|
* the RRset to convert.
|
||||||
* @return the canonical wire line format of the RRset. This is the second
|
* @param ttl
|
||||||
|
* the TTL to use when canonicalizing -- this is generally the
|
||||||
|
* TTL of the signature if there is a pre-existing signature. If
|
||||||
|
* not it is just the ttl of the rrset itself.
|
||||||
|
* @param labels
|
||||||
|
* the labels field of the signature, or 0.
|
||||||
|
* @return the canonical wire line format of the rrset. This is the second
|
||||||
* part of data to be signed.
|
* part of data to be signed.
|
||||||
*/
|
*/
|
||||||
public static byte[] generateCanonicalRRsetData(RRset rrset)
|
public static byte[] generateCanonicalRRsetData(RRset rrset, long ttl,
|
||||||
|
int labels)
|
||||||
{
|
{
|
||||||
DNSOutput image = new DNSOutput();
|
DNSOutput image = new DNSOutput();
|
||||||
|
|
||||||
// now convert load the wire format records in the RRset into a
|
if (ttl == 0) ttl = rrset.getTTL();
|
||||||
|
Name n = rrset.getName();
|
||||||
|
if (labels == 0)
|
||||||
|
{
|
||||||
|
labels = n.labels();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// correct for Name()'s conception of label count.
|
||||||
|
labels++;
|
||||||
|
}
|
||||||
|
boolean wildcardName = false;
|
||||||
|
if (n.labels() != labels)
|
||||||
|
{
|
||||||
|
n = n.wild(n.labels() - labels);
|
||||||
|
wildcardName = true;
|
||||||
|
log.fine("Detected wildcard expansion: " + rrset.getName()
|
||||||
|
+ " changed to " + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now convert 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();
|
||||||
|
if (r.getTTL() != ttl || wildcardName)
|
||||||
|
{
|
||||||
|
// If necessary, we need to create a new record with a new ttl
|
||||||
|
// or ownername.
|
||||||
|
// In the TTL case, this avoids changing the ttl in the
|
||||||
|
// response.
|
||||||
|
r = Record.newRecord(n, r.getType(), r.getDClass(), ttl, r
|
||||||
|
.rdataToWireCanonical());
|
||||||
|
}
|
||||||
byte[] wire_fmt = r.toWireCanonical();
|
byte[] wire_fmt = r.toWireCanonical();
|
||||||
canonical_rrs.add(wire_fmt);
|
canonical_rrs.add(wire_fmt);
|
||||||
}
|
}
|
||||||
@ -202,7 +239,9 @@ public class SignUtils
|
|||||||
public static byte[] generateSigData(RRset rrset, RRSIGRecord presig)
|
public static byte[] generateSigData(RRset rrset, RRSIGRecord presig)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
byte[] rrset_data = generateCanonicalRRsetData(rrset);
|
byte[] rrset_data = generateCanonicalRRsetData(rrset,
|
||||||
|
presig.getOrigTTL(),
|
||||||
|
presig.getLabels());
|
||||||
|
|
||||||
return generateSigData(rrset_data, presig);
|
return generateSigData(rrset_data, presig);
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ public class ZoneUtils
|
|||||||
{
|
{
|
||||||
res.add(r);
|
res.add(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (o instanceof RRset)
|
else if (o instanceof RRset)
|
||||||
{
|
{
|
||||||
RRset r = (RRset) o;
|
RRset r = (RRset) o;
|
||||||
@ -170,5 +170,26 @@ public class ZoneUtils
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
/** This is an alternate way to format an RRset into a string */
|
||||||
|
public static String rrsetToString(RRset rrset, boolean includeSigs)
|
||||||
|
{
|
||||||
|
StringBuffer out = new StringBuffer();
|
||||||
|
|
||||||
|
for (Iterator i = rrset.rrs(false); i.hasNext();)
|
||||||
|
{
|
||||||
|
Record r = (Record) i.next();
|
||||||
|
out.append(r.toString());
|
||||||
|
out.append("\n");
|
||||||
|
}
|
||||||
|
if (includeSigs)
|
||||||
|
{
|
||||||
|
for (Iterator i = rrset.sigs(); i.hasNext();)
|
||||||
|
{
|
||||||
|
Record r = (Record) i.next();
|
||||||
|
out.append(r.toString());
|
||||||
|
out.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user