2 This file is part of systemd.
4 Copyright 2015 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
25 #include "dns-domain.h"
26 #include "hexdecoct.h"
27 #include "resolved-dns-dnssec.h"
28 #include "resolved-dns-packet.h"
29 #include "string-table.h"
31 #define VERIFY_RRS_MAX 256
32 #define MAX_KEY_SIZE (32*1024)
34 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
35 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
37 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
38 #define NSEC3_ITERATIONS_MAX 2500
41 * The DNSSEC Chain of trust:
43 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
44 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
45 * DS RRs are protected like normal RRs
48 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
51 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
, bool mask_revoke
) {
56 /* The algorithm from RFC 4034, Appendix B. */
59 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
61 f
= (uint32_t) dnskey
->dnskey
.flags
;
64 f
&= ~DNSKEY_FLAG_REVOKE
;
66 sum
= f
+ ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
68 p
= dnskey
->dnskey
.key
;
70 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
71 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
73 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
75 return sum
& UINT32_C(0xFFFF);
78 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
82 /* Converts the specified hostname into DNSSEC canonicalized
89 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
95 if (buffer_max
< (size_t) r
+ 2)
98 /* The DNSSEC canonical form is not clear on what to
99 * do with dots appearing in labels, the way DNS-SD
100 * does it. Refuse it for now. */
102 if (memchr(buffer
, '.', r
))
105 ascii_strlower_n(buffer
, (size_t) r
);
115 /* Not even a single label: this is the root domain name */
117 assert(buffer_max
> 2);
129 static void initialize_libgcrypt(void) {
132 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
135 p
= gcry_check_version("1.4.5");
138 gcry_control(GCRYCTL_DISABLE_SECMEM
);
139 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
142 static int rr_compare(const void *a
, const void *b
) {
143 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
147 /* Let's order the RRs according to RFC 4034, Section 6.3 */
151 assert((*x
)->wire_format
);
154 assert((*y
)->wire_format
);
156 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
158 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
162 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
164 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
170 static int dnssec_rsa_verify_raw(
171 const char *hash_algorithm
,
172 const void *signature
, size_t signature_size
,
173 const void *data
, size_t data_size
,
174 const void *exponent
, size_t exponent_size
,
175 const void *modulus
, size_t modulus_size
) {
177 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
178 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
182 assert(hash_algorithm
);
184 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
190 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
196 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
202 ge
= gcry_sexp_build(&signature_sexp
,
204 "(sig-val (rsa (s %m)))",
212 ge
= gcry_sexp_build(&data_sexp
,
214 "(data (flags pkcs1) (hash %s %b))",
223 ge
= gcry_sexp_build(&public_key_sexp
,
225 "(public-key (rsa (n %m) (e %m)))",
233 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
234 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
237 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
251 gcry_sexp_release(public_key_sexp
);
253 gcry_sexp_release(signature_sexp
);
255 gcry_sexp_release(data_sexp
);
260 static int dnssec_rsa_verify(
261 const char *hash_algorithm
,
262 const void *hash
, size_t hash_size
,
263 DnsResourceRecord
*rrsig
,
264 DnsResourceRecord
*dnskey
) {
266 size_t exponent_size
, modulus_size
;
267 void *exponent
, *modulus
;
269 assert(hash_algorithm
);
271 assert(hash_size
> 0);
275 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
276 /* exponent is > 255 bytes long */
278 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
280 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
281 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
283 if (exponent_size
< 256)
286 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
289 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
290 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
293 /* exponent is <= 255 bytes long */
295 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
296 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
298 if (exponent_size
<= 0)
301 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
304 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
305 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
308 return dnssec_rsa_verify_raw(
310 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
312 exponent
, exponent_size
,
313 modulus
, modulus_size
);
316 static int dnssec_ecdsa_verify_raw(
317 const char *hash_algorithm
,
319 const void *signature_r
, size_t signature_r_size
,
320 const void *signature_s
, size_t signature_s_size
,
321 const void *data
, size_t data_size
,
322 const void *key
, size_t key_size
) {
324 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
325 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
329 assert(hash_algorithm
);
331 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
337 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
343 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
349 ge
= gcry_sexp_build(&signature_sexp
,
351 "(sig-val (ecdsa (r %m) (s %m)))",
359 ge
= gcry_sexp_build(&data_sexp
,
361 "(data (flags rfc6979) (hash %s %b))",
370 ge
= gcry_sexp_build(&public_key_sexp
,
372 "(public-key (ecc (curve %s) (q %m)))",
380 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
381 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
384 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
397 gcry_sexp_release(public_key_sexp
);
399 gcry_sexp_release(signature_sexp
);
401 gcry_sexp_release(data_sexp
);
406 static int dnssec_ecdsa_verify(
407 const char *hash_algorithm
,
409 const void *hash
, size_t hash_size
,
410 DnsResourceRecord
*rrsig
,
411 DnsResourceRecord
*dnskey
) {
422 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
424 curve
= "NIST P-256";
425 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
427 curve
= "NIST P-384";
431 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
434 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
437 q
= alloca(key_size
*2 + 1);
438 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
439 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
441 return dnssec_ecdsa_verify_raw(
444 rrsig
->rrsig
.signature
, key_size
,
445 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
450 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
451 gcry_md_write(md
, &v
, sizeof(v
));
454 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
456 gcry_md_write(md
, &v
, sizeof(v
));
459 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
461 gcry_md_write(md
, &v
, sizeof(v
));
464 static int dnssec_rrsig_prepare(DnsResourceRecord
*rrsig
) {
465 int n_key_labels
, n_signer_labels
;
469 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source and
470 * .n_skip_labels_signer fields so that we can use them later on. */
473 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
475 /* Check if this RRSIG RR is already prepared */
476 if (rrsig
->n_skip_labels_source
!= (unsigned) -1)
479 if (rrsig
->rrsig
.inception
> rrsig
->rrsig
.expiration
)
482 name
= DNS_RESOURCE_KEY_NAME(rrsig
->key
);
484 n_key_labels
= dns_name_count_labels(name
);
485 if (n_key_labels
< 0)
487 if (rrsig
->rrsig
.labels
> n_key_labels
)
490 n_signer_labels
= dns_name_count_labels(rrsig
->rrsig
.signer
);
491 if (n_signer_labels
< 0)
492 return n_signer_labels
;
493 if (n_signer_labels
> rrsig
->rrsig
.labels
)
496 r
= dns_name_skip(name
, n_key_labels
- n_signer_labels
, &name
);
502 /* Check if the signer is really a suffix of us */
503 r
= dns_name_equal(name
, rrsig
->rrsig
.signer
);
509 rrsig
->n_skip_labels_source
= n_key_labels
- rrsig
->rrsig
.labels
;
510 rrsig
->n_skip_labels_signer
= n_key_labels
- n_signer_labels
;
515 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
516 usec_t expiration
, inception
, skew
;
519 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
521 if (realtime
== USEC_INFINITY
)
522 realtime
= now(CLOCK_REALTIME
);
524 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
525 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
527 /* Consider inverted validity intervals as expired */
528 if (inception
> expiration
)
531 /* Permit a certain amount of clock skew of 10% of the valid
532 * time range. This takes inspiration from unbound's
534 skew
= (expiration
- inception
) / 10;
538 if (inception
< skew
)
543 if (expiration
+ skew
< expiration
)
544 expiration
= USEC_INFINITY
;
548 return realtime
< inception
|| realtime
> expiration
;
551 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
553 /* Translates a DNSSEC signature algorithm into a gcrypt
556 * Note that we implement all algorithms listed as "Must
557 * implement" and "Recommended to Implement" in RFC6944. We
558 * don't implement any algorithms that are listed as
559 * "Optional" or "Must Not Implement". Specifically, we do not
560 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
565 case DNSSEC_ALGORITHM_RSASHA1
:
566 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
569 case DNSSEC_ALGORITHM_RSASHA256
:
570 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
571 return GCRY_MD_SHA256
;
573 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
574 return GCRY_MD_SHA384
;
576 case DNSSEC_ALGORITHM_RSASHA512
:
577 return GCRY_MD_SHA512
;
584 static void dnssec_fix_rrset_ttl(
585 DnsResourceRecord
*list
[],
587 DnsResourceRecord
*rrsig
,
596 for (k
= 0; k
< n
; k
++) {
597 DnsResourceRecord
*rr
= list
[k
];
599 /* Pick the TTL as the minimum of the RR's TTL, the
600 * RR's original TTL according to the RRSIG and the
601 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
602 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
603 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
605 /* Copy over information about the signer and wildcard source of synthesis */
606 rr
->n_skip_labels_source
= rrsig
->n_skip_labels_source
;
607 rr
->n_skip_labels_signer
= rrsig
->n_skip_labels_signer
;
610 rrsig
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
613 int dnssec_verify_rrset(
615 const DnsResourceKey
*key
,
616 DnsResourceRecord
*rrsig
,
617 DnsResourceRecord
*dnskey
,
619 DnssecResult
*result
) {
621 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
622 DnsResourceRecord
**list
, *rr
;
623 const char *source
, *name
;
624 gcry_md_hd_t md
= NULL
;
635 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
636 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
638 /* Verifies the the RRSet matching the specified "key" in "a",
639 * using the signature "rrsig" and the key "dnskey". It's
640 * assumed the RRSIG and DNSKEY match. */
642 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
643 if (md_algorithm
== -EOPNOTSUPP
) {
644 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
647 if (md_algorithm
< 0)
650 r
= dnssec_rrsig_prepare(rrsig
);
652 *result
= DNSSEC_INVALID
;
658 r
= dnssec_rrsig_expired(rrsig
, realtime
);
662 *result
= DNSSEC_SIGNATURE_EXPIRED
;
666 name
= DNS_RESOURCE_KEY_NAME(key
);
668 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
669 if (dns_type_apex_only(rrsig
->rrsig
.type_covered
)) {
670 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
674 *result
= DNSSEC_INVALID
;
679 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
680 if (rrsig
->rrsig
.type_covered
== DNS_TYPE_DS
) {
681 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
685 *result
= DNSSEC_INVALID
;
690 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
691 r
= dns_name_suffix(name
, rrsig
->rrsig
.labels
, &source
);
694 if (r
> 0 && !dns_type_may_wildcard(rrsig
->rrsig
.type_covered
)) {
695 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
696 *result
= DNSSEC_INVALID
;
700 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
701 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
702 r
= dns_name_startswith(name
, "*");
712 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
713 list
= newa(DnsResourceRecord
*, dns_answer_size(a
));
715 DNS_ANSWER_FOREACH(rr
, a
) {
716 r
= dns_resource_key_equal(key
, rr
->key
);
722 /* We need the wire format for ordering, and digest calculation */
723 r
= dns_resource_record_to_wire_format(rr
, true);
729 if (n
> VERIFY_RRS_MAX
)
736 /* Bring the RRs into canonical order */
737 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
739 /* OK, the RRs are now in canonical order. Let's calculate the digest */
740 initialize_libgcrypt();
742 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
743 assert(hash_size
> 0);
745 gcry_md_open(&md
, md_algorithm
, 0);
749 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
750 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
751 md_add_uint8(md
, rrsig
->rrsig
.labels
);
752 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
753 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
754 md_add_uint32(md
, rrsig
->rrsig
.inception
);
755 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
757 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
760 gcry_md_write(md
, wire_format_name
, r
);
762 /* Convert the source of synthesis into wire format */
763 r
= dns_name_to_wire_format(source
, wire_format_name
, sizeof(wire_format_name
), true);
767 for (k
= 0; k
< n
; k
++) {
772 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
774 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
775 gcry_md_write(md
, wire_format_name
, r
);
777 md_add_uint16(md
, rr
->key
->type
);
778 md_add_uint16(md
, rr
->key
->class);
779 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
781 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
784 md_add_uint16(md
, (uint16_t) l
);
785 gcry_md_write(md
, DNS_RESOURCE_RECORD_RDATA(rr
), l
);
788 hash
= gcry_md_read(md
, 0);
794 switch (rrsig
->rrsig
.algorithm
) {
796 case DNSSEC_ALGORITHM_RSASHA1
:
797 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
798 case DNSSEC_ALGORITHM_RSASHA256
:
799 case DNSSEC_ALGORITHM_RSASHA512
:
800 r
= dnssec_rsa_verify(
801 gcry_md_algo_name(md_algorithm
),
807 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
808 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
809 r
= dnssec_ecdsa_verify(
810 gcry_md_algo_name(md_algorithm
),
811 rrsig
->rrsig
.algorithm
,
821 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
823 dnssec_fix_rrset_ttl(list
, n
, rrsig
, realtime
);
826 *result
= DNSSEC_INVALID
;
828 *result
= DNSSEC_VALIDATED_WILDCARD
;
830 *result
= DNSSEC_VALIDATED
;
839 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
844 /* Checks if the specified DNSKEY RR matches the key used for
845 * the signature in the specified RRSIG RR */
847 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
850 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
852 if (dnskey
->key
->class != rrsig
->key
->class)
854 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
856 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
858 if (dnskey
->dnskey
.protocol
!= 3)
860 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
863 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
866 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
869 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
873 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
875 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
877 if (rrsig
->key
->class != key
->class)
879 if (rrsig
->rrsig
.type_covered
!= key
->type
)
882 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
885 int dnssec_verify_rrset_search(
887 const DnsResourceKey
*key
,
888 DnsAnswer
*validated_dnskeys
,
890 DnssecResult
*result
,
891 DnsResourceRecord
**ret_rrsig
) {
893 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
894 DnsResourceRecord
*rrsig
;
900 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
902 if (!a
|| a
->n_rrs
<= 0)
905 /* Iterate through each RRSIG RR. */
906 DNS_ANSWER_FOREACH(rrsig
, a
) {
907 DnsResourceRecord
*dnskey
;
908 DnsAnswerFlags flags
;
910 /* Is this an RRSIG RR that applies to RRs matching our key? */
911 r
= dnssec_key_match_rrsig(key
, rrsig
);
919 /* Look for a matching key */
920 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
921 DnssecResult one_result
;
923 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
926 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
927 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
933 /* Take the time here, if it isn't set yet, so
934 * that we do all validations with the same
936 if (realtime
== USEC_INFINITY
)
937 realtime
= now(CLOCK_REALTIME
);
939 /* Yay, we found a matching RRSIG with a matching
940 * DNSKEY, awesome. Now let's verify all entries of
941 * the RRSet against the RRSIG and DNSKEY
944 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
948 switch (one_result
) {
950 case DNSSEC_VALIDATED
:
951 case DNSSEC_VALIDATED_WILDCARD
:
952 /* Yay, the RR has been validated,
953 * return immediately, but fix up the expiry */
957 *result
= one_result
;
961 /* If the signature is invalid, let's try another
962 key and/or signature. After all they
963 key_tags and stuff are not unique, and
964 might be shared by multiple keys. */
965 found_invalid
= true;
968 case DNSSEC_UNSUPPORTED_ALGORITHM
:
969 /* If the key algorithm is
970 unsupported, try another
971 RRSIG/DNSKEY pair, but remember we
972 encountered this, so that we can
973 return a proper error when we
974 encounter nothing better. */
975 found_unsupported_algorithm
= true;
978 case DNSSEC_SIGNATURE_EXPIRED
:
979 /* If the signature is expired, try
980 another one, but remember it, so
981 that we can return this */
982 found_expired_rrsig
= true;
986 assert_not_reached("Unexpected DNSSEC validation result");
991 if (found_expired_rrsig
)
992 *result
= DNSSEC_SIGNATURE_EXPIRED
;
993 else if (found_unsupported_algorithm
)
994 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
995 else if (found_invalid
)
996 *result
= DNSSEC_INVALID
;
997 else if (found_rrsig
)
998 *result
= DNSSEC_MISSING_KEY
;
1000 *result
= DNSSEC_NO_SIGNATURE
;
1008 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
1009 DnsResourceRecord
*rr
;
1012 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
1014 DNS_ANSWER_FOREACH(rr
, a
) {
1015 r
= dnssec_key_match_rrsig(key
, rr
);
1025 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1027 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1029 switch (algorithm
) {
1031 case DNSSEC_DIGEST_SHA1
:
1032 return GCRY_MD_SHA1
;
1034 case DNSSEC_DIGEST_SHA256
:
1035 return GCRY_MD_SHA256
;
1037 case DNSSEC_DIGEST_SHA384
:
1038 return GCRY_MD_SHA384
;
1045 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1046 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
1047 gcry_md_hd_t md
= NULL
;
1049 int md_algorithm
, r
;
1055 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1057 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1059 if (ds
->key
->type
!= DNS_TYPE_DS
)
1061 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1062 return -EKEYREJECTED
;
1063 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1064 return -EKEYREJECTED
;
1065 if (dnskey
->dnskey
.protocol
!= 3)
1066 return -EKEYREJECTED
;
1068 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1070 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1073 initialize_libgcrypt();
1075 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1076 if (md_algorithm
< 0)
1077 return md_algorithm
;
1079 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1080 assert(hash_size
> 0);
1082 if (ds
->ds
.digest_size
!= hash_size
)
1085 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
1089 gcry_md_open(&md
, md_algorithm
, 0);
1093 gcry_md_write(md
, owner_name
, r
);
1095 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1097 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1098 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1099 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1100 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1102 result
= gcry_md_read(md
, 0);
1108 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1115 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1116 DnsResourceRecord
*ds
;
1117 DnsAnswerFlags flags
;
1122 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1125 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1127 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1130 if (ds
->key
->type
!= DNS_TYPE_DS
)
1132 if (ds
->key
->class != dnskey
->key
->class)
1135 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1141 r
= dnssec_verify_dnskey_by_ds(dnskey
, ds
, false);
1142 if (IN_SET(r
, -EKEYREJECTED
, -EOPNOTSUPP
))
1143 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1153 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1155 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1157 switch (algorithm
) {
1159 case NSEC3_ALGORITHM_SHA1
:
1160 return GCRY_MD_SHA1
;
1167 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1168 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1169 gcry_md_hd_t md
= NULL
;
1180 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1183 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1184 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1188 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1192 initialize_libgcrypt();
1194 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1195 assert(hash_size
> 0);
1197 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1200 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1204 gcry_md_open(&md
, algorithm
, 0);
1208 gcry_md_write(md
, wire_format
, r
);
1209 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1211 result
= gcry_md_read(md
, 0);
1217 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1218 uint8_t tmp
[hash_size
];
1219 memcpy(tmp
, result
, hash_size
);
1222 gcry_md_write(md
, tmp
, hash_size
);
1223 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1225 result
= gcry_md_read(md
, 0);
1232 memcpy(ret
, result
, hash_size
);
1233 r
= (int) hash_size
;
1240 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1246 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1249 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1250 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1253 /* Ignore NSEC3 RRs whose algorithm we don't know */
1254 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1256 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1257 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1260 /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
1261 * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
1262 if (rr
->n_skip_labels_source
!= 0 && rr
->n_skip_labels_source
!= (unsigned) -1)
1264 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1265 if (rr
->n_skip_labels_signer
!= 1 && rr
->n_skip_labels_signer
!= (unsigned) -1)
1271 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1273 if (nsec3
== rr
) /* Shortcut */
1276 if (rr
->key
->class != nsec3
->key
->class)
1278 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1280 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1282 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1284 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1287 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1288 r
= dns_name_parent(&a
); /* strip off hash */
1294 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1295 r
= dns_name_parent(&b
); /* strip off hash */
1301 /* Make sure both have the same parent */
1302 return dns_name_equal(a
, b
);
1305 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1306 _cleanup_free_
char *l
= NULL
;
1310 assert(hashed_size
> 0);
1314 l
= base32hexmem(hashed
, hashed_size
, false);
1318 j
= strjoin(l
, ".", zone
, NULL
);
1323 return (int) hashed_size
;
1326 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1327 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1335 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1336 if (hashed_size
< 0)
1339 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1342 /* See RFC 5155, Section 8
1343 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1344 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1345 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1346 * matches the wildcard domain.
1348 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1349 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1350 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1351 * to conclude anything we indicate this by returning NO_RR. */
1352 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1353 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1354 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1355 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1356 DnsAnswerFlags flags
;
1358 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1363 /* First step, find the zone name and the NSEC3 parameters of the zone.
1364 * it is sufficient to look for the longest common suffix we find with
1365 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1366 * records from a given zone in a response must use the same
1368 zone
= DNS_RESOURCE_KEY_NAME(key
);
1370 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1371 r
= nsec3_is_good(zone_rr
, NULL
);
1377 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr
->key
), 1, zone
);
1384 /* Strip one label from the front */
1385 r
= dns_name_parent(&zone
);
1392 *result
= DNSSEC_NSEC_NO_RR
;
1396 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1397 p
= DNS_RESOURCE_KEY_NAME(key
);
1399 _cleanup_free_
char *hashed_domain
= NULL
;
1401 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1402 if (hashed_size
== -EOPNOTSUPP
) {
1403 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1406 if (hashed_size
< 0)
1409 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1411 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1417 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1420 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr
->key
), hashed_domain
);
1424 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1425 goto found_closest_encloser
;
1429 /* We didn't find the closest encloser with this name,
1430 * but let's remember this domain name, it might be
1431 * the next closer name */
1435 /* Strip one label from the front */
1436 r
= dns_name_parent(&p
);
1443 *result
= DNSSEC_NSEC_NO_RR
;
1446 found_closest_encloser
:
1447 /* We found a closest encloser in 'p'; next closer is 'pp' */
1450 /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR
1451 * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are
1452 * appropriately set. */
1454 if (key
->type
== DNS_TYPE_DS
) {
1455 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1458 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1459 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1463 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1464 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1465 *result
= DNSSEC_NSEC_FOUND
;
1466 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1467 *result
= DNSSEC_NSEC_CNAME
;
1469 *result
= DNSSEC_NSEC_NODATA
;
1474 *ttl
= enclosure_rr
->ttl
;
1479 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1480 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1483 /* Ensure that this data is from the delegated domain
1484 * (i.e. originates from the "lower" DNS server), and isn't
1485 * just glue records (i.e. doesn't originate from the "upper"
1487 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1488 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1491 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1493 wildcard
= strjoina("*.", p
);
1494 r
= nsec3_hashed_domain_make(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1497 if (r
!= hashed_size
)
1500 r
= nsec3_hashed_domain_make(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1503 if (r
!= hashed_size
)
1506 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1507 _cleanup_free_
char *next_hashed_domain
= NULL
;
1509 r
= nsec3_is_good(rr
, zone_rr
);
1515 r
= nsec3_hashed_domain_format(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, zone
, &next_hashed_domain
);
1519 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1523 if (rr
->nsec3
.flags
& 1)
1526 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1531 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
);
1535 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1540 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
, next_hashed_domain
);
1544 if (rr
->nsec3
.flags
& 1)
1545 /* This only makes sense if we have a wildcard delegation, which is
1546 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1547 * this not happening, so hence cannot simply conclude NXDOMAIN as
1551 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1557 if (wildcard_rr
&& no_wildcard
)
1561 *result
= DNSSEC_NSEC_NO_RR
;
1566 /* A wildcard exists that matches our query. */
1568 /* This is not specified in any RFC to the best of my knowledge, but
1569 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1570 * it means that we cannot prove that the source of synthesis is
1571 * correct, as there may be a closer match. */
1572 *result
= DNSSEC_NSEC_OPTOUT
;
1573 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1574 *result
= DNSSEC_NSEC_FOUND
;
1575 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1576 *result
= DNSSEC_NSEC_CNAME
;
1578 *result
= DNSSEC_NSEC_NODATA
;
1581 /* The RFC only specifies that we have to care for optout for NODATA for
1582 * DS records. However, children of an insecure opt-out delegation should
1583 * also be considered opt-out, rather than verified NXDOMAIN.
1584 * Note that we do not require a proof of wildcard non-existence if the
1585 * next closer domain is covered by an opt-out, as that would not provide
1586 * any additional information. */
1587 *result
= DNSSEC_NSEC_OPTOUT
;
1588 else if (no_wildcard
)
1589 *result
= DNSSEC_NSEC_NXDOMAIN
;
1591 *result
= DNSSEC_NSEC_NO_RR
;
1601 *ttl
= enclosure_rr
->ttl
;
1606 static int dnssec_nsec_wildcard_equal(DnsResourceRecord
*rr
, const char *name
) {
1607 char label
[DNS_LABEL_MAX
];
1612 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1614 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1616 if (rr
->n_skip_labels_source
!= 1)
1619 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1620 r
= dns_label_unescape(&n
, label
, sizeof(label
));
1623 if (r
!= 1 || label
[0] != '*')
1626 return dns_name_endswith(name
, n
);
1629 static int dnssec_nsec_in_path(DnsResourceRecord
*rr
, const char *name
) {
1630 const char *nn
, *common_suffix
;
1634 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1636 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1638 * A couple of examples:
1640 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1641 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1642 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1645 /* First, determine parent of next domain. */
1646 nn
= rr
->nsec
.next_domain_name
;
1647 r
= dns_name_parent(&nn
);
1651 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1652 * anything at all. */
1653 r
= dns_name_endswith(nn
, name
);
1657 /* 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. */
1658 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1662 return dns_name_endswith(name
, common_suffix
);
1665 static int dnssec_nsec_from_parent_zone(DnsResourceRecord
*rr
, const char *name
) {
1669 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1671 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1673 r
= dns_name_parent(&name
);
1677 r
= dns_name_equal(name
, DNS_RESOURCE_KEY_NAME(rr
->key
));
1681 /* DNAME, and NS without SOA is an indication for a delegation. */
1682 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_DNAME
))
1685 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) && !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1691 static int dnssec_nsec_covers(DnsResourceRecord
*rr
, const char *name
) {
1692 const char *common_suffix
, *p
;
1696 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1698 /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
1700 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1706 r
= dns_name_parent(&name
);
1712 r
= dns_name_equal(name
, common_suffix
);
1719 /* p is now the "Next Closer". */
1721 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), p
, rr
->nsec
.next_domain_name
);
1724 static int dnssec_nsec_covers_wildcard(DnsResourceRecord
*rr
, const char *name
) {
1725 const char *common_suffix
, *wc
;
1729 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1731 /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified
1732 * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as
1733 * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label.
1735 * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist
1736 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...)
1737 * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
1740 r
= dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1744 /* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */
1745 r
= dns_name_endswith(name
, common_suffix
);
1749 wc
= strjoina("*.", common_suffix
, NULL
);
1750 return dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wc
, rr
->nsec
.next_domain_name
);
1753 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1754 bool have_nsec3
= false, covering_rr_authenticated
= false, wildcard_rr_authenticated
= false;
1755 DnsResourceRecord
*rr
, *covering_rr
= NULL
, *wildcard_rr
= NULL
;
1756 DnsAnswerFlags flags
;
1763 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1765 name
= DNS_RESOURCE_KEY_NAME(key
);
1767 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1769 if (rr
->key
->class != key
->class)
1772 have_nsec3
= have_nsec3
|| (rr
->key
->type
== DNS_TYPE_NSEC3
);
1774 if (rr
->key
->type
!= DNS_TYPE_NSEC
)
1777 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1778 r
= dns_resource_record_is_synthetic(rr
);
1784 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1785 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), name
);
1789 /* If it's not a direct match, maybe it's a wild card match? */
1790 r
= dnssec_nsec_wildcard_equal(rr
, name
);
1795 if (key
->type
== DNS_TYPE_DS
) {
1796 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1797 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1798 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1801 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1802 * we got the child's NSEC. */
1803 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) &&
1804 !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1808 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1809 *result
= DNSSEC_NSEC_FOUND
;
1810 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1811 *result
= DNSSEC_NSEC_CNAME
;
1813 *result
= DNSSEC_NSEC_NODATA
;
1816 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1823 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1824 * of the NSEC RR. */
1825 r
= dnssec_nsec_in_path(rr
, name
);
1829 *result
= DNSSEC_NSEC_NODATA
;
1832 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1839 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1840 r
= dnssec_nsec_from_parent_zone(rr
, name
);
1846 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1847 r
= dnssec_nsec_covers(rr
, name
);
1850 if (r
> 0 && (!covering_rr
|| !covering_rr_authenticated
)) {
1852 covering_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1855 /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
1856 r
= dnssec_nsec_covers_wildcard(rr
, name
);
1859 if (r
> 0 && (!wildcard_rr
|| !wildcard_rr_authenticated
)) {
1861 wildcard_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1865 if (covering_rr
&& wildcard_rr
) {
1866 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1867 * proved the NXDOMAIN case. */
1868 *result
= DNSSEC_NSEC_NXDOMAIN
;
1871 *authenticated
= covering_rr_authenticated
&& wildcard_rr_authenticated
;
1873 *ttl
= MIN(covering_rr
->ttl
, wildcard_rr
->ttl
);
1878 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1880 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
1882 /* No approproate NSEC RR found, report this. */
1883 *result
= DNSSEC_NSEC_NO_RR
;
1887 static int dnssec_nsec_test_enclosed(DnsAnswer
*answer
, uint16_t type
, const char *name
, const char *zone
, bool *authenticated
) {
1888 DnsResourceRecord
*rr
;
1889 DnsAnswerFlags flags
;
1895 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
1896 * 'zone'. The 'zone' must be a suffix of the 'name'. */
1898 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1901 if (rr
->key
->type
!= type
&& type
!= DNS_TYPE_ANY
)
1904 switch (rr
->key
->type
) {
1908 /* We only care for NSEC RRs from the indicated zone */
1909 r
= dns_resource_record_is_signer(rr
, zone
);
1915 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), name
, rr
->nsec
.next_domain_name
);
1922 case DNS_TYPE_NSEC3
: {
1923 _cleanup_free_
char *hashed_domain
= NULL
, *next_hashed_domain
= NULL
;
1925 /* We only care for NSEC3 RRs from the indicated zone */
1926 r
= dns_resource_record_is_signer(rr
, zone
);
1932 r
= nsec3_is_good(rr
, NULL
);
1938 /* Format the domain we are testing with the NSEC3 RR's hash function */
1939 r
= nsec3_hashed_domain_make(
1946 if ((size_t) r
!= rr
->nsec3
.next_hashed_name_size
)
1949 /* Format the NSEC3's next hashed name as proper domain name */
1950 r
= nsec3_hashed_domain_format(
1951 rr
->nsec3
.next_hashed_name
,
1952 rr
->nsec3
.next_hashed_name_size
,
1954 &next_hashed_domain
);
1958 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), hashed_domain
, next_hashed_domain
);
1972 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1980 static int dnssec_test_positive_wildcard_nsec3(
1985 bool *authenticated
) {
1987 const char *next_closer
= NULL
;
1990 /* Run a positive NSEC3 wildcard proof. Specifically:
1992 * A proof that the the "next closer" of the generating wildcard does not exist.
1994 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
1995 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
1996 * exists for the NSEC3 RR and we are done.
1998 * 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
1999 * c.d.e.f does not exist. */
2003 r
= dns_name_parent(&name
);
2009 r
= dns_name_equal(name
, source
);
2016 return dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC3
, next_closer
, zone
, authenticated
);
2019 static int dnssec_test_positive_wildcard_nsec(
2024 bool *_authenticated
) {
2026 bool authenticated
= true;
2029 /* Run a positive NSEC wildcard proof. Specifically:
2031 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2032 * a prefix of the synthesizing source "source" in the zone "zone".
2034 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2036 * 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
2037 * have to prove that none of the following exist:
2048 _cleanup_free_
char *wc
= NULL
;
2051 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2052 * i.e between the owner name and the next name of an NSEC RR. */
2053 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, name
, zone
, &a
);
2057 authenticated
= authenticated
&& a
;
2059 /* Strip one label off */
2060 r
= dns_name_parent(&name
);
2064 /* Did we reach the source of synthesis? */
2065 r
= dns_name_equal(name
, source
);
2069 /* Successful exit */
2070 *_authenticated
= authenticated
;
2074 /* Safety check, that the source of synthesis is still our suffix */
2075 r
= dns_name_endswith(name
, source
);
2081 /* Replace the label we stripped off with an asterisk */
2082 wc
= strappend("*.", name
);
2086 /* And check if the proof holds for the asterisk name, too */
2087 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, wc
, zone
, &a
);
2091 authenticated
= authenticated
&& a
;
2092 /* In the next iteration we'll check the non-asterisk-prefixed version */
2096 int dnssec_test_positive_wildcard(
2101 bool *authenticated
) {
2108 assert(authenticated
);
2110 r
= dns_answer_contains_zone_nsec3(answer
, zone
);
2114 return dnssec_test_positive_wildcard_nsec3(answer
, name
, source
, zone
, authenticated
);
2116 return dnssec_test_positive_wildcard_nsec(answer
, name
, source
, zone
, authenticated
);
2121 int dnssec_verify_rrset(
2123 const DnsResourceKey
*key
,
2124 DnsResourceRecord
*rrsig
,
2125 DnsResourceRecord
*dnskey
,
2127 DnssecResult
*result
) {
2132 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
2137 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
2142 int dnssec_verify_rrset_search(
2144 const DnsResourceKey
*key
,
2145 DnsAnswer
*validated_dnskeys
,
2147 DnssecResult
*result
,
2148 DnsResourceRecord
**ret_rrsig
) {
2153 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
2158 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
2163 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
2168 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
2173 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
2178 int dnssec_test_positive_wildcard(
2183 bool *authenticated
) {
2190 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
2191 [DNSSEC_VALIDATED
] = "validated",
2192 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
2193 [DNSSEC_INVALID
] = "invalid",
2194 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
2195 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
2196 [DNSSEC_NO_SIGNATURE
] = "no-signature",
2197 [DNSSEC_MISSING_KEY
] = "missing-key",
2198 [DNSSEC_UNSIGNED
] = "unsigned",
2199 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
2200 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
2201 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
2203 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);
2205 static const char* const dnssec_verdict_table
[_DNSSEC_VERDICT_MAX
] = {
2206 [DNSSEC_SECURE
] = "secure",
2207 [DNSSEC_INSECURE
] = "insecure",
2208 [DNSSEC_BOGUS
] = "bogus",
2209 [DNSSEC_INDETERMINATE
] = "indeterminate",
2211 DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict
, DnssecVerdict
);