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/>.
21 #include <stdio_ext.h>
27 #include "alloc-util.h"
28 #include "dns-domain.h"
31 #include "gcrypt-util.h"
32 #include "hexdecoct.h"
33 #include "resolved-dns-dnssec.h"
34 #include "resolved-dns-packet.h"
35 #include "string-table.h"
37 #define VERIFY_RRS_MAX 256
38 #define MAX_KEY_SIZE (32*1024)
40 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
41 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
43 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
44 #define NSEC3_ITERATIONS_MAX 2500
47 * The DNSSEC Chain of trust:
49 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
50 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
51 * DS RRs are protected like normal RRs
54 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
57 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
, bool mask_revoke
) {
62 /* The algorithm from RFC 4034, Appendix B. */
65 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
67 f
= (uint32_t) dnskey
->dnskey
.flags
;
70 f
&= ~DNSKEY_FLAG_REVOKE
;
72 sum
= f
+ ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
74 p
= dnskey
->dnskey
.key
;
76 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
77 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
79 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
81 return sum
& UINT32_C(0xFFFF);
84 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
88 /* Converts the specified hostname into DNSSEC canonicalized
95 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
101 if (buffer_max
< (size_t) r
+ 2)
104 /* The DNSSEC canonical form is not clear on what to
105 * do with dots appearing in labels, the way DNS-SD
106 * does it. Refuse it for now. */
108 if (memchr(buffer
, '.', r
))
111 ascii_strlower_n(buffer
, (size_t) r
);
121 /* Not even a single label: this is the root domain name */
123 assert(buffer_max
> 2);
135 static int rr_compare(const void *a
, const void *b
) {
136 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
140 /* Let's order the RRs according to RFC 4034, Section 6.3 */
144 assert((*x
)->wire_format
);
147 assert((*y
)->wire_format
);
149 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
151 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
155 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
157 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
163 static int dnssec_rsa_verify_raw(
164 const char *hash_algorithm
,
165 const void *signature
, size_t signature_size
,
166 const void *data
, size_t data_size
,
167 const void *exponent
, size_t exponent_size
,
168 const void *modulus
, size_t modulus_size
) {
170 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
171 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
175 assert(hash_algorithm
);
177 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
183 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
189 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
195 ge
= gcry_sexp_build(&signature_sexp
,
197 "(sig-val (rsa (s %m)))",
205 ge
= gcry_sexp_build(&data_sexp
,
207 "(data (flags pkcs1) (hash %s %b))",
216 ge
= gcry_sexp_build(&public_key_sexp
,
218 "(public-key (rsa (n %m) (e %m)))",
226 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
227 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
230 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
244 gcry_sexp_release(public_key_sexp
);
246 gcry_sexp_release(signature_sexp
);
248 gcry_sexp_release(data_sexp
);
253 static int dnssec_rsa_verify(
254 const char *hash_algorithm
,
255 const void *hash
, size_t hash_size
,
256 DnsResourceRecord
*rrsig
,
257 DnsResourceRecord
*dnskey
) {
259 size_t exponent_size
, modulus_size
;
260 void *exponent
, *modulus
;
262 assert(hash_algorithm
);
264 assert(hash_size
> 0);
268 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
269 /* exponent is > 255 bytes long */
271 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
273 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
274 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
276 if (exponent_size
< 256)
279 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
282 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
283 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
286 /* exponent is <= 255 bytes long */
288 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
289 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
291 if (exponent_size
<= 0)
294 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
297 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
298 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
301 return dnssec_rsa_verify_raw(
303 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
305 exponent
, exponent_size
,
306 modulus
, modulus_size
);
309 static int dnssec_ecdsa_verify_raw(
310 const char *hash_algorithm
,
312 const void *signature_r
, size_t signature_r_size
,
313 const void *signature_s
, size_t signature_s_size
,
314 const void *data
, size_t data_size
,
315 const void *key
, size_t key_size
) {
317 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
318 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
322 assert(hash_algorithm
);
324 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
330 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
336 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
342 ge
= gcry_sexp_build(&signature_sexp
,
344 "(sig-val (ecdsa (r %m) (s %m)))",
352 ge
= gcry_sexp_build(&data_sexp
,
354 "(data (flags rfc6979) (hash %s %b))",
363 ge
= gcry_sexp_build(&public_key_sexp
,
365 "(public-key (ecc (curve %s) (q %m)))",
373 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
374 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
377 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
390 gcry_sexp_release(public_key_sexp
);
392 gcry_sexp_release(signature_sexp
);
394 gcry_sexp_release(data_sexp
);
399 static int dnssec_ecdsa_verify(
400 const char *hash_algorithm
,
402 const void *hash
, size_t hash_size
,
403 DnsResourceRecord
*rrsig
,
404 DnsResourceRecord
*dnskey
) {
415 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
417 curve
= "NIST P-256";
418 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
420 curve
= "NIST P-384";
424 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
427 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
430 q
= alloca(key_size
*2 + 1);
431 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
432 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
434 return dnssec_ecdsa_verify_raw(
437 rrsig
->rrsig
.signature
, key_size
,
438 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
443 #if GCRYPT_VERSION_NUMBER >= 0x010600
444 static int dnssec_eddsa_verify_raw(
446 const void *signature_r
, size_t signature_r_size
,
447 const void *signature_s
, size_t signature_s_size
,
448 const void *data
, size_t data_size
,
449 const void *key
, size_t key_size
) {
451 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
455 ge
= gcry_sexp_build(&signature_sexp
,
457 "(sig-val (eddsa (r %b) (s %b)))",
458 (int) signature_r_size
,
460 (int) signature_s_size
,
467 ge
= gcry_sexp_build(&data_sexp
,
469 "(data (flags eddsa) (hash-algo sha512) (value %b))",
477 ge
= gcry_sexp_build(&public_key_sexp
,
479 "(public-key (ecc (curve %s) (flags eddsa) (q %b)))",
488 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
489 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
492 log_debug("EdDSA signature check failed: %s", gpg_strerror(ge
));
498 gcry_sexp_release(public_key_sexp
);
500 gcry_sexp_release(signature_sexp
);
502 gcry_sexp_release(data_sexp
);
507 static int dnssec_eddsa_verify(
509 const void *data
, size_t data_size
,
510 DnsResourceRecord
*rrsig
,
511 DnsResourceRecord
*dnskey
) {
515 if (algorithm
== DNSSEC_ALGORITHM_ED25519
) {
521 if (dnskey
->dnskey
.key_size
!= key_size
)
524 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
527 return dnssec_eddsa_verify_raw(
529 rrsig
->rrsig
.signature
, key_size
,
530 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
532 dnskey
->dnskey
.key
, key_size
);
536 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
537 gcry_md_write(md
, &v
, sizeof(v
));
540 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
542 gcry_md_write(md
, &v
, sizeof(v
));
545 static void fwrite_uint8(FILE *fp
, uint8_t v
) {
546 fwrite(&v
, sizeof(v
), 1, fp
);
549 static void fwrite_uint16(FILE *fp
, uint16_t v
) {
551 fwrite(&v
, sizeof(v
), 1, fp
);
554 static void fwrite_uint32(FILE *fp
, uint32_t v
) {
556 fwrite(&v
, sizeof(v
), 1, fp
);
559 static int dnssec_rrsig_prepare(DnsResourceRecord
*rrsig
) {
560 int n_key_labels
, n_signer_labels
;
564 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source and
565 * .n_skip_labels_signer fields so that we can use them later on. */
568 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
570 /* Check if this RRSIG RR is already prepared */
571 if (rrsig
->n_skip_labels_source
!= (unsigned) -1)
574 if (rrsig
->rrsig
.inception
> rrsig
->rrsig
.expiration
)
577 name
= dns_resource_key_name(rrsig
->key
);
579 n_key_labels
= dns_name_count_labels(name
);
580 if (n_key_labels
< 0)
582 if (rrsig
->rrsig
.labels
> n_key_labels
)
585 n_signer_labels
= dns_name_count_labels(rrsig
->rrsig
.signer
);
586 if (n_signer_labels
< 0)
587 return n_signer_labels
;
588 if (n_signer_labels
> rrsig
->rrsig
.labels
)
591 r
= dns_name_skip(name
, n_key_labels
- n_signer_labels
, &name
);
597 /* Check if the signer is really a suffix of us */
598 r
= dns_name_equal(name
, rrsig
->rrsig
.signer
);
604 rrsig
->n_skip_labels_source
= n_key_labels
- rrsig
->rrsig
.labels
;
605 rrsig
->n_skip_labels_signer
= n_key_labels
- n_signer_labels
;
610 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
611 usec_t expiration
, inception
, skew
;
614 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
616 if (realtime
== USEC_INFINITY
)
617 realtime
= now(CLOCK_REALTIME
);
619 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
620 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
622 /* Consider inverted validity intervals as expired */
623 if (inception
> expiration
)
626 /* Permit a certain amount of clock skew of 10% of the valid
627 * time range. This takes inspiration from unbound's
629 skew
= (expiration
- inception
) / 10;
633 if (inception
< skew
)
638 if (expiration
+ skew
< expiration
)
639 expiration
= USEC_INFINITY
;
643 return realtime
< inception
|| realtime
> expiration
;
646 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
648 /* Translates a DNSSEC signature algorithm into a gcrypt
651 * Note that we implement all algorithms listed as "Must
652 * implement" and "Recommended to Implement" in RFC6944. We
653 * don't implement any algorithms that are listed as
654 * "Optional" or "Must Not Implement". Specifically, we do not
655 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
660 case DNSSEC_ALGORITHM_RSASHA1
:
661 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
664 case DNSSEC_ALGORITHM_RSASHA256
:
665 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
666 return GCRY_MD_SHA256
;
668 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
669 return GCRY_MD_SHA384
;
671 case DNSSEC_ALGORITHM_RSASHA512
:
672 return GCRY_MD_SHA512
;
679 static void dnssec_fix_rrset_ttl(
680 DnsResourceRecord
*list
[],
682 DnsResourceRecord
*rrsig
,
691 for (k
= 0; k
< n
; k
++) {
692 DnsResourceRecord
*rr
= list
[k
];
694 /* Pick the TTL as the minimum of the RR's TTL, the
695 * RR's original TTL according to the RRSIG and the
696 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
697 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
698 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
700 /* Copy over information about the signer and wildcard source of synthesis */
701 rr
->n_skip_labels_source
= rrsig
->n_skip_labels_source
;
702 rr
->n_skip_labels_signer
= rrsig
->n_skip_labels_signer
;
705 rrsig
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
708 int dnssec_verify_rrset(
710 const DnsResourceKey
*key
,
711 DnsResourceRecord
*rrsig
,
712 DnsResourceRecord
*dnskey
,
714 DnssecResult
*result
) {
716 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
717 DnsResourceRecord
**list
, *rr
;
718 const char *source
, *name
;
719 gcry_md_hd_t md
= NULL
;
723 _cleanup_free_
char *sig_data
= NULL
;
724 _cleanup_fclose_
FILE *f
= NULL
;
733 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
734 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
736 /* Verifies that the RRSet matches the specified "key" in "a",
737 * using the signature "rrsig" and the key "dnskey". It's
738 * assumed that RRSIG and DNSKEY match. */
740 r
= dnssec_rrsig_prepare(rrsig
);
742 *result
= DNSSEC_INVALID
;
748 r
= dnssec_rrsig_expired(rrsig
, realtime
);
752 *result
= DNSSEC_SIGNATURE_EXPIRED
;
756 name
= dns_resource_key_name(key
);
758 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
759 if (dns_type_apex_only(rrsig
->rrsig
.type_covered
)) {
760 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
764 *result
= DNSSEC_INVALID
;
769 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
770 if (rrsig
->rrsig
.type_covered
== DNS_TYPE_DS
) {
771 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
775 *result
= DNSSEC_INVALID
;
780 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
781 r
= dns_name_suffix(name
, rrsig
->rrsig
.labels
, &source
);
784 if (r
> 0 && !dns_type_may_wildcard(rrsig
->rrsig
.type_covered
)) {
785 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
786 *result
= DNSSEC_INVALID
;
790 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
791 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
792 r
= dns_name_startswith(name
, "*");
802 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
803 list
= newa(DnsResourceRecord
*, dns_answer_size(a
));
805 DNS_ANSWER_FOREACH(rr
, a
) {
806 r
= dns_resource_key_equal(key
, rr
->key
);
812 /* We need the wire format for ordering, and digest calculation */
813 r
= dns_resource_record_to_wire_format(rr
, true);
819 if (n
> VERIFY_RRS_MAX
)
826 /* Bring the RRs into canonical order */
827 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
829 f
= open_memstream(&sig_data
, &sig_size
);
832 __fsetlocking(f
, FSETLOCKING_BYCALLER
);
834 fwrite_uint16(f
, rrsig
->rrsig
.type_covered
);
835 fwrite_uint8(f
, rrsig
->rrsig
.algorithm
);
836 fwrite_uint8(f
, rrsig
->rrsig
.labels
);
837 fwrite_uint32(f
, rrsig
->rrsig
.original_ttl
);
838 fwrite_uint32(f
, rrsig
->rrsig
.expiration
);
839 fwrite_uint32(f
, rrsig
->rrsig
.inception
);
840 fwrite_uint16(f
, rrsig
->rrsig
.key_tag
);
842 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
845 fwrite(wire_format_name
, 1, r
, f
);
847 /* Convert the source of synthesis into wire format */
848 r
= dns_name_to_wire_format(source
, wire_format_name
, sizeof(wire_format_name
), true);
852 for (k
= 0; k
< n
; k
++) {
857 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
859 fwrite((uint8_t[]) { 1, '*'}, sizeof(uint8_t), 2, f
);
860 fwrite(wire_format_name
, 1, r
, f
);
862 fwrite_uint16(f
, rr
->key
->type
);
863 fwrite_uint16(f
, rr
->key
->class);
864 fwrite_uint32(f
, rrsig
->rrsig
.original_ttl
);
866 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
869 fwrite_uint16(f
, (uint16_t) l
);
870 fwrite(DNS_RESOURCE_RECORD_RDATA(rr
), 1, l
, f
);
873 r
= fflush_and_check(f
);
877 initialize_libgcrypt(false);
879 switch (rrsig
->rrsig
.algorithm
) {
880 #if GCRYPT_VERSION_NUMBER >= 0x010600
881 case DNSSEC_ALGORITHM_ED25519
:
884 case DNSSEC_ALGORITHM_ED25519
:
886 case DNSSEC_ALGORITHM_ED448
:
887 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
891 /* OK, the RRs are now in canonical order. Let's calculate the digest */
892 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
893 if (md_algorithm
== -EOPNOTSUPP
) {
894 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
898 if (md_algorithm
< 0) {
903 gcry_md_open(&md
, md_algorithm
, 0);
909 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
910 assert(hash_size
> 0);
912 gcry_md_write(md
, sig_data
, sig_size
);
914 hash
= gcry_md_read(md
, 0);
921 switch (rrsig
->rrsig
.algorithm
) {
923 case DNSSEC_ALGORITHM_RSASHA1
:
924 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
925 case DNSSEC_ALGORITHM_RSASHA256
:
926 case DNSSEC_ALGORITHM_RSASHA512
:
927 r
= dnssec_rsa_verify(
928 gcry_md_algo_name(md_algorithm
),
934 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
935 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
936 r
= dnssec_ecdsa_verify(
937 gcry_md_algo_name(md_algorithm
),
938 rrsig
->rrsig
.algorithm
,
943 #if GCRYPT_VERSION_NUMBER >= 0x010600
944 case DNSSEC_ALGORITHM_ED25519
:
945 r
= dnssec_eddsa_verify(
946 rrsig
->rrsig
.algorithm
,
957 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
959 dnssec_fix_rrset_ttl(list
, n
, rrsig
, realtime
);
962 *result
= DNSSEC_INVALID
;
964 *result
= DNSSEC_VALIDATED_WILDCARD
;
966 *result
= DNSSEC_VALIDATED
;
977 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
982 /* Checks if the specified DNSKEY RR matches the key used for
983 * the signature in the specified RRSIG RR */
985 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
988 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
990 if (dnskey
->key
->class != rrsig
->key
->class)
992 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
994 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
996 if (dnskey
->dnskey
.protocol
!= 3)
998 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
1001 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
1004 return dns_name_equal(dns_resource_key_name(dnskey
->key
), rrsig
->rrsig
.signer
);
1007 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
1011 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
1013 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
1015 if (rrsig
->key
->class != key
->class)
1017 if (rrsig
->rrsig
.type_covered
!= key
->type
)
1020 return dns_name_equal(dns_resource_key_name(rrsig
->key
), dns_resource_key_name(key
));
1023 int dnssec_verify_rrset_search(
1025 const DnsResourceKey
*key
,
1026 DnsAnswer
*validated_dnskeys
,
1028 DnssecResult
*result
,
1029 DnsResourceRecord
**ret_rrsig
) {
1031 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
1032 DnsResourceRecord
*rrsig
;
1038 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
1040 if (!a
|| a
->n_rrs
<= 0)
1043 /* Iterate through each RRSIG RR. */
1044 DNS_ANSWER_FOREACH(rrsig
, a
) {
1045 DnsResourceRecord
*dnskey
;
1046 DnsAnswerFlags flags
;
1048 /* Is this an RRSIG RR that applies to RRs matching our key? */
1049 r
= dnssec_key_match_rrsig(key
, rrsig
);
1057 /* Look for a matching key */
1058 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
1059 DnssecResult one_result
;
1061 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1064 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
1065 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
1071 /* Take the time here, if it isn't set yet, so
1072 * that we do all validations with the same
1074 if (realtime
== USEC_INFINITY
)
1075 realtime
= now(CLOCK_REALTIME
);
1077 /* Yay, we found a matching RRSIG with a matching
1078 * DNSKEY, awesome. Now let's verify all entries of
1079 * the RRSet against the RRSIG and DNSKEY
1082 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
1086 switch (one_result
) {
1088 case DNSSEC_VALIDATED
:
1089 case DNSSEC_VALIDATED_WILDCARD
:
1090 /* Yay, the RR has been validated,
1091 * return immediately, but fix up the expiry */
1095 *result
= one_result
;
1098 case DNSSEC_INVALID
:
1099 /* If the signature is invalid, let's try another
1100 key and/or signature. After all they
1101 key_tags and stuff are not unique, and
1102 might be shared by multiple keys. */
1103 found_invalid
= true;
1106 case DNSSEC_UNSUPPORTED_ALGORITHM
:
1107 /* If the key algorithm is
1108 unsupported, try another
1109 RRSIG/DNSKEY pair, but remember we
1110 encountered this, so that we can
1111 return a proper error when we
1112 encounter nothing better. */
1113 found_unsupported_algorithm
= true;
1116 case DNSSEC_SIGNATURE_EXPIRED
:
1117 /* If the signature is expired, try
1118 another one, but remember it, so
1119 that we can return this */
1120 found_expired_rrsig
= true;
1124 assert_not_reached("Unexpected DNSSEC validation result");
1129 if (found_expired_rrsig
)
1130 *result
= DNSSEC_SIGNATURE_EXPIRED
;
1131 else if (found_unsupported_algorithm
)
1132 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
1133 else if (found_invalid
)
1134 *result
= DNSSEC_INVALID
;
1135 else if (found_rrsig
)
1136 *result
= DNSSEC_MISSING_KEY
;
1138 *result
= DNSSEC_NO_SIGNATURE
;
1146 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
1147 DnsResourceRecord
*rr
;
1150 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
1152 DNS_ANSWER_FOREACH(rr
, a
) {
1153 r
= dnssec_key_match_rrsig(key
, rr
);
1163 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1165 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1167 switch (algorithm
) {
1169 case DNSSEC_DIGEST_SHA1
:
1170 return GCRY_MD_SHA1
;
1172 case DNSSEC_DIGEST_SHA256
:
1173 return GCRY_MD_SHA256
;
1175 case DNSSEC_DIGEST_SHA384
:
1176 return GCRY_MD_SHA384
;
1183 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1184 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
1185 gcry_md_hd_t md
= NULL
;
1187 int md_algorithm
, r
;
1193 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1195 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1197 if (ds
->key
->type
!= DNS_TYPE_DS
)
1199 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1200 return -EKEYREJECTED
;
1201 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1202 return -EKEYREJECTED
;
1203 if (dnskey
->dnskey
.protocol
!= 3)
1204 return -EKEYREJECTED
;
1206 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1208 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1211 initialize_libgcrypt(false);
1213 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1214 if (md_algorithm
< 0)
1215 return md_algorithm
;
1217 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1218 assert(hash_size
> 0);
1220 if (ds
->ds
.digest_size
!= hash_size
)
1223 r
= dnssec_canonicalize(dns_resource_key_name(dnskey
->key
), owner_name
, sizeof(owner_name
));
1227 gcry_md_open(&md
, md_algorithm
, 0);
1231 gcry_md_write(md
, owner_name
, r
);
1233 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1235 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1236 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1237 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1238 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1240 result
= gcry_md_read(md
, 0);
1246 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1253 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1254 DnsResourceRecord
*ds
;
1255 DnsAnswerFlags flags
;
1260 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1263 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1265 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1268 if (ds
->key
->type
!= DNS_TYPE_DS
)
1270 if (ds
->key
->class != dnskey
->key
->class)
1273 r
= dns_name_equal(dns_resource_key_name(dnskey
->key
), dns_resource_key_name(ds
->key
));
1279 r
= dnssec_verify_dnskey_by_ds(dnskey
, ds
, false);
1280 if (IN_SET(r
, -EKEYREJECTED
, -EOPNOTSUPP
))
1281 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1291 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1293 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1295 switch (algorithm
) {
1297 case NSEC3_ALGORITHM_SHA1
:
1298 return GCRY_MD_SHA1
;
1305 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1306 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1307 gcry_md_hd_t md
= NULL
;
1318 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1321 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1322 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1326 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1330 initialize_libgcrypt(false);
1332 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1333 assert(hash_size
> 0);
1335 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1338 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1342 gcry_md_open(&md
, algorithm
, 0);
1346 gcry_md_write(md
, wire_format
, r
);
1347 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1349 result
= gcry_md_read(md
, 0);
1355 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1356 uint8_t tmp
[hash_size
];
1357 memcpy(tmp
, result
, hash_size
);
1360 gcry_md_write(md
, tmp
, hash_size
);
1361 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1363 result
= gcry_md_read(md
, 0);
1370 memcpy(ret
, result
, hash_size
);
1371 r
= (int) hash_size
;
1378 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1384 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1387 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1388 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1391 /* Ignore NSEC3 RRs whose algorithm we don't know */
1392 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1394 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1395 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1398 /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
1399 * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
1400 if (!IN_SET(rr
->n_skip_labels_source
, 0, (unsigned) -1))
1402 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1403 if (!IN_SET(rr
->n_skip_labels_signer
, 1, (unsigned) -1))
1409 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1411 if (nsec3
== rr
) /* Shortcut */
1414 if (rr
->key
->class != nsec3
->key
->class)
1416 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1418 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1420 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1422 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1425 a
= dns_resource_key_name(rr
->key
);
1426 r
= dns_name_parent(&a
); /* strip off hash */
1432 b
= dns_resource_key_name(nsec3
->key
);
1433 r
= dns_name_parent(&b
); /* strip off hash */
1439 /* Make sure both have the same parent */
1440 return dns_name_equal(a
, b
);
1443 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1444 _cleanup_free_
char *l
= NULL
;
1448 assert(hashed_size
> 0);
1452 l
= base32hexmem(hashed
, hashed_size
, false);
1456 j
= strjoin(l
, ".", zone
);
1461 return (int) hashed_size
;
1464 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1465 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1473 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1474 if (hashed_size
< 0)
1477 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1480 /* See RFC 5155, Section 8
1481 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1482 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1483 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1484 * matches the wildcard domain.
1486 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1487 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1488 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1489 * to conclude anything we indicate this by returning NO_RR. */
1490 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1491 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1492 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1493 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1494 DnsAnswerFlags flags
;
1496 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1501 /* First step, find the zone name and the NSEC3 parameters of the zone.
1502 * it is sufficient to look for the longest common suffix we find with
1503 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1504 * records from a given zone in a response must use the same
1506 zone
= dns_resource_key_name(key
);
1508 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1509 r
= nsec3_is_good(zone_rr
, NULL
);
1515 r
= dns_name_equal_skip(dns_resource_key_name(zone_rr
->key
), 1, zone
);
1522 /* Strip one label from the front */
1523 r
= dns_name_parent(&zone
);
1530 *result
= DNSSEC_NSEC_NO_RR
;
1534 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1535 p
= dns_resource_key_name(key
);
1537 _cleanup_free_
char *hashed_domain
= NULL
;
1539 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1540 if (hashed_size
== -EOPNOTSUPP
) {
1541 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1544 if (hashed_size
< 0)
1547 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1549 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1555 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1558 r
= dns_name_equal(dns_resource_key_name(enclosure_rr
->key
), hashed_domain
);
1562 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1563 goto found_closest_encloser
;
1567 /* We didn't find the closest encloser with this name,
1568 * but let's remember this domain name, it might be
1569 * the next closer name */
1573 /* Strip one label from the front */
1574 r
= dns_name_parent(&p
);
1581 *result
= DNSSEC_NSEC_NO_RR
;
1584 found_closest_encloser
:
1585 /* We found a closest encloser in 'p'; next closer is 'pp' */
1588 /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR
1589 * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are
1590 * appropriately set. */
1592 if (key
->type
== DNS_TYPE_DS
) {
1593 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1596 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1597 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1601 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1602 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1603 *result
= DNSSEC_NSEC_FOUND
;
1604 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1605 *result
= DNSSEC_NSEC_CNAME
;
1607 *result
= DNSSEC_NSEC_NODATA
;
1612 *ttl
= enclosure_rr
->ttl
;
1617 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1618 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1621 /* Ensure that this data is from the delegated domain
1622 * (i.e. originates from the "lower" DNS server), and isn't
1623 * just glue records (i.e. doesn't originate from the "upper"
1625 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1626 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1629 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1631 wildcard
= strjoina("*.", p
);
1632 r
= nsec3_hashed_domain_make(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1635 if (r
!= hashed_size
)
1638 r
= nsec3_hashed_domain_make(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1641 if (r
!= hashed_size
)
1644 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1645 _cleanup_free_
char *next_hashed_domain
= NULL
;
1647 r
= nsec3_is_good(rr
, zone_rr
);
1653 r
= nsec3_hashed_domain_format(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, zone
, &next_hashed_domain
);
1657 r
= dns_name_between(dns_resource_key_name(rr
->key
), next_closer_domain
, next_hashed_domain
);
1661 if (rr
->nsec3
.flags
& 1)
1664 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1669 r
= dns_name_equal(dns_resource_key_name(rr
->key
), wildcard_domain
);
1673 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1678 r
= dns_name_between(dns_resource_key_name(rr
->key
), wildcard_domain
, next_hashed_domain
);
1682 if (rr
->nsec3
.flags
& 1)
1683 /* This only makes sense if we have a wildcard delegation, which is
1684 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1685 * this not happening, so hence cannot simply conclude NXDOMAIN as
1689 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1695 if (wildcard_rr
&& no_wildcard
)
1699 *result
= DNSSEC_NSEC_NO_RR
;
1704 /* A wildcard exists that matches our query. */
1706 /* This is not specified in any RFC to the best of my knowledge, but
1707 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1708 * it means that we cannot prove that the source of synthesis is
1709 * correct, as there may be a closer match. */
1710 *result
= DNSSEC_NSEC_OPTOUT
;
1711 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1712 *result
= DNSSEC_NSEC_FOUND
;
1713 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1714 *result
= DNSSEC_NSEC_CNAME
;
1716 *result
= DNSSEC_NSEC_NODATA
;
1719 /* The RFC only specifies that we have to care for optout for NODATA for
1720 * DS records. However, children of an insecure opt-out delegation should
1721 * also be considered opt-out, rather than verified NXDOMAIN.
1722 * Note that we do not require a proof of wildcard non-existence if the
1723 * next closer domain is covered by an opt-out, as that would not provide
1724 * any additional information. */
1725 *result
= DNSSEC_NSEC_OPTOUT
;
1726 else if (no_wildcard
)
1727 *result
= DNSSEC_NSEC_NXDOMAIN
;
1729 *result
= DNSSEC_NSEC_NO_RR
;
1739 *ttl
= enclosure_rr
->ttl
;
1744 static int dnssec_nsec_wildcard_equal(DnsResourceRecord
*rr
, const char *name
) {
1745 char label
[DNS_LABEL_MAX
];
1750 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1752 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1754 if (rr
->n_skip_labels_source
!= 1)
1757 n
= dns_resource_key_name(rr
->key
);
1758 r
= dns_label_unescape(&n
, label
, sizeof(label
));
1761 if (r
!= 1 || label
[0] != '*')
1764 return dns_name_endswith(name
, n
);
1767 static int dnssec_nsec_in_path(DnsResourceRecord
*rr
, const char *name
) {
1768 const char *nn
, *common_suffix
;
1772 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1774 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1776 * A couple of examples:
1778 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1779 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1780 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1783 /* First, determine parent of next domain. */
1784 nn
= rr
->nsec
.next_domain_name
;
1785 r
= dns_name_parent(&nn
);
1789 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1790 * anything at all. */
1791 r
= dns_name_endswith(nn
, name
);
1795 /* 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. */
1796 r
= dns_name_common_suffix(dns_resource_key_name(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1800 return dns_name_endswith(name
, common_suffix
);
1803 static int dnssec_nsec_from_parent_zone(DnsResourceRecord
*rr
, const char *name
) {
1807 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1809 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1811 r
= dns_name_parent(&name
);
1815 r
= dns_name_equal(name
, dns_resource_key_name(rr
->key
));
1819 /* DNAME, and NS without SOA is an indication for a delegation. */
1820 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_DNAME
))
1823 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) && !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1829 static int dnssec_nsec_covers(DnsResourceRecord
*rr
, const char *name
) {
1830 const char *common_suffix
, *p
;
1834 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1836 /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
1838 r
= dns_name_common_suffix(dns_resource_key_name(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1844 r
= dns_name_parent(&name
);
1850 r
= dns_name_equal(name
, common_suffix
);
1857 /* p is now the "Next Closer". */
1859 return dns_name_between(dns_resource_key_name(rr
->key
), p
, rr
->nsec
.next_domain_name
);
1862 static int dnssec_nsec_covers_wildcard(DnsResourceRecord
*rr
, const char *name
) {
1863 _cleanup_free_
char *wc
= NULL
;
1864 const char *common_suffix
;
1868 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1870 /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified
1871 * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as
1872 * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label.
1874 * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist
1875 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...)
1876 * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
1879 r
= dns_name_common_suffix(dns_resource_key_name(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1883 /* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */
1884 r
= dns_name_endswith(name
, common_suffix
);
1888 r
= dns_name_concat("*", common_suffix
, &wc
);
1892 return dns_name_between(dns_resource_key_name(rr
->key
), wc
, rr
->nsec
.next_domain_name
);
1895 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1896 bool have_nsec3
= false, covering_rr_authenticated
= false, wildcard_rr_authenticated
= false;
1897 DnsResourceRecord
*rr
, *covering_rr
= NULL
, *wildcard_rr
= NULL
;
1898 DnsAnswerFlags flags
;
1905 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1907 name
= dns_resource_key_name(key
);
1909 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1911 if (rr
->key
->class != key
->class)
1914 have_nsec3
= have_nsec3
|| (rr
->key
->type
== DNS_TYPE_NSEC3
);
1916 if (rr
->key
->type
!= DNS_TYPE_NSEC
)
1919 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1920 r
= dns_resource_record_is_synthetic(rr
);
1926 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1927 r
= dns_name_equal(dns_resource_key_name(rr
->key
), name
);
1931 /* If it's not a direct match, maybe it's a wild card match? */
1932 r
= dnssec_nsec_wildcard_equal(rr
, name
);
1937 if (key
->type
== DNS_TYPE_DS
) {
1938 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1939 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1940 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1943 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1944 * we got the child's NSEC. */
1945 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) &&
1946 !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1950 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1951 *result
= DNSSEC_NSEC_FOUND
;
1952 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1953 *result
= DNSSEC_NSEC_CNAME
;
1955 *result
= DNSSEC_NSEC_NODATA
;
1958 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1965 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1966 * of the NSEC RR. */
1967 r
= dnssec_nsec_in_path(rr
, name
);
1971 *result
= DNSSEC_NSEC_NODATA
;
1974 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1981 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1982 r
= dnssec_nsec_from_parent_zone(rr
, name
);
1988 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1989 r
= dnssec_nsec_covers(rr
, name
);
1992 if (r
> 0 && (!covering_rr
|| !covering_rr_authenticated
)) {
1994 covering_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1997 /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
1998 r
= dnssec_nsec_covers_wildcard(rr
, name
);
2001 if (r
> 0 && (!wildcard_rr
|| !wildcard_rr_authenticated
)) {
2003 wildcard_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
2007 if (covering_rr
&& wildcard_rr
) {
2008 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
2009 * proved the NXDOMAIN case. */
2010 *result
= DNSSEC_NSEC_NXDOMAIN
;
2013 *authenticated
= covering_rr_authenticated
&& wildcard_rr_authenticated
;
2015 *ttl
= MIN(covering_rr
->ttl
, wildcard_rr
->ttl
);
2020 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
2022 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
2024 /* No approproate NSEC RR found, report this. */
2025 *result
= DNSSEC_NSEC_NO_RR
;
2029 static int dnssec_nsec_test_enclosed(DnsAnswer
*answer
, uint16_t type
, const char *name
, const char *zone
, bool *authenticated
) {
2030 DnsResourceRecord
*rr
;
2031 DnsAnswerFlags flags
;
2037 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
2038 * 'zone'. The 'zone' must be a suffix of the 'name'. */
2040 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
2043 if (rr
->key
->type
!= type
&& type
!= DNS_TYPE_ANY
)
2046 switch (rr
->key
->type
) {
2050 /* We only care for NSEC RRs from the indicated zone */
2051 r
= dns_resource_record_is_signer(rr
, zone
);
2057 r
= dns_name_between(dns_resource_key_name(rr
->key
), name
, rr
->nsec
.next_domain_name
);
2064 case DNS_TYPE_NSEC3
: {
2065 _cleanup_free_
char *hashed_domain
= NULL
, *next_hashed_domain
= NULL
;
2067 /* We only care for NSEC3 RRs from the indicated zone */
2068 r
= dns_resource_record_is_signer(rr
, zone
);
2074 r
= nsec3_is_good(rr
, NULL
);
2080 /* Format the domain we are testing with the NSEC3 RR's hash function */
2081 r
= nsec3_hashed_domain_make(
2088 if ((size_t) r
!= rr
->nsec3
.next_hashed_name_size
)
2091 /* Format the NSEC3's next hashed name as proper domain name */
2092 r
= nsec3_hashed_domain_format(
2093 rr
->nsec3
.next_hashed_name
,
2094 rr
->nsec3
.next_hashed_name_size
,
2096 &next_hashed_domain
);
2100 r
= dns_name_between(dns_resource_key_name(rr
->key
), hashed_domain
, next_hashed_domain
);
2114 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
2122 static int dnssec_test_positive_wildcard_nsec3(
2127 bool *authenticated
) {
2129 const char *next_closer
= NULL
;
2132 /* Run a positive NSEC3 wildcard proof. Specifically:
2134 * A proof that the "next closer" of the generating wildcard does not exist.
2136 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
2137 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
2138 * exists for the NSEC3 RR and we are done.
2140 * 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
2141 * c.d.e.f does not exist. */
2145 r
= dns_name_parent(&name
);
2151 r
= dns_name_equal(name
, source
);
2158 return dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC3
, next_closer
, zone
, authenticated
);
2161 static int dnssec_test_positive_wildcard_nsec(
2166 bool *_authenticated
) {
2168 bool authenticated
= true;
2171 /* Run a positive NSEC wildcard proof. Specifically:
2173 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2174 * a prefix of the synthesizing source "source" in the zone "zone".
2176 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2178 * 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
2179 * have to prove that none of the following exist:
2190 _cleanup_free_
char *wc
= NULL
;
2193 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2194 * i.e between the owner name and the next name of an NSEC RR. */
2195 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, name
, zone
, &a
);
2199 authenticated
= authenticated
&& a
;
2201 /* Strip one label off */
2202 r
= dns_name_parent(&name
);
2206 /* Did we reach the source of synthesis? */
2207 r
= dns_name_equal(name
, source
);
2211 /* Successful exit */
2212 *_authenticated
= authenticated
;
2216 /* Safety check, that the source of synthesis is still our suffix */
2217 r
= dns_name_endswith(name
, source
);
2223 /* Replace the label we stripped off with an asterisk */
2224 wc
= strappend("*.", name
);
2228 /* And check if the proof holds for the asterisk name, too */
2229 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, wc
, zone
, &a
);
2233 authenticated
= authenticated
&& a
;
2234 /* In the next iteration we'll check the non-asterisk-prefixed version */
2238 int dnssec_test_positive_wildcard(
2243 bool *authenticated
) {
2250 assert(authenticated
);
2252 r
= dns_answer_contains_zone_nsec3(answer
, zone
);
2256 return dnssec_test_positive_wildcard_nsec3(answer
, name
, source
, zone
, authenticated
);
2258 return dnssec_test_positive_wildcard_nsec(answer
, name
, source
, zone
, authenticated
);
2263 int dnssec_verify_rrset(
2265 const DnsResourceKey
*key
,
2266 DnsResourceRecord
*rrsig
,
2267 DnsResourceRecord
*dnskey
,
2269 DnssecResult
*result
) {
2274 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
2279 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
2284 int dnssec_verify_rrset_search(
2286 const DnsResourceKey
*key
,
2287 DnsAnswer
*validated_dnskeys
,
2289 DnssecResult
*result
,
2290 DnsResourceRecord
**ret_rrsig
) {
2295 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
2300 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
2305 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
2310 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
2315 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
2320 int dnssec_test_positive_wildcard(
2325 bool *authenticated
) {
2332 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
2333 [DNSSEC_VALIDATED
] = "validated",
2334 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
2335 [DNSSEC_INVALID
] = "invalid",
2336 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
2337 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
2338 [DNSSEC_NO_SIGNATURE
] = "no-signature",
2339 [DNSSEC_MISSING_KEY
] = "missing-key",
2340 [DNSSEC_UNSIGNED
] = "unsigned",
2341 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
2342 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
2343 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
2345 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);
2347 static const char* const dnssec_verdict_table
[_DNSSEC_VERDICT_MAX
] = {
2348 [DNSSEC_SECURE
] = "secure",
2349 [DNSSEC_INSECURE
] = "insecure",
2350 [DNSSEC_BOGUS
] = "bogus",
2351 [DNSSEC_INDETERMINATE
] = "indeterminate",
2353 DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict
, DnssecVerdict
);