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