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 * - Iterative validation
39 * - NSEC proof of non-existance
40 * - NSEC3 proof of non-existance
41 * - Make trust anchor store read additional DS+DNSKEY data from disk
42 * - wildcard zones compatibility
43 * - multi-label zone compatibility
44 * - DNSSEC cname/dname compatibility
45 * - per-interface DNSSEC setting
46 * - retry on failed validation
47 * - fix TTL for cache entries to match RRSIG TTL
53 #define VERIFY_RRS_MAX 256
54 #define MAX_KEY_SIZE (32*1024)
56 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
57 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
60 * The DNSSEC Chain of trust:
62 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
63 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
64 * DS RRs are protected like normal RRs
67 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
70 static void initialize_libgcrypt(void) {
73 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
76 p
= gcry_check_version("1.4.5");
79 gcry_control(GCRYCTL_DISABLE_SECMEM
);
80 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
83 static bool dnssec_algorithm_supported(int algorithm
) {
84 return IN_SET(algorithm
,
85 DNSSEC_ALGORITHM_RSASHA1
,
86 DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
,
87 DNSSEC_ALGORITHM_RSASHA256
,
88 DNSSEC_ALGORITHM_RSASHA512
);
91 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
) {
96 /* The algorithm from RFC 4034, Appendix B. */
99 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
101 sum
= (uint32_t) dnskey
->dnskey
.flags
+
102 ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
104 p
= dnskey
->dnskey
.key
;
106 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
107 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
109 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
111 return sum
& UINT32_C(0xFFFF);
114 static int rr_compare(const void *a
, const void *b
) {
115 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
119 /* Let's order the RRs according to RFC 4034, Section 6.3 */
123 assert((*x
)->wire_format
);
126 assert((*y
)->wire_format
);
128 m
= MIN((*x
)->wire_format_size
, (*y
)->wire_format_size
);
130 r
= memcmp((*x
)->wire_format
, (*y
)->wire_format
, m
);
134 if ((*x
)->wire_format_size
< (*y
)->wire_format_size
)
136 else if ((*x
)->wire_format_size
> (*y
)->wire_format_size
)
142 static int dnssec_rsa_verify(
143 const char *hash_algorithm
,
144 const void *signature
, size_t signature_size
,
145 const void *data
, size_t data_size
,
146 const void *exponent
, size_t exponent_size
,
147 const void *modulus
, size_t modulus_size
) {
149 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
150 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
154 assert(hash_algorithm
);
156 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
162 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
168 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
174 ge
= gcry_sexp_build(&signature_sexp
,
176 "(sig-val (rsa (s %m)))",
184 ge
= gcry_sexp_build(&data_sexp
,
186 "(data (flags pkcs1) (hash %s %b))",
195 ge
= gcry_sexp_build(&public_key_sexp
,
197 "(public-key (rsa (n %m) (e %m)))",
205 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
206 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
209 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
223 gcry_sexp_release(public_key_sexp
);
225 gcry_sexp_release(signature_sexp
);
227 gcry_sexp_release(data_sexp
);
232 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
233 gcry_md_write(md
, &v
, sizeof(v
));
236 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
238 gcry_md_write(md
, &v
, sizeof(v
));
241 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
243 gcry_md_write(md
, &v
, sizeof(v
));
246 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
247 usec_t expiration
, inception
, skew
;
250 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
252 if (realtime
== USEC_INFINITY
)
253 realtime
= now(CLOCK_REALTIME
);
255 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
256 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
258 if (inception
> expiration
)
259 return -EKEYREJECTED
;
261 /* Permit a certain amount of clock skew of 10% of the valid
262 * time range. This takes inspiration from unbound's
264 skew
= (expiration
- inception
) / 10;
268 if (inception
< skew
)
273 if (expiration
+ skew
< expiration
)
274 expiration
= USEC_INFINITY
;
278 return realtime
< inception
|| realtime
> expiration
;
281 int dnssec_verify_rrset(
284 DnsResourceRecord
*rrsig
,
285 DnsResourceRecord
*dnskey
,
287 DnssecResult
*result
) {
289 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
290 size_t exponent_size
, modulus_size
, hash_size
;
291 void *exponent
, *modulus
, *hash
;
292 DnsResourceRecord
**list
, *rr
;
293 gcry_md_hd_t md
= NULL
;
301 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
302 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
304 /* Verifies the the RRSet matching the specified "key" in "a",
305 * using the signature "rrsig" and the key "dnskey". It's
306 * assumed the RRSIG and DNSKEY match. */
308 if (!dnssec_algorithm_supported(rrsig
->rrsig
.algorithm
)) {
309 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
313 if (a
->n_rrs
> VERIFY_RRS_MAX
)
316 r
= dnssec_rrsig_expired(rrsig
, realtime
);
320 *result
= DNSSEC_SIGNATURE_EXPIRED
;
324 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
325 list
= newa(DnsResourceRecord
*, a
->n_rrs
);
327 DNS_ANSWER_FOREACH(rr
, a
) {
328 r
= dns_resource_key_equal(key
, rr
->key
);
334 /* We need the wire format for ordering, and digest calculation */
335 r
= dns_resource_record_to_wire_format(rr
, true);
345 /* Bring the RRs into canonical order */
346 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
348 initialize_libgcrypt();
350 /* OK, the RRs are now in canonical order. Let's calculate the digest */
351 switch (rrsig
->rrsig
.algorithm
) {
353 case DNSSEC_ALGORITHM_RSASHA1
:
354 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
355 gcry_md_open(&md
, GCRY_MD_SHA1
, 0);
359 case DNSSEC_ALGORITHM_RSASHA256
:
360 gcry_md_open(&md
, GCRY_MD_SHA256
, 0);
364 case DNSSEC_ALGORITHM_RSASHA512
:
365 gcry_md_open(&md
, GCRY_MD_SHA512
, 0);
370 assert_not_reached("Unknown digest");
376 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
377 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
378 md_add_uint8(md
, rrsig
->rrsig
.labels
);
379 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
380 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
381 md_add_uint32(md
, rrsig
->rrsig
.inception
);
382 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
384 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
387 gcry_md_write(md
, wire_format_name
, r
);
389 for (k
= 0; k
< n
; k
++) {
393 r
= dns_name_to_wire_format(DNS_RESOURCE_KEY_NAME(rr
->key
), wire_format_name
, sizeof(wire_format_name
), true);
396 gcry_md_write(md
, wire_format_name
, r
);
398 md_add_uint16(md
, rr
->key
->type
);
399 md_add_uint16(md
, rr
->key
->class);
400 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
402 assert(rr
->wire_format_rdata_offset
<= rr
->wire_format_size
);
403 l
= rr
->wire_format_size
- rr
->wire_format_rdata_offset
;
406 md_add_uint16(md
, (uint16_t) l
);
407 gcry_md_write(md
, (uint8_t*) rr
->wire_format
+ rr
->wire_format_rdata_offset
, l
);
410 hash
= gcry_md_read(md
, 0);
416 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
417 /* exponent is > 255 bytes long */
419 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
421 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[0]) << 8) |
422 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[1]);
424 if (exponent_size
< 256) {
429 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
) {
434 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
435 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
438 /* exponent is <= 255 bytes long */
440 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
441 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
443 if (exponent_size
<= 0) {
448 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
) {
453 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
454 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
457 r
= dnssec_rsa_verify(
458 gcry_md_algo_name(gcry_md_get_algo(md
)),
459 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
461 exponent
, exponent_size
,
462 modulus
, modulus_size
);
466 *result
= r
? DNSSEC_VALIDATED
: DNSSEC_INVALID
;
474 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
) {
479 /* Checks if the specified DNSKEY RR matches the key used for
480 * the signature in the specified RRSIG RR */
482 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
485 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
487 if (dnskey
->key
->class != rrsig
->key
->class)
489 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
491 if (dnskey
->dnskey
.protocol
!= 3)
493 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
496 if (dnssec_keytag(dnskey
) != rrsig
->rrsig
.key_tag
)
499 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
502 int dnssec_key_match_rrsig(DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
506 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
508 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
510 if (rrsig
->key
->class != key
->class)
512 if (rrsig
->rrsig
.type_covered
!= key
->type
)
515 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
518 int dnssec_verify_rrset_search(
521 DnsAnswer
*validated_dnskeys
,
523 DnssecResult
*result
) {
525 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
526 DnsResourceRecord
*rrsig
;
532 /* Verifies all RRs from "a" that match the key "key", against DNSKEY and DS RRs in "validated_dnskeys" */
534 if (!a
|| a
->n_rrs
<= 0)
537 /* Iterate through each RRSIG RR. */
538 DNS_ANSWER_FOREACH(rrsig
, a
) {
539 DnsResourceRecord
*dnskey
;
541 /* Is this an RRSIG RR that applies to RRs matching our key? */
542 r
= dnssec_key_match_rrsig(key
, rrsig
);
550 /* Look for a matching key */
551 DNS_ANSWER_FOREACH(dnskey
, validated_dnskeys
) {
552 DnssecResult one_result
;
554 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
555 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
);
561 /* Take the time here, if it isn't set yet, so
562 * that we do all validations with the same
564 if (realtime
== USEC_INFINITY
)
565 realtime
= now(CLOCK_REALTIME
);
567 /* Yay, we found a matching RRSIG with a matching
568 * DNSKEY, awesome. Now let's verify all entries of
569 * the RRSet against the RRSIG and DNSKEY
572 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
576 switch (one_result
) {
578 case DNSSEC_VALIDATED
:
579 /* Yay, the RR has been validated,
580 * return immediately. */
581 *result
= DNSSEC_VALIDATED
;
585 /* If the signature is invalid, let's try another
586 key and/or signature. After all they
587 key_tags and stuff are not unique, and
588 might be shared by multiple keys. */
589 found_invalid
= true;
592 case DNSSEC_UNSUPPORTED_ALGORITHM
:
593 /* If the key algorithm is
594 unsupported, try another
595 RRSIG/DNSKEY pair, but remember we
596 encountered this, so that we can
597 return a proper error when we
598 encounter nothing better. */
599 found_unsupported_algorithm
= true;
602 case DNSSEC_SIGNATURE_EXPIRED
:
603 /* If the signature is expired, try
604 another one, but remember it, so
605 that we can return this */
606 found_expired_rrsig
= true;
610 assert_not_reached("Unexpected DNSSEC validation result");
615 if (found_expired_rrsig
)
616 *result
= DNSSEC_SIGNATURE_EXPIRED
;
617 else if (found_unsupported_algorithm
)
618 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
619 else if (found_invalid
)
620 *result
= DNSSEC_INVALID
;
621 else if (found_rrsig
)
622 *result
= DNSSEC_MISSING_KEY
;
624 *result
= DNSSEC_NO_SIGNATURE
;
629 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
633 /* Converts the specified hostname into DNSSEC canonicalized
642 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
650 /* DNSSEC validation is always done on the ASCII version of the label */
651 k
= dns_label_apply_idna(buffer
, r
, buffer
, buffer_max
);
658 if (buffer_max
< (size_t) r
+ 2)
661 /* The DNSSEC canonical form is not clear on what to
662 * do with dots appearing in labels, the way DNS-SD
663 * does it. Refuse it for now. */
665 if (memchr(buffer
, '.', r
))
668 for (i
= 0; i
< (size_t) r
; i
++) {
669 if (buffer
[i
] >= 'A' && buffer
[i
] <= 'Z')
670 buffer
[i
] = buffer
[i
] - 'A' + 'a';
682 /* Not even a single label: this is the root domain name */
684 assert(buffer_max
> 2);
694 static int digest_to_gcrypt(uint8_t algorithm
) {
696 /* Translates a DNSSEC digest algorithm into a gcrypt digest iedntifier */
700 case DNSSEC_DIGEST_SHA1
:
703 case DNSSEC_DIGEST_SHA256
:
704 return GCRY_MD_SHA256
;
711 int dnssec_verify_dnskey(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
) {
712 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
713 gcry_md_hd_t md
= NULL
;
722 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
724 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
726 if (ds
->key
->type
!= DNS_TYPE_DS
)
728 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
729 return -EKEYREJECTED
;
730 if (dnskey
->dnskey
.protocol
!= 3)
731 return -EKEYREJECTED
;
733 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
735 if (dnssec_keytag(dnskey
) != ds
->ds
.key_tag
)
738 initialize_libgcrypt();
740 algorithm
= digest_to_gcrypt(ds
->ds
.digest_type
);
744 hash_size
= gcry_md_get_algo_dlen(algorithm
);
745 assert(hash_size
> 0);
747 if (ds
->ds
.digest_size
!= hash_size
)
750 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
754 gcry_md_open(&md
, algorithm
, 0);
758 gcry_md_write(md
, owner_name
, r
);
759 md_add_uint16(md
, dnskey
->dnskey
.flags
);
760 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
761 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
762 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
764 result
= gcry_md_read(md
, 0);
770 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
777 int dnssec_verify_dnskey_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
778 DnsResourceRecord
*ds
;
783 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
786 DNS_ANSWER_FOREACH(ds
, validated_ds
) {
788 if (ds
->key
->type
!= DNS_TYPE_DS
)
791 r
= dnssec_verify_dnskey(dnskey
, ds
);
801 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
802 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
803 gcry_md_hd_t md
= NULL
;
814 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
817 algorithm
= digest_to_gcrypt(nsec3
->nsec3
.algorithm
);
821 initialize_libgcrypt();
823 hash_size
= gcry_md_get_algo_dlen(algorithm
);
824 assert(hash_size
> 0);
826 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
829 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
833 gcry_md_open(&md
, algorithm
, 0);
837 gcry_md_write(md
, wire_format
, r
);
838 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
840 result
= gcry_md_read(md
, 0);
846 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
847 uint8_t tmp
[hash_size
];
848 memcpy(tmp
, result
, hash_size
);
851 gcry_md_write(md
, tmp
, hash_size
);
852 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
854 result
= gcry_md_read(md
, 0);
861 memcpy(ret
, result
, hash_size
);
869 int dnssec_test_nsec(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
) {
870 DnsResourceRecord
*rr
;
876 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
878 DNS_ANSWER_FOREACH(rr
, answer
) {
880 if (rr
->key
->class != key
->class)
883 switch (rr
->key
->type
) {
887 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
891 *result
= bitmap_isset(rr
->nsec
.types
, key
->type
) ? DNSSEC_NSEC_FOUND
: DNSSEC_NSEC_NODATA
;
895 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
), rr
->nsec
.next_domain_name
);
899 *result
= DNSSEC_NSEC_NXDOMAIN
;
904 case DNS_TYPE_NSEC3
: {
905 _cleanup_free_
void *decoded
= NULL
;
907 char label
[DNS_LABEL_MAX
];
908 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
909 int label_length
, c
, q
;
913 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
914 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
917 p
= DNS_RESOURCE_KEY_NAME(rr
->key
);
918 label_length
= dns_label_unescape(&p
, label
, sizeof(label
));
919 if (label_length
< 0)
921 if (label_length
== 0)
924 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), p
);
930 r
= unbase32hexmem(label
, label_length
, false, &decoded
, &decoded_size
);
936 if (decoded_size
!= rr
->nsec3
.next_hashed_name_size
)
939 c
= memcmp(decoded
, rr
->nsec3
.next_hashed_name
, decoded_size
);
943 r
= dnssec_nsec3_hash(rr
, DNS_RESOURCE_KEY_NAME(key
), hashed
);
944 /* RFC 5155, Section 8.1 says we MUST ignore NSEC3 RRs with unknown algorithms */
945 if (r
== -EOPNOTSUPP
)
949 if ((size_t) r
!= decoded_size
)
952 r
= memcmp(decoded
, hashed
, decoded_size
);
954 *result
= bitmap_isset(rr
->nsec3
.types
, key
->type
) ? DNSSEC_NSEC_FOUND
: DNSSEC_NSEC_NODATA
;
958 q
= memcmp(hashed
, rr
->nsec3
.next_hashed_name
, decoded_size
);
965 *result
= DNSSEC_NSEC_NXDOMAIN
;
977 /* No approproate NSEC RR found, report this. */
978 *result
= DNSSEC_NSEC_NO_RR
;
982 static const char* const dnssec_mode_table
[_DNSSEC_MODE_MAX
] = {
984 [DNSSEC_TRUST
] = "trust",
985 [DNSSEC_YES
] = "yes",
987 DEFINE_STRING_TABLE_LOOKUP(dnssec_mode
, DnssecMode
);
989 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
990 [DNSSEC_VALIDATED
] = "validated",
991 [DNSSEC_INVALID
] = "invalid",
992 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
993 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
994 [DNSSEC_NO_SIGNATURE
] = "no-signature",
995 [DNSSEC_MISSING_KEY
] = "missing-key",
996 [DNSSEC_UNSIGNED
] = "unsigned",
997 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
998 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
1000 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);