fix a number of jdnssec-signzone signing bugs: do not incorrectly set the RRSIG bit on NSEC3 RRs corresponding to insecure delegations, ignore junk below a DNAME, ignore delegations below other delegations

git-svn-id: https://svn.verisignlabs.com/jdnssec/tools/trunk@218 4cbd57fe-54e5-0310-bd9a-f30fe5ea5e6e
This commit is contained in:
David Blacka 2010-12-06 00:25:04 +00:00
parent 14ea619299
commit 3c9e33baf7
4 changed files with 92 additions and 39 deletions

View File

@ -1,5 +1,18 @@
2010-12-05 David Blacka <davidb@verisignlabs.com> 2010-12-05 David Blacka <davidb@verisignlabs.com>
* jdnssec-signzone: Fix a bug that would incorrectly handle
delgations below delegations (those should be ignored.)
* jdnssec-signzone: Make the signer ignore junk below a DNAME.
This differs from BIND's dnssec-signzone behavior (currently), but
is the correct behavior, as stuff below a DNAME doesn't actually
exist in DNS. Note that if a name in a zone has both a DNAME and
a NS RRset (and is not at the apex), then the behavior is a bit
undefined.
* jdnssec-signzone: Fix a bug that would incorrectly set the RRSIG
bit for NSEC3 RRs corresponding to insecure delegations.
* jdnssec-signzone: add a "verbose signing" option. This will * jdnssec-signzone: add a "verbose signing" option. This will
cause the pre-signed bytes and the raw signature bytes to be cause the pre-signed bytes and the raw signature bytes to be
output when signing. output when signing.

View File

@ -266,7 +266,7 @@ public class JCEDnsSecSigner
*/ */
private Name addRRset(List toList, Name zonename, RRset rrset, List kskpairs, private Name addRRset(List toList, Name zonename, RRset rrset, List kskpairs,
List zskpairs, Date start, Date expire, boolean fullySignKeyset, List zskpairs, Date start, Date expire, boolean fullySignKeyset,
Name last_cut) throws IOException, GeneralSecurityException Name last_cut, Name last_dname) throws IOException, GeneralSecurityException
{ {
// add the records themselves // add the records themselves
for (Iterator i = rrset.rrs(); i.hasNext();) for (Iterator i = rrset.rrs(); i.hasNext();)
@ -275,7 +275,7 @@ public class JCEDnsSecSigner
} }
int type = SignUtils.recordSecType(zonename, rrset.getName(), rrset.getType(), int type = SignUtils.recordSecType(zonename, rrset.getName(), rrset.getType(),
last_cut); last_cut, last_dname);
// we don't sign non-normal sets (delegations, glue, invalid). // we don't sign non-normal sets (delegations, glue, invalid).
if (type == SignUtils.RR_DELEGATION) if (type == SignUtils.RR_DELEGATION)
@ -410,6 +410,7 @@ public class JCEDnsSecSigner
RRset rrset = new RRset(); RRset rrset = new RRset();
ArrayList signed_records = new ArrayList(); ArrayList signed_records = new ArrayList();
Name last_cut = null; Name last_cut = null;
Name last_dname = null;
for (ListIterator i = records.listIterator(); i.hasNext();) for (ListIterator i = records.listIterator(); i.hasNext();)
{ {
@ -436,7 +437,8 @@ public class JCEDnsSecSigner
// add the RRset to the list of signed_records, regardless of // add the RRset to the list of signed_records, regardless of
// whether or not we actually end up signing the set. // whether or not we actually end up signing the set.
last_cut = addRRset(signed_records, zonename, rrset, kskpairs, zskpairs, start, last_cut = addRRset(signed_records, zonename, rrset, kskpairs, zskpairs, start,
expire, fullySignKeyset, last_cut); expire, fullySignKeyset, last_cut, last_dname);
if (rrset.getType() == Type.DNAME) last_dname = rrset.getName();
rrset.clear(); rrset.clear();
rrset.addRR(r); rrset.addRR(r);
@ -444,7 +446,7 @@ public class JCEDnsSecSigner
// add the last RR set // add the last RR set
addRRset(signed_records, zonename, rrset, kskpairs, zskpairs, start, expire, addRRset(signed_records, zonename, rrset, kskpairs, zskpairs, start, expire,
fullySignKeyset, last_cut); fullySignKeyset, last_cut, last_dname);
return signed_records; return signed_records;
} }

