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 * - bus calls to override DNSEC setting per interface
39 * - log all DNSSEC downgrades
40 * - log all RRs that failed validation
42 * - Allow clients to request DNSSEC even if DNSSEC is off
43 * - make sure when getting an NXDOMAIN response through CNAME, we still process the first CNAMEs in the packet
44 * - update test-complex to also do ResolveAddress lookups
45 * - extend complex test to check "xn--kprw13d." DNAME domain
46 * - rework IDNA stuff: only to IDNA for ResolveAddress and ResolveService, and prepare a pair of lookup keys then, never do IDNA comparisons after that
49 #define VERIFY_RRS_MAX 256
50 #define MAX_KEY_SIZE (32*1024)
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)
55 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
56 #define NSEC3_ITERATIONS_MAX 2500
59 * The DNSSEC Chain of trust:
61 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
62 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
63 * DS RRs are protected like normal RRs
66 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
69 static void initialize_libgcrypt(void) {
72 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
75 p
= gcry_check_version("1.4.5");
78 gcry_control(GCRYCTL_DISABLE_SECMEM
);
79 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
82 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
, bool mask_revoke
) {
87 /* The algorithm from RFC 4034, Appendix B. */
90 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
92 f
= (uint32_t) dnskey
->dnskey
.flags
;
95 f
&= ~DNSKEY_FLAG_REVOKE
;
97 sum
= f
+ ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
99 p
= dnskey
->dnskey
.key
;
101 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
102 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
104 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
106 return sum
& UINT32_C(0xFFFF);
109 static int rr_compare(const void *a
, const void *b
) {
110 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
114 /* Let's order the RRs according to RFC 4034, Section 6.3 */
118 assert((*x
)->wire_format
);
121 assert((*y
)->wire_format
);
123 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
125 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
129 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
131 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
137 static int dnssec_rsa_verify_raw(
138 const char *hash_algorithm
,
139 const void *signature
, size_t signature_size
,
140 const void *data
, size_t data_size
,
141 const void *exponent
, size_t exponent_size
,
142 const void *modulus
, size_t modulus_size
) {
144 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
145 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
149 assert(hash_algorithm
);
151 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
157 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
163 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
169 ge
= gcry_sexp_build(&signature_sexp
,
171 "(sig-val (rsa (s %m)))",
179 ge
= gcry_sexp_build(&data_sexp
,
181 "(data (flags pkcs1) (hash %s %b))",
190 ge
= gcry_sexp_build(&public_key_sexp
,
192 "(public-key (rsa (n %m) (e %m)))",
200 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
201 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
204 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
218 gcry_sexp_release(public_key_sexp
);
220 gcry_sexp_release(signature_sexp
);
222 gcry_sexp_release(data_sexp
);
227 static int dnssec_rsa_verify(
228 const char *hash_algorithm
,
229 const void *hash
, size_t hash_size
,
230 DnsResourceRecord
*rrsig
,
231 DnsResourceRecord
*dnskey
) {
233 size_t exponent_size
, modulus_size
;
234 void *exponent
, *modulus
;
236 assert(hash_algorithm
);
238 assert(hash_size
> 0);
242 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
243 /* exponent is > 255 bytes long */
245 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
247 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
248 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
250 if (exponent_size
< 256)
253 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
256 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
257 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
260 /* exponent is <= 255 bytes long */
262 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
263 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
265 if (exponent_size
<= 0)
268 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
271 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
272 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
275 return dnssec_rsa_verify_raw(
277 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
279 exponent
, exponent_size
,
280 modulus
, modulus_size
);
283 static int dnssec_ecdsa_verify_raw(
284 const char *hash_algorithm
,
286 const void *signature_r
, size_t signature_r_size
,
287 const void *signature_s
, size_t signature_s_size
,
288 const void *data
, size_t data_size
,
289 const void *key
, size_t key_size
) {
291 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
292 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
296 assert(hash_algorithm
);
298 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
304 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
310 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
316 ge
= gcry_sexp_build(&signature_sexp
,
318 "(sig-val (ecdsa (r %m) (s %m)))",
326 ge
= gcry_sexp_build(&data_sexp
,
328 "(data (flags rfc6979) (hash %s %b))",
337 ge
= gcry_sexp_build(&public_key_sexp
,
339 "(public-key (ecc (curve %s) (q %m)))",
347 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
348 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
351 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
364 gcry_sexp_release(public_key_sexp
);
366 gcry_sexp_release(signature_sexp
);
368 gcry_sexp_release(data_sexp
);
373 static int dnssec_ecdsa_verify(
374 const char *hash_algorithm
,
376 const void *hash
, size_t hash_size
,
377 DnsResourceRecord
*rrsig
,
378 DnsResourceRecord
*dnskey
) {
389 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
391 curve
= "NIST P-256";
392 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
394 curve
= "NIST P-384";
398 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
401 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
404 q
= alloca(key_size
*2 + 1);
405 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
406 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
408 return dnssec_ecdsa_verify_raw(
411 rrsig
->rrsig
.signature
, key_size
,
412 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
417 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
418 gcry_md_write(md
, &v
, sizeof(v
));
421 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
423 gcry_md_write(md
, &v
, sizeof(v
));
426 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
428 gcry_md_write(md
, &v
, sizeof(v
));
431 static int dnssec_rrsig_prepare(DnsResourceRecord
*rrsig
) {
432 int n_key_labels
, n_signer_labels
;
436 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source and
437 * .n_skip_labels_signer fields so that we can use them later on. */
440 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
442 /* Check if this RRSIG RR is already prepared */
443 if (rrsig
->n_skip_labels_source
!= (unsigned) -1)
446 if (rrsig
->rrsig
.inception
> rrsig
->rrsig
.expiration
)
449 name
= DNS_RESOURCE_KEY_NAME(rrsig
->key
);
451 n_key_labels
= dns_name_count_labels(name
);
452 if (n_key_labels
< 0)
454 if (rrsig
->rrsig
.labels
> n_key_labels
)
457 n_signer_labels
= dns_name_count_labels(rrsig
->rrsig
.signer
);
458 if (n_signer_labels
< 0)
459 return n_signer_labels
;
460 if (n_signer_labels
> rrsig
->rrsig
.labels
)
463 r
= dns_name_skip(name
, n_key_labels
- n_signer_labels
, &name
);
469 /* Check if the signer is really a suffix of us */
470 r
= dns_name_equal(name
, rrsig
->rrsig
.signer
);
476 rrsig
->n_skip_labels_source
= n_key_labels
- rrsig
->rrsig
.labels
;
477 rrsig
->n_skip_labels_signer
= n_key_labels
- n_signer_labels
;
482 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
483 usec_t expiration
, inception
, skew
;
486 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
488 if (realtime
== USEC_INFINITY
)
489 realtime
= now(CLOCK_REALTIME
);
491 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
492 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
494 /* Consider inverted validity intervals as expired */
495 if (inception
> expiration
)
498 /* Permit a certain amount of clock skew of 10% of the valid
499 * time range. This takes inspiration from unbound's
501 skew
= (expiration
- inception
) / 10;
505 if (inception
< skew
)
510 if (expiration
+ skew
< expiration
)
511 expiration
= USEC_INFINITY
;
515 return realtime
< inception
|| realtime
> expiration
;
518 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
520 /* Translates a DNSSEC signature algorithm into a gcrypt
523 * Note that we implement all algorithms listed as "Must
524 * implement" and "Recommended to Implement" in RFC6944. We
525 * don't implement any algorithms that are listed as
526 * "Optional" or "Must Not Implement". Specifically, we do not
527 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
532 case DNSSEC_ALGORITHM_RSASHA1
:
533 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
536 case DNSSEC_ALGORITHM_RSASHA256
:
537 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
538 return GCRY_MD_SHA256
;
540 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
541 return GCRY_MD_SHA384
;
543 case DNSSEC_ALGORITHM_RSASHA512
:
544 return GCRY_MD_SHA512
;
551 static void dnssec_fix_rrset_ttl(
552 DnsResourceRecord
*list
[],
554 DnsResourceRecord
*rrsig
,
563 for (k
= 0; k
< n
; k
++) {
564 DnsResourceRecord
*rr
= list
[k
];
566 /* Pick the TTL as the minimum of the RR's TTL, the
567 * RR's original TTL according to the RRSIG and the
568 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
569 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
570 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
572 /* Copy over information about the signer and wildcard source of synthesis */
573 rr
->n_skip_labels_source
= rrsig
->n_skip_labels_source
;
574 rr
->n_skip_labels_signer
= rrsig
->n_skip_labels_signer
;
577 rrsig
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
580 int dnssec_verify_rrset(
582 const DnsResourceKey
*key
,
583 DnsResourceRecord
*rrsig
,
584 DnsResourceRecord
*dnskey
,
586 DnssecResult
*result
) {
588 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
589 DnsResourceRecord
**list
, *rr
;
590 const char *source
, *name
;
591 gcry_md_hd_t md
= NULL
;
602 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
603 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
605 /* Verifies the the RRSet matching the specified "key" in "a",
606 * using the signature "rrsig" and the key "dnskey". It's
607 * assumed the RRSIG and DNSKEY match. */
609 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
610 if (md_algorithm
== -EOPNOTSUPP
) {
611 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
614 if (md_algorithm
< 0)
617 r
= dnssec_rrsig_prepare(rrsig
);
619 *result
= DNSSEC_INVALID
;
625 r
= dnssec_rrsig_expired(rrsig
, realtime
);
629 *result
= DNSSEC_SIGNATURE_EXPIRED
;
633 name
= DNS_RESOURCE_KEY_NAME(key
);
635 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
636 if (dns_type_apex_only(rrsig
->rrsig
.type_covered
)) {
637 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
641 *result
= DNSSEC_INVALID
;
646 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
647 if (rrsig
->rrsig
.type_covered
== DNS_TYPE_DS
) {
648 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
652 *result
= DNSSEC_INVALID
;
657 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
658 r
= dns_name_suffix(name
, rrsig
->rrsig
.labels
, &source
);
661 if (r
> 0 && !dns_type_may_wildcard(rrsig
->rrsig
.type_covered
)) {
662 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
663 *result
= DNSSEC_INVALID
;
667 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
668 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
669 r
= dns_name_startswith(name
, "*");
679 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
680 list
= newa(DnsResourceRecord
*, dns_answer_size(a
));
682 DNS_ANSWER_FOREACH(rr
, a
) {
683 r
= dns_resource_key_equal(key
, rr
->key
);
689 /* We need the wire format for ordering, and digest calculation */
690 r
= dns_resource_record_to_wire_format(rr
, true);
696 if (n
> VERIFY_RRS_MAX
)
703 /* Bring the RRs into canonical order */
704 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
706 /* OK, the RRs are now in canonical order. Let's calculate the digest */
707 initialize_libgcrypt();
709 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
710 assert(hash_size
> 0);
712 gcry_md_open(&md
, md_algorithm
, 0);
716 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
717 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
718 md_add_uint8(md
, rrsig
->rrsig
.labels
);
719 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
720 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
721 md_add_uint32(md
, rrsig
->rrsig
.inception
);
722 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
724 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
727 gcry_md_write(md
, wire_format_name
, r
);
729 /* Convert the source of synthesis into wire format */
730 r
= dns_name_to_wire_format(source
, wire_format_name
, sizeof(wire_format_name
), true);
734 for (k
= 0; k
< n
; k
++) {
739 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
741 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
742 gcry_md_write(md
, wire_format_name
, r
);
744 md_add_uint16(md
, rr
->key
->type
);
745 md_add_uint16(md
, rr
->key
->class);
746 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
748 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
751 md_add_uint16(md
, (uint16_t) l
);
752 gcry_md_write(md
, DNS_RESOURCE_RECORD_RDATA(rr
), l
);
755 hash
= gcry_md_read(md
, 0);
761 switch (rrsig
->rrsig
.algorithm
) {
763 case DNSSEC_ALGORITHM_RSASHA1
:
764 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
765 case DNSSEC_ALGORITHM_RSASHA256
:
766 case DNSSEC_ALGORITHM_RSASHA512
:
767 r
= dnssec_rsa_verify(
768 gcry_md_algo_name(md_algorithm
),
774 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
775 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
776 r
= dnssec_ecdsa_verify(
777 gcry_md_algo_name(md_algorithm
),
778 rrsig
->rrsig
.algorithm
,
788 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
790 dnssec_fix_rrset_ttl(list
, n
, rrsig
, realtime
);
793 *result
= DNSSEC_INVALID
;
795 *result
= DNSSEC_VALIDATED_WILDCARD
;
797 *result
= DNSSEC_VALIDATED
;
806 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
811 /* Checks if the specified DNSKEY RR matches the key used for
812 * the signature in the specified RRSIG RR */
814 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
817 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
819 if (dnskey
->key
->class != rrsig
->key
->class)
821 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
823 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
825 if (dnskey
->dnskey
.protocol
!= 3)
827 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
830 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
833 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
836 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
840 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
842 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
844 if (rrsig
->key
->class != key
->class)
846 if (rrsig
->rrsig
.type_covered
!= key
->type
)
849 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
852 int dnssec_verify_rrset_search(
854 const DnsResourceKey
*key
,
855 DnsAnswer
*validated_dnskeys
,
857 DnssecResult
*result
,
858 DnsResourceRecord
**ret_rrsig
) {
860 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
861 DnsResourceRecord
*rrsig
;
867 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
869 if (!a
|| a
->n_rrs
<= 0)
872 /* Iterate through each RRSIG RR. */
873 DNS_ANSWER_FOREACH(rrsig
, a
) {
874 DnsResourceRecord
*dnskey
;
875 DnsAnswerFlags flags
;
877 /* Is this an RRSIG RR that applies to RRs matching our key? */
878 r
= dnssec_key_match_rrsig(key
, rrsig
);
886 /* Look for a matching key */
887 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
888 DnssecResult one_result
;
890 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
893 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
894 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
900 /* Take the time here, if it isn't set yet, so
901 * that we do all validations with the same
903 if (realtime
== USEC_INFINITY
)
904 realtime
= now(CLOCK_REALTIME
);
906 /* Yay, we found a matching RRSIG with a matching
907 * DNSKEY, awesome. Now let's verify all entries of
908 * the RRSet against the RRSIG and DNSKEY
911 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
915 switch (one_result
) {
917 case DNSSEC_VALIDATED
:
918 case DNSSEC_VALIDATED_WILDCARD
:
919 /* Yay, the RR has been validated,
920 * return immediately, but fix up the expiry */
924 *result
= one_result
;
928 /* If the signature is invalid, let's try another
929 key and/or signature. After all they
930 key_tags and stuff are not unique, and
931 might be shared by multiple keys. */
932 found_invalid
= true;
935 case DNSSEC_UNSUPPORTED_ALGORITHM
:
936 /* If the key algorithm is
937 unsupported, try another
938 RRSIG/DNSKEY pair, but remember we
939 encountered this, so that we can
940 return a proper error when we
941 encounter nothing better. */
942 found_unsupported_algorithm
= true;
945 case DNSSEC_SIGNATURE_EXPIRED
:
946 /* If the signature is expired, try
947 another one, but remember it, so
948 that we can return this */
949 found_expired_rrsig
= true;
953 assert_not_reached("Unexpected DNSSEC validation result");
958 if (found_expired_rrsig
)
959 *result
= DNSSEC_SIGNATURE_EXPIRED
;
960 else if (found_unsupported_algorithm
)
961 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
962 else if (found_invalid
)
963 *result
= DNSSEC_INVALID
;
964 else if (found_rrsig
)
965 *result
= DNSSEC_MISSING_KEY
;
967 *result
= DNSSEC_NO_SIGNATURE
;
975 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
976 DnsResourceRecord
*rr
;
979 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
981 DNS_ANSWER_FOREACH(rr
, a
) {
982 r
= dnssec_key_match_rrsig(key
, rr
);
992 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
996 /* Converts the specified hostname into DNSSEC canonicalized
1003 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
1009 if (buffer_max
< (size_t) r
+ 2)
1012 /* The DNSSEC canonical form is not clear on what to
1013 * do with dots appearing in labels, the way DNS-SD
1014 * does it. Refuse it for now. */
1016 if (memchr(buffer
, '.', r
))
1019 ascii_strlower_n(buffer
, (size_t) r
);
1025 buffer_max
-= r
+ 1;
1029 /* Not even a single label: this is the root domain name */
1031 assert(buffer_max
> 2);
1041 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1043 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1045 switch (algorithm
) {
1047 case DNSSEC_DIGEST_SHA1
:
1048 return GCRY_MD_SHA1
;
1050 case DNSSEC_DIGEST_SHA256
:
1051 return GCRY_MD_SHA256
;
1053 case DNSSEC_DIGEST_SHA384
:
1054 return GCRY_MD_SHA384
;
1061 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1062 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
1063 gcry_md_hd_t md
= NULL
;
1065 int md_algorithm
, r
;
1071 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1073 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1075 if (ds
->key
->type
!= DNS_TYPE_DS
)
1077 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1078 return -EKEYREJECTED
;
1079 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1080 return -EKEYREJECTED
;
1081 if (dnskey
->dnskey
.protocol
!= 3)
1082 return -EKEYREJECTED
;
1084 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1086 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1089 initialize_libgcrypt();
1091 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1092 if (md_algorithm
< 0)
1093 return md_algorithm
;
1095 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1096 assert(hash_size
> 0);
1098 if (ds
->ds
.digest_size
!= hash_size
)
1101 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
1105 gcry_md_open(&md
, md_algorithm
, 0);
1109 gcry_md_write(md
, owner_name
, r
);
1111 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1113 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1114 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1115 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1116 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1118 result
= gcry_md_read(md
, 0);
1124 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1131 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1132 DnsResourceRecord
*ds
;
1133 DnsAnswerFlags flags
;
1138 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1141 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1143 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1146 if (ds
->key
->type
!= DNS_TYPE_DS
)
1148 if (ds
->key
->class != dnskey
->key
->class)
1151 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1157 r
= dnssec_verify_dnskey_by_ds(dnskey
, ds
, false);
1158 if (IN_SET(r
, -EKEYREJECTED
, -EOPNOTSUPP
))
1159 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1169 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1171 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1173 switch (algorithm
) {
1175 case NSEC3_ALGORITHM_SHA1
:
1176 return GCRY_MD_SHA1
;
1183 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1184 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1185 gcry_md_hd_t md
= NULL
;
1196 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1199 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1200 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1204 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1208 initialize_libgcrypt();
1210 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1211 assert(hash_size
> 0);
1213 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1216 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1220 gcry_md_open(&md
, algorithm
, 0);
1224 gcry_md_write(md
, wire_format
, r
);
1225 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1227 result
= gcry_md_read(md
, 0);
1233 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1234 uint8_t tmp
[hash_size
];
1235 memcpy(tmp
, result
, hash_size
);
1238 gcry_md_write(md
, tmp
, hash_size
);
1239 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1241 result
= gcry_md_read(md
, 0);
1248 memcpy(ret
, result
, hash_size
);
1249 r
= (int) hash_size
;
1256 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1262 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1265 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1266 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1269 /* Ignore NSEC3 RRs whose algorithm we don't know */
1270 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1272 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1273 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1276 /* Ignore NSEC3 RRs generated from wildcards */
1277 if (rr
->n_skip_labels_source
!= 0)
1279 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1280 if (rr
->n_skip_labels_signer
!= 1)
1286 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1288 if (nsec3
== rr
) /* Shortcut */
1291 if (rr
->key
->class != nsec3
->key
->class)
1293 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1295 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1297 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1299 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1302 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1303 r
= dns_name_parent(&a
); /* strip off hash */
1309 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1310 r
= dns_name_parent(&b
); /* strip off hash */
1316 /* Make sure both have the same parent */
1317 return dns_name_equal(a
, b
);
1320 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1321 _cleanup_free_
char *l
= NULL
;
1325 assert(hashed_size
> 0);
1329 l
= base32hexmem(hashed
, hashed_size
, false);
1333 j
= strjoin(l
, ".", zone
, NULL
);
1338 return (int) hashed_size
;
1341 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1342 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1350 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1351 if (hashed_size
< 0)
1354 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1357 /* See RFC 5155, Section 8
1358 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1359 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1360 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1361 * matches the wildcard domain.
1363 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1364 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1365 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1366 * to conclude anything we indicate this by returning NO_RR. */
1367 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1368 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1369 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1370 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1371 DnsAnswerFlags flags
;
1373 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1378 /* First step, find the zone name and the NSEC3 parameters of the zone.
1379 * it is sufficient to look for the longest common suffix we find with
1380 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1381 * records from a given zone in a response must use the same
1383 zone
= DNS_RESOURCE_KEY_NAME(key
);
1385 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1386 r
= nsec3_is_good(zone_rr
, NULL
);
1392 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr
->key
), 1, zone
);
1399 /* Strip one label from the front */
1400 r
= dns_name_parent(&zone
);
1407 *result
= DNSSEC_NSEC_NO_RR
;
1411 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1412 p
= DNS_RESOURCE_KEY_NAME(key
);
1414 _cleanup_free_
char *hashed_domain
= NULL
;
1416 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1417 if (hashed_size
== -EOPNOTSUPP
) {
1418 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1421 if (hashed_size
< 0)
1424 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1426 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1432 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1435 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr
->key
), hashed_domain
);
1439 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1440 goto found_closest_encloser
;
1444 /* We didn't find the closest encloser with this name,
1445 * but let's remember this domain name, it might be
1446 * the next closer name */
1450 /* Strip one label from the front */
1451 r
= dns_name_parent(&p
);
1458 *result
= DNSSEC_NSEC_NO_RR
;
1461 found_closest_encloser
:
1462 /* We found a closest encloser in 'p'; next closer is 'pp' */
1464 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1465 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1468 /* Ensure that this data is from the delegated domain
1469 * (i.e. originates from the "lower" DNS server), and isn't
1470 * just glue records (i.e. doesn't originate from the "upper"
1472 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1473 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1477 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1478 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1479 *result
= DNSSEC_NSEC_FOUND
;
1480 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1481 *result
= DNSSEC_NSEC_CNAME
;
1483 *result
= DNSSEC_NSEC_NODATA
;
1488 *ttl
= enclosure_rr
->ttl
;
1493 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1495 wildcard
= strjoina("*.", p
);
1496 r
= nsec3_hashed_domain_make(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1499 if (r
!= hashed_size
)
1502 r
= nsec3_hashed_domain_make(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1505 if (r
!= hashed_size
)
1508 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1509 _cleanup_free_
char *next_hashed_domain
= NULL
;
1511 r
= nsec3_is_good(rr
, zone_rr
);
1517 r
= nsec3_hashed_domain_format(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, zone
, &next_hashed_domain
);
1521 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1525 if (rr
->nsec3
.flags
& 1)
1528 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1533 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
);
1537 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1542 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
, next_hashed_domain
);
1546 if (rr
->nsec3
.flags
& 1)
1547 /* This only makes sense if we have a wildcard delegation, which is
1548 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1549 * this not happening, so hence cannot simply conclude NXDOMAIN as
1553 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1559 if (wildcard_rr
&& no_wildcard
)
1563 *result
= DNSSEC_NSEC_NO_RR
;
1568 /* A wildcard exists that matches our query. */
1570 /* This is not specified in any RFC to the best of my knowledge, but
1571 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1572 * it means that we cannot prove that the source of synthesis is
1573 * correct, as there may be a closer match. */
1574 *result
= DNSSEC_NSEC_OPTOUT
;
1575 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1576 *result
= DNSSEC_NSEC_FOUND
;
1577 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1578 *result
= DNSSEC_NSEC_CNAME
;
1580 *result
= DNSSEC_NSEC_NODATA
;
1583 /* The RFC only specifies that we have to care for optout for NODATA for
1584 * DS records. However, children of an insecure opt-out delegation should
1585 * also be considered opt-out, rather than verified NXDOMAIN.
1586 * Note that we do not require a proof of wildcard non-existence if the
1587 * next closer domain is covered by an opt-out, as that would not provide
1588 * any additional information. */
1589 *result
= DNSSEC_NSEC_OPTOUT
;
1590 else if (no_wildcard
)
1591 *result
= DNSSEC_NSEC_NXDOMAIN
;
1593 *result
= DNSSEC_NSEC_NO_RR
;
1603 *ttl
= enclosure_rr
->ttl
;
1608 static int dnssec_nsec_wildcard_equal(DnsResourceRecord
*rr
, const char *name
) {
1609 char label
[DNS_LABEL_MAX
];
1614 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1616 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1618 if (rr
->n_skip_labels_source
!= 1)
1621 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1622 r
= dns_label_unescape(&n
, label
, sizeof(label
));
1625 if (r
!= 1 || label
[0] != '*')
1628 return dns_name_endswith(name
, n
);
1631 static int dnssec_nsec_in_path(DnsResourceRecord
*rr
, const char *name
) {
1632 const char *nn
, *common_suffix
;
1636 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1638 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1640 * A couple of examples:
1642 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1643 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1644 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1647 /* First, determine parent of next domain. */
1648 nn
= rr
->nsec
.next_domain_name
;
1649 r
= dns_name_parent(&nn
);
1653 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1654 * anything at all. */
1655 r
= dns_name_endswith(nn
, name
);
1659 /* 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. */
1660 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1664 return dns_name_endswith(name
, common_suffix
);
1667 static int dnssec_nsec_from_parent_zone(DnsResourceRecord
*rr
, const char *name
) {
1671 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1673 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1675 r
= dns_name_parent(&name
);
1679 r
= dns_name_equal(name
, DNS_RESOURCE_KEY_NAME(rr
->key
));
1683 /* DNAME, and NS without SOA is an indication for a delegation. */
1684 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_DNAME
))
1687 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) && !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1693 static int dnssec_nsec_covers(DnsResourceRecord
*rr
, const char *name
) {
1694 const char *common_suffix
, *p
;
1698 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1700 /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
1702 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1708 r
= dns_name_parent(&name
);
1714 r
= dns_name_equal(name
, common_suffix
);
1721 /* p is now the "Next Closer". */
1723 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), p
, rr
->nsec
.next_domain_name
);
1726 static int dnssec_nsec_covers_wildcard(DnsResourceRecord
*rr
, const char *name
) {
1727 const char *common_suffix
, *wc
;
1731 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1733 /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified
1734 * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as
1735 * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label.
1737 * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist
1738 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...)
1739 * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
1742 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1746 /* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */
1747 r
= dns_name_endswith(name
, common_suffix
);
1751 wc
= strjoina("*.", common_suffix
, NULL
);
1752 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wc
, rr
->nsec
.next_domain_name
);
1755 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1756 bool have_nsec3
= false, covering_rr_authenticated
= false, wildcard_rr_authenticated
= false;
1757 DnsResourceRecord
*rr
, *covering_rr
= NULL
, *wildcard_rr
= NULL
;
1758 DnsAnswerFlags flags
;
1765 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1767 name
= DNS_RESOURCE_KEY_NAME(key
);
1769 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1771 if (rr
->key
->class != key
->class)
1774 have_nsec3
= have_nsec3
|| (rr
->key
->type
== DNS_TYPE_NSEC3
);
1776 if (rr
->key
->type
!= DNS_TYPE_NSEC
)
1779 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1780 r
= dns_resource_record_is_synthetic(rr
);
1786 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1787 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), name
);
1791 /* If it's not a direct match, maybe it's a wild card match? */
1792 r
= dnssec_nsec_wildcard_equal(rr
, name
);
1797 if (key
->type
== DNS_TYPE_DS
) {
1798 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1799 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1800 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1803 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1804 * we got the child's NSEC. */
1805 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) &&
1806 !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1810 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1811 *result
= DNSSEC_NSEC_FOUND
;
1812 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1813 *result
= DNSSEC_NSEC_CNAME
;
1815 *result
= DNSSEC_NSEC_NODATA
;
1818 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1825 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1826 * of the NSEC RR. */
1827 r
= dnssec_nsec_in_path(rr
, name
);
1831 *result
= DNSSEC_NSEC_NODATA
;
1834 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1841 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1842 r
= dnssec_nsec_from_parent_zone(rr
, name
);
1848 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1849 r
= dnssec_nsec_covers(rr
, name
);
1852 if (r
> 0 && (!covering_rr
|| !covering_rr_authenticated
)) {
1854 covering_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1857 /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
1858 r
= dnssec_nsec_covers_wildcard(rr
, name
);
1861 if (r
> 0 && (!wildcard_rr
|| !wildcard_rr_authenticated
)) {
1863 wildcard_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1867 if (covering_rr
&& wildcard_rr
) {
1868 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1869 * proved the NXDOMAIN case. */
1870 *result
= DNSSEC_NSEC_NXDOMAIN
;
1873 *authenticated
= covering_rr_authenticated
&& wildcard_rr_authenticated
;
1875 *ttl
= MIN(covering_rr
->ttl
, wildcard_rr
->ttl
);
1880 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1882 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
1884 /* No approproate NSEC RR found, report this. */
1885 *result
= DNSSEC_NSEC_NO_RR
;
1889 int dnssec_nsec_test_enclosed(DnsAnswer
*answer
, uint16_t type
, const char *name
, const char *zone
, bool *authenticated
) {
1890 DnsResourceRecord
*rr
;
1891 DnsAnswerFlags flags
;
1897 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
1898 * 'zone'. The 'zone' must be a suffix of the 'name'. */
1900 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1903 if (rr
->key
->type
!= type
&& type
!= DNS_TYPE_ANY
)
1906 switch (rr
->key
->type
) {
1910 /* We only care for NSEC RRs from the indicated zone */
1911 r
= dns_resource_record_is_signer(rr
, zone
);
1917 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), name
, rr
->nsec
.next_domain_name
);
1924 case DNS_TYPE_NSEC3
: {
1925 _cleanup_free_
char *hashed_domain
= NULL
, *next_hashed_domain
= NULL
;
1927 /* We only care for NSEC3 RRs from the indicated zone */
1928 r
= dns_resource_record_is_signer(rr
, zone
);
1934 r
= nsec3_is_good(rr
, NULL
);
1940 /* Format the domain we are testing with the NSEC3 RR's hash function */
1941 r
= nsec3_hashed_domain_make(
1948 if ((size_t) r
!= rr
->nsec3
.next_hashed_name_size
)
1951 /* Format the NSEC3's next hashed name as proper domain name */
1952 r
= nsec3_hashed_domain_format(
1953 rr
->nsec3
.next_hashed_name
,
1954 rr
->nsec3
.next_hashed_name_size
,
1956 &next_hashed_domain
);
1960 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), hashed_domain
, next_hashed_domain
);
1974 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1982 static int dnssec_test_positive_wildcard_nsec3(
1987 bool *authenticated
) {
1989 const char *next_closer
= NULL
;
1992 /* Run a positive NSEC3 wildcard proof. Specifically:
1994 * A proof that the the "next closer" of the generating wildcard does not exist.
1996 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
1997 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
1998 * exists for the NSEC3 RR and we are done.
2000 * 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
2001 * c.d.e.f does not exist. */
2005 r
= dns_name_parent(&name
);
2011 r
= dns_name_equal(name
, source
);
2018 return dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC3
, next_closer
, zone
, authenticated
);
2021 static int dnssec_test_positive_wildcard_nsec(
2026 bool *_authenticated
) {
2028 bool authenticated
= true;
2031 /* Run a positive NSEC wildcard proof. Specifically:
2033 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2034 * a prefix of the synthesizing source "source" in the zone "zone".
2036 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2038 * 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
2039 * have to prove that none of the following exist:
2050 _cleanup_free_
char *wc
= NULL
;
2053 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2054 * i.e between the owner name and the next name of an NSEC RR. */
2055 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, name
, zone
, &a
);
2059 authenticated
= authenticated
&& a
;
2061 /* Strip one label off */
2062 r
= dns_name_parent(&name
);
2066 /* Did we reach the source of synthesis? */
2067 r
= dns_name_equal(name
, source
);
2071 /* Successful exit */
2072 *_authenticated
= authenticated
;
2076 /* Safety check, that the source of synthesis is still our suffix */
2077 r
= dns_name_endswith(name
, source
);
2083 /* Replace the label we stripped off with an asterisk */
2084 wc
= strappend("*.", name
);
2088 /* And check if the proof holds for the asterisk name, too */
2089 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, wc
, zone
, &a
);
2093 authenticated
= authenticated
&& a
;
2094 /* In the next iteration we'll check the non-asterisk-prefixed version */
2098 int dnssec_test_positive_wildcard(
2103 bool *authenticated
) {
2110 assert(authenticated
);
2112 r
= dns_answer_contains_zone_nsec3(answer
, zone
);
2116 return dnssec_test_positive_wildcard_nsec3(answer
, name
, source
, zone
, authenticated
);
2118 return dnssec_test_positive_wildcard_nsec(answer
, name
, source
, zone
, authenticated
);
2121 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
2122 [DNSSEC_VALIDATED
] = "validated",
2123 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
2124 [DNSSEC_INVALID
] = "invalid",
2125 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
2126 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
2127 [DNSSEC_NO_SIGNATURE
] = "no-signature",
2128 [DNSSEC_MISSING_KEY
] = "missing-key",
2129 [DNSSEC_UNSIGNED
] = "unsigned",
2130 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
2131 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
2132 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
2134 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);