1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
4 *
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
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17#include "mDNSEmbeddedAPI.h"
18#include "DNSSECSupport.h"
19#include "DNSCommon.h"
20#include "dnssec.h"
21#include "CryptoAlg.h"
22#include "nsec.h"
23#include "nsec3.h"
24
25// Define DNSSEC_DISABLED to remove all the DNSSEC functionality
26// and use the stub functions implemented later in this file.
27
28#ifndef DNSSEC_DISABLED
29
30//#define DNSSEC_DEBUG
31
32#ifdef DNSSEC_DEBUG
33#define debugdnssec LogMsg
34#else
35#define debugdnssec debug_noop
36#endif
37//
38// Implementation Notes
39//
40// The entry point to DNSSEC Verification is VerifySignature. This function is called from the "core" when
41// the answer delivered to the application needs DNSSEC validation. If a question needs DNSSEC
42// validation, "ValidationRequired" would be set. As we need to issue more queries to validate the
43// original question, we create another question as part of the verification process (question is part of
44// DNSSECVerifier). This question sets "ValidatingResponse" to distinguish itself from the original
45// question. Without this, it will be a duplicate and never sent out. The "core" almost treats both the
46// types identically (like adding EDNS0 option with DO bit etc.) except for a few differences. When RRSIGs
47// are added to the cache, "ValidatingResponse" question gets called back as long as the typeCovered matches
48// the question's qtype. See the comment in DNSSECRecordAnswersQuestion for the details. The other big
49// difference is that "ValidationRequired" question kicks off the verification process by calling into
50// "VerifySignature" whereas ValidationResponse don't do that as it gets callback for its questions.
51//
52// VerifySignature does not retain the original question that started the verification process. It just
53// remembers the name and the type. It takes a snapshot of the cache at that instance which will be
54// verified using DNSSEC. If the cache changes subsequently e.g., network change etc., it will be detected
55// when the validation is completed. If there is a change, it will be revalidated.
56//
57// The verification flow looks like this:
58//
59// VerifySignature -> StartDNSSECVerification - GetAllRRSetsForVerification -> FinishDNSSECVerification -> VerifySignature
60//
61// Verification is a recursive process. It stops when we find a trust anchor or if we have recursed too deep.
62//
63// If the original question resulted in NODATA/NXDOMAIN error, there should have been NSECs as part of the response.
64// These nsecs are cached along with the negative cache record. These are validated using ValidateWithNSECS called
65// from Verifysignature.
66//
67// The flow in this case looks like this:
68//
69// VerifySignature -> ValidateWithNSECS -> {NoDataProof, NameErrorProof} -> VerifyNSECS -> StartDNSSECVerification
70//
71// Once the DNSSEC verification is started, it is similar to the previous flow described above. When the verification
72// is done, DNSSECPositiveValidationCB or DNSSECNegativeValidationCB will be called which will then deliver the
73// validation results to the original question that started the validation.
74//
75// Insecure proofs are done when the verification ends up bogus. The flow would look like this
76//
77// VerifySignature -> StartDNSSECVerification - GetAllRRSetsForVerification -> FinishDNSSECVerification -> DNSSECValidationCB
78// {DNSSECPositiveValidationCB, DNSSECNegativeValidationCB} -> ProveInsecure -> VerifySignaure ->
79//
80// ProveInsecure finds the break in trust in a top-down fashion.
81//
82// Forward declaration
83mDNSlocal void VerifySigCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
84mDNSlocal mStatus TrustedKey(mDNS *const m, DNSSECVerifier *dv);
85mDNSlocal mDNSBool TrustedKeyPresent(mDNS *const m, DNSSECVerifier *dv);
86mDNSlocal mStatus ValidateDS(DNSSECVerifier *dv);
87mDNSlocal void DNSSECNegativeValidationCB(mDNS *const m, DNSSECVerifier *dv, CacheGroup *cg, ResourceRecord *answer, DNSSECStatus status);
88mDNSlocal RRVerifier* CopyRRVerifier(RRVerifier *from);
89
90// Currently we use this to convert a RRVerifier to resource record so that we can
91// use the standard DNS utility functions
92LargeCacheRecord largerec;
93
94// Verification is a recursive process. We arbitrarily limit to 10 just to be cautious which should be
95// removed in the future.
96#define MAX_RECURSE_COUNT   10
97
98// TTL (in seconds) when the DNSSEC status is Bogus
99#define RR_BOGUS_TTL        60
100
101// RFC 4034 Appendix B: Get the keyid of a DNS KEY. It is not transmitted
102// explicitly on the wire.
103//
104// Note: This just helps narrow down the list of keys to look at. It is possible
105// for two DNS keys to have the same ID i.e., key ID is not a unqiue tag
106//
107// 1st argument - the RDATA part of the DNSKEY RR
108// 2nd argument - the RDLENGTH
109//
110mDNSlocal mDNSu32 keytag(mDNSu8 *key, mDNSu32 keysize)
111{
112    unsigned long ac;
113    unsigned int i;
114
115    // DST_ALG_RSAMD5 will be rejected automatically as the keytag
116    // is calculated wrongly
117
118    for (ac = 0, i = 0; i < keysize; ++i)
119        ac += (i & 1) ? key[i] : key[i] << 8;
120    ac += (ac >> 16) & 0xFFFF;
121    return ac & 0xFFFF;
122}
123
124mDNSexport int DNSMemCmp(const mDNSu8 *const m1, const mDNSu8 *const m2, int len)
125{
126    int res;
127
128    res = mDNSPlatformMemCmp(m1, m2, len);
129    if (res != 0)
130        return (res < 0 ? -1 : 1);
131    return 0;
132}
133
134// RFC 4034:
135//
136// Section 6.1:
137//
138// For the purposes of DNS security, owner names are ordered by treating
139// individual labels as unsigned left-justified octet strings.  The
140// absence of a octet sorts before a zero value octet, and uppercase
141// US-ASCII letters are treated as if they were lowercase US-ASCII
142// letters.
143//
144// To compute the canonical ordering of a set of DNS names, start by
145// sorting the names according to their most significant (rightmost)
146// labels.  For names in which the most significant label is identical,
147// continue sorting according to their next most significant label, and
148// so forth.
149//
150// Returns 0 if the names are same
151// Returns -1 if d1 < d2
152// Returns  1 if d1 > d2
153//
154// subdomain is set if there is at least one label match (starting from the end)
155// and d1 has more labels than d2 e.g., a.b.com is a subdomain of b.com
156//
157mDNSexport int DNSSECCanonicalOrder(const domainname *const d1, const domainname *const d2, int *subdomain)
158{
159    int count, c1, c2;
160    int i, skip1, skip2;
161
162    c1 = CountLabels(d1);
163    skip1 = c1 - 1;
164    c2 = CountLabels(d2);
165    skip2 = c2 - 1;
166
167    if (subdomain) *subdomain = 0;
168
169    // Compare as many labels as possible starting from the rightmost
170    count = c1 < c2 ? c1 : c2;
171    for (i = count; i > 0; i--)
172    {
173        mDNSu8 *a, *b;
174        int j, len, lena, lenb;
175
176        a = (mDNSu8 *)SkipLeadingLabels(d1, skip1);
177        b = (mDNSu8 *)SkipLeadingLabels(d2, skip2);
178        lena = *a;
179        lenb = *b;
180        // Compare label by label. Note that "z" > "yak" because z > y, but z < za
181        // (lena - lenb check below) because 'za' has two characters. Hence compare the
182        // letters first and then compare the length of the label at the end.
183        len = lena < lenb ? lena : lenb;
184        a++; b++;
185        for (j = 0; j < len; j++)
186        {
187            mDNSu8 ac = *a++;
188            mDNSu8 bc = *b++;
189            if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
190            if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
191            if (ac != bc)
192            {
193                verbosedebugf("DNSSECCanonicalOrder: returning ac %c, bc %c", ac, bc);
194                return ((ac < bc) ? -1 : 1);
195            }
196        }
197        if ((lena - lenb) != 0)
198        {
199            verbosedebugf("DNSSECCanonicalOrder: returning lena %d lenb %d", lena, lenb);
200            return ((lena < lenb) ? -1 : 1);
201        }
202
203        // Continue with the next label
204        skip1--;
205        skip2--;
206    }
207    // We have compared label by label. Both of them are same if we are here.
208    //
209    // Two possibilities.
210    //
211    // 1) Both names have same number of labels. In that case, return zero.
212    // 2) The number of labels is not same. As zero label sorts before, names
213    //    with more number of labels is greater.
214
215    // a.b.com is a subdomain of b.com
216    if ((c1 > c2) && subdomain)
217        *subdomain = 1;
218
219    verbosedebugf("DNSSECCanonicalOrder: returning c1 %d c2 %d\n", c1, c2);
220    if (c1 != c2)
221        return ((c1 < c2) ? -1 : 1);
222    else
223        return 0;
224}
225
226// Initialize the question enough so that it can be answered from the cache using SameNameRecordAnswersQuestion or
227// ResourceRecordAnswersQuestion.
228mDNSexport void InitializeQuestion(mDNS *const m, DNSQuestion *question, mDNSInterfaceID InterfaceID, const domainname *qname,
229                                   mDNSu16 qtype, mDNSQuestionCallback *callback, void *context)
230{
231    debugf("InitializeQuestion: Called for %##s (%s)", qname->c, DNSTypeName(qtype));
232
233    if (question->ThisQInterval != -1) mDNS_StopQuery(m, question);
234
235    mDNS_SetupQuestion(question, InterfaceID, qname, qtype, callback, context);
236    question->qnamehash  = DomainNameHashValue(qname);
237    question->ValidatingResponse = mDNStrue;
238
239    // Need to hold the lock, as GetServerForQuestion (its callers) references m->timenow.
240    mDNS_Lock(m);
241    // We need to set the DNS server appropriately to match the question against the cache record.
242    // Though not all callers of this function need it, we always do it to keep it simple.
243    SetValidDNSServers(m, question);
244    question->qDNSServer = GetServerForQuestion(m, question);
245    mDNS_Unlock(m);
246
247    // Make it look like unicast
248    question->TargetQID = onesID;
249    question->TimeoutQuestion = 1;
250    question->ReturnIntermed = 1;
251    // SetupQuestion sets LongLived if qtype == PTR
252    question->LongLived = 0;
253}
254
255mDNSexport DNSSECVerifier *AllocateDNSSECVerifier(mDNS *const m, const domainname *name, mDNSu16 rrtype, mDNSInterfaceID InterfaceID,
256    mDNSu8 ValidationRequired, DNSSECVerifierCallback dvcallback, mDNSQuestionCallback qcallback)
257{
258    DNSSECVerifier *dv;
259
260    dv = (DNSSECVerifier *)mDNSPlatformMemAllocate(sizeof(DNSSECVerifier));
261    if (!dv) { LogMsg("AllocateDNSSECVerifier: ERROR!! memory alloc failed"); return mDNSNULL; }
262    mDNSPlatformMemZero(dv, sizeof(*dv));
263
264    LogDNSSEC("AllocateDNSSECVerifier called %p", dv);
265
266    // Remember the question's name and type so that when we are done processing all
267    // the verifications, we can trace the original question back
268    AssignDomainName(&dv->origName, name);
269    dv->origType = rrtype;
270    dv->InterfaceID = InterfaceID;
271    dv->DVCallback = dvcallback;
272    dv->q.ThisQInterval = -1;
273    ResetAuthChain(dv);
274    // These two are used for Insecure proof if we end up doing it.
275    // -Value of ValidationRequired so that we know whether this is a secure or insecure validation
276    // -InsecureProofDone tells us whether the proof has been done or not
277    dv->ValidationRequired = ValidationRequired;
278    dv->InsecureProofDone = 0;
279    dv->NumPackets = 0;
280    mDNS_Lock(m);
281    dv->StartTime = m->timenow;
282    mDNS_Unlock(m);
283    // The verifier's question has to be initialized as some of the callers assume it
284    InitializeQuestion(m, &dv->q, InterfaceID, name, rrtype, qcallback, dv);
285    return dv;
286}
287
288mDNSlocal AuthChain *AuthChainCopy(AuthChain *ae)
289{
290    RRVerifier *rvfrom, **rvto;
291    AuthChain **prev = mDNSNULL;
292    AuthChain *retac = mDNSNULL;
293    AuthChain *ac;
294
295
296    while (ae)
297    {
298        ac = mDNSPlatformMemAllocate(sizeof(AuthChain));
299        if (!ac)
300        {
301            LogMsg("AuthChainCopy: AuthChain alloc failure");
302            return mDNSfalse;
303        }
304
305        ac->next  = mDNSNULL;
306
307        if (!retac)
308            retac = ac;
309
310        rvfrom = ae->rrset;
311        rvto = &ac->rrset;
312        while (rvfrom)
313        {
314            *rvto = CopyRRVerifier(rvfrom);
315            rvfrom = rvfrom->next;
316            rvto = &((*rvto)->next);
317        }
318
319        rvfrom = ae->rrsig;
320        rvto = &ac->rrsig;
321        while (rvfrom)
322        {
323            *rvto = CopyRRVerifier(rvfrom);
324            rvfrom = rvfrom->next;
325            rvto = &((*rvto)->next);
326        }
327
328        rvfrom = ae->key;
329        rvto = &ac->key;
330        while (rvfrom)
331        {
332            *rvto = CopyRRVerifier(rvfrom);
333            rvfrom = rvfrom->next;
334            rvto = &((*rvto)->next);
335        }
336
337        if (prev)
338        {
339            *prev = ac;
340        }
341        prev = &(ac->next);
342        ae = ae->next;
343    }
344    return retac;
345}
346
347mDNSlocal void FreeDNSSECAuthChainInfo(AuthChain *ac)
348{
349    RRVerifier *rrset;
350    RRVerifier *next;
351    AuthChain *acnext;
352
353    LogDNSSEC("FreeDNSSECAuthChainInfo: called");
354
355    while (ac)
356    {
357        acnext = ac->next;
358        rrset = ac->rrset;
359        while (rrset)
360        {
361            next = rrset->next;
362            mDNSPlatformMemFree(rrset);
363            rrset = next;
364        }
365        ac->rrset = mDNSNULL;
366
367        rrset = ac->rrsig;
368        while (rrset)
369        {
370            next = rrset->next;
371            mDNSPlatformMemFree(rrset);
372            rrset = next;
373        }
374        ac->rrsig = mDNSNULL;
375
376        rrset = ac->key;
377        while (rrset)
378        {
379            next = rrset->next;
380            mDNSPlatformMemFree(rrset);
381            rrset = next;
382        }
383        ac->key = mDNSNULL;
384
385        mDNSPlatformMemFree(ac);
386        ac = acnext;
387    }
388}
389
390mDNSlocal void FreeDNSSECAuthChain(DNSSECVerifier *dv)
391{
392    if (dv->ac)
393    {
394        FreeDNSSECAuthChainInfo(dv->ac);
395        // if someone reuses the "dv", it will be initialized properly
396        ResetAuthChain(dv);
397    }
398    if (dv->saveac)
399    {
400        FreeDNSSECAuthChainInfo(dv->saveac);
401        dv->saveac = mDNSNULL;
402    }
403}
404
405mDNSlocal void FreeAuthChain(mDNS *const m, void *context)
406{
407    AuthChain *ac = (AuthChain *)context;
408    (void) m; // unused
409
410    FreeDNSSECAuthChainInfo(ac);
411}
412
413mDNSlocal void FreeDNSSECVerifierRRSets(DNSSECVerifier *dv)
414{
415    RRVerifier *rrset;
416    RRVerifier *next;
417
418    //debugdnssec("FreeDNSSECVerifierRRSets called %p", dv);
419    rrset = dv->rrset;
420    while (rrset)
421    {
422        next = rrset->next;
423        mDNSPlatformMemFree(rrset);
424        rrset = next;
425    }
426    dv->rrset = mDNSNULL;
427
428    rrset = dv->rrsig;
429    while (rrset)
430    {
431        next = rrset->next;
432        mDNSPlatformMemFree(rrset);
433        rrset = next;
434    }
435    dv->rrsig = mDNSNULL;
436
437    rrset = dv->key;
438    while (rrset)
439    {
440        next = rrset->next;
441        mDNSPlatformMemFree(rrset);
442        rrset = next;
443    }
444    dv->key = mDNSNULL;
445
446    rrset = dv->rrsigKey;
447    while (rrset)
448    {
449        next = rrset->next;
450        mDNSPlatformMemFree(rrset);
451        rrset = next;
452    }
453    dv->rrsigKey = mDNSNULL;
454
455    rrset = dv->ds;
456    while (rrset)
457    {
458        next = rrset->next;
459        mDNSPlatformMemFree(rrset);
460        rrset = next;
461    }
462    dv->ds = mDNSNULL;
463    rrset = dv->pendingNSEC;
464    while (rrset)
465    {
466        next = rrset->next;
467        mDNSPlatformMemFree(rrset);
468        rrset = next;
469    }
470    dv->pendingNSEC = mDNSNULL;
471}
472
473mDNSexport void FreeDNSSECVerifier(mDNS *const m, DNSSECVerifier *dv)
474{
475    LogDNSSEC("FreeDNSSECVerifier called %p", dv);
476    if (dv->q.ThisQInterval != -1)
477        mDNS_StopQuery(m, &dv->q);
478    FreeDNSSECVerifierRRSets(dv);
479    if (dv->ctx)
480        AlgDestroy(dv->ctx);
481    if (dv->ac || dv->saveac)
482        FreeDNSSECAuthChain(dv);
483    if (dv->parent)
484    {
485        LogDNSSEC("FreeDNSSECVerifier freeing parent %p", dv->parent);
486        FreeDNSSECVerifier(m, dv->parent);
487    }
488    mDNSPlatformMemFree(dv);
489}
490
491mDNSlocal RRVerifier* CopyRRVerifier(RRVerifier *from)
492{
493    RRVerifier *r;
494
495    r = mDNSPlatformMemAllocate(sizeof (RRVerifier) + from->rdlength);
496    if (!r)
497    {
498        LogMsg("CopyRRVerifier: memory failure");
499        return mDNSNULL;
500    }
501    mDNSPlatformMemCopy(r, from, sizeof(RRVerifier));
502    r->next = mDNSNULL;
503    r->rdata = (mDNSu8*) ((mDNSu8 *)r + sizeof(RRVerifier));
504    mDNSPlatformMemCopy(r->rdata, from->rdata, r->rdlength);
505    return r;
506}
507
508mDNSexport RRVerifier* AllocateRRVerifier(const ResourceRecord *const rr, mStatus *status)
509{
510    RRVerifier *r;
511
512    r = mDNSPlatformMemAllocate(sizeof (RRVerifier) + rr->rdlength);
513    if (!r)
514    {
515        LogMsg("AllocateRRVerifier: memory failure");
516        *status = mStatus_NoMemoryErr;
517        return mDNSNULL;
518    }
519    r->next = mDNSNULL;
520    r->rrtype = rr->rrtype;
521    r->rrclass = rr->rrclass;
522    r->rroriginalttl = rr->rroriginalttl;
523    r->rdlength = rr->rdlength;
524    r->namehash = rr->namehash;
525    r->rdatahash = rr->rdatahash;
526    AssignDomainName(&r->name, rr->name);
527    r->rdata = (mDNSu8*) ((mDNSu8 *)r + sizeof(RRVerifier));
528
529    // When we parsed the DNS response in GeLargeResourceRecord, for some records, we parse them into
530    // host order so that the rest of the code does not have to bother with converting from network order
531    // to host order. For signature verification, we need them back in network order. For DNSSEC records
532    // like DNSKEY and DS, we just copy over the data both in GetLargeResourceRecord and putRData.
533
534    if (!putRData(mDNSNULL, r->rdata, r->rdata + rr->rdlength, rr))
535    {
536        LogMsg("AllocateRRVerifier: putRData failed");
537        *status = mStatus_BadParamErr;
538        return mDNSNULL;
539    }
540    *status = mStatus_NoError;
541    return r;
542}
543
544mDNSexport mStatus AddRRSetToVerifier(DNSSECVerifier *dv, const ResourceRecord *const rr, RRVerifier *rv, RRVerifierSet set)
545{
546    RRVerifier *r;
547    RRVerifier **v;
548    mStatus status;
549
550    if (!rv)
551    {
552        r = AllocateRRVerifier(rr, &status);
553        if (!r) return status;
554    }
555    else
556        r = rv;
557
558    switch (set)
559    {
560    case RRVS_rr:
561        v = &dv->rrset;
562        break;
563    case RRVS_rrsig:
564        v = &dv->rrsig;
565        break;
566    case RRVS_key:
567        v = &dv->key;
568        break;
569    case RRVS_rrsig_key:
570        v = &dv->rrsigKey;
571        break;
572    case RRVS_ds:
573        v = &dv->ds;
574        break;
575    default:
576        LogMsg("AddRRSetToVerifier: ERROR!! default case %d", set);
577        return mStatus_BadParamErr;
578    }
579    while (*v)
580        v = &(*v)->next;
581    *v = r;
582    return mStatus_NoError;
583}
584
585// Validate the RRSIG. "type" tells which RRSIG that we are supposed to validate. We fetch RRSIG for
586// the rrset (type is RRVS_rrsig) and RRSIG for the key (type is RRVS_rrsig_key).
587mDNSexport void ValidateRRSIG(DNSSECVerifier *dv, RRVerifierSet type, const ResourceRecord *const rr)
588{
589    RRVerifier *rv;
590    mDNSu32 currentTime;
591    rdataRRSig *rrsigRData = (rdataRRSig *)((mDNSu8 *)rr->rdata + sizeofRDataHeader);
592
593    if (type == RRVS_rrsig)
594    {
595        rv = dv->rrset;
596    }
597    else if (type == RRVS_rrsig_key)
598    {
599        rv = dv->key;
600    }
601    else
602    {
603        LogMsg("ValidateRRSIG: ERROR!! type not valid %d", type);
604        return;
605    }
606
607    // RFC 4035:
608    // For each authoritative RRset in a signed zone, there MUST be at least
609    // one RRSIG record that meets the following requirements:
610    //
611    // RRSet is defined by same name, class and type
612    //
613    // 1. The RRSIG RR and the RRset MUST have the same owner name and the same class.
614    if (!SameDomainName(&rv->name, rr->name) || (rr->rrclass != rv->rrclass))
615    {
616        debugdnssec("ValidateRRSIG: name mismatch or class mismatch");
617        return;
618    }
619
620    // 2. The RRSIG RR's Type Covered field MUST equal the RRset's type.
621    if ((swap16(rrsigRData->typeCovered)) != rv->rrtype)
622    {
623        debugdnssec("ValidateRRSIG: typeCovered mismatch rrsig %d, rr type %d", swap16(rrsigRData->typeCovered), rv->rrtype);
624        return;
625    }
626
627    // 3. The number of labels in the RRset owner name MUST be greater than or equal
628    //    to the value in the RRSIG RR's Labels field.
629    if (rrsigRData->labels > CountLabels(&rv->name))
630    {
631        debugdnssec("ValidateRRSIG: labels count problem rrsig %d, rr %d", rrsigRData->labels, CountLabels(&rv->name));
632        return;
633    }
634
635    // 4. The RRSIG RR's Signer's Name field MUST be the name of the zone that contains
636    //    the RRset. For a stub resolver, this can't be done in a secure way. Hence we
637    //    do it this way (discussed in dnsext mailing list)
638    switch (rv->rrtype)
639    {
640    case kDNSType_NS:
641    case kDNSType_SOA:
642    case kDNSType_DNSKEY:
643        //Signed by the owner
644        if (!SameDomainName(&rv->name, (domainname *)&rrsigRData->signerName))
645        {
646            debugdnssec("ValidateRRSIG: Signer Name does not match the record name for %s", DNSTypeName(rv->rrtype));
647            return;
648        }
649        break;
650    case kDNSType_DS:
651        // Should be signed by the parent
652        if (SameDomainName(&rv->name, (domainname *)&rrsigRData->signerName))
653        {
654            debugdnssec("ValidateRRSIG: Signer Name matches the record name for %s", DNSTypeName(rv->rrtype));
655            return;
656        }
657    // FALLTHROUGH
658    default:
659    {
660        int c1 = CountLabels(&rv->name);
661        int c2 = CountLabels((domainname *)&rrsigRData->signerName);
662        if (c1 < c2)
663        {
664            debugdnssec("ValidateRRSIG: Signer Name not a subdomain label count %d < %d ", c1, c2);
665            return;
666        }
667        domainname *d = (domainname *)SkipLeadingLabels(&rv->name, c1 - c2);
668        if (!SameDomainName(d, (domainname *)&rrsigRData->signerName))
669        {
670            debugdnssec("ValidateRRSIG: Signer Name not a subdomain");
671            return;
672        }
673        break;
674    }
675    }
676
677    // 5. The validator's notion of the current time MUST be less than or equal to the
678    //    time listed in the RRSIG RR's Expiration field.
679    //
680    // 6. The validator's notion of the current time MUST be greater than or equal to the
681    //    time listed in the RRSIG RR's Inception field.
682    currentTime = mDNSPlatformUTC();
683
684    if (DNS_SERIAL_LT(swap32(rrsigRData->sigExpireTime), currentTime))
685    {
686        LogDNSSEC("ValidateRRSIG: Expired: currentTime %d, ExpireTime %d", (int)currentTime,
687                  swap32((int)rrsigRData->sigExpireTime));
688        return;
689    }
690    if (DNS_SERIAL_LT(currentTime, swap32(rrsigRData->sigInceptTime)))
691    {
692        LogDNSSEC("ValidateRRSIG: Future: currentTime %d, InceptTime %d", (int)currentTime,
693                  swap32((int)rrsigRData->sigInceptTime));
694        return;
695    }
696
697    if (AddRRSetToVerifier(dv, rr, mDNSNULL, type) != mStatus_NoError)
698    {
699        LogMsg("ValidateRRSIG: ERROR!! cannot allocate RRSet");
700        return;
701    }
702}
703
704mDNSlocal mStatus CheckRRSIGForRRSet(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
705{
706    mDNSu32 slot;
707    CacheGroup *cg;
708    CacheRecord *cr;
709    RRVerifier *rv;
710    mDNSBool expectRRSIG = mDNSfalse;
711
712    *negcr = mDNSNULL;
713    if (!dv->rrset)
714    {
715        LogMsg("CheckRRSIGForRRSet: ERROR!! rrset NULL for origName %##s (%s)", dv->origName.c,
716               DNSTypeName(dv->origType));
717        return mStatus_BadParamErr;
718    }
719
720    rv = dv->rrset;
721    slot = HashSlot(&rv->name);
722    cg = CacheGroupForName(m, slot, rv->namehash, &rv->name);
723    if (!cg)
724    {
725        debugdnssec("CheckRRSIGForRRSet: cg null");
726        return mStatus_NoSuchRecord;
727    }
728
729    for (cr=cg->members; cr; cr=cr->next)
730    {
731        debugdnssec("CheckRRSIGForRRSet: checking the validity of rrsig");
732        if (cr->resrec.rrtype != kDNSType_RRSIG)
733        {
734            // Check to see if we should expect RRSIGs for the type that we are looking for.
735            // We would expect RRSIGs, if we had previously issued the question with the
736            // EDNS0/DOK bit set.
737            if (cr->resrec.rrtype == dv->rrset->rrtype)
738            {
739                expectRRSIG = cr->CRDNSSECQuestion;
740                LogDNSSEC("CheckRRSIGForRRSet: %s RRSIG for %s", (expectRRSIG ? "Expecting" : "Not Expecting"), CRDisplayString(m, cr));
741            }
742            continue;
743        }
744        if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
745        {
746            if (!(*negcr))
747            {
748                LogDNSSEC("CheckRRSIGForRRSet: Negative cache record %s encountered for %##s (%s)", CRDisplayString(m, cr),
749                          rv->name.c, DNSTypeName(rv->rrtype));
750                *negcr = cr;
751            }
752            else
753            {
754                LogMsg("CheckRRSIGForRRSet: ERROR!! Negative cache record %s already set for %##s (%s)", CRDisplayString(m, cr),
755                       rv->name.c, DNSTypeName(rv->rrtype));
756            }
757            continue;
758        }
759        ValidateRRSIG(dv, RRVS_rrsig, &cr->resrec);
760    }
761    if (*negcr && dv->rrsig)
762    {
763        // Encountered both RRSIG and negative CR
764        LogMsg("CheckRRSIGForRRSet: ERROR!! Encountered negative cache record %s and RRSIG for %##s (%s)",
765               CRDisplayString(m, *negcr), rv->name.c, DNSTypeName(rv->rrtype));
766        return mStatus_BadParamErr;
767    }
768    // If we can't find RRSIGs, but we find a negative response then we need to validate that
769    // which the caller will do it. Otherwise, if we should be expecting RRSIGs to be in the
770    // cache already, then return error.
771    if (dv->rrsig || *negcr)
772        return mStatus_NoError;
773    else if (expectRRSIG)
774        return mStatus_BadParamErr;
775    else
776        return mStatus_NoSuchRecord;
777}
778
779mDNSlocal void CheckOneKeyForRRSIG(DNSSECVerifier *dv, const ResourceRecord *const rr)
780{
781    rdataRRSig *rrsig;
782
783    if (!dv->rrsig)
784    {
785        LogMsg("CheckOneKeyForRRSIG: ERROR!! rrsig NULL");
786        return;
787    }
788    rrsig = (rdataRRSig *)dv->rrsig->rdata;
789    if (!SameDomainName((domainname *)&rrsig->signerName, rr->name))
790    {
791        debugdnssec("CheckOneKeyForRRSIG: name mismatch");
792        return;
793    }
794
795    // We store all the keys including the ZSK and KSK and use them appropriately
796    // later
797    if (AddRRSetToVerifier(dv, rr, mDNSNULL, RRVS_key) != mStatus_NoError)
798    {
799        LogMsg("CheckOneKeyForRRSIG: ERROR!! cannot allocate RRSet");
800        return;
801    }
802}
803
804mDNSlocal mStatus CheckKeyForRRSIG(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
805{
806    mDNSu32 slot;
807    mDNSu32 namehash;
808    CacheGroup *cg;
809    CacheRecord *cr;
810    rdataRRSig *rrsig;
811    domainname *name;
812
813    *negcr = mDNSNULL;
814    if (!dv->rrsig)
815    {
816        LogMsg("CheckKeyForRRSIG: ERROR!! rrsig NULL");
817        return mStatus_BadParamErr;
818    }
819
820    // Signer name should be the same on all rrsig ??
821    rrsig = (rdataRRSig *)dv->rrsig->rdata;
822    name = (domainname *)&rrsig->signerName;
823
824    slot = HashSlot(name);
825    namehash = DomainNameHashValue(name);
826    cg = CacheGroupForName(m, slot, namehash, name);
827    if (!cg)
828    {
829        debugdnssec("CheckKeyForRRSIG: cg null for %##s", name->c);
830        return mStatus_NoSuchRecord;
831    }
832
833    for (cr=cg->members; cr; cr=cr->next)
834    {
835        if (cr->resrec.rrtype != kDNSType_DNSKEY) continue;
836        if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
837        {
838            if (!(*negcr))
839            {
840                LogDNSSEC("CheckKeyForRRSIG: Negative cache record %s encountered for %##s (DNSKEY)", CRDisplayString(m, cr),
841                          name->c);
842                *negcr = cr;
843            }
844            else
845            {
846                LogMsg("CheckKeyForRRSIG: ERROR!! Negative cache record %s already set for %##s (DNSKEY)", CRDisplayString(m, cr),
847                       name->c);
848            }
849            continue;
850        }
851        debugdnssec("CheckKeyForRRSIG: checking the validity of key record");
852        CheckOneKeyForRRSIG(dv, &cr->resrec);
853    }
854    if (*negcr && dv->key)
855    {
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;
860    }
861    if (dv->key || *negcr)
862        return mStatus_NoError;
863    else
864        return mStatus_NoSuchRecord;
865}
866
867mDNSlocal void CheckOneRRSIGForKey(DNSSECVerifier *dv, const ResourceRecord *const rr)
868{
869    rdataRRSig *rrsig;
870    if (!dv->rrsig)
871    {
872        LogMsg("CheckOneRRSIGForKey: ERROR!! rrsig NULL");
873        return;
874    }
875    rrsig = (rdataRRSig *)dv->rrsig->rdata;
876    if (!SameDomainName((domainname *)&rrsig->signerName, rr->name))
877    {
878        debugdnssec("CheckOneRRSIGForKey: name mismatch");
879        return;
880    }
881    ValidateRRSIG(dv, RRVS_rrsig_key, rr);
882}
883
884mDNSlocal mStatus CheckRRSIGForKey(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
885{
886    mDNSu32 slot;
887    mDNSu32 namehash;
888    CacheGroup *cg;
889    CacheRecord *cr;
890    rdataRRSig *rrsig;
891    domainname *name;
892    mDNSBool expectRRSIG = mDNSfalse;
893
894    *negcr = mDNSNULL;
895    if (!dv->rrsig)
896    {
897        LogMsg("CheckRRSIGForKey: ERROR!! rrsig NULL");
898        return mStatus_BadParamErr;
899    }
900    if (!dv->key)
901    {
902        LogMsg("CheckRRSIGForKey:  ERROR!! key NULL");
903        return mStatus_BadParamErr;
904    }
905    rrsig = (rdataRRSig *)dv->rrsig->rdata;
906    name = (domainname *)&rrsig->signerName;
907
908    slot = HashSlot(name);
909    namehash = DomainNameHashValue(name);
910    cg = CacheGroupForName(m, slot, namehash, name);
911    if (!cg)
912    {
913        debugdnssec("CheckRRSIGForKey: cg null %##s", name->c);
914        return mStatus_NoSuchRecord;
915    }
916    for (cr=cg->members; cr; cr=cr->next)
917    {
918        if (cr->resrec.rrtype != kDNSType_RRSIG)
919        {
920            // Check to see if we should expect RRSIGs for the DNSKEY record that we are
921            // looking for. We would expect RRSIGs, if we had previously issued the question
922            // with the EDNS0/DOK bit set.
923            if (cr->resrec.rrtype == kDNSType_DNSKEY)
924            {
925                expectRRSIG = cr->CRDNSSECQuestion;
926                LogDNSSEC("CheckRRSIGForKey: %s RRSIG for %s", (expectRRSIG ? "Expecting" : "Not Expecting"), CRDisplayString(m, cr));
927            }
928            continue;
929        }
930        if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
931        {
932            if (!(*negcr))
933            {
934                LogDNSSEC("CheckRRSIGForKey: Negative cache record %s encountered for %##s (RRSIG)", CRDisplayString(m, cr),
935                          name->c);
936                *negcr = cr;
937            }
938            else
939            {
940                LogMsg("CheckRRSIGForKey: ERROR!! Negative cache record %s already set for %##s (RRSIG)", CRDisplayString(m, cr),
941                       name->c);
942            }
943            continue;
944        }
945        debugdnssec("CheckRRSIGForKey: checking the validity of rrsig");
946        CheckOneRRSIGForKey(dv, &cr->resrec);
947    }
948    if (*negcr && dv->rrsigKey)
949    {
950        // Encountered both RRSIG and negative CR
951        LogMsg("CheckRRSIGForKey: ERROR!! Encountered negative cache record %s and DNSKEY for %##s",
952               CRDisplayString(m, *negcr), name->c);
953        return mStatus_BadParamErr;
954    }
955    // If we can't find RRSIGs, but we find a negative response then we need to validate that
956    // which the caller will do it. Finally, make sure that we are not expecting RRSIGS.
957    if (dv->rrsigKey || *negcr)
958        return mStatus_NoError;
959    else if (expectRRSIG)
960        return mStatus_BadParamErr;
961    else
962        return mStatus_NoSuchRecord;
963}
964
965mDNSlocal void CheckOneDSForKey(DNSSECVerifier *dv, const ResourceRecord *const rr)
966{
967    mDNSu16 tag;
968    rdataDS *DS;
969    RRVerifier *keyv;
970    rdataDNSKey *key;
971    rdataRRSig *rrsig;
972
973    if (!dv->rrsig)
974    {
975        LogMsg("CheckOneDSForKey: ERROR!! rrsig NULL");
976        return;
977    }
978    rrsig = (rdataRRSig *)dv->rrsig->rdata;
979    DS = (rdataDS *)((mDNSu8 *)rr->rdata + sizeofRDataHeader);
980
981    if (!SameDomainName((domainname *)&rrsig->signerName, rr->name))
982    {
983        debugdnssec("CheckOneDSForKey: name mismatch");
984        return;
985    }
986    for (keyv = dv->key; keyv; keyv = keyv->next)
987    {
988        key = (rdataDNSKey *)keyv->rdata;
989        tag = (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength);
990        if (tag != swap16(DS->keyTag))
991        {
992            debugdnssec("CheckOneDSForKey: keyTag mismatch keyTag %d, DStag %d", tag, swap16(DS->keyTag));
993            continue;
994        }
995        if (key->alg != DS->alg)
996        {
997            debugdnssec("CheckOneDSForKey: alg mismatch key alg%d, DS alg %d", key->alg, swap16(DS->alg));
998            continue;
999        }
1000        if (AddRRSetToVerifier(dv, rr, mDNSNULL, RRVS_ds) != mStatus_NoError)
1001        {
1002            debugdnssec("CheckOneDSForKey: cannot allocate RRSet");
1003        }
1004    }
1005}
1006
1007mDNSlocal mStatus CheckDSForKey(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
1008{
1009    mDNSu32 slot;
1010    mDNSu32 namehash;
1011    CacheGroup *cg;
1012    CacheRecord *cr;
1013    rdataRRSig *rrsig;
1014    domainname *name;
1015
1016    *negcr = mDNSNULL;
1017    if (!dv->rrsig)
1018    {
1019        LogMsg("CheckDSForKey: ERROR!! rrsig NULL");
1020        return mStatus_BadParamErr;
1021    }
1022    if (!dv->key)
1023    {
1024        LogMsg("CheckDSForKey: ERROR!! key NULL");
1025        return mStatus_BadParamErr;
1026    }
1027    rrsig = (rdataRRSig *)dv->rrsig->rdata;
1028    name = (domainname *)&rrsig->signerName;
1029    slot = HashSlot(name);
1030    namehash = DomainNameHashValue(name);
1031    cg = CacheGroupForName(m, slot, namehash, name);
1032    if (!cg)
1033    {
1034        debugdnssec("CheckDSForKey: cg null for %s", name->c);
1035        return mStatus_NoSuchRecord;
1036    }
1037    for (cr=cg->members; cr; cr=cr->next)
1038    {
1039        if (cr->resrec.rrtype != kDNSType_DS) continue;
1040        if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
1041        {
1042            if (!(*negcr))
1043            {
1044                LogDNSSEC("CheckDSForKey: Negative cache record %s encountered for %##s (DS)", CRDisplayString(m, cr),
1045                          name->c);
1046                *negcr = cr;
1047            }
1048            else
1049            {
1050                LogMsg("CheckDSForKey: ERROR!! Negative cache record %s already set for %##s (DS)", CRDisplayString(m, cr),
1051                       name->c);
1052            }
1053            continue;
1054        }
1055        CheckOneDSForKey(dv, &cr->resrec);
1056    }
1057    if (*negcr && dv->ds)
1058    {
1059        // Encountered both RRSIG and negative CR
1060        LogMsg("CheckDSForKey: ERROR!! Encountered negative cache record %s and DS for %##s",
1061               CRDisplayString(m, *negcr), name->c);
1062        return mStatus_BadParamErr;
1063    }
1064    if (dv->ds || *negcr)
1065        return mStatus_NoError;
1066    else
1067        return mStatus_NoSuchRecord;
1068    return (dv->ds ? mStatus_NoError : mStatus_NoSuchRecord);
1069}
1070
1071// It returns mDNStrue if we have all the rrsets for verification and mDNSfalse otherwise.
1072mDNSlocal mDNSBool GetAllRRSetsForVerification(mDNS *const m, DNSSECVerifier *dv)
1073{
1074    mStatus err;
1075    CacheRecord *negcr;
1076    rdataRRSig *rrsig;
1077
1078    if (!dv->rrset)
1079    {
1080        LogMsg("GetAllRRSetsForVerification: ERROR!! rrset NULL");
1081        dv->DVCallback(m, dv, DNSSEC_Bogus);
1082        return mDNSfalse;
1083    }
1084
1085    if (dv->next == RRVS_done) return mDNStrue;
1086
1087    debugdnssec("GetAllRRSetsForVerification: next %d", dv->next);
1088    switch (dv->next)
1089    {
1090    case RRVS_rrsig:
1091        // If we can't find the RRSIG for the rrset, re-issue the query.
1092        //
1093        // NOTE: It is possible that the cache might answer partially e.g., RRSIGs match qtype but the
1094        // whole set is not there. In that case the validation will fail. Ideally we should flush the
1095        // cache and reissue the query (TBD).
1096        err = CheckRRSIGForRRSet(m, dv, &negcr);
1097        if (err != mStatus_NoSuchRecord && err != mStatus_NoError)
1098        {
1099            dv->DVCallback(m, dv, DNSSEC_Bogus);
1100            return mDNSfalse;
1101        }
1102        // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
1103        // looks in "dv->q" for the proof. Note that we have to use currQtype as the response could be
1104        // a CNAME and dv->rrset->rrtype would be set to CNAME and not the original question type that
1105        // resulted in CNAME.
1106        InitializeQuestion(m, &dv->q, dv->InterfaceID, &dv->rrset->name, dv->currQtype, VerifySigCallback, dv);
1107        // We may not have the NSECS if the previous query was a non-DNSSEC query
1108        if (negcr && negcr->nsec)
1109        {
1110            ValidateWithNSECS(m, dv, negcr);
1111            return mDNSfalse;
1112        }
1113
1114        dv->next = RRVS_key;
1115        if (!dv->rrsig)
1116        {
1117            // We already found the rrset to verify. Ideally we should just issue the query for the RRSIG. Unfortunately,
1118            // that does not work well as the response may not contain the RRSIG whose typeCovered matches the
1119            // rrset->rrtype (recursive server returns what is in its cache). Hence, we send the original query with the
1120            // DO bit set again to get the RRSIG. Normally this would happen if there was question which did not require
1121            // DNSSEC validation (ValidationRequied = 0) populated the cache and later when the ValidationRequired question
1122            // comes along, we need to get the RRSIGs. If we started off with ValidationRequired question we would have
1123            // already set the DO bit and not able to get RRSIGs e.g., bad CPE device, we would reissue the query here
1124            // again once more.
1125            //
1126            // Also, if it is a wildcard expanded answer, we need to issue the query with the original type for it to
1127            // elicit the right NSEC records. Just querying for RRSIG alone is not sufficient.
1128            //
1129            // Note: For this to work, the core needs to deliver RRSIGs when they are added to the cache even if the
1130            // "qtype" is not RRSIG.
1131            debugdnssec("GetAllRRSetsForVerification: Fetching RRSIGS for RRSET");
1132            dv->NumPackets++;
1133            mDNS_StartQuery(m, &dv->q);
1134            return mDNSfalse;
1135        }
1136        // if we found the RRSIG, then fall through to find the DNSKEY
1137    case RRVS_key:
1138        err = CheckKeyForRRSIG(m, dv, &negcr);
1139        if (err != mStatus_NoSuchRecord && err != mStatus_NoError)
1140        {
1141            dv->DVCallback(m, dv, DNSSEC_Bogus);
1142            return mDNSfalse;
1143        }
1144        // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
1145        // looks in "dv->q" for the proof.
1146        rrsig = (rdataRRSig *)dv->rrsig->rdata;
1147        InitializeQuestion(m, &dv->q, dv->InterfaceID, (domainname *)&rrsig->signerName, kDNSType_DNSKEY, VerifySigCallback, dv);
1148        // We may not have the NSECS if the previous query was a non-DNSSEC query
1149        if (negcr && negcr->nsec)
1150        {
1151            ValidateWithNSECS(m, dv, negcr);
1152            return mDNSfalse;
1153        }
1154
1155        dv->next = RRVS_rrsig_key;
1156        if (!dv->key)
1157        {
1158            debugdnssec("GetAllRRSetsForVerification: Fetching DNSKEY for RRSET");
1159            dv->NumPackets++;
1160            mDNS_StartQuery(m, &dv->q);
1161            return mDNSfalse;
1162        }
1163    // if we found the DNSKEY, then fall through to find the RRSIG for the DNSKEY
1164    case RRVS_rrsig_key:
1165        err = CheckRRSIGForKey(m, dv, &negcr);
1166        // if we are falling through, then it is okay if we don't find the record
1167        if (err != mStatus_NoSuchRecord && err != mStatus_NoError)
1168        {
1169            dv->DVCallback(m, dv, DNSSEC_Bogus);
1170            return mDNSfalse;
1171        }
1172        // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
1173        // looks in "dv->q" for the proof.
1174        rrsig = (rdataRRSig *)dv->rrsig->rdata;
1175        InitializeQuestion(m, &dv->q, dv->InterfaceID, (domainname *)&rrsig->signerName, kDNSType_DNSKEY, VerifySigCallback, dv);
1176        // We may not have the NSECS if the previous query was a non-DNSSEC query
1177        if (negcr && negcr->nsec)
1178        {
1179            ValidateWithNSECS(m, dv, negcr);
1180            return mDNSfalse;
1181        }
1182        dv->next = RRVS_ds;
1183        debugdnssec("GetAllRRSetsForVerification: RRVS_rrsig_key %p", dv->rrsigKey);
1184        if (!dv->rrsigKey)
1185        {
1186            debugdnssec("GetAllRRSetsForVerification: Fetching RRSIGS for DNSKEY");
1187            dv->NumPackets++;
1188            mDNS_StartQuery(m, &dv->q);
1189            return mDNSfalse;
1190        }
1191    // if we found RRSIG for the DNSKEY, then fall through to find the DS
1192    case RRVS_ds:
1193    {
1194        domainname *qname;
1195        rrsig = (rdataRRSig *)dv->rrsig->rdata;
1196        qname = (domainname *)&rrsig->signerName;
1197
1198        err = CheckDSForKey(m, dv, &negcr);
1199        if (err != mStatus_NoSuchRecord && err != mStatus_NoError)
1200        {
1201            dv->DVCallback(m, dv, DNSSEC_Bogus);
1202            return mDNSfalse;
1203        }
1204        // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
1205        // looks in "dv->q" for the proof.
1206        InitializeQuestion(m, &dv->q, dv->InterfaceID, qname, kDNSType_DS, VerifySigCallback, dv);
1207        // We may not have the NSECS if the previous query was a non-DNSSEC query
1208        if (negcr && negcr->nsec)
1209        {
1210            ValidateWithNSECS(m, dv, negcr);
1211            return mDNSfalse;
1212        }
1213        dv->next = RRVS_done;
1214        // If we have a trust anchor, then don't bother looking up the DS record
1215        if (!dv->ds && !TrustedKeyPresent(m, dv))
1216        {
1217            // There is no DS for the root. Hence, if we don't have the trust
1218            // anchor for root, just fail.
1219            if (SameDomainName(qname, (const domainname *)"\000"))
1220            {
1221                LogDNSSEC("GetAllRRSetsForVerification: Reached root");
1222                dv->DVCallback(m, dv, DNSSEC_Bogus);
1223                return mDNSfalse;
1224            }
1225            debugdnssec("GetAllRRSetsForVerification: Fetching DS");
1226            dv->NumPackets++;
1227            mDNS_StartQuery(m, &dv->q);
1228            return mDNSfalse;
1229        }
1230        else
1231        {
1232            debugdnssec("GetAllRRSetsForVerification: Skipped fetching the DS");
1233            return mDNStrue;
1234        }
1235    }
1236    default:
1237        LogMsg("GetAllRRSetsForVerification: ERROR!! unknown next %d", dv->next);
1238        dv->DVCallback(m, dv, DNSSEC_Bogus);
1239        return mDNSfalse;
1240    }
1241}
1242
1243#ifdef DNSSEC_DEBUG
1244mDNSlocal void PrintFixedSignInfo(rdataRRSig *rrsig, domainname *signerName, int sigNameLen, mDNSu8 *fixedPart, int fixedPartLen)
1245{
1246    int j;
1247    char buf[RRSIG_FIXED_SIZE *3 + 1]; // 3 bytes count for %2x + 1 and the one byte for null at the end
1248    char sig[sigNameLen * 3 + 1];
1249    char fp[fixedPartLen * 3 + 1];
1250    int length;
1251
1252    length = 0;
1253    for (j = 0; j < RRSIG_FIXED_SIZE; j++)
1254        length += mDNS_snprintf(buf+length, sizeof(buf) - length - 1, "%2x ", ((mDNSu8 *)rrsig)[j]);
1255    LogMsg("RRSIG(%d) %s", RRSIG_FIXED_SIZE, buf);
1256
1257
1258    length = 0;
1259    for (j = 0; j < sigNameLen; j++)
1260        length += mDNS_snprintf(sig+length, sizeof(sig) - length - 1, "%2x ", signerName->c[j]);
1261    LogMsg("SIGNAME(%d) %s", sigNameLen, sig);
1262
1263    length = 0;
1264    for (j = 0; j < fixedPartLen; j++)
1265        length += mDNS_snprintf(fp+length, sizeof(fp) - length - 1, "%2x ", fixedPart[j]);
1266    LogMsg("fixedPart(%d) %s", fixedPartLen, fp);
1267}
1268
1269mDNSlocal void PrintVarSignInfo(mDNSu16 rdlen, mDNSu8 *rdata)
1270{
1271    unsigned int j;
1272    mDNSu8 *r;
1273    unsigned int blen = swap16(rdlen);
1274    char buf[blen * 3 + 1]; // 3 bytes count for %2x + 1 and the one byte for null at the end
1275    int length;
1276
1277    length = 0;
1278
1279    r = (mDNSu8 *)&rdlen;
1280    for (j = 0; j < sizeof(mDNSu16); j++)
1281        length += mDNS_snprintf(buf+length, sizeof(buf) - length - 1, "%2x ", r[j]);
1282    LogMsg("RDLENGTH(%d) %s", sizeof(mDNSu16), buf);
1283
1284    length = 0;
1285    for (j = 0; j < blen; j++)
1286        length += mDNS_snprintf(buf+length, sizeof(buf) - length - 1, "%2x ", rdata[j]);
1287    LogMsg("RDATA(%d) %s", blen, buf);
1288}
1289#else
1290mDNSlocal void PrintVarSignInfo(mDNSu16 rdlen, mDNSu8 *rdata)
1291{
1292    (void)rdlen;
1293    (void)rdata;
1294}
1295mDNSlocal void PrintFixedSignInfo(rdataRRSig *rrsig, domainname *signerName, int sigNameLen, mDNSu8 *fixedPart, int fixedPartLen)
1296{
1297    (void)rrsig;
1298    (void)signerName;
1299    (void)sigNameLen;
1300    (void)fixedPart;
1301    (void)fixedPartLen;
1302}
1303#endif
1304
1305// Used for RDATA comparison
1306typedef struct
1307{
1308    mDNSu16 rdlength;
1309    mDNSu16 rrtype;
1310    mDNSu8 *rdata;
1311} rdataComp;
1312
1313mDNSlocal int rdata_compare(mDNSu8 *const rdata1, mDNSu8 *const rdata2, int rdlen1, int rdlen2)
1314{
1315    int len;
1316    int ret;
1317
1318    len = (rdlen1 < rdlen2) ? rdlen1 : rdlen2;
1319
1320    ret = DNSMemCmp(rdata1, rdata2, len);
1321    if (ret != 0) return ret;
1322
1323    // RDATA is same at this stage. Consider them equal if they are of same length. Otherwise
1324    // decide based on their lengths.
1325    return ((rdlen1 == rdlen2) ? 0 : (rdlen1 < rdlen2) ? -1 : 1);
1326}
1327
1328mDNSlocal int name_compare(mDNSu8 *const rdata1, mDNSu8 *const rdata2, int rdlen1, int rdlen2)
1329{
1330    domainname *n1 = (domainname *)rdata1;
1331    domainname *n2 = (domainname *)rdata2;
1332    mDNSu8 *a = n1->c;
1333    mDNSu8 *b = n2->c;
1334    int count, c1, c2;
1335    int i, j, len;
1336
1337    c1 = CountLabels(n1);
1338    c2 = CountLabels(n2);
1339
1340    count = c1 < c2 ? c1 : c2;
1341
1342    // We can't use SameDomainName as we need to know exactly which is greater/smaller
1343    // for sorting purposes. Hence, we need to compare label by label
1344    for (i = 0; i < count; i++)
1345    {
1346        // Are the lengths same ?
1347        if (*a != *b)
1348        {
1349            debugdnssec("compare_name: returning c1 %d, c2 %d", *a, *b);
1350            return ((*a < *b) ? -1 : 1);
1351        }
1352        len = *a;
1353        rdlen1 -= (len + 1);
1354        rdlen2 -= (len + 1);
1355        if (rdlen1 < 0 || rdlen2 < 0)
1356        {
1357            LogMsg("name_compare: ERROR!! not enough data rdlen1 %d, rdlen2 %d", rdlen1, rdlen2);
1358            return -1;
1359        }
1360        a++; b++;
1361        for (j = 0; j < len; j++)
1362        {
1363            mDNSu8 ac = *a++;
1364            mDNSu8 bc = *b++;
1365            if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
1366            if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
1367            if (ac != bc)
1368            {
1369                debugdnssec("compare_name: returning ac %c, bc %c", ac, bc);
1370                return ((ac < bc) ? -1 : 1);
1371            }
1372        }
1373    }
1374
1375    return 0;
1376}
1377
1378mDNSlocal int srv_compare(rdataComp *const r1, rdataComp *const r2)
1379{
1380    int res;
1381    int length1, length2;
1382
1383    length1 = r1->rdlength;
1384    length2 = r2->rdlength;
1385    // We should have at least priority, weight, port plus 1 byte
1386    if (length1 < 7 || length2 < 7)
1387    {
1388        LogMsg("srv_compare: ERROR!! Length smaller than 7 bytes");
1389        return -1;
1390    }
1391    // Compare priority, weight and port
1392    res = DNSMemCmp(r1->rdata, r2->rdata, 6);
1393    if (res != 0) return res;
1394    length1 -= 6;
1395    length2 -= 6;
1396    return (name_compare(r1->rdata + 6, r2->rdata + 6, length1, length2));
1397}
1398
1399mDNSlocal int tsig_compare(rdataComp *const r1, rdataComp *const r2)
1400{
1401    int offset1, offset2;
1402    int length1, length2;
1403    int res, dlen;
1404
1405    offset1 = offset2 = 0;
1406    length1 = r1->rdlength;
1407    length2 = r2->rdlength;
1408
1409    // we should have at least one byte to start with
1410    if (length1 < 1 || length2 < 1)
1411    {
1412        LogMsg("sig_compare: Length smaller than 18 bytes");
1413        return -1;
1414    }
1415
1416    res = name_compare(r1->rdata, r2->rdata, length1, length2);
1417    if (res != 0) return res;
1418
1419    dlen = DomainNameLength((domainname *)r1->rdata);
1420    offset1 += dlen;
1421    offset2 += dlen;
1422    length1 -= dlen;
1423    length2 -= dlen;
1424
1425    if (length1 <= 1 || length2 <= 1)
1426    {
1427        LogMsg("tsig_compare: data too small to compare length1 %d, length2 %d", length1, length2);
1428        return -1;
1429    }
1430
1431    return (rdata_compare(r1->rdata + offset1, r2->rdata + offset2, length1, length2));
1432}
1433
1434// Compares types that conform to : <length><Value>
1435mDNSlocal int lenval_compare(mDNSu8 *d1, mDNSu8 *d2, int *len1, int *len2, int rem1, int rem2)
1436{
1437    int len;
1438    int res;
1439
1440    if (rem1 <= 1 || rem2 <= 1)
1441    {
1442        LogMsg("lenval_compare: data too small to compare length1 %d, length2 %d", rem1, rem2);
1443        return -1;
1444    }
1445    *len1 = (int)d1[0];
1446    *len2 = (int)d2[0];
1447    len = (*len1 < *len2 ? *len1 : *len2);
1448    res = DNSMemCmp(d1, d2, len + 1);
1449    return res;
1450}
1451
1452// RFC 2915: Order (2) Preference(2) and variable length: Flags Service Regexp Replacement
1453mDNSlocal int naptr_compare(rdataComp *const r1, rdataComp *const r2)
1454{
1455    mDNSu8 *d1 = r1->rdata;
1456    mDNSu8 *d2 = r2->rdata;
1457    int len1, len2, res;
1458    int length1, length2;
1459
1460    length1 = r1->rdlength;
1461    length2 = r2->rdlength;
1462
1463    // Order, Preference plus at least 1 byte
1464    if (length1 < 5 || length2 < 5)
1465    {
1466        LogMsg("naptr_compare: Length smaller than 18 bytes");
1467        return -1;
1468    }
1469    // Compare order and preference
1470    res = DNSMemCmp(d1, d2, 4);
1471    if (res != 0) return res;
1472
1473    d1 += 4;
1474    d2 += 4;
1475    length1 -= 4;
1476    length2 -= 4;
1477
1478    // Compare Flags (including the length byte)
1479    res = lenval_compare(d1, d2, &len1, &len2, length1, length2);
1480    if (res != 0) return res;
1481    d1 += (len1 + 1);
1482    d2 += (len2 + 1);
1483    length1 -= (len1 + 1);
1484    length2 -= (len2 + 1);
1485
1486    // Compare Service (including the length byte)
1487    res = lenval_compare(d1, d2, &len1, &len2, length1, length2);
1488    if (res != 0) return res;
1489    d1 += (len1 + 1);
1490    d2 += (len2 + 1);
1491    length1 -= (len1 + 1);
1492    length2 -= (len2 + 1);
1493
1494    // Compare regexp (including the length byte)
1495    res = lenval_compare(d1, d2, &len1, &len2, length1, length2);
1496    if (res != 0) return res;
1497    d1 += (len1 + 1);
1498    d2 += (len2 + 1);
1499    length1 -= (len1 + 1);
1500    length2 -= (len2 + 1);
1501
1502    // Compare Replacement
1503    return name_compare(d1, d2, length1, length2);
1504}
1505
1506// RFC 1035: MINFO: Two domain names
1507// RFC 1183: RP: Two domain names
1508mDNSlocal int dom2_compare(mDNSu8 *d1, mDNSu8 *d2, int length1, int length2)
1509{
1510    int res, dlen;
1511
1512    // We need at least one byte to start with
1513    if (length1 < 1 || length2 < 1)
1514    {
1515        LogMsg("dom2_compare:1: data too small length1 %d, length2 %d", length1, length2);
1516        return -1;
1517    }
1518    res = name_compare(d1, d2, length1, length2);
1519    if (res != 0) return res;
1520    dlen = DomainNameLength((domainname *)d1);
1521
1522    length1 -= dlen;
1523    length2 -= dlen;
1524    // We need at least one byte to start with
1525    if (length1 < 1 || length2 < 1)
1526    {
1527        LogMsg("dom2_compare:2: data too small length1 %d, length2 %d", length1, length2);
1528        return -1;
1529    }
1530
1531    d1 += dlen;
1532    d2 += dlen;
1533
1534    return name_compare(d1, d2, length1, length2);
1535}
1536
1537// MX : preference (2 bytes), domainname
1538mDNSlocal int mx_compare(rdataComp *const r1, rdataComp *const r2)
1539{
1540    int res;
1541    int length1, length2;
1542
1543    length1 = r1->rdlength;
1544    length2 = r2->rdlength;
1545
1546    // We need at least two bytes + 1 extra byte for the domainname to start with
1547    if (length1 < 3 || length2 < 3)
1548    {
1549        LogMsg("mx_compare: data too small length1 %d, length2 %d", length1, length2);
1550        return -1;
1551    }
1552
1553    res = DNSMemCmp(r1->rdata, r2->rdata, 2);
1554    if (res != 0) return res;
1555    length1 -= 2;
1556    length2 -= 2;
1557    return name_compare(r1->rdata + 2, r2->rdata + 2, length1, length2);
1558}
1559
1560// RFC 2163 (PX) : preference (2 bytes), map822. mapx400 (domainnames)
1561mDNSlocal int px_compare(rdataComp *const r1, rdataComp *const r2)
1562{
1563    int res;
1564
1565    // We need at least two bytes + 1 extra byte for the domainname to start with
1566    if (r1->rdlength < 3 || r2->rdlength < 3)
1567    {
1568        LogMsg("px_compare: data too small length1 %d, length2 %d", r1->rdlength, r2->rdlength);
1569        return -1;
1570    }
1571
1572    res = DNSMemCmp(r1->rdata, r2->rdata, 2);
1573    if (res != 0) return res;
1574
1575    return dom2_compare(r1->rdata + 2, r2->rdata + 2, r1->rdlength - 2, r2->rdlength - 2);
1576}
1577
1578mDNSlocal int soa_compare(rdataComp *r1, rdataComp *r2)
1579{
1580    int res, dlen;
1581    int offset1, offset2;
1582    int length1, length2;
1583
1584    length1 = r1->rdlength;
1585    length2 = r2->rdlength;
1586    offset1 = offset2 = 0;
1587
1588    // We need at least 20 bytes plus 1 byte for each domainname
1589    if (length1 < 22 || length2 < 22)
1590    {
1591        LogMsg("soa_compare:1: data too small length1 %d, length2 %d", length1, length2);
1592        return -1;
1593    }
1594
1595    // There are two domainnames followed by 20 bytes of serial, refresh, retry, expire and min
1596    // Compare the names and then the rest of the bytes
1597
1598    res = name_compare(r1->rdata, r2->rdata, length1, length2);
1599    if (res != 0) return res;
1600
1601    dlen = DomainNameLength((domainname *)r1->rdata);
1602
1603    length1 -= dlen;
1604    length2 -= dlen;
1605    if (length1 < 1 || length2 < 1)
1606    {
1607        LogMsg("soa_compare:2: data too small length1 %d, length2 %d", length1, length2);
1608        return -1;
1609    }
1610    offset1 += dlen;
1611    offset2 += dlen;
1612
1613    res = name_compare(r1->rdata + offset1, r2->rdata + offset2, length1, length2);
1614    if (res != 0) return res;
1615
1616    dlen = DomainNameLength((domainname *)r1->rdata);
1617    length1 -= dlen;
1618    length2 -= dlen;
1619    if (length1 < 20 || length2 < 20)
1620    {
1621        LogMsg("soa_compare:3: data too small length1 %d, length2 %d", length1, length2);
1622        return -1;
1623    }
1624    offset1 += dlen;
1625    offset2 += dlen;
1626
1627    return (rdata_compare(r1->rdata + offset1, r2->rdata + offset2, length1, length2));
1628}
1629
1630// RFC 4034 Section 6.0 states that:
1631//
1632// A canonical RR form and ordering within an RRset are required in order to
1633// construct and verify RRSIG RRs.
1634//
1635// This function is called to order within an RRset. We can't just do a memcmp as
1636// as stated in 6.3. This function is responsible for the third bullet in 6.2, where
1637// the RDATA has to be converted to lower case if it has domain names.
1638mDNSlocal int RDATACompare(const void *rdata1, const void *rdata2)
1639{
1640    rdataComp *r1 = (rdataComp *)rdata1;
1641    rdataComp *r2 = (rdataComp *)rdata2;
1642
1643    if (r1->rrtype != r2->rrtype)
1644    {
1645        LogMsg("RDATACompare: ERROR!! comparing rdata of wrong types type1: %d, type2: %d", r1->rrtype, r2->rrtype);
1646        return -1;
1647    }
1648    switch (r1->rrtype)
1649    {
1650    case kDNSType_A:                // 1. Address Record
1651    case kDNSType_NULL:             // 10 NULL RR
1652    case kDNSType_WKS:              // 11 Well-known-service
1653    case kDNSType_HINFO:            // 13 Host information
1654    case kDNSType_TXT:              // 16 Arbitrary text string
1655    case kDNSType_X25:              // 19 X_25 calling address
1656    case kDNSType_ISDN:             // 20 ISDN calling address
1657    case kDNSType_NSAP:             // 22 NSAP address
1658    case kDNSType_KEY:              // 25 Security key
1659    case kDNSType_GPOS:             // 27 Geographical position (withdrawn)
1660    case kDNSType_AAAA:             // 28 IPv6 Address
1661    case kDNSType_LOC:              // 29 Location Information
1662    case kDNSType_EID:              // 31 Endpoint identifier
1663    case kDNSType_NIMLOC:           // 32 Nimrod Locator
1664    case kDNSType_ATMA:             // 34 ATM Address
1665    case kDNSType_CERT:             // 37 Certification record
1666    case kDNSType_A6:               // 38 IPv6 Address (deprecated)
1667    case kDNSType_SINK:             // 40 Kitchen sink (experimental)
1668    case kDNSType_OPT:              // 41 EDNS0 option (meta-RR)
1669    case kDNSType_APL:              // 42 Address Prefix List
1670    case kDNSType_DS:               // 43 Delegation Signer
1671    case kDNSType_SSHFP:            // 44 SSH Key Fingerprint
1672    case kDNSType_IPSECKEY:         // 45 IPSECKEY
1673    case kDNSType_RRSIG:            // 46 RRSIG
1674    case kDNSType_NSEC:             // 47 Denial of Existence
1675    case kDNSType_DNSKEY:           // 48 DNSKEY
1676    case kDNSType_DHCID:            // 49 DHCP Client Identifier
1677    case kDNSType_NSEC3:            // 50 Hashed Authenticated Denial of Existence
1678    case kDNSType_NSEC3PARAM:       // 51 Hashed Authenticated Denial of Existence
1679    case kDNSType_HIP:              // 55 Host Identity Protocol
1680    case kDNSType_SPF:              // 99 Sender Policy Framework for E-Mail
1681    default:
1682        return rdata_compare(r1->rdata, r2->rdata, r1->rdlength, r2->rdlength);
1683    case kDNSType_NS:               //  2 Name Server
1684    case kDNSType_MD:               //  3 Mail Destination
1685    case kDNSType_MF:               //  4 Mail Forwarder
1686    case kDNSType_CNAME:            //  5 Canonical Name
1687    case kDNSType_MB:               //  7 Mailbox
1688    case kDNSType_MG:               //  8 Mail Group
1689    case kDNSType_MR:               //  9 Mail Rename
1690    case kDNSType_PTR:              // 12 Domain name pointer
1691    case kDNSType_NSAP_PTR:         // 23 Reverse NSAP lookup (deprecated)
1692    case kDNSType_DNAME:            // 39 Non-terminal DNAME (for IPv6)
1693        return name_compare(r1->rdata, r2->rdata, r1->rdlength, r2->rdlength);
1694    case kDNSType_SRV:              // 33 Service record
1695        return srv_compare(r1, r2);
1696    case kDNSType_SOA:              //  6 Start of Authority
1697        return soa_compare(r1, r2);
1698
1699    case kDNSType_RP:               // 17 Responsible person
1700    case kDNSType_MINFO:            // 14 Mailbox information
1701        return dom2_compare(r1->rdata, r2->rdata, r1->rdlength, r2->rdlength);
1702    case kDNSType_MX:               // 15 Mail Exchanger
1703    case kDNSType_AFSDB:            // 18 AFS cell database
1704    case kDNSType_RT:               // 21 Router
1705    case kDNSType_KX:               // 36 Key Exchange
1706        return mx_compare(r1, r2);
1707    case kDNSType_PX:               // 26 X.400 mail mapping
1708        return px_compare(r1, r2);
1709    case kDNSType_NAPTR:            // 35 Naming Authority PoinTeR
1710        return naptr_compare(r1, r2);
1711    case kDNSType_TKEY:             // 249 Transaction key
1712    case kDNSType_TSIG:             // 250 Transaction signature
1713        // TSIG and TKEY have a domainname followed by data
1714        return tsig_compare(r1, r2);
1715    // TBD: We are comparing them as opaque types, perhaps not right
1716    case kDNSType_SIG:              // 24 Security signature
1717    case kDNSType_NXT:              // 30 Next domain (security)
1718        LogMsg("RDATACompare: WARNING!! explicit support has not been added, using default");
1719        return rdata_compare(r1->rdata, r2->rdata, r1->rdlength, r2->rdlength);
1720    }
1721}
1722
1723
1724
1725// RFC 4034 section 6.2 requirement for verifying signature.
1726//
1727// 3. if the type of the RR is NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
1728// HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
1729// SRV, DNAME, A6, RRSIG, or NSEC, all uppercase US-ASCII letters in
1730// the DNS names contained within the RDATA are replaced by the
1731// corresponding lowercase US-ASCII letters;
1732//
1733// NSEC and HINFO is not needed as per dnssec-bis update. RRSIG is done elsewhere
1734// as part of signature verification
1735mDNSlocal void ConvertRDATAToCanonical(mDNSu16 rrtype, mDNSu16 rdlength, mDNSu8 *rdata)
1736{
1737    domainname name;
1738    int len;
1739    mDNSu8 *origRdata = rdata;
1740
1741    // Ensure that we have at least one byte of data to examine and modify.
1742
1743    if (!rdlength) { LogMsg("ConvertRDATAToCanonical: rdlength zero for rrtype %s", DNSTypeName(rrtype)); return; }
1744
1745    switch (rrtype)
1746    {
1747    // Not adding suppot for A6 as it is deprecated
1748    case kDNSType_A6:               // 38 IPv6 Address (deprecated)
1749    default:
1750        debugdnssec("ConvertRDATAToCanonical: returning from default %s", DNSTypeName(rrtype));
1751        return;
1752    case kDNSType_NS:               //  2 Name Server
1753    case kDNSType_MD:               //  3 Mail Destination
1754    case kDNSType_MF:               //  4 Mail Forwarder
1755    case kDNSType_CNAME:            //  5 Canonical Name
1756    case kDNSType_MB:               //  7 Mailbox
1757    case kDNSType_MG:               //  8 Mail Group
1758    case kDNSType_MR:               //  9 Mail Rename
1759    case kDNSType_PTR:              // 12 Domain name pointer
1760    case kDNSType_DNAME:            // 39 Non-terminal DNAME (for IPv6)
1761    case kDNSType_NXT:              // 30 Next domain (security)
1762
1763    // TSIG and TKEY are not mentioned in RFC 4034, but we just leave it here
1764    case kDNSType_TSIG:             // 250 Transaction signature
1765    case kDNSType_TKEY:             // 249 Transaction key
1766
1767        if (DNSNameToLowerCase((domainname *)rdata, &name) != mStatus_NoError)
1768        {
1769            LogMsg("ConvertRDATAToCanonical: ERROR!! DNSNameToLowerCase failed");
1770            return;
1771        }
1772        AssignDomainName((domainname *)rdata, &name);
1773        return;
1774    case kDNSType_MX:               // 15 Mail Exchanger
1775    case kDNSType_AFSDB:            // 18 AFS cell database
1776    case kDNSType_RT:               // 21 Router
1777    case kDNSType_KX:               // 36 Key Exchange
1778
1779        // format: preference - 2 bytes, followed by name
1780        // Ensure that we have at least 3 bytes (preference + 1 byte for the domain name)
1781        if (rdlength <= 3)
1782        {
1783            LogMsg("ConvertRDATAToCanonical:MX: rdlength %d for rrtype %s too small", rdlength, DNSTypeName(rrtype));
1784            return;
1785        }
1786        if (DNSNameToLowerCase((domainname *)(rdata + 2), &name) != mStatus_NoError)
1787        {
1788            LogMsg("ConvertRDATAToCanonical: MX: ERROR!! DNSNameToLowerCase failed");
1789            return;
1790        }
1791        AssignDomainName((domainname *)(rdata + 2), &name);
1792        return;
1793    case kDNSType_SRV:              // 33 Service record
1794        // format : priority, weight and port - 6 bytes, followed by name
1795        if (rdlength <= 7)
1796        {
1797            LogMsg("ConvertRDATAToCanonical:SRV: rdlength %d for rrtype %s too small", rdlength, DNSTypeName(rrtype));
1798            return;
1799        }
1800        if (DNSNameToLowerCase((domainname *)(rdata + 6), &name) != mStatus_NoError)
1801        {
1802            LogMsg("ConvertRDATAToCanonical: SRV: ERROR!! DNSNameToLowerCase failed");
1803            return;
1804        }
1805        AssignDomainName((domainname *)(rdata + 6), &name);
1806        return;
1807    case kDNSType_PX:               // 26 X.400 mail mapping
1808        if (rdlength <= 3)
1809        {
1810            LogMsg("ConvertRDATAToCanonical:PX: rdlength %d for rrtype %s too small", rdlength, DNSTypeName(rrtype));
1811            return;
1812        }
1813        // Preference followed by two domain names
1814        rdata += 2;
1815    /* FALLTHROUGH */
1816    case kDNSType_RP:               // 17 Responsible person
1817    case kDNSType_SOA:              //  6 Start of Authority
1818    case kDNSType_MINFO:            // 14 Mailbox information
1819        if (DNSNameToLowerCase((domainname *)rdata, &name) != mStatus_NoError)
1820        {
1821            LogMsg("ConvertRDATAToCanonical: SOA1: ERROR!! DNSNameToLowerCase failed");
1822            return;
1823        }
1824
1825        AssignDomainName((domainname *)rdata, &name);
1826        len = DomainNameLength((domainname *)rdata);
1827        if (rdlength <= len + 1)
1828        {
1829            LogMsg("ConvertRDATAToCanonical:RP: rdlength %d for rrtype %s too small", rdlength, DNSTypeName(rrtype));
1830            return;
1831        }
1832        rdata += len;
1833
1834        if (DNSNameToLowerCase((domainname *)rdata, &name) != mStatus_NoError)
1835        {
1836            LogMsg("ConvertRDATAToCanonical: SOA2: ERROR!! DNSNameToLowerCase failed");
1837            return;
1838        }
1839        AssignDomainName((domainname *)rdata, &name);
1840        return;
1841    case kDNSType_NAPTR:            // 35 Naming Authority Pointer
1842        // order and preference
1843        rdata += 4;
1844        // Flags (including the length byte)
1845        rdata += (((int) rdata[0]) + 1);
1846        // Service (including the length byte)
1847        rdata += (((int) rdata[0]) + 1);
1848        // regexp (including the length byte)
1849        rdata += (((int) rdata[0]) + 1);
1850
1851        // Replacement field is a domainname. If we have at least one more byte, then we are okay.
1852        if ((origRdata + rdlength) < rdata + 1)
1853        {
1854            LogMsg("ConvertRDATAToCanonical:NAPTR: origRdata %p, rdlength %d, rdata %p for rrtype %s too small", origRdata, rdlength, rdata, DNSTypeName(rrtype));
1855            return;
1856        }
1857        if (DNSNameToLowerCase((domainname *)rdata, &name) != mStatus_NoError)
1858        {
1859            LogMsg("ConvertRDATAToCanonical: NAPTR2: ERROR!! DNSNameToLowerCase failed");
1860            return;
1861        }
1862        AssignDomainName((domainname *)rdata, &name);
1863    case kDNSType_SIG:              // 24 Security signature
1864        // format: <18 bytes> <domainname> <data>
1865        if (rdlength <= 19)
1866        {
1867            LogMsg("ConvertRDATAToCanonical:SIG: rdlength %d for rrtype %s too small", rdlength, DNSTypeName(rrtype));
1868            return;
1869        }
1870        // Preference followed by two domain names
1871        rdata += 18;
1872        if (DNSNameToLowerCase((domainname *)rdata, &name) != mStatus_NoError)
1873        {
1874            LogMsg("ConvertRDATAToCanonical: SIG: ERROR!! DNSNameToLowerCase failed");
1875            return;
1876        }
1877        AssignDomainName((domainname *)rdata, &name);
1878        return;
1879    }
1880}
1881
1882mDNSlocal mDNSBool ValidateSignatureWithKey(DNSSECVerifier *dv, RRVerifier *rrset, RRVerifier *keyv, RRVerifier *sig)
1883{
1884    domainname name;
1885    domainname signerName;
1886    int labels;
1887    mDNSu8 fixedPart[MAX_DOMAIN_NAME + 8];  // domainname + type + class + ttl
1888    int fixedPartLen;
1889    RRVerifier *tmp;
1890    int nrrsets;
1891    rdataComp *ptr, *start, *p;
1892    rdataRRSig *rrsig;
1893    rdataDNSKey *key;
1894    int i;
1895    int sigNameLen;
1896    mDNSu16 temp;
1897    mStatus algRet;
1898
1899
1900    key = (rdataDNSKey *)keyv->rdata;
1901    rrsig = (rdataRRSig *)sig->rdata;
1902
1903    LogDNSSEC("ValidateSignatureWithKey: Validating signature with key with tag %d", (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength));
1904
1905    if (DNSNameToLowerCase((domainname *)&rrsig->signerName, &signerName) != mStatus_NoError)
1906    {
1907        LogMsg("ValidateSignatureWithKey: ERROR!! cannot convert signer name to lower case");
1908        return mDNSfalse;
1909    }
1910
1911    if (DNSNameToLowerCase((domainname *)&rrset->name, &name) != mStatus_NoError)
1912    {
1913        LogMsg("ValidateSignatureWithKey: ERROR!! cannot convert rrset name to lower case");
1914        return mDNSfalse;
1915    }
1916
1917    sigNameLen = DomainNameLength(&signerName);
1918    labels = CountLabels(&name);
1919    // RFC 4034: RRSIG validation
1920    //
1921    // signature = sign(RRSIG_RDATA | RR(1) | RR(2)... )
1922    //
1923    // where RRSIG_RDATA excludes the signature and signer name in canonical form
1924
1925    if (dv->ctx) AlgDestroy(dv->ctx);
1926    dv->ctx = AlgCreate(CRYPTO_ALG, rrsig->alg);
1927    if (!dv->ctx)
1928    {
1929        LogDNSSEC("ValidateSignatureWithKey: ERROR!! No algorithm support for %d", rrsig->alg);
1930        return mDNSfalse;
1931    }
1932    AlgAdd(dv->ctx, (const mDNSu8 *)rrsig, RRSIG_FIXED_SIZE);
1933    AlgAdd(dv->ctx, signerName.c, sigNameLen);
1934
1935    if (labels - rrsig->labels > 0)
1936    {
1937        domainname *d;
1938        LogDNSSEC("ValidateSignatureWithKey: ====splitting labels %d, rrsig->labels %d====", labels,rrsig->labels);
1939        d = (domainname *)SkipLeadingLabels(&name, labels - rrsig->labels);
1940        fixedPart[0] = 1;
1941        fixedPart[1] = '*';
1942        AssignDomainName((domainname *)(fixedPart + 2), d);
1943        fixedPartLen = DomainNameLength(d) + 2;
1944        // See RFC 4034 section 3.1.3. If you are looking up *.example.com,
1945        // the labels count in the RRSIG is 2, but this is not considered as
1946        // a wildcard answer
1947        if (name.c[0] != 1 || name.c[1] != '*')
1948        {
1949            LogDNSSEC("ValidateSignatureWithKey: Wildcard exapnded answer for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
1950            dv->flags |= WILDCARD_PROVES_ANSWER_EXPANDED;
1951            dv->wildcardName = (domainname *)SkipLeadingLabels(&dv->origName, labels - rrsig->labels);
1952            if (!dv->wildcardName) return mDNSfalse;
1953        }
1954    }
1955    else
1956    {
1957        debugdnssec("ValidateSignatureWithKey: assigning domainname");
1958        AssignDomainName((domainname *)fixedPart, &name);
1959        fixedPartLen = DomainNameLength(&name);
1960    }
1961    temp = swap16(rrset->rrtype);
1962    mDNSPlatformMemCopy(fixedPart + fixedPartLen, (mDNSu8 *)&temp, sizeof(rrset->rrtype));
1963    fixedPartLen += sizeof(rrset->rrtype);
1964    temp = swap16(rrset->rrclass);
1965    mDNSPlatformMemCopy(fixedPart + fixedPartLen, (mDNSu8 *)&temp, sizeof(rrset->rrclass));
1966    fixedPartLen += sizeof(rrset->rrclass);
1967    mDNSPlatformMemCopy(fixedPart + fixedPartLen, (mDNSu8 *)&rrsig->origTTL, sizeof(rrsig->origTTL));
1968    fixedPartLen += sizeof(rrsig->origTTL);
1969
1970
1971    for (tmp = rrset, nrrsets = 0; tmp; tmp = tmp->next)
1972        nrrsets++;
1973
1974    tmp = rrset;
1975    start = ptr = mDNSPlatformMemAllocate(nrrsets * sizeof (rdataComp));
1976    debugdnssec("ValidateSignatureWithKey: start %p, nrrsets %d", start, nrrsets);
1977    if (ptr)
1978    {
1979        // Need to initialize for failure case below
1980        mDNSPlatformMemZero(ptr, nrrsets * (sizeof (rdataComp)));
1981        while (tmp)
1982        {
1983            ptr->rdlength = tmp->rdlength;
1984            ptr->rrtype = tmp->rrtype;
1985            if (ptr->rdlength)
1986            {
1987                ptr->rdata = mDNSPlatformMemAllocate(ptr->rdlength);
1988                if (ptr->rdata)
1989                {
1990                    mDNSPlatformMemCopy(ptr->rdata, tmp->rdata, tmp->rdlength);
1991                }
1992                else
1993                {
1994                    for (i = 0; i < nrrsets; i++)
1995                        if (start[i].rdata) mDNSPlatformMemFree(start[i].rdata);
1996                    mDNSPlatformMemFree(start);
1997                    LogMsg("ValidateSignatureWithKey:1: ERROR!! RDATA memory alloation failure");
1998                    return mDNSfalse;
1999                }
2000            }
2001            ptr++;
2002            tmp = tmp->next;
2003        }
2004    }
2005    else
2006    {
2007        LogMsg("ValidateSignatureWithKey:2: ERROR!! RDATA memory alloation failure");
2008        return mDNSfalse;
2009    }
2010
2011    PrintFixedSignInfo(rrsig, &signerName, sigNameLen, fixedPart, fixedPartLen);
2012
2013    mDNSPlatformQsort(start, nrrsets, sizeof(rdataComp), RDATACompare);
2014    for (p = start, i = 0; i < nrrsets; p++, i++)
2015    {
2016        int rdlen;
2017
2018        // The array is sorted and hence checking adjacent entries for duplicate is sufficient
2019        if (i > 0)
2020        {
2021            rdataComp *q = p - 1;
2022            if (!RDATACompare((void *)p, (void *)q)) continue;
2023        }
2024
2025        // Add the fixed part
2026        AlgAdd(dv->ctx, (const mDNSu8 *)fixedPart, fixedPartLen);
2027
2028        // Add the rdlength
2029        rdlen = swap16(p->rdlength);
2030        AlgAdd(dv->ctx, (const mDNSu8 *)&rdlen, sizeof(mDNSu16));
2031
2032        ConvertRDATAToCanonical(p->rrtype, p->rdlength, p->rdata);
2033
2034        PrintVarSignInfo(rdlen, p->rdata);
2035        AlgAdd(dv->ctx, (const mDNSu8 *)p->rdata, p->rdlength);
2036    }
2037    // free the memory as we don't need it anymore
2038    for (i = 0; i < nrrsets; i++)
2039        if (start[i].rdata) mDNSPlatformMemFree(start[i].rdata);
2040    mDNSPlatformMemFree(start);
2041
2042    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);
2043    AlgDestroy(dv->ctx);
2044    dv->ctx = mDNSNULL;
2045    if (algRet != mStatus_NoError)
2046    {
2047        LogDNSSEC("ValidateSignatureWithKey: AlgVerify failed for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
2048        // Reset the state if we set any above.
2049        if (dv->flags & WILDCARD_PROVES_ANSWER_EXPANDED)
2050        {
2051            dv->flags &= ~WILDCARD_PROVES_ANSWER_EXPANDED;
2052            dv->wildcardName = mDNSNULL;
2053        }
2054        return mDNSfalse;
2055    }
2056    return mDNStrue;
2057}
2058
2059// Walk all the keys and for each key walk all the RRSIGS that signs the original rrset
2060mDNSlocal mStatus ValidateSignature(DNSSECVerifier *dv, RRVerifier **resultKey, RRVerifier **resultRRSIG)
2061{
2062    RRVerifier *rrset;
2063    RRVerifier *keyv;
2064    RRVerifier *rrsigv;
2065    RRVerifier *sig;
2066    rdataDNSKey *key;
2067    rdataRRSig *rrsig;
2068    mDNSu16 tag;
2069
2070    rrset = dv->rrset;
2071    sig = dv->rrsig;
2072
2073    for (keyv = dv->key; keyv; keyv = keyv->next)
2074    {
2075        key = (rdataDNSKey *)keyv->rdata;
2076        tag = (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength);
2077        for (rrsigv = sig; rrsigv; rrsigv = rrsigv->next)
2078        {
2079            rrsig = (rdataRRSig *)rrsigv->rdata;
2080            // 7. The RRSIG RR's Signer's Name, Algorithm, and Key Tag fields MUST match the owner
2081            //    name, algorithm, and key tag for some DNSKEY RR in the zone's apex DNSKEY RRset.
2082            if (!SameDomainName((domainname *)&rrsig->signerName, &keyv->name))
2083            {
2084                debugdnssec("ValidateSignature: name mismatch");
2085                continue;
2086            }
2087            if (key->alg != rrsig->alg)
2088            {
2089                debugdnssec("ValidateSignature: alg mismatch");
2090                continue;
2091            }
2092            if (tag != swap16(rrsig->keyTag))
2093            {
2094                debugdnssec("ValidateSignature: keyTag mismatch rrsig tag %d(0x%x), keyTag %d(0x%x)", swap16(rrsig->keyTag),
2095                            swap16(rrsig->keyTag), tag, tag);
2096                continue;
2097            }
2098            // 8. The matching DNSKEY RR MUST be present in the zone's apex DNSKEY RRset, and MUST
2099            //    have the Zone Flag bit (DNSKEY RDATA Flag bit 7) set.
2100            if (!((swap16(key->flags)) & DNSKEY_ZONE_SIGN_KEY))
2101            {
2102                debugdnssec("ValidateSignature: ZONE flag bit not set");
2103                continue;
2104            }
2105            debugdnssec("ValidateSignature:Found a key and RRSIG tag: %d", tag);
2106            if (ValidateSignatureWithKey(dv, rrset, keyv, rrsigv))
2107            {
2108                LogDNSSEC("ValidateSignature: Validated successfully with key tag %d", tag);
2109                *resultKey = keyv;
2110                *resultRRSIG = rrsigv;
2111                return mStatus_NoError;
2112            }
2113        }
2114    }
2115    *resultKey = mDNSNULL;
2116    *resultRRSIG = mDNSNULL;
2117    return mStatus_NoSuchRecord;
2118}
2119
2120mDNSlocal mDNSBool ValidateSignatureWithKeyForAllRRSigs(DNSSECVerifier *dv, RRVerifier *rrset, RRVerifier *keyv, RRVerifier *sig)
2121{
2122    rdataRRSig *rrsig;
2123    mDNSu16 tag;
2124
2125    while (sig)
2126    {
2127        rrsig = (rdataRRSig *)sig->rdata;
2128        tag = (mDNSu16)keytag(keyv->rdata, keyv->rdlength);
2129        if (tag == swap16(rrsig->keyTag))
2130        {
2131            if (ValidateSignatureWithKey(dv, rrset, keyv, sig))
2132            {
2133                LogDNSSEC("ValidateSignatureWithKeyForAllRRSigs: Validated");
2134                return mDNStrue;
2135            }
2136        }
2137        sig = sig->next;
2138    }
2139    return mDNSfalse;
2140}
2141
2142mDNSlocal mStatus ValidateDS(DNSSECVerifier *dv)
2143{
2144    mDNSu8 *digest;
2145    int digestLen;
2146    domainname name;
2147    rdataRRSig *rrsig;
2148    rdataDS *ds;
2149    rdataDNSKey *key;
2150    RRVerifier *keyv;
2151    RRVerifier *dsv;
2152    mStatus algRet;
2153
2154    rrsig = (rdataRRSig *)dv->rrsig->rdata;
2155
2156    // Walk all the DS Records to see if we have a matching DNS KEY record that verifies
2157    // the hash. If we find one, verify that this key was used to sign the KEY rrsets in
2158    // this zone. Loop till we find one.
2159    for (dsv = dv->ds; dsv; dsv = dsv->next)
2160    {
2161        ds = (rdataDS *)dsv->rdata;
2162        if ((ds->digestType != SHA1_DIGEST_TYPE) && (ds->digestType != SHA256_DIGEST_TYPE))
2163        {
2164            LogDNSSEC("ValidateDS: Unsupported digest %d", ds->digestType);
2165            return mStatus_BadParamErr;
2166        }
2167        else debugdnssec("ValidateDS: digest type %d", ds->digestType);
2168        for (keyv = dv->key; keyv; keyv = keyv->next)
2169        {
2170            key = (rdataDNSKey *)keyv->rdata;
2171            mDNSu16 tag = (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength);
2172            if (tag != swap16(ds->keyTag))
2173            {
2174                debugdnssec("ValidateDS:Not a valid keytag %d", tag);
2175                continue;
2176            }
2177
2178            if (DNSNameToLowerCase((domainname *)&rrsig->signerName, &name) != mStatus_NoError)
2179            {
2180                LogMsg("ValidateDS: ERROR!! cannot convert to lower case");
2181                continue;
2182            }
2183
2184            if (dv->ctx) AlgDestroy(dv->ctx);
2185            dv->ctx = AlgCreate(DIGEST_ALG, ds->digestType);
2186            if (!dv->ctx)
2187            {
2188                LogMsg("ValidateDS: ERROR!! Cannot allocate context");
2189                continue;
2190            }
2191            digest = (mDNSu8 *)&ds->digest;
2192            digestLen = dsv->rdlength - DS_FIXED_SIZE;
2193
2194            AlgAdd(dv->ctx, name.c, DomainNameLength(&name));
2195            AlgAdd(dv->ctx, (const mDNSu8 *)key, keyv->rdlength);
2196
2197            algRet = AlgVerify(dv->ctx, mDNSNULL, 0, digest, digestLen);
2198            AlgDestroy(dv->ctx);
2199            dv->ctx = mDNSNULL;
2200            if (algRet == mStatus_NoError)
2201            {
2202                LogDNSSEC("ValidateDS: DS Validated Successfully, need to verify the key %d", tag);
2203                // We found the DNS KEY that is authenticated by the DS in our parent zone. Check to see if this key
2204                // was used to sign the DNS KEY RRSET. If so, then the keys in our DNS KEY RRSET are valid
2205                if (ValidateSignatureWithKeyForAllRRSigs(dv, dv->key, keyv, dv->rrsigKey))
2206                {
2207                    LogDNSSEC("ValidateDS: DS Validated Successfully %d", tag);
2208                    return mStatus_NoError;
2209                }
2210            }
2211        }
2212    }
2213    return mStatus_NoSuchRecord;
2214}
2215
2216mDNSlocal mDNSBool UnlinkRRVerifier(DNSSECVerifier *dv, RRVerifier *elem, RRVerifierSet set)
2217{
2218    RRVerifier **v;
2219
2220    switch (set)
2221    {
2222    case RRVS_rr:
2223        v = &dv->rrset;
2224        break;
2225    case RRVS_rrsig:
2226        v = &dv->rrsig;
2227        break;
2228    case RRVS_key:
2229        v = &dv->key;
2230        break;
2231    case RRVS_rrsig_key:
2232        v = &dv->rrsigKey;
2233        break;
2234    case RRVS_ds:
2235        v = &dv->ds;
2236        break;
2237    default:
2238        LogMsg("UnlinkRRVerifier: ERROR!! default case %d", set);
2239        return mDNSfalse;
2240    }
2241    while (*v && *v != elem)
2242        v = &(*v)->next;
2243    if (!(*v))
2244    {
2245        LogMsg("UnlinkRRVerifier: ERROR!! cannot find element in set %d", set);
2246        return mDNSfalse;
2247    }
2248    *v = elem->next;                  // Cut this record from the list
2249    elem->next = mDNSNULL;
2250    return mDNStrue;
2251}
2252
2253// This can link a single AuthChain element or a list of AuthChain elements to
2254// DNSSECVerifier. The latter happens when we have multiple NSEC proofs and
2255// we gather up all the proofs in one place.
2256mDNSexport void AuthChainLink(DNSSECVerifier *dv, AuthChain *ae)
2257{
2258    AuthChain *head;
2259
2260    LogDNSSEC("AuthChainLink: called");
2261
2262    head = ae;
2263    // Get to the last element
2264    while (ae->next)
2265        ae = ae->next;
2266    *(dv->actail) = head;                // Append this record to tail of auth chain
2267    dv->actail = &(ae->next);          // Advance tail pointer
2268}
2269
2270mDNSlocal mDNSBool AuthChainAdd(DNSSECVerifier *dv, RRVerifier *resultKey, RRVerifier *resultRRSig)
2271{
2272    AuthChain *ae;
2273    rdataDNSKey *key;
2274    mDNSu16 tag;
2275
2276    if (!dv->rrset || !resultKey || !resultRRSig)
2277    {
2278        LogMsg("AuthChainAdd: ERROR!! input argument NULL");
2279        return mDNSfalse;
2280    }
2281
2282    // Unlink resultKey and resultRRSig and store as part of AuthChain
2283    if (!UnlinkRRVerifier(dv, resultKey, RRVS_key))
2284    {
2285        LogMsg("AuthChainAdd: ERROR!! cannot unlink key");
2286        return mDNSfalse;
2287    }
2288    if (!UnlinkRRVerifier(dv, resultRRSig, RRVS_rrsig))
2289    {
2290        LogMsg("AuthChainAdd: ERROR!! cannot unlink rrsig");
2291        return mDNSfalse;
2292    }
2293
2294    ae = mDNSPlatformMemAllocate(sizeof(AuthChain));
2295    if (!ae)
2296    {
2297        LogMsg("AuthChainAdd: AuthChain alloc failure");
2298        return mDNSfalse;
2299    }
2300
2301    ae->next  = mDNSNULL;
2302    ae->rrset = dv->rrset;
2303    dv->rrset = mDNSNULL;
2304
2305    ae->rrsig = resultRRSig;
2306    ae->key   = resultKey;
2307
2308    key = (rdataDNSKey *)resultKey->rdata;
2309    tag = (mDNSu16)keytag((mDNSu8 *)key, resultKey->rdlength);
2310    LogDNSSEC("AuthChainAdd: inserting AuthChain element with rrset %##s (%s), DNSKEY tag %d", ae->rrset->name.c, DNSTypeName(ae->rrset->rrtype), tag);
2311
2312    AuthChainLink(dv, ae);
2313    return mDNStrue;
2314}
2315
2316// RFC 4035: Section 5.3.3
2317//
2318// If the resolver accepts the RRset as authentic, the validator MUST set the TTL of
2319// the RRSIG RR and each RR in the authenticated RRset to a value no greater than the
2320// minimum of:
2321//
2322//   o  the RRset's TTL as received in the response;
2323//
2324//   o  the RRSIG RR's TTL as received in the response;
2325//
2326//   o  the value in the RRSIG RR's Original TTL field; and
2327//
2328//   o  the difference of the RRSIG RR's Signature Expiration time and the
2329//      current time.
2330mDNSlocal void SetTTLRRSet(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status)
2331{
2332    DNSQuestion question;
2333    CacheRecord *rr;
2334    RRVerifier *rrsigv;
2335    rdataRRSig *rrsig;
2336    mDNSu32 slot;
2337    CacheGroup *cg;
2338    int sigNameLen, len;
2339    mDNSu8 *ptr;
2340    mDNSu32 rrTTL, rrsigTTL, rrsigOrigTTL, rrsigTimeTTL;
2341    domainname *qname;
2342    mDNSu16 qtype;
2343    CacheRecord *rrsigRR;
2344    mDNSs32 now;
2345
2346    debugdnssec("SetTTLRRSet called");
2347
2348    if (status == DNSSEC_Insecure || status == DNSSEC_Indeterminate)
2349    {
2350        LogDNSSEC("SetTTLRRSET: not setting ttl for status %s", DNSSECStatusName(status));
2351        return;
2352    }
2353
2354    mDNS_Lock(m);
2355    now = m->timenow;
2356    mDNS_Unlock(m);
2357
2358    mDNSPlatformMemZero(&question, sizeof(DNSQuestion));
2359    rrTTL = rrsigTTL = rrsigOrigTTL = rrsigTimeTTL = 0;
2360
2361    // 1. Locate the rrset name and get its TTL (take the first one as a representative
2362    // of the rrset). Ideally, we should set the TTL on the first validation. Instead,
2363    // we do it whenever we validate which happens whenever a ValidationRequired question
2364    // finishes validation.
2365    qname = &dv->origName;
2366    qtype = dv->origType;
2367
2368    question.ThisQInterval = -1;
2369    InitializeQuestion(m, &question, dv->InterfaceID, qname, qtype, mDNSNULL, mDNSNULL);
2370    slot = HashSlot(&question.qname);
2371    cg = CacheGroupForName(m, slot, question.qnamehash, &question.qname);
2372
2373    if (!cg)
2374    {
2375        LogMsg("SetTTLRRSet cg NULL for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
2376        return;
2377    }
2378
2379    for (rr = cg->members; rr; rr = rr->next)
2380        if (SameNameRecordAnswersQuestion(&rr->resrec, &question))
2381        {
2382            // originalttl is never touched. The actual TTL is derived based on when it was
2383            // received.
2384            rrTTL = rr->resrec.rroriginalttl - (now - rr->TimeRcvd)/mDNSPlatformOneSecond;
2385            break;
2386        }
2387
2388    // Should we check to see if it matches the record in dv->ac->rrset ?
2389    if (!rr)
2390    {
2391        LogMsg("SetTTLRRSet: ERROR!! cannot locate main rrset for %##s (%s)", qname->c, DNSTypeName(qtype));
2392        return;
2393    }
2394
2395
2396    // 2. Get the RRSIG ttl. For NSEC records we need to get the NSEC record's TTL as
2397    // the negative cache record that we created may not be right.
2398
2399    if (dv->ac && dv->ac->rrsig)
2400    {
2401        rrsigv = dv->ac->rrsig;
2402        rrsig = (rdataRRSig *)rrsigv->rdata;
2403        sigNameLen = DomainNameLength((domainname *)&rrsig->signerName);
2404        // pointer to signature and the length
2405        ptr = (mDNSu8 *)(rrsigv->rdata + sigNameLen + RRSIG_FIXED_SIZE);
2406        len = rrsigv->rdlength - RRSIG_FIXED_SIZE - sigNameLen;
2407    }
2408    else
2409    {
2410        rrsigv = mDNSNULL;
2411        rrsig = mDNSNULL;
2412        ptr = mDNSNULL;
2413        sigNameLen = len = 0;
2414    }
2415
2416    rrsigRR = mDNSNULL;
2417    if (rr->resrec.RecordType == kDNSRecordTypePacketNegative && status == DNSSEC_Secure)
2418    {
2419        CacheRecord *ncr;
2420        rrTTL = 0;
2421        for (ncr = rr->nsec; ncr; ncr = ncr->next)
2422        {
2423            if (ncr->resrec.rrtype == kDNSType_NSEC || ncr->resrec.rrtype == kDNSType_NSEC3)
2424            {
2425                rrTTL = ncr->resrec.rroriginalttl - (now - ncr->TimeRcvd)/mDNSPlatformOneSecond;
2426                debugdnssec("SetTTLRRSet: NSEC TTL %u", rrTTL);
2427            }
2428            // Note: we can't use dv->origName here as the NSEC record's RRSIG may not match
2429            // the original name
2430            if (rrsigv && ncr->resrec.rrtype == kDNSType_RRSIG && SameDomainName(ncr->resrec.name, &rrsigv->name))
2431            {
2432                RDataBody2 *rdb = (RDataBody2 *)ncr->resrec.rdata->u.data;
2433                rdataRRSig *sig = (rdataRRSig *)rdb->data;
2434                if (rrsigv->rdlength != ncr->resrec.rdlength)
2435                {
2436                    debugdnssec("SetTTLRRSet length mismatch");
2437                    continue;
2438                }
2439                if (mDNSPlatformMemSame(sig, rrsig, rrsigv->rdlength))
2440                {
2441                    mDNSu32 remain = (now - ncr->TimeRcvd)/mDNSPlatformOneSecond;
2442                    rrsigTTL = ncr->resrec.rroriginalttl - remain;
2443                    rrsigOrigTTL = swap32(rrsig->origTTL) - remain;
2444                    rrsigTimeTTL = swap32(rrsig->sigExpireTime) - swap32(rrsig->sigInceptTime);
2445                }
2446            }
2447            if (rrTTL && (!rrsigv || rrsigTTL)) break;
2448        }
2449    }
2450    else if (rrsigv)
2451    {
2452        // Look for the matching RRSIG so that we can get its TTL
2453        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
2454            if (rr->resrec.rrtype == kDNSType_RRSIG && SameDomainName(rr->resrec.name, &rrsigv->name))
2455            {
2456                RDataBody2 *rdb = (RDataBody2 *)rr->resrec.rdata->u.data;
2457                rdataRRSig *sig = (rdataRRSig *)rdb->data;
2458                if (rrsigv->rdlength != rr->resrec.rdlength)
2459                {
2460                    debugdnssec("SetTTLRRSet length mismatch");
2461                    continue;
2462                }
2463                if (mDNSPlatformMemSame(sig, rrsig, rrsigv->rdlength))
2464                {
2465                    mDNSu32 remain = (now - rr->TimeRcvd)/mDNSPlatformOneSecond;
2466                    rrsigTTL = rr->resrec.rroriginalttl - remain;
2467                    rrsigOrigTTL = swap32(rrsig->origTTL) - remain;
2468                    rrsigTimeTTL = swap32(rrsig->sigExpireTime) - swap32(rrsig->sigInceptTime);
2469                    rrsigRR = rr;
2470                    break;
2471                }
2472            }
2473    }
2474
2475    // It is possible that there are no RRSIGs and in that case it is not an error
2476    // to find the rrsigTTL.
2477    if (!rrTTL || (rrsigv && (!rrsigTTL || !rrsigOrigTTL || !rrsigTimeTTL)))
2478    {
2479        LogDNSSEC("SetTTLRRSet: ERROR!! Bad TTL rrtl %u, rrsigTTL %u, rrsigOrigTTL %u, rrsigTimeTTL %u for %##s (%s)",
2480               rrTTL, rrsigTTL, rrsigOrigTTL, rrsigTimeTTL, qname->c, DNSTypeName(qtype));
2481        return;
2482    }
2483    LogDNSSEC("SetTTLRRSet: TTL rrtl %u, rrsigTTL %u, rrsigOrigTTL %u, rrsigTimeTTL %u for %##s (%s)",
2484        rrTTL, rrsigTTL, rrsigOrigTTL, rrsigTimeTTL, qname->c, DNSTypeName(qtype));
2485
2486    if (status == DNSSEC_Bogus)
2487    {
2488        rrTTL = RR_BOGUS_TTL;
2489        LogDNSSEC("SetTTLRRSet: setting to bogus TTL %d", rrTTL);
2490    }
2491
2492    if (rrsigv)
2493    {
2494        if (rrsigTTL < rrTTL)
2495            rrTTL = rrsigTTL;
2496        if (rrsigOrigTTL < rrTTL)
2497            rrTTL = rrsigOrigTTL;
2498        if (rrsigTimeTTL < rrTTL)
2499            rrTTL = rrsigTimeTTL;
2500    }
2501
2502    // Set the rrsig's TTL. For NSEC records, rrsigRR is NULL which means it expires when
2503    // the negative cache record expires.
2504    if (rrsigRR)
2505    {
2506        rrsigRR->resrec.rroriginalttl = rrTTL;
2507        rrsigRR->TimeRcvd = now;
2508        rrsigRR->UnansweredQueries = 0;
2509    }
2510
2511    // Find the RRset and set its TTL
2512    for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
2513    {
2514        if (SameNameRecordAnswersQuestion(&rr->resrec, &question))
2515        {
2516            LogDNSSEC("SetTTLRRSet: Setting the TTL %d for %s, question %##s (%s)", rrTTL, CRDisplayString(m, rr),
2517                      question.qname.c, DNSTypeName(rr->resrec.rrtype));
2518            rr->resrec.rroriginalttl = rrTTL;
2519            rr->TimeRcvd = now;
2520            rr->UnansweredQueries = 0;
2521            SetNextCacheCheckTimeForRecord(m, rr);
2522        }
2523    }
2524}
2525
2526mDNSlocal void FinishDNSSECVerification(mDNS *const m, DNSSECVerifier *dv)
2527{
2528    RRVerifier *resultKey;
2529    RRVerifier *resultRRSig;
2530
2531    LogDNSSEC("FinishDNSSECVerification: all rdata sets available for sig verification for %##s (%s)",
2532              dv->origName.c, DNSTypeName(dv->origType));
2533
2534    mDNS_StopQuery(m, &dv->q);
2535    if (ValidateSignature(dv, &resultKey, &resultRRSig) == mStatus_NoError)
2536    {
2537        rdataDNSKey *key;
2538        mDNSu16 tag;
2539        key = (rdataDNSKey *)resultKey->rdata;
2540        tag = (mDNSu16)keytag((mDNSu8 *)key, resultKey->rdlength);
2541
2542        LogDNSSEC("FinishDNSSECVerification: RRSIG validated by DNSKEY tag %d, %##s (%s)", tag, dv->rrset->name.c,
2543                  DNSTypeName(dv->rrset->rrtype));
2544
2545        if (TrustedKey(m, dv) == mStatus_NoError)
2546        {
2547            // Need to call this after we called TrustedKey, as AuthChainAdd
2548            // unlinks the resultKey and resultRRSig
2549            if (!AuthChainAdd(dv, resultKey, resultRRSig))
2550            {
2551                dv->DVCallback(m, dv, DNSSEC_Bogus);
2552                return;
2553            }
2554            // The callback will be called when NSEC verification is done.
2555            if ((dv->flags & WILDCARD_PROVES_ANSWER_EXPANDED))
2556            {
2557                WildcardAnswerProof(m, dv);
2558                return;
2559            }
2560            else
2561            {
2562                dv->DVCallback(m, dv, DNSSEC_Secure);
2563                return;
2564            }
2565        }
2566        if (!ValidateDS(dv))
2567        {
2568            // Need to call this after we called ValidateDS, as AuthChainAdd
2569            // unlinks the resultKey and resultRRSig
2570            if (!AuthChainAdd(dv, resultKey, resultRRSig))
2571            {
2572                dv->DVCallback(m, dv, DNSSEC_Bogus);
2573                return;
2574            }
2575            FreeDNSSECVerifierRRSets(dv);
2576            dv->recursed++;
2577            if (dv->recursed < MAX_RECURSE_COUNT)
2578            {
2579                LogDNSSEC("FinishDNSSECVerification: Recursion level %d for %##s (%s)", dv->recursed, dv->origName.c,
2580                          DNSTypeName(dv->origType));
2581                VerifySignature(m, dv, &dv->q);
2582                return;
2583            }
2584        }
2585        else
2586        {
2587            LogDNSSEC("FinishDNSSECVerification: ValidateDS failed %##s (%s)", dv->rrset->name.c, DNSTypeName(dv->rrset->rrtype));
2588            dv->DVCallback(m, dv, DNSSEC_Bogus);
2589            return;
2590        }
2591    }
2592    else
2593    {
2594        LogDNSSEC("FinishDNSSECVerification: Could not validate the rrset %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
2595        dv->DVCallback(m, dv, DNSSEC_Bogus);
2596        return;
2597    }
2598}
2599
2600mDNSexport void StartDNSSECVerification(mDNS *const m, void *context)
2601{
2602    mDNSBool done;
2603    DNSSECVerifier *dv = (DNSSECVerifier *)context;
2604
2605    done = GetAllRRSetsForVerification(m, dv);
2606    if (done)
2607    {
2608        if (dv->next != RRVS_done)
2609            LogMsg("StartDNSSECVerification: ERROR!! dv->next is not done");
2610        else
2611            LogDNSSEC("StartDNSSECVerification: all rdata sets available for sig verification");
2612        FinishDNSSECVerification(m, dv);
2613        return;
2614    }
2615    else debugdnssec("StartDNSSECVerification: all rdata sets not available for sig verification next %d", dv->next);
2616}
2617
2618mDNSexport char *DNSSECStatusName(DNSSECStatus status)
2619{
2620    switch (status)
2621    {
2622    case DNSSEC_Secure: return "Secure";
2623    case DNSSEC_Insecure: return "Insecure";
2624    case DNSSEC_Indeterminate: return "Indeterminate";
2625    case DNSSEC_Bogus: return "Bogus";
2626    default: return "Invalid";
2627    }
2628}
2629
2630// We could not use GenerateNegativeResponse as it assumes m->CurrentQuestion to be set. Even if
2631// we change that, we needs to fix its callers and so on. It is much simpler to call the callback.
2632mDNSlocal void DeliverDNSSECStatus(mDNS *const m, DNSSECVerifier *dv, ResourceRecord *answer, DNSSECStatus status)
2633{
2634
2635    // Can't use m->CurrentQuestion as it may already be in use
2636    if (m->ValidationQuestion)
2637        LogMsg("DeliverDNSSECStatus: ERROR!! m->ValidationQuestion already set: %##s (%s)",
2638               m->ValidationQuestion->qname.c, DNSTypeName(m->ValidationQuestion->qtype));
2639
2640    BumpDNSSECStats(m, kStatsActionSet, kStatsTypeStatus, status);
2641    BumpDNSSECStats(m, kStatsActionSet, kStatsTypeExtraPackets, dv->NumPackets);
2642    mDNS_Lock(m);
2643    BumpDNSSECStats(m, kStatsActionSet, kStatsTypeLatency, m->timenow - dv->StartTime);
2644    mDNS_Unlock(m);
2645
2646    m->ValidationQuestion = m->Questions;
2647    while (m->ValidationQuestion && m->ValidationQuestion != m->NewQuestions)
2648    {
2649        DNSQuestion *q = m->ValidationQuestion;
2650
2651        if (q->ValidatingResponse || !q->ValidationRequired ||
2652           (q->ValidationState != DNSSECValInProgress) || !ResourceRecordAnswersQuestion(answer, q))
2653        {
2654            m->ValidationQuestion = q->next;
2655            continue;
2656        }
2657
2658        q->ValidationState = DNSSECValDone;
2659        q->ValidationStatus = status;
2660
2661        MakeNegativeCacheRecord(m, &largerec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL);
2662        if (q->qtype == answer->rrtype || status != DNSSEC_Secure)
2663        {
2664            LogDNSSEC("DeliverDNSSECStatus: Generating dnssec status %s for %##s (%s)", DNSSECStatusName(status),
2665                q->qname.c, DNSTypeName(q->qtype));
2666            if (q->QuestionCallback)
2667            {
2668                if (q->DNSSECAuthInfo)
2669                    FreeDNSSECAuthChainInfo((AuthChain *)q->DNSSECAuthInfo);
2670                q->DNSSECAuthInfo = AuthChainCopy(dv->ac);
2671                q->DAIFreeCallback = FreeAuthChain;
2672                q->QuestionCallback(m, q, &largerec.r.resrec, QC_dnssec);
2673            }
2674        }
2675        else if (FollowCNAME(q, answer, QC_add))
2676        {
2677            LogDNSSEC("DeliverDNSSECStatus: Following CNAME dnssec status %s for %##s (%s)", DNSSECStatusName(status),
2678                q->qname.c, DNSTypeName(q->qtype));
2679            mDNS_Lock(m);
2680            AnswerQuestionByFollowingCNAME(m, q, answer);
2681            mDNS_Unlock(m);
2682        }
2683
2684        if (m->ValidationQuestion == q)    // If m->ValidationQuestion was not auto-advanced, do it ourselves now
2685            m->ValidationQuestion = q->next;
2686    }
2687    m->ValidationQuestion = mDNSNULL;
2688}
2689
2690// There is no work to be done if we could not validate DNSSEC (as the actual response for
2691// the query has already been delivered) except in the case of CNAMEs where we did not follow
2692// CNAMEs until we finished the DNSSEC processing.
2693mDNSlocal void DNSSECNoResponse(mDNS *const m, DNSSECVerifier *dv)
2694{
2695    CacheGroup *cg;
2696    CacheRecord *cr;
2697    mDNSu32 slot, namehash;
2698    ResourceRecord *answer = mDNSNULL;
2699
2700    LogDNSSEC("DNSSECNoResponse: called");
2701
2702    if (dv->ValidationRequired != DNSSEC_VALIDATION_SECURE_OPTIONAL)
2703    {
2704        LogMsg("DNSSECNoResponse: ERROR!! ValidationRequired incorrect %d", dv->ValidationRequired);
2705        return;
2706    }
2707
2708    BumpDNSSECStats(m, kStatsActionSet, kStatsTypeStatus, DNSSEC_NoResponse);
2709
2710    slot = HashSlot(&dv->origName);
2711    namehash = DomainNameHashValue(&dv->origName);
2712
2713    cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, &dv->origName);
2714    if (!cg)
2715    {
2716        LogDNSSEC("DNSSECNoResponse: cg NULL for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
2717        goto done;
2718    }
2719
2720    InitializeQuestion(m, &dv->q, dv->InterfaceID, &dv->origName, dv->origType, mDNSNULL, mDNSNULL);
2721
2722    // We don't have to reset ValidatingResponse (unlike in DeliverDNSSECStatus) as there are no
2723    // RRSIGs that can match the original question
2724    for (cr = cg->members; cr; cr = cr->next)
2725    {
2726        if (SameNameRecordAnswersQuestion(&cr->resrec, &dv->q))
2727        {
2728            answer = &cr->resrec;
2729            break;
2730        }
2731    }
2732
2733    // It is not an error for things to disappear underneath
2734    if (!answer)
2735    {
2736        LogDNSSEC("DNSSECNoResponse: answer NULL for %##s, %s", dv->origName.c, DNSTypeName(dv->origType));
2737        goto done;
2738    }
2739    if (answer->rrtype == kDNSType_RRSIG)
2740    {
2741        LogDNSSEC("DNSSECNoResponse: RRSIG present for %##s, %s", dv->origName.c, DNSTypeName(dv->origType));
2742        goto done;
2743    }
2744
2745    // Can't use m->CurrentQuestion as it may already be in use
2746    if (m->ValidationQuestion)
2747        LogMsg("DNSSECNoResponse: ERROR!! m->ValidationQuestion already set: %##s (%s)",
2748               m->ValidationQuestion->qname.c, DNSTypeName(m->ValidationQuestion->qtype));
2749
2750    m->ValidationQuestion = m->Questions;
2751    while (m->ValidationQuestion && m->ValidationQuestion != m->NewQuestions)
2752    {
2753        DNSQuestion *q = m->ValidationQuestion;
2754
2755        if (q->ValidatingResponse || !q->ValidationRequired ||
2756           (q->ValidationState != DNSSECValInProgress) || !ResourceRecordAnswersQuestion(answer, q))
2757        {
2758            m->ValidationQuestion = q->next;
2759            continue;
2760        }
2761
2762        // If we could not validate e.g., zone was not signed or bad delegation etc.,
2763        // disable validation. Ideally, for long outstanding questions, we should try again when
2764        // we switch networks. But for now, keep it simple.
2765        //
2766        // Note: If we followed a CNAME with no dnssec protection, it is even more important that
2767        // we disable validation as we don't want to deliver a "secure" dnssec response later e.g.,
2768        // it is possible that the CNAME is not secure but the address records are secure. In this
2769        // case, we don't want to deliver the secure response later as we followed a CNAME that was
2770        // not protected with DNSSEC.
2771
2772        q->ValidationRequired = 0;
2773        q->ValidationState = DNSSECValNotRequired;
2774
2775        if (FollowCNAME(q, answer, QC_add))
2776        {
2777            LogDNSSEC("DNSSECNoResponse: Following CNAME for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
2778
2779            mDNS_Lock(m);
2780            AnswerQuestionByFollowingCNAME(m, q, answer);
2781            mDNS_Unlock(m);
2782        }
2783
2784        if (m->ValidationQuestion == q)    // If m->ValidationQuestion was not auto-advanced, do it ourselves now
2785            m->ValidationQuestion = q->next;
2786    }
2787    m->ValidationQuestion = mDNSNULL;
2788
2789done:
2790    FreeDNSSECVerifier(m, dv);
2791}
2792
2793mDNSlocal void DNSSECPositiveValidationCB(mDNS *const m, DNSSECVerifier *dv, CacheGroup *cg, ResourceRecord *answer, DNSSECStatus status)
2794{
2795    RRVerifier *rrset;
2796    RRVerifier *rv;
2797    CacheRecord *cr;
2798    mDNSu16 rrtype, rrclass;
2799    CacheRecord *const lrr = &largerec.r;
2800
2801    LogDNSSEC("DNSSECPositiveValidationCB: called %s for %##s (%s)", DNSSECStatusName(status), dv->origName.c, DNSTypeName(dv->origType));
2802
2803    //
2804    // 1. Check to see if the rrset that was validated is the same as in cache. If they are not same,
2805    //    this validation result is not valid. When the rrset changed while the validation was in
2806    //    progress, the act of delivering the changed rrset again should have kicked off another
2807    //    verification.
2808    //
2809    // 2. Walk the question list to find the matching question. The original question that started
2810    //    the DNSSEC verification may or may not be there. As long as there is a matching question
2811    //    and waiting for the response, deliver the response.
2812    //
2813    // 3. If we are answering with CNAME, it is time to follow the CNAME if the response is secure
2814
2815    if (!dv->ac || status == DNSSEC_Insecure)
2816    {
2817        // For Insecure status, the auth chain contains information about the trust
2818        // chain starting from the known trust anchor. The rrsets are not related to
2819        // the origName like in Bogus or Secure.
2820        if (!answer)
2821            LogMsg("DNSSECPositiveValidationCB: ERROR: answer NULL");
2822    }
2823    else
2824    {
2825        if (!dv->ac->rrset)
2826        {
2827            LogMsg("DNSSECPositiveValidationCB: ERROR!! Validated RRSET NULL");
2828            goto done;
2829        }
2830
2831        rrset = dv->ac->rrset;
2832        rrtype = rrset->rrtype;
2833        rrclass = rrset->rrclass;
2834
2835        lrr->resrec.name = &largerec.namestorage;
2836
2837        for (rv = dv->ac->rrset; rv; rv = rv->next)
2838            rv->found = 0;
2839
2840        // Check to see if we can find all the elements in the rrset
2841        for (cr = cg ? cg->members : mDNSNULL; cr; cr = cr->next)
2842        {
2843            if (cr->resrec.rrtype == rrtype && cr->resrec.rrclass == rrclass)
2844            {
2845                for (rv = dv->ac->rrset; rv; rv = rv->next)
2846                {
2847                    if (rv->rdlength == cr->resrec.rdlength && rv->rdatahash == cr->resrec.rdatahash)
2848                    {
2849                        lrr->resrec.namehash = rv->namehash;
2850                        lrr->resrec.rrtype = rv->rrtype;
2851                        lrr->resrec.rrclass = rv->rrclass;
2852                        lrr->resrec.rdata = (RData*)&lrr->smallrdatastorage;
2853                        lrr->resrec.rdata->MaxRDLength = MaximumRDSize;
2854
2855                        // Convert the "rdata" to a suitable form before we can call SameRDataBody which expects
2856                        // some of the resource records in host order and also domainnames fully expanded. We
2857                        // converted the resource records into network order for verification purpose and hence
2858                        // need to convert them back again before comparing them.
2859                        if (!SetRData(mDNSNULL, rv->rdata, rv->rdata + rv->rdlength, &largerec, rv->rdlength))
2860                        {
2861                            LogMsg("DNSSECPositiveValidationCB: SetRData failed for %##s (%s)", rv->name.c, DNSTypeName(rv->rrtype));
2862                        }
2863                        else if (SameRDataBody(&cr->resrec, &lrr->resrec.rdata->u, SameDomainName))
2864                        {
2865                            answer = &cr->resrec;
2866                            rv->found = 1;
2867                            break;
2868                        }
2869                    }
2870                }
2871                if (!rv)
2872                {
2873                    // The validated rrset does not have the element in the cache, re-validate
2874                    LogDNSSEC("DNSSECPositiveValidationCB: CacheRecord %s, not found in the validated set", CRDisplayString(m, cr));
2875                    goto done;
2876                }
2877            }
2878        }
2879        // Check to see if we have elements that were not in the cache
2880        for (rv = dv->ac->rrset; rv; rv = rv->next)
2881        {
2882            if (!rv->found)
2883            {
2884                // We had more elements in the validated set, re-validate
2885                LogDNSSEC("DNSSECPositiveValidationCB: Record %##s (%s) not found in the cache", rv->name.c, DNSTypeName(rv->rrtype));
2886                goto done;
2887            }
2888        }
2889    }
2890
2891    // It is not an error for things to disappear underneath
2892    if (!answer)
2893    {
2894        LogDNSSEC("DNSSECPositiveValidationCB: answer NULL for %##s, %s", dv->origName.c, DNSTypeName(dv->origType));
2895        goto done;
2896    }
2897
2898    DeliverDNSSECStatus(m, dv, answer, status);
2899    SetTTLRRSet(m, dv, status);
2900
2901done:
2902    FreeDNSSECVerifier(m, dv);
2903}
2904
2905mDNSlocal void DNSSECNegativeValidationCB(mDNS *const m, DNSSECVerifier *dv, CacheGroup *cg, ResourceRecord *answer, DNSSECStatus status)
2906{
2907    RRVerifier *rv;
2908    CacheRecord *cr;
2909    mDNSu16 rrtype, rrclass;
2910    AuthChain *ac;
2911
2912    LogDNSSEC("DNSSECNegativeValidationCB: called %s for %##s (%s)", DNSSECStatusName(status), dv->origName.c, DNSTypeName(dv->origType));
2913
2914    if (dv->parent)
2915    {
2916        // When NSEC/NSEC3s validation is completed, it calls the parent's DVCallback with the
2917        // parent DNSSECVerifier which is the original one that started the verification. It itself
2918        // should not have a parent. If the NSEC/NSEC3 validation results in another NSEC/NSEC3
2919        // validation, it should chain up via the dv->parent all the way to the top.
2920        LogMsg("DNSSECNegativeValidationCB: ERROR!! dv->parent is set for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
2921        goto done;
2922    }
2923
2924    // 1. Locate the negative cache record and check the cached NSEC/NSEC3 records to see if it matches the
2925    //    NSEC/NSEC3s that were valiated. If the cached NSEC/NSEC3s changed while the validation was in progress,
2926    //    we ignore the validation results.
2927    //
2928    // 2. Walk the question list to find the matching question. The original question that started
2929    //    the DNSSEC verification may or may not be there. As long as there is a matching question
2930    //    and waiting for the response, deliver the response.
2931    //
2932    if (!dv->ac || status == DNSSEC_Insecure)
2933    {
2934        // For Insecure status, the auth chain contains information about the trust
2935        // chain starting from the known trust anchor. The rrsets are not related to
2936        // the origName like in Bogus or Secure.
2937        if (!answer)
2938            LogMsg("DNSSECNegativeValidationCB: ERROR: answer NULL");
2939    }
2940    else
2941    {
2942        if (!dv->ac->rrset)
2943        {
2944            LogMsg("DNSSECNegativeValidationCB: ERROR!! Validated RRSET NULL");
2945            goto done;
2946        }
2947
2948        rrtype = dv->origType;
2949        rrclass = dv->ac->rrset->rrclass;
2950
2951        for (ac = dv->ac; ac; ac = ac->next)
2952        {
2953            for (rv = ac->rrset; rv; rv = rv->next)
2954            {
2955                if (rv->rrtype == kDNSType_NSEC || rv->rrtype == kDNSType_NSEC3)
2956                {
2957                    LogDNSSEC("DNSSECNegativeValidationCB: Record %p %##s (%s) marking zero", rv, rv->name.c, DNSTypeName(rv->rrtype));
2958                    rv->found = 0;
2959                }
2960            }
2961        }
2962
2963        // Check to see if we can find all the elements in the rrset
2964        for (cr = cg->members; cr; cr = cr->next)
2965        {
2966            if (cr->resrec.RecordType == kDNSRecordTypePacketNegative &&
2967                cr->resrec.rrtype == rrtype && cr->resrec.rrclass == rrclass)
2968            {
2969                CacheRecord *ncr;
2970                for (ncr = cr->nsec; ncr; ncr = ncr->next)
2971                {
2972                    // We have RRSIGs for the NSECs cached there too
2973                    if (ncr->resrec.rrtype != kDNSType_NSEC && ncr->resrec.rrtype != kDNSType_NSEC3)
2974                        continue;
2975                    for (ac = dv->ac; ac; ac = ac->next)
2976                    {
2977                        for (rv = ac->rrset; rv; rv = rv->next)
2978                        {
2979                            if ((rv->rrtype == kDNSType_NSEC || rv->rrtype == kDNSType_NSEC3) && rv->rdlength == ncr->resrec.rdlength &&
2980                                rv->rdatahash == ncr->resrec.rdatahash)
2981                            {
2982                                if (SameDomainName(ncr->resrec.name, &rv->name) &&
2983                                    SameRDataBody(&ncr->resrec, (const RDataBody *)rv->rdata, SameDomainName))
2984                                {
2985                                    LogDNSSEC("DNSSECNegativeValidationCB: Record %p %##s (%s) marking one", rv, rv->name.c, DNSTypeName(rv->rrtype));
2986                                    answer = &cr->resrec;
2987                                    rv->found = 1;
2988                                    break;
2989                                }
2990                            }
2991                        }
2992                        if (rv)
2993                            break;
2994                    }
2995                }
2996                if (!rv)
2997                {
2998                    // The validated rrset does not have the element in the cache, re-validate
2999                    LogDNSSEC("DNSSECNegativeValidationCB: CacheRecord %s, not found in the validated set", CRDisplayString(m, cr));
3000                    goto done;
3001                }
3002            }
3003        }
3004        // Check to see if we have elements that were not in the cache
3005        for (ac = dv->ac; ac; ac = ac->next)
3006        {
3007            for (rv = ac->rrset; rv; rv = rv->next)
3008            {
3009                if (rv->rrtype == kDNSType_NSEC || rv->rrtype == kDNSType_NSEC3)
3010                {
3011                    if (!rv->found)
3012                    {
3013                        // We had more elements in the validated set, re-validate
3014                        LogDNSSEC("DNSSECNegativeValidationCB: Record %p %##s (%s) not found in the cache", rv, rv->name.c, DNSTypeName(rv->rrtype));
3015                        goto done;
3016                    }
3017                    rv->found = 0;
3018                }
3019            }
3020        }
3021    }
3022
3023    // It is not an error for things to disappear underneath
3024    if (!answer)
3025    {
3026        LogDNSSEC("DNSSECNegativeValidationCB: answer NULL for %##s, %s", dv->origName.c, DNSTypeName(dv->origType));
3027        goto done;
3028    }
3029
3030    DeliverDNSSECStatus(m, dv, answer, status);
3031    SetTTLRRSet(m, dv, status);
3032
3033done:
3034    FreeDNSSECVerifier(m, dv);
3035}
3036
3037mDNSlocal void DNSSECValidationCB(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status)
3038{
3039    mDNSu32 slot, namehash;
3040    CacheGroup *cg;
3041    CacheRecord *cr;
3042
3043    LogDNSSEC("DNSSECValidationCB: called %s for %##s (%s)", DNSSECStatusName(status), dv->origName.c, DNSTypeName(dv->origType));
3044
3045    // Currently, if we receive anything other than secure, we abort DNSSEC validation for
3046    // the optional case.
3047    if (dv->ValidationRequired == DNSSEC_VALIDATION_SECURE_OPTIONAL && status != DNSSEC_Secure)
3048    {
3049        DNSSECNoResponse(m, dv);
3050        return;
3051    }
3052
3053    if (dv->ValidationRequired == DNSSEC_VALIDATION_SECURE && !dv->InsecureProofDone && status == DNSSEC_Bogus)
3054    {
3055        dv->InsecureProofDone = 1;
3056        ProveInsecure(m, dv, mDNSNULL, mDNSNULL);
3057        return;
3058    }
3059    slot = HashSlot(&dv->origName);
3060    namehash = DomainNameHashValue(&dv->origName);
3061
3062    cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, &dv->origName);
3063    if (!cg)
3064    {
3065        LogDNSSEC("DNSSECValidationCB: cg NULL for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
3066        FreeDNSSECVerifier(m, dv);
3067        return;
3068    }
3069    InitializeQuestion(m, &dv->q, dv->InterfaceID, &dv->origName, dv->origType, mDNSNULL, mDNSNULL);
3070    // Need to be reset ValidatingResponse as we are looking for the cache record that would answer
3071    // the original question
3072    dv->q.ValidatingResponse = mDNSfalse;
3073    for (cr = cg->members; cr; cr = cr->next)
3074    {
3075        if (SameNameRecordAnswersQuestion(&cr->resrec, &dv->q))
3076        {
3077            if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
3078                DNSSECNegativeValidationCB(m, dv, cg, &cr->resrec, status);
3079            else
3080                DNSSECPositiveValidationCB(m, dv, cg, &cr->resrec, status);
3081            return;
3082        }
3083    }
3084}
3085
3086mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
3087{
3088    mDNSu32 slot = HashSlot(&q->qname);
3089    CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
3090    CacheRecord *rr;
3091    mDNSBool first = mDNSfalse;
3092    static mDNSBool TrustAnchorsUpdated = mDNSfalse;
3093
3094    LogDNSSEC("VerifySignature called for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
3095    if (!TrustAnchorsUpdated)
3096    {
3097        TrustAnchorsUpdated = mDNStrue;
3098        UpdateTrustAnchors(m);
3099    }
3100    if (!dv)
3101    {
3102        first = mDNStrue;
3103        if (!q->qDNSServer || q->qDNSServer->cellIntf)
3104        {
3105            LogDNSSEC("VerifySignature: Disabled");
3106            return;
3107        }
3108        // We assume that the verifier's question has been initialized here so that ValidateWithNSECS below
3109        // knows what it has prove the non-existence of.
3110        dv = AllocateDNSSECVerifier(m, &q->qname, q->qtype, q->InterfaceID, q->ValidationRequired, DNSSECValidationCB, VerifySigCallback);
3111        if (!dv)
3112        {
3113            LogMsg("VerifySignature: ERROR!! memory alloc failed");
3114            return;
3115        }
3116    }
3117
3118    // If we find a CNAME response to the question, remember what qtype
3119    // caused the CNAME response. origType is not sufficient as we
3120    // recursively validate the response and origType is initialized above
3121    // the first time this function is called.
3122    dv->currQtype = q->qtype;
3123
3124    // Walk the cache and get all the rrsets for verification.
3125    for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
3126        if (SameNameRecordAnswersQuestion(&rr->resrec, q))
3127        {
3128            // We also get called for RRSIGs which matches qtype. We don't need that here as we are
3129            // building rrset for matching q->qname. Checking for RRSIG type is important as otherwise
3130            // we would miss the CNAME answering any qtype.
3131            if (rr->resrec.rrtype == kDNSType_RRSIG && rr->resrec.rrtype != q->qtype)
3132            {
3133                LogDNSSEC("VerifySignature: Question %##s (%s) answered with RRSIG record %s, not using it", q->qname.c, DNSTypeName(q->qtype), CRDisplayString(m, rr));
3134                continue;
3135            }
3136
3137            // See DNSSECRecordAnswersQuestion: This should never happen. NSEC records are
3138            // answered directly only when the qtype is NSEC. Otherwise, NSEC records are
3139            // used only for denial of existence and hence should go through negative cache
3140            // entry.
3141            if (rr->resrec.rrtype == kDNSType_NSEC && q->qtype != kDNSType_NSEC)
3142            {
3143                LogMsg("VerifySignature: ERROR!! Question %##s (%s) answered using NSEC record %s", q->qname.c, DNSTypeName(q->qtype), CRDisplayString(m, rr));
3144                continue;
3145            }
3146
3147            // We might get a NSEC response when we first send the query out from the "core" for ValidationRequired
3148            // questions. Later as part of validating the response, we might get a NSEC response.
3149            if (rr->resrec.RecordType == kDNSRecordTypePacketNegative && DNSSECQuestion(q))
3150            {
3151                // If we can't find the NSEC, we can't validate. This can happens if we are
3152                // behind a non-DNSSEC aware CPE/server.
3153                if (!rr->nsec)
3154                {
3155                    LogDNSSEC("VerifySignature: No nsecs found for %s", CRDisplayString(m, rr));
3156                    dv->DVCallback(m, dv, DNSSEC_Bogus);
3157                    return;
3158                }
3159                ValidateWithNSECS(m, dv, rr);
3160                return;
3161            }
3162
3163            if (AddRRSetToVerifier(dv, &rr->resrec, mDNSNULL, RRVS_rr) != mStatus_NoError)
3164            {
3165                dv->DVCallback(m, dv, DNSSEC_Bogus);
3166                return;
3167            }
3168        }
3169    if (!dv->rrset)
3170    {
3171        LogMsg("VerifySignature: rrset mDNSNULL for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
3172        dv->DVCallback(m, dv, DNSSEC_Bogus);
3173        return;
3174    }
3175    dv->next = RRVS_rrsig;
3176    // Delay this so that the mDNS "core" can deliver all the results before
3177    // we can deliver the dnssec result
3178    if (first)
3179    {
3180        mDNSPlatformDispatchAsync(m, dv, StartDNSSECVerification);
3181    }
3182    else
3183    {
3184        StartDNSSECVerification(m, dv);
3185    }
3186}
3187
3188mDNSlocal mDNSBool TrustedKeyPresent(mDNS *const m, DNSSECVerifier *dv)
3189{
3190    rdataRRSig *rrsig;
3191    rdataDS *ds;
3192    rdataDNSKey *key;
3193    TrustAnchor *ta;
3194    RRVerifier *keyv;
3195
3196    rrsig = (rdataRRSig *)dv->rrsig->rdata;
3197
3198    // Walk all our trusted DS Records to see if we have a matching DNS KEY record that verifies
3199    // the hash. If we find one, verify that this key was used to sign the KEY rrsets in
3200    // this zone. Loop till we find one.
3201    for (ta = m->TrustAnchors; ta; ta = ta->next)
3202    {
3203        ds = (rdataDS *)&ta->rds;
3204        if ((ds->digestType != SHA1_DIGEST_TYPE) && (ds->digestType != SHA256_DIGEST_TYPE))
3205        {
3206            LogMsg("TrustedKeyPresent: Unsupported digest %d", ds->digestType);
3207            continue;
3208        }
3209        else
3210        {
3211            debugdnssec("TrustedKeyPresent: digest type %d", ds->digestType);
3212        }
3213        for (keyv = dv->key; keyv; keyv = keyv->next)
3214        {
3215            key = (rdataDNSKey *)keyv->rdata;
3216            mDNSu16 tag = (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength);
3217            if (tag != ds->keyTag)
3218            {
3219                debugdnssec("TrustedKeyPresent:Not a valid keytag %d", tag);
3220                continue;
3221            }
3222            if (!SameDomainName(&keyv->name, &ta->zone))
3223            {
3224                debugdnssec("TrustedKeyPresent: domainame mismatch key %##s, ta %##s", keyv->name.c, ta->zone.c);
3225                continue;
3226            }
3227            return mDNStrue;
3228        }
3229    }
3230    return mDNSfalse;
3231}
3232
3233mDNSlocal mStatus TrustedKey(mDNS *const m, DNSSECVerifier *dv)
3234{
3235    mDNSu8 *digest;
3236    int digestLen;
3237    domainname name;
3238    rdataRRSig *rrsig;
3239    rdataDS *ds;
3240    rdataDNSKey *key;
3241    TrustAnchor *ta;
3242    RRVerifier *keyv;
3243    mStatus algRet;
3244    mDNSu32 currTime = mDNSPlatformUTC();
3245
3246    rrsig = (rdataRRSig *)dv->rrsig->rdata;
3247
3248    // Walk all our trusted DS Records to see if we have a matching DNS KEY record that verifies
3249    // the hash. If we find one, verify that this key was used to sign the KEY rrsets in
3250    // this zone. Loop till we find one.
3251    for (ta = m->TrustAnchors; ta; ta = ta->next)
3252    {
3253        ds = (rdataDS *)&ta->rds;
3254        if ((ds->digestType != SHA1_DIGEST_TYPE) && (ds->digestType != SHA256_DIGEST_TYPE))
3255        {
3256            LogMsg("TrustedKey: Unsupported digest %d", ds->digestType);
3257            continue;
3258        }
3259        else
3260        {
3261            debugdnssec("TrustedKey: Zone %##s, digest type %d, tag %d", ta->zone.c, ds->digestType, ds->keyTag);
3262        }
3263        for (keyv = dv->key; keyv; keyv = keyv->next)
3264        {
3265            key = (rdataDNSKey *)keyv->rdata;
3266            mDNSu16 tag = (mDNSu16)keytag((mDNSu8 *)key, keyv->rdlength);
3267            if (tag != ds->keyTag)
3268            {
3269                debugdnssec("TrustedKey:Not a valid keytag %d", tag);
3270                continue;
3271            }
3272            if (!SameDomainName(&keyv->name, &ta->zone))
3273            {
3274                debugdnssec("TrustedKey: domainame mismatch key %##s, ta %##s", keyv->name.c, ta->zone.c);
3275                continue;
3276            }
3277            if (DNS_SERIAL_LT(ta->validUntil, currTime))
3278            {
3279                LogDNSSEC("TrustedKey: Expired: currentTime %d, ExpireTime %d", (int)currTime, ta->validUntil);
3280                continue;
3281            }
3282            if (DNS_SERIAL_LT(currTime, ta->validFrom))
3283            {
3284                LogDNSSEC("TrustedKey: Future: currentTime %d, InceptTime %d", (int)currTime, ta->validFrom);
3285                continue;
3286            }
3287
3288            if (DNSNameToLowerCase((domainname *)&rrsig->signerName, &name) != mStatus_NoError)
3289            {
3290                LogMsg("TrustedKey: ERROR!! cannot convert to lower case");
3291                continue;
3292            }
3293
3294            if (dv->ctx) AlgDestroy(dv->ctx);
3295            dv->ctx = AlgCreate(DIGEST_ALG, ds->digestType);
3296            if (!dv->ctx)
3297            {
3298                LogMsg("TrustedKey: ERROR!! No digest support");
3299                continue;
3300            }
3301            digest = ds->digest;
3302            digestLen = ta->digestLen;
3303
3304            AlgAdd(dv->ctx, name.c, DomainNameLength(&name));
3305            AlgAdd(dv->ctx, (const mDNSu8 *)key, keyv->rdlength);
3306
3307            algRet = AlgVerify(dv->ctx, mDNSNULL, 0, digest, digestLen);
3308            AlgDestroy(dv->ctx);
3309            dv->ctx = mDNSNULL;
3310            if (algRet == mStatus_NoError)
3311            {
3312                LogDNSSEC("TrustedKey: DS Validated Successfully, need to verify the key %d", tag);
3313                // We found the DNS KEY that is authenticated by the DS in our parent zone. Check to see if this key
3314                // was used to sign the DNS KEY RRSET. If so, then the keys in our DNS KEY RRSET are valid
3315                if (ValidateSignatureWithKeyForAllRRSigs(dv, dv->key, keyv, dv->rrsigKey))
3316                {
3317                    LogDNSSEC("TrustedKey: DS Validated Successfully %d", tag);
3318                    return mStatus_NoError;
3319                }
3320            }
3321        }
3322    }
3323    return mStatus_NoSuchRecord;
3324}
3325
3326mDNSlocal CacheRecord* NegativeCacheRecordForRR(mDNS *const m, const ResourceRecord *const rr)
3327{
3328    mDNSu32 slot;
3329    mDNSu32 namehash;
3330    CacheGroup *cg;
3331    CacheRecord *cr;
3332
3333    slot = HashSlot(rr->name);
3334    namehash = DomainNameHashValue(rr->name);
3335    cg = CacheGroupForName(m, slot, namehash, rr->name);
3336    if (!cg)
3337    {
3338        LogMsg("NegativeCacheRecordForRR: cg null %##s", rr->name->c);
3339        return mDNSNULL;
3340    }
3341    for (cr=cg->members; cr; cr=cr->next)
3342    {
3343        if (cr->resrec.RecordType == kDNSRecordTypePacketNegative && (&cr->resrec == rr))
3344            return cr;
3345    }
3346    return mDNSNULL;
3347}
3348
3349mDNSlocal void VerifySigCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
3350{
3351    DNSSECVerifier *dv = (DNSSECVerifier *)question->QuestionContext;
3352    mDNSu16 rrtype;
3353    CacheRecord *negcr;
3354
3355    debugdnssec("VerifySigCallback: AddRecord %d, dv %p", AddRecord, dv);
3356
3357    if (!AddRecord)
3358        return;
3359
3360    // After the first ADD event, we should ideally stop the question. If we don't stop
3361    // the question, we might get more callbacks and that can cause problems. For example,
3362    // in the first callback, we could start a insecure proof and while that is in progress,
3363    // if we get more callbacks, we will try to start another insecure proof. As we already
3364    // started an insecure proof, we won't start another but terminate the verification
3365    // process where we free the current DNSSECVerifier while the first insecure proof is
3366    // still referencing it.
3367    //
3368    // But there are cases below which might return if we have not received the right answer
3369    // yet e.g., no RRSIGs. In that case if the question is stopped, we will never get any
3370    // callbacks again and also we leak "dv". Hence it is important that we either process
3371    // the result or wait for more results. Note that the question eventually times out
3372    // and cleans up the "dv" i.e., we don't wait forever.
3373
3374    if (!answer)
3375    {
3376        LogDNSSEC("VerifySigCallback: Question %##s (%s) no dnssec response", question->qname.c, DNSTypeName(question->qtype));
3377        mDNS_StopQuery(m, question);
3378        dv->DVCallback(m, dv, DNSSEC_Bogus);
3379        return;
3380    }
3381
3382    LogDNSSEC("VerifySigCallback(%p): Called with record %s for question %##s (%s)", dv, RRDisplayString(m, answer), question->qname.c,
3383        DNSTypeName(question->qtype));
3384    mDNS_Lock(m);
3385    if ((m->timenow - question->StopTime) >= 0)
3386    {
3387        mDNS_Unlock(m);
3388        LogDNSSEC("VerifySigCallback: Question %##s (%s) timed out", question->qname.c, DNSTypeName(question->qtype));
3389        mDNS_StopQuery(m, question);
3390        dv->DVCallback(m, dv, DNSSEC_Bogus);
3391        return;
3392    }
3393    mDNS_Unlock(m);
3394
3395    if (answer->RecordType == kDNSRecordTypePacketNegative)
3396    {
3397        CacheRecord *cr;
3398        LogDNSSEC("VerifySigCallback: Received a negative answer with record %s, AddRecord %d",
3399                  RRDisplayString(m, answer), AddRecord);
3400        mDNS_StopQuery(m, question);
3401        cr = NegativeCacheRecordForRR(m, answer);
3402        if (cr && cr->nsec)
3403        {
3404            ValidateWithNSECS(m, dv, cr);
3405        }
3406        else
3407        {
3408
3409            LogDNSSEC("VerifySigCallback: Missing record (%s) Negative Cache Record %p", RRDisplayString(m, answer), cr);
3410            dv->DVCallback(m, dv, DNSSEC_Bogus);
3411        }
3412        return;
3413    }
3414
3415    if (!dv->rrset)
3416    {
3417        LogMsg("VerifySigCallback: ERROR!! rrset NULL");
3418        mDNS_StopQuery(m, question);
3419        dv->DVCallback(m, dv, DNSSEC_Bogus);
3420        return;
3421    }
3422
3423    rrtype = answer->rrtype;
3424    // Check whether we got any answers for the question. If there are no answers, we
3425    // can't do the verification.
3426    //
3427    // We need to look at the whole rrset for verifying the signatures. This callback gets
3428    // called back for each record in the rrset sequentially and we won't know when to start the
3429    // verification. Hence, we look for all the records in the rrset ourselves using the
3430    // CheckXXX function below. The caller has to ensure that all the records in the rrset are
3431    // added to the cache before calling this callback which happens naturally because all
3432    // unicast records are marked for DelayDelivery and hence added to the cache before the
3433    // callback is done.
3434    //
3435    // We also need the RRSIGs for the rrset to do the validation. It is possible that the
3436    // cache contains RRSIG records but it may not be a valid record when we filter them
3437    // in CheckXXX function. For example, some application can query for RRSIG records which
3438    // might come back with a partial set of RRSIG records from the recursive server and
3439    // they may not be the right ones for the current validation. In this case, we still
3440    // need to send the query out to get the right RRSIGs but the "core" should not answer
3441    // this query with the same records that we checked and found them to be unusable.
3442    //
3443    // We handle this in two ways:
3444    //
3445    // 1) AnswerNewQuestion always sends the "ValidatingResponse" query out bypassing the cache.
3446    //
3447    // 2) DNSSECRecordAnswersQuestion does not answer a question with RRSIGs matching the
3448    //    same name as the query until the typeCovered also matches the query's type.
3449    //
3450    // NOTE: We use "next - 1" as next always points to what we are going to fetch next and not the one
3451    // we are fetching currently
3452    switch(dv->next - 1)
3453    {
3454    case RRVS_rr:
3455        // Verification always starts at RRVS_rrsig (which means dv->next points at RRVS_key) as verification does
3456        // not begin until we have the main rrset.
3457        LogDNSSEC("VerifySigCallback: ERROR!! rrset %##s dv->next is RRVS_rr", dv->rrset->name.c);
3458        return;
3459    case RRVS_rrsig:
3460        // We can get called back with rrtype matching qtype as new records are added to the cache
3461        // triggered by other questions. This could potentially mean that the rrset that is being
3462        // validated by this "dv" whose rrsets were initialized at the beginning of the verification
3463        // may not be the right one. If this case happens, we will detect this at the end of validation
3464        // and throw away the validation results. This should not be a common case.
3465        if (rrtype != kDNSType_RRSIG)
3466        {
3467            LogDNSSEC("VerifySigCallback: RRVS_rrsig called with %s", RRDisplayString(m, answer));
3468            return;
3469        }
3470        mDNS_StopQuery(m, question);
3471        if (CheckRRSIGForRRSet(m, dv, &negcr) != mStatus_NoError)
3472        {
3473            LogDNSSEC("VerifySigCallback: Unable to find RRSIG for %##s (%s), question %##s", dv->rrset->name.c,
3474                      DNSTypeName(dv->rrset->rrtype), question->qname.c);
3475            dv->DVCallback(m, dv, DNSSEC_Bogus);
3476            return;
3477        }
3478        break;
3479    case RRVS_key:
3480        // We are waiting for the DNSKEY record and hence dv->key should be NULL. If RRSIGs are being
3481        // returned first, ignore them for now.
3482        if (dv->key)
3483            LogDNSSEC("VerifySigCallback: ERROR!! RRVS_key dv->key non-NULL for %##s", question->qname.c);
3484        if (rrtype == kDNSType_RRSIG)
3485        {
3486            LogDNSSEC("VerifySigCallback: RRVS_key rrset type %s, %##s received before DNSKEY", DNSTypeName(rrtype), question->qname.c);
3487            return;
3488        }
3489        if (rrtype != question->qtype)
3490        {
3491            LogDNSSEC("VerifySigCallback: ERROR!! RRVS_key rrset type %s, %##s not matching qtype %d", DNSTypeName(rrtype), question->qname.c,
3492                question->qtype);
3493            return;
3494        }
3495        mDNS_StopQuery(m, question);
3496        if (CheckKeyForRRSIG(m, dv, &negcr) != mStatus_NoError)
3497        {
3498            LogDNSSEC("VerifySigCallback: Unable to find DNSKEY for %##s (%s), question %##s", dv->rrset->name.c,
3499                      DNSTypeName(dv->rrset->rrtype), question->qname.c);
3500            dv->DVCallback(m, dv, DNSSEC_Bogus);
3501            return;
3502        }
3503        break;
3504    case RRVS_rrsig_key:
3505        // If we are in RRVS_rrsig_key, it means that we already found the relevant DNSKEYs (dv->key should be non-NULL).
3506        // If DNSKEY record is being returned i.e., it means it is being added to the cache, then it can't be in our
3507        // list.
3508        if (!dv->key)
3509            LogDNSSEC("VerifySigCallback: ERROR!! RRVS_rrsig_key dv->key NULL for %##s", question->qname.c);
3510        if (rrtype == question->qtype)
3511        {
3512            LogDNSSEC("VerifySigCallback: RRVS_rrsig_key rrset type %s, %##s", DNSTypeName(rrtype), question->qname.c);
3513            CheckOneKeyForRRSIG(dv, answer);
3514            return;
3515        }
3516        if (rrtype != kDNSType_RRSIG)
3517        {
3518            LogDNSSEC("VerifySigCallback: RRVS_rrsig_key rrset type %s, %##s not matching qtype %d", DNSTypeName(rrtype), question->qname.c,
3519                question->qtype);
3520            return;
3521        }
3522        mDNS_StopQuery(m, question);
3523        if (CheckRRSIGForKey(m, dv, &negcr) != mStatus_NoError)
3524        {
3525            LogDNSSEC("VerifySigCallback: Unable to find RRSIG for %##s (%s), question %##s", dv->rrset->name.c,
3526                      DNSTypeName(dv->rrset->rrtype), question->qname.c);
3527            dv->DVCallback(m, dv, DNSSEC_Bogus);
3528            return;
3529        }
3530        break;
3531    case RRVS_ds:
3532        if (rrtype == question->qtype)
3533        {
3534            LogDNSSEC("VerifySigCallback: RRVS_ds rrset type %s, %##s", DNSTypeName(rrtype), question->qname.c);
3535        }
3536        else
3537        {
3538            LogDNSSEC("VerifySigCallback: RRVS_ds rrset type %s, %##s received before DS", DNSTypeName(rrtype), question->qname.c);
3539        }
3540        mDNS_StopQuery(m, question);
3541        // It is not an error if we don't find the DS record as we could have
3542        // a trusted key. Or this is not a secure delegation which will be handled
3543        // below.
3544        if (CheckDSForKey(m, dv, &negcr) != mStatus_NoError)
3545        {
3546            LogDNSSEC("VerifySigCallback: Unable find DS for %##s (%s), question %##s", dv->rrset->name.c,
3547                      DNSTypeName(dv->rrset->rrtype), question->qname.c);
3548        }
3549        // dv->next is already at RRVS_done, so if we "break" from here, we will end up
3550        // in FinishDNSSECVerification. We should not do that if we receive a negative
3551        // response. For all other cases above, GetAllRRSetsForVerification handles
3552        // negative cache record
3553        if (negcr)
3554        {
3555            if (!negcr->nsec)
3556            {
3557                LogDNSSEC("VerifySigCallback: No nsec records for %##s (DS)", dv->ds->name.c);
3558                dv->DVCallback(m, dv, DNSSEC_Bogus);
3559                return;
3560            }
3561            ValidateWithNSECS(m, dv, negcr);
3562            return;
3563        }
3564        break;
3565    default:
3566        LogDNSSEC("VerifySigCallback: ERROR!! default case rrset %##s question %##s", dv->rrset->name.c, question->qname.c);
3567        mDNS_StopQuery(m, question);
3568        dv->DVCallback(m, dv, DNSSEC_Bogus);
3569        return;
3570    }
3571    if (dv->next != RRVS_done)
3572    {
3573        mDNSBool done = GetAllRRSetsForVerification(m, dv);
3574        if (done)
3575        {
3576            if (dv->next != RRVS_done)
3577                LogMsg("VerifySigCallback ERROR!! dv->next is not done");
3578            else
3579                LogDNSSEC("VerifySigCallback: all rdata sets available for sig verification");
3580        }
3581        else
3582        {
3583            LogDNSSEC("VerifySigCallback: all rdata sets not available for sig verification");
3584            return;
3585        }
3586    }
3587    FinishDNSSECVerification(m, dv);
3588}
3589
3590mDNSlocal TrustAnchor *FindTrustAnchor(mDNS *const m, const domainname *const name)
3591{
3592    TrustAnchor *ta;
3593    TrustAnchor *matchTA = mDNSNULL;
3594    TrustAnchor *rootTA = mDNSNULL;
3595    int currmatch = 0;
3596    int match;
3597    mDNSu32 currTime = mDNSPlatformUTC();
3598
3599    for (ta = m->TrustAnchors; ta; ta = ta->next)
3600    {
3601        if (DNS_SERIAL_LT(ta->validUntil, currTime))
3602        {
3603            LogDNSSEC("FindTrustAnchor: Expired: currentTime %d, ExpireTime %d", (int)currTime, ta->validUntil);
3604            continue;
3605        }
3606        if (DNS_SERIAL_LT(currTime, ta->validFrom))
3607        {
3608            LogDNSSEC("FindTrustAnchor: Future: currentTime %d, InceptTime %d", (int)currTime, ta->validFrom);
3609            continue;
3610        }
3611
3612        if (SameDomainName((const domainname *)"\000", &ta->zone))
3613            rootTA = ta;
3614
3615        match = CountLabelsMatch(&ta->zone, name);
3616        if (match > currmatch)
3617        {
3618            currmatch = match;
3619            matchTA = ta;
3620        }
3621    }
3622    if (matchTA)
3623    {
3624        LogDNSSEC("FindTrustAnhcor: matched %##s", matchTA->zone.c);
3625        return matchTA;
3626    }
3627    else if (rootTA)
3628    {
3629        LogDNSSEC("FindTrustAnhcor: matched rootTA %##s", rootTA->zone.c);
3630        return rootTA;
3631    }
3632    else
3633    {
3634        LogDNSSEC("FindTrustAnhcor: No Trust Anchor");
3635        return mDNSNULL;
3636    }
3637}
3638
3639mDNSlocal void DeliverInsecureProofResultAsync(mDNS *const m, void *context)
3640{
3641    InsecureContext *ic = (InsecureContext *)context;
3642    ic->dv->DVCallback(m, ic->dv, ic->status);
3643    if (ic->q.ThisQInterval != -1)
3644    {
3645        LogMsg("DeliverInsecureProofResultAsync: ERROR!! Question %##s (%s) not stopped already", ic->q.qname.c, DNSTypeName(ic->q.qtype));
3646        mDNS_StopQuery(m, &ic->q);
3647    }
3648    mDNSPlatformMemFree(ic);
3649}
3650
3651mDNSlocal void DeliverInsecureProofResult(mDNS *const m, InsecureContext *ic, DNSSECStatus status)
3652{
3653    // If the status is Bogus, restore the original auth chain before the insecure
3654    // proof.
3655    if (status == DNSSEC_Bogus)
3656    {
3657        LogDNSSEC("DeliverInsecureProofResult: Restoring the auth chain");
3658        if (ic->dv->ac)
3659        {
3660            FreeDNSSECAuthChainInfo(ic->dv->ac);
3661        }
3662        ResetAuthChain(ic->dv);
3663        ic->dv->ac = ic->dv->saveac;
3664        if (ic->dv->ac)
3665        {
3666            AuthChain *tmp = ic->dv->ac;
3667            AuthChain **tail = &tmp->next;
3668            while (tmp->next)
3669            {
3670                tail = &tmp->next;
3671                tmp = tmp->next;
3672            }
3673            ic->dv->actail = tail;
3674        }
3675        ic->dv->saveac = mDNSNULL;
3676    }
3677    else if (ic->dv->saveac)
3678    {
3679        FreeDNSSECAuthChainInfo(ic->dv->saveac);
3680        ic->dv->saveac = mDNSNULL;
3681    }
3682    ic->status = status;
3683    // Stop the question before we schedule the block so that we don't receive additional
3684    // callbacks again. Once the block runs, it will free the "ic" and you can't
3685    // have another block queued up. This can happen if we receive a callback after we
3686    // queue the block below.
3687    if (ic->q.ThisQInterval != -1)
3688        mDNS_StopQuery(m, &ic->q);
3689    mDNSPlatformDispatchAsync(m, ic, DeliverInsecureProofResultAsync);
3690}
3691
3692mDNSlocal mDNSBool AlgorithmSupported(rdataDS *ds)
3693{
3694    switch(ds->digestType)
3695    {
3696    case SHA1_DIGEST_TYPE:
3697    case SHA256_DIGEST_TYPE:
3698        break;
3699    default:
3700        LogDNSSEC("AlgorithmSupported: Unsupported digest %d", ds->digestType);
3701        return mDNSfalse;
3702    }
3703
3704    switch(ds->alg)
3705    {
3706    case CRYPTO_RSA_NSEC3_SHA1:
3707    case CRYPTO_RSA_SHA1:
3708    case CRYPTO_RSA_SHA256:
3709    case CRYPTO_RSA_SHA512:
3710        return mDNStrue;
3711    default:
3712        LogDNSSEC("AlgorithmSupported: Unsupported algorithm %d", ds->alg);
3713        return mDNSfalse;
3714    }
3715}
3716
3717// Note: This function is called when DNSSEC results are delivered (from DeliverDNSSECStatus) and we can't deliver DNSSEC result
3718// again within this function as "m->ValidationQuestion" is already in use. Hence we should dispatch off the delivery of insecure
3719// results asynchronously.
3720//
3721// Insecure proof callback can deliver either insecure or bogus, but never secure result.
3722mDNSlocal void ProveInsecureCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
3723{
3724    InsecureContext *ic = (InsecureContext *)question->QuestionContext;
3725    DNSSECVerifier *pdv = ic->dv;
3726    AuthChain *ac;
3727
3728    (void) answer;
3729
3730    if (!AddRecord)
3731        return;
3732
3733    mDNS_Lock(m);
3734    if ((m->timenow - question->StopTime) >= 0)
3735    {
3736        mDNS_Unlock(m);
3737        LogDNSSEC("ProveInsecureCallback: Question %##s (%s) timed out", question->qname.c, DNSTypeName(question->qtype));
3738        DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3739        return;
3740    }
3741    mDNS_Unlock(m);
3742
3743    // We only need to handle the actual DNSSEC results and the ones that are secure. Anything else results in
3744    // bogus.
3745    if (AddRecord != QC_dnssec)
3746    {
3747        LogDNSSEC("ProveInsecureCallback: Question %##s (%s), AddRecord %d, answer %s", question->qname.c,
3748            DNSTypeName(question->qtype), AddRecord, RRDisplayString(m, answer));
3749        return;
3750    }
3751
3752    LogDNSSEC("ProveInsecureCallback: ic %p Question %##s (%s), DNSSEC status %s", ic, question->qname.c, DNSTypeName(question->qtype),
3753            DNSSECStatusName(question->ValidationStatus));
3754
3755    // Insecure is delivered for NSEC3 OptOut
3756    if (question->ValidationStatus != DNSSEC_Secure && question->ValidationStatus != DNSSEC_Insecure)
3757    {
3758        LogDNSSEC("ProveInsecureCallback: Question %##s (%s) returned DNSSEC status %s", question->qname.c,
3759            DNSTypeName(question->qtype), DNSSECStatusName(question->ValidationStatus));
3760        goto done;
3761    }
3762    ac = (AuthChain *)question->DNSSECAuthInfo;
3763    if (!ac)
3764    {
3765        LogDNSSEC("ProveInsecureCallback: ac NULL for question %##s, %s", question->qname.c, DNSTypeName(question->qtype));
3766        goto done;
3767    }
3768    if (!ac->rrset)
3769    {
3770        LogDNSSEC("ProveInsecureCallback: ac->rrset NULL for question %##s, %s", question->qname.c, DNSTypeName(question->qtype));
3771        goto done;
3772    }
3773    if (ac->rrset->rrtype != kDNSType_DS && ac->rrset->rrtype != kDNSType_NSEC && ac->rrset->rrtype != kDNSType_NSEC3)
3774    {
3775        LogDNSSEC("ProveInsecureCallback: ac->rrset->rrtype %##s (%s) not handled", ac->rrset->name.c,
3776            DNSTypeName(ac->rrset->rrtype));
3777        goto done;
3778    }
3779    AuthChainLink(pdv, ac);
3780    question->DNSSECAuthInfo = mDNSNULL;
3781    if (ac->rrset->rrtype == kDNSType_DS)
3782    {
3783        rdataDS *ds = (rdataDS *)ac->rrset->rdata;
3784
3785        // If the delegation is secure, but the underlying zone is signed with an unsupported
3786        // algorithm, then we can't verify it. Deliver insecure in that case.
3787        if (!AlgorithmSupported(ds))
3788        {
3789            LogDNSSEC("ProveInsecureCallback: Unsupported algorithm %d or digest %d", ds->alg, ds->digestType);
3790            DeliverInsecureProofResult(m, ic, DNSSEC_Insecure);
3791            return;
3792        }
3793
3794        // If the delegation is secure and the name that we queried for is same as the original
3795        // name that started the insecure proof, then something is not right. We started the
3796        // insecure proof e.g., the zone is not signed, but we are able to validate a DS for
3797        // the same name which implies that the zone is signed (whose algorithm we support) and
3798        // we should not have started the insecurity proof in the first place.
3799        if (SameDomainName(&question->qname, &pdv->origName))
3800        {
3801            LogDNSSEC("ProveInsecureCallback: Insecure proof reached original name %##s, error", question->qname.c);
3802            DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3803            return;
3804        }
3805
3806        LogDNSSEC("ProveInsecureCallback: Trying one more level down");
3807        ProveInsecure(m, pdv, ic, mDNSNULL);
3808    }
3809    else if (ac->rrset->rrtype == kDNSType_NSEC || ac->rrset->rrtype == kDNSType_NSEC3)
3810    {
3811        CacheRecord *cr;
3812
3813        if (ac->rrset->rrtype == kDNSType_NSEC)
3814            cr = NSECRecordIsDelegation(m, &question->qname, question->qtype);
3815        else
3816            cr = NSEC3RecordIsDelegation(m, &question->qname, question->qtype);
3817		if (cr)
3818        {
3819            LogDNSSEC("ProveInsecureCallback: Non-existence proved and %s is a delegation for %##s (%s)", CRDisplayString(m, cr),
3820				question->qname.c, DNSTypeName(question->qtype));
3821            DeliverInsecureProofResult(m, ic, DNSSEC_Insecure);
3822			return;
3823        }
3824        // Could be a ENT. Go one more level down to see whether it is a secure delegation or not.
3825        if (!SameDomainName(&question->qname, &pdv->origName))
3826        {
3827            LogDNSSEC("ProveInsecureCallback: Not a delegation %##s (%s), go one more level down", question->qname.c, DNSTypeName(question->qtype));
3828            ProveInsecure(m, pdv, ic, mDNSNULL);
3829        }
3830        else
3831        {
3832             // Secure denial of existence and the name matches the original query. This means we should have
3833             // received an NSEC (if the type does not exist) or signed records (if the name and type exists)
3834             // and verified it successfully instead of starting the insecure proof. This could happen e.g.,
3835             // Wildcard expanded answer received without NSEC/NSEC3s etc. Also, is it possible that the
3836             // zone went from unsigned to signed in a short time ? For now, we return bogus.
3837             LogDNSSEC("ProveInsecureCallback: Not a delegation %##s (%s), but reached original name", question->qname.c,
3838                 DNSTypeName(question->qtype));
3839             DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3840        }
3841    }
3842    return;
3843done:
3844    DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3845}
3846
3847// We return Insecure if we don't have a trust anchor or we have a trust anchor and
3848// can prove that the delegation is not secure (and hence can't establish the trust
3849// chain) or the delegation is possibly secure but we don't have the algorithm support
3850// to prove that.
3851mDNSexport void ProveInsecure(mDNS *const m, DNSSECVerifier *dv, InsecureContext *ic, domainname *trigger)
3852{
3853    TrustAnchor *ta;
3854    domainname *sname;
3855
3856    if (ic == mDNSNULL)
3857    {
3858        ic = (InsecureContext *)mDNSPlatformMemAllocate(sizeof(InsecureContext));
3859        if (!ic)
3860        {
3861            LogMsg("mDNSPlatformMemAllocate: ERROR!! memory alloc failed for ic");
3862            return;
3863        }
3864
3865        // Save the AuthInfo while we are proving insecure. We don't want to mix up
3866        // the auth chain for Bogus and Insecure. If we prove it to be insecure, we
3867        // will add the chain corresponding to the insecure proof. Otherwise, we will
3868        // restore this chain.
3869        if (dv->ac)
3870        {
3871            if (!dv->saveac)
3872            {
3873                LogDNSSEC("ProveInsecure: saving authinfo");
3874            }
3875            else
3876            {
3877                LogDNSSEC("ProveInsecure: ERROR!! authinfo already set");
3878                FreeDNSSECAuthChainInfo(dv->saveac);
3879            }
3880            dv->saveac = dv->ac;
3881            ResetAuthChain(dv);
3882        }
3883        ic->dv = dv;
3884        ic->q.ThisQInterval = -1;
3885
3886        if (trigger)
3887        {
3888            LogDNSSEC("ProveInsecure: Setting Trigger %##s", trigger->c);
3889            ic->triggerLabelCount = CountLabels(trigger);
3890        }
3891        else
3892        {
3893            LogDNSSEC("ProveInsecure: No Trigger");
3894            ic->triggerLabelCount = CountLabels(&dv->origName);
3895        }
3896
3897        ta = FindTrustAnchor(m, &dv->origName);
3898        if (!ta)
3899        {
3900            LogDNSSEC("ProveInsecure: TrustAnchor NULL");
3901            DeliverInsecureProofResult(m, ic, DNSSEC_Insecure);
3902            return;
3903        }
3904        // We want to skip the labels that is already matched by the trust anchor so
3905        // that the first query starts just below the trust anchor
3906        ic->skip = CountLabels(&dv->origName) - CountLabels(&ta->zone);
3907        if (!ic->skip)
3908        {
3909            LogDNSSEC("ProveInsecure: origName %##s, skip is zero", dv->origName.c);
3910            DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3911            return;
3912        }
3913    }
3914    // Look for the DS record starting just below the trust anchor.
3915    //
3916    // 1. If we find an NSEC record, then see if it is a delegation. If it is, then
3917    //    we are done. Otherwise, go down one more level.
3918    //
3919    // 2. If we find a DS record and no algorithm support, return "insecure". Otherwise, go
3920    //    down one more level.
3921    //
3922    sname = (domainname *)SkipLeadingLabels(&dv->origName, (ic->skip ? ic->skip - 1 : 0));
3923    if (!sname)
3924    {
3925        LogDNSSEC("ProveInsecure: sname NULL, origName %##s, skip %d", dv->origName.c, ic->skip);
3926        DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3927        return;
3928    }
3929
3930    // Insecurity proof is started during the normal bottom-up validation when we have a break in the trust
3931    // chain e.g., we get NSEC/NSEC3s when looking up a DS record. Insecurity proof is top-down looking
3932    // for a break in the trust chain. If we have already tried the validation (before the insecurity
3933    // proof started) for this "sname", then don't bother with the proof. This happens sometimes, when
3934    // we can't prove whether a zone is insecurely delegated or not. For example, if we are looking up
3935    // host1.secure-nods.secure.example and when we encounter secure-nods, there is no DS record in the
3936    // parent. We start the insecurity proof remembering that "secure-nods.secure.example" is the trigger
3937    // point. As part of the proof we reach "secure-nods.secure.example". Even though secure.example
3938    // prove that the name "secure-nods.secure.example/DS" does not exist,  it can't prove that it is a
3939    // delegation. So, we continue one more level down to host1.secure-nods.secure.example and we
3940    // realize that we already tried the validation and hence abort here.
3941
3942    if (CountLabels(sname) > ic->triggerLabelCount)
3943    {
3944        LogDNSSEC("ProveInsecure: Beyond the trigger current name %##s, origName %##s", sname->c, dv->origName.c);
3945        DeliverInsecureProofResult(m, ic, DNSSEC_Bogus);
3946        return;
3947    }
3948
3949    LogDNSSEC("ProveInsecure: OrigName %##s (%s), Current %##s", dv->origName.c, DNSTypeName(dv->origType), sname->c);
3950    ic->skip--;
3951    InitializeQuestion(m, &ic->q, dv->InterfaceID, sname, kDNSType_DS, ProveInsecureCallback, ic);
3952    ic->q.ValidationRequired = DNSSEC_VALIDATION_INSECURE;
3953    ic->q.ValidatingResponse = 0;
3954    ic->q.DNSSECAuthInfo = mDNSNULL;
3955    mDNS_StartQuery(m, &ic->q);
3956}
3957
3958mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
3959{
3960    switch (type)
3961    {
3962    case kStatsTypeMemoryUsage:
3963        if (action == kStatsActionIncrement)
3964        {
3965            m->DNSSECStats.TotalMemUsed += value;
3966        }
3967        else if (action == kStatsActionDecrement)
3968        {
3969            m->DNSSECStats.TotalMemUsed -= value;
3970        }
3971        break;
3972    case kStatsTypeLatency:
3973        if (action == kStatsActionSet)
3974        {
3975            if (value <= 4)
3976            {
3977                m->DNSSECStats.Latency0++;
3978            }
3979            else if (value <= 9)
3980            {
3981                m->DNSSECStats.Latency5++;
3982            }
3983            else if (value <= 19)
3984            {
3985                m->DNSSECStats.Latency10++;
3986            }
3987            else if (value <= 49)
3988            {
3989                m->DNSSECStats.Latency20++;
3990            }
3991            else if (value <= 99)
3992            {
3993                m->DNSSECStats.Latency50++;
3994            }
3995            else
3996            {
3997                m->DNSSECStats.Latency100++;
3998            }
3999        }
4000        break;
4001    case kStatsTypeExtraPackets:
4002        if (action == kStatsActionSet)
4003        {
4004            if (value <= 2)
4005            {
4006                m->DNSSECStats.ExtraPackets0++;
4007            }
4008            else if (value <= 6)
4009            {
4010                m->DNSSECStats.ExtraPackets3++;
4011            }
4012            else if (value <= 9)
4013            {
4014                m->DNSSECStats.ExtraPackets7++;
4015            }
4016            else
4017            {
4018                m->DNSSECStats.ExtraPackets10++;
4019            }
4020        }
4021        break;
4022    case kStatsTypeStatus:
4023        if (action == kStatsActionSet)
4024        {
4025            switch(value)
4026            {
4027            case DNSSEC_Secure:
4028                m->DNSSECStats.SecureStatus++;
4029                break;
4030            case DNSSEC_Insecure:
4031                m->DNSSECStats.InsecureStatus++;
4032                break;
4033            case DNSSEC_Indeterminate:
4034                m->DNSSECStats.IndeterminateStatus++;
4035                break;
4036            case DNSSEC_Bogus:
4037                m->DNSSECStats.BogusStatus++;
4038                break;
4039            case DNSSEC_NoResponse:
4040                m->DNSSECStats.NoResponseStatus++;
4041                break;
4042            default:
4043                LogMsg("BumpDNSSECStats: unknown status %d", value);
4044            }
4045        }
4046        break;
4047    case kStatsTypeMsgSize:
4048        if (action == kStatsActionSet)
4049        {
4050            if (value <= 1024)
4051            {
4052                m->DNSSECStats.MsgSize0++;
4053            }
4054            else if (value <= 2048)
4055            {
4056                m->DNSSECStats.MsgSize1++;
4057            }
4058            else
4059            {
4060                m->DNSSECStats.MsgSize2++;
4061            }
4062        }
4063        break;
4064    case kStatsTypeProbe:
4065        if (action == kStatsActionIncrement)
4066        {
4067            m->DNSSECStats.NumProbesSent += value;
4068        }
4069        break;
4070    default:
4071        LogMsg("BumpDNSSECStats: unknown type %d", type);
4072    }
4073    return;
4074}
4075
4076#else // !DNSSEC_DISABLED
4077
4078mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
4079{
4080    (void)m;
4081    (void)dv;
4082    (void)q;
4083}
4084
4085mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
4086{
4087    (void)m;
4088    (void)action;
4089    (void)type;
4090    (void)value;
4091}
4092
4093mDNSexport void InitializeQuestion(mDNS *const m, DNSQuestion *question, mDNSInterfaceID InterfaceID, const domainname *qname, mDNSu16 qtype, mDNSQuestionCallback *callback, void *context)
4094{
4095    (void) m;
4096    (void) question;
4097    (void) InterfaceID;
4098    (void) qname;
4099    (void) qtype;
4100    (void) callback;
4101    (void) context;
4102}
4103
4104mDNSexport char *DNSSECStatusName(DNSSECStatus status)
4105{
4106    (void) status;
4107
4108    return mDNSNULL;
4109}
4110
4111#endif // !DNSSEC_DISABLED
4112