View File

@ -42,7 +42,7 @@ public class RecordComparator implements Comparator
} }
/** /**
* In general, types are compared numerically. However, SOA and NS are ordered * In general, types are compared numerically. However, SOA, NS, and DNAME are ordered
* before the rest. * before the rest.
*/ */
private int compareTypes(int a, int b) private int compareTypes(int a, int b)
@ -54,6 +54,9 @@ public class RecordComparator implements Comparator
if (a == Type.NS) return -1; if (a == Type.NS) return -1;
if (b == Type.NS) return 1; if (b == Type.NS) return 1;
if (a == Type.DNAME) return -1;
if (b == Type.DNAME) return 1;
if (a < b) return -1; if (a < b) return -1;
return 1; return 1;

View File

@ -49,6 +49,7 @@ public class SignUtils
public static final int RR_DELEGATION = 1; public static final int RR_DELEGATION = 1;
public static final int RR_GLUE = 2; public static final int RR_GLUE = 2;
public static final int RR_INVALID = 3; public static final int RR_INVALID = 3;
public static final int RR_DNAME = 4;
private static Logger log; private static Logger log;
@ -478,32 +479,43 @@ public class SignUtils
* while iterating over the zone in canonical order. * while iterating over the zone in canonical order.
*/ */
public static int recordSecType(Name zonename, Name name, int type, public static int recordSecType(Name zonename, Name name, int type,
Name last_cut) Name last_cut, Name last_dname)
{ {
// records not even in the zone itself are invalid. // records not even in the zone itself are invalid.
if (!name.subdomain(zonename)) return RR_INVALID; if (!name.subdomain(zonename)) return RR_INVALID;
// records that are at the zonename node are definitely normal. // all records a the zone apex are normal, by definition.
if (name.equals(zonename)) return RR_NORMAL; if (name.equals(zonename)) return RR_NORMAL;
if (last_cut != null && name.subdomain(last_cut))
{
// if we are at the same level as a delegation point, but not one of a set of types allowed at
// a delegation point (NS, DS, NSEC), this is glue.
if (name.equals(last_cut))
{
if (type != Type.NS && type != Type.DS && type != Type.NXT && type != Type.NSEC)
{
return RR_GLUE;
}
}
// if we are below the delegation point, this is glue.
else
{
return RR_GLUE;
}
}
// if we are below a DNAME, then the RR is invalid.
if (last_dname != null && name.subdomain(last_dname) && name.labels() > last_dname.labels())
{
return RR_INVALID;
}
// since we are not at zone level, any NS records are delegations // since we are not at zone level, any NS records are delegations
if (type == Type.NS) return RR_DELEGATION; if (type == Type.NS) return RR_DELEGATION;
if (last_cut != null) // and everything else is normal
{
// if we are at the same level as a delegation point, but not an
// NS record, then we either a DS record or glue.
if (name.equals(last_cut))
{
if (type == Type.DS || type == Type.NXT || type == Type.NSEC)
return RR_NORMAL;
// actually, this is probably INVALID, but it could be glue.
return RR_GLUE;
}
// below the delegation, we are glue
if (name.subdomain(last_cut)) return RR_GLUE;
}
return RR_NORMAL; return RR_NORMAL;
} }
@ -578,16 +590,16 @@ public class SignUtils
public boolean hasOptInSpan; // opt-in support. public boolean hasOptInSpan; // opt-in support.
public int nsecIndex; public int nsecIndex;
public NodeInfo(Record r) public NodeInfo(Record r, int nodeType)
{ {
this.name = r.getName(); this.name = r.getName();
this.type = r.getType(); this.type = nodeType;
this.ttl = r.getTTL(); this.ttl = r.getTTL();
this.dclass = r.getDClass(); this.dclass = r.getDClass();
this.typemap = new HashSet(); this.typemap = new HashSet();
this.isSecureNode = false; this.isSecureNode = false;
this.hasOptInSpan = false; this.hasOptInSpan = false;
addType(type); addType(r.getType());
} }
public void addType(int type) public void addType(int type)
@ -602,6 +614,10 @@ public class SignUtils
} }
} }
public boolean hasType(int type) {
return this.typemap.contains(new Integer(type));
}
public String toString() public String toString()
{ {
StringBuffer sb = new StringBuffer(name.toString()); StringBuffer sb = new StringBuffer(name.toString());
@ -645,6 +661,7 @@ public class SignUtils
NodeInfo current_node = null; NodeInfo current_node = null;
Name last_cut = null; Name last_cut = null;
Name last_dname = null;
int backup; int backup;
long nsec_ttl = 0; long nsec_ttl = 0;
@ -670,7 +687,7 @@ public class SignUtils
Record r = (Record) i.next(); Record r = (Record) i.next();
Name r_name = r.getName(); Name r_name = r.getName();
int r_type = r.getType(); int r_type = r.getType();
int r_sectype = recordSecType(zonename, r_name, r_type, last_cut); int r_sectype = recordSecType(zonename, r_name, r_type, last_cut, last_dname);
// skip irrelevant records // skip irrelevant records
if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue; if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue;
@ -678,10 +695,13 @@ public class SignUtils
// note our last delegation point so we can recognize glue. // note our last delegation point so we can recognize glue.
if (r_sectype == RR_DELEGATION) last_cut = r_name; if (r_sectype == RR_DELEGATION) last_cut = r_name;
// if this is a DNAME, note it so we can recognize junk
if (r_type == Type.DNAME) last_dname = r_name;
// first node -- initialize // first node -- initialize
if (current_node == null) if (current_node == null)
{ {
current_node = new NodeInfo(r); current_node = new NodeInfo(r, r_sectype);
current_node.addType(Type.RRSIG); current_node.addType(Type.RRSIG);
current_node.addType(Type.NSEC); current_node.addType(Type.NSEC);
continue; continue;
@ -715,7 +735,7 @@ public class SignUtils
last_node = current_node; last_node = current_node;
current_node.nsecIndex = i.previousIndex(); current_node.nsecIndex = i.previousIndex();
current_node = new NodeInfo(r); current_node = new NodeInfo(r, r_sectype);
current_node.addType(Type.RRSIG); current_node.addType(Type.RRSIG);
current_node.addType(Type.NSEC); current_node.addType(Type.NSEC);
} }
@ -771,6 +791,8 @@ public class SignUtils
NodeInfo last_node = null; NodeInfo last_node = null;
// For detecting glue. // For detecting glue.
Name last_cut = null; Name last_cut = null;
// For detecting junk below a DNAME
Name last_dname = null;
long nsec3_ttl = 0; long nsec3_ttl = 0;
@ -781,7 +803,7 @@ public class SignUtils
int r_type = r.getType(); int r_type = r.getType();
// Classify this record so we know if we can skip it. // Classify this record so we know if we can skip it.
int r_sectype = recordSecType(zonename, r_name, r_type, last_cut); int r_sectype = recordSecType(zonename, r_name, r_type, last_cut, last_dname);
// skip irrelevant records // skip irrelevant records
if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue; if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue;
@ -789,6 +811,9 @@ public class SignUtils
// note our last delegation point so we can recognize glue. // note our last delegation point so we can recognize glue.
if (r_sectype == RR_DELEGATION) last_cut = r_name; if (r_sectype == RR_DELEGATION) last_cut = r_name;
// note our last DNAME point, so we can recognize junk.
if (r_type == Type.DNAME) last_dname = r_name;
if (r_type == Type.SOA) if (r_type == Type.SOA)
{ {
SOARecord soa = (SOARecord) r; SOARecord soa = (SOARecord) r;
@ -802,7 +827,7 @@ public class SignUtils
// For the first iteration, we create our current node. // For the first iteration, we create our current node.
if (current_node == null) if (current_node == null)
{ {
current_node = new NodeInfo(r); current_node = new NodeInfo(r, r_sectype);
continue; continue;
} }
@ -820,7 +845,7 @@ public class SignUtils
proto_nsec3s); proto_nsec3s);
last_node = current_node; last_node = current_node;
current_node = new NodeInfo(r); current_node = new NodeInfo(r, r_sectype);
} }
// process last two nodes. // process last two nodes.
@ -889,6 +914,8 @@ public class SignUtils
NodeInfo last_node = null; NodeInfo last_node = null;
// For detecting glue. // For detecting glue.
Name last_cut = null; Name last_cut = null;
// For detecting out-of-zone records below a DNAME
Name last_dname = null;
long nsec3_ttl = 0; long nsec3_ttl = 0;
@ -905,7 +932,7 @@ public class SignUtils
int r_type = r.getType(); int r_type = r.getType();
// Classify this record so we know if we can skip it. // Classify this record so we know if we can skip it.
int r_sectype = recordSecType(zonename, r_name, r_type, last_cut); int r_sectype = recordSecType(zonename, r_name, r_type, last_cut, last_dname);
// skip irrelevant records // skip irrelevant records
if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue; if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue;
@ -913,6 +940,8 @@ public class SignUtils
// note our last delegation point so we can recognize glue. // note our last delegation point so we can recognize glue.
if (r_sectype == RR_DELEGATION) last_cut = r_name; if (r_sectype == RR_DELEGATION) last_cut = r_name;
if (r_type == Type.DNAME) last_dname = r_name;
if (r_type == Type.SOA) if (r_type == Type.SOA)
{ {
SOARecord soa = (SOARecord) r; SOARecord soa = (SOARecord) r;
@ -926,7 +955,7 @@ public class SignUtils
// For the first iteration, we create our current node. // For the first iteration, we create our current node.
if (current_node == null) if (current_node == null)
{ {
current_node = new NodeInfo(r); current_node = new NodeInfo(r, r_sectype);
continue; continue;
} }
@ -957,7 +986,7 @@ public class SignUtils
last_node.hasOptInSpan = true; last_node.hasOptInSpan = true;
} }
current_node = new NodeInfo(r); current_node = new NodeInfo(r, r_sectype);
} }
// process last two nodes. // process last two nodes.
@ -1007,7 +1036,9 @@ public class SignUtils
if (optIn && !node.isSecureNode) return; if (optIn && !node.isSecureNode) return;
// Add our default types. // Add our default types.
if (node.type == RR_NORMAL || (node.type == RR_DELEGATION && node.hasType(Type.DS))) {
node.addType(Type.RRSIG); node.addType(Type.RRSIG);
}
if (node.name.equals(zonename)) node.addType(Type.NSEC3PARAM); if (node.name.equals(zonename)) node.addType(Type.NSEC3PARAM);
// Check for ENTs -- note this will generate duplicate ENTs because it // Check for ENTs -- note this will generate duplicate ENTs because it
@ -1170,6 +1201,8 @@ public class SignUtils
NodeInfo current_node = null; NodeInfo current_node = null;
Name last_cut = null; Name last_cut = null;
Name last_dname = null;
int backup; int backup;
HashSet includeSet = null; HashSet includeSet = null;
@ -1183,7 +1216,7 @@ public class SignUtils
Record r = (Record) i.next(); Record r = (Record) i.next();
Name r_name = r.getName(); Name r_name = r.getName();
int r_type = r.getType(); int r_type = r.getType();
int r_sectype = recordSecType(zonename, r_name, r_type, last_cut); int r_sectype = recordSecType(zonename, r_name, r_type, last_cut, last_dname);
// skip irrelevant records // skip irrelevant records
if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue; if (r_sectype == RR_INVALID || r_sectype == RR_GLUE) continue;
@ -1191,10 +1224,12 @@ public class SignUtils
// note our last delegation point so we can recognize glue. // note our last delegation point so we can recognize glue.
if (r_sectype == RR_DELEGATION) last_cut = r_name; if (r_sectype == RR_DELEGATION) last_cut = r_name;
if (r_type == Type.DNAME) last_dname = r_name;
// first node -- initialize // first node -- initialize
if (current_node == null) if (current_node == null)
{ {
current_node = new NodeInfo(r); current_node = new NodeInfo(r, r_sectype);
current_node.addType(Type.RRSIG); current_node.addType(Type.RRSIG);
continue; continue;
} }
@ -1249,7 +1284,7 @@ public class SignUtils
} }
current_node.nsecIndex = i.previousIndex(); current_node.nsecIndex = i.previousIndex();
current_node = new NodeInfo(r); current_node = new NodeInfo(r, r_sectype);
current_node.addType(Type.RRSIG); current_node.addType(Type.RRSIG);
} }