Move all signZone() method variants into JCEDnsSecSigner, make the SignZone class use them.
git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@112 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
parent
5170a087c9
commit
e5270de8ee
@ -1,6 +1,6 @@
|
|||||||
// $Id$
|
// $Id$
|
||||||
//
|
//
|
||||||
// Copyright (C) 2001-2003 VeriSign, Inc.
|
// Copyright (C) 2001-2003, 2009 VeriSign, Inc.
|
||||||
//
|
//
|
||||||
// This library is free software; you can redistribute it and/or
|
// This library is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
@ -25,21 +25,42 @@ import java.io.FileFilter;
|
|||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.TimeZone;
|
||||||
import java.util.logging.Handler;
|
import java.util.logging.Handler;
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.apache.commons.cli.*;
|
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.Options;
|
||||||
|
import org.apache.commons.cli.PosixParser;
|
||||||
import org.xbill.DNS.*;
|
import org.apache.commons.cli.UnrecognizedOptionException;
|
||||||
|
import org.xbill.DNS.DNSKEYRecord;
|
||||||
|
import org.xbill.DNS.DNSSEC;
|
||||||
|
import org.xbill.DNS.DSRecord;
|
||||||
|
import org.xbill.DNS.Name;
|
||||||
|
import org.xbill.DNS.RRset;
|
||||||
|
import org.xbill.DNS.Record;
|
||||||
|
import org.xbill.DNS.TextParseException;
|
||||||
import org.xbill.DNS.utils.base16;
|
import org.xbill.DNS.utils.base16;
|
||||||
|
|
||||||
import com.verisignlabs.dnssec.security.*;
|
import com.verisignlabs.dnssec.security.BINDKeyUtils;
|
||||||
|
import com.verisignlabs.dnssec.security.DnsKeyAlgorithm;
|
||||||
|
import com.verisignlabs.dnssec.security.DnsKeyPair;
|
||||||
|
import com.verisignlabs.dnssec.security.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.
|
* This class forms the command line implementation of a DNSSEC zone signer.
|
||||||
@ -93,66 +114,80 @@ public class SignZone
|
|||||||
// boolean options
|
// boolean options
|
||||||
opts.addOption("h", "help", false, "Print this message.");
|
opts.addOption("h", "help", false, "Print this message.");
|
||||||
opts.addOption("a", "verify", false, "verify generated signatures>");
|
opts.addOption("a", "verify", false, "verify generated signatures>");
|
||||||
opts.addOption("F",
|
opts.addOption("F", "fully-sign-keyset", false,
|
||||||
"fully-sign-keyset",
|
"sign the zone apex keyset with all available keys.");
|
||||||
false,
|
|
||||||
"sign the zone apex keyset with all available keys.");
|
|
||||||
|
|
||||||
// Argument options
|
// Argument options
|
||||||
opts.addOption(OptionBuilder.hasOptionalArg().withLongOpt("verbose")
|
opts.addOption(OptionBuilder.hasOptionalArg()
|
||||||
.withArgName("level").withDescription("verbosity level.")
|
.withLongOpt("verbose")
|
||||||
|
.withArgName("level")
|
||||||
|
.withDescription("verbosity level.")
|
||||||
.create('v'));
|
.create('v'));
|
||||||
opts.addOption(OptionBuilder.hasArg().withArgName("dir")
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
|
.withArgName("dir")
|
||||||
.withLongOpt("keyset-directory")
|
.withLongOpt("keyset-directory")
|
||||||
.withDescription("directory to find keyset files (default '.').")
|
.withDescription("directory to find keyset files (default '.').")
|
||||||
.create('d'));
|
.create('d'));
|
||||||
opts.addOption(OptionBuilder.hasArg().withArgName("dir")
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
|
.withArgName("dir")
|
||||||
.withLongOpt("key-directory")
|
.withLongOpt("key-directory")
|
||||||
.withDescription("directory to find key files (default '.').")
|
.withDescription("directory to find key files (default '.').")
|
||||||
.create('D'));
|
.create('D'));
|
||||||
opts.addOption(OptionBuilder.hasArg().withArgName("time/offset")
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
|
.withArgName("time/offset")
|
||||||
.withLongOpt("start-time")
|
.withLongOpt("start-time")
|
||||||
.withDescription("signature starting time "
|
.withDescription("signature starting time (default is now - 1 hour)")
|
||||||
+ "(default is now - 1 hour)").create('s'));
|
.create('s'));
|
||||||
opts.addOption(OptionBuilder.hasArg().withArgName("time/offset")
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
|
.withArgName("time/offset")
|
||||||
.withLongOpt("expire-time")
|
.withLongOpt("expire-time")
|
||||||
.withDescription("signature expiration time "
|
.withDescription(
|
||||||
+ "(default is start-time + 30 days).").create('e'));
|
"signature expiration time (default is start-time + 30 days).")
|
||||||
opts.addOption(OptionBuilder.hasArg().withArgName("outfile")
|
.create('e'));
|
||||||
.withDescription("file the signed zone is written to "
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
+ "(default is <origin>.signed).").create('f'));
|
.withArgName("outfile")
|
||||||
opts.addOption(OptionBuilder.hasArg().withArgName("KSK file")
|
.withDescription(
|
||||||
|
"file the signed zone is written to (default is <origin>.signed).")
|
||||||
|
.create('f'));
|
||||||
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
|
.withArgName("KSK file")
|
||||||
.withLongOpt("ksk-file")
|
.withLongOpt("ksk-file")
|
||||||
.withDescription("this key is a key signing key (may repeat).")
|
.withDescription("this key is a key signing key (may repeat).")
|
||||||
.create('k'));
|
.create('k'));
|
||||||
opts.addOption(OptionBuilder.hasArg().withArgName("file")
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
|
.withArgName("file")
|
||||||
.withLongOpt("include-file")
|
.withLongOpt("include-file")
|
||||||
.withDescription("include names in this "
|
.withDescription("include names in this file in the NSEC/NSEC3 chain.")
|
||||||
+ "file in the NSEC/NSEC3 chain.").create('I'));
|
.create('I'));
|
||||||
|
|
||||||
// NSEC3 options
|
// NSEC3 options
|
||||||
opts.addOption("3", "use-nsec3", false, "use NSEC3 instead of NSEC");
|
opts.addOption("3", "use-nsec3", false, "use NSEC3 instead of NSEC");
|
||||||
opts.addOption("O",
|
opts.addOption("O", "use-opt-out", false,
|
||||||
"use-opt-out",
|
"generate a fully Opt-Out zone (only valid with NSEC3).");
|
||||||
false,
|
|
||||||
"generate a fully Opt-Out zone (only valid with NSEC3).");
|
|
||||||
|
|
||||||
opts.addOption(OptionBuilder.hasArg().withLongOpt("salt")
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
.withArgName("hex value").withDescription("supply a salt value.")
|
.withLongOpt("salt")
|
||||||
|
.withArgName("hex value")
|
||||||
|
.withDescription("supply a salt value.")
|
||||||
.create('S'));
|
.create('S'));
|
||||||
opts.addOption(OptionBuilder.hasArg().withLongOpt("random-salt")
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
.withArgName("length").withDescription("generate a random salt.")
|
.withLongOpt("random-salt")
|
||||||
|
.withArgName("length")
|
||||||
|
.withDescription("generate a random salt.")
|
||||||
.create('R'));
|
.create('R'));
|
||||||
opts.addOption(OptionBuilder.hasArg().withLongOpt("iterations")
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
|
.withLongOpt("iterations")
|
||||||
.withArgName("value")
|
.withArgName("value")
|
||||||
.withDescription("use this value for the iterations in NSEC3.")
|
.withDescription("use this value for the iterations in NSEC3.")
|
||||||
.create());
|
.create());
|
||||||
|
|
||||||
opts.addOption(OptionBuilder.hasArg()
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
.withArgName("alias:original:mnemonic").withLongOpt("alg-alias")
|
.withArgName("alias:original:mnemonic")
|
||||||
|
.withLongOpt("alg-alias")
|
||||||
.withDescription("Define an alias for an algorithm (may repeat).")
|
.withDescription("Define an alias for an algorithm (may repeat).")
|
||||||
.create('A'));
|
.create('A'));
|
||||||
opts.addOption(OptionBuilder.hasArg().withArgName("id")
|
opts.addOption(OptionBuilder.hasArg()
|
||||||
|
.withArgName("id")
|
||||||
.withLongOpt("ds-digest")
|
.withLongOpt("ds-digest")
|
||||||
.withDescription("Digest algorithm to use for generated DSs")
|
.withDescription("Digest algorithm to use for generated DSs")
|
||||||
.create());
|
.create());
|
||||||
@ -177,19 +212,19 @@ public class SignZone
|
|||||||
|
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
case 0 :
|
case 0:
|
||||||
rootLogger.setLevel(Level.OFF);
|
rootLogger.setLevel(Level.OFF);
|
||||||
break;
|
break;
|
||||||
case 4 :
|
case 4:
|
||||||
default :
|
default:
|
||||||
rootLogger.setLevel(Level.INFO);
|
rootLogger.setLevel(Level.INFO);
|
||||||
break;
|
break;
|
||||||
case 5 :
|
case 5:
|
||||||
rootLogger.setLevel(Level.FINE);
|
rootLogger.setLevel(Level.FINE);
|
||||||
break;
|
break;
|
||||||
case 6 :
|
case 6:
|
||||||
rootLogger.setLevel(Level.ALL);
|
rootLogger.setLevel(Level.ALL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Handler[] handlers = rootLogger.getHandlers();
|
Handler[] handlers = rootLogger.getHandlers();
|
||||||
for (int i = 0; i < handlers.length; i++)
|
for (int i = 0; i < handlers.length; i++)
|
||||||
@ -352,14 +387,10 @@ public class SignZone
|
|||||||
// print our own usage statement:
|
// print our own usage statement:
|
||||||
out.println("usage: signZone.sh [..options..] "
|
out.println("usage: signZone.sh [..options..] "
|
||||||
+ "zone_file [key_file ...] ");
|
+ "zone_file [key_file ...] ");
|
||||||
f.printHelp(out,
|
f.printHelp(out, 75, "signZone.sh", null, opts,
|
||||||
75,
|
HelpFormatter.DEFAULT_LEFT_PAD,
|
||||||
"signZone.sh",
|
HelpFormatter.DEFAULT_DESC_PAD,
|
||||||
null,
|
"\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
|
||||||
opts,
|
|
||||||
HelpFormatter.DEFAULT_LEFT_PAD,
|
|
||||||
HelpFormatter.DEFAULT_DESC_PAD,
|
|
||||||
"\ntime/offset = YYYYMMDDHHmmss|+offset|\"now\"+offset\n");
|
|
||||||
|
|
||||||
out.flush();
|
out.flush();
|
||||||
System.exit(64);
|
System.exit(64);
|
||||||
@ -369,8 +400,10 @@ public class SignZone
|
|||||||
/**
|
/**
|
||||||
* This is just a convenience method for parsing integers from strings.
|
* This is just a convenience method for parsing integers from strings.
|
||||||
*
|
*
|
||||||
* @param s the string to parse.
|
* @param s
|
||||||
* @param def the default value, if the string doesn't parse.
|
* the string to parse.
|
||||||
|
* @param def
|
||||||
|
* the default value, if the string doesn't parse.
|
||||||
* @return the parsed integer, or the default.
|
* @return the parsed integer, or the default.
|
||||||
*/
|
*/
|
||||||
private static int parseInt(String s, int def)
|
private static int parseInt(String s, int def)
|
||||||
@ -389,13 +422,16 @@ public class SignZone
|
|||||||
/**
|
/**
|
||||||
* Verify the generated signatures.
|
* Verify the generated signatures.
|
||||||
*
|
*
|
||||||
* @param zonename the origin name of the zone.
|
* @param zonename
|
||||||
* @param records a list of {@link org.xbill.DNS.Record}s.
|
* the origin name of the zone.
|
||||||
* @param keypairs a list of keypairs used the sign 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.
|
* @return true if all of the signatures validated.
|
||||||
*/
|
*/
|
||||||
private static boolean verifyZoneSigs(Name zonename, List records,
|
private static boolean verifyZoneSigs(Name zonename, List records,
|
||||||
List keypairs)
|
List keypairs)
|
||||||
{
|
{
|
||||||
boolean secure = true;
|
boolean secure = true;
|
||||||
|
|
||||||
@ -433,15 +469,18 @@ public class SignZone
|
|||||||
/**
|
/**
|
||||||
* 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 paths of the
|
* @param keyfiles
|
||||||
* keys to be loaded.
|
* a string array containing the base names or paths of the keys to
|
||||||
* @param start_index the starting index of keyfiles string array to use.
|
* be loaded.
|
||||||
* This allows us to use the straight command line argument array.
|
* @param start_index
|
||||||
* @param inDirectory the directory to look in (may be null).
|
* 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.
|
* @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) throws IOException
|
File inDirectory) throws IOException
|
||||||
{
|
{
|
||||||
if (keyfiles == null) return null;
|
if (keyfiles == null) return null;
|
||||||
|
|
||||||
@ -477,13 +516,13 @@ public class SignZone
|
|||||||
/**
|
/**
|
||||||
* 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 (may be
|
* @param inDirectory
|
||||||
* null, in which case it defaults to looking in the current
|
* the directory to look for the keyset files (may be null, in which
|
||||||
* working directory).
|
* case it defaults to looking in the current working directory).
|
||||||
* @param zonename the name of the zone we are signing, so we can ignore
|
* @param zonename
|
||||||
* keysets that do not belong in the zone.
|
* the name of the zone we are signing, so we can ignore keysets that
|
||||||
* @return a list of {@link org.xbill.DNS.Record}s found in the keyset
|
* do not belong in the zone.
|
||||||
* files.
|
* @return a list of {@link org.xbill.DNS.Record}s found in the keyset files.
|
||||||
*/
|
*/
|
||||||
private static List getKeysets(File inDirectory, Name zonename)
|
private static List getKeysets(File inDirectory, Name zonename)
|
||||||
throws IOException
|
throws IOException
|
||||||
@ -521,8 +560,8 @@ public class SignZone
|
|||||||
/**
|
/**
|
||||||
* 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 DNS
|
* @param nameListFile
|
||||||
* names.
|
* the path of a file containing a bare list of DNS 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) throws IOException
|
private static List getNameList(File nameListFile) throws IOException
|
||||||
@ -557,8 +596,10 @@ public class SignZone
|
|||||||
/**
|
/**
|
||||||
* 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
|
||||||
* @param duration the time/offset string to parse.
|
* the start time to calculate offsets from.
|
||||||
|
* @param duration
|
||||||
|
* the time/offset string to parse.
|
||||||
* @return the calculated time.
|
* @return the calculated time.
|
||||||
*/
|
*/
|
||||||
private static Date convertDuration(Date start, String duration)
|
private static Date convertDuration(Date start, String duration)
|
||||||
@ -587,9 +628,11 @@ public class SignZone
|
|||||||
/**
|
/**
|
||||||
* 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
|
||||||
* @param keypairs a list of {@link DnsKeyPair} objects that will be used to
|
* the zone origin.
|
||||||
* sign the zone.
|
* @param keypairs
|
||||||
|
* a list of {@link DnsKeyPair} objects that will be used to 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)
|
||||||
@ -600,306 +643,12 @@ public class SignZone
|
|||||||
{
|
{
|
||||||
DnsKeyPair kp = (DnsKeyPair) i.next();
|
DnsKeyPair kp = (DnsKeyPair) i.next();
|
||||||
Name keyname = kp.getDNSKEYRecord().getName();
|
Name keyname = kp.getDNSKEYRecord().getName();
|
||||||
if (!keyname.equals(zonename))
|
if (!keyname.equals(zonename)) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Conditionally sign an RRset and add it to the toList.
|
|
||||||
*
|
|
||||||
* @param toList the list to which we are adding the processed RRsets.
|
|
||||||
* @param zonename the zone apex name.
|
|
||||||
* @param rrset the rrset under consideration.
|
|
||||||
* @param keysigningkeypairs the List of KSKs..
|
|
||||||
* @param zonekeypairs the List of zone keys.
|
|
||||||
* @param start the RRSIG inception time.
|
|
||||||
* @param expire the RRSIG expiration time.
|
|
||||||
* @param fullySignKeyset if true, sign the zone apex keyset with both KSKs
|
|
||||||
* and ZSKs.
|
|
||||||
* @param last_cut the name of the last delegation point encountered.
|
|
||||||
* @return the name of the new last_cut.
|
|
||||||
*/
|
|
||||||
private static Name addRRset(JCEDnsSecSigner signer, List toList,
|
|
||||||
Name zonename, RRset rrset, List keysigningkeypairs, List zonekeypairs,
|
|
||||||
Date start, Date expire, boolean fullySignKeyset, Name last_cut)
|
|
||||||
throws IOException, GeneralSecurityException
|
|
||||||
{
|
|
||||||
// add the records themselves
|
|
||||||
for (Iterator i = rrset.rrs(); i.hasNext();)
|
|
||||||
{
|
|
||||||
toList.add(i.next());
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
|
||||||
if (type == SignUtils.RR_DELEGATION)
|
|
||||||
{
|
|
||||||
return rrset.getName();
|
|
||||||
}
|
|
||||||
if (type == SignUtils.RR_GLUE || type == SignUtils.RR_INVALID)
|
|
||||||
{
|
|
||||||
return last_cut;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for the zone apex keyset.
|
|
||||||
if (rrset.getName().equals(zonename) && rrset.getType() == Type.DNSKEY)
|
|
||||||
{
|
|
||||||
// if we have key signing keys, sign the keyset with them,
|
|
||||||
// otherwise we will just sign them with the zonesigning keys.
|
|
||||||
if (keysigningkeypairs != null && keysigningkeypairs.size() > 0)
|
|
||||||
{
|
|
||||||
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.
|
|
||||||
if (!fullySignKeyset) return last_cut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, we are OK to sign this set.
|
|
||||||
List sigs = signer.signRRset(rrset, zonekeypairs, start, expire);
|
|
||||||
toList.addAll(sigs);
|
|
||||||
|
|
||||||
return last_cut;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a zone, sign it.
|
|
||||||
*
|
|
||||||
* @param signer A signer (utility) object to use to actually sign stuff.
|
|
||||||
* @param zonename The name of the zone.
|
|
||||||
* @param records The records comprising the zone. They do not have to be in
|
|
||||||
* any particular order, as this method will order them as
|
|
||||||
* necessary.
|
|
||||||
* @param keysigningkeypairs The key pairs that are designated as "key
|
|
||||||
* signing keys".
|
|
||||||
* @param zonekeypair This key pairs that are designated as "zone signing
|
|
||||||
* keys".
|
|
||||||
* @param start The RRSIG inception time.
|
|
||||||
* @param expire The RRSIG expiration time.
|
|
||||||
* @param fullySignKeyset Sign the zone apex keyset with all available keys.
|
|
||||||
* @param digest_id The digest identifier to use when generating DS records.
|
|
||||||
*
|
|
||||||
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
|
||||||
* representing the signed zone.
|
|
||||||
*/
|
|
||||||
private static List signZone(JCEDnsSecSigner signer, Name zonename,
|
|
||||||
List records, List keysigningkeypairs, List zonekeypairs, Date start,
|
|
||||||
Date expire, boolean fullySignKeyset, int digest_id)
|
|
||||||
throws IOException, GeneralSecurityException
|
|
||||||
{
|
|
||||||
|
|
||||||
// Remove any existing DNSSEC records (NSEC, NSEC3, RRSIG)
|
|
||||||
SignUtils.removeGeneratedRecords(zonename, records);
|
|
||||||
|
|
||||||
// Sort the zone
|
|
||||||
Collections.sort(records, new RecordComparator());
|
|
||||||
|
|
||||||
// Remove any duplicate records.
|
|
||||||
SignUtils.removeDuplicateRecords(records);
|
|
||||||
|
|
||||||
// Generate DS records
|
|
||||||
SignUtils.generateDSRecords(zonename, records, digest_id);
|
|
||||||
|
|
||||||
// Generate the NSEC records
|
|
||||||
SignUtils.generateNSECRecords(zonename, records);
|
|
||||||
|
|
||||||
// Assemble into RRsets and sign.
|
|
||||||
RRset rrset = new RRset();
|
|
||||||
ArrayList signed_records = new ArrayList();
|
|
||||||
Name last_cut = null;
|
|
||||||
|
|
||||||
for (ListIterator i = records.listIterator(); i.hasNext();)
|
|
||||||
{
|
|
||||||
Record r = (Record) i.next();
|
|
||||||
|
|
||||||
// First record
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a zone sign it using NSEC3 records.
|
|
||||||
*
|
|
||||||
* @param signer A signer (utility) object used to actually sign stuff.
|
|
||||||
* @param zonename The name of the zone being signed.
|
|
||||||
* @param records The records comprising the zone. They do not have to be in
|
|
||||||
* any particular order, as this method will order them as
|
|
||||||
* necessary.
|
|
||||||
* @param keysigningkeypairs The key pairs that are designated as "key
|
|
||||||
* signing keys".
|
|
||||||
* @param zonekeypairs This key pairs that are designated as "zone signing
|
|
||||||
* keys".
|
|
||||||
* @param start The RRSIG inception time.
|
|
||||||
* @param expire The RRSIG expiration time.
|
|
||||||
* @param fullySignKeyset If true then the DNSKEY RRset will be signed by
|
|
||||||
* all available keys, if false, only the key signing keys.
|
|
||||||
* @param useOptOut If true, insecure delegations will be omitted from the
|
|
||||||
* NSEC3 chain, and all NSEC3 records will have the Opt-Out flag
|
|
||||||
* set.
|
|
||||||
* @param includedNames A list of names to include in the NSEC3 chain
|
|
||||||
* regardless.
|
|
||||||
* @param salt The salt to use for the NSEC3 hashing. null means no salt.
|
|
||||||
* @param iterations The number of iterations to use for the NSEC3 hashing.
|
|
||||||
* @param ds_digest_id The digest algorithm to use when generating DS
|
|
||||||
* records.
|
|
||||||
*
|
|
||||||
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
|
||||||
* representing the signed zone.
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws GeneralSecurityException
|
|
||||||
*/
|
|
||||||
private static List signZoneNSEC3(JCEDnsSecSigner signer, Name zonename,
|
|
||||||
List records, List keysigningkeypairs, List zonekeypairs, Date start,
|
|
||||||
Date expire, boolean fullySignKeyset, boolean useOptOut,
|
|
||||||
List includedNames, byte[] salt, int iterations, int ds_digest_id)
|
|
||||||
throws IOException, GeneralSecurityException
|
|
||||||
{
|
|
||||||
// Remove any existing DNSSEC records (NSEC, NSEC3, NSEC3PARAM, 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, ds_digest_id);
|
|
||||||
|
|
||||||
// Generate NSEC3 records
|
|
||||||
if (useOptOut)
|
|
||||||
{
|
|
||||||
SignUtils.generateOptOutNSEC3Records(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void execute(CLIState state) throws Exception
|
public static void execute(CLIState state) throws Exception
|
||||||
{
|
{
|
||||||
// Load the key pairs.
|
// Load the key pairs.
|
||||||
@ -1014,31 +763,19 @@ public class SignZone
|
|||||||
|
|
||||||
if (state.useNsec3)
|
if (state.useNsec3)
|
||||||
{
|
{
|
||||||
signed_records = signZoneNSEC3(signer,
|
signed_records = signer.signZoneNSEC3(zonename, records, kskpairs,
|
||||||
zonename,
|
keypairs, state.start,
|
||||||
records,
|
state.expire,
|
||||||
kskpairs,
|
state.fullySignKeyset,
|
||||||
keypairs,
|
state.useOptOut,
|
||||||
state.start,
|
state.includeNames, state.salt,
|
||||||
state.expire,
|
state.iterations, state.digest_id);
|
||||||
state.fullySignKeyset,
|
|
||||||
state.useOptOut,
|
|
||||||
state.includeNames,
|
|
||||||
state.salt,
|
|
||||||
state.iterations,
|
|
||||||
state.digest_id);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
signed_records = signZone(signer,
|
signed_records = signer.signZone(zonename, records, kskpairs, keypairs,
|
||||||
zonename,
|
state.start, state.expire,
|
||||||
records,
|
state.fullySignKeyset, state.digest_id);
|
||||||
kskpairs,
|
|
||||||
keypairs,
|
|
||||||
state.start,
|
|
||||||
state.expire,
|
|
||||||
state.fullySignKeyset,
|
|
||||||
state.digest_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// write out the signed zone
|
// write out the signed zone
|
||||||
@ -1080,8 +817,7 @@ public class SignZone
|
|||||||
}
|
}
|
||||||
catch (UnrecognizedOptionException e)
|
catch (UnrecognizedOptionException e)
|
||||||
{
|
{
|
||||||
System.err.println("error: unknown option encountered: "
|
System.err.println("error: unknown option encountered: " + e.getMessage());
|
||||||
+ e.getMessage());
|
|
||||||
state.usage();
|
state.usage();
|
||||||
}
|
}
|
||||||
catch (AlreadySelectedException e)
|
catch (AlreadySelectedException e)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// $Id$
|
// $Id$
|
||||||
//
|
//
|
||||||
// Copyright (C) 2001-2003 VeriSign, Inc.
|
// Copyright (C) 2001-2003, 2009 VeriSign, Inc.
|
||||||
//
|
//
|
||||||
// This library is free software; you can redistribute it and/or
|
// This library is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
@ -43,13 +43,14 @@ 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 RRset and
|
* In particular, it contains both an ability to sign an individual RRset and
|
||||||
* the ability to sign and entire zone. It primarily glues together the more
|
* the ability to sign an entire zone. It primarily glues 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$
|
* @author $Author$
|
||||||
* @version $Revision$
|
* @version $Revision$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class JCEDnsSecSigner
|
public class JCEDnsSecSigner
|
||||||
{
|
{
|
||||||
private DnsKeyConverter mKeyConverter;
|
private DnsKeyConverter mKeyConverter;
|
||||||
@ -57,36 +58,43 @@ public class JCEDnsSecSigner
|
|||||||
/**
|
/**
|
||||||
* Cryptographically generate a new DNSSEC key.
|
* Cryptographically generate a new DNSSEC key.
|
||||||
*
|
*
|
||||||
* @param owner the KEY RR's owner name.
|
* @param owner
|
||||||
* @param ttl the KEY RR's TTL.
|
* the KEY RR's owner name.
|
||||||
* @param dclass the KEY RR's DNS class.
|
* @param ttl
|
||||||
* @param algorithm the DNSSEC algorithm (RSAMD5, RSASHA1, or DSA).
|
* the KEY RR's TTL.
|
||||||
* @param flags any flags for the KEY RR.
|
* @param dclass
|
||||||
* @param keysize the size of the key to generate.
|
* the KEY RR's DNS class.
|
||||||
* @param useLargeExponent if generating an RSA key, use the large exponent.
|
* @param algorithm
|
||||||
|
* the DNSSEC algorithm (RSAMD5, RSASHA1, or DSA).
|
||||||
|
* @param flags
|
||||||
|
* any flags for the KEY RR.
|
||||||
|
* @param keysize
|
||||||
|
* the size of the key to generate.
|
||||||
|
* @param useLargeExponent
|
||||||
|
* if generating an RSA key, use the large exponent.
|
||||||
* @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, long ttl, int dclass,
|
public DnsKeyPair generateKey(Name owner, long ttl, int dclass,
|
||||||
int algorithm, int flags, int keysize, boolean useLargeExponent)
|
int algorithm, int flags, int keysize,
|
||||||
|
boolean useLargeExponent)
|
||||||
throws NoSuchAlgorithmException
|
throws NoSuchAlgorithmException
|
||||||
{
|
{
|
||||||
DnsKeyAlgorithm algorithms = DnsKeyAlgorithm.getInstance();
|
DnsKeyAlgorithm algorithms = DnsKeyAlgorithm.getInstance();
|
||||||
|
|
||||||
if (ttl < 0) ttl = 86400; // set to a reasonable default.
|
if (ttl < 0) ttl = 86400; // set to a reasonable default.
|
||||||
|
|
||||||
KeyPair pair = algorithms.generateKeyPair(algorithm, keysize, useLargeExponent);
|
KeyPair pair = algorithms.generateKeyPair(algorithm, keysize,
|
||||||
|
useLargeExponent);
|
||||||
|
|
||||||
if (mKeyConverter == null)
|
if (mKeyConverter == null)
|
||||||
{
|
{
|
||||||
mKeyConverter = new DnsKeyConverter();
|
mKeyConverter = new DnsKeyConverter();
|
||||||
}
|
}
|
||||||
|
|
||||||
DNSKEYRecord keyrec = mKeyConverter.generateDNSKEYRecord(owner,
|
DNSKEYRecord keyrec = mKeyConverter.generateDNSKEYRecord(owner, dclass,
|
||||||
dclass,
|
ttl, flags,
|
||||||
ttl,
|
algorithm,
|
||||||
flags,
|
pair.getPublic());
|
||||||
algorithm,
|
|
||||||
pair.getPublic());
|
|
||||||
|
|
||||||
DnsKeyPair dnspair = new DnsKeyPair();
|
DnsKeyPair dnspair = new DnsKeyPair();
|
||||||
dnspair.setDNSKEYRecord(keyrec);
|
dnspair.setDNSKEYRecord(keyrec);
|
||||||
@ -99,10 +107,14 @@ public class JCEDnsSecSigner
|
|||||||
/**
|
/**
|
||||||
* Sign an RRset.
|
* Sign an RRset.
|
||||||
*
|
*
|
||||||
* @param rrset the RRset to sign -- any existing signatures are ignored.
|
* @param rrset
|
||||||
* @param keypars a list of DnsKeyPair objects containing private keys.
|
* the RRset to sign -- any existing signatures are ignored.
|
||||||
* @param start the inception time for the resulting RRSIG records.
|
* @param keypars
|
||||||
* @param expire the expiration time for the resulting RRSIG records.
|
* a list of DnsKeyPair objects containing private keys.
|
||||||
|
* @param start
|
||||||
|
* the inception time for the resulting RRSIG records.
|
||||||
|
* @param expire
|
||||||
|
* the expiration time for the resulting RRSIG records.
|
||||||
* @return a list of RRSIGRecord objects.
|
* @return a list of RRSIGRecord objects.
|
||||||
*/
|
*/
|
||||||
public List signRRset(RRset rrset, List keypairs, Date start, Date expire)
|
public List signRRset(RRset rrset, List keypairs, Date start, Date expire)
|
||||||
@ -115,23 +127,20 @@ public class JCEDnsSecSigner
|
|||||||
if (expire == null) expire = new Date(start.getTime() + 1000L);
|
if (expire == null) expire = new Date(start.getTime() + 1000L);
|
||||||
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);
|
||||||
|
|
||||||
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,
|
RRSIGRecord presig = SignUtils.generatePreRRSIG(rrset, keyrec, start,
|
||||||
keyrec,
|
expire, rrset.getTTL());
|
||||||
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();
|
||||||
@ -142,8 +151,7 @@ public class JCEDnsSecSigner
|
|||||||
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.
|
||||||
@ -154,8 +162,9 @@ public class JCEDnsSecSigner
|
|||||||
// Convert to RFC 2536 format, if necessary.
|
// Convert to RFC 2536 format, if necessary.
|
||||||
if (algs.baseType(pair.getDNSKEYAlgorithm()) == DnsKeyAlgorithm.DSA)
|
if (algs.baseType(pair.getDNSKEYAlgorithm()) == DnsKeyAlgorithm.DSA)
|
||||||
{
|
{
|
||||||
sig = SignUtils.convertDSASignature(((DSAPublicKey) pair.getPublic())
|
sig = SignUtils.convertDSASignature(
|
||||||
.getParams(), sig);
|
((DSAPublicKey) pair.getPublic()).getParams(),
|
||||||
|
sig);
|
||||||
}
|
}
|
||||||
RRSIGRecord sigrec = SignUtils.generateRRSIG(sig, presig);
|
RRSIGRecord sigrec = SignUtils.generateRRSIG(sig, presig);
|
||||||
sigs.add(sigrec);
|
sigs.add(sigrec);
|
||||||
@ -165,11 +174,14 @@ public class JCEDnsSecSigner
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a completely self-signed KEY RRset.
|
* Create a completely self-signed DNSKEY RRset.
|
||||||
*
|
*
|
||||||
* @param keypairs the public & private keypairs to use in the keyset.
|
* @param keypairs
|
||||||
* @param start the RRSIG inception time.
|
* the public & private keypairs to use in the keyset.
|
||||||
* @param expire the RRSIG expiration time.
|
* @param start
|
||||||
|
* the RRSIG inception time.
|
||||||
|
* @param expire
|
||||||
|
* the RRSIG expiration time.
|
||||||
* @return a signed RRset.
|
* @return a signed RRset.
|
||||||
*/
|
*/
|
||||||
public RRset makeKeySet(List keypairs, Date start, Date expire)
|
public RRset makeKeySet(List keypairs, Date start, Date expire)
|
||||||
@ -198,21 +210,30 @@ public class JCEDnsSecSigner
|
|||||||
/**
|
/**
|
||||||
* 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
|
||||||
* @param zonename the zone apex name.
|
* the list to which we are adding the processed RRsets.
|
||||||
* @param rrset the rrset under consideration.
|
* @param zonename
|
||||||
* @param keysigningkeypairs the List of KSKs..
|
* the zone apex name.
|
||||||
* @param zonekeypairs the List of zone keys.
|
* @param rrset
|
||||||
* @param start the RRSIG inception time.
|
* the RRset under consideration.
|
||||||
* @param expire the RRSIG expiration time.
|
* @param kskpairs
|
||||||
* @param fullySignKeyset if true, sign the zone apex keyset with both KSKs
|
* the List of KSKs..
|
||||||
* and ZSKs.
|
* @param zskpairs
|
||||||
* @param last_cut the name of the last delegation point encountered.
|
* the List of zone keys.
|
||||||
|
* @param start
|
||||||
|
* the RRSIG inception time.
|
||||||
|
* @param expire
|
||||||
|
* the RRSIG expiration time.
|
||||||
|
* @param fullySignKeyset
|
||||||
|
* if true, sign the zone apex keyset with both KSKs and ZSKs.
|
||||||
|
* @param last_cut
|
||||||
|
* the name of the last delegation point encountered.
|
||||||
|
*
|
||||||
* @return the name of the new last_cut.
|
* @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 kskpairs,
|
||||||
List keysigningkeypairs, List zonekeypairs, Date start, Date expire,
|
List zskpairs, Date start, Date expire,
|
||||||
boolean fullySignKeyset, Name last_cut)
|
boolean fullySignKeyset, Name last_cut)
|
||||||
throws IOException, GeneralSecurityException
|
throws IOException, GeneralSecurityException
|
||||||
{
|
{
|
||||||
// add the records themselves
|
// add the records themselves
|
||||||
@ -221,28 +242,21 @@ public class JCEDnsSecSigner
|
|||||||
toList.add(i.next());
|
toList.add(i.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
int type = SignUtils.recordSecType(zonename, rrset.getName(), rrset
|
int type = SignUtils.recordSecType(zonename, rrset.getName(),
|
||||||
.getType(), last_cut);
|
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.
|
if (type == SignUtils.RR_DELEGATION) { return rrset.getName(); }
|
||||||
if (type == SignUtils.RR_DELEGATION)
|
if (type == SignUtils.RR_GLUE || type == SignUtils.RR_INVALID) { return last_cut; }
|
||||||
{
|
|
||||||
return rrset.getName();
|
|
||||||
}
|
|
||||||
if (type == SignUtils.RR_GLUE || type == SignUtils.RR_INVALID)
|
|
||||||
{
|
|
||||||
return last_cut;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for the zone apex keyset.
|
// check for the zone apex keyset.
|
||||||
if (rrset.getName().equals(zonename) && rrset.getType() == Type.DNSKEY)
|
if (rrset.getName().equals(zonename) && rrset.getType() == Type.DNSKEY)
|
||||||
{
|
{
|
||||||
// if we have key signing keys, sign the keyset with them,
|
// if we have ksks, sign the keyset with them, otherwise we will just sign
|
||||||
// otherwise we will just sign them with the zonesigning keys.
|
// them with the zsks.
|
||||||
if (keysigningkeypairs != null && keysigningkeypairs.size() > 0)
|
if (kskpairs != null && kskpairs.size() > 0)
|
||||||
{
|
{
|
||||||
List sigs = signRRset(rrset, keysigningkeypairs, start, expire);
|
List sigs = signRRset(rrset, kskpairs, start, expire);
|
||||||
toList.addAll(sigs);
|
toList.addAll(sigs);
|
||||||
|
|
||||||
// If we aren't going to sign with all the keys, bail out now.
|
// If we aren't going to sign with all the keys, bail out now.
|
||||||
@ -251,70 +265,108 @@ public class JCEDnsSecSigner
|
|||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, we are OK to sign this set.
|
// otherwise, we are OK to sign this set.
|
||||||
List sigs = signRRset(rrset, zonekeypairs, start, expire);
|
List sigs = signRRset(rrset, zskpairs, start, expire);
|
||||||
toList.addAll(sigs);
|
toList.addAll(sigs);
|
||||||
|
|
||||||
return last_cut;
|
return last_cut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Various NSEC/NSEC3 generation modes
|
||||||
|
private static final int NSEC_MODE = 0;
|
||||||
|
private static final int NSEC3_MODE = 1;
|
||||||
|
private static final int NSEC3_OPTOUT_MODE = 2;
|
||||||
|
private static final int NSEC_EXP_OPT_IN = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a zone, sign it.
|
* Master zone signing method. This method handles all of the different zone
|
||||||
|
* signing variants (NSEC with or without Opt-In, NSEC3 with or without
|
||||||
|
* Opt-Out, etc.) External users of this class are expected to use the
|
||||||
|
* appropriate public signZone* methods instead of this.
|
||||||
|
*
|
||||||
|
* @param zonename
|
||||||
|
* The name of the zone
|
||||||
|
* @param records
|
||||||
|
* The records comprising the zone. They do not have to be in any
|
||||||
|
* particular order, as this method will order them as necessary.
|
||||||
|
* @param kskpairs
|
||||||
|
* The key pairs designated as "key signing keys"
|
||||||
|
* @param zskpairs
|
||||||
|
* The key pairs designated as "zone signing keys"
|
||||||
|
* @param start
|
||||||
|
* The RRSIG inception time
|
||||||
|
* @param expire
|
||||||
|
* The RRSIG expiration time
|
||||||
|
* @param fullySignKeyset
|
||||||
|
* If true, all keys (ksk or zsk) will sign the DNSKEY RRset. If
|
||||||
|
* false, only the ksks will sign it.
|
||||||
|
* @param ds_digest_alg
|
||||||
|
* The hash algorithm to use for generating DS records
|
||||||
|
* (DSRecord.SHA1_DIGEST_ID, e.g.)
|
||||||
|
* @param mode
|
||||||
|
* The NSEC/NSEC3 generation mode: NSEC_MODE, NSEC3_MODE,
|
||||||
|
* NSEC3_OPTOUT_MODE, etc.
|
||||||
|
* @param includedNames
|
||||||
|
* When using an Opt-In/Opt-Out mode, the names listed here will be
|
||||||
|
* included in the NSEC/NSEC3 chain regardless
|
||||||
|
* @param salt
|
||||||
|
* When using an NSEC3 mode, use this salt.
|
||||||
|
* @param iterations
|
||||||
|
* When using an NSEC3 mode, use this number of iterations
|
||||||
|
* @param beConservative
|
||||||
|
* If true, then only turn on the Opt-In flag when there are insecure
|
||||||
|
* delegations in the span. Currently this only works for
|
||||||
|
* NSEC_EXP_OPT_IN mode.
|
||||||
*
|
*
|
||||||
* @param zonename the name of the zone.
|
|
||||||
* @param records the records comprising the zone. They do not have to be in
|
|
||||||
* any particular order, as this method will order them as
|
|
||||||
* necessary.
|
|
||||||
* @param keysigningkeypairs the key pairs that are designated as "key
|
|
||||||
* signing keys".
|
|
||||||
* @param start the RRSIG inception time.
|
|
||||||
* @param expire the RRSIG expiration time.
|
|
||||||
* @param useOptIn generate Opt-In style NXT records. It will consider any
|
|
||||||
* insecure delegation to be unsigned. To override this, include
|
|
||||||
* the name of the insecure delegation in the NXTIncludeNames list.
|
|
||||||
* @param useConservativeOptIn if true, Opt-In NXT records will only be
|
|
||||||
* generated if there are insecure, unsigned delegations in the
|
|
||||||
* span. Not effect if useOptIn is false.
|
|
||||||
* @param fullySignKeyset sign the zone apex keyset with all available keys.
|
|
||||||
* @param ds_digest_id TODO
|
|
||||||
* @param zonekeypair this key pairs that are designated as "zone signing
|
|
||||||
* keys".
|
|
||||||
* @param NXTIncludeNames names that are to be included in the NXT chain
|
|
||||||
* regardless. This may be null and is only used if useOptIn is
|
|
||||||
* true.
|
|
||||||
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
||||||
* representing the signed zone.
|
* representing the signed zone.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* @throws GeneralSecurityException
|
||||||
*/
|
*/
|
||||||
public List signZone(Name zonename, List records, List keysigningkeypairs,
|
private List signZone(Name zonename, List records, List kskpairs,
|
||||||
List zonekeypairs, Date start, Date expire, boolean useOptIn,
|
List zskpairs, Date start, Date expire,
|
||||||
boolean useConservativeOptIn, boolean fullySignKeyset,
|
boolean fullySignKeyset, int ds_digest_alg, int mode,
|
||||||
List NSECIncludeNames, int ds_digest_id)
|
List includedNames, byte[] salt, int iterations,
|
||||||
|
boolean beConservative)
|
||||||
throws IOException, GeneralSecurityException
|
throws IOException, GeneralSecurityException
|
||||||
{
|
{
|
||||||
|
// Remove any existing generated DNSSEC records (NSEC, NSEC3, NSEC3PARAM,
|
||||||
// Remove any existing DNSSEC records (NSEC, RRSIG)
|
// RRSIG)
|
||||||
SignUtils.removeGeneratedRecords(zonename, records);
|
SignUtils.removeGeneratedRecords(zonename, records);
|
||||||
// Sort the zone
|
|
||||||
Collections.sort(records, new RecordComparator());
|
|
||||||
|
|
||||||
// Remove any duplicate records.
|
RecordComparator rc = new RecordComparator();
|
||||||
|
// Sort the zone
|
||||||
|
Collections.sort(records, rc);
|
||||||
|
|
||||||
|
// Remove duplicate records
|
||||||
SignUtils.removeDuplicateRecords(records);
|
SignUtils.removeDuplicateRecords(records);
|
||||||
|
|
||||||
// Generate DS records
|
// Generate DS records. This replaces any non-zone-apex DNSKEY RRs with DS
|
||||||
SignUtils.generateDSRecords(zonename, records, ds_digest_id);
|
// RRs.
|
||||||
|
SignUtils.generateDSRecords(zonename, records, ds_digest_alg);
|
||||||
|
|
||||||
// Generate NXT records
|
// Generate the NSEC or NSEC3 records based on 'mode'
|
||||||
if (useOptIn)
|
switch (mode)
|
||||||
{
|
|
||||||
SignUtils.generateOptInNSECRecords(zonename,
|
|
||||||
records,
|
|
||||||
NSECIncludeNames,
|
|
||||||
useConservativeOptIn);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
case NSEC_MODE:
|
||||||
SignUtils.generateNSECRecords(zonename, records);
|
SignUtils.generateNSECRecords(zonename, records);
|
||||||
|
break;
|
||||||
|
case NSEC3_MODE:
|
||||||
|
SignUtils.generateNSEC3Records(zonename, records, salt, iterations);
|
||||||
|
break;
|
||||||
|
case NSEC3_OPTOUT_MODE:
|
||||||
|
SignUtils.generateOptOutNSEC3Records(zonename, records, includedNames,
|
||||||
|
salt, iterations);
|
||||||
|
break;
|
||||||
|
case NSEC_EXP_OPT_IN:
|
||||||
|
SignUtils.generateOptInNSECRecords(zonename, records, includedNames,
|
||||||
|
beConservative);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-sort so we can assemble into rrsets.
|
||||||
|
Collections.sort(records, rc);
|
||||||
|
|
||||||
// Assemble into RRsets and sign.
|
// Assemble into RRsets and sign.
|
||||||
RRset rrset = new RRset();
|
RRset rrset = new RRset();
|
||||||
ArrayList signed_records = new ArrayList();
|
ArrayList signed_records = new ArrayList();
|
||||||
@ -325,7 +377,7 @@ public class JCEDnsSecSigner
|
|||||||
Record r = (Record) i.next();
|
Record r = (Record) i.next();
|
||||||
|
|
||||||
// First record
|
// First record
|
||||||
if (rrset.getName() == null)
|
if (rrset.size() == 0)
|
||||||
{
|
{
|
||||||
rrset.addRR(r);
|
rrset.addRR(r);
|
||||||
continue;
|
continue;
|
||||||
@ -345,31 +397,155 @@ 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,
|
last_cut = addRRset(signed_records, zonename, rrset, kskpairs, zskpairs,
|
||||||
zonename,
|
start, expire, fullySignKeyset, last_cut);
|
||||||
rrset,
|
|
||||||
keysigningkeypairs,
|
|
||||||
zonekeypairs,
|
|
||||||
start,
|
|
||||||
expire,
|
|
||||||
fullySignKeyset,
|
|
||||||
last_cut);
|
|
||||||
|
|
||||||
rrset.clear();
|
rrset.clear();
|
||||||
rrset.addRR(r);
|
rrset.addRR(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the last RR set
|
// add the last RR set
|
||||||
addRRset(signed_records,
|
addRRset(signed_records, zonename, rrset, kskpairs, zskpairs, start,
|
||||||
zonename,
|
expire, fullySignKeyset, last_cut);
|
||||||
rrset,
|
|
||||||
keysigningkeypairs,
|
|
||||||
zonekeypairs,
|
|
||||||
start,
|
|
||||||
expire,
|
|
||||||
fullySignKeyset,
|
|
||||||
last_cut);
|
|
||||||
|
|
||||||
return signed_records;
|
return signed_records;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a zone, sign it using standard NSEC records.
|
||||||
|
*
|
||||||
|
* @param zonename
|
||||||
|
* The name of the zone.
|
||||||
|
* @param records
|
||||||
|
* The records comprising the zone. They do not have to be in any
|
||||||
|
* particular order, as this method will order them as necessary.
|
||||||
|
* @param kskpairs
|
||||||
|
* The key pairs that are designated as "key signing keys".
|
||||||
|
* @param zskpairs
|
||||||
|
* This key pairs that are designated as "zone signing keys".
|
||||||
|
* @param start
|
||||||
|
* The RRSIG inception time.
|
||||||
|
* @param expire
|
||||||
|
* The RRSIG expiration time.
|
||||||
|
* @param fullySignKeyset
|
||||||
|
* Sign the zone apex keyset with all available keys (instead of just
|
||||||
|
* the key signing keys).
|
||||||
|
* @param ds_digest_alg
|
||||||
|
* The digest algorithm to use when generating DS records.
|
||||||
|
*
|
||||||
|
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
||||||
|
* representing the signed zone.
|
||||||
|
*/
|
||||||
|
public List signZone(Name zonename, List records, List kskpairs,
|
||||||
|
List zskpairs, Date start, Date expire,
|
||||||
|
boolean fullySignKeyset, int ds_digest_alg)
|
||||||
|
throws IOException, GeneralSecurityException
|
||||||
|
{
|
||||||
|
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
|
||||||
|
fullySignKeyset, ds_digest_alg, NSEC_MODE, null, null, 0,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a zone, sign it using NSEC3 records.
|
||||||
|
*
|
||||||
|
* @param signer
|
||||||
|
* A signer (utility) object used to actually sign stuff.
|
||||||
|
* @param zonename
|
||||||
|
* The name of the zone being signed.
|
||||||
|
* @param records
|
||||||
|
* The records comprising the zone. They do not have to be in any
|
||||||
|
* particular order, as this method will order them as necessary.
|
||||||
|
* @param kskpairs
|
||||||
|
* The key pairs that are designated as "key signing keys".
|
||||||
|
* @param zskpairs
|
||||||
|
* This key pairs that are designated as "zone signing keys".
|
||||||
|
* @param start
|
||||||
|
* The RRSIG inception time.
|
||||||
|
* @param expire
|
||||||
|
* The RRSIG expiration time.
|
||||||
|
* @param fullySignKeyset
|
||||||
|
* If true then the DNSKEY RRset will be signed by all available
|
||||||
|
* keys, if false, only the key signing keys.
|
||||||
|
* @param useOptOut
|
||||||
|
* If true, insecure delegations will be omitted from the NSEC3
|
||||||
|
* chain, and all NSEC3 records will have the Opt-Out flag set.
|
||||||
|
* @param includedNames
|
||||||
|
* A list of names to include in the NSEC3 chain regardless.
|
||||||
|
* @param salt
|
||||||
|
* The salt to use for the NSEC3 hashing. null means no salt.
|
||||||
|
* @param iterations
|
||||||
|
* The number of iterations to use for the NSEC3 hashing.
|
||||||
|
* @param ds_digest_alg
|
||||||
|
* The digest algorithm to use when generating DS records.
|
||||||
|
*
|
||||||
|
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
||||||
|
* representing the signed zone.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* @throws GeneralSecurityException
|
||||||
|
*/
|
||||||
|
public List signZoneNSEC3(Name zonename, List records, List kskpairs,
|
||||||
|
List zskpairs, Date start, Date expire,
|
||||||
|
boolean fullySignKeyset, boolean useOptOut,
|
||||||
|
List includedNames, byte[] salt, int iterations,
|
||||||
|
int ds_digest_alg)
|
||||||
|
throws IOException, GeneralSecurityException
|
||||||
|
{
|
||||||
|
if (useOptOut)
|
||||||
|
{
|
||||||
|
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
|
||||||
|
fullySignKeyset, ds_digest_alg, NSEC3_OPTOUT_MODE,
|
||||||
|
includedNames, salt, iterations, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
|
||||||
|
fullySignKeyset, ds_digest_alg, NSEC3_MODE, null, salt,
|
||||||
|
iterations, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a zone, sign it using experimental Opt-In NSEC records (see RFC
|
||||||
|
* 4956).
|
||||||
|
*
|
||||||
|
* @param zonename
|
||||||
|
* the name of the zone.
|
||||||
|
* @param records
|
||||||
|
* the records comprising the zone. They do not have to be in any
|
||||||
|
* particular order, as this method will order them as necessary.
|
||||||
|
* @param kskpairs
|
||||||
|
* the key pairs that are designated as "key signing keys".
|
||||||
|
* @param zskpairs
|
||||||
|
* this key pairs that are designated as "zone signing keys".
|
||||||
|
* @param start
|
||||||
|
* the RRSIG inception time.
|
||||||
|
* @param expire
|
||||||
|
* the RRSIG expiration time.
|
||||||
|
* @param useConservativeOptIn
|
||||||
|
* if true, Opt-In NSEC records will only be generated if there are
|
||||||
|
* insecure, unsigned delegations in the span.
|
||||||
|
* @param fullySignKeyset
|
||||||
|
* sign the zone apex keyset with all available keys.
|
||||||
|
* @param ds_digest_alg
|
||||||
|
* The digest algorithm to use when generating DS records.
|
||||||
|
* @param NSECIncludeNames
|
||||||
|
* names that are to be included in the NSEC chain regardless. This
|
||||||
|
* may be null.
|
||||||
|
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
|
||||||
|
* representing the signed zone.
|
||||||
|
*/
|
||||||
|
public List signZoneOptIn(Name zonename, List records, List kskpairs,
|
||||||
|
List zskpairs, Date start, Date expire,
|
||||||
|
boolean useConservativeOptIn,
|
||||||
|
boolean fullySignKeyset, List NSECIncludeNames,
|
||||||
|
int ds_digest_alg)
|
||||||
|
throws IOException, GeneralSecurityException
|
||||||
|
{
|
||||||
|
|
||||||
|
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
|
||||||
|
fullySignKeyset, ds_digest_alg, NSEC_EXP_OPT_IN,
|
||||||
|
NSECIncludeNames, null, 0, useConservativeOptIn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user