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
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)
58 * The DNSSEC Chain of trust:
60 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
61 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
62 * DS RRs are protected like normal RRs
65 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
68 static void initialize_libgcrypt(void) {
71 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
74 p
= gcry_check_version("1.4.5");
77 gcry_control(GCRYCTL_DISABLE_SECMEM
);
78 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
81 static bool dnssec_algorithm_supported(int algorithm
) {
82 return IN_SET(algorithm
,
83 DNSSEC_ALGORITHM_RSASHA1
,
84 DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
,
85 DNSSEC_ALGORITHM_RSASHA256
,
86 DNSSEC_ALGORITHM_RSASHA512
);
89 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
) {
94 /* The algorithm from RFC 4034, Appendix B. */
97 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
99 sum
= (uint32_t) dnskey
->dnskey
.flags
+
100 ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
102 p
= dnskey
->dnskey
.key
;
104 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
105 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
107 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
109 return sum
& UINT32_C(0xFFFF);
112 static int rr_compare(const void *a
, const void *b
) {
113 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
117 /* Let's order the RRs according to RFC 4034, Section 6.3 */
121 assert((*x
)->wire_format
);
124 assert((*y
)->wire_format
);
126 m
= MIN((*x
)->wire_format_size
, (*y
)->wire_format_size
);
128 r
= memcmp((*x
)->wire_format
, (*y
)->wire_format
, m
);
132 if ((*x
)->wire_format_size
< (*y
)->wire_format_size
)
134 else if ((*x
)->wire_format_size
> (*y
)->wire_format_size
)
140 static int dnssec_rsa_verify(
141 const char *hash_algorithm
,
142 const void *signature
, size_t signature_size
,
143 const void *data
, size_t data_size
,
144 const void *exponent
, size_t exponent_size
,
145 const void *modulus
, size_t modulus_size
) {
147 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
148 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
152 assert(hash_algorithm
);
154 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
160 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
166 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
172 ge
= gcry_sexp_build(&signature_sexp
,
174 "(sig-val (rsa (s %m)))",
182 ge
= gcry_sexp_build(&data_sexp
,
184 "(data (flags pkcs1) (hash %s %b))",
193 ge
= gcry_sexp_build(&public_key_sexp
,
195 "(public-key (rsa (n %m) (e %m)))",
203 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
204 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
207 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
221 gcry_sexp_release(public_key_sexp
);
223 gcry_sexp_release(signature_sexp
);
225 gcry_sexp_release(data_sexp
);
230 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
231 gcry_md_write(md
, &v
, sizeof(v
));
234 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
236 gcry_md_write(md
, &v
, sizeof(v
));
239 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
241 gcry_md_write(md
, &v
, sizeof(v
));
244 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
245 usec_t expiration
, inception
, skew
;
248 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
250 if (realtime
== USEC_INFINITY
)
251 realtime
= now(CLOCK_REALTIME
);
253 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
254 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
256 if (inception
> expiration
)
257 return -EKEYREJECTED
;
259 /* Permit a certain amount of clock skew of 10% of the valid
260 * time range. This takes inspiration from unbound's
262 skew
= (expiration
- inception
) / 10;
266 if (inception
< skew
)
271 if (expiration
+ skew
< expiration
)
272 expiration
= USEC_INFINITY
;
276 return realtime
< inception
|| realtime
> expiration
;
279 int dnssec_verify_rrset(
282 DnsResourceRecord
*rrsig
,
283 DnsResourceRecord
*dnskey
,
285 DnssecResult
*result
) {
287 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
288 size_t exponent_size
, modulus_size
, hash_size
;
289 void *exponent
, *modulus
, *hash
;
290 DnsResourceRecord
**list
, *rr
;
291 gcry_md_hd_t md
= NULL
;
299 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
300 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
302 /* Verifies the the RRSet matching the specified "key" in "a",
303 * using the signature "rrsig" and the key "dnskey". It's
304 * assumed the RRSIG and DNSKEY match. */
306 if (!dnssec_algorithm_supported(rrsig
->rrsig
.algorithm
)) {
307 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
311 if (a
->n_rrs
> VERIFY_RRS_MAX
)
314 r
= dnssec_rrsig_expired(rrsig
, realtime
);
318 *result
= DNSSEC_SIGNATURE_EXPIRED
;
322 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
323 list
= newa(DnsResourceRecord
*, a
->n_rrs
);
325 DNS_ANSWER_FOREACH(rr
, a
) {
326 r
= dns_resource_key_equal(key
, rr
->key
);
332 /* We need the wire format for ordering, and digest calculation */
333 r
= dns_resource_record_to_wire_format(rr
, true);
343 /* Bring the RRs into canonical order */
344 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
346 initialize_libgcrypt();
348 /* OK, the RRs are now in canonical order. Let's calculate the digest */
349 switch (rrsig
->rrsig
.algorithm
) {
351 case DNSSEC_ALGORITHM_RSASHA1
:
352 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
353 gcry_md_open(&md
, GCRY_MD_SHA1
, 0);
357 case DNSSEC_ALGORITHM_RSASHA256
:
358 gcry_md_open(&md
, GCRY_MD_SHA256
, 0);
362 case DNSSEC_ALGORITHM_RSASHA512
:
363 gcry_md_open(&md
, GCRY_MD_SHA512
, 0);
368 assert_not_reached("Unknown digest");
374 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
375 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
376 md_add_uint8(md
, rrsig
->rrsig
.labels
);
377 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
378 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
379 md_add_uint32(md
, rrsig
->rrsig
.inception
);
380 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
382 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
385 gcry_md_write(md
, wire_format_name
, r
);
387 for (k
= 0; k
< n
; k
++) {
391 r
= dns_name_to_wire_format(DNS_RESOURCE_KEY_NAME(rr
->key
), wire_format_name
, sizeof(wire_format_name
), true);
394 gcry_md_write(md
, wire_format_name
, r
);
396 md_add_uint16(md
, rr
->key
->type
);
397 md_add_uint16(md
, rr
->key
->class);
398 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
400 assert(rr
->wire_format_rdata_offset
<= rr
->wire_format_size
);
401 l
= rr
->wire_format_size
- rr
->wire_format_rdata_offset
;
404 md_add_uint16(md
, (uint16_t) l
);
405 gcry_md_write(md
, (uint8_t*) rr
->wire_format
+ rr
->wire_format_rdata_offset
, l
);
408 hash
= gcry_md_read(md
, 0);
414 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
415 /* exponent is > 255 bytes long */
417 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
419 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[0]) << 8) |
420 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[1]);
422 if (exponent_size
< 256) {
427 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
) {
432 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
433 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
436 /* exponent is <= 255 bytes long */
438 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
439 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
441 if (exponent_size
<= 0) {
446 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
) {
451 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
452 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
455 r
= dnssec_rsa_verify(
456 gcry_md_algo_name(gcry_md_get_algo(md
)),
457 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
459 exponent
, exponent_size
,
460 modulus
, modulus_size
);
464 *result
= r
? DNSSEC_VALIDATED
: DNSSEC_INVALID
;
472 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
) {
477 /* Checks if the specified DNSKEY RR matches the key used for
478 * the signature in the specified RRSIG RR */
480 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
483 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
485 if (dnskey
->key
->class != rrsig
->key
->class)
487 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
489 if (dnskey
->dnskey
.protocol
!= 3)
491 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
494 if (dnssec_keytag(dnskey
) != rrsig
->rrsig
.key_tag
)
497 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
500 int dnssec_key_match_rrsig(DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
504 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
506 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
508 if (rrsig
->key
->class != key
->class)
510 if (rrsig
->rrsig
.type_covered
!= key
->type
)
513 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
516 int dnssec_verify_rrset_search(
519 DnsAnswer
*validated_dnskeys
,
521 DnssecResult
*result
) {
523 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
524 DnsResourceRecord
*rrsig
;
530 /* Verifies all RRs from "a" that match the key "key", against DNSKEY and DS RRs in "validated_dnskeys" */
532 if (!a
|| a
->n_rrs
<= 0)
535 /* Iterate through each RRSIG RR. */
536 DNS_ANSWER_FOREACH(rrsig
, a
) {
537 DnsResourceRecord
*dnskey
;
539 /* Is this an RRSIG RR that applies to RRs matching our key? */
540 r
= dnssec_key_match_rrsig(key
, rrsig
);
548 /* Look for a matching key */
549 DNS_ANSWER_FOREACH(dnskey
, validated_dnskeys
) {
550 DnssecResult one_result
;
552 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
553 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
);
559 /* Take the time here, if it isn't set yet, so
560 * that we do all validations with the same
562 if (realtime
== USEC_INFINITY
)
563 realtime
= now(CLOCK_REALTIME
);
565 /* Yay, we found a matching RRSIG with a matching
566 * DNSKEY, awesome. Now let's verify all entries of
567 * the RRSet against the RRSIG and DNSKEY
570 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
574 switch (one_result
) {
576 case DNSSEC_VALIDATED
:
577 /* Yay, the RR has been validated,
578 * return immediately. */
579 *result
= DNSSEC_VALIDATED
;
583 /* If the signature is invalid, let's try another
584 key and/or signature. After all they
585 key_tags and stuff are not unique, and
586 might be shared by multiple keys. */
587 found_invalid
= true;
590 case DNSSEC_UNSUPPORTED_ALGORITHM
:
591 /* If the key algorithm is
592 unsupported, try another
593 RRSIG/DNSKEY pair, but remember we
594 encountered this, so that we can
595 return a proper error when we
596 encounter nothing better. */
597 found_unsupported_algorithm
= true;
600 case DNSSEC_SIGNATURE_EXPIRED
:
601 /* If the signature is expired, try
602 another one, but remember it, so
603 that we can return this */
604 found_expired_rrsig
= true;
608 assert_not_reached("Unexpected DNSSEC validation result");
613 if (found_expired_rrsig
)
614 *result
= DNSSEC_SIGNATURE_EXPIRED
;
615 else if (found_unsupported_algorithm
)
616 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
617 else if (found_invalid
)
618 *result
= DNSSEC_INVALID
;
619 else if (found_rrsig
)
620 *result
= DNSSEC_MISSING_KEY
;
622 *result
= DNSSEC_NO_SIGNATURE
;
627 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
631 /* Converts the specified hostname into DNSSEC canonicalized
640 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
648 /* DNSSEC validation is always done on the ASCII version of the label */
649 k
= dns_label_apply_idna(buffer
, r
, buffer
, buffer_max
);
656 if (buffer_max
< (size_t) r
+ 2)
659 /* The DNSSEC canonical form is not clear on what to
660 * do with dots appearing in labels, the way DNS-SD
661 * does it. Refuse it for now. */
663 if (memchr(buffer
, '.', r
))
666 for (i
= 0; i
< (size_t) r
; i
++) {
667 if (buffer
[i
] >= 'A' && buffer
[i
] <= 'Z')
668 buffer
[i
] = buffer
[i
] - 'A' + 'a';
680 /* Not even a single label: this is the root domain name */
682 assert(buffer_max
> 2);
692 static int digest_to_gcrypt(uint8_t algorithm
) {
694 /* Translates a DNSSEC digest algorithm into a gcrypt digest iedntifier */
698 case DNSSEC_DIGEST_SHA1
:
701 case DNSSEC_DIGEST_SHA256
:
702 return GCRY_MD_SHA256
;
709 int dnssec_verify_dnskey(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
) {
710 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
711 gcry_md_hd_t md
= NULL
;
720 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
722 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
724 if (ds
->key
->type
!= DNS_TYPE_DS
)
726 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
727 return -EKEYREJECTED
;
728 if (dnskey
->dnskey
.protocol
!= 3)
729 return -EKEYREJECTED
;
731 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
733 if (dnssec_keytag(dnskey
) != ds
->ds
.key_tag
)
736 initialize_libgcrypt();
738 algorithm
= digest_to_gcrypt(ds
->ds
.digest_type
);
742 hash_size
= gcry_md_get_algo_dlen(algorithm
);
743 assert(hash_size
> 0);
745 if (ds
->ds
.digest_size
!= hash_size
)
748 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
752 gcry_md_open(&md
, algorithm
, 0);
756 gcry_md_write(md
, owner_name
, r
);
757 md_add_uint16(md
, dnskey
->dnskey
.flags
);
758 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
759 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
760 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
762 result
= gcry_md_read(md
, 0);
768 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
775 int dnssec_verify_dnskey_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
776 DnsResourceRecord
*ds
;
781 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
784 DNS_ANSWER_FOREACH(ds
, validated_ds
) {
786 if (ds
->key
->type
!= DNS_TYPE_DS
)
789 r
= dnssec_verify_dnskey(dnskey
, ds
);
799 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
800 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
801 gcry_md_hd_t md
= NULL
;
812 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
815 algorithm
= digest_to_gcrypt(nsec3
->nsec3
.algorithm
);
819 initialize_libgcrypt();
821 hash_size
= gcry_md_get_algo_dlen(algorithm
);
822 assert(hash_size
> 0);
824 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
827 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
831 gcry_md_open(&md
, algorithm
, 0);
835 gcry_md_write(md
, wire_format
, r
);
836 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
838 result
= gcry_md_read(md
, 0);
844 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
845 uint8_t tmp
[hash_size
];
846 memcpy(tmp
, result
, hash_size
);
849 gcry_md_write(md
, tmp
, hash_size
);
850 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
852 result
= gcry_md_read(md
, 0);
859 memcpy(ret
, result
, hash_size
);
867 int dnssec_test_nsec(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
) {
868 DnsResourceRecord
*rr
;
874 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
876 DNS_ANSWER_FOREACH(rr
, answer
) {
878 if (rr
->key
->class != key
->class)
881 switch (rr
->key
->type
) {
885 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
889 *result
= bitmap_isset(rr
->nsec
.types
, key
->type
) ? DNSSEC_NSEC_FOUND
: DNSSEC_NSEC_NODATA
;
893 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
), rr
->nsec
.next_domain_name
);
897 *result
= DNSSEC_NSEC_NXDOMAIN
;
902 case DNS_TYPE_NSEC3
: {
903 _cleanup_free_
void *decoded
= NULL
;
905 char label
[DNS_LABEL_MAX
];
906 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
907 int label_length
, c
, q
;
911 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
912 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
915 p
= DNS_RESOURCE_KEY_NAME(rr
->key
);
916 label_length
= dns_label_unescape(&p
, label
, sizeof(label
));
917 if (label_length
< 0)
919 if (label_length
== 0)
922 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), p
);
928 r
= unbase32hexmem(label
, label_length
, false, &decoded
, &decoded_size
);
934 if (decoded_size
!= rr
->nsec3
.next_hashed_name_size
)
937 c
= memcmp(decoded
, rr
->nsec3
.next_hashed_name
, decoded_size
);
941 r
= dnssec_nsec3_hash(rr
, DNS_RESOURCE_KEY_NAME(key
), hashed
);
942 /* RFC 5155, Section 8.1 says we MUST ignore NSEC3 RRs with unknown algorithms */
943 if (r
== -EOPNOTSUPP
)
947 if ((size_t) r
!= decoded_size
)
950 r
= memcmp(decoded
, hashed
, decoded_size
);
952 *result
= bitmap_isset(rr
->nsec3
.types
, key
->type
) ? DNSSEC_NSEC_FOUND
: DNSSEC_NSEC_NODATA
;
956 q
= memcmp(hashed
, rr
->nsec3
.next_hashed_name
, decoded_size
);
963 *result
= DNSSEC_NSEC_NXDOMAIN
;
975 /* No approproate NSEC RR found, report this. */
976 *result
= DNSSEC_NSEC_NO_RR
;
980 static const char* const dnssec_mode_table
[_DNSSEC_MODE_MAX
] = {
982 [DNSSEC_TRUST
] = "trust",
983 [DNSSEC_YES
] = "yes",
985 DEFINE_STRING_TABLE_LOOKUP(dnssec_mode
, DnssecMode
);
987 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
988 [DNSSEC_VALIDATED
] = "validated",
989 [DNSSEC_INVALID
] = "invalid",
990 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
991 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
992 [DNSSEC_NO_SIGNATURE
] = "no-signature",
993 [DNSSEC_MISSING_KEY
] = "missing-key",
994 [DNSSEC_UNSIGNED
] = "unsigned",
995 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
996 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
998 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);