]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-dnssec.c
resolved: fix DNSSEC canonical ordering logic
[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 #include <gcrypt.h>
23
24 #include "alloc-util.h"
25 #include "dns-domain.h"
26 #include "hexdecoct.h"
27 #include "resolved-dns-dnssec.h"
28 #include "resolved-dns-packet.h"
29 #include "string-table.h"
30
31 /* Open question:
32 *
33 * How does the DNSSEC canonical form of a hostname with a label
34 * containing a dot look like, the way DNS-SD does it?
35 *
36 * TODO:
37 *
38 * - wildcard zones compatibility (NSEC/NSEC3 wildcard check is missing)
39 * - multi-label zone compatibility
40 * - cname/dname compatibility
41 * - per-interface DNSSEC setting
42 * - nxdomain on qname
43 * - retry on failed validation?
44 * - DNSSEC key revocation support? https://tools.ietf.org/html/rfc5011
45 * - when doing negative caching, use NSEC/NSEC3 RR instead of SOA for TTL
46 *
47 * */
48
49 #define VERIFY_RRS_MAX 256
50 #define MAX_KEY_SIZE (32*1024)
51
52 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
53 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
54
55 /* Maximum number of NSEC3 iterations we'll do. */
56 #define NSEC3_ITERATIONS_MAX 2048
57
58 /*
59 * The DNSSEC Chain of trust:
60 *
61 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
62 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
63 * DS RRs are protected like normal RRs
64 *
65 * Example chain:
66 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
67 */
68
69 static void initialize_libgcrypt(void) {
70 const char *p;
71
72 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
73 return;
74
75 p = gcry_check_version("1.4.5");
76 assert(p);
77
78 gcry_control(GCRYCTL_DISABLE_SECMEM);
79 gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
80 }
81
82 uint16_t dnssec_keytag(DnsResourceRecord *dnskey) {
83 const uint8_t *p;
84 uint32_t sum;
85 size_t i;
86
87 /* The algorithm from RFC 4034, Appendix B. */
88
89 assert(dnskey);
90 assert(dnskey->key->type == DNS_TYPE_DNSKEY);
91
92 sum = (uint32_t) dnskey->dnskey.flags +
93 ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm);
94
95 p = dnskey->dnskey.key;
96
97 for (i = 0; i < dnskey->dnskey.key_size; i++)
98 sum += (i & 1) == 0 ? (uint32_t) p[i] << 8 : (uint32_t) p[i];
99
100 sum += (sum >> 16) & UINT32_C(0xFFFF);
101
102 return sum & UINT32_C(0xFFFF);
103 }
104
105 static int rr_compare(const void *a, const void *b) {
106 DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
107 size_t m;
108 int r;
109
110 /* Let's order the RRs according to RFC 4034, Section 6.3 */
111
112 assert(x);
113 assert(*x);
114 assert((*x)->wire_format);
115 assert(y);
116 assert(*y);
117 assert((*y)->wire_format);
118
119 m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x), DNS_RESOURCE_RECORD_RDATA_SIZE(*y));
120
121 r = memcmp(DNS_RESOURCE_RECORD_RDATA(*x), DNS_RESOURCE_RECORD_RDATA(*y), m);
122 if (r != 0)
123 return r;
124
125 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
126 return -1;
127 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y))
128 return 1;
129
130 return 0;
131 }
132
133 static int dnssec_rsa_verify_raw(
134 const char *hash_algorithm,
135 const void *signature, size_t signature_size,
136 const void *data, size_t data_size,
137 const void *exponent, size_t exponent_size,
138 const void *modulus, size_t modulus_size) {
139
140 gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
141 gcry_mpi_t n = NULL, e = NULL, s = NULL;
142 gcry_error_t ge;
143 int r;
144
145 assert(hash_algorithm);
146
147 ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL);
148 if (ge != 0) {
149 r = -EIO;
150 goto finish;
151 }
152
153 ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL);
154 if (ge != 0) {
155 r = -EIO;
156 goto finish;
157 }
158
159 ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL);
160 if (ge != 0) {
161 r = -EIO;
162 goto finish;
163 }
164
165 ge = gcry_sexp_build(&signature_sexp,
166 NULL,
167 "(sig-val (rsa (s %m)))",
168 s);
169
170 if (ge != 0) {
171 r = -EIO;
172 goto finish;
173 }
174
175 ge = gcry_sexp_build(&data_sexp,
176 NULL,
177 "(data (flags pkcs1) (hash %s %b))",
178 hash_algorithm,
179 (int) data_size,
180 data);
181 if (ge != 0) {
182 r = -EIO;
183 goto finish;
184 }
185
186 ge = gcry_sexp_build(&public_key_sexp,
187 NULL,
188 "(public-key (rsa (n %m) (e %m)))",
189 n,
190 e);
191 if (ge != 0) {
192 r = -EIO;
193 goto finish;
194 }
195
196 ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
197 if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
198 r = 0;
199 else if (ge != 0) {
200 log_debug("RSA signature check failed: %s", gpg_strerror(ge));
201 r = -EIO;
202 } else
203 r = 1;
204
205 finish:
206 if (e)
207 gcry_mpi_release(e);
208 if (n)
209 gcry_mpi_release(n);
210 if (s)
211 gcry_mpi_release(s);
212
213 if (public_key_sexp)
214 gcry_sexp_release(public_key_sexp);
215 if (signature_sexp)
216 gcry_sexp_release(signature_sexp);
217 if (data_sexp)
218 gcry_sexp_release(data_sexp);
219
220 return r;
221 }
222
223 static int dnssec_rsa_verify(
224 const char *hash_algorithm,
225 const void *hash, size_t hash_size,
226 DnsResourceRecord *rrsig,
227 DnsResourceRecord *dnskey) {
228
229 size_t exponent_size, modulus_size;
230 void *exponent, *modulus;
231
232 assert(hash_algorithm);
233 assert(hash);
234 assert(hash_size > 0);
235 assert(rrsig);
236 assert(dnskey);
237
238 if (*(uint8_t*) dnskey->dnskey.key == 0) {
239 /* exponent is > 255 bytes long */
240
241 exponent = (uint8_t*) dnskey->dnskey.key + 3;
242 exponent_size =
243 ((size_t) (((uint8_t*) dnskey->dnskey.key)[1]) << 8) |
244 ((size_t) ((uint8_t*) dnskey->dnskey.key)[2]);
245
246 if (exponent_size < 256)
247 return -EINVAL;
248
249 if (3 + exponent_size >= dnskey->dnskey.key_size)
250 return -EINVAL;
251
252 modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
253 modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
254
255 } else {
256 /* exponent is <= 255 bytes long */
257
258 exponent = (uint8_t*) dnskey->dnskey.key + 1;
259 exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
260
261 if (exponent_size <= 0)
262 return -EINVAL;
263
264 if (1 + exponent_size >= dnskey->dnskey.key_size)
265 return -EINVAL;
266
267 modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
268 modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
269 }
270
271 return dnssec_rsa_verify_raw(
272 hash_algorithm,
273 rrsig->rrsig.signature, rrsig->rrsig.signature_size,
274 hash, hash_size,
275 exponent, exponent_size,
276 modulus, modulus_size);
277 }
278
279 static int dnssec_ecdsa_verify_raw(
280 const char *hash_algorithm,
281 const char *curve,
282 const void *signature_r, size_t signature_r_size,
283 const void *signature_s, size_t signature_s_size,
284 const void *data, size_t data_size,
285 const void *key, size_t key_size) {
286
287 gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
288 gcry_mpi_t q = NULL, r = NULL, s = NULL;
289 gcry_error_t ge;
290 int k;
291
292 assert(hash_algorithm);
293
294 ge = gcry_mpi_scan(&r, GCRYMPI_FMT_USG, signature_r, signature_r_size, NULL);
295 if (ge != 0) {
296 k = -EIO;
297 goto finish;
298 }
299
300 ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature_s, signature_s_size, NULL);
301 if (ge != 0) {
302 k = -EIO;
303 goto finish;
304 }
305
306 ge = gcry_mpi_scan(&q, GCRYMPI_FMT_USG, key, key_size, NULL);
307 if (ge != 0) {
308 k = -EIO;
309 goto finish;
310 }
311
312 ge = gcry_sexp_build(&signature_sexp,
313 NULL,
314 "(sig-val (ecdsa (r %m) (s %m)))",
315 r,
316 s);
317 if (ge != 0) {
318 k = -EIO;
319 goto finish;
320 }
321
322 ge = gcry_sexp_build(&data_sexp,
323 NULL,
324 "(data (flags rfc6979) (hash %s %b))",
325 hash_algorithm,
326 (int) data_size,
327 data);
328 if (ge != 0) {
329 k = -EIO;
330 goto finish;
331 }
332
333 ge = gcry_sexp_build(&public_key_sexp,
334 NULL,
335 "(public-key (ecc (curve %s) (q %m)))",
336 curve,
337 q);
338 if (ge != 0) {
339 k = -EIO;
340 goto finish;
341 }
342
343 ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
344 if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
345 k = 0;
346 else if (ge != 0) {
347 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge));
348 k = -EIO;
349 } else
350 k = 1;
351 finish:
352 if (r)
353 gcry_mpi_release(r);
354 if (s)
355 gcry_mpi_release(s);
356 if (q)
357 gcry_mpi_release(q);
358
359 if (public_key_sexp)
360 gcry_sexp_release(public_key_sexp);
361 if (signature_sexp)
362 gcry_sexp_release(signature_sexp);
363 if (data_sexp)
364 gcry_sexp_release(data_sexp);
365
366 return k;
367 }
368
369 static int dnssec_ecdsa_verify(
370 const char *hash_algorithm,
371 int algorithm,
372 const void *hash, size_t hash_size,
373 DnsResourceRecord *rrsig,
374 DnsResourceRecord *dnskey) {
375
376 const char *curve;
377 size_t key_size;
378 uint8_t *q;
379
380 assert(hash);
381 assert(hash_size);
382 assert(rrsig);
383 assert(dnskey);
384
385 if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) {
386 key_size = 32;
387 curve = "NIST P-256";
388 } else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) {
389 key_size = 48;
390 curve = "NIST P-384";
391 } else
392 return -EOPNOTSUPP;
393
394 if (dnskey->dnskey.key_size != key_size * 2)
395 return -EINVAL;
396
397 if (rrsig->rrsig.signature_size != key_size * 2)
398 return -EINVAL;
399
400 q = alloca(key_size*2 + 1);
401 q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
402 memcpy(q+1, dnskey->dnskey.key, key_size*2);
403
404 return dnssec_ecdsa_verify_raw(
405 hash_algorithm,
406 curve,
407 rrsig->rrsig.signature, key_size,
408 (uint8_t*) rrsig->rrsig.signature + key_size, key_size,
409 hash, hash_size,
410 q, key_size*2+1);
411 }
412
413 static void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
414 gcry_md_write(md, &v, sizeof(v));
415 }
416
417 static void md_add_uint16(gcry_md_hd_t md, uint16_t v) {
418 v = htobe16(v);
419 gcry_md_write(md, &v, sizeof(v));
420 }
421
422 static void md_add_uint32(gcry_md_hd_t md, uint32_t v) {
423 v = htobe32(v);
424 gcry_md_write(md, &v, sizeof(v));
425 }
426
427 static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
428 usec_t expiration, inception, skew;
429
430 assert(rrsig);
431 assert(rrsig->key->type == DNS_TYPE_RRSIG);
432
433 if (realtime == USEC_INFINITY)
434 realtime = now(CLOCK_REALTIME);
435
436 expiration = rrsig->rrsig.expiration * USEC_PER_SEC;
437 inception = rrsig->rrsig.inception * USEC_PER_SEC;
438
439 if (inception > expiration)
440 return -EKEYREJECTED;
441
442 /* Permit a certain amount of clock skew of 10% of the valid
443 * time range. This takes inspiration from unbound's
444 * resolver. */
445 skew = (expiration - inception) / 10;
446 if (skew > SKEW_MAX)
447 skew = SKEW_MAX;
448
449 if (inception < skew)
450 inception = 0;
451 else
452 inception -= skew;
453
454 if (expiration + skew < expiration)
455 expiration = USEC_INFINITY;
456 else
457 expiration += skew;
458
459 return realtime < inception || realtime > expiration;
460 }
461
462 static int algorithm_to_gcrypt_md(uint8_t algorithm) {
463
464 /* Translates a DNSSEC signature algorithm into a gcrypt
465 * digest identifier.
466 *
467 * Note that we implement all algorithms listed as "Must
468 * implement" and "Recommended to Implement" in RFC6944. We
469 * don't implement any algorithms that are listed as
470 * "Optional" or "Must Not Implement". Specifically, we do not
471 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
472 * GOST-ECC. */
473
474 switch (algorithm) {
475
476 case DNSSEC_ALGORITHM_RSASHA1:
477 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
478 return GCRY_MD_SHA1;
479
480 case DNSSEC_ALGORITHM_RSASHA256:
481 case DNSSEC_ALGORITHM_ECDSAP256SHA256:
482 return GCRY_MD_SHA256;
483
484 case DNSSEC_ALGORITHM_ECDSAP384SHA384:
485 return GCRY_MD_SHA384;
486
487 case DNSSEC_ALGORITHM_RSASHA512:
488 return GCRY_MD_SHA512;
489
490 default:
491 return -EOPNOTSUPP;
492 }
493 }
494
495 int dnssec_verify_rrset(
496 DnsAnswer *a,
497 DnsResourceKey *key,
498 DnsResourceRecord *rrsig,
499 DnsResourceRecord *dnskey,
500 usec_t realtime,
501 DnssecResult *result) {
502
503 uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX];
504 size_t hash_size;
505 void *hash;
506 DnsResourceRecord **list, *rr;
507 gcry_md_hd_t md = NULL;
508 int r, md_algorithm;
509 size_t k, n = 0;
510
511 assert(key);
512 assert(rrsig);
513 assert(dnskey);
514 assert(result);
515 assert(rrsig->key->type == DNS_TYPE_RRSIG);
516 assert(dnskey->key->type == DNS_TYPE_DNSKEY);
517
518 /* Verifies the the RRSet matching the specified "key" in "a",
519 * using the signature "rrsig" and the key "dnskey". It's
520 * assumed the RRSIG and DNSKEY match. */
521
522 md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
523 if (md_algorithm == -EOPNOTSUPP) {
524 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
525 return 0;
526 }
527 if (md_algorithm < 0)
528 return md_algorithm;
529
530 r = dnssec_rrsig_expired(rrsig, realtime);
531 if (r < 0)
532 return r;
533 if (r > 0) {
534 *result = DNSSEC_SIGNATURE_EXPIRED;
535 return 0;
536 }
537
538 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
539 list = newa(DnsResourceRecord *, a->n_rrs);
540
541 DNS_ANSWER_FOREACH(rr, a) {
542 r = dns_resource_key_equal(key, rr->key);
543 if (r < 0)
544 return r;
545 if (r == 0)
546 continue;
547
548 /* We need the wire format for ordering, and digest calculation */
549 r = dns_resource_record_to_wire_format(rr, true);
550 if (r < 0)
551 return r;
552
553 list[n++] = rr;
554
555 if (n > VERIFY_RRS_MAX)
556 return -E2BIG;
557 }
558
559 if (n <= 0)
560 return -ENODATA;
561
562 /* Bring the RRs into canonical order */
563 qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
564
565 /* OK, the RRs are now in canonical order. Let's calculate the digest */
566 initialize_libgcrypt();
567
568 hash_size = gcry_md_get_algo_dlen(md_algorithm);
569 assert(hash_size > 0);
570
571 gcry_md_open(&md, md_algorithm, 0);
572 if (!md)
573 return -EIO;
574
575 md_add_uint16(md, rrsig->rrsig.type_covered);
576 md_add_uint8(md, rrsig->rrsig.algorithm);
577 md_add_uint8(md, rrsig->rrsig.labels);
578 md_add_uint32(md, rrsig->rrsig.original_ttl);
579 md_add_uint32(md, rrsig->rrsig.expiration);
580 md_add_uint32(md, rrsig->rrsig.inception);
581 md_add_uint16(md, rrsig->rrsig.key_tag);
582
583 r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
584 if (r < 0)
585 goto finish;
586 gcry_md_write(md, wire_format_name, r);
587
588 for (k = 0; k < n; k++) {
589 const char *suffix;
590 size_t l;
591 rr = list[k];
592
593 r = dns_name_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rrsig->rrsig.labels, &suffix);
594 if (r < 0)
595 goto finish;
596 if (r > 0) /* This is a wildcard! */
597 gcry_md_write(md, (uint8_t[]) { 1, '*'}, 2);
598
599 r = dns_name_to_wire_format(suffix, wire_format_name, sizeof(wire_format_name), true);
600 if (r < 0)
601 goto finish;
602 gcry_md_write(md, wire_format_name, r);
603
604 md_add_uint16(md, rr->key->type);
605 md_add_uint16(md, rr->key->class);
606 md_add_uint32(md, rrsig->rrsig.original_ttl);
607
608 l = DNS_RESOURCE_RECORD_RDATA_SIZE(rr);
609 assert(l <= 0xFFFF);
610
611 md_add_uint16(md, (uint16_t) l);
612 gcry_md_write(md, DNS_RESOURCE_RECORD_RDATA(rr), l);
613 }
614
615 hash = gcry_md_read(md, 0);
616 if (!hash) {
617 r = -EIO;
618 goto finish;
619 }
620
621 switch (rrsig->rrsig.algorithm) {
622
623 case DNSSEC_ALGORITHM_RSASHA1:
624 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
625 case DNSSEC_ALGORITHM_RSASHA256:
626 case DNSSEC_ALGORITHM_RSASHA512:
627 r = dnssec_rsa_verify(
628 gcry_md_algo_name(md_algorithm),
629 hash, hash_size,
630 rrsig,
631 dnskey);
632 break;
633
634 case DNSSEC_ALGORITHM_ECDSAP256SHA256:
635 case DNSSEC_ALGORITHM_ECDSAP384SHA384:
636 r = dnssec_ecdsa_verify(
637 gcry_md_algo_name(md_algorithm),
638 rrsig->rrsig.algorithm,
639 hash, hash_size,
640 rrsig,
641 dnskey);
642 break;
643 }
644
645 if (r < 0)
646 goto finish;
647
648 *result = r ? DNSSEC_VALIDATED : DNSSEC_INVALID;
649 r = 0;
650
651 finish:
652 gcry_md_close(md);
653 return r;
654 }
655
656 int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey) {
657
658 assert(rrsig);
659 assert(dnskey);
660
661 /* Checks if the specified DNSKEY RR matches the key used for
662 * the signature in the specified RRSIG RR */
663
664 if (rrsig->key->type != DNS_TYPE_RRSIG)
665 return -EINVAL;
666
667 if (dnskey->key->type != DNS_TYPE_DNSKEY)
668 return 0;
669 if (dnskey->key->class != rrsig->key->class)
670 return 0;
671 if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
672 return 0;
673 if ((dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE))
674 return 0;
675 if (dnskey->dnskey.protocol != 3)
676 return 0;
677 if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm)
678 return 0;
679
680 if (dnssec_keytag(dnskey) != rrsig->rrsig.key_tag)
681 return 0;
682
683 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), rrsig->rrsig.signer);
684 }
685
686 int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
687 int r;
688
689 assert(key);
690 assert(rrsig);
691
692 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
693
694 if (rrsig->key->type != DNS_TYPE_RRSIG)
695 return 0;
696 if (rrsig->key->class != key->class)
697 return 0;
698 if (rrsig->rrsig.type_covered != key->type)
699 return 0;
700
701 /* Make sure signer is a parent of the RRset */
702 r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rrsig->key), rrsig->rrsig.signer);
703 if (r <= 0)
704 return r;
705
706 /* Make sure the owner name has at least as many labels as the "label" fields indicates. */
707 r = dns_name_count_labels(DNS_RESOURCE_KEY_NAME(rrsig->key));
708 if (r < 0)
709 return r;
710 if (r < rrsig->rrsig.labels)
711 return 0;
712
713 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
714 }
715
716 static int dnssec_fix_rrset_ttl(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord *rrsig, usec_t realtime) {
717 DnsResourceRecord *rr;
718 int r;
719
720 assert(key);
721 assert(rrsig);
722
723 DNS_ANSWER_FOREACH(rr, a) {
724 r = dns_resource_key_equal(key, rr->key);
725 if (r < 0)
726 return r;
727 if (r == 0)
728 continue;
729
730 /* Pick the TTL as the minimum of the RR's TTL, the
731 * RR's original TTL according to the RRSIG and the
732 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
733 rr->ttl = MIN3(rr->ttl, rrsig->rrsig.original_ttl, rrsig->ttl);
734 rr->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
735 }
736
737 return 0;
738 }
739
740 int dnssec_verify_rrset_search(
741 DnsAnswer *a,
742 DnsResourceKey *key,
743 DnsAnswer *validated_dnskeys,
744 usec_t realtime,
745 DnssecResult *result) {
746
747 bool found_rrsig = false, found_invalid = false, found_expired_rrsig = false, found_unsupported_algorithm = false;
748 DnsResourceRecord *rrsig;
749 int r;
750
751 assert(key);
752 assert(result);
753
754 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
755
756 if (!a || a->n_rrs <= 0)
757 return -ENODATA;
758
759 /* Iterate through each RRSIG RR. */
760 DNS_ANSWER_FOREACH(rrsig, a) {
761 DnsResourceRecord *dnskey;
762 DnsAnswerFlags flags;
763
764 /* Is this an RRSIG RR that applies to RRs matching our key? */
765 r = dnssec_key_match_rrsig(key, rrsig);
766 if (r < 0)
767 return r;
768 if (r == 0)
769 continue;
770
771 found_rrsig = true;
772
773 /* Look for a matching key */
774 DNS_ANSWER_FOREACH_FLAGS(dnskey, flags, validated_dnskeys) {
775 DnssecResult one_result;
776
777 if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
778 continue;
779
780 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
781 r = dnssec_rrsig_match_dnskey(rrsig, dnskey);
782 if (r < 0)
783 return r;
784 if (r == 0)
785 continue;
786
787 /* Take the time here, if it isn't set yet, so
788 * that we do all validations with the same
789 * time. */
790 if (realtime == USEC_INFINITY)
791 realtime = now(CLOCK_REALTIME);
792
793 /* Yay, we found a matching RRSIG with a matching
794 * DNSKEY, awesome. Now let's verify all entries of
795 * the RRSet against the RRSIG and DNSKEY
796 * combination. */
797
798 r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime, &one_result);
799 if (r < 0)
800 return r;
801
802 switch (one_result) {
803
804 case DNSSEC_VALIDATED:
805 /* Yay, the RR has been validated,
806 * return immediately, but fix up the expiry */
807 r = dnssec_fix_rrset_ttl(a, key, rrsig, realtime);
808 if (r < 0)
809 return r;
810
811 *result = DNSSEC_VALIDATED;
812 return 0;
813
814 case DNSSEC_INVALID:
815 /* If the signature is invalid, let's try another
816 key and/or signature. After all they
817 key_tags and stuff are not unique, and
818 might be shared by multiple keys. */
819 found_invalid = true;
820 continue;
821
822 case DNSSEC_UNSUPPORTED_ALGORITHM:
823 /* If the key algorithm is
824 unsupported, try another
825 RRSIG/DNSKEY pair, but remember we
826 encountered this, so that we can
827 return a proper error when we
828 encounter nothing better. */
829 found_unsupported_algorithm = true;
830 continue;
831
832 case DNSSEC_SIGNATURE_EXPIRED:
833 /* If the signature is expired, try
834 another one, but remember it, so
835 that we can return this */
836 found_expired_rrsig = true;
837 continue;
838
839 default:
840 assert_not_reached("Unexpected DNSSEC validation result");
841 }
842 }
843 }
844
845 if (found_expired_rrsig)
846 *result = DNSSEC_SIGNATURE_EXPIRED;
847 else if (found_unsupported_algorithm)
848 *result = DNSSEC_UNSUPPORTED_ALGORITHM;
849 else if (found_invalid)
850 *result = DNSSEC_INVALID;
851 else if (found_rrsig)
852 *result = DNSSEC_MISSING_KEY;
853 else
854 *result = DNSSEC_NO_SIGNATURE;
855
856 return 0;
857 }
858
859 int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
860 DnsResourceRecord *rr;
861 int r;
862
863 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
864
865 DNS_ANSWER_FOREACH(rr, a) {
866 r = dnssec_key_match_rrsig(key, rr);
867 if (r < 0)
868 return r;
869 if (r > 0)
870 return 1;
871 }
872
873 return 0;
874 }
875
876 int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
877 size_t c = 0;
878 int r;
879
880 /* Converts the specified hostname into DNSSEC canonicalized
881 * form. */
882
883 if (buffer_max < 2)
884 return -ENOBUFS;
885
886 for (;;) {
887 size_t i;
888
889 r = dns_label_unescape(&n, buffer, buffer_max);
890 if (r < 0)
891 return r;
892 if (r == 0)
893 break;
894 if (r > 0) {
895 int k;
896
897 /* DNSSEC validation is always done on the ASCII version of the label */
898 k = dns_label_apply_idna(buffer, r, buffer, buffer_max);
899 if (k < 0)
900 return k;
901 if (k > 0)
902 r = k;
903 }
904
905 if (buffer_max < (size_t) r + 2)
906 return -ENOBUFS;
907
908 /* The DNSSEC canonical form is not clear on what to
909 * do with dots appearing in labels, the way DNS-SD
910 * does it. Refuse it for now. */
911
912 if (memchr(buffer, '.', r))
913 return -EINVAL;
914
915 for (i = 0; i < (size_t) r; i ++) {
916 if (buffer[i] >= 'A' && buffer[i] <= 'Z')
917 buffer[i] = buffer[i] - 'A' + 'a';
918 }
919
920 buffer[r] = '.';
921
922 buffer += r + 1;
923 c += r + 1;
924
925 buffer_max -= r + 1;
926 }
927
928 if (c <= 0) {
929 /* Not even a single label: this is the root domain name */
930
931 assert(buffer_max > 2);
932 buffer[0] = '.';
933 buffer[1] = 0;
934
935 return 1;
936 }
937
938 return (int) c;
939 }
940
941 static int digest_to_gcrypt_md(uint8_t algorithm) {
942
943 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
944
945 switch (algorithm) {
946
947 case DNSSEC_DIGEST_SHA1:
948 return GCRY_MD_SHA1;
949
950 case DNSSEC_DIGEST_SHA256:
951 return GCRY_MD_SHA256;
952
953 case DNSSEC_DIGEST_SHA384:
954 return GCRY_MD_SHA384;
955
956 default:
957 return -EOPNOTSUPP;
958 }
959 }
960
961 int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
962 char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
963 gcry_md_hd_t md = NULL;
964 size_t hash_size;
965 int md_algorithm, r;
966 void *result;
967
968 assert(dnskey);
969 assert(ds);
970
971 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
972
973 if (dnskey->key->type != DNS_TYPE_DNSKEY)
974 return -EINVAL;
975 if (ds->key->type != DNS_TYPE_DS)
976 return -EINVAL;
977 if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
978 return -EKEYREJECTED;
979 if (dnskey->dnskey.protocol != 3)
980 return -EKEYREJECTED;
981
982 if (dnskey->dnskey.algorithm != ds->ds.algorithm)
983 return 0;
984 if (dnssec_keytag(dnskey) != ds->ds.key_tag)
985 return 0;
986
987 initialize_libgcrypt();
988
989 md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
990 if (md_algorithm < 0)
991 return md_algorithm;
992
993 hash_size = gcry_md_get_algo_dlen(md_algorithm);
994 assert(hash_size > 0);
995
996 if (ds->ds.digest_size != hash_size)
997 return 0;
998
999 r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
1000 if (r < 0)
1001 return r;
1002
1003 gcry_md_open(&md, md_algorithm, 0);
1004 if (!md)
1005 return -EIO;
1006
1007 gcry_md_write(md, owner_name, r);
1008 md_add_uint16(md, dnskey->dnskey.flags);
1009 md_add_uint8(md, dnskey->dnskey.protocol);
1010 md_add_uint8(md, dnskey->dnskey.algorithm);
1011 gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
1012
1013 result = gcry_md_read(md, 0);
1014 if (!result) {
1015 r = -EIO;
1016 goto finish;
1017 }
1018
1019 r = memcmp(result, ds->ds.digest, ds->ds.digest_size) != 0;
1020
1021 finish:
1022 gcry_md_close(md);
1023 return r;
1024 }
1025
1026 int dnssec_verify_dnskey_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds) {
1027 DnsResourceRecord *ds;
1028 DnsAnswerFlags flags;
1029 int r;
1030
1031 assert(dnskey);
1032
1033 if (dnskey->key->type != DNS_TYPE_DNSKEY)
1034 return 0;
1035
1036 DNS_ANSWER_FOREACH_FLAGS(ds, flags, validated_ds) {
1037
1038 if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
1039 continue;
1040
1041 if (ds->key->type != DNS_TYPE_DS)
1042 continue;
1043
1044 if (ds->key->class != dnskey->key->class)
1045 continue;
1046
1047 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), DNS_RESOURCE_KEY_NAME(ds->key));
1048 if (r < 0)
1049 return r;
1050 if (r == 0)
1051 continue;
1052
1053 r = dnssec_verify_dnskey(dnskey, ds);
1054 if (r < 0)
1055 return r;
1056 if (r > 0)
1057 return 1;
1058 }
1059
1060 return 0;
1061 }
1062
1063 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm) {
1064
1065 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1066
1067 switch (algorithm) {
1068
1069 case NSEC3_ALGORITHM_SHA1:
1070 return GCRY_MD_SHA1;
1071
1072 default:
1073 return -EOPNOTSUPP;
1074 }
1075 }
1076
1077 int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
1078 uint8_t wire_format[DNS_WIRE_FOMAT_HOSTNAME_MAX];
1079 gcry_md_hd_t md = NULL;
1080 size_t hash_size;
1081 int algorithm;
1082 void *result;
1083 unsigned k;
1084 int r;
1085
1086 assert(nsec3);
1087 assert(name);
1088 assert(ret);
1089
1090 if (nsec3->key->type != DNS_TYPE_NSEC3)
1091 return -EINVAL;
1092
1093 if (nsec3->nsec3.iterations > NSEC3_ITERATIONS_MAX) {
1094 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3));
1095 return -EOPNOTSUPP;
1096 }
1097
1098 algorithm = nsec3_hash_to_gcrypt_md(nsec3->nsec3.algorithm);
1099 if (algorithm < 0)
1100 return algorithm;
1101
1102 initialize_libgcrypt();
1103
1104 hash_size = gcry_md_get_algo_dlen(algorithm);
1105 assert(hash_size > 0);
1106
1107 if (nsec3->nsec3.next_hashed_name_size != hash_size)
1108 return -EINVAL;
1109
1110 r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
1111 if (r < 0)
1112 return r;
1113
1114 gcry_md_open(&md, algorithm, 0);
1115 if (!md)
1116 return -EIO;
1117
1118 gcry_md_write(md, wire_format, r);
1119 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
1120
1121 result = gcry_md_read(md, 0);
1122 if (!result) {
1123 r = -EIO;
1124 goto finish;
1125 }
1126
1127 for (k = 0; k < nsec3->nsec3.iterations; k++) {
1128 uint8_t tmp[hash_size];
1129 memcpy(tmp, result, hash_size);
1130
1131 gcry_md_reset(md);
1132 gcry_md_write(md, tmp, hash_size);
1133 gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
1134
1135 result = gcry_md_read(md, 0);
1136 if (!result) {
1137 r = -EIO;
1138 goto finish;
1139 }
1140 }
1141
1142 memcpy(ret, result, hash_size);
1143 r = (int) hash_size;
1144
1145 finish:
1146 gcry_md_close(md);
1147 return r;
1148 }
1149
1150 static int nsec3_is_good(DnsResourceRecord *rr, DnsAnswerFlags flags, DnsResourceRecord *nsec3) {
1151 const char *a, *b;
1152 int r;
1153
1154 assert(rr);
1155
1156 if (rr->key->type != DNS_TYPE_NSEC3)
1157 return 0;
1158
1159 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1160 if (!IN_SET(rr->nsec3.flags, 0, 1))
1161 return 0;
1162
1163 /* Ignore NSEC3 RRs whose algorithm we don't know */
1164 if (nsec3_hash_to_gcrypt_md(rr->nsec3.algorithm) < 0)
1165 return 0;
1166 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1167 if (rr->nsec3.iterations > NSEC3_ITERATIONS_MAX)
1168 return 0;
1169
1170 if (!nsec3)
1171 return 1;
1172
1173 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1174
1175 if (nsec3 == rr) /* Shortcut */
1176 return 1;
1177
1178 if (rr->key->class != nsec3->key->class)
1179 return 0;
1180 if (rr->nsec3.algorithm != nsec3->nsec3.algorithm)
1181 return 0;
1182 if (rr->nsec3.iterations != nsec3->nsec3.iterations)
1183 return 0;
1184 if (rr->nsec3.salt_size != nsec3->nsec3.salt_size)
1185 return 0;
1186 if (memcmp(rr->nsec3.salt, nsec3->nsec3.salt, rr->nsec3.salt_size) != 0)
1187 return 0;
1188
1189 a = DNS_RESOURCE_KEY_NAME(rr->key);
1190 r = dns_name_parent(&a); /* strip off hash */
1191 if (r < 0)
1192 return r;
1193 if (r == 0)
1194 return 0;
1195
1196 b = DNS_RESOURCE_KEY_NAME(nsec3->key);
1197 r = dns_name_parent(&b); /* strip off hash */
1198 if (r < 0)
1199 return r;
1200 if (r == 0)
1201 return 0;
1202
1203 return dns_name_equal(a, b);
1204 }
1205
1206 static int nsec3_hashed_domain(DnsResourceRecord *nsec3, const char *domain, const char *zone, char **ret) {
1207 _cleanup_free_ char *l = NULL, *hashed_domain = NULL;
1208 uint8_t hashed[DNSSEC_HASH_SIZE_MAX];
1209 int hashed_size;
1210
1211 assert(nsec3);
1212 assert(domain);
1213 assert(zone);
1214 assert(ret);
1215
1216 hashed_size = dnssec_nsec3_hash(nsec3, domain, hashed);
1217 if (hashed_size < 0)
1218 return hashed_size;
1219
1220 l = base32hexmem(hashed, hashed_size, false);
1221 if (!l)
1222 return -ENOMEM;
1223
1224 hashed_domain = strjoin(l, ".", zone, NULL);
1225 if (!hashed_domain)
1226 return -ENOMEM;
1227
1228 *ret = hashed_domain;
1229 hashed_domain = NULL;
1230
1231 return hashed_size;
1232 }
1233
1234 /* See RFC 5155, Section 8
1235 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1236 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1237 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1238 * matches the wildcard domain.
1239 *
1240 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1241 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1242 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1243 * to conclude anything we indicate this by returning NO_RR. */
1244 static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated) {
1245 _cleanup_free_ char *next_closer_domain = NULL, *wildcard = NULL, *wildcard_domain = NULL;
1246 const char *zone, *p, *pp = NULL;
1247 DnsResourceRecord *rr, *enclosure_rr, *suffix_rr, *wildcard_rr = NULL;
1248 DnsAnswerFlags flags;
1249 int hashed_size, r;
1250 bool a, no_closer = false, no_wildcard = false, optout = false;
1251
1252 assert(key);
1253 assert(result);
1254 assert(authenticated);
1255
1256 /* First step, find the zone name and the NSEC3 parameters of the zone.
1257 * it is sufficient to look for the longest common suffix we find with
1258 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1259 * records from a given zone in a response must use the same
1260 * parameters. */
1261 zone = DNS_RESOURCE_KEY_NAME(key);
1262 for (;;) {
1263 DNS_ANSWER_FOREACH_FLAGS(suffix_rr, flags, answer) {
1264 r = nsec3_is_good(suffix_rr, flags, NULL);
1265 if (r < 0)
1266 return r;
1267 if (r == 0)
1268 continue;
1269
1270 r = dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(suffix_rr->key), 1, zone);
1271 if (r < 0)
1272 return r;
1273 if (r > 0)
1274 goto found_zone;
1275 }
1276
1277 /* Strip one label from the front */
1278 r = dns_name_parent(&zone);
1279 if (r < 0)
1280 return r;
1281 if (r == 0)
1282 break;
1283 }
1284
1285 *result = DNSSEC_NSEC_NO_RR;
1286 return 0;
1287
1288 found_zone:
1289 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1290 p = DNS_RESOURCE_KEY_NAME(key);
1291 for (;;) {
1292 _cleanup_free_ char *hashed_domain = NULL;
1293
1294 hashed_size = nsec3_hashed_domain(suffix_rr, p, zone, &hashed_domain);
1295 if (hashed_size == -EOPNOTSUPP) {
1296 *result = DNSSEC_NSEC_UNSUPPORTED_ALGORITHM;
1297 return 0;
1298 }
1299 if (hashed_size < 0)
1300 return hashed_size;
1301
1302 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr, flags, answer) {
1303
1304 r = nsec3_is_good(enclosure_rr, flags, suffix_rr);
1305 if (r < 0)
1306 return r;
1307 if (r == 0)
1308 continue;
1309
1310 if (enclosure_rr->nsec3.next_hashed_name_size != (size_t) hashed_size)
1311 continue;
1312
1313 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr->key), hashed_domain);
1314 if (r < 0)
1315 return r;
1316 if (r > 0) {
1317 a = flags & DNS_ANSWER_AUTHENTICATED;
1318 goto found_closest_encloser;
1319 }
1320 }
1321
1322 /* We didn't find the closest encloser with this name,
1323 * but let's remember this domain name, it might be
1324 * the next closer name */
1325
1326 pp = p;
1327
1328 /* Strip one label from the front */
1329 r = dns_name_parent(&p);
1330 if (r < 0)
1331 return r;
1332 if (r == 0)
1333 break;
1334 }
1335
1336 *result = DNSSEC_NSEC_NO_RR;
1337 return 0;
1338
1339 found_closest_encloser:
1340 /* We found a closest encloser in 'p'; next closer is 'pp' */
1341
1342 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1343 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_DNAME))
1344 return -EBADMSG;
1345
1346 /* Ensure that this data is from the delegated domain
1347 * (i.e. originates from the "lower" DNS server), and isn't
1348 * just glue records (i.e. doesn't originate from the "upper"
1349 * DNS server). */
1350 if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_NS) &&
1351 !bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA))
1352 return -EBADMSG;
1353
1354 if (!pp) {
1355 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1356 if (bitmap_isset(enclosure_rr->nsec3.types, key->type))
1357 *result = DNSSEC_NSEC_FOUND;
1358 else if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_CNAME))
1359 *result = DNSSEC_NSEC_CNAME;
1360 else
1361 *result = DNSSEC_NSEC_NODATA;
1362
1363 *authenticated = a;
1364
1365 return 0;
1366 }
1367
1368 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1369
1370 wildcard = strappend("*.", p);
1371 if (!wildcard)
1372 return -ENOMEM;
1373
1374 r = nsec3_hashed_domain(enclosure_rr, wildcard, zone, &wildcard_domain);
1375 if (r < 0)
1376 return r;
1377 if (r != hashed_size)
1378 return -EBADMSG;
1379
1380 r = nsec3_hashed_domain(enclosure_rr, pp, zone, &next_closer_domain);
1381 if (r < 0)
1382 return r;
1383 if (r != hashed_size)
1384 return -EBADMSG;
1385
1386 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1387 _cleanup_free_ char *label = NULL, *next_hashed_domain = NULL;
1388
1389 r = nsec3_is_good(rr, flags, suffix_rr);
1390 if (r < 0)
1391 return r;
1392 if (r == 0)
1393 continue;
1394
1395 label = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
1396 if (!label)
1397 return -ENOMEM;
1398
1399 next_hashed_domain = strjoin(label, ".", zone, NULL);
1400 if (!next_hashed_domain)
1401 return -ENOMEM;
1402
1403 r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), next_closer_domain, next_hashed_domain);
1404 if (r < 0)
1405 return r;
1406 if (r > 0) {
1407 if (rr->nsec3.flags & 1)
1408 optout = true;
1409
1410 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1411
1412 no_closer = true;
1413 }
1414
1415 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain);
1416 if (r < 0)
1417 return r;
1418 if (r > 0) {
1419 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1420
1421 wildcard_rr = rr;
1422 }
1423
1424 r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain, next_hashed_domain);
1425 if (r < 0)
1426 return r;
1427 if (r > 0) {
1428 if (rr->nsec3.flags & 1)
1429 /* This only makes sense if we have a wildcard delegation, which is
1430 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1431 * this not happening, so hence cannot simply conclude NXDOMAIN as
1432 * we would wish */
1433 optout = true;
1434
1435 a = a && (flags & DNS_ANSWER_AUTHENTICATED);
1436
1437 no_wildcard = true;
1438 }
1439 }
1440
1441 if (wildcard_rr && no_wildcard)
1442 return -EBADMSG;
1443
1444 if (!no_closer) {
1445 *result = DNSSEC_NSEC_NO_RR;
1446
1447 return 0;
1448 }
1449
1450 if (wildcard_rr) {
1451 /* A wildcard exists that matches our query. */
1452 if (optout)
1453 /* This is not specified in any RFC to the best of my knowledge, but
1454 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1455 * it means that we cannot prove that the source of synthesis is
1456 * correct, as there may be a closer match. */
1457 *result = DNSSEC_NSEC_OPTOUT;
1458 else if (bitmap_isset(wildcard_rr->nsec3.types, key->type))
1459 *result = DNSSEC_NSEC_FOUND;
1460 else if (bitmap_isset(wildcard_rr->nsec3.types, DNS_TYPE_CNAME))
1461 *result = DNSSEC_NSEC_CNAME;
1462 else
1463 *result = DNSSEC_NSEC_NODATA;
1464 } else {
1465 if (optout)
1466 /* The RFC only specifies that we have to care for optout for NODATA for
1467 * DS records. However, children of an insecure opt-out delegation should
1468 * also be considered opt-out, rather than verified NXDOMAIN.
1469 * Note that we do not require a proof of wildcard non-existence if the
1470 * next closer domain is covered by an opt-out, as that would not provide
1471 * any additional information. */
1472 *result = DNSSEC_NSEC_OPTOUT;
1473 else if (no_wildcard)
1474 *result = DNSSEC_NSEC_NXDOMAIN;
1475 else {
1476 *result = DNSSEC_NSEC_NO_RR;
1477
1478 return 0;
1479 }
1480 }
1481
1482 *authenticated = a;
1483
1484 return 0;
1485 }
1486
1487 int dnssec_test_nsec(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated) {
1488 DnsResourceRecord *rr;
1489 bool have_nsec3 = false;
1490 DnsAnswerFlags flags;
1491 int r;
1492
1493 assert(key);
1494 assert(result);
1495 assert(authenticated);
1496
1497 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1498
1499 DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
1500
1501 if (rr->key->class != key->class)
1502 continue;
1503
1504 switch (rr->key->type) {
1505
1506 case DNS_TYPE_NSEC:
1507
1508 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
1509 if (r < 0)
1510 return r;
1511 if (r > 0) {
1512 if (bitmap_isset(rr->nsec.types, key->type))
1513 *result = DNSSEC_NSEC_FOUND;
1514 else if (bitmap_isset(rr->nsec.types, DNS_TYPE_CNAME))
1515 *result = DNSSEC_NSEC_CNAME;
1516 else
1517 *result = DNSSEC_NSEC_NODATA;
1518 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1519 return 0;
1520 }
1521
1522 r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key), rr->nsec.next_domain_name);
1523 if (r < 0)
1524 return r;
1525 if (r > 0) {
1526 *result = DNSSEC_NSEC_NXDOMAIN;
1527 *authenticated = flags & DNS_ANSWER_AUTHENTICATED;
1528 return 0;
1529 }
1530 break;
1531
1532 case DNS_TYPE_NSEC3:
1533 have_nsec3 = true;
1534 break;
1535 }
1536 }
1537
1538 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1539 if (have_nsec3)
1540 return dnssec_test_nsec3(answer, key, result, authenticated);
1541
1542 /* No approproate NSEC RR found, report this. */
1543 *result = DNSSEC_NSEC_NO_RR;
1544 return 0;
1545 }
1546
1547 static const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = {
1548 [DNSSEC_NO] = "no",
1549 [DNSSEC_DOWNGRADE_OK] = "downgrade-ok",
1550 [DNSSEC_YES] = "yes",
1551 };
1552 DEFINE_STRING_TABLE_LOOKUP(dnssec_mode, DnssecMode);
1553
1554 static const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = {
1555 [DNSSEC_VALIDATED] = "validated",
1556 [DNSSEC_INVALID] = "invalid",
1557 [DNSSEC_SIGNATURE_EXPIRED] = "signature-expired",
1558 [DNSSEC_UNSUPPORTED_ALGORITHM] = "unsupported-algorithm",
1559 [DNSSEC_NO_SIGNATURE] = "no-signature",
1560 [DNSSEC_MISSING_KEY] = "missing-key",
1561 [DNSSEC_UNSIGNED] = "unsigned",
1562 [DNSSEC_FAILED_AUXILIARY] = "failed-auxiliary",
1563 [DNSSEC_NSEC_MISMATCH] = "nsec-mismatch",
1564 [DNSSEC_INCOMPATIBLE_SERVER] = "incompatible-server",
1565 };
1566 DEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult);