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
41 * - per-interface DNSSEC setting
43 * - retry on failed validation?
44 * - DNSSEC key revocation support? https://tools.ietf.org/html/rfc5011
45 * - when doing negative caching, use NSEC/NSEC3 RR instead of SOA for TTL
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
) {
87 /* The algorithm from RFC 4034, Appendix B. */
90 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
92 sum
= (uint32_t) dnskey
->dnskey
.flags
+
93 ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
95 p
= dnskey
->dnskey
.key
;
97 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
98 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
100 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
102 return sum
& UINT32_C(0xFFFF);
105 static int rr_compare(const void *a
, const void *b
) {
106 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
110 /* Let's order the RRs according to RFC 4034, Section 6.3 */
114 assert((*x
)->wire_format
);
117 assert((*y
)->wire_format
);
119 m
= MIN((*x
)->wire_format_size
, (*y
)->wire_format_size
);
121 r
= memcmp((*x
)->wire_format
, (*y
)->wire_format
, m
);
125 if ((*x
)->wire_format_size
< (*y
)->wire_format_size
)
127 else if ((*x
)->wire_format_size
> (*y
)->wire_format_size
)
133 static int dnssec_rsa_verify_raw(
134 const char *hash_algorithm
,
135 const void *signature
, size_t signature_size
,
136 const void *data
, size_t data_size
,
137 const void *exponent
, size_t exponent_size
,
138 const void *modulus
, size_t modulus_size
) {
140 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
141 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
145 assert(hash_algorithm
);
147 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
153 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
159 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
165 ge
= gcry_sexp_build(&signature_sexp
,
167 "(sig-val (rsa (s %m)))",
175 ge
= gcry_sexp_build(&data_sexp
,
177 "(data (flags pkcs1) (hash %s %b))",
186 ge
= gcry_sexp_build(&public_key_sexp
,
188 "(public-key (rsa (n %m) (e %m)))",
196 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
197 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
200 log_debug("RSA signature check failed: %s", gpg_strerror(ge
));
214 gcry_sexp_release(public_key_sexp
);
216 gcry_sexp_release(signature_sexp
);
218 gcry_sexp_release(data_sexp
);
223 static int dnssec_rsa_verify(
224 const char *hash_algorithm
,
225 const void *hash
, size_t hash_size
,
226 DnsResourceRecord
*rrsig
,
227 DnsResourceRecord
*dnskey
) {
229 size_t exponent_size
, modulus_size
;
230 void *exponent
, *modulus
;
232 assert(hash_algorithm
);
234 assert(hash_size
> 0);
238 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
239 /* exponent is > 255 bytes long */
241 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
243 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[1]) << 8) |
244 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[2]);
246 if (exponent_size
< 256)
249 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
)
252 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
253 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
256 /* exponent is <= 255 bytes long */
258 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
259 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
261 if (exponent_size
<= 0)
264 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
)
267 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
268 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
271 return dnssec_rsa_verify_raw(
273 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
275 exponent
, exponent_size
,
276 modulus
, modulus_size
);
279 static int dnssec_ecdsa_verify_raw(
280 const char *hash_algorithm
,
282 const void *signature_r
, size_t signature_r_size
,
283 const void *signature_s
, size_t signature_s_size
,
284 const void *data
, size_t data_size
,
285 const void *key
, size_t key_size
) {
287 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
288 gcry_mpi_t q
= NULL
, r
= NULL
, s
= NULL
;
292 assert(hash_algorithm
);
294 ge
= gcry_mpi_scan(&r
, GCRYMPI_FMT_USG
, signature_r
, signature_r_size
, NULL
);
300 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature_s
, signature_s_size
, NULL
);
306 ge
= gcry_mpi_scan(&q
, GCRYMPI_FMT_USG
, key
, key_size
, NULL
);
312 ge
= gcry_sexp_build(&signature_sexp
,
314 "(sig-val (ecdsa (r %m) (s %m)))",
322 ge
= gcry_sexp_build(&data_sexp
,
324 "(data (flags rfc6979) (hash %s %b))",
333 ge
= gcry_sexp_build(&public_key_sexp
,
335 "(public-key (ecc (curve %s) (q %m)))",
343 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
344 if (gpg_err_code(ge
) == GPG_ERR_BAD_SIGNATURE
)
347 log_debug("ECDSA signature check failed: %s", gpg_strerror(ge
));
360 gcry_sexp_release(public_key_sexp
);
362 gcry_sexp_release(signature_sexp
);
364 gcry_sexp_release(data_sexp
);
369 static int dnssec_ecdsa_verify(
370 const char *hash_algorithm
,
372 const void *hash
, size_t hash_size
,
373 DnsResourceRecord
*rrsig
,
374 DnsResourceRecord
*dnskey
) {
385 if (algorithm
== DNSSEC_ALGORITHM_ECDSAP256SHA256
) {
387 curve
= "NIST P-256";
388 } else if (algorithm
== DNSSEC_ALGORITHM_ECDSAP384SHA384
) {
390 curve
= "NIST P-384";
394 if (dnskey
->dnskey
.key_size
!= key_size
* 2)
397 if (rrsig
->rrsig
.signature_size
!= key_size
* 2)
400 q
= alloca(key_size
*2 + 1);
401 q
[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
402 memcpy(q
+1, dnskey
->dnskey
.key
, key_size
*2);
404 return dnssec_ecdsa_verify_raw(
407 rrsig
->rrsig
.signature
, key_size
,
408 (uint8_t*) rrsig
->rrsig
.signature
+ key_size
, key_size
,
413 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
414 gcry_md_write(md
, &v
, sizeof(v
));
417 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
419 gcry_md_write(md
, &v
, sizeof(v
));
422 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
424 gcry_md_write(md
, &v
, sizeof(v
));
427 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
428 usec_t expiration
, inception
, skew
;
431 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
433 if (realtime
== USEC_INFINITY
)
434 realtime
= now(CLOCK_REALTIME
);
436 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
437 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
439 if (inception
> expiration
)
440 return -EKEYREJECTED
;
442 /* Permit a certain amount of clock skew of 10% of the valid
443 * time range. This takes inspiration from unbound's
445 skew
= (expiration
- inception
) / 10;
449 if (inception
< skew
)
454 if (expiration
+ skew
< expiration
)
455 expiration
= USEC_INFINITY
;
459 return realtime
< inception
|| realtime
> expiration
;
462 static int algorithm_to_gcrypt_md(uint8_t algorithm
) {
464 /* Translates a DNSSEC signature algorithm into a gcrypt
467 * Note that we implement all algorithms listed as "Must
468 * implement" and "Recommended to Implement" in RFC6944. We
469 * don't implement any algorithms that are listed as
470 * "Optional" or "Must Not Implement". Specifically, we do not
471 * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
476 case DNSSEC_ALGORITHM_RSASHA1
:
477 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
480 case DNSSEC_ALGORITHM_RSASHA256
:
481 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
482 return GCRY_MD_SHA256
;
484 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
485 return GCRY_MD_SHA384
;
487 case DNSSEC_ALGORITHM_RSASHA512
:
488 return GCRY_MD_SHA512
;
495 int dnssec_verify_rrset(
498 DnsResourceRecord
*rrsig
,
499 DnsResourceRecord
*dnskey
,
501 DnssecResult
*result
) {
503 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
506 DnsResourceRecord
**list
, *rr
;
507 gcry_md_hd_t md
= NULL
;
515 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
516 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
518 /* Verifies the the RRSet matching the specified "key" in "a",
519 * using the signature "rrsig" and the key "dnskey". It's
520 * assumed the RRSIG and DNSKEY match. */
522 md_algorithm
= algorithm_to_gcrypt_md(rrsig
->rrsig
.algorithm
);
523 if (md_algorithm
== -EOPNOTSUPP
) {
524 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
527 if (md_algorithm
< 0)
530 r
= dnssec_rrsig_expired(rrsig
, realtime
);
534 *result
= DNSSEC_SIGNATURE_EXPIRED
;
538 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
539 list
= newa(DnsResourceRecord
*, a
->n_rrs
);
541 DNS_ANSWER_FOREACH(rr
, a
) {
542 r
= dns_resource_key_equal(key
, rr
->key
);
548 /* We need the wire format for ordering, and digest calculation */
549 r
= dns_resource_record_to_wire_format(rr
, true);
555 if (n
> VERIFY_RRS_MAX
)
562 /* Bring the RRs into canonical order */
563 qsort_safe(list
, n
, sizeof(DnsResourceRecord
*), rr_compare
);
565 /* OK, the RRs are now in canonical order. Let's calculate the digest */
566 initialize_libgcrypt();
568 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
569 assert(hash_size
> 0);
571 gcry_md_open(&md
, 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(md_algorithm
),
635 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
636 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
637 r
= dnssec_ecdsa_verify(
638 gcry_md_algo_name(md_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 static int dnssec_fix_rrset_ttl(DnsAnswer
*a
, const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
, usec_t realtime
) {
716 DnsResourceRecord
*rr
;
722 DNS_ANSWER_FOREACH(rr
, a
) {
723 r
= dns_resource_key_equal(key
, rr
->key
);
729 /* Pick the TTL as the minimum of the RR's TTL, the
730 * RR's original TTL according to the RRSIG and the
731 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
732 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
733 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
739 int dnssec_verify_rrset_search(
742 DnsAnswer
*validated_dnskeys
,
744 DnssecResult
*result
) {
746 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
747 DnsResourceRecord
*rrsig
;
753 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
755 if (!a
|| a
->n_rrs
<= 0)
758 /* Iterate through each RRSIG RR. */
759 DNS_ANSWER_FOREACH(rrsig
, a
) {
760 DnsResourceRecord
*dnskey
;
761 DnsAnswerFlags flags
;
763 /* Is this an RRSIG RR that applies to RRs matching our key? */
764 r
= dnssec_key_match_rrsig(key
, rrsig
);
772 /* Look for a matching key */
773 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
774 DnssecResult one_result
;
776 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
779 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
780 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
);
786 /* Take the time here, if it isn't set yet, so
787 * that we do all validations with the same
789 if (realtime
== USEC_INFINITY
)
790 realtime
= now(CLOCK_REALTIME
);
792 /* Yay, we found a matching RRSIG with a matching
793 * DNSKEY, awesome. Now let's verify all entries of
794 * the RRSet against the RRSIG and DNSKEY
797 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
801 switch (one_result
) {
803 case DNSSEC_VALIDATED
:
804 /* Yay, the RR has been validated,
805 * return immediately, but fix up the expiry */
806 r
= dnssec_fix_rrset_ttl(a
, key
, rrsig
, realtime
);
810 *result
= DNSSEC_VALIDATED
;
814 /* If the signature is invalid, let's try another
815 key and/or signature. After all they
816 key_tags and stuff are not unique, and
817 might be shared by multiple keys. */
818 found_invalid
= true;
821 case DNSSEC_UNSUPPORTED_ALGORITHM
:
822 /* If the key algorithm is
823 unsupported, try another
824 RRSIG/DNSKEY pair, but remember we
825 encountered this, so that we can
826 return a proper error when we
827 encounter nothing better. */
828 found_unsupported_algorithm
= true;
831 case DNSSEC_SIGNATURE_EXPIRED
:
832 /* If the signature is expired, try
833 another one, but remember it, so
834 that we can return this */
835 found_expired_rrsig
= true;
839 assert_not_reached("Unexpected DNSSEC validation result");
844 if (found_expired_rrsig
)
845 *result
= DNSSEC_SIGNATURE_EXPIRED
;
846 else if (found_unsupported_algorithm
)
847 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
848 else if (found_invalid
)
849 *result
= DNSSEC_INVALID
;
850 else if (found_rrsig
)
851 *result
= DNSSEC_MISSING_KEY
;
853 *result
= DNSSEC_NO_SIGNATURE
;
858 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
859 DnsResourceRecord
*rr
;
862 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
864 DNS_ANSWER_FOREACH(rr
, a
) {
865 r
= dnssec_key_match_rrsig(key
, rr
);
875 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
879 /* Converts the specified hostname into DNSSEC canonicalized
888 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
896 /* DNSSEC validation is always done on the ASCII version of the label */
897 k
= dns_label_apply_idna(buffer
, r
, buffer
, buffer_max
);
904 if (buffer_max
< (size_t) r
+ 2)
907 /* The DNSSEC canonical form is not clear on what to
908 * do with dots appearing in labels, the way DNS-SD
909 * does it. Refuse it for now. */
911 if (memchr(buffer
, '.', r
))
914 for (i
= 0; i
< (size_t) r
; i
++) {
915 if (buffer
[i
] >= 'A' && buffer
[i
] <= 'Z')
916 buffer
[i
] = buffer
[i
] - 'A' + 'a';
928 /* Not even a single label: this is the root domain name */
930 assert(buffer_max
> 2);
940 static int digest_to_gcrypt_md(uint8_t algorithm
) {
942 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
946 case DNSSEC_DIGEST_SHA1
:
949 case DNSSEC_DIGEST_SHA256
:
950 return GCRY_MD_SHA256
;
952 case DNSSEC_DIGEST_SHA384
:
953 return GCRY_MD_SHA384
;
960 int dnssec_verify_dnskey(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
) {
961 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
962 gcry_md_hd_t md
= NULL
;
970 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
972 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
974 if (ds
->key
->type
!= DNS_TYPE_DS
)
976 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
977 return -EKEYREJECTED
;
978 if (dnskey
->dnskey
.protocol
!= 3)
979 return -EKEYREJECTED
;
981 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
983 if (dnssec_keytag(dnskey
) != ds
->ds
.key_tag
)
986 initialize_libgcrypt();
988 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
989 if (md_algorithm
< 0)
992 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
993 assert(hash_size
> 0);
995 if (ds
->ds
.digest_size
!= hash_size
)
998 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
1002 gcry_md_open(&md
, md_algorithm
, 0);
1006 gcry_md_write(md
, owner_name
, r
);
1007 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1008 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1009 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1010 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1012 result
= gcry_md_read(md
, 0);
1018 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1025 int dnssec_verify_dnskey_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1026 DnsResourceRecord
*ds
;
1027 DnsAnswerFlags flags
;
1032 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1035 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1037 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1040 if (ds
->key
->type
!= DNS_TYPE_DS
)
1043 if (ds
->key
->class != dnskey
->key
->class)
1046 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1052 r
= dnssec_verify_dnskey(dnskey
, ds
);
1062 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1064 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1066 switch (algorithm
) {
1068 case NSEC3_ALGORITHM_SHA1
:
1069 return GCRY_MD_SHA1
;
1076 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1077 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1078 gcry_md_hd_t md
= NULL
;
1089 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1092 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1093 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1097 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1101 initialize_libgcrypt();
1103 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1104 assert(hash_size
> 0);
1106 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1109 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1113 gcry_md_open(&md
, algorithm
, 0);
1117 gcry_md_write(md
, wire_format
, r
);
1118 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1120 result
= gcry_md_read(md
, 0);
1126 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1127 uint8_t tmp
[hash_size
];
1128 memcpy(tmp
, result
, hash_size
);
1131 gcry_md_write(md
, tmp
, hash_size
);
1132 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1134 result
= gcry_md_read(md
, 0);
1141 memcpy(ret
, result
, hash_size
);
1142 r
= (int) hash_size
;
1149 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsAnswerFlags flags
, DnsResourceRecord
*nsec3
) {
1155 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1158 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1159 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1162 /* Ignore NSEC3 RRs whose algorithm we don't know */
1163 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1165 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1166 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1172 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1174 if (nsec3
== rr
) /* Shortcut */
1177 if (rr
->key
->class != nsec3
->key
->class)
1179 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1181 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1183 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1185 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1188 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1189 r
= dns_name_parent(&a
); /* strip off hash */
1195 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1196 r
= dns_name_parent(&b
); /* strip off hash */
1202 return dns_name_equal(a
, b
);
1205 static int nsec3_hashed_domain(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1206 _cleanup_free_
char *l
= NULL
, *hashed_domain
= NULL
;
1207 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1215 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1216 if (hashed_size
< 0)
1219 l
= base32hexmem(hashed
, hashed_size
, false);
1223 hashed_domain
= strjoin(l
, ".", zone
, NULL
);
1227 *ret
= hashed_domain
;
1228 hashed_domain
= NULL
;
1233 /* See RFC 5155, Section 8
1234 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1235 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1236 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1237 * matches the wildcard domain.
1239 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1240 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1241 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1242 * to conclude anything we indicate this by returning NO_RR. */
1243 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
) {
1244 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard
= NULL
, *wildcard_domain
= NULL
;
1245 const char *zone
, *p
, *pp
= NULL
;
1246 DnsResourceRecord
*rr
, *enclosure_rr
, *suffix_rr
, *wildcard_rr
= NULL
;
1247 DnsAnswerFlags flags
;
1249 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1253 assert(authenticated
);
1255 /* First step, find the zone name and the NSEC3 parameters of the zone.
1256 * it is sufficient to look for the longest common suffix we find with
1257 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1258 * records from a given zone in a response must use the same
1260 zone
= DNS_RESOURCE_KEY_NAME(key
);
1262 DNS_ANSWER_FOREACH_FLAGS(suffix_rr
, flags
, answer
) {
1263 r
= nsec3_is_good(suffix_rr
, flags
, NULL
);
1269 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(suffix_rr
->key
), 1, zone
);
1276 /* Strip one label from the front */
1277 r
= dns_name_parent(&zone
);
1284 *result
= DNSSEC_NSEC_NO_RR
;
1288 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1289 p
= DNS_RESOURCE_KEY_NAME(key
);
1291 _cleanup_free_
char *hashed_domain
= NULL
;
1293 hashed_size
= nsec3_hashed_domain(suffix_rr
, p
, zone
, &hashed_domain
);
1294 if (hashed_size
== -EOPNOTSUPP
) {
1295 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1298 if (hashed_size
< 0)
1301 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1303 r
= nsec3_is_good(enclosure_rr
, flags
, suffix_rr
);
1309 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1312 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr
->key
), hashed_domain
);
1316 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1317 goto found_closest_encloser
;
1321 /* We didn't find the closest encloser with this name,
1322 * but let's remember this domain name, it might be
1323 * the next closer name */
1327 /* Strip one label from the front */
1328 r
= dns_name_parent(&p
);
1335 *result
= DNSSEC_NSEC_NO_RR
;
1338 found_closest_encloser
:
1339 /* We found a closest encloser in 'p'; next closer is 'pp' */
1341 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1342 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1345 /* Ensure that this data is from the delegated domain
1346 * (i.e. originates from the "lower" DNS server), and isn't
1347 * just glue records (i.e. doesn't originate from the "upper"
1349 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1350 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1354 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1355 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1356 *result
= DNSSEC_NSEC_FOUND
;
1357 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1358 *result
= DNSSEC_NSEC_CNAME
;
1360 *result
= DNSSEC_NSEC_NODATA
;
1367 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1369 wildcard
= strappend("*.", p
);
1373 r
= nsec3_hashed_domain(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1376 if (r
!= hashed_size
)
1379 r
= nsec3_hashed_domain(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1382 if (r
!= hashed_size
)
1385 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1386 _cleanup_free_
char *label
= NULL
, *next_hashed_domain
= NULL
;
1388 r
= nsec3_is_good(rr
, flags
, suffix_rr
);
1394 label
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1398 next_hashed_domain
= strjoin(label
, ".", zone
, NULL
);
1399 if (!next_hashed_domain
)
1402 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1406 if (rr
->nsec3
.flags
& 1)
1409 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1414 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
);
1418 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1423 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
, next_hashed_domain
);
1427 if (rr
->nsec3
.flags
& 1)
1428 /* This only makes sense if we have a wildcard delegation, which is
1429 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1430 * this not happening, so hence cannot simply conclude NXDOMAIN as
1434 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1440 if (wildcard_rr
&& no_wildcard
)
1444 *result
= DNSSEC_NSEC_NO_RR
;
1450 /* A wildcard exists that matches our query. */
1452 /* This is not specified in any RFC to the best of my knowledge, but
1453 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1454 * it means that we cannot prove that the source of synthesis is
1455 * correct, as there may be a closer match. */
1456 *result
= DNSSEC_NSEC_OPTOUT
;
1457 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1458 *result
= DNSSEC_NSEC_FOUND
;
1459 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1460 *result
= DNSSEC_NSEC_CNAME
;
1462 *result
= DNSSEC_NSEC_NODATA
;
1465 /* The RFC only specifies that we have to care for optout for NODATA for
1466 * DS records. However, children of an insecure opt-out delegation should
1467 * also be considered opt-out, rather than verified NXDOMAIN.
1468 * Note that we do not require a proof of wildcard non-existence if the
1469 * next closer domain is covered by an opt-out, as that would not provide
1470 * any additional information. */
1471 *result
= DNSSEC_NSEC_OPTOUT
;
1472 else if (no_wildcard
)
1473 *result
= DNSSEC_NSEC_NXDOMAIN
;
1475 *result
= DNSSEC_NSEC_NO_RR
;
1486 int dnssec_test_nsec(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
) {
1487 DnsResourceRecord
*rr
;
1488 bool have_nsec3
= false;
1489 DnsAnswerFlags flags
;
1494 assert(authenticated
);
1496 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1498 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1500 if (rr
->key
->class != key
->class)
1503 switch (rr
->key
->type
) {
1507 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
1511 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1512 *result
= DNSSEC_NSEC_FOUND
;
1513 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1514 *result
= DNSSEC_NSEC_CNAME
;
1516 *result
= DNSSEC_NSEC_NODATA
;
1517 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1521 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
), rr
->nsec
.next_domain_name
);
1525 *result
= DNSSEC_NSEC_NXDOMAIN
;
1526 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1531 case DNS_TYPE_NSEC3
:
1537 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1539 return dnssec_test_nsec3(answer
, key
, result
, authenticated
);
1541 /* No approproate NSEC RR found, report this. */
1542 *result
= DNSSEC_NSEC_NO_RR
;
1546 static const char* const dnssec_mode_table
[_DNSSEC_MODE_MAX
] = {
1548 [DNSSEC_DOWNGRADE_OK
] = "downgrade-ok",
1549 [DNSSEC_YES
] = "yes",
1551 DEFINE_STRING_TABLE_LOOKUP(dnssec_mode
, DnssecMode
);
1553 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
1554 [DNSSEC_VALIDATED
] = "validated",
1555 [DNSSEC_INVALID
] = "invalid",
1556 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
1557 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
1558 [DNSSEC_NO_SIGNATURE
] = "no-signature",
1559 [DNSSEC_MISSING_KEY
] = "missing-key",
1560 [DNSSEC_UNSIGNED
] = "unsigned",
1561 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
1562 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
1563 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
1565 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);