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/>.
26 #include "alloc-util.h"
27 #include "dns-domain.h"
28 #include "hexdecoct.h"
29 #include "resolved-dns-dnssec.h"
30 #include "resolved-dns-packet.h"
31 #include "string-table.h"
33 #define VERIFY_RRS_MAX 256
34 #define MAX_KEY_SIZE (32*1024)
36 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
37 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
39 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
40 #define NSEC3_ITERATIONS_MAX 2500
43 * The DNSSEC Chain of trust:
45 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
46 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
47 * DS RRs are protected like normal RRs
50 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
53 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
, bool mask_revoke
) {
58 /* The algorithm from RFC 4034, Appendix B. */
61 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
63 f
= (uint32_t) dnskey
->dnskey
.flags
;
66 f
&= ~DNSKEY_FLAG_REVOKE
;
68 sum
= f
+ ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
70 p
= dnskey
->dnskey
.key
;
72 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
73 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
75 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
77 return sum
& UINT32_C(0xFFFF);
80 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
84 /* Converts the specified hostname into DNSSEC canonicalized
91 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
97 if (buffer_max
< (size_t) r
+ 2)
100 /* The DNSSEC canonical form is not clear on what to
101 * do with dots appearing in labels, the way DNS-SD
102 * does it. Refuse it for now. */
104 if (memchr(buffer
, '.', r
))
107 ascii_strlower_n(buffer
, (size_t) r
);
117 /* Not even a single label: this is the root domain name */
119 assert(buffer_max
> 2);
131 static void initialize_libgcrypt(void) {
134 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
137 p
= gcry_check_version("1.4.5");
140 gcry_control(GCRYCTL_DISABLE_SECMEM
);
141 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
144 static int rr_compare(const void *a
, const void *b
) {
145 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
149 /* Let's order the RRs according to RFC 4034, Section 6.3 */
153 assert((*x
)->wire_format
);
156 assert((*y
)->wire_format
);
158 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
160 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
164 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
166 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
172 static int dnssec_rsa_verify_raw(
173 const char *hash_algorithm
,
174 const void *signature
, size_t signature_size
,
175 const void *data
, size_t data_size
,
176 const void *exponent
, size_t exponent_size
,
177 const void *modulus
, size_t modulus_size
) {
179 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
180 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
184 assert(hash_algorithm
);
186 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
192 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
198 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
204 ge
= gcry_sexp_build(&signature_sexp
,
206 "(sig-val (rsa (s %m)))",
214 ge
= gcry_sexp_build(&data_sexp
,
216 "(data (flags pkcs1) (hash %s %b))",
225 ge
= gcry_sexp_build(&public_key_sexp
,
227 "(public-key (rsa (n %m) (e %m)))",
235 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
236 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
239 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
253 gcry_sexp_release(public_key_sexp
);
255 gcry_sexp_release(signature_sexp
);
257 gcry_sexp_release(data_sexp
);
262 static int dnssec_rsa_verify(
263 const char *hash_algorithm
,
264 const void *hash
, size_t hash_size
,
265 DnsResourceRecord
*rrsig
,
266 DnsResourceRecord
*dnskey
) {
268 size_t exponent_size
, modulus_size
;
269 void *exponent
, *modulus
;
271 assert(hash_algorithm
);
273 assert(hash_size
> 0);
277 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
278 /* exponent is > 255 bytes long */
280 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
282 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
283 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
285 if (exponent_size
< 256)
288 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
291 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
292 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
295 /* exponent is <= 255 bytes long */
297 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
298 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
300 if (exponent_size
<= 0)
303 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
306 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
307 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
310 return dnssec_rsa_verify_raw(
312 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
314 exponent
, exponent_size
,
315 modulus
, modulus_size
);
318 static int dnssec_ecdsa_verify_raw(
319 const char *hash_algorithm
,
321 const void *signature_r
, size_t signature_r_size
,
322 const void *signature_s
, size_t signature_s_size
,
323 const void *data
, size_t data_size
,
324 const void *key
, size_t key_size
) {
326 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
327 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
331 assert(hash_algorithm
);
333 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
339 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
345 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
351 ge
= gcry_sexp_build(&signature_sexp
,
353 "(sig-val (ecdsa (r %m) (s %m)))",
361 ge
= gcry_sexp_build(&data_sexp
,
363 "(data (flags rfc6979) (hash %s %b))",
372 ge
= gcry_sexp_build(&public_key_sexp
,
374 "(public-key (ecc (curve %s) (q %m)))",
382 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
383 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
386 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
399 gcry_sexp_release(public_key_sexp
);
401 gcry_sexp_release(signature_sexp
);
403 gcry_sexp_release(data_sexp
);
408 static int dnssec_ecdsa_verify(
409 const char *hash_algorithm
,
411 const void *hash
, size_t hash_size
,
412 DnsResourceRecord
*rrsig
,
413 DnsResourceRecord
*dnskey
) {
424 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
426 curve
= "NIST P-256";
427 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
429 curve
= "NIST P-384";
433 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
436 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
439 q
= alloca(key_size
*2 + 1);
440 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
441 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
443 return dnssec_ecdsa_verify_raw(
446 rrsig
->rrsig
.signature
, key_size
,
447 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
452 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
453 gcry_md_write(md
, &v
, sizeof(v
));
456 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
458 gcry_md_write(md
, &v
, sizeof(v
));
461 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
463 gcry_md_write(md
, &v
, sizeof(v
));
466 static int dnssec_rrsig_prepare(DnsResourceRecord
*rrsig
) {
467 int n_key_labels
, n_signer_labels
;
471 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source and
472 * .n_skip_labels_signer fields so that we can use them later on. */
475 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
477 /* Check if this RRSIG RR is already prepared */
478 if (rrsig
->n_skip_labels_source
!= (unsigned) -1)
481 if (rrsig
->rrsig
.inception
> rrsig
->rrsig
.expiration
)
484 name
= DNS_RESOURCE_KEY_NAME(rrsig
->key
);
486 n_key_labels
= dns_name_count_labels(name
);
487 if (n_key_labels
< 0)
489 if (rrsig
->rrsig
.labels
> n_key_labels
)
492 n_signer_labels
= dns_name_count_labels(rrsig
->rrsig
.signer
);
493 if (n_signer_labels
< 0)
494 return n_signer_labels
;
495 if (n_signer_labels
> rrsig
->rrsig
.labels
)
498 r
= dns_name_skip(name
, n_key_labels
- n_signer_labels
, &name
);
504 /* Check if the signer is really a suffix of us */
505 r
= dns_name_equal(name
, rrsig
->rrsig
.signer
);
511 rrsig
->n_skip_labels_source
= n_key_labels
- rrsig
->rrsig
.labels
;
512 rrsig
->n_skip_labels_signer
= n_key_labels
- n_signer_labels
;
517 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
518 usec_t expiration
, inception
, skew
;
521 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
523 if (realtime
== USEC_INFINITY
)
524 realtime
= now(CLOCK_REALTIME
);
526 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
527 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
529 /* Consider inverted validity intervals as expired */
530 if (inception
> expiration
)
533 /* Permit a certain amount of clock skew of 10% of the valid
534 * time range. This takes inspiration from unbound's
536 skew
= (expiration
- inception
) / 10;
540 if (inception
< skew
)
545 if (expiration
+ skew
< expiration
)
546 expiration
= USEC_INFINITY
;
550 return realtime
< inception
|| realtime
> expiration
;
553 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
555 /* Translates a DNSSEC signature algorithm into a gcrypt
558 * Note that we implement all algorithms listed as "Must
559 * implement" and "Recommended to Implement" in RFC6944. We
560 * don't implement any algorithms that are listed as
561 * "Optional" or "Must Not Implement". Specifically, we do not
562 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
567 case DNSSEC_ALGORITHM_RSASHA1
:
568 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
571 case DNSSEC_ALGORITHM_RSASHA256
:
572 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
573 return GCRY_MD_SHA256
;
575 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
576 return GCRY_MD_SHA384
;
578 case DNSSEC_ALGORITHM_RSASHA512
:
579 return GCRY_MD_SHA512
;
586 static void dnssec_fix_rrset_ttl(
587 DnsResourceRecord
*list
[],
589 DnsResourceRecord
*rrsig
,
598 for (k
= 0; k
< n
; k
++) {
599 DnsResourceRecord
*rr
= list
[k
];
601 /* Pick the TTL as the minimum of the RR's TTL, the
602 * RR's original TTL according to the RRSIG and the
603 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
604 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
605 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
607 /* Copy over information about the signer and wildcard source of synthesis */
608 rr
->n_skip_labels_source
= rrsig
->n_skip_labels_source
;
609 rr
->n_skip_labels_signer
= rrsig
->n_skip_labels_signer
;
612 rrsig
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
615 int dnssec_verify_rrset(
617 const DnsResourceKey
*key
,
618 DnsResourceRecord
*rrsig
,
619 DnsResourceRecord
*dnskey
,
621 DnssecResult
*result
) {
623 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
624 DnsResourceRecord
**list
, *rr
;
625 const char *source
, *name
;
626 gcry_md_hd_t md
= NULL
;
637 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
638 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
640 /* Verifies the the RRSet matching the specified "key" in "a",
641 * using the signature "rrsig" and the key "dnskey". It's
642 * assumed the RRSIG and DNSKEY match. */
644 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
645 if (md_algorithm
== -EOPNOTSUPP
) {
646 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
649 if (md_algorithm
< 0)
652 r
= dnssec_rrsig_prepare(rrsig
);
654 *result
= DNSSEC_INVALID
;
660 r
= dnssec_rrsig_expired(rrsig
, realtime
);
664 *result
= DNSSEC_SIGNATURE_EXPIRED
;
668 name
= DNS_RESOURCE_KEY_NAME(key
);
670 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
671 if (dns_type_apex_only(rrsig
->rrsig
.type_covered
)) {
672 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
676 *result
= DNSSEC_INVALID
;
681 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
682 if (rrsig
->rrsig
.type_covered
== DNS_TYPE_DS
) {
683 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
687 *result
= DNSSEC_INVALID
;
692 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
693 r
= dns_name_suffix(name
, rrsig
->rrsig
.labels
, &source
);
696 if (r
> 0 && !dns_type_may_wildcard(rrsig
->rrsig
.type_covered
)) {
697 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
698 *result
= DNSSEC_INVALID
;
702 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
703 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
704 r
= dns_name_startswith(name
, "*");
714 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
715 list
= newa(DnsResourceRecord
*, dns_answer_size(a
));
717 DNS_ANSWER_FOREACH(rr
, a
) {
718 r
= dns_resource_key_equal(key
, rr
->key
);
724 /* We need the wire format for ordering, and digest calculation */
725 r
= dns_resource_record_to_wire_format(rr
, true);
731 if (n
> VERIFY_RRS_MAX
)
738 /* Bring the RRs into canonical order */
739 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
741 /* OK, the RRs are now in canonical order. Let's calculate the digest */
742 initialize_libgcrypt();
744 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
745 assert(hash_size
> 0);
747 gcry_md_open(&md
, md_algorithm
, 0);
751 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
752 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
753 md_add_uint8(md
, rrsig
->rrsig
.labels
);
754 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
755 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
756 md_add_uint32(md
, rrsig
->rrsig
.inception
);
757 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
759 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
762 gcry_md_write(md
, wire_format_name
, r
);
764 /* Convert the source of synthesis into wire format */
765 r
= dns_name_to_wire_format(source
, wire_format_name
, sizeof(wire_format_name
), true);
769 for (k
= 0; k
< n
; k
++) {
774 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
776 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
777 gcry_md_write(md
, wire_format_name
, r
);
779 md_add_uint16(md
, rr
->key
->type
);
780 md_add_uint16(md
, rr
->key
->class);
781 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
783 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
786 md_add_uint16(md
, (uint16_t) l
);
787 gcry_md_write(md
, DNS_RESOURCE_RECORD_RDATA(rr
), l
);
790 hash
= gcry_md_read(md
, 0);
796 switch (rrsig
->rrsig
.algorithm
) {
798 case DNSSEC_ALGORITHM_RSASHA1
:
799 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
800 case DNSSEC_ALGORITHM_RSASHA256
:
801 case DNSSEC_ALGORITHM_RSASHA512
:
802 r
= dnssec_rsa_verify(
803 gcry_md_algo_name(md_algorithm
),
809 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
810 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
811 r
= dnssec_ecdsa_verify(
812 gcry_md_algo_name(md_algorithm
),
813 rrsig
->rrsig
.algorithm
,
823 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
825 dnssec_fix_rrset_ttl(list
, n
, rrsig
, realtime
);
828 *result
= DNSSEC_INVALID
;
830 *result
= DNSSEC_VALIDATED_WILDCARD
;
832 *result
= DNSSEC_VALIDATED
;
841 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
846 /* Checks if the specified DNSKEY RR matches the key used for
847 * the signature in the specified RRSIG RR */
849 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
852 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
854 if (dnskey
->key
->class != rrsig
->key
->class)
856 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
858 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
860 if (dnskey
->dnskey
.protocol
!= 3)
862 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
865 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
868 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
871 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
875 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
877 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
879 if (rrsig
->key
->class != key
->class)
881 if (rrsig
->rrsig
.type_covered
!= key
->type
)
884 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
887 int dnssec_verify_rrset_search(
889 const DnsResourceKey
*key
,
890 DnsAnswer
*validated_dnskeys
,
892 DnssecResult
*result
,
893 DnsResourceRecord
**ret_rrsig
) {
895 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
896 DnsResourceRecord
*rrsig
;
902 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
904 if (!a
|| a
->n_rrs
<= 0)
907 /* Iterate through each RRSIG RR. */
908 DNS_ANSWER_FOREACH(rrsig
, a
) {
909 DnsResourceRecord
*dnskey
;
910 DnsAnswerFlags flags
;
912 /* Is this an RRSIG RR that applies to RRs matching our key? */
913 r
= dnssec_key_match_rrsig(key
, rrsig
);
921 /* Look for a matching key */
922 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
923 DnssecResult one_result
;
925 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
928 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
929 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
935 /* Take the time here, if it isn't set yet, so
936 * that we do all validations with the same
938 if (realtime
== USEC_INFINITY
)
939 realtime
= now(CLOCK_REALTIME
);
941 /* Yay, we found a matching RRSIG with a matching
942 * DNSKEY, awesome. Now let's verify all entries of
943 * the RRSet against the RRSIG and DNSKEY
946 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
950 switch (one_result
) {
952 case DNSSEC_VALIDATED
:
953 case DNSSEC_VALIDATED_WILDCARD
:
954 /* Yay, the RR has been validated,
955 * return immediately, but fix up the expiry */
959 *result
= one_result
;
963 /* If the signature is invalid, let's try another
964 key and/or signature. After all they
965 key_tags and stuff are not unique, and
966 might be shared by multiple keys. */
967 found_invalid
= true;
970 case DNSSEC_UNSUPPORTED_ALGORITHM
:
971 /* If the key algorithm is
972 unsupported, try another
973 RRSIG/DNSKEY pair, but remember we
974 encountered this, so that we can
975 return a proper error when we
976 encounter nothing better. */
977 found_unsupported_algorithm
= true;
980 case DNSSEC_SIGNATURE_EXPIRED
:
981 /* If the signature is expired, try
982 another one, but remember it, so
983 that we can return this */
984 found_expired_rrsig
= true;
988 assert_not_reached("Unexpected DNSSEC validation result");
993 if (found_expired_rrsig
)
994 *result
= DNSSEC_SIGNATURE_EXPIRED
;
995 else if (found_unsupported_algorithm
)
996 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
997 else if (found_invalid
)
998 *result
= DNSSEC_INVALID
;
999 else if (found_rrsig
)
1000 *result
= DNSSEC_MISSING_KEY
;
1002 *result
= DNSSEC_NO_SIGNATURE
;
1010 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
1011 DnsResourceRecord
*rr
;
1014 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
1016 DNS_ANSWER_FOREACH(rr
, a
) {
1017 r
= dnssec_key_match_rrsig(key
, rr
);
1027 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1029 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1031 switch (algorithm
) {
1033 case DNSSEC_DIGEST_SHA1
:
1034 return GCRY_MD_SHA1
;
1036 case DNSSEC_DIGEST_SHA256
:
1037 return GCRY_MD_SHA256
;
1039 case DNSSEC_DIGEST_SHA384
:
1040 return GCRY_MD_SHA384
;
1047 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1048 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
1049 gcry_md_hd_t md
= NULL
;
1051 int md_algorithm
, r
;
1057 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1059 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1061 if (ds
->key
->type
!= DNS_TYPE_DS
)
1063 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1064 return -EKEYREJECTED
;
1065 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1066 return -EKEYREJECTED
;
1067 if (dnskey
->dnskey
.protocol
!= 3)
1068 return -EKEYREJECTED
;
1070 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1072 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1075 initialize_libgcrypt();
1077 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1078 if (md_algorithm
< 0)
1079 return md_algorithm
;
1081 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1082 assert(hash_size
> 0);
1084 if (ds
->ds
.digest_size
!= hash_size
)
1087 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
1091 gcry_md_open(&md
, md_algorithm
, 0);
1095 gcry_md_write(md
, owner_name
, r
);
1097 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1099 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1100 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1101 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1102 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1104 result
= gcry_md_read(md
, 0);
1110 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1117 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1118 DnsResourceRecord
*ds
;
1119 DnsAnswerFlags flags
;
1124 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1127 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1129 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1132 if (ds
->key
->type
!= DNS_TYPE_DS
)
1134 if (ds
->key
->class != dnskey
->key
->class)
1137 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1143 r
= dnssec_verify_dnskey_by_ds(dnskey
, ds
, false);
1144 if (IN_SET(r
, -EKEYREJECTED
, -EOPNOTSUPP
))
1145 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1155 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1157 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1159 switch (algorithm
) {
1161 case NSEC3_ALGORITHM_SHA1
:
1162 return GCRY_MD_SHA1
;
1169 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1170 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1171 gcry_md_hd_t md
= NULL
;
1182 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1185 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1186 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1190 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1194 initialize_libgcrypt();
1196 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1197 assert(hash_size
> 0);
1199 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1202 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1206 gcry_md_open(&md
, algorithm
, 0);
1210 gcry_md_write(md
, wire_format
, r
);
1211 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1213 result
= gcry_md_read(md
, 0);
1219 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1220 uint8_t tmp
[hash_size
];
1221 memcpy(tmp
, result
, hash_size
);
1224 gcry_md_write(md
, tmp
, hash_size
);
1225 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1227 result
= gcry_md_read(md
, 0);
1234 memcpy(ret
, result
, hash_size
);
1235 r
= (int) hash_size
;
1242 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1248 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1251 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1252 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1255 /* Ignore NSEC3 RRs whose algorithm we don't know */
1256 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1258 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1259 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1262 /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
1263 * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
1264 if (rr
->n_skip_labels_source
!= 0 && rr
->n_skip_labels_source
!= (unsigned) -1)
1266 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1267 if (rr
->n_skip_labels_signer
!= 1 && rr
->n_skip_labels_signer
!= (unsigned) -1)
1273 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1275 if (nsec3
== rr
) /* Shortcut */
1278 if (rr
->key
->class != nsec3
->key
->class)
1280 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1282 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1284 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1286 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1289 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1290 r
= dns_name_parent(&a
); /* strip off hash */
1296 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1297 r
= dns_name_parent(&b
); /* strip off hash */
1303 /* Make sure both have the same parent */
1304 return dns_name_equal(a
, b
);
1307 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1308 _cleanup_free_
char *l
= NULL
;
1312 assert(hashed_size
> 0);
1316 l
= base32hexmem(hashed
, hashed_size
, false);
1320 j
= strjoin(l
, ".", zone
, NULL
);
1325 return (int) hashed_size
;
1328 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1329 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1337 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1338 if (hashed_size
< 0)
1341 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1344 /* See RFC 5155, Section 8
1345 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1346 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1347 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1348 * matches the wildcard domain.
1350 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1351 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1352 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1353 * to conclude anything we indicate this by returning NO_RR. */
1354 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1355 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1356 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1357 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1358 DnsAnswerFlags flags
;
1360 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1365 /* First step, find the zone name and the NSEC3 parameters of the zone.
1366 * it is sufficient to look for the longest common suffix we find with
1367 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1368 * records from a given zone in a response must use the same
1370 zone
= DNS_RESOURCE_KEY_NAME(key
);
1372 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1373 r
= nsec3_is_good(zone_rr
, NULL
);
1379 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr
->key
), 1, zone
);
1386 /* Strip one label from the front */
1387 r
= dns_name_parent(&zone
);
1394 *result
= DNSSEC_NSEC_NO_RR
;
1398 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1399 p
= DNS_RESOURCE_KEY_NAME(key
);
1401 _cleanup_free_
char *hashed_domain
= NULL
;
1403 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1404 if (hashed_size
== -EOPNOTSUPP
) {
1405 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1408 if (hashed_size
< 0)
1411 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1413 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1419 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1422 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr
->key
), hashed_domain
);
1426 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1427 goto found_closest_encloser
;
1431 /* We didn't find the closest encloser with this name,
1432 * but let's remember this domain name, it might be
1433 * the next closer name */
1437 /* Strip one label from the front */
1438 r
= dns_name_parent(&p
);
1445 *result
= DNSSEC_NSEC_NO_RR
;
1448 found_closest_encloser
:
1449 /* We found a closest encloser in 'p'; next closer is 'pp' */
1452 /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR
1453 * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are
1454 * appropriately set. */
1456 if (key
->type
== DNS_TYPE_DS
) {
1457 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1460 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1461 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1465 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1466 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1467 *result
= DNSSEC_NSEC_FOUND
;
1468 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1469 *result
= DNSSEC_NSEC_CNAME
;
1471 *result
= DNSSEC_NSEC_NODATA
;
1476 *ttl
= enclosure_rr
->ttl
;
1481 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1482 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1485 /* Ensure that this data is from the delegated domain
1486 * (i.e. originates from the "lower" DNS server), and isn't
1487 * just glue records (i.e. doesn't originate from the "upper"
1489 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1490 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
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 static 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
);
2123 int dnssec_verify_rrset(
2125 const DnsResourceKey
*key
,
2126 DnsResourceRecord
*rrsig
,
2127 DnsResourceRecord
*dnskey
,
2129 DnssecResult
*result
) {
2134 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
2139 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
2144 int dnssec_verify_rrset_search(
2146 const DnsResourceKey
*key
,
2147 DnsAnswer
*validated_dnskeys
,
2149 DnssecResult
*result
,
2150 DnsResourceRecord
**ret_rrsig
) {
2155 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
2160 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
2165 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
2170 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
2175 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
2180 int dnssec_test_positive_wildcard(
2185 bool *authenticated
) {
2192 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
2193 [DNSSEC_VALIDATED
] = "validated",
2194 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
2195 [DNSSEC_INVALID
] = "invalid",
2196 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
2197 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
2198 [DNSSEC_NO_SIGNATURE
] = "no-signature",
2199 [DNSSEC_MISSING_KEY
] = "missing-key",
2200 [DNSSEC_UNSIGNED
] = "unsigned",
2201 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
2202 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
2203 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
2205 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);
2207 static const char* const dnssec_verdict_table
[_DNSSEC_VERDICT_MAX
] = {
2208 [DNSSEC_SECURE
] = "secure",
2209 [DNSSEC_INSECURE
] = "insecure",
2210 [DNSSEC_BOGUS
] = "bogus",
2211 [DNSSEC_INDETERMINATE
] = "indeterminate",
2213 DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict
, DnssecVerdict
);