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 "DNSCommon.h"
20 #include "CryptoAlg.h"
23 //#define DNSSEC_DEBUG
26 #define debugdnssec LogMsg
28 #define debugdnssec debug_noop
31 // Implementation Notes
33 // The entry point to DNSSEC Verification is VerifySignature. This function is called from the "core" when
34 // the answer delivered to the application needs DNSSEC validation. If a question needs DNSSEC
35 // validation, "ValidationRequired" would be set. As we need to issue more queries to validate the
36 // original question, we create another question as part of the verification process (question is part of
37 // DNSSECVerifier). This question sets "ValidatingResponse" to distinguish itself from the original
38 // question. Without this, it will be a duplicate and never sent out. The "core" almost treats both the
39 // types identically (like adding EDNS0 option with DO bit etc.) except for a few differences. When RRSIGs
40 // are added to the cache, "ValidatingResponse" question gets called back as long as the typeCovered matches
41 // the question's qtype. See the comment in DNSSECRecordAnswersQuestion for the details. The other big
42 // difference is that "ValidationRequired" question kicks off the verification process by calling into
43 // "VerifySignature" whereas ValidationResponse don't do that as it gets callback for its questions.
45 // VerifySignature does not retain the original question that started the verification process. It just
46 // remembers the name and the type. It takes a snapshot of the cache at that instance which will be
47 // verified using DNSSEC. If the cache changes subsequently e.g., network change etc., it will be detected
48 // when the validation is completed. If there is a change, it will be revalidated.
50 // The verification flow looks like this:
52 // VerifySignature -> StartDNSSECVerification - GetAllRRSetsForVerification -> FinishDNSSECVerification -> VerifySignature
54 // Verification is a recursive process. It stops when we find a trust anchor or if we have recursed too deep.
56 // If the original question resulted in NODATA/NXDOMAIN error, there should have been NSECs as part of the response.
57 // These nsecs are cached along with the negative cache record. These are validated using ValidateWithNSECS called
58 // from Verifysignature.
60 // The flow in this case looks like this:
62 // VerifySignature -> ValidateWithNSECS -> {NoDataProof, NameErrorProof} -> VerifyNSECS -> StartDNSSECVerification
64 // Once the DNSSEC verification is started, it is similar to the previous flow described above. When the verification
65 // is done, DNSSECPositiveValidationCB or DNSSECNegativeValidationCB will be called which will then deliver the
66 // validation results to the original question that started the validation.
68 // Forward declaration
69 mDNSlocal
void VerifySigCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
);
70 mDNSlocal mStatus
TrustedKey(mDNS
*const m
, DNSSECVerifier
*dv
);
71 mDNSlocal mDNSBool
TrustedKeyPresent(mDNS
*const m
, DNSSECVerifier
*dv
);
72 mDNSlocal mStatus
ValidateDS(DNSSECVerifier
*dv
);
73 mDNSlocal
void DNSSECNegativeValidationCB(mDNS
*const m
, DNSSECVerifier
*dv
, DNSSECStatus status
);
75 // Currently we use this to convert a RRVerifier to resource record so that we can
76 // use the standard DNS utility functions
77 LargeCacheRecord largerec
;
79 // Verification is a recursive process. We arbitrarily limit to 10 just to be cautious which should be
80 // removed in the future.
81 #define MAX_RECURSE_COUNT 10
83 // RFC 4034 Appendix B: Get the keyid of a DNS KEY. It is not transmitted
84 // explicitly on the wire.
86 // Note: This just helps narrow down the list of keys to look at. It is possible
87 // for two DNS keys to have the same ID i.e., key ID is not a unqiue tag
89 // 1st argument - the RDATA part of the DNSKEY RR
90 // 2nd argument - the RDLENGTH
92 mDNSlocal mDNSu32
keytag(mDNSu8
*key
, mDNSu32 keysize
)
97 // DST_ALG_RSAMD5 will be rejected automatically as the keytag
98 // is calculated wrongly
100 for (ac
= 0, i
= 0; i
< keysize
; ++i
)
101 ac
+= (i
& 1) ? key
[i
] : key
[i
] << 8;
102 ac
+= (ac
>> 16) & 0xFFFF;
106 mDNSlocal
int DNSMemCmp(mDNSu8
*const m1
, mDNSu8
*const m2
, int len
)
110 res
= mDNSPlatformMemCmp(m1
, m2
, len
);
112 return (res
< 0 ? -1 : 1);
116 mDNSlocal mStatus
DNSNameToLowerCase(domainname
*d
, domainname
*result
)
118 const mDNSu8
*a
= d
->c
;
119 mDNSu8
*b
= result
->c
;
120 const mDNSu8
*const max
= d
->c
+ MAX_DOMAIN_NAME
;
125 if (a
+ 1 + *a
>= max
)
127 LogMsg("DNSNameToLowerCase: ERROR!! Malformed Domain name");
128 return mStatus_BadParamErr
;
132 for (i
= 0; i
< len
; i
++)
135 if (mDNSIsUpperCase(ac
)) ac
+= 'a' - 'A';
141 return mStatus_NoError
;
144 // Initialize the question enough so that it can be answered from the cache using SameNameRecordAnswersQuestion or
145 // ResourceRecordAnswersQuestion.
146 mDNSexport
void InitializeQuestion(mDNS
*const m
, DNSQuestion
*question
, mDNSInterfaceID InterfaceID
, const domainname
*qname
,
147 mDNSu16 qtype
, mDNSQuestionCallback
*callback
, void *context
)
149 LogOperation("InitializeQuestion: Called for %##s (%s)", qname
->c
, DNSTypeName(qtype
));
151 if (question
->ThisQInterval
!= -1) mDNS_StopQuery(m
, question
);
153 mDNS_SetupQuestion(question
, InterfaceID
, qname
, qtype
, callback
, context
);
154 question
->qnamehash
= DomainNameHashValue(qname
);
155 question
->ValidatingResponse
= mDNStrue
;
157 // We need to set the DNS server appropriately to match the question against the cache record.
158 // Though not all callers of this function need it, we always do it to keep it simple.
159 SetValidDNSServers(m
, question
);
160 question
->qDNSServer
= GetServerForQuestion(m
, question
);
162 // Make it look like unicast
163 question
->TargetQID
= onesID
;
164 question
->TimeoutQuestion
= 1;
165 question
->ReturnIntermed
= 1;
166 // SetupQuestion sets LongLived if qtype == PTR
167 question
->LongLived
= 0;
170 mDNSexport DNSSECVerifier
*AllocateDNSSECVerifier(mDNS
*const m
, const domainname
*name
, mDNSu16 rrtype
, mDNSInterfaceID InterfaceID
,
171 DNSSECVerifierCallback dvcallback
, mDNSQuestionCallback qcallback
)
175 dv
= (DNSSECVerifier
*)mDNSPlatformMemAllocate(sizeof(DNSSECVerifier
));
176 if (!dv
) { LogMsg("AllocateDNSSECVerifier: ERROR!! memory alloc failed"); return mDNSNULL
; }
177 mDNSPlatformMemZero(dv
, sizeof(*dv
));
179 // Remember the question's name and type so that when we are done processing all
180 // the verifications, we can trace the original question back
181 AssignDomainName(&dv
->origName
, name
);
182 dv
->origType
= rrtype
;
183 dv
->InterfaceID
= InterfaceID
;
184 dv
->DVCallback
= dvcallback
;
185 dv
->q
.ThisQInterval
= -1;
187 dv
->actail
= &dv
->ac
;
188 // The verifier's question has to be initialized as some of the callers assume it
189 InitializeQuestion(m
, &dv
->q
, InterfaceID
, name
, rrtype
, qcallback
, dv
);
193 mDNSlocal
void FreeDNSSECAuthChain(DNSSECVerifier
*dv
)
197 AuthChain
*ac
, *acnext
;
199 LogDNSSEC("FreeDNSSECAuthChain: called");
210 mDNSPlatformMemFree(rrset
);
213 ac
->rrset
= mDNSNULL
;
219 mDNSPlatformMemFree(rrset
);
222 ac
->rrsig
= mDNSNULL
;
228 mDNSPlatformMemFree(rrset
);
233 mDNSPlatformMemFree(ac
);
239 mDNSlocal
void FreeDNSSECVerifierRRSets(DNSSECVerifier
*dv
)
244 //debugdnssec("FreeDNSSECVerifierRRSets called %p", dv);
249 mDNSPlatformMemFree(rrset
);
252 dv
->rrset
= mDNSNULL
;
258 mDNSPlatformMemFree(rrset
);
261 dv
->rrsig
= mDNSNULL
;
267 mDNSPlatformMemFree(rrset
);
272 rrset
= dv
->rrsigKey
;
276 mDNSPlatformMemFree(rrset
);
279 dv
->rrsigKey
= mDNSNULL
;
285 mDNSPlatformMemFree(rrset
);
291 mDNSPlatformMemFree(dv
->pendingNSEC
);
292 dv
->pendingNSEC
= mDNSNULL
;
296 mDNSexport
void FreeDNSSECVerifier(mDNS
*const m
, DNSSECVerifier
*dv
)
298 LogDNSSEC("FreeDNSSECVerifier called %p", dv
);
299 if (dv
->q
.ThisQInterval
!= -1) mDNS_StopQuery(m
, &dv
->q
);
300 FreeDNSSECVerifierRRSets(dv
);
301 if (dv
->ctx
) AlgDestroy(dv
->ctx
);
302 if (dv
->ac
) FreeDNSSECAuthChain(dv
);
305 LogDNSSEC("FreeDNSSECVerifier freeing parent %p", dv
->parent
);
306 FreeDNSSECVerifier(m
, dv
->parent
);
308 mDNSPlatformMemFree(dv
);
311 mDNSexport RRVerifier
* AllocateRRVerifier(const ResourceRecord
*const rr
, mStatus
*status
)
315 r
= mDNSPlatformMemAllocate(sizeof (RRVerifier
) + rr
->rdlength
);
318 LogMsg("AllocateRRVerifier: memory failure");
319 *status
= mStatus_NoMemoryErr
;
323 r
->rrtype
= rr
->rrtype
;
324 r
->rrclass
= rr
->rrclass
;
325 r
->rroriginalttl
= rr
->rroriginalttl
;
326 r
->rdlength
= rr
->rdlength
;
327 r
->namehash
= rr
->namehash
;
328 r
->rdatahash
= rr
->rdatahash
;
329 AssignDomainName(&r
->name
, rr
->name
);
330 r
->rdata
= (mDNSu8
*) ((mDNSu8
*)r
+ sizeof(RRVerifier
));
332 // When we parsed the DNS response in GeLargeResourceRecord, for some records, we parse them into
333 // host order so that the rest of the code does not have to bother with converting from network order
334 // to host order. For signature verification, we need them back in network order. For DNSSEC records
335 // like DNSKEY and DS, we just copy over the data both in GetLargeResourceRecord and putRData.
337 if (!putRData(mDNSNULL
, r
->rdata
, r
->rdata
+ rr
->rdlength
, rr
))
339 LogMsg("AllocateRRVerifier: putRData failed");
340 *status
= mStatus_BadParamErr
;
343 *status
= mStatus_NoError
;
347 mDNSexport mStatus
AddRRSetToVerifier(DNSSECVerifier
*dv
, const ResourceRecord
*const rr
, RRVerifier
*rv
, RRVerifierSet set
)
355 r
= AllocateRRVerifier(rr
, &status
);
356 if (!r
) return status
;
379 LogMsg("AddRRSetToVerifier: ERROR!! default case %d", set
);
380 return mStatus_BadParamErr
;
385 return mStatus_NoError
;
388 // Validate the RRSIG. "type" tells which RRSIG that we are supposed to validate. We fetch RRSIG for
389 // the rrset (type is RRVS_rrsig) and RRSIG for the key (type is RRVS_rrsig_key).
390 mDNSexport
void ValidateRRSIG(DNSSECVerifier
*dv
, RRVerifierSet type
, const ResourceRecord
*const rr
)
394 rdataRRSig
*rrsigRData
= (rdataRRSig
*)((mDNSu8
*)rr
->rdata
+ sizeofRDataHeader
);
396 if (type
== RRVS_rrsig
)
400 else if (type
== RRVS_rrsig_key
)
406 LogMsg("ValidateRRSIG: ERROR!! type not valid %d", type
);
411 // For each authoritative RRset in a signed zone, there MUST be at least
412 // one RRSIG record that meets the following requirements:
414 // RRSet is defined by same name, class and type
416 // 1. The RRSIG RR and the RRset MUST have the same owner name and the same class.
417 if (!SameDomainName(&rv
->name
, rr
->name
) || (rr
->rrclass
!= rv
->rrclass
))
419 debugdnssec("ValidateRRSIG: name mismatch or class mismatch");
423 // 2. The RRSIG RR's Type Covered field MUST equal the RRset's type.
424 if ((swap16(rrsigRData
->typeCovered
)) != rv
->rrtype
)
426 debugdnssec("ValidateRRSIG: typeCovered mismatch rrsig %d, rr type %d", swap16(rrsigRData
->typeCovered
), rv
->rrtype
);
430 // 3. The number of labels in the RRset owner name MUST be greater than or equal
431 // to the value in the RRSIG RR's Labels field.
432 if (rrsigRData
->labels
> CountLabels(&rv
->name
))
434 debugdnssec("ValidateRRSIG: labels count problem rrsig %d, rr %d", rrsigRData
->labels
, CountLabels(&rv
->name
));
438 // 4. The RRSIG RR's Signer's Name field MUST be the name of the zone that contains
439 // the RRset. For a stub resolver, this can't be done in a secure way. Hence we
440 // do it this way (discussed in dnsext mailing list)
445 case kDNSType_DNSKEY
:
446 //Signed by the owner
447 if (!SameDomainName(&rv
->name
, (domainname
*)&rrsigRData
->signerName
))
449 debugdnssec("ValidateRRSIG: Signer Name does not match the record name for %s", DNSTypeName(rv
->rrtype
));
454 // Should be signed by the parent
455 if (SameDomainName(&rv
->name
, (domainname
*)&rrsigRData
->signerName
))
457 debugdnssec("ValidateRRSIG: Signer Name matches the record name for %s", DNSTypeName(rv
->rrtype
));
463 int c1
= CountLabels(&rv
->name
);
464 int c2
= CountLabels((domainname
*)&rrsigRData
->signerName
);
467 debugdnssec("ValidateRRSIG: Signer Name not a subdomain label count %d < %d ", c1
, c2
);
470 domainname
*d
= (domainname
*)SkipLeadingLabels(&rv
->name
, c1
- c2
);
471 if (!SameDomainName(d
, (domainname
*)&rrsigRData
->signerName
))
473 debugdnssec("ValidateRRSIG: Signer Name not a subdomain");
480 // 5. The validator's notion of the current time MUST be less than or equal to the
481 // time listed in the RRSIG RR's Expiration field.
483 // 6. The validator's notion of the current time MUST be greater than or equal to the
484 // time listed in the RRSIG RR's Inception field.
485 currentTime
= mDNSPlatformUTC();
487 if (DNS_SERIAL_LT(swap32(rrsigRData
->sigExpireTime
), currentTime
))
489 LogDNSSEC("ValidateRRSIG: Expired: currentTime %d, ExpireTime %d", (int)currentTime
,
490 swap32((int)rrsigRData
->sigExpireTime
));
493 if (DNS_SERIAL_LT(currentTime
, swap32(rrsigRData
->sigInceptTime
)))
495 LogDNSSEC("ValidateRRSIG: Future: currentTime %d, InceptTime %d", (int)currentTime
,
496 swap32((int)rrsigRData
->sigInceptTime
));
500 if (AddRRSetToVerifier(dv
, rr
, mDNSNULL
, type
) != mStatus_NoError
)
502 LogMsg("ValidateRRSIG: ERROR!! cannot allocate RRSet");
507 mDNSlocal mStatus
CheckRRSIGForRRSet(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
**negcr
)
517 LogMsg("CheckRRSIGForRRSet: ERROR!! rrset NULL for origName %##s (%s)", dv
->origName
.c
,
518 DNSTypeName(dv
->origType
));
519 return mStatus_BadParamErr
;
523 slot
= HashSlot(&rv
->name
);
524 cg
= CacheGroupForName(m
, slot
, rv
->namehash
, &rv
->name
);
527 debugdnssec("CheckRRSIGForRRSet: cg null");
528 return mStatus_NoSuchRecord
;
531 for (cr
=cg
->members
; cr
; cr
=cr
->next
)
533 debugdnssec("CheckRRSIGForRRSet: checking the validity of rrsig");
534 if (cr
->resrec
.rrtype
!= kDNSType_RRSIG
) continue;
535 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
539 LogDNSSEC("CheckRRSIGForRRSet: Negative cache record %s encountered for %##s (%s)", CRDisplayString(m
, cr
),
540 rv
->name
.c
, rv
->rrtype
);
545 LogMsg("CheckRRSIGForRRSet: ERROR!! Negative cache record %s already set for %##s (%s)", CRDisplayString(m
, cr
),
546 rv
->name
.c
, rv
->rrtype
);
550 ValidateRRSIG(dv
, RRVS_rrsig
, &cr
->resrec
);
552 if (*negcr
&& dv
->rrsig
)
554 // Encountered both RRSIG and negative CR
555 LogMsg("CheckRRSIGForRRSet: ERROR!! Encountered negative cache record %s and RRSIG for %##s (%s)",
556 CRDisplayString(m
, *negcr
), rv
->name
.c
, rv
->rrtype
);
557 return mStatus_BadParamErr
;
559 if (dv
->rrsig
|| *negcr
)
560 return mStatus_NoError
;
562 return mStatus_NoSuchRecord
;
565 mDNSlocal
void CheckOneKeyForRRSIG(DNSSECVerifier
*dv
, const ResourceRecord
*const rr
)
571 LogMsg("CheckOneKeyForRRSIG: ERROR!! rrsig NULL");
574 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
575 if (!SameDomainName((domainname
*)&rrsig
->signerName
, rr
->name
))
577 debugdnssec("CheckOneKeyForRRSIG: name mismatch");
581 // We store all the keys including the ZSK and KSK and use them appropriately
583 if (AddRRSetToVerifier(dv
, rr
, mDNSNULL
, RRVS_key
) != mStatus_NoError
)
585 LogMsg("CheckOneKeyForRRSIG: ERROR!! cannot allocate RRSet");
590 mDNSlocal mStatus
CheckKeyForRRSIG(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
**negcr
)
602 LogMsg("CheckKeyForRRSIG: ERROR!! rrsig NULL");
603 return mStatus_BadParamErr
;
606 // Signer name should be the same on all rrsig ??
607 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
608 name
= (domainname
*)&rrsig
->signerName
;
610 slot
= HashSlot(name
);
611 namehash
= DomainNameHashValue(name
);
612 cg
= CacheGroupForName(m
, slot
, namehash
, name
);
615 debugdnssec("CheckKeyForRRSIG: cg null for %##s", name
->c
);
616 return mStatus_NoSuchRecord
;
619 for (cr
=cg
->members
; cr
; cr
=cr
->next
)
621 if (cr
->resrec
.rrtype
!= kDNSType_DNSKEY
) continue;
622 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
626 LogDNSSEC("CheckKeyForRRSIG: Negative cache record %s encountered for %##s (DNSKEY)", CRDisplayString(m
, cr
),
632 LogMsg("CheckKeyForRRSIG: ERROR!! Negative cache record %s already set for %##s (DNSKEY)", CRDisplayString(m
, cr
),
637 debugdnssec("CheckKeyForRRSIG: checking the validity of key record");
638 CheckOneKeyForRRSIG(dv
, &cr
->resrec
);
640 if (*negcr
&& dv
->key
)
642 // Encountered both RRSIG and negative CR
643 LogMsg("CheckKeyForRRSIG: ERROR!! Encountered negative cache record %s and DNSKEY for %##s",
644 CRDisplayString(m
, *negcr
), name
->c
);
645 return mStatus_BadParamErr
;
647 if (dv
->key
|| *negcr
)
648 return mStatus_NoError
;
650 return mStatus_NoSuchRecord
;
653 mDNSlocal
void CheckOneRRSIGForKey(DNSSECVerifier
*dv
, const ResourceRecord
*const rr
)
658 LogMsg("CheckOneRRSIGForKey: ERROR!! rrsig NULL");
661 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
662 if (!SameDomainName((domainname
*)&rrsig
->signerName
, rr
->name
))
664 debugdnssec("CheckOneRRSIGForKey: name mismatch");
667 ValidateRRSIG(dv
, RRVS_rrsig_key
, rr
);
670 mDNSlocal mStatus
CheckRRSIGForKey(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
**negcr
)
682 LogMsg("CheckRRSIGForKey: ERROR!! rrsig NULL");
683 return mStatus_BadParamErr
;
687 LogMsg("CheckRRSIGForKey: ERROR!! key NULL");
688 return mStatus_BadParamErr
;
690 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
691 name
= (domainname
*)&rrsig
->signerName
;
693 slot
= HashSlot(name
);
694 namehash
= DomainNameHashValue(name
);
695 cg
= CacheGroupForName(m
, slot
, namehash
, name
);
698 debugdnssec("CheckRRSIGForKey: cg null %##s", name
->c
);
699 return mStatus_NoSuchRecord
;
701 for (cr
=cg
->members
; cr
; cr
=cr
->next
)
703 if (cr
->resrec
.rrtype
!= kDNSType_RRSIG
) continue;
704 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
708 LogDNSSEC("CheckRRSIGForKey: Negative cache record %s encountered for %##s (RRSIG)", CRDisplayString(m
, cr
),
714 LogMsg("CheckRRSIGForKey: ERROR!! Negative cache record %s already set for %##s (RRSIG)", CRDisplayString(m
, cr
),
719 debugdnssec("CheckRRSIGForKey: checking the validity of rrsig");
720 CheckOneRRSIGForKey(dv
, &cr
->resrec
);
722 if (*negcr
&& dv
->rrsigKey
)
724 // Encountered both RRSIG and negative CR
725 LogMsg("CheckRRSIGForKey: ERROR!! Encountered negative cache record %s and DNSKEY for %##s",
726 CRDisplayString(m
, *negcr
), name
->c
);
727 return mStatus_BadParamErr
;
729 if (dv
->rrsigKey
|| *negcr
)
730 return mStatus_NoError
;
732 return mStatus_NoSuchRecord
;
735 mDNSlocal
void CheckOneDSForKey(DNSSECVerifier
*dv
, const ResourceRecord
*const rr
)
745 LogMsg("CheckOneDSForKey: ERROR!! rrsig NULL");
748 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
749 DS
= (rdataDS
*)((mDNSu8
*)rr
->rdata
+ sizeofRDataHeader
);
751 if (!SameDomainName((domainname
*)&rrsig
->signerName
, rr
->name
))
753 debugdnssec("CheckOneDSForKey: name mismatch");
756 for (keyv
= dv
->key
; keyv
; keyv
= keyv
->next
)
758 key
= (rdataDNSKey
*)keyv
->rdata
;
759 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
);
760 if (tag
!= swap16(DS
->keyTag
))
762 debugdnssec("CheckOneDSForKey: keyTag mismatch keyTag %d, DStag %d", tag
, swap16(DS
->keyTag
));
765 if (key
->alg
!= DS
->alg
)
767 debugdnssec("CheckOneDSForKey: alg mismatch key alg%d, DS alg %d", key
->alg
, swap16(DS
->alg
));
770 if (AddRRSetToVerifier(dv
, rr
, mDNSNULL
, RRVS_ds
) != mStatus_NoError
)
772 debugdnssec("CheckOneDSForKey: cannot allocate RRSet");
777 mDNSlocal mStatus
CheckDSForKey(mDNS
*const m
, DNSSECVerifier
*dv
, CacheRecord
**negcr
)
789 LogMsg("CheckDSForKey: ERROR!! rrsig NULL");
790 return mStatus_BadParamErr
;
794 LogMsg("CheckDSForKey: ERROR!! key NULL");
795 return mStatus_BadParamErr
;
797 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
798 name
= (domainname
*)&rrsig
->signerName
;
799 slot
= HashSlot(name
);
800 namehash
= DomainNameHashValue(name
);
801 cg
= CacheGroupForName(m
, slot
, namehash
, name
);
804 debugdnssec("CheckDSForKey: cg null for %s", name
->c
);
805 return mStatus_NoSuchRecord
;
807 for (cr
=cg
->members
; cr
; cr
=cr
->next
)
809 if (cr
->resrec
.rrtype
!= kDNSType_DS
) continue;
810 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
814 LogDNSSEC("CheckDSForKey: Negative cache record %s encountered for %##s (DS)", CRDisplayString(m
, cr
),
820 LogMsg("CheckDSForKey: ERROR!! Negative cache record %s already set for %##s (DS)", CRDisplayString(m
, cr
),
825 CheckOneDSForKey(dv
, &cr
->resrec
);
827 if (*negcr
&& dv
->ds
)
829 // Encountered both RRSIG and negative CR
830 LogMsg("CheckDSForKey: ERROR!! Encountered negative cache record %s and DS for %##s",
831 CRDisplayString(m
, *negcr
), name
->c
);
832 return mStatus_BadParamErr
;
834 if (dv
->ds
|| *negcr
)
835 return mStatus_NoError
;
837 return mStatus_NoSuchRecord
;
838 return (dv
->ds
? mStatus_NoError
: mStatus_NoSuchRecord
);
841 // It returns mDNStrue if we have all the rrsets for verification and mDNSfalse otherwise.
842 mDNSlocal mDNSBool
GetAllRRSetsForVerification(mDNS
*const m
, DNSSECVerifier
*dv
)
850 LogMsg("GetAllRRSetsForVerification: ERROR!! rrset NULL");
851 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
855 if (dv
->next
== RRVS_done
) return mDNStrue
;
857 debugdnssec("GetAllRRSetsForVerification: next %d", dv
->next
);
861 // If we can't find the RRSIG for the rrset, re-issue the query.
863 // NOTE: It is possible that the cache might answer partially e.g., RRSIGs match qtype but the
864 // whole set is not there. In that case the validation will fail. Ideally we should flush the
865 // cache and reissue the query (TBD).
866 err
= CheckRRSIGForRRSet(m
, dv
, &negcr
);
867 if (err
!= mStatus_NoSuchRecord
&& err
!= mStatus_NoError
)
869 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
872 // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
873 // looks in "dv->q" for the proof. Note that we have to use currQtype as the response could be
874 // a CNAME and dv->rrset->rrtype would be set to CNAME and not the original question type that
875 // resulted in CNAME.
876 InitializeQuestion(m
, &dv
->q
, dv
->InterfaceID
, &dv
->rrset
->name
, dv
->currQtype
, VerifySigCallback
, dv
);
877 // We may not have the NSECS if the previous query was a non-DNSSEC query
878 if (negcr
&& negcr
->nsec
)
880 dv
->DVCallback
= DNSSECNegativeValidationCB
;
881 ValidateWithNSECS(m
, dv
, negcr
);
888 // We already found the rrset to verify. Ideally we should just issue the query for the RRSIG. Unfortunately,
889 // that does not work well as the response may not contain the RRSIG whose typeCovered matches the
890 // rrset->rrtype (recursive server returns what is in its cache). Hence, we send the original query with the
891 // DO bit set again to get the RRSIG. Normally this would happen if there was question which did not require
892 // DNSSEC validation (ValidationRequied = 0) populated the cache and later when the ValidationRequired question
893 // comes along, we need to get the RRSIGs. If we started off with ValidationRequired question we would have
894 // already set the DO bit and not able to get RRSIGs e.g., bad CPE device, we would reissue the query here
897 // Also, if it is a wildcard expanded answer, we need to issue the query with the original type for it to
898 // elicit the right NSEC records. Just querying for RRSIG alone is not sufficient.
900 // Note: For this to work, the core needs to deliver RRSIGs when they are added to the cache even if the
901 // "qtype" is not RRSIG.
902 debugdnssec("GetAllRRSetsForVerification: Fetching RRSIGS for RRSET");
903 mDNS_StartQuery(m
, &dv
->q
);
906 // if we found the RRSIG, then fall through to find the DNSKEY
908 err
= CheckKeyForRRSIG(m
, dv
, &negcr
);
909 if (err
!= mStatus_NoSuchRecord
&& err
!= mStatus_NoError
)
911 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
914 // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
915 // looks in "dv->q" for the proof.
916 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
917 InitializeQuestion(m
, &dv
->q
, dv
->InterfaceID
, (domainname
*)&rrsig
->signerName
, kDNSType_DNSKEY
, VerifySigCallback
, dv
);
918 // We may not have the NSECS if the previous query was a non-DNSSEC query
919 if (negcr
&& negcr
->nsec
)
921 dv
->DVCallback
= DNSSECNegativeValidationCB
;
922 ValidateWithNSECS(m
, dv
, negcr
);
926 dv
->next
= RRVS_rrsig_key
;
929 debugdnssec("GetAllRRSetsForVerification: Fetching DNSKEY for RRSET");
930 mDNS_StartQuery(m
, &dv
->q
);
933 // if we found the DNSKEY, then fall through to find the RRSIG for the DNSKEY
935 err
= CheckRRSIGForKey(m
, dv
, &negcr
);
936 // if we are falling through, then it is okay if we don't find the record
937 if (err
!= mStatus_NoSuchRecord
&& err
!= mStatus_NoError
)
939 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
942 // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
943 // looks in "dv->q" for the proof.
944 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
945 InitializeQuestion(m
, &dv
->q
, dv
->InterfaceID
, (domainname
*)&rrsig
->signerName
, kDNSType_DNSKEY
, VerifySigCallback
, dv
);
946 // We may not have the NSECS if the previous query was a non-DNSSEC query
947 if (negcr
&& negcr
->nsec
)
949 dv
->DVCallback
= DNSSECNegativeValidationCB
;
950 ValidateWithNSECS(m
, dv
, negcr
);
954 debugdnssec("VerifySigCallback: RRVS_rrsig_key %p", dv
->rrsigKey
);
957 debugdnssec("GetAllRRSetsForVerification: Fetching RRSIGS for DNSKEY");
958 mDNS_StartQuery(m
, &dv
->q
);
961 // if we found RRSIG for the DNSKEY, then fall through to find the DS
965 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
966 qname
= (domainname
*)&rrsig
->signerName
;
968 err
= CheckDSForKey(m
, dv
, &negcr
);
969 if (err
!= mStatus_NoSuchRecord
&& err
!= mStatus_NoError
)
971 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
974 // Need to initialize the question as if we end up in ValidateWithNSECS below, the nsec proofs
975 // looks in "dv->q" for the proof.
976 InitializeQuestion(m
, &dv
->q
, dv
->InterfaceID
, qname
, kDNSType_DS
, VerifySigCallback
, dv
);
977 // We may not have the NSECS if the previous query was a non-DNSSEC query
978 if (negcr
&& negcr
->nsec
)
980 dv
->DVCallback
= DNSSECNegativeValidationCB
;
981 ValidateWithNSECS(m
, dv
, negcr
);
984 dv
->next
= RRVS_done
;
985 // If we have a trust anchor, then don't bother looking up the DS record
986 if (!dv
->ds
&& !TrustedKeyPresent(m
, dv
))
988 // There is no DS for the root. Hence, if we don't have the trust
989 // anchor for root, just fail.
990 if (SameDomainName(qname
, (const domainname
*)"\000"))
992 LogDNSSEC("GetAllRRSetsForVerification: Reached root");
993 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
996 debugdnssec("GetAllRRSetsForVerification: Fetching DS");
997 mDNS_StartQuery(m
, &dv
->q
);
1002 debugdnssec("GetAllRRSetsForVerification: Skipped fetching the DS");
1007 LogMsg("GetAllRRSetsForVerification: ERROR!! unknown next %d", dv
->next
);
1008 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
1014 mDNSlocal
void PrintFixedSignInfo(rdataRRSig
*rrsig
, domainname
*signerName
, int sigNameLen
, mDNSu8
*fixedPart
, int fixedPartLen
)
1017 char buf
[RRSIG_FIXED_SIZE
*3 + 1]; // 3 bytes count for %2x + 1 and the one byte for null at the end
1018 char sig
[sigNameLen
* 3 + 1];
1019 char fp
[fixedPartLen
* 3 + 1];
1023 for (j
= 0; j
< RRSIG_FIXED_SIZE
; j
++)
1024 length
+= mDNS_snprintf(buf
+length
, sizeof(buf
) - length
- 1, "%2x ", ((mDNSu8
*)rrsig
)[j
]);
1025 LogMsg("RRSIG(%d) %s", RRSIG_FIXED_SIZE
, buf
);
1029 for (j
= 0; j
< sigNameLen
; j
++)
1030 length
+= mDNS_snprintf(sig
+length
, sizeof(sig
) - length
- 1, "%2x ", signerName
->c
[j
]);
1031 LogMsg("SIGNAME(%d) %s", sigNameLen
, sig
);
1034 for (j
= 0; j
< fixedPartLen
; j
++)
1035 length
+= mDNS_snprintf(fp
+length
, sizeof(fp
) - length
- 1, "%2x ", fixedPart
[j
]);
1036 LogMsg("fixedPart(%d) %s", fixedPartLen
, fp
);
1039 mDNSlocal
void PrintVarSignInfo(mDNSu16 rdlen
, mDNSu8
*rdata
)
1043 unsigned int blen
= swap16(rdlen
);
1044 char buf
[blen
* 3 + 1]; // 3 bytes count for %2x + 1 and the one byte for null at the end
1049 r
= (mDNSu8
*)&rdlen
;
1050 for (j
= 0; j
< sizeof(mDNSu16
); j
++)
1051 length
+= mDNS_snprintf(buf
+length
, sizeof(buf
) - length
- 1, "%2x ", r
[j
]);
1052 LogMsg("RDLENGTH(%d) %s", sizeof(mDNSu16
), buf
);
1055 for (j
= 0; j
< blen
; j
++)
1056 length
+= mDNS_snprintf(buf
+length
, sizeof(buf
) - length
- 1, "%2x ", rdata
[j
]);
1057 LogMsg("RDATA(%d) %s", blen
, buf
);
1060 mDNSlocal
void PrintVarSignInfo(mDNSu16 rdlen
, mDNSu8
*rdata
)
1065 mDNSlocal
void PrintFixedSignInfo(rdataRRSig
*rrsig
, domainname
*signerName
, int sigNameLen
, mDNSu8
*fixedPart
, int fixedPartLen
)
1075 // Used for RDATA comparison
1083 mDNSlocal
int rdata_compare(mDNSu8
*const rdata1
, mDNSu8
*const rdata2
, int rdlen1
, int rdlen2
)
1088 len
= (rdlen1
< rdlen2
) ? rdlen1
: rdlen2
;
1090 ret
= DNSMemCmp(rdata1
, rdata2
, len
);
1091 if (ret
!= 0) return ret
;
1093 // RDATA is same at this stage. Consider them equal if they are of same length. Otherwise
1094 // decide based on their lengths.
1095 return ((rdlen1
== rdlen2
) ? 0 : (rdlen1
< rdlen2
) ? -1 : 1);
1098 mDNSlocal
int name_compare(mDNSu8
*const rdata1
, mDNSu8
*const rdata2
, int rdlen1
, int rdlen2
)
1100 domainname
*n1
= (domainname
*)rdata1
;
1101 domainname
*n2
= (domainname
*)rdata2
;
1107 c1
= CountLabels(n1
);
1108 c2
= CountLabels(n2
);
1110 count
= c1
< c2
? c1
: c2
;
1112 // We can't use SameDomainName as we need to know exactly which is greater/smaller
1113 // for sorting purposes. Hence, we need to compare label by label
1114 for (i
= 0; i
< count
; i
++)
1116 // Are the lengths same ?
1119 debugdnssec("compare_name: returning c1 %d, c2 %d", *a
, *b
);
1120 return ((*a
< *b
) ? -1 : 1);
1123 rdlen1
-= (len
+ 1);
1124 rdlen2
-= (len
+ 1);
1125 if (rdlen1
< 0 || rdlen2
< 0)
1127 LogMsg("name_compare: ERROR!! not enough data rdlen1 %d, rdlen2 %d", rdlen1
, rdlen2
);
1131 for (j
= 0; j
< len
; j
++)
1135 if (mDNSIsUpperCase(ac
)) ac
+= 'a' - 'A';
1136 if (mDNSIsUpperCase(bc
)) bc
+= 'a' - 'A';
1139 debugdnssec("compare_name: returning ac %c, bc %c", ac
, bc
);
1140 return ((ac
< bc
) ? -1 : 1);
1148 mDNSlocal
int srv_compare(rdataComp
*const r1
, rdataComp
*const r2
)
1151 int length1
, length2
;
1153 length1
= r1
->rdlength
;
1154 length2
= r2
->rdlength
;
1155 // We should have at least priority, weight, port plus 1 byte
1156 if (length1
< 7 || length2
< 7)
1158 LogMsg("srv_compare: ERROR!! Length smaller than 7 bytes");
1161 // Compare priority, weight and port
1162 res
= DNSMemCmp(r1
->rdata
, r2
->rdata
, 6);
1163 if (res
!= 0) return res
;
1166 return (name_compare(r1
->rdata
+ 6, r2
->rdata
+ 6, length1
, length2
));
1169 mDNSlocal
int tsig_compare(rdataComp
*const r1
, rdataComp
*const r2
)
1171 int offset1
, offset2
;
1172 int length1
, length2
;
1175 offset1
= offset2
= 0;
1176 length1
= r1
->rdlength
;
1177 length2
= r2
->rdlength
;
1179 // we should have at least one byte to start with
1180 if (length1
< 1 || length2
< 1)
1182 LogMsg("sig_compare: Length smaller than 18 bytes");
1186 res
= name_compare(r1
->rdata
, r2
->rdata
, length1
, length2
);
1187 if (res
!= 0) return res
;
1189 dlen
= DomainNameLength((domainname
*)r1
->rdata
);
1195 if (length1
<= 1 || length2
<= 1)
1197 LogMsg("tsig_compare: data too small to compare length1 %d, length2 %d", length1
, length2
);
1201 return (rdata_compare(r1
->rdata
+ offset1
, r2
->rdata
+ offset2
, length1
, length2
));
1204 // Compares types that conform to : <length><Value>
1205 mDNSlocal
int lenval_compare(mDNSu8
*d1
, mDNSu8
*d2
, int *len1
, int *len2
, int rem1
, int rem2
)
1210 if (rem1
<= 1 || rem2
<= 1)
1212 LogMsg("lenval_compare: data too small to compare length1 %d, length2 %d", rem1
, rem2
);
1217 len
= (*len1
< *len2
? *len1
: *len2
);
1218 res
= DNSMemCmp(d1
, d2
, len
+ 1);
1222 // RFC 2915: Order (2) Preference(2) and variable length: Flags Service Regexp Replacement
1223 mDNSlocal
int naptr_compare(rdataComp
*const r1
, rdataComp
*const r2
)
1225 mDNSu8
*d1
= r1
->rdata
;
1226 mDNSu8
*d2
= r2
->rdata
;
1227 int len1
, len2
, res
;
1228 int length1
, length2
;
1230 length1
= r1
->rdlength
;
1231 length2
= r2
->rdlength
;
1233 // Order, Preference plus at least 1 byte
1234 if (length1
< 5 || length2
< 5)
1236 LogMsg("naptr_compare: Length smaller than 18 bytes");
1239 // Compare order and preference
1240 res
= DNSMemCmp(d1
, d2
, 4);
1241 if (res
!= 0) return res
;
1248 // Compare Flags (including the length byte)
1249 res
= lenval_compare(d1
, d2
, &len1
, &len2
, length1
, length2
);
1250 if (res
!= 0) return res
;
1253 length1
-= (len1
+ 1);
1254 length2
-= (len2
+ 1);
1256 // Compare Service (including the length byte)
1257 res
= lenval_compare(d1
, d2
, &len1
, &len2
, length1
, length2
);
1258 if (res
!= 0) return res
;
1261 length1
-= (len1
+ 1);
1262 length2
-= (len2
+ 1);
1264 // Compare regexp (including the length byte)
1265 res
= lenval_compare(d1
, d2
, &len1
, &len2
, length1
, length2
);
1266 if (res
!= 0) return res
;
1269 length1
-= (len1
+ 1);
1270 length2
-= (len2
+ 1);
1272 // Compare Replacement
1273 return name_compare(d1
, d2
, length1
, length2
);
1276 // RFC 1035: MINFO: Two domain names
1277 // RFC 1183: RP: Two domain names
1278 mDNSlocal
int dom2_compare(mDNSu8
*d1
, mDNSu8
*d2
, int length1
, int length2
)
1282 // We need at least one byte to start with
1283 if (length1
< 1 || length2
< 1)
1285 LogMsg("dom2_compare:1: data too small length1 %d, length2 %d", length1
, length2
);
1288 res
= name_compare(d1
, d2
, length1
, length2
);
1289 if (res
!= 0) return res
;
1290 dlen
= DomainNameLength((domainname
*)d1
);
1294 // We need at least one byte to start with
1295 if (length1
< 1 || length2
< 1)
1297 LogMsg("dom2_compare:2: data too small length1 %d, length2 %d", length1
, length2
);
1304 return name_compare(d1
, d2
, length1
, length2
);
1307 // MX : preference (2 bytes), domainname
1308 mDNSlocal
int mx_compare(rdataComp
*const r1
, rdataComp
*const r2
)
1311 int length1
, length2
;
1313 length1
= r1
->rdlength
;
1314 length2
= r2
->rdlength
;
1316 // We need at least two bytes + 1 extra byte for the domainname to start with
1317 if (length1
< 3 || length2
< 3)
1319 LogMsg("mx_compare: data too small length1 %d, length2 %d", length1
, length2
);
1323 res
= DNSMemCmp(r1
->rdata
, r2
->rdata
, 2);
1324 if (res
!= 0) return res
;
1327 return name_compare(r1
->rdata
+ 2, r2
->rdata
+ 2, length1
, length2
);
1330 // RFC 2163 (PX) : preference (2 bytes), map822. mapx400 (domainnames)
1331 mDNSlocal
int px_compare(rdataComp
*const r1
, rdataComp
*const r2
)
1335 // We need at least two bytes + 1 extra byte for the domainname to start with
1336 if (r1
->rdlength
< 3 || r2
->rdlength
< 3)
1338 LogMsg("px_compare: data too small length1 %d, length2 %d", r1
->rdlength
, r2
->rdlength
);
1342 res
= DNSMemCmp(r1
->rdata
, r2
->rdata
, 2);
1343 if (res
!= 0) return res
;
1345 return dom2_compare(r1
->rdata
+ 2, r2
->rdata
+ 2, r1
->rdlength
- 2, r2
->rdlength
- 2);
1348 mDNSlocal
int soa_compare(rdataComp
*r1
, rdataComp
*r2
)
1351 int offset1
, offset2
;
1352 int length1
, length2
;
1354 length1
= r1
->rdlength
;
1355 length2
= r2
->rdlength
;
1356 offset1
= offset2
= 0;
1358 // We need at least 20 bytes plus 1 byte for each domainname
1359 if (length1
< 22 || length2
< 22)
1361 LogMsg("soa_compare:1: data too small length1 %d, length2 %d", length1
, length2
);
1365 // There are two domainnames followed by 20 bytes of serial, refresh, retry, expire and min
1366 // Compare the names and then the rest of the bytes
1368 res
= name_compare(r1
->rdata
, r2
->rdata
, length1
, length2
);
1369 if (res
!= 0) return res
;
1371 dlen
= DomainNameLength((domainname
*)r1
->rdata
);
1375 if (length1
< 1 || length2
< 1)
1377 LogMsg("soa_compare:2: data too small length1 %d, length2 %d", length1
, length2
);
1383 res
= name_compare(r1
->rdata
+ offset1
, r2
->rdata
+ offset2
, length1
, length2
);
1384 if (res
!= 0) return res
;
1386 dlen
= DomainNameLength((domainname
*)r1
->rdata
);
1389 if (length1
< 20 || length2
< 20)
1391 LogMsg("soa_compare:3: data too small length1 %d, length2 %d", length1
, length2
);
1397 return (rdata_compare(r1
->rdata
+ offset1
, r2
->rdata
+ offset2
, length1
, length2
));
1400 // RFC 4034 Section 6.0 states that:
1402 // A canonical RR form and ordering within an RRset are required in order to
1403 // construct and verify RRSIG RRs.
1405 // This function is called to order within an RRset. We can't just do a memcmp as
1406 // as stated in 6.3. This function is responsible for the third bullet in 6.2, where
1407 // the RDATA has to be converted to lower case if it has domain names.
1408 mDNSlocal
int RDATACompare(const void *rdata1
, const void *rdata2
)
1410 rdataComp
*r1
= (rdataComp
*)rdata1
;
1411 rdataComp
*r2
= (rdataComp
*)rdata2
;
1413 if (r1
->rrtype
!= r2
->rrtype
)
1415 LogMsg("RDATACompare: ERROR!! comparing rdata of wrong types type1: %d, type2: %d", r1
->rrtype
, r2
->rrtype
);
1420 case kDNSType_A
: // 1. Address Record
1421 case kDNSType_NULL
: // 10 NULL RR
1422 case kDNSType_WKS
: // 11 Well-known-service
1423 case kDNSType_HINFO
: // 13 Host information
1424 case kDNSType_TXT
: // 16 Arbitrary text string
1425 case kDNSType_X25
: // 19 X_25 calling address
1426 case kDNSType_ISDN
: // 20 ISDN calling address
1427 case kDNSType_NSAP
: // 22 NSAP address
1428 case kDNSType_KEY
: // 25 Security key
1429 case kDNSType_GPOS
: // 27 Geographical position (withdrawn)
1430 case kDNSType_AAAA
: // 28 IPv6 Address
1431 case kDNSType_LOC
: // 29 Location Information
1432 case kDNSType_EID
: // 31 Endpoint identifier
1433 case kDNSType_NIMLOC
: // 32 Nimrod Locator
1434 case kDNSType_ATMA
: // 34 ATM Address
1435 case kDNSType_CERT
: // 37 Certification record
1436 case kDNSType_A6
: // 38 IPv6 Address (deprecated)
1437 case kDNSType_SINK
: // 40 Kitchen sink (experimental)
1438 case kDNSType_OPT
: // 41 EDNS0 option (meta-RR)
1439 case kDNSType_APL
: // 42 Address Prefix List
1440 case kDNSType_DS
: // 43 Delegation Signer
1441 case kDNSType_SSHFP
: // 44 SSH Key Fingerprint
1442 case kDNSType_IPSECKEY
: // 45 IPSECKEY
1443 case kDNSType_RRSIG
: // 46 RRSIG
1444 case kDNSType_NSEC
: // 47 Denial of Existence
1445 case kDNSType_DNSKEY
: // 48 DNSKEY
1446 case kDNSType_DHCID
: // 49 DHCP Client Identifier
1447 case kDNSType_NSEC3
: // 50 Hashed Authenticated Denial of Existence
1448 case kDNSType_NSEC3PARAM
: // 51 Hashed Authenticated Denial of Existence
1449 case kDNSType_HIP
: // 55 Host Identity Protocol
1450 case kDNSType_SPF
: // 99 Sender Policy Framework for E-Mail
1452 return rdata_compare(r1
->rdata
, r2
->rdata
, r1
->rdlength
, r2
->rdlength
);
1453 case kDNSType_NS
: // 2 Name Server
1454 case kDNSType_MD
: // 3 Mail Destination
1455 case kDNSType_MF
: // 4 Mail Forwarder
1456 case kDNSType_CNAME
: // 5 Canonical Name
1457 case kDNSType_MB
: // 7 Mailbox
1458 case kDNSType_MG
: // 8 Mail Group
1459 case kDNSType_MR
: // 9 Mail Rename
1460 case kDNSType_PTR
: // 12 Domain name pointer
1461 case kDNSType_NSAP_PTR
: // 23 Reverse NSAP lookup (deprecated)
1462 case kDNSType_DNAME
: // 39 Non-terminal DNAME (for IPv6)
1463 return name_compare(r1
->rdata
, r2
->rdata
, r1
->rdlength
, r2
->rdlength
);
1464 case kDNSType_SRV
: // 33 Service record
1465 return srv_compare(r1
, r2
);
1466 case kDNSType_SOA
: // 6 Start of Authority
1467 return soa_compare(r1
, r2
);
1469 case kDNSType_RP
: // 17 Responsible person
1470 case kDNSType_MINFO
: // 14 Mailbox information
1471 return dom2_compare(r1
->rdata
, r2
->rdata
, r1
->rdlength
, r2
->rdlength
);
1472 case kDNSType_MX
: // 15 Mail Exchanger
1473 case kDNSType_AFSDB
: // 18 AFS cell database
1474 case kDNSType_RT
: // 21 Router
1475 case kDNSType_KX
: // 36 Key Exchange
1476 return mx_compare(r1
, r2
);
1477 case kDNSType_PX
: // 26 X.400 mail mapping
1478 return px_compare(r1
, r2
);
1479 case kDNSType_NAPTR
: // 35 Naming Authority PoinTeR
1480 return naptr_compare(r1
, r2
);
1481 case kDNSType_TKEY
: // 249 Transaction key
1482 case kDNSType_TSIG
: // 250 Transaction signature
1483 // TSIG and TKEY have a domainname followed by data
1484 return tsig_compare(r1
, r2
);
1485 // TBD: We are comparing them as opaque types, perhaps not right
1486 case kDNSType_SIG
: // 24 Security signature
1487 case kDNSType_NXT
: // 30 Next domain (security)
1488 LogMsg("RDATACompare: WARNING!! explicit support has not been added, using default");
1489 return rdata_compare(r1
->rdata
, r2
->rdata
, r1
->rdlength
, r2
->rdlength
);
1495 // RFC 4034 section 6.2 requirement for verifying signature.
1497 // 3. if the type of the RR is NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
1498 // HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
1499 // SRV, DNAME, A6, RRSIG, or NSEC, all uppercase US-ASCII letters in
1500 // the DNS names contained within the RDATA are replaced by the
1501 // corresponding lowercase US-ASCII letters;
1503 // NSEC and HINFO is not needed as per dnssec-bis update. RRSIG is done elsewhere
1504 // as part of signature verification
1505 mDNSlocal
void ConvertRDATAToCanonical(mDNSu16 rrtype
, mDNSu16 rdlength
, mDNSu8
*rdata
)
1509 mDNSu8
*origRdata
= rdata
;
1511 // Ensure that we have at least one byte of data to examine and modify.
1513 if (!rdlength
) { LogMsg("ConvertRDATAToCanonical: rdlength zero for rrtype %s", DNSTypeName(rrtype
)); return; }
1517 // Not adding suppot for A6 as it is deprecated
1518 case kDNSType_A6
: // 38 IPv6 Address (deprecated)
1520 debugdnssec("ConvertRDATAToCanonical: returning from default %s", DNSTypeName(rrtype
));
1522 case kDNSType_NS
: // 2 Name Server
1523 case kDNSType_MD
: // 3 Mail Destination
1524 case kDNSType_MF
: // 4 Mail Forwarder
1525 case kDNSType_CNAME
: // 5 Canonical Name
1526 case kDNSType_MB
: // 7 Mailbox
1527 case kDNSType_MG
: // 8 Mail Group
1528 case kDNSType_MR
: // 9 Mail Rename
1529 case kDNSType_PTR
: // 12 Domain name pointer
1530 case kDNSType_DNAME
: // 39 Non-terminal DNAME (for IPv6)
1531 case kDNSType_NXT
: // 30 Next domain (security)
1533 // TSIG and TKEY are not mentioned in RFC 4034, but we just leave it here
1534 case kDNSType_TSIG
: // 250 Transaction signature
1535 case kDNSType_TKEY
: // 249 Transaction key
1537 if (DNSNameToLowerCase((domainname
*)rdata
, &name
) != mStatus_NoError
)
1539 LogMsg("ConvertRDATAToCanonical: ERROR!! DNSNameToLowerCase failed");
1542 AssignDomainName((domainname
*)rdata
, &name
);
1544 case kDNSType_MX
: // 15 Mail Exchanger
1545 case kDNSType_AFSDB
: // 18 AFS cell database
1546 case kDNSType_RT
: // 21 Router
1547 case kDNSType_KX
: // 36 Key Exchange
1549 // format: preference - 2 bytes, followed by name
1550 // Ensure that we have at least 3 bytes (preference + 1 byte for the domain name)
1553 LogMsg("ConvertRDATAToCanonical:MX: rdlength %d for rrtype %s too small", rdlength
, DNSTypeName(rrtype
));
1556 if (DNSNameToLowerCase((domainname
*)(rdata
+ 2), &name
) != mStatus_NoError
)
1558 LogMsg("ConvertRDATAToCanonical: MX: ERROR!! DNSNameToLowerCase failed");
1561 AssignDomainName((domainname
*)(rdata
+ 2), &name
);
1563 case kDNSType_SRV
: // 33 Service record
1564 // format : priority, weight and port - 6 bytes, followed by name
1567 LogMsg("ConvertRDATAToCanonical:SRV: rdlength %d for rrtype %s too small", rdlength
, DNSTypeName(rrtype
));
1570 if (DNSNameToLowerCase((domainname
*)(rdata
+ 6), &name
) != mStatus_NoError
)
1572 LogMsg("ConvertRDATAToCanonical: SRV: ERROR!! DNSNameToLowerCase failed");
1575 AssignDomainName((domainname
*)(rdata
+ 6), &name
);
1577 case kDNSType_PX
: // 26 X.400 mail mapping
1580 LogMsg("ConvertRDATAToCanonical:PX: rdlength %d for rrtype %s too small", rdlength
, DNSTypeName(rrtype
));
1583 // Preference followed by two domain names
1586 case kDNSType_RP
: // 17 Responsible person
1587 case kDNSType_SOA
: // 6 Start of Authority
1588 case kDNSType_MINFO
: // 14 Mailbox information
1589 if (DNSNameToLowerCase((domainname
*)rdata
, &name
) != mStatus_NoError
)
1591 LogMsg("ConvertRDATAToCanonical: SOA1: ERROR!! DNSNameToLowerCase failed");
1595 AssignDomainName((domainname
*)rdata
, &name
);
1596 len
= DomainNameLength((domainname
*)rdata
);
1597 if (rdlength
<= len
+ 1)
1599 LogMsg("ConvertRDATAToCanonical:RP: rdlength %d for rrtype %s too small", rdlength
, DNSTypeName(rrtype
));
1604 if (DNSNameToLowerCase((domainname
*)rdata
, &name
) != mStatus_NoError
)
1606 LogMsg("ConvertRDATAToCanonical: SOA2: ERROR!! DNSNameToLowerCase failed");
1609 AssignDomainName((domainname
*)rdata
, &name
);
1611 case kDNSType_NAPTR
: // 35 Naming Authority Pointer
1612 // order and preference
1614 // Flags (including the length byte)
1615 rdata
+= (((int) rdata
[0]) + 1);
1616 // Service (including the length byte)
1617 rdata
+= (((int) rdata
[0]) + 1);
1618 // regexp (including the length byte)
1619 rdata
+= (((int) rdata
[0]) + 1);
1621 // Replacement field is a domainname. If we have at least one more byte, then we are okay.
1622 if ((origRdata
+ rdlength
) < rdata
+ 1)
1624 LogMsg("ConvertRDATAToCanonical:NAPTR: origRdata %p, rdlength %d, rdata %p for rrtype %s too small", origRdata
, rdlength
, rdata
, DNSTypeName(rrtype
));
1627 if (DNSNameToLowerCase((domainname
*)rdata
, &name
) != mStatus_NoError
)
1629 LogMsg("ConvertRDATAToCanonical: NAPTR2: ERROR!! DNSNameToLowerCase failed");
1632 AssignDomainName((domainname
*)rdata
, &name
);
1633 case kDNSType_SIG
: // 24 Security signature
1634 // format: <18 bytes> <domainname> <data>
1637 LogMsg("ConvertRDATAToCanonical:SIG: rdlength %d for rrtype %s too small", rdlength
, DNSTypeName(rrtype
));
1640 // Preference followed by two domain names
1642 if (DNSNameToLowerCase((domainname
*)rdata
, &name
) != mStatus_NoError
)
1644 LogMsg("ConvertRDATAToCanonical: SIG: ERROR!! DNSNameToLowerCase failed");
1647 AssignDomainName((domainname
*)rdata
, &name
);
1652 mDNSlocal mDNSBool
ValidateSignatureWithKey(DNSSECVerifier
*dv
, RRVerifier
*rrset
, RRVerifier
*keyv
, RRVerifier
*sig
)
1655 domainname signerName
;
1657 mDNSu8 fixedPart
[MAX_DOMAIN_NAME
+ 8]; // domainname + type + class + ttl
1661 rdataComp
*ptr
, *start
, *p
;
1670 key
= (rdataDNSKey
*)keyv
->rdata
;
1671 rrsig
= (rdataRRSig
*)sig
->rdata
;
1673 LogDNSSEC("ValidateSignatureWithKey: Validating signature with key with tag %d", (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
));
1675 if (DNSNameToLowerCase((domainname
*)&rrsig
->signerName
, &signerName
) != mStatus_NoError
)
1677 LogMsg("ValidateSignatureWithKey: ERROR!! cannot convert signer name to lower case");
1681 if (DNSNameToLowerCase((domainname
*)&rrset
->name
, &name
) != mStatus_NoError
)
1683 LogMsg("ValidateSignatureWithKey: ERROR!! cannot convert rrset name to lower case");
1687 sigNameLen
= DomainNameLength(&signerName
);
1688 labels
= CountLabels(&name
);
1689 // RFC 4034: RRSIG validation
1691 // signature = sign(RRSIG_RDATA | RR(1) | RR(2)... )
1693 // where RRSIG_RDATA excludes the signature and signer name in canonical form
1695 if (dv
->ctx
) AlgDestroy(dv
->ctx
);
1696 dv
->ctx
= AlgCreate(CRYPTO_ALG
, rrsig
->alg
);
1699 LogMsg("ValidateSignatureWithKey: ERROR!! No algorithm support for %d", rrsig
->alg
);
1702 AlgAdd(dv
->ctx
, (mDNSu8
*)rrsig
, RRSIG_FIXED_SIZE
);
1703 AlgAdd(dv
->ctx
, signerName
.c
, sigNameLen
);
1705 if (labels
- rrsig
->labels
> 0)
1708 LogDNSSEC("ValidateSignatureWithKey: ====splitting labels %d, rrsig->labels %d====", labels
,rrsig
->labels
);
1709 d
= (domainname
*)SkipLeadingLabels(&name
, labels
- rrsig
->labels
);
1712 AssignDomainName((domainname
*)(fixedPart
+ 2), d
);
1713 fixedPartLen
= DomainNameLength(d
) + 2;
1714 // See RFC 4034 section 3.1.3. If you are looking up *.example.com,
1715 // the labels count in the RRSIG is 2, but this is not considered as
1716 // a wildcard answer
1717 if (name
.c
[0] != 1 || name
.c
[1] != '*')
1719 LogDNSSEC("ValidateSignatureWithKey: Wildcard exapnded answer for %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
1720 dv
->flags
|= WILDCARD_PROVES_ANSWER_EXPANDED
;
1721 dv
->wildcardName
= (domainname
*)SkipLeadingLabels(&dv
->origName
, labels
- rrsig
->labels
);
1722 if (!dv
->wildcardName
) return mDNSfalse
;
1727 debugdnssec("ValidateSignatureWithKey: assigning domainname");
1728 AssignDomainName((domainname
*)fixedPart
, &name
);
1729 fixedPartLen
= DomainNameLength(&name
);
1731 temp
= swap16(rrset
->rrtype
);
1732 mDNSPlatformMemCopy(fixedPart
+ fixedPartLen
, (mDNSu8
*)&temp
, sizeof(rrset
->rrtype
));
1733 fixedPartLen
+= sizeof(rrset
->rrtype
);
1734 temp
= swap16(rrset
->rrclass
);
1735 mDNSPlatformMemCopy(fixedPart
+ fixedPartLen
, (mDNSu8
*)&temp
, sizeof(rrset
->rrclass
));
1736 fixedPartLen
+= sizeof(rrset
->rrclass
);
1737 mDNSPlatformMemCopy(fixedPart
+ fixedPartLen
, (mDNSu8
*)&rrsig
->origTTL
, sizeof(rrsig
->origTTL
));
1738 fixedPartLen
+= sizeof(rrsig
->origTTL
);
1741 for (tmp
= rrset
, nrrsets
= 0; tmp
; tmp
= tmp
->next
)
1745 start
= ptr
= mDNSPlatformMemAllocate(nrrsets
* sizeof (rdataComp
));
1746 debugdnssec("ValidateSignatureWithKey: start %p, nrrsets %d", start
, nrrsets
);
1749 // Need to initialize for failure case below
1750 mDNSPlatformMemZero(ptr
, nrrsets
* (sizeof (rdataComp
)));
1753 ptr
->rdlength
= tmp
->rdlength
;
1754 ptr
->rrtype
= tmp
->rrtype
;
1757 ptr
->rdata
= mDNSPlatformMemAllocate(ptr
->rdlength
);
1759 mDNSPlatformMemCopy(ptr
->rdata
, tmp
->rdata
, tmp
->rdlength
);
1762 for (i
= 0; i
< nrrsets
; i
++)
1763 if (start
[i
].rdata
) mDNSPlatformMemFree(start
[i
].rdata
);
1764 mDNSPlatformMemFree(start
);
1765 LogMsg("ValidateSignatureWithKey:1: ERROR!! RDATA memory alloation failure");
1775 LogMsg("ValidateSignatureWithKey:2: ERROR!! RDATA memory alloation failure");
1779 PrintFixedSignInfo(rrsig
, &signerName
, sigNameLen
, fixedPart
, fixedPartLen
);
1781 mDNSPlatformQsort(start
, nrrsets
, sizeof(rdataComp
), RDATACompare
);
1782 for (p
= start
, i
= 0; i
< nrrsets
; p
++, i
++)
1786 // The array is sorted and hence checking adjacent entries for duplicate is sufficient
1789 rdataComp
*q
= p
- 1;
1790 if (!RDATACompare((void *)p
, (void *)q
)) continue;
1793 // Add the fixed part
1794 AlgAdd(dv
->ctx
, fixedPart
, fixedPartLen
);
1797 rdlen
= swap16(p
->rdlength
);
1798 AlgAdd(dv
->ctx
, (mDNSu8
*)&rdlen
, sizeof(mDNSu16
));
1800 ConvertRDATAToCanonical(p
->rrtype
, p
->rdlength
, p
->rdata
);
1802 PrintVarSignInfo(rdlen
, p
->rdata
);
1803 AlgAdd(dv
->ctx
, p
->rdata
, p
->rdlength
);
1805 // free the memory as we don't need it anymore
1806 for (i
= 0; i
< nrrsets
; i
++)
1807 if (start
[i
].rdata
) mDNSPlatformMemFree(start
[i
].rdata
);
1808 mDNSPlatformMemFree(start
);
1810 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
);
1811 AlgDestroy(dv
->ctx
);
1813 if (algRet
!= mStatus_NoError
)
1815 LogDNSSEC("ValidateSignatureWithKey: AlgVerify failed for %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
1816 // Reset the state if we set any above.
1817 if (dv
->flags
& WILDCARD_PROVES_ANSWER_EXPANDED
)
1819 dv
->flags
&= ~WILDCARD_PROVES_ANSWER_EXPANDED
;
1820 dv
->wildcardName
= mDNSNULL
;
1827 // Walk all the keys and for each key walk all the RRSIGS that signs the original rrset
1828 mDNSlocal mStatus
ValidateSignature(DNSSECVerifier
*dv
, RRVerifier
**resultKey
, RRVerifier
**resultRRSIG
)
1841 for (keyv
= dv
->key
; keyv
; keyv
= keyv
->next
)
1843 key
= (rdataDNSKey
*)keyv
->rdata
;
1844 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
);
1845 for (rrsigv
= sig
; rrsigv
; rrsigv
= rrsigv
->next
)
1847 rrsig
= (rdataRRSig
*)rrsigv
->rdata
;
1848 // 7. The RRSIG RR's Signer's Name, Algorithm, and Key Tag fields MUST match the owner
1849 // name, algorithm, and key tag for some DNSKEY RR in the zone's apex DNSKEY RRset.
1850 if (!SameDomainName((domainname
*)&rrsig
->signerName
, &keyv
->name
))
1852 debugdnssec("ValidateSignature: name mismatch");
1855 if (key
->alg
!= rrsig
->alg
)
1857 debugdnssec("ValidateSignature: alg mismatch");
1860 if (tag
!= swap16(rrsig
->keyTag
))
1862 debugdnssec("ValidateSignature: keyTag mismatch rrsig tag %d(0x%x), keyTag %d(0x%x)", swap16(rrsig
->keyTag
),
1863 swap16(rrsig
->keyTag
), tag
, tag
);
1866 // 8. The matching DNSKEY RR MUST be present in the zone's apex DNSKEY RRset, and MUST
1867 // have the Zone Flag bit (DNSKEY RDATA Flag bit 7) set.
1868 if (!((swap16(key
->flags
)) & DNSKEY_ZONE_SIGN_KEY
))
1870 debugdnssec("ValidateSignature: ZONE flag bit not set");
1873 debugdnssec("ValidateSignature:Found a key and RRSIG tag: %d", tag
);
1874 if (ValidateSignatureWithKey(dv
, rrset
, keyv
, rrsigv
))
1876 LogDNSSEC("ValidateSignature: Validated successfully with key tag %d", tag
);
1878 *resultRRSIG
= rrsigv
;
1879 return mStatus_NoError
;
1883 *resultKey
= mDNSNULL
;
1884 *resultRRSIG
= mDNSNULL
;
1885 return mStatus_NoSuchRecord
;
1888 mDNSlocal mDNSBool
ValidateSignatureWithKeyForAllRRSigs(DNSSECVerifier
*dv
, RRVerifier
*rrset
, RRVerifier
*keyv
, RRVerifier
*sig
)
1895 rrsig
= (rdataRRSig
*)sig
->rdata
;
1896 tag
= (mDNSu16
)keytag(keyv
->rdata
, keyv
->rdlength
);
1897 if (tag
== swap16(rrsig
->keyTag
))
1899 if (ValidateSignatureWithKey(dv
, rrset
, keyv
, sig
))
1901 LogDNSSEC("ValidateSignatureWithKeyForAllRRSigs: Validated");
1910 mDNSlocal mStatus
ValidateDS(DNSSECVerifier
*dv
)
1922 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
1924 // Walk all the DS Records to see if we have a matching DNS KEY record that verifies
1925 // the hash. If we find one, verify that this key was used to sign the KEY rrsets in
1926 // this zone. Loop till we find one.
1927 for (dsv
= dv
->ds
; dsv
; dsv
= dsv
->next
)
1929 ds
= (rdataDS
*)dsv
->rdata
;
1930 if ((ds
->digestType
!= SHA1_DIGEST_TYPE
) && (ds
->digestType
!= SHA256_DIGEST_TYPE
))
1932 LogDNSSEC("ValidateDS: Unsupported digest %d", ds
->digestType
);
1933 return mStatus_BadParamErr
;
1935 else debugdnssec("ValidateDS: digest type %d", ds
->digestType
);
1936 for (keyv
= dv
->key
; keyv
; keyv
= keyv
->next
)
1938 key
= (rdataDNSKey
*)keyv
->rdata
;
1939 mDNSu16 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
);
1940 if (tag
!= swap16(ds
->keyTag
))
1942 debugdnssec("ValidateDS:Not a valid keytag %d", tag
);
1946 if (DNSNameToLowerCase((domainname
*)&rrsig
->signerName
, &name
) != mStatus_NoError
)
1948 LogMsg("ValidateDS: ERROR!! cannot convert to lower case");
1952 if (dv
->ctx
) AlgDestroy(dv
->ctx
);
1953 dv
->ctx
= AlgCreate(DIGEST_ALG
, ds
->digestType
);
1956 LogMsg("ValidateDS: ERROR!! Cannot allocate context");
1959 digest
= (mDNSu8
*)&ds
->digest
;
1960 digestLen
= dsv
->rdlength
- DS_FIXED_SIZE
;
1962 AlgAdd(dv
->ctx
, name
.c
, DomainNameLength(&name
));
1963 AlgAdd(dv
->ctx
, key
, keyv
->rdlength
);
1965 algRet
= AlgVerify(dv
->ctx
, mDNSNULL
, 0, digest
, digestLen
);
1966 AlgDestroy(dv
->ctx
);
1968 if (algRet
== mStatus_NoError
)
1970 LogDNSSEC("ValidateDS: DS Validated Successfully, need to verify the key %d", tag
);
1971 // We found the DNS KEY that is authenticated by the DS in our parent zone. Check to see if this key
1972 // was used to sign the DNS KEY RRSET. If so, then the keys in our DNS KEY RRSET are valid
1973 if (ValidateSignatureWithKeyForAllRRSigs(dv
, dv
->key
, keyv
, dv
->rrsigKey
))
1975 LogDNSSEC("ValidateDS: DS Validated Successfully %d", tag
);
1976 return mStatus_NoError
;
1981 return mStatus_NoSuchRecord
;
1984 mDNSlocal mDNSBool
UnlinkRRVerifier(DNSSECVerifier
*dv
, RRVerifier
*elem
, RRVerifierSet set
)
1999 case RRVS_rrsig_key
:
2006 LogMsg("UnlinkRRVerifier: ERROR!! default case %d", set
);
2009 while (*v
&& *v
!= elem
)
2013 LogMsg("UnlinkRRVerifier: ERROR!! cannot find element in set %d", set
);
2016 *v
= elem
->next
; // Cut this record from the list
2017 elem
->next
= mDNSNULL
;
2021 // This can link a single AuthChain element or a list of AuthChain elements to
2022 // DNSSECVerifier. The latter happens when we have multiple NSEC proofs and
2023 // we gather up all the proofs in one place.
2024 mDNSexport
void AuthChainLink(DNSSECVerifier
*dv
, AuthChain
*ae
)
2028 LogDNSSEC("AuthChainLink: called");
2031 // Get to the last element
2034 *(dv
->actail
) = head
; // Append this record to tail of auth chain
2035 dv
->actail
= &(ae
->next
); // Advance tail pointer
2038 mDNSlocal mDNSBool
AuthChainAdd(DNSSECVerifier
*dv
, RRVerifier
*resultKey
, RRVerifier
*resultRRSig
)
2044 if (!dv
->rrset
|| !resultKey
|| !resultRRSig
)
2046 LogMsg("AuthChainAdd: ERROR!! input argument NULL");
2050 // Unlink resultKey and resultRRSig and store as part of AuthChain
2051 if (!UnlinkRRVerifier(dv
, resultKey
, RRVS_key
))
2053 LogMsg("AuthChainAdd: ERROR!! cannot unlink key");
2056 if (!UnlinkRRVerifier(dv
, resultRRSig
, RRVS_rrsig
))
2058 LogMsg("AuthChainAdd: ERROR!! cannot unlink rrsig");
2062 ae
= mDNSPlatformMemAllocate(sizeof(AuthChain
));
2065 LogMsg("AuthChainAdd: AuthChain alloc failure");
2069 ae
->next
= mDNSNULL
;
2070 ae
->rrset
= dv
->rrset
;
2071 dv
->rrset
= mDNSNULL
;
2073 ae
->rrsig
= resultRRSig
;
2074 ae
->key
= resultKey
;
2076 key
= (rdataDNSKey
*)resultKey
->rdata
;
2077 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, resultKey
->rdlength
);
2078 LogDNSSEC("AuthChainAdd: inserting AuthChain element with rrset %##s (%s), DNSKEY tag %d", ae
->rrset
->name
.c
, DNSTypeName(ae
->rrset
->rrtype
), tag
);
2080 AuthChainLink(dv
, ae
);
2084 // RFC 4035: Section 5.3.3
2086 // If the resolver accepts the RRset as authentic, the validator MUST set the TTL of
2087 // the RRSIG RR and each RR in the authenticated RRset to a value no greater than the
2090 // o the RRset's TTL as received in the response;
2092 // o the RRSIG RR's TTL as received in the response;
2094 // o the value in the RRSIG RR's Original TTL field; and
2096 // o the difference of the RRSIG RR's Signature Expiration time and the
2098 mDNSlocal
void SetTTLRRSet(mDNS
*const m
, DNSSECVerifier
*dv
, DNSSECStatus status
)
2100 DNSQuestion question
;
2106 int sigNameLen
, len
;
2108 mDNSu32 rrTTL
, rrsigTTL
, rrsigOrigTTL
, rrsigTimeTTL
;
2111 CacheRecord
*rrsigRR
;
2113 debugdnssec("SetTTLRRSet called");
2115 // TBD: Just handle secure for now
2116 if (status
!= DNSSEC_Secure
) return;
2118 // check to make sure we built a AuthChain as part of verification
2119 if (!dv
->ac
|| !dv
->ac
->rrset
|| !dv
->ac
->rrsig
|| !dv
->ac
->key
)
2121 LogMsg("SetTTLRRSet: ERROR!! NULL element in chain");
2122 FreeDNSSECVerifier(m
, dv
);
2126 mDNSPlatformMemZero(&question
, sizeof(DNSQuestion
));
2127 rrTTL
= rrsigTTL
= rrsigOrigTTL
= rrsigTimeTTL
= 0;
2129 // 1. Locate the rrset name and get its TTL (take the first one as a representative
2131 qname
= &dv
->origName
;
2132 qtype
= dv
->origType
;
2134 question
.ThisQInterval
= -1;
2135 InitializeQuestion(m
, &question
, dv
->InterfaceID
, qname
, qtype
, mDNSNULL
, mDNSNULL
);
2136 slot
= HashSlot(&question
.qname
);
2137 cg
= CacheGroupForName(m
, slot
, question
.qnamehash
, &question
.qname
);
2139 if (!cg
) { LogMsg("SetTTLRRSet cg NULL"); return; }
2140 for (rr
= cg
->members
; rr
; rr
= rr
->next
)
2141 if (SameNameRecordAnswersQuestion(&rr
->resrec
, &question
))
2143 rrTTL
= rr
->resrec
.rroriginalttl
;
2147 // Should we check to see if it matches the record in dv->ac->rrset ?
2150 LogMsg("SetTTLRRSet: ERROR!! cannot locate main rrset for %##s (%s)", qname
->c
, DNSTypeName(qtype
));
2155 // 2. Get the RRSIG ttl. For NSEC records we need to get the NSEC record's TTL as
2156 // the negative cache record that we created may not be right.
2159 rrsig
= (rdataRRSig
*)rv
->rdata
;
2160 sigNameLen
= DomainNameLength((domainname
*)&rrsig
->signerName
);
2161 // pointer to signature and the length
2162 ptr
= (mDNSu8
*)(rv
->rdata
+ sigNameLen
+ RRSIG_FIXED_SIZE
);
2163 len
= rv
->rdlength
- RRSIG_FIXED_SIZE
- sigNameLen
;
2166 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
)
2170 for (ncr
= rr
->nsec
; ncr
; ncr
= ncr
->next
)
2172 if (ncr
->resrec
.rrtype
== kDNSType_NSEC
)
2174 rrTTL
= ncr
->resrec
.rroriginalttl
;
2175 debugdnssec("SetTTLRRSet: NSEC TTL %u", rrTTL
);
2177 // Note: we can't use dv->origName here as the NSEC record's RRSIG may not match
2178 // the original name
2179 if (ncr
->resrec
.rrtype
== kDNSType_RRSIG
&& SameDomainName(ncr
->resrec
.name
, &rv
->name
))
2181 RDataBody2
*rdb
= (RDataBody2
*)ncr
->resrec
.rdata
->u
.data
;
2182 rdataRRSig
*sig
= (rdataRRSig
*)rdb
->data
;
2183 if (rv
->rdlength
!= ncr
->resrec
.rdlength
)
2185 debugdnssec("SetTTLRRSet length mismatch");
2188 if (mDNSPlatformMemSame(sig
, rrsig
, rv
->rdlength
))
2190 rrsigTTL
= ncr
->resrec
.rroriginalttl
;
2191 rrsigOrigTTL
= swap32(rrsig
->origTTL
);
2192 rrsigTimeTTL
= swap32(rrsig
->sigExpireTime
) - swap32(rrsig
->sigInceptTime
);
2195 if (rrTTL
&& rrsigTTL
) break;
2200 // Look for the matching RRSIG so that we can get its TTL
2201 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
2202 if (rr
->resrec
.rrtype
== kDNSType_RRSIG
&& SameDomainName(rr
->resrec
.name
, &rv
->name
))
2204 RDataBody2
*rdb
= (RDataBody2
*)rr
->resrec
.rdata
->u
.data
;
2205 rdataRRSig
*sig
= (rdataRRSig
*)rdb
->data
;
2206 if (rv
->rdlength
!= rr
->resrec
.rdlength
)
2208 debugdnssec("SetTTLRRSet length mismatch");
2211 if (mDNSPlatformMemSame(sig
, rrsig
, rv
->rdlength
))
2213 rrsigTTL
= rr
->resrec
.rroriginalttl
;
2214 rrsigOrigTTL
= swap32(rrsig
->origTTL
);
2215 rrsigTimeTTL
= swap32(rrsig
->sigExpireTime
) - swap32(rrsig
->sigInceptTime
);
2222 if (!rrTTL
|| !rrsigTTL
|| !rrsigOrigTTL
|| !rrsigTimeTTL
)
2224 LogMsg("SetTTLRRSet: ERROR!! Bad TTL rrtl %u, rrsigTTL %u, rrsigOrigTTL %u, rrsigTimeTTL %u for %##s (%s)",
2225 rrTTL
, rrsigTTL
, rrsigOrigTTL
, rrsigTimeTTL
, qname
->c
, DNSTypeName(qtype
));
2230 LogDNSSEC("SetTTLRRSet: TTL rrtl %u, rrsigTTL %u, rrsigOrigTTL %u, rrsigTimeTTL %u for %##s (%s)",
2231 rrTTL
, rrsigTTL
, rrsigOrigTTL
, rrsigTimeTTL
, qname
->c
, DNSTypeName(qtype
));
2234 if (rrsigTTL
< rrTTL
)
2236 if (rrsigOrigTTL
< rrTTL
)
2237 rrTTL
= rrsigOrigTTL
;
2238 if (rrsigTimeTTL
< rrTTL
)
2239 rrTTL
= rrsigTimeTTL
;
2241 // Set the rrsig's TTL. For NSEC records, rrsigRR is NULL which means it expires when
2242 // the negative cache record expires.
2244 rrsigRR
->resrec
.rroriginalttl
= rrTTL
;
2246 // Find the RRset and set its TTL
2247 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
2249 if (SameNameRecordAnswersQuestion(&rr
->resrec
, &question
))
2251 LogDNSSEC("SetTTLRRSet: Setting the TTL %d for %s, question %##s (%s)", rrTTL
, CRDisplayString(m
, rr
),
2252 question
.qname
.c
, DNSTypeName(rr
->resrec
.rrtype
));
2253 rr
->resrec
.rroriginalttl
= rrTTL
;
2254 SetNextCacheCheckTimeForRecord(m
, rr
);
2259 mDNSlocal
void FinishDNSSECVerification(mDNS
*const m
, DNSSECVerifier
*dv
)
2261 RRVerifier
*resultKey
;
2262 RRVerifier
*resultRRSig
;
2264 LogDNSSEC("FinishDNSSECVerification: all rdata sets available for sig verification for %##s (%s)",
2265 dv
->origName
.c
, DNSTypeName(dv
->origType
));
2267 mDNS_StopQuery(m
, &dv
->q
);
2268 if (ValidateSignature(dv
, &resultKey
, &resultRRSig
) == mStatus_NoError
)
2272 key
= (rdataDNSKey
*)resultKey
->rdata
;
2273 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, resultKey
->rdlength
);
2275 LogDNSSEC("FinishDNSSECVerification: RRSIG validated by DNSKEY tag %d, %##s (%s)", tag
, dv
->rrset
->name
.c
,
2276 DNSTypeName(dv
->rrset
->rrtype
));
2278 if (TrustedKey(m
, dv
) == mStatus_NoError
)
2280 // Need to call this after we called TrustedKey, as AuthChainAdd
2281 // unlinks the resultKey and resultRRSig
2282 if (!AuthChainAdd(dv
, resultKey
, resultRRSig
))
2284 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
2287 // The callback will be called when NSEC verification is done.
2288 if ((dv
->flags
& WILDCARD_PROVES_ANSWER_EXPANDED
))
2290 WildcardAnswerProof(m
, dv
);
2295 dv
->DVCallback(m
, dv
, DNSSEC_Secure
);
2299 if (!ValidateDS(dv
))
2301 // Need to call this after we called ValidateDS, as AuthChainAdd
2302 // unlinks the resultKey and resultRRSig
2303 if (!AuthChainAdd(dv
, resultKey
, resultRRSig
))
2305 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
2308 FreeDNSSECVerifierRRSets(dv
);
2310 if (dv
->recursed
< MAX_RECURSE_COUNT
)
2312 LogDNSSEC("FinishDNSSECVerification: Recursion level %d for %##s (%s)", dv
->recursed
, dv
->origName
.c
,
2313 DNSTypeName(dv
->origType
));
2314 VerifySignature(m
, dv
, &dv
->q
);
2320 LogDNSSEC("FinishDNSSECVerification: ValidateDS failed %##s (%s)", dv
->rrset
->name
.c
, DNSTypeName(dv
->rrset
->rrtype
));
2321 dv
->DVCallback(m
, dv
, DNSSEC_Insecure
);
2327 LogDNSSEC("FinishDNSSECVerification: Could not validate the rrset %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
2328 dv
->DVCallback(m
, dv
, DNSSEC_Insecure
);
2333 mDNSexport
void StartDNSSECVerification(mDNS
*const m
, DNSSECVerifier
*dv
)
2337 done
= GetAllRRSetsForVerification(m
, dv
);
2340 if (dv
->next
!= RRVS_done
)
2341 LogMsg("StartDNSSECVerification: ERROR!! dv->next is not done");
2343 LogDNSSEC("StartDNSSECVerification: all rdata sets available for sig verification");
2344 FinishDNSSECVerification(m
, dv
);
2347 else debugdnssec("StartDNSSECVerification: all rdata sets not available for sig verification next %d", dv
->next
);
2350 mDNSlocal
char *DNSSECStatusName(DNSSECStatus status
)
2354 case DNSSEC_Secure
: return "Secure";
2355 case DNSSEC_Insecure
: return "Insecure";
2356 case DNSSEC_Indeterminate
: return "Indeterminate";
2357 case DNSSEC_Bogus
: return "Bogus";
2358 default: return "Invalid";
2362 // We could not use GenerateNegativeResponse as it assumes m->CurrentQuestion to be set. Even if
2363 // we change that, we needs to fix its callers and so on. It is much simpler to call the callback.
2364 mDNSlocal
void DeliverDNSSECStatus(mDNS
*const m
, ResourceRecord
*answer
, DNSSECStatus status
)
2367 // Can't use m->CurrentQuestion as it may already be in use
2368 if (m
->ValidationQuestion
)
2369 LogMsg("DeliverDNSSECStatus: ERROR!! m->ValidationQuestion already set: %##s (%s)",
2370 m
->ValidationQuestion
->qname
.c
, DNSTypeName(m
->ValidationQuestion
->qtype
));
2372 m
->ValidationQuestion
= m
->Questions
;
2373 while (m
->ValidationQuestion
&& m
->ValidationQuestion
!= m
->NewQuestions
)
2375 DNSQuestion
*q
= m
->ValidationQuestion
;
2377 if (q
->ValidatingResponse
|| !q
->ValidationRequired
||
2378 (q
->ValidationState
!= DNSSECValInProgress
) || !ResourceRecordAnswersQuestion(answer
, q
))
2380 m
->ValidationQuestion
= q
->next
;
2384 q
->ValidationState
= DNSSECValDone
;
2385 q
->ValidationStatus
= status
;
2387 MakeNegativeCacheRecord(m
, &largerec
.r
, &q
->qname
, q
->qnamehash
, q
->qtype
, q
->qclass
, 60, mDNSInterface_Any
, mDNSNULL
);
2388 if (q
->qtype
== answer
->rrtype
|| status
!= DNSSEC_Secure
)
2390 LogDNSSEC("DeliverDNSSECStatus: Generating dnssec status %s for %##s (%s)", DNSSECStatusName(status
),
2391 q
->qname
.c
, DNSTypeName(q
->qtype
));
2392 if (q
->QuestionCallback
) q
->QuestionCallback(m
, q
, &largerec
.r
.resrec
, QC_dnssec
);
2396 LogDNSSEC("DeliverDNSSECStatus: Following CNAME dnssec status %s for %##s (%s)", DNSSECStatusName(status
),
2397 q
->qname
.c
, DNSTypeName(q
->qtype
));
2399 AnswerQuestionByFollowingCNAME(m
, q
, answer
);
2403 if (m
->ValidationQuestion
== q
) // If m->ValidationQuestion was not auto-advanced, do it ourselves now
2404 m
->ValidationQuestion
= q
->next
;
2406 m
->ValidationQuestion
= mDNSNULL
;
2409 mDNSlocal
void DNSSECPositiveValidationCB(mDNS
*const m
, DNSSECVerifier
*dv
, DNSSECStatus status
)
2415 mDNSu32 slot
, namehash
;
2416 mDNSu16 rrtype
, rrclass
;
2417 CacheRecord
*const lrr
= &largerec
.r
;
2418 ResourceRecord
*answer
= mDNSNULL
;
2420 LogDNSSEC("DNSSECPositiveValidationCB: called status %s", DNSSECStatusName(status
));
2423 // 1. Check to see if the rrset that was validated is the same as in cache. If they are not same,
2424 // this validation result is not valid. When the rrset changed while the validation was in
2425 // progress, the act of delivering the changed rrset again should have kicked off another
2428 // 2. Walk the question list to find the matching question. The original question that started
2429 // the DNSSEC verification may or may not be there. As long as there is a matching question
2430 // and waiting for the response, deliver the response.
2432 // 3. If we are answering with CNAME, it is time to follow the CNAME if the response is secure
2434 slot
= HashSlot(&dv
->origName
);
2435 namehash
= DomainNameHashValue(&dv
->origName
);
2437 cg
= CacheGroupForName(m
, (const mDNSu32
)slot
, namehash
, &dv
->origName
);
2440 LogDNSSEC("DNSSECPositiveValidationCB: cg NULL for %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
2445 // If we don't have the AuthChain, it means we could not validate the rrset. Locate the
2446 // original question based on dv->origName, dv->origType.
2447 InitializeQuestion(m
, &dv
->q
, dv
->InterfaceID
, &dv
->origName
, dv
->origType
, mDNSNULL
, mDNSNULL
);
2448 // Need to be reset ValidatingResponse as we are looking for the cache record that would answer
2449 // the original question
2450 dv
->q
.ValidatingResponse
= mDNSfalse
;
2451 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
2453 if (SameNameRecordAnswersQuestion(&cr
->resrec
, &dv
->q
))
2455 answer
= &cr
->resrec
;
2464 LogMsg("DNSSECPositiveValidationCB: ERROR!! Validated RRSET NULL");
2468 rrset
= dv
->ac
->rrset
;
2469 rrtype
= rrset
->rrtype
;
2470 rrclass
= rrset
->rrclass
;
2472 lrr
->resrec
.name
= &largerec
.namestorage
;
2474 for (rv
= dv
->ac
->rrset
; rv
; rv
= rv
->next
)
2477 // Check to see if we can find all the elements in the rrset
2478 for (cr
= cg
? cg
->members
: mDNSNULL
; cr
; cr
= cr
->next
)
2480 if (cr
->resrec
.rrtype
== rrtype
&& cr
->resrec
.rrclass
== rrclass
)
2482 for (rv
= dv
->ac
->rrset
; rv
; rv
= rv
->next
)
2484 if (rv
->rdlength
== cr
->resrec
.rdlength
&& rv
->rdatahash
== cr
->resrec
.rdatahash
)
2486 lrr
->resrec
.namehash
= rv
->namehash
;
2487 lrr
->resrec
.rrtype
= rv
->rrtype
;
2488 lrr
->resrec
.rrclass
= rv
->rrclass
;
2489 lrr
->resrec
.rdata
= (RData
*)&lrr
->smallrdatastorage
;
2490 lrr
->resrec
.rdata
->MaxRDLength
= MaximumRDSize
;
2492 // Convert the "rdata" to a suitable form before we can call SameRDataBody which expects
2493 // some of the resource records in host order and also domainnames fully expanded. We
2494 // converted the resource records into network order for verification purpose and hence
2495 // need to convert them back again before comparing them.
2496 if (!SetRData(mDNSNULL
, rv
->rdata
, rv
->rdata
+ rv
->rdlength
, &largerec
, rv
->rdlength
))
2498 LogMsg("DNSSECPositiveValidationCB: SetRData failed for %##s (%s)", rv
->name
.c
, DNSTypeName(rv
->rrtype
));
2500 else if (SameRDataBody(&cr
->resrec
, &lrr
->resrec
.rdata
->u
, SameDomainName
))
2502 answer
= &cr
->resrec
;
2510 // The validated rrset does not have the element in the cache, re-validate
2511 LogDNSSEC("DNSSECPositiveValidationCB: CacheRecord %s, not found in the validated set", CRDisplayString(m
, cr
));
2516 // Check to see if we have elements that were not in the cache
2517 for (rv
= dv
->ac
->rrset
; rv
; rv
= rv
->next
)
2521 // We had more elements in the validated set, re-validate
2522 LogDNSSEC("DNSSECPositiveValidationCB: Record %##s (%s) not found in the cache", rv
->name
.c
, DNSTypeName(rv
->rrtype
));
2528 // It is not an error for things to disappear underneath
2531 LogDNSSEC("DNSSECPositiveValidationCB: answer NULL");
2535 DeliverDNSSECStatus(m
, answer
, status
);
2536 SetTTLRRSet(m
, dv
, status
);
2539 FreeDNSSECVerifier(m
, dv
);
2542 mDNSlocal
void DNSSECNegativeValidationCB(mDNS
*const m
, DNSSECVerifier
*dv
, DNSSECStatus status
)
2547 mDNSu32 slot
, namehash
;
2548 mDNSu16 rrtype
, rrclass
;
2549 ResourceRecord
*answer
= mDNSNULL
;
2552 LogDNSSEC("DNSSECNegativeValidationCB: called %s", DNSSECStatusName(status
));
2554 // 1. Locate the negative cache record and check the cached NSEC records to see if it matches the
2555 // NSECs that were valiated. If the cached NSECS changed while the validation was in progress,
2556 // we ignore the validation results.
2558 // 2. Walk the question list to find the matching question. The original question that started
2559 // the DNSSEC verification may or may not be there. As long as there is a matching question
2560 // and waiting for the response, deliver the response.
2562 slot
= HashSlot(&dv
->origName
);
2563 namehash
= DomainNameHashValue(&dv
->origName
);
2565 cg
= CacheGroupForName(m
, (const mDNSu32
)slot
, namehash
, &dv
->origName
);
2568 LogDNSSEC("DNSSECNegativeValidationCB: cg NULL for %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
2573 // If we don't have the AuthChain, it means we could not validate the rrset. Locate the
2574 // original question based on dv->origName, dv->origType.
2575 InitializeQuestion(m
, &dv
->q
, dv
->InterfaceID
, &dv
->origName
, dv
->origType
, mDNSNULL
, mDNSNULL
);
2576 // Need to be reset ValidatingResponse as we are looking for the cache record that would answer
2577 // the original question
2578 dv
->q
.ValidatingResponse
= mDNSfalse
;
2579 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
2581 if (SameNameRecordAnswersQuestion(&cr
->resrec
, &dv
->q
))
2583 answer
= &cr
->resrec
;
2592 LogMsg("DNSSECNegativeValidationCB: ERROR!! Validated RRSET NULL");
2596 rrtype
= dv
->origType
;
2597 rrclass
= dv
->ac
->rrset
->rrclass
;
2599 for (ac
= dv
->ac
; ac
; ac
= ac
->next
)
2601 for (rv
= ac
->rrset
; rv
; rv
= rv
->next
)
2603 if (rv
->rrtype
== kDNSType_NSEC
)
2608 // Check to see if we can find all the elements in the rrset
2609 for (cr
= cg
->members
; cr
; cr
= cr
->next
)
2611 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
&&
2612 cr
->resrec
.rrtype
== rrtype
&& cr
->resrec
.rrclass
== rrclass
)
2615 for (ncr
= cr
->nsec
; ncr
; ncr
= ncr
->next
)
2617 // We have RRSIGs for the NSECs cached there too
2618 if (ncr
->resrec
.rrtype
!= kDNSType_NSEC
)
2620 for (ac
= dv
->ac
; ac
; ac
= ac
->next
)
2622 for (rv
= ac
->rrset
; rv
; rv
= rv
->next
)
2624 if (rv
->rrtype
== kDNSType_NSEC
&& rv
->rdlength
== ncr
->resrec
.rdlength
&&
2625 rv
->rdatahash
== ncr
->resrec
.rdatahash
)
2627 if (SameDomainName(ncr
->resrec
.name
, &rv
->name
) &&
2628 SameRDataBody(&ncr
->resrec
, (const RDataBody
*)rv
->rdata
, SameDomainName
))
2630 LogDNSSEC("DNSSECNegativeValidationCB: setting found %s", CRDisplayString(m
, ncr
));
2631 answer
= &cr
->resrec
;
2643 // The validated rrset does not have the element in the cache, re-validate
2644 LogDNSSEC("DNSSECNegativeValidationCB: CacheRecord %s, not found in the validated set", CRDisplayString(m
, cr
));
2649 // Check to see if we have elements that were not in the cache
2650 for (ac
= dv
->ac
; ac
; ac
= ac
->next
)
2652 for (rv
= ac
->rrset
; rv
; rv
= rv
->next
)
2654 if (rv
->rrtype
== kDNSType_NSEC
)
2658 // We had more elements in the validated set, re-validate
2659 LogDNSSEC("DNSSECNegativeValidationCB: Record %##s (%s) not found in the cache", rv
->name
.c
, DNSTypeName(rv
->rrtype
));
2668 // It is not an error for things to disappear underneath
2671 LogDNSSEC("DNSSECNegativeValidationCB: answer NULL");
2675 DeliverDNSSECStatus(m
, answer
, status
);
2676 SetTTLRRSet(m
, dv
, status
);
2679 FreeDNSSECVerifier(m
, dv
);
2682 mDNSexport
void VerifySignature(mDNS
*const m
, DNSSECVerifier
*dv
, DNSQuestion
*q
)
2684 mDNSu32 slot
= HashSlot(&q
->qname
);
2685 CacheGroup
*const cg
= CacheGroupForName(m
, slot
, q
->qnamehash
, &q
->qname
);
2688 LogDNSSEC("VerifySignature called for %##s (%s)", q
->qname
.c
, DNSTypeName(q
->qtype
));
2691 if (!q
->qDNSServer
|| q
->qDNSServer
->cellIntf
)
2693 LogDNSSEC("VerifySignature: Disabled");
2696 // We assume that the verifier's question has been initialized here so that ValidateWithNSECS below
2697 // knows what it has prove the non-existence of.
2698 dv
= AllocateDNSSECVerifier(m
, &q
->qname
, q
->qtype
, q
->InterfaceID
, DNSSECPositiveValidationCB
, VerifySigCallback
);
2699 if (!dv
) { LogMsg("VerifySignature: ERROR!! memory alloc failed"); return; }
2702 // If we find a CNAME response to the question, remember what qtype
2703 // caused the CNAME response. origType is not sufficient as we
2704 // recursively validate the response and origType is initialized above
2705 // the first time this function is called.
2706 dv
->currQtype
= q
->qtype
;
2708 // Walk the cache and get all the rrsets for verification.
2709 for (rr
= cg
? cg
->members
: mDNSNULL
; rr
; rr
=rr
->next
)
2710 if (SameNameRecordAnswersQuestion(&rr
->resrec
, q
))
2712 // We also get called for RRSIGs which matches qtype. We don't need that here as we are
2713 // building rrset for matching q->qname. Checking for RRSIG type is important as otherwise
2714 // we would miss the CNAME answering any qtype.
2715 if (rr
->resrec
.rrtype
== kDNSType_RRSIG
&& rr
->resrec
.rrtype
!= q
->qtype
)
2717 LogDNSSEC("VerifySignature: Question %##s (%s) answered with RRSIG record %s, not using it", q
->qname
.c
, DNSTypeName(q
->qtype
), CRDisplayString(m
, rr
));
2721 // See DNSSECRecordAnswersQuestion: This should never happen. NSEC records are
2722 // answered directly only when the qtype is NSEC. Otherwise, NSEC records are
2723 // used only for denial of existence and hence should go through negative cache
2725 if (rr
->resrec
.rrtype
== kDNSType_NSEC
&& q
->qtype
!= kDNSType_NSEC
)
2727 LogMsg("VerifySignature: ERROR!! Question %##s (%s) answered using NSEC record %s", q
->qname
.c
, DNSTypeName(q
->qtype
), CRDisplayString(m
, rr
));
2731 // We might get a NSEC response when we first send the query out from the "core" for ValidationRequired
2732 // questions. Later as part of validating the response, we might get a NSEC response.
2733 if (rr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
&& DNSSECQuestion(q
))
2735 dv
->DVCallback
= DNSSECNegativeValidationCB
;
2736 // If we can't find the NSEC, we can't validate. This can happens if we are
2737 // behind a non-DNSSEC aware CPE/server.
2740 LogDNSSEC("VerifySignature: No nsecs found for %s", CRDisplayString(m
, rr
));
2741 dv
->DVCallback(m
, dv
, DNSSEC_Insecure
);
2744 ValidateWithNSECS(m
, dv
, rr
);
2748 if (AddRRSetToVerifier(dv
, &rr
->resrec
, mDNSNULL
, RRVS_rr
) != mStatus_NoError
)
2750 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
2756 LogMsg("VerifySignature: rrset mDNSNULL for %##s (%s)", dv
->origName
.c
, DNSTypeName(dv
->origType
));
2757 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
2760 dv
->next
= RRVS_rrsig
;
2761 StartDNSSECVerification(m
, dv
);
2765 mDNSlocal mDNSBool
TrustedKeyPresent(mDNS
*const m
, DNSSECVerifier
*dv
)
2773 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
2775 // Walk all our trusted DS Records to see if we have a matching DNS KEY record that verifies
2776 // the hash. If we find one, verify that this key was used to sign the KEY rrsets in
2777 // this zone. Loop till we find one.
2778 for (ta
= m
->TrustAnchors
; ta
; ta
= ta
->next
)
2780 ds
= (rdataDS
*)&ta
->rds
;
2781 if ((ds
->digestType
!= SHA1_DIGEST_TYPE
) && (ds
->digestType
!= SHA256_DIGEST_TYPE
))
2783 LogMsg("TrustedKeyPresent: Unsupported digest %d", ds
->digestType
);
2788 debugdnssec("TrustedKeyPresent: digest type %d", ds
->digestType
);
2790 for (keyv
= dv
->key
; keyv
; keyv
= keyv
->next
)
2792 key
= (rdataDNSKey
*)keyv
->rdata
;
2793 mDNSu16 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
);
2794 if (tag
!= ds
->keyTag
)
2796 debugdnssec("TrustedKeyPresent:Not a valid keytag %d", tag
);
2799 if (!SameDomainName(&keyv
->name
, &ta
->zone
))
2801 debugdnssec("TrustedKeyPresent: domainame mismatch key %##s, ta %##s", keyv
->name
.c
, ta
->zone
.c
);
2810 mDNSlocal mStatus
TrustedKey(mDNS
*const m
, DNSSECVerifier
*dv
)
2821 mDNSu32 currTime
= mDNSPlatformUTC();
2823 rrsig
= (rdataRRSig
*)dv
->rrsig
->rdata
;
2825 // Walk all our trusted DS Records to see if we have a matching DNS KEY record that verifies
2826 // the hash. If we find one, verify that this key was used to sign the KEY rrsets in
2827 // this zone. Loop till we find one.
2828 for (ta
= m
->TrustAnchors
; ta
; ta
= ta
->next
)
2830 ds
= (rdataDS
*)&ta
->rds
;
2831 if ((ds
->digestType
!= SHA1_DIGEST_TYPE
) && (ds
->digestType
!= SHA256_DIGEST_TYPE
))
2833 LogMsg("TrustedKey: Unsupported digest %d", ds
->digestType
);
2838 debugdnssec("TrustedKey: Zone %##s, digest type %d, tag %d", ta
->zone
.c
, ds
->digestType
, ds
->keyTag
);
2840 for (keyv
= dv
->key
; keyv
; keyv
= keyv
->next
)
2842 key
= (rdataDNSKey
*)keyv
->rdata
;
2843 mDNSu16 tag
= (mDNSu16
)keytag((mDNSu8
*)key
, keyv
->rdlength
);
2844 if (tag
!= ds
->keyTag
)
2846 debugdnssec("TrustedKey:Not a valid keytag %d", tag
);
2849 if (!SameDomainName(&keyv
->name
, &ta
->zone
))
2851 debugdnssec("TrustedKey: domainame mismatch key %##s, ta %##s", keyv
->name
.c
, ta
->zone
.c
);
2854 if (DNS_SERIAL_LT(ta
->validUntil
, currTime
))
2856 LogDNSSEC("TrustedKey: Expired: currentTime %d, ExpireTime %d", (int)currTime
, ta
->validUntil
);
2859 if (DNS_SERIAL_LT(currTime
, ta
->validFrom
))
2861 LogDNSSEC("TrustedKey: Future: currentTime %d, InceptTime %d", (int)currTime
, ta
->validFrom
);
2865 if (DNSNameToLowerCase((domainname
*)&rrsig
->signerName
, &name
) != mStatus_NoError
)
2867 LogMsg("TrustedKey: ERROR!! cannot convert to lower case");
2871 if (dv
->ctx
) AlgDestroy(dv
->ctx
);
2872 dv
->ctx
= AlgCreate(DIGEST_ALG
, ds
->digestType
);
2875 LogMsg("TrustedKey: ERROR!! No digest support");
2878 digest
= ds
->digest
;
2879 digestLen
= ta
->digestLen
;
2881 AlgAdd(dv
->ctx
, name
.c
, DomainNameLength(&name
));
2882 AlgAdd(dv
->ctx
, key
, keyv
->rdlength
);
2884 algRet
= AlgVerify(dv
->ctx
, mDNSNULL
, 0, digest
, digestLen
);
2885 AlgDestroy(dv
->ctx
);
2887 if (algRet
== mStatus_NoError
)
2889 LogDNSSEC("TrustedKey: DS Validated Successfully, need to verify the key %d", tag
);
2890 // We found the DNS KEY that is authenticated by the DS in our parent zone. Check to see if this key
2891 // was used to sign the DNS KEY RRSET. If so, then the keys in our DNS KEY RRSET are valid
2892 if (ValidateSignatureWithKeyForAllRRSigs(dv
, dv
->key
, keyv
, dv
->rrsigKey
))
2894 LogDNSSEC("TrustedKey: DS Validated Successfully %d", tag
);
2895 return mStatus_NoError
;
2900 return mStatus_NoSuchRecord
;
2903 mDNSlocal CacheRecord
* NegativeCacheRecordForRR(mDNS
*const m
, const ResourceRecord
*const rr
)
2910 slot
= HashSlot(rr
->name
);
2911 namehash
= DomainNameHashValue(rr
->name
);
2912 cg
= CacheGroupForName(m
, slot
, namehash
, rr
->name
);
2915 LogMsg("NegativeCacheRecordForRR: cg null %##s", rr
->name
->c
);
2918 for (cr
=cg
->members
; cr
; cr
=cr
->next
)
2920 if (cr
->resrec
.RecordType
== kDNSRecordTypePacketNegative
&& (&cr
->resrec
== rr
))
2926 mDNSlocal
void VerifySigCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
2928 DNSSECVerifier
*dv
= (DNSSECVerifier
*)question
->QuestionContext
;
2932 debugdnssec("VerifySigCallback: AddRecord %d, dv %p", AddRecord
, dv
);
2934 if (!AddRecord
) return;
2936 LogDNSSEC("VerifySigCallback: Called with record %s", RRDisplayString(m
, answer
));
2939 if ((m
->timenow
- question
->StopTime
) >= 0)
2942 LogDNSSEC("VerifySigCallback: Question %##s (%s) timed out", question
->qname
.c
, DNSTypeName(question
->qtype
));
2943 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
2948 if (answer
->RecordType
== kDNSRecordTypePacketNegative
)
2951 LogDNSSEC("VerifySigCallback: Received a negative answer with record %s, AddRecord %d",
2952 RRDisplayString(m
, answer
), AddRecord
);
2953 cr
= NegativeCacheRecordForRR(m
, answer
);
2956 dv
->DVCallback
= DNSSECNegativeValidationCB
;
2957 ValidateWithNSECS(m
, dv
, cr
);
2961 LogDNSSEC("VerifySigCallback: Missing record (%s) Negative Cache Record %p", RRDisplayString(m
, answer
), cr
);
2962 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
2969 LogMsg("VerifySigCallback: ERROR!! rrset NULL");
2970 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
2974 rrtype
= answer
->rrtype
;
2975 // Check whether we got any answers for the question. If there are no answers, we
2976 // can't do the verification.
2978 // We need to look at the whole rrset for verifying the signatures. This callback gets
2979 // called back for each record in the rrset sequentially and we won't know when to start the
2980 // verification. Hence, we look for all the records in the rrset ourselves using the
2981 // CheckXXX function below. The caller has to ensure that all the records in the rrset are
2982 // added to the cache before calling this callback which happens naturally because all
2983 // unicast records are marked for DelayDelivery and hence added to the cache before the
2984 // callback is done.
2986 // We also need the RRSIGs for the rrset to do the validation. It is possible that the
2987 // cache contains RRSIG records but it may not be a valid record when we filter them
2988 // in CheckXXX function. For example, some application can query for RRSIG records which
2989 // might come back with a partial set of RRSIG records from the recursive server and
2990 // they may not be the right ones for the current validation. In this case, we still
2991 // need to send the query out to get the right RRSIGs but the "core" should not answer
2992 // this query with the same records that we checked and found them to be unusable.
2994 // We handle this in two ways:
2996 // 1) AnswerNewQuestion always sends the "ValidatingResponse" query out bypassing the cache.
2998 // 2) DNSSECRecordAnswersQuestion does not answer a question with RRSIGs matching the
2999 // same name as the query until the typeCovered also matches the query's type.
3001 // NOTE: We use "next - 1" as next always points to what we are going to fetch next and not the one
3002 // we are fetching currently
3003 switch(dv
->next
- 1)
3006 // Verification always starts at RRVS_rrsig (which means dv->next points at RRVS_key) as verification does
3007 // not begin until we have the main rrset.
3008 LogDNSSEC("VerifySigCallback: ERROR!! rrset %##s dv->next is RRVS_rr", dv
->rrset
->name
.c
);
3011 // We can get called back with rrtype matching qtype as new records are added to the cache
3012 // triggered by other questions. This could potentially mean that the rrset that is being
3013 // validated by this "dv" whose rrsets were initialized at the beginning of the verification
3014 // may not be the right one. If this case happens, we will detect this at the end of validation
3015 // and throw away the validation results. This should not be a common case.
3016 if (rrtype
!= kDNSType_RRSIG
)
3018 LogDNSSEC("VerifySigCallback: RRVS_rrsig called with %s", RRDisplayString(m
, answer
));
3021 if (CheckRRSIGForRRSet(m
, dv
, &negcr
) != mStatus_NoError
)
3023 LogDNSSEC("VerifySigCallback: Unable to find RRSIG for %##s (%s), question %##s", dv
->rrset
->name
.c
,
3024 DNSTypeName(dv
->rrset
->rrtype
), question
->qname
.c
);
3025 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3030 // We are waiting for the DNSKEY record and hence dv->key should be NULL. If RRSIGs are being
3031 // returned first, ignore them for now.
3033 LogDNSSEC("VerifySigCallback: ERROR!! RRVS_key dv->key non-NULL for %##s", question
->qname
.c
);
3034 if (rrtype
== kDNSType_RRSIG
)
3036 LogDNSSEC("VerifySigCallback: RRVS_key rrset type %s, %##s received before DNSKEY", DNSTypeName(rrtype
), question
->qname
.c
);
3039 if (rrtype
!= question
->qtype
)
3041 LogDNSSEC("VerifySigCallback: ERROR!! RRVS_key rrset type %s, %##s not matching qtype %d", DNSTypeName(rrtype
), question
->qname
.c
,
3045 if (CheckKeyForRRSIG(m
, dv
, &negcr
) != mStatus_NoError
)
3047 LogDNSSEC("VerifySigCallback: Unable to find DNSKEY for %##s (%s), question %##s", dv
->rrset
->name
.c
,
3048 DNSTypeName(dv
->rrset
->rrtype
), question
->qname
.c
);
3049 dv
->DVCallback(m
, dv
, DNSSEC_Indeterminate
);
3053 case RRVS_rrsig_key
:
3054 // If we are in RRVS_rrsig_key, it means that we already found the relevant DNSKEYs (dv->key should be non-NULL).
3055 // If DNSKEY record is being returned i.e., it means it is being added to the cache, then it can't be in our
3058 LogDNSSEC("VerifySigCallback: ERROR!! RRVS_rrsig_key dv->key NULL for %##s", question
->qname
.c
);
3059 if (rrtype
== question
->qtype
)
3061 LogDNSSEC("VerifySigCallback: RRVS_rrsig_key rrset type %s, %##s", DNSTypeName(rrtype
), question
->qname
.c
);
3062 CheckOneKeyForRRSIG(dv
, answer
);
3065 if (rrtype
!= kDNSType_RRSIG
)
3067 LogDNSSEC("VerifySigCallback: RRVS_rrsig_key rrset type %s, %##s not matching qtype %d", DNSTypeName(rrtype
), question
->qname
.c
,
3071 if (CheckRRSIGForKey(m
, dv
, &negcr
) != mStatus_NoError
)
3073 LogDNSSEC("VerifySigCallback: Unable to find RRSIG for %##s (%s), question %##s", dv
->rrset
->name
.c
,
3074 DNSTypeName(dv
->rrset
->rrtype
), question
->qname
.c
);
3075 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3080 if (rrtype
== question
->qtype
)
3082 LogDNSSEC("VerifySigCallback: RRVS_ds rrset type %s, %##s", DNSTypeName(rrtype
), question
->qname
.c
);
3086 LogDNSSEC("VerifySigCallback: RRVS_ds rrset type %s, %##s received before DS", DNSTypeName(rrtype
), question
->qname
.c
);
3088 // It is not an error if we don't find the DS record as we could have
3089 // a trusted key. Or this is not a secure delegation which will be handled
3091 if (CheckDSForKey(m
, dv
, &negcr
) != mStatus_NoError
)
3093 LogDNSSEC("VerifySigCallback: Unable find DS for %##s (%s), question %##s", dv
->rrset
->name
.c
,
3094 DNSTypeName(dv
->rrset
->rrtype
), question
->qname
.c
);
3096 // dv->next is already at RRVS_done, so if we "break" from here, we will end up
3097 // in FinishDNSSECVerification. We should not do that if we receive a negative
3098 // response. For all other cases above, GetAllRRSetsForVerification handles
3099 // negative cache record
3104 LogDNSSEC("VerifySigCallback: No nsec records for %##s (DS)", dv
->ds
->name
.c
);
3105 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3108 dv
->DVCallback
= DNSSECNegativeValidationCB
;
3109 ValidateWithNSECS(m
, dv
, negcr
);
3114 LogDNSSEC("VerifySigCallback: ERROR!! default case rrset %##s question %##s", dv
->rrset
->name
.c
, question
->qname
.c
);
3115 dv
->DVCallback(m
, dv
, DNSSEC_Bogus
);
3118 if (dv
->next
!= RRVS_done
)
3120 mDNSBool done
= GetAllRRSetsForVerification(m
, dv
);
3123 if (dv
->next
!= RRVS_done
)
3124 LogMsg("VerifySigCallback ERROR!! dv->next is not done");
3126 LogDNSSEC("VerifySigCallback: all rdata sets available for sig verification");
3130 LogDNSSEC("VerifySigCallback: all rdata sets not available for sig verification");
3134 FinishDNSSECVerification(m
, dv
);