1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 #include "mDNSEmbeddedAPI.h"
18 #include "DNSSECSupport.h"
19 #include "DNSCommon.h"
21 #include "CryptoAlg.h"
25 // Define DNSSEC_DISABLED to remove all the DNSSEC functionality
26 // and use the stub functions implemented later in this file.
28 #ifndef DNSSEC_DISABLED
30 //#define DNSSEC_DEBUG
33 #define debugdnssec LogMsg
35 #define debugdnssec debug_noop
38 // Implementation Notes
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.
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.
57 // The verification flow looks like this:
59 // VerifySignature -> StartDNSSECVerification - GetAllRRSetsForVerification -> FinishDNSSECVerification -> VerifySignature
61 // Verification is a recursive process. It stops when we find a trust anchor or if we have recursed too deep.
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.
67 // The flow in this case looks like this:
69 // VerifySignature -> ValidateWithNSECS -> {NoDataProof, NameErrorProof} -> VerifyNSECS -> StartDNSSECVerification
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.
75 // Insecure proofs are done when the verification ends up bogus. The flow would look like this
77 // VerifySignature -> StartDNSSECVerification - GetAllRRSetsForVerification -> FinishDNSSECVerification -> DNSSECValidationCB
78 // {DNSSECPositiveValidationCB, DNSSECNegativeValidationCB} -> ProveInsecure -> VerifySignaure ->
80 // ProveInsecure finds the break in trust in a top-down fashion.
82 // Forward declaration
83 mDNSlocal
void VerifySigCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
);
84 mDNSlocal mStatus
TrustedKey(mDNS
*const m
, DNSSECVerifier
*dv
);
85 mDNSlocal mDNSBool
TrustedKeyPresent(mDNS
*const m
, DNSSECVerifier
*dv
);
86 mDNSlocal mStatus
ValidateDS(DNSSECVerifier
*dv
);
87 mDNSlocal
void DNSSECNegativeValidationCB(mDNS
*const m
, DNSSECVerifier
*dv
, CacheGroup
*cg
, ResourceRecord
*answer
, DNSSECStatus status
);
88 mDNSlocal RRVerifier
* CopyRRVerifier(RRVerifier
*from
);
90 // Currently we use this to convert a RRVerifier to resource record so that we can
91 // use the standard DNS utility functions
92 LargeCacheRecord largerec
;
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
98 // TTL (in seconds) when the DNSSEC status is Bogus
99 #define RR_BOGUS_TTL 60
101 // RFC 4034 Appendix B: Get the keyid of a DNS KEY. It is not transmitted
102 // explicitly on the wire.
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
107 // 1st argument - the RDATA part of the DNSKEY RR
108 // 2nd argument - the RDLENGTH
110 mDNSlocal mDNSu32
keytag(mDNSu8
*key
, mDNSu32 keysize
)
115 // DST_ALG_RSAMD5 will be rejected automatically as the keytag
116 // is calculated wrongly
118 for (ac
= 0, i
= 0; i
< keysize
; ++i
)
119 ac
+= (i
& 1) ? key
[i
] : key
[i
] << 8;
120 ac
+= (ac
>> 16) & 0xFFFF;
124 mDNSexport
int DNSMemCmp(const mDNSu8
*const m1
, const mDNSu8
*const m2
, int len
)
128 res
= mDNSPlatformMemCmp(m1
, m2
, len
);
130 return (res
< 0 ? -1 : 1);
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
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
150 // Returns 0 if the names are same
151 // Returns -1 if d1 < d2
152 // Returns 1 if d1 > d2
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
157 mDNSexport
int DNSSECCanonicalOrder(const domainname
*const d1
, const domainname
*const d2
, int *subdomain
)
162 c1
= CountLabels(d1
);
164 c2
= CountLabels(d2
);
167 if (subdomain
) *subdomain
= 0;
169 // Compare as many labels as possible starting from the rightmost
170 count
= c1
< c2
? c1
: c2
;
171 for (i
= count
; i
> 0; i
--)
174 int j
, len
, lena
, lenb
;
176 a
= (mDNSu8
*)SkipLeadingLabels(d1
, skip1
);
177 b
= (mDNSu8
*)SkipLeadingLabels(d2
, skip2
);
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
;
185 for (j
= 0; j
< len
; j
++)
189 if (mDNSIsUpperCase(ac
)) ac
+= 'a' - 'A';
190 if (mDNSIsUpperCase(bc
)) bc
+= 'a' - 'A';
193 verbosedebugf("DNSSECCanonicalOrder: returning ac %c, bc %c", ac
, bc
);
194 return ((ac
< bc
) ? -1 : 1);
197 if ((lena
- lenb
) != 0)
199 verbosedebugf("DNSSECCanonicalOrder: returning lena %d lenb %d", lena
, lenb
);
200 return ((lena
< lenb
) ? -1 : 1);
203 // Continue with the next label
207 // We have compared label by label. Both of them are same if we are here.
209 // Two possibilities.
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.
215 // a.b.com is a subdomain of b.com
216 if ((c1
> c2
) && subdomain
)
219 verbosedebugf("DNSSECCanonicalOrder: returning c1 %d c2 %d\n", c1
, c2
);
221 return ((c1
< c2
) ? -1 : 1);
226 // Initialize the question enough so that it can be answered from the cache using SameNameRecordAnswersQuestion or
227 // ResourceRecordAnswersQuestion.
228 mDNSexport
void InitializeQuestion(mDNS
*const m
, DNSQuestion
*question
, mDNSInterfaceID InterfaceID
, const domainname
*qname
,
229 mDNSu16 qtype
, mDNSQuestionCallback
*callback
, void *context
)
231 debugf("InitializeQuestion: Called for %##s (%s)", qname
->c
, DNSTypeName(qtype
));
233 if (question
->ThisQInterval
!= -1) mDNS_StopQuery(m
, question
);
235 mDNS_SetupQuestion(question
, InterfaceID
, qname
, qtype
, callback
, context
);
236 question
->qnamehash
= DomainNameHashValue(qname
);
237 question
->ValidatingResponse
= mDNStrue
;
239 // Need to hold the lock, as GetServerForQuestion (its callers) references m->timenow.
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
);
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;
255 mDNSexport DNSSECVerifier
*AllocateDNSSECVerifier(mDNS
*const m
, const domainname
*name
, mDNSu16 rrtype
, mDNSInterfaceID InterfaceID
,
256 mDNSu8 ValidationRequired
, DNSSECVerifierCallback dvcallback
, mDNSQuestionCallback qcallback
)
260 dv
= (DNSSECVerifier
*)mDNSPlatformMemAllocate(sizeof(DNSSECVerifier
));
261 if (!dv
) { LogMsg("AllocateDNSSECVerifier: ERROR!! memory alloc failed"); return mDNSNULL
; }
262 mDNSPlatformMemZero(dv
, sizeof(*dv
));
264 LogDNSSEC("AllocateDNSSECVerifier called %p", dv
);
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;
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;
281 dv
->StartTime
= m
->timenow
;
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
);
288 mDNSlocal AuthChain
*AuthChainCopy(AuthChain
*ae
)
290 RRVerifier
*rvfrom
, **rvto
;
291 AuthChain
**prev
= mDNSNULL
;
292 AuthChain
*retac
= mDNSNULL
;
298 ac
= mDNSPlatformMemAllocate(sizeof(AuthChain
));
301 LogMsg("AuthChainCopy: AuthChain alloc failure");
314 *rvto
= CopyRRVerifier(rvfrom
);
315 rvfrom
= rvfrom
->next
;
316 rvto
= &((*rvto
)->next
);
323 *rvto
= CopyRRVerifier(rvfrom
);
324 rvfrom
= rvfrom
->next
;
325 rvto
= &((*rvto
)->next
);
332 *rvto
= CopyRRVerifier(rvfrom
);
333 rvfrom
= rvfrom
->next
;
334 rvto
= &((*rvto
)->next
);
347 mDNSlocal
void FreeDNSSECAuthChainInfo(AuthChain
*ac
)
353 LogDNSSEC("FreeDNSSECAuthChainInfo: called");
362 mDNSPlatformMemFree(rrset
);
365 ac
->rrset
= mDNSNULL
;
371 mDNSPlatformMemFree(rrset
);
374 ac
->rrsig
= mDNSNULL
;
380 mDNSPlatformMemFree(rrset
);
385 mDNSPlatformMemFree(ac
);
390 mDNSlocal
void FreeDNSSECAuthChain(DNSSECVerifier
*dv
)
394 FreeDNSSECAuthChainInfo(dv
->ac
);
395 // if someone reuses the "dv", it will be initialized properly
400 FreeDNSSECAuthChainInfo(dv
->saveac
);
401 dv
->saveac
= mDNSNULL
;
405 mDNSlocal
void FreeAuthChain(mDNS
*const m
, void *context
)
407 AuthChain
*ac
= (AuthChain
*)context
;
410 FreeDNSSECAuthChainInfo(ac
);
413 mDNSlocal
void FreeDNSSECVerifierRRSets(DNSSECVerifier
*dv
)
418 //debugdnssec("FreeDNSSECVerifierRRSets called %p", dv);
423 mDNSPlatformMemFree(rrset
);
426 dv
->rrset
= mDNSNULL
;
432 mDNSPlatformMemFree(rrset
);
435 dv
->rrsig
= mDNSNULL
;
441 mDNSPlatformMemFree(rrset
);
446 rrset
= dv
->rrsigKey
;
450 mDNSPlatformMemFree(rrset
);
453 dv
->rrsigKey
= mDNSNULL
;
459 mDNSPlatformMemFree(rrset
);
463 rrset
= dv
->pendingNSEC
;
467 mDNSPlatformMemFree(rrset
);
470 dv
->pendingNSEC
= mDNSNULL
;
473 mDNSexport
void FreeDNSSECVerifier(mDNS
*const m
, DNSSECVerifier
*dv
)
475 LogDNSSEC("FreeDNSSECVerifier called %p", dv
);
476 if (dv
->q
.ThisQInterval
!= -1)
477 mDNS_StopQuery(m
, &dv
->q
);
478 FreeDNSSECVerifierRRSets(dv
);
481 if (dv
->ac
|| dv
->saveac
)
482 FreeDNSSECAuthChain(dv
);
485 LogDNSSEC("FreeDNSSECVerifier freeing parent %p", dv
->parent
);
486 FreeDNSSECVerifier(m
, dv
->parent
);
488 mDNSPlatformMemFree(dv
);
491 mDNSlocal RRVerifier
* CopyRRVerifier(RRVerifier
*from
)
495 r
= mDNSPlatformMemAllocate(sizeof (RRVerifier
) + from
->rdlength
);
498 LogMsg("CopyRRVerifier: memory failure");
501 mDNSPlatformMemCopy(r
, from
, sizeof(RRVerifier
));
503 r
->rdata
= (mDNSu8
*) ((mDNSu8
*)r
+ sizeof(RRVerifier
));
504 mDNSPlatformMemCopy(r
->rdata
, from
->rdata
, r
->rdlength
);
508 mDNSexport RRVerifier
* AllocateRRVerifier(const ResourceRecord
*const rr
, mStatus
*status
)
512 r
= mDNSPlatformMemAllocate(sizeof (RRVerifier
) + rr
->rdlength
);
515 LogMsg("AllocateRRVerifier: memory failure");
516 *status
= mStatus_NoMemoryErr
;
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
));
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.
534 if (!putRData(mDNSNULL
, r
->rdata
, r
->rdata
+ rr
->rdlength
, rr
))
536 LogMsg("AllocateRRVerifier: putRData failed");
537 *status
= mStatus_BadParamErr
;
540 *status
= mStatus_NoError
;
544 mDNSexport mStatus
AddRRSetToVerifier(DNSSECVerifier
*dv
, const ResourceRecord
*const rr
, RRVerifier
*rv
, RRVerifierSet set
)
552 r
= AllocateRRVerifier(rr
, &status
);
553 if (!r
) return status
;
576 LogMsg("AddRRSetToVerifier: ERROR!! default case %d", set
);
577 return mStatus_BadParamErr
;
582 return mStatus_NoError
;
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).
587 mDNSexport
void ValidateRRSIG(DNSSECVerifier
*dv
, RRVerifierSet type
, const ResourceRecord
*const rr
)
591 rdataRRSig
*rrsigRData
= (rdataRRSig
*)((mDNSu8
*)rr
->rdata
+ sizeofRDataHeader
);
593 if (type
== RRVS_rrsig
)
597 else if (type
== RRVS_rrsig_key
)
603 LogMsg("ValidateRRSIG: ERROR!! type not valid %d", type
);
608 // For each authoritative RRset in a signed zone, there MUST be at least
609 // one RRSIG record that meets the following requirements:
611 // RRSet is defined by same name, class and type
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
))
616 debugdnssec("ValidateRRSIG: name mismatch or class mismatch");
620 // 2. The RRSIG RR's Type Covered field MUST equal the RRset's type.
621 if ((swap16(rrsigRData
->typeCovered
)) != rv
->rrtype
)
623 debugdnssec("ValidateRRSIG: typeCovered mismatch rrsig %d, rr type %d", swap16(rrsigRData
->typeCovered
), rv
->rrtype
);
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
))
631 debugdnssec("ValidateRRSIG: labels count problem rrsig %d, rr %d", rrsigRData
->labels
, CountLabels(&rv
->name
));
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)
642 case kDNSType_DNSKEY
:
643 //Signed by the owner
644 if (!SameDomainName(&rv
->name
, (domainname
*)&rrsigRData
->signerName
))
646 debugdnssec("ValidateRRSIG: Signer Name does not match the record name for %s", DNSTypeName(rv
->rrtype
));
651 // Should be signed by the parent
652 if (SameDomainName(&rv
->name
, (domainname
*)&rrsigRData
->signerName
))
654 debugdnssec("ValidateRRSIG: Signer Name matches the record name for %s", DNSTypeName(rv
->rrtype
));
660 int c1
= CountLabels(&rv
->name
);
661 int c2
= CountLabels((domainname
*)&rrsigRData
->signerName
);
664 debugdnssec("ValidateRRSIG: Signer Name not a subdomain label count %d < %d ", c1
, c2
);
667 domainname
*d
= (domainname
*)SkipLeadingLabels(&rv
->name
, c1
- c2
);
668 if (!SameDomainName(d
, (domainname
*)&rrsigRData
->signerName
))
670 debugdnssec("ValidateRRSIG: Signer Name not a subdomain");
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.
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();
684 if (DNS_SERIAL_LT(swap32(rrsigRData
->sigExpireTime
), currentTime
))
686 LogDNSSEC("ValidateRRSIG: Expired: currentTime %d, ExpireTime %d", (int)currentTime
,
687 swap32((int)rrsigRData
->sigExpireTime
));
690 if (DNS_SERIAL_LT(currentTime
, swap32(rrsigRData
->sigInceptTime
)))
692 LogDNSSEC("ValidateRRSIG: Future: currentTime %d, InceptTime %d", (int)currentTime
,
693 swap32((int)rrsigRData
->sigInceptTime
));
697 if (AddRRSetToVerifier(dv
, rr
, mDNSNULL
, type
) != mStatus_NoError
)
699 LogMsg("ValidateRRSIG: ERROR!! cannot allocate RRSet");
704 mDNSlocal mStatus
CheckRRSIGForRRSet(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
**negcr
)
710 mDNSBool expectRRSIG
= mDNSfalse
;
715 LogMsg("CheckRRSIGForRRSet: ERROR!! rrset NULL for origName %##s (%s)", dv
->origName
.c
,
716 DNSTypeName(dv
->origType
));
717 return mStatus_BadParamErr
;
721 slot
= HashSlot(&rv
->name
);
722 cg
= CacheGroupForName(m
, slot
, rv
->namehash
, &rv
->name
);
725 debugdnssec("CheckRRSIGForRRSet: cg null");
726 return mStatus_NoSuchRecord
;
729 for (cr
=cg
->members
; cr
; cr
=cr
->next
)
731 debugdnssec("CheckRRSIGForRRSet: checking the validity of rrsig");
732 if (cr
->resrec
.rrtype
!= kDNSType_RRSIG
)
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
)
739 expectRRSIG
= cr
->CRDNSSECQuestion
;
740 LogDNSSEC("CheckRRSIGForRRSet: %s RRSIG for %s", (expectRRSIG
? "Expecting" : "Not Expecting"), CRDisplayString(m
, cr
));
744 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
748 LogDNSSEC("CheckRRSIGForRRSet: Negative cache record %s encountered for %##s (%s)", CRDisplayString(m
, cr
),
749 rv
->name
.c
, DNSTypeName(rv
->rrtype
));
754 LogMsg("CheckRRSIGForRRSet: ERROR!! Negative cache record %s already set for %##s (%s)", CRDisplayString(m
, cr
),
755 rv
->name
.c
, DNSTypeName(rv
->rrtype
));
759 ValidateRRSIG(dv
, RRVS_rrsig
, &cr
->resrec
);
761 if (*negcr
&& dv
->rrsig
)
763 // Encountered both RRSIG and negative CR
764 LogMsg("CheckRRSIGForRRSet: ERROR!! Encountered negative cache record %s and RRSIG for %##s (%s)",
765 CRDisplayString(m
, *negcr
), rv
->name
.c
, DNSTypeName(rv
->rrtype
));
766 return mStatus_BadParamErr
;
768 // If we can't find RRSIGs, but we find a negative response then we need to validate that
769 // which the caller will do it. Otherwise, if we should be expecting RRSIGs to be in the
770 // cache already, then return error.
771 if (dv
->rrsig
|| *negcr
)
772 return mStatus_NoError
;
773 else if (expectRRSIG
)
774 return mStatus_BadParamErr
;
776 return mStatus_NoSuchRecord
;
779 mDNSlocal
void CheckOneKeyForRRSIG(DNSSECVerifier
*dv
, const ResourceRecord
*const rr
)
785 LogMsg("CheckOneKeyForRRSIG: ERROR!! rrsig NULL");
788 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
789 if (!SameDomainName((domainname
*)&rrsig
->signerName
, rr
->name
))
791 debugdnssec("CheckOneKeyForRRSIG: name mismatch");
795 // We store all the keys including the ZSK and KSK and use them appropriately
797 if (AddRRSetToVerifier(dv
, rr
, mDNSNULL
, RRVS_key
) != mStatus_NoError
)
799 LogMsg("CheckOneKeyForRRSIG: ERROR!! cannot allocate RRSet");
804 mDNSlocal mStatus
CheckKeyForRRSIG(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
**negcr
)
816 LogMsg("CheckKeyForRRSIG: ERROR!! rrsig NULL");
817 return mStatus_BadParamErr
;
820 // Signer name should be the same on all rrsig ??
821 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
822 name
= (domainname
*)&rrsig
->signerName
;
824 slot
= HashSlot(name
);
825 namehash
= DomainNameHashValue(name
);
826 cg
= CacheGroupForName(m
, slot
, namehash
, name
);
829 debugdnssec("CheckKeyForRRSIG: cg null for %##s", name
->c
);
830 return mStatus_NoSuchRecord
;
833 for (cr
=cg
->members
; cr
; cr
=cr
->next
)
835 if (cr
->resrec
.rrtype
!= kDNSType_DNSKEY
) continue;
836 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
840 LogDNSSEC("CheckKeyForRRSIG: Negative cache record %s encountered for %##s (DNSKEY)", CRDisplayString(m
, cr
),
846 LogMsg("CheckKeyForRRSIG: ERROR!! Negative cache record %s already set for %##s (DNSKEY)", CRDisplayString(m
, cr
),
851 debugdnssec("CheckKeyForRRSIG: checking the validity of key record");
852 CheckOneKeyForRRSIG(dv
, &cr
->resrec
);
854 if (*negcr
&& dv
->key
)
856 // Encountered both RRSIG and negative CR
857 LogMsg("CheckKeyForRRSIG: ERROR!! Encountered negative cache record %s and DNSKEY for %##s",
858 CRDisplayString(m
, *negcr
), name
->c
);
859 return mStatus_BadParamErr
;
861 if (dv
->key
|| *negcr
)
862 return mStatus_NoError
;
864 return mStatus_NoSuchRecord
;
867 mDNSlocal
void CheckOneRRSIGForKey(DNSSECVerifier
*dv
, const ResourceRecord
*const rr
)
872 LogMsg("CheckOneRRSIGForKey: ERROR!! rrsig NULL");
875 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
876 if (!SameDomainName((domainname
*)&rrsig
->signerName
, rr
->name
))
878 debugdnssec("CheckOneRRSIGForKey: name mismatch");
881 ValidateRRSIG(dv
, RRVS_rrsig_key
, rr
);
884 mDNSlocal mStatus
CheckRRSIGForKey(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
**negcr
)
892 mDNSBool expectRRSIG
= mDNSfalse
;
897 LogMsg("CheckRRSIGForKey: ERROR!! rrsig NULL");
898 return mStatus_BadParamErr
;
902 LogMsg("CheckRRSIGForKey: ERROR!! key NULL");
903 return mStatus_BadParamErr
;
905 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
906 name
= (domainname
*)&rrsig
->signerName
;
908 slot
= HashSlot(name
);
909 namehash
= DomainNameHashValue(name
);
910 cg
= CacheGroupForName(m
, slot
, namehash
, name
);
913 debugdnssec("CheckRRSIGForKey: cg null %##s", name
->c
);
914 return mStatus_NoSuchRecord
;
916 for (cr
=cg
->members
; cr
; cr
=cr
->next
)
918 if (cr
->resrec
.rrtype
!= kDNSType_RRSIG
)
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
)
925 expectRRSIG
= cr
->CRDNSSECQuestion
;
926 LogDNSSEC("CheckRRSIGForKey: %s RRSIG for %s", (expectRRSIG
? "Expecting" : "Not Expecting"), CRDisplayString(m
, cr
));
930 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
934 LogDNSSEC("CheckRRSIGForKey: Negative cache record %s encountered for %##s (RRSIG)", CRDisplayString(m
, cr
),
940 LogMsg("CheckRRSIGForKey: ERROR!! Negative cache record %s already set for %##s (RRSIG)", CRDisplayString(m
, cr
),
945 debugdnssec("CheckRRSIGForKey: checking the validity of rrsig");
946 CheckOneRRSIGForKey(dv
, &cr
->resrec
);
948 if (*negcr
&& dv
->rrsigKey
)
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
;
955 // If we can't find RRSIGs, but we find a negative response then we need to validate that
956 // which the caller will do it. Finally, make sure that we are not expecting RRSIGS.
957 if (dv
->rrsigKey
|| *negcr
)
958 return mStatus_NoError
;
959 else if (expectRRSIG
)
960 return mStatus_BadParamErr
;
962 return mStatus_NoSuchRecord
;
965 mDNSlocal
void CheckOneDSForKey(DNSSECVerifier
*dv
, const ResourceRecord
*const rr
)
975 LogMsg("CheckOneDSForKey: ERROR!! rrsig NULL");
978 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
979 DS
= (rdataDS
*)((mDNSu8
*)rr
->rdata
+ sizeofRDataHeader
);
981 if (!SameDomainName((domainname
*)&rrsig
->signerName
, rr
->name
))
983 debugdnssec("CheckOneDSForKey: name mismatch");
986 for (keyv
= dv
->key
; keyv
; keyv
= keyv
->next
)
988 key
= (rdataDNSKey
*)keyv
->rdata
;
989 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
);
990 if (tag
!= swap16(DS
->keyTag
))
992 debugdnssec("CheckOneDSForKey: keyTag mismatch keyTag %d, DStag %d", tag
, swap16(DS
->keyTag
));
995 if (key
->alg
!= DS
->alg
)
997 debugdnssec("CheckOneDSForKey: alg mismatch key alg%d, DS alg %d", key
->alg
, swap16(DS
->alg
));
1000 if (AddRRSetToVerifier(dv
, rr
, mDNSNULL
, RRVS_ds
) != mStatus_NoError
)
1002 debugdnssec("CheckOneDSForKey: cannot allocate RRSet");
1007 mDNSlocal mStatus
CheckDSForKey(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
**negcr
)
1019 LogMsg("CheckDSForKey: ERROR!! rrsig NULL");
1020 return mStatus_BadParamErr
;
1024 LogMsg("CheckDSForKey: ERROR!! key NULL");
1025 return mStatus_BadParamErr
;
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
);
1034 debugdnssec("CheckDSForKey: cg null for %s", name
->c
);
1035 return mStatus_NoSuchRecord
;
1037 for (cr
=cg
->members
; cr
; cr
=cr
->next
)
1039 if (cr
->resrec
.rrtype
!= kDNSType_DS
) continue;
1040 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
1044 LogDNSSEC("CheckDSForKey: Negative cache record %s encountered for %##s (DS)", CRDisplayString(m
, cr
),
1050 LogMsg("CheckDSForKey: ERROR!! Negative cache record %s already set for %##s (DS)", CRDisplayString(m
, cr
),
1055 CheckOneDSForKey(dv
, &cr
->resrec
);
1057 if (*negcr
&& dv
->ds
)
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
;
1064 if (dv
->ds
|| *negcr
)
1065 return mStatus_NoError
;
1067 return mStatus_NoSuchRecord
;
1068 return (dv
->ds
? mStatus_NoError
: mStatus_NoSuchRecord
);
1071 // It returns mDNStrue if we have all the rrsets for verification and mDNSfalse otherwise.
1072 mDNSlocal mDNSBool
GetAllRRSetsForVerification(mDNS
*const m
, DNSSECVerifier
*dv
)
1080 LogMsg("GetAllRRSetsForVerification: ERROR!! rrset NULL");
1081 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
1085 if (dv
->next
== RRVS_done
) return mDNStrue
;
1087 debugdnssec("GetAllRRSetsForVerification: next %d", dv
->next
);
1091 // If we can't find the RRSIG for the rrset, re-issue the query.
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
)
1099 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
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
)
1110 ValidateWithNSECS(m
, dv
, negcr
);
1114 dv
->next
= RRVS_key
;
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
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.
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");
1133 mDNS_StartQuery(m
, &dv
->q
);
1136 // if we found the RRSIG, then fall through to find the DNSKEY
1138 err
= CheckKeyForRRSIG(m
, dv
, &negcr
);
1139 if (err
!= mStatus_NoSuchRecord
&& err
!= mStatus_NoError
)
1141 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
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
)
1151 ValidateWithNSECS(m
, dv
, negcr
);
1155 dv
->next
= RRVS_rrsig_key
;
1158 debugdnssec("GetAllRRSetsForVerification: Fetching DNSKEY for RRSET");
1160 mDNS_StartQuery(m
, &dv
->q
);
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
)
1169 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
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
)
1179 ValidateWithNSECS(m
, dv
, negcr
);
1183 debugdnssec("GetAllRRSetsForVerification: RRVS_rrsig_key %p", dv
->rrsigKey
);
1186 debugdnssec("GetAllRRSetsForVerification: Fetching RRSIGS for DNSKEY");
1188 mDNS_StartQuery(m
, &dv
->q
);
1191 // if we found RRSIG for the DNSKEY, then fall through to find the DS
1195 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
1196 qname
= (domainname
*)&rrsig
->signerName
;
1198 err
= CheckDSForKey(m
, dv
, &negcr
);
1199 if (err
!= mStatus_NoSuchRecord
&& err
!= mStatus_NoError
)
1201 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
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
)
1210 ValidateWithNSECS(m
, dv
, negcr
);
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
))
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"))
1221 LogDNSSEC("GetAllRRSetsForVerification: Reached root");
1222 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
1225 debugdnssec("GetAllRRSetsForVerification: Fetching DS");
1227 mDNS_StartQuery(m
, &dv
->q
);
1232 debugdnssec("GetAllRRSetsForVerification: Skipped fetching the DS");
1237 LogMsg("GetAllRRSetsForVerification: ERROR!! unknown next %d", dv
->next
);
1238 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
1244 mDNSlocal
void PrintFixedSignInfo(rdataRRSig
*rrsig
, domainname
*signerName
, int sigNameLen
, mDNSu8
*fixedPart
, int fixedPartLen
)
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];
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
);
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
);
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
);
1269 mDNSlocal
void PrintVarSignInfo(mDNSu16 rdlen
, mDNSu8
*rdata
)
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
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
);
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
);
1290 mDNSlocal
void PrintVarSignInfo(mDNSu16 rdlen
, mDNSu8
*rdata
)
1295 mDNSlocal
void PrintFixedSignInfo(rdataRRSig
*rrsig
, domainname
*signerName
, int sigNameLen
, mDNSu8
*fixedPart
, int fixedPartLen
)
1305 // Used for RDATA comparison
1313 mDNSlocal
int rdata_compare(mDNSu8
*const rdata1
, mDNSu8
*const rdata2
, int rdlen1
, int rdlen2
)
1318 len
= (rdlen1
< rdlen2
) ? rdlen1
: rdlen2
;
1320 ret
= DNSMemCmp(rdata1
, rdata2
, len
);
1321 if (ret
!= 0) return ret
;
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);
1328 mDNSlocal
int name_compare(mDNSu8
*const rdata1
, mDNSu8
*const rdata2
, int rdlen1
, int rdlen2
)
1330 domainname
*n1
= (domainname
*)rdata1
;
1331 domainname
*n2
= (domainname
*)rdata2
;
1337 c1
= CountLabels(n1
);
1338 c2
= CountLabels(n2
);
1340 count
= c1
< c2
? c1
: c2
;
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
++)
1346 // Are the lengths same ?
1349 debugdnssec("compare_name: returning c1 %d, c2 %d", *a
, *b
);
1350 return ((*a
< *b
) ? -1 : 1);
1353 rdlen1
-= (len
+ 1);
1354 rdlen2
-= (len
+ 1);
1355 if (rdlen1
< 0 || rdlen2
< 0)
1357 LogMsg("name_compare: ERROR!! not enough data rdlen1 %d, rdlen2 %d", rdlen1
, rdlen2
);
1361 for (j
= 0; j
< len
; j
++)
1365 if (mDNSIsUpperCase(ac
)) ac
+= 'a' - 'A';
1366 if (mDNSIsUpperCase(bc
)) bc
+= 'a' - 'A';
1369 debugdnssec("compare_name: returning ac %c, bc %c", ac
, bc
);
1370 return ((ac
< bc
) ? -1 : 1);
1378 mDNSlocal
int srv_compare(rdataComp
*const r1
, rdataComp
*const r2
)
1381 int length1
, length2
;
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)
1388 LogMsg("srv_compare: ERROR!! Length smaller than 7 bytes");
1391 // Compare priority, weight and port
1392 res
= DNSMemCmp(r1
->rdata
, r2
->rdata
, 6);
1393 if (res
!= 0) return res
;
1396 return (name_compare(r1
->rdata
+ 6, r2
->rdata
+ 6, length1
, length2
));
1399 mDNSlocal
int tsig_compare(rdataComp
*const r1
, rdataComp
*const r2
)
1401 int offset1
, offset2
;
1402 int length1
, length2
;
1405 offset1
= offset2
= 0;
1406 length1
= r1
->rdlength
;
1407 length2
= r2
->rdlength
;
1409 // we should have at least one byte to start with
1410 if (length1
< 1 || length2
< 1)
1412 LogMsg("sig_compare: Length smaller than 18 bytes");
1416 res
= name_compare(r1
->rdata
, r2
->rdata
, length1
, length2
);
1417 if (res
!= 0) return res
;
1419 dlen
= DomainNameLength((domainname
*)r1
->rdata
);
1425 if (length1
<= 1 || length2
<= 1)
1427 LogMsg("tsig_compare: data too small to compare length1 %d, length2 %d", length1
, length2
);
1431 return (rdata_compare(r1
->rdata
+ offset1
, r2
->rdata
+ offset2
, length1
, length2
));
1434 // Compares types that conform to : <length><Value>
1435 mDNSlocal
int lenval_compare(mDNSu8
*d1
, mDNSu8
*d2
, int *len1
, int *len2
, int rem1
, int rem2
)
1440 if (rem1
<= 1 || rem2
<= 1)
1442 LogMsg("lenval_compare: data too small to compare length1 %d, length2 %d", rem1
, rem2
);
1447 len
= (*len1
< *len2
? *len1
: *len2
);
1448 res
= DNSMemCmp(d1
, d2
, len
+ 1);
1452 // RFC 2915: Order (2) Preference(2) and variable length: Flags Service Regexp Replacement
1453 mDNSlocal
int naptr_compare(rdataComp
*const r1
, rdataComp
*const r2
)
1455 mDNSu8
*d1
= r1
->rdata
;
1456 mDNSu8
*d2
= r2
->rdata
;
1457 int len1
, len2
, res
;
1458 int length1
, length2
;
1460 length1
= r1
->rdlength
;
1461 length2
= r2
->rdlength
;
1463 // Order, Preference plus at least 1 byte
1464 if (length1
< 5 || length2
< 5)
1466 LogMsg("naptr_compare: Length smaller than 18 bytes");
1469 // Compare order and preference
1470 res
= DNSMemCmp(d1
, d2
, 4);
1471 if (res
!= 0) return res
;
1478 // Compare Flags (including the length byte)
1479 res
= lenval_compare(d1
, d2
, &len1
, &len2
, length1
, length2
);
1480 if (res
!= 0) return res
;
1483 length1
-= (len1
+ 1);
1484 length2
-= (len2
+ 1);
1486 // Compare Service (including the length byte)
1487 res
= lenval_compare(d1
, d2
, &len1
, &len2
, length1
, length2
);
1488 if (res
!= 0) return res
;
1491 length1
-= (len1
+ 1);
1492 length2
-= (len2
+ 1);
1494 // Compare regexp (including the length byte)
1495 res
= lenval_compare(d1
, d2
, &len1
, &len2
, length1
, length2
);
1496 if (res
!= 0) return res
;
1499 length1
-= (len1
+ 1);
1500 length2
-= (len2
+ 1);
1502 // Compare Replacement
1503 return name_compare(d1
, d2
, length1
, length2
);
1506 // RFC 1035: MINFO: Two domain names
1507 // RFC 1183: RP: Two domain names
1508 mDNSlocal
int dom2_compare(mDNSu8
*d1
, mDNSu8
*d2
, int length1
, int length2
)
1512 // We need at least one byte to start with
1513 if (length1
< 1 || length2
< 1)
1515 LogMsg("dom2_compare:1: data too small length1 %d, length2 %d", length1
, length2
);
1518 res
= name_compare(d1
, d2
, length1
, length2
);
1519 if (res
!= 0) return res
;
1520 dlen
= DomainNameLength((domainname
*)d1
);
1524 // We need at least one byte to start with
1525 if (length1
< 1 || length2
< 1)
1527 LogMsg("dom2_compare:2: data too small length1 %d, length2 %d", length1
, length2
);
1534 return name_compare(d1
, d2
, length1
, length2
);
1537 // MX : preference (2 bytes), domainname
1538 mDNSlocal
int mx_compare(rdataComp
*const r1
, rdataComp
*const r2
)
1541 int length1
, length2
;
1543 length1
= r1
->rdlength
;
1544 length2
= r2
->rdlength
;
1546 // We need at least two bytes + 1 extra byte for the domainname to start with
1547 if (length1
< 3 || length2
< 3)
1549 LogMsg("mx_compare: data too small length1 %d, length2 %d", length1
, length2
);
1553 res
= DNSMemCmp(r1
->rdata
, r2
->rdata
, 2);
1554 if (res
!= 0) return res
;
1557 return name_compare(r1
->rdata
+ 2, r2
->rdata
+ 2, length1
, length2
);
1560 // RFC 2163 (PX) : preference (2 bytes), map822. mapx400 (domainnames)
1561 mDNSlocal
int px_compare(rdataComp
*const r1
, rdataComp
*const r2
)
1565 // We need at least two bytes + 1 extra byte for the domainname to start with
1566 if (r1
->rdlength
< 3 || r2
->rdlength
< 3)
1568 LogMsg("px_compare: data too small length1 %d, length2 %d", r1
->rdlength
, r2
->rdlength
);
1572 res
= DNSMemCmp(r1
->rdata
, r2
->rdata
, 2);
1573 if (res
!= 0) return res
;
1575 return dom2_compare(r1
->rdata
+ 2, r2
->rdata
+ 2, r1
->rdlength
- 2, r2
->rdlength
- 2);
1578 mDNSlocal
int soa_compare(rdataComp
*r1
, rdataComp
*r2
)
1581 int offset1
, offset2
;
1582 int length1
, length2
;
1584 length1
= r1
->rdlength
;
1585 length2
= r2
->rdlength
;
1586 offset1
= offset2
= 0;
1588 // We need at least 20 bytes plus 1 byte for each domainname
1589 if (length1
< 22 || length2
< 22)
1591 LogMsg("soa_compare:1: data too small length1 %d, length2 %d", length1
, length2
);
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
1598 res
= name_compare(r1
->rdata
, r2
->rdata
, length1
, length2
);
1599 if (res
!= 0) return res
;
1601 dlen
= DomainNameLength((domainname
*)r1
->rdata
);
1605 if (length1
< 1 || length2
< 1)
1607 LogMsg("soa_compare:2: data too small length1 %d, length2 %d", length1
, length2
);
1613 res
= name_compare(r1
->rdata
+ offset1
, r2
->rdata
+ offset2
, length1
, length2
);
1614 if (res
!= 0) return res
;
1616 dlen
= DomainNameLength((domainname
*)r1
->rdata
);
1619 if (length1
< 20 || length2
< 20)
1621 LogMsg("soa_compare:3: data too small length1 %d, length2 %d", length1
, length2
);
1627 return (rdata_compare(r1
->rdata
+ offset1
, r2
->rdata
+ offset2
, length1
, length2
));
1630 // RFC 4034 Section 6.0 states that:
1632 // A canonical RR form and ordering within an RRset are required in order to
1633 // construct and verify RRSIG RRs.
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.
1638 mDNSlocal
int RDATACompare(const void *rdata1
, const void *rdata2
)
1640 rdataComp
*r1
= (rdataComp
*)rdata1
;
1641 rdataComp
*r2
= (rdataComp
*)rdata2
;
1643 if (r1
->rrtype
!= r2
->rrtype
)
1645 LogMsg("RDATACompare: ERROR!! comparing rdata of wrong types type1: %d, type2: %d", r1
->rrtype
, r2
->rrtype
);
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
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
);
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
);
1725 // RFC 4034 section 6.2 requirement for verifying signature.
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;
1733 // NSEC and HINFO is not needed as per dnssec-bis update. RRSIG is done elsewhere
1734 // as part of signature verification
1735 mDNSlocal
void ConvertRDATAToCanonical(mDNSu16 rrtype
, mDNSu16 rdlength
, mDNSu8
*rdata
)
1739 mDNSu8
*origRdata
= rdata
;
1741 // Ensure that we have at least one byte of data to examine and modify.
1743 if (!rdlength
) { LogMsg("ConvertRDATAToCanonical: rdlength zero for rrtype %s", DNSTypeName(rrtype
)); return; }
1747 // Not adding suppot for A6 as it is deprecated
1748 case kDNSType_A6
: // 38 IPv6 Address (deprecated)
1750 debugdnssec("ConvertRDATAToCanonical: returning from default %s", DNSTypeName(rrtype
));
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)
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
1767 if (DNSNameToLowerCase((domainname
*)rdata
, &name
) != mStatus_NoError
)
1769 LogMsg("ConvertRDATAToCanonical: ERROR!! DNSNameToLowerCase failed");
1772 AssignDomainName((domainname
*)rdata
, &name
);
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
1779 // format: preference - 2 bytes, followed by name
1780 // Ensure that we have at least 3 bytes (preference + 1 byte for the domain name)
1783 LogMsg("ConvertRDATAToCanonical:MX: rdlength %d for rrtype %s too small", rdlength
, DNSTypeName(rrtype
));
1786 if (DNSNameToLowerCase((domainname
*)(rdata
+ 2), &name
) != mStatus_NoError
)
1788 LogMsg("ConvertRDATAToCanonical: MX: ERROR!! DNSNameToLowerCase failed");
1791 AssignDomainName((domainname
*)(rdata
+ 2), &name
);
1793 case kDNSType_SRV
: // 33 Service record
1794 // format : priority, weight and port - 6 bytes, followed by name
1797 LogMsg("ConvertRDATAToCanonical:SRV: rdlength %d for rrtype %s too small", rdlength
, DNSTypeName(rrtype
));
1800 if (DNSNameToLowerCase((domainname
*)(rdata
+ 6), &name
) != mStatus_NoError
)
1802 LogMsg("ConvertRDATAToCanonical: SRV: ERROR!! DNSNameToLowerCase failed");
1805 AssignDomainName((domainname
*)(rdata
+ 6), &name
);
1807 case kDNSType_PX
: // 26 X.400 mail mapping
1810 LogMsg("ConvertRDATAToCanonical:PX: rdlength %d for rrtype %s too small", rdlength
, DNSTypeName(rrtype
));
1813 // Preference followed by two domain names
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
)
1821 LogMsg("ConvertRDATAToCanonical: SOA1: ERROR!! DNSNameToLowerCase failed");
1825 AssignDomainName((domainname
*)rdata
, &name
);
1826 len
= DomainNameLength((domainname
*)rdata
);
1827 if (rdlength
<= len
+ 1)
1829 LogMsg("ConvertRDATAToCanonical:RP: rdlength %d for rrtype %s too small", rdlength
, DNSTypeName(rrtype
));
1834 if (DNSNameToLowerCase((domainname
*)rdata
, &name
) != mStatus_NoError
)
1836 LogMsg("ConvertRDATAToCanonical: SOA2: ERROR!! DNSNameToLowerCase failed");
1839 AssignDomainName((domainname
*)rdata
, &name
);
1841 case kDNSType_NAPTR
: // 35 Naming Authority Pointer
1842 // order and preference
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);
1851 // Replacement field is a domainname. If we have at least one more byte, then we are okay.
1852 if ((origRdata
+ rdlength
) < rdata
+ 1)
1854 LogMsg("ConvertRDATAToCanonical:NAPTR: origRdata %p, rdlength %d, rdata %p for rrtype %s too small", origRdata
, rdlength
, rdata
, DNSTypeName(rrtype
));
1857 if (DNSNameToLowerCase((domainname
*)rdata
, &name
) != mStatus_NoError
)
1859 LogMsg("ConvertRDATAToCanonical: NAPTR2: ERROR!! DNSNameToLowerCase failed");
1862 AssignDomainName((domainname
*)rdata
, &name
);
1863 case kDNSType_SIG
: // 24 Security signature
1864 // format: <18 bytes> <domainname> <data>
1867 LogMsg("ConvertRDATAToCanonical:SIG: rdlength %d for rrtype %s too small", rdlength
, DNSTypeName(rrtype
));
1870 // Preference followed by two domain names
1872 if (DNSNameToLowerCase((domainname
*)rdata
, &name
) != mStatus_NoError
)
1874 LogMsg("ConvertRDATAToCanonical: SIG: ERROR!! DNSNameToLowerCase failed");
1877 AssignDomainName((domainname
*)rdata
, &name
);
1882 mDNSlocal mDNSBool
ValidateSignatureWithKey(DNSSECVerifier
*dv
, RRVerifier
*rrset
, RRVerifier
*keyv
, RRVerifier
*sig
)
1885 domainname signerName
;
1887 mDNSu8 fixedPart
[MAX_DOMAIN_NAME
+ 8]; // domainname + type + class + ttl
1891 rdataComp
*ptr
, *start
, *p
;
1900 key
= (rdataDNSKey
*)keyv
->rdata
;
1901 rrsig
= (rdataRRSig
*)sig
->rdata
;
1903 LogDNSSEC("ValidateSignatureWithKey: Validating signature with key with tag %d", (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
));
1905 if (DNSNameToLowerCase((domainname
*)&rrsig
->signerName
, &signerName
) != mStatus_NoError
)
1907 LogMsg("ValidateSignatureWithKey: ERROR!! cannot convert signer name to lower case");
1911 if (DNSNameToLowerCase((domainname
*)&rrset
->name
, &name
) != mStatus_NoError
)
1913 LogMsg("ValidateSignatureWithKey: ERROR!! cannot convert rrset name to lower case");
1917 sigNameLen
= DomainNameLength(&signerName
);
1918 labels
= CountLabels(&name
);
1919 // RFC 4034: RRSIG validation
1921 // signature = sign(RRSIG_RDATA | RR(1) | RR(2)... )
1923 // where RRSIG_RDATA excludes the signature and signer name in canonical form
1925 if (dv
->ctx
) AlgDestroy(dv
->ctx
);
1926 dv
->ctx
= AlgCreate(CRYPTO_ALG
, rrsig
->alg
);
1929 LogDNSSEC("ValidateSignatureWithKey: ERROR!! No algorithm support for %d", rrsig
->alg
);
1932 AlgAdd(dv
->ctx
, (const mDNSu8
*)rrsig
, RRSIG_FIXED_SIZE
);
1933 AlgAdd(dv
->ctx
, signerName
.c
, sigNameLen
);
1935 if (labels
- rrsig
->labels
> 0)
1938 LogDNSSEC("ValidateSignatureWithKey: ====splitting labels %d, rrsig->labels %d====", labels
,rrsig
->labels
);
1939 d
= (domainname
*)SkipLeadingLabels(&name
, labels
- rrsig
->labels
);
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] != '*')
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
;
1957 debugdnssec("ValidateSignatureWithKey: assigning domainname");
1958 AssignDomainName((domainname
*)fixedPart
, &name
);
1959 fixedPartLen
= DomainNameLength(&name
);
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
);
1971 for (tmp
= rrset
, nrrsets
= 0; tmp
; tmp
= tmp
->next
)
1975 start
= ptr
= mDNSPlatformMemAllocate(nrrsets
* sizeof (rdataComp
));
1976 debugdnssec("ValidateSignatureWithKey: start %p, nrrsets %d", start
, nrrsets
);
1979 // Need to initialize for failure case below
1980 mDNSPlatformMemZero(ptr
, nrrsets
* (sizeof (rdataComp
)));
1983 ptr
->rdlength
= tmp
->rdlength
;
1984 ptr
->rrtype
= tmp
->rrtype
;
1987 ptr
->rdata
= mDNSPlatformMemAllocate(ptr
->rdlength
);
1990 mDNSPlatformMemCopy(ptr
->rdata
, tmp
->rdata
, tmp
->rdlength
);
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");
2007 LogMsg("ValidateSignatureWithKey:2: ERROR!! RDATA memory alloation failure");
2011 PrintFixedSignInfo(rrsig
, &signerName
, sigNameLen
, fixedPart
, fixedPartLen
);
2013 mDNSPlatformQsort(start
, nrrsets
, sizeof(rdataComp
), RDATACompare
);
2014 for (p
= start
, i
= 0; i
< nrrsets
; p
++, i
++)
2018 // The array is sorted and hence checking adjacent entries for duplicate is sufficient
2021 rdataComp
*q
= p
- 1;
2022 if (!RDATACompare((void *)p
, (void *)q
)) continue;
2025 // Add the fixed part
2026 AlgAdd(dv
->ctx
, (const mDNSu8
*)fixedPart
, fixedPartLen
);
2029 rdlen
= swap16(p
->rdlength
);
2030 AlgAdd(dv
->ctx
, (const mDNSu8
*)&rdlen
, sizeof(mDNSu16
));
2032 ConvertRDATAToCanonical(p
->rrtype
, p
->rdlength
, p
->rdata
);
2034 PrintVarSignInfo(rdlen
, p
->rdata
);
2035 AlgAdd(dv
->ctx
, (const mDNSu8
*)p
->rdata
, p
->rdlength
);
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
);
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
);
2045 if (algRet
!= mStatus_NoError
)
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
)
2051 dv
->flags
&= ~WILDCARD_PROVES_ANSWER_EXPANDED
;
2052 dv
->wildcardName
= mDNSNULL
;
2059 // Walk all the keys and for each key walk all the RRSIGS that signs the original rrset
2060 mDNSlocal mStatus
ValidateSignature(DNSSECVerifier
*dv
, RRVerifier
**resultKey
, RRVerifier
**resultRRSIG
)
2073 for (keyv
= dv
->key
; keyv
; keyv
= keyv
->next
)
2075 key
= (rdataDNSKey
*)keyv
->rdata
;
2076 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
);
2077 for (rrsigv
= sig
; rrsigv
; rrsigv
= rrsigv
->next
)
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
))
2084 debugdnssec("ValidateSignature: name mismatch");
2087 if (key
->alg
!= rrsig
->alg
)
2089 debugdnssec("ValidateSignature: alg mismatch");
2092 if (tag
!= swap16(rrsig
->keyTag
))
2094 debugdnssec("ValidateSignature: keyTag mismatch rrsig tag %d(0x%x), keyTag %d(0x%x)", swap16(rrsig
->keyTag
),
2095 swap16(rrsig
->keyTag
), tag
, tag
);
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
))
2102 debugdnssec("ValidateSignature: ZONE flag bit not set");
2105 debugdnssec("ValidateSignature:Found a key and RRSIG tag: %d", tag
);
2106 if (ValidateSignatureWithKey(dv
, rrset
, keyv
, rrsigv
))
2108 LogDNSSEC("ValidateSignature: Validated successfully with key tag %d", tag
);
2110 *resultRRSIG
= rrsigv
;
2111 return mStatus_NoError
;
2115 *resultKey
= mDNSNULL
;
2116 *resultRRSIG
= mDNSNULL
;
2117 return mStatus_NoSuchRecord
;
2120 mDNSlocal mDNSBool
ValidateSignatureWithKeyForAllRRSigs(DNSSECVerifier
*dv
, RRVerifier
*rrset
, RRVerifier
*keyv
, RRVerifier
*sig
)
2127 rrsig
= (rdataRRSig
*)sig
->rdata
;
2128 tag
= (mDNSu16
)keytag(keyv
->rdata
, keyv
->rdlength
);
2129 if (tag
== swap16(rrsig
->keyTag
))
2131 if (ValidateSignatureWithKey(dv
, rrset
, keyv
, sig
))
2133 LogDNSSEC("ValidateSignatureWithKeyForAllRRSigs: Validated");
2142 mDNSlocal mStatus
ValidateDS(DNSSECVerifier
*dv
)
2154 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
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
)
2161 ds
= (rdataDS
*)dsv
->rdata
;
2162 if ((ds
->digestType
!= SHA1_DIGEST_TYPE
) && (ds
->digestType
!= SHA256_DIGEST_TYPE
))
2164 LogDNSSEC("ValidateDS: Unsupported digest %d", ds
->digestType
);
2165 return mStatus_BadParamErr
;
2167 else debugdnssec("ValidateDS: digest type %d", ds
->digestType
);
2168 for (keyv
= dv
->key
; keyv
; keyv
= keyv
->next
)
2170 key
= (rdataDNSKey
*)keyv
->rdata
;
2171 mDNSu16 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
);
2172 if (tag
!= swap16(ds
->keyTag
))
2174 debugdnssec("ValidateDS:Not a valid keytag %d", tag
);
2178 if (DNSNameToLowerCase((domainname
*)&rrsig
->signerName
, &name
) != mStatus_NoError
)
2180 LogMsg("ValidateDS: ERROR!! cannot convert to lower case");
2184 if (dv
->ctx
) AlgDestroy(dv
->ctx
);
2185 dv
->ctx
= AlgCreate(DIGEST_ALG
, ds
->digestType
);
2188 LogMsg("ValidateDS: ERROR!! Cannot allocate context");
2191 digest
= (mDNSu8
*)&ds
->digest
;
2192 digestLen
= dsv
->rdlength
- DS_FIXED_SIZE
;
2194 AlgAdd(dv
->ctx
, name
.c
, DomainNameLength(&name
));
2195 AlgAdd(dv
->ctx
, (const mDNSu8
*)key
, keyv
->rdlength
);
2197 algRet
= AlgVerify(dv
->ctx
, mDNSNULL
, 0, digest
, digestLen
);
2198 AlgDestroy(dv
->ctx
);
2200 if (algRet
== mStatus_NoError
)
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
))
2207 LogDNSSEC("ValidateDS: DS Validated Successfully %d", tag
);
2208 return mStatus_NoError
;
2213 return mStatus_NoSuchRecord
;
2216 mDNSlocal mDNSBool
UnlinkRRVerifier(DNSSECVerifier
*dv
, RRVerifier
*elem
, RRVerifierSet set
)
2231 case RRVS_rrsig_key
:
2238 LogMsg("UnlinkRRVerifier: ERROR!! default case %d", set
);
2241 while (*v
&& *v
!= elem
)
2245 LogMsg("UnlinkRRVerifier: ERROR!! cannot find element in set %d", set
);
2248 *v
= elem
->next
; // Cut this record from the list
2249 elem
->next
= mDNSNULL
;
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.
2256 mDNSexport
void AuthChainLink(DNSSECVerifier
*dv
, AuthChain
*ae
)
2260 LogDNSSEC("AuthChainLink: called");
2263 // Get to the last element
2266 *(dv
->actail
) = head
; // Append this record to tail of auth chain
2267 dv
->actail
= &(ae
->next
); // Advance tail pointer
2270 mDNSlocal mDNSBool
AuthChainAdd(DNSSECVerifier
*dv
, RRVerifier
*resultKey
, RRVerifier
*resultRRSig
)
2276 if (!dv
->rrset
|| !resultKey
|| !resultRRSig
)
2278 LogMsg("AuthChainAdd: ERROR!! input argument NULL");
2282 // Unlink resultKey and resultRRSig and store as part of AuthChain
2283 if (!UnlinkRRVerifier(dv
, resultKey
, RRVS_key
))
2285 LogMsg("AuthChainAdd: ERROR!! cannot unlink key");
2288 if (!UnlinkRRVerifier(dv
, resultRRSig
, RRVS_rrsig
))
2290 LogMsg("AuthChainAdd: ERROR!! cannot unlink rrsig");
2294 ae
= mDNSPlatformMemAllocate(sizeof(AuthChain
));
2297 LogMsg("AuthChainAdd: AuthChain alloc failure");
2301 ae
->next
= mDNSNULL
;
2302 ae
->rrset
= dv
->rrset
;
2303 dv
->rrset
= mDNSNULL
;
2305 ae
->rrsig
= resultRRSig
;
2306 ae
->key
= resultKey
;
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
);
2312 AuthChainLink(dv
, ae
);
2316 // RFC 4035: Section 5.3.3
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
2322 // o the RRset's TTL as received in the response;
2324 // o the RRSIG RR's TTL as received in the response;
2326 // o the value in the RRSIG RR's Original TTL field; and
2328 // o the difference of the RRSIG RR's Signature Expiration time and the
2330 mDNSlocal
void SetTTLRRSet(mDNS
*const m
, DNSSECVerifier
*dv
, DNSSECStatus status
)
2332 DNSQuestion question
;
2338 int sigNameLen
, len
;
2340 mDNSu32 rrTTL
, rrsigTTL
, rrsigOrigTTL
, rrsigTimeTTL
;
2343 CacheRecord
*rrsigRR
;
2346 debugdnssec("SetTTLRRSet called");
2348 if (status
== DNSSEC_Insecure
|| status
== DNSSEC_Indeterminate
)
2350 LogDNSSEC("SetTTLRRSET: not setting ttl for status %s", DNSSECStatusName(status
));
2358 mDNSPlatformMemZero(&question
, sizeof(DNSQuestion
));
2359 rrTTL
= rrsigTTL
= rrsigOrigTTL
= rrsigTimeTTL
= 0;
2361 // 1. Locate the rrset name and get its TTL (take the first one as a representative
2362 // of the rrset). Ideally, we should set the TTL on the first validation. Instead,
2363 // we do it whenever we validate which happens whenever a ValidationRequired question
2364 // finishes validation.
2365 qname
= &dv
->origName
;
2366 qtype
= dv
->origType
;
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
);
2375 LogMsg("SetTTLRRSet cg NULL for %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
2379 for (rr
= cg
->members
; rr
; rr
= rr
->next
)
2380 if (SameNameRecordAnswersQuestion(&rr
->resrec
, &question
))
2382 // originalttl is never touched. The actual TTL is derived based on when it was
2384 rrTTL
= rr
->resrec
.rroriginalttl
- (now
- rr
->TimeRcvd
)/mDNSPlatformOneSecond
;
2388 // Should we check to see if it matches the record in dv->ac->rrset ?
2391 LogMsg("SetTTLRRSet: ERROR!! cannot locate main rrset for %##s (%s)", qname
->c
, DNSTypeName(qtype
));
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.
2399 if (dv
->ac
&& dv
->ac
->rrsig
)
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
;
2413 sigNameLen
= len
= 0;
2417 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
&& status
== DNSSEC_Secure
)
2421 for (ncr
= rr
->nsec
; ncr
; ncr
= ncr
->next
)
2423 if (ncr
->resrec
.rrtype
== kDNSType_NSEC
|| ncr
->resrec
.rrtype
== kDNSType_NSEC3
)
2425 rrTTL
= ncr
->resrec
.rroriginalttl
- (now
- ncr
->TimeRcvd
)/mDNSPlatformOneSecond
;
2426 debugdnssec("SetTTLRRSet: NSEC TTL %u", rrTTL
);
2428 // Note: we can't use dv->origName here as the NSEC record's RRSIG may not match
2429 // the original name
2430 if (rrsigv
&& ncr
->resrec
.rrtype
== kDNSType_RRSIG
&& SameDomainName(ncr
->resrec
.name
, &rrsigv
->name
))
2432 RDataBody2
*rdb
= (RDataBody2
*)ncr
->resrec
.rdata
->u
.data
;
2433 rdataRRSig
*sig
= (rdataRRSig
*)rdb
->data
;
2434 if (rrsigv
->rdlength
!= ncr
->resrec
.rdlength
)
2436 debugdnssec("SetTTLRRSet length mismatch");
2439 if (mDNSPlatformMemSame(sig
, rrsig
, rrsigv
->rdlength
))
2441 mDNSu32 remain
= (now
- ncr
->TimeRcvd
)/mDNSPlatformOneSecond
;
2442 rrsigTTL
= ncr
->resrec
.rroriginalttl
- remain
;
2443 rrsigOrigTTL
= swap32(rrsig
->origTTL
) - remain
;
2444 rrsigTimeTTL
= swap32(rrsig
->sigExpireTime
) - swap32(rrsig
->sigInceptTime
);
2447 if (rrTTL
&& (!rrsigv
|| rrsigTTL
)) break;
2452 // Look for the matching RRSIG so that we can get its TTL
2453 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
2454 if (rr
->resrec
.rrtype
== kDNSType_RRSIG
&& SameDomainName(rr
->resrec
.name
, &rrsigv
->name
))
2456 RDataBody2
*rdb
= (RDataBody2
*)rr
->resrec
.rdata
->u
.data
;
2457 rdataRRSig
*sig
= (rdataRRSig
*)rdb
->data
;
2458 if (rrsigv
->rdlength
!= rr
->resrec
.rdlength
)
2460 debugdnssec("SetTTLRRSet length mismatch");
2463 if (mDNSPlatformMemSame(sig
, rrsig
, rrsigv
->rdlength
))
2465 mDNSu32 remain
= (now
- rr
->TimeRcvd
)/mDNSPlatformOneSecond
;
2466 rrsigTTL
= rr
->resrec
.rroriginalttl
- remain
;
2467 rrsigOrigTTL
= swap32(rrsig
->origTTL
) - remain
;
2468 rrsigTimeTTL
= swap32(rrsig
->sigExpireTime
) - swap32(rrsig
->sigInceptTime
);
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
)))
2479 LogDNSSEC("SetTTLRRSet: ERROR!! Bad TTL rrtl %u, rrsigTTL %u, rrsigOrigTTL %u, rrsigTimeTTL %u for %##s (%s)",
2480 rrTTL
, rrsigTTL
, rrsigOrigTTL
, rrsigTimeTTL
, qname
->c
, DNSTypeName(qtype
));
2483 LogDNSSEC("SetTTLRRSet: TTL rrtl %u, rrsigTTL %u, rrsigOrigTTL %u, rrsigTimeTTL %u for %##s (%s)",
2484 rrTTL
, rrsigTTL
, rrsigOrigTTL
, rrsigTimeTTL
, qname
->c
, DNSTypeName(qtype
));
2486 if (status
== DNSSEC_Bogus
)
2488 rrTTL
= RR_BOGUS_TTL
;
2489 LogDNSSEC("SetTTLRRSet: setting to bogus TTL %d", rrTTL
);
2494 if (rrsigTTL
< rrTTL
)
2496 if (rrsigOrigTTL
< rrTTL
)
2497 rrTTL
= rrsigOrigTTL
;
2498 if (rrsigTimeTTL
< rrTTL
)
2499 rrTTL
= rrsigTimeTTL
;
2502 // Set the rrsig's TTL. For NSEC records, rrsigRR is NULL which means it expires when
2503 // the negative cache record expires.
2506 rrsigRR
->resrec
.rroriginalttl
= rrTTL
;
2507 rrsigRR
->TimeRcvd
= now
;
2508 rrsigRR
->UnansweredQueries
= 0;
2511 // Find the RRset and set its TTL
2512 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
2514 if (SameNameRecordAnswersQuestion(&rr
->resrec
, &question
))
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
;
2520 rr
->UnansweredQueries
= 0;
2521 SetNextCacheCheckTimeForRecord(m
, rr
);
2526 mDNSlocal
void FinishDNSSECVerification(mDNS
*const m
, DNSSECVerifier
*dv
)
2528 RRVerifier
*resultKey
;
2529 RRVerifier
*resultRRSig
;
2531 LogDNSSEC("FinishDNSSECVerification: all rdata sets available for sig verification for %##s (%s)",
2532 dv
->origName
.c
, DNSTypeName(dv
->origType
));
2534 mDNS_StopQuery(m
, &dv
->q
);
2535 if (ValidateSignature(dv
, &resultKey
, &resultRRSig
) == mStatus_NoError
)
2539 key
= (rdataDNSKey
*)resultKey
->rdata
;
2540 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, resultKey
->rdlength
);
2542 LogDNSSEC("FinishDNSSECVerification: RRSIG validated by DNSKEY tag %d, %##s (%s)", tag
, dv
->rrset
->name
.c
,
2543 DNSTypeName(dv
->rrset
->rrtype
));
2545 if (TrustedKey(m
, dv
) == mStatus_NoError
)
2547 // Need to call this after we called TrustedKey, as AuthChainAdd
2548 // unlinks the resultKey and resultRRSig
2549 if (!AuthChainAdd(dv
, resultKey
, resultRRSig
))
2551 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
2554 // The callback will be called when NSEC verification is done.
2555 if ((dv
->flags
& WILDCARD_PROVES_ANSWER_EXPANDED
))
2557 WildcardAnswerProof(m
, dv
);
2562 dv
->DVCallback(m
, dv
, DNSSEC_Secure
);
2566 if (!ValidateDS(dv
))
2568 // Need to call this after we called ValidateDS, as AuthChainAdd
2569 // unlinks the resultKey and resultRRSig
2570 if (!AuthChainAdd(dv
, resultKey
, resultRRSig
))
2572 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
2575 FreeDNSSECVerifierRRSets(dv
);
2577 if (dv
->recursed
< MAX_RECURSE_COUNT
)
2579 LogDNSSEC("FinishDNSSECVerification: Recursion level %d for %##s (%s)", dv
->recursed
, dv
->origName
.c
,
2580 DNSTypeName(dv
->origType
));
2581 VerifySignature(m
, dv
, &dv
->q
);
2587 LogDNSSEC("FinishDNSSECVerification: ValidateDS failed %##s (%s)", dv
->rrset
->name
.c
, DNSTypeName(dv
->rrset
->rrtype
));
2588 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
2594 LogDNSSEC("FinishDNSSECVerification: Could not validate the rrset %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
2595 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
2600 mDNSexport
void StartDNSSECVerification(mDNS
*const m
, void *context
)
2603 DNSSECVerifier
*dv
= (DNSSECVerifier
*)context
;
2605 done
= GetAllRRSetsForVerification(m
, dv
);
2608 if (dv
->next
!= RRVS_done
)
2609 LogMsg("StartDNSSECVerification: ERROR!! dv->next is not done");
2611 LogDNSSEC("StartDNSSECVerification: all rdata sets available for sig verification");
2612 FinishDNSSECVerification(m
, dv
);
2615 else debugdnssec("StartDNSSECVerification: all rdata sets not available for sig verification next %d", dv
->next
);
2618 mDNSexport
char *DNSSECStatusName(DNSSECStatus status
)
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";
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.
2632 mDNSlocal
void DeliverDNSSECStatus(mDNS
*const m
, DNSSECVerifier
*dv
, ResourceRecord
*answer
, DNSSECStatus status
)
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
));
2640 BumpDNSSECStats(m
, kStatsActionSet
, kStatsTypeStatus
, status
);
2641 BumpDNSSECStats(m
, kStatsActionSet
, kStatsTypeExtraPackets
, dv
->NumPackets
);
2643 BumpDNSSECStats(m
, kStatsActionSet
, kStatsTypeLatency
, m
->timenow
- dv
->StartTime
);
2646 m
->ValidationQuestion
= m
->Questions
;
2647 while (m
->ValidationQuestion
&& m
->ValidationQuestion
!= m
->NewQuestions
)
2649 DNSQuestion
*q
= m
->ValidationQuestion
;
2651 if (q
->ValidatingResponse
|| !q
->ValidationRequired
||
2652 (q
->ValidationState
!= DNSSECValInProgress
) || !ResourceRecordAnswersQuestion(answer
, q
))
2654 m
->ValidationQuestion
= q
->next
;
2658 q
->ValidationState
= DNSSECValDone
;
2659 q
->ValidationStatus
= status
;
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
)
2664 LogDNSSEC("DeliverDNSSECStatus: Generating dnssec status %s for %##s (%s)", DNSSECStatusName(status
),
2665 q
->qname
.c
, DNSTypeName(q
->qtype
));
2666 if (q
->QuestionCallback
)
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
);
2675 else if (FollowCNAME(q
, answer
, QC_add
))
2677 LogDNSSEC("DeliverDNSSECStatus: Following CNAME dnssec status %s for %##s (%s)", DNSSECStatusName(status
),
2678 q
->qname
.c
, DNSTypeName(q
->qtype
));
2680 AnswerQuestionByFollowingCNAME(m
, q
, answer
);
2684 if (m
->ValidationQuestion
== q
) // If m->ValidationQuestion was not auto-advanced, do it ourselves now
2685 m
->ValidationQuestion
= q
->next
;
2687 m
->ValidationQuestion
= mDNSNULL
;
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.
2693 mDNSlocal
void DNSSECNoResponse(mDNS
*const m
, DNSSECVerifier
*dv
)
2697 mDNSu32 slot
, namehash
;
2698 ResourceRecord
*answer
= mDNSNULL
;
2700 LogDNSSEC("DNSSECNoResponse: called");
2702 if (dv
->ValidationRequired
!= DNSSEC_VALIDATION_SECURE_OPTIONAL
)
2704 LogMsg("DNSSECNoResponse: ERROR!! ValidationRequired incorrect %d", dv
->ValidationRequired
);
2708 BumpDNSSECStats(m
, kStatsActionSet
, kStatsTypeStatus
, DNSSEC_NoResponse
);
2710 slot
= HashSlot(&dv
->origName
);
2711 namehash
= DomainNameHashValue(&dv
->origName
);
2713 cg
= CacheGroupForName(m
, (const mDNSu32
)slot
, namehash
, &dv
->origName
);
2716 LogDNSSEC("DNSSECNoResponse: cg NULL for %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
2720 InitializeQuestion(m
, &dv
->q
, dv
->InterfaceID
, &dv
->origName
, dv
->origType
, mDNSNULL
, mDNSNULL
);
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
)
2726 if (SameNameRecordAnswersQuestion(&cr
->resrec
, &dv
->q
))
2728 answer
= &cr
->resrec
;
2733 // It is not an error for things to disappear underneath
2736 LogDNSSEC("DNSSECNoResponse: answer NULL for %##s, %s", dv
->origName
.c
, DNSTypeName(dv
->origType
));
2739 if (answer
->rrtype
== kDNSType_RRSIG
)
2741 LogDNSSEC("DNSSECNoResponse: RRSIG present for %##s, %s", dv
->origName
.c
, DNSTypeName(dv
->origType
));
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
));
2750 m
->ValidationQuestion
= m
->Questions
;
2751 while (m
->ValidationQuestion
&& m
->ValidationQuestion
!= m
->NewQuestions
)
2753 DNSQuestion
*q
= m
->ValidationQuestion
;
2755 if (q
->ValidatingResponse
|| !q
->ValidationRequired
||
2756 (q
->ValidationState
!= DNSSECValInProgress
) || !ResourceRecordAnswersQuestion(answer
, q
))
2758 m
->ValidationQuestion
= q
->next
;
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.
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.
2772 q
->ValidationRequired
= 0;
2773 q
->ValidationState
= DNSSECValNotRequired
;
2775 if (FollowCNAME(q
, answer
, QC_add
))
2777 LogDNSSEC("DNSSECNoResponse: Following CNAME for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2780 AnswerQuestionByFollowingCNAME(m
, q
, answer
);
2784 if (m
->ValidationQuestion
== q
) // If m->ValidationQuestion was not auto-advanced, do it ourselves now
2785 m
->ValidationQuestion
= q
->next
;
2787 m
->ValidationQuestion
= mDNSNULL
;
2790 FreeDNSSECVerifier(m
, dv
);
2793 mDNSlocal
void DNSSECPositiveValidationCB(mDNS
*const m
, DNSSECVerifier
*dv
, CacheGroup
*cg
, ResourceRecord
*answer
, DNSSECStatus status
)
2798 mDNSu16 rrtype
, rrclass
;
2799 CacheRecord
*const lrr
= &largerec
.r
;
2801 LogDNSSEC("DNSSECPositiveValidationCB: called %s for %##s (%s)", DNSSECStatusName(status
), dv
->origName
.c
, DNSTypeName(dv
->origType
));
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
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.
2813 // 3. If we are answering with CNAME, it is time to follow the CNAME if the response is secure
2815 if (!dv
->ac
|| status
== DNSSEC_Insecure
)
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.
2821 LogMsg("DNSSECPositiveValidationCB: ERROR: answer NULL");
2827 LogMsg("DNSSECPositiveValidationCB: ERROR!! Validated RRSET NULL");
2831 rrset
= dv
->ac
->rrset
;
2832 rrtype
= rrset
->rrtype
;
2833 rrclass
= rrset
->rrclass
;
2835 lrr
->resrec
.name
= &largerec
.namestorage
;
2837 for (rv
= dv
->ac
->rrset
; rv
; rv
= rv
->next
)
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
)
2843 if (cr
->resrec
.rrtype
== rrtype
&& cr
->resrec
.rrclass
== rrclass
)
2845 for (rv
= dv
->ac
->rrset
; rv
; rv
= rv
->next
)
2847 if (rv
->rdlength
== cr
->resrec
.rdlength
&& rv
->rdatahash
== cr
->resrec
.rdatahash
)
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
;
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
))
2861 LogMsg("DNSSECPositiveValidationCB: SetRData failed for %##s (%s)", rv
->name
.c
, DNSTypeName(rv
->rrtype
));
2863 else if (SameRDataBody(&cr
->resrec
, &lrr
->resrec
.rdata
->u
, SameDomainName
))
2865 answer
= &cr
->resrec
;
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
));
2879 // Check to see if we have elements that were not in the cache
2880 for (rv
= dv
->ac
->rrset
; rv
; rv
= rv
->next
)
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
));
2891 // It is not an error for things to disappear underneath
2894 LogDNSSEC("DNSSECPositiveValidationCB: answer NULL for %##s, %s", dv
->origName
.c
, DNSTypeName(dv
->origType
));
2898 DeliverDNSSECStatus(m
, dv
, answer
, status
);
2899 SetTTLRRSet(m
, dv
, status
);
2902 FreeDNSSECVerifier(m
, dv
);
2905 mDNSlocal
void DNSSECNegativeValidationCB(mDNS
*const m
, DNSSECVerifier
*dv
, CacheGroup
*cg
, ResourceRecord
*answer
, DNSSECStatus status
)
2909 mDNSu16 rrtype
, rrclass
;
2912 LogDNSSEC("DNSSECNegativeValidationCB: called %s for %##s (%s)", DNSSECStatusName(status
), dv
->origName
.c
, DNSTypeName(dv
->origType
));
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
));
2924 // 1. Locate the negative cache record and check the cached NSEC/NSEC3 records to see if it matches the
2925 // NSEC/NSEC3s that were valiated. If the cached NSEC/NSEC3s changed while the validation was in progress,
2926 // we ignore the validation results.
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.
2932 if (!dv
->ac
|| status
== DNSSEC_Insecure
)
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.
2938 LogMsg("DNSSECNegativeValidationCB: ERROR: answer NULL");
2944 LogMsg("DNSSECNegativeValidationCB: ERROR!! Validated RRSET NULL");
2948 rrtype
= dv
->origType
;
2949 rrclass
= dv
->ac
->rrset
->rrclass
;
2951 for (ac
= dv
->ac
; ac
; ac
= ac
->next
)
2953 for (rv
= ac
->rrset
; rv
; rv
= rv
->next
)
2955 if (rv
->rrtype
== kDNSType_NSEC
|| rv
->rrtype
== kDNSType_NSEC3
)
2957 LogDNSSEC("DNSSECNegativeValidationCB: Record %p %##s (%s) marking zero", rv
, rv
->name
.c
, DNSTypeName(rv
->rrtype
));
2963 // Check to see if we can find all the elements in the rrset
2964 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
2966 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
&&
2967 cr
->resrec
.rrtype
== rrtype
&& cr
->resrec
.rrclass
== rrclass
)
2970 for (ncr
= cr
->nsec
; ncr
; ncr
= ncr
->next
)
2972 // We have RRSIGs for the NSECs cached there too
2973 if (ncr
->resrec
.rrtype
!= kDNSType_NSEC
&& ncr
->resrec
.rrtype
!= kDNSType_NSEC3
)
2975 for (ac
= dv
->ac
; ac
; ac
= ac
->next
)
2977 for (rv
= ac
->rrset
; rv
; rv
= rv
->next
)
2979 if ((rv
->rrtype
== kDNSType_NSEC
|| rv
->rrtype
== kDNSType_NSEC3
) && rv
->rdlength
== ncr
->resrec
.rdlength
&&
2980 rv
->rdatahash
== ncr
->resrec
.rdatahash
)
2982 if (SameDomainName(ncr
->resrec
.name
, &rv
->name
) &&
2983 SameRDataBody(&ncr
->resrec
, (const RDataBody
*)rv
->rdata
, SameDomainName
))
2985 LogDNSSEC("DNSSECNegativeValidationCB: Record %p %##s (%s) marking one", rv
, rv
->name
.c
, DNSTypeName(rv
->rrtype
));
2986 answer
= &cr
->resrec
;
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
));
3004 // Check to see if we have elements that were not in the cache
3005 for (ac
= dv
->ac
; ac
; ac
= ac
->next
)
3007 for (rv
= ac
->rrset
; rv
; rv
= rv
->next
)
3009 if (rv
->rrtype
== kDNSType_NSEC
|| rv
->rrtype
== kDNSType_NSEC3
)
3013 // We had more elements in the validated set, re-validate
3014 LogDNSSEC("DNSSECNegativeValidationCB: Record %p %##s (%s) not found in the cache", rv
, rv
->name
.c
, DNSTypeName(rv
->rrtype
));
3023 // It is not an error for things to disappear underneath
3026 LogDNSSEC("DNSSECNegativeValidationCB: answer NULL for %##s, %s", dv
->origName
.c
, DNSTypeName(dv
->origType
));
3030 DeliverDNSSECStatus(m
, dv
, answer
, status
);
3031 SetTTLRRSet(m
, dv
, status
);
3034 FreeDNSSECVerifier(m
, dv
);
3037 mDNSlocal
void DNSSECValidationCB(mDNS
*const m
, DNSSECVerifier
*dv
, DNSSECStatus status
)
3039 mDNSu32 slot
, namehash
;
3043 LogDNSSEC("DNSSECValidationCB: called %s for %##s (%s)", DNSSECStatusName(status
), dv
->origName
.c
, DNSTypeName(dv
->origType
));
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
)
3049 DNSSECNoResponse(m
, dv
);
3053 if (dv
->ValidationRequired
== DNSSEC_VALIDATION_SECURE
&& !dv
->InsecureProofDone
&& status
== DNSSEC_Bogus
)
3055 dv
->InsecureProofDone
= 1;
3056 ProveInsecure(m
, dv
, mDNSNULL
, mDNSNULL
);
3059 slot
= HashSlot(&dv
->origName
);
3060 namehash
= DomainNameHashValue(&dv
->origName
);
3062 cg
= CacheGroupForName(m
, (const mDNSu32
)slot
, namehash
, &dv
->origName
);
3065 LogDNSSEC("DNSSECValidationCB: cg NULL for %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
3066 FreeDNSSECVerifier(m
, dv
);
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
)
3075 if (SameNameRecordAnswersQuestion(&cr
->resrec
, &dv
->q
))
3077 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
3078 DNSSECNegativeValidationCB(m
, dv
, cg
, &cr
->resrec
, status
);
3080 DNSSECPositiveValidationCB(m
, dv
, cg
, &cr
->resrec
, status
);
3086 mDNSexport
void VerifySignature(mDNS
*const m
, DNSSECVerifier
*dv
, DNSQuestion
*q
)
3088 mDNSu32 slot
= HashSlot(&q
->qname
);
3089 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
3091 mDNSBool first
= mDNSfalse
;
3092 static mDNSBool TrustAnchorsUpdated
= mDNSfalse
;
3094 LogDNSSEC("VerifySignature called for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
3095 if (!TrustAnchorsUpdated
)
3097 TrustAnchorsUpdated
= mDNStrue
;
3098 UpdateTrustAnchors(m
);
3103 if (!q
->qDNSServer
|| q
->qDNSServer
->cellIntf
)
3105 LogDNSSEC("VerifySignature: Disabled");
3108 // We assume that the verifier's question has been initialized here so that ValidateWithNSECS below
3109 // knows what it has prove the non-existence of.
3110 dv
= AllocateDNSSECVerifier(m
, &q
->qname
, q
->qtype
, q
->InterfaceID
, q
->ValidationRequired
, DNSSECValidationCB
, VerifySigCallback
);
3113 LogMsg("VerifySignature: ERROR!! memory alloc failed");
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
;
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
))
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
)
3133 LogDNSSEC("VerifySignature: Question %##s (%s) answered with RRSIG record %s, not using it", q
->qname
.c
, DNSTypeName(q
->qtype
), CRDisplayString(m
, rr
));
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
3141 if (rr
->resrec
.rrtype
== kDNSType_NSEC
&& q
->qtype
!= kDNSType_NSEC
)
3143 LogMsg("VerifySignature: ERROR!! Question %##s (%s) answered using NSEC record %s", q
->qname
.c
, DNSTypeName(q
->qtype
), CRDisplayString(m
, rr
));
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
))
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.
3155 LogDNSSEC("VerifySignature: No nsecs found for %s", CRDisplayString(m
, rr
));
3156 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3159 ValidateWithNSECS(m
, dv
, rr
);
3163 if (AddRRSetToVerifier(dv
, &rr
->resrec
, mDNSNULL
, RRVS_rr
) != mStatus_NoError
)
3165 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3171 LogMsg("VerifySignature: rrset mDNSNULL for %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
3172 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3175 dv
->next
= RRVS_rrsig
;
3176 // Delay this so that the mDNS "core" can deliver all the results before
3177 // we can deliver the dnssec result
3180 mDNSPlatformDispatchAsync(m
, dv
, StartDNSSECVerification
);
3184 StartDNSSECVerification(m
, dv
);
3188 mDNSlocal mDNSBool
TrustedKeyPresent(mDNS
*const m
, DNSSECVerifier
*dv
)
3196 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
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
)
3203 ds
= (rdataDS
*)&ta
->rds
;
3204 if ((ds
->digestType
!= SHA1_DIGEST_TYPE
) && (ds
->digestType
!= SHA256_DIGEST_TYPE
))
3206 LogMsg("TrustedKeyPresent: Unsupported digest %d", ds
->digestType
);
3211 debugdnssec("TrustedKeyPresent: digest type %d", ds
->digestType
);
3213 for (keyv
= dv
->key
; keyv
; keyv
= keyv
->next
)
3215 key
= (rdataDNSKey
*)keyv
->rdata
;
3216 mDNSu16 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
);
3217 if (tag
!= ds
->keyTag
)
3219 debugdnssec("TrustedKeyPresent:Not a valid keytag %d", tag
);
3222 if (!SameDomainName(&keyv
->name
, &ta
->zone
))
3224 debugdnssec("TrustedKeyPresent: domainame mismatch key %##s, ta %##s", keyv
->name
.c
, ta
->zone
.c
);
3233 mDNSlocal mStatus
TrustedKey(mDNS
*const m
, DNSSECVerifier
*dv
)
3244 mDNSu32 currTime
= mDNSPlatformUTC();
3246 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
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
)
3253 ds
= (rdataDS
*)&ta
->rds
;
3254 if ((ds
->digestType
!= SHA1_DIGEST_TYPE
) && (ds
->digestType
!= SHA256_DIGEST_TYPE
))
3256 LogMsg("TrustedKey: Unsupported digest %d", ds
->digestType
);
3261 debugdnssec("TrustedKey: Zone %##s, digest type %d, tag %d", ta
->zone
.c
, ds
->digestType
, ds
->keyTag
);
3263 for (keyv
= dv
->key
; keyv
; keyv
= keyv
->next
)
3265 key
= (rdataDNSKey
*)keyv
->rdata
;
3266 mDNSu16 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
);
3267 if (tag
!= ds
->keyTag
)
3269 debugdnssec("TrustedKey:Not a valid keytag %d", tag
);
3272 if (!SameDomainName(&keyv
->name
, &ta
->zone
))
3274 debugdnssec("TrustedKey: domainame mismatch key %##s, ta %##s", keyv
->name
.c
, ta
->zone
.c
);
3277 if (DNS_SERIAL_LT(ta
->validUntil
, currTime
))
3279 LogDNSSEC("TrustedKey: Expired: currentTime %d, ExpireTime %d", (int)currTime
, ta
->validUntil
);
3282 if (DNS_SERIAL_LT(currTime
, ta
->validFrom
))
3284 LogDNSSEC("TrustedKey: Future: currentTime %d, InceptTime %d", (int)currTime
, ta
->validFrom
);
3288 if (DNSNameToLowerCase((domainname
*)&rrsig
->signerName
, &name
) != mStatus_NoError
)
3290 LogMsg("TrustedKey: ERROR!! cannot convert to lower case");
3294 if (dv
->ctx
) AlgDestroy(dv
->ctx
);
3295 dv
->ctx
= AlgCreate(DIGEST_ALG
, ds
->digestType
);
3298 LogMsg("TrustedKey: ERROR!! No digest support");
3301 digest
= ds
->digest
;
3302 digestLen
= ta
->digestLen
;
3304 AlgAdd(dv
->ctx
, name
.c
, DomainNameLength(&name
));
3305 AlgAdd(dv
->ctx
, (const mDNSu8
*)key
, keyv
->rdlength
);
3307 algRet
= AlgVerify(dv
->ctx
, mDNSNULL
, 0, digest
, digestLen
);
3308 AlgDestroy(dv
->ctx
);
3310 if (algRet
== mStatus_NoError
)
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
))
3317 LogDNSSEC("TrustedKey: DS Validated Successfully %d", tag
);
3318 return mStatus_NoError
;
3323 return mStatus_NoSuchRecord
;
3326 mDNSlocal CacheRecord
* NegativeCacheRecordForRR(mDNS
*const m
, const ResourceRecord
*const rr
)
3333 slot
= HashSlot(rr
->name
);
3334 namehash
= DomainNameHashValue(rr
->name
);
3335 cg
= CacheGroupForName(m
, slot
, namehash
, rr
->name
);
3338 LogMsg("NegativeCacheRecordForRR: cg null %##s", rr
->name
->c
);
3341 for (cr
=cg
->members
; cr
; cr
=cr
->next
)
3343 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
&& (&cr
->resrec
== rr
))
3349 mDNSlocal
void VerifySigCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
3351 DNSSECVerifier
*dv
= (DNSSECVerifier
*)question
->QuestionContext
;
3355 debugdnssec("VerifySigCallback: AddRecord %d, dv %p", AddRecord
, dv
);
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.
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.
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
);
3382 LogDNSSEC("VerifySigCallback(%p): Called with record %s for question %##s (%s)", dv
, RRDisplayString(m
, answer
), question
->qname
.c
,
3383 DNSTypeName(question
->qtype
));
3385 if ((m
->timenow
- question
->StopTime
) >= 0)
3388 LogDNSSEC("VerifySigCallback: Question %##s (%s) timed out", question
->qname
.c
, DNSTypeName(question
->qtype
));
3389 mDNS_StopQuery(m
, question
);
3390 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3395 if (answer
->RecordType
== kDNSRecordTypePacketNegative
)
3398 LogDNSSEC("VerifySigCallback: Received a negative answer with record %s, AddRecord %d",
3399 RRDisplayString(m
, answer
), AddRecord
);
3400 mDNS_StopQuery(m
, question
);
3401 cr
= NegativeCacheRecordForRR(m
, answer
);
3404 ValidateWithNSECS(m
, dv
, cr
);
3409 LogDNSSEC("VerifySigCallback: Missing record (%s) Negative Cache Record %p", RRDisplayString(m
, answer
), cr
);
3410 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3417 LogMsg("VerifySigCallback: ERROR!! rrset NULL");
3418 mDNS_StopQuery(m
, question
);
3419 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
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.
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.
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.
3443 // We handle this in two ways:
3445 // 1) AnswerNewQuestion always sends the "ValidatingResponse" query out bypassing the cache.
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.
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)
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
);
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
)
3467 LogDNSSEC("VerifySigCallback: RRVS_rrsig called with %s", RRDisplayString(m
, answer
));
3470 mDNS_StopQuery(m
, question
);
3471 if (CheckRRSIGForRRSet(m
, dv
, &negcr
) != mStatus_NoError
)
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
);
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.
3483 LogDNSSEC("VerifySigCallback: ERROR!! RRVS_key dv->key non-NULL for %##s", question
->qname
.c
);
3484 if (rrtype
== kDNSType_RRSIG
)
3486 LogDNSSEC("VerifySigCallback: RRVS_key rrset type %s, %##s received before DNSKEY", DNSTypeName(rrtype
), question
->qname
.c
);
3489 if (rrtype
!= question
->qtype
)
3491 LogDNSSEC("VerifySigCallback: ERROR!! RRVS_key rrset type %s, %##s not matching qtype %d", DNSTypeName(rrtype
), question
->qname
.c
,
3495 mDNS_StopQuery(m
, question
);
3496 if (CheckKeyForRRSIG(m
, dv
, &negcr
) != mStatus_NoError
)
3498 LogDNSSEC("VerifySigCallback: Unable to find DNSKEY for %##s (%s), question %##s", dv
->rrset
->name
.c
,
3499 DNSTypeName(dv
->rrset
->rrtype
), question
->qname
.c
);
3500 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
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
3509 LogDNSSEC("VerifySigCallback: ERROR!! RRVS_rrsig_key dv->key NULL for %##s", question
->qname
.c
);
3510 if (rrtype
== question
->qtype
)
3512 LogDNSSEC("VerifySigCallback: RRVS_rrsig_key rrset type %s, %##s", DNSTypeName(rrtype
), question
->qname
.c
);
3513 CheckOneKeyForRRSIG(dv
, answer
);
3516 if (rrtype
!= kDNSType_RRSIG
)
3518 LogDNSSEC("VerifySigCallback: RRVS_rrsig_key rrset type %s, %##s not matching qtype %d", DNSTypeName(rrtype
), question
->qname
.c
,
3522 mDNS_StopQuery(m
, question
);
3523 if (CheckRRSIGForKey(m
, dv
, &negcr
) != mStatus_NoError
)
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
);
3532 if (rrtype
== question
->qtype
)
3534 LogDNSSEC("VerifySigCallback: RRVS_ds rrset type %s, %##s", DNSTypeName(rrtype
), question
->qname
.c
);
3538 LogDNSSEC("VerifySigCallback: RRVS_ds rrset type %s, %##s received before DS", DNSTypeName(rrtype
), question
->qname
.c
);
3540 mDNS_StopQuery(m
, question
);
3541 // It is not an error if we don't find the DS record as we could have
3542 // a trusted key. Or this is not a secure delegation which will be handled
3544 if (CheckDSForKey(m
, dv
, &negcr
) != mStatus_NoError
)
3546 LogDNSSEC("VerifySigCallback: Unable find DS for %##s (%s), question %##s", dv
->rrset
->name
.c
,
3547 DNSTypeName(dv
->rrset
->rrtype
), question
->qname
.c
);
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
3557 LogDNSSEC("VerifySigCallback: No nsec records for %##s (DS)", dv
->ds
->name
.c
);
3558 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3561 ValidateWithNSECS(m
, dv
, negcr
);
3566 LogDNSSEC("VerifySigCallback: ERROR!! default case rrset %##s question %##s", dv
->rrset
->name
.c
, question
->qname
.c
);
3567 mDNS_StopQuery(m
, question
);
3568 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3571 if (dv
->next
!= RRVS_done
)
3573 mDNSBool done
= GetAllRRSetsForVerification(m
, dv
);
3576 if (dv
->next
!= RRVS_done
)
3577 LogMsg("VerifySigCallback ERROR!! dv->next is not done");
3579 LogDNSSEC("VerifySigCallback: all rdata sets available for sig verification");
3583 LogDNSSEC("VerifySigCallback: all rdata sets not available for sig verification");
3587 FinishDNSSECVerification(m
, dv
);
3590 mDNSlocal TrustAnchor
*FindTrustAnchor(mDNS
*const m
, const domainname
*const name
)
3593 TrustAnchor
*matchTA
= mDNSNULL
;
3594 TrustAnchor
*rootTA
= mDNSNULL
;
3597 mDNSu32 currTime
= mDNSPlatformUTC();
3599 for (ta
= m
->TrustAnchors
; ta
; ta
= ta
->next
)
3601 if (DNS_SERIAL_LT(ta
->validUntil
, currTime
))
3603 LogDNSSEC("FindTrustAnchor: Expired: currentTime %d, ExpireTime %d", (int)currTime
, ta
->validUntil
);
3606 if (DNS_SERIAL_LT(currTime
, ta
->validFrom
))
3608 LogDNSSEC("FindTrustAnchor: Future: currentTime %d, InceptTime %d", (int)currTime
, ta
->validFrom
);
3612 if (SameDomainName((const domainname
*)"\000", &ta
->zone
))
3615 match
= CountLabelsMatch(&ta
->zone
, name
);
3616 if (match
> currmatch
)
3624 LogDNSSEC("FindTrustAnhcor: matched %##s", matchTA
->zone
.c
);
3629 LogDNSSEC("FindTrustAnhcor: matched rootTA %##s", rootTA
->zone
.c
);
3634 LogDNSSEC("FindTrustAnhcor: No Trust Anchor");
3639 mDNSlocal
void DeliverInsecureProofResultAsync(mDNS
*const m
, void *context
)
3641 InsecureContext
*ic
= (InsecureContext
*)context
;
3642 ic
->dv
->DVCallback(m
, ic
->dv
, ic
->status
);
3643 if (ic
->q
.ThisQInterval
!= -1)
3645 LogMsg("DeliverInsecureProofResultAsync: ERROR!! Question %##s (%s) not stopped already", ic
->q
.qname
.c
, DNSTypeName(ic
->q
.qtype
));
3646 mDNS_StopQuery(m
, &ic
->q
);
3648 mDNSPlatformMemFree(ic
);
3651 mDNSlocal
void DeliverInsecureProofResult(mDNS
*const m
, InsecureContext
*ic
, DNSSECStatus status
)
3653 // If the status is Bogus, restore the original auth chain before the insecure
3655 if (status
== DNSSEC_Bogus
)
3657 LogDNSSEC("DeliverInsecureProofResult: Restoring the auth chain");
3660 FreeDNSSECAuthChainInfo(ic
->dv
->ac
);
3662 ResetAuthChain(ic
->dv
);
3663 ic
->dv
->ac
= ic
->dv
->saveac
;
3666 AuthChain
*tmp
= ic
->dv
->ac
;
3667 AuthChain
**tail
= &tmp
->next
;
3673 ic
->dv
->actail
= tail
;
3675 ic
->dv
->saveac
= mDNSNULL
;
3677 else if (ic
->dv
->saveac
)
3679 FreeDNSSECAuthChainInfo(ic
->dv
->saveac
);
3680 ic
->dv
->saveac
= mDNSNULL
;
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
);
3692 mDNSlocal mDNSBool
AlgorithmSupported(rdataDS
*ds
)
3694 switch(ds
->digestType
)
3696 case SHA1_DIGEST_TYPE
:
3697 case SHA256_DIGEST_TYPE
:
3700 LogDNSSEC("AlgorithmSupported: Unsupported digest %d", ds
->digestType
);
3706 case CRYPTO_RSA_NSEC3_SHA1
:
3707 case CRYPTO_RSA_SHA1
:
3708 case CRYPTO_RSA_SHA256
:
3709 case CRYPTO_RSA_SHA512
:
3712 LogDNSSEC("AlgorithmSupported: Unsupported algorithm %d", ds
->alg
);
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.
3721 // Insecure proof callback can deliver either insecure or bogus, but never secure result.
3722 mDNSlocal
void ProveInsecureCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
3724 InsecureContext
*ic
= (InsecureContext
*)question
->QuestionContext
;
3725 DNSSECVerifier
*pdv
= ic
->dv
;
3734 if ((m
->timenow
- question
->StopTime
) >= 0)
3737 LogDNSSEC("ProveInsecureCallback: Question %##s (%s) timed out", question
->qname
.c
, DNSTypeName(question
->qtype
));
3738 DeliverInsecureProofResult(m
, ic
, DNSSEC_Bogus
);
3743 // We only need to handle the actual DNSSEC results and the ones that are secure. Anything else results in
3745 if (AddRecord
!= QC_dnssec
)
3747 LogDNSSEC("ProveInsecureCallback: Question %##s (%s), AddRecord %d, answer %s", question
->qname
.c
,
3748 DNSTypeName(question
->qtype
), AddRecord
, RRDisplayString(m
, answer
));
3752 LogDNSSEC("ProveInsecureCallback: ic %p Question %##s (%s), DNSSEC status %s", ic
, question
->qname
.c
, DNSTypeName(question
->qtype
),
3753 DNSSECStatusName(question
->ValidationStatus
));
3755 // Insecure is delivered for NSEC3 OptOut
3756 if (question
->ValidationStatus
!= DNSSEC_Secure
&& question
->ValidationStatus
!= DNSSEC_Insecure
)
3758 LogDNSSEC("ProveInsecureCallback: Question %##s (%s) returned DNSSEC status %s", question
->qname
.c
,
3759 DNSTypeName(question
->qtype
), DNSSECStatusName(question
->ValidationStatus
));
3762 ac
= (AuthChain
*)question
->DNSSECAuthInfo
;
3765 LogDNSSEC("ProveInsecureCallback: ac NULL for question %##s, %s", question
->qname
.c
, DNSTypeName(question
->qtype
));
3770 LogDNSSEC("ProveInsecureCallback: ac->rrset NULL for question %##s, %s", question
->qname
.c
, DNSTypeName(question
->qtype
));
3773 if (ac
->rrset
->rrtype
!= kDNSType_DS
&& ac
->rrset
->rrtype
!= kDNSType_NSEC
&& ac
->rrset
->rrtype
!= kDNSType_NSEC3
)
3775 LogDNSSEC("ProveInsecureCallback: ac->rrset->rrtype %##s (%s) not handled", ac
->rrset
->name
.c
,
3776 DNSTypeName(ac
->rrset
->rrtype
));
3779 AuthChainLink(pdv
, ac
);
3780 question
->DNSSECAuthInfo
= mDNSNULL
;
3781 if (ac
->rrset
->rrtype
== kDNSType_DS
)
3783 rdataDS
*ds
= (rdataDS
*)ac
->rrset
->rdata
;
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
))
3789 LogDNSSEC("ProveInsecureCallback: Unsupported algorithm %d or digest %d", ds
->alg
, ds
->digestType
);
3790 DeliverInsecureProofResult(m
, ic
, DNSSEC_Insecure
);
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
))
3801 LogDNSSEC("ProveInsecureCallback: Insecure proof reached original name %##s, error", question
->qname
.c
);
3802 DeliverInsecureProofResult(m
, ic
, DNSSEC_Bogus
);
3806 LogDNSSEC("ProveInsecureCallback: Trying one more level down");
3807 ProveInsecure(m
, pdv
, ic
, mDNSNULL
);
3809 else if (ac
->rrset
->rrtype
== kDNSType_NSEC
|| ac
->rrset
->rrtype
== kDNSType_NSEC3
)
3813 if (ac
->rrset
->rrtype
== kDNSType_NSEC
)
3814 cr
= NSECRecordIsDelegation(m
, &question
->qname
, question
->qtype
);
3816 cr
= NSEC3RecordIsDelegation(m
, &question
->qname
, question
->qtype
);
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
);
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
))
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
);
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
);
3844 DeliverInsecureProofResult(m
, ic
, DNSSEC_Bogus
);
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
3851 mDNSexport
void ProveInsecure(mDNS
*const m
, DNSSECVerifier
*dv
, InsecureContext
*ic
, domainname
*trigger
)
3858 ic
= (InsecureContext
*)mDNSPlatformMemAllocate(sizeof(InsecureContext
));
3861 LogMsg("mDNSPlatformMemAllocate: ERROR!! memory alloc failed for ic");
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.
3873 LogDNSSEC("ProveInsecure: saving authinfo");
3877 LogDNSSEC("ProveInsecure: ERROR!! authinfo already set");
3878 FreeDNSSECAuthChainInfo(dv
->saveac
);
3880 dv
->saveac
= dv
->ac
;
3884 ic
->q
.ThisQInterval
= -1;
3888 LogDNSSEC("ProveInsecure: Setting Trigger %##s", trigger
->c
);
3889 ic
->triggerLabelCount
= CountLabels(trigger
);
3893 LogDNSSEC("ProveInsecure: No Trigger");
3894 ic
->triggerLabelCount
= CountLabels(&dv
->origName
);
3897 ta
= FindTrustAnchor(m
, &dv
->origName
);
3900 LogDNSSEC("ProveInsecure: TrustAnchor NULL");
3901 DeliverInsecureProofResult(m
, ic
, DNSSEC_Insecure
);
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
);
3909 LogDNSSEC("ProveInsecure: origName %##s, skip is zero", dv
->origName
.c
);
3910 DeliverInsecureProofResult(m
, ic
, DNSSEC_Bogus
);
3914 // Look for the DS record starting just below the trust anchor.
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.
3919 // 2. If we find a DS record and no algorithm support, return "insecure". Otherwise, go
3920 // down one more level.
3922 sname
= (domainname
*)SkipLeadingLabels(&dv
->origName
, (ic
->skip
? ic
->skip
- 1 : 0));
3925 LogDNSSEC("ProveInsecure: sname NULL, origName %##s, skip %d", dv
->origName
.c
, ic
->skip
);
3926 DeliverInsecureProofResult(m
, ic
, DNSSEC_Bogus
);
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.
3942 if (CountLabels(sname
) > ic
->triggerLabelCount
)
3944 LogDNSSEC("ProveInsecure: Beyond the trigger current name %##s, origName %##s", sname
->c
, dv
->origName
.c
);
3945 DeliverInsecureProofResult(m
, ic
, DNSSEC_Bogus
);
3949 LogDNSSEC("ProveInsecure: OrigName %##s (%s), Current %##s", dv
->origName
.c
, DNSTypeName(dv
->origType
), sname
->c
);
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
);
3958 mDNSexport
void BumpDNSSECStats(mDNS
*const m
, DNSSECStatsAction action
, DNSSECStatsType type
, mDNSu32 value
)
3962 case kStatsTypeMemoryUsage
:
3963 if (action
== kStatsActionIncrement
)
3965 m
->DNSSECStats
.TotalMemUsed
+= value
;
3967 else if (action
== kStatsActionDecrement
)
3969 m
->DNSSECStats
.TotalMemUsed
-= value
;
3972 case kStatsTypeLatency
:
3973 if (action
== kStatsActionSet
)
3977 m
->DNSSECStats
.Latency0
++;
3979 else if (value
<= 9)
3981 m
->DNSSECStats
.Latency5
++;
3983 else if (value
<= 19)
3985 m
->DNSSECStats
.Latency10
++;
3987 else if (value
<= 49)
3989 m
->DNSSECStats
.Latency20
++;
3991 else if (value
<= 99)
3993 m
->DNSSECStats
.Latency50
++;
3997 m
->DNSSECStats
.Latency100
++;
4001 case kStatsTypeExtraPackets
:
4002 if (action
== kStatsActionSet
)
4006 m
->DNSSECStats
.ExtraPackets0
++;
4008 else if (value
<= 6)
4010 m
->DNSSECStats
.ExtraPackets3
++;
4012 else if (value
<= 9)
4014 m
->DNSSECStats
.ExtraPackets7
++;
4018 m
->DNSSECStats
.ExtraPackets10
++;
4022 case kStatsTypeStatus
:
4023 if (action
== kStatsActionSet
)
4028 m
->DNSSECStats
.SecureStatus
++;
4030 case DNSSEC_Insecure
:
4031 m
->DNSSECStats
.InsecureStatus
++;
4033 case DNSSEC_Indeterminate
:
4034 m
->DNSSECStats
.IndeterminateStatus
++;
4037 m
->DNSSECStats
.BogusStatus
++;
4039 case DNSSEC_NoResponse
:
4040 m
->DNSSECStats
.NoResponseStatus
++;
4043 LogMsg("BumpDNSSECStats: unknown status %d", value
);
4047 case kStatsTypeMsgSize
:
4048 if (action
== kStatsActionSet
)
4052 m
->DNSSECStats
.MsgSize0
++;
4054 else if (value
<= 2048)
4056 m
->DNSSECStats
.MsgSize1
++;
4060 m
->DNSSECStats
.MsgSize2
++;
4064 case kStatsTypeProbe
:
4065 if (action
== kStatsActionIncrement
)
4067 m
->DNSSECStats
.NumProbesSent
+= value
;
4071 LogMsg("BumpDNSSECStats: unknown type %d", type
);
4076 #else // !DNSSEC_DISABLED
4078 mDNSexport
void VerifySignature(mDNS
*const m
, DNSSECVerifier
*dv
, DNSQuestion
*q
)
4085 mDNSexport
void BumpDNSSECStats(mDNS
*const m
, DNSSECStatsAction action
, DNSSECStatsType type
, mDNSu32 value
)
4093 mDNSexport
void InitializeQuestion(mDNS
*const m
, DNSQuestion
*question
, mDNSInterfaceID InterfaceID
, const domainname
*qname
, mDNSu16 qtype
, mDNSQuestionCallback
*callback
, void *context
)
4104 mDNSexport
char *DNSSECStatusName(DNSSECStatus status
)
4111 #endif // !DNSSEC_DISABLED