]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-dnssec.c
Merge pull request #20303 from andir/sysconfig-example
[thirdparty/systemd.git] / src / resolve / resolved-dns-dnssec.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "alloc-util.h"
4 #include "dns-domain.h"
5 #include "fd-util.h"
6 #include "fileio.h"
7 #include "gcrypt-util.h"
8 #include "hexdecoct.h"
9 #include "memory-util.h"
10 #include "resolved-dns-dnssec.h"
11 #include "resolved-dns-packet.h"
12 #include "sort-util.h"
13 #include "string-table.h"
14
15 #define VERIFY_RRS_MAX 256
16 #define MAX_KEY_SIZE (32*1024)
17
18 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
19 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
20
21 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
22 #define NSEC3_ITERATIONS_MAX 2500
23
24 /*
25 * The DNSSEC Chain of trust:
26 *
27 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
28 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
29 * DS RRs are protected like normal RRs
30 *
31 * Example chain:
32 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
33 */
34
35 uint16_t dnssec_keytag(DnsResourceRecord *dnskey, bool mask_revoke) {
36 const uint8_t *p;
37 uint32_t sum, f;
38
39 /* The algorithm from RFC 4034, Appendix B. */
40
41 assert(dnskey);
42 assert(dnskey->key->type == DNS_TYPE_DNSKEY);
43
44 f = (uint32_t) dnskey->dnskey.flags;
45
46 if (mask_revoke)
47 f &= ~DNSKEY_FLAG_REVOKE;
48
49 sum = f + ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm);
50
51 p = dnskey->dnskey.key;
52
53 for (size_t i = 0; i < dnskey->dnskey.key_size; i++)
54 sum += (i & 1) == 0 ? (uint32_t) p[i] << 8 : (uint32_t) p[i];
55
56 sum += (sum >> 16) & UINT32_C(0xFFFF);
57
58 return sum & UINT32_C(0xFFFF);
59 }
60
61 #if HAVE_GCRYPT
62
63 static int rr_compare(DnsResourceRecord * const *a, DnsResourceRecord * const *b) {
64 const DnsResourceRecord *x = *a, *y = *b;
65 size_t m;
66 int r;
67
68 /* Let's order the RRs according to RFC 4034, Section 6.3 */
69
70 assert(x);
71 assert(x->wire_format);
72 assert(y);
73 assert(y->wire_format);
74
75 m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(x), DNS_RESOURCE_RECORD_RDATA_SIZE(y));
76
77 r = memcmp(DNS_RESOURCE_RECORD_RDATA(x), DNS_RESOURCE_RECORD_RDATA(y), m);
78 if (r != 0)
79 return r;
80
81 return CMP(DNS_RESOURCE_RECORD_RDATA_SIZE(x), DNS_RESOURCE_RECORD_RDATA_SIZE(y));
82 }
83
84 static int dnssec_rsa_verify_raw(
85 const char *hash_algorithm,
86 const void *signature, size_t signature_size,
87 const void *data, size_t data_size,
88 const void *exponent, size_t exponent_size,
89 const void *modulus, size_t modulus_size) {
90
91 gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
92 gcry_mpi_t n = NULL, e = NULL, s = NULL;
93 gcry_error_t ge;
94 int r;
95
96 assert(hash_algorithm);
97
98 ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL);
99 if (ge != 0) {
100 r = -EIO;
101 goto finish;
102 }
103
104 ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL);
105 if (ge != 0) {
106 r = -EIO;
107 goto finish;
108 }
109
110 ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL);
111 if (ge != 0) {
112 r = -EIO;
113 goto finish;
114 }
115
116 ge = gcry_sexp_build(&signature_sexp,
117 NULL,
118 "(sig-val (rsa (s %m)))",
119 s);
120
121 if (ge != 0) {
122 r = -EIO;
123 goto finish;
124 }
125
126 ge = gcry_sexp_build(&data_sexp,
127 NULL,
128 "(data (flags pkcs1) (hash %s %b))",
129 hash_algorithm,
130 (int) data_size,
131 data);
132 if (ge != 0) {
133 r = -EIO;
134 goto finish;
135 }
136
137 ge = gcry_sexp_build(&public_key_sexp,
138 NULL,
139 "(public-key (rsa (n %m) (e %m)))",
140 n,
141 e);
142 if (ge != 0) {
143 r = -EIO;
144 goto finish;
145 }
146
147 ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
148 if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
149 r = 0;
150 else if (ge != 0) {
151 log_debug("RSA signature check failed: %s", gpg_strerror(ge));
152 r = -EIO;
153 } else
154 r = 1;
155
156 finish:
157 if (e)
158 gcry_mpi_release(e);
159 if (n)
160 gcry_mpi_release(n);
161 if (s)
162 gcry_mpi_release(s);
163
164 if (public_key_sexp)
165 gcry_sexp_release(public_key_sexp);
166 if (signature_sexp)
167 gcry_sexp_release(signature_sexp);
168 if (data_sexp)
169 gcry_sexp_release(data_sexp);
170
171 return r;
172 }
173
174 static int dnssec_rsa_verify(
175 const char *hash_algorithm,
176 const void *hash, size_t hash_size,
177 DnsResourceRecord *rrsig,
178 DnsResourceRecord *dnskey) {
179
180 size_t exponent_size, modulus_size;
181 void *exponent, *modulus;
182
183 assert(hash_algorithm);
184 assert(hash);
185 assert(hash_size > 0);
186 assert(rrsig);
187 assert(dnskey);
188
189 if (*(uint8_t*) dnskey->dnskey.key == 0) {
190 /* exponent is > 255 bytes long */
191
192 exponent = (uint8_t*) dnskey->dnskey.key + 3;
193 exponent_size =
194 ((size_t) (((uint8_t*) dnskey->dnskey.key)[1]) << 8) |
195 ((size_t) ((uint8_t*) dnskey->dnskey.key)[2]);
196
197 if (exponent_size < 256)
198 return -EINVAL;
199
200 if (3 + exponent_size >= dnskey->dnskey.key_size)
201 return -EINVAL;
202
203 modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
204 modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
205
206 } else {
207 /* exponent is <= 255 bytes long */
208
209 exponent = (uint8_t*) dnskey->dnskey.key + 1;
210 exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
211
212 if (exponent_size <= 0)
213 return -EINVAL;
214
215 if (1 + exponent_size >= dnskey->dnskey.key_size)
216 return -EINVAL;
217
218 modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
219 modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
220 }
221
222 return dnssec_rsa_verify_raw(
223 hash_algorithm,
224 rrsig->rrsig.signature, rrsig->rrsig.signature_size,
225 hash, hash_size,
226 exponent, exponent_size,
227 modulus, modulus_size);
228 }
229
230 static int dnssec_ecdsa_verify_raw(
231 const char *hash_algorithm,
232 const char *curve,
233 const void *signature_r, size_t signature_r_size,
234 const void *signature_s, size_t signature_s_size,
235 const void *data, size_t data_size,
236 const void *key, size_t key_size) {
237
238 gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
239 gcry_mpi_t q = NULL, r = NULL, s = NULL;
240 gcry_error_t ge;
241 int k;
242
243 assert(hash_algorithm);
244
245 ge = gcry_mpi_scan(&r, GCRYMPI_FMT_USG, signature_r, signature_r_size, NULL);
246 if (ge != 0) {
247 k = -EIO;
248 goto finish;
249 }
250
251 ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature_s, signature_s_size, NULL);
252 if (ge != 0) {
253 k = -EIO;
254 goto finish;
255 }
256
257 ge = gcry_mpi_scan(&q, GCRYMPI_FMT_USG, key, key_size, NULL);
258 if (ge != 0) {
259 k = -EIO;
260 goto finish;
261 }
262
263 ge = gcry_sexp_build(&signature_sexp,
264 NULL,
265 "(sig-val (ecdsa (r %m) (s %m)))",
266 r,
267 s);
268 if (ge != 0) {
269 k = -EIO;
270 goto finish;
271 }
272
273 ge = gcry_sexp_build(&data_sexp,
274 NULL,
275 "(data (flags rfc6979) (hash %s %b))",
276 hash_algorithm,
277 (int) data_size,
278 data);
279 if (ge != 0) {
280 k = -EIO;
281 goto finish;
282 }
283
284 ge = gcry_sexp_build(&public_key_sexp,
285 NULL,
286 "(public-key (ecc (curve %s) (q %m)))",
287 curve,
288 q);
289 if (ge != 0) {
290 k = -EIO;
291 goto finish;
292 }
293
294 ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
295 if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
296 k = 0;
297 else if (ge != 0) {
298 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge));
299 k = -EIO;
300 } else
301 k = 1;
302 finish:
303 if (r)
304 gcry_mpi_release(r);
305 if (s)
306 gcry_mpi_release(s);
307 if (q)
308 gcry_mpi_release(q);
309
310 if (public_key_sexp)
311 gcry_sexp_release(public_key_sexp);
312 if (signature_sexp)
313 gcry_sexp_release(signature_sexp);
314 if (data_sexp)
315 gcry_sexp_release(data_sexp);
316
317 return k;
318 }
319
320 static int dnssec_ecdsa_verify(
321 const char *hash_algorithm,
322 int algorithm,
323 const void *hash, size_t hash_size,
324 DnsResourceRecord *rrsig,
325 DnsResourceRecord *dnskey) {
326
327 const char *curve;
328 size_t key_size;
329 uint8_t *q;
330
331 assert(hash);
332 assert(hash_size);
333 assert(rrsig);
334 assert(dnskey);
335
336 if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) {
337 key_size = 32;
338 curve = "NIST P-256";
339 } else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) {
340 key_size = 48;
341 curve = "NIST P-384";
342 } else
343 return -EOPNOTSUPP;
344
345 if (dnskey->dnskey.key_size != key_size * 2)
346 return -EINVAL;
347
348 if (rrsig->rrsig.signature_size != key_size * 2)
349 return -EINVAL;
350
351 q = newa(uint8_t, key_size*2 + 1);
352 q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
353 memcpy(q+1, dnskey->dnskey.key, key_size*2);
354
355 return dnssec_ecdsa_verify_raw(
356 hash_algorithm,
357 curve,
358 rrsig->rrsig.signature, key_size,
359 (uint8_t*) rrsig->rrsig.signature + key_size, key_size,
360 hash, hash_size,
361 q, key_size*2+1);
362 }
363
364 #if GCRYPT_VERSION_NUMBER >= 0x010600
365 static int dnssec_eddsa_verify_raw(
366 const char *curve,
367 const void *signature_r, size_t signature_r_size,
368 const void *signature_s, size_t signature_s_size,
369 const void *data, size_t data_size,
370 const void *key, size_t key_size) {
371
372 gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
373 gcry_error_t ge;
374 int k;
375
376 ge = gcry_sexp_build(&signature_sexp,
377 NULL,
378 "(sig-val (eddsa (r %b) (s %b)))",
379 (int) signature_r_size,
380 signature_r,
381 (int) signature_s_size,
382 signature_s);
383 if (ge != 0) {
384 k = -EIO;
385 goto finish;
386 }
387
388 ge = gcry_sexp_build(&data_sexp,
389 NULL,
390 "(data (flags eddsa) (hash-algo sha512) (value %b))",
391 (int) data_size,
392 data);
393 if (ge != 0) {
394 k = -EIO;
395 goto finish;
396 }
397
398 ge = gcry_sexp_build(&public_key_sexp,
399 NULL,
400 "(public-key (ecc (curve %s) (flags eddsa) (q %b)))",
401 curve,
402 (int) key_size,
403 key);
404 if (ge != 0) {
405 k = -EIO;
406 goto finish;
407 }
408
409 ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
410 if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
411 k = 0;
412 else if (ge != 0) {
413 log_debug("EdDSA signature check failed: %s", gpg_strerror(ge));
414 k = -EIO;
415 } else
416 k = 1;
417 finish:
418 if (public_key_sexp)
419 gcry_sexp_release(public_key_sexp);
420 if (signature_sexp)
421 gcry_sexp_release(signature_sexp);
422 if (data_sexp)
423 gcry_sexp_release(data_sexp);
424
425 return k;
426 }
427
428 static int dnssec_eddsa_verify(
429 int algorithm,
430 const void *data, size_t data_size,
431 DnsResourceRecord *rrsig,
432 DnsResourceRecord *dnskey) {
433 const char *curve;
434 size_t key_size;
435
436 if (algorithm == DNSSEC_ALGORITHM_ED25519) {
437 curve = "Ed25519";
438 key_size = 32;
439 } else
440 return -EOPNOTSUPP;
441
442 if (dnskey->dnskey.key_size != key_size)
443 return -EINVAL;
444
445 if (rrsig->rrsig.signature_size != key_size * 2)
446 return -EINVAL;
447
448 return dnssec_eddsa_verify_raw(
449 curve,
450 rrsig->rrsig.signature, key_size,
451 (uint8_t*) rrsig->rrsig.signature + key_size, key_size,
452 data, data_size,
453 dnskey->dnskey.key, key_size);
454 }
455 #endif
456
457 static void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
458 gcry_md_write(md, &v, sizeof(v));
459 }
460
461 static void md_add_uint16(gcry_md_hd_t md, uint16_t v) {
462 v = htobe16(v);
463 gcry_md_write(md, &v, sizeof(v));
464 }
465
466 static void fwrite_uint8(FILE *fp, uint8_t v) {
467 fwrite(&v, sizeof(v), 1, fp);
468 }
469
470 static void fwrite_uint16(FILE *fp, uint16_t v) {
471 v = htobe16(v);
472 fwrite(&v, sizeof(v), 1, fp);
473 }
474
475 static void fwrite_uint32(FILE *fp, uint32_t v) {
476 v = htobe32(v);
477 fwrite(&v, sizeof(v), 1, fp);
478 }
479
480 static int dnssec_rrsig_prepare(DnsResourceRecord *rrsig) {
481 int n_key_labels, n_signer_labels;
482 const char *name;
483 int r;
484
485 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source
486 * and .n_skip_labels_signer fields so that we can use them later on. */
487
488 assert(rrsig);
489 assert(rrsig->key->type == DNS_TYPE_RRSIG);
490
491 /* Check if this RRSIG RR is already prepared */
492 if (rrsig->n_skip_labels_source != UINT8_MAX)
493 return 0;
494
495 if (rrsig->rrsig.inception > rrsig->rrsig.expiration)
496 return -EINVAL;
497
498 name = dns_resource_key_name(rrsig->key);
499
500 n_key_labels = dns_name_count_labels(name);
501 if (n_key_labels < 0)
502 return n_key_labels;
503 if (rrsig->rrsig.labels > n_key_labels)
504 return -EINVAL;
505
506 n_signer_labels = dns_name_count_labels(rrsig->rrsig.signer);
507 if (n_signer_labels < 0)
508 return n_signer_labels;
509 if (n_signer_labels > rrsig->rrsig.labels)
510 return -EINVAL;
511
512 r = dns_name_skip(name, n_key_labels - n_signer_labels, &name);
513 if (r < 0)
514 return r;
515 if (r == 0)
516 return -EINVAL;
517
518 /* Check if the signer is really a suffix of us */
519 r = dns_name_equal(name, rrsig->rrsig.signer);
520 if (r < 0)
521 return r;
522 if (r == 0)
523 return -EINVAL;
524
525 assert(n_key_labels < UINT8_MAX); /* UINT8_MAX/-1 means unsigned. */
526 rrsig->n_skip_labels_source = n_key_labels - rrsig->rrsig.labels;
527 rrsig->n_skip_labels_signer = n_key_labels - n_signer_labels;
528
529 return 0;
530 }
531
532 static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
533 usec_t expiration, inception, skew;
534
535 assert(rrsig);
536 assert(rrsig->key->type == DNS_TYPE_RRSIG);
537
538 if (realtime == USEC_INFINITY)
539 realtime = now(CLOCK_REALTIME);
540
541 expiration = rrsig->rrsig.expiration * USEC_PER_SEC;
542 inception = rrsig->rrsig.inception * USEC_PER_SEC;
543
544 /* Consider inverted validity intervals as expired */
545 if (inception > expiration)
546 return true;
547
548 /* Permit a certain amount of clock skew of 10% of the valid
549 * time range. This takes inspiration from unbound's
550 * resolver. */
551 skew = (expiration - inception) / 10;
552 if (skew > SKEW_MAX)
553 skew = SKEW_MAX;
554
555 if (inception < skew)
556 inception = 0;
557 else
558 inception -= skew;
559
560 if (expiration + skew < expiration)
561 expiration = USEC_INFINITY;
562 else
563 expiration += skew;
564
565 return realtime < inception || realtime > expiration;
566 }
567
568 static int algorithm_to_gcrypt_md(uint8_t algorithm) {
569
570 /* Translates a DNSSEC signature algorithm into a gcrypt
571 * digest identifier.
572 *
573 * Note that we implement all algorithms listed as "Must
574 * implement" and "Recommended to Implement" in RFC6944. We
575 * don't implement any algorithms that are listed as
576 * "Optional" or "Must Not Implement". Specifically, we do not
577 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
578 * GOST-ECC. */
579
580 switch (algorithm) {
581
582 case DNSSEC_ALGORITHM_RSASHA1:
583 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
584 return GCRY_MD_SHA1;
585
586 case DNSSEC_ALGORITHM_RSASHA256:
587 case DNSSEC_ALGORITHM_ECDSAP256SHA256:
588 return GCRY_MD_SHA256;
589
590 case DNSSEC_ALGORITHM_ECDSAP384SHA384:
591 return GCRY_MD_SHA384;
592
593 case DNSSEC_ALGORITHM_RSASHA512:
594 return GCRY_MD_SHA512;
595
596 default:
597 return -EOPNOTSUPP;
598 }
599 }
600
601 static void dnssec_fix_rrset_ttl(
602 DnsResourceRecord *list[],
603 unsigned n,
604 DnsResourceRecord *rrsig,
605 usec_t realtime) {
606
607 assert(list);
608 assert(n > 0);
609 assert(rrsig);
610
611 for (unsigned k = 0; k < n; k++) {
612 DnsResourceRecord *rr = list[k];
613
614 /* Pick the TTL as the minimum of the RR's TTL, the
615 * RR's original TTL according to the RRSIG and the
616 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
617 rr->ttl = MIN3(rr->ttl, rrsig->rrsig.original_ttl, rrsig->ttl);
618 rr->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
619
620 /* Copy over information about the signer and wildcard source of synthesis */
621 rr->n_skip_labels_source = rrsig->n_skip_labels_source;
622 rr->n_skip_labels_signer = rrsig->n_skip_labels_signer;
623 }
624
625 rrsig->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
626 }
627
628 int dnssec_verify_rrset(
629 DnsAnswer *a,
630 const DnsResourceKey *key,
631 DnsResourceRecord *rrsig,
632 DnsResourceRecord *dnskey,
633 usec_t realtime,
634 DnssecResult *result) {
635
636 uint8_t wire_format_name[DNS_WIRE_FORMAT_HOSTNAME_MAX];
637 DnsResourceRecord **list, *rr;
638 const char *source, *name;
639 _cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
640 int r, md_algorithm;
641 size_t n = 0;
642 size_t sig_size = 0;
643 _cleanup_free_ char *sig_data = NULL;
644 _cleanup_fclose_ FILE *f = NULL;
645 size_t hash_size;
646 void *hash;
647 bool wildcard;
648
649 assert(key);
650 assert(rrsig);
651 assert(dnskey);
652 assert(result);
653 assert(rrsig->key->type == DNS_TYPE_RRSIG);
654 assert(dnskey->key->type == DNS_TYPE_DNSKEY);
655
656 /* Verifies that the RRSet matches the specified "key" in "a",
657 * using the signature "rrsig" and the key "dnskey". It's
658 * assumed that RRSIG and DNSKEY match. */
659
660 r = dnssec_rrsig_prepare(rrsig);
661 if (r == -EINVAL) {
662 *result = DNSSEC_INVALID;
663 return r;
664 }
665 if (r < 0)
666 return r;
667
668 r = dnssec_rrsig_expired(rrsig, realtime);
669 if (r < 0)
670 return r;
671 if (r > 0) {
672 *result = DNSSEC_SIGNATURE_EXPIRED;
673 return 0;
674 }
675
676 name = dns_resource_key_name(key);
677
678 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
679 if (dns_type_apex_only(rrsig->rrsig.type_covered)) {
680 r = dns_name_equal(rrsig->rrsig.signer, name);
681 if (r < 0)
682 return r;
683 if (r == 0) {
684 *result = DNSSEC_INVALID;
685 return 0;
686 }
687 }
688
689 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
690 if (rrsig->rrsig.type_covered == DNS_TYPE_DS) {
691 r = dns_name_equal(rrsig->rrsig.signer, name);
692 if (r < 0)
693 return r;
694 if (r > 0) {
695 *result = DNSSEC_INVALID;
696 return 0;
697 }
698 }
699
700 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
701 r = dns_name_suffix(name, rrsig->rrsig.labels, &source);
702 if (r < 0)
703 return r;
704 if (r > 0 && !dns_type_may_wildcard(rrsig->rrsig.type_covered)) {
705 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
706 *result = DNSSEC_INVALID;
707 return 0;
708 }
709 if (r == 1) {
710 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
711 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
712 r = dns_name_startswith(name, "*");
713 if (r < 0)
714 return r;
715 if (r > 0)
716 source = name;
717
718 wildcard = r == 0;
719 } else
720 wildcard = r > 0;
721
722 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
723 list = newa(DnsResourceRecord *, dns_answer_size(a));
724
725 DNS_ANSWER_FOREACH(rr, a) {
726 r = dns_resource_key_equal(key, rr->key);
727 if (r < 0)
728 return r;
729 if (r == 0)
730 continue;
731
732 /* We need the wire format for ordering, and digest calculation */
733 r = dns_resource_record_to_wire_format(rr, true);
734 if (r < 0)
735 return r;
736
737 list[n++] = rr;
738
739 if (n > VERIFY_RRS_MAX)
740 return -E2BIG;
741 }
742
743 if (n <= 0)
744 return -ENODATA;
745
746 /* Bring the RRs into canonical order */
747 typesafe_qsort(list, n, rr_compare);
748
749 f = open_memstream_unlocked(&sig_data, &sig_size);
750 if (!f)
751 return -ENOMEM;
752
753 fwrite_uint16(f, rrsig->rrsig.type_covered);
754 fwrite_uint8(f, rrsig->rrsig.algorithm);
755 fwrite_uint8(f, rrsig->rrsig.labels);
756 fwrite_uint32(f, rrsig->rrsig.original_ttl);
757 fwrite_uint32(f, rrsig->rrsig.expiration);
758 fwrite_uint32(f, rrsig->rrsig.inception);
759 fwrite_uint16(f, rrsig->rrsig.key_tag);
760
761 r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
762 if (r < 0)
763 return r;
764 fwrite(wire_format_name, 1, r, f);
765
766 /* Convert the source of synthesis into wire format */
767 r = dns_name_to_wire_format(source, wire_format_name, sizeof(wire_format_name), true);
768 if (r < 0)
769 return r;
770
771 for (size_t k = 0; k < n; k++) {
772 size_t l;
773
774 rr = list[k];
775
776 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
777 if (wildcard)
778 fwrite((uint8_t[]) { 1, '*'}, sizeof(uint8_t), 2, f);
779 fwrite(wire_format_name, 1, r, f);
780
781 fwrite_uint16(f, rr->key->type);
782 fwrite_uint16(f, rr->key->class);
783 fwrite_uint32(f, rrsig->rrsig.original_ttl);
784
785 l = DNS_RESOURCE_RECORD_RDATA_SIZE(rr);
786 assert(l <= 0xFFFF);
787
788 fwrite_uint16(f, (uint16_t) l);
789 fwrite(DNS_RESOURCE_RECORD_RDATA(rr), 1, l, f);
790 }
791
792 r = fflush_and_check(f);
793 if (r < 0)
794 return r;
795
796 initialize_libgcrypt(false);
797
798 switch (rrsig->rrsig.algorithm) {
799 #if GCRYPT_VERSION_NUMBER >= 0x010600
800 case DNSSEC_ALGORITHM_ED25519:
801 break;
802 #else
803 case DNSSEC_ALGORITHM_ED25519:
804 #endif
805 case DNSSEC_ALGORITHM_ED448:
806 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
807 return 0;
808 default: {
809 gcry_error_t err;
810
811 /* OK, the RRs are now in canonical order. Let's calculate the digest */
812 md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
813 if (md_algorithm == -EOPNOTSUPP) {
814 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
815 return 0;
816 }
817 if (md_algorithm < 0)
818 return md_algorithm;
819
820 err = gcry_md_open(&md, md_algorithm, 0);
821 if (gcry_err_code(err) != GPG_ERR_NO_ERROR || !md)
822 return -EIO;
823
824 hash_size = gcry_md_get_algo_dlen(md_algorithm);
825 assert(hash_size > 0);
826
827 gcry_md_write(md, sig_data, sig_size);
828
829 hash = gcry_md_read(md, 0);
830 if (!hash)
831 return -EIO;
832 }
833 }
834
835 switch (rrsig->rrsig.algorithm) {
836
837 case DNSSEC_ALGORITHM_RSASHA1:
838 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
839 case DNSSEC_ALGORITHM_RSASHA256:
840 case DNSSEC_ALGORITHM_RSASHA512:
841 r = dnssec_rsa_verify(
842 gcry_md_algo_name(md_algorithm),
843 hash, hash_size,
844 rrsig,
845 dnskey);
846 break;
847
848 case DNSSEC_ALGORITHM_ECDSAP256SHA256:
849 case DNSSEC_ALGORITHM_ECDSAP384SHA384:
850 r = dnssec_ecdsa_verify(
851 gcry_md_algo_name(md_algorithm),
852 rrsig->rrsig.algorithm,
853 hash, hash_size,
854 rrsig,
855 dnskey);
856 break;
857 #if GCRYPT_VERSION_NUMBER >= 0x010600
858 case DNSSEC_ALGORITHM_ED25519:
859 r = dnssec_eddsa_verify(
860 rrsig->rrsig.algorithm,
861 sig_data, sig_size,
862 rrsig,
863 dnskey);
864 break;
865 #endif
866 }
867 if (r < 0)
868 return r;
869
870 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
871 if (r > 0)
872 dnssec_fix_rrset_ttl(list, n, rrsig, realtime);
873
874 if (r == 0)
875 *result = DNSSEC_INVALID;
876 else if (wildcard)
877 *result = DNSSEC_VALIDATED_WILDCARD;
878 else
879 *result = DNSSEC_VALIDATED;
880
881 return 0;
882 }
883
884 int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok) {
885
886 assert(rrsig);
887 assert(dnskey);
888
889 /* Checks if the specified DNSKEY RR matches the key used for
890 * the signature in the specified RRSIG RR */
891
892 if (rrsig->key->type != DNS_TYPE_RRSIG)
893 return -EINVAL;
894
895 if (dnskey->key->type != DNS_TYPE_DNSKEY)
896 return 0;
897 if (dnskey->key->class != rrsig->key->class)
898 return 0;
899 if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
900 return 0;
901 if (!revoked_ok && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
902 return 0;
903 if (dnskey->dnskey.protocol != 3)
904 return 0;
905 if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm)
906 return 0;
907
908 if (dnssec_keytag(dnskey, false) != rrsig->rrsig.key_tag)
909 return 0;
910
911 return dns_name_equal(dns_resource_key_name(dnskey->key), rrsig->rrsig.signer);
912 }
913
914 int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
915 assert(key);
916 assert(rrsig);
917
918 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
919
920 if (rrsig->key->type != DNS_TYPE_RRSIG)
921 return 0;
922 if (rrsig->key->class != key->class)
923 return 0;
924 if (rrsig->rrsig.type_covered != key->type)
925 return 0;
926
927 return dns_name_equal(dns_resource_key_name(rrsig->key), dns_resource_key_name(key));
928 }
929
930 int dnssec_verify_rrset_search(
931 DnsAnswer *a,
932 const DnsResourceKey *key,
933 DnsAnswer *validated_dnskeys,
934 usec_t realtime,
935 DnssecResult *result,
936 DnsResourceRecord **ret_rrsig) {
937
938 bool found_rrsig = false, found_invalid = false, found_expired_rrsig = false, found_unsupported_algorithm = false;
939 DnsResourceRecord *rrsig;
940 int r;
941
942 assert(key);
943 assert(result);
944
945 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
946
947 if (!a || a->n_rrs <= 0)
948 return -ENODATA;
949
950 /* Iterate through each RRSIG RR. */
951 DNS_ANSWER_FOREACH(rrsig, a) {
952 DnsResourceRecord *dnskey;
953 DnsAnswerFlags flags;
954
955 /* Is this an RRSIG RR that applies to RRs matching our key? */
956 r = dnssec_key_match_rrsig(key, rrsig);
957 if (r < 0)
958 return r;
959 if (r == 0)
960 continue;
961
962 found_rrsig = true;
963
964 /* Look for a matching key */
965 DNS_ANSWER_FOREACH_FLAGS(dnskey, flags, validated_dnskeys) {
966 DnssecResult one_result;
967
968 if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
969 continue;
970
971 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
972 r = dnssec_rrsig_match_dnskey(rrsig, dnskey, false);
973 if (r < 0)
974 return r;
975 if (r == 0)
976 continue;
977
978 /* Take the time here, if it isn't set yet, so
979 * that we do all validations with the same
980 * time. */
981 if (realtime == USEC_INFINITY)
982 realtime = now(CLOCK_REALTIME);
983
984 /* Yay, we found a matching RRSIG with a matching
985 * DNSKEY, awesome. Now let's verify all entries of
986 * the RRSet against the RRSIG and DNSKEY
987 * combination. */
988
989 r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime, &one_result);
990 if (r < 0)
991 return r;
992
993 switch (one_result) {
994
995 case DNSSEC_VALIDATED:
996 case DNSSEC_VALIDATED_WILDCARD:
997 /* Yay, the RR has been validated,
998 * return immediately, but fix up the expiry */
999 if (ret_rrsig)
1000 *ret_rrsig = rrsig;
1001
1002 *result = one_result;
1003 return 0;
1004
1005 case DNSSEC_INVALID:
1006 /* If the signature is invalid, let's try another
1007 key and/or signature. After all they
1008 key_tags and stuff are not unique, and
1009 might be shared by multiple keys. */
1010 found_invalid = true;
1011 continue;
1012
1013 case DNSSEC_UNSUPPORTED_ALGORITHM:
1014 /* If the key algorithm is
1015 unsupported, try another
1016 RRSIG/DNSKEY pair, but remember we
1017 encountered this, so that we can
1018 return a proper error when we
1019 encounter nothing better. */
1020 found_unsupported_algorithm = true;
1021 continue;
1022
1023 case DNSSEC_SIGNATURE_EXPIRED:
1024 /* If the signature is expired, try
1025 another one, but remember it, so
1026 that we can return this */
1027 found_expired_rrsig = true;
1028 continue;
1029
1030 default:
1031 assert_not_reached();
1032 }
1033 }
1034 }
1035
1036 if (found_expired_rrsig)
1037 *result = DNSSEC_SIGNATURE_EXPIRED;
1038 else if (found_unsupported_algorithm)
1039 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
1040 else if (found_invalid)
1041 *result = DNSSEC_INVALID;
1042 else if (found_rrsig)
1043 *result = DNSSEC_MISSING_KEY;
1044 else
1045 *result = DNSSEC_NO_SIGNATURE;
1046
1047 if (ret_rrsig)
1048 *ret_rrsig = NULL;
1049
1050 return 0;
1051 }
1052
1053 int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
1054 DnsResourceRecord *rr;
1055 int r;
1056
1057 /* Checks whether there's at least one RRSIG in 'a' that protects RRs of the specified key */
1058
1059 DNS_ANSWER_FOREACH(rr, a) {
1060 r = dnssec_key_match_rrsig(key, rr);
1061 if (r < 0)
1062 return r;
1063 if (r > 0)
1064 return 1;
1065 }
1066
1067 return 0;
1068 }
1069
1070 static int digest_to_gcrypt_md(uint8_t algorithm) {
1071
1072 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1073
1074 switch (algorithm) {
1075
1076 case DNSSEC_DIGEST_SHA1:
1077 return GCRY_MD_SHA1;
1078
1079 case DNSSEC_DIGEST_SHA256:
1080 return GCRY_MD_SHA256;
1081
1082 case DNSSEC_DIGEST_SHA384:
1083 return GCRY_MD_SHA384;
1084
1085 default:
1086 return -EOPNOTSUPP;
1087 }
1088 }
1089
1090 int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) {
1091 uint8_t wire_format[DNS_WIRE_FORMAT_HOSTNAME_MAX];
1092 _cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
1093 gcry_error_t err;
1094 size_t hash_size;
1095 int md_algorithm, r;
1096 void *result;
1097
1098 assert(dnskey);
1099 assert(ds);
1100
1101 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1102
1103 if (dnskey->key->type != DNS_TYPE_DNSKEY)
1104 return -EINVAL;
1105 if (ds->key->type != DNS_TYPE_DS)
1106 return -EINVAL;
1107 if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
1108 return -EKEYREJECTED;
1109 if (!mask_revoke && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
1110 return -EKEYREJECTED;
1111 if (dnskey->dnskey.protocol != 3)
1112 return -EKEYREJECTED;
1113
1114 if (dnskey->dnskey.algorithm != ds->ds.algorithm)
1115 return 0;
1116 if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag)
1117 return 0;
1118
1119 initialize_libgcrypt(false);
1120
1121 md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
1122 if (md_algorithm < 0)
1123 return md_algorithm;
1124
1125 hash_size = gcry_md_get_algo_dlen(md_algorithm);
1126 assert(hash_size > 0);
1127
1128 if (ds->ds.digest_size != hash_size)
1129 return 0;
1130
1131 r = dns_name_to_wire_format(dns_resource_key_name(dnskey->key), wire_format, sizeof(wire_format), true);
1132 if (r < 0)
1133 return r;
1134
1135 err = gcry_md_open(&md, md_algorithm, 0);
1136 if (gcry_err_code(err) != GPG_ERR_NO_ERROR || !md)
1137 return -EIO;
1138
1139 gcry_md_write(md, wire_format, r);
1140 if (mask_revoke)
1141 md_add_uint16(md, dnskey->dnskey.flags & ~DNSKEY_FLAG_REVOKE);
1142 else
1143 md_add_uint16(md, dnskey->dnskey.flags);
1144 md_add_uint8(md, dnskey->dnskey.protocol);
1145 md_add_uint8(md, dnskey->dnskey.algorithm);
1146 gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
1147
1148 result = gcry_md_read(md, 0);
1149 if (!result)
1150 return -EIO;
1151
1152 return memcmp(result, ds->ds.digest, ds->ds.digest_size) == 0;
1153 }
1154
1155 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds) {
1156 DnsResourceRecord *ds;
1157 DnsAnswerFlags flags;
1158 int r;
1159
1160 assert(dnskey);
1161
1162 if (dnskey->key->type != DNS_TYPE_DNSKEY)
1163 return 0;
1164
1165 DNS_ANSWER_FOREACH_FLAGS(ds, flags, validated_ds) {
1166
1167 if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
1168 continue;
1169
1170 if (ds->key->type != DNS_TYPE_DS)
1171 continue;
1172 if (ds->key->class != dnskey->key->class)
1173 continue;
1174
1175 r = dns_name_equal(dns_resource_key_name(dnskey->key), dns_resource_key_name(ds->key));
1176 if (r < 0)
1177 return r;
1178 if (r == 0)
1179 continue;
1180
1181 r = dnssec_verify_dnskey_by_ds(dnskey, ds, false);
1182 if (IN_SET(r, -EKEYREJECTED, -EOPNOTSUPP))
1183 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1184 if (r < 0)
1185 return r;
1186 if (r > 0)
1187 return 1;
1188 }
1189
1190 return 0;
1191 }
1192
1193 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm) {
1194
1195 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1196
1197 switch (algorithm) {
1198
1199 case NSEC3_ALGORITHM_SHA1:
1200 return GCRY_MD_SHA1;
1201
1202 default:
1203 return -EOPNOTSUPP;
1204 }
1205 }
1206
1207 int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
1208 uint8_t wire_format[DNS_WIRE_FORMAT_HOSTNAME_MAX];
1209 _cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
1210 gcry_error_t err;
1211 size_t hash_size;
1212 int algorithm;
1213 void *result;
1214 int r;
1215
1216 assert(nsec3);
1217 assert(name);
1218 assert(ret);
1219
1220 if (nsec3->key->type != DNS_TYPE_NSEC3)
1221 return -EINVAL;
1222
1223 if (nsec3->nsec3.iterations > NSEC3_ITERATIONS_MAX)
1224 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1225 "Ignoring NSEC3 RR %s with excessive number of iterations.",
1226 dns_resource_record_to_string(nsec3));
1227
1228 algorithm = nsec3_hash_to_gcrypt_md(nsec3->nsec3.algorithm);
1229 if (algorithm < 0)
1230 return algorithm;
1231
1232 initialize_libgcrypt(false);
1233
1234 hash_size = gcry_md_get_algo_dlen(algorithm);
1235 assert(hash_size > 0);
1236
1237 if (nsec3->nsec3.next_hashed_name_size != hash_size)
1238 return -EINVAL;
1239
1240 r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
1241 if (r < 0)
1242 return r;
1243
1244 err = gcry_md_open(&md, algorithm, 0);
1245 if (gcry_err_code(err) != GPG_ERR_NO_ERROR || !md)
1246 return -EIO;
1247
1248 gcry_md_write(md, wire_format, r);
1249 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
1250
1251 result = gcry_md_read(md, 0);
1252 if (!result)
1253 return -EIO;
1254
1255 for (unsigned k = 0; k < nsec3->nsec3.iterations; k++) {
1256 uint8_t tmp[hash_size];
1257 memcpy(tmp, result, hash_size);
1258
1259 gcry_md_reset(md);
1260 gcry_md_write(md, tmp, hash_size);
1261 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
1262
1263 result = gcry_md_read(md, 0);
1264 if (!result)
1265 return -EIO;
1266 }
1267
1268 memcpy(ret, result, hash_size);
1269 return (int) hash_size;
1270 }
1271
1272 static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) {
1273 const char *a, *b;
1274 int r;
1275
1276 assert(rr);
1277
1278 if (rr->key->type != DNS_TYPE_NSEC3)
1279 return 0;
1280
1281 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1282 if (!IN_SET(rr->nsec3.flags, 0, 1))
1283 return 0;
1284
1285 /* Ignore NSEC3 RRs whose algorithm we don't know */
1286 if (nsec3_hash_to_gcrypt_md(rr->nsec3.algorithm) < 0)
1287 return 0;
1288 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1289 if (rr->nsec3.iterations > NSEC3_ITERATIONS_MAX)
1290 return 0;
1291
1292 /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
1293 * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
1294 if (!IN_SET(rr->n_skip_labels_source, 0, UINT8_MAX))
1295 return 0;
1296 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1297 if (!IN_SET(rr->n_skip_labels_signer, 1, UINT8_MAX))
1298 return 0;
1299
1300 if (!nsec3)
1301 return 1;
1302
1303 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1304
1305 if (nsec3 == rr) /* Shortcut */
1306 return 1;
1307
1308 if (rr->key->class != nsec3->key->class)
1309 return 0;
1310 if (rr->nsec3.algorithm != nsec3->nsec3.algorithm)
1311 return 0;
1312 if (rr->nsec3.iterations != nsec3->nsec3.iterations)
1313 return 0;
1314 if (rr->nsec3.salt_size != nsec3->nsec3.salt_size)
1315 return 0;
1316 if (memcmp_safe(rr->nsec3.salt, nsec3->nsec3.salt, rr->nsec3.salt_size) != 0)
1317 return 0;
1318
1319 a = dns_resource_key_name(rr->key);
1320 r = dns_name_parent(&a); /* strip off hash */
1321 if (r <= 0)
1322 return r;
1323
1324 b = dns_resource_key_name(nsec3->key);
1325 r = dns_name_parent(&b); /* strip off hash */
1326 if (r <= 0)
1327 return r;
1328
1329 /* Make sure both have the same parent */
1330 return dns_name_equal(a, b);
1331 }
1332
1333 static int nsec3_hashed_domain_format(const uint8_t *hashed, size_t hashed_size, const char *zone, char **ret) {
1334 _cleanup_free_ char *l = NULL;
1335 char *j;
1336
1337 assert(hashed);
1338 assert(hashed_size > 0);
1339 assert(zone);
1340 assert(ret);
1341
1342 l = base32hexmem(hashed, hashed_size, false);
1343 if (!l)
1344 return -ENOMEM;
1345
1346 j = strjoin(l, ".", zone);
1347 if (!j)
1348 return -ENOMEM;
1349
1350 *ret = j;
1351 return (int) hashed_size;
1352 }
1353
1354 static int nsec3_hashed_domain_make(DnsResourceRecord *nsec3, const char *domain, const char *zone, char **ret) {
1355 uint8_t hashed[DNSSEC_HASH_SIZE_MAX];
1356 int hashed_size;
1357
1358 assert(nsec3);
1359 assert(domain);
1360 assert(zone);
1361 assert(ret);
1362
1363 hashed_size = dnssec_nsec3_hash(nsec3, domain, hashed);
1364 if (hashed_size < 0)
1365 return hashed_size;
1366
1367 return nsec3_hashed_domain_format(hashed, (size_t) hashed_size, zone, ret);
1368 }
1369
1370 /* See RFC 5155, Section 8
1371 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1372 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1373 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1374 * matches the wildcard domain.
1375 *
1376 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1377 * that there is no proof either way. The latter is the case if a proof of non-existence of a given
1378 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1379 * to conclude anything we indicate this by returning NO_RR. */
1380 static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
1381 _cleanup_free_ char *next_closer_domain = NULL, *wildcard_domain = NULL;
1382 const char *zone, *p, *pp = NULL, *wildcard;
1383 DnsResourceRecord *rr, *enclosure_rr, *zone_rr, *wildcard_rr = NULL;
1384 DnsAnswerFlags flags;
1385 int hashed_size, r;
1386 bool a, no_closer = false, no_wildcard = false, optout = false;
1387
1388 assert(key);
1389 assert(result);
1390
1391 /* First step, find the zone name and the NSEC3 parameters of the zone.
1392 * it is sufficient to look for the longest common suffix we find with
1393 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1394 * records from a given zone in a response must use the same
1395 * parameters. */
1396 zone = dns_resource_key_name(key);
1397 for (;;) {
1398 DNS_ANSWER_FOREACH_FLAGS(zone_rr, flags, answer) {
1399 r = nsec3_is_good(zone_rr, NULL);
1400 if (r < 0)
1401 return r;
1402 if (r == 0)
1403 continue;
1404
1405 r = dns_name_equal_skip(dns_resource_key_name(zone_rr->key), 1, zone);
1406 if (r < 0)
1407 return r;
1408 if (r > 0)
1409 goto found_zone;
1410 }
1411
1412 /* Strip one label from the front */
1413 r = dns_name_parent(&zone);
1414 if (r < 0)
1415 return r;
1416 if (r == 0)
1417 break;
1418 }
1419
1420 *result = DNSSEC_NSEC_NO_RR;
1421 return 0;
1422
1423 found_zone:
1424 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1425 p = dns_resource_key_name(key);
1426 for (;;) {
1427 _cleanup_free_ char *hashed_domain = NULL;
1428
1429 hashed_size = nsec3_hashed_domain_make(zone_rr, p, zone, &hashed_domain);
1430 if (hashed_size == -EOPNOTSUPP) {
1431 *result = DNSSEC_NSEC_UNSUPPORTED_ALGORITHM;
1432 return 0;
1433 }
1434 if (hashed_size < 0)
1435 return hashed_size;
1436
1437 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr, flags, answer) {
1438
1439 r = nsec3_is_good(enclosure_rr, zone_rr);
1440 if (r < 0)
1441 return r;
1442 if (r == 0)
1443 continue;
1444
1445 if (enclosure_rr->nsec3.next_hashed_name_size != (size_t) hashed_size)
1446 continue;
1447
1448 r = dns_name_equal(dns_resource_key_name(enclosure_rr->key), hashed_domain);
1449 if (r < 0)
1450 return r;
1451 if (r > 0) {
1452 a = flags & DNS_ANSWER_AUTHENTICATED;
1453 goto found_closest_encloser;
1454 }
1455 }
1456
1457 /* We didn't find the closest encloser with this name,
1458 * but let's remember this domain name, it might be
1459 * the next closer name */
1460
1461 pp = p;
1462
1463 /* Strip one label from the front */
1464 r = dns_name_parent(&p);
1465 if (r < 0)
1466 return r;
1467 if (r == 0)
1468 break;
1469 }
1470
1471 *result = DNSSEC_NSEC_NO_RR;
1472 return 0;
1473
1474 found_closest_encloser:
1475 /* We found a closest encloser in 'p'; next closer is 'pp' */
1476
1477 if (!pp) {
1478 /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR
1479 * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are
1480 * appropriately set. */
1481
1482 if (key->type == DNS_TYPE_DS) {
1483 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA))
1484 return -EBADMSG;
1485 } else {
1486 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_NS) &&
1487 !bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA))
1488 return -EBADMSG;
1489 }
1490
1491 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1492 if (bitmap_isset(enclosure_rr->nsec3.types, key->type))
1493 *result = DNSSEC_NSEC_FOUND;
1494 else if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_CNAME))
1495 *result = DNSSEC_NSEC_CNAME;
1496 else
1497 *result = DNSSEC_NSEC_NODATA;
1498
1499 if (authenticated)
1500 *authenticated = a;
1501 if (ttl)
1502 *ttl = enclosure_rr->ttl;
1503
1504 return 0;
1505 }
1506
1507 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1508 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_DNAME))
1509 return -EBADMSG;
1510
1511 /* Ensure that this data is from the delegated domain
1512 * (i.e. originates from the "lower" DNS server), and isn't
1513 * just glue records (i.e. doesn't originate from the "upper"
1514 * DNS server). */
1515 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_NS) &&
1516 !bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA))
1517 return -EBADMSG;
1518
1519 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1520
1521 wildcard = strjoina("*.", p);
1522 r = nsec3_hashed_domain_make(enclosure_rr, wildcard, zone, &wildcard_domain);
1523 if (r < 0)
1524 return r;
1525 if (r != hashed_size)
1526 return -EBADMSG;
1527
1528 r = nsec3_hashed_domain_make(enclosure_rr, pp, zone, &next_closer_domain);
1529 if (r < 0)
1530 return r;
1531 if (r != hashed_size)
1532 return -EBADMSG;
1533
1534 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1535 _cleanup_free_ char *next_hashed_domain = NULL;
1536
1537 r = nsec3_is_good(rr, zone_rr);
1538 if (r < 0)
1539 return r;
1540 if (r == 0)
1541 continue;
1542
1543 r = nsec3_hashed_domain_format(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, zone, &next_hashed_domain);
1544 if (r < 0)
1545 return r;
1546
1547 r = dns_name_between(dns_resource_key_name(rr->key), next_closer_domain, next_hashed_domain);
1548 if (r < 0)
1549 return r;
1550 if (r > 0) {
1551 if (rr->nsec3.flags & 1)
1552 optout = true;
1553
1554 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1555
1556 no_closer = true;
1557 }
1558
1559 r = dns_name_equal(dns_resource_key_name(rr->key), wildcard_domain);
1560 if (r < 0)
1561 return r;
1562 if (r > 0) {
1563 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1564
1565 wildcard_rr = rr;
1566 }
1567
1568 r = dns_name_between(dns_resource_key_name(rr->key), wildcard_domain, next_hashed_domain);
1569 if (r < 0)
1570 return r;
1571 if (r > 0) {
1572 if (rr->nsec3.flags & 1)
1573 /* This only makes sense if we have a wildcard delegation, which is
1574 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1575 * this not happening, so hence cannot simply conclude NXDOMAIN as
1576 * we would wish */
1577 optout = true;
1578
1579 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1580
1581 no_wildcard = true;
1582 }
1583 }
1584
1585 if (wildcard_rr && no_wildcard)
1586 return -EBADMSG;
1587
1588 if (!no_closer) {
1589 *result = DNSSEC_NSEC_NO_RR;
1590 return 0;
1591 }
1592
1593 if (wildcard_rr) {
1594 /* A wildcard exists that matches our query. */
1595 if (optout)
1596 /* This is not specified in any RFC to the best of my knowledge, but
1597 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1598 * it means that we cannot prove that the source of synthesis is
1599 * correct, as there may be a closer match. */
1600 *result = DNSSEC_NSEC_OPTOUT;
1601 else if (bitmap_isset(wildcard_rr->nsec3.types, key->type))
1602 *result = DNSSEC_NSEC_FOUND;
1603 else if (bitmap_isset(wildcard_rr->nsec3.types, DNS_TYPE_CNAME))
1604 *result = DNSSEC_NSEC_CNAME;
1605 else
1606 *result = DNSSEC_NSEC_NODATA;
1607 } else {
1608 if (optout)
1609 /* The RFC only specifies that we have to care for optout for NODATA for
1610 * DS records. However, children of an insecure opt-out delegation should
1611 * also be considered opt-out, rather than verified NXDOMAIN.
1612 * Note that we do not require a proof of wildcard non-existence if the
1613 * next closer domain is covered by an opt-out, as that would not provide
1614 * any additional information. */
1615 *result = DNSSEC_NSEC_OPTOUT;
1616 else if (no_wildcard)
1617 *result = DNSSEC_NSEC_NXDOMAIN;
1618 else {
1619 *result = DNSSEC_NSEC_NO_RR;
1620
1621 return 0;
1622 }
1623 }
1624
1625 if (authenticated)
1626 *authenticated = a;
1627
1628 if (ttl)
1629 *ttl = enclosure_rr->ttl;
1630
1631 return 0;
1632 }
1633
1634 static int dnssec_nsec_wildcard_equal(DnsResourceRecord *rr, const char *name) {
1635 char label[DNS_LABEL_MAX];
1636 const char *n;
1637 int r;
1638
1639 assert(rr);
1640 assert(rr->key->type == DNS_TYPE_NSEC);
1641
1642 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1643
1644 if (rr->n_skip_labels_source != 1)
1645 return 0;
1646
1647 n = dns_resource_key_name(rr->key);
1648 r = dns_label_unescape(&n, label, sizeof label, 0);
1649 if (r <= 0)
1650 return r;
1651 if (r != 1 || label[0] != '*')
1652 return 0;
1653
1654 return dns_name_endswith(name, n);
1655 }
1656
1657 static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) {
1658 const char *nn, *common_suffix;
1659 int r;
1660
1661 assert(rr);
1662 assert(rr->key->type == DNS_TYPE_NSEC);
1663
1664 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1665 *
1666 * A couple of examples:
1667 *
1668 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1669 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1670 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1671 */
1672
1673 /* First, determine parent of next domain. */
1674 nn = rr->nsec.next_domain_name;
1675 r = dns_name_parent(&nn);
1676 if (r <= 0)
1677 return r;
1678
1679 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1680 * anything at all. */
1681 r = dns_name_endswith(nn, name);
1682 if (r <= 0)
1683 return r;
1684
1685 /* If the name we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */
1686 r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
1687 if (r < 0)
1688 return r;
1689
1690 return dns_name_endswith(name, common_suffix);
1691 }
1692
1693 static int dnssec_nsec_from_parent_zone(DnsResourceRecord *rr, const char *name) {
1694 int r;
1695
1696 assert(rr);
1697 assert(rr->key->type == DNS_TYPE_NSEC);
1698
1699 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1700
1701 r = dns_name_parent(&name);
1702 if (r <= 0)
1703 return r;
1704
1705 r = dns_name_equal(name, dns_resource_key_name(rr->key));
1706 if (r <= 0)
1707 return r;
1708
1709 /* DNAME, and NS without SOA is an indication for a delegation. */
1710 if (bitmap_isset(rr->nsec.types, DNS_TYPE_DNAME))
1711 return 1;
1712
1713 if (bitmap_isset(rr->nsec.types, DNS_TYPE_NS) && !bitmap_isset(rr->nsec.types, DNS_TYPE_SOA))
1714 return 1;
1715
1716 return 0;
1717 }
1718
1719 static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) {
1720 const char *signer;
1721 int r;
1722
1723 assert(rr);
1724 assert(rr->key->type == DNS_TYPE_NSEC);
1725
1726 /* Checks whether the name is covered by this NSEC RR. This means, that the name is somewhere below the NSEC's
1727 * signer name, and between the NSEC's two names. */
1728
1729 r = dns_resource_record_signer(rr, &signer);
1730 if (r < 0)
1731 return r;
1732
1733 r = dns_name_endswith(name, signer); /* this NSEC isn't suitable the name is not in the signer's domain */
1734 if (r <= 0)
1735 return r;
1736
1737 return dns_name_between(dns_resource_key_name(rr->key), name, rr->nsec.next_domain_name);
1738 }
1739
1740 static int dnssec_nsec_generate_wildcard(DnsResourceRecord *rr, const char *name, char **wc) {
1741 const char *common_suffix1, *common_suffix2, *signer;
1742 int r, labels1, labels2;
1743
1744 assert(rr);
1745 assert(rr->key->type == DNS_TYPE_NSEC);
1746
1747 /* Generates "Wildcard at the Closest Encloser" for the given name and NSEC RR. */
1748
1749 r = dns_resource_record_signer(rr, &signer);
1750 if (r < 0)
1751 return r;
1752
1753 r = dns_name_endswith(name, signer); /* this NSEC isn't suitable the name is not in the signer's domain */
1754 if (r <= 0)
1755 return r;
1756
1757 r = dns_name_common_suffix(name, dns_resource_key_name(rr->key), &common_suffix1);
1758 if (r < 0)
1759 return r;
1760
1761 r = dns_name_common_suffix(name, rr->nsec.next_domain_name, &common_suffix2);
1762 if (r < 0)
1763 return r;
1764
1765 labels1 = dns_name_count_labels(common_suffix1);
1766 if (labels1 < 0)
1767 return labels1;
1768
1769 labels2 = dns_name_count_labels(common_suffix2);
1770 if (labels2 < 0)
1771 return labels2;
1772
1773 if (labels1 > labels2)
1774 r = dns_name_concat("*", common_suffix1, 0, wc);
1775 else
1776 r = dns_name_concat("*", common_suffix2, 0, wc);
1777
1778 if (r < 0)
1779 return r;
1780
1781 return 0;
1782 }
1783
1784 int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
1785 bool have_nsec3 = false, covering_rr_authenticated = false, wildcard_rr_authenticated = false;
1786 DnsResourceRecord *rr, *covering_rr = NULL, *wildcard_rr = NULL;
1787 DnsAnswerFlags flags;
1788 const char *name;
1789 int r;
1790
1791 assert(key);
1792 assert(result);
1793
1794 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1795
1796 name = dns_resource_key_name(key);
1797
1798 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1799
1800 if (rr->key->class != key->class)
1801 continue;
1802
1803 have_nsec3 = have_nsec3 || (rr->key->type == DNS_TYPE_NSEC3);
1804
1805 if (rr->key->type != DNS_TYPE_NSEC)
1806 continue;
1807
1808 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1809 r = dns_resource_record_is_synthetic(rr);
1810 if (r == -ENODATA) /* No signing RR known. */
1811 continue;
1812 if (r < 0)
1813 return r;
1814 if (r > 0)
1815 continue;
1816
1817 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1818 r = dns_name_equal(dns_resource_key_name(rr->key), name);
1819 if (r < 0)
1820 return r;
1821 if (r == 0) {
1822 /* If it's not a direct match, maybe it's a wild card match? */
1823 r = dnssec_nsec_wildcard_equal(rr, name);
1824 if (r < 0)
1825 return r;
1826 }
1827 if (r > 0) {
1828 if (key->type == DNS_TYPE_DS) {
1829 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1830 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1831 if (bitmap_isset(rr->nsec.types, DNS_TYPE_SOA))
1832 continue;
1833 } else {
1834 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1835 * we got the child's NSEC. */
1836 if (bitmap_isset(rr->nsec.types, DNS_TYPE_NS) &&
1837 !bitmap_isset(rr->nsec.types, DNS_TYPE_SOA))
1838 continue;
1839 }
1840
1841 if (bitmap_isset(rr->nsec.types, key->type))
1842 *result = DNSSEC_NSEC_FOUND;
1843 else if (bitmap_isset(rr->nsec.types, DNS_TYPE_CNAME))
1844 *result = DNSSEC_NSEC_CNAME;
1845 else
1846 *result = DNSSEC_NSEC_NODATA;
1847
1848 if (authenticated)
1849 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1850 if (ttl)
1851 *ttl = rr->ttl;
1852
1853 return 0;
1854 }
1855
1856 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1857 * of the NSEC RR. */
1858 r = dnssec_nsec_in_path(rr, name);
1859 if (r < 0)
1860 return r;
1861 if (r > 0) {
1862 *result = DNSSEC_NSEC_NODATA;
1863
1864 if (authenticated)
1865 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1866 if (ttl)
1867 *ttl = rr->ttl;
1868
1869 return 0;
1870 }
1871
1872 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1873 r = dnssec_nsec_from_parent_zone(rr, name);
1874 if (r < 0)
1875 return r;
1876 if (r > 0)
1877 continue;
1878
1879 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1880 r = dnssec_nsec_covers(rr, name);
1881 if (r < 0)
1882 return r;
1883 if (r > 0 && (!covering_rr || !covering_rr_authenticated)) {
1884 covering_rr = rr;
1885 covering_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1886 }
1887 }
1888
1889 if (covering_rr) {
1890 _cleanup_free_ char *wc = NULL;
1891 r = dnssec_nsec_generate_wildcard(covering_rr, name, &wc);
1892 if (r < 0)
1893 return r;
1894
1895 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1896
1897 if (rr->key->class != key->class)
1898 continue;
1899
1900 if (rr->key->type != DNS_TYPE_NSEC)
1901 continue;
1902
1903 /* Check if this NSEC RR proves the nonexistence of the wildcard */
1904 r = dnssec_nsec_covers(rr, wc);
1905 if (r < 0)
1906 return r;
1907 if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) {
1908 wildcard_rr = rr;
1909 wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1910 }
1911 }
1912 }
1913
1914 if (covering_rr && wildcard_rr) {
1915 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1916 * proved the NXDOMAIN case. */
1917 *result = DNSSEC_NSEC_NXDOMAIN;
1918
1919 if (authenticated)
1920 *authenticated = covering_rr_authenticated && wildcard_rr_authenticated;
1921 if (ttl)
1922 *ttl = MIN(covering_rr->ttl, wildcard_rr->ttl);
1923
1924 return 0;
1925 }
1926
1927 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1928 if (have_nsec3)
1929 return dnssec_test_nsec3(answer, key, result, authenticated, ttl);
1930
1931 /* No appropriate NSEC RR found, report this. */
1932 *result = DNSSEC_NSEC_NO_RR;
1933 return 0;
1934 }
1935
1936 static int dnssec_nsec_test_enclosed(DnsAnswer *answer, uint16_t type, const char *name, const char *zone, bool *authenticated) {
1937 DnsResourceRecord *rr;
1938 DnsAnswerFlags flags;
1939 int r;
1940
1941 assert(name);
1942 assert(zone);
1943
1944 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
1945 * 'zone'. The 'zone' must be a suffix of the 'name'. */
1946
1947 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1948 bool found = false;
1949
1950 if (rr->key->type != type && type != DNS_TYPE_ANY)
1951 continue;
1952
1953 switch (rr->key->type) {
1954
1955 case DNS_TYPE_NSEC:
1956
1957 /* We only care for NSEC RRs from the indicated zone */
1958 r = dns_resource_record_is_signer(rr, zone);
1959 if (r < 0)
1960 return r;
1961 if (r == 0)
1962 continue;
1963
1964 r = dns_name_between(dns_resource_key_name(rr->key), name, rr->nsec.next_domain_name);
1965 if (r < 0)
1966 return r;
1967
1968 found = r > 0;
1969 break;
1970
1971 case DNS_TYPE_NSEC3: {
1972 _cleanup_free_ char *hashed_domain = NULL, *next_hashed_domain = NULL;
1973
1974 /* We only care for NSEC3 RRs from the indicated zone */
1975 r = dns_resource_record_is_signer(rr, zone);
1976 if (r < 0)
1977 return r;
1978 if (r == 0)
1979 continue;
1980
1981 r = nsec3_is_good(rr, NULL);
1982 if (r < 0)
1983 return r;
1984 if (r == 0)
1985 break;
1986
1987 /* Format the domain we are testing with the NSEC3 RR's hash function */
1988 r = nsec3_hashed_domain_make(
1989 rr,
1990 name,
1991 zone,
1992 &hashed_domain);
1993 if (r < 0)
1994 return r;
1995 if ((size_t) r != rr->nsec3.next_hashed_name_size)
1996 break;
1997
1998 /* Format the NSEC3's next hashed name as proper domain name */
1999 r = nsec3_hashed_domain_format(
2000 rr->nsec3.next_hashed_name,
2001 rr->nsec3.next_hashed_name_size,
2002 zone,
2003 &next_hashed_domain);
2004 if (r < 0)
2005 return r;
2006
2007 r = dns_name_between(dns_resource_key_name(rr->key), hashed_domain, next_hashed_domain);
2008 if (r < 0)
2009 return r;
2010
2011 found = r > 0;
2012 break;
2013 }
2014
2015 default:
2016 continue;
2017 }
2018
2019 if (found) {
2020 if (authenticated)
2021 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
2022 return 1;
2023 }
2024 }
2025
2026 return 0;
2027 }
2028
2029 static int dnssec_test_positive_wildcard_nsec3(
2030 DnsAnswer *answer,
2031 const char *name,
2032 const char *source,
2033 const char *zone,
2034 bool *authenticated) {
2035
2036 const char *next_closer = NULL;
2037 int r;
2038
2039 /* Run a positive NSEC3 wildcard proof. Specifically:
2040 *
2041 * A proof that the "next closer" of the generating wildcard does not exist.
2042 *
2043 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
2044 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
2045 * exists for the NSEC3 RR and we are done.
2046 *
2047 * To prove that a.b.c.d.e.f is rightfully synthesized from a wildcard *.d.e.f all we have to check is that
2048 * c.d.e.f does not exist. */
2049
2050 for (;;) {
2051 next_closer = name;
2052 r = dns_name_parent(&name);
2053 if (r <= 0)
2054 return r;
2055
2056 r = dns_name_equal(name, source);
2057 if (r < 0)
2058 return r;
2059 if (r > 0)
2060 break;
2061 }
2062
2063 return dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC3, next_closer, zone, authenticated);
2064 }
2065
2066 static int dnssec_test_positive_wildcard_nsec(
2067 DnsAnswer *answer,
2068 const char *name,
2069 const char *source,
2070 const char *zone,
2071 bool *_authenticated) {
2072
2073 bool authenticated = true;
2074 int r;
2075
2076 /* Run a positive NSEC wildcard proof. Specifically:
2077 *
2078 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2079 * a prefix of the synthesizing source "source" in the zone "zone".
2080 *
2081 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2082 *
2083 * Note that if we want to prove that a.b.c.d.e.f is rightfully synthesized from a wildcard *.d.e.f, then we
2084 * have to prove that none of the following exist:
2085 *
2086 * 1) a.b.c.d.e.f
2087 * 2) *.b.c.d.e.f
2088 * 3) b.c.d.e.f
2089 * 4) *.c.d.e.f
2090 * 5) c.d.e.f
2091 */
2092
2093 for (;;) {
2094 _cleanup_free_ char *wc = NULL;
2095 bool a = false;
2096
2097 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2098 * i.e between the owner name and the next name of an NSEC RR. */
2099 r = dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC, name, zone, &a);
2100 if (r <= 0)
2101 return r;
2102
2103 authenticated = authenticated && a;
2104
2105 /* Strip one label off */
2106 r = dns_name_parent(&name);
2107 if (r <= 0)
2108 return r;
2109
2110 /* Did we reach the source of synthesis? */
2111 r = dns_name_equal(name, source);
2112 if (r < 0)
2113 return r;
2114 if (r > 0) {
2115 /* Successful exit */
2116 *_authenticated = authenticated;
2117 return 1;
2118 }
2119
2120 /* Safety check, that the source of synthesis is still our suffix */
2121 r = dns_name_endswith(name, source);
2122 if (r < 0)
2123 return r;
2124 if (r == 0)
2125 return -EBADMSG;
2126
2127 /* Replace the label we stripped off with an asterisk */
2128 wc = strjoin("*.", name);
2129 if (!wc)
2130 return -ENOMEM;
2131
2132 /* And check if the proof holds for the asterisk name, too */
2133 r = dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC, wc, zone, &a);
2134 if (r <= 0)
2135 return r;
2136
2137 authenticated = authenticated && a;
2138 /* In the next iteration we'll check the non-asterisk-prefixed version */
2139 }
2140 }
2141
2142 int dnssec_test_positive_wildcard(
2143 DnsAnswer *answer,
2144 const char *name,
2145 const char *source,
2146 const char *zone,
2147 bool *authenticated) {
2148
2149 int r;
2150
2151 assert(name);
2152 assert(source);
2153 assert(zone);
2154 assert(authenticated);
2155
2156 r = dns_answer_contains_zone_nsec3(answer, zone);
2157 if (r < 0)
2158 return r;
2159 if (r > 0)
2160 return dnssec_test_positive_wildcard_nsec3(answer, name, source, zone, authenticated);
2161 else
2162 return dnssec_test_positive_wildcard_nsec(answer, name, source, zone, authenticated);
2163 }
2164
2165 #else
2166
2167 int dnssec_verify_rrset(
2168 DnsAnswer *a,
2169 const DnsResourceKey *key,
2170 DnsResourceRecord *rrsig,
2171 DnsResourceRecord *dnskey,
2172 usec_t realtime,
2173 DnssecResult *result) {
2174
2175 return -EOPNOTSUPP;
2176 }
2177
2178 int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok) {
2179
2180 return -EOPNOTSUPP;
2181 }
2182
2183 int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
2184
2185 return -EOPNOTSUPP;
2186 }
2187
2188 int dnssec_verify_rrset_search(
2189 DnsAnswer *a,
2190 const DnsResourceKey *key,
2191 DnsAnswer *validated_dnskeys,
2192 usec_t realtime,
2193 DnssecResult *result,
2194 DnsResourceRecord **ret_rrsig) {
2195
2196 return -EOPNOTSUPP;
2197 }
2198
2199 int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
2200
2201 return -EOPNOTSUPP;
2202 }
2203
2204 int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) {
2205
2206 return -EOPNOTSUPP;
2207 }
2208
2209 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds) {
2210
2211 return -EOPNOTSUPP;
2212 }
2213
2214 int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
2215
2216 return -EOPNOTSUPP;
2217 }
2218
2219 int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
2220
2221 return -EOPNOTSUPP;
2222 }
2223
2224 int dnssec_test_positive_wildcard(
2225 DnsAnswer *answer,
2226 const char *name,
2227 const char *source,
2228 const char *zone,
2229 bool *authenticated) {
2230
2231 return -EOPNOTSUPP;
2232 }
2233
2234 #endif
2235
2236 static const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = {
2237 [DNSSEC_VALIDATED] = "validated",
2238 [DNSSEC_VALIDATED_WILDCARD] = "validated-wildcard",
2239 [DNSSEC_INVALID] = "invalid",
2240 [DNSSEC_SIGNATURE_EXPIRED] = "signature-expired",
2241 [DNSSEC_UNSUPPORTED_ALGORITHM] = "unsupported-algorithm",
2242 [DNSSEC_NO_SIGNATURE] = "no-signature",
2243 [DNSSEC_MISSING_KEY] = "missing-key",
2244 [DNSSEC_UNSIGNED] = "unsigned",
2245 [DNSSEC_FAILED_AUXILIARY] = "failed-auxiliary",
2246 [DNSSEC_NSEC_MISMATCH] = "nsec-mismatch",
2247 [DNSSEC_INCOMPATIBLE_SERVER] = "incompatible-server",
2248 };
2249 DEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult);
2250
2251 static const char* const dnssec_verdict_table[_DNSSEC_VERDICT_MAX] = {
2252 [DNSSEC_SECURE] = "secure",
2253 [DNSSEC_INSECURE] = "insecure",
2254 [DNSSEC_BOGUS] = "bogus",
2255 [DNSSEC_INDETERMINATE] = "indeterminate",
2256 };
2257 DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict, DnssecVerdict);