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