1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2015 Lennart Poettering
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.
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.
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/>.
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"
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?
38 * - wildcard zones compatibility (NSEC/NSEC3 wildcard check is missing)
39 * - multi-label zone compatibility
40 * - cname/dname compatibility
42 * - bus calls to override DNSEC setting per interface
43 * - log all DNSSEC downgrades
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)
51 #define VERIFY_RRS_MAX 256
52 #define MAX_KEY_SIZE (32*1024)
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)
57 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
58 #define NSEC3_ITERATIONS_MAX 2500
61 * The DNSSEC Chain of trust:
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
68 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
71 static void initialize_libgcrypt(void) {
74 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
77 p
= gcry_check_version("1.4.5");
80 gcry_control(GCRYCTL_DISABLE_SECMEM
);
81 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
84 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
, bool mask_revoke
) {
89 /* The algorithm from RFC 4034, Appendix B. */
92 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
94 f
= (uint32_t) dnskey
->dnskey
.flags
;
97 f
&= ~DNSKEY_FLAG_REVOKE
;
99 sum
= f
+ ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
101 p
= dnskey
->dnskey
.key
;
103 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
104 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
106 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
108 return sum
& UINT32_C(0xFFFF);
111 static int rr_compare(const void *a
, const void *b
) {
112 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
116 /* Let's order the RRs according to RFC 4034, Section 6.3 */
120 assert((*x
)->wire_format
);
123 assert((*y
)->wire_format
);
125 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
127 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
131 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
133 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
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
) {
146 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
147 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
151 assert(hash_algorithm
);
153 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
159 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
165 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
171 ge
= gcry_sexp_build(&signature_sexp
,
173 "(sig-val (rsa (s %m)))",
181 ge
= gcry_sexp_build(&data_sexp
,
183 "(data (flags pkcs1) (hash %s %b))",
192 ge
= gcry_sexp_build(&public_key_sexp
,
194 "(public-key (rsa (n %m) (e %m)))",
202 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
203 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
206 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
220 gcry_sexp_release(public_key_sexp
);
222 gcry_sexp_release(signature_sexp
);
224 gcry_sexp_release(data_sexp
);
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
) {
235 size_t exponent_size
, modulus_size
;
236 void *exponent
, *modulus
;
238 assert(hash_algorithm
);
240 assert(hash_size
> 0);
244 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
245 /* exponent is > 255 bytes long */
247 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
249 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
250 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
252 if (exponent_size
< 256)
255 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
258 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
259 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
262 /* exponent is <= 255 bytes long */
264 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
265 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
267 if (exponent_size
<= 0)
270 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
273 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
274 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
277 return dnssec_rsa_verify_raw(
279 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
281 exponent
, exponent_size
,
282 modulus
, modulus_size
);
285 static int dnssec_ecdsa_verify_raw(
286 const char *hash_algorithm
,
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
) {
293 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
294 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
298 assert(hash_algorithm
);
300 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
306 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
312 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
318 ge
= gcry_sexp_build(&signature_sexp
,
320 "(sig-val (ecdsa (r %m) (s %m)))",
328 ge
= gcry_sexp_build(&data_sexp
,
330 "(data (flags rfc6979) (hash %s %b))",
339 ge
= gcry_sexp_build(&public_key_sexp
,
341 "(public-key (ecc (curve %s) (q %m)))",
349 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
350 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
353 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
366 gcry_sexp_release(public_key_sexp
);
368 gcry_sexp_release(signature_sexp
);
370 gcry_sexp_release(data_sexp
);
375 static int dnssec_ecdsa_verify(
376 const char *hash_algorithm
,
378 const void *hash
, size_t hash_size
,
379 DnsResourceRecord
*rrsig
,
380 DnsResourceRecord
*dnskey
) {
391 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
393 curve
= "NIST P-256";
394 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
396 curve
= "NIST P-384";
400 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
403 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
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);
410 return dnssec_ecdsa_verify_raw(
413 rrsig
->rrsig
.signature
, key_size
,
414 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
419 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
420 gcry_md_write(md
, &v
, sizeof(v
));
423 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
425 gcry_md_write(md
, &v
, sizeof(v
));
428 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
430 gcry_md_write(md
, &v
, sizeof(v
));
433 static int dnssec_rrsig_prepare(DnsResourceRecord
*rrsig
) {
434 int n_key_labels
, n_signer_labels
;
438 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source and
439 * .n_skip_labels_signer fields so that we can use them later on. */
442 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
444 /* Check if this RRSIG RR is already prepared */
445 if (rrsig
->n_skip_labels_source
!= (unsigned) -1)
448 if (rrsig
->rrsig
.inception
> rrsig
->rrsig
.expiration
)
451 name
= DNS_RESOURCE_KEY_NAME(rrsig
->key
);
453 n_key_labels
= dns_name_count_labels(name
);
454 if (n_key_labels
< 0)
456 if (rrsig
->rrsig
.labels
> n_key_labels
)
459 n_signer_labels
= dns_name_count_labels(rrsig
->rrsig
.signer
);
460 if (n_signer_labels
< 0)
461 return n_signer_labels
;
462 if (n_signer_labels
> rrsig
->rrsig
.labels
)
465 r
= dns_name_skip(name
, n_key_labels
- n_signer_labels
, &name
);
471 /* Check if the signer is really a suffix of us */
472 r
= dns_name_equal(name
, rrsig
->rrsig
.signer
);
478 rrsig
->n_skip_labels_source
= n_key_labels
- rrsig
->rrsig
.labels
;
479 rrsig
->n_skip_labels_signer
= n_key_labels
- n_signer_labels
;
484 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
485 usec_t expiration
, inception
, skew
;
488 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
490 if (realtime
== USEC_INFINITY
)
491 realtime
= now(CLOCK_REALTIME
);
493 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
494 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
496 /* Consider inverted validity intervals as expired */
497 if (inception
> expiration
)
500 /* Permit a certain amount of clock skew of 10% of the valid
501 * time range. This takes inspiration from unbound's
503 skew
= (expiration
- inception
) / 10;
507 if (inception
< skew
)
512 if (expiration
+ skew
< expiration
)
513 expiration
= USEC_INFINITY
;
517 return realtime
< inception
|| realtime
> expiration
;
520 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
522 /* Translates a DNSSEC signature algorithm into a gcrypt
525 * Note that we implement all algorithms listed as "Must
526 * implement" and "Recommended to Implement" in RFC6944. We
527 * don't implement any algorithms that are listed as
528 * "Optional" or "Must Not Implement". Specifically, we do not
529 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
534 case DNSSEC_ALGORITHM_RSASHA1
:
535 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
538 case DNSSEC_ALGORITHM_RSASHA256
:
539 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
540 return GCRY_MD_SHA256
;
542 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
543 return GCRY_MD_SHA384
;
545 case DNSSEC_ALGORITHM_RSASHA512
:
546 return GCRY_MD_SHA512
;
553 static void dnssec_fix_rrset_ttl(
554 DnsResourceRecord
*list
[],
556 DnsResourceRecord
*rrsig
,
565 for (k
= 0; k
< n
; k
++) {
566 DnsResourceRecord
*rr
= list
[k
];
568 /* Pick the TTL as the minimum of the RR's TTL, the
569 * RR's original TTL according to the RRSIG and the
570 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
571 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
572 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
574 /* Copy over information about the signer and wildcard source of synthesis */
575 rr
->n_skip_labels_source
= rrsig
->n_skip_labels_source
;
576 rr
->n_skip_labels_signer
= rrsig
->n_skip_labels_signer
;
579 rrsig
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
582 int dnssec_verify_rrset(
584 const DnsResourceKey
*key
,
585 DnsResourceRecord
*rrsig
,
586 DnsResourceRecord
*dnskey
,
588 DnssecResult
*result
) {
590 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
591 DnsResourceRecord
**list
, *rr
;
592 const char *source
, *name
;
593 gcry_md_hd_t md
= NULL
;
604 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
605 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
607 /* Verifies the the RRSet matching the specified "key" in "a",
608 * using the signature "rrsig" and the key "dnskey". It's
609 * assumed the RRSIG and DNSKEY match. */
611 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
612 if (md_algorithm
== -EOPNOTSUPP
) {
613 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
616 if (md_algorithm
< 0)
619 r
= dnssec_rrsig_prepare(rrsig
);
621 *result
= DNSSEC_INVALID
;
627 r
= dnssec_rrsig_expired(rrsig
, realtime
);
631 *result
= DNSSEC_SIGNATURE_EXPIRED
;
635 name
= DNS_RESOURCE_KEY_NAME(key
);
637 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
638 if (dns_type_apex_only(rrsig
->rrsig
.type_covered
)) {
639 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
643 *result
= DNSSEC_INVALID
;
648 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
649 if (rrsig
->rrsig
.type_covered
== DNS_TYPE_DS
) {
650 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
654 *result
= DNSSEC_INVALID
;
659 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
660 r
= dns_name_suffix(name
, rrsig
->rrsig
.labels
, &source
);
663 if (r
> 0 && !dns_type_may_wildcard(rrsig
->rrsig
.type_covered
)) {
664 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
665 *result
= DNSSEC_INVALID
;
669 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
670 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
671 r
= dns_name_startswith(name
, "*");
681 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
682 list
= newa(DnsResourceRecord
*, dns_answer_size(a
));
684 DNS_ANSWER_FOREACH(rr
, a
) {
685 r
= dns_resource_key_equal(key
, rr
->key
);
691 /* We need the wire format for ordering, and digest calculation */
692 r
= dns_resource_record_to_wire_format(rr
, true);
698 if (n
> VERIFY_RRS_MAX
)
705 /* Bring the RRs into canonical order */
706 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
708 /* OK, the RRs are now in canonical order. Let's calculate the digest */
709 initialize_libgcrypt();
711 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
712 assert(hash_size
> 0);
714 gcry_md_open(&md
, md_algorithm
, 0);
718 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
719 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
720 md_add_uint8(md
, rrsig
->rrsig
.labels
);
721 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
722 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
723 md_add_uint32(md
, rrsig
->rrsig
.inception
);
724 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
726 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
729 gcry_md_write(md
, wire_format_name
, r
);
731 /* Convert the source of synthesis into wire format */
732 r
= dns_name_to_wire_format(source
, wire_format_name
, sizeof(wire_format_name
), true);
736 for (k
= 0; k
< n
; k
++) {
741 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
743 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
744 gcry_md_write(md
, wire_format_name
, r
);
746 md_add_uint16(md
, rr
->key
->type
);
747 md_add_uint16(md
, rr
->key
->class);
748 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
750 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
753 md_add_uint16(md
, (uint16_t) l
);
754 gcry_md_write(md
, DNS_RESOURCE_RECORD_RDATA(rr
), l
);
757 hash
= gcry_md_read(md
, 0);
763 switch (rrsig
->rrsig
.algorithm
) {
765 case DNSSEC_ALGORITHM_RSASHA1
:
766 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
767 case DNSSEC_ALGORITHM_RSASHA256
:
768 case DNSSEC_ALGORITHM_RSASHA512
:
769 r
= dnssec_rsa_verify(
770 gcry_md_algo_name(md_algorithm
),
776 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
777 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
778 r
= dnssec_ecdsa_verify(
779 gcry_md_algo_name(md_algorithm
),
780 rrsig
->rrsig
.algorithm
,
790 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
792 dnssec_fix_rrset_ttl(list
, n
, rrsig
, realtime
);
795 *result
= DNSSEC_INVALID
;
797 *result
= DNSSEC_VALIDATED_WILDCARD
;
799 *result
= DNSSEC_VALIDATED
;
808 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
813 /* Checks if the specified DNSKEY RR matches the key used for
814 * the signature in the specified RRSIG RR */
816 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
819 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
821 if (dnskey
->key
->class != rrsig
->key
->class)
823 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
825 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
827 if (dnskey
->dnskey
.protocol
!= 3)
829 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
832 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
835 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
838 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
842 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
844 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
846 if (rrsig
->key
->class != key
->class)
848 if (rrsig
->rrsig
.type_covered
!= key
->type
)
851 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
854 int dnssec_verify_rrset_search(
856 const DnsResourceKey
*key
,
857 DnsAnswer
*validated_dnskeys
,
859 DnssecResult
*result
,
860 DnsResourceRecord
**ret_rrsig
) {
862 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
863 DnsResourceRecord
*rrsig
;
869 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
871 if (!a
|| a
->n_rrs
<= 0)
874 /* Iterate through each RRSIG RR. */
875 DNS_ANSWER_FOREACH(rrsig
, a
) {
876 DnsResourceRecord
*dnskey
;
877 DnsAnswerFlags flags
;
879 /* Is this an RRSIG RR that applies to RRs matching our key? */
880 r
= dnssec_key_match_rrsig(key
, rrsig
);
888 /* Look for a matching key */
889 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
890 DnssecResult one_result
;
892 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
895 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
896 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
902 /* Take the time here, if it isn't set yet, so
903 * that we do all validations with the same
905 if (realtime
== USEC_INFINITY
)
906 realtime
= now(CLOCK_REALTIME
);
908 /* Yay, we found a matching RRSIG with a matching
909 * DNSKEY, awesome. Now let's verify all entries of
910 * the RRSet against the RRSIG and DNSKEY
913 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
917 switch (one_result
) {
919 case DNSSEC_VALIDATED
:
920 case DNSSEC_VALIDATED_WILDCARD
:
921 /* Yay, the RR has been validated,
922 * return immediately, but fix up the expiry */
926 *result
= one_result
;
930 /* If the signature is invalid, let's try another
931 key and/or signature. After all they
932 key_tags and stuff are not unique, and
933 might be shared by multiple keys. */
934 found_invalid
= true;
937 case DNSSEC_UNSUPPORTED_ALGORITHM
:
938 /* If the key algorithm is
939 unsupported, try another
940 RRSIG/DNSKEY pair, but remember we
941 encountered this, so that we can
942 return a proper error when we
943 encounter nothing better. */
944 found_unsupported_algorithm
= true;
947 case DNSSEC_SIGNATURE_EXPIRED
:
948 /* If the signature is expired, try
949 another one, but remember it, so
950 that we can return this */
951 found_expired_rrsig
= true;
955 assert_not_reached("Unexpected DNSSEC validation result");
960 if (found_expired_rrsig
)
961 *result
= DNSSEC_SIGNATURE_EXPIRED
;
962 else if (found_unsupported_algorithm
)
963 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
964 else if (found_invalid
)
965 *result
= DNSSEC_INVALID
;
966 else if (found_rrsig
)
967 *result
= DNSSEC_MISSING_KEY
;
969 *result
= DNSSEC_NO_SIGNATURE
;
977 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
978 DnsResourceRecord
*rr
;
981 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
983 DNS_ANSWER_FOREACH(rr
, a
) {
984 r
= dnssec_key_match_rrsig(key
, rr
);
994 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
998 /* Converts the specified hostname into DNSSEC canonicalized
1005 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
1013 /* DNSSEC validation is always done on the ASCII version of the label */
1014 k
= dns_label_apply_idna(buffer
, r
, buffer
, buffer_max
);
1021 if (buffer_max
< (size_t) r
+ 2)
1024 /* The DNSSEC canonical form is not clear on what to
1025 * do with dots appearing in labels, the way DNS-SD
1026 * does it. Refuse it for now. */
1028 if (memchr(buffer
, '.', r
))
1031 ascii_strlower_n(buffer
, (size_t) r
);
1037 buffer_max
-= r
+ 1;
1041 /* Not even a single label: this is the root domain name */
1043 assert(buffer_max
> 2);
1053 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1055 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1057 switch (algorithm
) {
1059 case DNSSEC_DIGEST_SHA1
:
1060 return GCRY_MD_SHA1
;
1062 case DNSSEC_DIGEST_SHA256
:
1063 return GCRY_MD_SHA256
;
1065 case DNSSEC_DIGEST_SHA384
:
1066 return GCRY_MD_SHA384
;
1073 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1074 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
1075 gcry_md_hd_t md
= NULL
;
1077 int md_algorithm
, r
;
1083 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1085 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1087 if (ds
->key
->type
!= DNS_TYPE_DS
)
1089 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1090 return -EKEYREJECTED
;
1091 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1092 return -EKEYREJECTED
;
1093 if (dnskey
->dnskey
.protocol
!= 3)
1094 return -EKEYREJECTED
;
1096 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1098 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1101 initialize_libgcrypt();
1103 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1104 if (md_algorithm
< 0)
1105 return md_algorithm
;
1107 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1108 assert(hash_size
> 0);
1110 if (ds
->ds
.digest_size
!= hash_size
)
1113 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
1117 gcry_md_open(&md
, md_algorithm
, 0);
1121 gcry_md_write(md
, owner_name
, r
);
1123 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1125 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1126 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1127 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1128 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1130 result
= gcry_md_read(md
, 0);
1136 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1143 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1144 DnsResourceRecord
*ds
;
1145 DnsAnswerFlags flags
;
1150 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1153 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1155 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1158 if (ds
->key
->type
!= DNS_TYPE_DS
)
1160 if (ds
->key
->class != dnskey
->key
->class)
1163 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1169 r
= dnssec_verify_dnskey_by_ds(dnskey
, ds
, false);
1170 if (IN_SET(r
, -EKEYREJECTED
, -EOPNOTSUPP
))
1171 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1181 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1183 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1185 switch (algorithm
) {
1187 case NSEC3_ALGORITHM_SHA1
:
1188 return GCRY_MD_SHA1
;
1195 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1196 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1197 gcry_md_hd_t md
= NULL
;
1208 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1211 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1212 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1216 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1220 initialize_libgcrypt();
1222 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1223 assert(hash_size
> 0);
1225 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1228 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1232 gcry_md_open(&md
, algorithm
, 0);
1236 gcry_md_write(md
, wire_format
, r
);
1237 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1239 result
= gcry_md_read(md
, 0);
1245 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1246 uint8_t tmp
[hash_size
];
1247 memcpy(tmp
, result
, hash_size
);
1250 gcry_md_write(md
, tmp
, hash_size
);
1251 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1253 result
= gcry_md_read(md
, 0);
1260 memcpy(ret
, result
, hash_size
);
1261 r
= (int) hash_size
;
1268 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1274 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1277 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1278 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1281 /* Ignore NSEC3 RRs whose algorithm we don't know */
1282 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1284 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1285 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1288 /* Ignore NSEC3 RRs generated from wildcards */
1289 if (rr
->n_skip_labels_source
!= 0)
1291 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1292 if (rr
->n_skip_labels_signer
!= 1)
1298 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1300 if (nsec3
== rr
) /* Shortcut */
1303 if (rr
->key
->class != nsec3
->key
->class)
1305 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1307 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1309 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1311 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1314 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1315 r
= dns_name_parent(&a
); /* strip off hash */
1321 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1322 r
= dns_name_parent(&b
); /* strip off hash */
1328 /* Make sure both have the same parent */
1329 return dns_name_equal(a
, b
);
1332 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1333 _cleanup_free_
char *l
= NULL
;
1337 assert(hashed_size
> 0);
1341 l
= base32hexmem(hashed
, hashed_size
, false);
1345 j
= strjoin(l
, ".", zone
, NULL
);
1350 return (int) hashed_size
;
1353 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1354 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1362 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1363 if (hashed_size
< 0)
1366 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1369 /* See RFC 5155, Section 8
1370 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1371 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1372 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1373 * matches the wildcard domain.
1375 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1376 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1377 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1378 * to conclude anything we indicate this by returning NO_RR. */
1379 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1380 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1381 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1382 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1383 DnsAnswerFlags flags
;
1385 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1390 /* First step, find the zone name and the NSEC3 parameters of the zone.
1391 * it is sufficient to look for the longest common suffix we find with
1392 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1393 * records from a given zone in a response must use the same
1395 zone
= DNS_RESOURCE_KEY_NAME(key
);
1397 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1398 r
= nsec3_is_good(zone_rr
, NULL
);
1404 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr
->key
), 1, zone
);
1411 /* Strip one label from the front */
1412 r
= dns_name_parent(&zone
);
1419 *result
= DNSSEC_NSEC_NO_RR
;
1423 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1424 p
= DNS_RESOURCE_KEY_NAME(key
);
1426 _cleanup_free_
char *hashed_domain
= NULL
;
1428 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1429 if (hashed_size
== -EOPNOTSUPP
) {
1430 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1433 if (hashed_size
< 0)
1436 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1438 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1444 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1447 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr
->key
), hashed_domain
);
1451 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1452 goto found_closest_encloser
;
1456 /* We didn't find the closest encloser with this name,
1457 * but let's remember this domain name, it might be
1458 * the next closer name */
1462 /* Strip one label from the front */
1463 r
= dns_name_parent(&p
);
1470 *result
= DNSSEC_NSEC_NO_RR
;
1473 found_closest_encloser
:
1474 /* We found a closest encloser in 'p'; next closer is 'pp' */
1476 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1477 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1480 /* Ensure that this data is from the delegated domain
1481 * (i.e. originates from the "lower" DNS server), and isn't
1482 * just glue records (i.e. doesn't originate from the "upper"
1484 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1485 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1489 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1490 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1491 *result
= DNSSEC_NSEC_FOUND
;
1492 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1493 *result
= DNSSEC_NSEC_CNAME
;
1495 *result
= DNSSEC_NSEC_NODATA
;
1500 *ttl
= enclosure_rr
->ttl
;
1505 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1507 wildcard
= strjoina("*.", p
);
1508 r
= nsec3_hashed_domain_make(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1511 if (r
!= hashed_size
)
1514 r
= nsec3_hashed_domain_make(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1517 if (r
!= hashed_size
)
1520 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1521 _cleanup_free_
char *next_hashed_domain
= NULL
;
1523 r
= nsec3_is_good(rr
, zone_rr
);
1529 r
= nsec3_hashed_domain_format(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, zone
, &next_hashed_domain
);
1533 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1537 if (rr
->nsec3
.flags
& 1)
1540 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1545 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
);
1549 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1554 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
, next_hashed_domain
);
1558 if (rr
->nsec3
.flags
& 1)
1559 /* This only makes sense if we have a wildcard delegation, which is
1560 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1561 * this not happening, so hence cannot simply conclude NXDOMAIN as
1565 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1571 if (wildcard_rr
&& no_wildcard
)
1575 *result
= DNSSEC_NSEC_NO_RR
;
1580 /* A wildcard exists that matches our query. */
1582 /* This is not specified in any RFC to the best of my knowledge, but
1583 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1584 * it means that we cannot prove that the source of synthesis is
1585 * correct, as there may be a closer match. */
1586 *result
= DNSSEC_NSEC_OPTOUT
;
1587 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1588 *result
= DNSSEC_NSEC_FOUND
;
1589 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1590 *result
= DNSSEC_NSEC_CNAME
;
1592 *result
= DNSSEC_NSEC_NODATA
;
1595 /* The RFC only specifies that we have to care for optout for NODATA for
1596 * DS records. However, children of an insecure opt-out delegation should
1597 * also be considered opt-out, rather than verified NXDOMAIN.
1598 * Note that we do not require a proof of wildcard non-existence if the
1599 * next closer domain is covered by an opt-out, as that would not provide
1600 * any additional information. */
1601 *result
= DNSSEC_NSEC_OPTOUT
;
1602 else if (no_wildcard
)
1603 *result
= DNSSEC_NSEC_NXDOMAIN
;
1605 *result
= DNSSEC_NSEC_NO_RR
;
1615 *ttl
= enclosure_rr
->ttl
;
1620 static int dnssec_nsec_wildcard_equal(DnsResourceRecord
*rr
, const char *name
) {
1621 char label
[DNS_LABEL_MAX
];
1626 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1628 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1630 if (rr
->n_skip_labels_source
!= 1)
1633 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1634 r
= dns_label_unescape(&n
, label
, sizeof(label
));
1637 if (r
!= 1 || label
[0] != '*')
1640 return dns_name_endswith(name
, n
);
1643 static int dnssec_nsec_in_path(DnsResourceRecord
*rr
, const char *name
) {
1644 const char *nn
, *common_suffix
;
1648 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1650 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1652 * A couple of examples:
1654 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1655 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1656 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1659 /* First, determine parent of next domain. */
1660 nn
= rr
->nsec
.next_domain_name
;
1661 r
= dns_name_parent(&nn
);
1665 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1666 * anything at all. */
1667 r
= dns_name_endswith(nn
, name
);
1671 /* If the name we we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */
1672 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1676 return dns_name_endswith(name
, common_suffix
);
1679 static int dnssec_nsec_from_parent_zone(DnsResourceRecord
*rr
, const char *name
) {
1683 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1685 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1687 r
= dns_name_parent(&name
);
1691 r
= dns_name_equal(name
, DNS_RESOURCE_KEY_NAME(rr
->key
));
1695 /* DNAME, and NS without SOA is an indication for a delegation. */
1696 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_DNAME
))
1699 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) && !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1705 static int dnssec_nsec_covers(DnsResourceRecord
*rr
, const char *name
) {
1706 const char *common_suffix
, *p
;
1710 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1712 /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
1714 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1720 r
= dns_name_parent(&name
);
1726 r
= dns_name_equal(name
, common_suffix
);
1733 /* p is now the "Next Closer". */
1735 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), p
, rr
->nsec
.next_domain_name
);
1738 static int dnssec_nsec_covers_wildcard(DnsResourceRecord
*rr
, const char *name
) {
1739 const char *common_suffix
, *wc
;
1743 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1745 /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified
1746 * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as
1747 * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label.
1749 * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist
1750 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...)
1751 * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
1754 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1758 /* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */
1759 r
= dns_name_endswith(name
, common_suffix
);
1763 wc
= strjoina("*.", common_suffix
, NULL
);
1764 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wc
, rr
->nsec
.next_domain_name
);
1767 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1768 bool have_nsec3
= false, covering_rr_authenticated
= false, wildcard_rr_authenticated
= false;
1769 DnsResourceRecord
*rr
, *covering_rr
= NULL
, *wildcard_rr
= NULL
;
1770 DnsAnswerFlags flags
;
1777 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1779 name
= DNS_RESOURCE_KEY_NAME(key
);
1781 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1783 if (rr
->key
->class != key
->class)
1786 have_nsec3
= have_nsec3
|| (rr
->key
->type
== DNS_TYPE_NSEC3
);
1788 if (rr
->key
->type
!= DNS_TYPE_NSEC
)
1791 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1792 r
= dns_resource_record_is_synthetic(rr
);
1798 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1799 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), name
);
1803 /* If it's not a direct match, maybe it's a wild card match? */
1804 r
= dnssec_nsec_wildcard_equal(rr
, name
);
1809 if (key
->type
== DNS_TYPE_DS
) {
1810 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1811 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1812 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1815 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1816 * we got the child's NSEC. */
1817 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) &&
1818 !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1822 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1823 *result
= DNSSEC_NSEC_FOUND
;
1824 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1825 *result
= DNSSEC_NSEC_CNAME
;
1827 *result
= DNSSEC_NSEC_NODATA
;
1830 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1837 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1838 * of the NSEC RR. */
1839 r
= dnssec_nsec_in_path(rr
, name
);
1843 *result
= DNSSEC_NSEC_NODATA
;
1846 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1853 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1854 r
= dnssec_nsec_from_parent_zone(rr
, name
);
1860 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1861 r
= dnssec_nsec_covers(rr
, name
);
1864 if (r
> 0 && (!covering_rr
|| !covering_rr_authenticated
)) {
1866 covering_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1869 /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
1870 r
= dnssec_nsec_covers_wildcard(rr
, name
);
1873 if (r
> 0 && (!wildcard_rr
|| !wildcard_rr_authenticated
)) {
1875 wildcard_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1879 if (covering_rr
&& wildcard_rr
) {
1880 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1881 * proved the NXDOMAIN case. */
1882 *result
= DNSSEC_NSEC_NXDOMAIN
;
1885 *authenticated
= covering_rr_authenticated
&& wildcard_rr_authenticated
;
1887 *ttl
= MIN(covering_rr
->ttl
, wildcard_rr
->ttl
);
1892 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1894 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
1896 /* No approproate NSEC RR found, report this. */
1897 *result
= DNSSEC_NSEC_NO_RR
;
1901 int dnssec_nsec_test_enclosed(DnsAnswer
*answer
, uint16_t type
, const char *name
, const char *zone
, bool *authenticated
) {
1902 DnsResourceRecord
*rr
;
1903 DnsAnswerFlags flags
;
1909 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
1910 * 'zone'. The 'zone' must be a suffix of the 'name'. */
1912 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1915 if (rr
->key
->type
!= type
&& type
!= DNS_TYPE_ANY
)
1918 switch (rr
->key
->type
) {
1922 /* We only care for NSEC RRs from the indicated zone */
1923 r
= dns_resource_record_is_signer(rr
, zone
);
1929 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), name
, rr
->nsec
.next_domain_name
);
1936 case DNS_TYPE_NSEC3
: {
1937 _cleanup_free_
char *hashed_domain
= NULL
, *next_hashed_domain
= NULL
;
1939 /* We only care for NSEC3 RRs from the indicated zone */
1940 r
= dns_resource_record_is_signer(rr
, zone
);
1946 r
= nsec3_is_good(rr
, NULL
);
1952 /* Format the domain we are testing with the NSEC3 RR's hash function */
1953 r
= nsec3_hashed_domain_make(
1960 if ((size_t) r
!= rr
->nsec3
.next_hashed_name_size
)
1963 /* Format the NSEC3's next hashed name as proper domain name */
1964 r
= nsec3_hashed_domain_format(
1965 rr
->nsec3
.next_hashed_name
,
1966 rr
->nsec3
.next_hashed_name_size
,
1968 &next_hashed_domain
);
1972 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), hashed_domain
, next_hashed_domain
);
1986 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1994 static int dnssec_test_positive_wildcard_nsec3(
1999 bool *authenticated
) {
2001 const char *next_closer
= NULL
;
2004 /* Run a positive NSEC3 wildcard proof. Specifically:
2006 * A proof that the the "next closer" of the generating wildcard does not exist.
2008 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
2009 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
2010 * exists for the NSEC3 RR and we are done.
2012 * 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
2013 * c.d.e.f does not exist. */
2017 r
= dns_name_parent(&name
);
2023 r
= dns_name_equal(name
, source
);
2030 return dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC3
, next_closer
, zone
, authenticated
);
2033 static int dnssec_test_positive_wildcard_nsec(
2038 bool *_authenticated
) {
2040 bool authenticated
= true;
2043 /* Run a positive NSEC wildcard proof. Specifically:
2045 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2046 * a prefix of the synthesizing source "source" in the zone "zone".
2048 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2050 * 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
2051 * have to prove that none of the following exist:
2062 _cleanup_free_
char *wc
= NULL
;
2065 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2066 * i.e between the owner name and the next name of an NSEC RR. */
2067 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, name
, zone
, &a
);
2071 authenticated
= authenticated
&& a
;
2073 /* Strip one label off */
2074 r
= dns_name_parent(&name
);
2078 /* Did we reach the source of synthesis? */
2079 r
= dns_name_equal(name
, source
);
2083 /* Successful exit */
2084 *_authenticated
= authenticated
;
2088 /* Safety check, that the source of synthesis is still our suffix */
2089 r
= dns_name_endswith(name
, source
);
2095 /* Replace the label we stripped off with an asterisk */
2096 wc
= strappend("*.", name
);
2100 /* And check if the proof holds for the asterisk name, too */
2101 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, wc
, zone
, &a
);
2105 authenticated
= authenticated
&& a
;
2106 /* In the next iteration we'll check the non-asterisk-prefixed version */
2110 int dnssec_test_positive_wildcard(
2115 bool *authenticated
) {
2122 assert(authenticated
);
2124 r
= dns_answer_contains_zone_nsec3(answer
, zone
);
2128 return dnssec_test_positive_wildcard_nsec3(answer
, name
, source
, zone
, authenticated
);
2130 return dnssec_test_positive_wildcard_nsec(answer
, name
, source
, zone
, authenticated
);
2133 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
2134 [DNSSEC_VALIDATED
] = "validated",
2135 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
2136 [DNSSEC_INVALID
] = "invalid",
2137 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
2138 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
2139 [DNSSEC_NO_SIGNATURE
] = "no-signature",
2140 [DNSSEC_MISSING_KEY
] = "missing-key",
2141 [DNSSEC_UNSIGNED
] = "unsigned",
2142 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
2143 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
2144 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
2146 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);