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 "resolved-dns-dnssec.h"
27 #include "resolved-dns-packet.h"
31 * How does the DNSSEC canonical form of a hostname with a label
32 * containing a dot look like, the way DNS-SD does it?
36 #define VERIFY_RRS_MAX 256
37 #define MAX_KEY_SIZE (32*1024)
40 * The DNSSEC Chain of trust:
42 * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
43 * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
44 * DS RRs are protected like normal RRs
47 * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
50 static bool dnssec_algorithm_supported(int algorithm
) {
51 return IN_SET(algorithm
,
52 DNSSEC_ALGORITHM_RSASHA1
,
53 DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
,
54 DNSSEC_ALGORITHM_RSASHA256
,
55 DNSSEC_ALGORITHM_RSASHA512
);
58 static bool dnssec_digest_supported(int digest
) {
61 DNSSEC_DIGEST_SHA256
);
64 uint16_t dnssec_keytag(DnsResourceRecord
*dnskey
) {
69 /* The algorithm from RFC 4034, Appendix B. */
72 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
74 sum
= (uint32_t) dnskey
->dnskey
.flags
+
75 ((((uint32_t) dnskey
->dnskey
.protocol
) << 8) + (uint32_t) dnskey
->dnskey
.algorithm
);
77 p
= dnskey
->dnskey
.key
;
79 for (i
= 0; i
< dnskey
->dnskey
.key_size
; i
++)
80 sum
+= (i
& 1) == 0 ? (uint32_t) p
[i
] << 8 : (uint32_t) p
[i
];
82 sum
+= (sum
>> 16) & UINT32_C(0xFFFF);
84 return sum
& UINT32_C(0xFFFF);
87 static int rr_compare(const void *a
, const void *b
) {
88 DnsResourceRecord
**x
= (DnsResourceRecord
**) a
, **y
= (DnsResourceRecord
**) b
;
92 /* Let's order the RRs according to RFC 4034, Section 6.3 */
96 assert((*x
)->wire_format
);
99 assert((*y
)->wire_format
);
101 m
= MIN((*x
)->wire_format_size
, (*y
)->wire_format_size
);
103 r
= memcmp((*x
)->wire_format
, (*y
)->wire_format
, m
);
107 if ((*x
)->wire_format_size
< (*y
)->wire_format_size
)
109 else if ((*x
)->wire_format_size
> (*y
)->wire_format_size
)
115 static int dnssec_rsa_verify(
116 const char *hash_algorithm
,
117 const void *signature
, size_t signature_size
,
118 const void *data
, size_t data_size
,
119 const void *exponent
, size_t exponent_size
,
120 const void *modulus
, size_t modulus_size
) {
122 gcry_sexp_t public_key_sexp
= NULL
, data_sexp
= NULL
, signature_sexp
= NULL
;
123 gcry_mpi_t n
= NULL
, e
= NULL
, s
= NULL
;
127 assert(hash_algorithm
);
129 ge
= gcry_mpi_scan(&s
, GCRYMPI_FMT_USG
, signature
, signature_size
, NULL
);
135 ge
= gcry_mpi_scan(&e
, GCRYMPI_FMT_USG
, exponent
, exponent_size
, NULL
);
141 ge
= gcry_mpi_scan(&n
, GCRYMPI_FMT_USG
, modulus
, modulus_size
, NULL
);
147 ge
= gcry_sexp_build(&signature_sexp
,
149 "(sig-val (rsa (s %m)))",
157 ge
= gcry_sexp_build(&data_sexp
,
159 "(data (flags pkcs1) (hash %s %b))",
168 ge
= gcry_sexp_build(&public_key_sexp
,
170 "(public-key (rsa (n %m) (e %m)))",
178 ge
= gcry_pk_verify(signature_sexp
, data_sexp
, public_key_sexp
);
179 if (ge
== GPG_ERR_BAD_SIGNATURE
)
195 gcry_sexp_release(public_key_sexp
);
197 gcry_sexp_release(signature_sexp
);
199 gcry_sexp_release(data_sexp
);
204 static void md_add_uint8(gcry_md_hd_t md
, uint8_t v
) {
205 gcry_md_write(md
, &v
, sizeof(v
));
208 static void md_add_uint16(gcry_md_hd_t md
, uint16_t v
) {
210 gcry_md_write(md
, &v
, sizeof(v
));
213 static void md_add_uint32(gcry_md_hd_t md
, uint32_t v
) {
215 gcry_md_write(md
, &v
, sizeof(v
));
218 static int dnssec_rrsig_expired(DnsResourceRecord
*rrsig
, usec_t realtime
) {
219 usec_t expiration
, inception
, skew
;
222 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
224 if (realtime
== USEC_INFINITY
)
225 realtime
= now(CLOCK_REALTIME
);
227 expiration
= rrsig
->rrsig
.expiration
* USEC_PER_SEC
;
228 inception
= rrsig
->rrsig
.inception
* USEC_PER_SEC
;
230 if (inception
> expiration
)
233 /* Permit a certain amount of clock skew of 10% of the valid time range */
234 skew
= (expiration
- inception
) / 10;
236 if (inception
< skew
)
241 if (expiration
+ skew
< expiration
)
242 expiration
= USEC_INFINITY
;
246 return realtime
< inception
|| realtime
> expiration
;
249 int dnssec_verify_rrset(
252 DnsResourceRecord
*rrsig
,
253 DnsResourceRecord
*dnskey
,
256 uint8_t wire_format_name
[DNS_WIRE_FOMAT_HOSTNAME_MAX
];
257 size_t exponent_size
, modulus_size
, hash_size
;
258 void *exponent
, *modulus
, *hash
;
259 DnsResourceRecord
**list
, *rr
;
260 gcry_md_hd_t md
= NULL
;
267 assert(rrsig
->key
->type
== DNS_TYPE_RRSIG
);
268 assert(dnskey
->key
->type
== DNS_TYPE_DNSKEY
);
270 /* Verifies the the RRSet matching the specified "key" in "a",
271 * using the signature "rrsig" and the key "dnskey". It's
272 * assumed the RRSIG and DNSKEY match. */
274 if (!dnssec_algorithm_supported(rrsig
->rrsig
.algorithm
))
277 if (a
->n_rrs
> VERIFY_RRS_MAX
)
280 r
= dnssec_rrsig_expired(rrsig
, realtime
);
284 return DNSSEC_SIGNATURE_EXPIRED
;
286 /* Collect all relevant RRs in a single array, so that we can look at the RRset */
287 list
= newa(DnsResourceRecord
*, a
->n_rrs
);
289 DNS_ANSWER_FOREACH(rr
, a
) {
290 r
= dns_resource_key_equal(key
, rr
->key
);
296 /* We need the wire format for ordering, and digest calculation */
297 r
= dns_resource_record_to_wire_format(rr
, true);
307 /* Bring the RRs into canonical order */
308 qsort_safe(list
, n
, sizeof(DnsResourceRecord
), rr_compare
);
310 /* OK, the RRs are now in canonical order. Let's calculate the digest */
311 switch (rrsig
->rrsig
.algorithm
) {
313 case DNSSEC_ALGORITHM_RSASHA1
:
314 case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
:
315 gcry_md_open(&md
, GCRY_MD_SHA1
, 0);
319 case DNSSEC_ALGORITHM_RSASHA256
:
320 gcry_md_open(&md
, GCRY_MD_SHA256
, 0);
324 case DNSSEC_ALGORITHM_RSASHA512
:
325 gcry_md_open(&md
, GCRY_MD_SHA512
, 0);
330 assert_not_reached("Unknown digest");
336 md_add_uint16(md
, rrsig
->rrsig
.type_covered
);
337 md_add_uint8(md
, rrsig
->rrsig
.algorithm
);
338 md_add_uint8(md
, rrsig
->rrsig
.labels
);
339 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
340 md_add_uint32(md
, rrsig
->rrsig
.expiration
);
341 md_add_uint32(md
, rrsig
->rrsig
.inception
);
342 md_add_uint16(md
, rrsig
->rrsig
.key_tag
);
344 r
= dns_name_to_wire_format(rrsig
->rrsig
.signer
, wire_format_name
, sizeof(wire_format_name
), true);
347 gcry_md_write(md
, wire_format_name
, r
);
349 for (k
= 0; k
< n
; k
++) {
353 r
= dns_name_to_wire_format(DNS_RESOURCE_KEY_NAME(rr
->key
), wire_format_name
, sizeof(wire_format_name
), true);
356 gcry_md_write(md
, wire_format_name
, r
);
358 md_add_uint16(md
, rr
->key
->type
);
359 md_add_uint16(md
, rr
->key
->class);
360 md_add_uint32(md
, rrsig
->rrsig
.original_ttl
);
362 assert(rr
->wire_format_rdata_offset
<= rr
->wire_format_size
);
363 l
= rr
->wire_format_size
- rr
->wire_format_rdata_offset
;
366 md_add_uint16(md
, (uint16_t) l
);
367 gcry_md_write(md
, (uint8_t*) rr
->wire_format
+ rr
->wire_format_rdata_offset
, l
);
370 hash
= gcry_md_read(md
, 0);
376 if (*(uint8_t*) dnskey
->dnskey
.key
== 0) {
377 /* exponent is > 255 bytes long */
379 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 3;
381 ((size_t) (((uint8_t*) dnskey
->dnskey
.key
)[0]) << 8) |
382 ((size_t) ((uint8_t*) dnskey
->dnskey
.key
)[1]);
384 if (exponent_size
< 256) {
389 if (3 + exponent_size
>= dnskey
->dnskey
.key_size
) {
394 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 3 + exponent_size
;
395 modulus_size
= dnskey
->dnskey
.key_size
- 3 - exponent_size
;
398 /* exponent is <= 255 bytes long */
400 exponent
= (uint8_t*) dnskey
->dnskey
.key
+ 1;
401 exponent_size
= (size_t) ((uint8_t*) dnskey
->dnskey
.key
)[0];
403 if (exponent_size
<= 0) {
408 if (1 + exponent_size
>= dnskey
->dnskey
.key_size
) {
413 modulus
= (uint8_t*) dnskey
->dnskey
.key
+ 1 + exponent_size
;
414 modulus_size
= dnskey
->dnskey
.key_size
- 1 - exponent_size
;
417 r
= dnssec_rsa_verify(
418 gcry_md_algo_name(gcry_md_get_algo(md
)),
419 rrsig
->rrsig
.signature
, rrsig
->rrsig
.signature_size
,
421 exponent
, exponent_size
,
422 modulus
, modulus_size
);
426 r
= r
? DNSSEC_VERIFIED
: DNSSEC_INVALID
;
433 int dnssec_rrsig_match_dnskey(DnsResourceRecord
*rrsig
, DnsResourceRecord
*dnskey
) {
438 /* Checks if the specified DNSKEY RR matches the key used for
439 * the signature in the specified RRSIG RR */
441 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
444 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
446 if (dnskey
->key
->class != rrsig
->key
->class)
448 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
450 if (dnskey
->dnskey
.protocol
!= 3)
452 if (dnskey
->dnskey
.algorithm
!= rrsig
->rrsig
.algorithm
)
455 if (dnssec_keytag(dnskey
) != rrsig
->rrsig
.key_tag
)
458 return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey
->key
), DNS_RESOURCE_KEY_NAME(rrsig
->key
));
461 int dnssec_key_match_rrsig(DnsResourceKey
*key
, DnsResourceRecord
*rrsig
) {
465 /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
467 if (rrsig
->key
->type
!= DNS_TYPE_RRSIG
)
469 if (rrsig
->key
->class != key
->class)
471 if (rrsig
->rrsig
.type_covered
!= key
->type
)
474 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig
->key
), DNS_RESOURCE_KEY_NAME(key
));
477 int dnssec_verify_rrset_search(
480 DnsAnswer
*validated_dnskeys
,
483 bool found_rrsig
= false, found_dnskey
= false;
484 DnsResourceRecord
*rrsig
;
489 /* Verifies all RRs from "a" that match the key "key", against DNSKEY RRs in "validated_dnskeys" */
491 if (!a
|| a
->n_rrs
<= 0)
494 /* Iterate through each RRSIG RR. */
495 DNS_ANSWER_FOREACH(rrsig
, a
) {
496 DnsResourceRecord
*dnskey
;
498 r
= dnssec_key_match_rrsig(key
, rrsig
);
506 DNS_ANSWER_FOREACH(dnskey
, validated_dnskeys
) {
508 r
= dnssec_rrsig_match_dnskey(rrsig
, dnskey
);
516 /* Take the time here, if it isn't set yet, so
517 * that we do all validations with the same
519 if (realtime
== USEC_INFINITY
)
520 realtime
= now(CLOCK_REALTIME
);
522 /* Yay, we found a matching RRSIG with a matching
523 * DNSKEY, awesome. Now let's verify all entries of
524 * the RRSet against the RRSIG and DNSKEY
527 r
= dnssec_verify_rrset(a
, key
, rrsig
, dnskey
, realtime
);
528 if (r
< 0 && r
!= EOPNOTSUPP
)
530 if (r
== DNSSEC_VERIFIED
)
531 return DNSSEC_VERIFIED
;
533 /* If the signature is invalid, or done using
534 an unsupported algorithm, let's try another
535 key and/or signature. After all they
536 key_tags and stuff are not unique, and
537 might be shared by multiple keys. */
542 return DNSSEC_INVALID
;
545 return DNSSEC_MISSING_KEY
;
547 return DNSSEC_NO_SIGNATURE
;
550 int dnssec_canonicalize(const char *n
, char *buffer
, size_t buffer_max
) {
551 _cleanup_free_
char *s
= NULL
;
555 /* Converts the specified hostname into DNSSEC canonicalized
564 r
= dns_label_unescape(&n
, buffer
, buffer_max
);
572 /* DNSSEC validation is always done on the ASCII version of the label */
573 k
= dns_label_apply_idna(buffer
, r
, buffer
, buffer_max
);
580 if (buffer_max
< (size_t) r
+ 2)
583 /* The DNSSEC canonical form is not clear on what to
584 * do with dots appearing in labels, the way DNS-SD
585 * does it. Refuse it for now. */
587 if (memchr(buffer
, '.', r
))
590 for (i
= 0; i
< (size_t) r
; i
++) {
591 if (buffer
[i
] >= 'A' && buffer
[i
] <= 'Z')
592 buffer
[i
] = buffer
[i
] - 'A' + 'a';
604 /* Not even a single label: this is the root domain name */
606 assert(buffer_max
> 2);
616 int dnssec_verify_dnskey(DnsResourceRecord
*dnskey
, DnsResourceRecord
*ds
) {
617 gcry_md_hd_t md
= NULL
;
618 char owner_name
[DNSSEC_CANONICAL_HOSTNAME_MAX
];
625 /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
627 if (dnskey
->key
->type
!= DNS_TYPE_DNSKEY
)
629 if (ds
->key
->type
!= DNS_TYPE_DS
)
631 if ((dnskey
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
) == 0)
632 return -EKEYREJECTED
;
633 if (dnskey
->dnskey
.protocol
!= 3)
634 return -EKEYREJECTED
;
636 if (!dnssec_algorithm_supported(dnskey
->dnskey
.algorithm
))
638 if (!dnssec_digest_supported(ds
->ds
.digest_type
))
641 if (dnskey
->dnskey
.algorithm
!= ds
->ds
.algorithm
)
643 if (dnssec_keytag(dnskey
) != ds
->ds
.key_tag
)
646 switch (ds
->ds
.digest_type
) {
648 case DNSSEC_DIGEST_SHA1
:
650 if (ds
->ds
.digest_size
!= 20)
653 gcry_md_open(&md
, GCRY_MD_SHA1
, 0);
656 case DNSSEC_DIGEST_SHA256
:
658 if (ds
->ds
.digest_size
!= 32)
661 gcry_md_open(&md
, GCRY_MD_SHA256
, 0);
665 assert_not_reached("Unknown digest");
671 r
= dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey
->key
), owner_name
, sizeof(owner_name
));
675 gcry_md_write(md
, owner_name
, r
);
676 md_add_uint16(md
, dnskey
->dnskey
.flags
);
677 md_add_uint8(md
, dnskey
->dnskey
.protocol
);
678 md_add_uint8(md
, dnskey
->dnskey
.algorithm
);
679 gcry_md_write(md
, dnskey
->dnskey
.key
, dnskey
->dnskey
.key_size
);
681 result
= gcry_md_read(md
, 0);
687 r
= memcmp(result
, ds
->ds
.digest
, ds
->ds
.digest_size
) != 0;