2 * Copyright (c) 2009 VeriSign, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 package com.versign.tat.dnssec;
31 import java.io.IOException;
34 import org.xbill.DNS.*;
37 * This resolver module implements a "captive" DNSSEC validator. The captive
38 * validator does not have direct access to the Internet and DNS system --
39 * instead it attempts to validate DNS messages using only configured context.
40 * This is useful for determining if responses coming from a given authoritative
41 * server will validate independent of the normal chain of trust.
44 public class CaptiveValidator {
46 // A data structure holding all all of our trusted keys.
47 private TrustAnchorStore mTrustedKeys;
49 // The local validation utilities.
50 private ValUtils mValUtils;
52 // The local verification utility.
53 private DnsSecVerifier mVerifier;
55 public CaptiveValidator() {
56 mVerifier = new DnsSecVerifier();
57 mValUtils = new ValUtils(mVerifier);
58 mTrustedKeys = new TrustAnchorStore();
61 // ---------------- Module Initialization -------------------
64 * Add a set of trusted keys from a file. The file should be in DNS master
65 * zone file format. Only DNSKEY records will be added.
68 * The file contains the trusted keys.
71 @SuppressWarnings("unchecked")
72 public void addTrustedKeysFromFile(String filename) throws IOException {
73 // First read in the whole trust anchor file.
74 Master master = new Master(filename, Name.root, 0);
75 ArrayList<Record> records = new ArrayList<Record>();
78 while ((r = master.nextRecord()) != null) {
82 // Record.compareTo() should sort them into DNSSEC canonical order.
83 // Don't care about canonical order per se, but do want them to be
84 // formable into RRsets.
85 Collections.sort(records);
87 SRRset cur_rrset = new SRRset();
88 for (Record rec : records) {
89 // Skip RR types that cannot be used as trusted keys. I.e.,
90 // everything not a key :)
91 if (rec.getType() != Type.DNSKEY) continue;
93 // If our cur_rrset is empty, we can just add it.
94 if (cur_rrset.size() == 0) {
98 // If this record matches our current RRset, we can just add it.
99 if (cur_rrset.getName().equals(rec.getName())
100 && cur_rrset.getType() == rec.getType()
101 && cur_rrset.getDClass() == rec.getDClass()) {
102 cur_rrset.addRR(rec);
106 // Otherwise, we add the rrset to our set of trust anchors.
107 mTrustedKeys.store(cur_rrset);
108 cur_rrset = new SRRset();
109 cur_rrset.addRR(rec);
112 // add the last rrset (if it was not empty)
113 if (cur_rrset.size() > 0) {
114 mTrustedKeys.store(cur_rrset);
118 public void addTrustedKeysFromResponse(Message m) {
119 RRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
120 for (int i = 0; i < rrsets.length; ++i) {
121 if (rrsets[i].getType() == Type.DNSKEY) {
122 SRRset srrset = new SRRset(rrsets[i]);
123 mTrustedKeys.store(srrset);
128 // ----------------- Validation Support ----------------------
131 * This routine normalizes a response. This includes removing "irrelevant"
132 * records from the answer and additional sections and (re)synthesizing
133 * CNAMEs from DNAMEs, if present.
137 private SMessage normalize(SMessage m) {
138 if (m == null) return m;
140 if (m.getRcode() != Rcode.NOERROR && m.getRcode() != Rcode.NXDOMAIN) {
144 Name qname = m.getQuestion().getName();
145 int qtype = m.getQuestion().getType();
149 // For the ANSWER section, remove all "irrelevant" records and add
150 // synthesized CNAMEs from DNAMEs
151 // This will strip out-of-order CNAMEs as well.
152 List<SRRset> rrset_list = m.getSectionList(Section.ANSWER);
153 Set<Name> additional_names = new HashSet<Name>();
155 for (ListIterator<SRRset> i = rrset_list.listIterator(); i.hasNext();) {
156 SRRset rrset = i.next();
157 int type = rrset.getType();
158 Name n = rrset.getName();
160 // Handle DNAME synthesis; DNAME synthesis does not occur at the
161 // DNAME name itself.
162 if (type == Type.DNAME && ValUtils.strictSubdomain(sname, n)) {
163 if (rrset.size() > 1) {
164 // log.debug("Found DNAME rrset with size > 1: " + rrset);
165 // return Util.errorMessage(m, Rcode.SERVFAIL);
166 return null; // FIXME
168 DNAMERecord dname = (DNAMERecord) rrset.first();
170 Name cname_alias = sname.fromDNAME(dname);
171 // Note that synthesized CNAMEs should have a TTL of zero.
173 CNAMERecord cname = new CNAMERecord(sname,
174 dname.getDClass(), 0, cname_alias);
175 SRRset cname_rrset = new SRRset();
176 cname_rrset.addRR(cname);
180 } catch (NameTooLongException e) {
181 // log.debug("not adding synthesized CNAME -- "
182 // + "generated name is too long", e);
187 // The only records in the ANSWER section not allowed to
188 if (!n.equals(sname)) {
189 // log.debug("normalize: removing irrelevant rrset: " + rrset);
194 // Follow the CNAME chain.
195 if (type == Type.CNAME) {
196 if (rrset.size() > 1) {
197 // log.debug("Found CNAME rrset with size > 1: " + rrset);
198 // return Util.errorMessage(m, Rcode.SERVFAIL);
199 return null; // FIXME
202 CNAMERecord cname = (CNAMERecord) rrset.first();
203 sname = cname.getAlias();
207 // Otherwise, make sure that the RRset matches the qtype.
208 if (qtype != Type.ANY && qtype != type) {
209 // log.debug("normalize: removing irrelevant rrset: " + rrset);
213 // Otherwise, fetch the additional names from the relevant rrset.
214 rrsetAdditionalNames(additional_names, rrset);
217 // Get additional names from AUTHORITY
218 rrset_list = m.getSectionList(Section.AUTHORITY);
219 for (SRRset rrset : rrset_list) {
220 rrsetAdditionalNames(additional_names, rrset);
223 // For each record in the additional section, remove it if it is an
224 // address record and not in the collection of additional names found in
225 // ANSWER and AUTHORITY.
226 rrset_list = m.getSectionList(Section.ADDITIONAL);
227 for (Iterator<SRRset> i = rrset_list.iterator(); i.hasNext();) {
228 SRRset rrset = i.next();
229 int type = rrset.getType();
230 if ((type == Type.A || type == Type.AAAA)
231 && !additional_names.contains(rrset.getName())) {
234 // FIXME: what about other types?
241 * Extract additional names from the records in an rrset.
243 * @param additional_names
244 * The set to add the additional names to, if any.
246 * The rrset to extract from.
248 private void rrsetAdditionalNames(Set<Name> additional_names, SRRset rrset) {
249 if (rrset == null) return;
251 for (Iterator<Record> i = rrset.rrs(); i.hasNext();) {
253 Name add_name = r.getAdditionalName();
254 if (add_name != null) {
255 additional_names.add(add_name);
260 private SRRset findKeys(SMessage message) {
261 Name qname = message.getQName();
262 int qclass = message.getQClass();
264 return mTrustedKeys.find(qname, qclass);
268 * Check to see if a given response needs to go through the validation
269 * process. Typical reasons for this routine to return false are: CD bit was
270 * on in the original request, the response was already validated, or the
271 * response is a kind of message that is unvalidatable (i.e., SERVFAIL,
275 * The message to check.
277 * The original request received from the client.
279 * @return true if the response could use validation (although this does not
280 * mean we can actually validate this response).
282 private boolean needsValidation(SMessage message) {
283 int rcode = message.getRcode();
285 if (rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN) {
286 // log.debug("cannot validate non-answer.");
287 // log.trace("non-answer: " + response);
291 if (!mTrustedKeys.isBelowTrustAnchor(message.getQName(), message.getQClass())) {
298 * Given a "positive" response -- a response that contains an answer to the
299 * question, and no CNAME chain, validate this response. This generally
300 * consists of verifying the answer RRset and the authority RRsets.
302 * Note that by the time this method is called, the process of finding the
303 * trusted DNSKEY rrset that signs this response must already have been
307 * The response to validate.
309 * The request that generated this response.
311 * The trusted DNSKEY rrset that matches the signer of the
314 private void validatePositiveResponse(SMessage message, SRRset key_rrset) {
315 Name qname = message.getQName();
316 int qtype = message.getQType();
318 SMessage m = message;
320 // validate the ANSWER section - this will be the answer itself
321 SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
324 boolean wcNSEC_ok = false;
325 boolean dname = false;
326 List<NSEC3Record> nsec3s = null;
328 for (int i = 0; i < rrsets.length; i++) {
329 // Skip the CNAME following a (validated) DNAME.
330 // Because of the normalization routines in NameserverClient, there
331 // will always be an unsigned CNAME following a DNAME (unless
333 if (dname && rrsets[i].getType() == Type.CNAME) {
338 // Verify the answer rrset.
339 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
340 // If the (answer) rrset failed to validate, then this message is
342 if (status != SecurityStatus.SECURE) {
343 // log.debug("Positive response has failed ANSWER rrset: "
345 m.setStatus(SecurityStatus.BOGUS);
348 // Check to see if the rrset is the result of a wildcard expansion.
349 // If so, an additional check will need to be made in the authority
351 wc = ValUtils.rrsetWildcard(rrsets[i]);
353 // Notice a DNAME that should be followed by an unsigned CNAME.
354 if (qtype != Type.DNAME && rrsets[i].getType() == Type.DNAME) {
359 // validate the AUTHORITY section as well - this will generally be the
360 // NS rrset (which could be missing, no problem)
361 rrsets = m.getSectionRRsets(Section.AUTHORITY);
362 for (int i = 0; i < rrsets.length; i++) {
363 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
364 // If anything in the authority section fails to be secure, we have
367 if (status != SecurityStatus.SECURE) {
368 // log.debug("Positive response has failed AUTHORITY rrset: "
370 m.setStatus(SecurityStatus.BOGUS);
374 // If this is a positive wildcard response, and we have a (just
375 // verified) NSEC record, try to use it to 1) prove that qname
376 // doesn't exist and 2) that the correct wildcard was used.
377 if (wc != null && rrsets[i].getType() == Type.NSEC) {
378 NSECRecord nsec = (NSECRecord) rrsets[i].first();
380 if (ValUtils.nsecProvesNameError(nsec, qname,
381 key_rrset.getName())) {
382 Name nsec_wc = ValUtils.nsecWildcard(qname, nsec);
383 if (!wc.equals(nsec_wc)) {
384 // log.debug("Positive wildcard response wasn't generated "
385 // + "by the correct wildcard");
386 m.setStatus(SecurityStatus.BOGUS);
393 // Otherwise, if this is a positive wildcard response and we have
394 // NSEC3 records, collect them.
395 if (wc != null && rrsets[i].getType() == Type.NSEC3) {
396 if (nsec3s == null) nsec3s = new ArrayList<NSEC3Record>();
397 nsec3s.add((NSEC3Record) rrsets[i].first());
401 // If this was a positive wildcard response that we haven't already
402 // proven, and we have NSEC3 records, try to prove it using the NSEC3
404 if (wc != null && !wcNSEC_ok && nsec3s != null) {
405 if (NSEC3ValUtils.proveWildcard(nsec3s, qname, key_rrset.getName(),
411 // If after all this, we still haven't proven the positive wildcard
413 if (wc != null && !wcNSEC_ok) {
414 // log.debug("positive response was wildcard expansion and "
415 // + "did not prove original data did not exist");
416 m.setStatus(SecurityStatus.BOGUS);
420 // log.trace("Successfully validated positive response");
421 m.setStatus(SecurityStatus.SECURE);
424 private void validateReferral(SMessage message, SRRset key_rrset) {
425 SMessage m = message;
427 if (m.getCount(Section.ANSWER) > 0) {
428 // FIXME: fail somehow.
431 // validate the AUTHORITY section.
432 SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
434 boolean secure_delegation = false;
435 Name delegation = null;
436 Name nsec3zone = null;
437 NSECRecord nsec = null;
438 List<NSEC3Record> nsec3s = null;
440 // validate the AUTHORITY section as well - this will generally be the
441 // NS rrset, plus proof of a secure delegation or not
442 rrsets = m.getSectionRRsets(Section.AUTHORITY);
443 for (int i = 0; i < rrsets.length; i++) {
444 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
445 // If anything in the authority section fails to be secure, we have
447 if (status != SecurityStatus.SECURE) {
448 // log.debug("Positive response has failed AUTHORITY rrset: "
450 m.setStatus(SecurityStatus.BOGUS);
454 int type = rrsets[i].getType();
457 secure_delegation = true;
460 delegation = rrsets[i].getName();
463 nsec = (NSECRecord) rrsets[i].first();
466 if (nsec3s == null) nsec3s = new ArrayList<NSEC3Record>();
467 NSEC3Record nsec3 = (NSEC3Record) rrsets[i].first();
469 nsec3zone = rrsets[i].getSignerName(); // this is a hack of sorts.
472 // FIXME: should probably whine if we see something else.
477 // At this point, all validatable RRsets have been validated.
478 // Now to check to see if we have a valid combination of things.
479 if (delegation == null) {
480 // somehow we have a referral without an NS rrset.
481 m.setStatus(SecurityStatus.BOGUS);
485 if (secure_delegation) {
486 if (nsec != null || nsec3s.size() > 0) {
487 // we found both a DS rrset *and* NSEC/NSEC3 rrsets!
488 m.setStatus(SecurityStatus.BOGUS);
491 // otherwise, we are done.
492 m.setStatus(SecurityStatus.SECURE);
496 // Note: not going to care if both NSEC and NSEC3 rrsets were present.
498 byte status = ValUtils.nsecProvesNoDS(nsec, delegation);
499 if (status != SecurityStatus.SECURE) {
500 // The NSEC *must* prove that there was no DS record. The INSECURE state here is still bogus.
501 m.setStatus(SecurityStatus.BOGUS);
504 m.setStatus(SecurityStatus.SECURE);
508 if (nsec3s.size() > 0) {
509 byte status = NSEC3ValUtils.proveNoDS(nsec3s, delegation, nsec3zone);
510 if (status != SecurityStatus.SECURE) {
511 // the NSEC3 RRs MUST prove no DS, so the INDETERMINATE state is actually bogus
512 m.setStatus(SecurityStatus.BOGUS);
515 m.setStatus(SecurityStatus.SECURE);
519 // failed to find proof either way.
520 m.setStatus(SecurityStatus.BOGUS);
523 private void validateCNAMEResponse(SMessage message, SRRset key_rrset) {
528 * Given an "ANY" response -- a response that contains an answer to a
529 * qtype==ANY question, with answers. This consists of simply verifying all
530 * present answer/auth RRsets, with no checking that all types are present.
532 * NOTE: it may be possible to get parent-side delegation point records
533 * here, which won't all be signed. Right now, this routine relies on the
534 * upstream iterative resolver to not return these responses -- instead
535 * treating them as referrals.
537 * NOTE: RFC 4035 is silent on this issue, so this may change upon
540 * Note that by the time this method is called, the process of finding the
541 * trusted DNSKEY rrset that signs this response must already have been
545 * The response to validate.
547 * The trusted DNSKEY rrset that matches the signer of the
550 private void validateAnyResponse(SMessage message, SRRset key_rrset) {
551 int qtype = message.getQType();
553 if (qtype != Type.ANY)
554 throw new IllegalArgumentException(
555 "ANY validation called on non-ANY response.");
557 SMessage m = message;
559 // validate the ANSWER section.
560 SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
561 for (int i = 0; i < rrsets.length; i++) {
562 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
563 // If the (answer) rrset failed to validate, then this message is
565 if (status != SecurityStatus.SECURE) {
566 // log.debug("Positive response has failed ANSWER rrset: "
568 m.setStatus(SecurityStatus.BOGUS);
573 // validate the AUTHORITY section as well - this will be the NS rrset
574 // (which could be missing, no problem)
575 rrsets = m.getSectionRRsets(Section.AUTHORITY);
576 for (int i = 0; i < rrsets.length; i++) {
577 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
578 // If anything in the authority section fails to be secure, we have
581 if (status != SecurityStatus.SECURE) {
582 // log.debug("Positive response has failed AUTHORITY rrset: "
584 m.setStatus(SecurityStatus.BOGUS);
589 // log.trace("Successfully validated positive ANY response");
590 m.setStatus(SecurityStatus.SECURE);
594 * Validate a NOERROR/NODATA signed response -- a response that has a
595 * NOERROR Rcode but no ANSWER section RRsets. This consists of verifying
596 * the authority section rrsets and making certain that the authority
597 * section NSEC/NSEC3s proves that the qname does exist and the qtype
600 * Note that by the time this method is called, the process of finding the
601 * trusted DNSKEY rrset that signs this response must already have been
605 * The response to validate.
607 * The request that generated this response.
609 * The trusted DNSKEY rrset that signs this response.
611 private void validateNodataResponse(SMessage message, SRRset key_rrset) {
612 Name qname = message.getQName();
613 int qtype = message.getQType();
615 SMessage m = message;
617 // Since we are here, there must be nothing in the ANSWER section to
618 // validate. (Note: CNAME/DNAME responses will not directly get here --
619 // instead they are broken down into individual CNAME/DNAME/final answer
622 // validate the AUTHORITY section
623 SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
625 boolean hasValidNSEC = false; // If true, then the NODATA has been
627 Name ce = null; // for wildcard NODATA responses. This is the proven
629 NSECRecord wc = null; // for wildcard NODATA responses. This is the
631 List<NSEC3Record> nsec3s = null; // A collection of NSEC3 RRs found in the authority
633 Name nsec3Signer = null; // The RRSIG signer field for the NSEC3 RRs.
635 for (int i = 0; i < rrsets.length; i++) {
636 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
637 if (status != SecurityStatus.SECURE) {
638 // log.debug("NODATA response has failed AUTHORITY rrset: "
640 m.setStatus(SecurityStatus.BOGUS);
644 // If we encounter an NSEC record, try to use it to prove NODATA.
645 // This needs to handle the ENT NODATA case.
646 if (rrsets[i].getType() == Type.NSEC) {
647 NSECRecord nsec = (NSECRecord) rrsets[i].first();
648 if (ValUtils.nsecProvesNodata(nsec, qname, qtype)) {
650 if (nsec.getName().isWild()) wc = nsec;
651 } else if (ValUtils.nsecProvesNameError(
654 rrsets[i].getSignerName())) {
655 ce = ValUtils.closestEncloser(qname, nsec);
659 // Collect any NSEC3 records present.
660 if (rrsets[i].getType() == Type.NSEC3) {
661 if (nsec3s == null) nsec3s = new ArrayList<NSEC3Record>();
662 nsec3s.add((NSEC3Record) rrsets[i].first());
663 nsec3Signer = rrsets[i].getSignerName();
667 // check to see if we have a wildcard NODATA proof.
669 // The wildcard NODATA is 1 NSEC proving that qname does not exists (and
670 // also proving what the closest encloser is), and 1 NSEC showing the
671 // matching wildcard, which must be *.closest_encloser.
672 if (ce != null || wc != null) {
674 Name wc_name = new Name("*", ce);
675 if (!wc_name.equals(wc.getName())) {
676 hasValidNSEC = false;
678 } catch (TextParseException e) {
683 NSEC3ValUtils.stripUnknownAlgNSEC3s(nsec3s);
685 if (!hasValidNSEC && nsec3s != null && nsec3s.size() > 0) {
686 // try to prove NODATA with our NSEC3 record(s)
687 hasValidNSEC = NSEC3ValUtils.proveNodata(nsec3s, qname, qtype,
692 // log.debug("NODATA response failed to prove NODATA "
693 // + "status with NSEC/NSEC3");
694 // log.trace("Failed NODATA:\n" + m);
695 m.setStatus(SecurityStatus.BOGUS);
698 // log.trace("successfully validated NODATA response.");
699 m.setStatus(SecurityStatus.SECURE);
703 * Validate a NAMEERROR signed response -- a response that has a NXDOMAIN
704 * Rcode. This consists of verifying the authority section rrsets and making
705 * certain that the authority section NSEC proves that the qname doesn't
706 * exist and the covering wildcard also doesn't exist..
708 * Note that by the time this method is called, the process of finding the
709 * trusted DNSKEY rrset that signs this response must already have been
713 * The response to validate.
715 * The request that generated this response.
717 * The trusted DNSKEY rrset that signs this response.
719 private void validateNameErrorResponse(SMessage message, SRRset key_rrset) {
720 Name qname = message.getQName();
722 SMessage m = message;
724 // FIXME: should we check to see if there is anything in the answer
725 // section? if so, what should the result be?
727 // Validate the authority section -- all RRsets in the authority section
728 // must be signed and valid.
729 // In addition, the NSEC record(s) must prove the NXDOMAIN condition.
731 boolean hasValidNSEC = false;
732 boolean hasValidWCNSEC = false;
733 SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
734 List<NSEC3Record> nsec3s = null;
735 Name nsec3Signer = null;
737 for (int i = 0; i < rrsets.length; i++) {
738 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
739 if (status != SecurityStatus.SECURE) {
740 // log.debug("NameError response has failed AUTHORITY rrset: "
742 m.setStatus(SecurityStatus.BOGUS);
745 if (rrsets[i].getType() == Type.NSEC) {
746 NSECRecord nsec = (NSECRecord) rrsets[i].first();
748 if (ValUtils.nsecProvesNameError(nsec, qname,
749 rrsets[i].getSignerName())) {
752 if (ValUtils.nsecProvesNoWC(nsec, qname,
753 rrsets[i].getSignerName())) {
754 hasValidWCNSEC = true;
757 if (rrsets[i].getType() == Type.NSEC3) {
758 if (nsec3s == null) nsec3s = new ArrayList<NSEC3Record>();
759 nsec3s.add((NSEC3Record) rrsets[i].first());
760 nsec3Signer = rrsets[i].getSignerName();
764 NSEC3ValUtils.stripUnknownAlgNSEC3s(nsec3s);
766 if (nsec3s != null && nsec3s.size() > 0) {
767 // log.debug("Validating nxdomain: using NSEC3 records");
768 // Attempt to prove name error with nsec3 records.
770 if (NSEC3ValUtils.allNSEC3sIgnoreable(nsec3s, key_rrset, mVerifier)) {
771 // log.debug("all NSEC3s were validated but ignored.");
772 m.setStatus(SecurityStatus.INSECURE);
776 hasValidNSEC = NSEC3ValUtils.proveNameError(nsec3s, qname,
779 // Note that we assume that the NSEC3ValUtils proofs encompass the
780 // wildcard part of the proof.
781 hasValidWCNSEC = hasValidNSEC;
784 // If the message fails to prove either condition, it is bogus.
786 // log.debug("NameError response has failed to prove: "
787 // + "qname does not exist");
788 m.setStatus(SecurityStatus.BOGUS);
792 if (!hasValidWCNSEC) {
793 // log.debug("NameError response has failed to prove: "
794 // + "covering wildcard does not exist");
795 m.setStatus(SecurityStatus.BOGUS);
799 // Otherwise, we consider the message secure.
800 // log.trace("successfully validated NAME ERROR response.");
801 m.setStatus(SecurityStatus.SECURE);
804 public byte validateMessage(SMessage message, Name zone) {
806 // FIXME: it is unclear if we should actually normalize our responses
807 // Instead, maybe we should just fail if they are not normal?
808 message = normalize(message);
810 if (! needsValidation(message)) {
811 return SecurityStatus.UNCHECKED;
814 SRRset key_rrset = findKeys(message);
815 if (key_rrset == null) {
816 return SecurityStatus.BOGUS;
819 ValUtils.ResponseType subtype = ValUtils.classifyResponse(message, zone);
823 // log.trace("Validating a positive response");
824 validatePositiveResponse(message, key_rrset);
827 validateReferral(message, key_rrset);
830 // log.trace("Validating a NODATA response");
831 validateNodataResponse(message, key_rrset);
834 // log.trace("Validating a NXDOMAIN response");
835 validateNameErrorResponse(message, key_rrset);
838 // log.trace("Validating a CNAME response");
839 // forward on to the special CNAME state for this.
840 // state.state = ValEventState.CNAME_STATE;
841 validateCNAMEResponse(message, key_rrset);
844 // log.trace("Validating a positive ANY response");
845 validateAnyResponse(message, key_rrset);
848 // log.error("unhandled response subtype: " + subtype);
851 return message.getSecurityStatus().getStatus();