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 "gcrypt-util.h"
29 #include "hexdecoct.h"
30 #include "resolved-dns-dnssec.h"
31 #include "resolved-dns-packet.h"
32 #include "string-table.h"
34 #define VERIFY_RRS_MAX 256
35 #define MAX_KEY_SIZE (32*1024)
37 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
38 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
40 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
41 #define NSEC3_ITERATIONS_MAX 2500
44 * The DNSSEC Chain of trust:
46 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
47 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
48 * DS RRs are protected like normal RRs
51 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
54 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
, bool mask_revoke
) {
59 /* The algorithm from RFC 4034, Appendix B. */
62 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
64 f
= (uint32_t) dnskey
->dnskey
.flags
;
67 f
&= ~DNSKEY_FLAG_REVOKE
;
69 sum
= f
+ ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
71 p
= dnskey
->dnskey
.key
;
73 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
74 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
76 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
78 return sum
& UINT32_C(0xFFFF);
81 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
85 /* Converts the specified hostname into DNSSEC canonicalized
92 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
98 if (buffer_max
< (size_t) r
+ 2)
101 /* The DNSSEC canonical form is not clear on what to
102 * do with dots appearing in labels, the way DNS-SD
103 * does it. Refuse it for now. */
105 if (memchr(buffer
, '.', r
))
108 ascii_strlower_n(buffer
, (size_t) r
);
118 /* Not even a single label: this is the root domain name */
120 assert(buffer_max
> 2);
132 static int rr_compare(const void *a
, const void *b
) {
133 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
137 /* Let's order the RRs according to RFC 4034, Section 6.3 */
141 assert((*x
)->wire_format
);
144 assert((*y
)->wire_format
);
146 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
148 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
152 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
154 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
160 static int dnssec_rsa_verify_raw(
161 const char *hash_algorithm
,
162 const void *signature
, size_t signature_size
,
163 const void *data
, size_t data_size
,
164 const void *exponent
, size_t exponent_size
,
165 const void *modulus
, size_t modulus_size
) {
167 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
168 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
172 assert(hash_algorithm
);
174 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
180 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
186 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
192 ge
= gcry_sexp_build(&signature_sexp
,
194 "(sig-val (rsa (s %m)))",
202 ge
= gcry_sexp_build(&data_sexp
,
204 "(data (flags pkcs1) (hash %s %b))",
213 ge
= gcry_sexp_build(&public_key_sexp
,
215 "(public-key (rsa (n %m) (e %m)))",
223 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
224 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
227 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
241 gcry_sexp_release(public_key_sexp
);
243 gcry_sexp_release(signature_sexp
);
245 gcry_sexp_release(data_sexp
);
250 static int dnssec_rsa_verify(
251 const char *hash_algorithm
,
252 const void *hash
, size_t hash_size
,
253 DnsResourceRecord
*rrsig
,
254 DnsResourceRecord
*dnskey
) {
256 size_t exponent_size
, modulus_size
;
257 void *exponent
, *modulus
;
259 assert(hash_algorithm
);
261 assert(hash_size
> 0);
265 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
266 /* exponent is > 255 bytes long */
268 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
270 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
271 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
273 if (exponent_size
< 256)
276 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
279 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
280 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
283 /* exponent is <= 255 bytes long */
285 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
286 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
288 if (exponent_size
<= 0)
291 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
294 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
295 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
298 return dnssec_rsa_verify_raw(
300 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
302 exponent
, exponent_size
,
303 modulus
, modulus_size
);
306 static int dnssec_ecdsa_verify_raw(
307 const char *hash_algorithm
,
309 const void *signature_r
, size_t signature_r_size
,
310 const void *signature_s
, size_t signature_s_size
,
311 const void *data
, size_t data_size
,
312 const void *key
, size_t key_size
) {
314 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
315 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
319 assert(hash_algorithm
);
321 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
327 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
333 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
339 ge
= gcry_sexp_build(&signature_sexp
,
341 "(sig-val (ecdsa (r %m) (s %m)))",
349 ge
= gcry_sexp_build(&data_sexp
,
351 "(data (flags rfc6979) (hash %s %b))",
360 ge
= gcry_sexp_build(&public_key_sexp
,
362 "(public-key (ecc (curve %s) (q %m)))",
370 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
371 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
374 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
387 gcry_sexp_release(public_key_sexp
);
389 gcry_sexp_release(signature_sexp
);
391 gcry_sexp_release(data_sexp
);
396 static int dnssec_ecdsa_verify(
397 const char *hash_algorithm
,
399 const void *hash
, size_t hash_size
,
400 DnsResourceRecord
*rrsig
,
401 DnsResourceRecord
*dnskey
) {
412 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
414 curve
= "NIST P-256";
415 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
417 curve
= "NIST P-384";
421 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
424 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
427 q
= alloca(key_size
*2 + 1);
428 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
429 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
431 return dnssec_ecdsa_verify_raw(
434 rrsig
->rrsig
.signature
, key_size
,
435 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
440 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
441 gcry_md_write(md
, &v
, sizeof(v
));
444 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
446 gcry_md_write(md
, &v
, sizeof(v
));
449 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
451 gcry_md_write(md
, &v
, sizeof(v
));
454 static int dnssec_rrsig_prepare(DnsResourceRecord
*rrsig
) {
455 int n_key_labels
, n_signer_labels
;
459 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source and
460 * .n_skip_labels_signer fields so that we can use them later on. */
463 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
465 /* Check if this RRSIG RR is already prepared */
466 if (rrsig
->n_skip_labels_source
!= (unsigned) -1)
469 if (rrsig
->rrsig
.inception
> rrsig
->rrsig
.expiration
)
472 name
= DNS_RESOURCE_KEY_NAME(rrsig
->key
);
474 n_key_labels
= dns_name_count_labels(name
);
475 if (n_key_labels
< 0)
477 if (rrsig
->rrsig
.labels
> n_key_labels
)
480 n_signer_labels
= dns_name_count_labels(rrsig
->rrsig
.signer
);
481 if (n_signer_labels
< 0)
482 return n_signer_labels
;
483 if (n_signer_labels
> rrsig
->rrsig
.labels
)
486 r
= dns_name_skip(name
, n_key_labels
- n_signer_labels
, &name
);
492 /* Check if the signer is really a suffix of us */
493 r
= dns_name_equal(name
, rrsig
->rrsig
.signer
);
499 rrsig
->n_skip_labels_source
= n_key_labels
- rrsig
->rrsig
.labels
;
500 rrsig
->n_skip_labels_signer
= n_key_labels
- n_signer_labels
;
505 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
506 usec_t expiration
, inception
, skew
;
509 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
511 if (realtime
== USEC_INFINITY
)
512 realtime
= now(CLOCK_REALTIME
);
514 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
515 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
517 /* Consider inverted validity intervals as expired */
518 if (inception
> expiration
)
521 /* Permit a certain amount of clock skew of 10% of the valid
522 * time range. This takes inspiration from unbound's
524 skew
= (expiration
- inception
) / 10;
528 if (inception
< skew
)
533 if (expiration
+ skew
< expiration
)
534 expiration
= USEC_INFINITY
;
538 return realtime
< inception
|| realtime
> expiration
;
541 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
543 /* Translates a DNSSEC signature algorithm into a gcrypt
546 * Note that we implement all algorithms listed as "Must
547 * implement" and "Recommended to Implement" in RFC6944. We
548 * don't implement any algorithms that are listed as
549 * "Optional" or "Must Not Implement". Specifically, we do not
550 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
555 case DNSSEC_ALGORITHM_RSASHA1
:
556 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
559 case DNSSEC_ALGORITHM_RSASHA256
:
560 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
561 return GCRY_MD_SHA256
;
563 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
564 return GCRY_MD_SHA384
;
566 case DNSSEC_ALGORITHM_RSASHA512
:
567 return GCRY_MD_SHA512
;
574 static void dnssec_fix_rrset_ttl(
575 DnsResourceRecord
*list
[],
577 DnsResourceRecord
*rrsig
,
586 for (k
= 0; k
< n
; k
++) {
587 DnsResourceRecord
*rr
= list
[k
];
589 /* Pick the TTL as the minimum of the RR's TTL, the
590 * RR's original TTL according to the RRSIG and the
591 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
592 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
593 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
595 /* Copy over information about the signer and wildcard source of synthesis */
596 rr
->n_skip_labels_source
= rrsig
->n_skip_labels_source
;
597 rr
->n_skip_labels_signer
= rrsig
->n_skip_labels_signer
;
600 rrsig
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
603 int dnssec_verify_rrset(
605 const DnsResourceKey
*key
,
606 DnsResourceRecord
*rrsig
,
607 DnsResourceRecord
*dnskey
,
609 DnssecResult
*result
) {
611 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
612 DnsResourceRecord
**list
, *rr
;
613 const char *source
, *name
;
614 gcry_md_hd_t md
= NULL
;
625 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
626 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
628 /* Verifies the the RRSet matching the specified "key" in "a",
629 * using the signature "rrsig" and the key "dnskey". It's
630 * assumed the RRSIG and DNSKEY match. */
632 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
633 if (md_algorithm
== -EOPNOTSUPP
) {
634 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
637 if (md_algorithm
< 0)
640 r
= dnssec_rrsig_prepare(rrsig
);
642 *result
= DNSSEC_INVALID
;
648 r
= dnssec_rrsig_expired(rrsig
, realtime
);
652 *result
= DNSSEC_SIGNATURE_EXPIRED
;
656 name
= DNS_RESOURCE_KEY_NAME(key
);
658 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
659 if (dns_type_apex_only(rrsig
->rrsig
.type_covered
)) {
660 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
664 *result
= DNSSEC_INVALID
;
669 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
670 if (rrsig
->rrsig
.type_covered
== DNS_TYPE_DS
) {
671 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
675 *result
= DNSSEC_INVALID
;
680 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
681 r
= dns_name_suffix(name
, rrsig
->rrsig
.labels
, &source
);
684 if (r
> 0 && !dns_type_may_wildcard(rrsig
->rrsig
.type_covered
)) {
685 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
686 *result
= DNSSEC_INVALID
;
690 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
691 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
692 r
= dns_name_startswith(name
, "*");
702 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
703 list
= newa(DnsResourceRecord
*, dns_answer_size(a
));
705 DNS_ANSWER_FOREACH(rr
, a
) {
706 r
= dns_resource_key_equal(key
, rr
->key
);
712 /* We need the wire format for ordering, and digest calculation */
713 r
= dns_resource_record_to_wire_format(rr
, true);
719 if (n
> VERIFY_RRS_MAX
)
726 /* Bring the RRs into canonical order */
727 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
729 /* OK, the RRs are now in canonical order. Let's calculate the digest */
730 initialize_libgcrypt(false);
732 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
733 assert(hash_size
> 0);
735 gcry_md_open(&md
, md_algorithm
, 0);
739 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
740 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
741 md_add_uint8(md
, rrsig
->rrsig
.labels
);
742 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
743 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
744 md_add_uint32(md
, rrsig
->rrsig
.inception
);
745 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
747 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
750 gcry_md_write(md
, wire_format_name
, r
);
752 /* Convert the source of synthesis into wire format */
753 r
= dns_name_to_wire_format(source
, wire_format_name
, sizeof(wire_format_name
), true);
757 for (k
= 0; k
< n
; k
++) {
762 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
764 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
765 gcry_md_write(md
, wire_format_name
, r
);
767 md_add_uint16(md
, rr
->key
->type
);
768 md_add_uint16(md
, rr
->key
->class);
769 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
771 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
774 md_add_uint16(md
, (uint16_t) l
);
775 gcry_md_write(md
, DNS_RESOURCE_RECORD_RDATA(rr
), l
);
778 hash
= gcry_md_read(md
, 0);
784 switch (rrsig
->rrsig
.algorithm
) {
786 case DNSSEC_ALGORITHM_RSASHA1
:
787 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
788 case DNSSEC_ALGORITHM_RSASHA256
:
789 case DNSSEC_ALGORITHM_RSASHA512
:
790 r
= dnssec_rsa_verify(
791 gcry_md_algo_name(md_algorithm
),
797 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
798 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
799 r
= dnssec_ecdsa_verify(
800 gcry_md_algo_name(md_algorithm
),
801 rrsig
->rrsig
.algorithm
,
811 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
813 dnssec_fix_rrset_ttl(list
, n
, rrsig
, realtime
);
816 *result
= DNSSEC_INVALID
;
818 *result
= DNSSEC_VALIDATED_WILDCARD
;
820 *result
= DNSSEC_VALIDATED
;
829 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
834 /* Checks if the specified DNSKEY RR matches the key used for
835 * the signature in the specified RRSIG RR */
837 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
840 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
842 if (dnskey
->key
->class != rrsig
->key
->class)
844 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
846 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
848 if (dnskey
->dnskey
.protocol
!= 3)
850 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
853 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
856 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
859 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
863 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
865 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
867 if (rrsig
->key
->class != key
->class)
869 if (rrsig
->rrsig
.type_covered
!= key
->type
)
872 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
875 int dnssec_verify_rrset_search(
877 const DnsResourceKey
*key
,
878 DnsAnswer
*validated_dnskeys
,
880 DnssecResult
*result
,
881 DnsResourceRecord
**ret_rrsig
) {
883 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
884 DnsResourceRecord
*rrsig
;
890 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
892 if (!a
|| a
->n_rrs
<= 0)
895 /* Iterate through each RRSIG RR. */
896 DNS_ANSWER_FOREACH(rrsig
, a
) {
897 DnsResourceRecord
*dnskey
;
898 DnsAnswerFlags flags
;
900 /* Is this an RRSIG RR that applies to RRs matching our key? */
901 r
= dnssec_key_match_rrsig(key
, rrsig
);
909 /* Look for a matching key */
910 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
911 DnssecResult one_result
;
913 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
916 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
917 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
923 /* Take the time here, if it isn't set yet, so
924 * that we do all validations with the same
926 if (realtime
== USEC_INFINITY
)
927 realtime
= now(CLOCK_REALTIME
);
929 /* Yay, we found a matching RRSIG with a matching
930 * DNSKEY, awesome. Now let's verify all entries of
931 * the RRSet against the RRSIG and DNSKEY
934 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
938 switch (one_result
) {
940 case DNSSEC_VALIDATED
:
941 case DNSSEC_VALIDATED_WILDCARD
:
942 /* Yay, the RR has been validated,
943 * return immediately, but fix up the expiry */
947 *result
= one_result
;
951 /* If the signature is invalid, let's try another
952 key and/or signature. After all they
953 key_tags and stuff are not unique, and
954 might be shared by multiple keys. */
955 found_invalid
= true;
958 case DNSSEC_UNSUPPORTED_ALGORITHM
:
959 /* If the key algorithm is
960 unsupported, try another
961 RRSIG/DNSKEY pair, but remember we
962 encountered this, so that we can
963 return a proper error when we
964 encounter nothing better. */
965 found_unsupported_algorithm
= true;
968 case DNSSEC_SIGNATURE_EXPIRED
:
969 /* If the signature is expired, try
970 another one, but remember it, so
971 that we can return this */
972 found_expired_rrsig
= true;
976 assert_not_reached("Unexpected DNSSEC validation result");
981 if (found_expired_rrsig
)
982 *result
= DNSSEC_SIGNATURE_EXPIRED
;
983 else if (found_unsupported_algorithm
)
984 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
985 else if (found_invalid
)
986 *result
= DNSSEC_INVALID
;
987 else if (found_rrsig
)
988 *result
= DNSSEC_MISSING_KEY
;
990 *result
= DNSSEC_NO_SIGNATURE
;
998 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
999 DnsResourceRecord
*rr
;
1002 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
1004 DNS_ANSWER_FOREACH(rr
, a
) {
1005 r
= dnssec_key_match_rrsig(key
, rr
);
1015 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1017 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1019 switch (algorithm
) {
1021 case DNSSEC_DIGEST_SHA1
:
1022 return GCRY_MD_SHA1
;
1024 case DNSSEC_DIGEST_SHA256
:
1025 return GCRY_MD_SHA256
;
1027 case DNSSEC_DIGEST_SHA384
:
1028 return GCRY_MD_SHA384
;
1035 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1036 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
1037 gcry_md_hd_t md
= NULL
;
1039 int md_algorithm
, r
;
1045 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1047 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1049 if (ds
->key
->type
!= DNS_TYPE_DS
)
1051 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1052 return -EKEYREJECTED
;
1053 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1054 return -EKEYREJECTED
;
1055 if (dnskey
->dnskey
.protocol
!= 3)
1056 return -EKEYREJECTED
;
1058 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1060 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1063 initialize_libgcrypt(false);
1065 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1066 if (md_algorithm
< 0)
1067 return md_algorithm
;
1069 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1070 assert(hash_size
> 0);
1072 if (ds
->ds
.digest_size
!= hash_size
)
1075 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
1079 gcry_md_open(&md
, md_algorithm
, 0);
1083 gcry_md_write(md
, owner_name
, r
);
1085 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1087 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1088 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1089 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1090 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1092 result
= gcry_md_read(md
, 0);
1098 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1105 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1106 DnsResourceRecord
*ds
;
1107 DnsAnswerFlags flags
;
1112 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1115 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1117 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1120 if (ds
->key
->type
!= DNS_TYPE_DS
)
1122 if (ds
->key
->class != dnskey
->key
->class)
1125 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1131 r
= dnssec_verify_dnskey_by_ds(dnskey
, ds
, false);
1132 if (IN_SET(r
, -EKEYREJECTED
, -EOPNOTSUPP
))
1133 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1143 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1145 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1147 switch (algorithm
) {
1149 case NSEC3_ALGORITHM_SHA1
:
1150 return GCRY_MD_SHA1
;
1157 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1158 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1159 gcry_md_hd_t md
= NULL
;
1170 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1173 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1174 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1178 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1182 initialize_libgcrypt(false);
1184 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1185 assert(hash_size
> 0);
1187 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1190 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1194 gcry_md_open(&md
, algorithm
, 0);
1198 gcry_md_write(md
, wire_format
, r
);
1199 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1201 result
= gcry_md_read(md
, 0);
1207 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1208 uint8_t tmp
[hash_size
];
1209 memcpy(tmp
, result
, hash_size
);
1212 gcry_md_write(md
, tmp
, hash_size
);
1213 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1215 result
= gcry_md_read(md
, 0);
1222 memcpy(ret
, result
, hash_size
);
1223 r
= (int) hash_size
;
1230 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1236 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1239 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1240 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1243 /* Ignore NSEC3 RRs whose algorithm we don't know */
1244 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1246 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1247 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1250 /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
1251 * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
1252 if (rr
->n_skip_labels_source
!= 0 && rr
->n_skip_labels_source
!= (unsigned) -1)
1254 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1255 if (rr
->n_skip_labels_signer
!= 1 && rr
->n_skip_labels_signer
!= (unsigned) -1)
1261 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1263 if (nsec3
== rr
) /* Shortcut */
1266 if (rr
->key
->class != nsec3
->key
->class)
1268 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1270 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1272 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1274 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1277 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1278 r
= dns_name_parent(&a
); /* strip off hash */
1284 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1285 r
= dns_name_parent(&b
); /* strip off hash */
1291 /* Make sure both have the same parent */
1292 return dns_name_equal(a
, b
);
1295 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1296 _cleanup_free_
char *l
= NULL
;
1300 assert(hashed_size
> 0);
1304 l
= base32hexmem(hashed
, hashed_size
, false);
1308 j
= strjoin(l
, ".", zone
, NULL
);
1313 return (int) hashed_size
;
1316 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1317 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1325 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1326 if (hashed_size
< 0)
1329 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1332 /* See RFC 5155, Section 8
1333 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1334 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1335 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1336 * matches the wildcard domain.
1338 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1339 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1340 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1341 * to conclude anything we indicate this by returning NO_RR. */
1342 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1343 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1344 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1345 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1346 DnsAnswerFlags flags
;
1348 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1353 /* First step, find the zone name and the NSEC3 parameters of the zone.
1354 * it is sufficient to look for the longest common suffix we find with
1355 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1356 * records from a given zone in a response must use the same
1358 zone
= DNS_RESOURCE_KEY_NAME(key
);
1360 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1361 r
= nsec3_is_good(zone_rr
, NULL
);
1367 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr
->key
), 1, zone
);
1374 /* Strip one label from the front */
1375 r
= dns_name_parent(&zone
);
1382 *result
= DNSSEC_NSEC_NO_RR
;
1386 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1387 p
= DNS_RESOURCE_KEY_NAME(key
);
1389 _cleanup_free_
char *hashed_domain
= NULL
;
1391 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1392 if (hashed_size
== -EOPNOTSUPP
) {
1393 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1396 if (hashed_size
< 0)
1399 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1401 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1407 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1410 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr
->key
), hashed_domain
);
1414 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1415 goto found_closest_encloser
;
1419 /* We didn't find the closest encloser with this name,
1420 * but let's remember this domain name, it might be
1421 * the next closer name */
1425 /* Strip one label from the front */
1426 r
= dns_name_parent(&p
);
1433 *result
= DNSSEC_NSEC_NO_RR
;
1436 found_closest_encloser
:
1437 /* We found a closest encloser in 'p'; next closer is 'pp' */
1440 /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR
1441 * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are
1442 * appropriately set. */
1444 if (key
->type
== DNS_TYPE_DS
) {
1445 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1448 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1449 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1453 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1454 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1455 *result
= DNSSEC_NSEC_FOUND
;
1456 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1457 *result
= DNSSEC_NSEC_CNAME
;
1459 *result
= DNSSEC_NSEC_NODATA
;
1464 *ttl
= enclosure_rr
->ttl
;
1469 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1470 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1473 /* Ensure that this data is from the delegated domain
1474 * (i.e. originates from the "lower" DNS server), and isn't
1475 * just glue records (i.e. doesn't originate from the "upper"
1477 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1478 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1481 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1483 wildcard
= strjoina("*.", p
);
1484 r
= nsec3_hashed_domain_make(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1487 if (r
!= hashed_size
)
1490 r
= nsec3_hashed_domain_make(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1493 if (r
!= hashed_size
)
1496 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1497 _cleanup_free_
char *next_hashed_domain
= NULL
;
1499 r
= nsec3_is_good(rr
, zone_rr
);
1505 r
= nsec3_hashed_domain_format(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, zone
, &next_hashed_domain
);
1509 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1513 if (rr
->nsec3
.flags
& 1)
1516 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1521 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
);
1525 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1530 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
, next_hashed_domain
);
1534 if (rr
->nsec3
.flags
& 1)
1535 /* This only makes sense if we have a wildcard delegation, which is
1536 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1537 * this not happening, so hence cannot simply conclude NXDOMAIN as
1541 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1547 if (wildcard_rr
&& no_wildcard
)
1551 *result
= DNSSEC_NSEC_NO_RR
;
1556 /* A wildcard exists that matches our query. */
1558 /* This is not specified in any RFC to the best of my knowledge, but
1559 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1560 * it means that we cannot prove that the source of synthesis is
1561 * correct, as there may be a closer match. */
1562 *result
= DNSSEC_NSEC_OPTOUT
;
1563 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1564 *result
= DNSSEC_NSEC_FOUND
;
1565 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1566 *result
= DNSSEC_NSEC_CNAME
;
1568 *result
= DNSSEC_NSEC_NODATA
;
1571 /* The RFC only specifies that we have to care for optout for NODATA for
1572 * DS records. However, children of an insecure opt-out delegation should
1573 * also be considered opt-out, rather than verified NXDOMAIN.
1574 * Note that we do not require a proof of wildcard non-existence if the
1575 * next closer domain is covered by an opt-out, as that would not provide
1576 * any additional information. */
1577 *result
= DNSSEC_NSEC_OPTOUT
;
1578 else if (no_wildcard
)
1579 *result
= DNSSEC_NSEC_NXDOMAIN
;
1581 *result
= DNSSEC_NSEC_NO_RR
;
1591 *ttl
= enclosure_rr
->ttl
;
1596 static int dnssec_nsec_wildcard_equal(DnsResourceRecord
*rr
, const char *name
) {
1597 char label
[DNS_LABEL_MAX
];
1602 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1604 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1606 if (rr
->n_skip_labels_source
!= 1)
1609 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1610 r
= dns_label_unescape(&n
, label
, sizeof(label
));
1613 if (r
!= 1 || label
[0] != '*')
1616 return dns_name_endswith(name
, n
);
1619 static int dnssec_nsec_in_path(DnsResourceRecord
*rr
, const char *name
) {
1620 const char *nn
, *common_suffix
;
1624 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1626 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1628 * A couple of examples:
1630 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1631 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1632 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1635 /* First, determine parent of next domain. */
1636 nn
= rr
->nsec
.next_domain_name
;
1637 r
= dns_name_parent(&nn
);
1641 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1642 * anything at all. */
1643 r
= dns_name_endswith(nn
, name
);
1647 /* 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. */
1648 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1652 return dns_name_endswith(name
, common_suffix
);
1655 static int dnssec_nsec_from_parent_zone(DnsResourceRecord
*rr
, const char *name
) {
1659 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1661 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1663 r
= dns_name_parent(&name
);
1667 r
= dns_name_equal(name
, DNS_RESOURCE_KEY_NAME(rr
->key
));
1671 /* DNAME, and NS without SOA is an indication for a delegation. */
1672 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_DNAME
))
1675 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) && !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1681 static int dnssec_nsec_covers(DnsResourceRecord
*rr
, const char *name
) {
1682 const char *common_suffix
, *p
;
1686 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1688 /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
1690 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1696 r
= dns_name_parent(&name
);
1702 r
= dns_name_equal(name
, common_suffix
);
1709 /* p is now the "Next Closer". */
1711 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), p
, rr
->nsec
.next_domain_name
);
1714 static int dnssec_nsec_covers_wildcard(DnsResourceRecord
*rr
, const char *name
) {
1715 const char *common_suffix
, *wc
;
1719 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1721 /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified
1722 * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as
1723 * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label.
1725 * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist
1726 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...)
1727 * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
1730 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1734 /* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */
1735 r
= dns_name_endswith(name
, common_suffix
);
1739 wc
= strjoina("*.", common_suffix
, NULL
);
1740 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wc
, rr
->nsec
.next_domain_name
);
1743 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1744 bool have_nsec3
= false, covering_rr_authenticated
= false, wildcard_rr_authenticated
= false;
1745 DnsResourceRecord
*rr
, *covering_rr
= NULL
, *wildcard_rr
= NULL
;
1746 DnsAnswerFlags flags
;
1753 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1755 name
= DNS_RESOURCE_KEY_NAME(key
);
1757 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1759 if (rr
->key
->class != key
->class)
1762 have_nsec3
= have_nsec3
|| (rr
->key
->type
== DNS_TYPE_NSEC3
);
1764 if (rr
->key
->type
!= DNS_TYPE_NSEC
)
1767 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1768 r
= dns_resource_record_is_synthetic(rr
);
1774 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1775 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), name
);
1779 /* If it's not a direct match, maybe it's a wild card match? */
1780 r
= dnssec_nsec_wildcard_equal(rr
, name
);
1785 if (key
->type
== DNS_TYPE_DS
) {
1786 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1787 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1788 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1791 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1792 * we got the child's NSEC. */
1793 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) &&
1794 !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1798 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1799 *result
= DNSSEC_NSEC_FOUND
;
1800 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1801 *result
= DNSSEC_NSEC_CNAME
;
1803 *result
= DNSSEC_NSEC_NODATA
;
1806 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1813 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1814 * of the NSEC RR. */
1815 r
= dnssec_nsec_in_path(rr
, name
);
1819 *result
= DNSSEC_NSEC_NODATA
;
1822 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1829 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1830 r
= dnssec_nsec_from_parent_zone(rr
, name
);
1836 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1837 r
= dnssec_nsec_covers(rr
, name
);
1840 if (r
> 0 && (!covering_rr
|| !covering_rr_authenticated
)) {
1842 covering_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1845 /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
1846 r
= dnssec_nsec_covers_wildcard(rr
, name
);
1849 if (r
> 0 && (!wildcard_rr
|| !wildcard_rr_authenticated
)) {
1851 wildcard_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1855 if (covering_rr
&& wildcard_rr
) {
1856 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1857 * proved the NXDOMAIN case. */
1858 *result
= DNSSEC_NSEC_NXDOMAIN
;
1861 *authenticated
= covering_rr_authenticated
&& wildcard_rr_authenticated
;
1863 *ttl
= MIN(covering_rr
->ttl
, wildcard_rr
->ttl
);
1868 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1870 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
1872 /* No approproate NSEC RR found, report this. */
1873 *result
= DNSSEC_NSEC_NO_RR
;
1877 static int dnssec_nsec_test_enclosed(DnsAnswer
*answer
, uint16_t type
, const char *name
, const char *zone
, bool *authenticated
) {
1878 DnsResourceRecord
*rr
;
1879 DnsAnswerFlags flags
;
1885 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
1886 * 'zone'. The 'zone' must be a suffix of the 'name'. */
1888 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1891 if (rr
->key
->type
!= type
&& type
!= DNS_TYPE_ANY
)
1894 switch (rr
->key
->type
) {
1898 /* We only care for NSEC RRs from the indicated zone */
1899 r
= dns_resource_record_is_signer(rr
, zone
);
1905 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), name
, rr
->nsec
.next_domain_name
);
1912 case DNS_TYPE_NSEC3
: {
1913 _cleanup_free_
char *hashed_domain
= NULL
, *next_hashed_domain
= NULL
;
1915 /* We only care for NSEC3 RRs from the indicated zone */
1916 r
= dns_resource_record_is_signer(rr
, zone
);
1922 r
= nsec3_is_good(rr
, NULL
);
1928 /* Format the domain we are testing with the NSEC3 RR's hash function */
1929 r
= nsec3_hashed_domain_make(
1936 if ((size_t) r
!= rr
->nsec3
.next_hashed_name_size
)
1939 /* Format the NSEC3's next hashed name as proper domain name */
1940 r
= nsec3_hashed_domain_format(
1941 rr
->nsec3
.next_hashed_name
,
1942 rr
->nsec3
.next_hashed_name_size
,
1944 &next_hashed_domain
);
1948 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), hashed_domain
, next_hashed_domain
);
1962 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1970 static int dnssec_test_positive_wildcard_nsec3(
1975 bool *authenticated
) {
1977 const char *next_closer
= NULL
;
1980 /* Run a positive NSEC3 wildcard proof. Specifically:
1982 * A proof that the the "next closer" of the generating wildcard does not exist.
1984 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
1985 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
1986 * exists for the NSEC3 RR and we are done.
1988 * 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
1989 * c.d.e.f does not exist. */
1993 r
= dns_name_parent(&name
);
1999 r
= dns_name_equal(name
, source
);
2006 return dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC3
, next_closer
, zone
, authenticated
);
2009 static int dnssec_test_positive_wildcard_nsec(
2014 bool *_authenticated
) {
2016 bool authenticated
= true;
2019 /* Run a positive NSEC wildcard proof. Specifically:
2021 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2022 * a prefix of the synthesizing source "source" in the zone "zone".
2024 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2026 * 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
2027 * have to prove that none of the following exist:
2038 _cleanup_free_
char *wc
= NULL
;
2041 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2042 * i.e between the owner name and the next name of an NSEC RR. */
2043 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, name
, zone
, &a
);
2047 authenticated
= authenticated
&& a
;
2049 /* Strip one label off */
2050 r
= dns_name_parent(&name
);
2054 /* Did we reach the source of synthesis? */
2055 r
= dns_name_equal(name
, source
);
2059 /* Successful exit */
2060 *_authenticated
= authenticated
;
2064 /* Safety check, that the source of synthesis is still our suffix */
2065 r
= dns_name_endswith(name
, source
);
2071 /* Replace the label we stripped off with an asterisk */
2072 wc
= strappend("*.", name
);
2076 /* And check if the proof holds for the asterisk name, too */
2077 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, wc
, zone
, &a
);
2081 authenticated
= authenticated
&& a
;
2082 /* In the next iteration we'll check the non-asterisk-prefixed version */
2086 int dnssec_test_positive_wildcard(
2091 bool *authenticated
) {
2098 assert(authenticated
);
2100 r
= dns_answer_contains_zone_nsec3(answer
, zone
);
2104 return dnssec_test_positive_wildcard_nsec3(answer
, name
, source
, zone
, authenticated
);
2106 return dnssec_test_positive_wildcard_nsec(answer
, name
, source
, zone
, authenticated
);
2111 int dnssec_verify_rrset(
2113 const DnsResourceKey
*key
,
2114 DnsResourceRecord
*rrsig
,
2115 DnsResourceRecord
*dnskey
,
2117 DnssecResult
*result
) {
2122 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
2127 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
2132 int dnssec_verify_rrset_search(
2134 const DnsResourceKey
*key
,
2135 DnsAnswer
*validated_dnskeys
,
2137 DnssecResult
*result
,
2138 DnsResourceRecord
**ret_rrsig
) {
2143 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
2148 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
2153 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
2158 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
2163 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
2168 int dnssec_test_positive_wildcard(
2173 bool *authenticated
) {
2180 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
2181 [DNSSEC_VALIDATED
] = "validated",
2182 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
2183 [DNSSEC_INVALID
] = "invalid",
2184 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
2185 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
2186 [DNSSEC_NO_SIGNATURE
] = "no-signature",
2187 [DNSSEC_MISSING_KEY
] = "missing-key",
2188 [DNSSEC_UNSIGNED
] = "unsigned",
2189 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
2190 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
2191 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
2193 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);
2195 static const char* const dnssec_verdict_table
[_DNSSEC_VERDICT_MAX
] = {
2196 [DNSSEC_SECURE
] = "secure",
2197 [DNSSEC_INSECURE
] = "insecure",
2198 [DNSSEC_BOGUS
] = "bogus",
2199 [DNSSEC_INDETERMINATE
] = "indeterminate",
2201 DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict
, DnssecVerdict
);