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