1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2015 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "alloc-util.h"
26 #include "dns-domain.h"
27 #include "gcrypt-util.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 int rr_compare(const void *a
, const void *b
) {
132 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
136 /* Let's order the RRs according to RFC 4034, Section 6.3 */
140 assert((*x
)->wire_format
);
143 assert((*y
)->wire_format
);
145 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
147 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
151 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
153 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
159 static int dnssec_rsa_verify_raw(
160 const char *hash_algorithm
,
161 const void *signature
, size_t signature_size
,
162 const void *data
, size_t data_size
,
163 const void *exponent
, size_t exponent_size
,
164 const void *modulus
, size_t modulus_size
) {
166 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
167 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
171 assert(hash_algorithm
);
173 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
179 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
185 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
191 ge
= gcry_sexp_build(&signature_sexp
,
193 "(sig-val (rsa (s %m)))",
201 ge
= gcry_sexp_build(&data_sexp
,
203 "(data (flags pkcs1) (hash %s %b))",
212 ge
= gcry_sexp_build(&public_key_sexp
,
214 "(public-key (rsa (n %m) (e %m)))",
222 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
223 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
226 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
240 gcry_sexp_release(public_key_sexp
);
242 gcry_sexp_release(signature_sexp
);
244 gcry_sexp_release(data_sexp
);
249 static int dnssec_rsa_verify(
250 const char *hash_algorithm
,
251 const void *hash
, size_t hash_size
,
252 DnsResourceRecord
*rrsig
,
253 DnsResourceRecord
*dnskey
) {
255 size_t exponent_size
, modulus_size
;
256 void *exponent
, *modulus
;
258 assert(hash_algorithm
);
260 assert(hash_size
> 0);
264 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
265 /* exponent is > 255 bytes long */
267 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
269 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
270 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
272 if (exponent_size
< 256)
275 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
278 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
279 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
282 /* exponent is <= 255 bytes long */
284 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
285 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
287 if (exponent_size
<= 0)
290 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
293 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
294 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
297 return dnssec_rsa_verify_raw(
299 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
301 exponent
, exponent_size
,
302 modulus
, modulus_size
);
305 static int dnssec_ecdsa_verify_raw(
306 const char *hash_algorithm
,
308 const void *signature_r
, size_t signature_r_size
,
309 const void *signature_s
, size_t signature_s_size
,
310 const void *data
, size_t data_size
,
311 const void *key
, size_t key_size
) {
313 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
314 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
318 assert(hash_algorithm
);
320 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
326 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
332 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
338 ge
= gcry_sexp_build(&signature_sexp
,
340 "(sig-val (ecdsa (r %m) (s %m)))",
348 ge
= gcry_sexp_build(&data_sexp
,
350 "(data (flags rfc6979) (hash %s %b))",
359 ge
= gcry_sexp_build(&public_key_sexp
,
361 "(public-key (ecc (curve %s) (q %m)))",
369 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
370 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
373 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
386 gcry_sexp_release(public_key_sexp
);
388 gcry_sexp_release(signature_sexp
);
390 gcry_sexp_release(data_sexp
);
395 static int dnssec_ecdsa_verify(
396 const char *hash_algorithm
,
398 const void *hash
, size_t hash_size
,
399 DnsResourceRecord
*rrsig
,
400 DnsResourceRecord
*dnskey
) {
411 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
413 curve
= "NIST P-256";
414 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
416 curve
= "NIST P-384";
420 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
423 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
426 q
= alloca(key_size
*2 + 1);
427 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
428 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
430 return dnssec_ecdsa_verify_raw(
433 rrsig
->rrsig
.signature
, key_size
,
434 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
439 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
440 gcry_md_write(md
, &v
, sizeof(v
));
443 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
445 gcry_md_write(md
, &v
, sizeof(v
));
448 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
450 gcry_md_write(md
, &v
, sizeof(v
));
453 static int dnssec_rrsig_prepare(DnsResourceRecord
*rrsig
) {
454 int n_key_labels
, n_signer_labels
;
458 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source and
459 * .n_skip_labels_signer fields so that we can use them later on. */
462 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
464 /* Check if this RRSIG RR is already prepared */
465 if (rrsig
->n_skip_labels_source
!= (unsigned) -1)
468 if (rrsig
->rrsig
.inception
> rrsig
->rrsig
.expiration
)
471 name
= dns_resource_key_name(rrsig
->key
);
473 n_key_labels
= dns_name_count_labels(name
);
474 if (n_key_labels
< 0)
476 if (rrsig
->rrsig
.labels
> n_key_labels
)
479 n_signer_labels
= dns_name_count_labels(rrsig
->rrsig
.signer
);
480 if (n_signer_labels
< 0)
481 return n_signer_labels
;
482 if (n_signer_labels
> rrsig
->rrsig
.labels
)
485 r
= dns_name_skip(name
, n_key_labels
- n_signer_labels
, &name
);
491 /* Check if the signer is really a suffix of us */
492 r
= dns_name_equal(name
, rrsig
->rrsig
.signer
);
498 rrsig
->n_skip_labels_source
= n_key_labels
- rrsig
->rrsig
.labels
;
499 rrsig
->n_skip_labels_signer
= n_key_labels
- n_signer_labels
;
504 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
505 usec_t expiration
, inception
, skew
;
508 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
510 if (realtime
== USEC_INFINITY
)
511 realtime
= now(CLOCK_REALTIME
);
513 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
514 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
516 /* Consider inverted validity intervals as expired */
517 if (inception
> expiration
)
520 /* Permit a certain amount of clock skew of 10% of the valid
521 * time range. This takes inspiration from unbound's
523 skew
= (expiration
- inception
) / 10;
527 if (inception
< skew
)
532 if (expiration
+ skew
< expiration
)
533 expiration
= USEC_INFINITY
;
537 return realtime
< inception
|| realtime
> expiration
;
540 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
542 /* Translates a DNSSEC signature algorithm into a gcrypt
545 * Note that we implement all algorithms listed as "Must
546 * implement" and "Recommended to Implement" in RFC6944. We
547 * don't implement any algorithms that are listed as
548 * "Optional" or "Must Not Implement". Specifically, we do not
549 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
554 case DNSSEC_ALGORITHM_RSASHA1
:
555 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
558 case DNSSEC_ALGORITHM_RSASHA256
:
559 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
560 return GCRY_MD_SHA256
;
562 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
563 return GCRY_MD_SHA384
;
565 case DNSSEC_ALGORITHM_RSASHA512
:
566 return GCRY_MD_SHA512
;
573 static void dnssec_fix_rrset_ttl(
574 DnsResourceRecord
*list
[],
576 DnsResourceRecord
*rrsig
,
585 for (k
= 0; k
< n
; k
++) {
586 DnsResourceRecord
*rr
= list
[k
];
588 /* Pick the TTL as the minimum of the RR's TTL, the
589 * RR's original TTL according to the RRSIG and the
590 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
591 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
592 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
594 /* Copy over information about the signer and wildcard source of synthesis */
595 rr
->n_skip_labels_source
= rrsig
->n_skip_labels_source
;
596 rr
->n_skip_labels_signer
= rrsig
->n_skip_labels_signer
;
599 rrsig
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
602 int dnssec_verify_rrset(
604 const DnsResourceKey
*key
,
605 DnsResourceRecord
*rrsig
,
606 DnsResourceRecord
*dnskey
,
608 DnssecResult
*result
) {
610 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
611 DnsResourceRecord
**list
, *rr
;
612 const char *source
, *name
;
613 gcry_md_hd_t md
= NULL
;
624 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
625 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
627 /* Verifies that the RRSet matches the specified "key" in "a",
628 * using the signature "rrsig" and the key "dnskey". It's
629 * assumed that RRSIG and DNSKEY match. */
631 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
632 if (md_algorithm
== -EOPNOTSUPP
) {
633 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
636 if (md_algorithm
< 0)
639 r
= dnssec_rrsig_prepare(rrsig
);
641 *result
= DNSSEC_INVALID
;
647 r
= dnssec_rrsig_expired(rrsig
, realtime
);
651 *result
= DNSSEC_SIGNATURE_EXPIRED
;
655 name
= dns_resource_key_name(key
);
657 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
658 if (dns_type_apex_only(rrsig
->rrsig
.type_covered
)) {
659 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
663 *result
= DNSSEC_INVALID
;
668 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
669 if (rrsig
->rrsig
.type_covered
== DNS_TYPE_DS
) {
670 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
674 *result
= DNSSEC_INVALID
;
679 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
680 r
= dns_name_suffix(name
, rrsig
->rrsig
.labels
, &source
);
683 if (r
> 0 && !dns_type_may_wildcard(rrsig
->rrsig
.type_covered
)) {
684 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
685 *result
= DNSSEC_INVALID
;
689 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
690 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
691 r
= dns_name_startswith(name
, "*");
701 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
702 list
= newa(DnsResourceRecord
*, dns_answer_size(a
));
704 DNS_ANSWER_FOREACH(rr
, a
) {
705 r
= dns_resource_key_equal(key
, rr
->key
);
711 /* We need the wire format for ordering, and digest calculation */
712 r
= dns_resource_record_to_wire_format(rr
, true);
718 if (n
> VERIFY_RRS_MAX
)
725 /* Bring the RRs into canonical order */
726 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
728 /* OK, the RRs are now in canonical order. Let's calculate the digest */
729 initialize_libgcrypt(false);
731 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
732 assert(hash_size
> 0);
734 gcry_md_open(&md
, md_algorithm
, 0);
738 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
739 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
740 md_add_uint8(md
, rrsig
->rrsig
.labels
);
741 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
742 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
743 md_add_uint32(md
, rrsig
->rrsig
.inception
);
744 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
746 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
749 gcry_md_write(md
, wire_format_name
, r
);
751 /* Convert the source of synthesis into wire format */
752 r
= dns_name_to_wire_format(source
, wire_format_name
, sizeof(wire_format_name
), true);
756 for (k
= 0; k
< n
; k
++) {
761 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
763 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
764 gcry_md_write(md
, wire_format_name
, r
);
766 md_add_uint16(md
, rr
->key
->type
);
767 md_add_uint16(md
, rr
->key
->class);
768 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
770 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
773 md_add_uint16(md
, (uint16_t) l
);
774 gcry_md_write(md
, DNS_RESOURCE_RECORD_RDATA(rr
), l
);
777 hash
= gcry_md_read(md
, 0);
783 switch (rrsig
->rrsig
.algorithm
) {
785 case DNSSEC_ALGORITHM_RSASHA1
:
786 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
787 case DNSSEC_ALGORITHM_RSASHA256
:
788 case DNSSEC_ALGORITHM_RSASHA512
:
789 r
= dnssec_rsa_verify(
790 gcry_md_algo_name(md_algorithm
),
796 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
797 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
798 r
= dnssec_ecdsa_verify(
799 gcry_md_algo_name(md_algorithm
),
800 rrsig
->rrsig
.algorithm
,
810 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
812 dnssec_fix_rrset_ttl(list
, n
, rrsig
, realtime
);
815 *result
= DNSSEC_INVALID
;
817 *result
= DNSSEC_VALIDATED_WILDCARD
;
819 *result
= DNSSEC_VALIDATED
;
828 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
833 /* Checks if the specified DNSKEY RR matches the key used for
834 * the signature in the specified RRSIG RR */
836 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
839 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
841 if (dnskey
->key
->class != rrsig
->key
->class)
843 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
845 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
847 if (dnskey
->dnskey
.protocol
!= 3)
849 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
852 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
855 return dns_name_equal(dns_resource_key_name(dnskey
->key
), rrsig
->rrsig
.signer
);
858 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
862 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
864 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
866 if (rrsig
->key
->class != key
->class)
868 if (rrsig
->rrsig
.type_covered
!= key
->type
)
871 return dns_name_equal(dns_resource_key_name(rrsig
->key
), dns_resource_key_name(key
));
874 int dnssec_verify_rrset_search(
876 const DnsResourceKey
*key
,
877 DnsAnswer
*validated_dnskeys
,
879 DnssecResult
*result
,
880 DnsResourceRecord
**ret_rrsig
) {
882 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
883 DnsResourceRecord
*rrsig
;
889 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
891 if (!a
|| a
->n_rrs
<= 0)
894 /* Iterate through each RRSIG RR. */
895 DNS_ANSWER_FOREACH(rrsig
, a
) {
896 DnsResourceRecord
*dnskey
;
897 DnsAnswerFlags flags
;
899 /* Is this an RRSIG RR that applies to RRs matching our key? */
900 r
= dnssec_key_match_rrsig(key
, rrsig
);
908 /* Look for a matching key */
909 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
910 DnssecResult one_result
;
912 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
915 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
916 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
922 /* Take the time here, if it isn't set yet, so
923 * that we do all validations with the same
925 if (realtime
== USEC_INFINITY
)
926 realtime
= now(CLOCK_REALTIME
);
928 /* Yay, we found a matching RRSIG with a matching
929 * DNSKEY, awesome. Now let's verify all entries of
930 * the RRSet against the RRSIG and DNSKEY
933 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
937 switch (one_result
) {
939 case DNSSEC_VALIDATED
:
940 case DNSSEC_VALIDATED_WILDCARD
:
941 /* Yay, the RR has been validated,
942 * return immediately, but fix up the expiry */
946 *result
= one_result
;
950 /* If the signature is invalid, let's try another
951 key and/or signature. After all they
952 key_tags and stuff are not unique, and
953 might be shared by multiple keys. */
954 found_invalid
= true;
957 case DNSSEC_UNSUPPORTED_ALGORITHM
:
958 /* If the key algorithm is
959 unsupported, try another
960 RRSIG/DNSKEY pair, but remember we
961 encountered this, so that we can
962 return a proper error when we
963 encounter nothing better. */
964 found_unsupported_algorithm
= true;
967 case DNSSEC_SIGNATURE_EXPIRED
:
968 /* If the signature is expired, try
969 another one, but remember it, so
970 that we can return this */
971 found_expired_rrsig
= true;
975 assert_not_reached("Unexpected DNSSEC validation result");
980 if (found_expired_rrsig
)
981 *result
= DNSSEC_SIGNATURE_EXPIRED
;
982 else if (found_unsupported_algorithm
)
983 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
984 else if (found_invalid
)
985 *result
= DNSSEC_INVALID
;
986 else if (found_rrsig
)
987 *result
= DNSSEC_MISSING_KEY
;
989 *result
= DNSSEC_NO_SIGNATURE
;
997 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
998 DnsResourceRecord
*rr
;
1001 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
1003 DNS_ANSWER_FOREACH(rr
, a
) {
1004 r
= dnssec_key_match_rrsig(key
, rr
);
1014 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1016 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1018 switch (algorithm
) {
1020 case DNSSEC_DIGEST_SHA1
:
1021 return GCRY_MD_SHA1
;
1023 case DNSSEC_DIGEST_SHA256
:
1024 return GCRY_MD_SHA256
;
1026 case DNSSEC_DIGEST_SHA384
:
1027 return GCRY_MD_SHA384
;
1034 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1035 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
1036 gcry_md_hd_t md
= NULL
;
1038 int md_algorithm
, r
;
1044 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1046 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1048 if (ds
->key
->type
!= DNS_TYPE_DS
)
1050 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1051 return -EKEYREJECTED
;
1052 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1053 return -EKEYREJECTED
;
1054 if (dnskey
->dnskey
.protocol
!= 3)
1055 return -EKEYREJECTED
;
1057 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1059 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1062 initialize_libgcrypt(false);
1064 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1065 if (md_algorithm
< 0)
1066 return md_algorithm
;
1068 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1069 assert(hash_size
> 0);
1071 if (ds
->ds
.digest_size
!= hash_size
)
1074 r
= dnssec_canonicalize(dns_resource_key_name(dnskey
->key
), owner_name
, sizeof(owner_name
));
1078 gcry_md_open(&md
, md_algorithm
, 0);
1082 gcry_md_write(md
, owner_name
, r
);
1084 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1086 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1087 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1088 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1089 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1091 result
= gcry_md_read(md
, 0);
1097 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1104 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1105 DnsResourceRecord
*ds
;
1106 DnsAnswerFlags flags
;
1111 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1114 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1116 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1119 if (ds
->key
->type
!= DNS_TYPE_DS
)
1121 if (ds
->key
->class != dnskey
->key
->class)
1124 r
= dns_name_equal(dns_resource_key_name(dnskey
->key
), dns_resource_key_name(ds
->key
));
1130 r
= dnssec_verify_dnskey_by_ds(dnskey
, ds
, false);
1131 if (IN_SET(r
, -EKEYREJECTED
, -EOPNOTSUPP
))
1132 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1142 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1144 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1146 switch (algorithm
) {
1148 case NSEC3_ALGORITHM_SHA1
:
1149 return GCRY_MD_SHA1
;
1156 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1157 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1158 gcry_md_hd_t md
= NULL
;
1169 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1172 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1173 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1177 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1181 initialize_libgcrypt(false);
1183 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1184 assert(hash_size
> 0);
1186 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1189 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1193 gcry_md_open(&md
, algorithm
, 0);
1197 gcry_md_write(md
, wire_format
, r
);
1198 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1200 result
= gcry_md_read(md
, 0);
1206 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1207 uint8_t tmp
[hash_size
];
1208 memcpy(tmp
, result
, hash_size
);
1211 gcry_md_write(md
, tmp
, hash_size
);
1212 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1214 result
= gcry_md_read(md
, 0);
1221 memcpy(ret
, result
, hash_size
);
1222 r
= (int) hash_size
;
1229 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1235 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1238 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1239 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1242 /* Ignore NSEC3 RRs whose algorithm we don't know */
1243 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1245 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1246 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1249 /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
1250 * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
1251 if (!IN_SET(rr
->n_skip_labels_source
, 0, (unsigned) -1))
1253 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1254 if (!IN_SET(rr
->n_skip_labels_signer
, 1, (unsigned) -1))
1260 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1262 if (nsec3
== rr
) /* Shortcut */
1265 if (rr
->key
->class != nsec3
->key
->class)
1267 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1269 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1271 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1273 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1276 a
= dns_resource_key_name(rr
->key
);
1277 r
= dns_name_parent(&a
); /* strip off hash */
1283 b
= dns_resource_key_name(nsec3
->key
);
1284 r
= dns_name_parent(&b
); /* strip off hash */
1290 /* Make sure both have the same parent */
1291 return dns_name_equal(a
, b
);
1294 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1295 _cleanup_free_
char *l
= NULL
;
1299 assert(hashed_size
> 0);
1303 l
= base32hexmem(hashed
, hashed_size
, false);
1307 j
= strjoin(l
, ".", zone
);
1312 return (int) hashed_size
;
1315 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1316 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1324 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1325 if (hashed_size
< 0)
1328 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1331 /* See RFC 5155, Section 8
1332 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1333 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1334 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1335 * matches the wildcard domain.
1337 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1338 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1339 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1340 * to conclude anything we indicate this by returning NO_RR. */
1341 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1342 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1343 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1344 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1345 DnsAnswerFlags flags
;
1347 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1352 /* First step, find the zone name and the NSEC3 parameters of the zone.
1353 * it is sufficient to look for the longest common suffix we find with
1354 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1355 * records from a given zone in a response must use the same
1357 zone
= dns_resource_key_name(key
);
1359 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1360 r
= nsec3_is_good(zone_rr
, NULL
);
1366 r
= dns_name_equal_skip(dns_resource_key_name(zone_rr
->key
), 1, zone
);
1373 /* Strip one label from the front */
1374 r
= dns_name_parent(&zone
);
1381 *result
= DNSSEC_NSEC_NO_RR
;
1385 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1386 p
= dns_resource_key_name(key
);
1388 _cleanup_free_
char *hashed_domain
= NULL
;
1390 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1391 if (hashed_size
== -EOPNOTSUPP
) {
1392 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1395 if (hashed_size
< 0)
1398 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1400 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1406 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1409 r
= dns_name_equal(dns_resource_key_name(enclosure_rr
->key
), hashed_domain
);
1413 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1414 goto found_closest_encloser
;
1418 /* We didn't find the closest encloser with this name,
1419 * but let's remember this domain name, it might be
1420 * the next closer name */
1424 /* Strip one label from the front */
1425 r
= dns_name_parent(&p
);
1432 *result
= DNSSEC_NSEC_NO_RR
;
1435 found_closest_encloser
:
1436 /* We found a closest encloser in 'p'; next closer is 'pp' */
1439 /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR
1440 * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are
1441 * appropriately set. */
1443 if (key
->type
== DNS_TYPE_DS
) {
1444 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1447 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1448 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1452 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1453 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1454 *result
= DNSSEC_NSEC_FOUND
;
1455 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1456 *result
= DNSSEC_NSEC_CNAME
;
1458 *result
= DNSSEC_NSEC_NODATA
;
1463 *ttl
= enclosure_rr
->ttl
;
1468 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1469 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1472 /* Ensure that this data is from the delegated domain
1473 * (i.e. originates from the "lower" DNS server), and isn't
1474 * just glue records (i.e. doesn't originate from the "upper"
1476 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1477 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1480 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1482 wildcard
= strjoina("*.", p
);
1483 r
= nsec3_hashed_domain_make(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1486 if (r
!= hashed_size
)
1489 r
= nsec3_hashed_domain_make(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1492 if (r
!= hashed_size
)
1495 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1496 _cleanup_free_
char *next_hashed_domain
= NULL
;
1498 r
= nsec3_is_good(rr
, zone_rr
);
1504 r
= nsec3_hashed_domain_format(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, zone
, &next_hashed_domain
);
1508 r
= dns_name_between(dns_resource_key_name(rr
->key
), next_closer_domain
, next_hashed_domain
);
1512 if (rr
->nsec3
.flags
& 1)
1515 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1520 r
= dns_name_equal(dns_resource_key_name(rr
->key
), wildcard_domain
);
1524 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1529 r
= dns_name_between(dns_resource_key_name(rr
->key
), wildcard_domain
, next_hashed_domain
);
1533 if (rr
->nsec3
.flags
& 1)
1534 /* This only makes sense if we have a wildcard delegation, which is
1535 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1536 * this not happening, so hence cannot simply conclude NXDOMAIN as
1540 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1546 if (wildcard_rr
&& no_wildcard
)
1550 *result
= DNSSEC_NSEC_NO_RR
;
1555 /* A wildcard exists that matches our query. */
1557 /* This is not specified in any RFC to the best of my knowledge, but
1558 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1559 * it means that we cannot prove that the source of synthesis is
1560 * correct, as there may be a closer match. */
1561 *result
= DNSSEC_NSEC_OPTOUT
;
1562 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1563 *result
= DNSSEC_NSEC_FOUND
;
1564 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1565 *result
= DNSSEC_NSEC_CNAME
;
1567 *result
= DNSSEC_NSEC_NODATA
;
1570 /* The RFC only specifies that we have to care for optout for NODATA for
1571 * DS records. However, children of an insecure opt-out delegation should
1572 * also be considered opt-out, rather than verified NXDOMAIN.
1573 * Note that we do not require a proof of wildcard non-existence if the
1574 * next closer domain is covered by an opt-out, as that would not provide
1575 * any additional information. */
1576 *result
= DNSSEC_NSEC_OPTOUT
;
1577 else if (no_wildcard
)
1578 *result
= DNSSEC_NSEC_NXDOMAIN
;
1580 *result
= DNSSEC_NSEC_NO_RR
;
1590 *ttl
= enclosure_rr
->ttl
;
1595 static int dnssec_nsec_wildcard_equal(DnsResourceRecord
*rr
, const char *name
) {
1596 char label
[DNS_LABEL_MAX
];
1601 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1603 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1605 if (rr
->n_skip_labels_source
!= 1)
1608 n
= dns_resource_key_name(rr
->key
);
1609 r
= dns_label_unescape(&n
, label
, sizeof(label
));
1612 if (r
!= 1 || label
[0] != '*')
1615 return dns_name_endswith(name
, n
);
1618 static int dnssec_nsec_in_path(DnsResourceRecord
*rr
, const char *name
) {
1619 const char *nn
, *common_suffix
;
1623 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1625 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1627 * A couple of examples:
1629 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1630 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1631 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1634 /* First, determine parent of next domain. */
1635 nn
= rr
->nsec
.next_domain_name
;
1636 r
= dns_name_parent(&nn
);
1640 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1641 * anything at all. */
1642 r
= dns_name_endswith(nn
, name
);
1646 /* If the name 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. */
1647 r
= dns_name_common_suffix(dns_resource_key_name(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1651 return dns_name_endswith(name
, common_suffix
);
1654 static int dnssec_nsec_from_parent_zone(DnsResourceRecord
*rr
, const char *name
) {
1658 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1660 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1662 r
= dns_name_parent(&name
);
1666 r
= dns_name_equal(name
, dns_resource_key_name(rr
->key
));
1670 /* DNAME, and NS without SOA is an indication for a delegation. */
1671 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_DNAME
))
1674 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) && !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1680 static int dnssec_nsec_covers(DnsResourceRecord
*rr
, const char *name
) {
1681 const char *common_suffix
, *p
;
1685 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1687 /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
1689 r
= dns_name_common_suffix(dns_resource_key_name(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1695 r
= dns_name_parent(&name
);
1701 r
= dns_name_equal(name
, common_suffix
);
1708 /* p is now the "Next Closer". */
1710 return dns_name_between(dns_resource_key_name(rr
->key
), p
, rr
->nsec
.next_domain_name
);
1713 static int dnssec_nsec_covers_wildcard(DnsResourceRecord
*rr
, const char *name
) {
1714 _cleanup_free_
char *wc
= NULL
;
1715 const char *common_suffix
;
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 r
= dns_name_concat("*", common_suffix
, &wc
);
1743 return dns_name_between(dns_resource_key_name(rr
->key
), wc
, rr
->nsec
.next_domain_name
);
1746 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1747 bool have_nsec3
= false, covering_rr_authenticated
= false, wildcard_rr_authenticated
= false;
1748 DnsResourceRecord
*rr
, *covering_rr
= NULL
, *wildcard_rr
= NULL
;
1749 DnsAnswerFlags flags
;
1756 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1758 name
= dns_resource_key_name(key
);
1760 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1762 if (rr
->key
->class != key
->class)
1765 have_nsec3
= have_nsec3
|| (rr
->key
->type
== DNS_TYPE_NSEC3
);
1767 if (rr
->key
->type
!= DNS_TYPE_NSEC
)
1770 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1771 r
= dns_resource_record_is_synthetic(rr
);
1777 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1778 r
= dns_name_equal(dns_resource_key_name(rr
->key
), name
);
1782 /* If it's not a direct match, maybe it's a wild card match? */
1783 r
= dnssec_nsec_wildcard_equal(rr
, name
);
1788 if (key
->type
== DNS_TYPE_DS
) {
1789 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1790 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1791 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1794 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1795 * we got the child's NSEC. */
1796 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) &&
1797 !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1801 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1802 *result
= DNSSEC_NSEC_FOUND
;
1803 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1804 *result
= DNSSEC_NSEC_CNAME
;
1806 *result
= DNSSEC_NSEC_NODATA
;
1809 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1816 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1817 * of the NSEC RR. */
1818 r
= dnssec_nsec_in_path(rr
, name
);
1822 *result
= DNSSEC_NSEC_NODATA
;
1825 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1832 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1833 r
= dnssec_nsec_from_parent_zone(rr
, name
);
1839 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1840 r
= dnssec_nsec_covers(rr
, name
);
1843 if (r
> 0 && (!covering_rr
|| !covering_rr_authenticated
)) {
1845 covering_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1848 /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
1849 r
= dnssec_nsec_covers_wildcard(rr
, name
);
1852 if (r
> 0 && (!wildcard_rr
|| !wildcard_rr_authenticated
)) {
1854 wildcard_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1858 if (covering_rr
&& wildcard_rr
) {
1859 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1860 * proved the NXDOMAIN case. */
1861 *result
= DNSSEC_NSEC_NXDOMAIN
;
1864 *authenticated
= covering_rr_authenticated
&& wildcard_rr_authenticated
;
1866 *ttl
= MIN(covering_rr
->ttl
, wildcard_rr
->ttl
);
1871 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1873 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
1875 /* No approproate NSEC RR found, report this. */
1876 *result
= DNSSEC_NSEC_NO_RR
;
1880 static int dnssec_nsec_test_enclosed(DnsAnswer
*answer
, uint16_t type
, const char *name
, const char *zone
, bool *authenticated
) {
1881 DnsResourceRecord
*rr
;
1882 DnsAnswerFlags flags
;
1888 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
1889 * 'zone'. The 'zone' must be a suffix of the 'name'. */
1891 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1894 if (rr
->key
->type
!= type
&& type
!= DNS_TYPE_ANY
)
1897 switch (rr
->key
->type
) {
1901 /* We only care for NSEC RRs from the indicated zone */
1902 r
= dns_resource_record_is_signer(rr
, zone
);
1908 r
= dns_name_between(dns_resource_key_name(rr
->key
), name
, rr
->nsec
.next_domain_name
);
1915 case DNS_TYPE_NSEC3
: {
1916 _cleanup_free_
char *hashed_domain
= NULL
, *next_hashed_domain
= NULL
;
1918 /* We only care for NSEC3 RRs from the indicated zone */
1919 r
= dns_resource_record_is_signer(rr
, zone
);
1925 r
= nsec3_is_good(rr
, NULL
);
1931 /* Format the domain we are testing with the NSEC3 RR's hash function */
1932 r
= nsec3_hashed_domain_make(
1939 if ((size_t) r
!= rr
->nsec3
.next_hashed_name_size
)
1942 /* Format the NSEC3's next hashed name as proper domain name */
1943 r
= nsec3_hashed_domain_format(
1944 rr
->nsec3
.next_hashed_name
,
1945 rr
->nsec3
.next_hashed_name_size
,
1947 &next_hashed_domain
);
1951 r
= dns_name_between(dns_resource_key_name(rr
->key
), hashed_domain
, next_hashed_domain
);
1965 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1973 static int dnssec_test_positive_wildcard_nsec3(
1978 bool *authenticated
) {
1980 const char *next_closer
= NULL
;
1983 /* Run a positive NSEC3 wildcard proof. Specifically:
1985 * A proof that the "next closer" of the generating wildcard does not exist.
1987 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
1988 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
1989 * exists for the NSEC3 RR and we are done.
1991 * 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
1992 * c.d.e.f does not exist. */
1996 r
= dns_name_parent(&name
);
2002 r
= dns_name_equal(name
, source
);
2009 return dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC3
, next_closer
, zone
, authenticated
);
2012 static int dnssec_test_positive_wildcard_nsec(
2017 bool *_authenticated
) {
2019 bool authenticated
= true;
2022 /* Run a positive NSEC wildcard proof. Specifically:
2024 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2025 * a prefix of the synthesizing source "source" in the zone "zone".
2027 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2029 * 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
2030 * have to prove that none of the following exist:
2041 _cleanup_free_
char *wc
= NULL
;
2044 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2045 * i.e between the owner name and the next name of an NSEC RR. */
2046 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, name
, zone
, &a
);
2050 authenticated
= authenticated
&& a
;
2052 /* Strip one label off */
2053 r
= dns_name_parent(&name
);
2057 /* Did we reach the source of synthesis? */
2058 r
= dns_name_equal(name
, source
);
2062 /* Successful exit */
2063 *_authenticated
= authenticated
;
2067 /* Safety check, that the source of synthesis is still our suffix */
2068 r
= dns_name_endswith(name
, source
);
2074 /* Replace the label we stripped off with an asterisk */
2075 wc
= strappend("*.", name
);
2079 /* And check if the proof holds for the asterisk name, too */
2080 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, wc
, zone
, &a
);
2084 authenticated
= authenticated
&& a
;
2085 /* In the next iteration we'll check the non-asterisk-prefixed version */
2089 int dnssec_test_positive_wildcard(
2094 bool *authenticated
) {
2101 assert(authenticated
);
2103 r
= dns_answer_contains_zone_nsec3(answer
, zone
);
2107 return dnssec_test_positive_wildcard_nsec3(answer
, name
, source
, zone
, authenticated
);
2109 return dnssec_test_positive_wildcard_nsec(answer
, name
, source
, zone
, authenticated
);
2114 int dnssec_verify_rrset(
2116 const DnsResourceKey
*key
,
2117 DnsResourceRecord
*rrsig
,
2118 DnsResourceRecord
*dnskey
,
2120 DnssecResult
*result
) {
2125 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
2130 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
2135 int dnssec_verify_rrset_search(
2137 const DnsResourceKey
*key
,
2138 DnsAnswer
*validated_dnskeys
,
2140 DnssecResult
*result
,
2141 DnsResourceRecord
**ret_rrsig
) {
2146 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
2151 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
2156 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
2161 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
2166 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
2171 int dnssec_test_positive_wildcard(
2176 bool *authenticated
) {
2183 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
2184 [DNSSEC_VALIDATED
] = "validated",
2185 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
2186 [DNSSEC_INVALID
] = "invalid",
2187 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
2188 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
2189 [DNSSEC_NO_SIGNATURE
] = "no-signature",
2190 [DNSSEC_MISSING_KEY
] = "missing-key",
2191 [DNSSEC_UNSIGNED
] = "unsigned",
2192 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
2193 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
2194 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
2196 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);
2198 static const char* const dnssec_verdict_table
[_DNSSEC_VERDICT_MAX
] = {
2199 [DNSSEC_SECURE
] = "secure",
2200 [DNSSEC_INSECURE
] = "insecure",
2201 [DNSSEC_BOGUS
] = "bogus",
2202 [DNSSEC_INDETERMINATE
] = "indeterminate",
2204 DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict
, DnssecVerdict
);