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