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