m.setStatus(SecurityStatus.BOGUS);
}
- // FIXME: write CNAME validation code.
- private void validateCNAMEResponse(SMessage message, SRRset key_rrset) {}
+ /**
+ * Given a "CNAME" response (i.e., a response that contains at
+ * least one CNAME, and qtype != CNAME). This largely consists of
+ * validating each CNAME RRset until the CNAME chain goes "out of
+ * zone". Note that out-of-order CNAME chains will have been
+ * cleaned up via normalize(). When traversing the CNAME chain,
+ * we detect if the CNAME were generated from a wildcard, and we
+ * detect when the chain goes "out-of-zone". If the chain doesn't
+ * go out-of-zone, we then determine if the CNAME response was
+ * positive or negative (i.e., did it end with a non-CNAME
+ * RRset?). For each in-zone wildcard generated CNAME, we check
+ * for a proof that the alias (the owner of each cname) doesn't
+ * exist. If the response is negative (i.e., remains in-zone and
+ * results in no RRset, we do a NODATA or NXDOMAIN proof based on
+ * the actual RCODE.
+ *
+ * Note that once the CNAME chain goes out of zone, any further
+ * CNAMEs are not DNSSEC validated (we would need more trusted
+ * keysets for that), so this isn't useful in all cases (i.e., for
+ * testing a nameserver, like BIND, which generates CNAME chains
+ * across zones.)
+ *
+ * Note that by the time this method is called, the process of
+ * finding the trusted DNSKEY rrset that signs this reponse must
+ * already have been completed.
+ */
+ private void validateCNAMEResponse(SMessage message, SRRset key_rrset)
+ {
+ Name qname = message.getQName();
+ int qtype = message.getQType();
+
+ Name sname = qname; // this is the "current" name in the chain
+ boolean dname = false; // a flag indicating that prev iteration was a dname
+ boolean inZone = true; // a flag telling us if we ended up in zone.
+ boolean positive = false; // a flag telling us if we ended with a positive answer
+ List<Name> wildcards = new Vector<Name>();
+ Name wc = null;
+ Name zone = key_rrset.getName();
+
+ SRRset[] rrsets = message.getSectionRRsets(Section.ANSWER);
+
+ // Validate the ANSWER section RRsets.
+ for (int i = 0; i < rrsets.length; i++) {
+
+ int rtype = rrsets[i].getType();
+ Name rname = rrsets[i].getName();
+
+ // Follow the CNAME chain
+ if (rtype == Type.CNAME) {
+ // If we've gotten off track... Note: this should be
+ // impossible with normalization in effect.
+ if (!sname.equals(rname)) {
+ mErrorList.add("CNAME chain is broken: expected owner name of " +
+ sname + " got: " + rname);
+ message.setStatus(SecurityStatus.BOGUS);
+ return;
+ }
+
+ sname = ((CNAMERecord) rrsets[i].first()).getAlias();
+
+ // Check to see if the CNAME was generated by a
+ // wildcard. We store the generated name instead of
+ // the wildcard value, as we need to prove that the
+ // wildcard wasn't blocked.
+ wc = ValUtils.rrsetWildcard(rrsets[i]);
+ if (wc != null) {
+ wildcards.add(sname);
+ }
+ }
+
+ // Note when we see a DNAME.
+ if (rtype == Type.DNAME) {
+ dname = true;
+ wc = ValUtils.rrsetWildcard(rrsets[i]);
+ if (wc != null) {
+ mErrorList.add("Illegal wildcard DNAME found: " + rrsets[i]);
+ }
+ }
+
+ // Skip validation of CNAMEs following DNAMEs. The
+ // normalization step will have synthesized an unsigned
+ // CNAME RRset.
+ if (dname && rtype == Type.CNAME) {
+ dname = false;
+ continue;
+ }
+
+ if (rtype == qtype) {
+ positive = true;
+ }
+
+ // Once we've gone off the reservation, avoid further
+ // validation.
+ if (! rname.subdomain(zone)) {
+ inZone = false;
+ break;
+ }
+
+ int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
+
+ if (status != SecurityStatus.SECURE) {
+ mErrorList.add("CNAME response has a failed ANSWER rrset: " +
+ rrsets[i]);
+ message.setStatus(SecurityStatus.BOGUS);
+
+ return;
+ }
+ }
+
+
+ // Validate the AUTHORITY section.
+ rrsets = message.getSectionRRsets(Section.ANSWER);
+ for (int i = 0; i < rrsets.length; i++) {
+
+
+ }
+
+ log.trace("Successfully validated CNAME response");
+ message.setStatus(SecurityStatus.SECURE);
+ }
/**
* Given an "ANY" response -- a response that contains an answer