1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include "mDNSEmbeddedAPI.h"
19 #include "DNSSECSupport.h"
20 #include "DNSCommon.h"
22 #include "CryptoAlg.h"
26 // Define DNSSEC_DISABLED to remove all the DNSSEC functionality
27 // and use the stub functions implemented later in this file.
29 #ifndef DNSSEC_DISABLED
31 //#define DNSSEC_DEBUG
34 #define debugdnssec LogMsg
36 #define debugdnssec debug_noop
39 // Implementation Notes
41 // The entry point to DNSSEC Verification is VerifySignature. This function is called from the "core" when
42 // the answer delivered to the application needs DNSSEC validation. If a question needs DNSSEC
43 // validation, "ValidationRequired" would be set. As we need to issue more queries to validate the
44 // original question, we create another question as part of the verification process (question is part of
45 // DNSSECVerifier). This question sets "ValidatingResponse" to distinguish itself from the original
46 // question. Without this, it will be a duplicate and never sent out. The "core" almost treats both the
47 // types identically (like adding EDNS0 option with DO bit etc.) except for a few differences. When RRSIGs
48 // are added to the cache, "ValidatingResponse" question gets called back as long as the typeCovered matches
49 // the question's qtype. See the comment in DNSSECRecordAnswersQuestion for the details. The other big
50 // difference is that "ValidationRequired" question kicks off the verification process by calling into
51 // "VerifySignature" whereas ValidationResponse don't do that as it gets callback for its questions.
53 // VerifySignature does not retain the original question that started the verification process. It just
54 // remembers the name and the type. It takes a snapshot of the cache at that instance which will be
55 // verified using DNSSEC. If the cache changes subsequently e.g., network change etc., it will be detected
56 // when the validation is completed. If there is a change, it will be revalidated.
58 // The verification flow looks like this:
60 // VerifySignature -> StartDNSSECVerification - GetAllRRSetsForVerification -> FinishDNSSECVerification -> VerifySignature
62 // Verification is a recursive process. It stops when we find a trust anchor or if we have recursed too deep.
64 // If the original question resulted in NODATA/NXDOMAIN error, there should have been NSECs as part of the response.
65 // These nsecs are cached along with the negative cache record. These are validated using ValidateWithNSECS called
66 // from Verifysignature.
68 // The flow in this case looks like this:
70 // VerifySignature -> ValidateWithNSECS -> {NoDataProof, NameErrorProof} -> VerifyNSECS -> StartDNSSECVerification
72 // Once the DNSSEC verification is started, it is similar to the previous flow described above. When the verification
73 // is done, DNSSECPositiveValidationCB or DNSSECNegativeValidationCB will be called which will then deliver the
74 // validation results to the original question that started the validation.
76 // Insecure proofs are done when the verification ends up bogus. The flow would look like this
78 // VerifySignature -> StartDNSSECVerification - GetAllRRSetsForVerification -> FinishDNSSECVerification -> DNSSECValidationCB
79 // {DNSSECPositiveValidationCB, DNSSECNegativeValidationCB} -> ProveInsecure -> VerifySignaure ->
81 // ProveInsecure finds the break in trust in a top-down fashion.
83 // Forward declaration
84 mDNSlocal void VerifySigCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
85 mDNSlocal mStatus TrustedKey(mDNS *const m, DNSSECVerifier *dv);
86 mDNSlocal mDNSBool TrustedKeyPresent(mDNS *const m, DNSSECVerifier *dv);
87 mDNSlocal mStatus ValidateDS(DNSSECVerifier *dv);
88 mDNSlocal void DNSSECNegativeValidationCB(mDNS *const m, DNSSECVerifier *dv, CacheGroup *cg, ResourceRecord *answer, DNSSECStatus status);
89 mDNSlocal RRVerifier* CopyRRVerifier(RRVerifier *from);
90 mDNSlocal void FreeDNSSECAuthChainInfo(AuthChain *ac);
92 // Currently we use this to convert a RRVerifier to resource record so that we can
93 // use the standard DNS utility functions
94 LargeCacheRecord largerec;
96 // Verification is a recursive process. We arbitrarily limit to 10 just to be cautious which should be
97 // removed in the future.
98 #define MAX_RECURSE_COUNT 10
100 // TTL (in seconds) when the DNSSEC status is Bogus
101 #define RR_BOGUS_TTL 60
103 // RFC 4034 Appendix B: Get the keyid of a DNS KEY. It is not transmitted
104 // explicitly on the wire.
106 // Note: This just helps narrow down the list of keys to look at. It is possible
107 // for two DNS keys to have the same ID i.e., key ID is not a unqiue tag
109 // 1st argument - the RDATA part of the DNSKEY RR
110 // 2nd argument - the RDLENGTH
112 mDNSlocal mDNSu32 keytag(mDNSu8 *key, mDNSu32 keysize)
117 // DST_ALG_RSAMD5 will be rejected automatically as the keytag
118 // is calculated wrongly
120 for (ac = 0, i = 0; i < keysize; ++i)
121 ac += (i & 1) ? key[i] : key[i] << 8;
122 ac += (ac >> 16) & 0xFFFF;
126 mDNSexport int DNSMemCmp(const mDNSu8 *const m1, const mDNSu8 *const m2, int len)
130 res = mDNSPlatformMemCmp(m1, m2, len);
132 return (res < 0 ? -1 : 1);
140 // For the purposes of DNS security, owner names are ordered by treating
141 // individual labels as unsigned left-justified octet strings. The
142 // absence of a octet sorts before a zero value octet, and uppercase
143 // US-ASCII letters are treated as if they were lowercase US-ASCII
146 // To compute the canonical ordering of a set of DNS names, start by
147 // sorting the names according to their most significant (rightmost)
148 // labels. For names in which the most significant label is identical,
149 // continue sorting according to their next most significant label, and
152 // Returns 0 if the names are same
153 // Returns -1 if d1 < d2
154 // Returns 1 if d1 > d2
156 // subdomain is set if there is at least one label match (starting from the end)
157 // and d1 has more labels than d2 e.g., a.b.com is a subdomain of b.com
159 mDNSexport int DNSSECCanonicalOrder(const domainname *const d1, const domainname *const d2, int *subdomain)
164 c1 = CountLabels(d1);
166 c2 = CountLabels(d2);
169 if (subdomain) *subdomain = 0;
171 // Compare as many labels as possible starting from the rightmost
172 count = c1 < c2 ? c1 : c2;
173 for (i = count; i > 0; i--)
176 int j, len, lena, lenb;
178 a = (mDNSu8 *)SkipLeadingLabels(d1, skip1);
179 b = (mDNSu8 *)SkipLeadingLabels(d2, skip2);
182 // Compare label by label. Note that "z" > "yak" because z > y, but z < za
183 // (lena - lenb check below) because 'za' has two characters. Hence compare the
184 // letters first and then compare the length of the label at the end.
185 len = lena < lenb ? lena : lenb;
187 for (j = 0; j < len; j++)
191 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
192 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
195 verbosedebugf("DNSSECCanonicalOrder: returning ac %c, bc %c", ac, bc);
196 return ((ac < bc) ? -1 : 1);
199 if ((lena - lenb) != 0)
201 verbosedebugf("DNSSECCanonicalOrder: returning lena %d lenb %d", lena, lenb);
202 return ((lena < lenb) ? -1 : 1);
205 // Continue with the next label
209 // We have compared label by label. Both of them are same if we are here.
211 // Two possibilities.
213 // 1) Both names have same number of labels. In that case, return zero.
214 // 2) The number of labels is not same. As zero label sorts before, names
215 // with more number of labels is greater.
217 // a.b.com is a subdomain of b.com
218 if ((c1 > c2) && subdomain)
221 verbosedebugf("DNSSECCanonicalOrder: returning c1 %d c2 %d\n", c1, c2);
223 return ((c1 < c2) ? -1 : 1);
228 // Initialize the question enough so that it can be answered from the cache using SameNameRecordAnswersQuestion or
229 // ResourceRecordAnswersQuestion.
230 mDNSexport void InitializeQuestion(mDNS *const m, DNSQuestion *question, mDNSInterfaceID InterfaceID, const domainname *qname,
231 mDNSu16 qtype, mDNSQuestionCallback *callback, void *context)
233 debugf("InitializeQuestion: Called for %##s (%s)", qname->c, DNSTypeName(qtype));
235 if (question->ThisQInterval != -1) mDNS_StopQuery(m, question);
237 mDNS_SetupQuestion(question, InterfaceID, qname, qtype, callback, context);
238 question->qnamehash = DomainNameHashValue(qname);
239 question->ValidatingResponse = mDNStrue;
241 // Need to hold the lock, as GetServerForQuestion (its callers) references m->timenow.
243 // We need to set the DNS server appropriately to match the question against the cache record.
244 // Though not all callers of this function need it, we always do it to keep it simple.
245 SetValidDNSServers(m, question);
246 question->qDNSServer = GetServerForQuestion(m, question);
249 // Make it look like unicast
250 question->TargetQID = onesID;
251 question->TimeoutQuestion = 1;
252 question->ReturnIntermed = 1;
253 // SetupQuestion sets LongLived if qtype == PTR
254 question->LongLived = 0;
257 mDNSexport DNSSECVerifier *AllocateDNSSECVerifier(mDNS *const m, const domainname *name, mDNSu16 rrtype, mDNSInterfaceID InterfaceID,
258 mDNSu8 ValidationRequired, DNSSECVerifierCallback dvcallback, mDNSQuestionCallback qcallback)
262 dv = (DNSSECVerifier *)mDNSPlatformMemAllocate(sizeof(DNSSECVerifier));
263 if (!dv) { LogMsg("AllocateDNSSECVerifier: ERROR!! memory alloc failed"); return mDNSNULL; }
264 mDNSPlatformMemZero(dv, sizeof(*dv));
266 LogDNSSEC("AllocateDNSSECVerifier called %p", dv);
268 // Remember the question's name and type so that when we are done processing all
269 // the verifications, we can trace the original question back
270 AssignDomainName(&dv->origName, name);
271 dv->origType = rrtype;
272 dv->InterfaceID = InterfaceID;
273 dv->DVCallback = dvcallback;
274 dv->q.ThisQInterval = -1;
276 // These two are used for Insecure proof if we end up doing it.
277 // -Value of ValidationRequired so that we know whether this is a secure or insecure validation
278 // -InsecureProofDone tells us whether the proof has been done or not
279 dv->ValidationRequired = ValidationRequired;
280 dv->InsecureProofDone = 0;
283 dv->StartTime = m->timenow;
285 // The verifier's question has to be initialized as some of the callers assume it
286 InitializeQuestion(m, &dv->q, InterfaceID, name, rrtype, qcallback, dv);
290 mDNSlocal AuthChain *AuthChainCopy(AuthChain *ae)
292 RRVerifier *rvfrom, **rvto;
293 AuthChain **prev = mDNSNULL;
294 AuthChain *retac = mDNSNULL;
300 ac = mDNSPlatformMemAllocate(sizeof(AuthChain));
303 LogMsg("AuthChainCopy: AuthChain alloc failure");
305 FreeDNSSECAuthChainInfo(retac);
316 while (rvfrom && rvto)
318 *rvto = CopyRRVerifier(rvfrom);
319 rvfrom = rvfrom->next;
320 rvto = &((*rvto)->next);
325 while (rvfrom && rvto)
327 *rvto = CopyRRVerifier(rvfrom);
328 rvfrom = rvfrom->next;
329 rvto = &((*rvto)->next);
334 while (rvfrom && rvto)
336 *rvto = CopyRRVerifier(rvfrom);
337 rvfrom = rvfrom->next;
338 rvto = &((*rvto)->next);
351 mDNSlocal void FreeDNSSECAuthChainInfo(AuthChain *ac)
357 LogDNSSEC("FreeDNSSECAuthChainInfo: called");
366 mDNSPlatformMemFree(rrset);
369 ac->rrset = mDNSNULL;
375 mDNSPlatformMemFree(rrset);
378 ac->rrsig = mDNSNULL;
384 mDNSPlatformMemFree(rrset);
389 mDNSPlatformMemFree(ac);
394 mDNSlocal void FreeDNSSECAuthChain(DNSSECVerifier *dv)
398 FreeDNSSECAuthChainInfo(dv->ac);
399 // if someone reuses the "dv", it will be initialized properly
404 FreeDNSSECAuthChainInfo(dv->saveac);
405 dv->saveac = mDNSNULL;
409 mDNSlocal void FreeAuthChain(mDNS *const m, void *context)
411 AuthChain *ac = (AuthChain *)context;
414 FreeDNSSECAuthChainInfo(ac);
417 mDNSlocal void FreeDNSSECVerifierRRSets(DNSSECVerifier *dv)
422 //debugdnssec("FreeDNSSECVerifierRRSets called %p", dv);
427 mDNSPlatformMemFree(rrset);
430 dv->rrset = mDNSNULL;
436 mDNSPlatformMemFree(rrset);
439 dv->rrsig = mDNSNULL;
445 mDNSPlatformMemFree(rrset);
450 rrset = dv->rrsigKey;
454 mDNSPlatformMemFree(rrset);
457 dv->rrsigKey = mDNSNULL;
463 mDNSPlatformMemFree(rrset);
467 rrset = dv->pendingNSEC;
471 mDNSPlatformMemFree(rrset);
474 dv->pendingNSEC = mDNSNULL;
477 mDNSexport void FreeDNSSECVerifier(mDNS *const m, DNSSECVerifier *dv)
479 LogDNSSEC("FreeDNSSECVerifier called %p", dv);
480 if (dv->q.ThisQInterval != -1)
481 mDNS_StopQuery(m, &dv->q);
482 FreeDNSSECVerifierRRSets(dv);
485 if (dv->ac || dv->saveac)
486 FreeDNSSECAuthChain(dv);
489 LogDNSSEC("FreeDNSSECVerifier freeing parent %p", dv->parent);
490 FreeDNSSECVerifier(m, dv->parent);
492 mDNSPlatformMemFree(dv);
495 mDNSlocal RRVerifier* CopyRRVerifier(RRVerifier *from)
499 r = mDNSPlatformMemAllocate(sizeof (RRVerifier) + from->rdlength);
502 LogMsg("CopyRRVerifier: memory failure");
505 mDNSPlatformMemCopy(r, from, sizeof(RRVerifier));
507 r->rdata = (mDNSu8*) ((mDNSu8 *)r + sizeof(RRVerifier));
508 mDNSPlatformMemCopy(r->rdata, from->rdata, r->rdlength);
512 mDNSexport RRVerifier* AllocateRRVerifier(const ResourceRecord *const rr, mStatus *status)
516 r = mDNSPlatformMemAllocate(sizeof (RRVerifier) + rr->rdlength);
519 LogMsg("AllocateRRVerifier: memory failure");
520 *status = mStatus_NoMemoryErr;
524 r->rrtype = rr->rrtype;
525 r->rrclass = rr->rrclass;
526 r->rroriginalttl = rr->rroriginalttl;
527 r->rdlength = rr->rdlength;
528 r->namehash = rr->namehash;
529 r->rdatahash = rr->rdatahash;
530 AssignDomainName(&r->name, rr->name);
531 r->rdata = (mDNSu8*) ((mDNSu8 *)r + sizeof(RRVerifier));
533 // When we parsed the DNS response in GeLargeResourceRecord, for some records, we parse them into
534 // host order so that the rest of the code does not have to bother with converting from network order
535 // to host order. For signature verification, we need them back in network order. For DNSSEC records
536 // like DNSKEY and DS, we just copy over the data both in GetLargeResourceRecord and putRData.
538 if (!putRData(mDNSNULL, r->rdata, r->rdata + rr->rdlength, rr))
540 LogMsg("AllocateRRVerifier: putRData failed");
541 *status = mStatus_BadParamErr;
544 *status = mStatus_NoError;
548 mDNSexport mStatus AddRRSetToVerifier(DNSSECVerifier *dv, const ResourceRecord *const rr, RRVerifier *rv, RRVerifierSet set)
556 r = AllocateRRVerifier(rr, &status);
557 if (!r) return status;
580 LogMsg("AddRRSetToVerifier: ERROR!! default case %d", set);
581 return mStatus_BadParamErr;
586 return mStatus_NoError;
589 // Validate the RRSIG. "type" tells which RRSIG that we are supposed to validate. We fetch RRSIG for
590 // the rrset (type is RRVS_rrsig) and RRSIG for the key (type is RRVS_rrsig_key).
591 mDNSexport void ValidateRRSIG(DNSSECVerifier *dv, RRVerifierSet type, const ResourceRecord *const rr)
595 rdataRRSig *rrsigRData = (rdataRRSig *)((mDNSu8 *)rr->rdata + sizeofRDataHeader);
597 if (type == RRVS_rrsig)
601 else if (type == RRVS_rrsig_key)
607 LogMsg("ValidateRRSIG: ERROR!! type not valid %d", type);
612 // For each authoritative RRset in a signed zone, there MUST be at least
613 // one RRSIG record that meets the following requirements:
615 // RRSet is defined by same name, class and type
617 // 1. The RRSIG RR and the RRset MUST have the same owner name and the same class.
618 if (!SameDomainName(&rv->name, rr->name) || (rr->rrclass != rv->rrclass))
620 debugdnssec("ValidateRRSIG: name mismatch or class mismatch");
624 // 2. The RRSIG RR's Type Covered field MUST equal the RRset's type.
625 if ((swap16(rrsigRData->typeCovered)) != rv->rrtype)
627 debugdnssec("ValidateRRSIG: typeCovered mismatch rrsig %d, rr type %d", swap16(rrsigRData->typeCovered), rv->rrtype);
631 // 3. The number of labels in the RRset owner name MUST be greater than or equal
632 // to the value in the RRSIG RR's Labels field.
633 if (rrsigRData->labels > CountLabels(&rv->name))
635 debugdnssec("ValidateRRSIG: labels count problem rrsig %d, rr %d", rrsigRData->labels, CountLabels(&rv->name));
639 // 4. The RRSIG RR's Signer's Name field MUST be the name of the zone that contains
640 // the RRset. For a stub resolver, this can't be done in a secure way. Hence we
641 // do it this way (discussed in dnsext mailing list)
646 case kDNSType_DNSKEY:
647 //Signed by the owner
648 if (!SameDomainName(&rv->name, (domainname *)&rrsigRData->signerName))
650 debugdnssec("ValidateRRSIG: Signer Name does not match the record name for %s", DNSTypeName(rv->rrtype));
655 // Should be signed by the parent
656 if (SameDomainName(&rv->name, (domainname *)&rrsigRData->signerName))
658 debugdnssec("ValidateRRSIG: Signer Name matches the record name for %s", DNSTypeName(rv->rrtype));
664 int c1 = CountLabels(&rv->name);
665 int c2 = CountLabels((domainname *)&rrsigRData->signerName);
668 debugdnssec("ValidateRRSIG: Signer Name not a subdomain label count %d < %d ", c1, c2);
671 domainname *d = (domainname *)SkipLeadingLabels(&rv->name, c1 - c2);
672 if (!SameDomainName(d, (domainname *)&rrsigRData->signerName))
674 debugdnssec("ValidateRRSIG: Signer Name not a subdomain");
681 // 5. The validator's notion of the current time MUST be less than or equal to the
682 // time listed in the RRSIG RR's Expiration field.
684 // 6. The validator's notion of the current time MUST be greater than or equal to the
685 // time listed in the RRSIG RR's Inception field.
686 currentTime = mDNSPlatformUTC();
688 if (DNS_SERIAL_LT(swap32(rrsigRData->sigExpireTime), currentTime))
690 LogDNSSEC("ValidateRRSIG: Expired: currentTime %d, ExpireTime %d", (int)currentTime,
691 swap32((int)rrsigRData->sigExpireTime));
694 if (DNS_SERIAL_LT(currentTime, swap32(rrsigRData->sigInceptTime)))
696 LogDNSSEC("ValidateRRSIG: Future: currentTime %d, InceptTime %d", (int)currentTime,
697 swap32((int)rrsigRData->sigInceptTime));
701 if (AddRRSetToVerifier(dv, rr, mDNSNULL, type) != mStatus_NoError)
703 LogMsg("ValidateRRSIG: ERROR!! cannot allocate RRSet");
708 mDNSlocal mStatus CheckRRSIGForRRSet(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
713 mDNSBool expectRRSIG = mDNSfalse;
718 LogMsg("CheckRRSIGForRRSet: ERROR!! rrset NULL for origName %##s (%s)", dv->origName.c,
719 DNSTypeName(dv->origType));
720 return mStatus_BadParamErr;
724 cg = CacheGroupForName(m, rv->namehash, &rv->name);
727 debugdnssec("CheckRRSIGForRRSet: cg null");
728 return mStatus_NoSuchRecord;
731 for (cr=cg->members; cr; cr=cr->next)
733 debugdnssec("CheckRRSIGForRRSet: checking the validity of rrsig");
734 if (cr->resrec.rrtype != kDNSType_RRSIG)
736 // Check to see if we should expect RRSIGs for the type that we are looking for.
737 // We would expect RRSIGs, if we had previously issued the question with the
738 // EDNS0/DOK bit set.
739 if (cr->resrec.rrtype == dv->rrset->rrtype)
741 expectRRSIG = cr->CRDNSSECQuestion;
742 LogDNSSEC("CheckRRSIGForRRSet: %s RRSIG for %s", (expectRRSIG ? "Expecting" : "Not Expecting"), CRDisplayString(m, cr));
746 if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
750 LogDNSSEC("CheckRRSIGForRRSet: Negative cache record %s encountered for %##s (%s)", CRDisplayString(m, cr),
751 rv->name.c, DNSTypeName(rv->rrtype));
756 LogMsg("CheckRRSIGForRRSet: ERROR!! Negative cache record %s already set for %##s (%s)", CRDisplayString(m, cr),
757 rv->name.c, DNSTypeName(rv->rrtype));
761 ValidateRRSIG(dv, RRVS_rrsig, &cr->resrec);
763 if (*negcr && dv->rrsig)
765 // Encountered both RRSIG and negative CR
766 LogMsg("CheckRRSIGForRRSet: ERROR!! Encountered negative cache record %s and RRSIG for %##s (%s)",
767 CRDisplayString(m, *negcr), rv->name.c, DNSTypeName(rv->rrtype));
768 return mStatus_BadParamErr;
770 // If we can't find RRSIGs, but we find a negative response then we need to validate that
771 // which the caller will do it. Otherwise, if we should be expecting RRSIGs to be in the
772 // cache already, then return error.
773 if (dv->rrsig || *negcr)
774 return mStatus_NoError;
775 else if (expectRRSIG)
776 return mStatus_BadParamErr;
778 return mStatus_NoSuchRecord;
781 mDNSlocal void CheckOneKeyForRRSIG(DNSSECVerifier *dv, const ResourceRecord *const rr)
787 LogMsg("CheckOneKeyForRRSIG: ERROR!! rrsig NULL");
790 rrsig = (rdataRRSig *)dv->rrsig->rdata;
791 if (!SameDomainName((domainname *)&rrsig->signerName, rr->name))
793 debugdnssec("CheckOneKeyForRRSIG: name mismatch");
797 // We store all the keys including the ZSK and KSK and use them appropriately
799 if (AddRRSetToVerifier(dv, rr, mDNSNULL, RRVS_key) != mStatus_NoError)
801 LogMsg("CheckOneKeyForRRSIG: ERROR!! cannot allocate RRSet");
806 mDNSlocal mStatus CheckKeyForRRSIG(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
817 LogMsg("CheckKeyForRRSIG: ERROR!! rrsig NULL");
818 return mStatus_BadParamErr;
821 // Signer name should be the same on all rrsig ??
822 rrsig = (rdataRRSig *)dv->rrsig->rdata;
823 name = (domainname *)&rrsig->signerName;
825 namehash = DomainNameHashValue(name);
826 cg = CacheGroupForName(m, namehash, name);
829 debugdnssec("CheckKeyForRRSIG: cg null for %##s", name->c);
830 return mStatus_NoSuchRecord;
833 for (cr=cg->members; cr; cr=cr->next)
835 if (cr->resrec.rrtype != kDNSType_DNSKEY) continue;
836 if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
840 LogDNSSEC("CheckKeyForRRSIG: Negative cache record %s encountered for %##s (DNSKEY)", CRDisplayString(m, cr),
846 LogMsg("CheckKeyForRRSIG: ERROR!! Negative cache record %s already set for %##s (DNSKEY)", CRDisplayString(m, cr),
851 debugdnssec("CheckKeyForRRSIG: checking the validity of key record");
852 CheckOneKeyForRRSIG(dv, &cr->resrec);
854 if (*negcr && dv->key)
856 // Encountered both RRSIG and negative CR
857 LogMsg("CheckKeyForRRSIG: ERROR!! Encountered negative cache record %s and DNSKEY for %##s",
858 CRDisplayString(m, *negcr), name->c);
859 return mStatus_BadParamErr;
861 if (dv->key || *negcr)
862 return mStatus_NoError;
864 return mStatus_NoSuchRecord;
867 mDNSlocal void CheckOneRRSIGForKey(DNSSECVerifier *dv, const ResourceRecord *const rr)
872 LogMsg("CheckOneRRSIGForKey: ERROR!! rrsig NULL");
875 rrsig = (rdataRRSig *)dv->rrsig->rdata;
876 if (!SameDomainName((domainname *)&rrsig->signerName, rr->name))
878 debugdnssec("CheckOneRRSIGForKey: name mismatch");
881 ValidateRRSIG(dv, RRVS_rrsig_key, rr);
884 mDNSlocal mStatus CheckRRSIGForKey(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
891 mDNSBool expectRRSIG = mDNSfalse;
896 LogMsg("CheckRRSIGForKey: ERROR!! rrsig NULL");
897 return mStatus_BadParamErr;
901 LogMsg("CheckRRSIGForKey: ERROR!! key NULL");
902 return mStatus_BadParamErr;
904 rrsig = (rdataRRSig *)dv->rrsig->rdata;
905 name = (domainname *)&rrsig->signerName;
907 namehash = DomainNameHashValue(name);
908 cg = CacheGroupForName(m, namehash, name);
911 debugdnssec("CheckRRSIGForKey: cg null %##s", name->c);
912 return mStatus_NoSuchRecord;
914 for (cr=cg->members; cr; cr=cr->next)
916 if (cr->resrec.rrtype != kDNSType_RRSIG)
918 // Check to see if we should expect RRSIGs for the DNSKEY record that we are
919 // looking for. We would expect RRSIGs, if we had previously issued the question
920 // with the EDNS0/DOK bit set.
921 if (cr->resrec.rrtype == kDNSType_DNSKEY)
923 expectRRSIG = cr->CRDNSSECQuestion;
924 LogDNSSEC("CheckRRSIGForKey: %s RRSIG for %s", (expectRRSIG ? "Expecting" : "Not Expecting"), CRDisplayString(m, cr));
928 if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
932 LogDNSSEC("CheckRRSIGForKey: Negative cache record %s encountered for %##s (RRSIG)", CRDisplayString(m, cr),
938 LogMsg("CheckRRSIGForKey: ERROR!! Negative cache record %s already set for %##s (RRSIG)", CRDisplayString(m, cr),
943 debugdnssec("CheckRRSIGForKey: checking the validity of rrsig");
944 CheckOneRRSIGForKey(dv, &cr->resrec);
946 if (*negcr && dv->rrsigKey)
948 // Encountered both RRSIG and negative CR
949 LogMsg("CheckRRSIGForKey: ERROR!! Encountered negative cache record %s and DNSKEY for %##s",
950 CRDisplayString(m, *negcr), name->c);
951 return mStatus_BadParamErr;
953 // If we can't find RRSIGs, but we find a negative response then we need to validate that
954 // which the caller will do it. Finally, make sure that we are not expecting RRSIGS.
955 if (dv->rrsigKey || *negcr)
956 return mStatus_NoError;
957 else if (expectRRSIG)
958 return mStatus_BadParamErr;
960 return mStatus_NoSuchRecord;
963 mDNSlocal void CheckOneDSForKey(DNSSECVerifier *dv, const ResourceRecord *const rr)
973 LogMsg("CheckOneDSForKey: ERROR!! rrsig NULL");
976 rrsig = (rdataRRSig *)dv->rrsig->rdata;
977 DS = (rdataDS *)((mDNSu8 *)rr->rdata + sizeofRDataHeader);
979 if (!SameDomainName((domainname *)&rrsig->signerName, rr->name))
981 debugdnssec("CheckOneDSForKey: name mismatch");
984 for (keyv = dv->key; keyv; keyv = keyv->next)
986 key = (rdataDNSKey *)keyv->rdata;
987 tag = (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength);
988 if (tag != swap16(DS->keyTag))
990 debugdnssec("CheckOneDSForKey: keyTag mismatch keyTag %d, DStag %d", tag, swap16(DS->keyTag));
993 if (key->alg != DS->alg)
995 debugdnssec("CheckOneDSForKey: alg mismatch key alg%d, DS alg %d", key->alg, swap16(DS->alg));
998 if (AddRRSetToVerifier(dv, rr, mDNSNULL, RRVS_ds) != mStatus_NoError)
1000 debugdnssec("CheckOneDSForKey: cannot allocate RRSet");
1005 mDNSlocal mStatus CheckDSForKey(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
1016 LogMsg("CheckDSForKey: ERROR!! rrsig NULL");
1017 return mStatus_BadParamErr;
1021 LogMsg("CheckDSForKey: ERROR!! key NULL");
1022 return mStatus_BadParamErr;
1024 rrsig = (rdataRRSig *)dv->rrsig->rdata;
1025 name = (domainname *)&rrsig->signerName;
1026 namehash = DomainNameHashValue(name);
1027 cg = CacheGroupForName(m, namehash, name);
1030 debugdnssec("CheckDSForKey: cg null for %s", name->c);
1031 return mStatus_NoSuchRecord;
1033 for (cr=cg->members; cr; cr=cr->next)
1035 if (cr->resrec.rrtype != kDNSType_DS) continue;
1036 if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
1040 LogDNSSEC("CheckDSForKey: Negative cache record %s encountered for %##s (DS)", CRDisplayString(m, cr),
1046 LogMsg("CheckDSForKey: ERROR!! Negative cache record %s already set for %##s (DS)", CRDisplayString(m, cr),
1051 CheckOneDSForKey(dv, &cr->resrec);
1053 if (*negcr && dv->ds)
1055 // Encountered both RRSIG and negative CR
1056 LogMsg("CheckDSForKey: ERROR!! Encountered negative cache record %s and DS for %##s",
1057 CRDisplayString(m, *negcr), name->c);
1058 return mStatus_BadParamErr;
1060 if (dv->ds || *negcr)
1061 return mStatus_NoError;
1063 return mStatus_NoSuchRecord;
1066 // It returns mDNStrue if we have all the rrsets for verification and mDNSfalse otherwise.
1067 mDNSlocal mDNSBool GetAllRRSetsForVerification(mDNS *const m, DNSSECVerifier *dv)
1075 LogMsg("GetAllRRSetsForVerification: ERROR!! rrset NULL");
1076 dv->DVCallback(m, dv, DNSSEC_Bogus);
1080 if (dv->next == RRVS_done) return mDNStrue;
1082 debugdnssec("GetAllRRSetsForVerification: next %d", dv->next);
1086 // If we can't find the RRSIG for the rrset, re-issue the query.
1088 // NOTE: It is possible that the cache might answer partially e.g., RRSIGs match qtype but the
1089 // whole set is not there. In that case the validation will fail. Ideally we should flush the
1090 // cache and reissue the query (TBD).
1091 err = CheckRRSIGForRRSet(m, dv, &negcr);
1092 if (err != mStatus_NoSuchRecord && err != mStatus_NoError)
1094 dv->DVCallback(m, dv, DNSSEC_Bogus);
1097 // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
1098 // looks in "dv->q" for the proof. Note that we have to use currQtype as the response could be
1099 // a CNAME and dv->rrset->rrtype would be set to CNAME and not the original question type that
1100 // resulted in CNAME.
1101 InitializeQuestion(m, &dv->q, dv->InterfaceID, &dv->rrset->name, dv->currQtype, VerifySigCallback, dv);
1102 // We may not have the NSECS if the previous query was a non-DNSSEC query
1103 if (negcr && negcr->nsec)
1105 ValidateWithNSECS(m, dv, negcr);
1109 dv->next = RRVS_key;
1112 // We already found the rrset to verify. Ideally we should just issue the query for the RRSIG. Unfortunately,
1113 // that does not work well as the response may not contain the RRSIG whose typeCovered matches the
1114 // rrset->rrtype (recursive server returns what is in its cache). Hence, we send the original query with the
1115 // DO bit set again to get the RRSIG. Normally this would happen if there was question which did not require
1116 // DNSSEC validation (ValidationRequied = 0) populated the cache and later when the ValidationRequired question
1117 // comes along, we need to get the RRSIGs. If we started off with ValidationRequired question we would have
1118 // already set the DO bit and not able to get RRSIGs e.g., bad CPE device, we would reissue the query here
1121 // Also, if it is a wildcard expanded answer, we need to issue the query with the original type for it to
1122 // elicit the right NSEC records. Just querying for RRSIG alone is not sufficient.
1124 // Note: For this to work, the core needs to deliver RRSIGs when they are added to the cache even if the
1125 // "qtype" is not RRSIG.
1126 debugdnssec("GetAllRRSetsForVerification: Fetching RRSIGS for RRSET");
1128 mDNS_StartQuery(m, &dv->q);
1131 // if we found the RRSIG, then fall through to find the DNSKEY
1133 err = CheckKeyForRRSIG(m, dv, &negcr);
1134 if (err != mStatus_NoSuchRecord && err != mStatus_NoError)
1136 dv->DVCallback(m, dv, DNSSEC_Bogus);
1139 // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
1140 // looks in "dv->q" for the proof.
1141 rrsig = (rdataRRSig *)dv->rrsig->rdata;
1142 InitializeQuestion(m, &dv->q, dv->InterfaceID, (domainname *)&rrsig->signerName, kDNSType_DNSKEY, VerifySigCallback, dv);
1143 // We may not have the NSECS if the previous query was a non-DNSSEC query
1144 if (negcr && negcr->nsec)
1146 ValidateWithNSECS(m, dv, negcr);
1150 dv->next = RRVS_rrsig_key;
1153 debugdnssec("GetAllRRSetsForVerification: Fetching DNSKEY for RRSET");
1155 mDNS_StartQuery(m, &dv->q);
1158 // if we found the DNSKEY, then fall through to find the RRSIG for the DNSKEY
1159 case RRVS_rrsig_key:
1160 err = CheckRRSIGForKey(m, dv, &negcr);
1161 // if we are falling through, then it is okay if we don't find the record
1162 if (err != mStatus_NoSuchRecord && err != mStatus_NoError)
1164 dv->DVCallback(m, dv, DNSSEC_Bogus);
1167 // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
1168 // looks in "dv->q" for the proof.
1169 rrsig = (rdataRRSig *)dv->rrsig->rdata;
1170 InitializeQuestion(m, &dv->q, dv->InterfaceID, (domainname *)&rrsig->signerName, kDNSType_DNSKEY, VerifySigCallback, dv);
1171 // We may not have the NSECS if the previous query was a non-DNSSEC query
1172 if (negcr && negcr->nsec)
1174 ValidateWithNSECS(m, dv, negcr);
1178 debugdnssec("GetAllRRSetsForVerification: RRVS_rrsig_key %p", dv->rrsigKey);
1181 debugdnssec("GetAllRRSetsForVerification: Fetching RRSIGS for DNSKEY");
1183 mDNS_StartQuery(m, &dv->q);
1186 // if we found RRSIG for the DNSKEY, then fall through to find the DS
1190 rrsig = (rdataRRSig *)dv->rrsig->rdata;
1191 qname = (domainname *)&rrsig->signerName;
1193 err = CheckDSForKey(m, dv, &negcr);
1194 if (err != mStatus_NoSuchRecord && err != mStatus_NoError)
1196 dv->DVCallback(m, dv, DNSSEC_Bogus);
1199 // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
1200 // looks in "dv->q" for the proof.
1201 InitializeQuestion(m, &dv->q, dv->InterfaceID, qname, kDNSType_DS, VerifySigCallback, dv);
1202 // We may not have the NSECS if the previous query was a non-DNSSEC query
1203 if (negcr && negcr->nsec)
1205 ValidateWithNSECS(m, dv, negcr);
1208 dv->next = RRVS_done;
1209 // If we have a trust anchor, then don't bother looking up the DS record
1210 if (!dv->ds && !TrustedKeyPresent(m, dv))
1212 // There is no DS for the root. Hence, if we don't have the trust
1213 // anchor for root, just fail.
1214 if (SameDomainName(qname, (const domainname *)"\000"))
1216 LogDNSSEC("GetAllRRSetsForVerification: Reached root");
1217 dv->DVCallback(m, dv, DNSSEC_Bogus);
1220 debugdnssec("GetAllRRSetsForVerification: Fetching DS");
1222 mDNS_StartQuery(m, &dv->q);
1227 debugdnssec("GetAllRRSetsForVerification: Skipped fetching the DS");
1232 LogMsg("GetAllRRSetsForVerification: ERROR!! unknown next %d", dv->next);
1233 dv->DVCallback(m, dv, DNSSEC_Bogus);
1239 mDNSlocal void PrintFixedSignInfo(rdataRRSig *rrsig, domainname *signerName, int sigNameLen, mDNSu8 *fixedPart, int fixedPartLen)
1242 char buf[RRSIG_FIXED_SIZE *3 + 1]; // 3 bytes count for %2x + 1 and the one byte for null at the end
1243 char sig[sigNameLen * 3 + 1];
1244 char fp[fixedPartLen * 3 + 1];
1248 for (j = 0; j < RRSIG_FIXED_SIZE; j++)
1249 length += mDNS_snprintf(buf+length, sizeof(buf) - length - 1, "%2x ", ((mDNSu8 *)rrsig)[j]);
1250 LogMsg("RRSIG(%d) %s", RRSIG_FIXED_SIZE, buf);
1254 for (j = 0; j < sigNameLen; j++)
1255 length += mDNS_snprintf(sig+length, sizeof(sig) - length - 1, "%2x ", signerName->c[j]);
1256 LogMsg("SIGNAME(%d) %s", sigNameLen, sig);
1259 for (j = 0; j < fixedPartLen; j++)
1260 length += mDNS_snprintf(fp+length, sizeof(fp) - length - 1, "%2x ", fixedPart[j]);
1261 LogMsg("fixedPart(%d) %s", fixedPartLen, fp);
1264 mDNSlocal void PrintVarSignInfo(mDNSu16 rdlen, mDNSu8 *rdata)
1268 unsigned int blen = swap16(rdlen);
1269 char buf[blen * 3 + 1]; // 3 bytes count for %2x + 1 and the one byte for null at the end
1274 r = (mDNSu8 *)&rdlen;
1275 for (j = 0; j < sizeof(mDNSu16); j++)
1276 length += mDNS_snprintf(buf+length, sizeof(buf) - length - 1, "%2x ", r[j]);
1277 LogMsg("RDLENGTH(%d) %s", sizeof(mDNSu16), buf);
1280 for (j = 0; j < blen; j++)
1281 length += mDNS_snprintf(buf+length, sizeof(buf) - length - 1, "%2x ", rdata[j]);
1282 LogMsg("RDATA(%d) %s", blen, buf);
1285 mDNSlocal void PrintVarSignInfo(mDNSu16 rdlen, mDNSu8 *rdata)
1290 mDNSlocal void PrintFixedSignInfo(rdataRRSig *rrsig, domainname *signerName, int sigNameLen, mDNSu8 *fixedPart, int fixedPartLen)
1300 // Used for RDATA comparison
1308 mDNSlocal int rdata_compare(mDNSu8 *const rdata1, mDNSu8 *const rdata2, int rdlen1, int rdlen2)
1313 len = (rdlen1 < rdlen2) ? rdlen1 : rdlen2;
1315 ret = DNSMemCmp(rdata1, rdata2, len);
1316 if (ret != 0) return ret;
1318 // RDATA is same at this stage. Consider them equal if they are of same length. Otherwise
1319 // decide based on their lengths.
1320 return ((rdlen1 == rdlen2) ? 0 : (rdlen1 < rdlen2) ? -1 : 1);
1323 mDNSlocal int name_compare(mDNSu8 *const rdata1, mDNSu8 *const rdata2, int rdlen1, int rdlen2)
1325 domainname *n1 = (domainname *)rdata1;
1326 domainname *n2 = (domainname *)rdata2;
1332 c1 = CountLabels(n1);
1333 c2 = CountLabels(n2);
1335 count = c1 < c2 ? c1 : c2;
1337 // We can't use SameDomainName as we need to know exactly which is greater/smaller
1338 // for sorting purposes. Hence, we need to compare label by label
1339 for (i = 0; i < count; i++)
1341 // Are the lengths same ?
1344 debugdnssec("compare_name: returning c1 %d, c2 %d", *a, *b);
1345 return ((*a < *b) ? -1 : 1);
1348 rdlen1 -= (len + 1);
1349 rdlen2 -= (len + 1);
1350 if (rdlen1 < 0 || rdlen2 < 0)
1352 LogMsg("name_compare: ERROR!! not enough data rdlen1 %d, rdlen2 %d", rdlen1, rdlen2);
1356 for (j = 0; j < len; j++)
1360 if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
1361 if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
1364 debugdnssec("compare_name: returning ac %c, bc %c", ac, bc);
1365 return ((ac < bc) ? -1 : 1);
1373 mDNSlocal int srv_compare(rdataComp *const r1, rdataComp *const r2)
1376 int length1, length2;
1378 length1 = r1->rdlength;
1379 length2 = r2->rdlength;
1380 // We should have at least priority, weight, port plus 1 byte
1381 if (length1 < 7 || length2 < 7)
1383 LogMsg("srv_compare: ERROR!! Length smaller than 7 bytes");
1386 // Compare priority, weight and port
1387 res = DNSMemCmp(r1->rdata, r2->rdata, 6);
1388 if (res != 0) return res;
1391 return (name_compare(r1->rdata + 6, r2->rdata + 6, length1, length2));
1394 mDNSlocal int tsig_compare(rdataComp *const r1, rdataComp *const r2)
1396 int offset1, offset2;
1397 int length1, length2;
1400 offset1 = offset2 = 0;
1401 length1 = r1->rdlength;
1402 length2 = r2->rdlength;
1404 // we should have at least one byte to start with
1405 if (length1 < 1 || length2 < 1)
1407 LogMsg("sig_compare: Length smaller than 18 bytes");
1411 res = name_compare(r1->rdata, r2->rdata, length1, length2);
1412 if (res != 0) return res;
1414 dlen = DomainNameLength((domainname *)r1->rdata);
1420 if (length1 <= 1 || length2 <= 1)
1422 LogMsg("tsig_compare: data too small to compare length1 %d, length2 %d", length1, length2);
1426 return (rdata_compare(r1->rdata + offset1, r2->rdata + offset2, length1, length2));
1429 // Compares types that conform to : <length><Value>
1430 mDNSlocal int lenval_compare(mDNSu8 *d1, mDNSu8 *d2, int *len1, int *len2, int rem1, int rem2)
1435 if (rem1 <= 1 || rem2 <= 1)
1437 LogMsg("lenval_compare: data too small to compare length1 %d, length2 %d", rem1, rem2);
1442 len = (*len1 < *len2 ? *len1 : *len2);
1443 res = DNSMemCmp(d1, d2, len + 1);
1447 // RFC 2915: Order (2) Preference(2) and variable length: Flags Service Regexp Replacement
1448 mDNSlocal int naptr_compare(rdataComp *const r1, rdataComp *const r2)
1450 mDNSu8 *d1 = r1->rdata;
1451 mDNSu8 *d2 = r2->rdata;
1452 int len1, len2, res;
1453 int length1, length2;
1455 length1 = r1->rdlength;
1456 length2 = r2->rdlength;
1458 // Order, Preference plus at least 1 byte
1459 if (length1 < 5 || length2 < 5)
1461 LogMsg("naptr_compare: Length smaller than 18 bytes");
1464 // Compare order and preference
1465 res = DNSMemCmp(d1, d2, 4);
1466 if (res != 0) return res;
1473 // Compare Flags (including the length byte)
1474 res = lenval_compare(d1, d2, &len1, &len2, length1, length2);
1475 if (res != 0) return res;
1478 length1 -= (len1 + 1);
1479 length2 -= (len2 + 1);
1481 // Compare Service (including the length byte)
1482 res = lenval_compare(d1, d2, &len1, &len2, length1, length2);
1483 if (res != 0) return res;
1486 length1 -= (len1 + 1);
1487 length2 -= (len2 + 1);
1489 // Compare regexp (including the length byte)
1490 res = lenval_compare(d1, d2, &len1, &len2, length1, length2);
1491 if (res != 0) return res;
1494 length1 -= (len1 + 1);
1495 length2 -= (len2 + 1);
1497 // Compare Replacement
1498 return name_compare(d1, d2, length1, length2);
1501 // RFC 1035: MINFO: Two domain names
1502 // RFC 1183: RP: Two domain names
1503 mDNSlocal int dom2_compare(mDNSu8 *d1, mDNSu8 *d2, int length1, int length2)
1507 // We need at least one byte to start with
1508 if (length1 < 1 || length2 < 1)
1510 LogMsg("dom2_compare:1: data too small length1 %d, length2 %d", length1, length2);
1513 res = name_compare(d1, d2, length1, length2);
1514 if (res != 0) return res;
1515 dlen = DomainNameLength((domainname *)d1);
1519 // We need at least one byte to start with
1520 if (length1 < 1 || length2 < 1)
1522 LogMsg("dom2_compare:2: data too small length1 %d, length2 %d", length1, length2);
1529 return name_compare(d1, d2, length1, length2);
1532 // MX : preference (2 bytes), domainname
1533 mDNSlocal int mx_compare(rdataComp *const r1, rdataComp *const r2)
1536 int length1, length2;
1538 length1 = r1->rdlength;
1539 length2 = r2->rdlength;
1541 // We need at least two bytes + 1 extra byte for the domainname to start with
1542 if (length1 < 3 || length2 < 3)
1544 LogMsg("mx_compare: data too small length1 %d, length2 %d", length1, length2);
1548 res = DNSMemCmp(r1->rdata, r2->rdata, 2);
1549 if (res != 0) return res;
1552 return name_compare(r1->rdata + 2, r2->rdata + 2, length1, length2);
1555 // RFC 2163 (PX) : preference (2 bytes), map822. mapx400 (domainnames)
1556 mDNSlocal int px_compare(rdataComp *const r1, rdataComp *const r2)
1560 // We need at least two bytes + 1 extra byte for the domainname to start with
1561 if (r1->rdlength < 3 || r2->rdlength < 3)
1563 LogMsg("px_compare: data too small length1 %d, length2 %d", r1->rdlength, r2->rdlength);
1567 res = DNSMemCmp(r1->rdata, r2->rdata, 2);
1568 if (res != 0) return res;
1570 return dom2_compare(r1->rdata + 2, r2->rdata + 2, r1->rdlength - 2, r2->rdlength - 2);
1573 mDNSlocal int soa_compare(rdataComp *r1, rdataComp *r2)
1576 int offset1, offset2;
1577 int length1, length2;
1579 length1 = r1->rdlength;
1580 length2 = r2->rdlength;
1581 offset1 = offset2 = 0;
1583 // We need at least 20 bytes plus 1 byte for each domainname
1584 if (length1 < 22 || length2 < 22)
1586 LogMsg("soa_compare:1: data too small length1 %d, length2 %d", length1, length2);
1590 // There are two domainnames followed by 20 bytes of serial, refresh, retry, expire and min
1591 // Compare the names and then the rest of the bytes
1593 res = name_compare(r1->rdata, r2->rdata, length1, length2);
1594 if (res != 0) return res;
1596 dlen = DomainNameLength((domainname *)r1->rdata);
1600 if (length1 < 1 || length2 < 1)
1602 LogMsg("soa_compare:2: data too small length1 %d, length2 %d", length1, length2);
1608 res = name_compare(r1->rdata + offset1, r2->rdata + offset2, length1, length2);
1609 if (res != 0) return res;
1611 dlen = DomainNameLength((domainname *)r1->rdata);
1614 if (length1 < 20 || length2 < 20)
1616 LogMsg("soa_compare:3: data too small length1 %d, length2 %d", length1, length2);
1622 return (rdata_compare(r1->rdata + offset1, r2->rdata + offset2, length1, length2));
1625 // RFC 4034 Section 6.0 states that:
1627 // A canonical RR form and ordering within an RRset are required in order to
1628 // construct and verify RRSIG RRs.
1630 // This function is called to order within an RRset. We can't just do a memcmp as
1631 // as stated in 6.3. This function is responsible for the third bullet in 6.2, where
1632 // the RDATA has to be converted to lower case if it has domain names.
1633 mDNSlocal int RDATACompare(const void *rdata1, const void *rdata2)
1635 rdataComp *r1 = (rdataComp *)rdata1;
1636 rdataComp *r2 = (rdataComp *)rdata2;
1638 if (r1->rrtype != r2->rrtype)
1640 LogMsg("RDATACompare: ERROR!! comparing rdata of wrong types type1: %d, type2: %d", r1->rrtype, r2->rrtype);
1645 case kDNSType_A: // 1. Address Record
1646 case kDNSType_NULL: // 10 NULL RR
1647 case kDNSType_WKS: // 11 Well-known-service
1648 case kDNSType_HINFO: // 13 Host information
1649 case kDNSType_TXT: // 16 Arbitrary text string
1650 case kDNSType_X25: // 19 X_25 calling address
1651 case kDNSType_ISDN: // 20 ISDN calling address
1652 case kDNSType_NSAP: // 22 NSAP address
1653 case kDNSType_KEY: // 25 Security key
1654 case kDNSType_GPOS: // 27 Geographical position (withdrawn)
1655 case kDNSType_AAAA: // 28 IPv6 Address
1656 case kDNSType_LOC: // 29 Location Information
1657 case kDNSType_EID: // 31 Endpoint identifier
1658 case kDNSType_NIMLOC: // 32 Nimrod Locator
1659 case kDNSType_ATMA: // 34 ATM Address
1660 case kDNSType_CERT: // 37 Certification record
1661 case kDNSType_A6: // 38 IPv6 Address (deprecated)
1662 case kDNSType_SINK: // 40 Kitchen sink (experimental)
1663 case kDNSType_OPT: // 41 EDNS0 option (meta-RR)
1664 case kDNSType_APL: // 42 Address Prefix List
1665 case kDNSType_DS: // 43 Delegation Signer
1666 case kDNSType_SSHFP: // 44 SSH Key Fingerprint
1667 case kDNSType_IPSECKEY: // 45 IPSECKEY
1668 case kDNSType_RRSIG: // 46 RRSIG
1669 case kDNSType_NSEC: // 47 Denial of Existence
1670 case kDNSType_DNSKEY: // 48 DNSKEY
1671 case kDNSType_DHCID: // 49 DHCP Client Identifier
1672 case kDNSType_NSEC3: // 50 Hashed Authenticated Denial of Existence
1673 case kDNSType_NSEC3PARAM: // 51 Hashed Authenticated Denial of Existence
1674 case kDNSType_HIP: // 55 Host Identity Protocol
1675 case kDNSType_SPF: // 99 Sender Policy Framework for E-Mail
1677 return rdata_compare(r1->rdata, r2->rdata, r1->rdlength, r2->rdlength);
1678 case kDNSType_NS: // 2 Name Server
1679 case kDNSType_MD: // 3 Mail Destination
1680 case kDNSType_MF: // 4 Mail Forwarder
1681 case kDNSType_CNAME: // 5 Canonical Name
1682 case kDNSType_MB: // 7 Mailbox
1683 case kDNSType_MG: // 8 Mail Group
1684 case kDNSType_MR: // 9 Mail Rename
1685 case kDNSType_PTR: // 12 Domain name pointer
1686 case kDNSType_NSAP_PTR: // 23 Reverse NSAP lookup (deprecated)
1687 case kDNSType_DNAME: // 39 Non-terminal DNAME (for IPv6)
1688 return name_compare(r1->rdata, r2->rdata, r1->rdlength, r2->rdlength);
1689 case kDNSType_SRV: // 33 Service record
1690 return srv_compare(r1, r2);
1691 case kDNSType_SOA: // 6 Start of Authority
1692 return soa_compare(r1, r2);
1694 case kDNSType_RP: // 17 Responsible person
1695 case kDNSType_MINFO: // 14 Mailbox information
1696 return dom2_compare(r1->rdata, r2->rdata, r1->rdlength, r2->rdlength);
1697 case kDNSType_MX: // 15 Mail Exchanger
1698 case kDNSType_AFSDB: // 18 AFS cell database
1699 case kDNSType_RT: // 21 Router
1700 case kDNSType_KX: // 36 Key Exchange
1701 return mx_compare(r1, r2);
1702 case kDNSType_PX: // 26 X.400 mail mapping
1703 return px_compare(r1, r2);
1704 case kDNSType_NAPTR: // 35 Naming Authority PoinTeR
1705 return naptr_compare(r1, r2);
1706 case kDNSType_TKEY: // 249 Transaction key
1707 case kDNSType_TSIG: // 250 Transaction signature
1708 // TSIG and TKEY have a domainname followed by data
1709 return tsig_compare(r1, r2);
1710 // TBD: We are comparing them as opaque types, perhaps not right
1711 case kDNSType_SIG: // 24 Security signature
1712 case kDNSType_NXT: // 30 Next domain (security)
1713 LogMsg("RDATACompare: WARNING!! explicit support has not been added, using default");
1714 return rdata_compare(r1->rdata, r2->rdata, r1->rdlength, r2->rdlength);
1720 // RFC 4034 section 6.2 requirement for verifying signature.
1722 // 3. if the type of the RR is NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
1723 // HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
1724 // SRV, DNAME, A6, RRSIG, or NSEC, all uppercase US-ASCII letters in
1725 // the DNS names contained within the RDATA are replaced by the
1726 // corresponding lowercase US-ASCII letters;
1728 // NSEC and HINFO is not needed as per dnssec-bis update. RRSIG is done elsewhere
1729 // as part of signature verification
1730 mDNSlocal void ConvertRDATAToCanonical(mDNSu16 rrtype, mDNSu16 rdlength, mDNSu8 *rdata)
1734 mDNSu8 *origRdata = rdata;
1736 // Ensure that we have at least one byte of data to examine and modify.
1738 if (!rdlength) { LogMsg("ConvertRDATAToCanonical: rdlength zero for rrtype %s", DNSTypeName(rrtype)); return; }
1742 // Not adding suppot for A6 as it is deprecated
1743 case kDNSType_A6: // 38 IPv6 Address (deprecated)
1745 debugdnssec("ConvertRDATAToCanonical: returning from default %s", DNSTypeName(rrtype));
1747 case kDNSType_NS: // 2 Name Server
1748 case kDNSType_MD: // 3 Mail Destination
1749 case kDNSType_MF: // 4 Mail Forwarder
1750 case kDNSType_CNAME: // 5 Canonical Name
1751 case kDNSType_MB: // 7 Mailbox
1752 case kDNSType_MG: // 8 Mail Group
1753 case kDNSType_MR: // 9 Mail Rename
1754 case kDNSType_PTR: // 12 Domain name pointer
1755 case kDNSType_DNAME: // 39 Non-terminal DNAME (for IPv6)
1756 case kDNSType_NXT: // 30 Next domain (security)
1758 // TSIG and TKEY are not mentioned in RFC 4034, but we just leave it here
1759 case kDNSType_TSIG: // 250 Transaction signature
1760 case kDNSType_TKEY: // 249 Transaction key
1762 if (DNSNameToLowerCase((domainname *)rdata, &name) != mStatus_NoError)
1764 LogMsg("ConvertRDATAToCanonical: ERROR!! DNSNameToLowerCase failed");
1767 AssignDomainName((domainname *)rdata, &name);
1769 case kDNSType_MX: // 15 Mail Exchanger
1770 case kDNSType_AFSDB: // 18 AFS cell database
1771 case kDNSType_RT: // 21 Router
1772 case kDNSType_KX: // 36 Key Exchange
1774 // format: preference - 2 bytes, followed by name
1775 // Ensure that we have at least 3 bytes (preference + 1 byte for the domain name)
1778 LogMsg("ConvertRDATAToCanonical:MX: rdlength %d for rrtype %s too small", rdlength, DNSTypeName(rrtype));
1781 if (DNSNameToLowerCase((domainname *)(rdata + 2), &name) != mStatus_NoError)
1783 LogMsg("ConvertRDATAToCanonical: MX: ERROR!! DNSNameToLowerCase failed");
1786 AssignDomainName((domainname *)(rdata + 2), &name);
1788 case kDNSType_SRV: // 33 Service record
1789 // format : priority, weight and port - 6 bytes, followed by name
1792 LogMsg("ConvertRDATAToCanonical:SRV: rdlength %d for rrtype %s too small", rdlength, DNSTypeName(rrtype));
1795 if (DNSNameToLowerCase((domainname *)(rdata + 6), &name) != mStatus_NoError)
1797 LogMsg("ConvertRDATAToCanonical: SRV: ERROR!! DNSNameToLowerCase failed");
1800 AssignDomainName((domainname *)(rdata + 6), &name);
1802 case kDNSType_PX: // 26 X.400 mail mapping
1805 LogMsg("ConvertRDATAToCanonical:PX: rdlength %d for rrtype %s too small", rdlength, DNSTypeName(rrtype));
1808 // Preference followed by two domain names
1811 case kDNSType_RP: // 17 Responsible person
1812 case kDNSType_SOA: // 6 Start of Authority
1813 case kDNSType_MINFO: // 14 Mailbox information
1814 if (DNSNameToLowerCase((domainname *)rdata, &name) != mStatus_NoError)
1816 LogMsg("ConvertRDATAToCanonical: SOA1: ERROR!! DNSNameToLowerCase failed");
1820 AssignDomainName((domainname *)rdata, &name);
1821 len = DomainNameLength((domainname *)rdata);
1822 if (rdlength <= len + 1)
1824 LogMsg("ConvertRDATAToCanonical:RP: rdlength %d for rrtype %s too small", rdlength, DNSTypeName(rrtype));
1829 if (DNSNameToLowerCase((domainname *)rdata, &name) != mStatus_NoError)
1831 LogMsg("ConvertRDATAToCanonical: SOA2: ERROR!! DNSNameToLowerCase failed");
1834 AssignDomainName((domainname *)rdata, &name);
1836 case kDNSType_NAPTR: // 35 Naming Authority Pointer
1837 // order and preference
1839 // Flags (including the length byte)
1840 rdata += (((int) rdata[0]) + 1);
1841 // Service (including the length byte)
1842 rdata += (((int) rdata[0]) + 1);
1843 // regexp (including the length byte)
1844 rdata += (((int) rdata[0]) + 1);
1846 // Replacement field is a domainname. If we have at least one more byte, then we are okay.
1847 if ((origRdata + rdlength) < rdata + 1)
1849 LogMsg("ConvertRDATAToCanonical:NAPTR: origRdata %p, rdlength %d, rdata %p for rrtype %s too small", origRdata, rdlength, rdata, DNSTypeName(rrtype));
1852 if (DNSNameToLowerCase((domainname *)rdata, &name) != mStatus_NoError)
1854 LogMsg("ConvertRDATAToCanonical: NAPTR2: ERROR!! DNSNameToLowerCase failed");
1857 AssignDomainName((domainname *)rdata, &name);
1858 case kDNSType_SIG: // 24 Security signature
1859 // format: <18 bytes> <domainname> <data>
1862 LogMsg("ConvertRDATAToCanonical:SIG: rdlength %d for rrtype %s too small", rdlength, DNSTypeName(rrtype));
1865 // Preference followed by two domain names
1867 if (DNSNameToLowerCase((domainname *)rdata, &name) != mStatus_NoError)
1869 LogMsg("ConvertRDATAToCanonical: SIG: ERROR!! DNSNameToLowerCase failed");
1872 AssignDomainName((domainname *)rdata, &name);
1877 mDNSlocal mDNSBool ValidateSignatureWithKey(DNSSECVerifier *dv, RRVerifier *rrset, RRVerifier *keyv, RRVerifier *sig)
1880 domainname signerName;
1882 mDNSu8 fixedPart[MAX_DOMAIN_NAME + 8]; // domainname + type + class + ttl
1886 rdataComp *ptr, *start, *p;
1895 key = (rdataDNSKey *)keyv->rdata;
1896 rrsig = (rdataRRSig *)sig->rdata;
1898 LogDNSSEC("ValidateSignatureWithKey: Validating signature with key with tag %d", (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength));
1900 if (DNSNameToLowerCase((domainname *)&rrsig->signerName, &signerName) != mStatus_NoError)
1902 LogMsg("ValidateSignatureWithKey: ERROR!! cannot convert signer name to lower case");
1906 if (DNSNameToLowerCase((domainname *)&rrset->name, &name) != mStatus_NoError)
1908 LogMsg("ValidateSignatureWithKey: ERROR!! cannot convert rrset name to lower case");
1912 sigNameLen = DomainNameLength(&signerName);
1913 labels = CountLabels(&name);
1914 // RFC 4034: RRSIG validation
1916 // signature = sign(RRSIG_RDATA | RR(1) | RR(2)... )
1918 // where RRSIG_RDATA excludes the signature and signer name in canonical form
1920 if (dv->ctx) AlgDestroy(dv->ctx);
1921 dv->ctx = AlgCreate(CRYPTO_ALG, rrsig->alg);
1924 LogDNSSEC("ValidateSignatureWithKey: ERROR!! No algorithm support for %d", rrsig->alg);
1927 AlgAdd(dv->ctx, (const mDNSu8 *)rrsig, RRSIG_FIXED_SIZE);
1928 AlgAdd(dv->ctx, signerName.c, sigNameLen);
1930 if (labels - rrsig->labels > 0)
1933 LogDNSSEC("ValidateSignatureWithKey: ====splitting labels %d, rrsig->labels %d====", labels,rrsig->labels);
1934 d = (domainname *)SkipLeadingLabels(&name, labels - rrsig->labels);
1937 AssignDomainName((domainname *)(fixedPart + 2), d);
1938 fixedPartLen = DomainNameLength(d) + 2;
1939 // See RFC 4034 section 3.1.3. If you are looking up *.example.com,
1940 // the labels count in the RRSIG is 2, but this is not considered as
1941 // a wildcard answer
1942 if (name.c[0] != 1 || name.c[1] != '*')
1944 LogDNSSEC("ValidateSignatureWithKey: Wildcard exapnded answer for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
1945 dv->flags |= WILDCARD_PROVES_ANSWER_EXPANDED;
1946 dv->wildcardName = (domainname *)SkipLeadingLabels(&dv->origName, labels - rrsig->labels);
1947 if (!dv->wildcardName) return mDNSfalse;
1952 debugdnssec("ValidateSignatureWithKey: assigning domainname");
1953 AssignDomainName((domainname *)fixedPart, &name);
1954 fixedPartLen = DomainNameLength(&name);
1956 temp = swap16(rrset->rrtype);
1957 mDNSPlatformMemCopy(fixedPart + fixedPartLen, (mDNSu8 *)&temp, sizeof(rrset->rrtype));
1958 fixedPartLen += sizeof(rrset->rrtype);
1959 temp = swap16(rrset->rrclass);
1960 mDNSPlatformMemCopy(fixedPart + fixedPartLen, (mDNSu8 *)&temp, sizeof(rrset->rrclass));
1961 fixedPartLen += sizeof(rrset->rrclass);
1962 mDNSPlatformMemCopy(fixedPart + fixedPartLen, (mDNSu8 *)&rrsig->origTTL, sizeof(rrsig->origTTL));
1963 fixedPartLen += sizeof(rrsig->origTTL);
1966 for (tmp = rrset, nrrsets = 0; tmp; tmp = tmp->next)
1970 start = ptr = mDNSPlatformMemAllocate(nrrsets * sizeof (rdataComp));
1971 debugdnssec("ValidateSignatureWithKey: start %p, nrrsets %d", start, nrrsets);
1974 // Need to initialize for failure case below
1975 mDNSPlatformMemZero(ptr, nrrsets * (sizeof (rdataComp)));
1978 ptr->rdlength = tmp->rdlength;
1979 ptr->rrtype = tmp->rrtype;
1982 ptr->rdata = mDNSPlatformMemAllocate(ptr->rdlength);
1985 mDNSPlatformMemCopy(ptr->rdata, tmp->rdata, tmp->rdlength);
1989 for (i = 0; i < nrrsets; i++)
1990 if (start[i].rdata) mDNSPlatformMemFree(start[i].rdata);
1991 mDNSPlatformMemFree(start);
1992 LogMsg("ValidateSignatureWithKey:1: ERROR!! RDATA memory alloation failure");
2002 LogMsg("ValidateSignatureWithKey:2: ERROR!! RDATA memory alloation failure");
2006 PrintFixedSignInfo(rrsig, &signerName, sigNameLen, fixedPart, fixedPartLen);
2008 mDNSPlatformQsort(start, nrrsets, sizeof(rdataComp), RDATACompare);
2009 for (p = start, i = 0; i < nrrsets; p++, i++)
2013 // The array is sorted and hence checking adjacent entries for duplicate is sufficient
2016 rdataComp *q = p - 1;
2017 if (!RDATACompare((void *)p, (void *)q)) continue;
2020 // Add the fixed part
2021 AlgAdd(dv->ctx, (const mDNSu8 *)fixedPart, fixedPartLen);
2024 rdlen = swap16(p->rdlength);
2025 AlgAdd(dv->ctx, (const mDNSu8 *)&rdlen, sizeof(mDNSu16));
2027 ConvertRDATAToCanonical(p->rrtype, p->rdlength, p->rdata);
2029 PrintVarSignInfo(rdlen, p->rdata);
2030 AlgAdd(dv->ctx, (const mDNSu8 *)p->rdata, p->rdlength);
2032 // free the memory as we don't need it anymore
2033 for (i = 0; i < nrrsets; i++)
2034 if (start[i].rdata) mDNSPlatformMemFree(start[i].rdata);
2035 mDNSPlatformMemFree(start);
2037 algRet = AlgVerify(dv->ctx, (mDNSu8 *)&key->data, keyv->rdlength - DNSKEY_FIXED_SIZE, (mDNSu8 *)(sig->rdata + sigNameLen + RRSIG_FIXED_SIZE), sig->rdlength - RRSIG_FIXED_SIZE - sigNameLen);
2038 AlgDestroy(dv->ctx);
2040 if (algRet != mStatus_NoError)
2042 LogDNSSEC("ValidateSignatureWithKey: AlgVerify failed for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
2043 // Reset the state if we set any above.
2044 if (dv->flags & WILDCARD_PROVES_ANSWER_EXPANDED)
2046 dv->flags &= ~WILDCARD_PROVES_ANSWER_EXPANDED;
2047 dv->wildcardName = mDNSNULL;
2054 // Walk all the keys and for each key walk all the RRSIGS that signs the original rrset
2055 mDNSlocal mStatus ValidateSignature(DNSSECVerifier *dv, RRVerifier **resultKey, RRVerifier **resultRRSIG)
2068 for (keyv = dv->key; keyv; keyv = keyv->next)
2070 key = (rdataDNSKey *)keyv->rdata;
2071 tag = (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength);
2072 for (rrsigv = sig; rrsigv; rrsigv = rrsigv->next)
2074 rrsig = (rdataRRSig *)rrsigv->rdata;
2075 // 7. The RRSIG RR's Signer's Name, Algorithm, and Key Tag fields MUST match the owner
2076 // name, algorithm, and key tag for some DNSKEY RR in the zone's apex DNSKEY RRset.
2077 if (!SameDomainName((domainname *)&rrsig->signerName, &keyv->name))
2079 debugdnssec("ValidateSignature: name mismatch");
2082 if (key->alg != rrsig->alg)
2084 debugdnssec("ValidateSignature: alg mismatch");
2087 if (tag != swap16(rrsig->keyTag))
2089 debugdnssec("ValidateSignature: keyTag mismatch rrsig tag %d(0x%x), keyTag %d(0x%x)", swap16(rrsig->keyTag),
2090 swap16(rrsig->keyTag), tag, tag);
2093 // 8. The matching DNSKEY RR MUST be present in the zone's apex DNSKEY RRset, and MUST
2094 // have the Zone Flag bit (DNSKEY RDATA Flag bit 7) set.
2095 if (!((swap16(key->flags)) & DNSKEY_ZONE_SIGN_KEY))
2097 debugdnssec("ValidateSignature: ZONE flag bit not set");
2100 debugdnssec("ValidateSignature:Found a key and RRSIG tag: %d", tag);
2101 if (ValidateSignatureWithKey(dv, rrset, keyv, rrsigv))
2103 LogDNSSEC("ValidateSignature: Validated successfully with key tag %d", tag);
2105 *resultRRSIG = rrsigv;
2106 return mStatus_NoError;
2110 *resultKey = mDNSNULL;
2111 *resultRRSIG = mDNSNULL;
2112 return mStatus_NoSuchRecord;
2115 mDNSlocal mDNSBool ValidateSignatureWithKeyForAllRRSigs(DNSSECVerifier *dv, RRVerifier *rrset, RRVerifier *keyv, RRVerifier *sig)
2122 rrsig = (rdataRRSig *)sig->rdata;
2123 tag = (mDNSu16)keytag(keyv->rdata, keyv->rdlength);
2124 if (tag == swap16(rrsig->keyTag))
2126 if (ValidateSignatureWithKey(dv, rrset, keyv, sig))
2128 LogDNSSEC("ValidateSignatureWithKeyForAllRRSigs: Validated");
2137 mDNSlocal mStatus ValidateDS(DNSSECVerifier *dv)
2149 rrsig = (rdataRRSig *)dv->rrsig->rdata;
2151 // Walk all the DS Records to see if we have a matching DNS KEY record that verifies
2152 // the hash. If we find one, verify that this key was used to sign the KEY rrsets in
2153 // this zone. Loop till we find one.
2154 for (dsv = dv->ds; dsv; dsv = dsv->next)
2156 ds = (rdataDS *)dsv->rdata;
2157 if ((ds->digestType != SHA1_DIGEST_TYPE) && (ds->digestType != SHA256_DIGEST_TYPE))
2159 LogDNSSEC("ValidateDS: Unsupported digest %d", ds->digestType);
2160 return mStatus_BadParamErr;
2162 else debugdnssec("ValidateDS: digest type %d", ds->digestType);
2163 for (keyv = dv->key; keyv; keyv = keyv->next)
2165 key = (rdataDNSKey *)keyv->rdata;
2166 mDNSu16 tag = (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength);
2167 if (tag != swap16(ds->keyTag))
2169 debugdnssec("ValidateDS:Not a valid keytag %d", tag);
2173 if (DNSNameToLowerCase((domainname *)&rrsig->signerName, &name) != mStatus_NoError)
2175 LogMsg("ValidateDS: ERROR!! cannot convert to lower case");
2179 if (dv->ctx) AlgDestroy(dv->ctx);
2180 dv->ctx = AlgCreate(DIGEST_ALG, ds->digestType);
2183 LogMsg("ValidateDS: ERROR!! Cannot allocate context");
2186 digest = (mDNSu8 *)&ds->digest;
2187 digestLen = dsv->rdlength - DS_FIXED_SIZE;
2189 AlgAdd(dv->ctx, name.c, DomainNameLength(&name));
2190 AlgAdd(dv->ctx, (const mDNSu8 *)key, keyv->rdlength);
2192 algRet = AlgVerify(dv->ctx, mDNSNULL, 0, digest, digestLen);
2193 AlgDestroy(dv->ctx);
2195 if (algRet == mStatus_NoError)
2197 LogDNSSEC("ValidateDS: DS Validated Successfully, need to verify the key %d", tag);
2198 // We found the DNS KEY that is authenticated by the DS in our parent zone. Check to see if this key
2199 // was used to sign the DNS KEY RRSET. If so, then the keys in our DNS KEY RRSET are valid
2200 if (ValidateSignatureWithKeyForAllRRSigs(dv, dv->key, keyv, dv->rrsigKey))
2202 LogDNSSEC("ValidateDS: DS Validated Successfully %d", tag);
2203 return mStatus_NoError;
2208 return mStatus_NoSuchRecord;
2211 mDNSlocal mDNSBool UnlinkRRVerifier(DNSSECVerifier *dv, RRVerifier *elem, RRVerifierSet set)
2226 case RRVS_rrsig_key:
2233 LogMsg("UnlinkRRVerifier: ERROR!! default case %d", set);
2236 while (*v && *v != elem)
2240 LogMsg("UnlinkRRVerifier: ERROR!! cannot find element in set %d", set);
2243 *v = elem->next; // Cut this record from the list
2244 elem->next = mDNSNULL;
2248 // This can link a single AuthChain element or a list of AuthChain elements to
2249 // DNSSECVerifier. The latter happens when we have multiple NSEC proofs and
2250 // we gather up all the proofs in one place.
2251 mDNSexport void AuthChainLink(DNSSECVerifier *dv, AuthChain *ae)
2255 LogDNSSEC("AuthChainLink: called");
2258 // Get to the last element
2261 *(dv->actail) = head; // Append this record to tail of auth chain
2262 dv->actail = &(ae->next); // Advance tail pointer
2265 mDNSlocal mDNSBool AuthChainAdd(DNSSECVerifier *dv, RRVerifier *resultKey, RRVerifier *resultRRSig)
2271 if (!dv->rrset || !resultKey || !resultRRSig)
2273 LogMsg("AuthChainAdd: ERROR!! input argument NULL");
2277 // Unlink resultKey and resultRRSig and store as part of AuthChain
2278 if (!UnlinkRRVerifier(dv, resultKey, RRVS_key))
2280 LogMsg("AuthChainAdd: ERROR!! cannot unlink key");
2283 if (!UnlinkRRVerifier(dv, resultRRSig, RRVS_rrsig))
2285 LogMsg("AuthChainAdd: ERROR!! cannot unlink rrsig");
2289 ae = mDNSPlatformMemAllocate(sizeof(AuthChain));
2292 LogMsg("AuthChainAdd: AuthChain alloc failure");
2296 ae->next = mDNSNULL;
2297 ae->rrset = dv->rrset;
2298 dv->rrset = mDNSNULL;
2300 ae->rrsig = resultRRSig;
2301 ae->key = resultKey;
2303 key = (rdataDNSKey *)resultKey->rdata;
2304 tag = (mDNSu16)keytag((mDNSu8 *)key, resultKey->rdlength);
2305 LogDNSSEC("AuthChainAdd: inserting AuthChain element with rrset %##s (%s), DNSKEY tag %d", ae->rrset->name.c, DNSTypeName(ae->rrset->rrtype), tag);
2307 AuthChainLink(dv, ae);
2311 // RFC 4035: Section 5.3.3
2313 // If the resolver accepts the RRset as authentic, the validator MUST set the TTL of
2314 // the RRSIG RR and each RR in the authenticated RRset to a value no greater than the
2317 // o the RRset's TTL as received in the response;
2319 // o the RRSIG RR's TTL as received in the response;
2321 // o the value in the RRSIG RR's Original TTL field; and
2323 // o the difference of the RRSIG RR's Signature Expiration time and the
2325 mDNSlocal void SetTTLRRSet(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status)
2327 DNSQuestion question;
2332 mDNSu32 rrTTL, rrsigTTL, rrsigOrigTTL, rrsigTimeTTL;
2335 CacheRecord *rrsigRR;
2338 debugdnssec("SetTTLRRSet called");
2340 if (status == DNSSEC_Insecure || status == DNSSEC_Indeterminate)
2342 LogDNSSEC("SetTTLRRSET: not setting ttl for status %s", DNSSECStatusName(status));
2350 mDNSPlatformMemZero(&question, sizeof(DNSQuestion));
2351 rrTTL = rrsigTTL = rrsigOrigTTL = rrsigTimeTTL = 0;
2353 // 1. Locate the rrset name and get its TTL (take the first one as a representative
2354 // of the rrset). Ideally, we should set the TTL on the first validation. Instead,
2355 // we do it whenever we validate which happens whenever a ValidationRequired question
2356 // finishes validation.
2357 qname = &dv->origName;
2358 qtype = dv->origType;
2360 question.ThisQInterval = -1;
2361 InitializeQuestion(m, &question, dv->InterfaceID, qname, qtype, mDNSNULL, mDNSNULL);
2362 cg = CacheGroupForName(m, question.qnamehash, &question.qname);
2366 LogMsg("SetTTLRRSet cg NULL for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
2370 for (rr = cg->members; rr; rr = rr->next)
2371 if (SameNameRecordAnswersQuestion(&rr->resrec, &question))
2373 // originalttl is never touched. The actual TTL is derived based on when it was
2375 rrTTL = rr->resrec.rroriginalttl - (now - rr->TimeRcvd)/mDNSPlatformOneSecond;
2379 // Should we check to see if it matches the record in dv->ac->rrset ?
2382 LogMsg("SetTTLRRSet: ERROR!! cannot locate main rrset for %##s (%s)", qname->c, DNSTypeName(qtype));
2387 // 2. Get the RRSIG ttl. For NSEC records we need to get the NSEC record's TTL as
2388 // the negative cache record that we created may not be right.
2390 if (dv->ac && dv->ac->rrsig)
2392 rrsigv = dv->ac->rrsig;
2393 rrsig = (rdataRRSig *)rrsigv->rdata;
2402 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative && status == DNSSEC_Secure)
2406 for (ncr = rr->nsec; ncr; ncr = ncr->next)
2408 if (ncr->resrec.rrtype == kDNSType_NSEC || ncr->resrec.rrtype == kDNSType_NSEC3)
2410 rrTTL = ncr->resrec.rroriginalttl - (now - ncr->TimeRcvd)/mDNSPlatformOneSecond;
2411 debugdnssec("SetTTLRRSet: NSEC TTL %u", rrTTL);
2413 // Note: we can't use dv->origName here as the NSEC record's RRSIG may not match
2414 // the original name
2415 if (rrsigv && ncr->resrec.rrtype == kDNSType_RRSIG && SameDomainName(ncr->resrec.name, &rrsigv->name))
2417 RDataBody2 *rdb = (RDataBody2 *)ncr->resrec.rdata->u.data;
2418 rdataRRSig *sig = (rdataRRSig *)rdb->data;
2419 if (rrsigv->rdlength != ncr->resrec.rdlength)
2421 debugdnssec("SetTTLRRSet length mismatch");
2424 if (mDNSPlatformMemSame(sig, rrsig, rrsigv->rdlength))
2426 mDNSu32 remain = (now - ncr->TimeRcvd)/mDNSPlatformOneSecond;
2427 rrsigTTL = ncr->resrec.rroriginalttl - remain;
2428 rrsigOrigTTL = swap32(rrsig->origTTL) - remain;
2429 rrsigTimeTTL = swap32(rrsig->sigExpireTime) - swap32(rrsig->sigInceptTime);
2432 if (rrTTL && (!rrsigv || rrsigTTL)) break;
2437 // Look for the matching RRSIG so that we can get its TTL
2438 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
2439 if (rr->resrec.rrtype == kDNSType_RRSIG && SameDomainName(rr->resrec.name, &rrsigv->name))
2441 RDataBody2 *rdb = (RDataBody2 *)rr->resrec.rdata->u.data;
2442 rdataRRSig *sig = (rdataRRSig *)rdb->data;
2443 if (rrsigv->rdlength != rr->resrec.rdlength)
2445 debugdnssec("SetTTLRRSet length mismatch");
2448 if (mDNSPlatformMemSame(sig, rrsig, rrsigv->rdlength))
2450 mDNSu32 remain = (now - rr->TimeRcvd)/mDNSPlatformOneSecond;
2451 rrsigTTL = rr->resrec.rroriginalttl - remain;
2452 rrsigOrigTTL = swap32(rrsig->origTTL) - remain;
2453 rrsigTimeTTL = swap32(rrsig->sigExpireTime) - swap32(rrsig->sigInceptTime);
2460 // It is possible that there are no RRSIGs and in that case it is not an error
2461 // to find the rrsigTTL.
2462 if (!rrTTL || (rrsigv && (!rrsigTTL || !rrsigOrigTTL || !rrsigTimeTTL)))
2464 LogDNSSEC("SetTTLRRSet: ERROR!! Bad TTL rrtl %u, rrsigTTL %u, rrsigOrigTTL %u, rrsigTimeTTL %u for %##s (%s)",
2465 rrTTL, rrsigTTL, rrsigOrigTTL, rrsigTimeTTL, qname->c, DNSTypeName(qtype));
2468 LogDNSSEC("SetTTLRRSet: TTL rrtl %u, rrsigTTL %u, rrsigOrigTTL %u, rrsigTimeTTL %u for %##s (%s)",
2469 rrTTL, rrsigTTL, rrsigOrigTTL, rrsigTimeTTL, qname->c, DNSTypeName(qtype));
2471 if (status == DNSSEC_Bogus)
2473 rrTTL = RR_BOGUS_TTL;
2474 LogDNSSEC("SetTTLRRSet: setting to bogus TTL %d", rrTTL);
2479 if (rrsigTTL < rrTTL)
2481 if (rrsigOrigTTL < rrTTL)
2482 rrTTL = rrsigOrigTTL;
2483 if (rrsigTimeTTL < rrTTL)
2484 rrTTL = rrsigTimeTTL;
2487 // Set the rrsig's TTL. For NSEC records, rrsigRR is NULL which means it expires when
2488 // the negative cache record expires.
2491 rrsigRR->resrec.rroriginalttl = rrTTL;
2492 rrsigRR->TimeRcvd = now;
2493 rrsigRR->UnansweredQueries = 0;
2496 // Find the RRset and set its TTL
2497 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
2499 if (SameNameRecordAnswersQuestion(&rr->resrec, &question))
2501 LogDNSSEC("SetTTLRRSet: Setting the TTL %d for %s, question %##s (%s)", rrTTL, CRDisplayString(m, rr),
2502 question.qname.c, DNSTypeName(rr->resrec.rrtype));
2503 rr->resrec.rroriginalttl = rrTTL;
2505 rr->UnansweredQueries = 0;
2506 SetNextCacheCheckTimeForRecord(m, rr);
2511 mDNSlocal void FinishDNSSECVerification(mDNS *const m, DNSSECVerifier *dv)
2513 RRVerifier *resultKey;
2514 RRVerifier *resultRRSig;
2516 LogDNSSEC("FinishDNSSECVerification: all rdata sets available for sig verification for %##s (%s)",
2517 dv->origName.c, DNSTypeName(dv->origType));
2519 // Stop outstanding query if one exists
2520 if (dv->q.ThisQInterval != -1)
2521 mDNS_StopQuery(m, &dv->q);
2522 if (ValidateSignature(dv, &resultKey, &resultRRSig) == mStatus_NoError)
2526 key = (rdataDNSKey *)resultKey->rdata;
2527 tag = (mDNSu16)keytag((mDNSu8 *)key, resultKey->rdlength);
2529 LogDNSSEC("FinishDNSSECVerification: RRSIG validated by DNSKEY tag %d, %##s (%s)", tag, dv->rrset->name.c,
2530 DNSTypeName(dv->rrset->rrtype));
2532 if (TrustedKey(m, dv) == mStatus_NoError)
2534 // Need to call this after we called TrustedKey, as AuthChainAdd
2535 // unlinks the resultKey and resultRRSig
2536 if (!AuthChainAdd(dv, resultKey, resultRRSig))
2538 dv->DVCallback(m, dv, DNSSEC_Bogus);
2541 // The callback will be called when NSEC verification is done.
2542 if ((dv->flags & WILDCARD_PROVES_ANSWER_EXPANDED))
2544 WildcardAnswerProof(m, dv);
2549 dv->DVCallback(m, dv, DNSSEC_Secure);
2553 if (!ValidateDS(dv))
2555 // Need to call this after we called ValidateDS, as AuthChainAdd
2556 // unlinks the resultKey and resultRRSig
2557 if (!AuthChainAdd(dv, resultKey, resultRRSig))
2559 dv->DVCallback(m, dv, DNSSEC_Bogus);
2562 FreeDNSSECVerifierRRSets(dv);
2564 if (dv->recursed < MAX_RECURSE_COUNT)
2566 LogDNSSEC("FinishDNSSECVerification: Recursion level %d for %##s (%s)", dv->recursed, dv->origName.c,
2567 DNSTypeName(dv->origType));
2568 VerifySignature(m, dv, &dv->q);
2574 LogDNSSEC("FinishDNSSECVerification: ValidateDS failed %##s (%s)", dv->rrset->name.c, DNSTypeName(dv->rrset->rrtype));
2575 dv->DVCallback(m, dv, DNSSEC_Bogus);
2581 LogDNSSEC("FinishDNSSECVerification: Could not validate the rrset %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
2582 dv->DVCallback(m, dv, DNSSEC_Bogus);
2587 mDNSexport void StartDNSSECVerification(mDNS *const m, void *context)
2590 DNSSECVerifier *dv = (DNSSECVerifier *)context;
2592 done = GetAllRRSetsForVerification(m, dv);
2595 if (dv->next != RRVS_done)
2596 LogMsg("StartDNSSECVerification: ERROR!! dv->next is not done");
2598 LogDNSSEC("StartDNSSECVerification: all rdata sets available for sig verification");
2599 FinishDNSSECVerification(m, dv);
2602 else debugdnssec("StartDNSSECVerification: all rdata sets not available for sig verification next %d", dv->next);
2605 mDNSexport char *DNSSECStatusName(DNSSECStatus status)
2609 case DNSSEC_Secure: return "Secure";
2610 case DNSSEC_Insecure: return "Insecure";
2611 case DNSSEC_Indeterminate: return "Indeterminate";
2612 case DNSSEC_Bogus: return "Bogus";
2613 default: return "Invalid";
2617 // We could not use GenerateNegativeResponse as it assumes m->CurrentQuestion to be set. Even if
2618 // we change that, we needs to fix its callers and so on. It is much simpler to call the callback.
2619 mDNSlocal void DeliverDNSSECStatus(mDNS *const m, DNSSECVerifier *dv, ResourceRecord *answer, DNSSECStatus status)
2622 // Can't use m->CurrentQuestion as it may already be in use
2623 if (m->ValidationQuestion)
2624 LogMsg("DeliverDNSSECStatus: ERROR!! m->ValidationQuestion already set: %##s (%s)",
2625 m->ValidationQuestion->qname.c, DNSTypeName(m->ValidationQuestion->qtype));
2627 BumpDNSSECStats(m, kStatsActionSet, kStatsTypeStatus, status);
2628 BumpDNSSECStats(m, kStatsActionSet, kStatsTypeExtraPackets, dv->NumPackets);
2630 BumpDNSSECStats(m, kStatsActionSet, kStatsTypeLatency, m->timenow - dv->StartTime);
2633 m->ValidationQuestion = m->Questions;
2634 while (m->ValidationQuestion && m->ValidationQuestion != m->NewQuestions)
2636 DNSQuestion *q = m->ValidationQuestion;
2638 if (q->ValidatingResponse || !q->ValidationRequired ||
2639 (q->ValidationState != DNSSECValInProgress) || !ResourceRecordAnswersQuestion(answer, q))
2641 m->ValidationQuestion = q->next;
2645 q->ValidationState = DNSSECValDone;
2646 q->ValidationStatus = status;
2648 MakeNegativeCacheRecord(m, &largerec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL);
2649 if (q->qtype == answer->rrtype || status != DNSSEC_Secure)
2651 LogDNSSEC("DeliverDNSSECStatus: Generating dnssec status %s for %##s (%s)", DNSSECStatusName(status),
2652 q->qname.c, DNSTypeName(q->qtype));
2653 if (q->QuestionCallback)
2655 if (q->DNSSECAuthInfo)
2656 FreeDNSSECAuthChainInfo((AuthChain *)q->DNSSECAuthInfo);
2657 q->DNSSECAuthInfo = AuthChainCopy(dv->ac);
2658 q->DAIFreeCallback = FreeAuthChain;
2659 q->QuestionCallback(m, q, &largerec.r.resrec, QC_dnssec);
2662 else if (FollowCNAME(q, answer, QC_add))
2664 LogDNSSEC("DeliverDNSSECStatus: Following CNAME dnssec status %s for %##s (%s)", DNSSECStatusName(status),
2665 q->qname.c, DNSTypeName(q->qtype));
2667 AnswerQuestionByFollowingCNAME(m, q, answer);
2671 if (m->ValidationQuestion == q) // If m->ValidationQuestion was not auto-advanced, do it ourselves now
2672 m->ValidationQuestion = q->next;
2674 m->ValidationQuestion = mDNSNULL;
2677 // There is no work to be done if we could not validate DNSSEC (as the actual response for
2678 // the query has already been delivered) except in the case of CNAMEs where we did not follow
2679 // CNAMEs until we finished the DNSSEC processing.
2680 mDNSlocal void DNSSECNoResponse(mDNS *const m, DNSSECVerifier *dv)
2685 ResourceRecord *answer = mDNSNULL;
2687 LogDNSSEC("DNSSECNoResponse: called");
2689 if (dv->ValidationRequired != DNSSEC_VALIDATION_SECURE_OPTIONAL)
2691 LogMsg("DNSSECNoResponse: ERROR!! ValidationRequired incorrect %d", dv->ValidationRequired);
2695 BumpDNSSECStats(m, kStatsActionSet, kStatsTypeStatus, DNSSEC_NoResponse);
2697 namehash = DomainNameHashValue(&dv->origName);
2699 cg = CacheGroupForName(m, namehash, &dv->origName);
2702 LogDNSSEC("DNSSECNoResponse: cg NULL for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
2706 InitializeQuestion(m, &dv->q, dv->InterfaceID, &dv->origName, dv->origType, mDNSNULL, mDNSNULL);
2708 // We don't have to reset ValidatingResponse (unlike in DeliverDNSSECStatus) as there are no
2709 // RRSIGs that can match the original question
2710 for (cr = cg->members; cr; cr = cr->next)
2712 if (SameNameRecordAnswersQuestion(&cr->resrec, &dv->q))
2714 answer = &cr->resrec;
2719 // It is not an error for things to disappear underneath
2722 LogDNSSEC("DNSSECNoResponse: answer NULL for %##s, %s", dv->origName.c, DNSTypeName(dv->origType));
2725 if (answer->rrtype == kDNSType_RRSIG)
2727 LogDNSSEC("DNSSECNoResponse: RRSIG present for %##s, %s", dv->origName.c, DNSTypeName(dv->origType));
2731 // Can't use m->CurrentQuestion as it may already be in use
2732 if (m->ValidationQuestion)
2733 LogMsg("DNSSECNoResponse: ERROR!! m->ValidationQuestion already set: %##s (%s)",
2734 m->ValidationQuestion->qname.c, DNSTypeName(m->ValidationQuestion->qtype));
2736 m->ValidationQuestion = m->Questions;
2737 while (m->ValidationQuestion && m->ValidationQuestion != m->NewQuestions)
2739 DNSQuestion *q = m->ValidationQuestion;
2741 if (q->ValidatingResponse || !q->ValidationRequired ||
2742 (q->ValidationState != DNSSECValInProgress) || !ResourceRecordAnswersQuestion(answer, q))
2744 m->ValidationQuestion = q->next;
2748 // If we could not validate e.g., zone was not signed or bad delegation etc.,
2749 // disable validation. Ideally, for long outstanding questions, we should try again when
2750 // we switch networks. But for now, keep it simple.
2752 // Note: If we followed a CNAME with no dnssec protection, it is even more important that
2753 // we disable validation as we don't want to deliver a "secure" dnssec response later e.g.,
2754 // it is possible that the CNAME is not secure but the address records are secure. In this
2755 // case, we don't want to deliver the secure response later as we followed a CNAME that was
2756 // not protected with DNSSEC.
2758 q->ValidationRequired = 0;
2759 q->ValidationState = DNSSECValNotRequired;
2761 if (FollowCNAME(q, answer, QC_add))
2763 LogDNSSEC("DNSSECNoResponse: Following CNAME for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2766 AnswerQuestionByFollowingCNAME(m, q, answer);
2770 if (m->ValidationQuestion == q) // If m->ValidationQuestion was not auto-advanced, do it ourselves now
2771 m->ValidationQuestion = q->next;
2773 m->ValidationQuestion = mDNSNULL;
2776 FreeDNSSECVerifier(m, dv);
2779 mDNSlocal void DNSSECPositiveValidationCB(mDNS *const m, DNSSECVerifier *dv, CacheGroup *cg, ResourceRecord *answer, DNSSECStatus status)
2784 mDNSu16 rrtype, rrclass;
2785 CacheRecord *const lrr = &largerec.r;
2787 LogDNSSEC("DNSSECPositiveValidationCB: called %s for %##s (%s)", DNSSECStatusName(status), dv->origName.c, DNSTypeName(dv->origType));
2790 // 1. Check to see if the rrset that was validated is the same as in cache. If they are not same,
2791 // this validation result is not valid. When the rrset changed while the validation was in
2792 // progress, the act of delivering the changed rrset again should have kicked off another
2795 // 2. Walk the question list to find the matching question. The original question that started
2796 // the DNSSEC verification may or may not be there. As long as there is a matching question
2797 // and waiting for the response, deliver the response.
2799 // 3. If we are answering with CNAME, it is time to follow the CNAME if the response is secure
2801 if (!dv->ac || status == DNSSEC_Insecure)
2803 // For Insecure status, the auth chain contains information about the trust
2804 // chain starting from the known trust anchor. The rrsets are not related to
2805 // the origName like in Bogus or Secure.
2807 LogMsg("DNSSECPositiveValidationCB: ERROR: answer NULL");
2813 LogMsg("DNSSECPositiveValidationCB: ERROR!! Validated RRSET NULL");
2817 rrset = dv->ac->rrset;
2818 rrtype = rrset->rrtype;
2819 rrclass = rrset->rrclass;
2821 lrr->resrec.name = &largerec.namestorage;
2823 for (rv = dv->ac->rrset; rv; rv = rv->next)
2826 // Check to see if we can find all the elements in the rrset
2827 for (cr = cg ? cg->members : mDNSNULL; cr; cr = cr->next)
2829 if (cr->resrec.rrtype == rrtype && cr->resrec.rrclass == rrclass)
2831 for (rv = dv->ac->rrset; rv; rv = rv->next)
2833 if (rv->rdlength == cr->resrec.rdlength && rv->rdatahash == cr->resrec.rdatahash)
2835 lrr->resrec.namehash = rv->namehash;
2836 lrr->resrec.rrtype = rv->rrtype;
2837 lrr->resrec.rrclass = rv->rrclass;
2838 lrr->resrec.rdata = (RData*)&lrr->smallrdatastorage;
2839 lrr->resrec.rdata->MaxRDLength = MaximumRDSize;
2841 // Convert the "rdata" to a suitable form before we can call SameRDataBody which expects
2842 // some of the resource records in host order and also domainnames fully expanded. We
2843 // converted the resource records into network order for verification purpose and hence
2844 // need to convert them back again before comparing them.
2845 if (!SetRData(mDNSNULL, rv->rdata, rv->rdata + rv->rdlength, &largerec, rv->rdlength))
2847 LogMsg("DNSSECPositiveValidationCB: SetRData failed for %##s (%s)", rv->name.c, DNSTypeName(rv->rrtype));
2849 else if (SameRDataBody(&cr->resrec, &lrr->resrec.rdata->u, SameDomainName))
2851 answer = &cr->resrec;
2859 // The validated rrset does not have the element in the cache, re-validate
2860 LogDNSSEC("DNSSECPositiveValidationCB: CacheRecord %s, not found in the validated set", CRDisplayString(m, cr));
2865 // Check to see if we have elements that were not in the cache
2866 for (rv = dv->ac->rrset; rv; rv = rv->next)
2870 // We had more elements in the validated set, re-validate
2871 LogDNSSEC("DNSSECPositiveValidationCB: Record %##s (%s) not found in the cache", rv->name.c, DNSTypeName(rv->rrtype));
2877 // It is not an error for things to disappear underneath
2880 LogDNSSEC("DNSSECPositiveValidationCB: answer NULL for %##s, %s", dv->origName.c, DNSTypeName(dv->origType));
2884 DeliverDNSSECStatus(m, dv, answer, status);
2885 SetTTLRRSet(m, dv, status);
2888 FreeDNSSECVerifier(m, dv);
2891 mDNSlocal void DNSSECNegativeValidationCB(mDNS *const m, DNSSECVerifier *dv, CacheGroup *cg, ResourceRecord *answer, DNSSECStatus status)
2895 mDNSu16 rrtype, rrclass;
2898 LogDNSSEC("DNSSECNegativeValidationCB: called %s for %##s (%s)", DNSSECStatusName(status), dv->origName.c, DNSTypeName(dv->origType));
2902 // When NSEC/NSEC3s validation is completed, it calls the parent's DVCallback with the
2903 // parent DNSSECVerifier which is the original one that started the verification. It itself
2904 // should not have a parent. If the NSEC/NSEC3 validation results in another NSEC/NSEC3
2905 // validation, it should chain up via the dv->parent all the way to the top.
2906 LogMsg("DNSSECNegativeValidationCB: ERROR!! dv->parent is set for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
2910 // 1. Locate the negative cache record and check the cached NSEC/NSEC3 records to see if it matches the
2911 // NSEC/NSEC3s that were valiated. If the cached NSEC/NSEC3s changed while the validation was in progress,
2912 // we ignore the validation results.
2914 // 2. Walk the question list to find the matching question. The original question that started
2915 // the DNSSEC verification may or may not be there. As long as there is a matching question
2916 // and waiting for the response, deliver the response.
2918 if (!dv->ac || status == DNSSEC_Insecure)
2920 // For Insecure status, the auth chain contains information about the trust
2921 // chain starting from the known trust anchor. The rrsets are not related to
2922 // the origName like in Bogus or Secure.
2924 LogMsg("DNSSECNegativeValidationCB: ERROR: answer NULL");
2930 LogMsg("DNSSECNegativeValidationCB: ERROR!! Validated RRSET NULL");
2934 rrtype = dv->origType;
2935 rrclass = dv->ac->rrset->rrclass;
2937 for (ac = dv->ac; ac; ac = ac->next)
2939 for (rv = ac->rrset; rv; rv = rv->next)
2941 if (rv->rrtype == kDNSType_NSEC || rv->rrtype == kDNSType_NSEC3)
2943 LogDNSSEC("DNSSECNegativeValidationCB: Record %p %##s (%s) marking zero", rv, rv->name.c, DNSTypeName(rv->rrtype));
2949 // Check to see if we can find all the elements in the rrset
2950 for (cr = cg->members; cr; cr = cr->next)
2952 if (cr->resrec.RecordType == kDNSRecordTypePacketNegative &&
2953 cr->resrec.rrtype == rrtype && cr->resrec.rrclass == rrclass)
2956 for (ncr = cr->nsec; ncr; ncr = ncr->next)
2958 // We have RRSIGs for the NSECs cached there too
2959 if (ncr->resrec.rrtype != kDNSType_NSEC && ncr->resrec.rrtype != kDNSType_NSEC3)
2961 for (ac = dv->ac; ac; ac = ac->next)
2963 for (rv = ac->rrset; rv; rv = rv->next)
2965 if ((rv->rrtype == kDNSType_NSEC || rv->rrtype == kDNSType_NSEC3) && rv->rdlength == ncr->resrec.rdlength &&
2966 rv->rdatahash == ncr->resrec.rdatahash)
2968 if (SameDomainName(ncr->resrec.name, &rv->name) &&
2969 SameRDataBody(&ncr->resrec, (const RDataBody *)rv->rdata, SameDomainName))
2971 LogDNSSEC("DNSSECNegativeValidationCB: Record %p %##s (%s) marking one", rv, rv->name.c, DNSTypeName(rv->rrtype));
2972 answer = &cr->resrec;
2984 // The validated rrset does not have the element in the cache, re-validate
2985 LogDNSSEC("DNSSECNegativeValidationCB: CacheRecord %s, not found in the validated set", CRDisplayString(m, cr));
2990 // Check to see if we have elements that were not in the cache
2991 for (ac = dv->ac; ac; ac = ac->next)
2993 for (rv = ac->rrset; rv; rv = rv->next)
2995 if (rv->rrtype == kDNSType_NSEC || rv->rrtype == kDNSType_NSEC3)
2999 // We had more elements in the validated set, re-validate
3000 LogDNSSEC("DNSSECNegativeValidationCB: Record %p %##s (%s) not found in the cache", rv, rv->name.c, DNSTypeName(rv->rrtype));
3009 // It is not an error for things to disappear underneath
3012 LogDNSSEC("DNSSECNegativeValidationCB: answer NULL for %##s, %s", dv->origName.c, DNSTypeName(dv->origType));
3016 DeliverDNSSECStatus(m, dv, answer, status);
3017 SetTTLRRSet(m, dv, status);
3020 FreeDNSSECVerifier(m, dv);
3023 mDNSlocal void DNSSECValidationCB(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status)
3029 LogDNSSEC("DNSSECValidationCB: called %s for %##s (%s)", DNSSECStatusName(status), dv->origName.c, DNSTypeName(dv->origType));
3031 // Currently, if we receive anything other than secure, we abort DNSSEC validation for
3032 // the optional case.
3033 if (dv->ValidationRequired == DNSSEC_VALIDATION_SECURE_OPTIONAL && status != DNSSEC_Secure)
3035 DNSSECNoResponse(m, dv);
3039 if (dv->ValidationRequired == DNSSEC_VALIDATION_SECURE && !dv->InsecureProofDone && status == DNSSEC_Bogus)
3041 dv->InsecureProofDone = 1;
3042 ProveInsecure(m, dv, mDNSNULL, mDNSNULL);
3045 namehash = DomainNameHashValue(&dv->origName);
3047 cg = CacheGroupForName(m, namehash, &dv->origName);
3050 LogDNSSEC("DNSSECValidationCB: cg NULL for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
3051 FreeDNSSECVerifier(m, dv);
3054 InitializeQuestion(m, &dv->q, dv->InterfaceID, &dv->origName, dv->origType, mDNSNULL, mDNSNULL);
3055 // Need to be reset ValidatingResponse as we are looking for the cache record that would answer
3056 // the original question
3057 dv->q.ValidatingResponse = mDNSfalse;
3058 for (cr = cg->members; cr; cr = cr->next)
3060 if (SameNameRecordAnswersQuestion(&cr->resrec, &dv->q))
3062 if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
3063 DNSSECNegativeValidationCB(m, dv, cg, &cr->resrec, status);
3065 DNSSECPositiveValidationCB(m, dv, cg, &cr->resrec, status);
3071 mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
3073 CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
3075 mDNSBool first = mDNSfalse;
3076 static mDNSBool TrustAnchorsUpdated = mDNSfalse;
3078 LogDNSSEC("VerifySignature called for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3079 if (!TrustAnchorsUpdated)
3081 TrustAnchorsUpdated = mDNStrue;
3082 UpdateTrustAnchors(m);
3087 if (!q->qDNSServer || q->qDNSServer->cellIntf)
3089 LogDNSSEC("VerifySignature: Disabled");
3092 // We assume that the verifier's question has been initialized here so that ValidateWithNSECS below
3093 // knows what it has prove the non-existence of.
3094 dv = AllocateDNSSECVerifier(m, &q->qname, q->qtype, q->InterfaceID, q->ValidationRequired, DNSSECValidationCB, VerifySigCallback);
3097 LogMsg("VerifySignature: ERROR!! memory alloc failed");
3102 // If we find a CNAME response to the question, remember what qtype
3103 // caused the CNAME response. origType is not sufficient as we
3104 // recursively validate the response and origType is initialized above
3105 // the first time this function is called.
3106 dv->currQtype = q->qtype;
3108 // Walk the cache and get all the rrsets for verification.
3109 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
3110 if (SameNameRecordAnswersQuestion(&rr->resrec, q))
3112 // We also get called for RRSIGs which matches qtype. We don't need that here as we are
3113 // building rrset for matching q->qname. Checking for RRSIG type is important as otherwise
3114 // we would miss the CNAME answering any qtype.
3115 if (rr->resrec.rrtype == kDNSType_RRSIG && rr->resrec.rrtype != q->qtype)
3117 LogDNSSEC("VerifySignature: Question %##s (%s) answered with RRSIG record %s, not using it", q->qname.c, DNSTypeName(q->qtype), CRDisplayString(m, rr));
3121 // See DNSSECRecordAnswersQuestion: This should never happen. NSEC records are
3122 // answered directly only when the qtype is NSEC. Otherwise, NSEC records are
3123 // used only for denial of existence and hence should go through negative cache
3125 if (rr->resrec.rrtype == kDNSType_NSEC && q->qtype != kDNSType_NSEC)
3127 LogMsg("VerifySignature: ERROR!! Question %##s (%s) answered using NSEC record %s", q->qname.c, DNSTypeName(q->qtype), CRDisplayString(m, rr));
3131 // We might get a NSEC response when we first send the query out from the "core" for ValidationRequired
3132 // questions. Later as part of validating the response, we might get a NSEC response.
3133 if (rr->resrec.RecordType == kDNSRecordTypePacketNegative && DNSSECQuestion(q))
3135 // If we can't find the NSEC, we can't validate. This can happens if we are
3136 // behind a non-DNSSEC aware CPE/server.
3139 LogDNSSEC("VerifySignature: No nsecs found for %s", CRDisplayString(m, rr));
3140 dv->DVCallback(m, dv, DNSSEC_Bogus);
3143 ValidateWithNSECS(m, dv, rr);
3147 if (AddRRSetToVerifier(dv, &rr->resrec, mDNSNULL, RRVS_rr) != mStatus_NoError)
3149 dv->DVCallback(m, dv, DNSSEC_Bogus);
3155 LogMsg("VerifySignature: rrset mDNSNULL for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
3156 dv->DVCallback(m, dv, DNSSEC_Bogus);
3159 dv->next = RRVS_rrsig;
3160 // Delay this so that the mDNS "core" can deliver all the results before
3161 // we can deliver the dnssec result
3164 mDNSPlatformDispatchAsync(m, dv, StartDNSSECVerification);
3168 StartDNSSECVerification(m, dv);
3172 mDNSlocal mDNSBool TrustedKeyPresent(mDNS *const m, DNSSECVerifier *dv)
3179 // Walk all our trusted DS Records to see if we have a matching DNS KEY record that verifies
3180 // the hash. If we find one, verify that this key was used to sign the KEY rrsets in
3181 // this zone. Loop till we find one.
3182 for (ta = m->TrustAnchors; ta; ta = ta->next)
3184 ds = (rdataDS *)&ta->rds;
3185 if ((ds->digestType != SHA1_DIGEST_TYPE) && (ds->digestType != SHA256_DIGEST_TYPE))
3187 LogMsg("TrustedKeyPresent: Unsupported digest %d", ds->digestType);
3192 debugdnssec("TrustedKeyPresent: digest type %d", ds->digestType);
3194 for (keyv = dv->key; keyv; keyv = keyv->next)
3196 key = (rdataDNSKey *)keyv->rdata;
3197 mDNSu16 tag = (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength);
3198 if (tag != ds->keyTag)
3200 debugdnssec("TrustedKeyPresent:Not a valid keytag %d", tag);
3203 if (!SameDomainName(&keyv->name, &ta->zone))
3205 debugdnssec("TrustedKeyPresent: domainame mismatch key %##s, ta %##s", keyv->name.c, ta->zone.c);
3214 mDNSlocal mStatus TrustedKey(mDNS *const m, DNSSECVerifier *dv)
3225 mDNSu32 currTime = mDNSPlatformUTC();
3227 rrsig = (rdataRRSig *)dv->rrsig->rdata;
3229 // Walk all our trusted DS Records to see if we have a matching DNS KEY record that verifies
3230 // the hash. If we find one, verify that this key was used to sign the KEY rrsets in
3231 // this zone. Loop till we find one.
3232 for (ta = m->TrustAnchors; ta; ta = ta->next)
3234 ds = (rdataDS *)&ta->rds;
3235 if ((ds->digestType != SHA1_DIGEST_TYPE) && (ds->digestType != SHA256_DIGEST_TYPE))
3237 LogMsg("TrustedKey: Unsupported digest %d", ds->digestType);
3242 debugdnssec("TrustedKey: Zone %##s, digest type %d, tag %d", ta->zone.c, ds->digestType, ds->keyTag);
3244 for (keyv = dv->key; keyv; keyv = keyv->next)
3246 key = (rdataDNSKey *)keyv->rdata;
3247 mDNSu16 tag = (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength);
3248 if (tag != ds->keyTag)
3250 debugdnssec("TrustedKey:Not a valid keytag %d", tag);
3253 if (!SameDomainName(&keyv->name, &ta->zone))
3255 debugdnssec("TrustedKey: domainame mismatch key %##s, ta %##s", keyv->name.c, ta->zone.c);
3258 if (DNS_SERIAL_LT(ta->validUntil, currTime))
3260 LogDNSSEC("TrustedKey: Expired: currentTime %d, ExpireTime %d", (int)currTime, ta->validUntil);
3263 if (DNS_SERIAL_LT(currTime, ta->validFrom))
3265 LogDNSSEC("TrustedKey: Future: currentTime %d, InceptTime %d", (int)currTime, ta->validFrom);
3269 if (DNSNameToLowerCase((domainname *)&rrsig->signerName, &name) != mStatus_NoError)
3271 LogMsg("TrustedKey: ERROR!! cannot convert to lower case");
3275 if (dv->ctx) AlgDestroy(dv->ctx);
3276 dv->ctx = AlgCreate(DIGEST_ALG, ds->digestType);
3279 LogMsg("TrustedKey: ERROR!! No digest support");
3282 digest = ds->digest;
3283 digestLen = ta->digestLen;
3285 AlgAdd(dv->ctx, name.c, DomainNameLength(&name));
3286 AlgAdd(dv->ctx, (const mDNSu8 *)key, keyv->rdlength);
3288 algRet = AlgVerify(dv->ctx, mDNSNULL, 0, digest, digestLen);
3289 AlgDestroy(dv->ctx);
3291 if (algRet == mStatus_NoError)
3293 LogDNSSEC("TrustedKey: DS Validated Successfully, need to verify the key %d", tag);
3294 // We found the DNS KEY that is authenticated by the DS in our parent zone. Check to see if this key
3295 // was used to sign the DNS KEY RRSET. If so, then the keys in our DNS KEY RRSET are valid
3296 if (ValidateSignatureWithKeyForAllRRSigs(dv, dv->key, keyv, dv->rrsigKey))
3298 LogDNSSEC("TrustedKey: DS Validated Successfully %d", tag);
3299 return mStatus_NoError;
3304 return mStatus_NoSuchRecord;
3307 mDNSlocal CacheRecord* NegativeCacheRecordForRR(mDNS *const m, const ResourceRecord *const rr)
3313 namehash = DomainNameHashValue(rr->name);
3314 cg = CacheGroupForName(m, namehash, rr->name);
3317 LogMsg("NegativeCacheRecordForRR: cg null %##s", rr->name->c);
3320 for (cr=cg->members; cr; cr=cr->next)
3322 if (cr->resrec.RecordType == kDNSRecordTypePacketNegative && (&cr->resrec == rr))
3328 mDNSlocal void VerifySigCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
3330 DNSSECVerifier *dv = (DNSSECVerifier *)question->QuestionContext;
3334 debugdnssec("VerifySigCallback: AddRecord %d, dv %p", AddRecord, dv);
3339 // After the first ADD event, we should ideally stop the question. If we don't stop
3340 // the question, we might get more callbacks and that can cause problems. For example,
3341 // in the first callback, we could start a insecure proof and while that is in progress,
3342 // if we get more callbacks, we will try to start another insecure proof. As we already
3343 // started an insecure proof, we won't start another but terminate the verification
3344 // process where we free the current DNSSECVerifier while the first insecure proof is
3345 // still referencing it.
3347 // But there are cases below which might return if we have not received the right answer
3348 // yet e.g., no RRSIGs. In that case if the question is stopped, we will never get any
3349 // callbacks again and also we leak "dv". Hence it is important that we either process
3350 // the result or wait for more results. Note that the question eventually times out
3351 // and cleans up the "dv" i.e., we don't wait forever.
3355 LogDNSSEC("VerifySigCallback: Question %##s (%s) no dnssec response", question->qname.c, DNSTypeName(question->qtype));
3356 mDNS_StopQuery(m, question);
3357 dv->DVCallback(m, dv, DNSSEC_Bogus);
3361 LogDNSSEC("VerifySigCallback(%p): Called with record %s for question %##s (%s)", dv, RRDisplayString(m, answer), question->qname.c,
3362 DNSTypeName(question->qtype));
3364 if ((m->timenow - question->StopTime) >= 0)
3367 LogDNSSEC("VerifySigCallback: Question %##s (%s) timed out", question->qname.c, DNSTypeName(question->qtype));
3368 mDNS_StopQuery(m, question);
3369 dv->DVCallback(m, dv, DNSSEC_Bogus);
3374 if (answer->RecordType == kDNSRecordTypePacketNegative)
3377 LogDNSSEC("VerifySigCallback: Received a negative answer with record %s, AddRecord %d",
3378 RRDisplayString(m, answer), AddRecord);
3379 mDNS_StopQuery(m, question);
3380 cr = NegativeCacheRecordForRR(m, answer);
3383 ValidateWithNSECS(m, dv, cr);
3388 LogDNSSEC("VerifySigCallback: Missing record (%s) Negative Cache Record %p", RRDisplayString(m, answer), cr);
3389 dv->DVCallback(m, dv, DNSSEC_Bogus);
3396 LogMsg("VerifySigCallback: ERROR!! rrset NULL");
3397 mDNS_StopQuery(m, question);
3398 dv->DVCallback(m, dv, DNSSEC_Bogus);
3402 rrtype = answer->rrtype;
3403 // Check whether we got any answers for the question. If there are no answers, we
3404 // can't do the verification.
3406 // We need to look at the whole rrset for verifying the signatures. This callback gets
3407 // called back for each record in the rrset sequentially and we won't know when to start the
3408 // verification. Hence, we look for all the records in the rrset ourselves using the
3409 // CheckXXX function below. The caller has to ensure that all the records in the rrset are
3410 // added to the cache before calling this callback which happens naturally because all
3411 // unicast records are marked for DelayDelivery and hence added to the cache before the
3412 // callback is done.
3414 // We also need the RRSIGs for the rrset to do the validation. It is possible that the
3415 // cache contains RRSIG records but it may not be a valid record when we filter them
3416 // in CheckXXX function. For example, some application can query for RRSIG records which
3417 // might come back with a partial set of RRSIG records from the recursive server and
3418 // they may not be the right ones for the current validation. In this case, we still
3419 // need to send the query out to get the right RRSIGs but the "core" should not answer
3420 // this query with the same records that we checked and found them to be unusable.
3422 // We handle this in two ways:
3424 // 1) AnswerNewQuestion always sends the "ValidatingResponse" query out bypassing the cache.
3426 // 2) DNSSECRecordAnswersQuestion does not answer a question with RRSIGs matching the
3427 // same name as the query until the typeCovered also matches the query's type.
3429 // NOTE: We use "next - 1" as next always points to what we are going to fetch next and not the one
3430 // we are fetching currently
3431 switch(dv->next - 1)
3434 // Verification always starts at RRVS_rrsig (which means dv->next points at RRVS_key) as verification does
3435 // not begin until we have the main rrset.
3436 LogDNSSEC("VerifySigCallback: ERROR!! rrset %##s dv->next is RRVS_rr", dv->rrset->name.c);
3439 // We can get called back with rrtype matching qtype as new records are added to the cache
3440 // triggered by other questions. This could potentially mean that the rrset that is being
3441 // validated by this "dv" whose rrsets were initialized at the beginning of the verification
3442 // may not be the right one. If this case happens, we will detect this at the end of validation
3443 // and throw away the validation results. This should not be a common case.
3444 if (rrtype != kDNSType_RRSIG)
3446 LogDNSSEC("VerifySigCallback: RRVS_rrsig called with %s", RRDisplayString(m, answer));
3449 mDNS_StopQuery(m, question);
3450 if (CheckRRSIGForRRSet(m, dv, &negcr) != mStatus_NoError)
3452 LogDNSSEC("VerifySigCallback: Unable to find RRSIG for %##s (%s), question %##s", dv->rrset->name.c,
3453 DNSTypeName(dv->rrset->rrtype), question->qname.c);
3454 dv->DVCallback(m, dv, DNSSEC_Bogus);
3459 // We are waiting for the DNSKEY record and hence dv->key should be NULL. If RRSIGs are being
3460 // returned first, ignore them for now.
3462 LogDNSSEC("VerifySigCallback: ERROR!! RRVS_key dv->key non-NULL for %##s", question->qname.c);
3463 if (rrtype == kDNSType_RRSIG)
3465 LogDNSSEC("VerifySigCallback: RRVS_key rrset type %s, %##s received before DNSKEY", DNSTypeName(rrtype), question->qname.c);
3468 if (rrtype != question->qtype)
3470 LogDNSSEC("VerifySigCallback: ERROR!! RRVS_key rrset type %s, %##s not matching qtype %d", DNSTypeName(rrtype), question->qname.c,
3474 mDNS_StopQuery(m, question);
3475 if (CheckKeyForRRSIG(m, dv, &negcr) != mStatus_NoError)
3477 LogDNSSEC("VerifySigCallback: Unable to find DNSKEY for %##s (%s), question %##s", dv->rrset->name.c,
3478 DNSTypeName(dv->rrset->rrtype), question->qname.c);
3479 dv->DVCallback(m, dv, DNSSEC_Bogus);
3483 case RRVS_rrsig_key:
3484 // If we are in RRVS_rrsig_key, it means that we already found the relevant DNSKEYs (dv->key should be non-NULL).
3485 // If DNSKEY record is being returned i.e., it means it is being added to the cache, then it can't be in our
3488 LogDNSSEC("VerifySigCallback: ERROR!! RRVS_rrsig_key dv->key NULL for %##s", question->qname.c);
3489 if (rrtype == question->qtype)
3491 LogDNSSEC("VerifySigCallback: RRVS_rrsig_key rrset type %s, %##s", DNSTypeName(rrtype), question->qname.c);
3492 CheckOneKeyForRRSIG(dv, answer);
3495 if (rrtype != kDNSType_RRSIG)
3497 LogDNSSEC("VerifySigCallback: RRVS_rrsig_key rrset type %s, %##s not matching qtype %d", DNSTypeName(rrtype), question->qname.c,
3501 mDNS_StopQuery(m, question);
3502 if (CheckRRSIGForKey(m, dv, &negcr) != mStatus_NoError)
3504 LogDNSSEC("VerifySigCallback: Unable to find RRSIG for %##s (%s), question %##s", dv->rrset->name.c,
3505 DNSTypeName(dv->rrset->rrtype), question->qname.c);
3506 dv->DVCallback(m, dv, DNSSEC_Bogus);
3511 if (rrtype == question->qtype)
3513 LogDNSSEC("VerifySigCallback: RRVS_ds rrset type %s, %##s", DNSTypeName(rrtype), question->qname.c);
3517 LogDNSSEC("VerifySigCallback: RRVS_ds rrset type %s, %##s received before DS", DNSTypeName(rrtype), question->qname.c);
3519 mDNS_StopQuery(m, question);
3520 // It is not an error if we don't find the DS record as we could have
3521 // a trusted key. Or this is not a secure delegation which will be handled
3523 if (CheckDSForKey(m, dv, &negcr) != mStatus_NoError)
3525 LogDNSSEC("VerifySigCallback: Unable find DS for %##s (%s), question %##s", dv->rrset->name.c,
3526 DNSTypeName(dv->rrset->rrtype), question->qname.c);
3528 // dv->next is already at RRVS_done, so if we "break" from here, we will end up
3529 // in FinishDNSSECVerification. We should not do that if we receive a negative
3530 // response. For all other cases above, GetAllRRSetsForVerification handles
3531 // negative cache record
3536 LogDNSSEC("VerifySigCallback: No nsec records for %##s (DS)", dv->ds->name.c);
3537 dv->DVCallback(m, dv, DNSSEC_Bogus);
3540 ValidateWithNSECS(m, dv, negcr);
3545 LogDNSSEC("VerifySigCallback: ERROR!! default case rrset %##s question %##s", dv->rrset->name.c, question->qname.c);
3546 mDNS_StopQuery(m, question);
3547 dv->DVCallback(m, dv, DNSSEC_Bogus);
3550 if (dv->next != RRVS_done)
3552 mDNSBool done = GetAllRRSetsForVerification(m, dv);
3555 if (dv->next != RRVS_done)
3556 LogMsg("VerifySigCallback ERROR!! dv->next is not done");
3558 LogDNSSEC("VerifySigCallback: all rdata sets available for sig verification");
3562 LogDNSSEC("VerifySigCallback: all rdata sets not available for sig verification");
3566 FinishDNSSECVerification(m, dv);
3569 mDNSlocal TrustAnchor *FindTrustAnchor(mDNS *const m, const domainname *const name)
3572 TrustAnchor *matchTA = mDNSNULL;
3573 TrustAnchor *rootTA = mDNSNULL;
3576 mDNSu32 currTime = mDNSPlatformUTC();
3578 for (ta = m->TrustAnchors; ta; ta = ta->next)
3580 if (DNS_SERIAL_LT(ta->validUntil, currTime))
3582 LogDNSSEC("FindTrustAnchor: Expired: currentTime %d, ExpireTime %d", (int)currTime, ta->validUntil);
3585 if (DNS_SERIAL_LT(currTime, ta->validFrom))
3587 LogDNSSEC("FindTrustAnchor: Future: currentTime %d, InceptTime %d", (int)currTime, ta->validFrom);
3591 if (SameDomainName((const domainname *)"\000", &ta->zone))
3594 match = CountLabelsMatch(&ta->zone, name);
3595 if (match > currmatch)
3603 LogDNSSEC("FindTrustAnhcor: matched %##s", matchTA->zone.c);
3608 LogDNSSEC("FindTrustAnhcor: matched rootTA %##s", rootTA->zone.c);
3613 LogDNSSEC("FindTrustAnhcor: No Trust Anchor");
3618 mDNSlocal void DeliverInsecureProofResultAsync(mDNS *const m, void *context)
3620 InsecureContext *ic = (InsecureContext *)context;
3621 ic->dv->DVCallback(m, ic->dv, ic->status);
3622 if (ic->q.ThisQInterval != -1)
3624 LogMsg("DeliverInsecureProofResultAsync: ERROR!! Question %##s (%s) not stopped already", ic->q.qname.c, DNSTypeName(ic->q.qtype));
3625 mDNS_StopQuery(m, &ic->q);
3627 mDNSPlatformMemFree(ic);
3630 mDNSlocal void DeliverInsecureProofResult(mDNS *const m, InsecureContext *ic, DNSSECStatus status)
3632 // If the status is Bogus, restore the original auth chain before the insecure
3634 if (status == DNSSEC_Bogus)
3636 LogDNSSEC("DeliverInsecureProofResult: Restoring the auth chain");
3639 FreeDNSSECAuthChainInfo(ic->dv->ac);
3641 ResetAuthChain(ic->dv);
3642 ic->dv->ac = ic->dv->saveac;
3645 AuthChain *tmp = ic->dv->ac;
3646 AuthChain **tail = &tmp->next;
3652 ic->dv->actail = tail;
3654 ic->dv->saveac = mDNSNULL;
3656 else if (ic->dv->saveac)
3658 FreeDNSSECAuthChainInfo(ic->dv->saveac);
3659 ic->dv->saveac = mDNSNULL;
3661 ic->status = status;
3662 // Stop the question before we schedule the block so that we don't receive additional
3663 // callbacks again. Once the block runs, it will free the "ic" and you can't
3664 // have another block queued up. This can happen if we receive a callback after we
3665 // queue the block below.
3666 if (ic->q.ThisQInterval != -1)
3667 mDNS_StopQuery(m, &ic->q);
3668 mDNSPlatformDispatchAsync(m, ic, DeliverInsecureProofResultAsync);
3671 mDNSlocal mDNSBool AlgorithmSupported(rdataDS *ds)
3673 switch(ds->digestType)
3675 case SHA1_DIGEST_TYPE:
3676 case SHA256_DIGEST_TYPE:
3679 LogDNSSEC("AlgorithmSupported: Unsupported digest %d", ds->digestType);
3685 case CRYPTO_RSA_NSEC3_SHA1:
3686 case CRYPTO_RSA_SHA1:
3687 case CRYPTO_RSA_SHA256:
3688 case CRYPTO_RSA_SHA512:
3691 LogDNSSEC("AlgorithmSupported: Unsupported algorithm %d", ds->alg);
3696 // Note: This function is called when DNSSEC results are delivered (from DeliverDNSSECStatus) and we can't deliver DNSSEC result
3697 // again within this function as "m->ValidationQuestion" is already in use. Hence we should dispatch off the delivery of insecure
3698 // results asynchronously.
3700 // Insecure proof callback can deliver either insecure or bogus, but never secure result.
3701 mDNSlocal void ProveInsecureCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
3703 InsecureContext *ic = (InsecureContext *)question->QuestionContext;
3704 DNSSECVerifier *pdv = ic->dv;
3713 if ((m->timenow - question->StopTime) >= 0)
3716 LogDNSSEC("ProveInsecureCallback: Question %##s (%s) timed out", question->qname.c, DNSTypeName(question->qtype));
3717 DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3722 // We only need to handle the actual DNSSEC results and the ones that are secure. Anything else results in
3724 if (AddRecord != QC_dnssec)
3726 LogDNSSEC("ProveInsecureCallback: Question %##s (%s), AddRecord %d, answer %s", question->qname.c,
3727 DNSTypeName(question->qtype), AddRecord, RRDisplayString(m, answer));
3731 LogDNSSEC("ProveInsecureCallback: ic %p Question %##s (%s), DNSSEC status %s", ic, question->qname.c, DNSTypeName(question->qtype),
3732 DNSSECStatusName(question->ValidationStatus));
3734 // Insecure is delivered for NSEC3 OptOut
3735 if (question->ValidationStatus != DNSSEC_Secure && question->ValidationStatus != DNSSEC_Insecure)
3737 LogDNSSEC("ProveInsecureCallback: Question %##s (%s) returned DNSSEC status %s", question->qname.c,
3738 DNSTypeName(question->qtype), DNSSECStatusName(question->ValidationStatus));
3741 ac = (AuthChain *)question->DNSSECAuthInfo;
3744 LogDNSSEC("ProveInsecureCallback: ac NULL for question %##s, %s", question->qname.c, DNSTypeName(question->qtype));
3749 LogDNSSEC("ProveInsecureCallback: ac->rrset NULL for question %##s, %s", question->qname.c, DNSTypeName(question->qtype));
3752 if (ac->rrset->rrtype != kDNSType_DS && ac->rrset->rrtype != kDNSType_NSEC && ac->rrset->rrtype != kDNSType_NSEC3)
3754 LogDNSSEC("ProveInsecureCallback: ac->rrset->rrtype %##s (%s) not handled", ac->rrset->name.c,
3755 DNSTypeName(ac->rrset->rrtype));
3758 AuthChainLink(pdv, ac);
3759 question->DNSSECAuthInfo = mDNSNULL;
3760 if (ac->rrset->rrtype == kDNSType_DS)
3762 rdataDS *ds = (rdataDS *)ac->rrset->rdata;
3764 // If the delegation is secure, but the underlying zone is signed with an unsupported
3765 // algorithm, then we can't verify it. Deliver insecure in that case.
3766 if (!AlgorithmSupported(ds))
3768 LogDNSSEC("ProveInsecureCallback: Unsupported algorithm %d or digest %d", ds->alg, ds->digestType);
3769 DeliverInsecureProofResult(m, ic, DNSSEC_Insecure);
3773 // If the delegation is secure and the name that we queried for is same as the original
3774 // name that started the insecure proof, then something is not right. We started the
3775 // insecure proof e.g., the zone is not signed, but we are able to validate a DS for
3776 // the same name which implies that the zone is signed (whose algorithm we support) and
3777 // we should not have started the insecurity proof in the first place.
3778 if (SameDomainName(&question->qname, &pdv->origName))
3780 LogDNSSEC("ProveInsecureCallback: Insecure proof reached original name %##s, error", question->qname.c);
3781 DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3785 LogDNSSEC("ProveInsecureCallback: Trying one more level down");
3786 ProveInsecure(m, pdv, ic, mDNSNULL);
3788 else if (ac->rrset->rrtype == kDNSType_NSEC || ac->rrset->rrtype == kDNSType_NSEC3)
3792 if (ac->rrset->rrtype == kDNSType_NSEC)
3793 cr = NSECRecordIsDelegation(m, &question->qname, question->qtype);
3795 cr = NSEC3RecordIsDelegation(m, &question->qname, question->qtype);
3798 LogDNSSEC("ProveInsecureCallback: Non-existence proved and %s is a delegation for %##s (%s)", CRDisplayString(m, cr),
3799 question->qname.c, DNSTypeName(question->qtype));
3800 DeliverInsecureProofResult(m, ic, DNSSEC_Insecure);
3803 // Could be a ENT. Go one more level down to see whether it is a secure delegation or not.
3804 if (!SameDomainName(&question->qname, &pdv->origName))
3806 LogDNSSEC("ProveInsecureCallback: Not a delegation %##s (%s), go one more level down", question->qname.c, DNSTypeName(question->qtype));
3807 ProveInsecure(m, pdv, ic, mDNSNULL);
3811 // Secure denial of existence and the name matches the original query. This means we should have
3812 // received an NSEC (if the type does not exist) or signed records (if the name and type exists)
3813 // and verified it successfully instead of starting the insecure proof. This could happen e.g.,
3814 // Wildcard expanded answer received without NSEC/NSEC3s etc. Also, is it possible that the
3815 // zone went from unsigned to signed in a short time ? For now, we return bogus.
3816 LogDNSSEC("ProveInsecureCallback: Not a delegation %##s (%s), but reached original name", question->qname.c,
3817 DNSTypeName(question->qtype));
3818 DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3823 DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3826 // We return Insecure if we don't have a trust anchor or we have a trust anchor and
3827 // can prove that the delegation is not secure (and hence can't establish the trust
3828 // chain) or the delegation is possibly secure but we don't have the algorithm support
3830 mDNSexport void ProveInsecure(mDNS *const m, DNSSECVerifier *dv, InsecureContext *ic, domainname *trigger)
3837 ic = (InsecureContext *)mDNSPlatformMemAllocate(sizeof(InsecureContext));
3840 LogMsg("mDNSPlatformMemAllocate: ERROR!! memory alloc failed for ic");
3844 // Save the AuthInfo while we are proving insecure. We don't want to mix up
3845 // the auth chain for Bogus and Insecure. If we prove it to be insecure, we
3846 // will add the chain corresponding to the insecure proof. Otherwise, we will
3847 // restore this chain.
3852 LogDNSSEC("ProveInsecure: saving authinfo");
3856 LogDNSSEC("ProveInsecure: ERROR!! authinfo already set");
3857 FreeDNSSECAuthChainInfo(dv->saveac);
3859 dv->saveac = dv->ac;
3863 ic->q.ThisQInterval = -1;
3867 LogDNSSEC("ProveInsecure: Setting Trigger %##s", trigger->c);
3868 ic->triggerLabelCount = CountLabels(trigger);
3872 LogDNSSEC("ProveInsecure: No Trigger");
3873 ic->triggerLabelCount = CountLabels(&dv->origName);
3876 ta = FindTrustAnchor(m, &dv->origName);
3879 LogDNSSEC("ProveInsecure: TrustAnchor NULL");
3880 DeliverInsecureProofResult(m, ic, DNSSEC_Insecure);
3883 // We want to skip the labels that is already matched by the trust anchor so
3884 // that the first query starts just below the trust anchor
3885 ic->skip = CountLabels(&dv->origName) - CountLabels(&ta->zone);
3888 LogDNSSEC("ProveInsecure: origName %##s, skip is zero", dv->origName.c);
3889 DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3893 // Look for the DS record starting just below the trust anchor.
3895 // 1. If we find an NSEC record, then see if it is a delegation. If it is, then
3896 // we are done. Otherwise, go down one more level.
3898 // 2. If we find a DS record and no algorithm support, return "insecure". Otherwise, go
3899 // down one more level.
3901 sname = (domainname *)SkipLeadingLabels(&dv->origName, (ic->skip ? ic->skip - 1 : 0));
3904 LogDNSSEC("ProveInsecure: sname NULL, origName %##s, skip %d", dv->origName.c, ic->skip);
3905 DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3909 // Insecurity proof is started during the normal bottom-up validation when we have a break in the trust
3910 // chain e.g., we get NSEC/NSEC3s when looking up a DS record. Insecurity proof is top-down looking
3911 // for a break in the trust chain. If we have already tried the validation (before the insecurity
3912 // proof started) for this "sname", then don't bother with the proof. This happens sometimes, when
3913 // we can't prove whether a zone is insecurely delegated or not. For example, if we are looking up
3914 // host1.secure-nods.secure.example and when we encounter secure-nods, there is no DS record in the
3915 // parent. We start the insecurity proof remembering that "secure-nods.secure.example" is the trigger
3916 // point. As part of the proof we reach "secure-nods.secure.example". Even though secure.example
3917 // prove that the name "secure-nods.secure.example/DS" does not exist, it can't prove that it is a
3918 // delegation. So, we continue one more level down to host1.secure-nods.secure.example and we
3919 // realize that we already tried the validation and hence abort here.
3921 if (CountLabels(sname) > ic->triggerLabelCount)
3923 LogDNSSEC("ProveInsecure: Beyond the trigger current name %##s, origName %##s", sname->c, dv->origName.c);
3924 DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3928 LogDNSSEC("ProveInsecure: OrigName %##s (%s), Current %##s", dv->origName.c, DNSTypeName(dv->origType), sname->c);
3930 InitializeQuestion(m, &ic->q, dv->InterfaceID, sname, kDNSType_DS, ProveInsecureCallback, ic);
3931 ic->q.ValidationRequired = DNSSEC_VALIDATION_INSECURE;
3932 ic->q.ValidatingResponse = 0;
3933 ic->q.DNSSECAuthInfo = mDNSNULL;
3934 mDNS_StartQuery(m, &ic->q);
3937 mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
3941 case kStatsTypeMemoryUsage:
3942 if (action == kStatsActionIncrement)
3944 m->DNSSECStats.TotalMemUsed += value;
3946 else if (action == kStatsActionDecrement)
3948 m->DNSSECStats.TotalMemUsed -= value;
3951 case kStatsTypeLatency:
3952 if (action == kStatsActionSet)
3956 m->DNSSECStats.Latency0++;
3958 else if (value <= 9)
3960 m->DNSSECStats.Latency5++;
3962 else if (value <= 19)
3964 m->DNSSECStats.Latency10++;
3966 else if (value <= 49)
3968 m->DNSSECStats.Latency20++;
3970 else if (value <= 99)
3972 m->DNSSECStats.Latency50++;
3976 m->DNSSECStats.Latency100++;
3980 case kStatsTypeExtraPackets:
3981 if (action == kStatsActionSet)
3985 m->DNSSECStats.ExtraPackets0++;
3987 else if (value <= 6)
3989 m->DNSSECStats.ExtraPackets3++;
3991 else if (value <= 9)
3993 m->DNSSECStats.ExtraPackets7++;
3997 m->DNSSECStats.ExtraPackets10++;
4001 case kStatsTypeStatus:
4002 if (action == kStatsActionSet)
4007 m->DNSSECStats.SecureStatus++;
4009 case DNSSEC_Insecure:
4010 m->DNSSECStats.InsecureStatus++;
4012 case DNSSEC_Indeterminate:
4013 m->DNSSECStats.IndeterminateStatus++;
4016 m->DNSSECStats.BogusStatus++;
4018 case DNSSEC_NoResponse:
4019 m->DNSSECStats.NoResponseStatus++;
4022 LogMsg("BumpDNSSECStats: unknown status %d", value);
4026 case kStatsTypeMsgSize:
4027 if (action == kStatsActionSet)
4031 m->DNSSECStats.MsgSize0++;
4033 else if (value <= 2048)
4035 m->DNSSECStats.MsgSize1++;
4039 m->DNSSECStats.MsgSize2++;
4043 case kStatsTypeProbe:
4044 if (action == kStatsActionIncrement)
4046 m->DNSSECStats.NumProbesSent += value;
4050 LogMsg("BumpDNSSECStats: unknown type %d", type);
4055 #else // !DNSSEC_DISABLED
4057 mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
4064 mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
4072 mDNSexport void InitializeQuestion(mDNS *const m, DNSQuestion *question, mDNSInterfaceID InterfaceID, const domainname *qname, mDNSu16 qtype, mDNSQuestionCallback *callback, void *context)
4083 mDNSexport char *DNSSECStatusName(DNSSECStatus status)
4090 #endif // !DNSSEC_DISABLED