1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "dns-domain.h"
7 #include "gcrypt-util.h"
9 #include "memory-util.h"
10 #include "resolved-dns-dnssec.h"
11 #include "resolved-dns-packet.h"
12 #include "sort-util.h"
13 #include "string-table.h"
15 #define VERIFY_RRS_MAX 256
16 #define MAX_KEY_SIZE (32*1024)
18 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
19 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
21 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
22 #define NSEC3_ITERATIONS_MAX 2500
25 * The DNSSEC Chain of trust:
27 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
28 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
29 * DS RRs are protected like normal RRs
32 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
35 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
, bool mask_revoke
) {
39 /* The algorithm from RFC 4034, Appendix B. */
42 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
44 f
= (uint32_t) dnskey
->dnskey
.flags
;
47 f
&= ~DNSKEY_FLAG_REVOKE
;
49 sum
= f
+ ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
51 p
= dnskey
->dnskey
.key
;
53 for (size_t i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
54 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
56 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
58 return sum
& UINT32_C(0xFFFF);
63 static int rr_compare(DnsResourceRecord
* const *a
, DnsResourceRecord
* const *b
) {
64 const DnsResourceRecord
*x
= *a
, *y
= *b
;
68 /* Let's order the RRs according to RFC 4034, Section 6.3 */
71 assert(x
->wire_format
);
73 assert(y
->wire_format
);
75 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(x
), DNS_RESOURCE_RECORD_RDATA_SIZE(y
));
77 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(x
), DNS_RESOURCE_RECORD_RDATA(y
), m
);
81 return CMP(DNS_RESOURCE_RECORD_RDATA_SIZE(x
), DNS_RESOURCE_RECORD_RDATA_SIZE(y
));
84 static int dnssec_rsa_verify_raw(
85 const char *hash_algorithm
,
86 const void *signature
, size_t signature_size
,
87 const void *data
, size_t data_size
,
88 const void *exponent
, size_t exponent_size
,
89 const void *modulus
, size_t modulus_size
) {
91 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
92 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
96 assert(hash_algorithm
);
98 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
104 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
110 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
116 ge
= gcry_sexp_build(&signature_sexp
,
118 "(sig-val (rsa (s %m)))",
126 ge
= gcry_sexp_build(&data_sexp
,
128 "(data (flags pkcs1) (hash %s %b))",
137 ge
= gcry_sexp_build(&public_key_sexp
,
139 "(public-key (rsa (n %m) (e %m)))",
147 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
148 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
151 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
165 gcry_sexp_release(public_key_sexp
);
167 gcry_sexp_release(signature_sexp
);
169 gcry_sexp_release(data_sexp
);
174 static int dnssec_rsa_verify(
175 const char *hash_algorithm
,
176 const void *hash
, size_t hash_size
,
177 DnsResourceRecord
*rrsig
,
178 DnsResourceRecord
*dnskey
) {
180 size_t exponent_size
, modulus_size
;
181 void *exponent
, *modulus
;
183 assert(hash_algorithm
);
185 assert(hash_size
> 0);
189 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
190 /* exponent is > 255 bytes long */
192 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
194 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
195 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
197 if (exponent_size
< 256)
200 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
203 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
204 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
207 /* exponent is <= 255 bytes long */
209 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
210 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
212 if (exponent_size
<= 0)
215 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
218 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
219 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
222 return dnssec_rsa_verify_raw(
224 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
226 exponent
, exponent_size
,
227 modulus
, modulus_size
);
230 static int dnssec_ecdsa_verify_raw(
231 const char *hash_algorithm
,
233 const void *signature_r
, size_t signature_r_size
,
234 const void *signature_s
, size_t signature_s_size
,
235 const void *data
, size_t data_size
,
236 const void *key
, size_t key_size
) {
238 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
239 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
243 assert(hash_algorithm
);
245 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
251 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
257 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
263 ge
= gcry_sexp_build(&signature_sexp
,
265 "(sig-val (ecdsa (r %m) (s %m)))",
273 ge
= gcry_sexp_build(&data_sexp
,
275 "(data (flags rfc6979) (hash %s %b))",
284 ge
= gcry_sexp_build(&public_key_sexp
,
286 "(public-key (ecc (curve %s) (q %m)))",
294 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
295 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
298 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
311 gcry_sexp_release(public_key_sexp
);
313 gcry_sexp_release(signature_sexp
);
315 gcry_sexp_release(data_sexp
);
320 static int dnssec_ecdsa_verify(
321 const char *hash_algorithm
,
323 const void *hash
, size_t hash_size
,
324 DnsResourceRecord
*rrsig
,
325 DnsResourceRecord
*dnskey
) {
336 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
338 curve
= "NIST P-256";
339 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
341 curve
= "NIST P-384";
345 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
348 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
351 q
= newa(uint8_t, key_size
*2 + 1);
352 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
353 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
355 return dnssec_ecdsa_verify_raw(
358 rrsig
->rrsig
.signature
, key_size
,
359 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
364 #if GCRYPT_VERSION_NUMBER >= 0x010600
365 static int dnssec_eddsa_verify_raw(
367 const void *signature_r
, size_t signature_r_size
,
368 const void *signature_s
, size_t signature_s_size
,
369 const void *data
, size_t data_size
,
370 const void *key
, size_t key_size
) {
372 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
376 ge
= gcry_sexp_build(&signature_sexp
,
378 "(sig-val (eddsa (r %b) (s %b)))",
379 (int) signature_r_size
,
381 (int) signature_s_size
,
388 ge
= gcry_sexp_build(&data_sexp
,
390 "(data (flags eddsa) (hash-algo sha512) (value %b))",
398 ge
= gcry_sexp_build(&public_key_sexp
,
400 "(public-key (ecc (curve %s) (flags eddsa) (q %b)))",
409 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
410 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
413 log_debug("EdDSA signature check failed: %s", gpg_strerror(ge
));
419 gcry_sexp_release(public_key_sexp
);
421 gcry_sexp_release(signature_sexp
);
423 gcry_sexp_release(data_sexp
);
428 static int dnssec_eddsa_verify(
430 const void *data
, size_t data_size
,
431 DnsResourceRecord
*rrsig
,
432 DnsResourceRecord
*dnskey
) {
436 if (algorithm
== DNSSEC_ALGORITHM_ED25519
) {
442 if (dnskey
->dnskey
.key_size
!= key_size
)
445 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
448 return dnssec_eddsa_verify_raw(
450 rrsig
->rrsig
.signature
, key_size
,
451 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
453 dnskey
->dnskey
.key
, key_size
);
457 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
458 gcry_md_write(md
, &v
, sizeof(v
));
461 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
463 gcry_md_write(md
, &v
, sizeof(v
));
466 static void fwrite_uint8(FILE *fp
, uint8_t v
) {
467 fwrite(&v
, sizeof(v
), 1, fp
);
470 static void fwrite_uint16(FILE *fp
, uint16_t v
) {
472 fwrite(&v
, sizeof(v
), 1, fp
);
475 static void fwrite_uint32(FILE *fp
, uint32_t v
) {
477 fwrite(&v
, sizeof(v
), 1, fp
);
480 static int dnssec_rrsig_prepare(DnsResourceRecord
*rrsig
) {
481 int n_key_labels
, n_signer_labels
;
485 /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source
486 * and .n_skip_labels_signer fields so that we can use them later on. */
489 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
491 /* Check if this RRSIG RR is already prepared */
492 if (rrsig
->n_skip_labels_source
!= UINT8_MAX
)
495 if (rrsig
->rrsig
.inception
> rrsig
->rrsig
.expiration
)
498 name
= dns_resource_key_name(rrsig
->key
);
500 n_key_labels
= dns_name_count_labels(name
);
501 if (n_key_labels
< 0)
503 if (rrsig
->rrsig
.labels
> n_key_labels
)
506 n_signer_labels
= dns_name_count_labels(rrsig
->rrsig
.signer
);
507 if (n_signer_labels
< 0)
508 return n_signer_labels
;
509 if (n_signer_labels
> rrsig
->rrsig
.labels
)
512 r
= dns_name_skip(name
, n_key_labels
- n_signer_labels
, &name
);
518 /* Check if the signer is really a suffix of us */
519 r
= dns_name_equal(name
, rrsig
->rrsig
.signer
);
525 assert(n_key_labels
< UINT8_MAX
); /* UINT8_MAX/-1 means unsigned. */
526 rrsig
->n_skip_labels_source
= n_key_labels
- rrsig
->rrsig
.labels
;
527 rrsig
->n_skip_labels_signer
= n_key_labels
- n_signer_labels
;
532 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
533 usec_t expiration
, inception
, skew
;
536 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
538 if (realtime
== USEC_INFINITY
)
539 realtime
= now(CLOCK_REALTIME
);
541 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
542 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
544 /* Consider inverted validity intervals as expired */
545 if (inception
> expiration
)
548 /* Permit a certain amount of clock skew of 10% of the valid
549 * time range. This takes inspiration from unbound's
551 skew
= (expiration
- inception
) / 10;
555 if (inception
< skew
)
560 if (expiration
+ skew
< expiration
)
561 expiration
= USEC_INFINITY
;
565 return realtime
< inception
|| realtime
> expiration
;
568 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
570 /* Translates a DNSSEC signature algorithm into a gcrypt
573 * Note that we implement all algorithms listed as "Must
574 * implement" and "Recommended to Implement" in RFC6944. We
575 * don't implement any algorithms that are listed as
576 * "Optional" or "Must Not Implement". Specifically, we do not
577 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
582 case DNSSEC_ALGORITHM_RSASHA1
:
583 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
586 case DNSSEC_ALGORITHM_RSASHA256
:
587 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
588 return GCRY_MD_SHA256
;
590 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
591 return GCRY_MD_SHA384
;
593 case DNSSEC_ALGORITHM_RSASHA512
:
594 return GCRY_MD_SHA512
;
601 static void dnssec_fix_rrset_ttl(
602 DnsResourceRecord
*list
[],
604 DnsResourceRecord
*rrsig
,
611 for (unsigned k
= 0; k
< n
; k
++) {
612 DnsResourceRecord
*rr
= list
[k
];
614 /* Pick the TTL as the minimum of the RR's TTL, the
615 * RR's original TTL according to the RRSIG and the
616 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
617 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
618 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
620 /* Copy over information about the signer and wildcard source of synthesis */
621 rr
->n_skip_labels_source
= rrsig
->n_skip_labels_source
;
622 rr
->n_skip_labels_signer
= rrsig
->n_skip_labels_signer
;
625 rrsig
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
628 int dnssec_verify_rrset(
630 const DnsResourceKey
*key
,
631 DnsResourceRecord
*rrsig
,
632 DnsResourceRecord
*dnskey
,
634 DnssecResult
*result
) {
636 uint8_t wire_format_name
[DNS_WIRE_FORMAT_HOSTNAME_MAX
];
637 DnsResourceRecord
**list
, *rr
;
638 const char *source
, *name
;
639 _cleanup_(gcry_md_closep
) gcry_md_hd_t md
= NULL
;
643 _cleanup_free_
char *sig_data
= NULL
;
644 _cleanup_fclose_
FILE *f
= NULL
;
653 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
654 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
656 /* Verifies that the RRSet matches the specified "key" in "a",
657 * using the signature "rrsig" and the key "dnskey". It's
658 * assumed that RRSIG and DNSKEY match. */
660 r
= dnssec_rrsig_prepare(rrsig
);
662 *result
= DNSSEC_INVALID
;
668 r
= dnssec_rrsig_expired(rrsig
, realtime
);
672 *result
= DNSSEC_SIGNATURE_EXPIRED
;
676 name
= dns_resource_key_name(key
);
678 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
679 if (dns_type_apex_only(rrsig
->rrsig
.type_covered
)) {
680 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
684 *result
= DNSSEC_INVALID
;
689 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
690 if (rrsig
->rrsig
.type_covered
== DNS_TYPE_DS
) {
691 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
695 *result
= DNSSEC_INVALID
;
700 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
701 r
= dns_name_suffix(name
, rrsig
->rrsig
.labels
, &source
);
704 if (r
> 0 && !dns_type_may_wildcard(rrsig
->rrsig
.type_covered
)) {
705 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
706 *result
= DNSSEC_INVALID
;
710 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
711 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
712 r
= dns_name_startswith(name
, "*");
722 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
723 list
= newa(DnsResourceRecord
*, dns_answer_size(a
));
725 DNS_ANSWER_FOREACH(rr
, a
) {
726 r
= dns_resource_key_equal(key
, rr
->key
);
732 /* We need the wire format for ordering, and digest calculation */
733 r
= dns_resource_record_to_wire_format(rr
, true);
739 if (n
> VERIFY_RRS_MAX
)
746 /* Bring the RRs into canonical order */
747 typesafe_qsort(list
, n
, rr_compare
);
749 f
= open_memstream_unlocked(&sig_data
, &sig_size
);
753 fwrite_uint16(f
, rrsig
->rrsig
.type_covered
);
754 fwrite_uint8(f
, rrsig
->rrsig
.algorithm
);
755 fwrite_uint8(f
, rrsig
->rrsig
.labels
);
756 fwrite_uint32(f
, rrsig
->rrsig
.original_ttl
);
757 fwrite_uint32(f
, rrsig
->rrsig
.expiration
);
758 fwrite_uint32(f
, rrsig
->rrsig
.inception
);
759 fwrite_uint16(f
, rrsig
->rrsig
.key_tag
);
761 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
764 fwrite(wire_format_name
, 1, r
, f
);
766 /* Convert the source of synthesis into wire format */
767 r
= dns_name_to_wire_format(source
, wire_format_name
, sizeof(wire_format_name
), true);
771 for (size_t k
= 0; k
< n
; k
++) {
776 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
778 fwrite((uint8_t[]) { 1, '*'}, sizeof(uint8_t), 2, f
);
779 fwrite(wire_format_name
, 1, r
, f
);
781 fwrite_uint16(f
, rr
->key
->type
);
782 fwrite_uint16(f
, rr
->key
->class);
783 fwrite_uint32(f
, rrsig
->rrsig
.original_ttl
);
785 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
788 fwrite_uint16(f
, (uint16_t) l
);
789 fwrite(DNS_RESOURCE_RECORD_RDATA(rr
), 1, l
, f
);
792 r
= fflush_and_check(f
);
796 initialize_libgcrypt(false);
798 switch (rrsig
->rrsig
.algorithm
) {
799 #if GCRYPT_VERSION_NUMBER >= 0x010600
800 case DNSSEC_ALGORITHM_ED25519
:
803 case DNSSEC_ALGORITHM_ED25519
:
805 case DNSSEC_ALGORITHM_ED448
:
806 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
811 /* OK, the RRs are now in canonical order. Let's calculate the digest */
812 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
813 if (md_algorithm
== -EOPNOTSUPP
) {
814 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
817 if (md_algorithm
< 0)
820 err
= gcry_md_open(&md
, md_algorithm
, 0);
821 if (gcry_err_code(err
) != GPG_ERR_NO_ERROR
|| !md
)
824 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
825 assert(hash_size
> 0);
827 gcry_md_write(md
, sig_data
, sig_size
);
829 hash
= gcry_md_read(md
, 0);
835 switch (rrsig
->rrsig
.algorithm
) {
837 case DNSSEC_ALGORITHM_RSASHA1
:
838 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
839 case DNSSEC_ALGORITHM_RSASHA256
:
840 case DNSSEC_ALGORITHM_RSASHA512
:
841 r
= dnssec_rsa_verify(
842 gcry_md_algo_name(md_algorithm
),
848 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
849 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
850 r
= dnssec_ecdsa_verify(
851 gcry_md_algo_name(md_algorithm
),
852 rrsig
->rrsig
.algorithm
,
857 #if GCRYPT_VERSION_NUMBER >= 0x010600
858 case DNSSEC_ALGORITHM_ED25519
:
859 r
= dnssec_eddsa_verify(
860 rrsig
->rrsig
.algorithm
,
870 /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */
872 dnssec_fix_rrset_ttl(list
, n
, rrsig
, realtime
);
875 *result
= DNSSEC_INVALID
;
877 *result
= DNSSEC_VALIDATED_WILDCARD
;
879 *result
= DNSSEC_VALIDATED
;
884 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
889 /* Checks if the specified DNSKEY RR matches the key used for
890 * the signature in the specified RRSIG RR */
892 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
895 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
897 if (dnskey
->key
->class != rrsig
->key
->class)
899 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
901 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
903 if (dnskey
->dnskey
.protocol
!= 3)
905 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
908 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
911 return dns_name_equal(dns_resource_key_name(dnskey
->key
), rrsig
->rrsig
.signer
);
914 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
918 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
920 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
922 if (rrsig
->key
->class != key
->class)
924 if (rrsig
->rrsig
.type_covered
!= key
->type
)
927 return dns_name_equal(dns_resource_key_name(rrsig
->key
), dns_resource_key_name(key
));
930 int dnssec_verify_rrset_search(
932 const DnsResourceKey
*key
,
933 DnsAnswer
*validated_dnskeys
,
935 DnssecResult
*result
,
936 DnsResourceRecord
**ret_rrsig
) {
938 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
939 DnsResourceRecord
*rrsig
;
945 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
947 if (!a
|| a
->n_rrs
<= 0)
950 /* Iterate through each RRSIG RR. */
951 DNS_ANSWER_FOREACH(rrsig
, a
) {
952 DnsResourceRecord
*dnskey
;
953 DnsAnswerFlags flags
;
955 /* Is this an RRSIG RR that applies to RRs matching our key? */
956 r
= dnssec_key_match_rrsig(key
, rrsig
);
964 /* Look for a matching key */
965 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
966 DnssecResult one_result
;
968 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
971 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
972 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
978 /* Take the time here, if it isn't set yet, so
979 * that we do all validations with the same
981 if (realtime
== USEC_INFINITY
)
982 realtime
= now(CLOCK_REALTIME
);
984 /* Yay, we found a matching RRSIG with a matching
985 * DNSKEY, awesome. Now let's verify all entries of
986 * the RRSet against the RRSIG and DNSKEY
989 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
993 switch (one_result
) {
995 case DNSSEC_VALIDATED
:
996 case DNSSEC_VALIDATED_WILDCARD
:
997 /* Yay, the RR has been validated,
998 * return immediately, but fix up the expiry */
1002 *result
= one_result
;
1005 case DNSSEC_INVALID
:
1006 /* If the signature is invalid, let's try another
1007 key and/or signature. After all they
1008 key_tags and stuff are not unique, and
1009 might be shared by multiple keys. */
1010 found_invalid
= true;
1013 case DNSSEC_UNSUPPORTED_ALGORITHM
:
1014 /* If the key algorithm is
1015 unsupported, try another
1016 RRSIG/DNSKEY pair, but remember we
1017 encountered this, so that we can
1018 return a proper error when we
1019 encounter nothing better. */
1020 found_unsupported_algorithm
= true;
1023 case DNSSEC_SIGNATURE_EXPIRED
:
1024 /* If the signature is expired, try
1025 another one, but remember it, so
1026 that we can return this */
1027 found_expired_rrsig
= true;
1031 assert_not_reached("Unexpected DNSSEC validation result");
1036 if (found_expired_rrsig
)
1037 *result
= DNSSEC_SIGNATURE_EXPIRED
;
1038 else if (found_unsupported_algorithm
)
1039 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
1040 else if (found_invalid
)
1041 *result
= DNSSEC_INVALID
;
1042 else if (found_rrsig
)
1043 *result
= DNSSEC_MISSING_KEY
;
1045 *result
= DNSSEC_NO_SIGNATURE
;
1053 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
1054 DnsResourceRecord
*rr
;
1057 /* Checks whether there's at least one RRSIG in 'a' that protects RRs of the specified key */
1059 DNS_ANSWER_FOREACH(rr
, a
) {
1060 r
= dnssec_key_match_rrsig(key
, rr
);
1070 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1072 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1074 switch (algorithm
) {
1076 case DNSSEC_DIGEST_SHA1
:
1077 return GCRY_MD_SHA1
;
1079 case DNSSEC_DIGEST_SHA256
:
1080 return GCRY_MD_SHA256
;
1082 case DNSSEC_DIGEST_SHA384
:
1083 return GCRY_MD_SHA384
;
1090 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1091 uint8_t wire_format
[DNS_WIRE_FORMAT_HOSTNAME_MAX
];
1092 _cleanup_(gcry_md_closep
) gcry_md_hd_t md
= NULL
;
1095 int md_algorithm
, r
;
1101 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1103 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1105 if (ds
->key
->type
!= DNS_TYPE_DS
)
1107 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1108 return -EKEYREJECTED
;
1109 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1110 return -EKEYREJECTED
;
1111 if (dnskey
->dnskey
.protocol
!= 3)
1112 return -EKEYREJECTED
;
1114 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1116 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1119 initialize_libgcrypt(false);
1121 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1122 if (md_algorithm
< 0)
1123 return md_algorithm
;
1125 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1126 assert(hash_size
> 0);
1128 if (ds
->ds
.digest_size
!= hash_size
)
1131 r
= dns_name_to_wire_format(dns_resource_key_name(dnskey
->key
), wire_format
, sizeof(wire_format
), true);
1135 err
= gcry_md_open(&md
, md_algorithm
, 0);
1136 if (gcry_err_code(err
) != GPG_ERR_NO_ERROR
|| !md
)
1139 gcry_md_write(md
, wire_format
, r
);
1141 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1143 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1144 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1145 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1146 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1148 result
= gcry_md_read(md
, 0);
1152 return memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) == 0;
1155 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1156 DnsResourceRecord
*ds
;
1157 DnsAnswerFlags flags
;
1162 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1165 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1167 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1170 if (ds
->key
->type
!= DNS_TYPE_DS
)
1172 if (ds
->key
->class != dnskey
->key
->class)
1175 r
= dns_name_equal(dns_resource_key_name(dnskey
->key
), dns_resource_key_name(ds
->key
));
1181 r
= dnssec_verify_dnskey_by_ds(dnskey
, ds
, false);
1182 if (IN_SET(r
, -EKEYREJECTED
, -EOPNOTSUPP
))
1183 return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */
1193 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1195 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1197 switch (algorithm
) {
1199 case NSEC3_ALGORITHM_SHA1
:
1200 return GCRY_MD_SHA1
;
1207 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1208 uint8_t wire_format
[DNS_WIRE_FORMAT_HOSTNAME_MAX
];
1209 _cleanup_(gcry_md_closep
) gcry_md_hd_t md
= NULL
;
1220 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1223 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1224 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1225 "Ignoring NSEC3 RR %s with excessive number of iterations.",
1226 dns_resource_record_to_string(nsec3
));
1228 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1232 initialize_libgcrypt(false);
1234 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1235 assert(hash_size
> 0);
1237 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1240 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1244 err
= gcry_md_open(&md
, algorithm
, 0);
1245 if (gcry_err_code(err
) != GPG_ERR_NO_ERROR
|| !md
)
1248 gcry_md_write(md
, wire_format
, r
);
1249 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1251 result
= gcry_md_read(md
, 0);
1255 for (unsigned k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1256 uint8_t tmp
[hash_size
];
1257 memcpy(tmp
, result
, hash_size
);
1260 gcry_md_write(md
, tmp
, hash_size
);
1261 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1263 result
= gcry_md_read(md
, 0);
1268 memcpy(ret
, result
, hash_size
);
1269 return (int) hash_size
;
1272 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1278 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1281 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1282 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1285 /* Ignore NSEC3 RRs whose algorithm we don't know */
1286 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1288 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1289 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1292 /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
1293 * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
1294 if (!IN_SET(rr
->n_skip_labels_source
, 0, UINT8_MAX
))
1296 /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
1297 if (!IN_SET(rr
->n_skip_labels_signer
, 1, UINT8_MAX
))
1303 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1305 if (nsec3
== rr
) /* Shortcut */
1308 if (rr
->key
->class != nsec3
->key
->class)
1310 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1312 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1314 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1316 if (memcmp_safe(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1319 a
= dns_resource_key_name(rr
->key
);
1320 r
= dns_name_parent(&a
); /* strip off hash */
1324 b
= dns_resource_key_name(nsec3
->key
);
1325 r
= dns_name_parent(&b
); /* strip off hash */
1329 /* Make sure both have the same parent */
1330 return dns_name_equal(a
, b
);
1333 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1334 _cleanup_free_
char *l
= NULL
;
1338 assert(hashed_size
> 0);
1342 l
= base32hexmem(hashed
, hashed_size
, false);
1346 j
= strjoin(l
, ".", zone
);
1351 return (int) hashed_size
;
1354 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1355 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1363 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1364 if (hashed_size
< 0)
1367 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1370 /* See RFC 5155, Section 8
1371 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1372 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1373 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1374 * matches the wildcard domain.
1376 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1377 * that there is no proof either way. The latter is the case if a proof of non-existence of a given
1378 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1379 * to conclude anything we indicate this by returning NO_RR. */
1380 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1381 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1382 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1383 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1384 DnsAnswerFlags flags
;
1386 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1391 /* First step, find the zone name and the NSEC3 parameters of the zone.
1392 * it is sufficient to look for the longest common suffix we find with
1393 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1394 * records from a given zone in a response must use the same
1396 zone
= dns_resource_key_name(key
);
1398 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1399 r
= nsec3_is_good(zone_rr
, NULL
);
1405 r
= dns_name_equal_skip(dns_resource_key_name(zone_rr
->key
), 1, zone
);
1412 /* Strip one label from the front */
1413 r
= dns_name_parent(&zone
);
1420 *result
= DNSSEC_NSEC_NO_RR
;
1424 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1425 p
= dns_resource_key_name(key
);
1427 _cleanup_free_
char *hashed_domain
= NULL
;
1429 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1430 if (hashed_size
== -EOPNOTSUPP
) {
1431 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1434 if (hashed_size
< 0)
1437 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1439 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1445 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1448 r
= dns_name_equal(dns_resource_key_name(enclosure_rr
->key
), hashed_domain
);
1452 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1453 goto found_closest_encloser
;
1457 /* We didn't find the closest encloser with this name,
1458 * but let's remember this domain name, it might be
1459 * the next closer name */
1463 /* Strip one label from the front */
1464 r
= dns_name_parent(&p
);
1471 *result
= DNSSEC_NSEC_NO_RR
;
1474 found_closest_encloser
:
1475 /* We found a closest encloser in 'p'; next closer is 'pp' */
1478 /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR
1479 * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are
1480 * appropriately set. */
1482 if (key
->type
== DNS_TYPE_DS
) {
1483 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1486 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1487 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1491 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1492 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1493 *result
= DNSSEC_NSEC_FOUND
;
1494 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1495 *result
= DNSSEC_NSEC_CNAME
;
1497 *result
= DNSSEC_NSEC_NODATA
;
1502 *ttl
= enclosure_rr
->ttl
;
1507 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1508 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1511 /* Ensure that this data is from the delegated domain
1512 * (i.e. originates from the "lower" DNS server), and isn't
1513 * just glue records (i.e. doesn't originate from the "upper"
1515 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1516 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1519 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1521 wildcard
= strjoina("*.", p
);
1522 r
= nsec3_hashed_domain_make(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1525 if (r
!= hashed_size
)
1528 r
= nsec3_hashed_domain_make(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1531 if (r
!= hashed_size
)
1534 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1535 _cleanup_free_
char *next_hashed_domain
= NULL
;
1537 r
= nsec3_is_good(rr
, zone_rr
);
1543 r
= nsec3_hashed_domain_format(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, zone
, &next_hashed_domain
);
1547 r
= dns_name_between(dns_resource_key_name(rr
->key
), next_closer_domain
, next_hashed_domain
);
1551 if (rr
->nsec3
.flags
& 1)
1554 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1559 r
= dns_name_equal(dns_resource_key_name(rr
->key
), wildcard_domain
);
1563 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1568 r
= dns_name_between(dns_resource_key_name(rr
->key
), wildcard_domain
, next_hashed_domain
);
1572 if (rr
->nsec3
.flags
& 1)
1573 /* This only makes sense if we have a wildcard delegation, which is
1574 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1575 * this not happening, so hence cannot simply conclude NXDOMAIN as
1579 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1585 if (wildcard_rr
&& no_wildcard
)
1589 *result
= DNSSEC_NSEC_NO_RR
;
1594 /* A wildcard exists that matches our query. */
1596 /* This is not specified in any RFC to the best of my knowledge, but
1597 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1598 * it means that we cannot prove that the source of synthesis is
1599 * correct, as there may be a closer match. */
1600 *result
= DNSSEC_NSEC_OPTOUT
;
1601 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1602 *result
= DNSSEC_NSEC_FOUND
;
1603 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1604 *result
= DNSSEC_NSEC_CNAME
;
1606 *result
= DNSSEC_NSEC_NODATA
;
1609 /* The RFC only specifies that we have to care for optout for NODATA for
1610 * DS records. However, children of an insecure opt-out delegation should
1611 * also be considered opt-out, rather than verified NXDOMAIN.
1612 * Note that we do not require a proof of wildcard non-existence if the
1613 * next closer domain is covered by an opt-out, as that would not provide
1614 * any additional information. */
1615 *result
= DNSSEC_NSEC_OPTOUT
;
1616 else if (no_wildcard
)
1617 *result
= DNSSEC_NSEC_NXDOMAIN
;
1619 *result
= DNSSEC_NSEC_NO_RR
;
1629 *ttl
= enclosure_rr
->ttl
;
1634 static int dnssec_nsec_wildcard_equal(DnsResourceRecord
*rr
, const char *name
) {
1635 char label
[DNS_LABEL_MAX
];
1640 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1642 /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */
1644 if (rr
->n_skip_labels_source
!= 1)
1647 n
= dns_resource_key_name(rr
->key
);
1648 r
= dns_label_unescape(&n
, label
, sizeof label
, 0);
1651 if (r
!= 1 || label
[0] != '*')
1654 return dns_name_endswith(name
, n
);
1657 static int dnssec_nsec_in_path(DnsResourceRecord
*rr
, const char *name
) {
1658 const char *nn
, *common_suffix
;
1662 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1664 /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT)
1666 * A couple of examples:
1668 * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT
1669 * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs
1670 * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs
1673 /* First, determine parent of next domain. */
1674 nn
= rr
->nsec
.next_domain_name
;
1675 r
= dns_name_parent(&nn
);
1679 /* If the name we just determined is not equal or child of the name we are interested in, then we can't say
1680 * anything at all. */
1681 r
= dns_name_endswith(nn
, name
);
1685 /* 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. */
1686 r
= dns_name_common_suffix(dns_resource_key_name(rr
->key
), rr
->nsec
.next_domain_name
, &common_suffix
);
1690 return dns_name_endswith(name
, common_suffix
);
1693 static int dnssec_nsec_from_parent_zone(DnsResourceRecord
*rr
, const char *name
) {
1697 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1699 /* Checks whether this NSEC originates to the parent zone or the child zone. */
1701 r
= dns_name_parent(&name
);
1705 r
= dns_name_equal(name
, dns_resource_key_name(rr
->key
));
1709 /* DNAME, and NS without SOA is an indication for a delegation. */
1710 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_DNAME
))
1713 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) && !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1719 static int dnssec_nsec_covers(DnsResourceRecord
*rr
, const char *name
) {
1724 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1726 /* Checks whether the name is covered by this NSEC RR. This means, that the name is somewhere below the NSEC's
1727 * signer name, and between the NSEC's two names. */
1729 r
= dns_resource_record_signer(rr
, &signer
);
1733 r
= dns_name_endswith(name
, signer
); /* this NSEC isn't suitable the name is not in the signer's domain */
1737 return dns_name_between(dns_resource_key_name(rr
->key
), name
, rr
->nsec
.next_domain_name
);
1740 static int dnssec_nsec_generate_wildcard(DnsResourceRecord
*rr
, const char *name
, char **wc
) {
1741 const char *common_suffix1
, *common_suffix2
, *signer
;
1742 int r
, labels1
, labels2
;
1745 assert(rr
->key
->type
== DNS_TYPE_NSEC
);
1747 /* Generates "Wildcard at the Closest Encloser" for the given name and NSEC RR. */
1749 r
= dns_resource_record_signer(rr
, &signer
);
1753 r
= dns_name_endswith(name
, signer
); /* this NSEC isn't suitable the name is not in the signer's domain */
1757 r
= dns_name_common_suffix(name
, dns_resource_key_name(rr
->key
), &common_suffix1
);
1761 r
= dns_name_common_suffix(name
, rr
->nsec
.next_domain_name
, &common_suffix2
);
1765 labels1
= dns_name_count_labels(common_suffix1
);
1769 labels2
= dns_name_count_labels(common_suffix2
);
1773 if (labels1
> labels2
)
1774 r
= dns_name_concat("*", common_suffix1
, 0, wc
);
1776 r
= dns_name_concat("*", common_suffix2
, 0, wc
);
1784 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1785 bool have_nsec3
= false, covering_rr_authenticated
= false, wildcard_rr_authenticated
= false;
1786 DnsResourceRecord
*rr
, *covering_rr
= NULL
, *wildcard_rr
= NULL
;
1787 DnsAnswerFlags flags
;
1794 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1796 name
= dns_resource_key_name(key
);
1798 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1800 if (rr
->key
->class != key
->class)
1803 have_nsec3
= have_nsec3
|| (rr
->key
->type
== DNS_TYPE_NSEC3
);
1805 if (rr
->key
->type
!= DNS_TYPE_NSEC
)
1808 /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */
1809 r
= dns_resource_record_is_synthetic(rr
);
1810 if (r
== -ENODATA
) /* No signing RR known. */
1817 /* Check if this is a direct match. If so, we have encountered a NODATA case */
1818 r
= dns_name_equal(dns_resource_key_name(rr
->key
), name
);
1822 /* If it's not a direct match, maybe it's a wild card match? */
1823 r
= dnssec_nsec_wildcard_equal(rr
, name
);
1828 if (key
->type
== DNS_TYPE_DS
) {
1829 /* If we look for a DS RR and the server sent us the NSEC RR of the child zone
1830 * we have a problem. For DS RRs we want the NSEC RR from the parent */
1831 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1834 /* For all RR types, ensure that if NS is set SOA is set too, so that we know
1835 * we got the child's NSEC. */
1836 if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_NS
) &&
1837 !bitmap_isset(rr
->nsec
.types
, DNS_TYPE_SOA
))
1841 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1842 *result
= DNSSEC_NSEC_FOUND
;
1843 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1844 *result
= DNSSEC_NSEC_CNAME
;
1846 *result
= DNSSEC_NSEC_NODATA
;
1849 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1856 /* Check if the name we are looking for is an empty non-terminal within the owner or next name
1857 * of the NSEC RR. */
1858 r
= dnssec_nsec_in_path(rr
, name
);
1862 *result
= DNSSEC_NSEC_NODATA
;
1865 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1872 /* The following two "covering" checks, are not useful if the NSEC is from the parent */
1873 r
= dnssec_nsec_from_parent_zone(rr
, name
);
1879 /* Check if this NSEC RR proves the absence of an explicit RR under this name */
1880 r
= dnssec_nsec_covers(rr
, name
);
1883 if (r
> 0 && (!covering_rr
|| !covering_rr_authenticated
)) {
1885 covering_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1890 _cleanup_free_
char *wc
= NULL
;
1891 r
= dnssec_nsec_generate_wildcard(covering_rr
, name
, &wc
);
1895 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1897 if (rr
->key
->class != key
->class)
1900 if (rr
->key
->type
!= DNS_TYPE_NSEC
)
1903 /* Check if this NSEC RR proves the nonexistence of the wildcard */
1904 r
= dnssec_nsec_covers(rr
, wc
);
1907 if (r
> 0 && (!wildcard_rr
|| !wildcard_rr_authenticated
)) {
1909 wildcard_rr_authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1914 if (covering_rr
&& wildcard_rr
) {
1915 /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
1916 * proved the NXDOMAIN case. */
1917 *result
= DNSSEC_NSEC_NXDOMAIN
;
1920 *authenticated
= covering_rr_authenticated
&& wildcard_rr_authenticated
;
1922 *ttl
= MIN(covering_rr
->ttl
, wildcard_rr
->ttl
);
1927 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1929 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
1931 /* No appropriate NSEC RR found, report this. */
1932 *result
= DNSSEC_NSEC_NO_RR
;
1936 static int dnssec_nsec_test_enclosed(DnsAnswer
*answer
, uint16_t type
, const char *name
, const char *zone
, bool *authenticated
) {
1937 DnsResourceRecord
*rr
;
1938 DnsAnswerFlags flags
;
1944 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
1945 * 'zone'. The 'zone' must be a suffix of the 'name'. */
1947 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1950 if (rr
->key
->type
!= type
&& type
!= DNS_TYPE_ANY
)
1953 switch (rr
->key
->type
) {
1957 /* We only care for NSEC RRs from the indicated zone */
1958 r
= dns_resource_record_is_signer(rr
, zone
);
1964 r
= dns_name_between(dns_resource_key_name(rr
->key
), name
, rr
->nsec
.next_domain_name
);
1971 case DNS_TYPE_NSEC3
: {
1972 _cleanup_free_
char *hashed_domain
= NULL
, *next_hashed_domain
= NULL
;
1974 /* We only care for NSEC3 RRs from the indicated zone */
1975 r
= dns_resource_record_is_signer(rr
, zone
);
1981 r
= nsec3_is_good(rr
, NULL
);
1987 /* Format the domain we are testing with the NSEC3 RR's hash function */
1988 r
= nsec3_hashed_domain_make(
1995 if ((size_t) r
!= rr
->nsec3
.next_hashed_name_size
)
1998 /* Format the NSEC3's next hashed name as proper domain name */
1999 r
= nsec3_hashed_domain_format(
2000 rr
->nsec3
.next_hashed_name
,
2001 rr
->nsec3
.next_hashed_name_size
,
2003 &next_hashed_domain
);
2007 r
= dns_name_between(dns_resource_key_name(rr
->key
), hashed_domain
, next_hashed_domain
);
2021 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
2029 static int dnssec_test_positive_wildcard_nsec3(
2034 bool *authenticated
) {
2036 const char *next_closer
= NULL
;
2039 /* Run a positive NSEC3 wildcard proof. Specifically:
2041 * A proof that the "next closer" of the generating wildcard does not exist.
2043 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
2044 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
2045 * exists for the NSEC3 RR and we are done.
2047 * 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
2048 * c.d.e.f does not exist. */
2052 r
= dns_name_parent(&name
);
2056 r
= dns_name_equal(name
, source
);
2063 return dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC3
, next_closer
, zone
, authenticated
);
2066 static int dnssec_test_positive_wildcard_nsec(
2071 bool *_authenticated
) {
2073 bool authenticated
= true;
2076 /* Run a positive NSEC wildcard proof. Specifically:
2078 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
2079 * a prefix of the synthesizing source "source" in the zone "zone".
2081 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
2083 * 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
2084 * have to prove that none of the following exist:
2094 _cleanup_free_
char *wc
= NULL
;
2097 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
2098 * i.e between the owner name and the next name of an NSEC RR. */
2099 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, name
, zone
, &a
);
2103 authenticated
= authenticated
&& a
;
2105 /* Strip one label off */
2106 r
= dns_name_parent(&name
);
2110 /* Did we reach the source of synthesis? */
2111 r
= dns_name_equal(name
, source
);
2115 /* Successful exit */
2116 *_authenticated
= authenticated
;
2120 /* Safety check, that the source of synthesis is still our suffix */
2121 r
= dns_name_endswith(name
, source
);
2127 /* Replace the label we stripped off with an asterisk */
2128 wc
= strjoin("*.", name
);
2132 /* And check if the proof holds for the asterisk name, too */
2133 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, wc
, zone
, &a
);
2137 authenticated
= authenticated
&& a
;
2138 /* In the next iteration we'll check the non-asterisk-prefixed version */
2142 int dnssec_test_positive_wildcard(
2147 bool *authenticated
) {
2154 assert(authenticated
);
2156 r
= dns_answer_contains_zone_nsec3(answer
, zone
);
2160 return dnssec_test_positive_wildcard_nsec3(answer
, name
, source
, zone
, authenticated
);
2162 return dnssec_test_positive_wildcard_nsec(answer
, name
, source
, zone
, authenticated
);
2167 int dnssec_verify_rrset(
2169 const DnsResourceKey
*key
,
2170 DnsResourceRecord
*rrsig
,
2171 DnsResourceRecord
*dnskey
,
2173 DnssecResult
*result
) {
2178 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
2183 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
2188 int dnssec_verify_rrset_search(
2190 const DnsResourceKey
*key
,
2191 DnsAnswer
*validated_dnskeys
,
2193 DnssecResult
*result
,
2194 DnsResourceRecord
**ret_rrsig
) {
2199 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
2204 int dnssec_verify_dnskey_by_ds(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
2209 int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
2214 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
2219 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
2224 int dnssec_test_positive_wildcard(
2229 bool *authenticated
) {
2236 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
2237 [DNSSEC_VALIDATED
] = "validated",
2238 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
2239 [DNSSEC_INVALID
] = "invalid",
2240 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
2241 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
2242 [DNSSEC_NO_SIGNATURE
] = "no-signature",
2243 [DNSSEC_MISSING_KEY
] = "missing-key",
2244 [DNSSEC_UNSIGNED
] = "unsigned",
2245 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
2246 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
2247 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
2249 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);
2251 static const char* const dnssec_verdict_table
[_DNSSEC_VERDICT_MAX
] = {
2252 [DNSSEC_SECURE
] = "secure",
2253 [DNSSEC_INSECURE
] = "insecure",
2254 [DNSSEC_BOGUS
] = "bogus",
2255 [DNSSEC_INDETERMINATE
] = "indeterminate",
2257 DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict
, DnssecVerdict
);