Add ability to define the TTL of the NSEC3PARAM record.

git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@133 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
David Blacka 2009-02-07 20:37:29 +00:00
parent 6202d0a0a3
commit b35bab0bdd
3 changed files with 187 additions and 51 deletions

View File

@ -97,6 +97,7 @@ public class SignZone
public byte[] salt = null;
public int iterations = 0;
public int digest_id = DSRecord.SHA1_DIGEST_ID;
public long nsec3paramttl = -1;
public CLIState()
{
@ -124,7 +125,7 @@ public class SignZone
OptionBuilder.withDescription("verbosity level.");
// Argument options
opts.addOption(OptionBuilder.create('v'));
OptionBuilder.hasArg();
OptionBuilder.withArgName("dir");
OptionBuilder.withLongOpt("keyset-directory");
@ -159,7 +160,7 @@ public class SignZone
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");
@ -176,25 +177,31 @@ public class SignZone
OptionBuilder.withArgName("hex value");
OptionBuilder.withDescription("supply a salt value.");
opts.addOption(OptionBuilder.create('S'));
OptionBuilder.hasArg();
OptionBuilder.withLongOpt("random-salt");
OptionBuilder.withArgName("length");
OptionBuilder.withDescription("generate a random salt.");
opts.addOption(OptionBuilder.create('R'));
OptionBuilder.hasArg();
OptionBuilder.withLongOpt("iterations");
OptionBuilder.withArgName("value");
OptionBuilder.withDescription("use this value for the iterations in NSEC3.");
opts.addOption(OptionBuilder.create());
OptionBuilder.hasArg();
OptionBuilder.withLongOpt("nsec3paramttl");
OptionBuilder.withArgName("ttl");
OptionBuilder.withDescription("use this value for the NSEC3PARAM RR ttl");
opts.addOption(OptionBuilder.create());
OptionBuilder.hasArg();
OptionBuilder.withArgName("alias:original:mnemonic");
OptionBuilder.withLongOpt("alg-alias");
OptionBuilder.withDescription("Define an alias for an algorithm (may repeat).");
opts.addOption(OptionBuilder.create('A'));
OptionBuilder.hasArg();
OptionBuilder.withArgName("id");
OptionBuilder.withLongOpt("ds-digest");
@ -351,6 +358,11 @@ public class SignZone
}
}
if ((optstr = cli.getOptionValue("nsec3paramttl")) != null)
{
nsec3paramttl = parseInt(optstr, -1);
}
String[] files = cli.getArgs();
if (files.length < 1)
@ -715,7 +727,10 @@ public class SignZone
{
DnsKeyPair kp = (DnsKeyPair) i.next();
Name keyname = kp.getDNSKEYRecord().getName();
if (!keyname.equals(zonename)) { return false; }
if (!keyname.equals(zonename))
{
return false;
}
}
return true;
@ -852,7 +867,8 @@ public class SignZone
state.fullySignKeyset,
state.useOptOut,
state.includeNames, state.salt,
state.iterations, state.digest_id);
state.iterations, state.digest_id,
state.nsec3paramttl);
}
else
{

View File

@ -151,7 +151,7 @@ public class JCEDnsSecSigner
System.out.println("missing private key that goes with:\n"
+ pair.getDNSKEYRecord());
throw new GeneralSecurityException(
"cannot sign without a valid Signer (probably missing private key)");
"cannot sign without a valid Signer (probably missing private key)");
}
// sign the data.
@ -246,8 +246,14 @@ public class JCEDnsSecSigner
rrset.getType(), last_cut);
// we don't sign non-normal sets (delegations, glue, invalid).
if (type == SignUtils.RR_DELEGATION) { return rrset.getName(); }
if (type == SignUtils.RR_GLUE || type == SignUtils.RR_INVALID) { return last_cut; }
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)
@ -316,7 +322,9 @@ public class JCEDnsSecSigner
* 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 nsec3paramttl
* The TTL to use for the generated NSEC3PARAM record. Negative
* values will use the SOA TTL.
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
* representing the signed zone.
*
@ -327,7 +335,7 @@ public class JCEDnsSecSigner
List zskpairs, Date start, Date expire,
boolean fullySignKeyset, int ds_digest_alg, int mode,
List includedNames, byte[] salt, int iterations,
boolean beConservative)
long nsec3paramttl, boolean beConservative)
throws IOException, GeneralSecurityException
{
// Remove any existing generated DNSSEC records (NSEC, NSEC3, NSEC3PARAM,
@ -348,20 +356,21 @@ public class JCEDnsSecSigner
// Generate the NSEC or NSEC3 records based on 'mode'
switch (mode)
{
case NSEC_MODE:
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;
case NSEC_MODE:
SignUtils.generateNSECRecords(zonename, records);
break;
case NSEC3_MODE:
SignUtils.generateNSEC3Records(zonename, records, salt, iterations,
nsec3paramttl);
break;
case NSEC3_OPTOUT_MODE:
SignUtils.generateOptOutNSEC3Records(zonename, records, includedNames,
salt, iterations, nsec3paramttl);
break;
case NSEC_EXP_OPT_IN:
SignUtils.generateOptInNSECRecords(zonename, records, includedNames,
beConservative);
break;
}
// Re-sort so we can assemble into rrsets.
@ -443,7 +452,7 @@ public class JCEDnsSecSigner
{
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
fullySignKeyset, ds_digest_alg, NSEC_MODE, null, null, 0,
false);
0, false);
}
/**
@ -478,7 +487,9 @@ public class JCEDnsSecSigner
* The number of iterations to use for the NSEC3 hashing.
* @param ds_digest_alg
* The digest algorithm to use when generating DS records.
*
* @param nsec3paramttl
* The TTL to use for the generated NSEC3PARAM record. Negative
* values will use the SOA TTL.
* @return an ordered list of {@link org.xbill.DNS.Record} objects,
* representing the signed zone.
*
@ -489,20 +500,20 @@ public class JCEDnsSecSigner
List zskpairs, Date start, Date expire,
boolean fullySignKeyset, boolean useOptOut,
List includedNames, byte[] salt, int iterations,
int ds_digest_alg)
int ds_digest_alg, long nsec3paramttl)
throws IOException, GeneralSecurityException
{
if (useOptOut)
{
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
fullySignKeyset, ds_digest_alg, NSEC3_OPTOUT_MODE,
includedNames, salt, iterations, false);
includedNames, salt, iterations, nsec3paramttl, false);
}
else
{
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
fullySignKeyset, ds_digest_alg, NSEC3_MODE, null, salt,
iterations, false);
iterations, nsec3paramttl, false);
}
}
@ -546,6 +557,6 @@ public class JCEDnsSecSigner
return signZone(zonename, records, kskpairs, zskpairs, start, expire,
fullySignKeyset, ds_digest_alg, NSEC_EXP_OPT_IN,
NSECIncludeNames, null, 0, useConservativeOptIn);
NSECIncludeNames, null, 0, 0, useConservativeOptIn);
}
}

View File

@ -338,16 +338,18 @@ public class SignUtils
public static byte[] convertDSASignature(DSAParams params, byte[] signature)
throws SignatureException
{
if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT)
if (signature[0] != ASN1_SEQ || signature[2] != ASN1_INT)
{
throw new SignatureException("Invalid ASN.1 signature format: expected SEQ, INT");
throw new SignatureException(
"Invalid ASN.1 signature format: expected SEQ, INT");
}
byte r_pad = (byte) (signature[3] - 20);
if (signature[24 + r_pad] != ASN1_INT)
{
throw new SignatureException("Invalid ASN.1 signature format: expected SEQ, INT, INT");
if (signature[24 + r_pad] != ASN1_INT)
{
throw new SignatureException(
"Invalid ASN.1 signature format: expected SEQ, INT, INT");
}
log.finer("(start) ASN.1 DSA Sig:\n" + base64.toString(signature));
@ -503,8 +505,7 @@ public class SignUtils
// Current record is part of the current RRset.
if (rrset.getName().equals(r.getName())
&& rrset.getDClass() == r.getDClass()
&& ((r.getType() == Type.RRSIG && rrset.getType() == ((RRSIGRecord) r).getTypeCovered()) ||
rrset.getType() == r.getType()))
&& ((r.getType() == Type.RRSIG && rrset.getType() == ((RRSIGRecord) r).getTypeCovered()) || rrset.getType() == r.getType()))
{
rrset.addRR(r);
continue;
@ -585,7 +586,7 @@ public class SignUtils
/**
* Given a canonical (by name) ordered list of records in a zone, generate the
* NXT records in place.
* NSEC records in place.
*
* Note that the list that the records are stored in must support the
* listIterator.add() operation.
@ -620,8 +621,8 @@ public class SignUtils
break;
}
}
if (nsec_ttl == 0)
{
if (nsec_ttl == 0)
{
throw new IllegalArgumentException("Zone did not contain a SOA record");
}
@ -699,8 +700,31 @@ public class SignUtils
log.finer("Generated: " + nsec);
}
/**
* Given a canonical (by name) ordered list of records in a zone, generate the
* NSEC3 records in place.
*
* Note that the list that the records are stored in must support the
* listIterator.add() operation.
*
* @param zonename
* the name of the zone (used to distinguish between zone apex NS
* RRsets and delegations).
* @param records
* a list of {@link org.xbill.DNS.Record} objects in DNSSEC canonical
* order.
* @param salt
* The NSEC3 salt to use (may be null or empty for no salt).
* @param iterations
* The number of hash iterations to use.
* @param nsec3param_ttl
* The TTL to use for the generated NSEC3PARAM records (NSEC3 records
* will use the SOA minimum)
* @throws NoSuchAlgorithmException
*/
public static void generateNSEC3Records(Name zonename, List records,
byte[] salt, int iterations)
byte[] salt, int iterations,
long nsec3param_ttl)
throws NoSuchAlgorithmException
{
List proto_nsec3s = new ArrayList();
@ -710,7 +734,6 @@ public class SignUtils
Name last_cut = null;
long nsec3_ttl = 0;
long nsec3param_ttl = 0;
for (Iterator i = records.iterator(); i.hasNext();)
{
@ -731,7 +754,10 @@ public class SignUtils
{
SOARecord soa = (SOARecord) r;
nsec3_ttl = soa.getMinimum();
nsec3param_ttl = soa.getTTL();
if (nsec3param_ttl < 0)
{
nsec3param_ttl = soa.getTTL();
}
}
// For the first iteration, we create our current node.
@ -785,9 +811,38 @@ public class SignUtils
}
/**
* Given a canonical (by name) ordered list of records in a zone, generate the
* NSEC3 records in place using Opt-Out NSEC3 records. This means that
* non-apex NS RRs (and glue below those delegations) will, by default, not be
* included in the NSEC3 chain.
*
* Note that the list that the records are stored in must support the
* listIterator.add() operation.
*
* @param zonename
* the name of the zone (used to distinguish between zone apex NS
* RRsets and delegations).
* @param records
* a list of {@link org.xbill.DNS.Record} objects in DNSSEC canonical
* order.
* @param includedNames
* A list of {@link org.xbill.DNS.Name} objects. These names will be
* included in the NSEC3 chain (if they exist in the zone)
* regardless.
* @param salt
* The NSEC3 salt to use (may be null or empty for no salt).
* @param iterations
* The number of hash iterations to use.
* @param nsec3param_ttl
* The TTL to use for the generated NSEC3PARAM records (NSEC3 records
* will use the SOA minimum)
* @throws NoSuchAlgorithmException
*/
public static void generateOptOutNSEC3Records(Name zonename, List records,
List includedNames,
byte[] salt, int iterations)
byte[] salt, int iterations,
long nsec3param_ttl)
throws NoSuchAlgorithmException
{
List proto_nsec3s = new ArrayList();
@ -797,7 +852,6 @@ public class SignUtils
Name last_cut = null;
long nsec3_ttl = 0;
long nsec3param_ttl = 0;
HashSet includeSet = null;
if (includedNames != null)
@ -824,7 +878,10 @@ public class SignUtils
{
SOARecord soa = (SOARecord) r;
nsec3_ttl = soa.getMinimum();
nsec3param_ttl = soa.getTTL();
if (nsec3param_ttl < 0)
{
nsec3param_ttl = soa.getTTL();
}
}
// For the first iteration, we create our current node.
@ -883,6 +940,25 @@ public class SignUtils
records.add(nsec3param);
}
/**
* For a given node (representing all of the RRsets at a given name), generate
* all of the necessary NSEC3 records for it. That is, generate the NSEC3 for
* the node itself, and for any potential empty non-terminals.
*
* @param node
* The node in question.
* @param zonename
* The zonename.
* @param salt
* The salt to use for the NSEC3 RRs
* @param iterations
* The iterations to use for the NSEC3 RRs.
* @param optIn
* If true, the NSEC3 will have the Opt-Out flag set.
* @param nsec3s
* The current list of NSEC3s -- this will be updated.
* @throws NoSuchAlgorithmException
*/
private static void generateNSEC3ForNode(NodeInfo node, Name zonename,
byte[] salt, int iterations,
boolean optIn, List nsec3s)
@ -912,6 +988,27 @@ public class SignUtils
nsec3s.add(nsec3);
}
/**
* Create a "prototype" NSEC3 record. Basically, a mutable NSEC3 record.
*
* @param name
* The original ownername to use.
* @param zonename
* The zonename to use.
* @param ttl
* The TTL to use.
* @param salt
* The salt to use.
* @param iterations
* The number of hash iterations to use.
* @param optIn
* The value of the Opt-Out flag.
* @param types
* The typecodes present at this name.
* @return A mutable NSEC3 record.
*
* @throws NoSuchAlgorithmException
*/
private static ProtoNSEC3 generateNSEC3(Name name, Name zonename, long ttl,
byte[] salt, int iterations,
boolean optIn, int[] types)
@ -921,14 +1018,26 @@ public class SignUtils
iterations, salt);
byte flags = (byte) (optIn ? 0x01 : 0x00);
ProtoNSEC3 r = new ProtoNSEC3(hash, name, zonename, DClass.IN, ttl, flags,
NSEC3Record.SHA1_DIGEST_ID, iterations, salt,
null, types);
ProtoNSEC3 r = new ProtoNSEC3(hash, name, zonename, DClass.IN, ttl,
NSEC3Record.SHA1_DIGEST_ID, flags,
iterations, salt, null, types);
log.finer("Generated: " + r);
return r;
}
/**
* Given a list of {@link ProtoNSEC3} object (mutable NSEC3 RRs), convert the
* list into the set of actual {@link org.xbill.DNS.NSEC3Record} objects. This
* will remove duplicates and finalize the records.
*
* @param nsec3s
* The list of ProtoNSEC3 objects
* @param ttl
* The TTL to assign to the finished NSEC3 records. In general, this
* should match the SOA minimum value for the zone.
* @return The list of {@link org.xbill.DNS.NSEC3Record} objects.
*/
private static List finishNSEC3s(List nsec3s, long ttl)
{
if (nsec3s == null) return null;