1 /***************************** -*- Java -*- ********************************\
3 * Copyright (c) 2009 VeriSign, Inc. All rights reserved. *
5 * This software is provided solely in connection with the terms of the *
6 * license agreement. Any other use without the prior express written *
7 * permission of VeriSign is completely prohibited. The software and *
8 * documentation are "Commercial Items", as that term is defined in 48 *
9 * C.F.R. section 2.101, consisting of "Commercial Computer Software" and *
10 * "Commercial Computer Software Documentation" as such terms are defined *
11 * in 48 C.F.R. section 252.227-7014(a)(5) and 48 C.F.R. section *
12 * 252.227-7014(a)(1), and used in 48 C.F.R. section 12.212 and 48 C.F.R. *
13 * section 227.7202, as applicable. Pursuant to the above and other *
14 * relevant sections of the Code of Federal Regulations, as applicable, *
15 * VeriSign's publications, commercial computer software, and commercial *
16 * computer software documentation are distributed and licensed to United *
17 * States Government end users with only those rights as granted to all *
18 * other end users, according to the terms and conditions contained in the *
19 * license agreement(s) that accompany the products and software *
22 \***************************************************************************/
24 package com.verisign.tat.dnssec;
26 import org.apache.log4j.Logger;
28 import org.xbill.DNS.*;
30 import java.io.IOException;
35 * This resolver module implements a "captive" DNSSEC validator. The captive
36 * validator does not have direct access to the Internet and DNS system --
37 * instead it attempts to validate DNS messages using only configured context.
38 * This is useful for determining if responses coming from a given authoritative
39 * server will validate independent of the normal chain of trust.
41 public class CaptiveValidator {
42 // A data structure holding all all of our trusted keys.
43 private TrustAnchorStore mTrustedKeys;
45 // The local validation utilities.
46 private ValUtils mValUtils;
48 // The local verification utility.
49 private DnsSecVerifier mVerifier;
50 private Logger log = Logger.getLogger(this.getClass());
52 public CaptiveValidator() {
53 mVerifier = new DnsSecVerifier();
54 mValUtils = new ValUtils(mVerifier);
55 mTrustedKeys = new TrustAnchorStore();
58 // ---------------- Module Initialization -------------------
61 * Add a set of trusted keys from a file. The file should be in DNS master
62 * zone file format. Only DNSKEY records will be added.
65 * The file contains the trusted keys.
68 @SuppressWarnings("unchecked")
69 public void addTrustedKeysFromFile(String filename) throws IOException {
70 // First read in the whole trust anchor file.
71 Master master = new Master(filename, Name.root, 0);
72 ArrayList<Record> records = new ArrayList<Record>();
75 while ((r = master.nextRecord()) != null) {
79 // Record.compareTo() should sort them into DNSSEC canonical order.
80 // Don't care about canonical order per se, but do want them to be
81 // formable into RRsets.
82 Collections.sort(records);
84 SRRset cur_rrset = new SRRset();
86 for (Record rec : records) {
87 // Skip RR types that cannot be used as trusted keys. I.e.,
88 // everything not a key :)
89 if (rec.getType() != Type.DNSKEY) {
93 // If our cur_rrset is empty, we can just add it.
94 if (cur_rrset.size() == 0) {
100 // If this record matches our current RRset, we can just add it.
101 if (cur_rrset.getName().equals(rec.getName())
102 && (cur_rrset.getType() == rec.getType())
103 && (cur_rrset.getDClass() == rec.getDClass())) {
104 cur_rrset.addRR(rec);
109 // Otherwise, we add the rrset to our set of trust anchors.
110 mTrustedKeys.store(cur_rrset);
111 cur_rrset = new SRRset();
112 cur_rrset.addRR(rec);
115 // add the last rrset (if it was not empty)
116 if (cur_rrset.size() > 0) {
117 mTrustedKeys.store(cur_rrset);
121 public void addTrustedKeysFromResponse(Message m) {
122 RRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
124 for (int i = 0; i < rrsets.length; ++i) {
125 if (rrsets[i].getType() == Type.DNSKEY) {
126 SRRset srrset = new SRRset(rrsets[i]);
127 mTrustedKeys.store(srrset);
132 // ----------------- Validation Support ----------------------
135 * This routine normalizes a response. This includes removing "irrelevant"
136 * records from the answer and additional sections and (re)synthesizing
137 * CNAMEs from DNAMEs, if present.
141 private SMessage normalize(SMessage m) {
146 if ((m.getRcode() != Rcode.NOERROR) && (m.getRcode() != Rcode.NXDOMAIN)) {
150 Name qname = m.getQuestion().getName();
151 int qtype = m.getQuestion().getType();
155 // For the ANSWER section, remove all "irrelevant" records and add
156 // synthesized CNAMEs from DNAMEs
157 // This will strip out-of-order CNAMEs as well.
158 List<SRRset> rrset_list = m.getSectionList(Section.ANSWER);
159 Set<Name> additional_names = new HashSet<Name>();
161 for (ListIterator<SRRset> i = rrset_list.listIterator(); i.hasNext();) {
162 SRRset rrset = i.next();
163 int type = rrset.getType();
164 Name n = rrset.getName();
166 // Handle DNAME synthesis; DNAME synthesis does not occur at the
167 // DNAME name itself.
168 if ((type == Type.DNAME) && ValUtils.strictSubdomain(sname, n)) {
169 if (rrset.size() > 1) {
170 log.debug("Found DNAME rrset with size > 1: " + rrset);
171 m.setStatus(SecurityStatus.INVALID);
176 DNAMERecord dname = (DNAMERecord) rrset.first();
179 Name cname_alias = sname.fromDNAME(dname);
181 // Note that synthesized CNAMEs should have a TTL of zero.
182 CNAMERecord cname = new CNAMERecord(sname, dname
183 .getDClass(), 0, cname_alias);
184 SRRset cname_rrset = new SRRset();
185 cname_rrset.addRR(cname);
189 } catch (NameTooLongException e) {
190 log.debug("not adding synthesized CNAME -- "
191 + "generated name is too long", e);
197 // The only records in the ANSWER section not allowed to
198 if (!n.equals(sname)) {
199 log.debug("normalize: removing irrelevant rrset: " + rrset);
205 // Follow the CNAME chain.
206 if (type == Type.CNAME) {
207 if (rrset.size() > 1) {
208 log.debug("Found CNAME rrset with size > 1: " + rrset);
209 m.setStatus(SecurityStatus.INVALID);
214 CNAMERecord cname = (CNAMERecord) rrset.first();
215 sname = cname.getAlias();
220 // Otherwise, make sure that the RRset matches the qtype.
221 if ((qtype != Type.ANY) && (qtype != type)) {
222 log.debug("normalize: removing irrelevant rrset: " + rrset);
226 // Otherwise, fetch the additional names from the relevant rrset.
227 rrsetAdditionalNames(additional_names, rrset);
230 // Get additional names from AUTHORITY
231 rrset_list = m.getSectionList(Section.AUTHORITY);
233 for (SRRset rrset : rrset_list) {
234 rrsetAdditionalNames(additional_names, rrset);
237 // For each record in the additional section, remove it if it is an
238 // address record and not in the collection of additional names found in
239 // ANSWER and AUTHORITY.
240 rrset_list = m.getSectionList(Section.ADDITIONAL);
242 for (Iterator<SRRset> i = rrset_list.iterator(); i.hasNext();) {
243 SRRset rrset = i.next();
244 int type = rrset.getType();
246 if (((type == Type.A) || (type == Type.AAAA))
247 && !additional_names.contains(rrset.getName())) {
256 * Extract additional names from the records in an rrset.
258 * @param additional_names
259 * The set to add the additional names to, if any.
261 * The rrset to extract from.
263 private void rrsetAdditionalNames(Set<Name> additional_names, SRRset rrset) {
268 for (Iterator<Record> i = rrset.rrs(); i.hasNext();) {
270 Name add_name = r.getAdditionalName();
272 if (add_name != null) {
273 additional_names.add(add_name);
278 private SRRset findKeys(SMessage message) {
279 Name qname = message.getQName();
280 int qclass = message.getQClass();
282 return mTrustedKeys.find(qname, qclass);
286 * Check to see if a given response needs to go through the validation
287 * process. Typical reasons for this routine to return false are: CD bit was
288 * on in the original request, the response was already validated, or the
289 * response is a kind of message that is unvalidatable (i.e., SERVFAIL,
293 * The message to check.
295 * The original request received from the client.
297 * @return true if the response could use validation (although this does not
298 * mean we can actually validate this response).
300 private boolean needsValidation(SMessage message) {
301 int rcode = message.getRcode();
303 if ((rcode != Rcode.NOERROR) && (rcode != Rcode.NXDOMAIN)) {
304 log.debug("cannot validate non-answer.");
305 log.trace("non-answer: " + message);
310 if (!mTrustedKeys.isBelowTrustAnchor(message.getQName(), message
319 * Given a "positive" response -- a response that contains an answer to the
320 * question, and no CNAME chain, validate this response. This generally
321 * consists of verifying the answer RRset and the authority RRsets.
323 * Note that by the time this method is called, the process of finding the
324 * trusted DNSKEY rrset that signs this response must already have been
328 * The response to validate.
330 * The request that generated this response.
332 * The trusted DNSKEY rrset that matches the signer of the
335 private void validatePositiveResponse(SMessage message, SRRset key_rrset) {
336 Name qname = message.getQName();
337 int qtype = message.getQType();
339 SMessage m = message;
341 // validate the ANSWER section - this will be the answer itself
342 SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
345 boolean wcNSEC_ok = false;
346 boolean dname = false;
347 List<NSEC3Record> nsec3s = null;
349 for (int i = 0; i < rrsets.length; i++) {
350 // Skip the CNAME following a (validated) DNAME.
351 // Because of the normalization routines in NameserverClient, there
352 // will always be an unsigned CNAME following a DNAME (unless
354 if (dname && (rrsets[i].getType() == Type.CNAME)) {
360 // Verify the answer rrset.
361 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
363 // If the (answer) rrset failed to validate, then this message is
365 if (status != SecurityStatus.SECURE) {
366 log.debug("Positive response has failed ANSWER rrset: "
368 m.setStatus(SecurityStatus.BOGUS);
373 // Check to see if the rrset is the result of a wildcard expansion.
374 // If so, an additional check will need to be made in the authority
376 wc = ValUtils.rrsetWildcard(rrsets[i]);
378 // Notice a DNAME that should be followed by an unsigned CNAME.
379 if ((qtype != Type.DNAME) && (rrsets[i].getType() == Type.DNAME)) {
384 // validate the AUTHORITY section as well - this will generally be the
385 // NS rrset (which could be missing, no problem)
386 rrsets = m.getSectionRRsets(Section.AUTHORITY);
388 for (int i = 0; i < rrsets.length; i++) {
389 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
391 // If anything in the authority section fails to be secure, we have
394 if (status != SecurityStatus.SECURE) {
395 log.debug("Positive response has failed AUTHORITY rrset: "
397 m.setStatus(SecurityStatus.BOGUS);
402 // If this is a positive wildcard response, and we have a (just
403 // verified) NSEC record, try to use it to 1) prove that qname
404 // doesn't exist and 2) that the correct wildcard was used.
405 if ((wc != null) && (rrsets[i].getType() == Type.NSEC)) {
406 NSECRecord nsec = (NSECRecord) rrsets[i].first();
408 if (ValUtils.nsecProvesNameError(nsec, qname, key_rrset
410 Name nsec_wc = ValUtils.nsecWildcard(qname, nsec);
412 if (!wc.equals(nsec_wc)) {
413 // log.debug("Positive wildcard response wasn't generated "
414 // + "by the correct wildcard");
415 m.setStatus(SecurityStatus.BOGUS);
424 // Otherwise, if this is a positive wildcard response and we have
425 // NSEC3 records, collect them.
426 if ((wc != null) && (rrsets[i].getType() == Type.NSEC3)) {
427 if (nsec3s == null) {
428 nsec3s = new ArrayList<NSEC3Record>();
431 nsec3s.add((NSEC3Record) rrsets[i].first());
435 // If this was a positive wildcard response that we haven't already
436 // proven, and we have NSEC3 records, try to prove it using the NSEC3
438 if ((wc != null) && !wcNSEC_ok && (nsec3s != null)) {
439 if (NSEC3ValUtils.proveWildcard(nsec3s, qname, key_rrset.getName(),
445 // If after all this, we still haven't proven the positive wildcard
447 if ((wc != null) && !wcNSEC_ok) {
448 // log.debug("positive response was wildcard expansion and "
449 // + "did not prove original data did not exist");
450 m.setStatus(SecurityStatus.BOGUS);
455 log.trace("Successfully validated positive response");
456 m.setStatus(SecurityStatus.SECURE);
459 private void validateReferral(SMessage message, SRRset key_rrset) {
460 SMessage m = message;
462 if (m.getCount(Section.ANSWER) > 0) {
463 m.setStatus(SecurityStatus.INVALID);
468 // validate the AUTHORITY section.
469 SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
471 boolean secure_delegation = false;
472 Name delegation = null;
473 Name nsec3zone = null;
474 NSECRecord nsec = null;
475 List<NSEC3Record> nsec3s = null;
477 // validate the AUTHORITY section as well - this will generally be the
478 // NS rrset, plus proof of a secure delegation or not
479 rrsets = m.getSectionRRsets(Section.AUTHORITY);
481 for (int i = 0; i < rrsets.length; i++) {
482 int type = rrsets[i].getType();
484 // The NS RRset won't be signed, but everything else should be.
485 if (type != Type.NS) {
486 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
488 // If anything in the authority section fails to be secure, we
491 if (status != SecurityStatus.SECURE) {
492 log.debug("Positive response has failed AUTHORITY rrset: "
494 m.setStatus(SecurityStatus.BOGUS);
502 secure_delegation = true;
507 delegation = rrsets[i].getName();
512 nsec = (NSECRecord) rrsets[i].first();
518 if (nsec3s == null) {
519 nsec3s = new ArrayList<NSEC3Record>();
522 NSEC3Record nsec3 = (NSEC3Record) rrsets[i].first();
524 nsec3zone = rrsets[i].getSignerName(); // this is a hack of
530 log.warn("Encountered unexpected type in a REFERRAL response: "
531 + Type.string(type));
537 // At this point, all validatable RRsets have been validated.
538 // Now to check to see if we have a valid combination of things.
539 if (delegation == null) {
540 // somehow we have a referral without an NS rrset.
541 m.setStatus(SecurityStatus.BOGUS);
546 if (secure_delegation) {
547 if ((nsec != null) || ((nsec3s != null) && (nsec3s.size() > 0))) {
548 // we found both a DS rrset *and* NSEC/NSEC3 rrsets!
549 m.setStatus(SecurityStatus.BOGUS);
554 // otherwise, we are done.
555 m.setStatus(SecurityStatus.SECURE);
560 // Note: not going to care if both NSEC and NSEC3 rrsets were present.
562 byte status = ValUtils.nsecProvesNoDS(nsec, delegation);
564 if (status != SecurityStatus.SECURE) {
565 // The NSEC *must* prove that there was no DS record. The
566 // INSECURE state here is still bogus.
567 m.setStatus(SecurityStatus.BOGUS);
572 m.setStatus(SecurityStatus.SECURE);
577 if (nsec3s.size() > 0) {
578 byte status = NSEC3ValUtils
579 .proveNoDS(nsec3s, delegation, nsec3zone);
581 if (status != SecurityStatus.SECURE) {
582 // the NSEC3 RRs MUST prove no DS, so the INDETERMINATE state is
584 m.setStatus(SecurityStatus.BOGUS);
589 m.setStatus(SecurityStatus.SECURE);
594 // failed to find proof either way.
595 m.setStatus(SecurityStatus.BOGUS);
598 private void validateCNAMEResponse(SMessage message, SRRset key_rrset) {
602 * Given an "ANY" response -- a response that contains an answer to a
603 * qtype==ANY question, with answers. This consists of simply verifying all
604 * present answer/auth RRsets, with no checking that all types are present.
606 * NOTE: it may be possible to get parent-side delegation point records
607 * here, which won't all be signed. Right now, this routine relies on the
608 * upstream iterative resolver to not return these responses -- instead
609 * treating them as referrals.
611 * NOTE: RFC 4035 is silent on this issue, so this may change upon
614 * Note that by the time this method is called, the process of finding the
615 * trusted DNSKEY rrset that signs this response must already have been
619 * The response to validate.
621 * The trusted DNSKEY rrset that matches the signer of the
624 private void validateAnyResponse(SMessage message, SRRset key_rrset) {
625 int qtype = message.getQType();
627 if (qtype != Type.ANY) {
628 throw new IllegalArgumentException(
629 "ANY validation called on non-ANY response.");
632 SMessage m = message;
634 // validate the ANSWER section.
635 SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
637 for (int i = 0; i < rrsets.length; i++) {
638 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
640 // If the (answer) rrset failed to validate, then this message is
642 if (status != SecurityStatus.SECURE) {
643 log.debug("Positive response has failed ANSWER rrset: "
645 m.setStatus(SecurityStatus.BOGUS);
651 // validate the AUTHORITY section as well - this will be the NS rrset
652 // (which could be missing, no problem)
653 rrsets = m.getSectionRRsets(Section.AUTHORITY);
655 for (int i = 0; i < rrsets.length; i++) {
656 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
658 // If anything in the authority section fails to be secure, we have
661 if (status != SecurityStatus.SECURE) {
662 log.debug("Positive response has failed AUTHORITY rrset: "
664 m.setStatus(SecurityStatus.BOGUS);
670 log.trace("Successfully validated positive ANY response");
671 m.setStatus(SecurityStatus.SECURE);
675 * Validate a NOERROR/NODATA signed response -- a response that has a
676 * NOERROR Rcode but no ANSWER section RRsets. This consists of verifying
677 * the authority section rrsets and making certain that the authority
678 * section NSEC/NSEC3s proves that the qname does exist and the qtype
681 * Note that by the time this method is called, the process of finding the
682 * trusted DNSKEY rrset that signs this response must already have been
686 * The response to validate.
688 * The request that generated this response.
690 * The trusted DNSKEY rrset that signs this response.
692 private void validateNodataResponse(SMessage message, SRRset key_rrset) {
693 Name qname = message.getQName();
694 int qtype = message.getQType();
696 SMessage m = message;
698 // Since we are here, there must be nothing in the ANSWER section to
699 // validate. (Note: CNAME/DNAME responses will not directly get here --
700 // instead they are broken down into individual CNAME/DNAME/final answer
703 // validate the AUTHORITY section
704 SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
706 boolean hasValidNSEC = false; // If true, then the NODATA has been
709 Name ce = null; // for wildcard NODATA responses. This is the proven
712 NSECRecord wc = null; // for wildcard NODATA responses. This is the
715 List<NSEC3Record> nsec3s = null; // A collection of NSEC3 RRs found in
719 Name nsec3Signer = null; // The RRSIG signer field for the NSEC3 RRs.
721 for (int i = 0; i < rrsets.length; i++) {
722 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
724 if (status != SecurityStatus.SECURE) {
725 log.debug("NODATA response has failed AUTHORITY rrset: "
727 m.setStatus(SecurityStatus.BOGUS);
732 // If we encounter an NSEC record, try to use it to prove NODATA.
733 // This needs to handle the ENT NODATA case.
734 if (rrsets[i].getType() == Type.NSEC) {
735 NSECRecord nsec = (NSECRecord) rrsets[i].first();
737 if (ValUtils.nsecProvesNodata(nsec, qname, qtype)) {
740 if (nsec.getName().isWild()) {
743 } else if (ValUtils.nsecProvesNameError(nsec, qname, rrsets[i]
745 ce = ValUtils.closestEncloser(qname, nsec);
749 // Collect any NSEC3 records present.
750 if (rrsets[i].getType() == Type.NSEC3) {
751 if (nsec3s == null) {
752 nsec3s = new ArrayList<NSEC3Record>();
755 nsec3s.add((NSEC3Record) rrsets[i].first());
756 nsec3Signer = rrsets[i].getSignerName();
760 // check to see if we have a wildcard NODATA proof.
762 // The wildcard NODATA is 1 NSEC proving that qname does not exists (and
763 // also proving what the closest encloser is), and 1 NSEC showing the
764 // matching wildcard, which must be *.closest_encloser.
765 if ((ce != null) || (wc != null)) {
767 Name wc_name = new Name("*", ce);
769 if (!wc_name.equals(wc.getName())) {
770 hasValidNSEC = false;
772 } catch (TextParseException e) {
777 NSEC3ValUtils.stripUnknownAlgNSEC3s(nsec3s);
779 if (!hasValidNSEC && (nsec3s != null) && (nsec3s.size() > 0)) {
780 // try to prove NODATA with our NSEC3 record(s)
781 hasValidNSEC = NSEC3ValUtils.proveNodata(nsec3s, qname, qtype,
786 log.debug("NODATA response failed to prove NODATA "
787 + "status with NSEC/NSEC3");
788 log.trace("Failed NODATA:\n" + m);
789 m.setStatus(SecurityStatus.BOGUS);
794 log.trace("successfully validated NODATA response.");
795 m.setStatus(SecurityStatus.SECURE);
799 * Validate a NAMEERROR signed response -- a response that has a NXDOMAIN
800 * Rcode. This consists of verifying the authority section rrsets and making
801 * certain that the authority section NSEC proves that the qname doesn't
802 * exist and the covering wildcard also doesn't exist..
804 * Note that by the time this method is called, the process of finding the
805 * trusted DNSKEY rrset that signs this response must already have been
809 * The response to validate.
811 * The request that generated this response.
813 * The trusted DNSKEY rrset that signs this response.
815 private void validateNameErrorResponse(SMessage message, SRRset key_rrset) {
816 Name qname = message.getQName();
818 SMessage m = message;
820 if (message.getCount(Section.ANSWER) > 0) {
822 .warn("NAME ERROR response contained records in the ANSWER SECTION");
823 message.setStatus(SecurityStatus.INVALID);
828 // Validate the authority section -- all RRsets in the authority section
829 // must be signed and valid.
830 // In addition, the NSEC record(s) must prove the NXDOMAIN condition.
831 boolean hasValidNSEC = false;
832 boolean hasValidWCNSEC = false;
833 SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
834 List<NSEC3Record> nsec3s = null;
835 Name nsec3Signer = null;
837 for (int i = 0; i < rrsets.length; i++) {
838 int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
840 if (status != SecurityStatus.SECURE) {
841 log.debug("NameError response has failed AUTHORITY rrset: "
843 m.setStatus(SecurityStatus.BOGUS);
848 if (rrsets[i].getType() == Type.NSEC) {
849 NSECRecord nsec = (NSECRecord) rrsets[i].first();
851 if (ValUtils.nsecProvesNameError(nsec, qname, rrsets[i]
856 if (ValUtils.nsecProvesNoWC(nsec, qname, rrsets[i]
858 hasValidWCNSEC = true;
862 if (rrsets[i].getType() == Type.NSEC3) {
863 if (nsec3s == null) {
864 nsec3s = new ArrayList<NSEC3Record>();
867 nsec3s.add((NSEC3Record) rrsets[i].first());
868 nsec3Signer = rrsets[i].getSignerName();
872 NSEC3ValUtils.stripUnknownAlgNSEC3s(nsec3s);
874 if ((nsec3s != null) && (nsec3s.size() > 0)) {
875 log.debug("Validating nxdomain: using NSEC3 records");
877 // Attempt to prove name error with nsec3 records.
878 if (NSEC3ValUtils.allNSEC3sIgnoreable(nsec3s, key_rrset, mVerifier)) {
879 // log.debug("all NSEC3s were validated but ignored.");
880 m.setStatus(SecurityStatus.INSECURE);
885 hasValidNSEC = NSEC3ValUtils.proveNameError(nsec3s, qname,
888 // Note that we assume that the NSEC3ValUtils proofs encompass the
889 // wildcard part of the proof.
890 hasValidWCNSEC = hasValidNSEC;
893 // If the message fails to prove either condition, it is bogus.
895 log.debug("NameError response has failed to prove: "
896 + "qname does not exist");
897 m.setStatus(SecurityStatus.BOGUS);
902 if (!hasValidWCNSEC) {
903 log.debug("NameError response has failed to prove: "
904 + "covering wildcard does not exist");
905 m.setStatus(SecurityStatus.BOGUS);
910 // Otherwise, we consider the message secure.
911 log.trace("successfully validated NAME ERROR response.");
912 m.setStatus(SecurityStatus.SECURE);
915 public byte validateMessage(SMessage message, Name zone) {
916 if (!zone.isAbsolute()) {
918 zone = Name.concatenate(zone, Name.root);
919 } catch (NameTooLongException e) {
922 return SecurityStatus.UNCHECKED;
926 // FIXME: it is unclear if we should actually normalize our responses
927 // Instead, maybe we should just fail if they are not normal?
928 message = normalize(message);
930 if (!needsValidation(message)) {
931 return SecurityStatus.UNCHECKED;
934 SRRset key_rrset = findKeys(message);
936 if (key_rrset == null) {
937 return SecurityStatus.BOGUS;
940 ValUtils.ResponseType subtype = ValUtils
941 .classifyResponse(message, zone);
945 log.trace("Validating a positive response");
946 validatePositiveResponse(message, key_rrset);
951 validateReferral(message, key_rrset);
956 log.trace("Validating a NODATA response");
957 validateNodataResponse(message, key_rrset);
962 log.trace("Validating a NXDOMAIN response");
963 validateNameErrorResponse(message, key_rrset);
968 log.trace("Validating a CNAME response");
969 validateCNAMEResponse(message, key_rrset);
974 log.trace("Validating a positive ANY response");
975 validateAnyResponse(message, key_rrset);
980 log.error("unhandled response subtype: " + subtype);
983 return message.getSecurityStatus().getStatus();
986 public byte validateMessage(Message message, String zone)
987 throws TextParseException {
988 SMessage sm = new SMessage(message);
989 Name z = Name.fromString(zone);
991 return validateMessage(sm, z);
994 public List<String> listTrustedKeys() {
995 return mTrustedKeys.listTrustAnchors();