remove some warnings by using java 5 features
[captive-validator.git] / src / com / versign / tat / dnssec / NSEC3ValUtils.java
index 72674d5..8e77136 100644 (file)
@@ -37,829 +37,720 @@ import org.xbill.DNS.utils.base32;
 
 import com.versign.tat.dnssec.SignUtils.ByteArrayComparator;
 
-
-
-public class NSEC3ValUtils
-{
-
-  // FIXME: should probably refactor to handle different NSEC3 parameters more
-  // efficiently.
-  // Given a list of NSEC3 RRs, they should be grouped according to
-  // parameters. The idea is to hash and compare for each group independently,
-  // instead of having to skip NSEC3 RRs with the wrong parameters.
-
-
-  private static Name   asterisk_label = Name.fromConstantString("*");
-
-  /**
-   * This is a class to encapsulate a unique set of NSEC3 parameters:
-   * algorithm, iterations, and salt.
-   */
-  private static class NSEC3Parameters
-  {
-    public byte   alg;
-    public byte[] salt;
-    public int    iterations;
-
-    public NSEC3Parameters(NSEC3Record r)
-    {
-      alg = r.getHashAlgorithm();
-      salt = r.getSalt();
-      iterations = r.getIterations();
-    }
-
-    public boolean match(NSEC3Record r, ByteArrayComparator bac)
-    {
-      if (r.getHashAlgorithm() != alg) return false;
-      if (r.getIterations() != iterations) return false;
-
-      if (salt == null && r.getSalt() != null) return false;
-
-      if (bac == null) bac = new ByteArrayComparator();
-      return bac.compare(r.getSalt(), salt) == 0;
-    }
-  }
-
-  /**
-   * This is just a simple class to enapsulate the response to a closest
-   * encloser proof.
-   */
-  private static class CEResponse
-  {
-    public Name        closestEncloser;
-    public NSEC3Record ce_nsec3;
-    public NSEC3Record nc_nsec3;
-
-    public CEResponse(Name ce, NSEC3Record nsec3)
-    {
-      this.closestEncloser = ce;
-      this.ce_nsec3 = nsec3;
-    }
-  }
-
-  public static boolean supportsHashAlgorithm(int alg)
-  {
-    if (alg == NSEC3Record.SHA1_DIGEST_ID) return true;
-    return false;
-  }
-  
-  public static void stripUnknownAlgNSEC3s(List nsec3s)
-  {
-    if (nsec3s == null) return;
-    for (ListIterator i = nsec3s.listIterator(); i.hasNext(); )
-    {
-      NSEC3Record nsec3 = (NSEC3Record) i.next();
-      if (!supportsHashAlgorithm(nsec3.getHashAlgorithm()))
-      {
-        i.remove();
-      }
-    }
-  }
-  
-  /**
-   * Given a list of NSEC3Records that are part of a message, determine the
-   * NSEC3 parameters (hash algorithm, iterations, and salt) present. If there
-   * is more than one distinct grouping, return null;
-   * 
-   * @param nsec3s A list of NSEC3Record object.
-   * @return A set containing a number of objects (NSEC3Parameter objects)
-   *         that correspond to each distinct set of parameters, or null if
-   *         the nsec3s list was empty.
-   */
-  public static NSEC3Parameters nsec3Parameters(List nsec3s)
-  {
-    if (nsec3s == null || nsec3s.size() == 0) return null;
-
-    NSEC3Parameters params = new NSEC3Parameters((NSEC3Record) nsec3s.get(0));
-    ByteArrayComparator bac = new ByteArrayComparator();
-    
-    for (Iterator i = nsec3s.iterator(); i.hasNext();)
-    {
-      if (! params.match((NSEC3Record) i.next(), bac))
-      {
-        return null;
-      }
-    }  
-    return params;
-  }
-
-  /**
-   * In a list of NSEC3Record object pulled from a given message, find the
-   * NSEC3 that directly matches a given name, without hashing.
-   * 
-   * @param n The name in question.
-   * @param nsec3s A list of NSEC3Records from a given message.
-   * @return The matching NSEC3Record, or null if there wasn't one.
-   */
-  // private static NSEC3Record findDirectMatchingNSEC3(Name n, List nsec3s)
-  // {
-  // if (n == null || nsec3s == null) return null;
-  //
-  // for (Iterator i = nsec3s.iterator(); i.hasNext();)
-  // {
-  // NSEC3Record nsec3 = (NSEC3Record) i.next();
-  // if (n.equals(nsec3.getName())) return nsec3;
-  // }
-  //
-  // return null;
-  // }
-  /**
-   * Given a hash and an a zone name, construct an NSEC3 ownername.
-   * 
-   * @param hash The hash of an original name.
-   * @param zonename The zone to use in constructing the NSEC3 name.
-   * @return The NSEC3 name.
-   */
-  private static Name hashName(byte[] hash, Name zonename)
-  {
-    try
-    {
-      return new Name(base32.toString(hash).toLowerCase(), zonename);
-    }
-    catch (TextParseException e)
-    {
-      // Note, this should never happen.
-      return null;
-    }
-  }
-
-  /**
-   * Given a set of NSEC3 parameters, hash a name.
-   * 
-   * @param name The name to hash.
-   * @param params The parameters to hash with.
-   * @return The hash.
-   */
-  private static byte[] hash(Name name, NSEC3Parameters params)
-  {
-    try
-    {
-      return NSEC3Record.hash(name,
-          params.alg,
-          params.iterations,
-          params.salt);
-    }
-    catch (NoSuchAlgorithmException e)
-    {
-//      st_log.debug("Did not recognize hash algorithm: " + params.alg);
-      return null;
-    }
-  }
-
-  /**
-   * Given the name of a closest encloser, return the name *.closest_encloser.
-   * 
-   * @param closestEncloser The name to start with.
-   * @return The wildcard name.
-   */
-  private static Name ceWildcard(Name closestEncloser)
-  {
-    try
-    {
-      Name wc = Name.concatenate(asterisk_label, closestEncloser);
-      return wc;
-    }
-    catch (NameTooLongException e)
-    {
-      return null;
-    }
-  }
-
-  /**
-   * Given a qname and its proven closest encloser, calculate the "next
-   * closest" name. Basically, this is the name that is one label longer than
-   * the closest encloser that is still a subdomain of qname.
-   * 
-   * @param qname The qname.
-   * @param closestEncloser The closest encloser name.
-   * @return The next closer name.
-   */
-  private static Name nextClosest(Name qname, Name closestEncloser)
-  {
-    int strip = qname.labels() - closestEncloser.labels() - 1;
-    return (strip > 0) ? new Name(qname, strip) : qname;
-  }
-
-  /**
-   * Find the NSEC3Record that matches a hash of a name.
-   * 
-   * @param hash The pre-calculated hash of a name.
-   * @param zonename The name of the zone that the NSEC3s are from.
-   * @param nsec3s A list of NSEC3Records from a given message.
-   * @param params The parameters used for calculating the hash.
-   * @param bac An already allocated ByteArrayComparator, for reuse. This may
-   *          be null.
-   * 
-   * @return The matching NSEC3Record, if one is present.
-   */
-  private static NSEC3Record findMatchingNSEC3(byte[] hash, Name zonename,
-      List nsec3s, NSEC3Parameters params, ByteArrayComparator bac)
-  {
-    Name n = hashName(hash, zonename);
-
-    for (Iterator i = nsec3s.iterator(); i.hasNext();)
-    {
-      NSEC3Record nsec3 = (NSEC3Record) i.next();
-      // Skip nsec3 records that are using different parameters.
-      if (!params.match(nsec3, bac)) continue;
-      if (n.equals(nsec3.getName())) return nsec3;
-    }
-    return null;
-  }
-
-  /**
-   * Given a hash and a candidate NSEC3Record, determine if that NSEC3Record
-   * covers the hash. Covers specifically means that the hash is in between
-   * the owner and next hashes and does not equal either.
-   * 
-   * @param nsec3 The candidate NSEC3Record.
-   * @param hash The precalculated hash.
-   * @param bac An already allocated comparator. This may be null.
-   * @return True if the NSEC3Record covers the hash.
-   */
-  private static boolean nsec3Covers(NSEC3Record nsec3, byte[] hash,
-      ByteArrayComparator bac)
-  {
-    byte[] owner = nsec3.getOwner();
-    byte[] next = nsec3.getNext();
-
-    // This is the "normal case: owner < next and owner < hash < next
-    if (bac.compare(owner, hash) < 0 && bac.compare(hash, next) < 0)
-      return true;
-
-    // this is the end of zone case: next < owner && hash > owner || hash <
-    // next
-    if (bac.compare(next, owner) <= 0
-        && (bac.compare(hash, next) < 0 || bac.compare(owner, hash) < 0))
-      return true;
-     
-    // Otherwise, the NSEC3 does not cover the hash.
-    return false;
-  }
-
-  /**
-   * Given a pre-hashed name, find a covering NSEC3 from among a list of
-   * NSEC3s.
-   * 
-   * @param hash The hash to consider.
-   * @param zonename The name of the zone.
-   * @param nsec3s The list of NSEC3s present in a message.
-   * @param params The NSEC3 parameters used to generate the hash -- NSEC3s
-   *          that do not use those parameters will be skipped.
-   * 
-   * @return A covering NSEC3 if one is present, null otherwise.
-   */
-  private static NSEC3Record findCoveringNSEC3(byte[] hash, Name zonename,
-      List nsec3s, NSEC3Parameters params, ByteArrayComparator bac)
-  {
-    ByteArrayComparator comparator = new ByteArrayComparator();
-
-    for (Iterator i = nsec3s.iterator(); i.hasNext();)
-    {
-      NSEC3Record nsec3 = (NSEC3Record) i.next();
-      if (!params.match(nsec3, bac)) continue;
-
-      if (nsec3Covers(nsec3, hash, comparator)) return nsec3;
-    }
-
-    return null;
-  }
-
-
-  /**
-   * Given a name and a list of NSEC3s, find the candidate closest encloser.
-   * This will be the first ancestor of 'name' (including itself) to have a
-   * matching NSEC3 RR.
-   * 
-   * @param name The name the start with.
-   * @param zonename The name of the zone that the NSEC3s came from.
-   * @param nsec3s The list of NSEC3s.
-   * @param nsec3params The NSEC3 parameters.
-   * @param bac A pre-allocated comparator. May be null.
-   * 
-   * @return A CEResponse containing the closest encloser name and the NSEC3
-   *         RR that matched it, or null if there wasn't one.
-   */
-  private static CEResponse findClosestEncloser(Name name, Name zonename,
-      List nsec3s, NSEC3Parameters params, ByteArrayComparator bac)
-  {
-    Name n = name;
-
-    NSEC3Record nsec3;
-
-    // This scans from longest name to shortest, so the first match we find is
-    // the only viable candidate.
-    // FIXME: modify so that the NSEC3 matching the zone apex need not be
-    // present.
-    while (n.labels() >= zonename.labels())
-    {
-      nsec3 = findMatchingNSEC3(hash(n, params), zonename, nsec3s, params, bac);
-      if (nsec3 != null) return new CEResponse(n, nsec3);
-      n = new Name(n, 1);
-    }
-
-    return null;
-  }
-
-  /**
-   * Given a List of nsec3 RRs, find and prove the closest encloser to qname.
-   * 
-   * @param qname The qname in question.
-   * @param zonename The name of the zone that the NSEC3 RRs come from.
-   * @param nsec3s The list of NSEC3s found the this response (already
-   *          verified).
-   * @param params The NSEC3 parameters found in the response.
-   * @param bac A pre-allocated comparator. May be null.
-   * @param proveDoesNotExist If true, then if the closest encloser turns out
-   *          to be qname, then null is returned.
-   * @return null if the proof isn't completed. Otherwise, return a CEResponse
-   *         object which contains the closest encloser name and the NSEC3
-   *         that matches it.
-   */
-  private static CEResponse proveClosestEncloser(Name qname, Name zonename,
-      List nsec3s, NSEC3Parameters params, ByteArrayComparator bac,
-      boolean proveDoesNotExist)
-  {
-    CEResponse candidate = findClosestEncloser(qname,
-        zonename,
-        nsec3s,
-        params,
-        bac);
-
-    if (candidate == null)
-    {
-//      st_log.debug("proveClosestEncloser: could not find a "
-//          + "candidate for the closest encloser.");
-      return null;
+public class NSEC3ValUtils {
+
+    // FIXME: should probably refactor to handle different NSEC3 parameters more
+    // efficiently.
+    // Given a list of NSEC3 RRs, they should be grouped according to
+    // parameters. The idea is to hash and compare for each group independently,
+    // instead of having to skip NSEC3 RRs with the wrong parameters.
+
+    private static Name asterisk_label = Name.fromConstantString("*");
+
+    /**
+     * This is a class to encapsulate a unique set of NSEC3 parameters:
+     * algorithm, iterations, and salt.
+     */
+    private static class NSEC3Parameters {
+        public byte   alg;
+        public byte[] salt;
+        public int    iterations;
+
+        public NSEC3Parameters(NSEC3Record r) {
+            alg = r.getHashAlgorithm();
+            salt = r.getSalt();
+            iterations = r.getIterations();
+        }
+
+        public boolean match(NSEC3Record r, ByteArrayComparator bac) {
+            if (r.getHashAlgorithm() != alg) return false;
+            if (r.getIterations() != iterations) return false;
+
+            if (salt == null && r.getSalt() != null) return false;
+
+            if (bac == null) bac = new ByteArrayComparator();
+            return bac.compare(r.getSalt(), salt) == 0;
+        }
+    }
+
+    /**
+     * This is just a simple class to encapsulate the response to a closest
+     * encloser proof.
+     */
+    private static class CEResponse {
+        public Name        closestEncloser;
+        public NSEC3Record ce_nsec3;
+        public NSEC3Record nc_nsec3;
+
+        public CEResponse(Name ce, NSEC3Record nsec3) {
+            this.closestEncloser = ce;
+            this.ce_nsec3 = nsec3;
+        }
+    }
+
+    public static boolean supportsHashAlgorithm(int alg) {
+        if (alg == NSEC3Record.SHA1_DIGEST_ID) return true;
+        return false;
     }
 
-    if (candidate.closestEncloser.equals(qname))
-    {
-      if (proveDoesNotExist)
-      {
-//        st_log.debug("proveClosestEncloser: proved that qname existed!");
+    public static void stripUnknownAlgNSEC3s(List<NSEC3Record> nsec3s) {
+        if (nsec3s == null) return;
+        for (ListIterator<NSEC3Record> i = nsec3s.listIterator(); i.hasNext();) {
+            NSEC3Record nsec3 = i.next();
+            if (!supportsHashAlgorithm(nsec3.getHashAlgorithm())) {
+                i.remove();
+            }
+        }
+    }
+
+    /**
+     * Given a list of NSEC3Records that are part of a message, determine the
+     * NSEC3 parameters (hash algorithm, iterations, and salt) present. If there
+     * is more than one distinct grouping, return null;
+     * 
+     * @param nsec3s
+     *            A list of NSEC3Record object.
+     * @return A set containing a number of objects (NSEC3Parameter objects)
+     *         that correspond to each distinct set of parameters, or null if
+     *         the nsec3s list was empty.
+     */
+    public static NSEC3Parameters nsec3Parameters(List<NSEC3Record> nsec3s) {
+        if (nsec3s == null || nsec3s.size() == 0) return null;
+
+        NSEC3Parameters params = new NSEC3Parameters(
+                (NSEC3Record) nsec3s.get(0));
+        ByteArrayComparator bac = new ByteArrayComparator();
+
+        for (NSEC3Record nsec3 : nsec3s) {
+            if (!params.match(nsec3, bac)) return null;
+        }
+
+        return params;
+    }
+
+
+    /**
+     * Given a hash and an a zone name, construct an NSEC3 ownername.
+     * 
+     * @param hash
+     *            The hash of an original name.
+     * @param zonename
+     *            The zone to use in constructing the NSEC3 name.
+     * @return The NSEC3 name.
+     */
+    private static Name hashName(byte[] hash, Name zonename) {
+        try {
+            return new Name(base32.toString(hash).toLowerCase(), zonename);
+        } catch (TextParseException e) {
+            // Note, this should never happen.
+            return null;
+        }
+    }
+
+    /**
+     * Given a set of NSEC3 parameters, hash a name.
+     * 
+     * @param name
+     *            The name to hash.
+     * @param params
+     *            The parameters to hash with.
+     * @return The hash.
+     */
+    private static byte[] hash(Name name, NSEC3Parameters params) {
+        try {
+            return NSEC3Record.hash(name, params.alg, params.iterations,
+                                    params.salt);
+        } catch (NoSuchAlgorithmException e) {
+            // st_log.debug("Did not recognize hash algorithm: " + params.alg);
+            return null;
+        }
+    }
+
+    /**
+     * Given the name of a closest encloser, return the name *.closest_encloser.
+     * 
+     * @param closestEncloser
+     *            The name to start with.
+     * @return The wildcard name.
+     */
+    private static Name ceWildcard(Name closestEncloser) {
+        try {
+            Name wc = Name.concatenate(asterisk_label, closestEncloser);
+            return wc;
+        } catch (NameTooLongException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Given a qname and its proven closest encloser, calculate the "next
+     * closest" name. Basically, this is the name that is one label longer than
+     * the closest encloser that is still a subdomain of qname.
+     * 
+     * @param qname
+     *            The qname.
+     * @param closestEncloser
+     *            The closest encloser name.
+     * @return The next closer name.
+     */
+    private static Name nextClosest(Name qname, Name closestEncloser) {
+        int strip = qname.labels() - closestEncloser.labels() - 1;
+        return (strip > 0) ? new Name(qname, strip) : qname;
+    }
+
+    /**
+     * Find the NSEC3Record that matches a hash of a name.
+     * 
+     * @param hash
+     *            The pre-calculated hash of a name.
+     * @param zonename
+     *            The name of the zone that the NSEC3s are from.
+     * @param nsec3s
+     *            A list of NSEC3Records from a given message.
+     * @param params
+     *            The parameters used for calculating the hash.
+     * @param bac
+     *            An already allocated ByteArrayComparator, for reuse. This may
+     *            be null.
+     * 
+     * @return The matching NSEC3Record, if one is present.
+     */
+    private static NSEC3Record findMatchingNSEC3(byte[] hash, Name zonename,
+                                                 List<NSEC3Record> nsec3s,
+                                                 NSEC3Parameters params,
+                                                 ByteArrayComparator bac) {
+        Name n = hashName(hash, zonename);
+
+        for (NSEC3Record nsec3 : nsec3s) {
+            // Skip nsec3 records that are using different parameters.
+            if (!params.match(nsec3, bac)) continue;
+            if (n.equals(nsec3.getName())) return nsec3;
+        }
         return null;
-      }
-      // otherwise, we need to nothing else to prove that qname is its own
-      // closest encloser.
-      return candidate;
     }
 
-    // If the closest encloser is actually a delegation, then the response
-    // should have been a referral. If it is a DNAME, then it should have been
-    // a DNAME response.
-    if (candidate.ce_nsec3.hasType(Type.NS)
-        && !candidate.ce_nsec3.hasType(Type.SOA))
-    {
-//      st_log.debug("proveClosestEncloser: closest encloser "
-//          + "was a delegation!");
-      return null;
-    }
-    if (candidate.ce_nsec3.hasType(Type.DNAME))
-    {
-//      st_log.debug("proveClosestEncloser: closest encloser was a DNAME!");
-      return null;
-    }
-
-    // Otherwise, we need to show that the next closer name is covered.
-    Name nextClosest = nextClosest(qname, candidate.closestEncloser);
-    
-    byte[] nc_hash = hash(nextClosest, params);
-    candidate.nc_nsec3 = findCoveringNSEC3(nc_hash,
-        zonename,
-        nsec3s,
-        params,
-        bac);
-    if (candidate.nc_nsec3 == null)
-    {
-//      st_log.debug("Could not find proof that the "
-//          + "closest encloser was the closest encloser");
-      return null;
-    }
-
-    return candidate;
-  }
-
-  private static int maxIterations(int baseAlg, int keysize)
-  {
-    switch (baseAlg)
-    {
-      case DnsSecVerifier.RSA:
-        if (keysize == 0) return 2500; // the max at 4096
-        if (keysize > 2048) return 2500;
-        if (keysize > 1024) return 500;
-        if (keysize > 0) return 150;
-        break;
-      case DnsSecVerifier.DSA:
-        if (keysize == 0) return 5000; // the max at 2048;
-        if (keysize > 1024) return 5000;
-        if (keysize > 0) return 1500;
-        break;
-    }
-    return -1;
-  }
-  
-  private static boolean validIterations(NSEC3Parameters nsec3params, 
-      RRset dnskey_rrset, DnsSecVerifier verifier)
-  {
-    // for now, we return the maximum iterations based simply on the key
-    // algorithms that may have been used to sign the NSEC3 RRsets.
-    
-    int max_iterations = 0;
-    for (Iterator i = dnskey_rrset.rrs(); i.hasNext();)
-    {
-      DNSKEYRecord dnskey = (DNSKEYRecord) i.next();
-      int baseAlg = verifier.baseAlgorithm(dnskey.getAlgorithm());
-      int iters = maxIterations(baseAlg, 0);
-      max_iterations = max_iterations < iters ? iters : max_iterations;
-    }
-    
-    if (nsec3params.iterations > max_iterations) return false;
-    
-   return true; 
-  }
-  
-  /**
-   * Determine if all of the NSEC3s in a response are legally ignoreable
-   * (i.e., their presence should lead to an INSECURE result). Currently, this
-   * is solely based on iterations.
-   * 
-   * @param nsec3s The list of NSEC3s. If there is more than one set of NSEC3
-   *          parameters present, this test will not be performed.
-   * @param dnskey_rrset The set of validating DNSKEYs.
-   * @param verifier The verifier used to verify the NSEC3 RRsets. This is
-   *          solely used to map algorithm aliases.
-   * @return true if all of the NSEC3s can be legally ignored, false if not.
-   */
-  public static boolean allNSEC3sIgnoreable(List nsec3s, RRset dnskey_rrset, DnsSecVerifier verifier)
-  {
-    NSEC3Parameters params = nsec3Parameters(nsec3s);
-    if (params == null) return false;
-    
-    return !validIterations(params, dnskey_rrset, verifier);
-  }
-  
-  /**
-   * Determine if the set of NSEC3 records provided with a response prove NAME
-   * ERROR. This means that the NSEC3s prove a) the closest encloser exists,
-   * b) the direct child of the closest encloser towards qname doesn't exist,
-   * and c) *.closest encloser does not exist.
-   * 
-   * @param nsec3s The list of NSEC3s.
-   * @param qname The query name to check against.
-   * @param zonename This is the name of the zone that the NSEC3s belong to.
-   *          This may be discovered in any number of ways. A good one is to
-   *          use the signerName from the NSEC3 record's RRSIG.
-   * @return SecurityStatus.SECURE of the Name Error is proven by the NSEC3
-   *         RRs, BOGUS if not, INSECURE if all of the NSEC3s could be validly
-   *         ignored.
-   */
-  public static boolean proveNameError(List nsec3s, Name qname, Name zonename)
-  {
-    if (nsec3s == null || nsec3s.size() == 0) return false;
-
-    NSEC3Parameters nsec3params = nsec3Parameters(nsec3s);
-    if (nsec3params == null)
-    {
-//      st_log.debug("Could not find a single set of " +
-//          "NSEC3 parameters (multiple parameters present).");
-      return false;
-    }
-    
-    ByteArrayComparator bac = new ByteArrayComparator();
-
-    // First locate and prove the closest encloser to qname. We will use the
-    // variant that fails if the closest encloser turns out to be qname.
-    CEResponse ce = proveClosestEncloser(qname,
-        zonename,
-        nsec3s,
-        nsec3params,
-        bac,
-        true);
-
-    if (ce == null)
-    {
-//      st_log.debug("proveNameError: failed to prove a closest encloser.");
-      return false;
-    }
-
-    // At this point, we know that qname does not exist. Now we need to prove
-    // that the wildcard does not exist.
-    Name wc = ceWildcard(ce.closestEncloser);
-    byte[] wc_hash = hash(wc, nsec3params);
-    NSEC3Record nsec3 = findCoveringNSEC3(wc_hash,
-        zonename,
-        nsec3s,
-        nsec3params,
-        bac);
-    if (nsec3 == null)
-    {
-//      st_log.debug("proveNameError: could not prove that the "
-//          + "applicable wildcard did not exist.");
-      return false;
-    }
-
-    return true;
-  }
-
-  /**
-   * Determine if the set of NSEC3 records provided with a response prove NAME
-   * ERROR when qtype = NSEC3. This is a special case, and (currently anyway)
-   * it suffices to simply prove that the NSEC3 RRset itself does not exist,
-   * without proving that no wildcard could have generated it, etc..
-   * 
-   * @param nsec3s The list of NSEC3s.
-   * @param qname The query name to check against.
-   * @param zonename This is the name of the zone that the NSEC3s belong to.
-   *          This may be discovered in any number of ways. A good one is to
-   *          use the signerName from the NSEC3 record's RRSIG.
-   * @return true of the Name Error is proven by the NSEC3 RRs, false if not.
-   */
-  // public static boolean proveNSEC3NameError(List nsec3s, Name qname,
-  // Name zonename)
-  // {
-  // if (nsec3s == null || nsec3s.size() == 0) return false;
-  //
-  // for (Iterator i = nsec3s.iterator(); i.hasNext(); )
-  // {
-  // NSEC3Record nsec3 = (NSEC3Record) i.next();
-  //      
-  // // Convert owner and next into Names.
-  // Name owner = nsec3.getName();
-  // Name next = null;
-  // try
-  // {
-  // next = new Name(base32.toString(nsec3.getNext()), zonename);
-  // }
-  // catch (TextParseException e)
-  // {
-  // continue;
-  // }
-  //      
-  // // Now see if qname is covered by the NSEC3.
-  //      
-  // // normal case, owner < qname < next.
-  // if (owner.compareTo(next) < 0 && owner.compareTo(qname) < 0 &&
-  // next.compareTo(qname) > 0)
-  // {
-  // st_log.debug("proveNSEC3NameError: found a covering NSEC3: " + nsec3);
-  // return true;
-  // }
-  // // end-of-zone case: next < owner and qname > owner || qname < next.
-  // if (owner.compareTo(next) > 0 && (owner.compareTo(qname) < 0 ||
-  // next.compareTo(qname) > 0))
-  // {
-  // st_log.debug("proveNSEC3NameError: found a covering NSEC3: " + nsec3);
-  // return true;
-  // }
-  // }
-  //    
-  // st_log.debug("proveNSEC3NameError: did not find a covering NSEC3");
-  // return false;
-  // }
-  /**
-   * Determine if the NSEC3s provided in a response prove the NOERROR/NODATA
-   * status. There are a number of different variants to this:
-   * 
-   * 1) Normal NODATA -- qname is matched to an NSEC3 record, type is not
-   * present.
-   * 
-   * 2) ENT NODATA -- because there must be NSEC3 record for
-   * empty-non-terminals, this is the same as #1.
-   * 
-   * 3) NSEC3 ownername NODATA -- qname matched an existing, lone NSEC3
-   * ownername, but qtype was not NSEC3. NOTE: as of nsec-05, this case no
-   * longer exists.
-   * 
-   * 4) Wildcard NODATA -- A wildcard matched the name, but not the type.
-   * 
-   * 5) Opt-In DS NODATA -- the qname is covered by an opt-in span and qtype ==
-   * DS. (or maybe some future record with the same parent-side-only property)
-   * 
-   * @param nsec3s The NSEC3Records to consider.
-   * @param qname The qname in question.
-   * @param qtype The qtype in question.
-   * @param zonename The name of the zone that the NSEC3s came from.
-   * @return true if the NSEC3s prove the proposition.
-   */
-  public static boolean proveNodata(List nsec3s, Name qname, int qtype,
-      Name zonename)
-  {
-    if (nsec3s == null || nsec3s.size() == 0) return false;
-
-    NSEC3Parameters nsec3params = nsec3Parameters(nsec3s);
-    if (nsec3params == null)
-    {
-//      st_log.debug("could not find a single set of "
-//          + "NSEC3 parameters (multiple parameters present)");
-      return false;
-    }
-    ByteArrayComparator bac = new ByteArrayComparator();
-
-    NSEC3Record nsec3 = findMatchingNSEC3(hash(qname, nsec3params),
-        zonename,
-        nsec3s,
-        nsec3params,
-        bac);
-    // Cases 1 & 2.
-    if (nsec3 != null)
-    {
-      if (nsec3.hasType(qtype))
-      {
-//        st_log.debug("proveNodata: Matching NSEC3 proved that type existed!");
-        return false;
-      }
-      if (nsec3.hasType(Type.CNAME))
-      {
-//        st_log.debug("proveNodata: Matching NSEC3 proved "
-//            + "that a CNAME existed!");
+    /**
+     * Given a hash and a candidate NSEC3Record, determine if that NSEC3Record
+     * covers the hash. Covers specifically means that the hash is in between
+     * the owner and next hashes and does not equal either.
+     * 
+     * @param nsec3
+     *            The candidate NSEC3Record.
+     * @param hash
+     *            The precalculated hash.
+     * @param bac
+     *            An already allocated comparator. This may be null.
+     * @return True if the NSEC3Record covers the hash.
+     */
+    private static boolean nsec3Covers(NSEC3Record nsec3, byte[] hash,
+                                       ByteArrayComparator bac) {
+        byte[] owner = nsec3.getOwner();
+        byte[] next = nsec3.getNext();
+
+        // This is the "normal case: owner < next and owner < hash < next
+        if (bac.compare(owner, hash) < 0 && bac.compare(hash, next) < 0)
+            return true;
+
+        // this is the end of zone case: next < owner && hash > owner || hash <
+        // next
+        if (bac.compare(next, owner) <= 0
+            && (bac.compare(hash, next) < 0 || bac.compare(owner, hash) < 0))
+            return true;
+
+        // Otherwise, the NSEC3 does not cover the hash.
         return false;
-      }
-      return true;
     }
 
-    // For cases 3 - 5, we need the proven closest encloser, and it can't
-    // match qname. Although, at this point, we know that it won't since we
-    // just checked that.
-    CEResponse ce = proveClosestEncloser(qname,
-        zonename,
-        nsec3s,
-        nsec3params,
-        bac,
-        true);
-
-    // At this point, not finding a match or a proven closest encloser is a
-    // problem.
-    if (ce == null)
-    {
-//      st_log.debug("proveNodata: did not match qname, "
-//          + "nor found a proven closest encloser.");
-      return false;
-    }
+    /**
+     * Given a pre-hashed name, find a covering NSEC3 from among a list of
+     * NSEC3s.
+     * 
+     * @param hash
+     *            The hash to consider.
+     * @param zonename
+     *            The name of the zone.
+     * @param nsec3s
+     *            The list of NSEC3s present in a message.
+     * @param params
+     *            The NSEC3 parameters used to generate the hash -- NSEC3s that
+     *            do not use those parameters will be skipped.
+     * 
+     * @return A covering NSEC3 if one is present, null otherwise.
+     */
+    private static NSEC3Record findCoveringNSEC3(byte[] hash, Name zonename,
+                                                 List<NSEC3Record> nsec3s,
+                                                 NSEC3Parameters params,
+                                                 ByteArrayComparator bac) {
+        ByteArrayComparator comparator = new ByteArrayComparator();
+
+        for (NSEC3Record nsec3 : nsec3s) {
+            if (!params.match(nsec3, bac)) continue;
+            if (nsec3Covers(nsec3, hash, comparator)) return nsec3;
+        }
 
-    // Case 3: REMOVED
-
-    // Case 4:
-    Name wc = ceWildcard(ce.closestEncloser);
-    nsec3 = findMatchingNSEC3(hash(wc, nsec3params),
-        zonename,
-        nsec3s,
-        nsec3params,
-        bac);
-
-    if (nsec3 != null)
-    {
-      if (nsec3.hasType(qtype))
-      {
-//        st_log.debug("proveNodata: matching wildcard had qtype!");
-        return false;
-      }
-      return true;
+        return null;
     }
 
-    // Case 5.
-    if (qtype != Type.DS)
-    {
-//      st_log.debug("proveNodata: could not find matching NSEC3, "
-//          + "nor matching wildcard, and qtype is not DS -- no more options.");
-      return false;
-    }
+    /**
+     * Given a name and a list of NSEC3s, find the candidate closest encloser.
+     * This will be the first ancestor of 'name' (including itself) to have a
+     * matching NSEC3 RR.
+     * 
+     * @param name
+     *            The name the start with.
+     * @param zonename
+     *            The name of the zone that the NSEC3s came from.
+     * @param nsec3s
+     *            The list of NSEC3s.
+     * @param nsec3params
+     *            The NSEC3 parameters.
+     * @param bac
+     *            A pre-allocated comparator. May be null.
+     * 
+     * @return A CEResponse containing the closest encloser name and the NSEC3
+     *         RR that matched it, or null if there wasn't one.
+     */
+    private static CEResponse findClosestEncloser(Name name, Name zonename,
+                                                  List<NSEC3Record> nsec3s,
+                                                  NSEC3Parameters params,
+                                                  ByteArrayComparator bac) {
+        Name n = name;
+
+        NSEC3Record nsec3;
+
+        // This scans from longest name to shortest, so the first match we find
+        // is
+        // the only viable candidate.
+        // FIXME: modify so that the NSEC3 matching the zone apex need not be
+        // present.
+        while (n.labels() >= zonename.labels()) {
+            nsec3 = findMatchingNSEC3(hash(n, params), zonename, nsec3s,
+                                      params, bac);
+            if (nsec3 != null) return new CEResponse(n, nsec3);
+            n = new Name(n, 1);
+        }
 
-    // We need to make sure that the covering NSEC3 is opt-in.
-    if (!ce.nc_nsec3.getOptInFlag())
-    {
-//      st_log.debug("proveNodata: covering NSEC3 was not "
-//          + "opt-in in an opt-in DS NOERROR/NODATA case.");
-      return false;
+        return null;
     }
 
-    return true;
-  }
-
-  /**
-   * Prove that a positive wildcard match was appropriate (no direct match
-   * RRset).
-   * 
-   * @param nsec3s The NSEC3 records to work with.
-   * @param qname The qname that was matched to the wildard
-   * @param zonename The name of the zone that the NSEC3s come from.
-   * @param wildcard The purported wildcard that matched.
-   * @return true if the NSEC3 records prove this case.
-   */
-  public static boolean proveWildcard(List nsec3s, Name qname, Name zonename,
-      Name wildcard)
-  {
-    if (nsec3s == null || nsec3s.size() == 0) return false;
-    if (qname == null || wildcard == null) return false;
-
-    NSEC3Parameters nsec3params = nsec3Parameters(nsec3s);
-    if (nsec3params == null) 
-    {
-//      st_log.debug("couldn't find a single set of NSEC3 parameters (multiple parameters present).");
-      return false;
-    }
-    
-    ByteArrayComparator bac = new ByteArrayComparator();
-
-    // We know what the (purported) closest encloser is by just looking at the
-    // supposed generating wildcard.
-    CEResponse candidate = new CEResponse(new Name(wildcard, 1), null);
-
-    // Now we still need to prove that the original data did not exist.
-    // Otherwise, we need to show that the next closer name is covered.
-    Name nextClosest = nextClosest(qname, candidate.closestEncloser);
-    candidate.nc_nsec3 = findCoveringNSEC3(hash(nextClosest, nsec3params),
-        zonename,
-        nsec3s,
-        nsec3params,
-        bac);
-
-    if (candidate.nc_nsec3 == null)
-    {
-//      st_log.debug("proveWildcard: did not find a covering NSEC3 "
-//          + "that covered the next closer name to " + qname + " from "
-//          + candidate.closestEncloser + " (derived from wildcard " + wildcard
-//          + ")");
-      return false;
-    }
+    /**
+     * Given a List of nsec3 RRs, find and prove the closest encloser to qname.
+     * 
+     * @param qname
+     *            The qname in question.
+     * @param zonename
+     *            The name of the zone that the NSEC3 RRs come from.
+     * @param nsec3s
+     *            The list of NSEC3s found the this response (already verified).
+     * @param params
+     *            The NSEC3 parameters found in the response.
+     * @param bac
+     *            A pre-allocated comparator. May be null.
+     * @param proveDoesNotExist
+     *            If true, then if the closest encloser turns out to be qname,
+     *            then null is returned.
+     * @return null if the proof isn't completed. Otherwise, return a CEResponse
+     *         object which contains the closest encloser name and the NSEC3
+     *         that matches it.
+     */
+    private static CEResponse proveClosestEncloser(Name qname, Name zonename,
+                                                   List<NSEC3Record> nsec3s,
+                                                   NSEC3Parameters params,
+                                                   ByteArrayComparator bac,
+                                                   boolean proveDoesNotExist) {
+        CEResponse candidate = findClosestEncloser(qname, zonename, nsec3s,
+                                                   params, bac);
+
+        if (candidate == null) {
+            // st_log.debug("proveClosestEncloser: could not find a "
+            // + "candidate for the closest encloser.");
+            return null;
+        }
+
+        if (candidate.closestEncloser.equals(qname)) {
+            if (proveDoesNotExist) {
+                // st_log.debug("proveClosestEncloser: proved that qname existed!");
+                return null;
+            }
+            // otherwise, we need to nothing else to prove that qname is its own
+            // closest encloser.
+            return candidate;
+        }
+
+        // If the closest encloser is actually a delegation, then the response
+        // should have been a referral. If it is a DNAME, then it should have
+        // been
+        // a DNAME response.
+        if (candidate.ce_nsec3.hasType(Type.NS)
+            && !candidate.ce_nsec3.hasType(Type.SOA)) {
+            // st_log.debug("proveClosestEncloser: closest encloser "
+            // + "was a delegation!");
+            return null;
+        }
+        if (candidate.ce_nsec3.hasType(Type.DNAME)) {
+            // st_log.debug("proveClosestEncloser: closest encloser was a DNAME!");
+            return null;
+        }
+
+        // Otherwise, we need to show that the next closer name is covered.
+        Name nextClosest = nextClosest(qname, candidate.closestEncloser);
+
+        byte[] nc_hash = hash(nextClosest, params);
+        candidate.nc_nsec3 = findCoveringNSEC3(nc_hash, zonename, nsec3s,
+                                               params, bac);
+        if (candidate.nc_nsec3 == null) {
+            // st_log.debug("Could not find proof that the "
+            // + "closest encloser was the closest encloser");
+            return null;
+        }
+
+        return candidate;
+    }
+
+    private static int maxIterations(int baseAlg, int keysize) {
+        switch (baseAlg) {
+        case DnsSecVerifier.RSA:
+            if (keysize == 0) return 2500; // the max at 4096
+            if (keysize > 2048) return 2500;
+            if (keysize > 1024) return 500;
+            if (keysize > 0) return 150;
+            break;
+        case DnsSecVerifier.DSA:
+            if (keysize == 0) return 5000; // the max at 2048;
+            if (keysize > 1024) return 5000;
+            if (keysize > 0) return 1500;
+            break;
+        }
+        return -1;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static boolean validIterations(NSEC3Parameters nsec3params,
+                                           RRset dnskey_rrset,
+                                           DnsSecVerifier verifier) {
+        // for now, we return the maximum iterations based simply on the key
+        // algorithms that may have been used to sign the NSEC3 RRsets.
+
+        int max_iterations = 0;
+        for (Iterator i = dnskey_rrset.rrs(); i.hasNext();) {
+            DNSKEYRecord dnskey = (DNSKEYRecord) i.next();
+            int baseAlg = verifier.baseAlgorithm(dnskey.getAlgorithm());
+            int iters = maxIterations(baseAlg, 0);
+            max_iterations = max_iterations < iters ? iters : max_iterations;
+        }
+
+        if (nsec3params.iterations > max_iterations) return false;
+
+        return true;
+    }
+
+    /**
+     * Determine if all of the NSEC3s in a response are legally ignoreable
+     * (i.e., their presence should lead to an INSECURE result). Currently, this
+     * is solely based on iterations.
+     * 
+     * @param nsec3s
+     *            The list of NSEC3s. If there is more than one set of NSEC3
+     *            parameters present, this test will not be performed.
+     * @param dnskey_rrset
+     *            The set of validating DNSKEYs.
+     * @param verifier
+     *            The verifier used to verify the NSEC3 RRsets. This is solely
+     *            used to map algorithm aliases.
+     * @return true if all of the NSEC3s can be legally ignored, false if not.
+     */
+    public static boolean allNSEC3sIgnoreable(List<NSEC3Record> nsec3s,
+                                              RRset dnskey_rrset,
+                                              DnsSecVerifier verifier) {
+        NSEC3Parameters params = nsec3Parameters(nsec3s);
+        if (params == null) return false;
+
+        return !validIterations(params, dnskey_rrset, verifier);
+    }
+
+    /**
+     * Determine if the set of NSEC3 records provided with a response prove NAME
+     * ERROR. This means that the NSEC3s prove a) the closest encloser exists,
+     * b) the direct child of the closest encloser towards qname doesn't exist,
+     * and c) *.closest encloser does not exist.
+     * 
+     * @param nsec3s
+     *            The list of NSEC3s.
+     * @param qname
+     *            The query name to check against.
+     * @param zonename
+     *            This is the name of the zone that the NSEC3s belong to. This
+     *            may be discovered in any number of ways. A good one is to use
+     *            the signerName from the NSEC3 record's RRSIG.
+     * @return SecurityStatus.SECURE of the Name Error is proven by the NSEC3
+     *         RRs, BOGUS if not, INSECURE if all of the NSEC3s could be validly
+     *         ignored.
+     */
+    public static boolean proveNameError(List<NSEC3Record> nsec3s, Name qname,
+                                         Name zonename) {
+        if (nsec3s == null || nsec3s.size() == 0) return false;
+
+        NSEC3Parameters nsec3params = nsec3Parameters(nsec3s);
+        if (nsec3params == null) {
+            // st_log.debug("Could not find a single set of " +
+            // "NSEC3 parameters (multiple parameters present).");
+            return false;
+        }
+
+        ByteArrayComparator bac = new ByteArrayComparator();
+
+        // First locate and prove the closest encloser to qname. We will use the
+        // variant that fails if the closest encloser turns out to be qname.
+        CEResponse ce = proveClosestEncloser(qname, zonename, nsec3s,
+                                             nsec3params, bac, true);
+
+        if (ce == null) {
+            // st_log.debug("proveNameError: failed to prove a closest encloser.");
+            return false;
+        }
+
+        // At this point, we know that qname does not exist. Now we need to
+        // prove
+        // that the wildcard does not exist.
+        Name wc = ceWildcard(ce.closestEncloser);
+        byte[] wc_hash = hash(wc, nsec3params);
+        NSEC3Record nsec3 = findCoveringNSEC3(wc_hash, zonename, nsec3s,
+                                              nsec3params, bac);
+        if (nsec3 == null) {
+            // st_log.debug("proveNameError: could not prove that the "
+            // + "applicable wildcard did not exist.");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Determine if the NSEC3s provided in a response prove the NOERROR/NODATA
+     * status. There are a number of different variants to this:
+     * 
+     * 1) Normal NODATA -- qname is matched to an NSEC3 record, type is not
+     * present.
+     * 
+     * 2) ENT NODATA -- because there must be NSEC3 record for
+     * empty-non-terminals, this is the same as #1.
+     * 
+     * 3) NSEC3 ownername NODATA -- qname matched an existing, lone NSEC3
+     * ownername, but qtype was not NSEC3. NOTE: as of nsec-05, this case no
+     * longer exists.
+     * 
+     * 4) Wildcard NODATA -- A wildcard matched the name, but not the type.
+     * 
+     * 5) Opt-In DS NODATA -- the qname is covered by an opt-in span and qtype
+     * == DS. (or maybe some future record with the same parent-side-only
+     * property)
+     * 
+     * @param nsec3s
+     *            The NSEC3Records to consider.
+     * @param qname
+     *            The qname in question.
+     * @param qtype
+     *            The qtype in question.
+     * @param zonename
+     *            The name of the zone that the NSEC3s came from.
+     * @return true if the NSEC3s prove the proposition.
+     */
+    public static boolean proveNodata(List<NSEC3Record> nsec3s, Name qname,
+                                      int qtype, Name zonename) {
+        if (nsec3s == null || nsec3s.size() == 0) return false;
+
+        NSEC3Parameters nsec3params = nsec3Parameters(nsec3s);
+        if (nsec3params == null) {
+            // st_log.debug("could not find a single set of "
+            // + "NSEC3 parameters (multiple parameters present)");
+            return false;
+        }
+        ByteArrayComparator bac = new ByteArrayComparator();
+
+        NSEC3Record nsec3 = findMatchingNSEC3(hash(qname, nsec3params),
+                                              zonename, nsec3s, nsec3params,
+                                              bac);
+        // Cases 1 & 2.
+        if (nsec3 != null) {
+            if (nsec3.hasType(qtype)) {
+                // st_log.debug("proveNodata: Matching NSEC3 proved that type existed!");
+                return false;
+            }
+            if (nsec3.hasType(Type.CNAME)) {
+                // st_log.debug("proveNodata: Matching NSEC3 proved "
+                // + "that a CNAME existed!");
+                return false;
+            }
+            return true;
+        }
+
+        // For cases 3 - 5, we need the proven closest encloser, and it can't
+        // match qname. Although, at this point, we know that it won't since we
+        // just checked that.
+        CEResponse ce = proveClosestEncloser(qname, zonename, nsec3s,
+                                             nsec3params, bac, true);
+
+        // At this point, not finding a match or a proven closest encloser is a
+        // problem.
+        if (ce == null) {
+            // st_log.debug("proveNodata: did not match qname, "
+            // + "nor found a proven closest encloser.");
+            return false;
+        }
+
+        // Case 3: REMOVED
+
+        // Case 4:
+        Name wc = ceWildcard(ce.closestEncloser);
+        nsec3 = findMatchingNSEC3(hash(wc, nsec3params), zonename, nsec3s,
+                                  nsec3params, bac);
+
+        if (nsec3 != null) {
+            if (nsec3.hasType(qtype)) {
+                // st_log.debug("proveNodata: matching wildcard had qtype!");
+                return false;
+            }
+            return true;
+        }
+
+        // Case 5.
+        if (qtype != Type.DS) {
+            // st_log.debug("proveNodata: could not find matching NSEC3, "
+            // +
+            // "nor matching wildcard, and qtype is not DS -- no more options.");
+            return false;
+        }
+
+        // We need to make sure that the covering NSEC3 is opt-in.
+        if (!ce.nc_nsec3.getOptInFlag()) {
+            // st_log.debug("proveNodata: covering NSEC3 was not "
+            // + "opt-in in an opt-in DS NOERROR/NODATA case.");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Prove that a positive wildcard match was appropriate (no direct match
+     * RRset).
+     * 
+     * @param nsec3s
+     *            The NSEC3 records to work with.
+     * @param qname
+     *            The qname that was matched to the wildcard
+     * @param zonename
+     *            The name of the zone that the NSEC3s come from.
+     * @param wildcard
+     *            The purported wildcard that matched.
+     * @return true if the NSEC3 records prove this case.
+     */
+    public static boolean proveWildcard(List<NSEC3Record> nsec3s, Name qname,
+                                        Name zonename, Name wildcard) {
+        if (nsec3s == null || nsec3s.size() == 0) return false;
+        if (qname == null || wildcard == null) return false;
+
+        NSEC3Parameters nsec3params = nsec3Parameters(nsec3s);
+        if (nsec3params == null) {
+            // st_log.debug("couldn't find a single set of NSEC3 parameters (multiple parameters present).");
+            return false;
+        }
+
+        ByteArrayComparator bac = new ByteArrayComparator();
+
+        // We know what the (purported) closest encloser is by just looking at
+        // the
+        // supposed generating wildcard.
+        CEResponse candidate = new CEResponse(new Name(wildcard, 1), null);
+
+        // Now we still need to prove that the original data did not exist.
+        // Otherwise, we need to show that the next closer name is covered.
+        Name nextClosest = nextClosest(qname, candidate.closestEncloser);
+        candidate.nc_nsec3 = findCoveringNSEC3(hash(nextClosest, nsec3params),
+                                               zonename, nsec3s, nsec3params,
+                                               bac);
+
+        if (candidate.nc_nsec3 == null) {
+            // st_log.debug("proveWildcard: did not find a covering NSEC3 "
+            // + "that covered the next closer name to " + qname + " from "
+            // + candidate.closestEncloser + " (derived from wildcard " +
+            // wildcard
+            // + ")");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Prove that a DS response either had no DS, or wasn't a delegation point.
+     * 
+     * Fundamentally there are two cases here: normal NODATA and Opt-In NODATA.
+     * 
+     * @param nsec3s
+     *            The NSEC3 RRs to examine.
+     * @param qname
+     *            The name of the DS in question.
+     * @param zonename
+     *            The name of the zone that the NSEC3 RRs come from.
+     * 
+     * @return SecurityStatus.SECURE if it was proven that there is no DS in a
+     *         secure (i.e., not opt-in) way, SecurityStatus.INSECURE if there
+     *         was no DS in an insecure (i.e., opt-in) way,
+     *         SecurityStatus.INDETERMINATE if it was clear that this wasn't a
+     *         delegation point, and SecurityStatus.BOGUS if the proofs don't
+     *         work out.
+     */
+    public static int proveNoDS(List<NSEC3Record> nsec3s, Name qname,
+                                Name zonename) {
+        if (nsec3s == null || nsec3s.size() == 0) return SecurityStatus.BOGUS;
+
+        NSEC3Parameters nsec3params = nsec3Parameters(nsec3s);
+        if (nsec3params == null) {
+            // st_log.debug("couldn't find a single set of " +
+            // "NSEC3 parameters (multiple parameters present).");
+            return SecurityStatus.BOGUS;
+        }
+        ByteArrayComparator bac = new ByteArrayComparator();
+
+        // Look for a matching NSEC3 to qname -- this is the normal NODATA case.
+        NSEC3Record nsec3 = findMatchingNSEC3(hash(qname, nsec3params),
+                                              zonename, nsec3s, nsec3params,
+                                              bac);
+
+        if (nsec3 != null) {
+            // If the matching NSEC3 has the SOA bit set, it is from the wrong
+            // zone
+            // (the child instead of the parent). If it has the DS bit set, then
+            // we
+            // were lied to.
+            if (nsec3.hasType(Type.SOA) || nsec3.hasType(Type.DS)) {
+                return SecurityStatus.BOGUS;
+            }
+            // If the NSEC3 RR doesn't have the NS bit set, then this wasn't a
+            // delegation point.
+            if (!nsec3.hasType(Type.NS)) return SecurityStatus.INDETERMINATE;
+
+            // Otherwise, this proves no DS.
+            return SecurityStatus.SECURE;
+        }
+
+        // Otherwise, we are probably in the opt-in case.
+        CEResponse ce = proveClosestEncloser(qname, zonename, nsec3s,
+                                             nsec3params, bac, true);
+        if (ce == null) {
+            return SecurityStatus.BOGUS;
+        }
+
+        // If we had the closest encloser proof, then we need to check that the
+        // covering NSEC3 was opt-in -- the proveClosestEncloser step already
+        // checked to see if the closest encloser was a delegation or DNAME.
+        if (ce.nc_nsec3.getOptInFlag()) {
+            return SecurityStatus.SECURE;
+        }
 
-    return true;
-  }
-
-  /**
-   * Prove that a DS response either had no DS, or wasn't a delegation point.
-   * 
-   * Fundamentally there are two cases here: normal NODATA and Opt-In NODATA.
-   * 
-   * @param nsec3s The NSEC3 RRs to examine.
-   * @param qname The name of the DS in question.
-   * @param zonename The name of the zone that the NSEC3 RRs come from.
-   * 
-   * @return SecurityStatus.SECURE if it was proven that there is no DS in a
-   *         secure (i.e., not opt-in) way, SecurityStatus.INSECURE if there
-   *         was no DS in an insecure (i.e., opt-in) way,
-   *         SecurityStatus.INDETERMINATE if it was clear that this wasn't a
-   *         delegation point, and SecurityStatus.BOGUS if the proofs don't
-   *         work out.
-   */
-  public static int proveNoDS(List nsec3s, Name qname, Name zonename)
-  {
-    if (nsec3s == null || nsec3s.size() == 0) return SecurityStatus.BOGUS;
-
-    NSEC3Parameters nsec3params = nsec3Parameters(nsec3s);
-    if (nsec3params == null)
-    {
-//      st_log.debug("couldn't find a single set of " +
-//          "NSEC3 parameters (multiple parameters present).");
-      return SecurityStatus.BOGUS;      
-    }
-    ByteArrayComparator bac = new ByteArrayComparator();
-
-    // Look for a matching NSEC3 to qname -- this is the normal NODATA case.
-    NSEC3Record nsec3 = findMatchingNSEC3(hash(qname, nsec3params),
-        zonename,
-        nsec3s,
-        nsec3params,
-        bac);
-
-    if (nsec3 != null)
-    {
-      // If the matching NSEC3 has the SOA bit set, it is from the wrong zone
-      // (the child instead of the parent). If it has the DS bit set, then we
-      // were lied to.
-      if (nsec3.hasType(Type.SOA) || nsec3.hasType(Type.DS))
-      {
         return SecurityStatus.BOGUS;
-      }
-      // If the NSEC3 RR doesn't have the NS bit set, then this wasn't a
-      // delegation point.
-      if (!nsec3.hasType(Type.NS)) return SecurityStatus.INDETERMINATE;
-
-      // Otherwise, this proves no DS.
-      return SecurityStatus.SECURE;
-    }
-
-    // Otherwise, we are probably in the opt-in case.
-    CEResponse ce = proveClosestEncloser(qname,
-        zonename,
-        nsec3s,
-        nsec3params,
-        bac,
-        true);
-    if (ce == null)
-    {
-      return SecurityStatus.BOGUS;
     }
 
-    // If we had the closest encloser proof, then we need to check that the
-    // covering NSEC3 was opt-in -- the proveClosestEncloser step already
-    // checked to see if the closest encloser was a delegation or DNAME.
-    if (ce.nc_nsec3.getOptInFlag())
-    {
-      return SecurityStatus.SECURE;
-    }
-
-    return SecurityStatus.BOGUS;
-  }
-
 }