resolved-dns-dnssec.c revision aa89931749f081be8b1f90643c81ae2860257e53
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen This file is part of systemd.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Copyright 2015 Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen systemd is free software; you can redistribute it and/or modify it
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen under the terms of the GNU Lesser General Public License as published by
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen (at your option) any later version.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen systemd is distributed in the hope that it will be useful, but
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Lesser General Public License for more details.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen You should have received a copy of the GNU Lesser General Public License
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/* Open question:
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen * How does the DNSSEC canonical form of a hostname with a label
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen * containing a dot look like, the way DNS-SD does it?
a5a807e63a50314e190e9166d8a453cd8dd258e3Zbigniew Jędrzejewski-Szmek * - Iterative validation
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering * - NSEC proof of non-existance
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering * - NSEC3 proof of non-existance
39d8db043b599a7382f94bfc904d5e108af438bdLennart Poettering * - Make trust anchor store read additional DS+DNSKEY data from disk
39d8db043b599a7382f94bfc904d5e108af438bdLennart Poettering * - wildcard zones compatibility
39d8db043b599a7382f94bfc904d5e108af438bdLennart Poettering * - multi-label zone compatibility
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - DNSSEC cname/dname compatibility
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - per-interface DNSSEC setting
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - DSA support
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * - EC support?
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * The DNSSEC Chain of trust:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * DS RRs are protected like normal RRs
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Example chain:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool dnssec_algorithm_supported(int algorithm) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool dnssec_digest_supported(int digest) {
21d73c87b09ec2b8642424bc714ce9af3da4fc40Lennart Poetteringuint16_t dnssec_keytag(DnsResourceRecord *dnskey) {
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering /* The algorithm from RFC 4034, Appendix B. */
a2a416f768e2aa7db5b975cd50eb19237cac9cceLennart Poettering assert(dnskey->key->type == DNS_TYPE_DNSKEY);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering for (i = 0; i < dnskey->dnskey.key_size; i++)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering sum += (i & 1) == 0 ? (uint32_t) p[i] << 8 : (uint32_t) p[i];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int rr_compare(const void *a, const void *b) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Let's order the RRs according to RFC 4034, Section 6.3 */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering m = MIN((*x)->wire_format_size, (*y)->wire_format_size);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = memcmp((*x)->wire_format, (*y)->wire_format, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if ((*x)->wire_format_size < (*y)->wire_format_size)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else if ((*x)->wire_format_size > (*y)->wire_format_size)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *signature, size_t signature_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *exponent, size_t exponent_size,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *modulus, size_t modulus_size) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "(sig-val (rsa (s %m)))",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "(data (flags pkcs1) (hash %s %b))",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "(public-key (rsa (n %m) (e %m)))",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else if (ge != 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("RSA signature check failed: %s", gpg_strerror(ge));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void md_add_uint16(gcry_md_hd_t md, uint16_t v) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void md_add_uint32(gcry_md_hd_t md, uint32_t v) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(rrsig->key->type == DNS_TYPE_RRSIG);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering expiration = rrsig->rrsig.expiration * USEC_PER_SEC;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering inception = rrsig->rrsig.inception * USEC_PER_SEC;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Permit a certain amount of clock skew of 10% of the valid
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * time range. This takes inspiration from unbound's
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * resolver. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return realtime < inception || realtime > expiration;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t exponent_size, modulus_size, hash_size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(rrsig->key->type == DNS_TYPE_RRSIG);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(dnskey->key->type == DNS_TYPE_DNSKEY);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Verifies the the RRSet matching the specified "key" in "a",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * using the signature "rrsig" and the key "dnskey". It's
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * assumed the RRSIG and DNSKEY match. */
0014a4ad505d119c7ac4346d9d774c3f17f663a5Lennart Poettering if (!dnssec_algorithm_supported(rrsig->rrsig.algorithm))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dnssec_rrsig_expired(rrsig, realtime);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Collect all relevant RRs in a single array, so that we can look at the RRset */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering list = newa(DnsResourceRecord *, a->n_rrs);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dns_resource_key_equal(key, rr->key);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering /* We need the wire format for ordering, and digest calculation */
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = dns_resource_record_to_wire_format(rr, true);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering /* Bring the RRs into canonical order */
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering /* OK, the RRs are now in canonical order. Let's calculate the digest */
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint16(md, rrsig->rrsig.type_covered);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint8(md, rrsig->rrsig.algorithm);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint32(md, rrsig->rrsig.original_ttl);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint32(md, rrsig->rrsig.expiration);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint32(md, rrsig->rrsig.inception);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering for (k = 0; k < n; k++) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering r = dns_name_to_wire_format(DNS_RESOURCE_KEY_NAME(rr->key), wire_format_name, sizeof(wire_format_name), true);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering md_add_uint32(md, rrsig->rrsig.original_ttl);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering assert(rr->wire_format_rdata_offset <= rr->wire_format_size);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering l = rr->wire_format_size - rr->wire_format_rdata_offset;
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering gcry_md_write(md, (uint8_t*) rr->wire_format + rr->wire_format_rdata_offset, l);
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (*(uint8_t*) dnskey->dnskey.key == 0) {
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering /* exponent is > 255 bytes long */
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering exponent = (uint8_t*) dnskey->dnskey.key + 3;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering ((size_t) (((uint8_t*) dnskey->dnskey.key)[0]) << 8) |
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering ((size_t) ((uint8_t*) dnskey->dnskey.key)[1]);
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (3 + exponent_size >= dnskey->dnskey.key_size) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering modulus_size = dnskey->dnskey.key_size - 3 - exponent_size;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering /* exponent is <= 255 bytes long */
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering exponent = (uint8_t*) dnskey->dnskey.key + 1;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0];
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering if (1 + exponent_size >= dnskey->dnskey.key_size) {
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering modulus_size = dnskey->dnskey.key_size - 1 - exponent_size;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering rrsig->rrsig.signature, rrsig->rrsig.signature_size,
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering r = r ? DNSSEC_VERIFIED : DNSSEC_INVALID;
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poetteringint dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Checks if the specified DNSKEY RR matches the key used for
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * the signature in the specified RRSIG RR */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (dnssec_keytag(dnskey) != rrsig->rrsig.key_tag)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), rrsig->rrsig.signer);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenint dnssec_key_match_rrsig(DnsResourceKey *key, DnsResourceRecord *rrsig) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */
eb60f9cd4e93ff5016dc1b5486fd1b7e1565fd92Lennart Poettering if (rrsig->rrsig.type_covered != key->type)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering bool found_rrsig = false, found_dnskey = false;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Verifies all RRs from "a" that match the key "key", against DNSKEY and DS RRs in "validated_dnskeys" */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!a || a->n_rrs <= 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Iterate through each RRSIG RR. */
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering DNS_ANSWER_FOREACH(dnskey, validated_dnskeys) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = dnssec_rrsig_match_dnskey(rrsig, dnskey);
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering /* Take the time here, if it isn't set yet, so
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering * that we do all validations with the same
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering /* Yay, we found a matching RRSIG with a matching
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen * DNSKEY, awesome. Now let's verify all entries of
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering * the RRSet against the RRSIG and DNSKEY
f0e1546763304aedc90e91d70dab9eeb7c966cf8Lennart Poettering * combination. */
096b6773886bd7a0c8c97aa684b0b67dfae58355Lennart Poettering r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime);
096b6773886bd7a0c8c97aa684b0b67dfae58355Lennart Poettering if (r < 0 && r != EOPNOTSUPP)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* If the signature is invalid, or done using
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering an unsupported algorithm, let's try another
edc501d4674dadc304d45a7e1c5b69e207eb8cd4Lennart Poettering key and/or signature. After all they
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering key_tags and stuff are not unique, and
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering might be shared by multiple keys. */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenint dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* Converts the specified hostname into DNSSEC canonicalized
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering r = dns_label_unescape(&n, buffer, buffer_max);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering /* DNSSEC validation is always done on the ASCII version of the label */
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering k = dns_label_apply_idna(buffer, r, buffer, buffer_max);
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering /* The DNSSEC canonical form is not clear on what to
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering * do with dots appearing in labels, the way DNS-SD
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering * does it. Refuse it for now. */
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering for (i = 0; i < (size_t) r; i ++) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (buffer[i] >= 'A' && buffer[i] <= 'Z')
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering /* Not even a single label: this is the root domain name */
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering return (int) c;
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poetteringint dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) {
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX];
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnskey->key->type != DNS_TYPE_DNSKEY)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnskey->dnskey.algorithm != ds->ds.algorithm)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (dnssec_keytag(dnskey) != ds->ds.key_tag)
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering if (!dnssec_digest_supported(ds->ds.digest_type))
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering md_add_uint8(md, dnskey->dnskey.protocol);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen r = memcmp(result, ds->ds.digest, ds->ds.digest_size) != 0;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersenstatic const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = {