]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/dnssec_v2/dnssec_v2_crypto.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / dnssec_v2 / dnssec_v2_crypto.c
1 //
2 // dnssec_v2_crypto.c
3 // mDNSResponder
4 //
5 // Copyright (c) 2020 Apple Inc. All rights reserved.
6 //
7
8 #include "mDNSEmbeddedAPI.h"
9 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
10 #include <stdio.h>
11 #include <CommonCrypto/CommonDigestSPI.h>
12 #include <Security/Security.h>
13 #include <Security/SecKeyPriv.h>
14 #include "dnssec_v2_crypto.h"
15 #include "dnssec_v2_helper.h"
16 #include "dnssec_v2_log.h"
17 #include "base_n.h"
18
19 mDNSlocal void
20 parse_rsa_pubkey(
21 mDNSu8 * const _Nonnull public_key,
22 const mDNSu16 key_length,
23 uint8_t ** const _Nonnull out_modulus,
24 signed long * const _Nonnull out_modulus_length,
25 uint8_t ** const _Nonnull out_exponent,
26 signed long * const _Nonnull out_exponent_length);
27
28 mDNSlocal void
29 print_validation_progress(const mDNSu32 request_id, const dnssec_dnskey_t * const dnskey, const dnssec_rrsig_t * const rrsig);
30
31 // The array index means the algorithm number, the array element value means the prefered order to use when there is
32 // multiple algorithms avaliable, the order is determined by "The most secure, the better", 0 is the lowest priority.
33
34 //======================================================================================================================
35 // get_priority_of_ds_digest
36 //======================================================================================================================
37
38 mDNSexport mDNSs16
39 get_priority_of_ds_digest(mDNSu8 digest) {
40 // ref 1: https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml
41 // ref 2: https://tools.ietf.org/html/draft-ietf-dnsop-algorithm-update-10
42 mDNSs16 priority;
43
44 switch (digest) {
45 case DS_DIGEST_SHA_1:
46 // Algorithm Number 1 SHA-1 MUST
47 priority = 0;
48 break;
49 case DS_DIGEST_SHA_256:
50 // Algorithm Number 2 SHA-256 MUST
51 priority = 1;
52 break;
53 case DS_DIGEST_SHA_384:
54 // Algorithm Number 4 SHA-384 RECOMMENDED
55 priority = 2;
56 break;
57 default:
58 // Algorithm Number 0 Reserved
59 // Algorithm Number 3 GOST R 34.11-94 NOT SUPPORTED
60 // Algorithm Number 5-255 Unassigned
61 priority = -1;
62 break;
63 }
64
65 return priority;
66 }
67
68 //======================================================================================================================
69 // get_priority_of_dnskey_algorithm
70 //======================================================================================================================
71
72 mDNSexport mDNSs16
73 get_priority_of_dnskey_algorithm(mDNSu8 algorithm) {
74 // ref 1: https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xml
75 // ref 2: https://tools.ietf.org/html/draft-ietf-dnsop-algorithm-update-10
76
77 mDNSs16 priority;
78
79 switch (algorithm) {
80 case DNSKEY_ALGORITHM_RSASHA1:
81 // Algorithm Number 5 RSA/SHA-1 MUST
82 priority = 0;
83 break;
84 case DNSKEY_ALGORITHM_RSASHA1_NSEC3_SHA1:
85 // Algorithm Number 7 RSASHA1-NSEC3-SHA1 MUST
86 priority = 1;
87 break;
88 case DNSKEY_ALGORITHM_RSASHA256:
89 // Algorithm Number 8 RSA/SHA-256 MUST
90 priority = 2;
91 break;
92 case DNSKEY_ALGORITHM_RSASHA512:
93 // Algorithm Number 10 RSA/SHA-512 MUST
94 priority = 3;
95 break;
96 case DNSKEY_ALGORITHM_ECDSAP256SHA256:
97 // Algorithm Number 13 ECDSA Curve P-256 with SHA-256 RECOMMENDED
98 priority = 4;
99 break;
100 case DNSKEY_ALGORITHM_ECDSAP384SHA384:
101 // Algorithm Number 14 ECDSA Curve P-384 with SHA-384 RECOMMENDED
102 priority = 5;
103 break;
104 default:
105 // Algorithm Number 0 Delete N/A
106 // Algorithm Number 1 RSA/MD5 MUST NOT
107 // Algorithm Number 2 Diffie-Hellman NOT SUPPORTED
108 // Algorithm Number 3 DSA/SHA1 MUST NOT
109 // Algorithm Number 4 Reserved
110 // Algorithm Number 6 DSA-NSEC3-SHA1 MUST NOT
111 // Algorithm Number 9 Reserved
112 // Algorithm Number 11 Reserved
113 // Algorithm Number 12 GOST R 34.10-2001 MAY
114 // Algorithm Number 15 Ed25519 RECOMMENDED, but NOT SUPPORTED
115 // Algorithm Number 16 Ed448 RECOMMENDED, but NOT SUPPORTED
116 // Algorithm Number 17-122 Unassigned
117 // Algorithm Number 123-251 Reserved
118 // Algorithm Number 252 Reserved for Indirect Keys
119 // Algorithm Number 253 private algorithm
120 // Algorithm Number 254 private algorithm OID
121 // Algorithm Number 255 Reserved
122 priority = -1;
123 break;
124 }
125
126 return priority;
127 }
128
129 //======================================================================================================================
130 // validate_signed_data_with_rrsig_and_dnskey
131 // the main function doing signature validation
132 //======================================================================================================================
133
134 mDNSexport mDNSBool
135 validate_signed_data_with_rrsig_and_dnskey(
136 const mDNSu32 request_id,
137 const mDNSu8 * const _Nonnull signed_data,
138 const mDNSu32 signed_data_length,
139 const dnssec_rrsig_t * const _Nonnull rrsig,
140 const dnssec_dnskey_t * const _Nonnull dnskey) {
141
142 mDNSBool valid = mDNSfalse;
143 const mDNSu8 * data_or_digest_be_signed = mDNSNULL;
144 mDNSu32 data_or_digest_be_signed_length;
145 SecKeyAlgorithm verify_algorithm;
146 const void * public_key_type;
147 CFErrorRef cf_error = mDNSNULL;
148 CFDataRef data_to_verify_CFData = mDNSNULL;
149 CFDataRef sig_to_match_CFData = mDNSNULL;
150 SecKeyRef key = mDNSNULL;
151 digest_type_t digest_type = DIGEST_UNSUPPORTED;
152
153 // choose different signature validation algorithm and public key
154 switch (dnskey->algorithm) {
155 case DNSKEY_ALGORITHM_RSASHA1:
156 verify_algorithm = kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1;
157 public_key_type = kSecAttrKeyTypeRSA;
158 break;
159 case DNSKEY_ALGORITHM_RSASHA1_NSEC3_SHA1:
160 verify_algorithm = kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1;
161 public_key_type = kSecAttrKeyTypeRSA;
162 break;
163 case DNSKEY_ALGORITHM_RSASHA256:
164 verify_algorithm = kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256;
165 public_key_type = kSecAttrKeyTypeRSA;
166 break;
167 case DNSKEY_ALGORITHM_RSASHA512:
168 verify_algorithm = kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512;
169 public_key_type = kSecAttrKeyTypeRSA;
170 break;
171 case DNSKEY_ALGORITHM_ECDSAP256SHA256:
172 verify_algorithm = kSecKeyAlgorithmECDSASignatureRFC4754;
173 public_key_type = kSecAttrKeyTypeECSECPrimeRandom;
174 digest_type = DIGEST_SHA_256;
175 data_or_digest_be_signed_length = 32;
176 break;
177 case DNSKEY_ALGORITHM_ECDSAP384SHA384:
178 verify_algorithm = kSecKeyAlgorithmECDSASignatureRFC4754;
179 public_key_type = kSecAttrKeyTypeECSECPrimeRandom;
180 digest_type = DIGEST_SHA_384;
181 data_or_digest_be_signed_length = 48;
182 break;
183 default:
184 log_error("Unsupported DNSKEY algorithm; algorithm=%d", dnskey->algorithm);
185 goto exit;
186 }
187
188 // public key creation for RSA and ECDSA is different
189 if (public_key_type == kSecAttrKeyTypeRSA) {
190 // RSA
191 // The format of public key is not the standard PEM DER ASN.1 PKCS#1 RSA Public key format, so we need to parse
192 // the modulus and exponent explicitly.
193 SecRSAPublicKeyParams params;
194 parse_rsa_pubkey(dnskey->public_key, dnskey->public_key_length, &params.modulus, &params.modulusLength, &params.exponent, &params.exponentLength);
195 key = SecKeyCreateRSAPublicKey(kCFAllocatorDefault, (const uint8_t *)&params, sizeof(params), kSecKeyEncodingRSAPublicParams);
196 require_quiet(key != mDNSNULL, exit);
197
198 data_or_digest_be_signed = signed_data;
199 data_or_digest_be_signed_length = signed_data_length;
200 // RSA uses original data to verify record.
201 } else if (public_key_type == kSecAttrKeyTypeECSECPrimeRandom) {
202 // ECDSA
203 const void * public_key_options_key[] = {kSecAttrKeyType, kSecAttrKeyClass};
204 const void * public_key_options_values[] = {kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClassPublic};
205 CFDataRef public_key_CFData = mDNSNULL;
206 CFDictionaryRef public_key_options = mDNSNULL;
207 CFNumberRef key_size_CFNumber = mDNSNULL;
208 mDNSu8 * ecdsa_key_bytes_encoding = mDNSNULL;
209 mDNSu32 ecdsa_key_length = dnskey->public_key_length + 1;
210 mDNSu8 data_digest[MAX_HASH_OUTPUT_SIZE];
211
212 // create security framework readable public key format
213 ecdsa_key_bytes_encoding = malloc(ecdsa_key_length);
214 require_quiet(ecdsa_key_bytes_encoding != mDNSNULL, ecdsa_exit);
215
216 ecdsa_key_bytes_encoding[0] = 4;
217 memcpy(ecdsa_key_bytes_encoding + 1, dnskey->public_key, dnskey->public_key_length);
218
219 public_key_CFData = CFDataCreate(kCFAllocatorDefault, ecdsa_key_bytes_encoding, ecdsa_key_length);
220 require_quiet(public_key_CFData != NULL, ecdsa_exit);
221
222 public_key_options = CFDictionaryCreate(kCFAllocatorDefault, public_key_options_key,
223 public_key_options_values, sizeof(public_key_options_key) / sizeof(void *),
224 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
225 require_quiet(public_key_options != NULL, ecdsa_exit);
226
227 // create the public key
228 key = SecKeyCreateWithData(public_key_CFData, public_key_options, &cf_error);
229 require_action(key != mDNSNULL, ecdsa_exit, log_error("SecKeyCreateWithData failed: %@", CFErrorCopyDescription(cf_error)));
230
231 // ECDSA uses digest to verify record.
232 mDNSBool calculated = calculate_digest_for_data(signed_data, signed_data_length, digest_type, data_digest, sizeof(data_digest));
233 require_action(calculated, ecdsa_exit, log_error("calculate_digest_for_data failed to return the digest;"));
234 data_or_digest_be_signed = data_digest;
235 // data_be_signed_length is set in the previous switch statement.
236
237 ecdsa_exit:
238 if (public_key_CFData != NULL) CFRelease(public_key_CFData);
239 if (public_key_options != NULL) CFRelease(public_key_options);
240 if (key_size_CFNumber != NULL) CFRelease(key_size_CFNumber);
241 if (cf_error != NULL) {
242 CFRelease(cf_error);
243 cf_error = mDNSNULL;
244 }
245 if (ecdsa_key_bytes_encoding != mDNSNULL) free(ecdsa_key_bytes_encoding);
246 } else {
247 goto exit;
248 }
249
250 require_quiet(key != mDNSNULL, exit);
251
252 // create data and signature to verify
253 data_to_verify_CFData = CFDataCreate(kCFAllocatorDefault, data_or_digest_be_signed, data_or_digest_be_signed_length);
254 sig_to_match_CFData = CFDataCreate(kCFAllocatorDefault, rrsig->signature, rrsig->signature_length);
255
256 Boolean matches = SecKeyVerifySignature(key, verify_algorithm, data_to_verify_CFData, sig_to_match_CFData, &cf_error);
257 if (matches) {
258 print_validation_progress(request_id, dnskey, rrsig);
259 } else {
260 log_default("SecKeyVerifySignature error: %@", CFErrorCopyDescription(cf_error));
261 }
262
263 valid = matches ? mDNStrue : mDNSfalse;
264
265 exit:
266 if (key != mDNSNULL) CFRelease(key);
267 if (data_to_verify_CFData != mDNSNULL) CFRelease(data_to_verify_CFData);
268 if (sig_to_match_CFData != mDNSNULL) CFRelease(sig_to_match_CFData);
269 if (cf_error != mDNSNULL) CFRelease(cf_error);
270
271 return valid;
272 }
273
274 //======================================================================================================================
275 // Hash
276 //======================================================================================================================
277
278 //======================================================================================================================
279 // calculate_digest_for_data
280 // get the corresponding digest
281 //======================================================================================================================
282
283 mDNSexport mDNSBool
284 calculate_digest_for_data(
285 const mDNSu8 * const _Nonnull data,
286 const mDNSu32 data_length,
287 const digest_type_t digest_type,
288 mDNSu8 * const _Nonnull digest_buffer,
289 mDNSu32 buffer_size) {
290
291 CCDigestAlgorithm cc_digest_algorithm;
292 CCDigestCtx cc_digest_context;
293 mDNSBool calculated = mDNSfalse;
294
295 switch (digest_type) {
296 case DIGEST_SHA_1: // SHA-1
297 require_quiet(buffer_size >= SHA1_OUTPUT_SIZE, exit); // SHA-1 produces 20 bytes
298 #pragma clang diagnostic push // ignore the deprecation warning for SHA-1, since NSEC3 now only uses SHA-1 to get the digest.
299 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
300 cc_digest_algorithm = kCCDigestSHA1;
301 #pragma clang diagnostic pop
302 break;
303 case DIGEST_SHA_256: // SHA-256
304 require_quiet(buffer_size >= SHA256_OUTPUT_SIZE, exit); // SHA-256 produces 256-bit(32-byte) digest
305 cc_digest_algorithm = kCCDigestSHA256;
306 break;
307 case DIGEST_SHA_384: // SHA-384
308 require_quiet(buffer_size >= SHA384_OUTPUT_SIZE, exit); // SHA-384 produces 384-bit(48-byte) digest
309 cc_digest_algorithm = kCCDigestSHA384;
310 break;
311 case DIGEST_SHA_512: // SHA-512
312 require_quiet(buffer_size >= SHA512_OUTPUT_SIZE, exit); // SHA-512 produces 512-bit(64-byte) digest
313 cc_digest_algorithm = kCCDigestSHA512;
314 break;
315 default:
316 goto exit;
317 }
318
319 CCDigestInit(cc_digest_algorithm, &cc_digest_context);
320 CCDigestUpdate(&cc_digest_context, data, data_length);
321 CCDigestFinal(&cc_digest_context, digest_buffer);
322 calculated = mDNStrue;
323
324 exit:
325 return calculated;
326 }
327
328 //======================================================================================================================
329 // calculate_b32_hash_for_nsec3
330 // get Base32 encoding from the digest of riginal data
331 //======================================================================================================================
332
333 mDNSexport mDNSu8 * _Nullable
334 calculate_b32_hash_for_nsec3(
335 const mDNSu8 * const _Nonnull name,
336 const mDNSu16 name_length,
337 const mDNSu8 hash_type,
338 const mDNSu8 * const _Nullable salt,
339 const mDNSu32 salt_length,
340 const mDNSu16 iterations) {
341
342 mDNSu8 name_hash[MAX_HASH_OUTPUT_SIZE];
343 mDNSu32 name_hash_length;
344 mDNSu8 *name_hash_b32 = mDNSNULL;
345
346 name_hash_length = get_hash_length_for_nsec3_hash_type(hash_type);
347
348 mDNSBool calculated = calculate_hash_for_nsec3(name_hash, sizeof(name_hash), hash_type, name, name_length, salt, salt_length, iterations);
349 require_quiet(calculated, exit);
350
351 name_hash_b32 = (mDNSu8 *)base_n_encode(DNSSEC_BASE_32_HEX, name_hash, name_hash_length);
352 require_quiet(name_hash_b32 != mDNSNULL, exit);
353
354 exit:
355 return name_hash_b32;
356 }
357
358 //======================================================================================================================
359 // calculate_hash_for_nsec3
360 // get the hash value for nsec3 which includes salt and multiple iteration
361 //======================================================================================================================
362
363 mDNSexport mDNSBool
364 calculate_hash_for_nsec3(
365 mDNSu8 * const _Nonnull hash_buffer,
366 const mDNSu32 buffer_size,
367 const mDNSu8 hash_type,
368 const mDNSu8 * const _Nonnull name,
369 const mDNSu16 name_length,
370 const mDNSu8 * const _Nullable salt,
371 const mDNSu32 salt_length,
372 const mDNSu16 iterations) {
373
374 // data_to_be_hashed will be used to generate the hash, it should be big enough to hold 1) first hash iteration: name | salt, 2) the remaining iteration: hash_result_from_the_last_iteration | salt.
375 mDNSu8 data_to_be_hashed[MAX(MAX_HASH_OUTPUT_SIZE, MAX_DOMAIN_NAME) + 256];
376 mDNSu32 data_length;
377 mDNSu32 hash_length;
378 digest_type_t digest_type;
379 mDNSBool calculated = mDNSfalse;
380
381 memcpy(data_to_be_hashed, name, name_length);
382 memcpy(data_to_be_hashed + name_length, salt, salt_length);
383 data_length = name_length + salt_length;
384
385 // choose correct hash algorithm to get digest
386 switch (hash_type) {
387 case NSEC3_HASH_ALGORITHM_SHA_1:
388 digest_type = DIGEST_SHA_1;
389 hash_length = 20;
390 break;
391 default:
392 goto exit;
393 }
394 calculated = calculate_digest_for_data(data_to_be_hashed, data_length, digest_type, hash_buffer, buffer_size);
395 require_quiet(calculated, exit);
396
397 // do iteration
398 for (mDNSs32 i = 0; i < iterations; i++) {
399 memcpy(data_to_be_hashed, hash_buffer, hash_length);
400 memcpy(data_to_be_hashed + hash_length, salt, salt_length);
401 data_length = hash_length + salt_length;
402
403 calculated = calculate_digest_for_data(data_to_be_hashed, data_length, hash_type, hash_buffer, buffer_size);
404 require_quiet(calculated, exit);
405 }
406
407 calculated = mDNStrue;
408 exit:
409 return calculated;
410 }
411
412 //======================================================================================================================
413 // get_hash_length_for_nsec3_hash_type
414 //======================================================================================================================
415
416 mDNSexport mDNSu32
417 get_hash_length_for_nsec3_hash_type(const nsec3_hash_algorithm_type_t nsec3_hash_type) {
418 digest_type_t digest_type;
419
420 switch (nsec3_hash_type) {
421 case NSEC3_HASH_ALGORITHM_SHA_1:
422 digest_type = DIGEST_SHA_1;
423 break;
424 default:
425 digest_type = DIGEST_UNSUPPORTED;
426 break;
427 }
428
429 return get_digest_length_for_digest_type(digest_type);
430 }
431
432 //======================================================================================================================
433 // get_digest_length_for_digest_type
434 //======================================================================================================================
435
436 mDNSexport mDNSu32
437 get_digest_length_for_ds_digest_type(const ds_digest_type_t ds_digest_type) {
438 digest_type_t digest_type;
439
440 switch (ds_digest_type) {
441 case DS_DIGEST_SHA_1:
442 digest_type = DIGEST_SHA_1;
443 break;
444 case DS_DIGEST_SHA_256:
445 digest_type = DIGEST_SHA_256;
446 break;
447 case DS_DIGEST_SHA_384:
448 digest_type = DIGEST_SHA_384;
449 break;
450 default:
451 digest_type = DIGEST_UNSUPPORTED;
452 break;
453 }
454
455 return get_digest_length_for_digest_type(digest_type);
456 }
457
458 //======================================================================================================================
459 // get_digest_length_for_digest_type
460 //======================================================================================================================
461
462 mDNSexport mDNSu32
463 get_digest_length_for_digest_type(const digest_type_t digest_type) {
464 mDNSu32 digest_length;
465
466 switch (digest_type) {
467 case DIGEST_SHA_1:
468 digest_length = SHA1_OUTPUT_SIZE;
469 break;
470 case DIGEST_SHA_256:
471 digest_length = SHA256_OUTPUT_SIZE;
472 break;
473 case DIGEST_SHA_384:
474 digest_length = SHA384_OUTPUT_SIZE;
475 break;
476 case DIGEST_SHA_512:
477 digest_length = SHA512_OUTPUT_SIZE;
478 break;
479 default:
480 digest_length = 0;
481 break;
482 }
483
484 return digest_length;
485 }
486
487 //======================================================================================================================
488 // parse_rsa_pubkey
489 // parse RSA key according to https://tools.ietf.org/html/rfc3110
490 //======================================================================================================================
491
492 mDNSlocal void
493 parse_rsa_pubkey(
494 mDNSu8 * const _Nonnull public_key,
495 const mDNSu16 key_length,
496 uint8_t ** const _Nonnull out_modulus,
497 signed long * const _Nonnull out_modulus_length,
498 uint8_t ** const _Nonnull out_exponent,
499 signed long * const _Nonnull out_exponent_length) {
500
501 mDNSu8 exponent_length_length;
502 if (public_key[0] != 0) {
503 *out_exponent_length = public_key[0];
504 exponent_length_length = 1;
505 } else {
506 *out_exponent_length = (((uint32_t)public_key[1] << 8) | (uint32_t)public_key[2]);
507 exponent_length_length = 3;
508 }
509
510 *out_exponent = public_key + exponent_length_length;
511
512 *out_modulus_length = key_length - (*out_exponent_length + exponent_length_length);
513
514 *out_modulus = public_key + exponent_length_length + *out_exponent_length;
515 }
516
517 //======================================================================================================================
518 // Canonical order and form
519 //======================================================================================================================
520
521 //======================================================================================================================
522 // canonical_form_name_length
523 //======================================================================================================================
524
525 mDNSexport mDNSu8
526 canonical_form_name_length(const mDNSu8 * const _Nonnull name) {
527 // assume that domainname* is already in canonical form
528 return DOMAIN_NAME_LENGTH(name);
529 }
530
531 //======================================================================================================================
532 // compare_canonical_dns_name
533 // compare the domain name from the right most label, and compare label by label
534 //======================================================================================================================
535
536 mDNSexport mDNSs8
537 compare_canonical_dns_name(const mDNSu8 * const _Nonnull left, const mDNSu8 * const _Nonnull right) {
538 const mDNSu16 left_len = DOMAIN_NAME_LENGTH(left);
539 const mDNSu8 * left_limit = left + left_len - 1;
540 const mDNSu16 right_len = DOMAIN_NAME_LENGTH(right);
541 const mDNSu8 * right_limit = right + right_len - 1;
542 mDNSBool result;
543
544 const mDNSu8 * left_label_length_ptrs[256];
545 mDNSu32 left_ptrs_size = 0;
546 const mDNSu8 * right_label_length_ptrs[256];
547 mDNSu32 right_ptrs_size = 0;
548
549 // load the start of each label into an array
550 for (const mDNSu8 * left_ptr = left; left_ptr < left_limit; left_ptr += 1 + *left_ptr) {
551 left_label_length_ptrs[left_ptrs_size++] = left_ptr;
552 require_action(left_ptrs_size < sizeof(left_label_length_ptrs), exit,
553 result = 0; log_error("domain name has more than 255 labels, returning 0"));
554 }
555
556 for (const mDNSu8 * right_ptr = right; right_ptr < right_limit; right_ptr += 1 + *right_ptr) {
557 right_label_length_ptrs[right_ptrs_size++] = right_ptr;
558 require_action(right_ptrs_size < sizeof(right_label_length_ptrs), exit,
559 result = 0; log_error("domain name has more than 255 labels, returning 0"));
560 }
561
562 // start comparing
563 while (left_ptrs_size > 0 && right_ptrs_size > 0) {
564 const mDNSu8 * left_ptr = left_label_length_ptrs[left_ptrs_size - 1];
565 const mDNSu8 * right_ptr = right_label_length_ptrs[right_ptrs_size - 1];
566 const mDNSu8 left_label_length = *left_ptr;
567 const mDNSu8 right_label_length = *right_ptr;
568
569 mDNSs8 compare_label = compare_canonical_dns_label(left_ptr + 1, left_label_length, right_ptr + 1, right_label_length);
570 require_action_quiet(compare_label == 0, exit, result = compare_label);
571 left_ptrs_size--;
572 right_ptrs_size--;
573 }
574
575 // -1 -> <
576 // 0 -> =
577 // +1 -> >
578 if (left_ptrs_size == 0 && right_ptrs_size == 0) {
579 result = 0;
580 } else if (left_ptrs_size == 0) {
581 result = -1;
582 } else if (right_ptrs_size == 0) {
583 result = 1;
584 } else {
585 log_error("Impossible case here");
586 result = 0;
587 }
588
589 exit:
590 return result;
591 }
592
593 //======================================================================================================================
594 // copy_canonical_name
595 // copy domain name to canonical form
596 //======================================================================================================================
597
598 mDNSexport mDNSu8
599 copy_canonical_name(mDNSu8 * const _Nonnull dst, const mDNSu8 * const _Nonnull name) {
600 // assume that "name" is already fully expanded.
601 mDNSu16 name_length = DOMAIN_NAME_LENGTH(name);
602 mDNSu8 *ptr = mDNSNULL;
603 mDNSu32 bytes_convert = 0;
604
605 require_action_quiet(name_length > 0 && name_length <= MAX_DOMAIN_NAME, exit, bytes_convert = 0;
606 log_error("name is a malformed DNS name"));
607 memcpy(dst, name, name_length);
608
609 for (ptr = dst; *ptr != 0; ptr += *ptr + 1) {
610 mDNSu8 label_length = *ptr;
611 mDNSu8 * label_end = ptr + label_length;
612 for (mDNSu8 *ch_ptr = ptr + 1; ch_ptr <= label_end; ch_ptr++) {
613 char ch = *ch_ptr;
614 if (IS_UPPER_CASE(ch)) {
615 *ch_ptr = TO_LOWER_CASE(ch);
616 }
617 }
618 }
619
620 bytes_convert = ptr + 1 - dst;
621 verify_action(bytes_convert == name_length,
622 log_error("convert more bytes than the actual name length; written=%u, name_length=%u", bytes_convert, name_length);
623 bytes_convert = 0);
624
625 exit:
626 return bytes_convert;
627 }
628
629 //======================================================================================================================
630 // compare_canonical_dns_label
631 //======================================================================================================================
632
633 mDNSexport mDNSs8
634 compare_canonical_dns_label(
635 const mDNSu8 * _Nonnull left_label,
636 const mDNSu8 left_label_length,
637 const mDNSu8 * _Nonnull right_label,
638 const mDNSu8 right_label_length) {
639
640 mDNSu8 length_limit = MIN(left_label_length, right_label_length);
641
642 for (mDNSu8 i = 0; i < length_limit; i++) {
643 mDNSu8 left_ch = to_lowercase_if_char(*left_label);
644 mDNSu8 right_ch = to_lowercase_if_char(*right_label);
645 if (left_ch < right_ch) return -1;
646 else if (left_ch > right_ch) return 1;
647 left_label++;
648 right_label++;
649 }
650
651 if (left_label_length < right_label_length) {
652 return -1;
653 } else if (left_label_length > right_label_length) {
654 return 1;
655 } else {
656 // left_label_length == right_label_length
657 return 0;
658 }
659 }
660
661 #ifdef UNIT_TEST
662 mDNSexport mDNSu8
663 copy_canonical_name_ut(mDNSu8 * const _Nonnull dst, const mDNSu8 * const _Nonnull name) {
664 return copy_canonical_name(dst, name);
665 }
666 #endif // UNIT_TEST
667
668 mDNSlocal void
669 print_validation_progress(const mDNSu32 request_id, const dnssec_dnskey_t * const dnskey, const dnssec_rrsig_t * const rrsig) {
670 log_default("[R%u] "PRI_DM_NAME ": DNSKEY (alg=%u, tag=%u, length=%u) -----> " PRI_DM_NAME ": " PUB_S, request_id,
671 DM_NAME_PARAM(&dnskey->dnssec_rr.name), dnskey->algorithm, dnskey->key_tag, dnskey->public_key_length,
672 DM_NAME_PARAM(&rrsig->dnssec_rr.name), DNS_TYPE_STR(rrsig->type_covered));
673 }
674
675 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)