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
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 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
) {
84 /* The algorithm from RFC 4034, Appendix B. */
87 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
89 sum
= (uint32_t) dnskey
->dnskey
.flags
+
90 ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
92 p
= dnskey
->dnskey
.key
;
94 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
95 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
97 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
99 return sum
& UINT32_C(0xFFFF);
102 static int rr_compare(const void *a
, const void *b
) {
103 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
107 /* Let's order the RRs according to RFC 4034, Section 6.3 */
111 assert((*x
)->wire_format
);
114 assert((*y
)->wire_format
);
116 m
= MIN((*x
)->wire_format_size
, (*y
)->wire_format_size
);
118 r
= memcmp((*x
)->wire_format
, (*y
)->wire_format
, m
);
122 if ((*x
)->wire_format_size
< (*y
)->wire_format_size
)
124 else if ((*x
)->wire_format_size
> (*y
)->wire_format_size
)
130 static int dnssec_rsa_verify_raw(
131 const char *hash_algorithm
,
132 const void *signature
, size_t signature_size
,
133 const void *data
, size_t data_size
,
134 const void *exponent
, size_t exponent_size
,
135 const void *modulus
, size_t modulus_size
) {
137 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
138 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
142 assert(hash_algorithm
);
144 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
150 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
156 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
162 ge
= gcry_sexp_build(&signature_sexp
,
164 "(sig-val (rsa (s %m)))",
172 ge
= gcry_sexp_build(&data_sexp
,
174 "(data (flags pkcs1) (hash %s %b))",
183 ge
= gcry_sexp_build(&public_key_sexp
,
185 "(public-key (rsa (n %m) (e %m)))",
193 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
194 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
197 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
211 gcry_sexp_release(public_key_sexp
);
213 gcry_sexp_release(signature_sexp
);
215 gcry_sexp_release(data_sexp
);
220 static int dnssec_rsa_verify(
221 const char *hash_algorithm
,
222 const void *hash
, size_t hash_size
,
223 DnsResourceRecord
*rrsig
,
224 DnsResourceRecord
*dnskey
) {
226 size_t exponent_size
, modulus_size
;
227 void *exponent
, *modulus
;
229 assert(hash_algorithm
);
231 assert(hash_size
> 0);
235 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
236 /* exponent is > 255 bytes long */
238 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
240 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[0]) << 8) |
241 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[1]);
243 if (exponent_size
< 256)
246 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
249 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
250 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
253 /* exponent is <= 255 bytes long */
255 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
256 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
258 if (exponent_size
<= 0)
261 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
264 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
265 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
268 return dnssec_rsa_verify_raw(
270 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
272 exponent
, exponent_size
,
273 modulus
, modulus_size
);
276 static int dnssec_ecdsa_verify_raw(
277 const char *hash_algorithm
,
279 const void *signature_r
, size_t signature_r_size
,
280 const void *signature_s
, size_t signature_s_size
,
281 const void *data
, size_t data_size
,
282 const void *key
, size_t key_size
) {
284 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
285 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
289 assert(hash_algorithm
);
291 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
297 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
303 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
309 ge
= gcry_sexp_build(&signature_sexp
,
311 "(sig-val (ecdsa (r %m) (s %m)))",
319 ge
= gcry_sexp_build(&data_sexp
,
321 "(data (flags rfc6979) (hash %s %b))",
330 ge
= gcry_sexp_build(&public_key_sexp
,
332 "(public-key (ecc (curve %s) (q %m)))",
340 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
341 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
344 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
357 gcry_sexp_release(public_key_sexp
);
359 gcry_sexp_release(signature_sexp
);
361 gcry_sexp_release(data_sexp
);
366 static int dnssec_ecdsa_verify(
367 const char *hash_algorithm
,
369 const void *hash
, size_t hash_size
,
370 DnsResourceRecord
*rrsig
,
371 DnsResourceRecord
*dnskey
) {
382 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
384 curve
= "NIST P-256";
385 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
387 curve
= "NIST P-384";
391 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
394 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
397 q
= alloca(key_size
*2 + 1);
398 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
399 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
401 return dnssec_ecdsa_verify_raw(
404 rrsig
->rrsig
.signature
, key_size
,
405 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
410 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
411 gcry_md_write(md
, &v
, sizeof(v
));
414 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
416 gcry_md_write(md
, &v
, sizeof(v
));
419 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
421 gcry_md_write(md
, &v
, sizeof(v
));
424 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
425 usec_t expiration
, inception
, skew
;
428 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
430 if (realtime
== USEC_INFINITY
)
431 realtime
= now(CLOCK_REALTIME
);
433 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
434 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
436 if (inception
> expiration
)
437 return -EKEYREJECTED
;
439 /* Permit a certain amount of clock skew of 10% of the valid
440 * time range. This takes inspiration from unbound's
442 skew
= (expiration
- inception
) / 10;
446 if (inception
< skew
)
451 if (expiration
+ skew
< expiration
)
452 expiration
= USEC_INFINITY
;
456 return realtime
< inception
|| realtime
> expiration
;
459 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
461 /* Translates a DNSSEC signature algorithm into a gcrypt digest identifier */
465 case DNSSEC_ALGORITHM_RSASHA1
:
466 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
469 case DNSSEC_ALGORITHM_RSASHA256
:
470 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
471 return GCRY_MD_SHA256
;
473 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
474 return GCRY_MD_SHA384
;
476 case DNSSEC_ALGORITHM_RSASHA512
:
477 return GCRY_MD_SHA512
;
484 int dnssec_verify_rrset(
487 DnsResourceRecord
*rrsig
,
488 DnsResourceRecord
*dnskey
,
490 DnssecResult
*result
) {
492 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
495 DnsResourceRecord
**list
, *rr
;
496 gcry_md_hd_t md
= NULL
;
504 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
505 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
507 /* Verifies the the RRSet matching the specified "key" in "a",
508 * using the signature "rrsig" and the key "dnskey". It's
509 * assumed the RRSIG and DNSKEY match. */
511 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
512 if (md_algorithm
== -EOPNOTSUPP
) {
513 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
516 if (md_algorithm
< 0)
519 if (a
->n_rrs
> VERIFY_RRS_MAX
)
522 r
= dnssec_rrsig_expired(rrsig
, realtime
);
526 *result
= DNSSEC_SIGNATURE_EXPIRED
;
530 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
531 list
= newa(DnsResourceRecord
*, a
->n_rrs
);
533 DNS_ANSWER_FOREACH(rr
, a
) {
534 r
= dns_resource_key_equal(key
, rr
->key
);
540 /* We need the wire format for ordering, and digest calculation */
541 r
= dns_resource_record_to_wire_format(rr
, true);
551 /* Bring the RRs into canonical order */
552 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
554 /* OK, the RRs are now in canonical order. Let's calculate the digest */
555 initialize_libgcrypt();
557 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
558 assert(hash_size
> 0);
560 gcry_md_open(&md
, md_algorithm
, 0);
564 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
565 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
566 md_add_uint8(md
, rrsig
->rrsig
.labels
);
567 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
568 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
569 md_add_uint32(md
, rrsig
->rrsig
.inception
);
570 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
572 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
575 gcry_md_write(md
, wire_format_name
, r
);
577 for (k
= 0; k
< n
; k
++) {
582 r
= dns_name_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rrsig
->rrsig
.labels
, &suffix
);
585 if (r
> 0) /* This is a wildcard! */
586 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
588 r
= dns_name_to_wire_format(suffix
, wire_format_name
, sizeof(wire_format_name
), true);
591 gcry_md_write(md
, wire_format_name
, r
);
593 md_add_uint16(md
, rr
->key
->type
);
594 md_add_uint16(md
, rr
->key
->class);
595 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
597 assert(rr
->wire_format_rdata_offset
<= rr
->wire_format_size
);
598 l
= rr
->wire_format_size
- rr
->wire_format_rdata_offset
;
601 md_add_uint16(md
, (uint16_t) l
);
602 gcry_md_write(md
, (uint8_t*) rr
->wire_format
+ rr
->wire_format_rdata_offset
, l
);
605 hash
= gcry_md_read(md
, 0);
611 switch (rrsig
->rrsig
.algorithm
) {
613 case DNSSEC_ALGORITHM_RSASHA1
:
614 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
615 case DNSSEC_ALGORITHM_RSASHA256
:
616 case DNSSEC_ALGORITHM_RSASHA512
:
617 r
= dnssec_rsa_verify(
618 gcry_md_algo_name(md_algorithm
),
624 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
625 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
626 r
= dnssec_ecdsa_verify(
627 gcry_md_algo_name(md_algorithm
),
628 rrsig
->rrsig
.algorithm
,
638 *result
= r
? DNSSEC_VALIDATED
: DNSSEC_INVALID
;
646 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
) {
651 /* Checks if the specified DNSKEY RR matches the key used for
652 * the signature in the specified RRSIG RR */
654 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
657 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
659 if (dnskey
->key
->class != rrsig
->key
->class)
661 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
663 if (dnskey
->dnskey
.protocol
!= 3)
665 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
668 if (dnssec_keytag(dnskey
) != rrsig
->rrsig
.key_tag
)
671 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
674 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
680 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
682 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
684 if (rrsig
->key
->class != key
->class)
686 if (rrsig
->rrsig
.type_covered
!= key
->type
)
689 /* Make sure signer is a parent of the RRset */
690 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(rrsig
->key
), rrsig
->rrsig
.signer
);
694 /* Make sure the owner name has at least as many labels as the "label" fields indicates. */
695 r
= dns_name_count_labels(DNS_RESOURCE_KEY_NAME(rrsig
->key
));
698 if (r
< rrsig
->rrsig
.labels
)
701 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
704 static int dnssec_fix_rrset_ttl(DnsAnswer
*a
, const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
, usec_t realtime
) {
705 DnsResourceRecord
*rr
;
711 DNS_ANSWER_FOREACH(rr
, a
) {
712 r
= dns_resource_key_equal(key
, rr
->key
);
718 /* Pick the TTL as the minimum of the RR's TTL, the
719 * RR's original TTL according to the RRSIG and the
720 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
721 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
722 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
728 int dnssec_verify_rrset_search(
731 DnsAnswer
*validated_dnskeys
,
733 DnssecResult
*result
) {
735 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
736 DnsResourceRecord
*rrsig
;
742 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
744 if (!a
|| a
->n_rrs
<= 0)
747 /* Iterate through each RRSIG RR. */
748 DNS_ANSWER_FOREACH(rrsig
, a
) {
749 DnsResourceRecord
*dnskey
;
750 DnsAnswerFlags flags
;
752 /* Is this an RRSIG RR that applies to RRs matching our key? */
753 r
= dnssec_key_match_rrsig(key
, rrsig
);
761 /* Look for a matching key */
762 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
763 DnssecResult one_result
;
765 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
768 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
769 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
);
775 /* Take the time here, if it isn't set yet, so
776 * that we do all validations with the same
778 if (realtime
== USEC_INFINITY
)
779 realtime
= now(CLOCK_REALTIME
);
781 /* Yay, we found a matching RRSIG with a matching
782 * DNSKEY, awesome. Now let's verify all entries of
783 * the RRSet against the RRSIG and DNSKEY
786 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
790 switch (one_result
) {
792 case DNSSEC_VALIDATED
:
793 /* Yay, the RR has been validated,
794 * return immediately, but fix up the expiry */
795 r
= dnssec_fix_rrset_ttl(a
, key
, rrsig
, realtime
);
799 *result
= DNSSEC_VALIDATED
;
803 /* If the signature is invalid, let's try another
804 key and/or signature. After all they
805 key_tags and stuff are not unique, and
806 might be shared by multiple keys. */
807 found_invalid
= true;
810 case DNSSEC_UNSUPPORTED_ALGORITHM
:
811 /* If the key algorithm is
812 unsupported, try another
813 RRSIG/DNSKEY pair, but remember we
814 encountered this, so that we can
815 return a proper error when we
816 encounter nothing better. */
817 found_unsupported_algorithm
= true;
820 case DNSSEC_SIGNATURE_EXPIRED
:
821 /* If the signature is expired, try
822 another one, but remember it, so
823 that we can return this */
824 found_expired_rrsig
= true;
828 assert_not_reached("Unexpected DNSSEC validation result");
833 if (found_expired_rrsig
)
834 *result
= DNSSEC_SIGNATURE_EXPIRED
;
835 else if (found_unsupported_algorithm
)
836 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
837 else if (found_invalid
)
838 *result
= DNSSEC_INVALID
;
839 else if (found_rrsig
)
840 *result
= DNSSEC_MISSING_KEY
;
842 *result
= DNSSEC_NO_SIGNATURE
;
847 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
848 DnsResourceRecord
*rr
;
851 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
853 DNS_ANSWER_FOREACH(rr
, a
) {
854 r
= dnssec_key_match_rrsig(key
, rr
);
864 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
868 /* Converts the specified hostname into DNSSEC canonicalized
877 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
885 /* DNSSEC validation is always done on the ASCII version of the label */
886 k
= dns_label_apply_idna(buffer
, r
, buffer
, buffer_max
);
893 if (buffer_max
< (size_t) r
+ 2)
896 /* The DNSSEC canonical form is not clear on what to
897 * do with dots appearing in labels, the way DNS-SD
898 * does it. Refuse it for now. */
900 if (memchr(buffer
, '.', r
))
903 for (i
= 0; i
< (size_t) r
; i
++) {
904 if (buffer
[i
] >= 'A' && buffer
[i
] <= 'Z')
905 buffer
[i
] = buffer
[i
] - 'A' + 'a';
917 /* Not even a single label: this is the root domain name */
919 assert(buffer_max
> 2);
929 static int digest_to_gcrypt_md(uint8_t algorithm
) {
931 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
935 case DNSSEC_DIGEST_SHA1
:
938 case DNSSEC_DIGEST_SHA256
:
939 return GCRY_MD_SHA256
;
941 case DNSSEC_DIGEST_SHA384
:
942 return GCRY_MD_SHA384
;
949 int dnssec_verify_dnskey(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
) {
950 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
951 gcry_md_hd_t md
= NULL
;
959 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
961 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
963 if (ds
->key
->type
!= DNS_TYPE_DS
)
965 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
966 return -EKEYREJECTED
;
967 if (dnskey
->dnskey
.protocol
!= 3)
968 return -EKEYREJECTED
;
970 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
972 if (dnssec_keytag(dnskey
) != ds
->ds
.key_tag
)
975 initialize_libgcrypt();
977 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
978 if (md_algorithm
< 0)
981 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
982 assert(hash_size
> 0);
984 if (ds
->ds
.digest_size
!= hash_size
)
987 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
991 gcry_md_open(&md
, md_algorithm
, 0);
995 gcry_md_write(md
, owner_name
, r
);
996 md_add_uint16(md
, dnskey
->dnskey
.flags
);
997 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
998 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
999 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1001 result
= gcry_md_read(md
, 0);
1007 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1014 int dnssec_verify_dnskey_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1015 DnsResourceRecord
*ds
;
1016 DnsAnswerFlags flags
;
1021 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1024 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1026 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1029 if (ds
->key
->type
!= DNS_TYPE_DS
)
1032 if (ds
->key
->class != dnskey
->key
->class)
1035 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1041 r
= dnssec_verify_dnskey(dnskey
, ds
);
1051 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1052 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1053 gcry_md_hd_t md
= NULL
;
1064 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1067 algorithm
= digest_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1071 initialize_libgcrypt();
1073 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1074 assert(hash_size
> 0);
1076 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1079 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1083 gcry_md_open(&md
, algorithm
, 0);
1087 gcry_md_write(md
, wire_format
, r
);
1088 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1090 result
= gcry_md_read(md
, 0);
1096 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1097 uint8_t tmp
[hash_size
];
1098 memcpy(tmp
, result
, hash_size
);
1101 gcry_md_write(md
, tmp
, hash_size
);
1102 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1104 result
= gcry_md_read(md
, 0);
1111 memcpy(ret
, result
, hash_size
);
1112 r
= (int) hash_size
;
1119 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsAnswerFlags flags
, DnsResourceRecord
*nsec3
) {
1125 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1128 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1129 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1135 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1137 if (nsec3
== rr
) /* Shortcut */
1140 if (rr
->key
->class != nsec3
->key
->class)
1142 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1144 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1146 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1148 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1151 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1152 r
= dns_name_parent(&a
); /* strip off hash */
1158 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1159 r
= dns_name_parent(&b
); /* strip off hash */
1165 return dns_name_equal(a
, b
);
1168 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
) {
1169 _cleanup_free_
char *next_closer_domain
= NULL
, *l
= NULL
;
1170 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1171 const char *suffix
, *p
, *pp
= NULL
;
1172 DnsResourceRecord
*rr
, *suffix_rr
;
1173 DnsAnswerFlags flags
;
1179 assert(authenticated
);
1181 /* First step, look for the longest common suffix we find with any NSEC3 RR in the response. */
1182 suffix
= DNS_RESOURCE_KEY_NAME(key
);
1184 DNS_ANSWER_FOREACH_FLAGS(suffix_rr
, flags
, answer
) {
1185 r
= nsec3_is_good(suffix_rr
, flags
, NULL
);
1191 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(suffix_rr
->key
), 1, suffix
);
1198 /* Strip one label from the front */
1199 r
= dns_name_parent(&suffix
);
1206 *result
= DNSSEC_NSEC_NO_RR
;
1210 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1211 p
= DNS_RESOURCE_KEY_NAME(key
);
1213 _cleanup_free_
char *hashed_domain
= NULL
, *label
= NULL
;
1215 hashed_size
= dnssec_nsec3_hash(suffix_rr
, p
, hashed
);
1216 if (hashed_size
== -EOPNOTSUPP
) {
1217 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1220 if (hashed_size
< 0)
1223 label
= base32hexmem(hashed
, hashed_size
, false);
1227 hashed_domain
= strjoin(label
, ".", suffix
, NULL
);
1231 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1233 r
= nsec3_is_good(rr
, flags
, suffix_rr
);
1239 if (rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1242 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), hashed_domain
);
1246 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1247 goto found_closest_encloser
;
1251 /* We didn't find the closest encloser with this name,
1252 * but let's remember this domain name, it might be
1253 * the next closer name */
1257 /* Strip one label from the front */
1258 r
= dns_name_parent(&p
);
1265 *result
= DNSSEC_NSEC_NO_RR
;
1268 found_closest_encloser
:
1269 /* We found a closest encloser in 'p'; next closer is 'pp' */
1271 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1272 if (bitmap_isset(rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1275 /* Ensure that this data is from the delegated domain
1276 * (i.e. originates from the "lower" DNS server), and isn't
1277 * just glue records (i.e. doesn't originate from the "upper"
1279 if (bitmap_isset(rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1280 !bitmap_isset(rr
->nsec3
.types
, DNS_TYPE_SOA
))
1284 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1285 *result
= bitmap_isset(rr
->nsec3
.types
, key
->type
) ? DNSSEC_NSEC_FOUND
: DNSSEC_NSEC_NODATA
;
1290 r
= dnssec_nsec3_hash(rr
, pp
, hashed
);
1293 if (r
!= hashed_size
)
1296 l
= base32hexmem(hashed
, hashed_size
, false);
1300 next_closer_domain
= strjoin(l
, ".", p
, NULL
);
1301 if (!next_closer_domain
)
1304 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1305 _cleanup_free_
char *label
= NULL
, *next_hashed_domain
= NULL
;
1307 r
= nsec3_is_good(rr
, flags
, suffix_rr
);
1313 label
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1317 next_hashed_domain
= strjoin(label
, ".", p
, NULL
);
1318 if (!next_hashed_domain
)
1321 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1325 if (rr
->nsec3
.flags
& 1)
1326 *result
= DNSSEC_NSEC_OPTOUT
;
1328 *result
= DNSSEC_NSEC_NXDOMAIN
;
1330 *authenticated
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1335 *result
= DNSSEC_NSEC_NO_RR
;
1339 int dnssec_test_nsec(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
) {
1340 DnsResourceRecord
*rr
;
1341 bool have_nsec3
= false;
1342 DnsAnswerFlags flags
;
1347 assert(authenticated
);
1349 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1351 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1353 if (rr
->key
->class != key
->class)
1356 switch (rr
->key
->type
) {
1360 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
1364 *result
= bitmap_isset(rr
->nsec
.types
, key
->type
) ? DNSSEC_NSEC_FOUND
: DNSSEC_NSEC_NODATA
;
1365 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1369 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
), rr
->nsec
.next_domain_name
);
1373 *result
= DNSSEC_NSEC_NXDOMAIN
;
1374 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1379 case DNS_TYPE_NSEC3
:
1385 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1387 return dnssec_test_nsec3(answer
, key
, result
, authenticated
);
1389 /* No approproate NSEC RR found, report this. */
1390 *result
= DNSSEC_NSEC_NO_RR
;
1394 static const char* const dnssec_mode_table
[_DNSSEC_MODE_MAX
] = {
1396 [DNSSEC_DOWNGRADE_OK
] = "downgrade-ok",
1397 [DNSSEC_YES
] = "yes",
1399 DEFINE_STRING_TABLE_LOOKUP(dnssec_mode
, DnssecMode
);
1401 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
1402 [DNSSEC_VALIDATED
] = "validated",
1403 [DNSSEC_INVALID
] = "invalid",
1404 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
1405 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
1406 [DNSSEC_NO_SIGNATURE
] = "no-signature",
1407 [DNSSEC_MISSING_KEY
] = "missing-key",
1408 [DNSSEC_UNSIGNED
] = "unsigned",
1409 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
1410 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
1411 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
1413 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);