1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2015 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
25 #include "dns-domain.h"
26 #include "hexdecoct.h"
27 #include "resolved-dns-dnssec.h"
28 #include "resolved-dns-packet.h"
29 #include "string-table.h"
33 * How does the DNSSEC canonical form of a hostname with a label
34 * containing a dot look like, the way DNS-SD does it?
38 * - wildcard zones compatibility (NSEC/NSEC3 wildcard check is missing)
39 * - multi-label zone compatibility
40 * - cname/dname compatibility
42 * - bus calls to override DNSEC setting per interface
43 * - log all DNSSEC downgrades
46 * - RFC 4035, Section 5.3.4 (When receiving a positive wildcard reply, use NSEC to ensure it actually really applies)
47 * - RFC 6840, Section 4.1 (ensure we don't get fed a glue NSEC from the parent zone)
48 * - RFC 6840, Section 4.3 (check for CNAME on NSEC too)
51 #define VERIFY_RRS_MAX 256
52 #define MAX_KEY_SIZE (32*1024)
54 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
55 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
57 /* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
58 #define NSEC3_ITERATIONS_MAX 2500
61 * The DNSSEC Chain of trust:
63 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
64 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
65 * DS RRs are protected like normal RRs
68 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
71 static void initialize_libgcrypt(void) {
74 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
77 p
= gcry_check_version("1.4.5");
80 gcry_control(GCRYCTL_DISABLE_SECMEM
);
81 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
84 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
, bool mask_revoke
) {
89 /* The algorithm from RFC 4034, Appendix B. */
92 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
94 f
= (uint32_t) dnskey
->dnskey
.flags
;
97 f
&= ~DNSKEY_FLAG_REVOKE
;
99 sum
= f
+ ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
101 p
= dnskey
->dnskey
.key
;
103 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
104 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
106 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
108 return sum
& UINT32_C(0xFFFF);
111 static int rr_compare(const void *a
, const void *b
) {
112 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
116 /* Let's order the RRs according to RFC 4034, Section 6.3 */
120 assert((*x
)->wire_format
);
123 assert((*y
)->wire_format
);
125 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
127 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
131 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
133 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
139 static int dnssec_rsa_verify_raw(
140 const char *hash_algorithm
,
141 const void *signature
, size_t signature_size
,
142 const void *data
, size_t data_size
,
143 const void *exponent
, size_t exponent_size
,
144 const void *modulus
, size_t modulus_size
) {
146 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
147 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
151 assert(hash_algorithm
);
153 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
159 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
165 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
171 ge
= gcry_sexp_build(&signature_sexp
,
173 "(sig-val (rsa (s %m)))",
181 ge
= gcry_sexp_build(&data_sexp
,
183 "(data (flags pkcs1) (hash %s %b))",
192 ge
= gcry_sexp_build(&public_key_sexp
,
194 "(public-key (rsa (n %m) (e %m)))",
202 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
203 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
206 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
220 gcry_sexp_release(public_key_sexp
);
222 gcry_sexp_release(signature_sexp
);
224 gcry_sexp_release(data_sexp
);
229 static int dnssec_rsa_verify(
230 const char *hash_algorithm
,
231 const void *hash
, size_t hash_size
,
232 DnsResourceRecord
*rrsig
,
233 DnsResourceRecord
*dnskey
) {
235 size_t exponent_size
, modulus_size
;
236 void *exponent
, *modulus
;
238 assert(hash_algorithm
);
240 assert(hash_size
> 0);
244 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
245 /* exponent is > 255 bytes long */
247 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
249 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
250 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
252 if (exponent_size
< 256)
255 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
258 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
259 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
262 /* exponent is <= 255 bytes long */
264 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
265 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
267 if (exponent_size
<= 0)
270 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
273 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
274 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
277 return dnssec_rsa_verify_raw(
279 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
281 exponent
, exponent_size
,
282 modulus
, modulus_size
);
285 static int dnssec_ecdsa_verify_raw(
286 const char *hash_algorithm
,
288 const void *signature_r
, size_t signature_r_size
,
289 const void *signature_s
, size_t signature_s_size
,
290 const void *data
, size_t data_size
,
291 const void *key
, size_t key_size
) {
293 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
294 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
298 assert(hash_algorithm
);
300 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
306 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
312 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
318 ge
= gcry_sexp_build(&signature_sexp
,
320 "(sig-val (ecdsa (r %m) (s %m)))",
328 ge
= gcry_sexp_build(&data_sexp
,
330 "(data (flags rfc6979) (hash %s %b))",
339 ge
= gcry_sexp_build(&public_key_sexp
,
341 "(public-key (ecc (curve %s) (q %m)))",
349 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
350 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
353 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
366 gcry_sexp_release(public_key_sexp
);
368 gcry_sexp_release(signature_sexp
);
370 gcry_sexp_release(data_sexp
);
375 static int dnssec_ecdsa_verify(
376 const char *hash_algorithm
,
378 const void *hash
, size_t hash_size
,
379 DnsResourceRecord
*rrsig
,
380 DnsResourceRecord
*dnskey
) {
391 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
393 curve
= "NIST P-256";
394 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
396 curve
= "NIST P-384";
400 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
403 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
406 q
= alloca(key_size
*2 + 1);
407 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
408 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
410 return dnssec_ecdsa_verify_raw(
413 rrsig
->rrsig
.signature
, key_size
,
414 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
419 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
420 gcry_md_write(md
, &v
, sizeof(v
));
423 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
425 gcry_md_write(md
, &v
, sizeof(v
));
428 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
430 gcry_md_write(md
, &v
, sizeof(v
));
433 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
434 usec_t expiration
, inception
, skew
;
437 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
439 if (realtime
== USEC_INFINITY
)
440 realtime
= now(CLOCK_REALTIME
);
442 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
443 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
445 /* Consider inverted validity intervals as expired */
446 if (inception
> expiration
)
449 /* Permit a certain amount of clock skew of 10% of the valid
450 * time range. This takes inspiration from unbound's
452 skew
= (expiration
- inception
) / 10;
456 if (inception
< skew
)
461 if (expiration
+ skew
< expiration
)
462 expiration
= USEC_INFINITY
;
466 return realtime
< inception
|| realtime
> expiration
;
469 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
471 /* Translates a DNSSEC signature algorithm into a gcrypt
474 * Note that we implement all algorithms listed as "Must
475 * implement" and "Recommended to Implement" in RFC6944. We
476 * don't implement any algorithms that are listed as
477 * "Optional" or "Must Not Implement". Specifically, we do not
478 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
483 case DNSSEC_ALGORITHM_RSASHA1
:
484 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
487 case DNSSEC_ALGORITHM_RSASHA256
:
488 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
489 return GCRY_MD_SHA256
;
491 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
492 return GCRY_MD_SHA384
;
494 case DNSSEC_ALGORITHM_RSASHA512
:
495 return GCRY_MD_SHA512
;
502 int dnssec_verify_rrset(
504 const DnsResourceKey
*key
,
505 DnsResourceRecord
*rrsig
,
506 DnsResourceRecord
*dnskey
,
508 DnssecResult
*result
) {
510 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
511 DnsResourceRecord
**list
, *rr
;
512 const char *source
, *name
;
513 gcry_md_hd_t md
= NULL
;
524 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
525 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
527 /* Verifies the the RRSet matching the specified "key" in "a",
528 * using the signature "rrsig" and the key "dnskey". It's
529 * assumed the RRSIG and DNSKEY match. */
531 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
532 if (md_algorithm
== -EOPNOTSUPP
) {
533 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
536 if (md_algorithm
< 0)
539 r
= dnssec_rrsig_expired(rrsig
, realtime
);
543 *result
= DNSSEC_SIGNATURE_EXPIRED
;
547 name
= DNS_RESOURCE_KEY_NAME(key
);
549 /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
550 if (dns_type_apex_only(rrsig
->rrsig
.type_covered
)) {
551 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
555 *result
= DNSSEC_INVALID
;
560 /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */
561 if (rrsig
->rrsig
.type_covered
== DNS_TYPE_DS
) {
562 r
= dns_name_equal(rrsig
->rrsig
.signer
, name
);
566 *result
= DNSSEC_INVALID
;
571 /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */
572 r
= dns_name_suffix(name
, rrsig
->rrsig
.labels
, &source
);
575 if (r
> 0 && !dns_type_may_wildcard(rrsig
->rrsig
.type_covered
)) {
576 /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */
577 *result
= DNSSEC_INVALID
;
581 /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really
582 * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */
583 r
= dns_name_startswith(name
, "*");
593 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
594 list
= newa(DnsResourceRecord
*, dns_answer_size(a
));
596 DNS_ANSWER_FOREACH(rr
, a
) {
597 r
= dns_resource_key_equal(key
, rr
->key
);
603 /* We need the wire format for ordering, and digest calculation */
604 r
= dns_resource_record_to_wire_format(rr
, true);
610 if (n
> VERIFY_RRS_MAX
)
617 /* Bring the RRs into canonical order */
618 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
620 /* OK, the RRs are now in canonical order. Let's calculate the digest */
621 initialize_libgcrypt();
623 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
624 assert(hash_size
> 0);
626 gcry_md_open(&md
, md_algorithm
, 0);
630 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
631 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
632 md_add_uint8(md
, rrsig
->rrsig
.labels
);
633 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
634 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
635 md_add_uint32(md
, rrsig
->rrsig
.inception
);
636 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
638 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
641 gcry_md_write(md
, wire_format_name
, r
);
643 /* Convert the source of synthesis into wire format */
644 r
= dns_name_to_wire_format(source
, wire_format_name
, sizeof(wire_format_name
), true);
648 for (k
= 0; k
< n
; k
++) {
653 /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
655 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
656 gcry_md_write(md
, wire_format_name
, r
);
658 md_add_uint16(md
, rr
->key
->type
);
659 md_add_uint16(md
, rr
->key
->class);
660 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
662 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
665 md_add_uint16(md
, (uint16_t) l
);
666 gcry_md_write(md
, DNS_RESOURCE_RECORD_RDATA(rr
), l
);
669 hash
= gcry_md_read(md
, 0);
675 switch (rrsig
->rrsig
.algorithm
) {
677 case DNSSEC_ALGORITHM_RSASHA1
:
678 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
679 case DNSSEC_ALGORITHM_RSASHA256
:
680 case DNSSEC_ALGORITHM_RSASHA512
:
681 r
= dnssec_rsa_verify(
682 gcry_md_algo_name(md_algorithm
),
688 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
689 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
690 r
= dnssec_ecdsa_verify(
691 gcry_md_algo_name(md_algorithm
),
692 rrsig
->rrsig
.algorithm
,
703 *result
= DNSSEC_INVALID
;
705 *result
= DNSSEC_VALIDATED_WILDCARD
;
707 *result
= DNSSEC_VALIDATED
;
715 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
720 /* Checks if the specified DNSKEY RR matches the key used for
721 * the signature in the specified RRSIG RR */
723 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
726 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
728 if (dnskey
->key
->class != rrsig
->key
->class)
730 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
732 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
734 if (dnskey
->dnskey
.protocol
!= 3)
736 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
739 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
742 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
745 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
751 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
753 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
755 if (rrsig
->key
->class != key
->class)
757 if (rrsig
->rrsig
.type_covered
!= key
->type
)
760 /* Make sure signer is a parent of the RRset */
761 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(rrsig
->key
), rrsig
->rrsig
.signer
);
765 /* Make sure the owner name has at least as many labels as the "label" fields indicates. */
766 r
= dns_name_count_labels(DNS_RESOURCE_KEY_NAME(rrsig
->key
));
769 if (r
< rrsig
->rrsig
.labels
)
772 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
775 static int dnssec_fix_rrset_ttl(DnsAnswer
*a
, const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
, usec_t realtime
) {
776 DnsResourceRecord
*rr
;
782 DNS_ANSWER_FOREACH(rr
, a
) {
783 r
= dns_resource_key_equal(key
, rr
->key
);
789 /* Pick the TTL as the minimum of the RR's TTL, the
790 * RR's original TTL according to the RRSIG and the
791 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
792 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
793 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
799 int dnssec_verify_rrset_search(
801 const DnsResourceKey
*key
,
802 DnsAnswer
*validated_dnskeys
,
804 DnssecResult
*result
,
805 DnsResourceRecord
**ret_rrsig
) {
807 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
808 DnsResourceRecord
*rrsig
;
814 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
816 if (!a
|| a
->n_rrs
<= 0)
819 /* Iterate through each RRSIG RR. */
820 DNS_ANSWER_FOREACH(rrsig
, a
) {
821 DnsResourceRecord
*dnskey
;
822 DnsAnswerFlags flags
;
824 /* Is this an RRSIG RR that applies to RRs matching our key? */
825 r
= dnssec_key_match_rrsig(key
, rrsig
);
833 /* Look for a matching key */
834 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
835 DnssecResult one_result
;
837 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
840 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
841 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
847 /* Take the time here, if it isn't set yet, so
848 * that we do all validations with the same
850 if (realtime
== USEC_INFINITY
)
851 realtime
= now(CLOCK_REALTIME
);
853 /* Yay, we found a matching RRSIG with a matching
854 * DNSKEY, awesome. Now let's verify all entries of
855 * the RRSet against the RRSIG and DNSKEY
858 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
862 switch (one_result
) {
864 case DNSSEC_VALIDATED
:
865 case DNSSEC_VALIDATED_WILDCARD
:
866 /* Yay, the RR has been validated,
867 * return immediately, but fix up the expiry */
868 r
= dnssec_fix_rrset_ttl(a
, key
, rrsig
, realtime
);
875 *result
= one_result
;
879 /* If the signature is invalid, let's try another
880 key and/or signature. After all they
881 key_tags and stuff are not unique, and
882 might be shared by multiple keys. */
883 found_invalid
= true;
886 case DNSSEC_UNSUPPORTED_ALGORITHM
:
887 /* If the key algorithm is
888 unsupported, try another
889 RRSIG/DNSKEY pair, but remember we
890 encountered this, so that we can
891 return a proper error when we
892 encounter nothing better. */
893 found_unsupported_algorithm
= true;
896 case DNSSEC_SIGNATURE_EXPIRED
:
897 /* If the signature is expired, try
898 another one, but remember it, so
899 that we can return this */
900 found_expired_rrsig
= true;
904 assert_not_reached("Unexpected DNSSEC validation result");
909 if (found_expired_rrsig
)
910 *result
= DNSSEC_SIGNATURE_EXPIRED
;
911 else if (found_unsupported_algorithm
)
912 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
913 else if (found_invalid
)
914 *result
= DNSSEC_INVALID
;
915 else if (found_rrsig
)
916 *result
= DNSSEC_MISSING_KEY
;
918 *result
= DNSSEC_NO_SIGNATURE
;
926 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
927 DnsResourceRecord
*rr
;
930 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
932 DNS_ANSWER_FOREACH(rr
, a
) {
933 r
= dnssec_key_match_rrsig(key
, rr
);
943 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
947 /* Converts the specified hostname into DNSSEC canonicalized
954 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
962 /* DNSSEC validation is always done on the ASCII version of the label */
963 k
= dns_label_apply_idna(buffer
, r
, buffer
, buffer_max
);
970 if (buffer_max
< (size_t) r
+ 2)
973 /* The DNSSEC canonical form is not clear on what to
974 * do with dots appearing in labels, the way DNS-SD
975 * does it. Refuse it for now. */
977 if (memchr(buffer
, '.', r
))
980 ascii_strlower_n(buffer
, (size_t) r
);
990 /* Not even a single label: this is the root domain name */
992 assert(buffer_max
> 2);
1002 static int digest_to_gcrypt_md(uint8_t algorithm
) {
1004 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
1006 switch (algorithm
) {
1008 case DNSSEC_DIGEST_SHA1
:
1009 return GCRY_MD_SHA1
;
1011 case DNSSEC_DIGEST_SHA256
:
1012 return GCRY_MD_SHA256
;
1014 case DNSSEC_DIGEST_SHA384
:
1015 return GCRY_MD_SHA384
;
1022 int dnssec_verify_dnskey(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
1023 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
1024 gcry_md_hd_t md
= NULL
;
1026 int md_algorithm
, r
;
1032 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
1034 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1036 if (ds
->key
->type
!= DNS_TYPE_DS
)
1038 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
1039 return -EKEYREJECTED
;
1040 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
1041 return -EKEYREJECTED
;
1042 if (dnskey
->dnskey
.protocol
!= 3)
1043 return -EKEYREJECTED
;
1045 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
1047 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
1050 initialize_libgcrypt();
1052 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
1053 if (md_algorithm
< 0)
1054 return md_algorithm
;
1056 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1057 assert(hash_size
> 0);
1059 if (ds
->ds
.digest_size
!= hash_size
)
1062 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
1066 gcry_md_open(&md
, md_algorithm
, 0);
1070 gcry_md_write(md
, owner_name
, r
);
1072 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1074 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1075 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1076 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1077 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1079 result
= gcry_md_read(md
, 0);
1085 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1092 int dnssec_verify_dnskey_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1093 DnsResourceRecord
*ds
;
1094 DnsAnswerFlags flags
;
1099 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1102 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1104 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1107 if (ds
->key
->type
!= DNS_TYPE_DS
)
1110 if (ds
->key
->class != dnskey
->key
->class)
1113 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1119 r
= dnssec_verify_dnskey(dnskey
, ds
, false);
1120 if (r
== -EKEYREJECTED
)
1121 return 0; /* The DNSKEY is revoked or otherwise invalid, we won't bless it */
1131 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1133 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1135 switch (algorithm
) {
1137 case NSEC3_ALGORITHM_SHA1
:
1138 return GCRY_MD_SHA1
;
1145 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1146 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1147 gcry_md_hd_t md
= NULL
;
1158 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1161 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1162 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1166 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1170 initialize_libgcrypt();
1172 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1173 assert(hash_size
> 0);
1175 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1178 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1182 gcry_md_open(&md
, algorithm
, 0);
1186 gcry_md_write(md
, wire_format
, r
);
1187 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1189 result
= gcry_md_read(md
, 0);
1195 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1196 uint8_t tmp
[hash_size
];
1197 memcpy(tmp
, result
, hash_size
);
1200 gcry_md_write(md
, tmp
, hash_size
);
1201 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1203 result
= gcry_md_read(md
, 0);
1210 memcpy(ret
, result
, hash_size
);
1211 r
= (int) hash_size
;
1218 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsResourceRecord
*nsec3
) {
1224 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1227 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1228 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1231 /* Ignore NSEC3 RRs whose algorithm we don't know */
1232 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1234 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1235 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1241 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1243 if (nsec3
== rr
) /* Shortcut */
1246 if (rr
->key
->class != nsec3
->key
->class)
1248 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1250 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1252 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1254 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1257 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1258 r
= dns_name_parent(&a
); /* strip off hash */
1264 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1265 r
= dns_name_parent(&b
); /* strip off hash */
1271 return dns_name_equal(a
, b
);
1274 static int nsec3_hashed_domain_format(const uint8_t *hashed
, size_t hashed_size
, const char *zone
, char **ret
) {
1275 _cleanup_free_
char *l
= NULL
;
1279 assert(hashed_size
> 0);
1283 l
= base32hexmem(hashed
, hashed_size
, false);
1287 j
= strjoin(l
, ".", zone
, NULL
);
1292 return (int) hashed_size
;
1295 static int nsec3_hashed_domain_make(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1296 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1304 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1305 if (hashed_size
< 0)
1308 return nsec3_hashed_domain_format(hashed
, (size_t) hashed_size
, zone
, ret
);
1311 /* See RFC 5155, Section 8
1312 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1313 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1314 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1315 * matches the wildcard domain.
1317 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1318 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1319 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1320 * to conclude anything we indicate this by returning NO_RR. */
1321 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1322 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard_domain
= NULL
;
1323 const char *zone
, *p
, *pp
= NULL
, *wildcard
;
1324 DnsResourceRecord
*rr
, *enclosure_rr
, *zone_rr
, *wildcard_rr
= NULL
;
1325 DnsAnswerFlags flags
;
1327 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1332 /* First step, find the zone name and the NSEC3 parameters of the zone.
1333 * it is sufficient to look for the longest common suffix we find with
1334 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1335 * records from a given zone in a response must use the same
1337 zone
= DNS_RESOURCE_KEY_NAME(key
);
1339 DNS_ANSWER_FOREACH_FLAGS(zone_rr
, flags
, answer
) {
1340 r
= nsec3_is_good(zone_rr
, NULL
);
1346 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr
->key
), 1, zone
);
1353 /* Strip one label from the front */
1354 r
= dns_name_parent(&zone
);
1361 *result
= DNSSEC_NSEC_NO_RR
;
1365 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1366 p
= DNS_RESOURCE_KEY_NAME(key
);
1368 _cleanup_free_
char *hashed_domain
= NULL
;
1370 hashed_size
= nsec3_hashed_domain_make(zone_rr
, p
, zone
, &hashed_domain
);
1371 if (hashed_size
== -EOPNOTSUPP
) {
1372 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1375 if (hashed_size
< 0)
1378 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1380 r
= nsec3_is_good(enclosure_rr
, zone_rr
);
1386 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1389 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr
->key
), hashed_domain
);
1393 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1394 goto found_closest_encloser
;
1398 /* We didn't find the closest encloser with this name,
1399 * but let's remember this domain name, it might be
1400 * the next closer name */
1404 /* Strip one label from the front */
1405 r
= dns_name_parent(&p
);
1412 *result
= DNSSEC_NSEC_NO_RR
;
1415 found_closest_encloser
:
1416 /* We found a closest encloser in 'p'; next closer is 'pp' */
1418 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1419 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1422 /* Ensure that this data is from the delegated domain
1423 * (i.e. originates from the "lower" DNS server), and isn't
1424 * just glue records (i.e. doesn't originate from the "upper"
1426 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1427 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1431 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1432 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1433 *result
= DNSSEC_NSEC_FOUND
;
1434 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1435 *result
= DNSSEC_NSEC_CNAME
;
1437 *result
= DNSSEC_NSEC_NODATA
;
1442 *ttl
= enclosure_rr
->ttl
;
1447 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1449 wildcard
= strjoina("*.", p
);
1450 r
= nsec3_hashed_domain_make(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1453 if (r
!= hashed_size
)
1456 r
= nsec3_hashed_domain_make(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1459 if (r
!= hashed_size
)
1462 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1463 _cleanup_free_
char *next_hashed_domain
= NULL
;
1465 r
= nsec3_is_good(rr
, zone_rr
);
1471 r
= nsec3_hashed_domain_format(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, zone
, &next_hashed_domain
);
1475 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1479 if (rr
->nsec3
.flags
& 1)
1482 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1487 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
);
1491 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1496 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
, next_hashed_domain
);
1500 if (rr
->nsec3
.flags
& 1)
1501 /* This only makes sense if we have a wildcard delegation, which is
1502 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1503 * this not happening, so hence cannot simply conclude NXDOMAIN as
1507 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1513 if (wildcard_rr
&& no_wildcard
)
1517 *result
= DNSSEC_NSEC_NO_RR
;
1522 /* A wildcard exists that matches our query. */
1524 /* This is not specified in any RFC to the best of my knowledge, but
1525 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1526 * it means that we cannot prove that the source of synthesis is
1527 * correct, as there may be a closer match. */
1528 *result
= DNSSEC_NSEC_OPTOUT
;
1529 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1530 *result
= DNSSEC_NSEC_FOUND
;
1531 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1532 *result
= DNSSEC_NSEC_CNAME
;
1534 *result
= DNSSEC_NSEC_NODATA
;
1537 /* The RFC only specifies that we have to care for optout for NODATA for
1538 * DS records. However, children of an insecure opt-out delegation should
1539 * also be considered opt-out, rather than verified NXDOMAIN.
1540 * Note that we do not require a proof of wildcard non-existence if the
1541 * next closer domain is covered by an opt-out, as that would not provide
1542 * any additional information. */
1543 *result
= DNSSEC_NSEC_OPTOUT
;
1544 else if (no_wildcard
)
1545 *result
= DNSSEC_NSEC_NXDOMAIN
;
1547 *result
= DNSSEC_NSEC_NO_RR
;
1557 *ttl
= enclosure_rr
->ttl
;
1562 int dnssec_nsec_test(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1563 DnsResourceRecord
*rr
;
1564 bool have_nsec3
= false;
1565 DnsAnswerFlags flags
;
1571 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1573 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1575 if (rr
->key
->class != key
->class)
1578 switch (rr
->key
->type
) {
1582 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
1586 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1587 *result
= DNSSEC_NSEC_FOUND
;
1588 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1589 *result
= DNSSEC_NSEC_CNAME
;
1591 *result
= DNSSEC_NSEC_NODATA
;
1594 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1601 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
), rr
->nsec
.next_domain_name
);
1605 *result
= DNSSEC_NSEC_NXDOMAIN
;
1608 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1616 case DNS_TYPE_NSEC3
:
1622 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1624 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
1626 /* No approproate NSEC RR found, report this. */
1627 *result
= DNSSEC_NSEC_NO_RR
;
1631 int dnssec_nsec_test_enclosed(DnsAnswer
*answer
, uint16_t type
, const char *name
, const char *zone
, bool *authenticated
) {
1632 DnsResourceRecord
*rr
;
1633 DnsAnswerFlags flags
;
1639 /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified
1640 * 'zone'. The 'zone' must be a suffix of the 'name'. */
1642 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1645 if (rr
->key
->type
!= type
&& type
!= DNS_TYPE_ANY
)
1648 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(rr
->key
), zone
);
1654 switch (rr
->key
->type
) {
1657 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), name
, rr
->nsec
.next_domain_name
);
1664 case DNS_TYPE_NSEC3
: {
1665 _cleanup_free_
char *hashed_domain
= NULL
, *next_hashed_domain
= NULL
;
1667 r
= nsec3_is_good(rr
, NULL
);
1673 /* Format the domain we are testing with the NSEC3 RR's hash function */
1674 r
= nsec3_hashed_domain_make(
1681 if ((size_t) r
!= rr
->nsec3
.next_hashed_name_size
)
1684 /* Format the NSEC3's next hashed name as proper domain name */
1685 r
= nsec3_hashed_domain_format(
1686 rr
->nsec3
.next_hashed_name
,
1687 rr
->nsec3
.next_hashed_name_size
,
1689 &next_hashed_domain
);
1693 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), hashed_domain
, next_hashed_domain
);
1707 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1715 static int dnssec_test_positive_wildcard_nsec3(
1720 bool *authenticated
) {
1722 const char *next_closer
= NULL
;
1725 /* Run a positive NSEC3 wildcard proof. Specifically:
1727 * A proof that the the "next closer" of the generating wildcard does not exist.
1729 * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
1730 * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
1731 * exists for the NSEC3 RR and we are done.
1733 * 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
1734 * c.d.e.f does not exist. */
1738 r
= dns_name_parent(&name
);
1744 r
= dns_name_equal(name
, source
);
1751 return dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC3
, next_closer
, zone
, authenticated
);
1754 static int dnssec_test_positive_wildcard_nsec(
1759 bool *_authenticated
) {
1761 bool authenticated
= true;
1764 /* Run a positive NSEC wildcard proof. Specifically:
1766 * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and
1767 * a prefix of the synthesizing source "source" in the zone "zone".
1769 * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4
1771 * 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
1772 * have to prove that none of the following exist:
1783 _cleanup_free_
char *wc
= NULL
;
1786 /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing,
1787 * i.e between the owner name and the next name of an NSEC RR. */
1788 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, name
, zone
, &a
);
1792 authenticated
= authenticated
&& a
;
1794 /* Strip one label off */
1795 r
= dns_name_parent(&name
);
1799 /* Did we reach the source of synthesis? */
1800 r
= dns_name_equal(name
, source
);
1804 /* Successful exit */
1805 *_authenticated
= authenticated
;
1809 /* Safety check, that the source of synthesis is still our suffix */
1810 r
= dns_name_endswith(name
, source
);
1816 /* Replace the label we stripped off with an asterisk */
1817 wc
= strappend("*.", name
);
1821 /* And check if the proof holds for the asterisk name, too */
1822 r
= dnssec_nsec_test_enclosed(answer
, DNS_TYPE_NSEC
, wc
, zone
, &a
);
1826 authenticated
= authenticated
&& a
;
1827 /* In the next iteration we'll check the non-asterisk-prefixed version */
1831 int dnssec_test_positive_wildcard(
1836 bool *authenticated
) {
1843 assert(authenticated
);
1845 r
= dns_answer_contains_zone_nsec3(answer
, zone
);
1849 return dnssec_test_positive_wildcard_nsec3(answer
, name
, source
, zone
, authenticated
);
1851 return dnssec_test_positive_wildcard_nsec(answer
, name
, source
, zone
, authenticated
);
1854 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
1855 [DNSSEC_VALIDATED
] = "validated",
1856 [DNSSEC_VALIDATED_WILDCARD
] = "validated-wildcard",
1857 [DNSSEC_INVALID
] = "invalid",
1858 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
1859 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
1860 [DNSSEC_NO_SIGNATURE
] = "no-signature",
1861 [DNSSEC_MISSING_KEY
] = "missing-key",
1862 [DNSSEC_UNSIGNED
] = "unsigned",
1863 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
1864 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
1865 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
1867 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);