X-Git-Url: https://blacka.com/cgi-bin/gitweb.cgi?p=captive-validator.git;a=blobdiff_plain;f=src%2Fcom%2Fverisign%2Ftat%2Fdnssec%2FCaptiveValidator.java;fp=src%2Fcom%2Fverisign%2Ftat%2Fdnssec%2FCaptiveValidator.java;h=530496751283412ac88ff9cf08ddf7f4868f0265;hp=6b451a389c97e6ca7ef103dbba083329146784db;hb=bc35e72aed44b6cf79766c7f4f27ea81390931df;hpb=ecbb43bf6ccadf516a3fe4ef07446bdd21003da0 diff --git a/src/com/verisign/tat/dnssec/CaptiveValidator.java b/src/com/verisign/tat/dnssec/CaptiveValidator.java index 6b451a3..5304967 100644 --- a/src/com/verisign/tat/dnssec/CaptiveValidator.java +++ b/src/com/verisign/tat/dnssec/CaptiveValidator.java @@ -611,8 +611,126 @@ public class CaptiveValidator { 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 wildcards = new Vector(); + 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