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