1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2015 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
25 #include "dns-domain.h"
26 #include "hexdecoct.h"
27 #include "resolved-dns-dnssec.h"
28 #include "resolved-dns-packet.h"
29 #include "string-table.h"
33 * How does the DNSSEC canonical form of a hostname with a label
34 * containing a dot look like, the way DNS-SD does it?
38 * - wildcard zones compatibility (NSEC/NSEC3 wildcard check is missing)
39 * - multi-label zone compatibility
40 * - cname/dname compatibility
42 * - workable hack for the .corp, .home, .box case
43 * - bus calls to override DNSEC setting per interface
44 * - log all DNSSEC downgrades
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)
55 /* Maximum number of NSEC3 iterations we'll do. */
56 #define NSEC3_ITERATIONS_MAX 2048
59 * The DNSSEC Chain of trust:
61 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
62 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
63 * DS RRs are protected like normal RRs
66 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
69 static void initialize_libgcrypt(void) {
72 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
75 p
= gcry_check_version("1.4.5");
78 gcry_control(GCRYCTL_DISABLE_SECMEM
);
79 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
82 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
, bool mask_revoke
) {
87 /* The algorithm from RFC 4034, Appendix B. */
90 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
92 f
= (uint32_t) dnskey
->dnskey
.flags
;
95 f
&= ~DNSKEY_FLAG_REVOKE
;
97 sum
= f
+ ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
99 p
= dnskey
->dnskey
.key
;
101 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
102 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
104 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
106 return sum
& UINT32_C(0xFFFF);
109 static int rr_compare(const void *a
, const void *b
) {
110 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
114 /* Let's order the RRs according to RFC 4034, Section 6.3 */
118 assert((*x
)->wire_format
);
121 assert((*y
)->wire_format
);
123 m
= MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
125 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
129 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
131 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
137 static int dnssec_rsa_verify_raw(
138 const char *hash_algorithm
,
139 const void *signature
, size_t signature_size
,
140 const void *data
, size_t data_size
,
141 const void *exponent
, size_t exponent_size
,
142 const void *modulus
, size_t modulus_size
) {
144 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
145 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
149 assert(hash_algorithm
);
151 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
157 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
163 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
169 ge
= gcry_sexp_build(&signature_sexp
,
171 "(sig-val (rsa (s %m)))",
179 ge
= gcry_sexp_build(&data_sexp
,
181 "(data (flags pkcs1) (hash %s %b))",
190 ge
= gcry_sexp_build(&public_key_sexp
,
192 "(public-key (rsa (n %m) (e %m)))",
200 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
201 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
204 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
218 gcry_sexp_release(public_key_sexp
);
220 gcry_sexp_release(signature_sexp
);
222 gcry_sexp_release(data_sexp
);
227 static int dnssec_rsa_verify(
228 const char *hash_algorithm
,
229 const void *hash
, size_t hash_size
,
230 DnsResourceRecord
*rrsig
,
231 DnsResourceRecord
*dnskey
) {
233 size_t exponent_size
, modulus_size
;
234 void *exponent
, *modulus
;
236 assert(hash_algorithm
);
238 assert(hash_size
> 0);
242 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
243 /* exponent is > 255 bytes long */
245 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
247 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
248 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
250 if (exponent_size
< 256)
253 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
256 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
257 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
260 /* exponent is <= 255 bytes long */
262 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
263 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
265 if (exponent_size
<= 0)
268 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
271 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
272 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
275 return dnssec_rsa_verify_raw(
277 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
279 exponent
, exponent_size
,
280 modulus
, modulus_size
);
283 static int dnssec_ecdsa_verify_raw(
284 const char *hash_algorithm
,
286 const void *signature_r
, size_t signature_r_size
,
287 const void *signature_s
, size_t signature_s_size
,
288 const void *data
, size_t data_size
,
289 const void *key
, size_t key_size
) {
291 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
292 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
296 assert(hash_algorithm
);
298 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
304 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
310 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
316 ge
= gcry_sexp_build(&signature_sexp
,
318 "(sig-val (ecdsa (r %m) (s %m)))",
326 ge
= gcry_sexp_build(&data_sexp
,
328 "(data (flags rfc6979) (hash %s %b))",
337 ge
= gcry_sexp_build(&public_key_sexp
,
339 "(public-key (ecc (curve %s) (q %m)))",
347 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
348 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
351 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
364 gcry_sexp_release(public_key_sexp
);
366 gcry_sexp_release(signature_sexp
);
368 gcry_sexp_release(data_sexp
);
373 static int dnssec_ecdsa_verify(
374 const char *hash_algorithm
,
376 const void *hash
, size_t hash_size
,
377 DnsResourceRecord
*rrsig
,
378 DnsResourceRecord
*dnskey
) {
389 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
391 curve
= "NIST P-256";
392 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
394 curve
= "NIST P-384";
398 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
401 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
404 q
= alloca(key_size
*2 + 1);
405 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
406 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
408 return dnssec_ecdsa_verify_raw(
411 rrsig
->rrsig
.signature
, key_size
,
412 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
417 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
418 gcry_md_write(md
, &v
, sizeof(v
));
421 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
423 gcry_md_write(md
, &v
, sizeof(v
));
426 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
428 gcry_md_write(md
, &v
, sizeof(v
));
431 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
432 usec_t expiration
, inception
, skew
;
435 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
437 if (realtime
== USEC_INFINITY
)
438 realtime
= now(CLOCK_REALTIME
);
440 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
441 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
443 if (inception
> expiration
)
444 return -EKEYREJECTED
;
446 /* Permit a certain amount of clock skew of 10% of the valid
447 * time range. This takes inspiration from unbound's
449 skew
= (expiration
- inception
) / 10;
453 if (inception
< skew
)
458 if (expiration
+ skew
< expiration
)
459 expiration
= USEC_INFINITY
;
463 return realtime
< inception
|| realtime
> expiration
;
466 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
468 /* Translates a DNSSEC signature algorithm into a gcrypt
471 * Note that we implement all algorithms listed as "Must
472 * implement" and "Recommended to Implement" in RFC6944. We
473 * don't implement any algorithms that are listed as
474 * "Optional" or "Must Not Implement". Specifically, we do not
475 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
480 case DNSSEC_ALGORITHM_RSASHA1
:
481 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
484 case DNSSEC_ALGORITHM_RSASHA256
:
485 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
486 return GCRY_MD_SHA256
;
488 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
489 return GCRY_MD_SHA384
;
491 case DNSSEC_ALGORITHM_RSASHA512
:
492 return GCRY_MD_SHA512
;
499 int dnssec_verify_rrset(
501 const DnsResourceKey
*key
,
502 DnsResourceRecord
*rrsig
,
503 DnsResourceRecord
*dnskey
,
505 DnssecResult
*result
) {
507 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
510 DnsResourceRecord
**list
, *rr
;
511 gcry_md_hd_t md
= NULL
;
519 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
520 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
522 /* Verifies the the RRSet matching the specified "key" in "a",
523 * using the signature "rrsig" and the key "dnskey". It's
524 * assumed the RRSIG and DNSKEY match. */
526 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
527 if (md_algorithm
== -EOPNOTSUPP
) {
528 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
531 if (md_algorithm
< 0)
534 r
= dnssec_rrsig_expired(rrsig
, realtime
);
538 *result
= DNSSEC_SIGNATURE_EXPIRED
;
542 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
543 list
= newa(DnsResourceRecord
*, a
->n_rrs
);
545 DNS_ANSWER_FOREACH(rr
, a
) {
546 r
= dns_resource_key_equal(key
, rr
->key
);
552 /* We need the wire format for ordering, and digest calculation */
553 r
= dns_resource_record_to_wire_format(rr
, true);
559 if (n
> VERIFY_RRS_MAX
)
566 /* Bring the RRs into canonical order */
567 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
569 /* OK, the RRs are now in canonical order. Let's calculate the digest */
570 initialize_libgcrypt();
572 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
573 assert(hash_size
> 0);
575 gcry_md_open(&md
, md_algorithm
, 0);
579 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
580 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
581 md_add_uint8(md
, rrsig
->rrsig
.labels
);
582 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
583 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
584 md_add_uint32(md
, rrsig
->rrsig
.inception
);
585 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
587 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
590 gcry_md_write(md
, wire_format_name
, r
);
592 for (k
= 0; k
< n
; k
++) {
597 r
= dns_name_suffix(DNS_RESOURCE_KEY_NAME(rr
->key
), rrsig
->rrsig
.labels
, &suffix
);
600 if (r
> 0) /* This is a wildcard! */
601 gcry_md_write(md
, (uint8_t[]) { 1, '*'}, 2);
603 r
= dns_name_to_wire_format(suffix
, wire_format_name
, sizeof(wire_format_name
), true);
606 gcry_md_write(md
, wire_format_name
, r
);
608 md_add_uint16(md
, rr
->key
->type
);
609 md_add_uint16(md
, rr
->key
->class);
610 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
612 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
615 md_add_uint16(md
, (uint16_t) l
);
616 gcry_md_write(md
, DNS_RESOURCE_RECORD_RDATA(rr
), l
);
619 hash
= gcry_md_read(md
, 0);
625 switch (rrsig
->rrsig
.algorithm
) {
627 case DNSSEC_ALGORITHM_RSASHA1
:
628 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
629 case DNSSEC_ALGORITHM_RSASHA256
:
630 case DNSSEC_ALGORITHM_RSASHA512
:
631 r
= dnssec_rsa_verify(
632 gcry_md_algo_name(md_algorithm
),
638 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
639 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
640 r
= dnssec_ecdsa_verify(
641 gcry_md_algo_name(md_algorithm
),
642 rrsig
->rrsig
.algorithm
,
652 *result
= r
? DNSSEC_VALIDATED
: DNSSEC_INVALID
;
660 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
, bool revoked_ok
) {
665 /* Checks if the specified DNSKEY RR matches the key used for
666 * the signature in the specified RRSIG RR */
668 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
671 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
673 if (dnskey
->key
->class != rrsig
->key
->class)
675 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
677 if (!revoked_ok
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
679 if (dnskey
->dnskey
.protocol
!= 3)
681 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
684 if (dnssec_keytag(dnskey
, false) != rrsig
->rrsig
.key_tag
)
687 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
690 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
696 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
698 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
700 if (rrsig
->key
->class != key
->class)
702 if (rrsig
->rrsig
.type_covered
!= key
->type
)
705 /* Make sure signer is a parent of the RRset */
706 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(rrsig
->key
), rrsig
->rrsig
.signer
);
710 /* Make sure the owner name has at least as many labels as the "label" fields indicates. */
711 r
= dns_name_count_labels(DNS_RESOURCE_KEY_NAME(rrsig
->key
));
714 if (r
< rrsig
->rrsig
.labels
)
717 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
720 static int dnssec_fix_rrset_ttl(DnsAnswer
*a
, const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
, usec_t realtime
) {
721 DnsResourceRecord
*rr
;
727 DNS_ANSWER_FOREACH(rr
, a
) {
728 r
= dns_resource_key_equal(key
, rr
->key
);
734 /* Pick the TTL as the minimum of the RR's TTL, the
735 * RR's original TTL according to the RRSIG and the
736 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
737 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
738 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
744 int dnssec_verify_rrset_search(
746 const DnsResourceKey
*key
,
747 DnsAnswer
*validated_dnskeys
,
749 DnssecResult
*result
) {
751 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
752 DnsResourceRecord
*rrsig
;
758 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
760 if (!a
|| a
->n_rrs
<= 0)
763 /* Iterate through each RRSIG RR. */
764 DNS_ANSWER_FOREACH(rrsig
, a
) {
765 DnsResourceRecord
*dnskey
;
766 DnsAnswerFlags flags
;
768 /* Is this an RRSIG RR that applies to RRs matching our key? */
769 r
= dnssec_key_match_rrsig(key
, rrsig
);
777 /* Look for a matching key */
778 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
779 DnssecResult one_result
;
781 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
784 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
785 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
, false);
791 /* Take the time here, if it isn't set yet, so
792 * that we do all validations with the same
794 if (realtime
== USEC_INFINITY
)
795 realtime
= now(CLOCK_REALTIME
);
797 /* Yay, we found a matching RRSIG with a matching
798 * DNSKEY, awesome. Now let's verify all entries of
799 * the RRSet against the RRSIG and DNSKEY
802 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
806 switch (one_result
) {
808 case DNSSEC_VALIDATED
:
809 /* Yay, the RR has been validated,
810 * return immediately, but fix up the expiry */
811 r
= dnssec_fix_rrset_ttl(a
, key
, rrsig
, realtime
);
815 *result
= DNSSEC_VALIDATED
;
819 /* If the signature is invalid, let's try another
820 key and/or signature. After all they
821 key_tags and stuff are not unique, and
822 might be shared by multiple keys. */
823 found_invalid
= true;
826 case DNSSEC_UNSUPPORTED_ALGORITHM
:
827 /* If the key algorithm is
828 unsupported, try another
829 RRSIG/DNSKEY pair, but remember we
830 encountered this, so that we can
831 return a proper error when we
832 encounter nothing better. */
833 found_unsupported_algorithm
= true;
836 case DNSSEC_SIGNATURE_EXPIRED
:
837 /* If the signature is expired, try
838 another one, but remember it, so
839 that we can return this */
840 found_expired_rrsig
= true;
844 assert_not_reached("Unexpected DNSSEC validation result");
849 if (found_expired_rrsig
)
850 *result
= DNSSEC_SIGNATURE_EXPIRED
;
851 else if (found_unsupported_algorithm
)
852 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
853 else if (found_invalid
)
854 *result
= DNSSEC_INVALID
;
855 else if (found_rrsig
)
856 *result
= DNSSEC_MISSING_KEY
;
858 *result
= DNSSEC_NO_SIGNATURE
;
863 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
864 DnsResourceRecord
*rr
;
867 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
869 DNS_ANSWER_FOREACH(rr
, a
) {
870 r
= dnssec_key_match_rrsig(key
, rr
);
880 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
884 /* Converts the specified hostname into DNSSEC canonicalized
893 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
901 /* DNSSEC validation is always done on the ASCII version of the label */
902 k
= dns_label_apply_idna(buffer
, r
, buffer
, buffer_max
);
909 if (buffer_max
< (size_t) r
+ 2)
912 /* The DNSSEC canonical form is not clear on what to
913 * do with dots appearing in labels, the way DNS-SD
914 * does it. Refuse it for now. */
916 if (memchr(buffer
, '.', r
))
919 for (i
= 0; i
< (size_t) r
; i
++) {
920 if (buffer
[i
] >= 'A' && buffer
[i
] <= 'Z')
921 buffer
[i
] = buffer
[i
] - 'A' + 'a';
933 /* Not even a single label: this is the root domain name */
935 assert(buffer_max
> 2);
945 static int digest_to_gcrypt_md(uint8_t algorithm
) {
947 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
951 case DNSSEC_DIGEST_SHA1
:
954 case DNSSEC_DIGEST_SHA256
:
955 return GCRY_MD_SHA256
;
957 case DNSSEC_DIGEST_SHA384
:
958 return GCRY_MD_SHA384
;
965 int dnssec_verify_dnskey(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
, bool mask_revoke
) {
966 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
967 gcry_md_hd_t md
= NULL
;
975 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
977 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
979 if (ds
->key
->type
!= DNS_TYPE_DS
)
981 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
982 return -EKEYREJECTED
;
983 if (!mask_revoke
&& (dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
984 return -EKEYREJECTED
;
985 if (dnskey
->dnskey
.protocol
!= 3)
986 return -EKEYREJECTED
;
988 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
990 if (dnssec_keytag(dnskey
, mask_revoke
) != ds
->ds
.key_tag
)
993 initialize_libgcrypt();
995 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
996 if (md_algorithm
< 0)
999 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
1000 assert(hash_size
> 0);
1002 if (ds
->ds
.digest_size
!= hash_size
)
1005 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
1009 gcry_md_open(&md
, md_algorithm
, 0);
1013 gcry_md_write(md
, owner_name
, r
);
1015 md_add_uint16(md
, dnskey
->dnskey
.flags
& ~DNSKEY_FLAG_REVOKE
);
1017 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1018 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1019 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1020 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1022 result
= gcry_md_read(md
, 0);
1028 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1035 int dnssec_verify_dnskey_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1036 DnsResourceRecord
*ds
;
1037 DnsAnswerFlags flags
;
1042 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1045 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1047 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1050 if (ds
->key
->type
!= DNS_TYPE_DS
)
1053 if (ds
->key
->class != dnskey
->key
->class)
1056 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1062 r
= dnssec_verify_dnskey(dnskey
, ds
, false);
1063 if (r
== -EKEYREJECTED
)
1064 return 0; /* The DNSKEY is revoked or otherwise invalid, we won't bless it */
1074 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1076 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1078 switch (algorithm
) {
1080 case NSEC3_ALGORITHM_SHA1
:
1081 return GCRY_MD_SHA1
;
1088 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1089 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1090 gcry_md_hd_t md
= NULL
;
1101 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1104 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1105 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1109 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1113 initialize_libgcrypt();
1115 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1116 assert(hash_size
> 0);
1118 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1121 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1125 gcry_md_open(&md
, algorithm
, 0);
1129 gcry_md_write(md
, wire_format
, r
);
1130 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1132 result
= gcry_md_read(md
, 0);
1138 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1139 uint8_t tmp
[hash_size
];
1140 memcpy(tmp
, result
, hash_size
);
1143 gcry_md_write(md
, tmp
, hash_size
);
1144 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1146 result
= gcry_md_read(md
, 0);
1153 memcpy(ret
, result
, hash_size
);
1154 r
= (int) hash_size
;
1161 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsAnswerFlags flags
, DnsResourceRecord
*nsec3
) {
1167 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1170 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1171 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1174 /* Ignore NSEC3 RRs whose algorithm we don't know */
1175 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1177 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1178 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1184 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1186 if (nsec3
== rr
) /* Shortcut */
1189 if (rr
->key
->class != nsec3
->key
->class)
1191 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1193 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1195 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1197 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1200 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1201 r
= dns_name_parent(&a
); /* strip off hash */
1207 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1208 r
= dns_name_parent(&b
); /* strip off hash */
1214 return dns_name_equal(a
, b
);
1217 static int nsec3_hashed_domain(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1218 _cleanup_free_
char *l
= NULL
, *hashed_domain
= NULL
;
1219 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1227 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1228 if (hashed_size
< 0)
1231 l
= base32hexmem(hashed
, hashed_size
, false);
1235 hashed_domain
= strjoin(l
, ".", zone
, NULL
);
1239 *ret
= hashed_domain
;
1240 hashed_domain
= NULL
;
1245 /* See RFC 5155, Section 8
1246 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1247 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1248 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1249 * matches the wildcard domain.
1251 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1252 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1253 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1254 * to conclude anything we indicate this by returning NO_RR. */
1255 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1256 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard
= NULL
, *wildcard_domain
= NULL
;
1257 const char *zone
, *p
, *pp
= NULL
;
1258 DnsResourceRecord
*rr
, *enclosure_rr
, *suffix_rr
, *wildcard_rr
= NULL
;
1259 DnsAnswerFlags flags
;
1261 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1266 /* First step, find the zone name and the NSEC3 parameters of the zone.
1267 * it is sufficient to look for the longest common suffix we find with
1268 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1269 * records from a given zone in a response must use the same
1271 zone
= DNS_RESOURCE_KEY_NAME(key
);
1273 DNS_ANSWER_FOREACH_FLAGS(suffix_rr
, flags
, answer
) {
1274 r
= nsec3_is_good(suffix_rr
, flags
, NULL
);
1280 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(suffix_rr
->key
), 1, zone
);
1287 /* Strip one label from the front */
1288 r
= dns_name_parent(&zone
);
1295 *result
= DNSSEC_NSEC_NO_RR
;
1299 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1300 p
= DNS_RESOURCE_KEY_NAME(key
);
1302 _cleanup_free_
char *hashed_domain
= NULL
;
1304 hashed_size
= nsec3_hashed_domain(suffix_rr
, p
, zone
, &hashed_domain
);
1305 if (hashed_size
== -EOPNOTSUPP
) {
1306 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1309 if (hashed_size
< 0)
1312 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1314 r
= nsec3_is_good(enclosure_rr
, flags
, suffix_rr
);
1320 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1323 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr
->key
), hashed_domain
);
1327 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1328 goto found_closest_encloser
;
1332 /* We didn't find the closest encloser with this name,
1333 * but let's remember this domain name, it might be
1334 * the next closer name */
1338 /* Strip one label from the front */
1339 r
= dns_name_parent(&p
);
1346 *result
= DNSSEC_NSEC_NO_RR
;
1349 found_closest_encloser
:
1350 /* We found a closest encloser in 'p'; next closer is 'pp' */
1352 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1353 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1356 /* Ensure that this data is from the delegated domain
1357 * (i.e. originates from the "lower" DNS server), and isn't
1358 * just glue records (i.e. doesn't originate from the "upper"
1360 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1361 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1365 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1366 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1367 *result
= DNSSEC_NSEC_FOUND
;
1368 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1369 *result
= DNSSEC_NSEC_CNAME
;
1371 *result
= DNSSEC_NSEC_NODATA
;
1376 *ttl
= enclosure_rr
->ttl
;
1381 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1383 wildcard
= strappend("*.", p
);
1387 r
= nsec3_hashed_domain(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1390 if (r
!= hashed_size
)
1393 r
= nsec3_hashed_domain(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1396 if (r
!= hashed_size
)
1399 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1400 _cleanup_free_
char *label
= NULL
, *next_hashed_domain
= NULL
;
1402 r
= nsec3_is_good(rr
, flags
, suffix_rr
);
1408 label
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1412 next_hashed_domain
= strjoin(label
, ".", zone
, NULL
);
1413 if (!next_hashed_domain
)
1416 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1420 if (rr
->nsec3
.flags
& 1)
1423 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1428 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
);
1432 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1437 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
, next_hashed_domain
);
1441 if (rr
->nsec3
.flags
& 1)
1442 /* This only makes sense if we have a wildcard delegation, which is
1443 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1444 * this not happening, so hence cannot simply conclude NXDOMAIN as
1448 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1454 if (wildcard_rr
&& no_wildcard
)
1458 *result
= DNSSEC_NSEC_NO_RR
;
1463 /* A wildcard exists that matches our query. */
1465 /* This is not specified in any RFC to the best of my knowledge, but
1466 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1467 * it means that we cannot prove that the source of synthesis is
1468 * correct, as there may be a closer match. */
1469 *result
= DNSSEC_NSEC_OPTOUT
;
1470 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1471 *result
= DNSSEC_NSEC_FOUND
;
1472 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1473 *result
= DNSSEC_NSEC_CNAME
;
1475 *result
= DNSSEC_NSEC_NODATA
;
1478 /* The RFC only specifies that we have to care for optout for NODATA for
1479 * DS records. However, children of an insecure opt-out delegation should
1480 * also be considered opt-out, rather than verified NXDOMAIN.
1481 * Note that we do not require a proof of wildcard non-existence if the
1482 * next closer domain is covered by an opt-out, as that would not provide
1483 * any additional information. */
1484 *result
= DNSSEC_NSEC_OPTOUT
;
1485 else if (no_wildcard
)
1486 *result
= DNSSEC_NSEC_NXDOMAIN
;
1488 *result
= DNSSEC_NSEC_NO_RR
;
1498 *ttl
= enclosure_rr
->ttl
;
1503 int dnssec_test_nsec(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
, uint32_t *ttl
) {
1504 DnsResourceRecord
*rr
;
1505 bool have_nsec3
= false;
1506 DnsAnswerFlags flags
;
1512 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1514 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1516 if (rr
->key
->class != key
->class)
1519 switch (rr
->key
->type
) {
1523 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
1527 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1528 *result
= DNSSEC_NSEC_FOUND
;
1529 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1530 *result
= DNSSEC_NSEC_CNAME
;
1532 *result
= DNSSEC_NSEC_NODATA
;
1535 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1542 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
), rr
->nsec
.next_domain_name
);
1546 *result
= DNSSEC_NSEC_NXDOMAIN
;
1549 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1557 case DNS_TYPE_NSEC3
:
1563 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1565 return dnssec_test_nsec3(answer
, key
, result
, authenticated
, ttl
);
1567 /* No approproate NSEC RR found, report this. */
1568 *result
= DNSSEC_NSEC_NO_RR
;
1572 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
1573 [DNSSEC_VALIDATED
] = "validated",
1574 [DNSSEC_INVALID
] = "invalid",
1575 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
1576 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
1577 [DNSSEC_NO_SIGNATURE
] = "no-signature",
1578 [DNSSEC_MISSING_KEY
] = "missing-key",
1579 [DNSSEC_UNSIGNED
] = "unsigned",
1580 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
1581 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
1582 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
1584 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);