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 _cleanup_(gcry_md_closep
) 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
;
890 /* OK, the RRs are now in canonical order. Let's calculate the digest */
891 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
892 if (md_algorithm
== -EOPNOTSUPP
) {
893 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
896 if (md_algorithm
< 0)
899 gcry_md_open(&md
, md_algorithm
, 0);
903 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
904 assert(hash_size
> 0);
906 gcry_md_write(md
, sig_data
, sig_size
);
908 hash
= gcry_md_read(md
, 0);
913 switch (rrsig
->rrsig
.algorithm
) {
915 case DNSSEC_ALGORITHM_RSASHA1
:
916 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
917 case DNSSEC_ALGORITHM_RSASHA256
:
918 case DNSSEC_ALGORITHM_RSASHA512
:
919 r
= dnssec_rsa_verify(
920 gcry_md_algo_name(md_algorithm
),
926 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
927 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
928 r
= dnssec_ecdsa_verify(
929 gcry_md_algo_name(md_algorithm
),
930 rrsig
->rrsig
.algorithm
,
935 #if GCRYPT_VERSION_NUMBER >= 0x010600
936 case DNSSEC_ALGORITHM_ED25519
:
937 r
= dnssec_eddsa_verify(
938 rrsig
->rrsig
.algorithm
,
948 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
950 dnssec_fix_rrset_ttl(list
, n
, rrsig
, realtime
);
953 *result
= DNSSEC_INVALID
;
955 *result
= DNSSEC_VALIDATED_WILDCARD
;
957 *result
= DNSSEC_VALIDATED
;
962 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
967 /* Checks if the specified DNSKEY RR matches the key used for
968 * the signature in the specified RRSIG RR */
970 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
973 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
975 if (dnskey
->key
->class != rrsig
->key
->class)
977 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
979 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
981 if (dnskey
->dnskey
.protocol
!= 3)
983 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
986 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
989 return dns_name_equal(dns_resource_key_name(dnskey
->key
), rrsig
->rrsig
.signer
);
992 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
996 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
998 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
1000 if (rrsig
->key
->class != key
->class)
1002 if (rrsig
->rrsig
.type_covered
!= key
->type
)
1005 return dns_name_equal(dns_resource_key_name(rrsig
->key
), dns_resource_key_name(key
));
1008 int dnssec_verify_rrset_search(
1010 const DnsResourceKey
*key
,
1011 DnsAnswer
*validated_dnskeys
,
1013 DnssecResult
*result
,
1014 DnsResourceRecord
**ret_rrsig
) {
1016 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
1017 DnsResourceRecord
*rrsig
;
1023 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
1025 if (!a
|| a
->n_rrs
<= 0)
1028 /* Iterate through each RRSIG RR. */
1029 DNS_ANSWER_FOREACH(rrsig
, a
) {
1030 DnsResourceRecord
*dnskey
;
1031 DnsAnswerFlags flags
;
1033 /* Is this an RRSIG RR that applies to RRs matching our key? */
1034 r
= dnssec_key_match_rrsig(key
, rrsig
);
1042 /* Look for a matching key */
1043 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
1044 DnssecResult one_result
;
1046 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1049 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
1050 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
1056 /* Take the time here, if it isn't set yet, so
1057 * that we do all validations with the same
1059 if (realtime
== USEC_INFINITY
)
1060 realtime
= now(CLOCK_REALTIME
);
1062 /* Yay, we found a matching RRSIG with a matching
1063 * DNSKEY, awesome. Now let's verify all entries of
1064 * the RRSet against the RRSIG and DNSKEY
1067 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
1071 switch (one_result
) {
1073 case DNSSEC_VALIDATED
:
1074 case DNSSEC_VALIDATED_WILDCARD
:
1075 /* Yay, the RR has been validated,
1076 * return immediately, but fix up the expiry */
1080 *result
= one_result
;
1083 case DNSSEC_INVALID
:
1084 /* If the signature is invalid, let's try another
1085 key and/or signature. After all they
1086 key_tags and stuff are not unique, and
1087 might be shared by multiple keys. */
1088 found_invalid
= true;
1091 case DNSSEC_UNSUPPORTED_ALGORITHM
:
1092 /* If the key algorithm is
1093 unsupported, try another
1094 RRSIG/DNSKEY pair, but remember we
1095 encountered this, so that we can
1096 return a proper error when we
1097 encounter nothing better. */
1098 found_unsupported_algorithm
= true;
1101 case DNSSEC_SIGNATURE_EXPIRED
:
1102 /* If the signature is expired, try
1103 another one, but remember it, so
1104 that we can return this */
1105 found_expired_rrsig
= true;
1109 assert_not_reached("Unexpected DNSSEC validation result");
1114 if (found_expired_rrsig
)
1115 *result
= DNSSEC_SIGNATURE_EXPIRED
;
1116 else if (found_unsupported_algorithm
)
1117 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
1118 else if (found_invalid
)
1119 *result
= DNSSEC_INVALID
;
1120 else if (found_rrsig
)
1121 *result
= DNSSEC_MISSING_KEY
;
1123 *result
= DNSSEC_NO_SIGNATURE
;
1131 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
1132 DnsResourceRecord
*rr
;
1135 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
1137 DNS_ANSWER_FOREACH(rr
, a
) {
1138 r
= dnssec_key_match_rrsig(key
, rr
);
1148 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1150 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1152 switch (algorithm
) {
1154 case DNSSEC_DIGEST_SHA1
:
1155 return GCRY_MD_SHA1
;
1157 case DNSSEC_DIGEST_SHA256
:
1158 return GCRY_MD_SHA256
;
1160 case DNSSEC_DIGEST_SHA384
:
1161 return GCRY_MD_SHA384
;
1168 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1169 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
1170 _cleanup_(gcry_md_closep
) gcry_md_hd_t md
= NULL
;
1172 int md_algorithm
, r
;
1178 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1180 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1182 if (ds
->key
->type
!= DNS_TYPE_DS
)
1184 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1185 return -EKEYREJECTED
;
1186 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1187 return -EKEYREJECTED
;
1188 if (dnskey
->dnskey
.protocol
!= 3)
1189 return -EKEYREJECTED
;
1191 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1193 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1196 initialize_libgcrypt(false);
1198 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1199 if (md_algorithm
< 0)
1200 return md_algorithm
;
1202 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1203 assert(hash_size
> 0);
1205 if (ds
->ds
.digest_size
!= hash_size
)
1208 r
= dnssec_canonicalize(dns_resource_key_name(dnskey
->key
), owner_name
, sizeof(owner_name
));
1212 gcry_md_open(&md
, md_algorithm
, 0);
1216 gcry_md_write(md
, owner_name
, r
);
1218 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1220 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1221 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1222 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1223 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1225 result
= gcry_md_read(md
, 0);
1229 return memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1232 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1233 DnsResourceRecord
*ds
;
1234 DnsAnswerFlags flags
;
1239 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1242 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1244 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1247 if (ds
->key
->type
!= DNS_TYPE_DS
)
1249 if (ds
->key
->class != dnskey
->key
->class)
1252 r
= dns_name_equal(dns_resource_key_name(dnskey
->key
), dns_resource_key_name(ds
->key
));
1258 r
= dnssec_verify_dnskey_by_ds(dnskey
, ds
, false);
1259 if (IN_SET(r
, -EKEYREJECTED
, -EOPNOTSUPP
))
1260 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1270 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1272 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1274 switch (algorithm
) {
1276 case NSEC3_ALGORITHM_SHA1
:
1277 return GCRY_MD_SHA1
;
1284 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1285 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1286 gcry_md_hd_t md
= NULL
;
1297 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1300 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1301 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1305 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1309 initialize_libgcrypt(false);
1311 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1312 assert(hash_size
> 0);
1314 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1317 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1321 gcry_md_open(&md
, algorithm
, 0);
1325 gcry_md_write(md
, wire_format
, r
);
1326 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1328 result
= gcry_md_read(md
, 0);
1334 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1335 uint8_t tmp
[hash_size
];
1336 memcpy(tmp
, result
, hash_size
);
1339 gcry_md_write(md
, tmp
, hash_size
);
1340 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1342 result
= gcry_md_read(md
, 0);
1349 memcpy(ret
, result
, hash_size
);
1350 r
= (int) hash_size
;
1357 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1363 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1366 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1367 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1370 /* Ignore NSEC3 RRs whose algorithm we don't know */
1371 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1373 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1374 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1377 /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
1378 * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
1379 if (!IN_SET(rr
->n_skip_labels_source
, 0, (unsigned) -1))
1381 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1382 if (!IN_SET(rr
->n_skip_labels_signer
, 1, (unsigned) -1))
1388 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1390 if (nsec3
== rr
) /* Shortcut */
1393 if (rr
->key
->class != nsec3
->key
->class)
1395 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1397 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1399 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1401 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1404 a
= dns_resource_key_name(rr
->key
);
1405 r
= dns_name_parent(&a
); /* strip off hash */
1411 b
= dns_resource_key_name(nsec3
->key
);
1412 r
= dns_name_parent(&b
); /* strip off hash */
1418 /* Make sure both have the same parent */
1419 return dns_name_equal(a
, b
);
1422 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1423 _cleanup_free_
char *l
= NULL
;
1427 assert(hashed_size
> 0);
1431 l
= base32hexmem(hashed
, hashed_size
, false);
1435 j
= strjoin(l
, ".", zone
);
1440 return (int) hashed_size
;
1443 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1444 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1452 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1453 if (hashed_size
< 0)
1456 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1459 /* See RFC 5155, Section 8
1460 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1461 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1462 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1463 * matches the wildcard domain.
1465 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1466 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1467 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1468 * to conclude anything we indicate this by returning NO_RR. */
1469 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1470 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1471 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1472 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1473 DnsAnswerFlags flags
;
1475 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1480 /* First step, find the zone name and the NSEC3 parameters of the zone.
1481 * it is sufficient to look for the longest common suffix we find with
1482 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1483 * records from a given zone in a response must use the same
1485 zone
= dns_resource_key_name(key
);
1487 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1488 r
= nsec3_is_good(zone_rr
, NULL
);
1494 r
= dns_name_equal_skip(dns_resource_key_name(zone_rr
->key
), 1, zone
);
1501 /* Strip one label from the front */
1502 r
= dns_name_parent(&zone
);
1509 *result
= DNSSEC_NSEC_NO_RR
;
1513 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1514 p
= dns_resource_key_name(key
);
1516 _cleanup_free_
char *hashed_domain
= NULL
;
1518 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1519 if (hashed_size
== -EOPNOTSUPP
) {
1520 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1523 if (hashed_size
< 0)
1526 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1528 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1534 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1537 r
= dns_name_equal(dns_resource_key_name(enclosure_rr
->key
), hashed_domain
);
1541 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1542 goto found_closest_encloser
;
1546 /* We didn't find the closest encloser with this name,
1547 * but let's remember this domain name, it might be
1548 * the next closer name */
1552 /* Strip one label from the front */
1553 r
= dns_name_parent(&p
);
1560 *result
= DNSSEC_NSEC_NO_RR
;
1563 found_closest_encloser
:
1564 /* We found a closest encloser in 'p'; next closer is 'pp' */
1567 /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR
1568 * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are
1569 * appropriately set. */
1571 if (key
->type
== DNS_TYPE_DS
) {
1572 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1575 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1576 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1580 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1581 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1582 *result
= DNSSEC_NSEC_FOUND
;
1583 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1584 *result
= DNSSEC_NSEC_CNAME
;
1586 *result
= DNSSEC_NSEC_NODATA
;
1591 *ttl
= enclosure_rr
->ttl
;
1596 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1597 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1600 /* Ensure that this data is from the delegated domain
1601 * (i.e. originates from the "lower" DNS server), and isn't
1602 * just glue records (i.e. doesn't originate from the "upper"
1604 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1605 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1608 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1610 wildcard
= strjoina("*.", p
);
1611 r
= nsec3_hashed_domain_make(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1614 if (r
!= hashed_size
)
1617 r
= nsec3_hashed_domain_make(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1620 if (r
!= hashed_size
)
1623 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1624 _cleanup_free_
char *next_hashed_domain
= NULL
;
1626 r
= nsec3_is_good(rr
, zone_rr
);
1632 r
= nsec3_hashed_domain_format(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, zone
, &next_hashed_domain
);
1636 r
= dns_name_between(dns_resource_key_name(rr
->key
), next_closer_domain
, next_hashed_domain
);
1640 if (rr
->nsec3
.flags
& 1)
1643 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1648 r
= dns_name_equal(dns_resource_key_name(rr
->key
), wildcard_domain
);
1652 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1657 r
= dns_name_between(dns_resource_key_name(rr
->key
), wildcard_domain
, next_hashed_domain
);
1661 if (rr
->nsec3
.flags
& 1)
1662 /* This only makes sense if we have a wildcard delegation, which is
1663 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1664 * this not happening, so hence cannot simply conclude NXDOMAIN as
1668 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1674 if (wildcard_rr
&& no_wildcard
)
1678 *result
= DNSSEC_NSEC_NO_RR
;
1683 /* A wildcard exists that matches our query. */
1685 /* This is not specified in any RFC to the best of my knowledge, but
1686 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1687 * it means that we cannot prove that the source of synthesis is
1688 * correct, as there may be a closer match. */
1689 *result
= DNSSEC_NSEC_OPTOUT
;
1690 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1691 *result
= DNSSEC_NSEC_FOUND
;
1692 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1693 *result
= DNSSEC_NSEC_CNAME
;
1695 *result
= DNSSEC_NSEC_NODATA
;
1698 /* The RFC only specifies that we have to care for optout for NODATA for
1699 * DS records. However, children of an insecure opt-out delegation should
1700 * also be considered opt-out, rather than verified NXDOMAIN.
1701 * Note that we do not require a proof of wildcard non-existence if the
1702 * next closer domain is covered by an opt-out, as that would not provide
1703 * any additional information. */
1704 *result
= DNSSEC_NSEC_OPTOUT
;
1705 else if (no_wildcard
)
1706 *result
= DNSSEC_NSEC_NXDOMAIN
;
1708 *result
= DNSSEC_NSEC_NO_RR
;
1718 *ttl
= enclosure_rr
->ttl
;
1723 static int dnssec_nsec_wildcard_equal(DnsResourceRecord
*rr
, const char *name
) {
1724 char label
[DNS_LABEL_MAX
];
1729 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1731 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1733 if (rr
->n_skip_labels_source
!= 1)
1736 n
= dns_resource_key_name(rr
->key
);
1737 r
= dns_label_unescape(&n
, label
, sizeof(label
));
1740 if (r
!= 1 || label
[0] != '*')
1743 return dns_name_endswith(name
, n
);
1746 static int dnssec_nsec_in_path(DnsResourceRecord
*rr
, const char *name
) {
1747 const char *nn
, *common_suffix
;
1751 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1753 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1755 * A couple of examples:
1757 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1758 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1759 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1762 /* First, determine parent of next domain. */
1763 nn
= rr
->nsec
.next_domain_name
;
1764 r
= dns_name_parent(&nn
);
1768 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1769 * anything at all. */
1770 r
= dns_name_endswith(nn
, name
);
1774 /* 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. */
1775 r
= dns_name_common_suffix(dns_resource_key_name(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1779 return dns_name_endswith(name
, common_suffix
);
1782 static int dnssec_nsec_from_parent_zone(DnsResourceRecord
*rr
, const char *name
) {
1786 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1788 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1790 r
= dns_name_parent(&name
);
1794 r
= dns_name_equal(name
, dns_resource_key_name(rr
->key
));
1798 /* DNAME, and NS without SOA is an indication for a delegation. */
1799 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_DNAME
))
1802 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) && !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1808 static int dnssec_nsec_covers(DnsResourceRecord
*rr
, const char *name
) {
1809 const char *common_suffix
, *p
;
1813 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1815 /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
1817 r
= dns_name_common_suffix(dns_resource_key_name(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1823 r
= dns_name_parent(&name
);
1829 r
= dns_name_equal(name
, common_suffix
);
1836 /* p is now the "Next Closer". */
1838 return dns_name_between(dns_resource_key_name(rr
->key
), p
, rr
->nsec
.next_domain_name
);
1841 static int dnssec_nsec_covers_wildcard(DnsResourceRecord
*rr
, const char *name
) {
1842 _cleanup_free_
char *wc
= NULL
;
1843 const char *common_suffix
;
1847 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1849 /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified
1850 * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as
1851 * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label.
1853 * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist
1854 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...)
1855 * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
1858 r
= dns_name_common_suffix(dns_resource_key_name(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1862 /* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */
1863 r
= dns_name_endswith(name
, common_suffix
);
1867 r
= dns_name_concat("*", common_suffix
, &wc
);
1871 return dns_name_between(dns_resource_key_name(rr
->key
), wc
, rr
->nsec
.next_domain_name
);
1874 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1875 bool have_nsec3
= false, covering_rr_authenticated
= false, wildcard_rr_authenticated
= false;
1876 DnsResourceRecord
*rr
, *covering_rr
= NULL
, *wildcard_rr
= NULL
;
1877 DnsAnswerFlags flags
;
1884 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1886 name
= dns_resource_key_name(key
);
1888 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1890 if (rr
->key
->class != key
->class)
1893 have_nsec3
= have_nsec3
|| (rr
->key
->type
== DNS_TYPE_NSEC3
);
1895 if (rr
->key
->type
!= DNS_TYPE_NSEC
)
1898 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1899 r
= dns_resource_record_is_synthetic(rr
);
1905 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1906 r
= dns_name_equal(dns_resource_key_name(rr
->key
), name
);
1910 /* If it's not a direct match, maybe it's a wild card match? */
1911 r
= dnssec_nsec_wildcard_equal(rr
, name
);
1916 if (key
->type
== DNS_TYPE_DS
) {
1917 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1918 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1919 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1922 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1923 * we got the child's NSEC. */
1924 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) &&
1925 !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1929 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1930 *result
= DNSSEC_NSEC_FOUND
;
1931 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1932 *result
= DNSSEC_NSEC_CNAME
;
1934 *result
= DNSSEC_NSEC_NODATA
;
1937 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1944 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1945 * of the NSEC RR. */
1946 r
= dnssec_nsec_in_path(rr
, name
);
1950 *result
= DNSSEC_NSEC_NODATA
;
1953 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1960 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1961 r
= dnssec_nsec_from_parent_zone(rr
, name
);
1967 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1968 r
= dnssec_nsec_covers(rr
, name
);
1971 if (r
> 0 && (!covering_rr
|| !covering_rr_authenticated
)) {
1973 covering_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1976 /* Check if this NSEC RR proves the absence of a wildcard RR under this name */
1977 r
= dnssec_nsec_covers_wildcard(rr
, name
);
1980 if (r
> 0 && (!wildcard_rr
|| !wildcard_rr_authenticated
)) {
1982 wildcard_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1986 if (covering_rr
&& wildcard_rr
) {
1987 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1988 * proved the NXDOMAIN case. */
1989 *result
= DNSSEC_NSEC_NXDOMAIN
;
1992 *authenticated
= covering_rr_authenticated
&& wildcard_rr_authenticated
;
1994 *ttl
= MIN(covering_rr
->ttl
, wildcard_rr
->ttl
);
1999 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
2001 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
2003 /* No approproate NSEC RR found, report this. */
2004 *result
= DNSSEC_NSEC_NO_RR
;
2008 static int dnssec_nsec_test_enclosed(DnsAnswer
*answer
, uint16_t type
, const char *name
, const char *zone
, bool *authenticated
) {
2009 DnsResourceRecord
*rr
;
2010 DnsAnswerFlags flags
;
2016 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
2017 * 'zone'. The 'zone' must be a suffix of the 'name'. */
2019 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
2022 if (rr
->key
->type
!= type
&& type
!= DNS_TYPE_ANY
)
2025 switch (rr
->key
->type
) {
2029 /* We only care for NSEC RRs from the indicated zone */
2030 r
= dns_resource_record_is_signer(rr
, zone
);
2036 r
= dns_name_between(dns_resource_key_name(rr
->key
), name
, rr
->nsec
.next_domain_name
);
2043 case DNS_TYPE_NSEC3
: {
2044 _cleanup_free_
char *hashed_domain
= NULL
, *next_hashed_domain
= NULL
;
2046 /* We only care for NSEC3 RRs from the indicated zone */
2047 r
= dns_resource_record_is_signer(rr
, zone
);
2053 r
= nsec3_is_good(rr
, NULL
);
2059 /* Format the domain we are testing with the NSEC3 RR's hash function */
2060 r
= nsec3_hashed_domain_make(
2067 if ((size_t) r
!= rr
->nsec3
.next_hashed_name_size
)
2070 /* Format the NSEC3's next hashed name as proper domain name */
2071 r
= nsec3_hashed_domain_format(
2072 rr
->nsec3
.next_hashed_name
,
2073 rr
->nsec3
.next_hashed_name_size
,
2075 &next_hashed_domain
);
2079 r
= dns_name_between(dns_resource_key_name(rr
->key
), hashed_domain
, next_hashed_domain
);
2093 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
2101 static int dnssec_test_positive_wildcard_nsec3(
2106 bool *authenticated
) {
2108 const char *next_closer
= NULL
;
2111 /* Run a positive NSEC3 wildcard proof. Specifically:
2113 * A proof that the "next closer" of the generating wildcard does not exist.
2115 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
2116 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
2117 * exists for the NSEC3 RR and we are done.
2119 * 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
2120 * c.d.e.f does not exist. */
2124 r
= dns_name_parent(&name
);
2130 r
= dns_name_equal(name
, source
);
2137 return dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC3
, next_closer
, zone
, authenticated
);
2140 static int dnssec_test_positive_wildcard_nsec(
2145 bool *_authenticated
) {
2147 bool authenticated
= true;
2150 /* Run a positive NSEC wildcard proof. Specifically:
2152 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2153 * a prefix of the synthesizing source "source" in the zone "zone".
2155 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2157 * 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
2158 * have to prove that none of the following exist:
2169 _cleanup_free_
char *wc
= NULL
;
2172 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2173 * i.e between the owner name and the next name of an NSEC RR. */
2174 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, name
, zone
, &a
);
2178 authenticated
= authenticated
&& a
;
2180 /* Strip one label off */
2181 r
= dns_name_parent(&name
);
2185 /* Did we reach the source of synthesis? */
2186 r
= dns_name_equal(name
, source
);
2190 /* Successful exit */
2191 *_authenticated
= authenticated
;
2195 /* Safety check, that the source of synthesis is still our suffix */
2196 r
= dns_name_endswith(name
, source
);
2202 /* Replace the label we stripped off with an asterisk */
2203 wc
= strappend("*.", name
);
2207 /* And check if the proof holds for the asterisk name, too */
2208 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, wc
, zone
, &a
);
2212 authenticated
= authenticated
&& a
;
2213 /* In the next iteration we'll check the non-asterisk-prefixed version */
2217 int dnssec_test_positive_wildcard(
2222 bool *authenticated
) {
2229 assert(authenticated
);
2231 r
= dns_answer_contains_zone_nsec3(answer
, zone
);
2235 return dnssec_test_positive_wildcard_nsec3(answer
, name
, source
, zone
, authenticated
);
2237 return dnssec_test_positive_wildcard_nsec(answer
, name
, source
, zone
, authenticated
);
2242 int dnssec_verify_rrset(
2244 const DnsResourceKey
*key
,
2245 DnsResourceRecord
*rrsig
,
2246 DnsResourceRecord
*dnskey
,
2248 DnssecResult
*result
) {
2253 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
2258 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
2263 int dnssec_verify_rrset_search(
2265 const DnsResourceKey
*key
,
2266 DnsAnswer
*validated_dnskeys
,
2268 DnssecResult
*result
,
2269 DnsResourceRecord
**ret_rrsig
) {
2274 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
2279 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
2284 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
2289 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
2294 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
2299 int dnssec_test_positive_wildcard(
2304 bool *authenticated
) {
2311 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
2312 [DNSSEC_VALIDATED
] = "validated",
2313 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
2314 [DNSSEC_INVALID
] = "invalid",
2315 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
2316 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
2317 [DNSSEC_NO_SIGNATURE
] = "no-signature",
2318 [DNSSEC_MISSING_KEY
] = "missing-key",
2319 [DNSSEC_UNSIGNED
] = "unsigned",
2320 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
2321 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
2322 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
2324 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);
2326 static const char* const dnssec_verdict_table
[_DNSSEC_VERDICT_MAX
] = {
2327 [DNSSEC_SECURE
] = "secure",
2328 [DNSSEC_INSECURE
] = "insecure",
2329 [DNSSEC_BOGUS
] = "bogus",
2330 [DNSSEC_INDETERMINATE
] = "indeterminate",
2332 DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict
, DnssecVerdict
);