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