We now compile, although we probably don't really work
This commit is contained in:
parent
a852ce1790
commit
c43169bc24
@ -1,7 +1,5 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2005 VeriSign, Inc. All rights reserved.
|
||||
* Copyright (c) 2009 VeriSign, Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -39,12 +37,9 @@ import org.xbill.DNS.*;
|
||||
/**
|
||||
* This is a collection of routines encompassing the logic of validating
|
||||
* different message types.
|
||||
*
|
||||
* @author davidb
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class ValUtils
|
||||
{
|
||||
|
||||
public class ValUtils {
|
||||
|
||||
// These are response subtypes. They are necessary for determining the
|
||||
// validation strategy. They have no bearing on the iterative resolution
|
||||
@ -74,33 +69,29 @@ public class ValUtils
|
||||
/** A local copy of the verifier object. */
|
||||
private DnsSecVerifier mVerifier;
|
||||
|
||||
public ValUtils(DnsSecVerifier verifier)
|
||||
{
|
||||
public ValUtils(DnsSecVerifier verifier) {
|
||||
mVerifier = verifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a response, classify ANSWER responses into a subtype.
|
||||
*
|
||||
* @param m The response to classify.
|
||||
* @param m
|
||||
* The response to classify.
|
||||
*
|
||||
* @return A subtype ranging from UNKNOWN to NAMEERROR.
|
||||
*/
|
||||
public static int classifyResponse(SMessage m)
|
||||
{
|
||||
public static int classifyResponse(SMessage m) {
|
||||
// Normal Name Error's are easy to detect -- but don't mistake a CNAME
|
||||
// chain ending in NXDOMAIN.
|
||||
if (m.getRcode() == Rcode.NXDOMAIN
|
||||
&& m.getCount(Section.ANSWER) == 0)
|
||||
{
|
||||
if (m.getRcode() == Rcode.NXDOMAIN && m.getCount(Section.ANSWER) == 0) {
|
||||
return NAMEERROR;
|
||||
}
|
||||
|
||||
// Next is NODATA
|
||||
// st_log.debug("classifyResponse: ancount = " +
|
||||
// m.getCount(Section.ANSWER));
|
||||
if (m.getCount(Section.ANSWER) == 0)
|
||||
{
|
||||
if (m.getCount(Section.ANSWER) == 0) {
|
||||
return NODATA;
|
||||
}
|
||||
|
||||
@ -108,10 +99,10 @@ public class ValUtils
|
||||
// responses because CNAME answers require extra processing.
|
||||
int qtype = m.getQuestion().getType();
|
||||
|
||||
// We distinguish between ANY and CNAME or POSITIVE because ANY responses
|
||||
// We distinguish between ANY and CNAME or POSITIVE because ANY
|
||||
// responses
|
||||
// are validated differently.
|
||||
if (qtype == Type.ANY)
|
||||
{
|
||||
if (qtype == Type.ANY) {
|
||||
return ANY;
|
||||
}
|
||||
|
||||
@ -119,8 +110,7 @@ public class ValUtils
|
||||
|
||||
// Note that DNAMEs will be ignored here, unless qtype=DNAME. Unless
|
||||
// qtype=CNAME, this will yield a CNAME response.
|
||||
for (int i = 0; i < rrsets.length; i++)
|
||||
{
|
||||
for (int i = 0; i < rrsets.length; i++) {
|
||||
if (rrsets[i].getType() == qtype) return POSITIVE;
|
||||
if (rrsets[i].getType() == Type.CNAME) return CNAME;
|
||||
}
|
||||
@ -134,29 +124,27 @@ public class ValUtils
|
||||
* to determine if the response is, in fact, signed at all, and, if so, what
|
||||
* is the name of the most pertinent keyset.
|
||||
*
|
||||
* @param m The response to analyze.
|
||||
* @param request The request that generated the response.
|
||||
* @param m
|
||||
* The response to analyze.
|
||||
* @param request
|
||||
* The request that generated the response.
|
||||
* @return a signer name, if the response is signed (even partially), or
|
||||
* null if the response isn't signed.
|
||||
*/
|
||||
public Name findSigner(SMessage m)
|
||||
{
|
||||
public Name findSigner(SMessage m) {
|
||||
int subtype = classifyResponse(m);
|
||||
Name qname = m.getQName();
|
||||
|
||||
SRRset[] rrsets;
|
||||
|
||||
switch (subtype)
|
||||
{
|
||||
switch (subtype) {
|
||||
case POSITIVE:
|
||||
case CNAME:
|
||||
case ANY:
|
||||
// Check to see if the ANSWER section RRset
|
||||
rrsets = m.getSectionRRsets(Section.ANSWER);
|
||||
for (int i = 0; i < rrsets.length; i++)
|
||||
{
|
||||
if (rrsets[i].getName().equals(qname))
|
||||
{
|
||||
for (int i = 0; i < rrsets.length; i++) {
|
||||
if (rrsets[i].getName().equals(qname)) {
|
||||
return rrsets[i].getSignerName();
|
||||
}
|
||||
}
|
||||
@ -166,11 +154,9 @@ public class ValUtils
|
||||
case NODATA:
|
||||
// Check to see if the AUTH section NSEC record(s) have rrsigs
|
||||
rrsets = m.getSectionRRsets(Section.AUTHORITY);
|
||||
for (int i = 0; i < rrsets.length; i++)
|
||||
{
|
||||
for (int i = 0; i < rrsets.length; i++) {
|
||||
if (rrsets[i].getType() == Type.NSEC
|
||||
|| rrsets[i].getType() == Type.NSEC3)
|
||||
{
|
||||
|| rrsets[i].getType() == Type.NSEC3) {
|
||||
return rrsets[i].getSignerName();
|
||||
}
|
||||
}
|
||||
@ -182,14 +168,11 @@ public class ValUtils
|
||||
}
|
||||
}
|
||||
|
||||
public boolean dssetIsUsable(SRRset ds_rrset)
|
||||
{
|
||||
for (Iterator i = ds_rrset.rrs(); i.hasNext();)
|
||||
{
|
||||
public boolean dssetIsUsable(SRRset ds_rrset) {
|
||||
for (Iterator i = ds_rrset.rrs(); i.hasNext();) {
|
||||
DSRecord ds = (DSRecord) i.next();
|
||||
if (supportsDigestID(ds.getDigestID())
|
||||
&& mVerifier.supportsAlgorithm(ds.getAlgorithm()))
|
||||
{
|
||||
&& mVerifier.supportsAlgorithm(ds.getAlgorithm())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -201,10 +184,11 @@ public class ValUtils
|
||||
* Given a DS rrset and a DNSKEY rrset, match the DS to a DNSKEY and verify
|
||||
* the DNSKEY rrset with that key.
|
||||
*
|
||||
* @param dnskey_rrset The DNSKEY rrset to match against. The security
|
||||
* status of this rrset will be updated on a successful
|
||||
* verification.
|
||||
* @param ds_rrset The DS rrset to match with. This rrset must already be
|
||||
* @param dnskey_rrset
|
||||
* The DNSKEY rrset to match against. The security status of this
|
||||
* rrset will be updated on a successful verification.
|
||||
* @param ds_rrset
|
||||
* The DS rrset to match with. This rrset must already be
|
||||
* trusted.
|
||||
*
|
||||
* @return a KeyEntry. This will either contain the now trusted
|
||||
@ -289,7 +273,8 @@ public class ValUtils
|
||||
// // If no DSs were understandable, then this is OK.
|
||||
// if (!hasUsefulDS)
|
||||
// {
|
||||
//// log.debug("No usuable DS records were found -- treating as insecure.");
|
||||
// //
|
||||
// log.debug("No usuable DS records were found -- treating as insecure.");
|
||||
// return KeyEntry.newNullKeyEntry(ds_rrset.getName(), ds_rrset
|
||||
// .getDClass(), ds_rrset.getTTL());
|
||||
// }
|
||||
@ -297,26 +282,24 @@ public class ValUtils
|
||||
// // log.debug("Failed to match any usable DS to a DNSKEY.");
|
||||
// return KeyEntry.newBadKeyEntry(ds_rrset.getName(), ds_rrset.getDClass());
|
||||
// }
|
||||
|
||||
/**
|
||||
* Given a DNSKEY record, generate the DS record from it.
|
||||
*
|
||||
* @param keyrec the DNSKEY record in question.
|
||||
* @param ds_alg The DS digest algorithm in use.
|
||||
* @param keyrec
|
||||
* the DNSKEY record in question.
|
||||
* @param ds_alg
|
||||
* The DS digest algorithm in use.
|
||||
* @return the corresponding {@link org.xbill.DNS.DSRecord}
|
||||
*/
|
||||
public static byte[] calculateDSHash(DNSKEYRecord keyrec, int ds_alg)
|
||||
{
|
||||
public static byte[] calculateDSHash(DNSKEYRecord keyrec, int ds_alg) {
|
||||
DNSOutput os = new DNSOutput();
|
||||
|
||||
os.writeByteArray(keyrec.getName().toWireCanonical());
|
||||
os.writeByteArray(keyrec.rdataToWireCanonical());
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
MessageDigest md = null;
|
||||
switch (ds_alg)
|
||||
{
|
||||
switch (ds_alg) {
|
||||
case DSRecord.SHA1_DIGEST_ID:
|
||||
md = MessageDigest.getInstance("SHA");
|
||||
return md.digest(os.toByteArray());
|
||||
@ -328,16 +311,13 @@ public class ValUtils
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// st_log.error("Error using DS algorithm: " + ds_alg, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean supportsDigestID(int digest_id)
|
||||
{
|
||||
public static boolean supportsDigestID(int digest_id) {
|
||||
if (digest_id == DSRecord.SHA1_DIGEST_ID) return true;
|
||||
if (digest_id == DSRecord.SHA256_DIGEST_ID) return true;
|
||||
return false;
|
||||
@ -346,14 +326,13 @@ public class ValUtils
|
||||
/**
|
||||
* Check to see if a type is a special DNSSEC type.
|
||||
*
|
||||
* @param type The type.
|
||||
* @param type
|
||||
* The type.
|
||||
*
|
||||
* @return true if the type is one of the special DNSSEC types.
|
||||
*/
|
||||
public static boolean isDNSSECType(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
public static boolean isDNSSECType(int type) {
|
||||
switch (type) {
|
||||
case Type.DNSKEY:
|
||||
case Type.NSEC:
|
||||
case Type.DS:
|
||||
@ -369,16 +348,16 @@ public class ValUtils
|
||||
* Set the security status of a particular RRset. This will only upgrade the
|
||||
* security status.
|
||||
*
|
||||
* @param rrset The SRRset to update.
|
||||
* @param security The security status.
|
||||
* @param rrset
|
||||
* The SRRset to update.
|
||||
* @param security
|
||||
* The security status.
|
||||
*/
|
||||
public static void setRRsetSecurity(SRRset rrset, byte security)
|
||||
{
|
||||
public static void setRRsetSecurity(SRRset rrset, byte security) {
|
||||
if (rrset == null) return;
|
||||
|
||||
int cur_sec = rrset.getSecurityStatus();
|
||||
if (cur_sec == SecurityStatus.UNCHECKED || security > cur_sec)
|
||||
{
|
||||
if (cur_sec == SecurityStatus.UNCHECKED || security > cur_sec) {
|
||||
rrset.setSecurityStatus(security);
|
||||
}
|
||||
}
|
||||
@ -389,30 +368,27 @@ public class ValUtils
|
||||
* less) and all of the RRsets.
|
||||
*
|
||||
* @param m
|
||||
* @param security KeyEntry ke;
|
||||
* @param security
|
||||
* KeyEntry ke;
|
||||
*
|
||||
* SMessage m = response.getSMessage(); SRRset ans_rrset =
|
||||
* m.findAnswerRRset(qname, qtype, qclass);
|
||||
*
|
||||
* ke = verifySRRset(ans_rrset, key_rrset); if
|
||||
* (ans_rrset.getSecurityStatus() != SecurityStatus.SECURE) { return; }
|
||||
* key_rrset = ke.getRRset();
|
||||
* (ans_rrset.getSecurityStatus() != SecurityStatus.SECURE) {
|
||||
* return; } key_rrset = ke.getRRset();
|
||||
*/
|
||||
public static void setMessageSecurity(SMessage m, byte security)
|
||||
{
|
||||
public static void setMessageSecurity(SMessage m, byte security) {
|
||||
if (m == null) return;
|
||||
|
||||
int cur_sec = m.getStatus();
|
||||
if (cur_sec == SecurityStatus.UNCHECKED || security > cur_sec)
|
||||
{
|
||||
if (cur_sec == SecurityStatus.UNCHECKED || security > cur_sec) {
|
||||
m.setStatus(security);
|
||||
}
|
||||
|
||||
for (int section = Section.ANSWER; section <= Section.ADDITIONAL; section++)
|
||||
{
|
||||
for (int section = Section.ANSWER; section <= Section.ADDITIONAL; section++) {
|
||||
SRRset[] rrsets = m.getSectionRRsets(section);
|
||||
for (int i = 0; i < rrsets.length; i++)
|
||||
{
|
||||
for (int i = 0; i < rrsets.length; i++) {
|
||||
setRRsetSecurity(rrsets[i], security);
|
||||
}
|
||||
}
|
||||
@ -423,31 +399,33 @@ public class ValUtils
|
||||
* it. This will return the status (either BOGUS or SECURE) and set that
|
||||
* status in rrset.
|
||||
*
|
||||
* @param rrset The SRRset to verify.
|
||||
* @param key_rrset The set of keys to verify against.
|
||||
* @param rrset
|
||||
* The SRRset to verify.
|
||||
* @param key_rrset
|
||||
* The set of keys to verify against.
|
||||
* @return The status (BOGUS or SECURE).
|
||||
*/
|
||||
public byte verifySRRset(SRRset rrset, SRRset key_rrset)
|
||||
{
|
||||
String rrset_name = rrset.getName() + "/" + Type.string(rrset.getType())
|
||||
+ "/" + DClass.string(rrset.getDClass());
|
||||
public byte verifySRRset(SRRset rrset, SRRset key_rrset) {
|
||||
String rrset_name = rrset.getName() + "/"
|
||||
+ Type.string(rrset.getType()) + "/"
|
||||
+ DClass.string(rrset.getDClass());
|
||||
|
||||
if (rrset.getSecurityStatus() == SecurityStatus.SECURE)
|
||||
{
|
||||
if (rrset.getSecurityStatus() == SecurityStatus.SECURE) {
|
||||
// log.trace("verifySRRset: rrset <" + rrset_name
|
||||
// + "> previously found to be SECURE");
|
||||
return SecurityStatus.SECURE;
|
||||
}
|
||||
|
||||
byte status = mVerifier.verify(rrset, key_rrset);
|
||||
if (status != SecurityStatus.SECURE)
|
||||
{
|
||||
// log.debug("verifySRRset: rrset <" + rrset_name + "> found to be BAD");
|
||||
if (status != SecurityStatus.SECURE) {
|
||||
// log.debug("verifySRRset: rrset <" + rrset_name +
|
||||
// "> found to be BAD");
|
||||
status = SecurityStatus.BOGUS;
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// log.trace("verifySRRset: rrset <" + rrset_name + "> found to be SECURE");
|
||||
// log.trace("verifySRRset: rrset <" + rrset_name +
|
||||
// "> found to be SECURE");
|
||||
// }
|
||||
|
||||
rrset.setSecurityStatus(status);
|
||||
@ -457,14 +435,14 @@ public class ValUtils
|
||||
/**
|
||||
* Determine if a given type map has a given typ.
|
||||
*
|
||||
* @param types The type map from the NSEC record.
|
||||
* @param type The type to look for.
|
||||
* @param types
|
||||
* The type map from the NSEC record.
|
||||
* @param type
|
||||
* The type to look for.
|
||||
* @return true if the type is present in the type map, false otherwise.
|
||||
*/
|
||||
public static boolean typeMapHasType(int[] types, int type)
|
||||
{
|
||||
for (int i = 0; i < types.length; i++)
|
||||
{
|
||||
public static boolean typeMapHasType(int[] types, int type) {
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (types[i] == type) return true;
|
||||
}
|
||||
return false;
|
||||
@ -477,41 +455,56 @@ public class ValUtils
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the longest common name between two domain names.
|
||||
*
|
||||
* @param domain1
|
||||
* @param domain2
|
||||
* @return
|
||||
*/
|
||||
public static Name longestCommonName(Name domain1, Name domain2) {
|
||||
if (domain1 == null || domain2 == null) return null;
|
||||
// for now, do this in a a fairly brute force way
|
||||
// FIXME: convert this to direct operations on the byte[]
|
||||
|
||||
int this_labels = domain1.labels();
|
||||
int name_labels = domain2.labels();
|
||||
int d1_labels = domain1.labels();
|
||||
int d2_labels = domain2.labels();
|
||||
|
||||
int l = (this_labels < name_labels) ? this_labels : name_labels;
|
||||
for (int i = l; i > 0; i--)
|
||||
{
|
||||
Name n = new Name(domain2, name_labels - i);
|
||||
if (n.equals(name, offset(this_labels - i)))
|
||||
{
|
||||
return n;
|
||||
int l = (d1_labels < d2_labels) ? d1_labels : d2_labels;
|
||||
for (int i = l; i > 0; i--) {
|
||||
Name n1 = new Name(domain1, d1_labels - i);
|
||||
Name n2 = new Name(domain2, d2_labels - i);
|
||||
if (n1.equals(n2)) {
|
||||
return n1;
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
return Name.root;
|
||||
}
|
||||
|
||||
public static boolean strictSubdomain(Name child, Name parent) {
|
||||
int clabels = child.labels();
|
||||
int plabels = parent.labels();
|
||||
if (plabels >= clabels) return false;
|
||||
|
||||
Name n = new Name(child, clabels - plabels);
|
||||
return parent.equals(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine by looking at a signed RRset whether or not the rrset name was
|
||||
* the result of a wildcard expansion.
|
||||
*
|
||||
* @param rrset The rrset to examine.
|
||||
* @param rrset
|
||||
* The rrset to examine.
|
||||
* @return true if the rrset is a wildcard expansion. This will return false
|
||||
* for all unsigned rrsets.
|
||||
*/
|
||||
public static boolean rrsetIsWildcardExpansion(RRset rrset)
|
||||
{
|
||||
public static boolean rrsetIsWildcardExpansion(RRset rrset) {
|
||||
if (rrset == null) return false;
|
||||
RRSIGRecord rrsig = rrsetFirstSig(rrset);
|
||||
|
||||
if (rrset.getName().labels() - 1 > rrsig.getLabels())
|
||||
{
|
||||
if (rrset.getName().labels() - 1 > rrsig.getLabels()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -523,12 +516,12 @@ public class ValUtils
|
||||
* the result of a wildcard expansion. If so, return the name of the
|
||||
* generating wildcard.
|
||||
*
|
||||
* @param rrset The rrset to chedck.
|
||||
* @param rrset
|
||||
* The rrset to chedck.
|
||||
* @return the wildcard name, if the rrset was synthesized from a wildcard.
|
||||
* null if not.
|
||||
*/
|
||||
public static Name rrsetWildcard(RRset rrset)
|
||||
{
|
||||
public static Name rrsetWildcard(RRset rrset) {
|
||||
if (rrset == null) return null;
|
||||
RRSIGRecord rrsig = rrsetFirstSig(rrset);
|
||||
|
||||
@ -536,29 +529,23 @@ public class ValUtils
|
||||
// then this rrset was synthesized from a wildcard.
|
||||
// Note that the RRSIG label count doesn't count the root label.
|
||||
int label_diff = (rrset.getName().labels() - 1) - rrsig.getLabels();
|
||||
if (label_diff > 0)
|
||||
{
|
||||
if (label_diff > 0) {
|
||||
return rrset.getName().wild(label_diff);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Name closestEncloser(Name domain, NSECRecord nsec)
|
||||
{
|
||||
Name n1 = domain.longestCommonName(nsec.getName());
|
||||
Name n2 = domain.longestCommonName(nsec.getNext());
|
||||
public static Name closestEncloser(Name domain, NSECRecord nsec) {
|
||||
Name n1 = longestCommonName(domain, nsec.getName());
|
||||
Name n2 = longestCommonName(domain, nsec.getNext());
|
||||
|
||||
return (n1.labels() > n2.labels()) ? n1 : n2;
|
||||
}
|
||||
|
||||
public static Name nsecWildcard(Name domain, NSECRecord nsec)
|
||||
{
|
||||
try
|
||||
{
|
||||
public static Name nsecWildcard(Name domain, NSECRecord nsec) {
|
||||
try {
|
||||
return new Name("*", closestEncloser(domain, nsec));
|
||||
}
|
||||
catch (TextParseException e)
|
||||
{
|
||||
} catch (TextParseException e) {
|
||||
// this should never happen.
|
||||
return null;
|
||||
}
|
||||
@ -568,39 +555,41 @@ public class ValUtils
|
||||
* Determine if the given NSEC proves a NameError (NXDOMAIN) for a given
|
||||
* qname.
|
||||
*
|
||||
* @param nsec The NSEC to check.
|
||||
* @param qname The qname to check against.
|
||||
* @param signerName The signer name of the NSEC record, which is used as
|
||||
* the zone name, for a more precise (but perhaps more brittle)
|
||||
* check for the last NSEC in a zone.
|
||||
* @param nsec
|
||||
* The NSEC to check.
|
||||
* @param qname
|
||||
* The qname to check against.
|
||||
* @param signerName
|
||||
* The signer name of the NSEC record, which is used as the zone
|
||||
* name, for a more precise (but perhaps more brittle) check for
|
||||
* the last NSEC in a zone.
|
||||
* @return true if the NSEC proves the condition.
|
||||
*/
|
||||
public static boolean nsecProvesNameError(NSECRecord nsec, Name qname,
|
||||
Name signerName)
|
||||
{
|
||||
Name signerName) {
|
||||
Name owner = nsec.getName();
|
||||
Name next = nsec.getNext();
|
||||
|
||||
// If NSEC owner == qname, then this NSEC proves that qname exists.
|
||||
if (qname.equals(owner))
|
||||
{
|
||||
if (qname.equals(owner)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If NSEC is a parent of qname, we need to check the type map
|
||||
// If the parent name has a DNAME or is a delegation point, then this NSEC
|
||||
// If the parent name has a DNAME or is a delegation point, then this
|
||||
// NSEC
|
||||
// is being misused.
|
||||
if (qname.subdomain(owner)
|
||||
&& (typeMapHasType(nsec.getTypes(), Type.DNAME) || (typeMapHasType(nsec
|
||||
.getTypes(),
|
||||
Type.NS) && !typeMapHasType(nsec.getTypes(), Type.SOA))))
|
||||
{
|
||||
&& (typeMapHasType(nsec.getTypes(), Type.DNAME) || (typeMapHasType(
|
||||
nsec.getTypes(),
|
||||
Type.NS) && !typeMapHasType(
|
||||
nsec.getTypes(),
|
||||
Type.SOA)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (qname.compareTo(owner) > 0 && (qname.compareTo(next) < 0)
|
||||
|| signerName.equals(next))
|
||||
{
|
||||
|| signerName.equals(next)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -610,27 +599,26 @@ public class ValUtils
|
||||
* Determine if a NSEC record proves the non-existence of a wildcard that
|
||||
* could have produced qname.
|
||||
*
|
||||
* @param nsec The nsec to check.
|
||||
* @param qname The qname to check against.
|
||||
* @param signerName The signer name for the NSEC rrset, used as the zone
|
||||
* name.
|
||||
* @param nsec
|
||||
* The nsec to check.
|
||||
* @param qname
|
||||
* The qname to check against.
|
||||
* @param signerName
|
||||
* The signer name for the NSEC rrset, used as the zone name.
|
||||
* @return true if the NSEC proves the condition.
|
||||
*/
|
||||
public static boolean nsecProvesNoWC(NSECRecord nsec, Name qname,
|
||||
Name signerName)
|
||||
{
|
||||
Name signerName) {
|
||||
Name owner = nsec.getName();
|
||||
Name next = nsec.getNext();
|
||||
|
||||
int qname_labels = qname.labels();
|
||||
int signer_labels = signerName.labels();
|
||||
|
||||
for (int i = qname_labels - signer_labels; i > 0; i--)
|
||||
{
|
||||
for (int i = qname_labels - signer_labels; i > 0; i--) {
|
||||
Name wc_name = qname.wild(i);
|
||||
if (wc_name.compareTo(owner) > 0
|
||||
&& (wc_name.compareTo(next) < 0 || signerName.equals(next)))
|
||||
{
|
||||
&& (wc_name.compareTo(next) < 0 || signerName.equals(next))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -645,31 +633,34 @@ public class ValUtils
|
||||
* must still be provided proof that qname did not directly exist and that
|
||||
* the wildcard is, in fact, *.closest_encloser.
|
||||
*
|
||||
* @param nsec The NSEC to check
|
||||
* @param qname The query name to check against.
|
||||
* @param qtype The query type to check against.
|
||||
* @param nsec
|
||||
* The NSEC to check
|
||||
* @param qname
|
||||
* The query name to check against.
|
||||
* @param qtype
|
||||
* The query type to check against.
|
||||
* @return true if the NSEC proves the condition.
|
||||
*/
|
||||
public static boolean nsecProvesNodata(NSECRecord nsec, Name qname,
|
||||
int qtype)
|
||||
{
|
||||
if (!nsec.getName().equals(qname))
|
||||
{
|
||||
int qtype) {
|
||||
if (!nsec.getName().equals(qname)) {
|
||||
// wildcard checking.
|
||||
|
||||
// If this is a wildcard NSEC, make sure that a) it was possible to have
|
||||
// If this is a wildcard NSEC, make sure that a) it was possible to
|
||||
// have
|
||||
// generated qname from the wildcard and b) the type map does not
|
||||
// contain qtype. Note that this does NOT prove that this wildcard was
|
||||
// contain qtype. Note that this does NOT prove that this wildcard
|
||||
// was
|
||||
// the applicable wildcard.
|
||||
if (nsec.getName().isWild())
|
||||
{
|
||||
if (nsec.getName().isWild()) {
|
||||
// the is the purported closest encloser.
|
||||
Name ce = new Name(nsec.getName(), 1);
|
||||
|
||||
// The qname must be a strict subdomain of the closest encloser, and
|
||||
// The qname must be a strict subdomain of the closest encloser,
|
||||
// and
|
||||
// the qtype must be absent from the type map.
|
||||
if (!qname.strictSubdomain(ce) || typeMapHasType(nsec.getTypes(), qtype))
|
||||
{
|
||||
if (!strictSubdomain(qname, ce)
|
||||
|| typeMapHasType(nsec.getTypes(), qtype)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -677,57 +668,55 @@ public class ValUtils
|
||||
|
||||
// empty-non-terminal checking.
|
||||
|
||||
// If the nsec is proving that qname is an ENT, the nsec owner will be
|
||||
// If the nsec is proving that qname is an ENT, the nsec owner will
|
||||
// be
|
||||
// less than qname, and the next name will be a child domain of the
|
||||
// qname.
|
||||
if (nsec.getNext().strictSubdomain(qname)
|
||||
&& qname.compareTo(nsec.getName()) > 0)
|
||||
{
|
||||
if (strictSubdomain(nsec.getNext(), qname)
|
||||
&& qname.compareTo(nsec.getName()) > 0) {
|
||||
return true;
|
||||
}
|
||||
// Otherwise, this NSEC does not prove ENT, so it does not prove NODATA.
|
||||
// Otherwise, this NSEC does not prove ENT, so it does not prove
|
||||
// NODATA.
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the qtype exists, then we should have gotten it.
|
||||
if (typeMapHasType(nsec.getTypes(), qtype))
|
||||
{
|
||||
if (typeMapHasType(nsec.getTypes(), qtype)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the name is a CNAME node, then we should have gotten the CNAME
|
||||
if (typeMapHasType(nsec.getTypes(), Type.CNAME))
|
||||
{
|
||||
if (typeMapHasType(nsec.getTypes(), Type.CNAME)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If an NS set exists at this name, and NOT a SOA (so this is a zone cut,
|
||||
// not a zone apex), then we should have gotten a referral (or we just got
|
||||
// If an NS set exists at this name, and NOT a SOA (so this is a zone
|
||||
// cut,
|
||||
// not a zone apex), then we should have gotten a referral (or we just
|
||||
// got
|
||||
// the wrong NSEC).
|
||||
if (typeMapHasType(nsec.getTypes(), Type.NS)
|
||||
&& !typeMapHasType(nsec.getTypes(), Type.SOA))
|
||||
{
|
||||
&& !typeMapHasType(nsec.getTypes(), Type.SOA)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int nsecProvesNoDS(NSECRecord nsec, Name qname)
|
||||
{
|
||||
public static int nsecProvesNoDS(NSECRecord nsec, Name qname) {
|
||||
// Could check to make sure the qname is a subdomain of nsec
|
||||
int[] types = nsec.getTypes();
|
||||
if (typeMapHasType(types, Type.SOA) || typeMapHasType(types, Type.DS))
|
||||
{
|
||||
if (typeMapHasType(types, Type.SOA) || typeMapHasType(types, Type.DS)) {
|
||||
// SOA present means that this is the NSEC from the child, not the
|
||||
// parent (so it is the wrong one)
|
||||
// DS present means that there should have been a positive response to
|
||||
// DS present means that there should have been a positive response
|
||||
// to
|
||||
// the DS query, so there is something wrong.
|
||||
return SecurityStatus.BOGUS;
|
||||
}
|
||||
|
||||
if (!typeMapHasType(types, Type.NS))
|
||||
{
|
||||
if (!typeMapHasType(types, Type.NS)) {
|
||||
// If there is no NS at this point at all, then this doesn't prove
|
||||
// anything one way or the other.
|
||||
return SecurityStatus.INSECURE;
|
||||
|
Loading…
Reference in New Issue
Block a user