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