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 * - Make trust anchor store read additional DS+DNSKEY data from disk
39 * - wildcard zones compatibility (NSEC/NSEC3 wildcard check is missing)
40 * - multi-label zone compatibility
41 * - cname/dname compatibility
42 * - per-interface DNSSEC setting
43 * - fix TTL for cache entries to match RRSIG TTL
44 * - retry on failed validation?
49 #define VERIFY_RRS_MAX 256
50 #define MAX_KEY_SIZE (32*1024)
52 /* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
53 #define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
56 * The DNSSEC Chain of trust:
58 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
59 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
60 * DS RRs are protected like normal RRs
63 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
66 static void initialize_libgcrypt(void) {
69 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
72 p
= gcry_check_version("1.4.5");
75 gcry_control(GCRYCTL_DISABLE_SECMEM
);
76 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
79 static bool dnssec_algorithm_supported(int algorithm
) {
80 return IN_SET(algorithm
,
81 DNSSEC_ALGORITHM_RSASHA1
,
82 DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
,
83 DNSSEC_ALGORITHM_RSASHA256
,
84 DNSSEC_ALGORITHM_RSASHA512
,
85 DNSSEC_ALGORITHM_ECDSAP256SHA256
,
86 DNSSEC_ALGORITHM_ECDSAP384SHA384
);
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_raw(
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 int dnssec_rsa_verify(
231 const char *hash_algorithm
,
232 const void *hash
, size_t hash_size
,
233 DnsResourceRecord
*rrsig
,
234 DnsResourceRecord
*dnskey
) {
236 size_t exponent_size
, modulus_size
;
237 void *exponent
, *modulus
;
239 assert(hash_algorithm
);
241 assert(hash_size
> 0);
245 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
246 /* exponent is > 255 bytes long */
248 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
250 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[0]) << 8) |
251 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[1]);
253 if (exponent_size
< 256)
256 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
259 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
260 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
263 /* exponent is <= 255 bytes long */
265 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
266 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
268 if (exponent_size
<= 0)
271 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
274 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
275 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
278 return dnssec_rsa_verify_raw(
280 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
282 exponent
, exponent_size
,
283 modulus
, modulus_size
);
286 static int dnssec_ecdsa_verify_raw(
287 const char *hash_algorithm
,
289 const void *signature_r
, size_t signature_r_size
,
290 const void *signature_s
, size_t signature_s_size
,
291 const void *data
, size_t data_size
,
292 const void *key
, size_t key_size
) {
294 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
295 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
299 assert(hash_algorithm
);
301 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
307 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
313 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
319 ge
= gcry_sexp_build(&signature_sexp
,
321 "(sig-val (ecdsa (r %m) (s %m)))",
329 ge
= gcry_sexp_build(&data_sexp
,
331 "(data (flags rfc6979) (hash %s %b))",
340 ge
= gcry_sexp_build(&public_key_sexp
,
342 "(public-key (ecc (curve %s) (q %m)))",
350 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
351 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
354 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
367 gcry_sexp_release(public_key_sexp
);
369 gcry_sexp_release(signature_sexp
);
371 gcry_sexp_release(data_sexp
);
376 static int dnssec_ecdsa_verify(
377 const char *hash_algorithm
,
379 const void *hash
, size_t hash_size
,
380 DnsResourceRecord
*rrsig
,
381 DnsResourceRecord
*dnskey
) {
392 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
394 curve
= "NIST P-256";
395 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
397 curve
= "NIST P-384";
401 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
404 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
407 q
= alloca(key_size
*2 + 1);
408 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
409 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
411 return dnssec_ecdsa_verify_raw(
414 rrsig
->rrsig
.signature
, key_size
,
415 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
420 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
421 gcry_md_write(md
, &v
, sizeof(v
));
424 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
426 gcry_md_write(md
, &v
, sizeof(v
));
429 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
431 gcry_md_write(md
, &v
, sizeof(v
));
434 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
435 usec_t expiration
, inception
, skew
;
438 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
440 if (realtime
== USEC_INFINITY
)
441 realtime
= now(CLOCK_REALTIME
);
443 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
444 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
446 if (inception
> expiration
)
447 return -EKEYREJECTED
;
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(uint8_t algorithm
) {
471 /* Translates a DNSSEC signature algorithm into a gcrypt digest identifier */
475 case DNSSEC_ALGORITHM_RSASHA1
:
476 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
479 case DNSSEC_ALGORITHM_RSASHA256
:
480 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
481 return GCRY_MD_SHA256
;
483 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
484 return GCRY_MD_SHA384
;
486 case DNSSEC_ALGORITHM_RSASHA512
:
487 return GCRY_MD_SHA512
;
494 int dnssec_verify_rrset(
497 DnsResourceRecord
*rrsig
,
498 DnsResourceRecord
*dnskey
,
500 DnssecResult
*result
) {
502 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
505 DnsResourceRecord
**list
, *rr
;
506 gcry_md_hd_t md
= NULL
;
514 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
515 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
517 /* Verifies the the RRSet matching the specified "key" in "a",
518 * using the signature "rrsig" and the key "dnskey". It's
519 * assumed the RRSIG and DNSKEY match. */
521 if (!dnssec_algorithm_supported(rrsig
->rrsig
.algorithm
)) {
522 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
526 if (a
->n_rrs
> VERIFY_RRS_MAX
)
529 r
= dnssec_rrsig_expired(rrsig
, realtime
);
533 *result
= DNSSEC_SIGNATURE_EXPIRED
;
537 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
538 list
= newa(DnsResourceRecord
*, a
->n_rrs
);
540 DNS_ANSWER_FOREACH(rr
, a
) {
541 r
= dns_resource_key_equal(key
, rr
->key
);
547 /* We need the wire format for ordering, and digest calculation */
548 r
= dns_resource_record_to_wire_format(rr
, true);
558 /* Bring the RRs into canonical order */
559 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
561 /* OK, the RRs are now in canonical order. Let's calculate the digest */
562 initialize_libgcrypt();
564 algorithm
= algorithm_to_gcrypt(rrsig
->rrsig
.algorithm
);
568 hash_size
= gcry_md_get_algo_dlen(algorithm
);
569 assert(hash_size
> 0);
571 gcry_md_open(&md
, algorithm
, 0);
575 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
576 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
577 md_add_uint8(md
, rrsig
->rrsig
.labels
);
578 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
579 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
580 md_add_uint32(md
, rrsig
->rrsig
.inception
);
581 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
583 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
586 gcry_md_write(md
, wire_format_name
, r
);
588 for (k
= 0; k
< n
; k
++) {
593 r
= dns_name_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rrsig
->rrsig
.labels
, &suffix
);
596 if (r
> 0) /* This is a wildcard! */
597 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
599 r
= dns_name_to_wire_format(suffix
, wire_format_name
, sizeof(wire_format_name
), true);
602 gcry_md_write(md
, wire_format_name
, r
);
604 md_add_uint16(md
, rr
->key
->type
);
605 md_add_uint16(md
, rr
->key
->class);
606 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
608 assert(rr
->wire_format_rdata_offset
<= rr
->wire_format_size
);
609 l
= rr
->wire_format_size
- rr
->wire_format_rdata_offset
;
612 md_add_uint16(md
, (uint16_t) l
);
613 gcry_md_write(md
, (uint8_t*) rr
->wire_format
+ rr
->wire_format_rdata_offset
, l
);
616 hash
= gcry_md_read(md
, 0);
622 switch (rrsig
->rrsig
.algorithm
) {
624 case DNSSEC_ALGORITHM_RSASHA1
:
625 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
626 case DNSSEC_ALGORITHM_RSASHA256
:
627 case DNSSEC_ALGORITHM_RSASHA512
:
628 r
= dnssec_rsa_verify(
629 gcry_md_algo_name(algorithm
),
635 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
636 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
637 r
= dnssec_ecdsa_verify(
638 gcry_md_algo_name(algorithm
),
639 rrsig
->rrsig
.algorithm
,
649 *result
= r
? DNSSEC_VALIDATED
: DNSSEC_INVALID
;
657 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
) {
662 /* Checks if the specified DNSKEY RR matches the key used for
663 * the signature in the specified RRSIG RR */
665 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
668 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
670 if (dnskey
->key
->class != rrsig
->key
->class)
672 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
674 if (dnskey
->dnskey
.protocol
!= 3)
676 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
679 if (dnssec_keytag(dnskey
) != rrsig
->rrsig
.key_tag
)
682 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
685 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
691 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
693 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
695 if (rrsig
->key
->class != key
->class)
697 if (rrsig
->rrsig
.type_covered
!= key
->type
)
700 /* Make sure signer is a parent of the RRset */
701 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(rrsig
->key
), rrsig
->rrsig
.signer
);
705 /* Make sure the owner name has at least as many labels as the "label" fields indicates. */
706 r
= dns_name_count_labels(DNS_RESOURCE_KEY_NAME(rrsig
->key
));
709 if (r
< rrsig
->rrsig
.labels
)
712 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
715 int dnssec_verify_rrset_search(
718 DnsAnswer
*validated_dnskeys
,
720 DnssecResult
*result
) {
722 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
723 DnsResourceRecord
*rrsig
;
729 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
731 if (!a
|| a
->n_rrs
<= 0)
734 /* Iterate through each RRSIG RR. */
735 DNS_ANSWER_FOREACH(rrsig
, a
) {
736 DnsResourceRecord
*dnskey
;
737 DnsAnswerFlags flags
;
739 /* Is this an RRSIG RR that applies to RRs matching our key? */
740 r
= dnssec_key_match_rrsig(key
, rrsig
);
748 /* Look for a matching key */
749 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
750 DnssecResult one_result
;
752 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
755 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
756 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
);
762 /* Take the time here, if it isn't set yet, so
763 * that we do all validations with the same
765 if (realtime
== USEC_INFINITY
)
766 realtime
= now(CLOCK_REALTIME
);
768 /* Yay, we found a matching RRSIG with a matching
769 * DNSKEY, awesome. Now let's verify all entries of
770 * the RRSet against the RRSIG and DNSKEY
773 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
777 switch (one_result
) {
779 case DNSSEC_VALIDATED
:
780 /* Yay, the RR has been validated,
781 * return immediately. */
782 *result
= DNSSEC_VALIDATED
;
786 /* If the signature is invalid, let's try another
787 key and/or signature. After all they
788 key_tags and stuff are not unique, and
789 might be shared by multiple keys. */
790 found_invalid
= true;
793 case DNSSEC_UNSUPPORTED_ALGORITHM
:
794 /* If the key algorithm is
795 unsupported, try another
796 RRSIG/DNSKEY pair, but remember we
797 encountered this, so that we can
798 return a proper error when we
799 encounter nothing better. */
800 found_unsupported_algorithm
= true;
803 case DNSSEC_SIGNATURE_EXPIRED
:
804 /* If the signature is expired, try
805 another one, but remember it, so
806 that we can return this */
807 found_expired_rrsig
= true;
811 assert_not_reached("Unexpected DNSSEC validation result");
816 if (found_expired_rrsig
)
817 *result
= DNSSEC_SIGNATURE_EXPIRED
;
818 else if (found_unsupported_algorithm
)
819 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
820 else if (found_invalid
)
821 *result
= DNSSEC_INVALID
;
822 else if (found_rrsig
)
823 *result
= DNSSEC_MISSING_KEY
;
825 *result
= DNSSEC_NO_SIGNATURE
;
830 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
831 DnsResourceRecord
*rr
;
834 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
836 DNS_ANSWER_FOREACH(rr
, a
) {
837 r
= dnssec_key_match_rrsig(key
, rr
);
847 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
851 /* Converts the specified hostname into DNSSEC canonicalized
860 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
868 /* DNSSEC validation is always done on the ASCII version of the label */
869 k
= dns_label_apply_idna(buffer
, r
, buffer
, buffer_max
);
876 if (buffer_max
< (size_t) r
+ 2)
879 /* The DNSSEC canonical form is not clear on what to
880 * do with dots appearing in labels, the way DNS-SD
881 * does it. Refuse it for now. */
883 if (memchr(buffer
, '.', r
))
886 for (i
= 0; i
< (size_t) r
; i
++) {
887 if (buffer
[i
] >= 'A' && buffer
[i
] <= 'Z')
888 buffer
[i
] = buffer
[i
] - 'A' + 'a';
900 /* Not even a single label: this is the root domain name */
902 assert(buffer_max
> 2);
912 static int digest_to_gcrypt(uint8_t algorithm
) {
914 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
918 case DNSSEC_DIGEST_SHA1
:
921 case DNSSEC_DIGEST_SHA256
:
922 return GCRY_MD_SHA256
;
924 case DNSSEC_DIGEST_SHA384
:
925 return GCRY_MD_SHA384
;
932 int dnssec_verify_dnskey(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
) {
933 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
934 gcry_md_hd_t md
= NULL
;
942 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
944 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
946 if (ds
->key
->type
!= DNS_TYPE_DS
)
948 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
949 return -EKEYREJECTED
;
950 if (dnskey
->dnskey
.protocol
!= 3)
951 return -EKEYREJECTED
;
953 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
955 if (dnssec_keytag(dnskey
) != ds
->ds
.key_tag
)
958 initialize_libgcrypt();
960 algorithm
= digest_to_gcrypt(ds
->ds
.digest_type
);
964 hash_size
= gcry_md_get_algo_dlen(algorithm
);
965 assert(hash_size
> 0);
967 if (ds
->ds
.digest_size
!= hash_size
)
970 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
974 gcry_md_open(&md
, algorithm
, 0);
978 gcry_md_write(md
, owner_name
, r
);
979 md_add_uint16(md
, dnskey
->dnskey
.flags
);
980 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
981 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
982 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
984 result
= gcry_md_read(md
, 0);
990 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
997 int dnssec_verify_dnskey_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
998 DnsResourceRecord
*ds
;
999 DnsAnswerFlags flags
;
1004 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1007 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1009 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1012 if (ds
->key
->type
!= DNS_TYPE_DS
)
1015 if (ds
->key
->class != dnskey
->key
->class)
1018 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1024 r
= dnssec_verify_dnskey(dnskey
, ds
);
1034 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1035 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1036 gcry_md_hd_t md
= NULL
;
1047 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1050 algorithm
= digest_to_gcrypt(nsec3
->nsec3
.algorithm
);
1054 initialize_libgcrypt();
1056 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1057 assert(hash_size
> 0);
1059 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1062 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1066 gcry_md_open(&md
, algorithm
, 0);
1070 gcry_md_write(md
, wire_format
, r
);
1071 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1073 result
= gcry_md_read(md
, 0);
1079 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1080 uint8_t tmp
[hash_size
];
1081 memcpy(tmp
, result
, hash_size
);
1084 gcry_md_write(md
, tmp
, hash_size
);
1085 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1087 result
= gcry_md_read(md
, 0);
1094 memcpy(ret
, result
, hash_size
);
1095 r
= (int) hash_size
;
1102 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsAnswerFlags flags
, DnsResourceRecord
*nsec3
) {
1108 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1111 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1112 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1118 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1120 if (nsec3
== rr
) /* Shortcut */
1123 if (rr
->key
->class != nsec3
->key
->class)
1125 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1127 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1129 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1131 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1134 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1135 r
= dns_name_parent(&a
); /* strip off hash */
1141 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1142 r
= dns_name_parent(&b
); /* strip off hash */
1148 return dns_name_equal(a
, b
);
1151 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
) {
1152 _cleanup_free_
char *next_closer_domain
= NULL
, *l
= NULL
;
1153 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1154 const char *suffix
, *p
, *pp
= NULL
;
1155 DnsResourceRecord
*rr
, *suffix_rr
;
1156 DnsAnswerFlags flags
;
1162 assert(authenticated
);
1164 /* First step, look for the longest common suffix we find with any NSEC3 RR in the response. */
1165 suffix
= DNS_RESOURCE_KEY_NAME(key
);
1167 DNS_ANSWER_FOREACH_FLAGS(suffix_rr
, flags
, answer
) {
1168 _cleanup_free_
char *hashed_domain
= NULL
, *label
= NULL
;
1170 r
= nsec3_is_good(suffix_rr
, flags
, NULL
);
1176 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(suffix_rr
->key
), 1, suffix
);
1183 /* Strip one label from the front */
1184 r
= dns_name_parent(&suffix
);
1191 *result
= DNSSEC_NSEC_NO_RR
;
1195 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1196 p
= DNS_RESOURCE_KEY_NAME(key
);
1198 _cleanup_free_
char *hashed_domain
= NULL
, *label
= NULL
;
1200 hashed_size
= dnssec_nsec3_hash(suffix_rr
, p
, hashed
);
1201 if (hashed_size
== -EOPNOTSUPP
) {
1202 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1205 if (hashed_size
< 0)
1208 label
= base32hexmem(hashed
, hashed_size
, false);
1212 hashed_domain
= strjoin(label
, ".", suffix
, NULL
);
1216 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1218 r
= nsec3_is_good(rr
, flags
, suffix_rr
);
1224 if (rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1227 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), hashed_domain
);
1231 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1232 goto found_closest_encloser
;
1236 /* We didn't find the closest encloser with this name,
1237 * but let's remember this domain name, it might be
1238 * the next closer name */
1242 /* Strip one label from the front */
1243 r
= dns_name_parent(&p
);
1250 *result
= DNSSEC_NSEC_NO_RR
;
1253 found_closest_encloser
:
1254 /* We found a closest encloser in 'p'; next closer is 'pp' */
1256 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1257 if (bitmap_isset(rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1260 /* Ensure that this data is from the delegated domain
1261 * (i.e. originates from the "lower" DNS server), and isn't
1262 * just glue records (i.e. doesn't originate from the "upper"
1264 if (bitmap_isset(rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1265 !bitmap_isset(rr
->nsec3
.types
, DNS_TYPE_SOA
))
1269 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1270 *result
= bitmap_isset(rr
->nsec3
.types
, key
->type
) ? DNSSEC_NSEC_FOUND
: DNSSEC_NSEC_NODATA
;
1275 r
= dnssec_nsec3_hash(rr
, pp
, hashed
);
1278 if (r
!= hashed_size
)
1281 l
= base32hexmem(hashed
, hashed_size
, false);
1285 next_closer_domain
= strjoin(l
, ".", p
, NULL
);
1286 if (!next_closer_domain
)
1289 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1290 _cleanup_free_
char *label
= NULL
, *next_hashed_domain
= NULL
;
1292 r
= nsec3_is_good(rr
, flags
, suffix_rr
);
1298 label
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1302 next_hashed_domain
= strjoin(label
, ".", p
, NULL
);
1303 if (!next_hashed_domain
)
1306 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1310 if (rr
->nsec3
.flags
& 1)
1311 *result
= DNSSEC_NSEC_OPTOUT
;
1313 *result
= DNSSEC_NSEC_NXDOMAIN
;
1315 *authenticated
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1320 *result
= DNSSEC_NSEC_NO_RR
;
1324 int dnssec_test_nsec(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
) {
1325 DnsResourceRecord
*rr
;
1326 bool have_nsec3
= false;
1327 DnsAnswerFlags flags
;
1332 assert(authenticated
);
1334 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1336 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1338 if (rr
->key
->class != key
->class)
1341 switch (rr
->key
->type
) {
1345 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
1349 *result
= bitmap_isset(rr
->nsec
.types
, key
->type
) ? DNSSEC_NSEC_FOUND
: DNSSEC_NSEC_NODATA
;
1350 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1354 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
), rr
->nsec
.next_domain_name
);
1358 *result
= DNSSEC_NSEC_NXDOMAIN
;
1359 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1364 case DNS_TYPE_NSEC3
:
1370 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1372 return dnssec_test_nsec3(answer
, key
, result
, authenticated
);
1374 /* No approproate NSEC RR found, report this. */
1375 *result
= DNSSEC_NSEC_NO_RR
;
1379 static const char* const dnssec_mode_table
[_DNSSEC_MODE_MAX
] = {
1381 [DNSSEC_DOWNGRADE_OK
] = "downgrade-ok",
1382 [DNSSEC_YES
] = "yes",
1384 DEFINE_STRING_TABLE_LOOKUP(dnssec_mode
, DnssecMode
);
1386 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
1387 [DNSSEC_VALIDATED
] = "validated",
1388 [DNSSEC_INVALID
] = "invalid",
1389 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
1390 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
1391 [DNSSEC_NO_SIGNATURE
] = "no-signature",
1392 [DNSSEC_MISSING_KEY
] = "missing-key",
1393 [DNSSEC_UNSIGNED
] = "unsigned",
1394 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
1395 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
1396 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
1398 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);