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(DNS_RESOURCE_RECORD_RDATA_SIZE(*x
), DNS_RESOURCE_RECORD_RDATA_SIZE(*y
));
121 r
= memcmp(DNS_RESOURCE_RECORD_RDATA(*x
), DNS_RESOURCE_RECORD_RDATA(*y
), m
);
125 if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
127 else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x
) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y
))
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 l
= DNS_RESOURCE_RECORD_RDATA_SIZE(rr
);
611 md_add_uint16(md
, (uint16_t) l
);
612 gcry_md_write(md
, DNS_RESOURCE_RECORD_RDATA(rr
), l
);
615 hash
= gcry_md_read(md
, 0);
621 switch (rrsig
->rrsig
.algorithm
) {
623 case DNSSEC_ALGORITHM_RSASHA1
:
624 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
625 case DNSSEC_ALGORITHM_RSASHA256
:
626 case DNSSEC_ALGORITHM_RSASHA512
:
627 r
= dnssec_rsa_verify(
628 gcry_md_algo_name(md_algorithm
),
634 case DNSSEC_ALGORITHM_ECDSAP256SHA256
:
635 case DNSSEC_ALGORITHM_ECDSAP384SHA384
:
636 r
= dnssec_ecdsa_verify(
637 gcry_md_algo_name(md_algorithm
),
638 rrsig
->rrsig
.algorithm
,
648 *result
= r
? DNSSEC_VALIDATED
: DNSSEC_INVALID
;
656 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
) {
661 /* Checks if the specified DNSKEY RR matches the key used for
662 * the signature in the specified RRSIG RR */
664 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
667 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
669 if (dnskey
->key
->class != rrsig
->key
->class)
671 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
673 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
))
675 if (dnskey
->dnskey
.protocol
!= 3)
677 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
680 if (dnssec_keytag(dnskey
) != rrsig
->rrsig
.key_tag
)
683 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), rrsig
->rrsig
.signer
);
686 int dnssec_key_match_rrsig(const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
692 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
694 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
696 if (rrsig
->key
->class != key
->class)
698 if (rrsig
->rrsig
.type_covered
!= key
->type
)
701 /* Make sure signer is a parent of the RRset */
702 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(rrsig
->key
), rrsig
->rrsig
.signer
);
706 /* Make sure the owner name has at least as many labels as the "label" fields indicates. */
707 r
= dns_name_count_labels(DNS_RESOURCE_KEY_NAME(rrsig
->key
));
710 if (r
< rrsig
->rrsig
.labels
)
713 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
716 static int dnssec_fix_rrset_ttl(DnsAnswer
*a
, const DnsResourceKey
*key
, DnsResourceRecord
*rrsig
, usec_t realtime
) {
717 DnsResourceRecord
*rr
;
723 DNS_ANSWER_FOREACH(rr
, a
) {
724 r
= dns_resource_key_equal(key
, rr
->key
);
730 /* Pick the TTL as the minimum of the RR's TTL, the
731 * RR's original TTL according to the RRSIG and the
732 * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */
733 rr
->ttl
= MIN3(rr
->ttl
, rrsig
->rrsig
.original_ttl
, rrsig
->ttl
);
734 rr
->expiry
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
740 int dnssec_verify_rrset_search(
743 DnsAnswer
*validated_dnskeys
,
745 DnssecResult
*result
) {
747 bool found_rrsig
= false, found_invalid
= false, found_expired_rrsig
= false, found_unsupported_algorithm
= false;
748 DnsResourceRecord
*rrsig
;
754 /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */
756 if (!a
|| a
->n_rrs
<= 0)
759 /* Iterate through each RRSIG RR. */
760 DNS_ANSWER_FOREACH(rrsig
, a
) {
761 DnsResourceRecord
*dnskey
;
762 DnsAnswerFlags flags
;
764 /* Is this an RRSIG RR that applies to RRs matching our key? */
765 r
= dnssec_key_match_rrsig(key
, rrsig
);
773 /* Look for a matching key */
774 DNS_ANSWER_FOREACH_FLAGS(dnskey
, flags
, validated_dnskeys
) {
775 DnssecResult one_result
;
777 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
780 /* Is this a DNSKEY RR that matches they key of our RRSIG? */
781 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
);
787 /* Take the time here, if it isn't set yet, so
788 * that we do all validations with the same
790 if (realtime
== USEC_INFINITY
)
791 realtime
= now(CLOCK_REALTIME
);
793 /* Yay, we found a matching RRSIG with a matching
794 * DNSKEY, awesome. Now let's verify all entries of
795 * the RRSet against the RRSIG and DNSKEY
798 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
, &one_result
);
802 switch (one_result
) {
804 case DNSSEC_VALIDATED
:
805 /* Yay, the RR has been validated,
806 * return immediately, but fix up the expiry */
807 r
= dnssec_fix_rrset_ttl(a
, key
, rrsig
, realtime
);
811 *result
= DNSSEC_VALIDATED
;
815 /* If the signature is invalid, let's try another
816 key and/or signature. After all they
817 key_tags and stuff are not unique, and
818 might be shared by multiple keys. */
819 found_invalid
= true;
822 case DNSSEC_UNSUPPORTED_ALGORITHM
:
823 /* If the key algorithm is
824 unsupported, try another
825 RRSIG/DNSKEY pair, but remember we
826 encountered this, so that we can
827 return a proper error when we
828 encounter nothing better. */
829 found_unsupported_algorithm
= true;
832 case DNSSEC_SIGNATURE_EXPIRED
:
833 /* If the signature is expired, try
834 another one, but remember it, so
835 that we can return this */
836 found_expired_rrsig
= true;
840 assert_not_reached("Unexpected DNSSEC validation result");
845 if (found_expired_rrsig
)
846 *result
= DNSSEC_SIGNATURE_EXPIRED
;
847 else if (found_unsupported_algorithm
)
848 *result
= DNSSEC_UNSUPPORTED_ALGORITHM
;
849 else if (found_invalid
)
850 *result
= DNSSEC_INVALID
;
851 else if (found_rrsig
)
852 *result
= DNSSEC_MISSING_KEY
;
854 *result
= DNSSEC_NO_SIGNATURE
;
859 int dnssec_has_rrsig(DnsAnswer
*a
, const DnsResourceKey
*key
) {
860 DnsResourceRecord
*rr
;
863 /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */
865 DNS_ANSWER_FOREACH(rr
, a
) {
866 r
= dnssec_key_match_rrsig(key
, rr
);
876 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
880 /* Converts the specified hostname into DNSSEC canonicalized
889 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
897 /* DNSSEC validation is always done on the ASCII version of the label */
898 k
= dns_label_apply_idna(buffer
, r
, buffer
, buffer_max
);
905 if (buffer_max
< (size_t) r
+ 2)
908 /* The DNSSEC canonical form is not clear on what to
909 * do with dots appearing in labels, the way DNS-SD
910 * does it. Refuse it for now. */
912 if (memchr(buffer
, '.', r
))
915 for (i
= 0; i
< (size_t) r
; i
++) {
916 if (buffer
[i
] >= 'A' && buffer
[i
] <= 'Z')
917 buffer
[i
] = buffer
[i
] - 'A' + 'a';
929 /* Not even a single label: this is the root domain name */
931 assert(buffer_max
> 2);
941 static int digest_to_gcrypt_md(uint8_t algorithm
) {
943 /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
947 case DNSSEC_DIGEST_SHA1
:
950 case DNSSEC_DIGEST_SHA256
:
951 return GCRY_MD_SHA256
;
953 case DNSSEC_DIGEST_SHA384
:
954 return GCRY_MD_SHA384
;
961 int dnssec_verify_dnskey(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
) {
962 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
963 gcry_md_hd_t md
= NULL
;
971 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
973 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
975 if (ds
->key
->type
!= DNS_TYPE_DS
)
977 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
978 return -EKEYREJECTED
;
979 if (dnskey
->dnskey
.protocol
!= 3)
980 return -EKEYREJECTED
;
982 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
984 if (dnssec_keytag(dnskey
) != ds
->ds
.key_tag
)
987 initialize_libgcrypt();
989 md_algorithm
= digest_to_gcrypt_md(ds
->ds
.digest_type
);
990 if (md_algorithm
< 0)
993 hash_size
= gcry_md_get_algo_dlen(md_algorithm
);
994 assert(hash_size
> 0);
996 if (ds
->ds
.digest_size
!= hash_size
)
999 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
1003 gcry_md_open(&md
, md_algorithm
, 0);
1007 gcry_md_write(md
, owner_name
, r
);
1008 md_add_uint16(md
, dnskey
->dnskey
.flags
);
1009 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
1010 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
1011 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
1013 result
= gcry_md_read(md
, 0);
1019 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;
1026 int dnssec_verify_dnskey_search(DnsResourceRecord
*dnskey
, DnsAnswer
*validated_ds
) {
1027 DnsResourceRecord
*ds
;
1028 DnsAnswerFlags flags
;
1033 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
1036 DNS_ANSWER_FOREACH_FLAGS(ds
, flags
, validated_ds
) {
1038 if ((flags
& DNS_ANSWER_AUTHENTICATED
) == 0)
1041 if (ds
->key
->type
!= DNS_TYPE_DS
)
1044 if (ds
->key
->class != dnskey
->key
->class)
1047 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(ds
->key
));
1053 r
= dnssec_verify_dnskey(dnskey
, ds
);
1063 static int nsec3_hash_to_gcrypt_md(uint8_t algorithm
) {
1065 /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
1067 switch (algorithm
) {
1069 case NSEC3_ALGORITHM_SHA1
:
1070 return GCRY_MD_SHA1
;
1077 int dnssec_nsec3_hash(DnsResourceRecord
*nsec3
, const char *name
, void *ret
) {
1078 uint8_t wire_format
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
1079 gcry_md_hd_t md
= NULL
;
1090 if (nsec3
->key
->type
!= DNS_TYPE_NSEC3
)
1093 if (nsec3
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
) {
1094 log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3
));
1098 algorithm
= nsec3_hash_to_gcrypt_md(nsec3
->nsec3
.algorithm
);
1102 initialize_libgcrypt();
1104 hash_size
= gcry_md_get_algo_dlen(algorithm
);
1105 assert(hash_size
> 0);
1107 if (nsec3
->nsec3
.next_hashed_name_size
!= hash_size
)
1110 r
= dns_name_to_wire_format(name
, wire_format
, sizeof(wire_format
), true);
1114 gcry_md_open(&md
, algorithm
, 0);
1118 gcry_md_write(md
, wire_format
, r
);
1119 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1121 result
= gcry_md_read(md
, 0);
1127 for (k
= 0; k
< nsec3
->nsec3
.iterations
; k
++) {
1128 uint8_t tmp
[hash_size
];
1129 memcpy(tmp
, result
, hash_size
);
1132 gcry_md_write(md
, tmp
, hash_size
);
1133 gcry_md_write(md
, nsec3
->nsec3
.salt
, nsec3
->nsec3
.salt_size
);
1135 result
= gcry_md_read(md
, 0);
1142 memcpy(ret
, result
, hash_size
);
1143 r
= (int) hash_size
;
1150 static int nsec3_is_good(DnsResourceRecord
*rr
, DnsAnswerFlags flags
, DnsResourceRecord
*nsec3
) {
1156 if (rr
->key
->type
!= DNS_TYPE_NSEC3
)
1159 /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */
1160 if (!IN_SET(rr
->nsec3
.flags
, 0, 1))
1163 /* Ignore NSEC3 RRs whose algorithm we don't know */
1164 if (nsec3_hash_to_gcrypt_md(rr
->nsec3
.algorithm
) < 0)
1166 /* Ignore NSEC3 RRs with an excessive number of required iterations */
1167 if (rr
->nsec3
.iterations
> NSEC3_ITERATIONS_MAX
)
1173 /* If a second NSEC3 RR is specified, also check if they are from the same zone. */
1175 if (nsec3
== rr
) /* Shortcut */
1178 if (rr
->key
->class != nsec3
->key
->class)
1180 if (rr
->nsec3
.algorithm
!= nsec3
->nsec3
.algorithm
)
1182 if (rr
->nsec3
.iterations
!= nsec3
->nsec3
.iterations
)
1184 if (rr
->nsec3
.salt_size
!= nsec3
->nsec3
.salt_size
)
1186 if (memcmp(rr
->nsec3
.salt
, nsec3
->nsec3
.salt
, rr
->nsec3
.salt_size
) != 0)
1189 a
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1190 r
= dns_name_parent(&a
); /* strip off hash */
1196 b
= DNS_RESOURCE_KEY_NAME(nsec3
->key
);
1197 r
= dns_name_parent(&b
); /* strip off hash */
1203 return dns_name_equal(a
, b
);
1206 static int nsec3_hashed_domain(DnsResourceRecord
*nsec3
, const char *domain
, const char *zone
, char **ret
) {
1207 _cleanup_free_
char *l
= NULL
, *hashed_domain
= NULL
;
1208 uint8_t hashed
[DNSSEC_HASH_SIZE_MAX
];
1216 hashed_size
= dnssec_nsec3_hash(nsec3
, domain
, hashed
);
1217 if (hashed_size
< 0)
1220 l
= base32hexmem(hashed
, hashed_size
, false);
1224 hashed_domain
= strjoin(l
, ".", zone
, NULL
);
1228 *ret
= hashed_domain
;
1229 hashed_domain
= NULL
;
1234 /* See RFC 5155, Section 8
1235 * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest
1236 * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there
1237 * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that
1238 * matches the wildcard domain.
1240 * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or
1241 * that there is no proof either way. The latter is the case if a the proof of non-existence of a given
1242 * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records
1243 * to conclude anything we indicate this by returning NO_RR. */
1244 static int dnssec_test_nsec3(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
) {
1245 _cleanup_free_
char *next_closer_domain
= NULL
, *wildcard
= NULL
, *wildcard_domain
= NULL
;
1246 const char *zone
, *p
, *pp
= NULL
;
1247 DnsResourceRecord
*rr
, *enclosure_rr
, *suffix_rr
, *wildcard_rr
= NULL
;
1248 DnsAnswerFlags flags
;
1250 bool a
, no_closer
= false, no_wildcard
= false, optout
= false;
1254 assert(authenticated
);
1256 /* First step, find the zone name and the NSEC3 parameters of the zone.
1257 * it is sufficient to look for the longest common suffix we find with
1258 * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
1259 * records from a given zone in a response must use the same
1261 zone
= DNS_RESOURCE_KEY_NAME(key
);
1263 DNS_ANSWER_FOREACH_FLAGS(suffix_rr
, flags
, answer
) {
1264 r
= nsec3_is_good(suffix_rr
, flags
, NULL
);
1270 r
= dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(suffix_rr
->key
), 1, zone
);
1277 /* Strip one label from the front */
1278 r
= dns_name_parent(&zone
);
1285 *result
= DNSSEC_NSEC_NO_RR
;
1289 /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
1290 p
= DNS_RESOURCE_KEY_NAME(key
);
1292 _cleanup_free_
char *hashed_domain
= NULL
;
1294 hashed_size
= nsec3_hashed_domain(suffix_rr
, p
, zone
, &hashed_domain
);
1295 if (hashed_size
== -EOPNOTSUPP
) {
1296 *result
= DNSSEC_NSEC_UNSUPPORTED_ALGORITHM
;
1299 if (hashed_size
< 0)
1302 DNS_ANSWER_FOREACH_FLAGS(enclosure_rr
, flags
, answer
) {
1304 r
= nsec3_is_good(enclosure_rr
, flags
, suffix_rr
);
1310 if (enclosure_rr
->nsec3
.next_hashed_name_size
!= (size_t) hashed_size
)
1313 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr
->key
), hashed_domain
);
1317 a
= flags
& DNS_ANSWER_AUTHENTICATED
;
1318 goto found_closest_encloser
;
1322 /* We didn't find the closest encloser with this name,
1323 * but let's remember this domain name, it might be
1324 * the next closer name */
1328 /* Strip one label from the front */
1329 r
= dns_name_parent(&p
);
1336 *result
= DNSSEC_NSEC_NO_RR
;
1339 found_closest_encloser
:
1340 /* We found a closest encloser in 'p'; next closer is 'pp' */
1342 /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */
1343 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_DNAME
))
1346 /* Ensure that this data is from the delegated domain
1347 * (i.e. originates from the "lower" DNS server), and isn't
1348 * just glue records (i.e. doesn't originate from the "upper"
1350 if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_NS
) &&
1351 !bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_SOA
))
1355 /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */
1356 if (bitmap_isset(enclosure_rr
->nsec3
.types
, key
->type
))
1357 *result
= DNSSEC_NSEC_FOUND
;
1358 else if (bitmap_isset(enclosure_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1359 *result
= DNSSEC_NSEC_CNAME
;
1361 *result
= DNSSEC_NSEC_NODATA
;
1368 /* Prove that there is no next closer and whether or not there is a wildcard domain. */
1370 wildcard
= strappend("*.", p
);
1374 r
= nsec3_hashed_domain(enclosure_rr
, wildcard
, zone
, &wildcard_domain
);
1377 if (r
!= hashed_size
)
1380 r
= nsec3_hashed_domain(enclosure_rr
, pp
, zone
, &next_closer_domain
);
1383 if (r
!= hashed_size
)
1386 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1387 _cleanup_free_
char *label
= NULL
, *next_hashed_domain
= NULL
;
1389 r
= nsec3_is_good(rr
, flags
, suffix_rr
);
1395 label
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1399 next_hashed_domain
= strjoin(label
, ".", zone
, NULL
);
1400 if (!next_hashed_domain
)
1403 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), next_closer_domain
, next_hashed_domain
);
1407 if (rr
->nsec3
.flags
& 1)
1410 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1415 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
);
1419 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1424 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), wildcard_domain
, next_hashed_domain
);
1428 if (rr
->nsec3
.flags
& 1)
1429 /* This only makes sense if we have a wildcard delegation, which is
1430 * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on
1431 * this not happening, so hence cannot simply conclude NXDOMAIN as
1435 a
= a
&& (flags
& DNS_ANSWER_AUTHENTICATED
);
1441 if (wildcard_rr
&& no_wildcard
)
1445 *result
= DNSSEC_NSEC_NO_RR
;
1451 /* A wildcard exists that matches our query. */
1453 /* This is not specified in any RFC to the best of my knowledge, but
1454 * if the next closer enclosure is covered by an opt-out NSEC3 RR
1455 * it means that we cannot prove that the source of synthesis is
1456 * correct, as there may be a closer match. */
1457 *result
= DNSSEC_NSEC_OPTOUT
;
1458 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, key
->type
))
1459 *result
= DNSSEC_NSEC_FOUND
;
1460 else if (bitmap_isset(wildcard_rr
->nsec3
.types
, DNS_TYPE_CNAME
))
1461 *result
= DNSSEC_NSEC_CNAME
;
1463 *result
= DNSSEC_NSEC_NODATA
;
1466 /* The RFC only specifies that we have to care for optout for NODATA for
1467 * DS records. However, children of an insecure opt-out delegation should
1468 * also be considered opt-out, rather than verified NXDOMAIN.
1469 * Note that we do not require a proof of wildcard non-existence if the
1470 * next closer domain is covered by an opt-out, as that would not provide
1471 * any additional information. */
1472 *result
= DNSSEC_NSEC_OPTOUT
;
1473 else if (no_wildcard
)
1474 *result
= DNSSEC_NSEC_NXDOMAIN
;
1476 *result
= DNSSEC_NSEC_NO_RR
;
1487 int dnssec_test_nsec(DnsAnswer
*answer
, DnsResourceKey
*key
, DnssecNsecResult
*result
, bool *authenticated
) {
1488 DnsResourceRecord
*rr
;
1489 bool have_nsec3
= false;
1490 DnsAnswerFlags flags
;
1495 assert(authenticated
);
1497 /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
1499 DNS_ANSWER_FOREACH_FLAGS(rr
, flags
, answer
) {
1501 if (rr
->key
->class != key
->class)
1504 switch (rr
->key
->type
) {
1508 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
1512 if (bitmap_isset(rr
->nsec
.types
, key
->type
))
1513 *result
= DNSSEC_NSEC_FOUND
;
1514 else if (bitmap_isset(rr
->nsec
.types
, DNS_TYPE_CNAME
))
1515 *result
= DNSSEC_NSEC_CNAME
;
1517 *result
= DNSSEC_NSEC_NODATA
;
1518 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1522 r
= dns_name_between(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
), rr
->nsec
.next_domain_name
);
1526 *result
= DNSSEC_NSEC_NXDOMAIN
;
1527 *authenticated
= flags
& DNS_ANSWER_AUTHENTICATED
;
1532 case DNS_TYPE_NSEC3
:
1538 /* OK, this was not sufficient. Let's see if NSEC3 can help. */
1540 return dnssec_test_nsec3(answer
, key
, result
, authenticated
);
1542 /* No approproate NSEC RR found, report this. */
1543 *result
= DNSSEC_NSEC_NO_RR
;
1547 static const char* const dnssec_mode_table
[_DNSSEC_MODE_MAX
] = {
1549 [DNSSEC_DOWNGRADE_OK
] = "downgrade-ok",
1550 [DNSSEC_YES
] = "yes",
1552 DEFINE_STRING_TABLE_LOOKUP(dnssec_mode
, DnssecMode
);
1554 static const char* const dnssec_result_table
[_DNSSEC_RESULT_MAX
] = {
1555 [DNSSEC_VALIDATED
] = "validated",
1556 [DNSSEC_INVALID
] = "invalid",
1557 [DNSSEC_SIGNATURE_EXPIRED
] = "signature-expired",
1558 [DNSSEC_UNSUPPORTED_ALGORITHM
] = "unsupported-algorithm",
1559 [DNSSEC_NO_SIGNATURE
] = "no-signature",
1560 [DNSSEC_MISSING_KEY
] = "missing-key",
1561 [DNSSEC_UNSIGNED
] = "unsigned",
1562 [DNSSEC_FAILED_AUXILIARY
] = "failed-auxiliary",
1563 [DNSSEC_NSEC_MISMATCH
] = "nsec-mismatch",
1564 [DNSSEC_INCOMPATIBLE_SERVER
] = "incompatible-server",
1566 DEFINE_STRING_TABLE_LOOKUP(dnssec_result
, DnssecResult
);