NSEC3 support, remove plain opt-in support until private algs work

git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@35 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
David Blacka
2005-10-27 21:50:54 +00:00
parent ab479a3e7b
commit 04ab26f434
4 changed files with 755 additions and 135 deletions

View File

@@ -28,13 +28,8 @@ import java.io.PrintWriter;
import java.security.GeneralSecurityException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.TimeZone;
import java.util.*;
import java.util.logging.Handler;
import java.util.logging.Logger;
import java.util.logging.Level;
@@ -47,6 +42,7 @@ import org.xbill.DNS.RRset;
import org.xbill.DNS.Record;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.Type;
import org.xbill.DNS.utils.base16;
import com.verisignlabs.dnssec.security.BINDKeyUtils;
import com.verisignlabs.dnssec.security.DnsKeyPair;
@@ -68,8 +64,7 @@ public class SignZone
private static Logger log;
/**
* This is a small inner class used to hold all of the command line option
* state.
* This is an inner class used to hold all of the command line option state.
*/
private static class CLIState
{
@@ -85,9 +80,11 @@ public class SignZone
public boolean verifySigs = false;
public boolean selfSignKeys = true;
public boolean useOptIn = false;
public boolean optInConserve = false;
public boolean fullySignKeyset = false;
public List includeNames = null;
public boolean useNsec3 = false;
public byte[] salt = null;
public int iterations = 0;
public CLIState()
{
@@ -115,23 +112,25 @@ public class SignZone
case 0 :
rootLogger.setLevel(Level.OFF);
break;
case 5 :
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 (cli.hasOption('3')) useNsec3 = true;
if (cli.hasOption('O')) useOptIn = true;
if (cli.hasOption('C'))
{
useOptIn = true;
optInConserve = true;
}
if (cli.hasOption('F')) fullySignKeyset = true;
@@ -185,6 +184,21 @@ public class SignZone
includeNames = getNameList(includeNamesFile);
}
if ((optstr = cli.getOptionValue("salt")) != null)
{
salt = base16.fromString(optstr);
}
if ((optstr = cli.getOptionValue("random-salt")) != null)
{
int length = parseInt(optstr, 0);
if (length > 0 && length <= 255)
{
Random random = new Random();
salt = new byte[length];
random.nextBytes(salt);
}
}
String[] files = cli.getArgs();
if (files.length < 2)
@@ -209,73 +223,60 @@ public class SignZone
// boolean options
opts.addOption("h", "help", false, "Print this message.");
opts.addOption("a", false, "verify generated signatures>");
opts.addOption("a", "verify", 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);
"sign the zone apex keyset with all available keys.");
// 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'));
opts.addOption(OptionBuilder.hasOptionalArg().withLongOpt("verbose")
.withArgName("level").withDescription("verbosity level")
.create('v'));
opts.addOption(OptionBuilder.hasArg().withArgName("dir")
.withLongOpt("keyset-directory")
.withDescription("directory to find keyset files (default '.').")
.create('d'));
opts.addOption(OptionBuilder.hasArg().withArgName("dir")
.withLongOpt("key-directory")
.withDescription("directory to find key files (default '.').")
.create('D'));
opts.addOption(OptionBuilder.hasArg().withArgName("time/offset")
.withLongOpt("start-time")
.withDescription("signature starting time "
+ "(default is now - 1 hour)").create('s'));
opts.addOption(OptionBuilder.hasArg().withArgName("time/offset")
.withLongOpt("expire-time")
.withDescription("signature expiration time "
+ "(default is start-time + 30 days).").create('e'));
opts.addOption(OptionBuilder.hasArg().withArgName("outfile")
.withDescription("file the signed zone is written to "
+ "(default is <origin>.signed).").create('f'));
opts.addOption(OptionBuilder.hasArgs().withArgName("KSK file")
.withLongOpt("ksk-file").withDescription("this key is a key "
+ "signing key (may repeat).").create('k'));
opts.addOption(OptionBuilder.hasArg().withArgName("file")
.withLongOpt("include-file")
.withDescription("include names in this "
+ "file in the NSEC/NSEC3 chain.").create('I'));
OptionBuilder.hasArg();
OptionBuilder.withArgName("dir");
OptionBuilder.withLongOpt("keyset-directory");
OptionBuilder.withDescription("directory to find keyset files (default '.').");
opts.addOption(OptionBuilder.create('d'));
// NSEC3 options
opts.addOption("3", "use-nsec3", false, "use NSEC3 instead of NSEC");
opts.addOption("O",
"use-opt-in",
false,
"generate a fully Opt-In zone.");
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'));
opts.addOption(OptionBuilder.hasArg().withLongOpt("salt")
.withArgName("hex value").withDescription("supply a salt value.")
.create());
opts.addOption(OptionBuilder.hasArg().withLongOpt("random-salt")
.withArgName("length").withDescription("generate a random salt.")
.create());
opts.addOption(OptionBuilder.hasArg().withLongOpt("iterations")
.withArgName("value")
.withDescription("use this value for the iterations in NSEC3.")
.create());
}
/** Print out the usage and help statements, then quit. */
@@ -286,7 +287,8 @@ public class SignZone
PrintWriter out = new PrintWriter(System.err);
// print our own usage statement:
out.println("usage: signZone.sh [..options..] zone_file [key_file ...] ");
out.println("usage: signZone.sh [..options..] "
+ "zone_file [key_file ...] ");
f.printHelp(out,
75,
"signZone.sh",
@@ -572,10 +574,8 @@ public class SignZone
toList.add(i.next());
}
int type = SignUtils.recordSecType(zonename,
rrset.getName(),
rrset.getType(),
last_cut);
int type = SignUtils.recordSecType(zonename, rrset.getName(), rrset
.getType(), last_cut);
// we don't sign non-normal sets (delegations, glue, invalid).
// we also don't sign the zone key set unless we've been asked.
@@ -595,7 +595,8 @@ public class SignZone
// otherwise we will just sign them with the zonesigning keys.
if (keysigningkeypairs != null && keysigningkeypairs.size() > 0)
{
List sigs = signer.signRRset(rrset, keysigningkeypairs, start, expire);
List sigs = signer
.signRRset(rrset, keysigningkeypairs, start, expire);
toList.addAll(sigs);
// If we aren't going to sign with all the keys, bail out now.
@@ -639,13 +640,13 @@ public class SignZone
*/
private static List signZone(JCEDnsSecSigner signer, Name zonename,
List records, List keysigningkeypairs, List zonekeypairs, Date start,
Date expire, boolean useOptIn, boolean useConservativeOptIn,
boolean fullySignKeyset, List NSECIncludeNames) throws IOException,
GeneralSecurityException
Date expire, boolean fullySignKeyset)
throws IOException, GeneralSecurityException
{
// Remove any existing DNSSEC records (NSEC, RRSIG)
// Remove any existing DNSSEC records (NSEC, NSEC3, RRSIG)
SignUtils.removeGeneratedRecords(zonename, records);
// Sort the zone
Collections.sort(records, new RecordComparator());
@@ -655,18 +656,8 @@ public class SignZone
// Generate DS records
SignUtils.generateDSRecords(zonename, records);
// Generate NXT records
if (useOptIn)
{
SignUtils.generateOptInNSECRecords(zonename,
records,
NSECIncludeNames,
useConservativeOptIn);
}
else
{
SignUtils.generateNSECRecords(zonename, records);
}
// Generate the NSEC records
SignUtils.generateNSECRecords(zonename, records);
// Assemble into RRsets and sign.
RRset rrset = new RRset();
@@ -678,7 +669,102 @@ public class SignZone
Record r = (Record) i.next();
// First record
if (rrset.getName() == null)
if (rrset.size() == 0)
{
rrset.addRR(r);
continue;
}
// Current record is part of the current RRset.
if (rrset.getName().equals(r.getName())
&& rrset.getDClass() == r.getDClass()
&& rrset.getType() == r.getType())
{
rrset.addRR(r);
continue;
}
// Otherwise, we have completed the RRset
// Sign the records
// add the RRset to the list of signed_records, regardless of
// whether or not we actually end up signing the set.
last_cut = addRRset(signer,
signed_records,
zonename,
rrset,
keysigningkeypairs,
zonekeypairs,
start,
expire,
fullySignKeyset,
last_cut);
rrset.clear();
rrset.addRR(r);
}
// add the last RR set
addRRset(signer,
signed_records,
zonename,
rrset,
keysigningkeypairs,
zonekeypairs,
start,
expire,
fullySignKeyset,
last_cut);
return signed_records;
}
private static List signZoneNSEC3(JCEDnsSecSigner signer, Name zonename,
List records, List keysigningkeypairs, List zonekeypairs, Date start,
Date expire, boolean fullySignKeyset, boolean useOptIn,
List includedNames, byte[] salt, int iterations)
throws IOException, GeneralSecurityException
{
// Remove any existing DNSSEC records (NSEC, NSEC3, RRSIG)
SignUtils.removeGeneratedRecords(zonename, records);
// Sort the zone
Collections.sort(records, new RecordComparator());
// Remove duplicate records
SignUtils.removeDuplicateRecords(records);
// Generate DS records
SignUtils.generateDSRecords(zonename, records);
// Generate NSEC3 records
if (useOptIn)
{
SignUtils.generateOptInNSEC3Records(zonename,
records,
includedNames,
salt,
iterations);
}
else
{
SignUtils.generateNSEC3Records(zonename, records, salt, iterations);
}
// Re-sort so we can assemble into rrsets.
Collections.sort(records, new RecordComparator());
// Assemble into RRsets and sign.
RRset rrset = new RRset();
ArrayList signed_records = new ArrayList();
Name last_cut = null;
for (ListIterator i = records.listIterator(); i.hasNext();)
{
Record r = (Record) i.next();
// First record
if (rrset.size() == 0)
{
rrset.addRR(r);
continue;
@@ -823,17 +909,34 @@ public class SignZone
JCEDnsSecSigner signer = new JCEDnsSecSigner();
// Sign the zone.
List signed_records = signZone(signer,
zonename,
records,
kskpairs,
keypairs,
state.start,
state.expire,
state.useOptIn,
state.optInConserve,
state.fullySignKeyset,
state.includeNames);
List signed_records;
if (state.useNsec3)
{
signed_records = signZoneNSEC3(signer,
zonename,
records,
kskpairs,
keypairs,
state.start,
state.expire,
state.fullySignKeyset,
state.useOptIn,
state.includeNames,
state.salt,
state.iterations);
}
else
{
signed_records = signZone(signer,
zonename,
records,
kskpairs,
keypairs,
state.start,
state.expire,
state.fullySignKeyset);
}
// write out the signed zone
// force multiline mode for now