2 // dnssec_v2_validation.c
5 // Copyright (c) 2020 Apple Inc. All rights reserved.
8 #include "mDNSEmbeddedAPI.h"
9 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
10 #include <string.h> // for strerror
11 #include <errno.h> // for errno
12 #include "DNSCommon.h" // DomainNameHashValue
13 #include "dnssec_v2_structs.h"
14 #include "dnssec_v2_validation.h"
15 #include "dnssec_v2_retrieval.h"
16 #include "dnssec_v2_crypto.h"
17 #include "dnssec_v2_trust_anchor.h"
18 #include "dnssec_v2_log.h"
19 #include "dnssec_v2_helper.h"
22 //======================================================================================================================
24 //======================================================================================================================
26 #define NSEC3_FLAG_OPT_OUT_BIT 1
27 #define NSEC3_FLAG_SET NSEC3_FLAG_OPT_OUT_BIT
29 //======================================================================================================================
30 // MARK: - validator type define
31 //======================================================================================================================
32 typedef struct dnssec_validator_node dnssec_validator_node_t
;
33 struct dnssec_validator_node
{
36 response_type_t rr_response_type
;
39 const dnssec_dnskey_t
* _Nullable key
;
40 const dnssec_rrsig_t
* _Nullable sig
;
43 const dnssec_dnskey_t
* _Nullable key
;
44 const dnssec_rrsig_t
* _Nullable sig
;
45 const dnssec_ds_t
* _Nullable ds
;
48 const dnssec_nsec_t
* _Nullable nsec
;
51 const dnssec_nsec3_t
* _Nullable nsec3
;
54 dnssec_validator_node_type_t type
;
55 const mDNSu8
* _Nonnull name
;
56 // type: resource_records, list_t<dnssec_original_t>; type: zone_signing_key, list<dnssec_dnskey_t>; type: key_signing_key, list<dnssec_dnskey_t>;
57 // type: nsec, list_t<one_nsec_with_rrsigs>; type: nsec3, list_t<one_nsec3_wtih_rrsigs>
58 const list_t
* _Nullable siblings
;
59 const list_t
* _Nonnull rrssigs_covering_it
;
63 //======================================================================================================================
64 // MARK: - local functions prototype
65 //======================================================================================================================
68 // MARK: NSEC validation
70 mDNSlocal dnssec_validation_result_t
71 validate_nsec_response(
72 const mDNSu32 qname_hash
,
73 const mDNSu8
* const _Nonnull qname
,
76 const nsecs_with_rrsig_t
* const _Nonnull nsecs_with_rrsig
,
77 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_1
,
78 const list_t
* _Nullable
* _Nonnull out_rrsigs_1
,
79 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_2
,
80 const list_t
* _Nullable
* _Nonnull out_rrsigs_2
);
84 const mDNSu32 qname_hash
,
85 const mDNSu8
* const _Nonnull qname
,
88 const list_t
* const _Nonnull nsecs
,
89 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_data
,
90 const list_t
* _Nullable
* _Nonnull out_rrsigs
);
93 nsec_proves_name_error(
94 const mDNSu8
* const _Nonnull qname
,
95 const list_t
* const _Nonnull nsecs
,
96 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_exact_match
,
97 const list_t
* _Nullable
* _Nonnull out_rrsigs_no_exact_match
,
98 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_wildcard
,
99 const list_t
* _Nullable
* _Nonnull out_rrsigs_no_wildcard
);
102 nsec_proves_wildcard_answer(
103 const mDNSu8
* const _Nonnull qname
,
105 const list_t
* const _Nonnull nsecs
,
106 const list_t
* const _Nonnull wildcard_answer
,
107 const list_t
* const _Nonnull wildcard_rrsig
,
108 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_exact_match
,
109 const list_t
* _Nullable
* _Nonnull out_rrsigs_no_exact_match
);
112 nsec_proves_wildcard_no_data(
113 const mDNSu8
* const _Nonnull qname
,
114 const mDNSu16 qclass
,
116 const list_t
* const _Nonnull nsecs
,
117 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_exact_match
,
118 const list_t
* _Nullable
* _Nonnull out_rrsigs_no_exact_match
,
119 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_matching_stype
,
120 const list_t
* _Nullable
* _Nonnull out_rrsigs_no_matching_stype
);
122 // MARK: NSEC3 validation
125 is_nsec3_iteration_valid(const dnssec_context_t
* const context
);
128 get_maximum_nsec3_iteration_for_dnskey_length(mDNSu16 key_length
);
130 mDNSlocal dnssec_validation_result_t
131 get_initial_children_to_validate(
132 dnssec_context_t
* const _Nonnull context
,
133 dnssec_validator_node_t
* const _Nonnull child
,
134 mDNSu8
* const _Nonnull out_child_size
);
136 mDNSlocal dnssec_validation_result_t
137 validate_nsec3_response(
138 const mDNSu8
* const _Nonnull qname
,
140 const nsec3s_with_rrsig_t
* const _Nonnull nsec3s_with_rrsig
,
141 const dnssec_nsec3_t
* _Nullable
* _Nonnull out_nsec3_1
,
142 const list_t
* _Nullable
* _Nonnull out_rrsig_1
,
143 const dnssec_nsec3_t
* _Nullable
* _Nonnull out_nsec3_2
,
144 const list_t
* _Nullable
* _Nonnull out_rrsig_2
,
145 const dnssec_nsec3_t
* _Nullable
* _Nonnull out_nsec3_3
,
146 const list_t
* _Nullable
* _Nonnull out_rrsig_3
);
148 mDNSlocal dnssec_validation_result_t
149 nsec3_proves_closest_encloser(
150 const mDNSu8
* const _Nonnull name
,
151 const list_t
* const _Nonnull nsec3s
,
152 const mDNSu8
* const _Nonnull zone_name
,
153 mDNSu8 canonical_name
[MAX_DOMAIN_NAME
],
154 const dnssec_nsec3_t
* _Nullable
* const _Nonnull out_nsec3_closest_encloser_proof
,
155 const list_t
* _Nullable
* const _Nonnull out_rrsig_closest_encloser_proof
,
156 const dnssec_nsec3_t
* _Nullable
* const _Nonnull out_nsec3_next_closer_proof
,
157 const list_t
* _Nullable
* const _Nonnull out_rrsig_next_closer_proof
,
158 const mDNSu8
* _Nullable
* const _Nonnull out_closest_encloser_name
,
159 const mDNSu8
* _Nullable
* const _Nonnull out_next_closer_name
);
162 nsec3_contains_different_hash_iteration_salt(const list_t
* const nsec3s
);
165 ignore_this_nsec3_record(const dnssec_nsec3_t
* const _Nonnull dnssec_nsec3
);
167 // MARK: NSEC/NSEC3 helper function
170 bit_map_contain_dns_type(const mDNSu8
* const _Nonnull bit_maps
, const mDNSu16 bit_maps_length
, const mDNSu16 type
);
172 // MARK: validator initializer
175 initialize_validator_node_with_rr(
176 dnssec_validator_node_t
* const _Nonnull node
,
177 const mDNSu8
* const _Nonnull name
,
178 const list_t
* const _Nonnull siblings
,
179 const list_t
* const _Nonnull rrsigs_covering_it
, // list_t<dnssec_rrsig_t>
180 response_type_t response_type
); // list_t<dnssec_rrsig_t>
183 initialize_validator_node_with_nsec(
184 dnssec_validator_node_t
* const _Nonnull node
,
185 const dnssec_nsec_t
* _Nullable nsec
,
186 const mDNSu8
* const _Nonnull name
,
187 const list_t
* const _Nonnull rrsig_covering_it
); // list_t<dnssec_rrsig_t>
190 initialize_validator_node_with_nsec3(
191 dnssec_validator_node_t
* const _Nonnull node
,
192 const dnssec_nsec3_t
* _Nullable nsec3
,
193 const mDNSu8
* const _Nonnull name
,
194 const list_t
* const _Nonnull rrsig_covering_it
); // list_t<dnssec_rrsig_t>
197 initialize_validator_node_with_zsk(
198 dnssec_validator_node_t
* const _Nonnull node
,
199 const dnssec_dnskey_t
* const _Nonnull key
,
200 const dnssec_rrsig_t
* const _Nonnull sig
,
201 const mDNSu8
* const _Nonnull name
,
202 const list_t
* const _Nonnull siblings
, // list<dnssec_dnskey_t>
203 const list_t
* const _Nonnull rrsig_covering_it
, // list_t<dnssec_rrsig_t>
207 initialize_validator_node_with_ksk(
208 dnssec_validator_node_t
* const _Nonnull node
,
209 const dnssec_dnskey_t
* const _Nonnull key
,
210 const dnssec_rrsig_t
* const _Nonnull sig
,
211 const dnssec_ds_t
* const _Nullable ds
,
212 const mDNSu8
* const _Nonnull name
,
213 const list_t
* const _Nonnull siblings
, // list<dnssec_ds_t>
214 const list_t
* const _Nonnull rrsig_covering_it
, // list_t<dnssec_rrsig_t>
218 uninitialize_validator_node(dnssec_validator_node_t
* const _Nonnull node
);
220 // MARK: validation function
222 mDNSlocal dnssec_validation_result_t
223 build_trust_from_ksk_to_zsk(
224 const mDNSu32 request_id
,
225 const dnssec_zone_t
* const _Nonnull zone
,
226 const list_t
* const _Nonnull dnskeys
,
227 const list_t
* const _Nonnull dses
,
228 const list_t
* const _Nonnull rrsigs_covering_dnskey
,
229 dnssec_validator_node_t
* _Nonnull children
,
230 const mDNSu8 child_size
,
231 dnssec_validator_node_t
* _Nonnull parents
,
232 mDNSu8
* const _Nonnull out_parent_size
);
234 mDNSlocal dnssec_validation_result_t
235 build_trust_from_zsk(
236 const mDNSu32 request_id
,
237 const dnssec_zone_t
* const _Nonnull zone
,
238 const list_t
* const _Nonnull dnskey_list
,
239 const list_t
* const _Nonnull rrsig_list_covering_dnskey
,
240 dnssec_validator_node_t
* _Nonnull children
,
241 const mDNSu8 child_size
,
242 dnssec_validator_node_t
* _Nonnull parents
,
243 mDNSu8
* const _Nonnull out_parent_size
);
245 mDNSlocal dnssec_validation_result_t
246 validate_validator_node(const dnssec_validator_node_t
* const _Nonnull nodes
, const mDNSu8 nodes_count
);
248 mDNSlocal dnssec_validation_result_t
249 validate_validator_path_between_parents_and_children(
250 const mDNSu32 request_id
,
251 dnssec_validator_node_t
* _Nonnull children
,
252 dnssec_validator_node_t
* _Nonnull parents
,
253 mDNSu8
* const _Nonnull out_parent_size
);
255 mDNSlocal dnssec_validation_result_t
256 validate_validator_path(
257 const mDNSu32 request_id
,
258 const dnssec_validator_node_t
* const _Nonnull child
,
259 const dnssec_validator_node_t
* const _Nonnull parent
);
261 mDNSlocal dnssec_validation_result_t
262 check_trust_validator_node(const dnssec_validator_node_t
* const _Nonnull node
);
265 dedup_validator_with_the_same_siblings(
266 dnssec_validator_node_t
* _Nonnull parents
,
267 mDNSu8
* const _Nonnull out_parent_size
);
270 print_ds_validation_progress(const dnssec_validator_node_t
* const _Nonnull nodes
, const mDNSu8 nodes_count
);
272 mDNSlocal dnssec_validation_result_t
273 validate_zone_records_type(const dnssec_zone_t
* const _Nonnull zone
);
275 mDNSlocal dnssec_validation_result_t
276 validate_ds(const dnssec_ds_t
* const _Nonnull ds
);
278 mDNSlocal dnssec_validation_result_t
279 validate_dnskey(const dnssec_dnskey_t
* const _Nonnull dnskey
, mDNSBool security_entry_point
);
281 mDNSlocal dnssec_validation_result_t
282 validate_rrsig(const dnssec_rrsig_t
* const _Nonnull rrsig
);
284 mDNSlocal dnssec_validation_result_t
285 validate_nsec(const dnssec_nsec_t
* const _Nonnull nsec
);
287 mDNSlocal dnssec_validation_result_t
288 validate_nsec3(const dnssec_nsec3_t
* const _Nonnull nsec3
);
290 mDNSlocal dnssec_validation_result_t
291 check_if_ds_ksk_matches(const dnssec_ds_t
* const _Nonnull ds
, const dnssec_dnskey_t
* const _Nonnull ksk
);
293 mDNSlocal dnssec_validation_result_t
294 validate_path_from_zsk_to_rr(
295 const mDNSu32 request_id
,
296 const dnssec_validator_node_t
* const _Nonnull parent
,
297 const list_t
* const _Nonnull originals
/* list_t<dnssec_original_t> */,
298 response_type_t response_type
);
300 mDNSlocal dnssec_validation_result_t
301 validate_path_from_ksk_to_zsk(
302 const mDNSu32 request_id
,
303 const dnssec_validator_node_t
* const _Nonnull parent
,
304 const list_t
* const _Nonnull zsks
/* list_t<dnssec_dnskey_t> */);
306 mDNSlocal dnssec_validation_result_t
307 validate_path_from_zsk_to_ds(
308 const mDNSu32 request_id
,
309 const dnssec_validator_node_t
* const _Nonnull parent
,
310 const list_t
* const _Nonnull dses
/* list_t<dnssec_dses_t> */);
312 mDNSlocal dnssec_validation_result_t
313 validate_path_from_zsk_to_nsec(
314 const mDNSu32 request_id
,
315 const dnssec_validator_node_t
* const _Nonnull parent
,
316 const dnssec_validator_node_t
* const _Nonnull child
);
318 mDNSlocal dnssec_validation_result_t
319 validate_path_from_zsk_to_nsec3(
320 const mDNSu32 request_id
,
321 const dnssec_validator_node_t
* const _Nonnull parent
,
322 const dnssec_validator_node_t
* const _Nonnull child
);
324 mDNSlocal dnssec_validation_result_t
325 check_rrsig_validity_with_dnssec_rr(
326 const dnssec_rrsig_t
* const _Nonnull rrsig
,
327 const dnssec_rr_t
* const _Nonnull rr
);
329 mDNSlocal dnssec_validation_result_t
330 check_rrsig_validity_with_rrs(
331 const dnssec_rrsig_t
* const _Nonnull rrsig
,
332 const list_t
* const _Nonnull list_to_check
,
333 response_type_t response_type_in_list
,
334 const mDNSu16 record_type_in_list
);
336 // MARK: reconstruct signed data
339 reconstruct_signed_data_with_rrs(
340 const list_t
* const _Nonnull rr_set
,
341 const dnssec_rrsig_t
* const _Nonnull dnssec_rrsig
,
342 const response_type_t response_type
,
343 const mDNSu16 record_type
,
344 mDNSu32
* const _Nonnull out_signed_data_length
);
347 reconstruct_signed_data_with_one_dnssec_rr(
348 const dnssec_rr_t
* const _Nonnull dnssec_rr
,
349 const dnssec_rrsig_t
* const _Nonnull dnssec_rrsig
,
350 mDNSu32
* const _Nonnull out_signed_data_length
);
353 reconstruct_signed_data_internal(
354 const dnssec_rr_t
* const rr_array
[],
355 const mDNSu8 rr_count
,
356 const dnssec_rrsig_t
* const _Nonnull dnssec_rrsig
,
357 mDNSu32
* const _Nonnull out_signed_data_length
);
360 calculate_signed_data_length(
361 const dnssec_rr_t
* const rr_array
[_Nonnull
],
362 const mDNSu8 rr_count
,
363 const dnssec_rrsig_t
* const _Nonnull dnssec_rrsig
,
364 mDNSu32
* const _Nonnull out_length
);
367 calculate_name_length_in_signed_data(const mDNSu8
* const _Nonnull name
, const mDNSu8 rrsig_labels
);
370 calculate_rdata_length_in_signed_data(const dnssec_rr_t
* const _Nonnull dnssec_rr
);
372 mDNSlocal
const mDNSu8
*
373 get_wildcard_name(const mDNSu8
* const _Nonnull name
, mDNSu8
* const _Nonnull buffer
, const mDNSu16 buffer_length
);
376 copy_rr_for_signed_data(
377 mDNSu8
* _Nonnull dst
,
378 const dnssec_rr_t
* const _Nonnull rr
,
379 const dnssec_rrsig_t
* const _Nonnull rrsig
);
382 copy_name_in_rr_for_signed_data(
383 mDNSu8
* const _Nonnull dst
,
384 const mDNSu8
* const _Nonnull name
,
385 const dnssec_rrsig_t
* const _Nonnull dnssec_rrsig
);
388 copy_rdata_in_rr(mDNSu8
* const _Nonnull dst
, const mDNSu8
* const rdata
, const mDNSu16 rdata_length
, const mDNSu8 rr_type
);
390 // MARK: sort function
393 sort_records_with_algorithm(dnssec_context_t
* const _Nonnull context
);
396 dnssec_ds_t_comparator(const list_node_t
* _Nonnull
const left
, const list_node_t
* _Nonnull
const right
);
399 dnssec_rrsig_t_comparator(const list_node_t
* _Nonnull
const left
, const list_node_t
* _Nonnull
const right
);
402 sort_rr_array_canonically(const dnssec_rr_t
* rr_array
[_Nonnull
], const mDNSu8 rr_count
);
405 dnssec_rr_t_comparator(const dnssec_rr_t
* const _Nonnull left
, const dnssec_rr_t
* const _Nonnull right
);
408 rr_array_dedup(const dnssec_rr_t
* rr_array
[_Nonnull
], const mDNSu8 rr_count
);
411 //======================================================================================================================
412 // MARK: - function definations
413 //======================================================================================================================
416 // MARK: validate_dnssec
418 mDNSexport dnssec_validation_result_t
419 validate_dnssec(dnssec_context_t
* const _Nonnull context
) {
420 dnssec_validator_node_t child_node
[4] = {0}; // 4 is big enough to hold: nsec3_1, nsec3_2, nsec3_3, wildcard
421 dnssec_validator_node_t parent_node
[4] = {0}; // the same reason as the above
422 dnssec_validator_node_t
* child
= child_node
;
423 dnssec_validator_node_t
* parent
= parent_node
;
424 mDNSu8 child_size
= 0;
425 mDNSu8 parent_size
= 0;
426 const mDNSu32 request_id
= context
->original
.original_parameters
.request_id
;
428 dnssec_validator_node_t
* temp_validator
= mDNSNULL
;
429 mDNSu8 temp_size
= 0;
430 dnssec_validation_result_t validation_result
= dnssec_validation_valid
;
431 mDNSBool nsec3_iteration_valid
;
433 nsec3_iteration_valid
= is_nsec3_iteration_valid(context
);
434 require_action_quiet(nsec3_iteration_valid
, exit
, validation_result
= dnssec_validation_nsec3_invalid_hash_iteration
);
436 // sort records with most secure algorithm comes first
437 sort_records_with_algorithm(context
);
439 // get the original records out
440 validation_result
= get_initial_children_to_validate(context
, child
, &child_size
);
441 require_quiet(validation_result
== dnssec_validation_valid
&& child_size
!= 0, exit
);
443 // check if the original RRSET is valid
444 validation_result
= validate_validator_node(child
, child_size
);
445 require_quiet(validation_result
== dnssec_validation_valid
, exit
);
447 // check if the original RRSET is trusted by our trusted anchor, it is only possbile when the user queryies for
448 // DNSKEY record since trust anchor is used to trust DNSKEY
449 validation_result
= check_trust_validator_node(child
);
450 if (validation_result
== dnssec_validation_trusted
) {
454 // Check the validation through the entire chain of trust
455 for (list_node_t
*zone_node
= list_get_first(&context
->zone_chain
);
456 !list_has_ended(&context
->zone_chain
, zone_node
);
457 zone_node
= list_next(zone_node
)) {
459 // check for every zone
460 dnssec_zone_t
* zone
= (dnssec_zone_t
*)zone_node
->data
;
461 list_t
* dnskeys
= &zone
->dnskeys_with_rrsig
.dnskey_records
;
462 list_t
* dnskey_rrsigs
= &zone
->dnskeys_with_rrsig
.rrsig_records
;
463 list_t
* dses
= &zone
->dses_with_rrsig
.u
.original
.ds_records
;
464 list_t
* ds_rrsigs
= &zone
->dses_with_rrsig
.u
.original
.rrsig_records
;
466 // It is possible that some records in the critical path of trust chain is missing(NSEC/NSEC3) or redirected(CNAME)
467 validation_result
= validate_zone_records_type(zone
);
468 require_quiet(validation_result
== dnssec_validation_valid
, exit
);
470 // Validate the previous records(DS or RR) with Zone Signing Key(ZSK)
471 validation_result
= build_trust_from_zsk(request_id
, zone
, dnskeys
, dnskey_rrsigs
, child
, child_size
, parent
, &parent_size
);
473 if (validation_result
!= dnssec_validation_valid
) {
477 if (parent_size
== 0) {
478 validation_result
= dnssec_validation_trusted
;
482 // validate Zone Signing Key(ZSK) with Key Signing Key(KSK)
483 temp_validator
= parent
;
485 child
= temp_validator
;
486 temp_size
= parent_size
;
487 parent_size
= child_size
;
488 child_size
= temp_size
;
489 // TODO: test got NSEC/NSEC3 in the middle
491 validation_result
= build_trust_from_ksk_to_zsk(request_id
, zone
, dnskeys
, dses
, ds_rrsigs
, child
, child_size
, parent
, &parent_size
);
492 if (validation_result
!= dnssec_validation_valid
) {
496 // print_ds_validation_progress(parent, parent_size);
498 if (parent_size
== 0) {
499 validation_result
= dnssec_validation_trusted
;
503 // repeat the validation process until reaching trust anchor
504 temp_validator
= parent
;
506 child
= temp_validator
;
507 temp_size
= parent_size
;
508 parent_size
= child_size
;
509 child_size
= temp_size
;
513 return validation_result
;
516 mDNSlocal dnssec_validation_result_t
517 validate_nsec_response(
518 const mDNSu32 qname_hash
,
519 const mDNSu8
* const _Nonnull qname
,
520 const mDNSu16 qclass
,
522 const nsecs_with_rrsig_t
* const _Nonnull nsecs_with_rrsig
,
523 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_1
,
524 const list_t
* _Nullable
* _Nonnull out_rrsigs_1
,
525 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_2
,
526 const list_t
* _Nullable
* _Nonnull out_rrsigs_2
) {
528 const list_t
* const nsecs
= &nsecs_with_rrsig
->nsec_and_rrsigs_same_name
;
530 // dnssec_validation_nsec_no_data
531 if (nsec_proves_no_data(qname_hash
, qname
, qclass
, qtype
, nsecs
, out_nsec_1
, out_rrsigs_1
)) {
532 return dnssec_validation_nsec_no_data
;
535 // dnssec_validation_nsec_name_error
536 if (nsec_proves_name_error(qname
, nsecs
, out_nsec_1
, out_rrsigs_1
, out_nsec_2
, out_rrsigs_2
)) {
537 return dnssec_validation_nsec_name_error
;
540 // dnssec_validation_nsec_wildcard_answer
541 if (nsec_proves_wildcard_answer(qname
, qtype
, nsecs
, &nsecs_with_rrsig
->wildcard_answers
, &nsecs_with_rrsig
->wildcard_rrsigs
, out_nsec_1
, out_rrsigs_2
)) {
542 return dnssec_validation_nsec_wildcard_answer
;
545 // dnssec_validation_nsec_wildcard_no_data
546 if (nsec_proves_wildcard_no_data(qname
, qclass
, qtype
, nsecs
, out_nsec_1
, out_rrsigs_1
, out_nsec_2
, out_rrsigs_2
)) {
547 return dnssec_validation_nsec_wildcard_no_data
;
550 return dnssec_validation_nsec_invalid_nsec_result
;
553 // MARK: validate_dnssec
554 // According to https://tools.ietf.org/html/rfc5155#section-10.3 , the iteration field of NSEC3 should have an upper bound
555 // to prevent denial-of-service attacks
557 is_nsec3_iteration_valid(const dnssec_context_t
* const context
) {
558 mDNSBool valid
= mDNStrue
;
559 // check original response
560 const originals_with_rrsig_t
* const originals_with_rrsig
= &context
->original
.original_result_with_rrsig
;
562 if (originals_with_rrsig
->type
== nsec3_response
) {
563 const nsec3s_with_rrsig_t
* const nsec3s_with_rrsig
= &originals_with_rrsig
->u
.nsec3s_with_rrsig
;
564 const list_t
* const nsec3_and_rrsigs_same_name
= &nsec3s_with_rrsig
->nsec3_and_rrsigs_same_name
; // list_t<one_nsec3_with_rrsigs_t>
565 const dnssec_zone_t
* zone_with_dnskey
;
566 const dnskeys_with_rrsig_t
* dnskeys_with_rrsig
;
567 const list_t
* dnskeys
;
569 require_action_quiet(!list_empty(nsec3_and_rrsigs_same_name
), exit
, valid
= mDNSfalse
);
571 require_quiet(!list_empty(&context
->zone_chain
), exit
);
572 zone_with_dnskey
= (dnssec_zone_t
*)list_get_first(&context
->zone_chain
)->data
;
573 dnskeys_with_rrsig
= (dnskeys_with_rrsig_t
*)&zone_with_dnskey
->dnskeys_with_rrsig
;
575 dnskeys
= &dnskeys_with_rrsig
->dnskey_records
;
576 require_action_quiet(!list_empty(dnskeys
), exit
, valid
= mDNSfalse
);
578 for (const list_node_t
*one_nsec3_node
= list_get_first(nsec3_and_rrsigs_same_name
);
579 !list_has_ended(nsec3_and_rrsigs_same_name
, one_nsec3_node
);
580 one_nsec3_node
= list_next(one_nsec3_node
)) {
582 const one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
*)one_nsec3_node
->data
;
583 const list_t
* const rrsigs
= &one_nsec3
->rrsig_records
; // list_t<dnssec_rrsig_t>
584 const mDNSu16 nsec3_iteration
= one_nsec3
->nsec3_record
.iterations
;
586 for (const list_node_t
* rrsig_node
= list_get_first(rrsigs
);
587 !list_has_ended(rrsigs
, rrsig_node
);
588 rrsig_node
= list_next(rrsig_node
)) {
590 const dnssec_rrsig_t
* const dnssec_rrsig
= (dnssec_rrsig_t
*)rrsig_node
->data
;
591 const mDNSu16 key_tag_from_rrsig
= dnssec_rrsig
->key_tag
;
593 for (const list_node_t
* dnskey_node
= list_get_first(dnskeys
);
594 !list_has_ended(dnskeys
, dnskey_node
);
595 dnskey_node
= list_next(dnskey_node
)) {
597 const dnssec_dnskey_t
* const dnssec_dnskey
= (dnssec_dnskey_t
*)dnskey_node
->data
;
598 const mDNSu16 key_tag_from_dnskey
= dnssec_dnskey
->key_tag
;
599 mDNSu16 max_iteration
;
601 if (key_tag_from_rrsig
!= key_tag_from_dnskey
) {
605 max_iteration
= get_maximum_nsec3_iteration_for_dnskey_length(dnssec_dnskey
->public_key_length
);
606 require_action_quiet(nsec3_iteration
<= max_iteration
, exit
, valid
= mDNSfalse
);
617 get_maximum_nsec3_iteration_for_dnskey_length(mDNSu16 key_length
) {
619 mDNSs32 rounded_key_length_in_bits
= key_length
* 8;
620 static const mDNSs32 fixed_key_size
[] = {
623 static const mDNSs32 max_iteration_for_fixed_key_size
[] = {
626 // use "sizeof(fixed_key_size) == sizeof(max_iteration_for_fixed_key_size) ? sizeof(fixed_key_size) / sizeof(mDNSu32) : -1" to check if two array have matched elements.
627 mDNSu32 distance_to_fixed_key_size
[sizeof(fixed_key_size
) == sizeof(max_iteration_for_fixed_key_size
) ? sizeof(fixed_key_size
) / sizeof(mDNSu32
) : -1];
629 // get the closest key size from 102, 2048, 4096
630 for (size_t i
= 0; i
< sizeof(fixed_key_size
) / sizeof(mDNSu32
); i
++) {
631 distance_to_fixed_key_size
[i
] = abs(fixed_key_size
[i
] - rounded_key_length_in_bits
);
634 mDNSu32 min_distance
= UINT_MAX
;
635 size_t min_distance_index
= -1;
636 for (size_t i
= 0; i
< sizeof(fixed_key_size
) / sizeof(mDNSu32
); i
++) {
637 if (min_distance
< distance_to_fixed_key_size
[i
]) {
640 min_distance
= distance_to_fixed_key_size
[i
];
641 min_distance_index
= i
;
644 switch (fixed_key_size
[min_distance_index
]) {
662 mDNSlocal dnssec_validation_result_t
663 get_initial_children_to_validate(
664 dnssec_context_t
* const _Nonnull context
,
665 dnssec_validator_node_t
* const _Nonnull child
,
666 mDNSu8
* const _Nonnull out_child_size
) {
668 const list_t
* original_siblings
;
669 mDNSu8 child_size
= 0;
670 dnssec_validation_result_t validation_result
= dnssec_validation_valid
;
671 const response_type_t type
= context
->original
.original_result_with_rrsig
.type
;
672 const mDNSu8
* qname
= context
->original
.original_parameters
.question_name
.c
;
673 const mDNSu32 qname_hash
= DomainNameHashValue((domainname
*)qname
);
674 const mDNSu16 qclass
= context
->original
.original_parameters
.question_class
;
675 const mDNSu16 qtype
= context
->original
.original_parameters
.question_type
;
676 const trust_anchors_t
* const orig_trust_anchor
= context
->original
.original_trust_anchor
;
677 mDNSu32 request_id
= GET_REQUEST_ID(context
);
678 mDNSu32 question_id
= GET_QUESTION_ID(context
);
681 case original_response
: {
682 // check if the trust anchor installed for the question name already trusts all the answers
683 mDNSBool trusted_original_response
= mDNStrue
;
684 const list_t
* const original_rr_list
= &context
->original
.original_result_with_rrsig
.u
.original
.original_records
;
685 if (qtype
== kDNSType_DNSKEY
&& trust_anchor_contains_dnskey(orig_trust_anchor
)) {
686 const list_t
* const dnskey_trust_anchors
= &orig_trust_anchor
->dnskey_trust_anchors
;
687 dnssec_dnskey_t left
;
689 for (list_node_t
* dnssec_original_node
= list_get_first(original_rr_list
);
690 !list_has_ended(original_rr_list
, dnssec_original_node
);
691 dnssec_original_node
= list_next(dnssec_original_node
)) {
693 const dnssec_original_t
* const original
= (dnssec_original_t
*)dnssec_original_node
->data
;
694 parse_dns_type_dnskey_t(original
->dnssec_rr
.rdata
, original
->dnssec_rr
.rdata_length
,
695 &left
.flags
, &left
.protocol
, &left
.algorithm
, &left
.public_key_length
, &left
.public_key
);
697 mDNSBool trust_anchor_matches
= mDNSfalse
;
698 for (const list_node_t
* dnskey_node
= list_get_first(dnskey_trust_anchors
);
699 !list_has_ended(dnskey_trust_anchors
, dnskey_node
);
700 dnskey_node
= list_next(dnskey_node
)) {
701 const dnssec_dnskey_t
* const right_ptr
= (dnssec_dnskey_t
*)dnskey_node
->data
;
702 if (equals_dnssec_dnskey_t(&left
, right_ptr
)) {
703 trust_anchor_matches
= mDNStrue
;
708 if (!trust_anchor_matches
) {
709 trusted_original_response
= mDNSfalse
;
713 } else if (qtype
== kDNSType_DS
&& trust_anchor_contains_ds(orig_trust_anchor
)) {
714 const list_t
* const ds_trust_anchors
= &orig_trust_anchor
->ds_trust_anchors
;
716 mDNSBool is_valid
= mDNSfalse
;
718 for (list_node_t
* dnssec_original_node
= list_get_first(original_rr_list
);
719 !list_has_ended(original_rr_list
, dnssec_original_node
);
720 dnssec_original_node
= list_next(dnssec_original_node
)) {
722 const dnssec_original_t
* const original
= (dnssec_original_t
*)dnssec_original_node
->data
;
723 is_valid
= parse_dns_type_ds_t(original
->dnssec_rr
.rdata
, original
->dnssec_rr
.rdata_length
,
724 &left
.key_tag
, &left
.algorithm
, &left
.digest_type
, &left
.digest_length
, &left
.digest
);
725 verify_action(is_valid
,
726 log_debug("[R%u->Q%u] The returned DS records are malformated", request_id
, question_id
);
730 mDNSBool trust_anchor_matches
= mDNSfalse
;
731 for (const list_node_t
* ds_node
= list_get_first(ds_trust_anchors
);
732 !list_has_ended(ds_trust_anchors
, ds_node
);
733 ds_node
= list_next(ds_node
)) {
734 const dnssec_ds_t
* const right_ptr
= (dnssec_ds_t
*)ds_node
->data
;
735 if (equals_dnssec_ds_t(&left
, right_ptr
)) {
736 trust_anchor_matches
= mDNStrue
;
741 if (!trust_anchor_matches
) {
742 trusted_original_response
= mDNSfalse
;
747 trusted_original_response
= mDNSfalse
;
750 if (trusted_original_response
) {
751 validation_result
= dnssec_validation_trusted
;
754 } // fall into case cname_response
755 case cname_response
: {
756 const list_t
* rrsigs
; // list_t<dnssec_rrsig_t>
757 if (type
== original_response
) {
758 original_siblings
= &context
->original
.original_result_with_rrsig
.u
.original
.original_records
;
759 rrsigs
= &context
->original
.original_result_with_rrsig
.u
.original
.rrsig_records
;
760 } else if (type
== cname_response
) {
761 original_siblings
= &context
->original
.original_result_with_rrsig
.u
.cname_with_rrsig
.cname_records
;
762 rrsigs
= &context
->original
.original_result_with_rrsig
.u
.cname_with_rrsig
.rrsig_records
;
764 validation_result
= dnssec_validation_invalid_internal_state
;
767 initialize_validator_node_with_rr(&child
[child_size
], qname
, original_siblings
, rrsigs
, type
);
771 case nsec_response
: {
772 // check the meaning of NSEC response: No Name, No Data, Wildcard Answer, Wildcard No Data
773 const dnssec_nsec_t
* nsec_to_verify_1
= mDNSNULL
;
774 const list_t
* rrsigs_to_verify_1
= mDNSNULL
;
775 const dnssec_nsec_t
* nsec_to_verify_2
= mDNSNULL
;
776 const list_t
* rrsigs_to_verify_2
= mDNSNULL
;
777 nsecs_with_rrsig_t
* nsecs_with_rrsig
= &context
->original
.original_result_with_rrsig
.u
.nsecs_with_rrsig
;
779 nsecs_with_rrsig
->nsec_result
= validate_nsec_response(qname_hash
, qname
, qclass
, qtype
, nsecs_with_rrsig
,
780 &nsec_to_verify_1
, &rrsigs_to_verify_1
, &nsec_to_verify_2
, &rrsigs_to_verify_2
);
782 require_action_quiet(
783 (nsecs_with_rrsig
->nsec_result
== dnssec_validation_nsec_no_data
784 || nsecs_with_rrsig
->nsec_result
== dnssec_validation_nsec_name_error
785 || nsecs_with_rrsig
->nsec_result
== dnssec_validation_nsec_wildcard_answer
786 || nsecs_with_rrsig
->nsec_result
== dnssec_validation_nsec_wildcard_no_data
)
787 && rrsigs_to_verify_1
!= mDNSNULL
788 , exit
, validation_result
= nsecs_with_rrsig
->nsec_result
); // When the assertion holds, rrsigs_to_verify_1 must be nonnull.
790 initialize_validator_node_with_nsec(&child
[child_size
], nsec_to_verify_1
, qname
, rrsigs_to_verify_1
);
793 if (nsec_to_verify_2
!= mDNSNULL
) {
794 initialize_validator_node_with_nsec(&child
[child_size
], nsec_to_verify_2
, qname
, rrsigs_to_verify_2
);
798 if (!list_empty(&nsecs_with_rrsig
->wildcard_answers
)) {
799 // and nsecs_with_rrsig->wildcard_rrsigs is not empty either
800 initialize_validator_node_with_rr(&child
[child_size
], qname
, &nsecs_with_rrsig
->wildcard_answers
,
801 &nsecs_with_rrsig
->wildcard_rrsigs
, original_response
);
806 case nsec3_response
: {
807 const dnssec_nsec3_t
* nsec3_to_verify_1
= mDNSNULL
;
808 const list_t
* rrsigs_to_verify_1
= mDNSNULL
;
809 const dnssec_nsec3_t
* nsec3_to_verify_2
= mDNSNULL
;
810 const list_t
* rrsigs_to_verify_2
= mDNSNULL
;
811 const dnssec_nsec3_t
* nsec3_to_verify_3
= mDNSNULL
;
812 const list_t
* rrsigs_to_verify_3
= mDNSNULL
;
813 nsec3s_with_rrsig_t
* nsec3s_with_rrsig
= &context
->original
.original_result_with_rrsig
.u
.nsec3s_with_rrsig
;
815 nsec3s_with_rrsig
->nsec3_result
= validate_nsec3_response(qname
, qtype
, nsec3s_with_rrsig
,
816 &nsec3_to_verify_1
, &rrsigs_to_verify_1
, &nsec3_to_verify_2
, &rrsigs_to_verify_2
, &nsec3_to_verify_3
, &rrsigs_to_verify_3
);
818 require_action_quiet(
819 nsec3s_with_rrsig
->nsec3_result
== dnssec_validation_nsec3_no_data_response
820 || nsec3s_with_rrsig
->nsec3_result
== dnssec_validation_nsec3_no_data_response
821 || nsec3s_with_rrsig
->nsec3_result
== dnssec_validation_nsec3_no_data_response_opt_out
822 || nsec3s_with_rrsig
->nsec3_result
== dnssec_validation_nsec3_wildcard_no_data
823 || nsec3s_with_rrsig
->nsec3_result
== dnssec_validation_nsec3_wildcard_answer_response
824 || nsec3s_with_rrsig
->nsec3_result
== dnssec_validation_nsec3_name_error
825 , exit
, validation_result
= nsec3s_with_rrsig
->nsec3_result
);
827 initialize_validator_node_with_nsec3(&child
[child_size
], nsec3_to_verify_1
, qname
, rrsigs_to_verify_1
);
830 if (nsec3_to_verify_2
!= mDNSNULL
) {
831 initialize_validator_node_with_nsec3(&child
[child_size
], nsec3_to_verify_2
, qname
, rrsigs_to_verify_2
);
835 if (nsec3_to_verify_3
!= mDNSNULL
) {
836 initialize_validator_node_with_nsec3(&child
[child_size
], nsec3_to_verify_3
, qname
, rrsigs_to_verify_3
);
840 if (!list_empty(&nsec3s_with_rrsig
->wildcard_answers
)) {
841 // and nsecs_with_rrsig->wildcard_rrsigs is not empty either
842 initialize_validator_node_with_rr(&child
[child_size
], qname
, &nsec3s_with_rrsig
->wildcard_answers
,
843 &nsec3s_with_rrsig
->wildcard_rrsigs
, rr_validator
);
849 log_error("DNSSEC validation starts with unknown orginal resource record;");
850 validation_result
= dnssec_validation_invalid_internal_state
;
855 *out_child_size
= child_size
;
856 return validation_result
;
859 mDNSlocal dnssec_validation_result_t
860 validate_nsec3_response(
861 const mDNSu8
* const _Nonnull qname
,
863 const nsec3s_with_rrsig_t
* const _Nonnull nsec3s_with_rrsig
,
864 const dnssec_nsec3_t
* _Nullable
* _Nonnull out_nsec3_1
,
865 const list_t
* _Nullable
* _Nonnull out_rrsig_1
,
866 const dnssec_nsec3_t
* _Nullable
* _Nonnull out_nsec3_2
,
867 const list_t
* _Nullable
* _Nonnull out_rrsig_2
,
868 const dnssec_nsec3_t
* _Nullable
* _Nonnull out_nsec3_3
,
869 const list_t
* _Nullable
* _Nonnull out_rrsig_3
) {
871 dnssec_validation_result_t validation_result
= dnssec_validation_validating
;
872 dnssec_validation_result_t error
;
873 const list_t
* const nsec3s
= &nsec3s_with_rrsig
->nsec3_and_rrsigs_same_name
;
874 const one_nsec3_with_rrsigs_t
* const first_one_nsec3
= (one_nsec3_with_rrsigs_t
*)(list_get_first(nsec3s
)->data
);
875 const dnssec_nsec3_t
* const first_dnssec_nsec3
= &first_one_nsec3
->nsec3_record
;
876 const mDNSu8 hash_algorithm
= first_dnssec_nsec3
->hash_algorithm
;
877 const mDNSu8
* const salt
= first_dnssec_nsec3
->salt
;
878 const mDNSu8 salt_length
= first_dnssec_nsec3
->salt_length
;
879 const mDNSu16 iterations
= first_dnssec_nsec3
->iterations
;
880 mDNSu8
* qname_hash_b32
= mDNSNULL
;
881 mDNSu16 qname_length
= DOMAIN_NAME_LENGTH(qname
);
882 mDNSu8 canonical_name
[MAX_DOMAIN_NAME
];
884 require_action(!list_empty(nsec3s
), exit
, validation_result
= dnssec_validation_bogus
;
885 log_default("nsec3 list is empty"));
887 require_action(!nsec3_contains_different_hash_iteration_salt(nsec3s
), exit
, validation_result
= dnssec_validation_nsec3_different_hash_iteration_salt
;
888 log_default("NSEC3s with different algorithm, salt or iteration in the same response"));
890 // check if there is any wildcard response
891 if (!list_empty(&nsec3s_with_rrsig
->wildcard_answers
)) {
892 // Wildcard Answer Responses
893 const list_t
* const wildcard_answers
= &nsec3s_with_rrsig
->wildcard_answers
; // list_t<dnssec_rr_t>
894 const mDNSu8
* closest_encloser_name
;
895 mDNSu8 closest_encloser_name_length
;
896 const dnssec_nsec3_t
* nsec3_closest_encloser_proof
;
897 const list_t
* rrsig_closest_encloser_proof
;
898 const mDNSu8
* next_closer
;
899 const dnssec_nsec3_t
* nsec3_next_closer_proof
;
900 const list_t
* rrsig_next_closer_proof
;
902 error
= nsec3_proves_closest_encloser(qname
, nsec3s
, qname
, canonical_name
, &nsec3_closest_encloser_proof
,
903 &rrsig_closest_encloser_proof
, &nsec3_next_closer_proof
, &rrsig_next_closer_proof
, &closest_encloser_name
,
905 require_action(error
== dnssec_validation_nsec3_provable_closest_encloser
, exit
,
906 validation_result
= dnssec_validation_bogus
;log_default("Cannot find closest encloser;"));
907 closest_encloser_name_length
= DOMAIN_NAME_LENGTH(closest_encloser_name
);
909 // make sure that this closest encloser is the immediate ancestor to the generating wildcard
910 for (list_node_t
*node
= list_get_first(wildcard_answers
); !list_has_ended(wildcard_answers
, node
); node
= list_next(node
)) {
911 const dnssec_rr_t
* const dnssec_rr
= (dnssec_rr_t
*)node
->data
;
912 const mDNSu8
* name
= dnssec_rr
->name
.c
;
914 mDNSBool matches
= memcmp(name
+ 1 + *name
, closest_encloser_name
,
915 MIN(DOMAIN_NAME_LENGTH(name
), closest_encloser_name_length
));
917 require_action(matches
, exit
, validation_result
= dnssec_validation_bogus
);
920 *out_nsec3_1
= nsec3_closest_encloser_proof
;
921 *out_rrsig_1
= rrsig_closest_encloser_proof
;
922 *out_nsec3_2
= nsec3_next_closer_proof
;
923 *out_rrsig_2
= rrsig_next_closer_proof
;
924 validation_result
= dnssec_validation_nsec3_wildcard_answer_response
;
928 // check if there is a matching NSEC3 that matches qname
930 mDNSu8 qname_hash
[MAX_HASH_OUTPUT_SIZE
];
931 mDNSu32 qname_hash_length
;
932 mDNSu8 qname_hash_b32_length
;
933 const dnssec_nsec3_t
* nsec3_that_matches_qname
= mDNSNULL
;
935 // get the base32 format of qname hash
937 qname_hash_length
= get_hash_length_for_nsec3_hash_type(hash_algorithm
);
938 mDNSBool calculated
= calculate_hash_for_nsec3(qname_hash
, sizeof(qname_hash
), hash_algorithm
, qname
, qname_length
, salt
, salt_length
, iterations
);
939 require_action(calculated
, exit
, validation_result
= dnssec_validation_invalid_internal_state
);
940 qname_hash_b32
= (mDNSu8
*)base_n_encode(DNSSEC_BASE_32_HEX
, qname_hash
, qname_hash_length
);
941 qname_hash_b32_length
= strlen((char *)qname_hash_b32
);
943 for (list_node_t
* one_nsec3_node
= list_get_first(nsec3s
);
944 !list_has_ended(nsec3s
, one_nsec3_node
);
945 one_nsec3_node
= list_next(one_nsec3_node
)) {
947 const one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
*)one_nsec3_node
->data
;
948 const dnssec_nsec3_t
* const dnssec_nsec3
= &one_nsec3
->nsec3_record
;
949 const mDNSu8
* const frist_label_owner_name
= dnssec_nsec3
->dnssec_rr
.name
.c
+ 1;
950 const mDNSu8 first_label_length
= *dnssec_nsec3
->dnssec_rr
.name
.c
;
952 if (compare_canonical_dns_label(qname_hash_b32
, qname_hash_b32_length
, frist_label_owner_name
, first_label_length
) == 0) {
953 *out_nsec3_1
= dnssec_nsec3
;
954 *out_rrsig_1
= &one_nsec3
->rrsig_records
;
955 nsec3_that_matches_qname
= dnssec_nsec3
;
960 if (nsec3_that_matches_qname
!= mDNSNULL
) {
961 // No Data Responses, QTYPE is not DS
962 // No Data Responses, QTYPE is DS
964 // An NSEC3 RR that matches QNAME is present.
965 mDNSBool contains_type
;
966 contains_type
= bit_map_contain_dns_type(nsec3_that_matches_qname
->type_bit_maps
, nsec3_that_matches_qname
->type_bit_maps_length
, qtype
);
967 require_action(!contains_type
, exit
, validation_result
= dnssec_validation_bogus
;
968 log_default("NSEC3 contains DNS type that should not exist;" PUB_S
, DNS_TYPE_STR(qtype
)));
970 contains_type
= bit_map_contain_dns_type(nsec3_that_matches_qname
->type_bit_maps
, nsec3_that_matches_qname
->type_bit_maps_length
, kDNSType_CNAME
);
971 require_action(!contains_type
, exit
, validation_result
= dnssec_validation_bogus
;
972 log_default("NSEC3 contains DNS type that should not exist;" PUB_S
, DNS_TYPE_STR(kDNSType_CNAME
)));
974 validation_result
= dnssec_validation_nsec3_no_data_response
;
977 // Wildcard No Data Responses
978 // Name Error Responses
979 // No Data Responses, QTYPE is DS
980 const mDNSu8
* closest_encloser_name
;
981 mDNSu8 closest_encloser_name_length
;
982 const dnssec_nsec3_t
* nsec3_closest_encloser_proof
;
983 const list_t
* rrsig_closest_encloser_proof
;
984 const mDNSu8
* next_closer
;
985 const dnssec_nsec3_t
* nsec3_next_closer_proof
;
986 const list_t
* rrsig_next_closer_proof
;
987 mDNSu8 wildcard_closest_encloser
[MAX_DOMAIN_NAME
];
988 mDNSu8 wildcard_length
;
989 mDNSu8
* wildcard_hash_b32
= mDNSNULL
;
990 mDNSu32 wildcard_hash_b32_length
;
992 // find closest encloser
993 error
= nsec3_proves_closest_encloser(qname
, nsec3s
, qname
, canonical_name
, &nsec3_closest_encloser_proof
,
994 &rrsig_closest_encloser_proof
, &nsec3_next_closer_proof
, &rrsig_next_closer_proof
,
995 &closest_encloser_name
, &next_closer
);
996 require_action(error
== dnssec_validation_nsec3_provable_closest_encloser
, exit
,
997 validation_result
= dnssec_validation_bogus
;log_default("Cannot find closest encloser;"));
998 closest_encloser_name_length
= DOMAIN_NAME_LENGTH(closest_encloser_name
);
1000 *out_nsec3_1
= nsec3_closest_encloser_proof
;
1001 *out_rrsig_1
= rrsig_closest_encloser_proof
;
1002 *out_nsec3_2
= nsec3_next_closer_proof
;
1003 *out_rrsig_2
= rrsig_next_closer_proof
;
1005 // check if it is "No Data Responses, QTYPE is DS" case, the "Opt-out" case
1006 if (qtype
== kDNSType_DS
) {
1007 if ((nsec3_closest_encloser_proof
->flags
& NSEC3_FLAG_OPT_OUT_BIT
)) {
1008 validation_result
= dnssec_validation_nsec3_no_data_response_opt_out
;
1010 validation_result
= dnssec_validation_bogus
;
1015 require_action(closest_encloser_name_length
+ 2 <= sizeof(wildcard_closest_encloser
), exit
,
1016 validation_result
= dnssec_validation_bogus
; log_error("wildcard closest encloser length is invalid"));
1018 // check if wildcard exists
1019 // get wildcard name
1020 wildcard_closest_encloser
[0] = 1;
1021 wildcard_closest_encloser
[1] = '*';
1022 memcpy(wildcard_closest_encloser
+ 2, closest_encloser_name
, closest_encloser_name_length
);
1023 wildcard_length
= DOMAIN_NAME_LENGTH(wildcard_closest_encloser
);
1025 wildcard_hash_b32
= calculate_b32_hash_for_nsec3(wildcard_closest_encloser
, wildcard_length
,
1026 first_dnssec_nsec3
->hash_algorithm
, first_dnssec_nsec3
->salt
, first_dnssec_nsec3
->salt_length
, first_dnssec_nsec3
->iterations
);
1027 require_action(wildcard_hash_b32
!= mDNSNULL
, exit
,
1028 validation_result
= dnssec_validation_no_memory
;log_error("b32_encode failed"));
1030 wildcard_hash_b32_length
= strlen((char *)wildcard_hash_b32
);
1032 for (list_node_t
*one_nsec3_node
= list_get_first(nsec3s
);
1033 !list_has_ended(nsec3s
, one_nsec3_node
);
1034 one_nsec3_node
= list_next(one_nsec3_node
)) {
1036 const one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
*)one_nsec3_node
->data
;
1037 const dnssec_nsec3_t
* const dnssec_nsec3
= &one_nsec3
->nsec3_record
;
1038 const mDNSu8
* current
= (mDNSu8
*)(dnssec_nsec3
->dnssec_rr
.name
.c
+ 1);
1039 const mDNSu8 current_length
= *(dnssec_nsec3
->dnssec_rr
.name
.c
);
1040 const mDNSu8
* next
= (mDNSu8
*)(dnssec_nsec3
->next_hashed_owner_name_b32
);
1041 const mDNSu8 next_length
= dnssec_nsec3
->next_hashed_owner_name_b32_length
;
1042 mDNSBool last_nsec
= compare_canonical_dns_label(current
, current_length
, next
, next_length
) > 0;
1044 if (compare_canonical_dns_label(current
, current_length
, wildcard_hash_b32
, wildcard_hash_b32_length
) == 0) {
1045 // Wildcard No Data Responses
1046 *out_nsec3_2
= dnssec_nsec3
;
1049 mDNSBool contains_type
;
1050 contains_type
= bit_map_contain_dns_type(dnssec_nsec3
->type_bit_maps
, dnssec_nsec3
->type_bit_maps_length
, qtype
);
1051 require_action(!contains_type
, for_loop_exit
,
1052 validation_result
= dnssec_validation_bogus
;
1053 log_default("NSEC3 contains DNS type that should not exist;" PUB_S
, DNS_TYPE_STR(qtype
)));
1055 contains_type
= bit_map_contain_dns_type(dnssec_nsec3
->type_bit_maps
, dnssec_nsec3
->type_bit_maps_length
, kDNSType_CNAME
);
1056 require_action(!contains_type
, for_loop_exit
,
1057 validation_result
= dnssec_validation_bogus
;
1058 log_default("NSEC3 contains DNS type that should not exist;" PUB_S
, DNS_TYPE_STR(kDNSType_CNAME
)));
1060 *out_nsec3_3
= dnssec_nsec3
;
1061 *out_rrsig_3
= &one_nsec3
->rrsig_records
;
1062 validation_result
= dnssec_validation_nsec3_wildcard_no_data
;
1067 if (compare_canonical_dns_label(current
, current_length
, wildcard_hash_b32
, wildcard_hash_b32_length
) < 0
1068 && (last_nsec
|| compare_canonical_dns_label(wildcard_hash_b32
, wildcard_hash_b32_length
, next
, next_length
) < 0)) {
1069 // Name Error Responses
1070 *out_nsec3_3
= dnssec_nsec3
;
1071 *out_rrsig_3
= &one_nsec3
->rrsig_records
;
1072 validation_result
= dnssec_validation_nsec3_name_error
;
1077 validation_result
= dnssec_validation_bogus
;
1079 if (wildcard_hash_b32
!= mDNSNULL
) {
1080 free(wildcard_hash_b32
);
1081 wildcard_hash_b32
= mDNSNULL
;
1087 if (qname_hash_b32
!= mDNSNULL
) {
1088 free(qname_hash_b32
);
1090 return validation_result
;
1094 calculate_key_tag(const mDNSu8 key
[_Nonnull
], const mDNSu16 key_len
, const mDNSu8 algorithm
)
1096 if (algorithm
== 1) {
1097 // The key tag is defined to be the most significant 16 bits of the least significant 24 bits in the public key modulus.
1098 // However, RSA/MD5 whose algorithm number is 1 is not supported by mDNSResponder, so we will not implement it.
1102 mDNSu32 key_tag
= 0;
1104 for (mDNSu32 i
= 0; i
< key_len
; i
++)
1106 if (i
& 1) key_tag
+= key
[i
];
1107 else key_tag
+= (mDNSu32
)(key
[i
] << 8);
1109 key_tag
+= (key_tag
>> 16) & 0xFFFF;
1115 //======================================================================================================================
1117 //======================================================================================================================
1119 //======================================================================================================================
1120 // bit_map_contain_dns_type
1121 //======================================================================================================================
1124 bit_map_contain_dns_type(const mDNSu8
* const _Nonnull bit_maps
, const mDNSu16 bit_maps_length
, const mDNSu16 type
) {
1125 const mDNSu8 window_index
= type
/ 256;
1126 const mDNSu8 offset
= type
% 256;
1127 const mDNSu8
* ptr
= bit_maps
;
1128 const mDNSu8
* ptr_limit
= ptr
+ bit_maps_length
;
1130 for (;ptr
< ptr_limit
; ptr
+= 2 + *(ptr
+ 1)) {
1131 const mDNSu8 current_window_index
= *ptr
;
1132 const mDNSu8 block_bit_map_length
= *(ptr
+ 1);
1133 const mDNSu32 bit_count
= block_bit_map_length
* 8;
1134 const mDNSu8 mask
= 1 << (7 - (offset
% 8));
1135 const mDNSu8
* current_block
= ptr
+ 2;
1137 if (current_window_index
!= window_index
) {
1141 if (offset
>= bit_count
) {
1145 if ((current_block
[offset
/ 8] & mask
) != 0) {
1153 //======================================================================================================================
1154 // NSEC result validation
1155 //======================================================================================================================
1157 //======================================================================================================================
1158 // nsec_proves_no_data
1159 //======================================================================================================================
1162 nsec_proves_no_data(
1163 const mDNSu32 qname_hash
,
1164 const mDNSu8
* const _Nonnull qname
,
1165 const mDNSu16 qclass
,
1166 const mDNSu16 qtype
,
1167 const list_t
* const _Nonnull nsecs
,
1168 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_data
,
1169 const list_t
* _Nullable
* _Nonnull out_rrsigs
) {
1171 for (list_node_t
*nsec_node
= list_get_first(nsecs
); !list_has_ended(nsecs
, nsec_node
); nsec_node
= list_next(nsec_node
)) {
1172 const one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
*)nsec_node
->data
;
1174 const dnssec_nsec_t
* const dnssec_nsec
= &one_nsec
->nsec_record
;
1177 if (qname_hash
!= dnssec_nsec
->dnssec_rr
.name_hash
|| !DOMAIN_NAME_EQUALS(qname
, dnssec_nsec
->exist_domain_name
)) {
1182 if (qclass
!= dnssec_nsec
->dnssec_rr
.rr_class
) {
1186 // does not contain the STYPE
1187 if (bit_map_contain_dns_type(dnssec_nsec
->type_bit_maps
, dnssec_nsec
->type_bit_maps_length
, qtype
)) {
1192 *out_nsec_no_data
= dnssec_nsec
;
1193 *out_rrsigs
= &one_nsec
->rrsig_records
;
1200 //======================================================================================================================
1201 // nsec_proves_name_error
1202 //======================================================================================================================
1205 nsec_proves_name_error(
1206 const mDNSu8
* const _Nonnull qname
,
1207 const list_t
* const _Nonnull nsecs
,
1208 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_exact_match
,
1209 const list_t
* _Nullable
* _Nonnull out_rrsigs_no_exact_match
,
1210 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_wildcard
,
1211 const list_t
* _Nullable
* _Nonnull out_rrsigs_no_wildcard
) {
1213 mDNSBool no_exact_match
= mDNSfalse
;
1214 mDNSBool no_wildcard_match
= mDNSfalse
;
1216 for (list_node_t
*nsec_node
= list_get_first(nsecs
); !list_has_ended(nsecs
, nsec_node
); nsec_node
= list_next(nsec_node
)) {
1217 const one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
*)nsec_node
->data
;
1219 const dnssec_nsec_t
* const dnssec_nsec
= &one_nsec
->nsec_record
;
1220 const mDNSu8
* const prev
= dnssec_nsec
->exist_domain_name
;
1221 const mDNSu8
* const next
= dnssec_nsec
->next_domain_name
;
1222 mDNSs8 name_compare_result
;
1223 mDNSBool last_nsec
= compare_canonical_dns_name(next
, prev
) < 0;;
1225 // check if an NSEC RR proving that there is no exact match for <SNAME, SCLASS> exist
1226 while (!no_exact_match
) {
1228 name_compare_result
= compare_canonical_dns_name(qname
, prev
);
1229 if (name_compare_result
<= 0) {
1234 name_compare_result
= compare_canonical_dns_name(next
, qname
);
1235 if (!last_nsec
&& name_compare_result
<= 0) {
1239 *out_nsec_no_exact_match
= dnssec_nsec
;
1240 *out_rrsigs_no_exact_match
= &one_nsec
->rrsig_records
;
1241 no_exact_match
= mDNStrue
;
1244 // check if an NSEC RR proving that the zone contains no RRsets that would match <SNAME, SCLASS>
1245 // via wildcard name expansion exists
1246 while (!no_wildcard_match
) {
1247 mDNSu8 buffer
[MAX_DOMAIN_NAME
];
1248 const mDNSu8
* const wildcard_name
= get_wildcard_name(qname
, buffer
, sizeof(buffer
));
1249 if (wildcard_name
== mDNSNULL
) {
1253 // prev < wildcard_name
1254 name_compare_result
= compare_canonical_dns_name(wildcard_name
, prev
);
1255 if (name_compare_result
<= 0) {
1259 // wildcard_name < next
1260 name_compare_result
= compare_canonical_dns_name(next
, wildcard_name
);
1261 if (!last_nsec
&& name_compare_result
<= 0) {
1265 *out_nsec_no_wildcard
= dnssec_nsec
;
1266 *out_rrsigs_no_wildcard
= &one_nsec
->rrsig_records
;
1267 no_wildcard_match
= mDNStrue
;
1270 if (no_exact_match
&& no_wildcard_match
) {
1275 return no_exact_match
&& no_wildcard_match
;
1278 //======================================================================================================================
1279 // nsec_proves_wildcard_answer
1280 //======================================================================================================================
1283 nsec_proves_wildcard_answer(
1284 const mDNSu8
* const _Nonnull qname
,
1285 const mDNSu16 qtype
,
1286 const list_t
* const _Nonnull nsecs
,
1287 const list_t
* const _Nonnull wildcard_answer
,
1288 const list_t
* const _Nonnull wildcard_rrsig
,
1289 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_exact_match
,
1290 const list_t
* _Nullable
* _Nonnull out_rrsigs_no_exact_match
) {
1292 mDNSBool no_exact_match
= mDNSfalse
;
1293 mDNSBool contains_wildcard_answer
= mDNSfalse
;
1294 mDNSBool contains_wildcard_rrsig
= mDNSfalse
;
1296 for (list_node_t
*nsec_node
= list_get_first(nsecs
); !list_has_ended(nsecs
, nsec_node
); nsec_node
= list_next(nsec_node
)) {
1297 const one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
*)nsec_node
->data
;
1299 const dnssec_nsec_t
* const dnssec_nsec
= &one_nsec
->nsec_record
;
1300 const mDNSu8
* const prev
= dnssec_nsec
->exist_domain_name
;
1301 const mDNSu8
* const next
= dnssec_nsec
->next_domain_name
;
1302 mDNSs8 name_compare_result
;
1303 mDNSBool last_nsec
= compare_canonical_dns_name(prev
, next
) > 0;
1306 name_compare_result
= compare_canonical_dns_name(qname
, prev
);
1307 if (name_compare_result
<= 0) {
1312 name_compare_result
= compare_canonical_dns_name(next
, qname
);
1313 if (!last_nsec
&& name_compare_result
<= 0) {
1317 *out_nsec_no_exact_match
= dnssec_nsec
;
1318 *out_rrsigs_no_exact_match
= &one_nsec
->rrsig_records
;
1319 no_exact_match
= mDNStrue
;
1322 // contains wildcard answer
1323 contains_wildcard_answer
= !list_empty(wildcard_answer
);
1325 // contains wildcard RRSIG
1326 for (list_node_t
*rrsig_node
= list_get_first(wildcard_rrsig
); !list_has_ended(wildcard_rrsig
, rrsig_node
); rrsig_node
= list_next(rrsig_node
)) {
1327 const dnssec_rrsig_t
* const dnssec_rrsig
= (dnssec_rrsig_t
*)rrsig_node
->data
;
1328 // cover the wildcard
1329 if (dnssec_rrsig
->type_covered
!= qtype
) {
1333 // label is 1 less than the question name
1334 if (dnssec_rrsig
->labels
+ 1 != get_number_of_labels(dnssec_rrsig
->dnssec_rr
.name
.c
)) {
1338 contains_wildcard_rrsig
= mDNStrue
;
1341 return no_exact_match
&& contains_wildcard_answer
&& contains_wildcard_rrsig
;
1344 //======================================================================================================================
1345 // nsec_proves_wildcard_no_data
1346 //======================================================================================================================
1349 nsec_proves_wildcard_no_data(
1350 const mDNSu8
* const _Nonnull qname
,
1351 const mDNSu16 qclass
,
1352 const mDNSu16 qtype
,
1353 const list_t
* const _Nonnull nsecs
,
1354 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_exact_match
,
1355 const list_t
* _Nullable
* _Nonnull out_rrsigs_no_exact_match
,
1356 const dnssec_nsec_t
* _Nullable
* _Nonnull out_nsec_no_matching_stype
,
1357 const list_t
* _Nullable
* _Nonnull out_rrsigs_no_matching_stype
){
1359 mDNSBool no_exact_match
= mDNSfalse
;
1360 mDNSBool no_matching_stype
= mDNSfalse
;
1362 for (list_node_t
*nsec_node
= list_get_first(nsecs
); !list_has_ended(nsecs
, nsec_node
); nsec_node
= list_next(nsec_node
)) {
1363 const one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
*)nsec_node
->data
;
1365 const dnssec_nsec_t
* const dnssec_nsec
= &one_nsec
->nsec_record
;
1366 const mDNSu8
* const prev
= dnssec_nsec
->exist_domain_name
;
1367 const mDNSu8
* const next
= dnssec_nsec
->next_domain_name
;
1368 mDNSs8 name_compare_result
;
1369 mDNSBool last_nsec
= compare_canonical_dns_name(prev
, next
) > 0;
1371 // check if an NSEC RR proving that there is no exact match for <SNAME, SCLASS> exist
1372 while (!no_exact_match
) {
1374 name_compare_result
= compare_canonical_dns_name(qname
, prev
);
1375 if (name_compare_result
<= 0) {
1380 name_compare_result
= compare_canonical_dns_name(next
, qname
);
1381 if (!last_nsec
&& name_compare_result
<= 0) {
1385 *out_nsec_no_exact_match
= dnssec_nsec
;
1386 *out_rrsigs_no_exact_match
= &one_nsec
->rrsig_records
;
1387 no_exact_match
= mDNStrue
;
1390 // check if an NSEC RR proving that there are no RRsets matching STYPE at the wildcard owner name that matched
1391 // <SNAME, SCLASS> via wildcard expansion, exists
1392 while (!no_matching_stype
) {
1394 mDNSu8 wildcard_name
[256];
1396 if (!DOMAIN_NAME_EQUALS(get_wildcard_name(qname
, wildcard_name
, sizeof(wildcard_name
)), dnssec_nsec
->exist_domain_name
)) {
1401 if (qclass
!= dnssec_nsec
->dnssec_rr
.rr_class
) {
1405 // does not contain the STYPE
1406 if (bit_map_contain_dns_type(dnssec_nsec
->type_bit_maps
, dnssec_nsec
->type_bit_maps_length
, qtype
)) {
1410 *out_nsec_no_matching_stype
= dnssec_nsec
;
1411 *out_rrsigs_no_matching_stype
= &one_nsec
->rrsig_records
;
1412 no_matching_stype
= mDNStrue
;
1415 if (no_exact_match
&& no_matching_stype
) {
1420 return no_exact_match
&& no_matching_stype
;
1423 //======================================================================================================================
1424 // NSEC3 result validation
1425 //======================================================================================================================
1427 mDNSlocal dnssec_validation_result_t
1428 nsec3_proves_closest_encloser(
1429 const mDNSu8
* const _Nonnull name
,
1430 const list_t
* const _Nonnull nsec3s
,
1431 const mDNSu8
* const _Nonnull zone_name
,
1432 mDNSu8 canonical_name
[MAX_DOMAIN_NAME
],
1433 const dnssec_nsec3_t
* _Nullable
* const _Nonnull out_nsec3_closest_encloser_proof
,
1434 const list_t
* _Nullable
* const _Nonnull out_rrsig_closest_encloser_proof
,
1435 const dnssec_nsec3_t
* _Nullable
* const _Nonnull out_nsec3_next_closer_proof
,
1436 const list_t
* _Nullable
* const _Nonnull out_rrsig_next_closer_proof
,
1437 const mDNSu8
* _Nullable
* const _Nonnull out_closest_encloser_name
,
1438 const mDNSu8
* _Nullable
* const _Nonnull out_next_closer_name
) {
1440 dnssec_validation_result_t result
= dnssec_validation_validating
;
1441 const one_nsec3_with_rrsigs_t
* const first_one_nsec3
= (one_nsec3_with_rrsigs_t
*)list_get_first(nsec3s
)->data
;
1442 const dnssec_nsec3_t
* const first_dnssec_nsec3
= &first_one_nsec3
->nsec3_record
;
1443 const mDNSu8 hash_algorithm
= first_dnssec_nsec3
->hash_algorithm
;
1444 const mDNSu16 iterations
= first_dnssec_nsec3
->iterations
;
1445 const mDNSu8
* const salt
= first_dnssec_nsec3
->salt
;
1446 const mDNSu8 salt_length
= first_dnssec_nsec3
->salt_length
;
1447 mDNSu8 checking_flag
;
1448 mDNSu16 canonical_name_length
;
1449 const mDNSu8
* sname
;
1450 mDNSu16 sname_length
;
1451 mDNSBool break_loop
;
1453 copy_canonical_name(canonical_name
, name
);
1454 canonical_name_length
= DOMAIN_NAME_LENGTH(canonical_name
);
1456 sname
= canonical_name
;
1457 sname_length
= canonical_name_length
;
1458 checking_flag
= mDNSfalse
;
1460 while (*sname
!= 0 && result
== dnssec_validation_validating
) {
1461 mDNSu8
* const hash_b32
= calculate_b32_hash_for_nsec3(sname
, sname_length
, hash_algorithm
, salt
, salt_length
, iterations
);
1462 require_action(hash_b32
!= mDNSNULL
, exit
, result
= dnssec_validation_no_memory
);
1463 mDNSu8 hash_b32_length
= strlen((char *)hash_b32
);
1464 break_loop
= mDNSfalse
;
1466 for (list_node_t
*one_nsec3_node
= list_get_first(nsec3s
);
1467 !list_has_ended(nsec3s
, one_nsec3_node
) && !break_loop
;
1468 one_nsec3_node
= list_next(one_nsec3_node
)) {
1470 const one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
*)one_nsec3_node
->data
;
1471 const dnssec_nsec3_t
* const dnssec_nsec3
= &one_nsec3
->nsec3_record
;
1472 const mDNSu8
* current
= (mDNSu8
*)(dnssec_nsec3
->dnssec_rr
.name
.c
+ 1);
1473 const mDNSu8 current_length
= *(dnssec_nsec3
->dnssec_rr
.name
.c
);
1474 const mDNSu8
* next
= (mDNSu8
*)(dnssec_nsec3
->next_hashed_owner_name_b32
);
1475 const mDNSu8 next_length
= dnssec_nsec3
->next_hashed_owner_name_b32_length
;
1476 const mDNSBool last_nsec3
= compare_canonical_dns_label(current
, current_length
, next
, next_length
) > 0;
1478 // ignore invalid NSEC3 record
1479 if (ignore_this_nsec3_record(dnssec_nsec3
)) {
1483 // If there is an NSEC3 RR in the response that covers SNAME
1484 if (compare_canonical_dns_label(current
, current_length
, hash_b32
, hash_b32_length
) < 0
1485 && (last_nsec3
|| compare_canonical_dns_label(hash_b32
, hash_b32_length
, next
, next_length
) < 0)) { // SNAME is covered by this NSEC3 record.
1487 checking_flag
= mDNStrue
;
1488 *out_nsec3_next_closer_proof
= dnssec_nsec3
;
1489 *out_rrsig_next_closer_proof
= &one_nsec3
->rrsig_records
;
1490 *out_next_closer_name
= sname
;
1491 break_loop
= mDNStrue
;
1492 } else if (compare_canonical_dns_label(current
, current_length
, hash_b32
, hash_b32_length
) == 0) {
1493 // If there is a matching NSEC3 RR in the response,
1494 // and the flag was set,
1495 require_action_quiet(checking_flag
, exit
, result
= dnssec_validation_bogus
);
1497 // and the nsec3 record comes from a proper zone,
1498 mDNSu8 subdomain
= is_a_subdomain_of_b(sname
, zone_name
);
1499 require_action_quiet(subdomain
, exit
, result
= dnssec_validation_nsec3_nsec3_not_from_the_zone
);
1501 // then this NEC3 proves closest encloser
1502 *out_nsec3_closest_encloser_proof
= dnssec_nsec3
;
1503 *out_rrsig_closest_encloser_proof
= &one_nsec3
->rrsig_records
;
1504 *out_closest_encloser_name
= sname
;
1505 break_loop
= mDNStrue
;
1506 result
= dnssec_validation_nsec3_provable_closest_encloser
;
1511 sname_length
-= 1 + *sname
;
1512 sname
+= 1 + *sname
;
1514 checking_flag
= mDNSfalse
;
1523 //======================================================================================================================
1524 // nsec3_contains_different_hash_iteration_salt
1525 //======================================================================================================================
1528 nsec3_contains_different_hash_iteration_salt(const list_t
* const nsec3s
) {
1529 if (list_empty(nsec3s
)) {
1533 const one_nsec3_with_rrsigs_t
* const first_one_nsec3
= (one_nsec3_with_rrsigs_t
*)(list_get_first(nsec3s
)->data
);
1534 const dnssec_nsec3_t
* const first_dnssec_nsec3
= &first_one_nsec3
->nsec3_record
;
1536 for (list_node_t
*one_nsec3_node
= list_get_first(nsec3s
);
1537 !list_has_ended(nsec3s
, one_nsec3_node
);
1538 one_nsec3_node
= list_next(one_nsec3_node
)) {
1540 const one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
*)one_nsec3_node
->data
;
1541 const dnssec_nsec3_t
* const dnssec_nsec3
= &one_nsec3
->nsec3_record
;
1543 if (dnssec_nsec3
->hash_algorithm
!= first_dnssec_nsec3
->hash_algorithm
1544 || dnssec_nsec3
->iterations
!= first_dnssec_nsec3
->iterations
1545 || dnssec_nsec3
->salt_length
!= first_dnssec_nsec3
->salt_length
1546 || memcmp(dnssec_nsec3
->salt
, first_dnssec_nsec3
->salt
, dnssec_nsec3
->salt_length
) != 0) {
1554 //======================================================================================================================
1555 // ignore_this_nsec3_record
1556 //======================================================================================================================
1559 ignore_this_nsec3_record(const dnssec_nsec3_t
* const _Nonnull dnssec_nsec3
) {
1560 // ignore the NSEC3 with unknown hash type, right now we only support SHA1(1)
1561 if (dnssec_nsec3
->hash_algorithm
!= 1) {
1565 mDNSu8 flags
= dnssec_nsec3
->flags
;
1566 flags
= (flags
& (~1));
1567 // ignore the NSEC3 with any flag bits set except for the least significant bit, which is used as Opt-out option
1575 //======================================================================================================================
1576 // build_trust_from_ksk_to_zsk
1577 //======================================================================================================================
1579 mDNSlocal dnssec_validation_result_t
1580 build_trust_from_ksk_to_zsk(
1581 const mDNSu32 request_id
,
1582 const dnssec_zone_t
* const _Nonnull zone
,
1583 const list_t
* const _Nonnull dnskeys
,
1584 const list_t
* const _Nonnull dses
,
1585 const list_t
* const _Nonnull rrsigs_covering_dnskey
,
1586 dnssec_validator_node_t
* _Nonnull children
,
1587 const mDNSu8 child_size
,
1588 dnssec_validator_node_t
* _Nonnull parents
,
1589 mDNSu8
* const _Nonnull out_parent_size
) {
1591 dnssec_validation_result_t result
= dnssec_validation_invalid
;
1592 dnssec_validation_result_t error
;
1593 const mDNSu8
* const zone_name
= zone
->domain_name
.c
;
1594 const list_t
* const dnskey_trust_anchors
= zone
->trust_anchor
? &zone
->trust_anchor
->dnskey_trust_anchors
: mDNSNULL
;
1595 const list_t
* const ds_trust_anchors
= zone
->trust_anchor
? &zone
->trust_anchor
->ds_trust_anchors
: mDNSNULL
;
1596 mDNSu8 parent_size
= 0;
1598 for (mDNSu8 i
= 0; i
< child_size
; i
++) {
1599 dnssec_validator_node_t
* child
= &children
[i
];
1600 const list_t
* const rrsigs
= child
->rrssigs_covering_it
;
1602 for (const list_node_t
* rrsig_node
= list_get_first(rrsigs
); !list_has_ended(rrsigs
, rrsig_node
); rrsig_node
= list_next(rrsig_node
)) {
1603 const dnssec_rrsig_t
* const dnssec_rrsig
= (dnssec_rrsig_t
*)rrsig_node
->data
;
1604 const mDNSu16 key_tag_from_rrsig
= dnssec_rrsig
->key_tag
;
1606 verify_action(dnssec_rrsig
->type_covered
== kDNSType_DNSKEY
, continue);
1608 const dnssec_dnskey_t
* dnssec_dnskey
= mDNSNULL
;
1609 const dnssec_ds_t
* dnssec_ds
= mDNSNULL
;
1610 dnssec_validator_node_t
* parent
= mDNSNULL
;
1611 mDNSBool find_trust_anchor
= mDNSfalse
;
1613 if (dnskey_trust_anchors
!= mDNSNULL
&& !list_empty(dnskey_trust_anchors
)) {
1614 for (const list_node_t
* dnskey_node
= list_get_first(dnskey_trust_anchors
);
1615 !list_has_ended(dnskey_trust_anchors
, dnskey_node
);
1616 dnskey_node
= list_next(dnskey_node
)) {
1618 dnssec_dnskey
= (dnssec_dnskey_t
*)dnskey_node
->data
;
1619 const mDNSu16 key_tag_from_dnskey
= dnssec_dnskey
->key_tag
;
1620 mDNSBool entry_point
= (DNSKEY_FLAG_SECURITY_ENTRY_POINT
& dnssec_dnskey
->flags
);
1622 if (key_tag_from_rrsig
!= key_tag_from_dnskey
|| !entry_point
) {
1623 dnssec_dnskey
= mDNSNULL
;
1627 find_trust_anchor
= mDNStrue
;
1628 goto initialize_parent
;
1632 if (!find_trust_anchor
&& ds_trust_anchors
!= mDNSNULL
&& !list_empty(ds_trust_anchors
)) {
1633 for (const list_node_t
* dnskey_node
= list_get_first(dnskeys
);
1634 !list_has_ended(dnskeys
, dnskey_node
);
1635 dnskey_node
= list_next(dnskey_node
)) {
1637 dnssec_dnskey
= (dnssec_dnskey_t
*)dnskey_node
->data
;
1638 const mDNSu16 key_tag_from_dnskey
= dnssec_dnskey
->key_tag
;
1639 mDNSBool entry_point
= (DNSKEY_FLAG_SECURITY_ENTRY_POINT
& dnssec_dnskey
->flags
);
1641 if (key_tag_from_rrsig
!= key_tag_from_dnskey
|| !entry_point
) {
1642 dnssec_dnskey
= mDNSNULL
;
1646 for (const list_node_t
* ds_node
= list_get_first(ds_trust_anchors
);
1647 !list_has_ended(ds_trust_anchors
, ds_node
);
1648 ds_node
= list_next(ds_node
)) {
1650 dnssec_ds
= (dnssec_ds_t
*)ds_node
->data
;
1651 const mDNSu16 key_tag_from_ds
= dnssec_ds
->key_tag
;
1653 if (key_tag_from_rrsig
!= key_tag_from_ds
) {
1654 dnssec_ds
= mDNSNULL
;
1658 find_trust_anchor
= mDNStrue
;
1659 goto initialize_parent
;
1664 if (!find_trust_anchor
) {
1665 for (const list_node_t
* dnskey_node
= list_get_first(dnskeys
); !list_has_ended(dnskeys
, dnskey_node
); dnskey_node
= list_next(dnskey_node
)) {
1666 dnssec_dnskey
= (dnssec_dnskey_t
*)dnskey_node
->data
;
1667 const mDNSu16 key_tag_from_dnskey
= dnssec_dnskey
->key_tag
;
1668 mDNSBool entry_point
= (DNSKEY_FLAG_SECURITY_ENTRY_POINT
& dnssec_dnskey
->flags
);
1670 if (key_tag_from_rrsig
!= key_tag_from_dnskey
|| !entry_point
) {
1671 dnssec_dnskey
= mDNSNULL
;
1675 for (const list_node_t
* ds_node
= list_get_first(dses
);
1676 !list_has_ended(dses
, ds_node
);
1677 ds_node
= list_next(ds_node
)) {
1679 dnssec_ds
= (dnssec_ds_t
*)ds_node
->data
;
1680 const mDNSu16 key_tag_from_ds
= dnssec_ds
->key_tag
;
1682 if (key_tag_from_rrsig
!= key_tag_from_ds
) {
1683 dnssec_ds
= mDNSNULL
;
1687 goto initialize_parent
;
1692 if (dnssec_dnskey
== mDNSNULL
&& dnssec_ds
== mDNSNULL
) {
1697 parent
= &parents
[parent_size
];
1699 uninitialize_validator_node(parent
);
1700 initialize_validator_node_with_ksk(parent
, dnssec_dnskey
, dnssec_rrsig
, dnssec_ds
, zone_name
,
1701 dses
, rrsigs_covering_dnskey
, find_trust_anchor
);
1707 require_action_quiet(parent_size
== child_size
, exit
, result
= dnssec_validation_no_matching_key_tag
);
1709 error
= validate_validator_node(parents
, parent_size
);
1710 require_action_quiet(error
== dnssec_validation_valid
, exit
, result
= error
);
1712 error
= validate_validator_path_between_parents_and_children(request_id
, children
, parents
, &parent_size
);
1713 require_action_quiet(error
== dnssec_validation_valid
, exit
, result
= error
);
1715 dedup_validator_with_the_same_siblings(parents
, &parent_size
);
1717 *out_parent_size
= parent_size
;
1719 result
= dnssec_validation_valid
;
1725 //======================================================================================================================
1726 // build_trust_from_zsk
1727 //======================================================================================================================
1729 mDNSlocal dnssec_validation_result_t
1730 build_trust_from_zsk(
1731 const mDNSu32 request_id
,
1732 const dnssec_zone_t
* const _Nonnull zone
,
1733 const list_t
* const _Nonnull dnskeys
,
1734 const list_t
* const _Nonnull rrsigs_covering_dnskeys
,
1735 dnssec_validator_node_t
* _Nonnull children
,
1736 const mDNSu8 child_size
,
1737 dnssec_validator_node_t
* _Nonnull parents
,
1738 mDNSu8
* const _Nonnull out_parent_size
) {
1740 dnssec_validation_result_t result
= dnssec_validation_invalid
;
1741 dnssec_validation_result_t error
;
1742 const mDNSu8
* const zone_name
= zone
->domain_name
.c
;
1743 const trust_anchors_t
* const trust_anchor
= zone
->trust_anchor
;
1744 const list_t
* const dnskey_trust_anchors
= &trust_anchor
->dnskey_trust_anchors
;
1745 mDNSBool contain_trust_anchor
= trust_anchor_contains_dnskey(zone
->trust_anchor
);
1746 mDNSu8 parent_size
= 0;
1748 for (mDNSu8 i
= 0; i
< child_size
; i
++) {
1749 dnssec_validator_node_t
* child
= &children
[i
];
1750 const list_t
* const rrsigs
= child
->rrssigs_covering_it
;
1752 for (const list_node_t
* rrsig_node
= list_get_first(rrsigs
); !list_has_ended(rrsigs
, rrsig_node
); rrsig_node
= list_next(rrsig_node
)) {
1753 const dnssec_rrsig_t
* const dnssec_rrsig
= (dnssec_rrsig_t
*)rrsig_node
->data
;
1754 const mDNSu16 key_tag_from_rrsig
= dnssec_rrsig
->key_tag
;
1756 if (contain_trust_anchor
) {
1757 // has saved dnskey as trust anchor
1758 for (const list_node_t
* dnskey_node
= list_get_first(dnskey_trust_anchors
);
1759 !list_has_ended(dnskey_trust_anchors
, dnskey_node
);
1760 dnskey_node
= list_next(dnskey_node
)) {
1762 const dnssec_dnskey_t
* const dnssec_dnskey
= (dnssec_dnskey_t
*)dnskey_node
->data
;
1763 const mDNSu16 key_tag_from_dnskey
= dnssec_dnskey
->key_tag
;
1765 if (key_tag_from_rrsig
!= key_tag_from_dnskey
) {
1769 dnssec_validator_node_t
* const parent
= &parents
[parent_size
];
1771 uninitialize_validator_node(parent
);
1772 initialize_validator_node_with_zsk(parent
, dnssec_dnskey
, dnssec_rrsig
, zone_name
, dnskeys
, rrsigs_covering_dnskeys
, mDNStrue
);
1774 goto find_matching_parent
;
1777 for (const list_node_t
* dnskey_node
= list_get_first(dnskeys
);
1778 !list_has_ended(dnskeys
, dnskey_node
);
1779 dnskey_node
= list_next(dnskey_node
)) {
1781 const dnssec_dnskey_t
* const dnssec_dnskey
= (dnssec_dnskey_t
*)dnskey_node
->data
;
1782 const mDNSu16 key_tag_from_dnskey
= dnssec_dnskey
->key_tag
;
1784 if (key_tag_from_rrsig
!= key_tag_from_dnskey
) {
1788 dnssec_validator_node_t
* const parent
= &parents
[parent_size
];
1790 uninitialize_validator_node(parent
);
1791 initialize_validator_node_with_zsk(parent
, dnssec_dnskey
, dnssec_rrsig
, zone_name
, dnskeys
, rrsigs_covering_dnskeys
, mDNSfalse
);
1793 goto find_matching_parent
;
1797 find_matching_parent
:
1800 if (contain_trust_anchor
&& parent_size
!= child_size
) {
1801 // trust anchor cannot be used to verify this response, now going back to records retrieval
1802 result
= dnssec_validation_trust_anchor_does_not_macth
;
1805 require_action_quiet(parent_size
== child_size
, exit
, result
= dnssec_validation_no_matching_key_tag
);
1807 error
= validate_validator_node(parents
, parent_size
);
1808 require_action_quiet(error
== dnssec_validation_valid
, exit
, result
= error
);
1810 error
= validate_validator_path_between_parents_and_children(request_id
, children
, parents
, &parent_size
);
1811 require_action_quiet(error
== dnssec_validation_valid
, exit
, result
= error
);
1813 dedup_validator_with_the_same_siblings(parents
, &parent_size
);
1815 *out_parent_size
= parent_size
;
1817 result
= dnssec_validation_valid
;
1823 //======================================================================================================================
1824 // initialize_validator_node_with_rr
1825 //======================================================================================================================
1828 initialize_validator_node_with_rr(
1829 dnssec_validator_node_t
* const _Nonnull node
,
1830 const mDNSu8
* const _Nonnull name
,
1831 const list_t
* const _Nonnull siblings
,
1832 const list_t
* const _Nonnull rrsigs_covering_it
, // list_t<dnssec_rrsig_t>
1833 response_type_t response_type
) { // list_t<dnssec_original_t>
1835 node
->type
= rr_validator
;
1836 node
->u
.rr
.rr_response_type
= response_type
;
1838 node
->siblings
= siblings
;
1839 node
->rrssigs_covering_it
= rrsigs_covering_it
;
1840 node
->trusted
= mDNSfalse
;
1843 //======================================================================================================================
1844 // initialize_validator_node_with_nsec
1845 //======================================================================================================================
1848 initialize_validator_node_with_nsec(
1849 dnssec_validator_node_t
* const _Nonnull node
,
1850 const dnssec_nsec_t
* _Nullable nsec
,
1851 const mDNSu8
* const _Nonnull name
,
1852 const list_t
* const _Nonnull rrsig_covering_it
) { // list_t<dnssec_rrsig_t>
1854 node
->type
= nsec_validator
;
1855 node
->u
.nsec
.nsec
= nsec
;
1857 node
->siblings
= mDNSNULL
;
1858 node
->rrssigs_covering_it
= rrsig_covering_it
;
1859 node
->trusted
= mDNSfalse
;
1862 //======================================================================================================================
1863 // initialize_validator_node_with_nsec3
1864 //======================================================================================================================
1867 initialize_validator_node_with_nsec3(
1868 dnssec_validator_node_t
* const _Nonnull node
,
1869 const dnssec_nsec3_t
* _Nullable nsec3
,
1870 const mDNSu8
* const _Nonnull name
,
1871 const list_t
* const _Nonnull rrsig_covering_it
) { // list_t<dnssec_rrsig_t>
1873 node
->type
= nsec3_validator
;
1874 node
->u
.nsec3
.nsec3
= nsec3
;
1876 node
->siblings
= mDNSNULL
;
1877 node
->rrssigs_covering_it
= rrsig_covering_it
;
1878 node
->trusted
= mDNSfalse
;
1881 //======================================================================================================================
1882 // initialize_validator_node_with_zsk
1883 //======================================================================================================================
1886 initialize_validator_node_with_zsk(
1887 dnssec_validator_node_t
* const _Nonnull node
,
1888 const dnssec_dnskey_t
* const _Nonnull key
,
1889 const dnssec_rrsig_t
* const _Nonnull sig
,
1890 const mDNSu8
* const _Nonnull name
,
1891 const list_t
* const _Nonnull siblings
, // list<dnssec_dnskey_t>
1892 const list_t
* const _Nonnull rrsig_covering_it
, // list_t<dnssec_rrsig_t>
1895 node
->type
= zsk_validator
;
1896 node
->u
.zsk
.key
= key
;
1897 node
->u
.zsk
.sig
= sig
;
1899 node
->siblings
= siblings
;
1900 node
->rrssigs_covering_it
= rrsig_covering_it
;
1901 node
->trusted
= trusted
;
1904 //======================================================================================================================
1905 // initialize_validator_node_with_ksk
1906 //======================================================================================================================
1909 initialize_validator_node_with_ksk(
1910 dnssec_validator_node_t
* const _Nonnull node
,
1911 const dnssec_dnskey_t
* const _Nonnull key
,
1912 const dnssec_rrsig_t
* const _Nonnull sig
,
1913 const dnssec_ds_t
* const _Nullable ds
,
1914 const mDNSu8
* const _Nonnull name
,
1915 const list_t
* const _Nonnull siblings
, // list<dnssec_ds_t>
1916 const list_t
* const _Nonnull rrsig_covering_it
, // list_t<dnssec_rrsig_t>
1919 node
->type
= ksk_validator
;
1920 node
->u
.ksk
.key
= key
;
1921 node
->u
.ksk
.sig
= sig
;
1922 node
->u
.ksk
.ds
= ds
;
1924 node
->siblings
= siblings
;
1925 node
->rrssigs_covering_it
= rrsig_covering_it
;
1926 node
->trusted
= trusted
;
1929 //======================================================================================================================
1930 // uninitialize_validator_node
1931 //======================================================================================================================
1934 uninitialize_validator_node(dnssec_validator_node_t
* const _Nonnull node
) {
1935 bzero(node
, sizeof(dnssec_validator_node_t
));
1938 //======================================================================================================================
1939 // is_validator_node_valid
1940 //======================================================================================================================
1942 mDNSlocal dnssec_validation_result_t
1943 validate_validator_node(const dnssec_validator_node_t
* const _Nonnull nodes
, const mDNSu8 nodes_count
) {
1945 dnssec_validation_result_t result
= dnssec_validation_valid
;
1947 for (mDNSu8 i
= 0; i
< nodes_count
; i
++) {
1948 const dnssec_validator_node_t
* const node
= &nodes
[i
];
1950 switch (node
->type
) {
1953 case nsec_validator
:
1954 result
= validate_nsec(node
->u
.nsec
.nsec
);
1955 require_quiet(result
== dnssec_validation_valid
, exit
);
1957 case nsec3_validator
:
1958 result
= validate_nsec3(node
->u
.nsec3
.nsec3
);
1959 require_quiet(result
== dnssec_validation_valid
, exit
);
1962 result
= validate_dnskey(node
->u
.zsk
.key
, mDNSfalse
);
1963 require_quiet(result
== dnssec_validation_valid
, exit
);
1965 result
= validate_rrsig(node
->u
.zsk
.sig
);
1966 require_quiet(result
== dnssec_validation_valid
, exit
);
1968 require_action(node
->u
.zsk
.key
->algorithm
== node
->u
.zsk
.sig
->algorithm
, exit
,
1969 result
= dnssec_validation_algorithm_number_not_equal
);
1972 result
= validate_dnskey(node
->u
.ksk
.key
, mDNStrue
);
1973 require_quiet(result
== dnssec_validation_valid
, exit
);
1975 result
= validate_rrsig(node
->u
.ksk
.sig
);
1976 require_quiet(result
== dnssec_validation_valid
, exit
);
1978 if (node
->u
.ksk
.ds
!= mDNSNULL
) {
1979 result
= validate_ds(node
->u
.ksk
.ds
);
1980 require_quiet(result
== dnssec_validation_valid
, exit
);
1982 require_action_quiet(node
->trusted
, exit
, result
= dnssec_validation_invalid_internal_state
);
1985 if (node
->u
.ksk
.ds
!= mDNSNULL
) {
1986 require_action(node
->u
.ksk
.key
->algorithm
== node
->u
.ksk
.ds
->algorithm
, exit
,
1987 result
= dnssec_validation_algorithm_number_not_equal
);
1990 require_action(node
->u
.ksk
.key
->algorithm
== node
->u
.ksk
.sig
->algorithm
, exit
,
1991 result
= dnssec_validation_algorithm_number_not_equal
);
1993 if (node
->u
.ksk
.ds
!= mDNSNULL
) {
1994 result
= check_if_ds_ksk_matches(node
->u
.ksk
.ds
, node
->u
.ksk
.key
);
1995 require_quiet(result
== dnssec_validation_valid
, exit
);
1999 result
= dnssec_validation_invalid_internal_state
;
2008 //======================================================================================================================
2009 // validate_validator_path_between_parents_and_children
2010 //======================================================================================================================
2012 mDNSlocal dnssec_validation_result_t
2013 validate_validator_path_between_parents_and_children(
2014 const mDNSu32 request_id
,
2015 dnssec_validator_node_t
* _Nonnull children
,
2016 dnssec_validator_node_t
* _Nonnull parents
,
2017 mDNSu8
* const _Nonnull out_parent_size
) {
2019 dnssec_validation_result_t result
;
2020 dnssec_validation_result_t error
;
2021 mDNSu8 parent_size
= *out_parent_size
;
2023 require_action_quiet(parent_size
!= 0, exit
, result
= dnssec_validation_invalid_internal_state
);
2025 for (mDNSu8 i
= 0; i
< parent_size
; i
++) {
2026 const dnssec_validator_node_t
* const child
= &children
[i
];
2027 const dnssec_validator_node_t
* const parent
= &parents
[i
];
2029 error
= validate_validator_path(request_id
, child
, parent
);
2030 require_action_quiet(error
== dnssec_validation_valid
, exit
, result
= error
);
2032 if (parent
->type
== ksk_validator
) {
2033 const dnssec_dnskey_t
* const ksk
= parent
->u
.ksk
.key
;
2034 const dnssec_ds_t
* const ds
= parent
->u
.ksk
.ds
;
2036 error
= check_trust_validator_node(parent
);
2037 if (error
== dnssec_validation_trusted
) {
2038 if (ds
!= mDNSNULL
) {
2040 log_default("[R%u] " PRI_DM_NAME
": DS (digest_type=%u, tag=%u, trust_anchor) -----> " PRI_DM_NAME
": DNSKEY (KSK, alg=%u, tag=%u, length=%u)",
2041 request_id
, DM_NAME_PARAM(&ds
->dnssec_rr
.name
), ds
->digest_type
, ds
->key_tag
,
2042 DM_NAME_PARAM(&ksk
->dnssec_rr
.name
), ksk
->algorithm
, ksk
->key_tag
, ksk
->public_key_length
);
2044 // dnskey trust anchor
2045 log_default("[R%u] " PRI_DM_NAME
": DNSKEY (KSK, alg=%u, tag=%u, length=%u, trust_anchor)",
2047 DM_NAME_PARAM(&ksk
->dnssec_rr
.name
), ksk
->algorithm
, ksk
->key_tag
, ksk
->public_key_length
);
2050 // parent node is trusted by the policy, no need to verify it
2051 if (i
< parent_size
- 1) {
2052 children
[i
] = children
[i
+ 1];
2053 parents
[i
] = parents
[i
+ 1];
2058 log_default("[R%u] " PRI_DM_NAME
": DS (digest_type=%u, tag=%u) -----> " PRI_DM_NAME
": DNSKEY (KSK, alg=%u, tag=%u, length=%u)",
2059 request_id
, DM_NAME_PARAM(&ds
->dnssec_rr
.name
), ds
->digest_type
, ds
->key_tag
,
2060 DM_NAME_PARAM(&ksk
->dnssec_rr
.name
), ksk
->algorithm
, ksk
->key_tag
, ksk
->public_key_length
);
2065 *out_parent_size
= parent_size
;
2066 result
= dnssec_validation_valid
;
2072 //======================================================================================================================
2073 // validate_validator_path
2074 //======================================================================================================================
2076 mDNSlocal dnssec_validation_result_t
2077 validate_validator_path(
2078 const mDNSu32 request_id
,
2079 const dnssec_validator_node_t
* const _Nonnull child
,
2080 const dnssec_validator_node_t
* const _Nonnull parent
) {
2082 dnssec_validation_result_t result
= dnssec_validation_valid
;
2084 if (child
->type
== zsk_validator
&& parent
->type
== ksk_validator
) {
2085 result
= validate_path_from_ksk_to_zsk(request_id
, parent
, child
->siblings
);
2086 } else if (child
->type
== ksk_validator
&& parent
->type
== zsk_validator
) {
2087 result
= validate_path_from_zsk_to_ds(request_id
, parent
, child
->siblings
);
2088 } else if (child
->type
== rr_validator
&& parent
->type
== zsk_validator
) {
2089 result
= validate_path_from_zsk_to_rr(request_id
, parent
, child
->siblings
, child
->u
.rr
.rr_response_type
);
2090 } else if (child
->type
== nsec_validator
&& parent
->type
== zsk_validator
) {
2091 result
= validate_path_from_zsk_to_nsec(request_id
, parent
, child
);
2092 } else if (child
->type
== nsec3_validator
&& parent
->type
== zsk_validator
) {
2093 result
= validate_path_from_zsk_to_nsec3(request_id
, parent
, child
);
2095 result
= dnssec_validation_path_invalid_node_type
;
2102 //======================================================================================================================
2103 // check_trust_validator_node
2104 //======================================================================================================================
2106 mDNSlocal dnssec_validation_result_t
2107 check_trust_validator_node(const dnssec_validator_node_t
* const _Nonnull node
) {
2108 return node
->trusted
? dnssec_validation_trusted
: dnssec_validation_not_trusted
;
2111 //======================================================================================================================
2112 // dedup_validator_with_the_same_siblings
2113 //======================================================================================================================
2116 dedup_validator_with_the_same_siblings(
2117 dnssec_validator_node_t
* _Nonnull parents
,
2118 mDNSu8
* const _Nonnull out_parent_size
) {
2120 const dnssec_validator_node_t
* temp_parents
[4] = {mDNSNULL
};
2121 mDNSu8 temp_parent_size
= 0;
2122 mDNSu8 parent_size
= *out_parent_size
;
2124 for (mDNSu8 i
= 0; i
< parent_size
; i
++) {
2125 const dnssec_validator_node_t
* const parent
= &parents
[i
];
2126 mDNSBool duplicate
= mDNSfalse
;
2128 for (mDNSu8 j
= 0; j
< temp_parent_size
; j
++) {
2129 const dnssec_validator_node_t
* const parent_nodup
= temp_parents
[j
];
2130 // if two nodes to be verified have the same siblings to verify, they are the duplicates, since RRSIG signs the entire siblings
2131 if (parent_nodup
->siblings
== parent
->siblings
) {
2132 duplicate
= mDNStrue
;
2137 temp_parents
[temp_parent_size
] = parent
;
2142 for (mDNSu8 i
= 0; i
< temp_parent_size
; i
++) {
2143 parents
[i
] = *temp_parents
[i
];
2145 parent_size
= temp_parent_size
;
2146 *out_parent_size
= parent_size
;
2149 //======================================================================================================================
2150 // dedup_validator_with_the_same_siblings
2151 //======================================================================================================================
2153 mDNSlocal
void __unused
2154 print_ds_validation_progress(const dnssec_validator_node_t
* const _Nonnull nodes
, const mDNSu8 nodes_count
) {
2155 for (mDNSu8 i
= 0; i
< nodes_count
; i
++) {
2156 const dnssec_validator_node_t
* const node
= &nodes
[i
];
2157 verify_action(node
->type
== ksk_validator
,
2158 log_error("validator type is not Key Signing Key; type=%u", node
->type
); continue);
2160 const dnssec_dnskey_t
* const ksk
= node
->u
.ksk
.key
;
2161 const dnssec_ds_t
* const ds
= node
->u
.ksk
.ds
;
2163 log_default(PRI_DM_NAME
": DS (digest_type=%u, tag=%u) ----->" PRI_DM_NAME
": DNSKEY (KSK, alg=%u, tag=%u, length=%u)",
2164 DM_NAME_PARAM(&ds
->dnssec_rr
.name
), ds
->digest_type
, ds
->key_tag
,
2165 DM_NAME_PARAM(&ksk
->dnssec_rr
.name
), ksk
->algorithm
, ksk
->key_tag
, ksk
->public_key_length
);
2170 //======================================================================================================================
2171 // validate_zone_records_type
2172 //======================================================================================================================
2174 mDNSlocal dnssec_validation_result_t
2175 validate_zone_records_type(const dnssec_zone_t
* const _Nonnull zone
) {
2176 dnssec_validation_result_t result
= dnssec_validation_valid
;
2178 if (zone
->dnskey_request_started
&& zone
->ds_request_started
) {
2179 // the most common case where zone does not have any trust anchor.
2180 require_action_quiet(zone
->dses_with_rrsig
.type
== original_response
, exit
, result
= dnssec_validation_non_dnskey_ds_record_chain
);
2181 } else if (!zone
->dnskey_request_started
&& zone
->ds_request_started
) {
2182 // This is impossible because if dnskey request is not started that means we have trust anchor for DNSKEY, and there
2183 // is no need to send DS query, thus ds_request_started could not be true
2184 result
= dnssec_validation_invalid_internal_state
;
2186 } else if (zone
->dnskey_request_started
&& !zone
->ds_request_started
) {
2187 // It means the system has DS trust anchor installed, thus there is no need to query for DS record, only DNSKEY
2188 // record is required, and we must have DS trust anchor
2189 require_action_quiet(zone
->trust_anchor
!= mDNSNULL
&& !list_empty(&zone
->trust_anchor
->ds_trust_anchors
), exit
, result
= dnssec_validation_invalid_internal_state
);
2190 } else { // !zone->dnskey_request_started && !zone->ds_request_started
2191 // The system has DNSKEY trust anchor, and there is no need to query for DNSKEY or DS record at all.
2192 // we must have DNSKEY trust anchor
2193 require_action_quiet(zone
->trust_anchor
!= mDNSNULL
&& !list_empty(&zone
->trust_anchor
->dnskey_trust_anchors
), exit
, result
= dnssec_validation_invalid_internal_state
);
2200 //======================================================================================================================
2202 //======================================================================================================================
2204 mDNSlocal dnssec_validation_result_t
2205 validate_ds(const dnssec_ds_t
* const _Nonnull ds
) {
2206 dnssec_validation_result_t result
= dnssec_validation_valid
;
2207 mDNSs16 digest_priority
;
2208 mDNSs16 algorithm_priority
;
2209 // TODO: print dnssec_ds_t when failing to pass validation
2211 // check digest type
2212 digest_priority
= get_priority_of_ds_digest(ds
->digest_type
);
2213 require_action(digest_priority
!= -1, exit
, result
= dnssec_validation_ds_digest_not_supported
;
2214 log_default("Unsupported or invalid DS digest type; digest_type=%u", ds
->digest_type
));
2216 // check algorithm type
2217 algorithm_priority
= get_priority_of_dnskey_algorithm(ds
->algorithm
);
2218 require_action(algorithm_priority
!= -1, exit
, result
= dnssec_validation_dnskey_algorithm_not_supported
;
2219 log_default("Unsupported or invalid DNSKEY algorithm type; algorithm=%u", ds
->algorithm
));
2224 //======================================================================================================================
2226 //======================================================================================================================
2228 mDNSlocal dnssec_validation_result_t
2229 validate_dnskey(const dnssec_dnskey_t
* const _Nonnull dnskey
, mDNSBool security_entry_point
) {
2230 dnssec_validation_result_t result
= dnssec_validation_valid
;
2231 mDNSs16 algorithm_priority
;
2233 // check zone key flag
2234 require_action((dnskey
->flags
& DNSKEY_FLAG_ZONE_KEY
) != 0, exit
, result
= dnssec_validation_dnskey_invalid_flags
;
2235 log_default("Not a DNSSEC DNSKEY in DNSKEY; flags=%x", dnskey
->flags
));
2237 // check the security entry point flag
2238 require_action(!security_entry_point
|| (dnskey
->flags
& DNSKEY_FLAG_SECURITY_ENTRY_POINT
) != 0, exit
,
2239 result
= dnssec_validation_dnskey_invalid_flags
);
2242 require_action(dnskey
->protocol
== 3, exit
, result
= dnssec_validation_dnskey_wrong_protocol
;
2243 log_default("Not a DNSSEC Protocol in DNSKEY; protocol=%u", dnskey
->protocol
));
2245 // check DNSKEY algorithm
2246 algorithm_priority
= get_priority_of_dnskey_algorithm(dnskey
->algorithm
);
2247 require_action(algorithm_priority
!= -1, exit
, result
= dnssec_validation_dnskey_algorithm_not_supported
;
2248 log_default("Unsupported or invalid DNSKEY algorithm type in DNSKEY; algorithm=%u", dnskey
->algorithm
));
2254 //======================================================================================================================
2256 //======================================================================================================================
2258 mDNSlocal dnssec_validation_result_t
2259 validate_rrsig(const dnssec_rrsig_t
* const _Nonnull rrsig
) {
2260 dnssec_validation_result_t result
= dnssec_validation_valid
;
2261 mDNSs16 algorithm_priority
;
2264 // TODO: print dnssec_rrsig_t when failing to pass validation
2266 // check DNSKEY algorithm
2267 algorithm_priority
= get_priority_of_dnskey_algorithm(rrsig
->algorithm
);
2268 require_action(algorithm_priority
!= -1, exit
, result
= dnssec_validation_dnskey_algorithm_not_supported
;
2269 log_default("Unsupported or invalid DNSKEY algorithm type in RRSIG; algorithm=%u", rrsig
->algorithm
));
2271 // TODO: check the label field for RRSIG
2273 // check inception and expiration time
2274 now
= time(mDNSNULL
);
2275 require_action(now
<= UINT32_MAX
, exit
, result
= dnssec_validation_invalid_internal_state
;
2276 log_fault("the value of time(NULL) is now greater than UINT32_MAX"));
2278 now_u32
= (mDNSu32
)now
;
2279 require_action(now_u32
>= rrsig
->signature_inception
, exit
, result
= dnssec_validation_rrsig_use_before_inception
;
2280 log_default("RRSIG incpetion time is greater than the current time; inception_time=%u, now=%d", rrsig
->signature_inception
, now_u32
));
2282 require_action(now_u32
<= rrsig
->signature_expiration
, exit
, result
= dnssec_validation_rrsig_use_after_expiration
;
2283 log_default("RRSIG expiration time is less than the current time; expiration_time=%u, now=%d", rrsig
->signature_expiration
, now_u32
));
2289 //======================================================================================================================
2291 //======================================================================================================================
2293 mDNSlocal dnssec_validation_result_t
2294 validate_nsec(const dnssec_nsec_t
* const _Nonnull nsec
) {
2297 return dnssec_validation_valid
;
2300 //======================================================================================================================
2302 //======================================================================================================================
2304 mDNSlocal dnssec_validation_result_t
2305 validate_nsec3(const dnssec_nsec3_t
* const _Nonnull nsec3
) {
2306 dnssec_validation_result_t result
= dnssec_validation_valid
;
2307 // check if hash algorithm is supported
2308 switch (nsec3
->hash_algorithm
) {
2309 case 1: // only SHA-1 is supported
2312 result
= dnssec_validation_nsec3_unsupported_hash_algorithm
;
2316 // check flags, only Opt-Out flag is defined, all undefined flags should be zero
2317 require_action((nsec3
->flags
& (~NSEC3_FLAG_SET
)) == 0, exit
, result
= dnssec_validation_nsec3_unsupported_flag
);
2323 //======================================================================================================================
2324 // check_if_ds_ksk_matches
2325 //======================================================================================================================
2327 mDNSlocal dnssec_validation_result_t
2328 check_if_ds_ksk_matches(const dnssec_ds_t
* const _Nonnull ds
, const dnssec_dnskey_t
* const _Nonnull ksk
) {
2329 // reconstruct the data that will be hashed
2330 dnssec_validation_result_t result
= dnssec_validation_valid
;
2332 const mDNSu8
* const owner_name
= ksk
->dnssec_rr
.name
.c
;
2333 const mDNSu16 owner_name_length
= DOMAIN_NAME_LENGTH(owner_name
);
2334 const mDNSu8
* const dnskey_rdata
= ksk
->dnssec_rr
.rdata
;
2335 const mDNSu16 rdata_length
= ksk
->dnssec_rr
.rdata_length
;
2336 mDNSu8 digest_buffer
[MAX_HASH_OUTPUT_SIZE
];
2337 mDNSu32 digest_size
;
2338 digest_type_t digest_type
;
2339 const mDNSu32 data_to_be_hashed_length
= owner_name_length
+ rdata_length
;
2340 mDNSu8
* const data_to_be_hashed
= malloc(data_to_be_hashed_length
);
2341 require_action(data_to_be_hashed
!= mDNSNULL
, exit
, result
= dnssec_validation_no_memory
);
2343 memcpy(data_to_be_hashed
, owner_name
, owner_name_length
);
2344 memcpy(data_to_be_hashed
+ owner_name_length
, dnskey_rdata
, rdata_length
);
2346 switch (ds
->digest_type
) {
2347 case DS_DIGEST_SHA_1
:
2348 digest_type
= DIGEST_SHA_1
;
2350 case DS_DIGEST_SHA_256
:
2351 digest_type
= DIGEST_SHA_256
;
2353 case DS_DIGEST_SHA_384
:
2354 digest_type
= DIGEST_SHA_384
;
2357 result
= dnssec_validation_ds_digest_not_supported
;
2360 digest_size
= get_digest_length_for_ds_digest_type(ds
->digest_type
);
2361 mDNSBool calculated
= calculate_digest_for_data(data_to_be_hashed
, data_to_be_hashed_length
, digest_type
, digest_buffer
, sizeof(digest_buffer
));
2362 require_action_quiet(calculated
, exit
, result
= dnssec_validation_invalid_internal_state
);
2363 require_action(digest_size
== ds
->digest_length
, exit
, result
= dnssec_validation_bogus
);
2365 matches
= (memcmp(digest_buffer
, ds
->digest
, digest_size
) == 0);
2367 require_action(matches
, exit
, result
= dnssec_validation_bogus
);
2370 if (data_to_be_hashed
!= mDNSNULL
) {
2371 free(data_to_be_hashed
);
2376 mDNSlocal dnssec_validation_result_t
2377 validate_path_from_zsk_to_rr(
2378 const mDNSu32 request_id
,
2379 const dnssec_validator_node_t
* const _Nonnull parent
,
2380 const list_t
* const _Nonnull originals
/* list_t<dnssec_original_t> or list_t<dnssec_cname_t> */,
2381 response_type_t response_type
) {
2383 dnssec_validation_result_t result
= dnssec_validation_valid
;
2384 mDNSu8
* signed_data
= mDNSNULL
;
2385 mDNSu32 signed_data_length
;
2386 mDNSBool is_signed_data_valid
;
2388 result
= check_rrsig_validity_with_rrs(parent
->u
.zsk
.sig
, originals
, response_type
, kDNSQType_ANY
);
2389 require_action(result
== dnssec_validation_valid
, exit
, log_default("RRSIG is not valid for validation"));
2391 signed_data
= reconstruct_signed_data_with_rrs(originals
, parent
->u
.zsk
.sig
, response_type
, kDNSQType_ANY
, &signed_data_length
);
2392 require_action(signed_data
!= mDNSNULL
, exit
, result
= dnssec_validation_no_memory
;
2393 log_default("No enough memory to allocate for signed data;"));
2395 is_signed_data_valid
= validate_signed_data_with_rrsig_and_dnskey(request_id
, signed_data
, signed_data_length
, parent
->u
.zsk
.sig
, parent
->u
.zsk
.key
);
2397 result
= is_signed_data_valid
? dnssec_validation_valid
: dnssec_validation_invalid
;
2400 if (signed_data
!= mDNSNULL
) {
2402 signed_data
= mDNSNULL
;
2407 mDNSlocal dnssec_validation_result_t
2408 validate_path_from_ksk_to_zsk(
2409 const mDNSu32 request_id
,
2410 const dnssec_validator_node_t
* const _Nonnull parent
,
2411 const list_t
* const _Nonnull zsks
/* list_t<dnssec_dnskey_t> */) {
2413 dnssec_validation_result_t result
= dnssec_validation_valid
;
2414 mDNSu8
* signed_data
= mDNSNULL
;
2415 mDNSu32 signed_data_length
;
2416 mDNSBool is_signed_data_valid
;
2418 // TODO: original_response could be nsec nsec3
2419 result
= check_rrsig_validity_with_rrs(parent
->u
.ksk
.sig
, zsks
, original_response
, kDNSType_DNSKEY
);
2420 require_quiet(result
== dnssec_validation_valid
, exit
);
2422 signed_data
= reconstruct_signed_data_with_rrs(zsks
, parent
->u
.ksk
.sig
, original_response
, kDNSType_DNSKEY
, &signed_data_length
);
2423 require_action(signed_data
!= mDNSNULL
, exit
, result
= dnssec_validation_no_memory
;
2424 log_default("No enough memory to allocate for signed data;"));
2426 is_signed_data_valid
= validate_signed_data_with_rrsig_and_dnskey(request_id
, signed_data
, signed_data_length
, parent
->u
.ksk
.sig
, parent
->u
.ksk
.key
);
2427 result
= is_signed_data_valid
? dnssec_validation_valid
: dnssec_validation_invalid
;
2430 if (signed_data
!= mDNSNULL
) {
2432 signed_data
= mDNSNULL
;
2437 mDNSlocal dnssec_validation_result_t
2438 validate_path_from_zsk_to_ds(
2439 const mDNSu32 request_id
,
2440 const dnssec_validator_node_t
* const _Nonnull parent
,
2441 const list_t
* const _Nonnull dses
/* list_t<dnssec_ds_t> */) {
2443 dnssec_validation_result_t result
= dnssec_validation_valid
;
2444 mDNSu8
* signed_data
= mDNSNULL
;
2445 mDNSu32 signed_data_length
;
2446 mDNSBool is_signed_data_valid
;
2448 // TODO: original_response could be nsec nsec3
2449 result
= check_rrsig_validity_with_rrs(parent
->u
.zsk
.sig
, dses
, original_response
, kDNSType_DS
);
2450 require_quiet(result
== dnssec_validation_valid
, exit
);
2452 signed_data
= reconstruct_signed_data_with_rrs(dses
, parent
->u
.zsk
.sig
, original_response
, kDNSType_DS
, &signed_data_length
);
2453 require_action(signed_data
!= mDNSNULL
, exit
, result
= dnssec_validation_no_memory
;
2454 log_default("No enough memory to allocate for signed data;"));
2456 is_signed_data_valid
= validate_signed_data_with_rrsig_and_dnskey(request_id
, signed_data
, signed_data_length
, parent
->u
.zsk
.sig
, parent
->u
.zsk
.key
);
2457 result
= is_signed_data_valid
? dnssec_validation_valid
: dnssec_validation_invalid
;
2460 if (signed_data
!= mDNSNULL
) {
2462 signed_data
= mDNSNULL
;
2468 mDNSlocal dnssec_validation_result_t
2469 validate_path_from_zsk_to_nsec(
2470 const mDNSu32 request_id
,
2471 const dnssec_validator_node_t
* const _Nonnull parent
,
2472 const dnssec_validator_node_t
* const _Nonnull child
) {
2474 dnssec_validation_result_t result
;
2475 dnssec_validation_result_t error
;
2476 mDNSu8
* signed_data
= mDNSNULL
;
2477 mDNSu32 signed_data_length
;
2478 mDNSBool is_signed_data_valid
;
2480 error
= check_rrsig_validity_with_dnssec_rr(parent
->u
.zsk
.sig
, &child
->u
.nsec
.nsec
->dnssec_rr
);
2481 require_action(error
== dnssec_validation_valid
, exit
, result
= error
; log_default("RRSIG is invalid"));
2483 signed_data
= reconstruct_signed_data_with_one_dnssec_rr(&child
->u
.nsec
.nsec
->dnssec_rr
, parent
->u
.zsk
.sig
, &signed_data_length
);
2484 require_action(signed_data
!= mDNSNULL
, exit
, result
= dnssec_validation_no_memory
;
2485 log_error("No enough memory to allocate for signed data;"));
2487 is_signed_data_valid
= validate_signed_data_with_rrsig_and_dnskey(request_id
, signed_data
, signed_data_length
, parent
->u
.zsk
.sig
, parent
->u
.zsk
.key
);
2488 result
= is_signed_data_valid
? dnssec_validation_valid
: dnssec_validation_invalid
;
2491 if (signed_data
!= mDNSNULL
) {
2493 signed_data
= mDNSNULL
;
2498 mDNSlocal dnssec_validation_result_t
2499 validate_path_from_zsk_to_nsec3(
2500 const mDNSu32 request_id
,
2501 const dnssec_validator_node_t
* const _Nonnull parent
,
2502 const dnssec_validator_node_t
* const _Nonnull child
) {
2504 dnssec_validation_result_t result
;
2505 dnssec_validation_result_t error
;
2506 mDNSu8
* signed_data
= mDNSNULL
;
2507 mDNSu32 signed_data_length
;
2508 mDNSBool is_signed_data_valid
;
2510 error
= check_rrsig_validity_with_dnssec_rr(parent
->u
.zsk
.sig
, &child
->u
.nsec3
.nsec3
->dnssec_rr
);
2511 require_action(error
== dnssec_validation_valid
, exit
, result
= error
; log_default("RRSIG is invalid"));
2513 signed_data
= reconstruct_signed_data_with_one_dnssec_rr(&child
->u
.nsec3
.nsec3
->dnssec_rr
, parent
->u
.zsk
.sig
, &signed_data_length
);
2514 require_action(signed_data
!= mDNSNULL
, exit
, result
= dnssec_validation_no_memory
;
2515 log_error("No enough memory to allocate for signed data;"));
2517 is_signed_data_valid
= validate_signed_data_with_rrsig_and_dnskey(request_id
, signed_data
, signed_data_length
, parent
->u
.zsk
.sig
, parent
->u
.zsk
.key
);
2518 result
= is_signed_data_valid
? dnssec_validation_valid
: dnssec_validation_invalid
;
2521 if (signed_data
!= mDNSNULL
) {
2523 signed_data
= mDNSNULL
;
2528 //======================================================================================================================
2529 // check_rrsig_validity_with_rr
2530 //======================================================================================================================
2532 mDNSlocal dnssec_validation_result_t
2533 check_rrsig_validity_with_dnssec_rr(
2534 const dnssec_rrsig_t
* const _Nonnull rrsig
,
2535 const dnssec_rr_t
* const _Nonnull rr
) {
2537 dnssec_validation_result_t result
= dnssec_validation_valid
;
2538 const mDNSu8
* const owner_name
= rrsig
->dnssec_rr
.name
.c
;
2539 const mDNSu32 owner_name_hash
= rrsig
->dnssec_rr
.name_hash
;
2540 const mDNSu16
class = rrsig
->dnssec_rr
.rr_class
;
2541 const mDNSu8
* const signer_name
= rrsig
->signer_name
;
2542 const mDNSu16 type_covered
= rrsig
->type_covered
;
2543 const mDNSu8 labels_rrsig
= rrsig
->labels
;
2546 // The RRSIG RR and the RRset MUST have the same owner name,
2547 require_action(owner_name_hash
== rr
->name_hash
, exit
, result
= dnssec_validation_path_unmatched_owner_name
;
2548 log_default("The owner names of RRSIG and records do not match; RRSIG=" PRI_DM_NAME
", RR=" PRI_DM_NAME
,
2549 DM_NAME_PARAM((const domainname
* const)owner_name
), DM_NAME_PARAM(&rr
->name
)));
2550 require_action(DOMAIN_NAME_EQUALS(owner_name
, rr
->name
.c
), exit
, result
= dnssec_validation_path_unmatched_owner_name
;
2551 log_default("The owner names of RRSIG and records do not match; RRSIG=" PRI_DM_NAME
", RR=" PRI_DM_NAME
,
2552 DM_NAME_PARAM((const domainname
* const)owner_name
), DM_NAME_PARAM(&rr
->name
)));
2554 // and the same class.
2555 require_action(class == rr
->rr_class
, exit
, result
= dnssec_validation_path_unmatched_class
;
2556 log_default("The classes of RRSIG and records do not match; RRSIG=%u, RR=%u", class, rr
->rr_class
));
2558 // TODO: The RRSIG RR's Signer's Name field MUST be the name of the zone that contains the RRset
2561 // The RRSIG RR's Type Covered field MUST equal the RRset's type.
2562 require_action(type_covered
== rr
->rr_type
, exit
, result
= dnssec_validation_path_unmatched_type_covered
;
2563 log_default("The RRSIG does not cover the current record; RRSIG=" PUB_S
", RR=" PUB_S
,
2564 DNS_TYPE_STR(type_covered
), DNS_TYPE_STR(rr
->rr_type
)));
2566 // The number of labels in the RRset owner name MUST be greater than or equal to the value in the RRSIG RR's Labels field.
2567 labels_rr
= get_number_of_labels(rr
->name
.c
);
2568 require_action(labels_rrsig
<= labels_rr
, exit
, result
= dnssec_validation_path_invalid_label_count
;
2569 log_default("the RRSIG's label is not less than or equal to the number of labels in RR's owner's name; RRSIG=%u, RR=%u",
2570 labels_rrsig
, labels_rr
));
2576 //======================================================================================================================
2577 // check_rrsig_validity_with_dnssec_rrs
2578 //======================================================================================================================
2580 mDNSlocal dnssec_validation_result_t
2581 check_rrsig_validity_with_rrs(
2582 const dnssec_rrsig_t
* const _Nonnull rrsig
,
2583 const list_t
* const _Nonnull list_to_check
,
2584 response_type_t response_type_in_list
,
2585 const mDNSu16 record_type_in_list
) {
2587 dnssec_validation_result_t result
= dnssec_validation_valid
;
2588 const dnssec_rr_t
* rr
;
2590 for (list_node_t
*node
= list_get_first(list_to_check
); !list_has_ended(list_to_check
, node
); node
= list_next(node
)) {
2591 // get correct node from the list
2592 switch (response_type_in_list
) {
2593 case original_response
:
2595 if (record_type_in_list
== kDNSQType_ANY
) {
2596 const dnssec_original_t
* const original
= (dnssec_original_t
*)node
->data
;
2597 rr
= &original
->dnssec_rr
;
2598 } else if (record_type_in_list
== kDNSType_DNSKEY
) {
2599 const dnssec_dnskey_t
* const dnskey
= (dnssec_dnskey_t
*)node
->data
;
2600 rr
= &dnskey
->dnssec_rr
;
2601 } else if (record_type_in_list
== kDNSType_DS
) {
2602 const dnssec_ds_t
* const ds
= (dnssec_ds_t
*)node
->data
;
2603 rr
= &ds
->dnssec_rr
;
2605 result
= dnssec_validation_path_invalid_node_type
;
2610 case cname_response
:
2612 const dnssec_cname_t
* const cname
= (dnssec_cname_t
*)node
->data
;
2613 rr
= &cname
->dnssec_rr
;
2618 if (record_type_in_list
== kDNSQType_ANY
) {
2619 rr
= (dnssec_rr_t
*)node
->data
;
2620 } else if (record_type_in_list
== kDNSType_NSEC
) {
2621 const dnssec_nsec_t
* const nsec
= (dnssec_nsec_t
*)node
->data
;
2622 rr
= &nsec
->dnssec_rr
;
2624 result
= dnssec_validation_path_invalid_node_type
;
2629 case nsec3_response
:
2631 const dnssec_nsec3_t
* const nsec3
= (dnssec_nsec3_t
*)node
->data
;
2632 rr
= &nsec3
->dnssec_rr
;
2637 result
= dnssec_validation_path_invalid_node_type
;
2642 result
= check_rrsig_validity_with_dnssec_rr(rrsig
, rr
);
2643 require_quiet(result
== dnssec_validation_valid
, exit
);
2650 //======================================================================================================================
2651 // reconstruct_signed_data_with_dnssec_rrs
2652 //======================================================================================================================
2655 reconstruct_signed_data_with_rrs(
2656 const list_t
* const _Nonnull rr_set
,
2657 const dnssec_rrsig_t
* const _Nonnull dnssec_rrsig
,
2658 const response_type_t response_type
,
2659 const mDNSu16 record_type
,
2660 mDNSu32
* const _Nonnull out_signed_data_length
) {
2662 mDNSu8 rr_count
= 0;
2663 const dnssec_rr_t
* rr_array
[256]; // The maximum number of RR in one RRSET should be no more than 256
2665 // sort RRset in canonical order
2666 for (list_node_t
*node
= list_get_first(rr_set
); !list_has_ended(rr_set
, node
); node
= list_next(node
)) {
2669 switch (response_type
) {
2670 case original_response
:
2671 if (record_type
== kDNSQType_ANY
) {
2672 rr
= &((dnssec_original_t
*)node
->data
)->dnssec_rr
;
2673 } else if (record_type
== kDNSType_DNSKEY
) {
2674 rr
= &((dnssec_dnskey_t
*)node
->data
)->dnssec_rr
;
2675 } else if (record_type
== kDNSType_DS
) {
2676 rr
= &((dnssec_ds_t
*)node
->data
)->dnssec_rr
;
2678 // It should never happen.
2679 log_error("incorrect DNSSEC data type");
2683 case cname_response
:
2684 rr
= &((dnssec_cname_t
*)node
->data
)->dnssec_rr
;
2686 case nsec_response
: {
2687 if (record_type
== kDNSQType_ANY
) {
2688 rr
= (dnssec_rr_t
*)node
->data
;
2689 } else if (record_type
== kDNSType_NSEC
) {
2690 rr
= &((dnssec_nsec_t
*)node
->data
)->dnssec_rr
;
2696 case nsec3_response
:
2697 rr
= &((dnssec_nsec3_t
*)node
->data
)->dnssec_rr
;
2700 // It should never happen.
2701 log_error("signed data has unknown_response type");
2705 rr_array
[rr_count
] = rr
;
2708 sort_rr_array_canonically(rr_array
, rr_count
);
2710 // deduplicate RRs in RRSet
2711 rr_array_dedup(rr_array
, rr_count
);
2713 return reconstruct_signed_data_internal(rr_array
, rr_count
, dnssec_rrsig
, out_signed_data_length
);
2719 //======================================================================================================================
2720 // reconstruct_signed_data_with_one_dnssec_rr
2721 //======================================================================================================================
2724 reconstruct_signed_data_with_one_dnssec_rr(
2725 const dnssec_rr_t
* const _Nonnull dnssec_rr
,
2726 const dnssec_rrsig_t
* const _Nonnull dnssec_rrsig
,
2727 mDNSu32
* const _Nonnull out_signed_data_length
) {
2729 mDNSu8 rr_count
= 0;
2730 const dnssec_rr_t
*rr_array
[1];
2732 rr_array
[0] = dnssec_rr
;
2735 return reconstruct_signed_data_internal(rr_array
, rr_count
, dnssec_rrsig
, out_signed_data_length
);
2738 //======================================================================================================================
2739 // reconstruct_signed_data_internal
2740 //======================================================================================================================
2743 reconstruct_signed_data_internal(
2744 const dnssec_rr_t
* const rr_array
[],
2745 const mDNSu8 rr_count
,
2746 const dnssec_rrsig_t
* const _Nonnull dnssec_rrsig
,
2747 mDNSu32
* const _Nonnull out_signed_data_length
) {
2749 mStatus error
= mStatus_NoError
;
2750 mDNSu32 signed_data_length
= 0;
2751 mDNSu8
* signed_data
= mDNSNULL
;
2752 mDNSu8
* data_ptr
= mDNSNULL
;
2753 mDNSu8
* data_limit
= mDNSNULL
;
2754 mDNSu32 number_bytes_copied
= 0;
2756 // calculate correct signed data length taking duplicates, domain name decompression and wildcard expansion into consideration
2757 error
= calculate_signed_data_length(rr_array
, rr_count
, dnssec_rrsig
, &signed_data_length
);
2758 require_quiet(error
== mStatus_NoError
, exit
);
2760 // allocate memory for the signed data
2761 signed_data
= malloc(signed_data_length
);
2762 require_action(signed_data
!= mDNSNULL
, exit
, error
= mStatus_NoMemoryErr
; log_fault("malloc failed; error_description='%s'", strerror(errno
)));
2764 data_ptr
= signed_data
;
2765 data_limit
= data_ptr
+ signed_data_length
;
2767 // signed_data += RRSIG_RDATA
2768 memcpy(data_ptr
, dnssec_rrsig
->dnssec_rr
.rdata
, offsetof(dns_type_rrsig_t
, signer_name
));
2769 data_ptr
+= offsetof(dns_type_rrsig_t
, signer_name
);
2771 // signed_data += RRSIG_RDATA(signer's name)
2772 data_ptr
+= copy_canonical_name(data_ptr
, dnssec_rrsig
->signer_name
);
2774 for (mDNSu8 i
= 0; i
< rr_count
; i
++) {
2775 const dnssec_rr_t
* const rr
= rr_array
[i
];
2776 if (rr
== mDNSNULL
) { // the current record is a duplicate one
2780 // signed_data+= RR(i)
2781 data_ptr
+= copy_rr_for_signed_data(data_ptr
, rr
, dnssec_rrsig
);
2784 *out_signed_data_length
= signed_data_length
;
2785 number_bytes_copied
= data_ptr
- signed_data
;
2786 require_action(number_bytes_copied
== signed_data_length
, exit
, error
= mStatus_UnknownErr
;
2787 log_error("reconstruct_signed_data failed, number of bytes copied is not equal to the size of memory allocated; copied=%u, allocated=%u",
2788 number_bytes_copied
, signed_data_length
));
2789 require_quiet(data_ptr
== data_limit
, exit
);
2792 if (error
!= mStatus_NoError
) {
2793 if (signed_data
!= mDNSNULL
) {
2795 signed_data
= mDNSNULL
;
2801 //======================================================================================================================
2802 // calculate_signed_data_length
2803 //======================================================================================================================
2806 calculate_signed_data_length(
2807 const dnssec_rr_t
* const rr_array
[_Nonnull
],
2808 const mDNSu8 rr_count
,
2809 const dnssec_rrsig_t
* const _Nonnull dnssec_rrsig
,
2810 mDNSu32
* const _Nonnull out_length
) {
2812 mStatus error
= mStatus_NoError
;
2813 mDNSu32 signed_data_length
= 0;
2815 // signed_data += RRSIG_RDATA(before signer's name) + signer's name
2816 signed_data_length
+= offsetof(dns_type_rrsig_t
, signer_name
) + canonical_form_name_length(dnssec_rrsig
->signer_name
);
2818 // signed_data += RR(x)
2819 for (mDNSu8 i
= 0; i
< rr_count
; i
++) {
2820 const dnssec_rr_t
* const rr
= rr_array
[i
];
2821 mDNSu32 rr_length
= 0;
2822 mDNSs16 name_length
= 0;
2823 if (rr
== mDNSNULL
) { // It is a duplicate records, now skips it.
2827 name_length
= calculate_name_length_in_signed_data(rr
->name
.c
, dnssec_rrsig
->labels
);
2828 require_action(name_length
!= -1, exit
, error
= mStatus_Invalid
;
2829 log_default("rrsig label count is invalid, cannot be used to validate records;"));
2832 rr_length
+= name_length
;
2834 // RR(i) += type + class + OrigTTL + RDATA length
2835 rr_length
+= sizeof(rr
->rr_type
) + sizeof(rr
->rr_class
) + sizeof(dnssec_rrsig
->original_TTL
) + sizeof(rr
->rdata_length
);
2838 rr_length
+= calculate_rdata_length_in_signed_data(rr
);
2840 signed_data_length
+= rr_length
;
2843 *out_length
= signed_data_length
;
2848 //======================================================================================================================
2849 // calculate_name_length_in_signed_data
2850 //======================================================================================================================
2852 // length is calculated based on RFC 4035 Section 5.3.2. Reconstructing the Signed Data
2854 calculate_name_length_in_signed_data(const mDNSu8
* const _Nonnull name
, const mDNSu8 rrsig_labels
) {
2855 // assume that the domainname* is already fully qualified
2856 mDNSu8 name_labels
= get_number_of_labels(name
);
2857 if (name_labels
== rrsig_labels
) {
2858 return DOMAIN_NAME_LENGTH(name
);
2859 } else if (name_labels
> rrsig_labels
) {
2860 // wild card case, ignore this case for now
2861 return DOMAIN_NAME_LENGTH(name
);
2863 // name_labels < rrsig_labels
2868 //======================================================================================================================
2869 // calculate_rdata_length_in_signed_data
2870 //======================================================================================================================
2872 // ref: https://tools.ietf.org/html/rfc4034#section-6.2
2874 calculate_rdata_length_in_signed_data(const dnssec_rr_t
* const _Nonnull dnssec_rr
) {
2876 // 1. All the name in the rr is fully expanded and fully qualified.
2877 // 2. There is no wildcard name.
2879 return dnssec_rr
->rdata_length
;
2882 //======================================================================================================================
2883 // copy_canonical_name
2884 //======================================================================================================================
2885 mDNSlocal
const mDNSu8
*
2886 get_wildcard_name(const mDNSu8
* const _Nonnull name
, mDNSu8
* const _Nonnull buffer
, const mDNSu16 buffer_length
) {
2887 const mDNSu8
* ptr
= name
;
2888 const mDNSu16 name_length
= DOMAIN_NAME_LENGTH(ptr
);
2889 const mDNSu8
* const ptr_limit
= ptr
+ name_length
;
2890 mDNSu8
* buffer_ptr
= buffer
;
2892 verify_action(name_length
<= buffer_length
, return mDNSNULL
);
2894 while (ptr
< ptr_limit
) {
2895 const mDNSu8
* const label
= ptr
+ 1;
2896 const mDNSu8 label_length
= *ptr
;
2899 buffer_ptr
[1] = '*';
2901 buffer_ptr
[0] = label_length
;
2902 memcpy(buffer_ptr
+ 1, label
, label_length
);
2906 buffer_ptr
+= 1 + buffer_ptr
[0];
2912 //======================================================================================================================
2913 // copy_rr_for_signed_data
2914 //======================================================================================================================
2917 copy_rr_for_signed_data(
2918 mDNSu8
* _Nonnull dst
,
2919 const dnssec_rr_t
* const _Nonnull rr
,
2920 const dnssec_rrsig_t
* const _Nonnull rrsig
) {
2922 mDNSu16 canonical_rdata_length
;
2923 mDNSu8
* const original_dst
= dst
;
2926 dst
+= copy_name_in_rr_for_signed_data(dst
, rr
->name
.c
, rrsig
);
2929 mDNSu16 rr_type_net
= htons(rr
->rr_type
);
2930 memcpy(dst
, &rr_type_net
, sizeof(rr_type_net
));
2931 dst
+= sizeof(rr_type_net
);
2934 mDNSu16 rr_class_net
= htons(rr
->rr_class
);
2935 memcpy(dst
, &rr_class_net
, sizeof(rr_class_net
));
2936 dst
+= sizeof(rr_class_net
);
2938 // RR(i) += Original TTL
2939 mDNSu32 original_ttl_net
= htonl(rrsig
->original_TTL
);
2940 memcpy(dst
, &original_ttl_net
, sizeof(original_ttl_net
));
2941 dst
+= sizeof(original_ttl_net
);
2943 // RR(i) += RDATA length (canonical form of RDATA)
2944 canonical_rdata_length
= calculate_rdata_length_in_signed_data(rr
);
2945 mDNSu16 canonical_rdata_length_net
= ntohs(canonical_rdata_length
);
2946 memcpy(dst
, &canonical_rdata_length_net
, sizeof(canonical_rdata_length_net
));
2947 dst
+= sizeof(canonical_rdata_length_net
);
2949 // RR(i) += RDATA (canonical form)
2950 dst
+= copy_rdata_in_rr(dst
, rr
->rdata
, rr
->rdata_length
, rr
->rr_type
);
2952 return dst
- original_dst
;
2955 //======================================================================================================================
2956 // copy_name_in_rr_for_signed_data
2957 //======================================================================================================================
2960 copy_name_in_rr_for_signed_data(
2961 mDNSu8
* const _Nonnull dst
,
2962 const mDNSu8
* const _Nonnull name
,
2963 const dnssec_rrsig_t
* const _Nonnull dnssec_rrsig
) {
2965 mDNSu8 name_labels
= get_number_of_labels(name
);
2966 mDNSu8 rrsig_labels
= dnssec_rrsig
->labels
;
2969 if (name_labels
== rrsig_labels
) {
2970 bytes_write
= copy_canonical_name(dst
, name
);
2972 // name_labels > rrsig_labels
2973 // It is impossible to have "name_labels < rrsig_labels", since the function calculate_signed_data_length
2974 // already checks the validity of the records.
2975 // TODO: wildcard domain name.
2982 //======================================================================================================================
2984 //======================================================================================================================
2986 // The rdata is in the canonical form. ref: https://tools.ietf.org/html/rfc4034#section-6.2
2988 copy_rdata_in_rr(mDNSu8
* const _Nonnull dst
, const mDNSu8
* const rdata
, const mDNSu16 rdata_length
, const mDNSu8 rr_type
) {
2989 // TODO: First assume all the rdata is already in canonical form.
2992 memcpy(dst
, rdata
, rdata_length
);
2994 return rdata_length
;
2997 //======================================================================================================================
2999 //======================================================================================================================
3001 //======================================================================================================================
3002 // sort_records_with_algorithm
3003 //======================================================================================================================
3006 sort_records_with_algorithm(dnssec_context_t
* const _Nonnull context
) {
3008 originals_with_rrsig_t
* originals_with_rrsig
= &context
->original
.original_result_with_rrsig
;
3009 response_type_t type
;
3011 type
= originals_with_rrsig
->type
;
3012 // sort RRSIG in original response
3014 case original_response
:
3015 case cname_response
:
3016 if (type
== original_response
) {
3017 rrsigs
= &originals_with_rrsig
->u
.original
.rrsig_records
;
3018 } else if (type
== cname_response
) {
3019 rrsigs
= &originals_with_rrsig
->u
.cname_with_rrsig
.rrsig_records
;
3021 goto invalid_type_exit
;
3023 list_sort(rrsigs
, &dnssec_rrsig_t_comparator
);
3026 case nsec3_response
:
3027 if (type
== nsec_response
) {
3028 list_t
*nsec_list
= &originals_with_rrsig
->u
.nsecs_with_rrsig
.nsec_and_rrsigs_same_name
;
3029 for (list_node_t
*nsec_node
= list_get_first(nsec_list
); !list_has_ended(nsec_list
, nsec_node
); nsec_node
= list_next(nsec_node
)) {
3030 one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
*)nsec_node
->data
;
3031 list_sort(&one_nsec
->rrsig_records
, &dnssec_rrsig_t_comparator
);
3033 } else if (type
== nsec3_response
) {
3034 list_t
*nsec3_list
= &originals_with_rrsig
->u
.nsec3s_with_rrsig
.nsec3_and_rrsigs_same_name
;
3035 for (list_node_t
*nsec3_node
= list_get_first(nsec3_list
); !list_has_ended(nsec3_list
, nsec3_node
); nsec3_node
= list_next(nsec3_node
)) {
3036 one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
*)nsec3_node
->data
;
3037 list_sort(&one_nsec3
->rrsig_records
, &dnssec_rrsig_t_comparator
);
3040 goto invalid_type_exit
;
3044 goto invalid_type_exit
;
3048 // sort RRSIG and DS in zone records
3049 for (list_node_t
*node
= list_get_first(&context
->zone_chain
); !list_has_ended(&context
->zone_chain
, node
); node
= list_next(node
)) {
3050 dnssec_zone_t
* zone
= (dnssec_zone_t
*)node
->data
;
3051 dnskeys_with_rrsig_t
* dnskeys_with_rrsig
= &zone
->dnskeys_with_rrsig
;
3052 dses_with_rrsig_t
* dses_with_rrsig
= &zone
->dses_with_rrsig
;
3054 // sort DNSKEY RRSIG
3055 if (zone
->dnskey_request_started
) {
3056 list_sort(&dnskeys_with_rrsig
->rrsig_records
, &dnssec_rrsig_t_comparator
);
3059 if (zone
->ds_request_started
)
3062 type
= dses_with_rrsig
->type
;
3064 case original_response
:
3065 list_sort(&dses_with_rrsig
->u
.original
.rrsig_records
, &dnssec_rrsig_t_comparator
);
3068 case nsec3_response
:
3069 if (type
== nsec_response
) {
3070 list_t
*nsec_list
= &dses_with_rrsig
->u
.nsecs_with_rrsig
.nsec_and_rrsigs_same_name
;
3071 for (list_node_t
*nsec_node
= list_get_first(nsec_list
); !list_has_ended(nsec_list
, nsec_node
); nsec_node
= list_next(nsec_node
)) {
3072 one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
*)nsec_node
->data
;
3073 list_sort(&one_nsec
->rrsig_records
, &dnssec_rrsig_t_comparator
);
3075 } else if (type
== nsec3_response
) {
3076 list_t
*nsec3_list
= &dses_with_rrsig
->u
.nsec3s_with_rrsig
.nsec3_and_rrsigs_same_name
;
3077 for (list_node_t
*nsec3_node
= list_get_first(nsec3_list
); !list_has_ended(nsec3_list
, nsec3_node
); nsec3_node
= list_next(nsec3_node
)) {
3078 one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
*)nsec3_node
->data
;
3079 list_sort(&one_nsec3
->rrsig_records
, &dnssec_rrsig_t_comparator
);
3082 goto invalid_type_exit
;
3086 goto invalid_type_exit
;
3093 log_error("Invalid original response type; type=%d", type
);
3097 //======================================================================================================================
3098 // dnssec_ds_t_comparator
3099 //======================================================================================================================
3100 mDNSlocal mDNSs8 __unused
3101 dnssec_ds_t_comparator(const list_node_t
* _Nonnull
const left
, const list_node_t
* _Nonnull
const right
) {
3103 dnssec_ds_t
* left_ds
= (dnssec_ds_t
*)left
->data
;
3104 dnssec_ds_t
* right_ds
= (dnssec_ds_t
*)right
->data
;
3105 mDNSs16 left_priority
= get_priority_of_ds_digest(left_ds
->digest_type
);
3106 mDNSs16 right_priority
= get_priority_of_ds_digest(right_ds
->digest_type
);
3108 if (left_priority
< right_priority
) {
3110 } else if (left_priority
> right_priority
) {
3113 // left_priority == right_priority
3120 //======================================================================================================================
3121 // dnssec_rrsig_t_comparator
3122 //======================================================================================================================
3125 dnssec_rrsig_t_comparator(const list_node_t
* _Nonnull
const left
, const list_node_t
* _Nonnull
const right
) {
3127 dnssec_rrsig_t
*left_rrsig
= (dnssec_rrsig_t
*)left
->data
;
3128 dnssec_rrsig_t
*right_rrsig
= (dnssec_rrsig_t
*)right
->data
;
3129 mDNSs16 left_priority
= get_priority_of_dnskey_algorithm(left_rrsig
->algorithm
);
3130 mDNSs16 right_priority
= get_priority_of_dnskey_algorithm(right_rrsig
->algorithm
);
3132 if (left_priority
< right_priority
) {
3134 } else if (left_priority
> right_priority
) {
3137 // left_priority == right_priority
3144 //======================================================================================================================
3146 //======================================================================================================================
3149 sort_rr_array_canonically(const dnssec_rr_t
* rr_array
[_Nonnull
], const mDNSu8 rr_count
) {
3150 // insertion sort is good for partially sorted array
3151 for (mDNSs32 j
, i
= 1; i
< rr_count
; i
++) {
3152 const dnssec_rr_t
* dnssec_rr_to_insert
= rr_array
[i
];
3155 while (j
>= 0 && dnssec_rr_t_comparator(dnssec_rr_to_insert
, rr_array
[j
]) == -1) {
3156 rr_array
[j
+ 1] = rr_array
[j
];
3159 rr_array
[j
+ 1] = dnssec_rr_to_insert
;
3163 //======================================================================================================================
3165 //======================================================================================================================
3168 dnssec_rr_t_comparator(const dnssec_rr_t
* const _Nonnull left
, const dnssec_rr_t
* const _Nonnull right
) {
3169 mDNSu16 left_length
= left
->rdata_length
;
3170 mDNSu16 right_length
= right
->rdata_length
;
3171 mDNSu16 min_length
= MIN(left_length
, right_length
);
3172 mDNSs32 memcmp_result
= memcmp(left
->rdata
, right
->rdata
, min_length
);
3174 if (memcmp_result
< 0) {
3176 } else if (memcmp_result
> 0) {
3179 // memcmp_result == 0
3180 if (left_length
> right_length
) {
3182 } else if (left_length
< right_length
) {
3185 // left_length == right_length
3186 log_error("two RR are canonically equal;");
3193 //======================================================================================================================
3195 //======================================================================================================================
3198 rr_array_dedup(const dnssec_rr_t
* rr_array
[_Nonnull
], const mDNSu8 rr_count
) {
3199 mDNSBool duplicate
= mDNSfalse
;
3200 for (int i
= 0, n
= (int)rr_count
- 1; i
< n
; i
++) {
3201 const dnssec_rr_t
*prev
= rr_array
[i
];
3202 const dnssec_rr_t
*next
= rr_array
[i
+ 1];
3203 if (equal_dnssec_rr_t(prev
, next
)) {
3204 rr_array
[i
] = mDNSNULL
;
3205 duplicate
= mDNStrue
;
3211 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)