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
46 #define VERIFY_RRS_MAX 256
47 #define MAX_KEY_SIZE (32*1024)
49 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
50 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
52 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
53 #define NSEC3_ITERATIONS_MAX 2500
56 * The DNSSEC Chain of trust:
58 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
59 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
60 * DS RRs are protected like normal RRs
63 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
66 static void initialize_libgcrypt(void) {
69 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
72 p
= gcry_check_version("1.4.5");
75 gcry_control(GCRYCTL_DISABLE_SECMEM
);
76 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
79 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
, bool mask_revoke
) {
84 /* The algorithm from RFC 4034, Appendix B. */
87 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
89 f
= (uint32_t) dnskey
->dnskey
.flags
;
92 f
&= ~DNSKEY_FLAG_REVOKE
;
94 sum
= f
+ ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
96 p
= dnskey
->dnskey
.key
;
98 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
99 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
101 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
103 return sum
& UINT32_C(0xFFFF);
106 static int rr_compare(const void *a
, const void *b
) {
107 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
111 /* Let's order the RRs according to RFC 4034, Section 6.3 */
115 assert((*x
)->wire_format
);
118 assert((*y
)->wire_format
);
120 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
122 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
126 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
128 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
134 static int dnssec_rsa_verify_raw(
135 const char *hash_algorithm
,
136 const void *signature
, size_t signature_size
,
137 const void *data
, size_t data_size
,
138 const void *exponent
, size_t exponent_size
,
139 const void *modulus
, size_t modulus_size
) {
141 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
142 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
146 assert(hash_algorithm
);
148 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
154 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
160 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
166 ge
= gcry_sexp_build(&signature_sexp
,
168 "(sig-val (rsa (s %m)))",
176 ge
= gcry_sexp_build(&data_sexp
,
178 "(data (flags pkcs1) (hash %s %b))",
187 ge
= gcry_sexp_build(&public_key_sexp
,
189 "(public-key (rsa (n %m) (e %m)))",
197 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
198 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
201 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
215 gcry_sexp_release(public_key_sexp
);
217 gcry_sexp_release(signature_sexp
);
219 gcry_sexp_release(data_sexp
);
224 static int dnssec_rsa_verify(
225 const char *hash_algorithm
,
226 const void *hash
, size_t hash_size
,
227 DnsResourceRecord
*rrsig
,
228 DnsResourceRecord
*dnskey
) {
230 size_t exponent_size
, modulus_size
;
231 void *exponent
, *modulus
;
233 assert(hash_algorithm
);
235 assert(hash_size
> 0);
239 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
240 /* exponent is > 255 bytes long */
242 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
244 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
245 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
247 if (exponent_size
< 256)
250 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
253 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
254 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
257 /* exponent is <= 255 bytes long */
259 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
260 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
262 if (exponent_size
<= 0)
265 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
268 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
269 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
272 return dnssec_rsa_verify_raw(
274 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
276 exponent
, exponent_size
,
277 modulus
, modulus_size
);
280 static int dnssec_ecdsa_verify_raw(
281 const char *hash_algorithm
,
283 const void *signature_r
, size_t signature_r_size
,
284 const void *signature_s
, size_t signature_s_size
,
285 const void *data
, size_t data_size
,
286 const void *key
, size_t key_size
) {
288 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
289 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
293 assert(hash_algorithm
);
295 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
301 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
307 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
313 ge
= gcry_sexp_build(&signature_sexp
,
315 "(sig-val (ecdsa (r %m) (s %m)))",
323 ge
= gcry_sexp_build(&data_sexp
,
325 "(data (flags rfc6979) (hash %s %b))",
334 ge
= gcry_sexp_build(&public_key_sexp
,
336 "(public-key (ecc (curve %s) (q %m)))",
344 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
345 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
348 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
361 gcry_sexp_release(public_key_sexp
);
363 gcry_sexp_release(signature_sexp
);
365 gcry_sexp_release(data_sexp
);
370 static int dnssec_ecdsa_verify(
371 const char *hash_algorithm
,
373 const void *hash
, size_t hash_size
,
374 DnsResourceRecord
*rrsig
,
375 DnsResourceRecord
*dnskey
) {
386 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
388 curve
= "NIST P-256";
389 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
391 curve
= "NIST P-384";
395 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
398 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
401 q
= alloca(key_size
*2 + 1);
402 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
403 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
405 return dnssec_ecdsa_verify_raw(
408 rrsig
->rrsig
.signature
, key_size
,
409 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
414 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
415 gcry_md_write(md
, &v
, sizeof(v
));
418 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
420 gcry_md_write(md
, &v
, sizeof(v
));
423 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
425 gcry_md_write(md
, &v
, sizeof(v
));
428 static int dnssec_rrsig_prepare(DnsResourceRecord
*rrsig
) {
429 int n_key_labels
, n_signer_labels
;
433 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source and
434 * .n_skip_labels_signer fields so that we can use them later on. */
437 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
439 /* Check if this RRSIG RR is already prepared */
440 if (rrsig
->n_skip_labels_source
!= (unsigned) -1)
443 if (rrsig
->rrsig
.inception
> rrsig
->rrsig
.expiration
)
446 name
= DNS_RESOURCE_KEY_NAME(rrsig
->key
);
448 n_key_labels
= dns_name_count_labels(name
);
449 if (n_key_labels
< 0)
451 if (rrsig
->rrsig
.labels
> n_key_labels
)
454 n_signer_labels
= dns_name_count_labels(rrsig
->rrsig
.signer
);
455 if (n_signer_labels
< 0)
456 return n_signer_labels
;
457 if (n_signer_labels
> rrsig
->rrsig
.labels
)
460 r
= dns_name_skip(name
, n_key_labels
- n_signer_labels
, &name
);
466 /* Check if the signer is really a suffix of us */
467 r
= dns_name_equal(name
, rrsig
->rrsig
.signer
);
473 rrsig
->n_skip_labels_source
= n_key_labels
- rrsig
->rrsig
.labels
;
474 rrsig
->n_skip_labels_signer
= n_key_labels
- n_signer_labels
;
479 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
480 usec_t expiration
, inception
, skew
;
483 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
485 if (realtime
== USEC_INFINITY
)
486 realtime
= now(CLOCK_REALTIME
);
488 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
489 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
491 /* Consider inverted validity intervals as expired */
492 if (inception
> expiration
)
495 /* Permit a certain amount of clock skew of 10% of the valid
496 * time range. This takes inspiration from unbound's
498 skew
= (expiration
- inception
) / 10;
502 if (inception
< skew
)
507 if (expiration
+ skew
< expiration
)
508 expiration
= USEC_INFINITY
;
512 return realtime
< inception
|| realtime
> expiration
;
515 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
517 /* Translates a DNSSEC signature algorithm into a gcrypt
520 * Note that we implement all algorithms listed as "Must
521 * implement" and "Recommended to Implement" in RFC6944. We
522 * don't implement any algorithms that are listed as
523 * "Optional" or "Must Not Implement". Specifically, we do not
524 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
529 case DNSSEC_ALGORITHM_RSASHA1
:
530 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
533 case DNSSEC_ALGORITHM_RSASHA256
:
534 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
535 return GCRY_MD_SHA256
;
537 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
538 return GCRY_MD_SHA384
;
540 case DNSSEC_ALGORITHM_RSASHA512
:
541 return GCRY_MD_SHA512
;
548 static void dnssec_fix_rrset_ttl(
549 DnsResourceRecord
*list
[],
551 DnsResourceRecord
*rrsig
,
560 for (k
= 0; k
< n
; k
++) {
561 DnsResourceRecord
*rr
= list
[k
];
563 /* Pick the TTL as the minimum of the RR's TTL, the
564 * RR's original TTL according to the RRSIG and the
565 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
566 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
567 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
569 /* Copy over information about the signer and wildcard source of synthesis */
570 rr
->n_skip_labels_source
= rrsig
->n_skip_labels_source
;
571 rr
->n_skip_labels_signer
= rrsig
->n_skip_labels_signer
;
574 rrsig
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
577 int dnssec_verify_rrset(
579 const DnsResourceKey
*key
,
580 DnsResourceRecord
*rrsig
,
581 DnsResourceRecord
*dnskey
,
583 DnssecResult
*result
) {
585 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
586 DnsResourceRecord
**list
, *rr
;
587 const char *source
, *name
;
588 gcry_md_hd_t md
= NULL
;
599 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
600 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
602 /* Verifies the the RRSet matching the specified "key" in "a",
603 * using the signature "rrsig" and the key "dnskey". It's
604 * assumed the RRSIG and DNSKEY match. */
606 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
607 if (md_algorithm
== -EOPNOTSUPP
) {
608 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
611 if (md_algorithm
< 0)
614 r
= dnssec_rrsig_prepare(rrsig
);
616 *result
= DNSSEC_INVALID
;
622 r
= dnssec_rrsig_expired(rrsig
, realtime
);
626 *result
= DNSSEC_SIGNATURE_EXPIRED
;
630 name
= DNS_RESOURCE_KEY_NAME(key
);
632 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
633 if (dns_type_apex_only(rrsig
->rrsig
.type_covered
)) {
634 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
638 *result
= DNSSEC_INVALID
;
643 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
644 if (rrsig
->rrsig
.type_covered
== DNS_TYPE_DS
) {
645 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
649 *result
= DNSSEC_INVALID
;
654 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
655 r
= dns_name_suffix(name
, rrsig
->rrsig
.labels
, &source
);
658 if (r
> 0 && !dns_type_may_wildcard(rrsig
->rrsig
.type_covered
)) {
659 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
660 *result
= DNSSEC_INVALID
;
664 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
665 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
666 r
= dns_name_startswith(name
, "*");
676 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
677 list
= newa(DnsResourceRecord
*, dns_answer_size(a
));
679 DNS_ANSWER_FOREACH(rr
, a
) {
680 r
= dns_resource_key_equal(key
, rr
->key
);
686 /* We need the wire format for ordering, and digest calculation */
687 r
= dns_resource_record_to_wire_format(rr
, true);
693 if (n
> VERIFY_RRS_MAX
)
700 /* Bring the RRs into canonical order */
701 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
703 /* OK, the RRs are now in canonical order. Let's calculate the digest */
704 initialize_libgcrypt();
706 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
707 assert(hash_size
> 0);
709 gcry_md_open(&md
, md_algorithm
, 0);
713 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
714 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
715 md_add_uint8(md
, rrsig
->rrsig
.labels
);
716 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
717 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
718 md_add_uint32(md
, rrsig
->rrsig
.inception
);
719 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
721 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
724 gcry_md_write(md
, wire_format_name
, r
);
726 /* Convert the source of synthesis into wire format */
727 r
= dns_name_to_wire_format(source
, wire_format_name
, sizeof(wire_format_name
), true);
731 for (k
= 0; k
< n
; k
++) {
736 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
738 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
739 gcry_md_write(md
, wire_format_name
, r
);
741 md_add_uint16(md
, rr
->key
->type
);
742 md_add_uint16(md
, rr
->key
->class);
743 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
745 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
748 md_add_uint16(md
, (uint16_t) l
);
749 gcry_md_write(md
, DNS_RESOURCE_RECORD_RDATA(rr
), l
);
752 hash
= gcry_md_read(md
, 0);
758 switch (rrsig
->rrsig
.algorithm
) {
760 case DNSSEC_ALGORITHM_RSASHA1
:
761 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
762 case DNSSEC_ALGORITHM_RSASHA256
:
763 case DNSSEC_ALGORITHM_RSASHA512
:
764 r
= dnssec_rsa_verify(
765 gcry_md_algo_name(md_algorithm
),
771 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
772 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
773 r
= dnssec_ecdsa_verify(
774 gcry_md_algo_name(md_algorithm
),
775 rrsig
->rrsig
.algorithm
,
785 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
787 dnssec_fix_rrset_ttl(list
, n
, rrsig
, realtime
);
790 *result
= DNSSEC_INVALID
;
792 *result
= DNSSEC_VALIDATED_WILDCARD
;
794 *result
= DNSSEC_VALIDATED
;
803 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
808 /* Checks if the specified DNSKEY RR matches the key used for
809 * the signature in the specified RRSIG RR */
811 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
814 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
816 if (dnskey
->key
->class != rrsig
->key
->class)
818 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
820 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
822 if (dnskey
->dnskey
.protocol
!= 3)
824 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
827 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
830 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
833 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
837 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
839 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
841 if (rrsig
->key
->class != key
->class)
843 if (rrsig
->rrsig
.type_covered
!= key
->type
)
846 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
849 int dnssec_verify_rrset_search(
851 const DnsResourceKey
*key
,
852 DnsAnswer
*validated_dnskeys
,
854 DnssecResult
*result
,
855 DnsResourceRecord
**ret_rrsig
) {
857 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
858 DnsResourceRecord
*rrsig
;
864 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
866 if (!a
|| a
->n_rrs
<= 0)
869 /* Iterate through each RRSIG RR. */
870 DNS_ANSWER_FOREACH(rrsig
, a
) {
871 DnsResourceRecord
*dnskey
;
872 DnsAnswerFlags flags
;
874 /* Is this an RRSIG RR that applies to RRs matching our key? */
875 r
= dnssec_key_match_rrsig(key
, rrsig
);
883 /* Look for a matching key */
884 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
885 DnssecResult one_result
;
887 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
890 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
891 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
897 /* Take the time here, if it isn't set yet, so
898 * that we do all validations with the same
900 if (realtime
== USEC_INFINITY
)
901 realtime
= now(CLOCK_REALTIME
);
903 /* Yay, we found a matching RRSIG with a matching
904 * DNSKEY, awesome. Now let's verify all entries of
905 * the RRSet against the RRSIG and DNSKEY
908 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
912 switch (one_result
) {
914 case DNSSEC_VALIDATED
:
915 case DNSSEC_VALIDATED_WILDCARD
:
916 /* Yay, the RR has been validated,
917 * return immediately, but fix up the expiry */
921 *result
= one_result
;
925 /* If the signature is invalid, let's try another
926 key and/or signature. After all they
927 key_tags and stuff are not unique, and
928 might be shared by multiple keys. */
929 found_invalid
= true;
932 case DNSSEC_UNSUPPORTED_ALGORITHM
:
933 /* If the key algorithm is
934 unsupported, try another
935 RRSIG/DNSKEY pair, but remember we
936 encountered this, so that we can
937 return a proper error when we
938 encounter nothing better. */
939 found_unsupported_algorithm
= true;
942 case DNSSEC_SIGNATURE_EXPIRED
:
943 /* If the signature is expired, try
944 another one, but remember it, so
945 that we can return this */
946 found_expired_rrsig
= true;
950 assert_not_reached("Unexpected DNSSEC validation result");
955 if (found_expired_rrsig
)
956 *result
= DNSSEC_SIGNATURE_EXPIRED
;
957 else if (found_unsupported_algorithm
)
958 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
959 else if (found_invalid
)
960 *result
= DNSSEC_INVALID
;
961 else if (found_rrsig
)
962 *result
= DNSSEC_MISSING_KEY
;
964 *result
= DNSSEC_NO_SIGNATURE
;
972 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
973 DnsResourceRecord
*rr
;
976 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
978 DNS_ANSWER_FOREACH(rr
, a
) {
979 r
= dnssec_key_match_rrsig(key
, rr
);
989 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
993 /* Converts the specified hostname into DNSSEC canonicalized
1000 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
1006 if (buffer_max
< (size_t) r
+ 2)
1009 /* The DNSSEC canonical form is not clear on what to
1010 * do with dots appearing in labels, the way DNS-SD
1011 * does it. Refuse it for now. */
1013 if (memchr(buffer
, '.', r
))
1016 ascii_strlower_n(buffer
, (size_t) r
);
1022 buffer_max
-= r
+ 1;
1026 /* Not even a single label: this is the root domain name */
1028 assert(buffer_max
> 2);
1038 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1040 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1042 switch (algorithm
) {
1044 case DNSSEC_DIGEST_SHA1
:
1045 return GCRY_MD_SHA1
;
1047 case DNSSEC_DIGEST_SHA256
:
1048 return GCRY_MD_SHA256
;
1050 case DNSSEC_DIGEST_SHA384
:
1051 return GCRY_MD_SHA384
;
1058 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1059 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
1060 gcry_md_hd_t md
= NULL
;
1062 int md_algorithm
, r
;
1068 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1070 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1072 if (ds
->key
->type
!= DNS_TYPE_DS
)
1074 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1075 return -EKEYREJECTED
;
1076 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1077 return -EKEYREJECTED
;
1078 if (dnskey
->dnskey
.protocol
!= 3)
1079 return -EKEYREJECTED
;
1081 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1083 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1086 initialize_libgcrypt();
1088 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1089 if (md_algorithm
< 0)
1090 return md_algorithm
;
1092 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1093 assert(hash_size
> 0);
1095 if (ds
->ds
.digest_size
!= hash_size
)
1098 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
1102 gcry_md_open(&md
, md_algorithm
, 0);
1106 gcry_md_write(md
, owner_name
, r
);
1108 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1110 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1111 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1112 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1113 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1115 result
= gcry_md_read(md
, 0);
1121 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1128 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1129 DnsResourceRecord
*ds
;
1130 DnsAnswerFlags flags
;
1135 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1138 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1140 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1143 if (ds
->key
->type
!= DNS_TYPE_DS
)
1145 if (ds
->key
->class != dnskey
->key
->class)
1148 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1154 r
= dnssec_verify_dnskey_by_ds(dnskey
, ds
, false);
1155 if (IN_SET(r
, -EKEYREJECTED
, -EOPNOTSUPP
))
1156 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1166 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1168 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1170 switch (algorithm
) {
1172 case NSEC3_ALGORITHM_SHA1
:
1173 return GCRY_MD_SHA1
;
1180 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1181 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1182 gcry_md_hd_t md
= NULL
;
1193 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1196 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1197 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1201 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1205 initialize_libgcrypt();
1207 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1208 assert(hash_size
> 0);
1210 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1213 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1217 gcry_md_open(&md
, algorithm
, 0);
1221 gcry_md_write(md
, wire_format
, r
);
1222 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1224 result
= gcry_md_read(md
, 0);
1230 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1231 uint8_t tmp
[hash_size
];
1232 memcpy(tmp
, result
, hash_size
);
1235 gcry_md_write(md
, tmp
, hash_size
);
1236 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1238 result
= gcry_md_read(md
, 0);
1245 memcpy(ret
, result
, hash_size
);
1246 r
= (int) hash_size
;
1253 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1259 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1262 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1263 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1266 /* Ignore NSEC3 RRs whose algorithm we don't know */
1267 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1269 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1270 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1273 /* Ignore NSEC3 RRs generated from wildcards */
1274 if (rr
->n_skip_labels_source
!= 0)
1276 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1277 if (rr
->n_skip_labels_signer
!= 1)
1283 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1285 if (nsec3
== rr
) /* Shortcut */
1288 if (rr
->key
->class != nsec3
->key
->class)
1290 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1292 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1294 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1296 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1299 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1300 r
= dns_name_parent(&a
); /* strip off hash */
1306 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1307 r
= dns_name_parent(&b
); /* strip off hash */
1313 /* Make sure both have the same parent */
1314 return dns_name_equal(a
, b
);
1317 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1318 _cleanup_free_
char *l
= NULL
;
1322 assert(hashed_size
> 0);
1326 l
= base32hexmem(hashed
, hashed_size
, false);
1330 j
= strjoin(l
, ".", zone
, NULL
);
1335 return (int) hashed_size
;
1338 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1339 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1347 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1348 if (hashed_size
< 0)
1351 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1354 /* See RFC 5155, Section 8
1355 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1356 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1357 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1358 * matches the wildcard domain.
1360 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1361 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1362 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1363 * to conclude anything we indicate this by returning NO_RR. */
1364 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1365 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1366 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1367 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1368 DnsAnswerFlags flags
;
1370 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1375 /* First step, find the zone name and the NSEC3 parameters of the zone.
1376 * it is sufficient to look for the longest common suffix we find with
1377 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1378 * records from a given zone in a response must use the same
1380 zone
= DNS_RESOURCE_KEY_NAME(key
);
1382 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1383 r
= nsec3_is_good(zone_rr
, NULL
);
1389 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr
->key
), 1, zone
);
1396 /* Strip one label from the front */
1397 r
= dns_name_parent(&zone
);
1404 *result
= DNSSEC_NSEC_NO_RR
;
1408 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1409 p
= DNS_RESOURCE_KEY_NAME(key
);
1411 _cleanup_free_
char *hashed_domain
= NULL
;
1413 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1414 if (hashed_size
== -EOPNOTSUPP
) {
1415 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1418 if (hashed_size
< 0)
1421 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1423 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1429 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1432 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr
->key
), hashed_domain
);
1436 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1437 goto found_closest_encloser
;
1441 /* We didn't find the closest encloser with this name,
1442 * but let's remember this domain name, it might be
1443 * the next closer name */
1447 /* Strip one label from the front */
1448 r
= dns_name_parent(&p
);
1455 *result
= DNSSEC_NSEC_NO_RR
;
1458 found_closest_encloser
:
1459 /* We found a closest encloser in 'p'; next closer is 'pp' */
1462 /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR
1463 * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are
1464 * appropriately set. */
1466 if (key
->type
== DNS_TYPE_DS
) {
1467 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1470 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1471 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1475 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1476 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1477 *result
= DNSSEC_NSEC_FOUND
;
1478 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1479 *result
= DNSSEC_NSEC_CNAME
;
1481 *result
= DNSSEC_NSEC_NODATA
;
1486 *ttl
= enclosure_rr
->ttl
;
1491 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1492 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1495 /* Ensure that this data is from the delegated domain
1496 * (i.e. originates from the "lower" DNS server), and isn't
1497 * just glue records (i.e. doesn't originate from the "upper"
1499 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1500 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1503 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1505 wildcard
= strjoina("*.", p
);
1506 r
= nsec3_hashed_domain_make(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1509 if (r
!= hashed_size
)
1512 r
= nsec3_hashed_domain_make(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1515 if (r
!= hashed_size
)
1518 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1519 _cleanup_free_
char *next_hashed_domain
= NULL
;
1521 r
= nsec3_is_good(rr
, zone_rr
);
1527 r
= nsec3_hashed_domain_format(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, zone
, &next_hashed_domain
);
1531 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1535 if (rr
->nsec3
.flags
& 1)
1538 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1543 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
);
1547 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1552 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
, next_hashed_domain
);
1556 if (rr
->nsec3
.flags
& 1)
1557 /* This only makes sense if we have a wildcard delegation, which is
1558 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1559 * this not happening, so hence cannot simply conclude NXDOMAIN as
1563 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1569 if (wildcard_rr
&& no_wildcard
)
1573 *result
= DNSSEC_NSEC_NO_RR
;
1578 /* A wildcard exists that matches our query. */
1580 /* This is not specified in any RFC to the best of my knowledge, but
1581 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1582 * it means that we cannot prove that the source of synthesis is
1583 * correct, as there may be a closer match. */
1584 *result
= DNSSEC_NSEC_OPTOUT
;
1585 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1586 *result
= DNSSEC_NSEC_FOUND
;
1587 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1588 *result
= DNSSEC_NSEC_CNAME
;
1590 *result
= DNSSEC_NSEC_NODATA
;
1593 /* The RFC only specifies that we have to care for optout for NODATA for
1594 * DS records. However, children of an insecure opt-out delegation should
1595 * also be considered opt-out, rather than verified NXDOMAIN.
1596 * Note that we do not require a proof of wildcard non-existence if the
1597 * next closer domain is covered by an opt-out, as that would not provide
1598 * any additional information. */
1599 *result
= DNSSEC_NSEC_OPTOUT
;
1600 else if (no_wildcard
)
1601 *result
= DNSSEC_NSEC_NXDOMAIN
;
1603 *result
= DNSSEC_NSEC_NO_RR
;
1613 *ttl
= enclosure_rr
->ttl
;
1618 static int dnssec_nsec_wildcard_equal(DnsResourceRecord
*rr
, const char *name
) {
1619 char label
[DNS_LABEL_MAX
];
1624 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1626 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1628 if (rr
->n_skip_labels_source
!= 1)
1631 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1632 r
= dns_label_unescape(&n
, label
, sizeof(label
));
1635 if (r
!= 1 || label
[0] != '*')
1638 return dns_name_endswith(name
, n
);
1641 static int dnssec_nsec_in_path(DnsResourceRecord
*rr
, const char *name
) {
1642 const char *nn
, *common_suffix
;
1646 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1648 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1650 * A couple of examples:
1652 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1653 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1654 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1657 /* First, determine parent of next domain. */
1658 nn
= rr
->nsec
.next_domain_name
;
1659 r
= dns_name_parent(&nn
);
1663 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1664 * anything at all. */
1665 r
= dns_name_endswith(nn
, name
);
1669 /* 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. */
1670 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1674 return dns_name_endswith(name
, common_suffix
);
1677 static int dnssec_nsec_from_parent_zone(DnsResourceRecord
*rr
, const char *name
) {
1681 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1683 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1685 r
= dns_name_parent(&name
);
1689 r
= dns_name_equal(name
, DNS_RESOURCE_KEY_NAME(rr
->key
));
1693 /* DNAME, and NS without SOA is an indication for a delegation. */
1694 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_DNAME
))
1697 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) && !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1703 static int dnssec_nsec_covers(DnsResourceRecord
*rr
, const char *name
) {
1704 const char *common_suffix
, *p
;
1708 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1710 /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
1712 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1718 r
= dns_name_parent(&name
);
1724 r
= dns_name_equal(name
, common_suffix
);
1731 /* p is now the "Next Closer". */
1733 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), p
, rr
->nsec
.next_domain_name
);
1736 static int dnssec_nsec_covers_wildcard(DnsResourceRecord
*rr
, const char *name
) {
1737 const char *common_suffix
, *wc
;
1741 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1743 /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified
1744 * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as
1745 * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label.
1747 * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist
1748 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...)
1749 * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
1752 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1756 /* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */
1757 r
= dns_name_endswith(name
, common_suffix
);
1761 wc
= strjoina("*.", common_suffix
, NULL
);
1762 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wc
, rr
->nsec
.next_domain_name
);
1765 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1766 bool have_nsec3
= false, covering_rr_authenticated
= false, wildcard_rr_authenticated
= false;
1767 DnsResourceRecord
*rr
, *covering_rr
= NULL
, *wildcard_rr
= NULL
;
1768 DnsAnswerFlags flags
;
1775 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1777 name
= DNS_RESOURCE_KEY_NAME(key
);
1779 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1781 if (rr
->key
->class != key
->class)
1784 have_nsec3
= have_nsec3
|| (rr
->key
->type
== DNS_TYPE_NSEC3
);
1786 if (rr
->key
->type
!= DNS_TYPE_NSEC
)
1789 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1790 r
= dns_resource_record_is_synthetic(rr
);
1796 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1797 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), name
);
1801 /* If it's not a direct match, maybe it's a wild card match? */
1802 r
= dnssec_nsec_wildcard_equal(rr
, name
);
1807 if (key
->type
== DNS_TYPE_DS
) {
1808 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1809 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1810 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1813 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1814 * we got the child's NSEC. */
1815 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) &&
1816 !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1820 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1821 *result
= DNSSEC_NSEC_FOUND
;
1822 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1823 *result
= DNSSEC_NSEC_CNAME
;
1825 *result
= DNSSEC_NSEC_NODATA
;
1828 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1835 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1836 * of the NSEC RR. */
1837 r
= dnssec_nsec_in_path(rr
, name
);
1841 *result
= DNSSEC_NSEC_NODATA
;
1844 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1851 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1852 r
= dnssec_nsec_from_parent_zone(rr
, name
);
1858 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1859 r
= dnssec_nsec_covers(rr
, name
);
1862 if (r
> 0 && (!covering_rr
|| !covering_rr_authenticated
)) {
1864 covering_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1867 /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
1868 r
= dnssec_nsec_covers_wildcard(rr
, name
);
1871 if (r
> 0 && (!wildcard_rr
|| !wildcard_rr_authenticated
)) {
1873 wildcard_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1877 if (covering_rr
&& wildcard_rr
) {
1878 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1879 * proved the NXDOMAIN case. */
1880 *result
= DNSSEC_NSEC_NXDOMAIN
;
1883 *authenticated
= covering_rr_authenticated
&& wildcard_rr_authenticated
;
1885 *ttl
= MIN(covering_rr
->ttl
, wildcard_rr
->ttl
);
1890 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1892 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
1894 /* No approproate NSEC RR found, report this. */
1895 *result
= DNSSEC_NSEC_NO_RR
;
1899 int dnssec_nsec_test_enclosed(DnsAnswer
*answer
, uint16_t type
, const char *name
, const char *zone
, bool *authenticated
) {
1900 DnsResourceRecord
*rr
;
1901 DnsAnswerFlags flags
;
1907 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
1908 * 'zone'. The 'zone' must be a suffix of the 'name'. */
1910 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1913 if (rr
->key
->type
!= type
&& type
!= DNS_TYPE_ANY
)
1916 switch (rr
->key
->type
) {
1920 /* We only care for NSEC RRs from the indicated zone */
1921 r
= dns_resource_record_is_signer(rr
, zone
);
1927 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), name
, rr
->nsec
.next_domain_name
);
1934 case DNS_TYPE_NSEC3
: {
1935 _cleanup_free_
char *hashed_domain
= NULL
, *next_hashed_domain
= NULL
;
1937 /* We only care for NSEC3 RRs from the indicated zone */
1938 r
= dns_resource_record_is_signer(rr
, zone
);
1944 r
= nsec3_is_good(rr
, NULL
);
1950 /* Format the domain we are testing with the NSEC3 RR's hash function */
1951 r
= nsec3_hashed_domain_make(
1958 if ((size_t) r
!= rr
->nsec3
.next_hashed_name_size
)
1961 /* Format the NSEC3's next hashed name as proper domain name */
1962 r
= nsec3_hashed_domain_format(
1963 rr
->nsec3
.next_hashed_name
,
1964 rr
->nsec3
.next_hashed_name_size
,
1966 &next_hashed_domain
);
1970 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), hashed_domain
, next_hashed_domain
);
1984 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1992 static int dnssec_test_positive_wildcard_nsec3(
1997 bool *authenticated
) {
1999 const char *next_closer
= NULL
;
2002 /* Run a positive NSEC3 wildcard proof. Specifically:
2004 * A proof that the the "next closer" of the generating wildcard does not exist.
2006 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
2007 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
2008 * exists for the NSEC3 RR and we are done.
2010 * 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
2011 * c.d.e.f does not exist. */
2015 r
= dns_name_parent(&name
);
2021 r
= dns_name_equal(name
, source
);
2028 return dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC3
, next_closer
, zone
, authenticated
);
2031 static int dnssec_test_positive_wildcard_nsec(
2036 bool *_authenticated
) {
2038 bool authenticated
= true;
2041 /* Run a positive NSEC wildcard proof. Specifically:
2043 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2044 * a prefix of the synthesizing source "source" in the zone "zone".
2046 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2048 * 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
2049 * have to prove that none of the following exist:
2060 _cleanup_free_
char *wc
= NULL
;
2063 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2064 * i.e between the owner name and the next name of an NSEC RR. */
2065 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, name
, zone
, &a
);
2069 authenticated
= authenticated
&& a
;
2071 /* Strip one label off */
2072 r
= dns_name_parent(&name
);
2076 /* Did we reach the source of synthesis? */
2077 r
= dns_name_equal(name
, source
);
2081 /* Successful exit */
2082 *_authenticated
= authenticated
;
2086 /* Safety check, that the source of synthesis is still our suffix */
2087 r
= dns_name_endswith(name
, source
);
2093 /* Replace the label we stripped off with an asterisk */
2094 wc
= strappend("*.", name
);
2098 /* And check if the proof holds for the asterisk name, too */
2099 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, wc
, zone
, &a
);
2103 authenticated
= authenticated
&& a
;
2104 /* In the next iteration we'll check the non-asterisk-prefixed version */
2108 int dnssec_test_positive_wildcard(
2113 bool *authenticated
) {
2120 assert(authenticated
);
2122 r
= dns_answer_contains_zone_nsec3(answer
, zone
);
2126 return dnssec_test_positive_wildcard_nsec3(answer
, name
, source
, zone
, authenticated
);
2128 return dnssec_test_positive_wildcard_nsec(answer
, name
, source
, zone
, authenticated
);
2131 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
2132 [DNSSEC_VALIDATED
] = "validated",
2133 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
2134 [DNSSEC_INVALID
] = "invalid",
2135 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
2136 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
2137 [DNSSEC_NO_SIGNATURE
] = "no-signature",
2138 [DNSSEC_MISSING_KEY
] = "missing-key",
2139 [DNSSEC_UNSIGNED
] = "unsigned",
2140 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
2141 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
2142 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
2144 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);